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>
54 Due to the frequent use of malloc/free in the code base (as opposed to
55 stack based allocation) these wrapper routines were added for easier debugging
56 - after their introduction several asserts fired that found genuine bugs. In
57 theory, for most programs that are not daemons we never really need to free memory
58 since it gets freed on program exit anyway. In addition, malloc should never
59 really fail - if so it usually indicates a programming error.
60 NOTE: On AIX the address 0x00000000 is a valid address, corresponding to a
61 read-only map present in the address space of all running programs.
64 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
65 void *xmalloc(size_t size) {
66 char *result = malloc(size);
68 LOG(LOG_ERR, "Failed to allocate %d bytes of memory\n", size);
70 // LOG(LOG_ERR, "malloc");
77 void *xmalloc_assert(size_t size) {
78 char *result = malloc(size);
80 LOG(LOG_ERR, "Failed to allocate %d bytes of memory\n", size);
81 OUTPUT("About to return NULL pointer - cannot continue\n");
87 void xfree(void *buf) {
89 LOG(LOG_ERR, "Freeing a NULL pointer is bad");
92 #ifndef NEVER_FREE_MEMORY
98 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
100 * malloc and copy string
102 char *smalloc(char *str) {
106 DEBUG("null input\n");
110 /* check string length */
113 LOG(LOG_ERR, "Failed to duplicate string '%s'\n", str);
122 * malloc and copy string
124 char *smalloc_assert(char *str) {
128 DEBUG("smalloc - string is NULL\n");
132 /* check string length */
135 LOG(LOG_ERR, "Failed to duplicate string '%s'\n", str);
136 OUTPUT("About to return NULL pointer - cannot continue\n");
144 * malloc and copy string with length
152 char *snmalloc(char *str, int len) {
157 LOG(LOG_ERR, "smalloc - string is NULL\n");
166 out = xmalloc_assert(len);
167 strncpy(out, str, len);
168 /* ensure always NULL-terminated */
171 out = strndup(str, len);
177 * get NEW string buffer
179 * snmalloc2("ABCDEF", 2,3) => "CDE"
186 BYTE *snmalloc2(BYTE *buf, int offset, int len) {
190 LOG(LOG_ERR, "null input");
194 LOG(LOG_ERR, "offset < 0");
198 LOG(LOG_ERR, "len < 0");
203 BYTE *output = (BYTE *) xmalloc(len + 1);
204 if (output == NULL) {
208 memcpy((void *) output, (void *) &buf[offset], len);
218 void sfree(char *str) {
225 * get fullpathname of file
226 * This malloc new buf for the fullpathname.
229 * basepath must be start from /
231 * UnitTest : check_conf
234 char *getFullpathName(char *basepath, char *filename) {
235 char *fullpath = NULL;
241 if (basepath == NULL) {
242 LOG(LOG_ERR, "null input");
245 if (filename == NULL) {
246 LOG(LOG_ERR, "null input");
250 /* start from root */
251 if (filename[0] == '/') {
252 /* seems fullpath, copy the filename to new buf */
253 return smalloc(filename);
256 /* basepath + filename */
257 if (basepath[0] != '/') {
258 /* relative path -> error when it run as daemon */
259 LOG(LOG_TODO, "getFullpathName() - basepath, '%s' is not started from root\n", basepath);
266 0x00 /AAA/ + BBB => /AAA/BBB
267 0x01 /AAA/ + ./BBB => /AAA/BBB
268 0x10 /AAA + BBB => /AAA/BBB
269 0x11 /AAA + ./BBB => /AAA/BBB
271 basepath_len = strlen(basepath);
272 filename_len = strlen(filename);
274 if (filename_len < 2) {
275 LOG(LOG_ERR, "ilename len < 2\n");
279 /* basepath has "/" at end. else add "/" */
280 if (basepath[basepath_len - 1] != '/') {
283 /* filename has "./" at start ? remove */
284 if ((filename[0] == '.') && (filename[1] == '/')) {
291 /* /AAA/ + BBB => /AAA/BBB */
292 fullpath = xmalloc_assert(basepath_len + filename_len + 1);
293 memcpy(fullpath, basepath, basepath_len);
294 memcpy(&fullpath[basepath_len], filename, filename_len);
295 fullpath[basepath_len + filename_len] = 0;
298 /* /AAA/ + ./BBB => /AAA/BBB */
299 fullpath = xmalloc_assert(basepath_len + filename_len + 1 - 2);
300 memcpy(fullpath, basepath, basepath_len);
301 memcpy(&fullpath[basepath_len], filename + 2, filename_len - 2);
302 fullpath[basepath_len + filename_len - 2] = 0;
305 /* /AAA + BBB => /AAA/BBB */
306 fullpath = xmalloc_assert(basepath_len + 1 + filename_len + 1);
307 memcpy(fullpath, basepath, basepath_len);
308 fullpath[basepath_len] = '/';
309 memcpy(&fullpath[basepath_len + 1], filename, filename_len);
310 fullpath[basepath_len + filename_len + 1] = 0;
313 /* /AAA + ./BBB => /AAA/BBB */
314 fullpath = xmalloc_assert(basepath_len + 1 + filename_len + 1 - 2);
315 memcpy(fullpath, basepath, basepath_len);
316 fullpath[basepath_len] = '/';
317 memcpy(&fullpath[basepath_len + 1], filename + 2, filename_len - 2);
318 fullpath[basepath_len + filename_len - 1] = 0;
321 LOG(LOG_ERR, "internal error\n");
329 * Get dirname from fullpath filename
331 * this malloc new string
333 * /AAA/BBB/CCC/DDD => /AAA/BBB/CCC/
336 char *getFullpathDir(char *filename) {
337 char *fullpath = NULL;
342 if (filename == NULL) {
343 LOG(LOG_ERR, "null input");
347 filename_len = strlen(filename);
349 for (i = filename_len; i > 0; i--) {
350 if (filename[i] == '/') {
351 // slash = &filename[i];
356 fullpath = xmalloc_assert(i+2);
357 memcpy(fullpath, filename, i+1);
366 * Little Endian (Intel)
368 UINT32 byte2uint32(BYTE *b) {
372 LOG(LOG_ERR, "byte2uint32 - NULL");
373 OUTPUT("About to return NULL pointer - cannot continue\n"); // TODO
394 char * trim(char *str) {
400 LOG(LOG_ERR, "null input");
405 strLen = strlen(str);
411 end = str + strLen - 1;
413 /* skip space at start */
414 while (*str == ' ') {
419 /* remove space at tail */
421 while (*end == ' ') {
430 * BYTE* -> Hex string (malloc)
433 char *getHexString(BYTE *bin, int size) {
441 LOG(LOG_ERR, "null input");
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]);
451 LOG(LOG_ERR, "FATAL");
466 char *outBuf, int outBufLen, char *head, BYTE *data, int num, char *tail) {
471 if (outBuf == NULL) {
472 LOG(LOG_ERR, "null input");
476 LOG(LOG_ERR, "null input");
480 LOG(LOG_ERR, "null input");
484 LOG(LOG_ERR, "null input");
489 outSoFar += snprintf(outBuf, outBufLen, "%s[%d]=", head, num);
491 for (i = 0; i < num; i++) {
492 if ( outSoFar < outBufLen ) {
493 outSoFar += snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%02X", data[i]);
496 if ( outSoFar < outBufLen ) {
497 snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%s", tail);
501 void printHex(char *head, BYTE *data, int num, char *tail) {
504 snprintHex(outBuf, 1023, head, data, num, tail);
505 /* I could just use OUTPUT(outBuf), but since warnings are errors
506 I have to use this less efficient form */
507 OUTPUT("%s", outBuf);
510 void debugHex(char *head, BYTE *data, int num, char *tail) {
512 snprintHex(outBuf, 1023, head, data, num, tail);
513 writeLog(LOG_DEBUG, outBuf);
516 void fprintHex(FILE *fp, BYTE *data, int num) {
521 LOG(LOG_ERR, "null input");
525 LOG(LOG_ERR, "null input");
530 for (i = 0; i < num; i++) {
531 fprintf(fp, "%02X", data[i]);
538 UINT32 b2l(UINT32 in) {
558 * @param filename output filename
559 * @param len message length
565 char *filename, int len, BYTE * msg) {
567 const int max_retries = 10;
573 LOG(LOG_ERR, "len <0 \n");
577 LOG(LOG_ERR, "msg is NULL \n");
580 if (filename == NULL) {
581 LOG(LOG_ERR, "filename is NULL \n");
585 if ((fp = fopen(filename, "w+b")) == NULL) {
586 LOG(LOG_ERR, "File open failed, %s \n", filename);
587 return PTS_FATAL; // TODO(munetoh): set PTS error code.
590 /* If the filesystem is full, we shouldn't hang whilst trying to
591 write the file to disk -> we only allow so many attempts. */
592 while (n_tries < max_retries) {
593 int bytes_written = fwrite(&msg[ptr], 1, len, fp);
594 /* DEBUG_IFM(" %s %d %d\n", filename, rc, len); */
595 ptr += bytes_written;
596 len -= bytes_written;
603 /* DEBUG_IFM(" %s %d \n", filename, len); */
608 LOG(LOG_ERR, "After %d retries still have %d bytes unwritten to '%s'\n", max_retries, len, filename);
618 UINT32 getUint32(BYTE *buf) {
623 LOG(LOG_ERR, "null input");
626 // TODO check the size?
628 data = (buf[0] << 24) |
640 int makeDir(char *dirname) {
641 int rc = PTS_SUCCESS;
645 if (dirname == NULL) {
646 LOG(LOG_ERR, "null input");
651 rc = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR |
652 S_IRGRP | S_IWGRP | S_IXGRP);
656 LOG(LOG_ERR, "mkdir %s failed, EACCES", dirname);
661 rc = lstat(dirname, &st);
663 if ((st.st_mode & S_IFMT) != S_IFDIR) {
664 LOG(LOG_ERR, "directory, %s is not a directory %x %x\n",
665 dirname, (st.st_mode & S_IFMT), S_IFDIR);
666 rc = PTS_INTERNAL_ERROR;
672 LOG(LOG_ERR, "lstat(%s) failed, errno=%d\n", dirname, errno);
677 LOG(LOG_ERR, "mkdir %s failed, EFAULT", dirname);
680 // TODO add others :-)
682 LOG(LOG_ERR, "mkdir %s failed, errono = 0x%X", dirname, errno);
695 * PTS_SUCCESS - exist
696 * PTS_INTERNAL_ERROR - not exist or not a dir
699 int checkDir(char *dirname) {
703 if (dirname == NULL) {
704 LOG(LOG_ERR, "null input");
708 if (lstat(dirname, &st) == -1) {
710 return PTS_INTERNAL_ERROR; // TODO OPENPTS_DIR_MISSING;
711 } else if ((st.st_mode & S_IFMT) != S_IFDIR) {
713 return PTS_INTERNAL_ERROR;
716 return PTS_SUCCESS; // TODO OPENPTS_DIR_EXIST;
720 * Check file (reguler file)
722 int checkFile(char *filename) {
726 if (filename == NULL) {
727 LOG(LOG_ERR, "null input");
731 if (lstat(filename, &st) == -1) {
733 return OPENPTS_FILE_MISSING;
734 } else if ((st.st_mode & S_IFMT) != S_IFREG) {
736 return PTS_INTERNAL_ERROR;
739 return OPENPTS_FILE_EXISTS;
745 ssize_t wrapRead(int fd, void *buf, size_t count) {
750 LOG(LOG_ERR, "null input");
755 len = read(fd, buf, count);
756 if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
766 ssize_t wrapWrite(int fd, const void *buf, size_t count) {
771 LOG(LOG_ERR, "null input");
776 len = write(fd, buf, count);
777 if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
785 * recursive part of unlinkDir()
787 static int unlinkDir_(char *dirPath) {
789 struct dirent *entry;
790 char path[PATH_MAX + 1];
795 if (dirPath == NULL) {
796 LOG(LOG_ERR, "null input");
800 dirHandle = opendir(dirPath);
801 if (dirHandle == NULL) {
802 LOG(LOG_ERR, "opendir(%s) fail", dirPath);
809 rc = readdir_r(dirHandle, &dr, &entry);
811 if (entry == NULL) break;
813 if (strcmp(".", entry->d_name) == 0) continue;
814 if (strcmp("..", entry->d_name) == 0) continue;
816 snprintf(path, sizeof(path), "%s/%s", dirPath, entry->d_name);
817 if (stat(path, &st) != 0) {
818 LOG(LOG_ERR, "stat(%s) fail", path);
823 if (S_ISDIR(st.st_mode)) {
824 if (unlinkDir_(path) != 0) {
828 } else if (S_ISREG(st.st_mode)) {
829 if (unlink(path) != 0) {
830 LOG(LOG_ERR, "unlink(%s) fail", path);
838 if (rmdir(dirPath) != 0) {
839 LOG(LOG_ERR, "rmdir(%s) fail", dirPath);
853 * Recursively destroy the content of a directory
855 int unlinkDir(const char *dirPath) {
856 char path[PATH_MAX + 1];
859 if (dirPath == NULL) {
860 LOG(LOG_ERR, "null input");
863 if (dirPath[0] == '\0' || strlen(dirPath) >= PATH_MAX) {
864 LOG(LOG_ERR, "bad dirPath, %s", dirPath);
868 strncpy(path, dirPath, sizeof(path));
869 // there is at least one byte free before path[PATH_MAX]
871 return unlinkDir_(path);