Make mkdir -m work
[oweals/busybox.git] / utility.c
1 /*
2  * Utility routines.
3  *
4  * Copyright (C) tons of folks.  Tracking down who wrote what
5  * isn't something I'm going to worry about...  If you wrote something
6  * here, please feel free to acknowledge your work.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  * Based in part on code from sash, Copyright (c) 1999 by David I. Bell 
23  * Permission has been granted to redistribute this code under the GPL.
24  *
25  */
26
27 #include "internal.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <time.h>
34 #include <utime.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <ctype.h>
38
39 /* volatile so gcc knows this is the enod of the line */
40 volatile void usage(const char *usage)
41 {
42     fprintf(stderr, "Usage: %s\n", usage);
43     exit(FALSE);
44 }
45
46
47 #if defined (BB_INIT) || defined (BB_PS)
48
49 /* Returns kernel version encoded as major*65536 + minor*256 + patch,
50  * so, for example,  to check if the kernel is greater than 2.2.11:
51  *      if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
52  */
53 int
54 get_kernel_revision()
55 {
56   FILE *file;
57   int major=0, minor=0, patch=0;
58   char* filename="/proc/sys/kernel/osrelease";
59
60   file = fopen(filename,"r");
61   if (file == NULL) {
62     perror(filename);
63     return( 0);
64   }
65   fscanf(file,"%d.%d.%d",&major,&minor,&patch);
66   fclose(file);
67   return major*65536 + minor*256 + patch;
68 }
69
70 #endif
71
72
73
74 #if defined (BB_CP) || defined (BB_MV)
75 /*
76  * Return TRUE if a fileName is a directory.
77  * Nonexistant files return FALSE.
78  */
79 int isDirectory(const char *name)
80 {
81     struct stat statBuf;
82
83     if (stat(name, &statBuf) < 0)
84         return FALSE;
85     if (S_ISDIR(statBuf.st_mode))
86         return TRUE;
87     return(FALSE);
88 }
89
90
91 /*
92  * Copy one file to another, while possibly preserving its modes, times,
93  * and modes.  Returns TRUE if successful, or FALSE on a failure with an
94  * error message output.  (Failure is not indicted if the attributes cannot
95  * be set.)
96  *  -Erik Andersen
97  */
98 int
99 copyFile( const char *srcName, const char *destName, 
100          int setModes, int followLinks)
101 {
102     int rfd;
103     int wfd;
104     int rcc;
105     int result;
106     char buf[BUF_SIZE];
107     struct stat srcStatBuf;
108     struct stat dstStatBuf;
109     struct utimbuf times;
110
111     if (followLinks == FALSE)
112         result = stat(srcName, &srcStatBuf);
113     else 
114         result = lstat(srcName, &srcStatBuf);
115     if (result < 0) {
116         perror(srcName);
117         return FALSE;
118     }
119
120     if (followLinks == FALSE)
121         result = stat(destName, &dstStatBuf);
122     else 
123         result = lstat(destName, &dstStatBuf);
124     if (result < 0) {
125         dstStatBuf.st_ino = -1;
126         dstStatBuf.st_dev = -1;
127     }
128
129     if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
130         (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
131         fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
132         return FALSE;
133     }
134
135     if (S_ISDIR(srcStatBuf.st_mode)) {
136         //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
137         /* Make sure the directory is writable */
138         if (mkdir(destName, 0777777 ^ umask(0))) {
139             perror(destName);
140             return (FALSE);
141         }
142     } else if (S_ISLNK(srcStatBuf.st_mode)) {
143         char *link_val;
144         int link_size;
145
146         //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
147         link_val = (char *) alloca(PATH_MAX + 2);
148         link_size = readlink(srcName, link_val, PATH_MAX + 1);
149         if (link_size < 0) {
150             perror(srcName);
151             return (FALSE);
152         }
153         link_val[link_size] = '\0';
154         link_size = symlink(link_val, destName);
155         if (link_size != 0) {
156             perror(destName);
157             return (FALSE);
158         }
159     } else if (S_ISFIFO(srcStatBuf.st_mode)) {
160         //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
161         if (mkfifo(destName, 644)) {
162             perror(destName);
163             return (FALSE);
164         }
165     } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode) 
166             || S_ISSOCK (srcStatBuf.st_mode)) {
167         //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
168         if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
169             perror(destName);
170             return (FALSE);
171         }
172     } else if (S_ISREG(srcStatBuf.st_mode)) {
173         //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
174         rfd = open(srcName, O_RDONLY);
175         if (rfd < 0) {
176             perror(srcName);
177             return FALSE;
178         }
179
180         wfd = creat(destName, srcStatBuf.st_mode);
181         if (wfd < 0) {
182             perror(destName);
183             close(rfd);
184             return FALSE;
185         }
186
187         while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
188             if (fullWrite(wfd, buf, rcc) < 0)
189                 goto error_exit;
190         }
191         if (rcc < 0) {
192             goto error_exit;
193         }
194
195         close(rfd);
196         if (close(wfd) < 0) {
197             return FALSE;
198         }
199     }
200
201     if (setModes == TRUE) {
202         //fprintf(stderr, "Setting permissions for %s\n", destName);
203         chmod(destName, srcStatBuf.st_mode);
204         if (followLinks == TRUE)
205             chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
206         else
207             lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
208
209         times.actime = srcStatBuf.st_atime;
210         times.modtime = srcStatBuf.st_mtime;
211
212         utime(destName, &times);
213     }
214
215     return TRUE;
216
217
218   error_exit:
219     perror(destName);
220     close(rfd);
221     close(wfd);
222
223     return FALSE;
224 }
225 #endif
226
227
228
229 #ifdef BB_TAR
230 /*
231  * Return the standard ls-like mode string from a file mode.
232  * This is static and so is overwritten on each call.
233  */
234 const char *modeString(int mode)
235 {
236     static char buf[12];
237
238     strcpy(buf, "----------");
239
240     /*
241      * Fill in the file type.
242      */
243     if (S_ISDIR(mode))
244         buf[0] = 'd';
245     if (S_ISCHR(mode))
246         buf[0] = 'c';
247     if (S_ISBLK(mode))
248         buf[0] = 'b';
249     if (S_ISFIFO(mode))
250         buf[0] = 'p';
251     if (S_ISLNK(mode))
252         buf[0] = 'l';
253     if (S_ISSOCK(mode))
254         buf[0] = 's';
255     /*
256      * Now fill in the normal file permissions.
257      */
258     if (mode & S_IRUSR)
259         buf[1] = 'r';
260     if (mode & S_IWUSR)
261         buf[2] = 'w';
262     if (mode & S_IXUSR)
263         buf[3] = 'x';
264     if (mode & S_IRGRP)
265         buf[4] = 'r';
266     if (mode & S_IWGRP)
267         buf[5] = 'w';
268     if (mode & S_IXGRP)
269         buf[6] = 'x';
270     if (mode & S_IROTH)
271         buf[7] = 'r';
272     if (mode & S_IWOTH)
273         buf[8] = 'w';
274     if (mode & S_IXOTH)
275         buf[9] = 'x';
276
277     /*
278      * Finally fill in magic stuff like suid and sticky text.
279      */
280     if (mode & S_ISUID)
281         buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
282     if (mode & S_ISGID)
283         buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
284     if (mode & S_ISVTX)
285         buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
286
287     return buf;
288 }
289
290
291 /*
292  * Get the time string to be used for a file.
293  * This is down to the minute for new files, but only the date for old files.
294  * The string is returned from a static buffer, and so is overwritten for
295  * each call.
296  */
297 const char *timeString(time_t timeVal)
298 {
299     time_t now;
300     char *str;
301     static char buf[26];
302
303     time(&now);
304
305     str = ctime(&timeVal);
306
307     strcpy(buf, &str[4]);
308     buf[12] = '\0';
309
310     if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
311         strcpy(&buf[7], &str[20]);
312         buf[11] = '\0';
313     }
314
315     return buf;
316 }
317
318
319 /*
320  * Write all of the supplied buffer out to a file.
321  * This does multiple writes as necessary.
322  * Returns the amount written, or -1 on an error.
323  */
324 int fullWrite(int fd, const char *buf, int len)
325 {
326     int cc;
327     int total;
328
329     total = 0;
330
331     while (len > 0) {
332         cc = write(fd, buf, len);
333
334         if (cc < 0)
335             return -1;
336
337         buf += cc;
338         total += cc;
339         len -= cc;
340     }
341
342     return total;
343 }
344
345
346 /*
347  * Read all of the supplied buffer from a file.
348  * This does multiple reads as necessary.
349  * Returns the amount read, or -1 on an error.
350  * A short read is returned on an end of file.
351  */
352 int fullRead(int fd, char *buf, int len)
353 {
354     int cc;
355     int total;
356
357     total = 0;
358
359     while (len > 0) {
360         cc = read(fd, buf, len);
361
362         if (cc < 0)
363             return -1;
364
365         if (cc == 0)
366             break;
367
368         buf += cc;
369         total += cc;
370         len -= cc;
371     }
372
373     return total;
374 }
375 #endif
376
377
378 #if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS)
379 /*
380  * Walk down all the directories under the specified 
381  * location, and do something (something specified
382  * by the fileAction and dirAction function pointers).
383  *
384  * Unfortunatly, while nftw(3) could replace this and reduce 
385  * code size a bit, nftw() wasn't supported before GNU libc 2.1, 
386  * and so isn't sufficiently portable to take over...
387  */
388 int
389 recursiveAction(const char *fileName, int recurse, int followLinks, int depthFirst,
390                 int (*fileAction) (const char *fileName, struct stat* statbuf),
391                 int (*dirAction) (const char *fileName, struct stat* statbuf))
392 {
393     int status;
394     struct stat statbuf;
395     struct dirent *next;
396
397     if (followLinks == FALSE)
398         status = stat(fileName, &statbuf);
399     else
400         status = lstat(fileName, &statbuf);
401
402     if (status < 0) {
403         perror(fileName);
404         return (FALSE);
405     }
406
407     if (recurse == FALSE) {
408         if (S_ISDIR(statbuf.st_mode)) {
409             if (dirAction != NULL)
410                 return (dirAction(fileName, &statbuf));
411             else
412                 return (TRUE);
413         } 
414     }
415
416     if (S_ISDIR(statbuf.st_mode)) {
417         DIR *dir;
418         dir = opendir(fileName);
419         if (!dir) {
420             perror(fileName);
421             return (FALSE);
422         }
423         if (dirAction != NULL && depthFirst == FALSE) {
424             status = dirAction(fileName, &statbuf);
425             if (status == FALSE) {
426                 perror(fileName);
427                 return (FALSE);
428             }
429         }
430         while ((next = readdir(dir)) != NULL) {
431             char nextFile[NAME_MAX];
432             if ((strcmp(next->d_name, "..") == 0)
433                 || (strcmp(next->d_name, ".") == 0)) {
434                 continue;
435             }
436             sprintf(nextFile, "%s/%s", fileName, next->d_name);
437             status =
438                 recursiveAction(nextFile, TRUE, followLinks, depthFirst, 
439                         fileAction, dirAction);
440             if (status < 0) {
441                 closedir(dir);
442                 return (FALSE);
443             }
444         }
445         status = closedir(dir);
446         if (status < 0) {
447             perror(fileName);
448             return (FALSE);
449         }
450         if (dirAction != NULL && depthFirst == TRUE) {
451             status = dirAction(fileName, &statbuf);
452             if (status == FALSE) {
453                 perror(fileName);
454                 return (FALSE);
455             }
456         }
457     } else {
458         if (fileAction == NULL)
459             return (TRUE);
460         else
461             return (fileAction(fileName, &statbuf));
462     }
463     return (TRUE);
464 }
465
466 #endif
467
468
469
470 #if defined (BB_TAR) || defined (BB_MKDIR)
471 /*
472  * Attempt to create the directories along the specified path, except for
473  * the final component.  The mode is given for the final directory only,
474  * while all previous ones get default protections.  Errors are not reported
475  * here, as failures to restore files can be reported later.
476  */
477 extern void createPath (const char *name, int mode)
478 {
479     char *cp;
480     char *cpOld;
481     char buf[NAME_MAX];
482
483     strcpy (buf, name);
484
485     cp = strchr (buf, '/');
486
487     while (cp) {
488         cpOld = cp;
489         cp = strchr (cp + 1, '/');
490
491         *cpOld = '\0';
492
493         if (mkdir (buf, cp ? 0777 : mode) == 0)
494             printf ("Directory \"%s\" created\n", buf);
495
496         *cpOld = '/';
497     }
498 }
499 #endif
500
501
502
503 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
504 /* [ugoa]{+|-|=}[rwxst] */
505
506
507
508 extern int 
509 parse_mode( const char* s, mode_t* theMode)
510 {
511         mode_t andMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
512         mode_t orMode = 0;
513         mode_t  mode = 0;
514         mode_t  groups = 0;
515         char    type;
516         char    c;
517
518         do {
519                 for ( ; ; ) {
520                         switch ( c = *s++ ) {
521                         case '\0':
522                                 return -1;
523                         case 'u':
524                                 groups |= S_ISUID|S_IRWXU;
525                                 continue;
526                         case 'g':
527                                 groups |= S_ISGID|S_IRWXG;
528                                 continue;
529                         case 'o':
530                                 groups |= S_IRWXO;
531                                 continue;
532                         case 'a':
533                                 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
534                                 continue;
535                         case '+':
536                         case '=':
537                         case '-':
538                                 type = c;
539                                 if ( groups == 0 ) /* The default is "all" */
540                                         groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
541                                 break;
542                         default:
543                                 if ( isdigit(c) && c >= '0' && c <= '7' && 
544                                                 mode == 0 && groups == 0 ) {
545                                         *theMode = strtol(--s, NULL, 8);
546                                         return (TRUE);
547                                 }
548                                 else
549                                         return (FALSE);
550                         }
551                         break;
552                 }
553
554                 while ( (c = *s++) != '\0' ) {
555                         switch ( c ) {
556                         case ',':
557                                 break;
558                         case 'r':
559                                 mode |= S_IRUSR|S_IRGRP|S_IROTH;
560                                 continue;
561                         case 'w':
562                                 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
563                                 continue;
564                         case 'x':
565                                 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
566                                 continue;
567                         case 's':
568                                 mode |= S_IXGRP|S_ISUID|S_ISGID;
569                                 continue;
570                         case 't':
571                                 mode |= 0;
572                                 continue;
573                         default:
574                                 *theMode &= andMode;
575                                 *theMode |= orMode;
576                                 return( TRUE);
577                         }
578                         break;
579                 }
580                 switch ( type ) {
581                 case '=':
582                         andMode &= ~(groups);
583                         /* fall through */
584                 case '+':
585                         orMode |= mode & groups;
586                         break;
587                 case '-':
588                         andMode &= ~(mode & groups);
589                         orMode &= andMode;
590                         break;
591                 }
592         } while ( c == ',' );
593         *theMode &= andMode;
594         *theMode |= orMode;
595         return (TRUE);
596 }
597
598
599 #endif
600
601
602
603
604
605
606
607 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
608
609 /* Use this to avoid needing the glibc NSS stuff 
610  * This uses storage buf to hold things.
611  * */
612 uid_t 
613 my_getid(const char *filename, char *name, uid_t id) 
614 {
615         FILE *file;
616         char *rname, *start, *end, buf[128];
617         uid_t rid;
618
619         file=fopen(filename,"r");
620         if (file == NULL) {
621             perror(filename);
622             return (-1);
623         }
624
625         while (fgets (buf, 128, file) != NULL) {
626                 if (buf[0] == '#')
627                         continue;
628
629                 start = buf;
630                 end = strchr (start, ':');
631                 if (end == NULL)
632                         continue;
633                 *end = '\0';
634                 rname = start;
635
636                 start = end + 1;
637                 end = strchr (start, ':');
638                 if (end == NULL)
639                         continue;
640
641                 start = end + 1;
642                 rid = (uid_t) strtol (start, &end, 10);
643                 if (end == start)
644                         continue;
645
646                 if (name) {
647                     if (0 == strcmp(rname, name))
648                         return( rid);
649                 }
650                 if ( id != -1 && id == rid ) {
651                     strncpy(name, rname, 8);
652                     return( TRUE);
653                 }
654         }
655         fclose(file);
656         return (-1);
657 }
658
659 uid_t 
660 my_getpwnam(char *name) 
661 {
662     return my_getid("/etc/passwd", name, -1);
663 }
664
665 gid_t 
666 my_getgrnam(char *name) 
667 {
668     return my_getid("/etc/group", name, -1);
669 }
670
671 void
672 my_getpwuid(char* name, uid_t uid) 
673 {
674     my_getid("/etc/passwd", name, uid);
675 }
676
677 void
678 my_getgrgid(char* group, gid_t gid) 
679 {
680     my_getid("/etc/group", group, gid);
681 }
682
683
684 #endif
685
686
687
688 #if !defined BB_REGEXP && (defined BB_GREP || defined BB_FIND )  
689 /* This tries to find a needle in a haystack, but does so by
690  * only trying to match literal strings (look 'ma, no regexps!)
691  * This is short, sweet, and carries _very_ little baggage,
692  * unlike its beefier cousin a few lines down...
693  *  -Erik Andersen
694  */
695 extern int find_match(char *haystack, char *needle, int ignoreCase)
696 {
697
698     if (ignoreCase == FALSE) {
699         haystack = strstr (haystack, needle);
700         if (haystack == NULL)
701             return FALSE;
702         return TRUE;
703     } else {
704         int i;
705         char needle1[BUF_SIZE];
706         char haystack1[BUF_SIZE];
707
708         strncpy( haystack1, haystack, sizeof(haystack1));
709         strncpy( needle1, needle, sizeof(needle1));
710         for( i=0; i<sizeof(haystack1) && haystack1[i]; i++)
711             haystack1[i]=tolower( haystack1[i]);
712         for( i=0; i<sizeof(needle1) && needle1[i]; i++)
713             needle1[i]=tolower( needle1[i]);
714         haystack = strstr (haystack1, needle1);
715         if (haystack == NULL)
716             return FALSE;
717         return TRUE;
718     }
719 }
720 #endif
721
722 /* END CODE */
723