Stuf
[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 #if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
40 #  if defined BB_FEATURE_USE_PROCFS
41 const char mtab_file[] = "/proc/mounts";
42 #  else
43 #    if defined BB_MTAB
44 const char mtab_file[] = "/etc/mtab";
45 #    else
46 #      error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or BB_FEATURE_USE_PROCFS
47 #    endif
48 #  endif
49 #endif
50
51
52 /* volatile so gcc knows this is the end of the line */
53 extern void usage(const char *usage)
54 {
55     fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n", BB_VER, BB_BT);
56     fprintf(stderr, "Usage: %s\n", usage);
57     exit(FALSE);
58 }
59
60
61 #if defined (BB_INIT) || defined (BB_PS)
62
63 #if ! defined BB_FEATURE_USE_PROCFS
64 #error Sorry, I depend on the /proc filesystem right now.
65 #endif
66 /* Returns kernel version encoded as major*65536 + minor*256 + patch,
67  * so, for example,  to check if the kernel is greater than 2.2.11:
68  *      if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
69  */
70 int
71 get_kernel_revision()
72 {
73   FILE *file;
74   int major=0, minor=0, patch=0;
75   char* filename="/proc/sys/kernel/osrelease";
76
77   file = fopen(filename,"r");
78   if (file == NULL) {
79     /* bummer, /proc must not be mounted... */
80     return( 0);
81   }
82   fscanf(file,"%d.%d.%d",&major,&minor,&patch);
83   fclose(file);
84   return major*65536 + minor*256 + patch;
85 }
86
87 #endif
88
89
90
91 #if defined (BB_CP) || defined (BB_MV)
92 /*
93  * Return TRUE if a fileName is a directory.
94  * Nonexistant files return FALSE.
95  */
96 int isDirectory(const char *name)
97 {
98     struct stat statBuf;
99
100     if (stat(name, &statBuf) < 0)
101         return FALSE;
102     if (S_ISDIR(statBuf.st_mode))
103         return TRUE;
104     return(FALSE);
105 }
106
107
108 /*
109  * Copy one file to another, while possibly preserving its modes, times,
110  * and modes.  Returns TRUE if successful, or FALSE on a failure with an
111  * error message output.  (Failure is not indicted if the attributes cannot
112  * be set.)
113  *  -Erik Andersen
114  */
115 int
116 copyFile( const char *srcName, const char *destName, 
117          int setModes, int followLinks)
118 {
119     int rfd;
120     int wfd;
121     int rcc;
122     int result;
123     char buf[BUF_SIZE];
124     struct stat srcStatBuf;
125     struct stat dstStatBuf;
126     struct utimbuf times;
127
128     if (followLinks == FALSE)
129         result = stat(srcName, &srcStatBuf);
130     else 
131         result = lstat(srcName, &srcStatBuf);
132     if (result < 0) {
133         perror(srcName);
134         return FALSE;
135     }
136
137     if (followLinks == FALSE)
138         result = stat(destName, &dstStatBuf);
139     else 
140         result = lstat(destName, &dstStatBuf);
141     if (result < 0) {
142         dstStatBuf.st_ino = -1;
143         dstStatBuf.st_dev = -1;
144     }
145
146     if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
147         (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
148         fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
149         return FALSE;
150     }
151
152     if (S_ISDIR(srcStatBuf.st_mode)) {
153         //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
154         /* Make sure the directory is writable */
155         if (mkdir(destName, 0777777 ^ umask(0))) {
156             perror(destName);
157             return (FALSE);
158         }
159     } else if (S_ISLNK(srcStatBuf.st_mode)) {
160         char *link_val;
161         int link_size;
162
163         //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
164         link_val = (char *) alloca(PATH_MAX + 2);
165         link_size = readlink(srcName, link_val, PATH_MAX + 1);
166         if (link_size < 0) {
167             perror(srcName);
168             return (FALSE);
169         }
170         link_val[link_size] = '\0';
171         link_size = symlink(link_val, destName);
172         if (link_size != 0) {
173             perror(destName);
174             return (FALSE);
175         }
176     } else if (S_ISFIFO(srcStatBuf.st_mode)) {
177         //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
178         if (mkfifo(destName, 644)) {
179             perror(destName);
180             return (FALSE);
181         }
182     } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode) 
183             || S_ISSOCK (srcStatBuf.st_mode)) {
184         //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
185         if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
186             perror(destName);
187             return (FALSE);
188         }
189     } else if (S_ISREG(srcStatBuf.st_mode)) {
190         //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
191         rfd = open(srcName, O_RDONLY);
192         if (rfd < 0) {
193             perror(srcName);
194             return FALSE;
195         }
196
197         wfd = creat(destName, srcStatBuf.st_mode);
198         if (wfd < 0) {
199             perror(destName);
200             close(rfd);
201             return FALSE;
202         }
203
204         while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
205             if (fullWrite(wfd, buf, rcc) < 0)
206                 goto error_exit;
207         }
208         if (rcc < 0) {
209             goto error_exit;
210         }
211
212         close(rfd);
213         if (close(wfd) < 0) {
214             return FALSE;
215         }
216     }
217
218     if (setModes == TRUE) {
219         //fprintf(stderr, "Setting permissions for %s\n", destName);
220         chmod(destName, srcStatBuf.st_mode);
221         if (followLinks == TRUE)
222             chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
223         else
224             lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
225
226         times.actime = srcStatBuf.st_atime;
227         times.modtime = srcStatBuf.st_mtime;
228
229         utime(destName, &times);
230     }
231
232     return TRUE;
233
234
235   error_exit:
236     perror(destName);
237     close(rfd);
238     close(wfd);
239
240     return FALSE;
241 }
242 #endif
243
244
245
246 #if defined BB_TAR || defined BB_LS
247
248 #define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
249 #define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
250
251 /* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
252 static const mode_t SBIT[] = {
253     0, 0, S_ISUID,
254     0, 0, S_ISGID,
255     0, 0, S_ISVTX
256 };
257
258 /* The 9 mode bits to test */
259 static const mode_t MBIT[] = {
260     S_IRUSR, S_IWUSR, S_IXUSR,
261     S_IRGRP, S_IWGRP, S_IXGRP,
262     S_IROTH, S_IWOTH, S_IXOTH
263 };
264
265 #define MODE1  "rwxrwxrwx"
266 #define MODE0  "---------"
267 #define SMODE1 "..s..s..t"
268 #define SMODE0 "..S..S..T"
269
270 /*
271  * Return the standard ls-like mode string from a file mode.
272  * This is static and so is overwritten on each call.
273  */
274 const char *modeString(int mode)
275 {
276     static char buf[12];
277
278     int i;
279     buf[0] = TYPECHAR(mode);
280     for (i=0; i<9; i++) {
281         if (mode & SBIT[i])
282             buf[i+1] = (mode & MBIT[i])? 
283                 SMODE1[i] : SMODE0[i];
284         else
285             buf[i+1] = (mode & MBIT[i])? 
286                 MODE1[i] : MODE0[i];
287     }
288     return buf;
289 }
290 #endif
291
292
293 #ifdef BB_TAR
294 /*
295  * Return the standard ls-like time string from a time_t
296  * This is static and so is overwritten on each call.
297  */
298 const char *timeString(time_t timeVal)
299 {
300     time_t now;
301     char *str;
302     static char buf[26];
303
304     time(&now);
305
306     str = ctime(&timeVal);
307
308     strcpy(buf, &str[4]);
309     buf[12] = '\0';
310
311     if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
312         strcpy(&buf[7], &str[20]);
313         buf[11] = '\0';
314     }
315
316     return buf;
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 since glibc2.1
387  * is so stinking huge.
388  */
389 int
390 recursiveAction(const char *fileName, int recurse, int followLinks, int depthFirst,
391                 int (*fileAction) (const char *fileName, struct stat* statbuf),
392                 int (*dirAction) (const char *fileName, struct stat* statbuf))
393 {
394     int status;
395     struct stat statbuf;
396     struct dirent *next;
397
398     if (followLinks == TRUE)
399         status = stat(fileName, &statbuf);
400     else
401         status = lstat(fileName, &statbuf);
402
403     if (status < 0) {
404         perror(fileName);
405         return (FALSE);
406     }
407
408     if ( (followLinks == FALSE) && (S_ISLNK(statbuf.st_mode)) ) {
409         if (fileAction == NULL)
410             return (TRUE);
411         else
412             return (fileAction(fileName, &statbuf));
413     }
414
415     if (recurse == FALSE) {
416         if (S_ISDIR(statbuf.st_mode)) {
417             if (dirAction != NULL)
418                 return (dirAction(fileName, &statbuf));
419             else
420                 return (TRUE);
421         } 
422     }
423
424     if (S_ISDIR(statbuf.st_mode)) {
425         DIR *dir;
426         dir = opendir(fileName);
427         if (!dir) {
428             perror(fileName);
429             return (FALSE);
430         }
431         if (dirAction != NULL && depthFirst == FALSE) {
432             status = dirAction(fileName, &statbuf);
433             if (status == FALSE) {
434                 perror(fileName);
435                 return (FALSE);
436             }
437         }
438         while ((next = readdir(dir)) != NULL) {
439             char nextFile[NAME_MAX];
440             if ((strcmp(next->d_name, "..") == 0)
441                 || (strcmp(next->d_name, ".") == 0)) {
442                 continue;
443             }
444             sprintf(nextFile, "%s/%s", fileName, next->d_name);
445             status =
446                 recursiveAction(nextFile, TRUE, followLinks, depthFirst, 
447                         fileAction, dirAction);
448             if (status < 0) {
449                 closedir(dir);
450                 return (FALSE);
451             }
452         }
453         status = closedir(dir);
454         if (status < 0) {
455             perror(fileName);
456             return (FALSE);
457         }
458         if (dirAction != NULL && depthFirst == TRUE) {
459             status = dirAction(fileName, &statbuf);
460             if (status == FALSE) {
461                 perror(fileName);
462                 return (FALSE);
463             }
464         }
465     } else {
466         if (fileAction == NULL)
467             return (TRUE);
468         else
469             return (fileAction(fileName, &statbuf));
470     }
471     return (TRUE);
472 }
473
474 #endif
475
476
477
478 #if defined (BB_TAR) || defined (BB_MKDIR)
479 /*
480  * Attempt to create the directories along the specified path, except for
481  * the final component.  The mode is given for the final directory only,
482  * while all previous ones get default protections.  Errors are not reported
483  * here, as failures to restore files can be reported later.
484  */
485 extern void createPath (const char *name, int mode)
486 {
487     char *cp;
488     char *cpOld;
489     char buf[NAME_MAX];
490
491     strcpy( buf, name);
492     cp = strchr (buf, '/');
493     while (cp) {
494         cpOld = cp;
495         cp = strchr (cp + 1, '/');
496         *cpOld = '\0';
497         mkdir (buf, cp ? 0777 : mode);
498         *cpOld = '/';
499     }
500 }
501 #endif
502
503
504
505 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
506 /* [ugoa]{+|-|=}[rwxst] */
507
508
509
510 extern int 
511 parse_mode( const char* s, mode_t* theMode)
512 {
513         mode_t andMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
514         mode_t orMode = 0;
515         mode_t  mode = 0;
516         mode_t  groups = 0;
517         char    type;
518         char    c;
519
520         do {
521                 for ( ; ; ) {
522                         switch ( c = *s++ ) {
523                         case '\0':
524                                 return -1;
525                         case 'u':
526                                 groups |= S_ISUID|S_IRWXU;
527                                 continue;
528                         case 'g':
529                                 groups |= S_ISGID|S_IRWXG;
530                                 continue;
531                         case 'o':
532                                 groups |= S_IRWXO;
533                                 continue;
534                         case 'a':
535                                 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
536                                 continue;
537                         case '+':
538                         case '=':
539                         case '-':
540                                 type = c;
541                                 if ( groups == 0 ) /* The default is "all" */
542                                         groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
543                                 break;
544                         default:
545                                 if ( isdigit(c) && c >= '0' && c <= '7' && 
546                                                 mode == 0 && groups == 0 ) {
547                                         *theMode = strtol(--s, NULL, 8);
548                                         return (TRUE);
549                                 }
550                                 else
551                                         return (FALSE);
552                         }
553                         break;
554                 }
555
556                 while ( (c = *s++) != '\0' ) {
557                         switch ( c ) {
558                         case ',':
559                                 break;
560                         case 'r':
561                                 mode |= S_IRUSR|S_IRGRP|S_IROTH;
562                                 continue;
563                         case 'w':
564                                 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
565                                 continue;
566                         case 'x':
567                                 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
568                                 continue;
569                         case 's':
570                                 mode |= S_IXGRP|S_ISUID|S_ISGID;
571                                 continue;
572                         case 't':
573                                 mode |= 0;
574                                 continue;
575                         default:
576                                 *theMode &= andMode;
577                                 *theMode |= orMode;
578                                 return( TRUE);
579                         }
580                         break;
581                 }
582                 switch ( type ) {
583                 case '=':
584                         andMode &= ~(groups);
585                         /* fall through */
586                 case '+':
587                         orMode |= mode & groups;
588                         break;
589                 case '-':
590                         andMode &= ~(mode & groups);
591                         orMode &= andMode;
592                         break;
593                 }
594         } while ( c == ',' );
595         *theMode &= andMode;
596         *theMode |= orMode;
597         return (TRUE);
598 }
599
600
601 #endif
602
603
604
605
606
607
608
609 #if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
610
611 /* Use this to avoid needing the glibc NSS stuff 
612  * This uses storage buf to hold things.
613  * */
614 uid_t 
615 my_getid(const char *filename, char *name, uid_t id) 
616 {
617         FILE *file;
618         char *rname, *start, *end, buf[128];
619         uid_t rid;
620
621         file=fopen(filename,"r");
622         if (file == NULL) {
623             perror(filename);
624             return (-1);
625         }
626
627         while (fgets (buf, 128, file) != NULL) {
628                 if (buf[0] == '#')
629                         continue;
630
631                 start = buf;
632                 end = strchr (start, ':');
633                 if (end == NULL)
634                         continue;
635                 *end = '\0';
636                 rname = start;
637
638                 start = end + 1;
639                 end = strchr (start, ':');
640                 if (end == NULL)
641                         continue;
642
643                 start = end + 1;
644                 rid = (uid_t) strtol (start, &end, 10);
645                 if (end == start)
646                         continue;
647
648                 if (name) {
649                     if (0 == strcmp(rname, name))
650                         return( rid);
651                 }
652                 if ( id != -1 && id == rid ) {
653                     strncpy(name, rname, 8);
654                     return( TRUE);
655                 }
656         }
657         fclose(file);
658         return (-1);
659 }
660
661 uid_t 
662 my_getpwnam(char *name) 
663 {
664     return my_getid("/etc/passwd", name, -1);
665 }
666
667 gid_t 
668 my_getgrnam(char *name) 
669 {
670     return my_getid("/etc/group", name, -1);
671 }
672
673 void
674 my_getpwuid(char* name, uid_t uid) 
675 {
676     my_getid("/etc/passwd", name, uid);
677 }
678
679 void
680 my_getgrgid(char* group, gid_t gid) 
681 {
682     my_getid("/etc/group", group, gid);
683 }
684
685
686 #endif
687
688
689
690
691 #if (defined BB_CHVT) || (defined BB_DEALLOCVT)
692
693
694 #include <linux/kd.h>
695 #include <sys/ioctl.h>
696
697 int is_a_console(int fd) 
698 {
699   char arg;
700   
701   arg = 0;
702   return (ioctl(fd, KDGKBTYPE, &arg) == 0
703           && ((arg == KB_101) || (arg == KB_84)));
704 }
705
706 static int open_a_console(char *fnam) 
707 {
708   int fd;
709   
710   /* try read-only */
711   fd = open(fnam, O_RDWR);
712   
713   /* if failed, try read-only */
714   if (fd < 0 && errno == EACCES)
715       fd = open(fnam, O_RDONLY);
716   
717   /* if failed, try write-only */
718   if (fd < 0 && errno == EACCES)
719       fd = open(fnam, O_WRONLY);
720   
721   /* if failed, fail */
722   if (fd < 0)
723       return -1;
724   
725   /* if not a console, fail */
726   if (! is_a_console(fd))
727     {
728       close(fd);
729       return -1;
730     }
731   
732   /* success */
733   return fd;
734 }
735
736 /*
737  * Get an fd for use with kbd/console ioctls.
738  * We try several things because opening /dev/console will fail
739  * if someone else used X (which does a chown on /dev/console).
740  *
741  * if tty_name is non-NULL, try this one instead.
742  */
743
744 int get_console_fd(char* tty_name) 
745 {
746   int fd;
747
748   if (tty_name)
749     {
750       if (-1 == (fd = open_a_console(tty_name)))
751         return -1;
752       else
753         return fd;
754     }
755   
756   fd = open_a_console("/dev/tty");
757   if (fd >= 0)
758     return fd;
759   
760   fd = open_a_console("/dev/tty0");
761   if (fd >= 0)
762     return fd;
763   
764   fd = open_a_console("/dev/console");
765   if (fd >= 0)
766     return fd;
767   
768   for (fd = 0; fd < 3; fd++)
769     if (is_a_console(fd))
770       return fd;
771   
772   fprintf(stderr,
773           "Couldnt get a file descriptor referring to the console\n");
774   return -1;            /* total failure */
775 }
776
777
778 #endif
779
780
781 #if !defined BB_REGEXP && (defined BB_GREP || defined BB_SED)  
782
783 /* Do a case insensitive strstr() */
784 char* stristr(char *haystack, const char *needle)
785 {
786     int len = strlen( needle );
787     while( *haystack ) {
788         if( !strncasecmp( haystack, needle, len ) )
789             break;
790         haystack++;
791     }
792
793     if( !(*haystack) )
794             haystack = NULL;
795
796     return haystack;
797 }
798
799 /* This tries to find a needle in a haystack, but does so by
800  * only trying to match literal strings (look 'ma, no regexps!)
801  * This is short, sweet, and carries _very_ little baggage,
802  * unlike its beefier cousin in regexp.c
803  *  -Erik Andersen
804  */
805 extern int find_match(char *haystack, char *needle, int ignoreCase)
806 {
807
808     if (ignoreCase == FALSE)
809         haystack = strstr (haystack, needle);
810     else
811         haystack = stristr (haystack, needle);
812     if (haystack == NULL)
813         return FALSE;
814     return TRUE;
815 }
816
817
818 /* This performs substitutions after a string match has been found.  */
819 extern int replace_match(char *haystack, char *needle, char *newNeedle, int ignoreCase)
820 {
821     int foundOne=0;
822     char *where, *slider, *slider1, *oldhayStack;
823
824     if (ignoreCase == FALSE)
825         where = strstr (haystack, needle);
826     else
827         where = stristr (haystack, needle);
828
829     if (strcmp(needle, newNeedle)==0)
830         return FALSE;
831
832     oldhayStack = (char*)malloc((unsigned)(strlen(haystack)));
833     while(where!=NULL) {
834         foundOne++;
835         strcpy(oldhayStack, haystack);
836 #if 0
837         if ( strlen(newNeedle) > strlen(needle)) {
838             haystack = (char *)realloc(haystack, (unsigned)(strlen(haystack) - 
839                 strlen(needle) + strlen(newNeedle)));
840         }
841 #endif
842         for(slider=haystack,slider1=oldhayStack;slider!=where;slider++,slider1++);
843         *slider=0;
844         haystack=strcat(haystack, newNeedle);
845         slider1+=strlen(needle);
846         haystack = strcat(haystack, slider1);
847         where = strstr (slider, needle);
848     }
849     free( oldhayStack);
850
851     if (foundOne > 0)
852         return TRUE;
853     else
854         return FALSE;
855 }
856
857
858 #endif
859
860
861 #if defined BB_FIND
862 /*
863  * Routine to see if a text string is matched by a wildcard pattern.
864  * Returns TRUE if the text is matched, or FALSE if it is not matched
865  * or if the pattern is invalid.
866  *  *           matches zero or more characters
867  *  ?           matches a single character
868  *  [abc]       matches 'a', 'b' or 'c'
869  *  \c          quotes character c
870  * Adapted from code written by Ingo Wilken, and
871  * then taken from sash, Copyright (c) 1999 by David I. Bell
872  * Permission is granted to use, distribute, or modify this source,
873  * provided that this copyright notice remains intact.
874  * Permission to distribute this code under the GPL has been granted.
875  */
876 extern int
877 check_wildcard_match(const char* text, const char* pattern)
878 {
879     const char* retryPat;
880     const char* retryText;
881     int         ch;
882     int         found;
883
884     retryPat = NULL;
885     retryText = NULL;
886
887     while (*text || *pattern)
888     {
889         ch = *pattern++;
890
891         switch (ch)
892         {
893             case '*':  
894                 retryPat = pattern;
895                 retryText = text;
896                 break;
897
898             case '[':  
899                 found = FALSE;
900
901                 while ((ch = *pattern++) != ']')
902                 {
903                     if (ch == '\\')
904                         ch = *pattern++;
905
906                     if (ch == '\0')
907                         return FALSE;
908
909                     if (*text == ch)
910                         found = TRUE;
911                 }
912
913                 //if (!found)
914                 if (found==TRUE)
915                 {
916                     pattern = retryPat;
917                     text = ++retryText;
918                 }
919
920                 /* fall into next case */
921
922             case '?':  
923                 if (*text++ == '\0')
924                     return FALSE;
925
926                 break;
927
928             case '\\':  
929                 ch = *pattern++;
930
931                 if (ch == '\0')
932                         return FALSE;
933
934                 /* fall into next case */
935
936             default:        
937                 if (*text == ch)
938                 {
939                     if (*text)
940                         text++;
941                     break;
942                 }
943
944                 if (*text)
945                 {
946                     pattern = retryPat;
947                     text = ++retryText;
948                     break;
949                 }
950
951                 return FALSE;
952         }
953
954         if (pattern == NULL)
955                 return FALSE;
956     }
957
958     return TRUE;
959 }
960 #endif
961
962
963
964
965 #if defined BB_DF | defined BB_MTAB
966 /*
967  * Given a block device, find the mount table entry if that block device
968  * is mounted.
969  *
970  * Given any other file (or directory), find the mount table entry for its
971  * filesystem.
972  */
973 extern struct mntent *findMountPoint(const char *name, const char *table)
974 {
975     struct stat s;
976     dev_t mountDevice;
977     FILE *mountTable;
978     struct mntent *mountEntry;
979
980     if (stat(name, &s) != 0)
981         return 0;
982
983     if ((s.st_mode & S_IFMT) == S_IFBLK)
984         mountDevice = s.st_rdev;
985     else
986         mountDevice = s.st_dev;
987
988
989     if ((mountTable = setmntent(table, "r")) == 0)
990         return 0;
991
992     while ((mountEntry = getmntent(mountTable)) != 0) {
993         if (strcmp(name, mountEntry->mnt_dir) == 0
994             || strcmp(name, mountEntry->mnt_fsname) == 0)       /* String match. */
995             break;
996         if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice)  /* Match the device. */
997             break;
998         if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice)      /* Match the directory's mount point. */
999             break;
1000     }
1001     endmntent(mountTable);
1002     return mountEntry;
1003 }
1004
1005 #endif
1006
1007
1008
1009 #if !defined BB_MTAB && (defined BB_MOUNT || defined BB_DF )
1010 extern void whine_if_fstab_is_missing()
1011 {
1012     struct stat statBuf;
1013     if (stat("/etc/fstab", &statBuf) < 0) 
1014         fprintf(stderr, "/etc/fstab file missing -- install one to name /dev/root.\n\n");
1015 }
1016 #endif
1017
1018
1019 /* END CODE */
1020
1021
1022
1023
1024
1025
1026
1027
1028