OSDN Git Service

aix feeadback
[openpts/openpts.git] / src / misc.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
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.
8  *
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)
12  * any later version.
13  *
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.
18  *
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.
22  */
23
24 /**
25  * \file src/misc.c
26  * \brief misc functions
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-09-08
29  * cleanup 2011-07-06 SM
30  *
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <dirent.h>
37
38 #include <netdb.h>
39 #include <errno.h>
40
41 #define __USE_GNU
42 #include <search.h>  // hash table
43
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <sys/stat.h>
47 #include <netinet/in.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50
51 #include <openpts.h>
52 // #include <log.h>
53
54 /**
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.
63 **/
64
65 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
66 void *xmalloc(size_t size) {
67     char *result = malloc(size);
68     if (NULL == result) {
69         ERROR("Failed to allocate %d bytes of memory\n", size);
70         // if ( size > 0 ) {
71         //     ERROR("malloc");
72         // }
73     }
74     return result;
75 }
76 #endif
77
78 void *xmalloc_assert(size_t size) {
79     char *result = malloc(size);
80     if (NULL == result) {
81         ERROR("Failed to allocate %d bytes of memory\n", size);
82         ASSERT(0, "About to return NULL pointer - cannot continue\n");
83     }
84     return result;
85 }
86
87 void xfree(void *buf) {
88     ASSERT(NULL != buf, "Freeing a NULL pointer is bad\n");
89 #ifndef NEVER_FREE_MEMORY
90     free(buf);
91 #endif
92 }
93
94
95 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
96 /**
97  * malloc and copy string
98  */
99 char *smalloc(char *str) {
100     char *out;
101
102     if (str == NULL) {
103         DEBUG("smalloc - string is NULL\n");
104         return NULL;
105     }
106
107     /* check string length */
108     out = strdup(str);
109     if (out == NULL) {
110         ERROR("Failed to duplicate string '%s'\n", str);
111     }
112
113 #if 0
114     len = (int)strlen(str);
115
116     /* malloc */
117     out = (char *) malloc(len + 1);
118     if (out == NULL) {
119         ERROR("smalloc - no memory\n");
120         return NULL;
121     }
122
123     /* copy */
124     memcpy(out, str, len);
125     out[len] = 0;  // \n
126
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])) {
131             out[i] = '_';
132         }
133     }
134 #endif
135
136     return out;
137 }
138 #endif
139
140
141 /**
142  * malloc and copy string
143  */
144 char *smalloc_assert(char *str) {
145     char *out;
146
147     if (str == NULL) {
148         DEBUG("smalloc - string is NULL\n");
149         return NULL;
150     }
151
152     /* check string length */
153     out = strdup(str);
154     if (NULL == out) {
155         ERROR("Failed to duplicate string '%s'\n", str);
156         ASSERT(0, "About to return NULL pointer - cannot continue\n");
157     }
158
159     return out;
160 }
161
162 /**
163  * malloc and copy string with length
164  * add \n
165  * len(str) > len
166  *
167  *  str    len   out
168  *  AAAAA  5     AAAA\n
169  *  AAAAA  4     AAA\n
170  */
171 char *snmalloc(char *str, int len) {
172     char *out;
173
174     /* check */
175     if (str == NULL) {
176         DEBUG("smalloc - string is NULL\n");
177         return NULL;
178     }
179
180     if (len == 0) {
181         return NULL;
182     }
183
184 #ifdef MACOS
185     out = xmalloc_assert(len);
186     strncpy(out, str, len);
187     /* ensure always NULL-terminated */
188     out[len - 1] = '\0';
189 #else
190     out = strndup(str, len);
191 #endif
192     return out;
193 }
194
195 /**
196  * get NEW string buffer
197  *
198  *  snmalloc2("ABCDEF", 2,3) => "CDE"
199  *
200  *
201  * @param buf input
202  * @param offset
203  * @param len
204  */
205 BYTE *snmalloc2(BYTE *buf, int offset, int len) {
206     BYTE *output = (BYTE *) xmalloc(len + 1);
207     if (output == NULL) {
208         return NULL;
209     }
210
211     memcpy((void *) output, (void *) &buf[offset], len);
212     output[len] = 0;
213
214     return output;
215 }
216
217
218 /**
219  * free string buffer
220  */
221 void sfree(char *str) {
222     xfree(str);
223 }
224
225
226
227 /**
228  * get fullpathname of file
229  * This malloc new buf for the fullpathname. 
230  * In config
231  *
232  * basepath must be start from /
233  *  
234  * UnitTest : check_conf
235  *
236  */
237 char *getFullpathName(char *basepath, char *filename) {
238     char *fullpath = NULL;
239     int basepath_len;
240     int filename_len;
241     int slash = 0;
242
243     /* check */
244     ASSERT(filename != NULL, "getFullpathName - filename is NULL\n");
245     ASSERT(basepath != NULL, "getFullpathName - basepath is NULL\n");
246
247     /* start from root */
248     if (filename[0] == '/') {
249         /* seems fullpath, copy the filename to new buf */
250         return smalloc(filename);
251     }
252
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);
257     }
258
259
260     /*
261       rule
262
263         0x00 /AAA/ +   BBB => /AAA/BBB
264         0x01 /AAA/ + ./BBB => /AAA/BBB
265         0x10 /AAA  +   BBB => /AAA/BBB
266         0x11 /AAA  + ./BBB => /AAA/BBB  
267     */
268     basepath_len = strlen(basepath);
269     filename_len = strlen(filename);
270
271     if (filename_len < 2) {
272         ERROR("ilename len < 2\n");
273         return NULL;
274     }
275
276     /* basepath has "/" at end. else add "/" */
277     if (basepath[basepath_len - 1] !=  '/') {
278         slash = 0x10;
279     }
280     /* filename has "./" at start ? remove */
281     if ((filename[0] ==  '.') && (filename[1] ==  '/')) {
282         slash |= 0x01;
283     }
284
285     /* */
286     switch (slash) {
287         case 0x00:
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;
293             break;
294         case 0x01:
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;
300             break;
301         case 0x10:
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;
308             break;
309         case 0x11:
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;
316             break;
317         default:
318             ERROR("internal error\n");
319             break;
320     }  // switch
321
322     return fullpath;
323 }
324
325 /**
326  * Get dirname from fullpath filename
327  * 
328  * this malloc new string
329  *
330  * /AAA/BBB/CCC/DDD => /AAA/BBB/CCC/ 
331  *
332  */
333 char *getFullpathDir(char *filename) {
334     char *fullpath = NULL;
335     // char *slash;
336     int filename_len;
337     int i;
338
339     ASSERT(filename != NULL, "getFullpathDir - filename is NULL\n");
340
341     filename_len = strlen(filename);
342
343     for (i = filename_len; i > 0; i--) {
344         if (filename[i] == '/') {
345             // slash = &filename[i];
346             break;
347         }
348     }
349
350     fullpath = xmalloc_assert(i+2);
351     memcpy(fullpath, filename, i+1);
352     fullpath[i+1] = 0;
353     return fullpath;
354 }
355
356
357
358 /**
359  * Byte to Uint32 
360  * Little Endian (Intel)
361  */
362 UINT32 byte2uint32(BYTE *b) {
363     UINT32 a = 0;
364
365     if (b == NULL) {
366         ERROR("byte2uint32 - NULL");
367         exit(-1);
368     }
369
370 #if 0  // BE
371     a = b[0];
372     a = a << 8;
373     a += b[1];
374     a = a << 8;
375     a += b[2];
376     a = a << 8;
377     a += b[3];
378 #else
379     a = b[3];
380     a = a << 8;
381     a += b[2];
382     a = a << 8;
383     a += b[1];
384     a = a << 8;
385     a += b[0];
386 #endif
387
388     return a;
389 }
390
391 /**
392  * remove space
393  *
394  * Unit Test
395  * TODO
396  */
397 char * trim(char *str) {
398     size_t strLen;
399     char *start, *end;
400
401     ASSERT(str != NULL, "trim - str is NULL\n");
402
403     strLen = strlen(str);
404     if (0 == strLen) {
405         return str;
406     }
407
408     start = str;
409     end = str + strLen - 1;
410
411     /* skip space at start */
412     while (*str == ' ') {
413         str++;
414     }
415     start = str;
416
417     /* remove space at tail */
418     // TBD
419     while (*end == ' ') {
420         *end = 0;
421         end--;
422     }
423
424     return start;
425 }
426
427 /**
428  * BYTE* -> Hex string (malloc)
429  * 
430  */
431 char *getHexString(BYTE *bin, int size) {
432     char * buf;
433     char * ptr;
434     int i;
435     int len;
436
437     /* check */
438     // if (bin == NULL) {
439     //    ERROR("getHexString() buf is null\n");
440     //    return NULL;
441     // }
442     ASSERT(bin != NULL, "getHexString - bin is NULL\n");
443
444
445     buf = xmalloc_assert(size * 2 + 1);
446     ptr = buf;
447     for (i = 0; i < size; i++) {
448         // len = snprintf(ptr, sizeof(ptr), "%02x", bin[i]);
449         len = snprintf(ptr, 3, "%02x", bin[i]);
450         if (len != 2) {
451             ERROR("FATAL");
452             free(buf);
453             return NULL;
454         }
455         ptr += 2;  // len;
456     }
457     ptr[0] = '\0';
458
459     return buf;
460 }
461
462 /**
463  * print Hex string 
464  */
465 void snprintHex(
466     char *outBuf, int outBufLen, char *head, BYTE *data, int num, char *tail) {
467     int outSoFar = 0;
468     int i;
469
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");
474
475     outSoFar += snprintf(outBuf, outBufLen, "%s[%d]=", head, num);
476
477     for (i = 0; i < num; i++) {
478         if ( outSoFar < outBufLen ) {
479             outSoFar += snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%02X", data[i]);
480         }
481     }
482     if ( outSoFar < outBufLen ) {
483         snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%s", tail);
484     }
485 }
486
487 void printHex(char *head, BYTE *data, int num, char *tail) {
488     char outBuf[1024];
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);
493 }
494
495 void debugHex(char *head, BYTE *data, int num, char *tail) {
496     char outBuf[1024];
497     snprintHex(outBuf, 1023, head, data, num, tail);
498     writeLog(LOG_DEBUG, outBuf);
499 }
500
501 void fprintHex(FILE *fp, BYTE *data, int num) {
502     int i;
503     for (i = 0; i < num; i++) {
504         fprintf(fp, "%02X", data[i]);
505     }
506 }
507
508 /**
509  *  Convert Endian 
510  */
511 UINT32 b2l(UINT32 in) {
512     UINT32 out;
513
514     out  = in & 0xff;
515     in   = in  >> 8;
516     out  = out << 8;
517     out += in & 0xff;
518     in   = in  >> 8;
519     out  = out << 8;
520     out += in & 0xff;
521     in   = in  >> 8;
522     out  = out << 8;
523     out += in & 0xff;
524
525     return out;
526 }
527
528 /**
529  * save to file
530  *
531  * @param filename output filename
532  * @param len message length
533  * @param msg message
534  *
535  *
536  */
537 int saveToFile(
538     char *filename, int len, BYTE * msg) {
539     FILE *fp;
540     const int max_retries = 10;
541     int n_tries = 0;
542     int ptr = 0;
543
544     if (len < 0) {
545         ERROR("len <0 \n");
546         return PTS_FATAL;
547     }
548     if (msg == NULL) {
549         ERROR("msg is NULL \n");
550         return PTS_FATAL;
551     }
552     if (filename == NULL) {
553         ERROR("filename is NULL \n");
554         return PTS_FATAL;
555     }
556
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.
560     }
561
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;
569         n_tries++;
570         if (len <= 0) {
571             break;
572         }
573     }
574
575     /* DEBUG_IFM(" %s %d \n", filename, len); */
576
577     fclose(fp);
578
579     if (len > 0) {
580         ERROR("After %d retries still have %d bytes unwritten to '%s'\n", max_retries, len, filename);
581         return PTS_FATAL;
582     } else {
583         return PTS_SUCCESS;
584     }
585 }
586
587 /**
588  */
589 int getUint32(BYTE *buf) {
590     int data;
591     data = (buf[0] << 24) |
592            (buf[1] << 16) |
593            (buf[2] << 8)  |
594             buf[3];
595
596     return data;
597 }
598
599 /**
600  * make Dir 
601  *
602  */
603 int makeDir(char *dirname) {
604     int rc = PTS_SUCCESS;
605     struct stat st;
606
607     /* create anyway */
608     rc = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR |
609                         S_IRGRP | S_IWGRP | S_IXGRP);
610     if (rc != 0) {
611         switch (errno) {
612         case EACCES:
613             ERROR("mkdir %s failed, EACCES", dirname);
614             rc = PTS_FATAL;
615             break;
616         case EEXIST:
617             /* already exist */
618             rc = lstat(dirname, &st);
619             if (rc == 0) {
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;
624                 } else {
625                     // OK
626                     rc = PTS_SUCCESS;
627                 }
628             } else {
629                 ERROR("lstat(%s) failed, errno=%d\n", dirname, errno);
630                 rc = PTS_FATAL;
631             }
632             break;
633         case EFAULT:
634             ERROR("mkdir %s failed, EFAULT", dirname);
635             rc = PTS_FATAL;
636             break;
637         // TODO add others :-)
638         default:
639             ERROR("mkdir %s failed, errono = 0x%X", dirname, errno);
640             rc = PTS_FATAL;
641             break;
642         }
643     }
644
645     return rc;
646 }
647
648 /**
649  * check Dir 
650  *
651  * Return
652  *   PTS_SUCCESS           - exist
653  *   PTS_INTERNAL_ERROR    - not exist or not a dir
654  *
655  */
656 int checkDir(char *dirname) {
657     struct stat st;
658
659     if (dirname == NULL) {
660         return PTS_FATAL;
661     }
662
663     if (lstat(dirname, &st) == -1) {
664         /* Missing dir */
665         return PTS_INTERNAL_ERROR;  // TODO OPENPTS_DIR_MISSING;
666     } else if ((st.st_mode & S_IFMT) != S_IFDIR) {
667         /* not DIR */
668         return PTS_INTERNAL_ERROR;
669     }
670
671     return PTS_SUCCESS;  // TODO OPENPTS_DIR_EXIST;
672 }
673
674 /**
675  * Check file (reguler file)
676  */
677 int checkFile(char *filename) {
678     struct stat st;
679
680     if (filename == NULL) {
681         return PTS_FATAL;
682     }
683
684     if (lstat(filename, &st) == -1) {
685         /* Missing dir */
686         return OPENPTS_FILE_MISSING;
687     } else if ((st.st_mode & S_IFMT) != S_IFREG) {
688         /* not FILE */
689         return PTS_INTERNAL_ERROR;
690     }
691
692     return OPENPTS_FILE_EXISTS;
693 }
694
695 /**
696  * wrap read()
697  */
698 ssize_t wrapRead(int fd, void *buf, size_t count) {
699     ssize_t len;
700     while (1) {
701         len = read(fd, buf, count);
702         if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
703             continue;
704         }
705         return len;
706     }
707 }
708
709 /**
710  * wrap write()
711  */
712 ssize_t wrapWrite(int fd, const void *buf, size_t count) {
713     ssize_t len;
714     while (1) {
715         len = write(fd, buf, count);
716         if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
717             continue;
718         }
719         return len;
720     }
721 }
722
723 /**
724  * recursive part of unlinkDir()
725  */
726 static int unlinkDir_(char *dirPath) {
727     DIR *dirHandle;
728     struct dirent *entry;
729     // int retVal;
730     char path[PATH_MAX + 1];
731     struct dirent dr;
732     int rc;
733
734
735     dirHandle = opendir(dirPath);
736     if (dirHandle == NULL) {
737         ERROR("opendir(%s) fail", dirPath);
738         return PTS_FATAL;
739     }
740
741     while (1) {
742         struct stat st;
743
744         rc = readdir_r(dirHandle, &dr, &entry);
745         if (rc != 0) break;
746         if (entry == NULL) break;
747
748         if (strcmp(".", entry->d_name) == 0) continue;
749         if (strcmp("..", entry->d_name) == 0) continue;
750
751         snprintf(path, sizeof(path), "%s/%s", dirPath, entry->d_name);
752         if (stat(path, &st) != 0) {
753             ERROR("stat(%s) fail", path);
754             rc = PTS_FATAL;
755             goto free_error;
756         }
757
758         if (S_ISDIR(st.st_mode)) {
759             if (unlinkDir_(path) != 0) {
760                 rc = PTS_FATAL;
761                 goto free_error;
762             }
763         } else if (S_ISREG(st.st_mode)) {
764             if (unlink(path) != 0) {
765                 ERROR("unlink(%s) fail", path);
766                 rc = PTS_FATAL;
767                 goto free_error;
768             }
769         }
770     }
771
772     /* rm this dir */
773     if (rmdir(dirPath) != 0) {
774         ERROR("rmdir(%s) fail", dirPath);
775         rc = PTS_FATAL;
776         goto free_error;
777     }
778
779     rc = PTS_SUCCESS;
780
781   free_error:
782     closedir(dirHandle);
783
784     return rc;
785 }
786
787 /**
788  * Recursively destroy the content of a directory
789  */
790 int unlinkDir(const char *dirPath) {
791     char path[PATH_MAX + 1];
792
793     if (dirPath == NULL || dirPath[0] == '\0' || strlen(dirPath) >= PATH_MAX) {
794         return -1;
795     }
796
797     strncpy(path, dirPath, sizeof(path));
798     // there is at least one byte free before path[PATH_MAX]
799
800     return unlinkDir_(path);
801 }
802
803
804