OSDN Git Service

Re-organize console out and logging out
[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
53 /**
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.
62 **/
63
64 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
65 void *xmalloc(size_t size) {
66     char *result = malloc(size);
67     if (NULL == result) {
68         LOG(LOG_ERR, "Failed to allocate %d bytes of memory\n", size);
69         // if ( size > 0 ) {
70         //     LOG(LOG_ERR, "malloc");
71         // }
72     }
73     return result;
74 }
75 #endif
76
77 void *xmalloc_assert(size_t size) {
78     char *result = malloc(size);
79     if (NULL == result) {
80         LOG(LOG_ERR, "Failed to allocate %d bytes of memory\n", size);
81         OUTPUT("About to return NULL pointer - cannot continue\n");
82         exit(1);
83     }
84     return result;
85 }
86
87 void xfree(void *buf) {
88     if (buf == NULL) {
89         LOG(LOG_ERR, "Freeing a NULL pointer is bad");
90         return;
91     }
92 #ifndef NEVER_FREE_MEMORY
93     free(buf);
94 #endif
95 }
96
97
98 #ifndef ALWAYS_ASSERT_ON_BAD_ALLOC
99 /**
100  * malloc and copy string
101  */
102 char *smalloc(char *str) {
103     char *out;
104
105     if (str == NULL) {
106         DEBUG("null input\n");
107         return NULL;
108     }
109
110     /* check string length */
111     out = strdup(str);
112     if (out == NULL) {
113         LOG(LOG_ERR, "Failed to duplicate string '%s'\n", str);
114     }
115
116     return out;
117 }
118 #endif
119
120
121 /**
122  * malloc and copy string
123  */
124 char *smalloc_assert(char *str) {
125     char *out;
126
127     if (str == NULL) {
128         DEBUG("smalloc - string is NULL\n");
129         return NULL;
130     }
131
132     /* check string length */
133     out = strdup(str);
134     if (NULL == out) {
135         LOG(LOG_ERR, "Failed to duplicate string '%s'\n", str);
136         OUTPUT("About to return NULL pointer - cannot continue\n");
137         exit(1);
138     }
139
140     return out;
141 }
142
143 /**
144  * malloc and copy string with length
145  * add \n
146  * len(str) > len
147  *
148  *  str    len   out
149  *  AAAAA  5     AAAA\n
150  *  AAAAA  4     AAA\n
151  */
152 char *snmalloc(char *str, int len) {
153     char *out;
154
155     /* check */
156     if (str == NULL) {
157         LOG(LOG_ERR, "smalloc - string is NULL\n");
158         return NULL;
159     }
160
161     if (len == 0) {
162         return NULL;
163     }
164
165 #ifdef MACOS
166     out = xmalloc_assert(len);
167     strncpy(out, str, len);
168     /* ensure always NULL-terminated */
169     out[len - 1] = '\0';
170 #else
171     out = strndup(str, len);
172 #endif
173     return out;
174 }
175
176 /**
177  * get NEW string buffer
178  *
179  *  snmalloc2("ABCDEF", 2,3) => "CDE"
180  *
181  *
182  * @param buf input
183  * @param offset
184  * @param len
185  */
186 BYTE *snmalloc2(BYTE *buf, int offset, int len) {
187
188     /* check */
189     if (buf == NULL) {
190         LOG(LOG_ERR, "null input");
191         return NULL;
192     }
193     if (offset < 0) {
194         LOG(LOG_ERR, "offset < 0");
195         return NULL;
196     }
197     if (len < 0) {
198         LOG(LOG_ERR, "len < 0");
199         return NULL;
200     }
201
202     /* alloc */
203     BYTE *output = (BYTE *) xmalloc(len + 1);
204     if (output == NULL) {
205         return NULL;
206     }
207
208     memcpy((void *) output, (void *) &buf[offset], len);
209     output[len] = 0;
210
211     return output;
212 }
213
214
215 /**
216  * free string buffer
217  */
218 void sfree(char *str) {
219     xfree(str);
220 }
221
222
223
224 /**
225  * get fullpathname of file
226  * This malloc new buf for the fullpathname. 
227  * In config
228  *
229  * basepath must be start from /
230  *  
231  * UnitTest : check_conf
232  *
233  */
234 char *getFullpathName(char *basepath, char *filename) {
235     char *fullpath = NULL;
236     int basepath_len;
237     int filename_len;
238     int slash = 0;
239
240     /* check */
241     if (basepath == NULL) {
242         LOG(LOG_ERR, "null input");
243         return NULL;
244     }
245     if (filename == NULL) {
246         LOG(LOG_ERR, "null input");
247         return NULL;
248     }
249
250     /* start from root */
251     if (filename[0] == '/') {
252         /* seems fullpath, copy the filename to new buf */
253         return smalloc(filename);
254     }
255
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);
260     }
261
262
263     /*
264       rule
265
266         0x00 /AAA/ +   BBB => /AAA/BBB
267         0x01 /AAA/ + ./BBB => /AAA/BBB
268         0x10 /AAA  +   BBB => /AAA/BBB
269         0x11 /AAA  + ./BBB => /AAA/BBB  
270     */
271     basepath_len = strlen(basepath);
272     filename_len = strlen(filename);
273
274     if (filename_len < 2) {
275         LOG(LOG_ERR, "ilename len < 2\n");
276         return NULL;
277     }
278
279     /* basepath has "/" at end. else add "/" */
280     if (basepath[basepath_len - 1] !=  '/') {
281         slash = 0x10;
282     }
283     /* filename has "./" at start ? remove */
284     if ((filename[0] ==  '.') && (filename[1] ==  '/')) {
285         slash |= 0x01;
286     }
287
288     /* */
289     switch (slash) {
290         case 0x00:
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;
296             break;
297         case 0x01:
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;
303             break;
304         case 0x10:
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;
311             break;
312         case 0x11:
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;
319             break;
320         default:
321             LOG(LOG_ERR, "internal error\n");
322             break;
323     }  // switch
324
325     return fullpath;
326 }
327
328 /**
329  * Get dirname from fullpath filename
330  * 
331  * this malloc new string
332  *
333  * /AAA/BBB/CCC/DDD => /AAA/BBB/CCC/ 
334  *
335  */
336 char *getFullpathDir(char *filename) {
337     char *fullpath = NULL;
338     int filename_len;
339     int i;
340
341     /* check */
342     if (filename == NULL) {
343         LOG(LOG_ERR, "null input");
344         return NULL;
345     }
346
347     filename_len = strlen(filename);
348
349     for (i = filename_len; i > 0; i--) {
350         if (filename[i] == '/') {
351             // slash = &filename[i];
352             break;
353         }
354     }
355
356     fullpath = xmalloc_assert(i+2);
357     memcpy(fullpath, filename, i+1);
358     fullpath[i+1] = 0;
359     return fullpath;
360 }
361
362
363
364 /**
365  * Byte to Uint32 
366  * Little Endian (Intel)
367  */
368 UINT32 byte2uint32(BYTE *b) {
369     UINT32 a = 0;
370
371     if (b == NULL) {
372         LOG(LOG_ERR, "byte2uint32 - NULL");
373         OUTPUT("About to return NULL pointer - cannot continue\n");  // TODO
374         exit(1);
375     }
376
377     a = b[3];
378     a = a << 8;
379     a += b[2];
380     a = a << 8;
381     a += b[1];
382     a = a << 8;
383     a += b[0];
384
385     return a;
386 }
387
388 /**
389  * remove space
390  *
391  * Unit Test
392  * TODO
393  */
394 char * trim(char *str) {
395     size_t strLen;
396     char *start, *end;
397
398     /* check */
399     if (str == NULL) {
400         LOG(LOG_ERR, "null input");
401         return NULL;
402     }
403
404     /* check len */
405     strLen = strlen(str);
406     if (0 == strLen) {
407         return str;
408     }
409
410     start = str;
411     end = str + strLen - 1;
412
413     /* skip space at start */
414     while (*str == ' ') {
415         str++;
416     }
417     start = str;
418
419     /* remove space at tail */
420     // TBD
421     while (*end == ' ') {
422         *end = 0;
423         end--;
424     }
425
426     return start;
427 }
428
429 /**
430  * BYTE* -> Hex string (malloc)
431  * 
432  */
433 char *getHexString(BYTE *bin, int size) {
434     char * buf;
435     char * ptr;
436     int i;
437     int len;
438
439     /* check */
440     if (bin == NULL) {
441         LOG(LOG_ERR, "null input");
442         return NULL;
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             LOG(LOG_ERR, "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     /* check */
471     if (outBuf == NULL) {
472         LOG(LOG_ERR, "null input");
473         return;
474     }
475     if (head == NULL) {
476         LOG(LOG_ERR, "null input");
477         return;
478     }
479     if (data == NULL) {
480         LOG(LOG_ERR, "null input");
481         return;
482     }
483     if (tail == NULL) {
484         LOG(LOG_ERR, "null input");
485         return;
486     }
487
488     /* */
489     outSoFar += snprintf(outBuf, outBufLen, "%s[%d]=", head, num);
490
491     for (i = 0; i < num; i++) {
492         if ( outSoFar < outBufLen ) {
493             outSoFar += snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%02X", data[i]);
494         }
495     }
496     if ( outSoFar < outBufLen ) {
497         snprintf(&outBuf[outSoFar], outBufLen - outSoFar, "%s", tail);
498     }
499 }
500
501 void printHex(char *head, BYTE *data, int num, char *tail) {
502     char outBuf[1024];
503
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);
508 }
509
510 void debugHex(char *head, BYTE *data, int num, char *tail) {
511     char outBuf[1024];
512     snprintHex(outBuf, 1023, head, data, num, tail);
513     writeLog(LOG_DEBUG, outBuf);
514 }
515
516 void fprintHex(FILE *fp, BYTE *data, int num) {
517     int i;
518
519     /* check */
520     if (fp == NULL) {
521         LOG(LOG_ERR, "null input");
522         return;
523     }
524     if (data == NULL) {
525         LOG(LOG_ERR, "null input");
526         return;
527     }
528
529     /* fprintf */
530     for (i = 0; i < num; i++) {
531         fprintf(fp, "%02X", data[i]);
532     }
533 }
534
535 /**
536  *  Convert Endian 
537  */
538 UINT32 b2l(UINT32 in) {
539     UINT32 out;
540
541     out  = in & 0xff;
542     in   = in  >> 8;
543     out  = out << 8;
544     out += in & 0xff;
545     in   = in  >> 8;
546     out  = out << 8;
547     out += in & 0xff;
548     in   = in  >> 8;
549     out  = out << 8;
550     out += in & 0xff;
551
552     return out;
553 }
554
555 /**
556  * save to file
557  *
558  * @param filename output filename
559  * @param len message length
560  * @param msg message
561  *
562  *
563  */
564 int saveToFile(
565     char *filename, int len, BYTE * msg) {
566     FILE *fp;
567     const int max_retries = 10;
568     int n_tries = 0;
569     int ptr = 0;
570
571     /* check */
572     if (len < 0) {
573         LOG(LOG_ERR, "len <0 \n");
574         return PTS_FATAL;
575     }
576     if (msg == NULL) {
577         LOG(LOG_ERR, "msg is NULL \n");
578         return PTS_FATAL;
579     }
580     if (filename == NULL) {
581         LOG(LOG_ERR, "filename is NULL \n");
582         return PTS_FATAL;
583     }
584
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.
588     }
589
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;
597         n_tries++;
598         if (len <= 0) {
599             break;
600         }
601     }
602
603     /* DEBUG_IFM(" %s %d \n", filename, len); */
604
605     fclose(fp);
606
607     if (len > 0) {
608         LOG(LOG_ERR, "After %d retries still have %d bytes unwritten to '%s'\n", max_retries, len, filename);
609         return PTS_FATAL;
610     } else {
611         return PTS_SUCCESS;
612     }
613 }
614
615 /**
616  * byte[4] => UINT32
617  */
618 UINT32 getUint32(BYTE *buf) {
619     UINT32 data;
620
621     /* check */
622     if (buf == NULL) {
623         LOG(LOG_ERR, "null input");
624         return 0;  // TODO
625     }
626     // TODO check the size?
627
628     data = (buf[0] << 24) |
629            (buf[1] << 16) |
630            (buf[2] << 8)  |
631             buf[3];
632
633     return data;
634 }
635
636 /**
637  * make Dir 
638  *
639  */
640 int makeDir(char *dirname) {
641     int rc = PTS_SUCCESS;
642     struct stat st;
643
644     /* check */
645     if (dirname == NULL) {
646         LOG(LOG_ERR, "null input");
647         return PTS_FATAL;
648     }
649
650     /* create anyway */
651     rc = mkdir(dirname, S_IRUSR | S_IWUSR | S_IXUSR |
652                         S_IRGRP | S_IWGRP | S_IXGRP);
653     if (rc != 0) {
654         switch (errno) {
655         case EACCES:
656             LOG(LOG_ERR, "mkdir %s failed, EACCES", dirname);
657             rc = PTS_FATAL;
658             break;
659         case EEXIST:
660             /* already exist */
661             rc = lstat(dirname, &st);
662             if (rc == 0) {
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;
667                 } else {
668                     // OK
669                     rc = PTS_SUCCESS;
670                 }
671             } else {
672                 LOG(LOG_ERR, "lstat(%s) failed, errno=%d\n", dirname, errno);
673                 rc = PTS_FATAL;
674             }
675             break;
676         case EFAULT:
677             LOG(LOG_ERR, "mkdir %s failed, EFAULT", dirname);
678             rc = PTS_FATAL;
679             break;
680         // TODO add others :-)
681         default:
682             LOG(LOG_ERR, "mkdir %s failed, errono = 0x%X", dirname, errno);
683             rc = PTS_FATAL;
684             break;
685         }
686     }
687
688     return rc;
689 }
690
691 /**
692  * check Dir 
693  *
694  * Return
695  *   PTS_SUCCESS           - exist
696  *   PTS_INTERNAL_ERROR    - not exist or not a dir
697  *
698  */
699 int checkDir(char *dirname) {
700     struct stat st;
701
702     /* check */
703     if (dirname == NULL) {
704         LOG(LOG_ERR, "null input");
705         return PTS_FATAL;
706     }
707
708     if (lstat(dirname, &st) == -1) {
709         /* Missing dir */
710         return PTS_INTERNAL_ERROR;  // TODO OPENPTS_DIR_MISSING;
711     } else if ((st.st_mode & S_IFMT) != S_IFDIR) {
712         /* not DIR */
713         return PTS_INTERNAL_ERROR;
714     }
715
716     return PTS_SUCCESS;  // TODO OPENPTS_DIR_EXIST;
717 }
718
719 /**
720  * Check file (reguler file)
721  */
722 int checkFile(char *filename) {
723     struct stat st;
724
725     /* check */
726     if (filename == NULL) {
727         LOG(LOG_ERR, "null input");
728         return PTS_FATAL;
729     }
730
731     if (lstat(filename, &st) == -1) {
732         /* Missing dir */
733         return OPENPTS_FILE_MISSING;
734     } else if ((st.st_mode & S_IFMT) != S_IFREG) {
735         /* not FILE */
736         return PTS_INTERNAL_ERROR;
737     }
738
739     return OPENPTS_FILE_EXISTS;
740 }
741
742 /**
743  * wrap read()
744  */
745 ssize_t wrapRead(int fd, void *buf, size_t count) {
746     ssize_t len;
747
748     /* check */
749     if (buf == NULL) {
750         LOG(LOG_ERR, "null input");
751         return 0;  // TODO
752     }
753
754     while (1) {
755         len = read(fd, buf, count);
756         if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
757             continue;
758         }
759         return len;
760     }
761 }
762
763 /**
764  * wrap write()
765  */
766 ssize_t wrapWrite(int fd, const void *buf, size_t count) {
767     ssize_t len;
768
769     /* check */
770     if (buf == NULL) {
771         LOG(LOG_ERR, "null input");
772         return 0;  // TODO
773     }
774
775     while (1) {
776         len = write(fd, buf, count);
777         if ((len < 0) && (errno == EAGAIN || errno == EINTR)) {
778             continue;
779         }
780         return len;
781     }
782 }
783
784 /**
785  * recursive part of unlinkDir()
786  */
787 static int unlinkDir_(char *dirPath) {
788     DIR *dirHandle;
789     struct dirent *entry;
790     char path[PATH_MAX + 1];
791     struct dirent dr;
792     int rc;
793
794     /* check */
795     if (dirPath == NULL) {
796         LOG(LOG_ERR, "null input");
797         return PTS_FATAL;
798     }
799
800     dirHandle = opendir(dirPath);
801     if (dirHandle == NULL) {
802         LOG(LOG_ERR, "opendir(%s) fail", dirPath);
803         return PTS_FATAL;
804     }
805
806     while (1) {
807         struct stat st;
808
809         rc = readdir_r(dirHandle, &dr, &entry);
810         if (rc != 0) break;
811         if (entry == NULL) break;
812
813         if (strcmp(".", entry->d_name) == 0) continue;
814         if (strcmp("..", entry->d_name) == 0) continue;
815
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);
819             rc = PTS_FATAL;
820             goto free_error;
821         }
822
823         if (S_ISDIR(st.st_mode)) {
824             if (unlinkDir_(path) != 0) {
825                 rc = PTS_FATAL;
826                 goto free_error;
827             }
828         } else if (S_ISREG(st.st_mode)) {
829             if (unlink(path) != 0) {
830                 LOG(LOG_ERR, "unlink(%s) fail", path);
831                 rc = PTS_FATAL;
832                 goto free_error;
833             }
834         }
835     }
836
837     /* rm this dir */
838     if (rmdir(dirPath) != 0) {
839         LOG(LOG_ERR, "rmdir(%s) fail", dirPath);
840         rc = PTS_FATAL;
841         goto free_error;
842     }
843
844     rc = PTS_SUCCESS;
845
846   free_error:
847     closedir(dirHandle);
848
849     return rc;
850 }
851
852 /**
853  * Recursively destroy the content of a directory
854  */
855 int unlinkDir(const char *dirPath) {
856     char path[PATH_MAX + 1];
857
858     /* check */
859     if (dirPath == NULL) {
860         LOG(LOG_ERR, "null input");
861         return PTS_FATAL;
862     }
863     if (dirPath[0] == '\0' || strlen(dirPath) >= PATH_MAX) {
864         LOG(LOG_ERR, "bad dirPath, %s", dirPath);
865         return PTS_FATAL;
866     }
867
868     strncpy(path, dirPath, sizeof(path));
869     // there is at least one byte free before path[PATH_MAX]
870
871     return unlinkDir_(path);
872 }
873
874
875