blob: 2a840f78e484d08dd7c7b1aca08959d0fe912f85 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
2 * Utility routines.
3 *
Eric Andersenc4996011999-10-20 22:08:37 +00004 * 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.
Eric Andersencc8ed391999-10-05 16:24:54 +00007 *
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
Eric Andersen2b69c401999-10-05 22:58:32 +000027#include "internal.h"
28#include <stdio.h>
29#include <string.h>
30#include <errno.h>
31#include <fcntl.h>
Eric Andersen2b69c401999-10-05 22:58:32 +000032#include <dirent.h>
33#include <time.h>
34#include <utime.h>
Eric Andersenf811e071999-10-09 00:25:00 +000035#include <sys/stat.h>
36#include <unistd.h>
Eric Andersence8f3b91999-10-20 07:03:36 +000037#include <ctype.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000038
Eric Andersend0246fb1999-11-04 21:18:07 +000039#if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
Eric Andersen0ecb54a1999-12-05 23:24:55 +000040# if defined BB_FEATURE_USE_PROCFS
Eric Andersend0246fb1999-11-04 21:18:07 +000041const char mtab_file[] = "/proc/mounts";
Eric Andersen0ecb54a1999-12-05 23:24:55 +000042# else
43# if defined BB_MTAB
44const 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
Eric Andersend0246fb1999-11-04 21:18:07 +000049#endif
50
51
Eric Andersend73dc5b1999-11-10 23:13:02 +000052extern void usage(const char *usage)
Eric Andersenb0e9a701999-10-18 22:28:26 +000053{
Eric Andersena07f0b01999-10-22 19:49:09 +000054 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n", BB_VER, BB_BT);
Eric Andersenb0e9a701999-10-18 22:28:26 +000055 fprintf(stderr, "Usage: %s\n", usage);
56 exit(FALSE);
57}
58
59
Eric Andersend23f9ba1999-10-20 19:18:15 +000060#if defined (BB_INIT) || defined (BB_PS)
61
Eric Andersen0ecb54a1999-12-05 23:24:55 +000062#if ! defined BB_FEATURE_USE_PROCFS
63#error Sorry, I depend on the /proc filesystem right now.
64#endif
Eric Andersend23f9ba1999-10-20 19:18:15 +000065/* Returns kernel version encoded as major*65536 + minor*256 + patch,
66 * so, for example, to check if the kernel is greater than 2.2.11:
67 * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
68 */
69int
70get_kernel_revision()
71{
Eric Andersenaa0765e1999-10-22 04:30:20 +000072 FILE *file;
Eric Andersend23f9ba1999-10-20 19:18:15 +000073 int major=0, minor=0, patch=0;
Eric Andersenaa0765e1999-10-22 04:30:20 +000074 char* filename="/proc/sys/kernel/osrelease";
Eric Andersend23f9ba1999-10-20 19:18:15 +000075
Eric Andersenaa0765e1999-10-22 04:30:20 +000076 file = fopen(filename,"r");
77 if (file == NULL) {
Eric Andersen2f6c04f1999-11-01 23:59:44 +000078 /* bummer, /proc must not be mounted... */
Eric Andersenaa0765e1999-10-22 04:30:20 +000079 return( 0);
80 }
81 fscanf(file,"%d.%d.%d",&major,&minor,&patch);
82 fclose(file);
Eric Andersend23f9ba1999-10-20 19:18:15 +000083 return major*65536 + minor*256 + patch;
84}
85
86#endif
87
88
Eric Andersenc6cb79d1999-10-13 18:01:10 +000089
90#if defined (BB_CP) || defined (BB_MV)
91/*
92 * Return TRUE if a fileName is a directory.
93 * Nonexistant files return FALSE.
94 */
95int isDirectory(const char *name)
Eric Andersencc8ed391999-10-05 16:24:54 +000096{
Eric Andersenc6cb79d1999-10-13 18:01:10 +000097 struct stat statBuf;
Eric Andersencc8ed391999-10-05 16:24:54 +000098
Eric Andersenc6cb79d1999-10-13 18:01:10 +000099 if (stat(name, &statBuf) < 0)
100 return FALSE;
Eric Andersen9b587181999-10-17 05:43:39 +0000101 if (S_ISDIR(statBuf.st_mode))
102 return TRUE;
103 return(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000104}
105
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000106
107/*
108 * Copy one file to another, while possibly preserving its modes, times,
109 * and modes. Returns TRUE if successful, or FALSE on a failure with an
110 * error message output. (Failure is not indicted if the attributes cannot
111 * be set.)
Eric Andersenc4996011999-10-20 22:08:37 +0000112 * -Erik Andersen
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000113 */
114int
Eric Andersen3c163821999-10-14 22:16:57 +0000115copyFile( const char *srcName, const char *destName,
116 int setModes, int followLinks)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000117{
118 int rfd;
119 int wfd;
120 int rcc;
121 int result;
122 char buf[BUF_SIZE];
123 struct stat srcStatBuf;
124 struct stat dstStatBuf;
125 struct utimbuf times;
126
127 if (followLinks == FALSE)
128 result = stat(srcName, &srcStatBuf);
129 else
130 result = lstat(srcName, &srcStatBuf);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000131 if (result < 0) {
132 perror(srcName);
133 return FALSE;
134 }
135
136 if (followLinks == FALSE)
137 result = stat(destName, &dstStatBuf);
138 else
139 result = lstat(destName, &dstStatBuf);
140 if (result < 0) {
141 dstStatBuf.st_ino = -1;
142 dstStatBuf.st_dev = -1;
143 }
144
145 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
146 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
147 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
148 return FALSE;
149 }
150
151 if (S_ISDIR(srcStatBuf.st_mode)) {
152 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
153 /* Make sure the directory is writable */
Erik Andersen2fe08c71999-12-29 02:10:35 +0000154 result = mkdir(destName, 0777777 ^ umask(0));
155 if (result < 0 && errno != EEXIST) {
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000156 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';
Eric Andersen3c163821999-10-14 22:16:57 +0000171 link_size = symlink(link_val, destName);
172 if (link_size != 0) {
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000173 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);
Erik Andersen4d1d0111999-12-17 18:44:15 +0000221#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
222 if (followLinks == FALSE)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000223 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
Erik Andersen4d1d0111999-12-17 18:44:15 +0000224 else
225#endif
226 chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000227
228 times.actime = srcStatBuf.st_atime;
229 times.modtime = srcStatBuf.st_mtime;
230
231 utime(destName, &times);
232 }
233
234 return TRUE;
235
236
237 error_exit:
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000238 perror(destName);
239 close(rfd);
240 close(wfd);
241
242 return FALSE;
243}
Eric Andersencc8ed391999-10-05 16:24:54 +0000244#endif
245
246
247
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000248#if defined BB_TAR || defined BB_LS
249
250#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
251#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
252
253/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
254static const mode_t SBIT[] = {
255 0, 0, S_ISUID,
256 0, 0, S_ISGID,
257 0, 0, S_ISVTX
258};
259
260/* The 9 mode bits to test */
261static const mode_t MBIT[] = {
262 S_IRUSR, S_IWUSR, S_IXUSR,
263 S_IRGRP, S_IWGRP, S_IXGRP,
264 S_IROTH, S_IWOTH, S_IXOTH
265};
266
267#define MODE1 "rwxrwxrwx"
268#define MODE0 "---------"
269#define SMODE1 "..s..s..t"
270#define SMODE0 "..S..S..T"
271
Eric Andersencc8ed391999-10-05 16:24:54 +0000272/*
273 * Return the standard ls-like mode string from a file mode.
274 * This is static and so is overwritten on each call.
275 */
Eric Andersenf811e071999-10-09 00:25:00 +0000276const char *modeString(int mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000277{
Eric Andersenf811e071999-10-09 00:25:00 +0000278 static char buf[12];
Eric Andersencc8ed391999-10-05 16:24:54 +0000279
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000280 int i;
281 buf[0] = TYPECHAR(mode);
282 for (i=0; i<9; i++) {
283 if (mode & SBIT[i])
284 buf[i+1] = (mode & MBIT[i])?
285 SMODE1[i] : SMODE0[i];
286 else
287 buf[i+1] = (mode & MBIT[i])?
288 MODE1[i] : MODE0[i];
289 }
Eric Andersenf811e071999-10-09 00:25:00 +0000290 return buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000291}
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000292#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000293
294
Eric Andersen1792f8c1999-12-09 06:11:36 +0000295#if defined BB_TAR
Eric Andersencc8ed391999-10-05 16:24:54 +0000296/*
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000297 * Return the standard ls-like time string from a time_t
298 * This is static and so is overwritten on each call.
Eric Andersen17d49ef1999-10-06 20:25:32 +0000299 */
Eric Andersenf811e071999-10-09 00:25:00 +0000300const char *timeString(time_t timeVal)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000301{
Eric Andersenf811e071999-10-09 00:25:00 +0000302 time_t now;
303 char *str;
304 static char buf[26];
Eric Andersen17d49ef1999-10-06 20:25:32 +0000305
Eric Andersenf811e071999-10-09 00:25:00 +0000306 time(&now);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000307
Eric Andersenf811e071999-10-09 00:25:00 +0000308 str = ctime(&timeVal);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000309
Eric Andersenf811e071999-10-09 00:25:00 +0000310 strcpy(buf, &str[4]);
311 buf[12] = '\0';
Eric Andersen17d49ef1999-10-06 20:25:32 +0000312
Eric Andersenf811e071999-10-09 00:25:00 +0000313 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
314 strcpy(&buf[7], &str[20]);
315 buf[11] = '\0';
316 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000317
Eric Andersenf811e071999-10-09 00:25:00 +0000318 return buf;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000319}
320
Eric Andersen17d49ef1999-10-06 20:25:32 +0000321/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000322 * Write all of the supplied buffer out to a file.
323 * This does multiple writes as necessary.
324 * Returns the amount written, or -1 on an error.
325 */
Eric Andersenf811e071999-10-09 00:25:00 +0000326int fullWrite(int fd, const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000327{
Eric Andersenf811e071999-10-09 00:25:00 +0000328 int cc;
329 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000330
Eric Andersenf811e071999-10-09 00:25:00 +0000331 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000332
Eric Andersenf811e071999-10-09 00:25:00 +0000333 while (len > 0) {
334 cc = write(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000335
Eric Andersenf811e071999-10-09 00:25:00 +0000336 if (cc < 0)
337 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000338
Eric Andersenf811e071999-10-09 00:25:00 +0000339 buf += cc;
340 total += cc;
341 len -= cc;
342 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000343
Eric Andersenf811e071999-10-09 00:25:00 +0000344 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000345}
Eric Andersen1792f8c1999-12-09 06:11:36 +0000346#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000347
348
Eric Andersen1792f8c1999-12-09 06:11:36 +0000349#if defined BB_TAR || defined BB_TAIL
Eric Andersencc8ed391999-10-05 16:24:54 +0000350/*
351 * Read all of the supplied buffer from a file.
352 * This does multiple reads as necessary.
353 * Returns the amount read, or -1 on an error.
354 * A short read is returned on an end of file.
355 */
Eric Andersenf811e071999-10-09 00:25:00 +0000356int fullRead(int fd, char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000357{
Eric Andersenf811e071999-10-09 00:25:00 +0000358 int cc;
359 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000360
Eric Andersenf811e071999-10-09 00:25:00 +0000361 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000362
Eric Andersenf811e071999-10-09 00:25:00 +0000363 while (len > 0) {
364 cc = read(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000365
Eric Andersenf811e071999-10-09 00:25:00 +0000366 if (cc < 0)
367 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000368
Eric Andersenf811e071999-10-09 00:25:00 +0000369 if (cc == 0)
370 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000371
Eric Andersenf811e071999-10-09 00:25:00 +0000372 buf += cc;
373 total += cc;
374 len -= cc;
375 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000376
Eric Andersenf811e071999-10-09 00:25:00 +0000377 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000378}
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000379#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000380
381
Erik Andersend387d011999-12-21 02:55:11 +0000382#if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS) || defined (BB_INSMOD)
Eric Andersencc8ed391999-10-05 16:24:54 +0000383/*
Eric Andersen2b69c401999-10-05 22:58:32 +0000384 * Walk down all the directories under the specified
385 * location, and do something (something specified
386 * by the fileAction and dirAction function pointers).
Eric Andersenb7a1a751999-10-19 23:37:14 +0000387 *
Eric Andersen63a0e531999-10-22 05:12:14 +0000388 * Unfortunatly, while nftw(3) could replace this and reduce
389 * code size a bit, nftw() wasn't supported before GNU libc 2.1,
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000390 * and so isn't sufficiently portable to take over since glibc2.1
391 * is so stinking huge.
Eric Andersencc8ed391999-10-05 16:24:54 +0000392 */
393int
Eric Andersen63a0e531999-10-22 05:12:14 +0000394recursiveAction(const char *fileName, int recurse, int followLinks, int depthFirst,
Eric Andersen9b587181999-10-17 05:43:39 +0000395 int (*fileAction) (const char *fileName, struct stat* statbuf),
396 int (*dirAction) (const char *fileName, struct stat* statbuf))
Eric Andersencc8ed391999-10-05 16:24:54 +0000397{
Eric Andersenf811e071999-10-09 00:25:00 +0000398 int status;
399 struct stat statbuf;
400 struct dirent *next;
Eric Andersen9d3aba71999-10-06 09:04:55 +0000401
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000402 if (followLinks == TRUE)
Eric Andersenf811e071999-10-09 00:25:00 +0000403 status = stat(fileName, &statbuf);
Eric Andersen3c163821999-10-14 22:16:57 +0000404 else
405 status = lstat(fileName, &statbuf);
406
Eric Andersencc8ed391999-10-05 16:24:54 +0000407 if (status < 0) {
408 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000409 return (FALSE);
410 }
411
Eric Andersen50d63601999-11-09 01:47:36 +0000412 if ( (followLinks == FALSE) && (S_ISLNK(statbuf.st_mode)) ) {
413 if (fileAction == NULL)
414 return (TRUE);
415 else
416 return (fileAction(fileName, &statbuf));
417 }
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000418
Eric Andersenf811e071999-10-09 00:25:00 +0000419 if (recurse == FALSE) {
420 if (S_ISDIR(statbuf.st_mode)) {
Eric Andersen3c163821999-10-14 22:16:57 +0000421 if (dirAction != NULL)
Eric Andersen9b587181999-10-17 05:43:39 +0000422 return (dirAction(fileName, &statbuf));
Eric Andersenf811e071999-10-09 00:25:00 +0000423 else
Eric Andersen3c163821999-10-14 22:16:57 +0000424 return (TRUE);
425 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000426 }
427
Eric Andersen2b69c401999-10-05 22:58:32 +0000428 if (S_ISDIR(statbuf.st_mode)) {
429 DIR *dir;
430 dir = opendir(fileName);
431 if (!dir) {
432 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000433 return (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000434 }
Eric Andersen63a0e531999-10-22 05:12:14 +0000435 if (dirAction != NULL && depthFirst == FALSE) {
Eric Andersen9b587181999-10-17 05:43:39 +0000436 status = dirAction(fileName, &statbuf);
Eric Andersenf811e071999-10-09 00:25:00 +0000437 if (status == FALSE) {
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000438 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000439 return (FALSE);
440 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000441 }
Eric Andersenf811e071999-10-09 00:25:00 +0000442 while ((next = readdir(dir)) != NULL) {
443 char nextFile[NAME_MAX];
444 if ((strcmp(next->d_name, "..") == 0)
445 || (strcmp(next->d_name, ".") == 0)) {
446 continue;
447 }
448 sprintf(nextFile, "%s/%s", fileName, next->d_name);
449 status =
Eric Andersen63a0e531999-10-22 05:12:14 +0000450 recursiveAction(nextFile, TRUE, followLinks, depthFirst,
Eric Andersenbed30e91999-10-18 19:02:32 +0000451 fileAction, dirAction);
Eric Andersenf811e071999-10-09 00:25:00 +0000452 if (status < 0) {
453 closedir(dir);
454 return (FALSE);
455 }
456 }
457 status = closedir(dir);
Eric Andersen2b69c401999-10-05 22:58:32 +0000458 if (status < 0) {
459 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000460 return (FALSE);
Eric Andersen2b69c401999-10-05 22:58:32 +0000461 }
Eric Andersen63a0e531999-10-22 05:12:14 +0000462 if (dirAction != NULL && depthFirst == TRUE) {
Eric Andersenbed30e91999-10-18 19:02:32 +0000463 status = dirAction(fileName, &statbuf);
464 if (status == FALSE) {
465 perror(fileName);
466 return (FALSE);
467 }
468 }
Eric Andersenf811e071999-10-09 00:25:00 +0000469 } else {
Eric Andersenf811e071999-10-09 00:25:00 +0000470 if (fileAction == NULL)
471 return (TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000472 else
Eric Andersen9b587181999-10-17 05:43:39 +0000473 return (fileAction(fileName, &statbuf));
Eric Andersencc8ed391999-10-05 16:24:54 +0000474 }
Eric Andersenf811e071999-10-09 00:25:00 +0000475 return (TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000476}
477
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000478#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000479
Eric Andersenf6be9441999-10-13 21:12:06 +0000480
481
Erik Andersena8991081999-12-29 03:34:00 +0000482#if defined (BB_TAR) || defined (BB_MKDIR)
Eric Andersenf6be9441999-10-13 21:12:06 +0000483/*
484 * Attempt to create the directories along the specified path, except for
485 * the final component. The mode is given for the final directory only,
486 * while all previous ones get default protections. Errors are not reported
487 * here, as failures to restore files can be reported later.
488 */
489extern void createPath (const char *name, int mode)
490{
491 char *cp;
492 char *cpOld;
493 char buf[NAME_MAX];
494
Eric Andersencb41c2e1999-11-22 07:41:00 +0000495 strcpy( buf, name);
Eric Andersenf6be9441999-10-13 21:12:06 +0000496 cp = strchr (buf, '/');
Eric Andersenf6be9441999-10-13 21:12:06 +0000497 while (cp) {
498 cpOld = cp;
499 cp = strchr (cp + 1, '/');
Eric Andersenf6be9441999-10-13 21:12:06 +0000500 *cpOld = '\0';
Eric Andersenb6a44b81999-11-13 04:47:09 +0000501 mkdir (buf, cp ? 0777 : mode);
Eric Andersenf6be9441999-10-13 21:12:06 +0000502 *cpOld = '/';
503 }
504}
505#endif
506
507
508
509#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
Eric Andersence8f3b91999-10-20 07:03:36 +0000510/* [ugoa]{+|-|=}[rwxst] */
511
512
513
514extern int
515parse_mode( const char* s, mode_t* theMode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000516{
Eric Andersence8f3b91999-10-20 07:03:36 +0000517 mode_t andMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
518 mode_t orMode = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000519 mode_t mode = 0;
Eric Andersence8f3b91999-10-20 07:03:36 +0000520 mode_t groups = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000521 char type;
522 char c;
523
524 do {
525 for ( ; ; ) {
526 switch ( c = *s++ ) {
527 case '\0':
Eric Andersence8f3b91999-10-20 07:03:36 +0000528 return -1;
Eric Andersenf6be9441999-10-13 21:12:06 +0000529 case 'u':
530 groups |= S_ISUID|S_IRWXU;
531 continue;
532 case 'g':
533 groups |= S_ISGID|S_IRWXG;
534 continue;
535 case 'o':
536 groups |= S_IRWXO;
537 continue;
538 case 'a':
539 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
540 continue;
541 case '+':
542 case '=':
543 case '-':
544 type = c;
Eric Andersence8f3b91999-10-20 07:03:36 +0000545 if ( groups == 0 ) /* The default is "all" */
Eric Andersenf6be9441999-10-13 21:12:06 +0000546 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
547 break;
548 default:
Eric Andersenfa0540f1999-10-22 18:18:31 +0000549 if ( isdigit(c) && c >= '0' && c <= '7' &&
550 mode == 0 && groups == 0 ) {
551 *theMode = strtol(--s, NULL, 8);
Eric Andersenf6be9441999-10-13 21:12:06 +0000552 return (TRUE);
553 }
554 else
555 return (FALSE);
556 }
557 break;
558 }
559
560 while ( (c = *s++) != '\0' ) {
561 switch ( c ) {
562 case ',':
563 break;
564 case 'r':
565 mode |= S_IRUSR|S_IRGRP|S_IROTH;
566 continue;
567 case 'w':
568 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
569 continue;
570 case 'x':
571 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
572 continue;
573 case 's':
574 mode |= S_IXGRP|S_ISUID|S_ISGID;
575 continue;
576 case 't':
Eric Andersence8f3b91999-10-20 07:03:36 +0000577 mode |= 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000578 continue;
579 default:
Eric Andersence8f3b91999-10-20 07:03:36 +0000580 *theMode &= andMode;
581 *theMode |= orMode;
582 return( TRUE);
Eric Andersenf6be9441999-10-13 21:12:06 +0000583 }
584 break;
585 }
586 switch ( type ) {
587 case '=':
Eric Andersence8f3b91999-10-20 07:03:36 +0000588 andMode &= ~(groups);
Eric Andersenf6be9441999-10-13 21:12:06 +0000589 /* fall through */
590 case '+':
Eric Andersence8f3b91999-10-20 07:03:36 +0000591 orMode |= mode & groups;
Eric Andersenf6be9441999-10-13 21:12:06 +0000592 break;
593 case '-':
Eric Andersence8f3b91999-10-20 07:03:36 +0000594 andMode &= ~(mode & groups);
595 orMode &= andMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000596 break;
597 }
598 } while ( c == ',' );
Eric Andersence8f3b91999-10-20 07:03:36 +0000599 *theMode &= andMode;
600 *theMode |= orMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000601 return (TRUE);
602}
Eric Andersence8f3b91999-10-20 07:03:36 +0000603
604
Eric Andersenf6be9441999-10-13 21:12:06 +0000605#endif
606
Eric Andersene674eb71999-10-19 20:52:57 +0000607
608
Eric Andersend23f9ba1999-10-20 19:18:15 +0000609
610
611
612
613#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
614
615/* Use this to avoid needing the glibc NSS stuff
616 * This uses storage buf to hold things.
617 * */
618uid_t
619my_getid(const char *filename, char *name, uid_t id)
620{
Eric Andersenaa0765e1999-10-22 04:30:20 +0000621 FILE *file;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000622 char *rname, *start, *end, buf[128];
623 uid_t rid;
624
Eric Andersenaa0765e1999-10-22 04:30:20 +0000625 file=fopen(filename,"r");
626 if (file == NULL) {
627 perror(filename);
628 return (-1);
629 }
Eric Andersend23f9ba1999-10-20 19:18:15 +0000630
Eric Andersenaa0765e1999-10-22 04:30:20 +0000631 while (fgets (buf, 128, file) != NULL) {
Eric Andersend23f9ba1999-10-20 19:18:15 +0000632 if (buf[0] == '#')
633 continue;
634
635 start = buf;
636 end = strchr (start, ':');
637 if (end == NULL)
638 continue;
639 *end = '\0';
640 rname = start;
641
642 start = end + 1;
643 end = strchr (start, ':');
644 if (end == NULL)
645 continue;
646
647 start = end + 1;
648 rid = (uid_t) strtol (start, &end, 10);
649 if (end == start)
650 continue;
651
652 if (name) {
Eric Andersen48091fb1999-12-09 01:15:52 +0000653 if (0 == strcmp(rname, name)) {
654 fclose( file);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000655 return( rid);
Eric Andersen48091fb1999-12-09 01:15:52 +0000656 }
Eric Andersend23f9ba1999-10-20 19:18:15 +0000657 }
658 if ( id != -1 && id == rid ) {
659 strncpy(name, rname, 8);
Eric Andersen48091fb1999-12-09 01:15:52 +0000660 fclose( file);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000661 return( TRUE);
662 }
663 }
Eric Andersenaa0765e1999-10-22 04:30:20 +0000664 fclose(file);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000665 return (-1);
666}
667
668uid_t
669my_getpwnam(char *name)
670{
671 return my_getid("/etc/passwd", name, -1);
672}
673
674gid_t
675my_getgrnam(char *name)
676{
677 return my_getid("/etc/group", name, -1);
678}
679
680void
681my_getpwuid(char* name, uid_t uid)
682{
683 my_getid("/etc/passwd", name, uid);
684}
685
686void
687my_getgrgid(char* group, gid_t gid)
688{
689 my_getid("/etc/group", group, gid);
690}
691
692
693#endif
694
695
Eric Andersenaa0765e1999-10-22 04:30:20 +0000696
Eric Andersen0460ff21999-10-25 23:32:44 +0000697
698#if (defined BB_CHVT) || (defined BB_DEALLOCVT)
699
700
701#include <linux/kd.h>
702#include <sys/ioctl.h>
703
704int is_a_console(int fd)
705{
706 char arg;
707
708 arg = 0;
709 return (ioctl(fd, KDGKBTYPE, &arg) == 0
710 && ((arg == KB_101) || (arg == KB_84)));
711}
712
713static int open_a_console(char *fnam)
714{
715 int fd;
716
717 /* try read-only */
718 fd = open(fnam, O_RDWR);
719
720 /* if failed, try read-only */
721 if (fd < 0 && errno == EACCES)
722 fd = open(fnam, O_RDONLY);
723
724 /* if failed, try write-only */
725 if (fd < 0 && errno == EACCES)
726 fd = open(fnam, O_WRONLY);
727
728 /* if failed, fail */
729 if (fd < 0)
730 return -1;
731
732 /* if not a console, fail */
733 if (! is_a_console(fd))
734 {
735 close(fd);
736 return -1;
737 }
738
739 /* success */
740 return fd;
741}
742
743/*
744 * Get an fd for use with kbd/console ioctls.
745 * We try several things because opening /dev/console will fail
746 * if someone else used X (which does a chown on /dev/console).
747 *
748 * if tty_name is non-NULL, try this one instead.
749 */
750
751int get_console_fd(char* tty_name)
752{
753 int fd;
754
755 if (tty_name)
756 {
757 if (-1 == (fd = open_a_console(tty_name)))
758 return -1;
759 else
760 return fd;
761 }
762
763 fd = open_a_console("/dev/tty");
764 if (fd >= 0)
765 return fd;
766
767 fd = open_a_console("/dev/tty0");
768 if (fd >= 0)
769 return fd;
770
771 fd = open_a_console("/dev/console");
772 if (fd >= 0)
773 return fd;
774
775 for (fd = 0; fd < 3; fd++)
776 if (is_a_console(fd))
777 return fd;
778
779 fprintf(stderr,
780 "Couldnt get a file descriptor referring to the console\n");
781 return -1; /* total failure */
782}
783
784
785#endif
786
787
Eric Andersenb186d981999-12-03 09:19:54 +0000788#if !defined BB_REGEXP && (defined BB_GREP || defined BB_SED)
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000789
790/* Do a case insensitive strstr() */
791char* stristr(char *haystack, const char *needle)
792{
793 int len = strlen( needle );
794 while( *haystack ) {
795 if( !strncasecmp( haystack, needle, len ) )
796 break;
797 haystack++;
798 }
799
800 if( !(*haystack) )
801 haystack = NULL;
802
803 return haystack;
804}
805
Eric Andersenc1525e81999-10-29 00:07:31 +0000806/* This tries to find a needle in a haystack, but does so by
807 * only trying to match literal strings (look 'ma, no regexps!)
808 * This is short, sweet, and carries _very_ little baggage,
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000809 * unlike its beefier cousin in regexp.c
Eric Andersenc1525e81999-10-29 00:07:31 +0000810 * -Erik Andersen
811 */
812extern int find_match(char *haystack, char *needle, int ignoreCase)
813{
814
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000815 if (ignoreCase == FALSE)
Eric Andersenc1525e81999-10-29 00:07:31 +0000816 haystack = strstr (haystack, needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000817 else
818 haystack = stristr (haystack, needle);
819 if (haystack == NULL)
820 return FALSE;
821 return TRUE;
Eric Andersenc1525e81999-10-29 00:07:31 +0000822}
823
824
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000825/* This performs substitutions after a string match has been found. */
Eric Andersenc1525e81999-10-29 00:07:31 +0000826extern int replace_match(char *haystack, char *needle, char *newNeedle, int ignoreCase)
827{
Eric Andersen7f1acfd1999-10-29 23:09:13 +0000828 int foundOne=0;
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000829 char *where, *slider, *slider1, *oldhayStack;
Eric Andersenc1525e81999-10-29 00:07:31 +0000830
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000831 if (ignoreCase == FALSE)
Eric Andersenc1525e81999-10-29 00:07:31 +0000832 where = strstr (haystack, needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000833 else
834 where = stristr (haystack, needle);
835
836 if (strcmp(needle, newNeedle)==0)
837 return FALSE;
838
839 oldhayStack = (char*)malloc((unsigned)(strlen(haystack)));
840 while(where!=NULL) {
841 foundOne++;
842 strcpy(oldhayStack, haystack);
843#if 0
844 if ( strlen(newNeedle) > strlen(needle)) {
Eric Andersenc1525e81999-10-29 00:07:31 +0000845 haystack = (char *)realloc(haystack, (unsigned)(strlen(haystack) -
846 strlen(needle) + strlen(newNeedle)));
Eric Andersenc1525e81999-10-29 00:07:31 +0000847 }
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000848#endif
849 for(slider=haystack,slider1=oldhayStack;slider!=where;slider++,slider1++);
850 *slider=0;
851 haystack=strcat(haystack, newNeedle);
852 slider1+=strlen(needle);
853 haystack = strcat(haystack, slider1);
854 where = strstr (slider, needle);
Eric Andersenc1525e81999-10-29 00:07:31 +0000855 }
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000856 free( oldhayStack);
857
Eric Andersen7f1acfd1999-10-29 23:09:13 +0000858 if (foundOne > 0)
Eric Andersenc1525e81999-10-29 00:07:31 +0000859 return TRUE;
860 else
861 return FALSE;
862}
863
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000864
Eric Andersenc1525e81999-10-29 00:07:31 +0000865#endif
Eric Andersen29d2e361999-11-06 06:07:27 +0000866
867
Eric Andersenb186d981999-12-03 09:19:54 +0000868#if defined BB_FIND
869/*
870 * Routine to see if a text string is matched by a wildcard pattern.
871 * Returns TRUE if the text is matched, or FALSE if it is not matched
872 * or if the pattern is invalid.
873 * * matches zero or more characters
874 * ? matches a single character
875 * [abc] matches 'a', 'b' or 'c'
876 * \c quotes character c
877 * Adapted from code written by Ingo Wilken, and
878 * then taken from sash, Copyright (c) 1999 by David I. Bell
879 * Permission is granted to use, distribute, or modify this source,
880 * provided that this copyright notice remains intact.
881 * Permission to distribute this code under the GPL has been granted.
882 */
883extern int
884check_wildcard_match(const char* text, const char* pattern)
885{
886 const char* retryPat;
887 const char* retryText;
888 int ch;
889 int found;
890
891 retryPat = NULL;
892 retryText = NULL;
893
894 while (*text || *pattern)
895 {
896 ch = *pattern++;
897
898 switch (ch)
899 {
900 case '*':
901 retryPat = pattern;
902 retryText = text;
903 break;
904
905 case '[':
906 found = FALSE;
907
908 while ((ch = *pattern++) != ']')
909 {
910 if (ch == '\\')
911 ch = *pattern++;
912
913 if (ch == '\0')
914 return FALSE;
915
916 if (*text == ch)
917 found = TRUE;
918 }
919
920 //if (!found)
921 if (found==TRUE)
922 {
923 pattern = retryPat;
924 text = ++retryText;
925 }
926
927 /* fall into next case */
928
929 case '?':
930 if (*text++ == '\0')
931 return FALSE;
932
933 break;
934
935 case '\\':
936 ch = *pattern++;
937
938 if (ch == '\0')
939 return FALSE;
940
941 /* fall into next case */
942
943 default:
944 if (*text == ch)
945 {
946 if (*text)
947 text++;
948 break;
949 }
950
951 if (*text)
952 {
953 pattern = retryPat;
954 text = ++retryText;
955 break;
956 }
957
958 return FALSE;
959 }
960
961 if (pattern == NULL)
962 return FALSE;
963 }
964
965 return TRUE;
966}
967#endif
968
969
Eric Andersen29d2e361999-11-06 06:07:27 +0000970
971
972#if defined BB_DF | defined BB_MTAB
973/*
974 * Given a block device, find the mount table entry if that block device
975 * is mounted.
976 *
977 * Given any other file (or directory), find the mount table entry for its
978 * filesystem.
979 */
980extern struct mntent *findMountPoint(const char *name, const char *table)
981{
982 struct stat s;
983 dev_t mountDevice;
984 FILE *mountTable;
985 struct mntent *mountEntry;
986
987 if (stat(name, &s) != 0)
988 return 0;
989
990 if ((s.st_mode & S_IFMT) == S_IFBLK)
991 mountDevice = s.st_rdev;
992 else
993 mountDevice = s.st_dev;
994
995
996 if ((mountTable = setmntent(table, "r")) == 0)
997 return 0;
998
999 while ((mountEntry = getmntent(mountTable)) != 0) {
1000 if (strcmp(name, mountEntry->mnt_dir) == 0
1001 || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
1002 break;
1003 if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
1004 break;
1005 if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
1006 break;
1007 }
1008 endmntent(mountTable);
1009 return mountEntry;
1010}
1011
1012#endif
1013
1014
1015
1016#if !defined BB_MTAB && (defined BB_MOUNT || defined BB_DF )
1017extern void whine_if_fstab_is_missing()
1018{
1019 struct stat statBuf;
1020 if (stat("/etc/fstab", &statBuf) < 0)
1021 fprintf(stderr, "/etc/fstab file missing -- install one to name /dev/root.\n\n");
1022}
1023#endif
1024
1025
Eric Andersen1792f8c1999-12-09 06:11:36 +00001026#if defined BB_DD || defined BB_TAIL
1027/*
1028 * Read a number with a possible multiplier.
1029 * Returns -1 if the number format is illegal.
1030 */
1031extern long getNum (const char *cp)
1032{
1033 long value;
1034
1035 if (!isDecimal (*cp))
1036 return -1;
1037
1038 value = 0;
1039
1040 while (isDecimal (*cp))
1041 value = value * 10 + *cp++ - '0';
1042
1043 switch (*cp++) {
1044 case 'm':
1045 value *= 1048576;
1046 break;
1047
1048 case 'k':
1049 value *= 1024;
1050 break;
1051
1052 case 'b':
1053 value *= 512;
1054 break;
1055
1056 case 'w':
1057 value *= 2;
1058 break;
1059
1060 case '\0':
1061 return value;
1062
1063 default:
1064 return -1;
1065 }
1066
1067 if (*cp)
1068 return -1;
1069
1070 return value;
1071}
1072#endif
1073
Eric Andersen6805d5d1999-12-09 22:39:55 +00001074
1075#if defined BB_INIT || defined BB_HALT || defined BB_REBOOT
1076
1077#if ! defined BB_FEATURE_USE_PROCFS
1078#error Sorry, I depend on the /proc filesystem right now.
1079#endif
John Beppuf95ca971999-12-09 22:10:18 +00001080/* findInitPid()
1081 *
1082 * This finds the pid of init (which is not always 1).
1083 * Currently, it's implemented by rummaging through the proc filesystem.
1084 *
1085 * [return]
1086 * 0 failure
1087 * pid when init's pid is found.
1088 */
1089extern pid_t
1090findInitPid()
1091{
1092 pid_t init_pid;
1093 char filename[256];
1094 char buffer[256];
1095
1096 /* no need to opendir ;) */
1097 for (init_pid = 1; init_pid < 65536; init_pid++) {
1098 FILE *status;
1099
1100 sprintf(filename, "/proc/%d/status", init_pid);
1101 status = fopen(filename, "r");
1102 if (!status) { continue; }
1103 fgets(buffer, 256, status);
1104 fclose(status);
1105
Eric Andersen6805d5d1999-12-09 22:39:55 +00001106 if ( (strstr(buffer, "init\n") != NULL )) {
John Beppuf95ca971999-12-09 22:10:18 +00001107 return init_pid;
1108 }
1109 }
1110 return 0;
1111}
1112#endif
Eric Andersen1792f8c1999-12-09 06:11:36 +00001113
Eric Andersencc8ed391999-10-05 16:24:54 +00001114/* END CODE */