2 * This file is part of the OpenPTS project.
4 * The Initial Developer of the Original Code is International
5 * Business Machines Corporation. Portions created by IBM
6 * Corporation are Copyright (C) 2010 International Business
7 * Machines Corporation. All Rights Reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the Common Public License as published by
11 * IBM Corporation; either version 1 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * Common Public License for more details.
19 * You should have received a copy of the Common Public License
20 * along with this program; if not, a copy can be viewed at
21 * http://www.opensource.org/licenses/cpl1.0.php.
26 * \brief misc functions
27 * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
29 * cleanup 2011-07-06 SM
42 #include <search.h> // hash table
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
55 Due to the frequent use of malloc/free in the code base (as opposed to
56 stack based allocation) these wrapper routines were added for easier debugging
57 - after their introduction several asserts fired that found genuine bugs. In
58 theory, for most programs that are not daemons we never really need to free memory
59 since it gets freed on program exit anyway. In addition, malloc should never
60 really fail - if so it usually indicates a programming error.
61 NOTE: On AIX the address 0x00000000 is a valid address, corresponding to a
62 read-only map present in the address space of all running programs.
65 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
66 void *xmalloc(size_t size) {
67 char *result = malloc(size);
69 ERROR("Failed to allocate %d bytes of memory\n", size);
78 void *xmalloc_assert(size_t size) {
79 char *result = malloc(size);
81 ERROR("Failed to allocate %d bytes of memory\n", size);
82 ASSERT(0, "About to return NULL pointer - cannot continue\n");
87 void xfree(void *buf) {
88 ASSERT(NULL != buf, "Freeing a NULL pointer is bad\n");
89 #ifndef NEVER_FREE_MEMORY
95 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
97 * malloc and copy string
99 char *smalloc(char *str) {
103 DEBUG("smalloc - string is NULL\n");
107 /* check string length */
110 ERROR("Failed to duplicate string '%s'\n", str);
114 len = (int)strlen(str);
117 out = (char *) malloc(len + 1);
119 ERROR("smalloc - no memory\n");
124 memcpy(out, str, len);
127 /* remove bad chars :-P */
128 // TODO 20101118 SM added for the safe print
129 for (i = 0; i < len; i++) {
130 if ((out[i] < 0x20) || (0x7e < out[i])) {
142 * malloc and copy string
144 char *smalloc_assert(char *str) {
148 DEBUG("smalloc - string is NULL\n");
152 /* check string length */
155 ERROR("Failed to duplicate string '%s'\n", str);
156 ASSERT(0, "About to return NULL pointer - cannot continue\n");
163 * malloc and copy string with length
171 char *snmalloc(char *str, int len) {
176 DEBUG("smalloc - string is NULL\n");
185 out = xmalloc_assert(len);
186 strncpy(out, str, len);
187 /* ensure always NULL-terminated */
190 out = strndup(str, len);
196 * get NEW string buffer
198 * snmalloc2("ABCDEF", 2,3) => "CDE"
205 BYTE *snmalloc2(BYTE *buf, int offset, int len) {
206 BYTE *output = (BYTE *) xmalloc(len + 1);
207 if (output == NULL) {
211 memcpy((void *) output, (void *) &buf[offset], len);
221 void sfree(char *str) {
228 * get fullpathname of file
229 * This malloc new buf for the fullpathname.
232 * basepath must be start from /
234 * UnitTest : check_conf
237 char *getFullpathName(char *basepath, char *filename) {
238 char *fullpath = NULL;
244 ASSERT(filename != NULL, "getFullpathName - filename is NULL\n");
245 ASSERT(basepath != NULL, "getFullpathName - basepath is NULL\n");
247 /* start from root */
248 if (filename[0] == '/') {
249 /* seems fullpath, copy the filename to new buf */
250 return smalloc(filename);
253 /* basepath + filename */
254 if (basepath[0] != '/') {
255 /* relative path -> error when it run as daemon */
256 TODO("getFullpathName() - basepath, '%s' is not started from root\n", basepath);
263 0x00 /AAA/ + BBB => /AAA/BBB
264 0x01 /AAA/ + ./BBB => /AAA/BBB
265 0x10 /AAA + BBB => /AAA/BBB
266 0x11 /AAA + ./BBB => /AAA/BBB
268 basepath_len = strlen(basepath);
269 filename_len = strlen(filename);
271 if (filename_len < 2) {
272 ERROR("ilename len < 2\n");
276 /* basepath has "/" at end. else add "/" */
277 if (basepath[basepath_len - 1] != '/') {
280 /* filename has "./" at start ? remove */
281 if ((filename[0] == '.') && (filename[1] == '/')) {
288 /* /AAA/ + BBB => /AAA/BBB */
289 fullpath = xmalloc_assert(basepath_len + filename_len + 1);
290 memcpy(fullpath, basepath, basepath_len);
291 memcpy(&fullpath[basepath_len], filename, filename_len);
292 fullpath[basepath_len + filename_len] = 0;
295 /* /AAA/ + ./BBB => /AAA/BBB */
296 fullpath = xmalloc_assert(basepath_len + filename_len + 1 - 2);
297 memcpy(fullpath, basepath, basepath_len);
298 memcpy(&fullpath[basepath_len], filename + 2, filename_len - 2);
299 fullpath[basepath_len + filename_len - 2] = 0;
302 /* /AAA + BBB => /AAA/BBB */
303 fullpath = xmalloc_assert(basepath_len + 1 + filename_len + 1);
304 memcpy(fullpath, basepath, basepath_len);
305 fullpath[basepath_len] = '/';
306 memcpy(&fullpath[basepath_len + 1], filename, filename_len);
307 fullpath[basepath_len + filename_len + 1] = 0;
310 /* /AAA + ./BBB => /AAA/BBB */
311 fullpath = xmalloc_assert(basepath_len + 1 + filename_len + 1 - 2);
312 memcpy(fullpath, basepath, basepath_len);
313 fullpath[basepath_len] = '/';
314 memcpy(&fullpath[basepath_len + 1], filename + 2, filename_len - 2);
315 fullpath[basepath_len + filename_len - 1] = 0;
318 ERROR("internal error\n");
326 * Get dirname from fullpath filename
328 * this malloc new string
330 * /AAA/BBB/CCC/DDD => /AAA/BBB/CCC/
333 char *getFullpathDir(char *filename) {
334 char *fullpath = NULL;
339 ASSERT(filename != NULL, "getFullpathDir - filename is NULL\n");
341 filename_len = strlen(filename);
343 for (i = filename_len; i > 0; i--) {
344 if (filename[i] == '/') {
345 // slash = &filename[i];
350 fullpath = xmalloc_assert(i+2);
351 memcpy(fullpath, filename, i+1);
360 * Little Endian (Intel)
362 UINT32 byte2uint32(BYTE *b) {
366 ERROR("byte2uint32 - NULL");
397 char * trim(char *str) {
401 ASSERT(str != NULL, "trim - str is NULL\n");
403 strLen = strlen(str);
409 end = str + strLen - 1;
411 /* skip space at start */
412 while (*str == ' ') {
417 /* remove space at tail */
419 while (*end == ' ') {
428 * BYTE* -> Hex string (malloc)
431 char *getHexString(BYTE *bin, int size) {
438 // if (bin == NULL) {
439 // ERROR("getHexString() buf is null\n");
442 ASSERT(bin != NULL, "getHexString - bin is NULL\n");
445 buf = xmalloc_assert(size * 2 + 1);
447 for (i = 0; i < size; i++) {
448 // len = snprintf(ptr, sizeof(ptr), "%02x", bin[i]);
449 len = snprintf(ptr, 3, "%02x", bin[i]);
466 char *outBuf, int outBufLen, char *head, BYTE *data, int num, char *tail) {
470 ASSERT(outBuf != NULL, "snprintHex - outBuf is NULL\n");
471 ASSERT(head != NULL, "snprintHex - head is NULL\n");
472 ASSERT(data != NULL, "snprintHex - data is NULL\n");
473 ASSERT(tail != NULL, "snprintHex - tail is NULL\n");
475 outSoFar += snprintf(outBuf, outBufLen, "%s[%d]=", head, num);
477 for (i = 0; i < num; i++) {
478 if ( outSoFar < outBufLen ) {
479 outSoFar += snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%02X", data[i]);
482 if ( outSoFar < outBufLen ) {
483 snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%s", tail);
487 void printHex(char *head, BYTE *data, int num, char *tail) {
489 snprintHex(outBuf, 1023, head, data, num, tail);
490 /* I could just use OUTPUT(outBuf), but since warnings are errors
491 I have to use this less efficient form */
492 OUTPUT("%s", outBuf);
495 void debugHex(char *head, BYTE *data, int num, char *tail) {
497 snprintHex(outBuf, 1023, head, data, num, tail);
498 writeLog(LOG_DEBUG, outBuf);
501 void fprintHex(FILE *fp, BYTE *data, int num) {
503 for (i = 0; i < num; i++) {
504 fprintf(fp, "%02X", data[i]);
511 UINT32 b2l(UINT32 in) {
531 * @param filename output filename
532 * @param len message length
538 char *filename, int len, BYTE * msg) {
540 const int max_retries = 10;
549 ERROR("msg is NULL \n");
552 if (filename == NULL) {
553 ERROR("filename is NULL \n");
557 if ((fp = fopen(filename, "w+b")) == NULL) {
558 ERROR("File open failed, %s \n", filename);
559 return PTS_FATAL; // TODO(munetoh): set PTS error code.
562 /* If the filesystem is full, we shouldn't hang whilst trying to
563 write the file to disk -> we only allow so many attempts. */
564 while (n_tries < max_retries) {
565 int bytes_written = fwrite(&msg[ptr], 1, len, fp);
566 /* DEBUG_IFM(" %s %d %d\n", filename, rc, len); */
567 ptr += bytes_written;
568 len -= bytes_written;
575 /* DEBUG_IFM(" %s %d \n", filename, len); */
580 ERROR("After %d retries still have %d bytes unwritten to '%s'\n", max_retries, len, filename);
589 int getUint32(BYTE *buf) {
591 data = (buf[0] << 24) |
603 int makeDir(char *dirname) {
604 int rc = PTS_SUCCESS;
608 rc = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR |
609 S_IRGRP | S_IWGRP | S_IXGRP);
613 ERROR("mkdir %s failed, EACCES", dirname);
618 rc = lstat(dirname, &st);
620 if ((st.st_mode & S_IFMT) != S_IFDIR) {
621 ERROR("directory, %s is not a directory %x %x\n",
622 dirname, (st.st_mode & S_IFMT), S_IFDIR);
623 rc = PTS_INTERNAL_ERROR;
629 ERROR("lstat(%s) failed, errno=%d\n", dirname, errno);
634 ERROR("mkdir %s failed, EFAULT", dirname);
637 // TODO add others :-)
639 ERROR("mkdir %s failed, errono = 0x%X", dirname, errno);
652 * PTS_SUCCESS - exist
653 * PTS_INTERNAL_ERROR - not exist or not a dir
656 int checkDir(char *dirname) {
659 if (dirname == NULL) {
663 if (lstat(dirname, &st) == -1) {
665 return PTS_INTERNAL_ERROR; // TODO OPENPTS_DIR_MISSING;
666 } else if ((st.st_mode & S_IFMT) != S_IFDIR) {
668 return PTS_INTERNAL_ERROR;
671 return PTS_SUCCESS; // TODO OPENPTS_DIR_EXIST;
675 * Check file (reguler file)
677 int checkFile(char *filename) {
680 if (filename == NULL) {
684 if (lstat(filename, &st) == -1) {
686 return OPENPTS_FILE_MISSING;
687 } else if ((st.st_mode & S_IFMT) != S_IFREG) {
689 return PTS_INTERNAL_ERROR;
692 return OPENPTS_FILE_EXISTS;
698 ssize_t wrapRead(int fd, void *buf, size_t count) {
701 len = read(fd, buf, count);
702 if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
712 ssize_t wrapWrite(int fd, const void *buf, size_t count) {
715 len = write(fd, buf, count);
716 if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
724 * recursive part of unlinkDir()
726 static int unlinkDir_(char *dirPath) {
728 struct dirent *entry;
730 char path[PATH_MAX + 1];
735 dirHandle = opendir(dirPath);
736 if (dirHandle == NULL) {
737 ERROR("opendir(%s) fail", dirPath);
744 rc = readdir_r(dirHandle, &dr, &entry);
746 if (entry == NULL) break;
748 if (strcmp(".", entry->d_name) == 0) continue;
749 if (strcmp("..", entry->d_name) == 0) continue;
751 snprintf(path, sizeof(path), "%s/%s", dirPath, entry->d_name);
752 if (stat(path, &st) != 0) {
753 ERROR("stat(%s) fail", path);
758 if (S_ISDIR(st.st_mode)) {
759 if (unlinkDir_(path) != 0) {
763 } else if (S_ISREG(st.st_mode)) {
764 if (unlink(path) != 0) {
765 ERROR("unlink(%s) fail", path);
773 if (rmdir(dirPath) != 0) {
774 ERROR("rmdir(%s) fail", dirPath);
788 * Recursively destroy the content of a directory
790 int unlinkDir(const char *dirPath) {
791 char path[PATH_MAX + 1];
793 if (dirPath == NULL || dirPath[0] == '\0' || strlen(dirPath) >= PATH_MAX) {
797 strncpy(path, dirPath, sizeof(path));
798 // there is at least one byte free before path[PATH_MAX]
800 return unlinkDir_(path);