blob: 5bfed81d707a701a2d59a9bc19e0347a522001fe [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002/*
3 * Utility routines.
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 * Copyright (C) tons of folks. Tracking down who wrote what
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
Eric Andersencc8ed391999-10-05 16:24:54 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) 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 GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */
27
Eric Andersen2b69c401999-10-05 22:58:32 +000028#include "internal.h"
Erik Andersenfac10d72000-02-07 05:29:42 +000029#if defined (BB_CHMOD_CHOWN_CHGRP) \
30 || defined (BB_CP_MV) \
31 || defined (BB_FIND) \
32 || defined (BB_LS) \
33 || defined (BB_INSMOD)
34/* same conditions as recursiveAction */
35#define bb_need_name_too_long
36#endif
37#define BB_DECLARE_EXTERN
38#include "messages.c"
39
Eric Andersen2b69c401999-10-05 22:58:32 +000040#include <stdio.h>
41#include <string.h>
42#include <errno.h>
43#include <fcntl.h>
Eric Andersen2b69c401999-10-05 22:58:32 +000044#include <dirent.h>
45#include <time.h>
46#include <utime.h>
Eric Andersenf811e071999-10-09 00:25:00 +000047#include <sys/stat.h>
48#include <unistd.h>
Eric Andersence8f3b91999-10-20 07:03:36 +000049#include <ctype.h>
Erik Andersene49d5ec2000-02-08 19:58:47 +000050#include <sys/param.h> /* for PATH_MAX */
Eric Andersencc8ed391999-10-05 16:24:54 +000051
Erik Andersen5cbdd712000-01-26 20:06:48 +000052#if defined BB_FEATURE_MOUNT_LOOP
53#include <fcntl.h>
54#include <sys/ioctl.h>
55#include <linux/loop.h>
56#endif
57
58
Eric Andersend0246fb1999-11-04 21:18:07 +000059#if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
Eric Andersen0ecb54a1999-12-05 23:24:55 +000060# if defined BB_FEATURE_USE_PROCFS
Eric Andersend0246fb1999-11-04 21:18:07 +000061const char mtab_file[] = "/proc/mounts";
Eric Andersen0ecb54a1999-12-05 23:24:55 +000062# else
63# if defined BB_MTAB
64const char mtab_file[] = "/etc/mtab";
65# else
66# error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or BB_FEATURE_USE_PROCFS
67# endif
68# endif
Eric Andersend0246fb1999-11-04 21:18:07 +000069#endif
70
71
Eric Andersend73dc5b1999-11-10 23:13:02 +000072extern void usage(const char *usage)
Eric Andersenb0e9a701999-10-18 22:28:26 +000073{
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n",
75 BB_VER, BB_BT);
76 fprintf(stderr, "Usage: %s\n", usage);
77 exit FALSE;
Eric Andersenb0e9a701999-10-18 22:28:26 +000078}
79
Erik Andersen9ffdaa62000-02-11 21:55:04 +000080extern void errorMsg(char *s, ...)
81{
82 va_list p;
83
84 va_start(p, s);
85 fflush(stdout);
86 fprintf(stderr, "\n");
87 vfprintf(stderr, s, p);
88 fprintf(stderr, "\n");
89 va_end(p);
90}
91
92extern void fatalError(char *s, ...)
93{
94 va_list p;
95
96 va_start(p, s);
97 fflush(stdout);
98 fprintf(stderr, "\n");
99 vfprintf(stderr, s, p);
100 fprintf(stderr, "\n");
101 va_end(p);
102 exit( FALSE);
103}
Eric Andersenb0e9a701999-10-18 22:28:26 +0000104
Eric Andersend23f9ba1999-10-20 19:18:15 +0000105#if defined (BB_INIT) || defined (BB_PS)
106
Eric Andersen0ecb54a1999-12-05 23:24:55 +0000107#if ! defined BB_FEATURE_USE_PROCFS
108#error Sorry, I depend on the /proc filesystem right now.
109#endif
Eric Andersend23f9ba1999-10-20 19:18:15 +0000110/* Returns kernel version encoded as major*65536 + minor*256 + patch,
111 * so, for example, to check if the kernel is greater than 2.2.11:
112 * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
113 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000114int get_kernel_revision()
Eric Andersend23f9ba1999-10-20 19:18:15 +0000115{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000116 FILE *file;
117 int major = 0, minor = 0, patch = 0;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000118
Erik Andersene49d5ec2000-02-08 19:58:47 +0000119 file = fopen("/proc/sys/kernel/osrelease", "r");
120 if (file == NULL) {
121 /* bummer, /proc must not be mounted... */
122 return (0);
123 }
124 fscanf(file, "%d.%d.%d", &major, &minor, &patch);
125 fclose(file);
126 return major * 65536 + minor * 256 + patch;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000127}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128#endif /* BB_INIT || BB_PS */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000129
130
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000131
Erik Andersenfac10d72000-02-07 05:29:42 +0000132#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000133/*
134 * Return TRUE if a fileName is a directory.
135 * Nonexistant files return FALSE.
136 */
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000137int isDirectory(const char *fileName, const int followLinks, struct stat *statBuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000138{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000139 int status;
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000140 int didMalloc = 0;
141
142 if (statBuf == NULL) {
143 statBuf = (struct stat *)xmalloc(sizeof(struct stat));
144 ++didMalloc;
145 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000146
Erik Andersene49d5ec2000-02-08 19:58:47 +0000147 if (followLinks == TRUE)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000148 status = stat(fileName, statBuf);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000149 else
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000150 status = lstat(fileName, statBuf);
Erik Andersenfac10d72000-02-07 05:29:42 +0000151
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000152 if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
153 status = FALSE;
154 }
155 else status = TRUE;
156
157 if (didMalloc) {
158 free(statBuf);
159 statBuf = NULL;
160 }
161 return status;
Eric Andersencc8ed391999-10-05 16:24:54 +0000162}
Erik Andersenfac10d72000-02-07 05:29:42 +0000163#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000164
Erik Andersenfac10d72000-02-07 05:29:42 +0000165#if defined (BB_CP_MV)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000166/*
167 * Copy one file to another, while possibly preserving its modes, times,
168 * and modes. Returns TRUE if successful, or FALSE on a failure with an
169 * error message output. (Failure is not indicted if the attributes cannot
170 * be set.)
Eric Andersenc4996011999-10-20 22:08:37 +0000171 * -Erik Andersen
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000172 */
173int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000174copyFile(const char *srcName, const char *destName,
175 int setModes, int followLinks)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000176{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000177 int rfd;
178 int wfd;
179 int rcc;
180 int status;
181 char buf[BUF_SIZE];
182 struct stat srcStatBuf;
183 struct stat dstStatBuf;
184 struct utimbuf times;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000185
Erik Andersene49d5ec2000-02-08 19:58:47 +0000186 if (followLinks == TRUE)
187 status = stat(srcName, &srcStatBuf);
188 else
189 status = lstat(srcName, &srcStatBuf);
Erik Andersenfac10d72000-02-07 05:29:42 +0000190
Erik Andersenfac10d72000-02-07 05:29:42 +0000191 if (status < 0) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000192 perror(srcName);
193 return FALSE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000194 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000195
196 if (followLinks == TRUE)
197 status = stat(destName, &dstStatBuf);
198 else
199 status = lstat(destName, &dstStatBuf);
200
201 if (status < 0) {
202 dstStatBuf.st_ino = -1;
203 dstStatBuf.st_dev = -1;
204 }
205
206 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
207 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
208 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
209 return FALSE;
210 }
211
212 if (S_ISDIR(srcStatBuf.st_mode)) {
213 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
214 /* Make sure the directory is writable */
215 status = mkdir(destName, 0777777 ^ umask(0));
216 if (status < 0 && errno != EEXIST) {
217 perror(destName);
218 return FALSE;
219 }
220 } else if (S_ISLNK(srcStatBuf.st_mode)) {
221 char link_val[PATH_MAX + 1];
222 int link_size;
223
224 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
225 /* Warning: This could possibly truncate silently, to PATH_MAX chars */
226 link_size = readlink(srcName, &link_val[0], PATH_MAX);
227 if (link_size < 0) {
228 perror(srcName);
229 return FALSE;
230 }
231 link_val[link_size] = '\0';
232 status = symlink(link_val, destName);
233 if (status < 0) {
234 perror(destName);
235 return FALSE;
236 }
Erik Andersen8e759aa2000-01-29 05:52:40 +0000237#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000238 if (setModes == TRUE) {
239 if (lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
240 perror(destName);
241 return FALSE;
242 }
243 }
Erik Andersen8e759aa2000-01-29 05:52:40 +0000244#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000245 return TRUE;
246 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
247 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
248 if (mkfifo(destName, 0644) < 0) {
249 perror(destName);
250 return FALSE;
251 }
252 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
253 || S_ISSOCK(srcStatBuf.st_mode)) {
254 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
255 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
256 perror(destName);
257 return FALSE;
258 }
259 } else if (S_ISREG(srcStatBuf.st_mode)) {
260 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
261 rfd = open(srcName, O_RDONLY);
262 if (rfd < 0) {
263 perror(srcName);
264 return FALSE;
265 }
266
267 wfd =
268 open(destName, O_WRONLY | O_CREAT | O_TRUNC,
269 srcStatBuf.st_mode);
270 if (wfd < 0) {
271 perror(destName);
272 close(rfd);
273 return FALSE;
274 }
275
276 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
277 if (fullWrite(wfd, buf, rcc) < 0)
278 goto error_exit;
279 }
280 if (rcc < 0) {
281 goto error_exit;
282 }
283
284 close(rfd);
285 if (close(wfd) < 0) {
286 return FALSE;
287 }
288 }
289
290 if (setModes == TRUE) {
291 /* This is fine, since symlinks never get here */
292 if (chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
293 perror(destName);
294 exit FALSE;
295 }
296 if (chmod(destName, srcStatBuf.st_mode) < 0) {
297 perror(destName);
298 exit FALSE;
299 }
300 times.actime = srcStatBuf.st_atime;
301 times.modtime = srcStatBuf.st_mtime;
302 if (utime(destName, &times) < 0) {
303 perror(destName);
304 exit FALSE;
305 }
306 }
307
Erik Andersenfac10d72000-02-07 05:29:42 +0000308 return TRUE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000309
Erik Andersene49d5ec2000-02-08 19:58:47 +0000310 error_exit:
311 perror(destName);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000312 close(rfd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000313 close(wfd);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000314
Erik Andersene49d5ec2000-02-08 19:58:47 +0000315 return FALSE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000316}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000317#endif /* BB_CP_MV */
Eric Andersencc8ed391999-10-05 16:24:54 +0000318
319
320
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000321#if defined BB_TAR || defined BB_LS
322
323#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
324#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
325
326/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
327static const mode_t SBIT[] = {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000328 0, 0, S_ISUID,
329 0, 0, S_ISGID,
330 0, 0, S_ISVTX
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000331};
332
333/* The 9 mode bits to test */
334static const mode_t MBIT[] = {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000335 S_IRUSR, S_IWUSR, S_IXUSR,
336 S_IRGRP, S_IWGRP, S_IXGRP,
337 S_IROTH, S_IWOTH, S_IXOTH
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000338};
339
340#define MODE1 "rwxrwxrwx"
341#define MODE0 "---------"
342#define SMODE1 "..s..s..t"
343#define SMODE0 "..S..S..T"
344
Eric Andersencc8ed391999-10-05 16:24:54 +0000345/*
346 * Return the standard ls-like mode string from a file mode.
347 * This is static and so is overwritten on each call.
348 */
Eric Andersenf811e071999-10-09 00:25:00 +0000349const char *modeString(int mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000350{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000351 static char buf[12];
Eric Andersencc8ed391999-10-05 16:24:54 +0000352
Erik Andersene49d5ec2000-02-08 19:58:47 +0000353 int i;
354
355 buf[0] = TYPECHAR(mode);
356 for (i = 0; i < 9; i++) {
357 if (mode & SBIT[i])
358 buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
359 else
360 buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
361 }
362 return buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000363}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000364#endif /* BB_TAR || BB_LS */
Eric Andersencc8ed391999-10-05 16:24:54 +0000365
366
Eric Andersen1792f8c1999-12-09 06:11:36 +0000367#if defined BB_TAR
Eric Andersencc8ed391999-10-05 16:24:54 +0000368/*
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000369 * Return the standard ls-like time string from a time_t
370 * This is static and so is overwritten on each call.
Eric Andersen17d49ef1999-10-06 20:25:32 +0000371 */
Eric Andersenf811e071999-10-09 00:25:00 +0000372const char *timeString(time_t timeVal)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000373{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000374 time_t now;
375 char *str;
376 static char buf[26];
Eric Andersen17d49ef1999-10-06 20:25:32 +0000377
Erik Andersene49d5ec2000-02-08 19:58:47 +0000378 time(&now);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000379
Erik Andersene49d5ec2000-02-08 19:58:47 +0000380 str = ctime(&timeVal);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000381
Erik Andersene49d5ec2000-02-08 19:58:47 +0000382 strcpy(buf, &str[4]);
383 buf[12] = '\0';
Eric Andersen17d49ef1999-10-06 20:25:32 +0000384
Erik Andersene49d5ec2000-02-08 19:58:47 +0000385 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
386 strcpy(&buf[7], &str[20]);
387 buf[11] = '\0';
388 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000389
Erik Andersene49d5ec2000-02-08 19:58:47 +0000390 return buf;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000391}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000392#endif /* BB_TAR */
Eric Andersen17d49ef1999-10-06 20:25:32 +0000393
Erik Andersenfac10d72000-02-07 05:29:42 +0000394#if defined BB_TAR || defined BB_CP_MV
Eric Andersen17d49ef1999-10-06 20:25:32 +0000395/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000396 * Write all of the supplied buffer out to a file.
397 * This does multiple writes as necessary.
398 * Returns the amount written, or -1 on an error.
399 */
Eric Andersenf811e071999-10-09 00:25:00 +0000400int fullWrite(int fd, const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000401{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000402 int cc;
403 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000404
Erik Andersene49d5ec2000-02-08 19:58:47 +0000405 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000406
Erik Andersene49d5ec2000-02-08 19:58:47 +0000407 while (len > 0) {
408 cc = write(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000409
Erik Andersene49d5ec2000-02-08 19:58:47 +0000410 if (cc < 0)
411 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000412
Erik Andersene49d5ec2000-02-08 19:58:47 +0000413 buf += cc;
414 total += cc;
415 len -= cc;
416 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000417
Erik Andersene49d5ec2000-02-08 19:58:47 +0000418 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000419}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000420#endif /* BB_TAR || BB_CP_MV */
Eric Andersencc8ed391999-10-05 16:24:54 +0000421
422
Eric Andersen1792f8c1999-12-09 06:11:36 +0000423#if defined BB_TAR || defined BB_TAIL
Eric Andersencc8ed391999-10-05 16:24:54 +0000424/*
425 * Read all of the supplied buffer from a file.
426 * This does multiple reads as necessary.
427 * Returns the amount read, or -1 on an error.
428 * A short read is returned on an end of file.
429 */
Eric Andersenf811e071999-10-09 00:25:00 +0000430int fullRead(int fd, char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000431{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000432 int cc;
433 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000434
Erik Andersene49d5ec2000-02-08 19:58:47 +0000435 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000436
Erik Andersene49d5ec2000-02-08 19:58:47 +0000437 while (len > 0) {
438 cc = read(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000439
Erik Andersene49d5ec2000-02-08 19:58:47 +0000440 if (cc < 0)
441 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000442
Erik Andersene49d5ec2000-02-08 19:58:47 +0000443 if (cc == 0)
444 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000445
Erik Andersene49d5ec2000-02-08 19:58:47 +0000446 buf += cc;
447 total += cc;
448 len -= cc;
449 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000450
Erik Andersene49d5ec2000-02-08 19:58:47 +0000451 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000452}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000453#endif /* BB_TAR || BB_TAIL */
Eric Andersencc8ed391999-10-05 16:24:54 +0000454
455
Erik Andersenfac10d72000-02-07 05:29:42 +0000456#if defined (BB_CHMOD_CHOWN_CHGRP) \
457 || defined (BB_CP_MV) \
458 || defined (BB_FIND) \
459 || defined (BB_LS) \
460 || defined (BB_INSMOD)
Eric Andersencc8ed391999-10-05 16:24:54 +0000461/*
Eric Andersen2b69c401999-10-05 22:58:32 +0000462 * Walk down all the directories under the specified
463 * location, and do something (something specified
464 * by the fileAction and dirAction function pointers).
Eric Andersenb7a1a751999-10-19 23:37:14 +0000465 *
Eric Andersen63a0e531999-10-22 05:12:14 +0000466 * Unfortunatly, while nftw(3) could replace this and reduce
467 * code size a bit, nftw() wasn't supported before GNU libc 2.1,
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000468 * and so isn't sufficiently portable to take over since glibc2.1
469 * is so stinking huge.
Eric Andersencc8ed391999-10-05 16:24:54 +0000470 */
Erik Andersenfac10d72000-02-07 05:29:42 +0000471int recursiveAction(const char *fileName,
Erik Andersene49d5ec2000-02-08 19:58:47 +0000472 int recurse, int followLinks, int depthFirst,
473 int (*fileAction) (const char *fileName,
474 struct stat * statbuf),
475 int (*dirAction) (const char *fileName,
476 struct stat * statbuf))
Eric Andersencc8ed391999-10-05 16:24:54 +0000477{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000478 int status;
479 struct stat statbuf;
480 struct dirent *next;
Eric Andersen9d3aba71999-10-06 09:04:55 +0000481
Erik Andersene49d5ec2000-02-08 19:58:47 +0000482 if (followLinks == TRUE)
483 status = stat(fileName, &statbuf);
Eric Andersen50d63601999-11-09 01:47:36 +0000484 else
Erik Andersene49d5ec2000-02-08 19:58:47 +0000485 status = lstat(fileName, &statbuf);
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000486
Eric Andersen2b69c401999-10-05 22:58:32 +0000487 if (status < 0) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000488#ifdef BB_DEBUG_PRINT_SCAFFOLD
489 fprintf(stderr,
490 "status=%d followLinks=%d TRUE=%d\n",
491 status, followLinks, TRUE);
492#endif
Eric Andersenbed30e91999-10-18 19:02:32 +0000493 perror(fileName);
Erik Andersenfac10d72000-02-07 05:29:42 +0000494 return FALSE;
Eric Andersenbed30e91999-10-18 19:02:32 +0000495 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000496
497 if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
498 if (fileAction == NULL)
499 return TRUE;
500 else
501 return fileAction(fileName, &statbuf);
502 }
503
504 if (recurse == FALSE) {
505 if (S_ISDIR(statbuf.st_mode)) {
506 if (dirAction != NULL)
507 return (dirAction(fileName, &statbuf));
508 else
509 return TRUE;
510 }
511 }
512
513 if (S_ISDIR(statbuf.st_mode)) {
514 DIR *dir;
515
516 dir = opendir(fileName);
517 if (!dir) {
518 perror(fileName);
519 return FALSE;
520 }
521 if (dirAction != NULL && depthFirst == FALSE) {
522 status = dirAction(fileName, &statbuf);
523 if (status == FALSE) {
524 perror(fileName);
525 return FALSE;
526 }
527 }
528 while ((next = readdir(dir)) != NULL) {
529 char nextFile[PATH_MAX + 1];
530
531 if ((strcmp(next->d_name, "..") == 0)
532 || (strcmp(next->d_name, ".") == 0)) {
533 continue;
534 }
535 if (strlen(fileName) + strlen(next->d_name) + 1 > PATH_MAX) {
536 fprintf(stderr, name_too_long, "ftw");
537 return FALSE;
538 }
539 sprintf(nextFile, "%s/%s", fileName, next->d_name);
540 status =
541 recursiveAction(nextFile, TRUE, followLinks, depthFirst,
542 fileAction, dirAction);
543 if (status < 0) {
544 closedir(dir);
545 return FALSE;
546 }
547 }
548 status = closedir(dir);
549 if (status < 0) {
550 perror(fileName);
551 return FALSE;
552 }
553 if (dirAction != NULL && depthFirst == TRUE) {
554 status = dirAction(fileName, &statbuf);
555 if (status == FALSE) {
556 perror(fileName);
557 return FALSE;
558 }
559 }
560 } else {
561 if (fileAction == NULL)
562 return TRUE;
563 else
564 return fileAction(fileName, &statbuf);
565 }
566 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000567}
568
Erik Andersene49d5ec2000-02-08 19:58:47 +0000569#endif /* BB_CHMOD_CHOWN_CHGRP || BB_CP_MV || BB_FIND || BB_LS || BB_INSMOD */
Eric Andersencc8ed391999-10-05 16:24:54 +0000570
Eric Andersenf6be9441999-10-13 21:12:06 +0000571
572
Erik Andersena8991081999-12-29 03:34:00 +0000573#if defined (BB_TAR) || defined (BB_MKDIR)
Eric Andersenf6be9441999-10-13 21:12:06 +0000574/*
575 * Attempt to create the directories along the specified path, except for
576 * the final component. The mode is given for the final directory only,
577 * while all previous ones get default protections. Errors are not reported
578 * here, as failures to restore files can be reported later.
579 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000580extern int createPath(const char *name, int mode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000581{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000582 char *cp;
583 char *cpOld;
584 char buf[PATH_MAX + 1];
585 int retVal = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000586
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 strcpy(buf, name);
588 for (cp = buf; *cp == '/'; cp++);
589 cp = strchr(cp, '/');
590 while (cp) {
591 cpOld = cp;
592 cp = strchr(cp + 1, '/');
593 *cpOld = '\0';
594 retVal = mkdir(buf, cp ? 0777 : mode);
595 if (retVal != 0 && errno != EEXIST) {
596 perror(buf);
597 return FALSE;
598 }
599 *cpOld = '/';
Erik Andersen06936df2000-01-23 02:14:20 +0000600 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000601 return TRUE;
Eric Andersenf6be9441999-10-13 21:12:06 +0000602}
Erik Andersene49d5ec2000-02-08 19:58:47 +0000603#endif /* BB_TAR || BB_MKDIR */
Eric Andersenf6be9441999-10-13 21:12:06 +0000604
605
606
607#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
Eric Andersence8f3b91999-10-20 07:03:36 +0000608/* [ugoa]{+|-|=}[rwxst] */
609
610
611
Erik Andersene49d5ec2000-02-08 19:58:47 +0000612extern int parse_mode(const char *s, mode_t * theMode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000613{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000614 mode_t andMode =
615
616 S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersence8f3b91999-10-20 07:03:36 +0000617 mode_t orMode = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000618 mode_t mode = 0;
619 mode_t groups = 0;
620 char type;
621 char c;
Eric Andersenf6be9441999-10-13 21:12:06 +0000622
623 do {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000624 for (;;) {
625 switch (c = *s++) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000626 case '\0':
Eric Andersence8f3b91999-10-20 07:03:36 +0000627 return -1;
Eric Andersenf6be9441999-10-13 21:12:06 +0000628 case 'u':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000629 groups |= S_ISUID | S_IRWXU;
Eric Andersenf6be9441999-10-13 21:12:06 +0000630 continue;
631 case 'g':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000632 groups |= S_ISGID | S_IRWXG;
Eric Andersenf6be9441999-10-13 21:12:06 +0000633 continue;
634 case 'o':
635 groups |= S_IRWXO;
636 continue;
637 case 'a':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000638 groups |= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersenf6be9441999-10-13 21:12:06 +0000639 continue;
640 case '+':
641 case '=':
642 case '-':
643 type = c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000644 if (groups == 0) /* The default is "all" */
645 groups |=
646 S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersenf6be9441999-10-13 21:12:06 +0000647 break;
648 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000649 if (isdigit(c) && c >= '0' && c <= '7' &&
650 mode == 0 && groups == 0) {
Eric Andersenfa0540f1999-10-22 18:18:31 +0000651 *theMode = strtol(--s, NULL, 8);
Eric Andersenf6be9441999-10-13 21:12:06 +0000652 return (TRUE);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000653 } else
Eric Andersenf6be9441999-10-13 21:12:06 +0000654 return (FALSE);
655 }
656 break;
657 }
658
Erik Andersene49d5ec2000-02-08 19:58:47 +0000659 while ((c = *s++) != '\0') {
660 switch (c) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000661 case ',':
662 break;
663 case 'r':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000664 mode |= S_IRUSR | S_IRGRP | S_IROTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000665 continue;
666 case 'w':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000667 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000668 continue;
669 case 'x':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000670 mode |= S_IXUSR | S_IXGRP | S_IXOTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000671 continue;
672 case 's':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000673 mode |= S_IXGRP | S_ISUID | S_ISGID;
Eric Andersenf6be9441999-10-13 21:12:06 +0000674 continue;
675 case 't':
Eric Andersence8f3b91999-10-20 07:03:36 +0000676 mode |= 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000677 continue;
678 default:
Eric Andersence8f3b91999-10-20 07:03:36 +0000679 *theMode &= andMode;
680 *theMode |= orMode;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000681 return (TRUE);
Eric Andersenf6be9441999-10-13 21:12:06 +0000682 }
683 break;
684 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000685 switch (type) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000686 case '=':
Eric Andersence8f3b91999-10-20 07:03:36 +0000687 andMode &= ~(groups);
Eric Andersenf6be9441999-10-13 21:12:06 +0000688 /* fall through */
689 case '+':
Eric Andersence8f3b91999-10-20 07:03:36 +0000690 orMode |= mode & groups;
Eric Andersenf6be9441999-10-13 21:12:06 +0000691 break;
692 case '-':
Eric Andersence8f3b91999-10-20 07:03:36 +0000693 andMode &= ~(mode & groups);
694 orMode &= andMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000695 break;
696 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000697 } while (c == ',');
Eric Andersence8f3b91999-10-20 07:03:36 +0000698 *theMode &= andMode;
699 *theMode |= orMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000700 return (TRUE);
701}
Eric Andersence8f3b91999-10-20 07:03:36 +0000702
703
Erik Andersene49d5ec2000-02-08 19:58:47 +0000704#endif /* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR */
Eric Andersenf6be9441999-10-13 21:12:06 +0000705
Eric Andersene674eb71999-10-19 20:52:57 +0000706
707
Eric Andersend23f9ba1999-10-20 19:18:15 +0000708
709
710
711
712#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
713
714/* Use this to avoid needing the glibc NSS stuff
715 * This uses storage buf to hold things.
716 * */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000717uid_t my_getid(const char *filename, char *name, uid_t id)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000718{
Eric Andersenaa0765e1999-10-22 04:30:20 +0000719 FILE *file;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000720 char *rname, *start, *end, buf[128];
721 uid_t rid;
722
Erik Andersene49d5ec2000-02-08 19:58:47 +0000723 file = fopen(filename, "r");
Eric Andersenaa0765e1999-10-22 04:30:20 +0000724 if (file == NULL) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000725 perror(filename);
726 return (-1);
Eric Andersenaa0765e1999-10-22 04:30:20 +0000727 }
Eric Andersend23f9ba1999-10-20 19:18:15 +0000728
Erik Andersene49d5ec2000-02-08 19:58:47 +0000729 while (fgets(buf, 128, file) != NULL) {
Eric Andersend23f9ba1999-10-20 19:18:15 +0000730 if (buf[0] == '#')
731 continue;
732
733 start = buf;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000734 end = strchr(start, ':');
Eric Andersend23f9ba1999-10-20 19:18:15 +0000735 if (end == NULL)
736 continue;
737 *end = '\0';
738 rname = start;
739
740 start = end + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000741 end = strchr(start, ':');
Eric Andersend23f9ba1999-10-20 19:18:15 +0000742 if (end == NULL)
743 continue;
744
745 start = end + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000746 rid = (uid_t) strtol(start, &end, 10);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000747 if (end == start)
748 continue;
749
750 if (name) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000751 if (0 == strcmp(rname, name)) {
752 fclose(file);
753 return (rid);
754 }
755 }
756 if (id != -1 && id == rid) {
757 strncpy(name, rname, 8);
758 fclose(file);
759 return (TRUE);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000760 }
761 }
Eric Andersenaa0765e1999-10-22 04:30:20 +0000762 fclose(file);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000763 return (-1);
764}
765
Erik Andersene49d5ec2000-02-08 19:58:47 +0000766uid_t my_getpwnam(char *name)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000767{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000768 return my_getid("/etc/passwd", name, -1);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000769}
770
Erik Andersene49d5ec2000-02-08 19:58:47 +0000771gid_t my_getgrnam(char *name)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000772{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000773 return my_getid("/etc/group", name, -1);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000774}
775
Erik Andersene49d5ec2000-02-08 19:58:47 +0000776void my_getpwuid(char *name, uid_t uid)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000777{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000778 my_getid("/etc/passwd", name, uid);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000779}
780
Erik Andersene49d5ec2000-02-08 19:58:47 +0000781void my_getgrgid(char *group, gid_t gid)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000782{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000783 my_getid("/etc/group", group, gid);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000784}
785
786
Erik Andersene49d5ec2000-02-08 19:58:47 +0000787#endif /* BB_CHMOD_CHOWN_CHGRP || BB_PS */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000788
789
Eric Andersenaa0765e1999-10-22 04:30:20 +0000790
Eric Andersen0460ff21999-10-25 23:32:44 +0000791
792#if (defined BB_CHVT) || (defined BB_DEALLOCVT)
793
794
795#include <linux/kd.h>
796#include <sys/ioctl.h>
797
Erik Andersene49d5ec2000-02-08 19:58:47 +0000798int is_a_console(int fd)
Eric Andersen0460ff21999-10-25 23:32:44 +0000799{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000800 char arg;
801
802 arg = 0;
803 return (ioctl(fd, KDGKBTYPE, &arg) == 0
804 && ((arg == KB_101) || (arg == KB_84)));
Eric Andersen0460ff21999-10-25 23:32:44 +0000805}
806
Erik Andersene49d5ec2000-02-08 19:58:47 +0000807static int open_a_console(char *fnam)
Eric Andersen0460ff21999-10-25 23:32:44 +0000808{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000809 int fd;
810
811 /* try read-only */
812 fd = open(fnam, O_RDWR);
813
814 /* if failed, try read-only */
815 if (fd < 0 && errno == EACCES)
816 fd = open(fnam, O_RDONLY);
817
818 /* if failed, try write-only */
819 if (fd < 0 && errno == EACCES)
820 fd = open(fnam, O_WRONLY);
821
822 /* if failed, fail */
823 if (fd < 0)
824 return -1;
825
826 /* if not a console, fail */
827 if (!is_a_console(fd)) {
828 close(fd);
829 return -1;
830 }
831
832 /* success */
833 return fd;
Eric Andersen0460ff21999-10-25 23:32:44 +0000834}
835
836/*
837 * Get an fd for use with kbd/console ioctls.
838 * We try several things because opening /dev/console will fail
839 * if someone else used X (which does a chown on /dev/console).
840 *
841 * if tty_name is non-NULL, try this one instead.
842 */
843
Erik Andersene49d5ec2000-02-08 19:58:47 +0000844int get_console_fd(char *tty_name)
Eric Andersen0460ff21999-10-25 23:32:44 +0000845{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000846 int fd;
Eric Andersen0460ff21999-10-25 23:32:44 +0000847
Erik Andersene49d5ec2000-02-08 19:58:47 +0000848 if (tty_name) {
849 if (-1 == (fd = open_a_console(tty_name)))
850 return -1;
851 else
852 return fd;
853 }
854
855 fd = open_a_console("/dev/tty");
856 if (fd >= 0)
857 return fd;
858
859 fd = open_a_console("/dev/tty0");
860 if (fd >= 0)
861 return fd;
862
863 fd = open_a_console("/dev/console");
864 if (fd >= 0)
865 return fd;
866
867 for (fd = 0; fd < 3; fd++)
868 if (is_a_console(fd))
869 return fd;
870
871 fprintf(stderr,
872 "Couldnt get a file descriptor referring to the console\n");
873 return -1; /* total failure */
Eric Andersen0460ff21999-10-25 23:32:44 +0000874}
875
876
Erik Andersene49d5ec2000-02-08 19:58:47 +0000877#endif /* BB_CHVT || BB_DEALLOCVT */
Eric Andersen0460ff21999-10-25 23:32:44 +0000878
879
Erik Andersene49d5ec2000-02-08 19:58:47 +0000880#if !defined BB_REGEXP && (defined BB_GREP || defined BB_SED)
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000881
882/* Do a case insensitive strstr() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000883char *stristr(char *haystack, const char *needle)
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000884{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000885 int len = strlen(needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000886
Erik Andersene49d5ec2000-02-08 19:58:47 +0000887 while (*haystack) {
888 if (!strncasecmp(haystack, needle, len))
889 break;
890 haystack++;
891 }
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000892
Erik Andersene49d5ec2000-02-08 19:58:47 +0000893 if (!(*haystack))
894 haystack = NULL;
895
896 return haystack;
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000897}
898
Eric Andersenc1525e81999-10-29 00:07:31 +0000899/* This tries to find a needle in a haystack, but does so by
900 * only trying to match literal strings (look 'ma, no regexps!)
901 * This is short, sweet, and carries _very_ little baggage,
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000902 * unlike its beefier cousin in regexp.c
Eric Andersenc1525e81999-10-29 00:07:31 +0000903 * -Erik Andersen
904 */
905extern int find_match(char *haystack, char *needle, int ignoreCase)
906{
907
Erik Andersene49d5ec2000-02-08 19:58:47 +0000908 if (ignoreCase == FALSE)
909 haystack = strstr(haystack, needle);
910 else
911 haystack = stristr(haystack, needle);
912 if (haystack == NULL)
913 return FALSE;
914 return TRUE;
Eric Andersenc1525e81999-10-29 00:07:31 +0000915}
916
917
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000918/* This performs substitutions after a string match has been found. */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000919extern int replace_match(char *haystack, char *needle, char *newNeedle,
920 int ignoreCase)
Eric Andersenc1525e81999-10-29 00:07:31 +0000921{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000922 int foundOne = 0;
923 char *where, *slider, *slider1, *oldhayStack;
Eric Andersenc1525e81999-10-29 00:07:31 +0000924
Erik Andersene49d5ec2000-02-08 19:58:47 +0000925 if (ignoreCase == FALSE)
926 where = strstr(haystack, needle);
927 else
928 where = stristr(haystack, needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000929
Erik Andersene49d5ec2000-02-08 19:58:47 +0000930 if (strcmp(needle, newNeedle) == 0)
931 return FALSE;
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000932
Erik Andersene49d5ec2000-02-08 19:58:47 +0000933 oldhayStack = (char *) malloc((unsigned) (strlen(haystack)));
934 while (where != NULL) {
935 foundOne++;
936 strcpy(oldhayStack, haystack);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000937#if 0
Erik Andersene49d5ec2000-02-08 19:58:47 +0000938 if (strlen(newNeedle) > strlen(needle)) {
939 haystack =
940 (char *) realloc(haystack,
941 (unsigned) (strlen(haystack) -
942 strlen(needle) +
943 strlen(newNeedle)));
944 }
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000945#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000946 for (slider = haystack, slider1 = oldhayStack; slider != where;
947 slider++, slider1++);
948 *slider = 0;
949 haystack = strcat(haystack, newNeedle);
950 slider1 += strlen(needle);
951 haystack = strcat(haystack, slider1);
952 where = strstr(slider, needle);
953 }
954 free(oldhayStack);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000955
Erik Andersene49d5ec2000-02-08 19:58:47 +0000956 if (foundOne > 0)
957 return TRUE;
958 else
959 return FALSE;
Eric Andersenc1525e81999-10-29 00:07:31 +0000960}
961
Erik Andersene49d5ec2000-02-08 19:58:47 +0000962#endif /* ! BB_REGEXP && (BB_GREP || BB_SED) */
Eric Andersen29d2e361999-11-06 06:07:27 +0000963
964
Eric Andersenb186d981999-12-03 09:19:54 +0000965#if defined BB_FIND
966/*
967 * Routine to see if a text string is matched by a wildcard pattern.
968 * Returns TRUE if the text is matched, or FALSE if it is not matched
969 * or if the pattern is invalid.
970 * * matches zero or more characters
971 * ? matches a single character
972 * [abc] matches 'a', 'b' or 'c'
973 * \c quotes character c
974 * Adapted from code written by Ingo Wilken, and
975 * then taken from sash, Copyright (c) 1999 by David I. Bell
976 * Permission is granted to use, distribute, or modify this source,
977 * provided that this copyright notice remains intact.
978 * Permission to distribute this code under the GPL has been granted.
979 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000980extern int check_wildcard_match(const char *text, const char *pattern)
Eric Andersenb186d981999-12-03 09:19:54 +0000981{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000982 const char *retryPat;
983 const char *retryText;
984 int ch;
985 int found;
Eric Andersenb186d981999-12-03 09:19:54 +0000986
Erik Andersene49d5ec2000-02-08 19:58:47 +0000987 retryPat = NULL;
988 retryText = NULL;
Eric Andersenb186d981999-12-03 09:19:54 +0000989
Erik Andersene49d5ec2000-02-08 19:58:47 +0000990 while (*text || *pattern) {
Eric Andersenb186d981999-12-03 09:19:54 +0000991 ch = *pattern++;
992
Erik Andersene49d5ec2000-02-08 19:58:47 +0000993 switch (ch) {
994 case '*':
995 retryPat = pattern;
996 retryText = text;
997 break;
998
999 case '[':
1000 found = FALSE;
1001
1002 while ((ch = *pattern++) != ']') {
1003 if (ch == '\\')
1004 ch = *pattern++;
1005
1006 if (ch == '\0')
1007 return FALSE;
1008
1009 if (*text == ch)
1010 found = TRUE;
1011 }
1012
1013 //if (!found)
1014 if (found == TRUE) {
1015 pattern = retryPat;
1016 text = ++retryText;
1017 }
1018
1019 /* fall into next case */
1020
1021 case '?':
1022 if (*text++ == '\0')
1023 return FALSE;
1024
1025 break;
1026
1027 case '\\':
1028 ch = *pattern++;
1029
1030 if (ch == '\0')
1031 return FALSE;
1032
1033 /* fall into next case */
1034
1035 default:
1036 if (*text == ch) {
1037 if (*text)
1038 text++;
1039 break;
1040 }
1041
1042 if (*text) {
1043 pattern = retryPat;
1044 text = ++retryText;
1045 break;
1046 }
1047
Eric Andersenb186d981999-12-03 09:19:54 +00001048 return FALSE;
Eric Andersenb186d981999-12-03 09:19:54 +00001049 }
1050
Erik Andersene49d5ec2000-02-08 19:58:47 +00001051 if (pattern == NULL)
1052 return FALSE;
Eric Andersenb186d981999-12-03 09:19:54 +00001053 }
1054
Erik Andersene49d5ec2000-02-08 19:58:47 +00001055 return TRUE;
Eric Andersenb186d981999-12-03 09:19:54 +00001056}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001057#endif /* BB_FIND */
Eric Andersenb186d981999-12-03 09:19:54 +00001058
1059
Eric Andersen29d2e361999-11-06 06:07:27 +00001060
1061
Erik Andersen7dc16072000-01-04 01:10:25 +00001062#if defined BB_DF || defined BB_MTAB
Eric Andersen29d2e361999-11-06 06:07:27 +00001063/*
1064 * Given a block device, find the mount table entry if that block device
1065 * is mounted.
1066 *
1067 * Given any other file (or directory), find the mount table entry for its
1068 * filesystem.
1069 */
1070extern struct mntent *findMountPoint(const char *name, const char *table)
1071{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001072 struct stat s;
1073 dev_t mountDevice;
1074 FILE *mountTable;
1075 struct mntent *mountEntry;
Eric Andersen29d2e361999-11-06 06:07:27 +00001076
Erik Andersene49d5ec2000-02-08 19:58:47 +00001077 if (stat(name, &s) != 0)
1078 return 0;
Eric Andersen29d2e361999-11-06 06:07:27 +00001079
Erik Andersene49d5ec2000-02-08 19:58:47 +00001080 if ((s.st_mode & S_IFMT) == S_IFBLK)
1081 mountDevice = s.st_rdev;
1082 else
1083 mountDevice = s.st_dev;
Eric Andersen29d2e361999-11-06 06:07:27 +00001084
1085
Erik Andersene49d5ec2000-02-08 19:58:47 +00001086 if ((mountTable = setmntent(table, "r")) == 0)
1087 return 0;
Eric Andersen29d2e361999-11-06 06:07:27 +00001088
Erik Andersene49d5ec2000-02-08 19:58:47 +00001089 while ((mountEntry = getmntent(mountTable)) != 0) {
1090 if (strcmp(name, mountEntry->mnt_dir) == 0
1091 || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
1092 break;
1093 if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
1094 break;
1095 if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
1096 break;
1097 }
1098 endmntent(mountTable);
1099 return mountEntry;
Eric Andersen29d2e361999-11-06 06:07:27 +00001100}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001101#endif /* BB_DF || BB_MTAB */
Eric Andersen29d2e361999-11-06 06:07:27 +00001102
1103
1104
Eric Andersen1792f8c1999-12-09 06:11:36 +00001105#if defined BB_DD || defined BB_TAIL
1106/*
1107 * Read a number with a possible multiplier.
1108 * Returns -1 if the number format is illegal.
1109 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001110extern long getNum(const char *cp)
Eric Andersen1792f8c1999-12-09 06:11:36 +00001111{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001112 long value;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001113
Erik Andersene49d5ec2000-02-08 19:58:47 +00001114 if (!isDecimal(*cp))
1115 return -1;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001116
Erik Andersene49d5ec2000-02-08 19:58:47 +00001117 value = 0;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001118
Erik Andersene49d5ec2000-02-08 19:58:47 +00001119 while (isDecimal(*cp))
1120 value = value * 10 + *cp++ - '0';
Eric Andersen1792f8c1999-12-09 06:11:36 +00001121
Erik Andersene49d5ec2000-02-08 19:58:47 +00001122 switch (*cp++) {
1123 case 'M':
1124 case 'm': /* `tail' uses it traditionally */
1125 value *= 1048576;
1126 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001127
Erik Andersene49d5ec2000-02-08 19:58:47 +00001128 case 'k':
1129 value *= 1024;
1130 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001131
Erik Andersene49d5ec2000-02-08 19:58:47 +00001132 case 'b':
1133 value *= 512;
1134 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001135
Erik Andersene49d5ec2000-02-08 19:58:47 +00001136 case 'w':
1137 value *= 2;
1138 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001139
Erik Andersene49d5ec2000-02-08 19:58:47 +00001140 case '\0':
1141 return value;
1142
1143 default:
1144 return -1;
1145 }
1146
1147 if (*cp)
1148 return -1;
1149
Eric Andersen1792f8c1999-12-09 06:11:36 +00001150 return value;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001151}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001152#endif /* BB_DD || BB_TAIL */
Eric Andersen1792f8c1999-12-09 06:11:36 +00001153
Eric Andersen6805d5d1999-12-09 22:39:55 +00001154
Erik Andersen31cf8e02000-02-07 20:31:19 +00001155#if defined BB_INIT || defined BB_SYSLOGD
1156/* try to open up the specified device */
1157extern int device_open(char *device, int mode)
1158{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001159 int m, f, fd = -1;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001160
Erik Andersene49d5ec2000-02-08 19:58:47 +00001161 m = mode | O_NONBLOCK;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001162
Erik Andersene49d5ec2000-02-08 19:58:47 +00001163 /* Retry up to 5 times */
1164 for (f = 0; f < 5; f++)
1165 if ((fd = open(device, m, 0600)) >= 0)
1166 break;
1167 if (fd < 0)
1168 return fd;
1169 /* Reset original flags. */
1170 if (m != mode)
1171 fcntl(fd, F_SETFL, mode);
Erik Andersen31cf8e02000-02-07 20:31:19 +00001172 return fd;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001173}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001174#endif /* BB_INIT BB_SYSLOGD */
Erik Andersen31cf8e02000-02-07 20:31:19 +00001175
1176
Erik Andersene49d5ec2000-02-08 19:58:47 +00001177#if defined BB_INIT || defined BB_HALT || defined BB_REBOOT
Eric Andersen6805d5d1999-12-09 22:39:55 +00001178
1179#if ! defined BB_FEATURE_USE_PROCFS
1180#error Sorry, I depend on the /proc filesystem right now.
1181#endif
John Beppuf95ca971999-12-09 22:10:18 +00001182/* findInitPid()
1183 *
1184 * This finds the pid of init (which is not always 1).
1185 * Currently, it's implemented by rummaging through the proc filesystem.
1186 *
1187 * [return]
1188 * 0 failure
1189 * pid when init's pid is found.
1190 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001191extern pid_t findInitPid()
John Beppuf95ca971999-12-09 22:10:18 +00001192{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001193 pid_t init_pid;
1194 char filename[256];
1195 char buffer[256];
John Beppuf95ca971999-12-09 22:10:18 +00001196
Erik Andersene49d5ec2000-02-08 19:58:47 +00001197 /* no need to opendir ;) */
1198 for (init_pid = 1; init_pid < 65536; init_pid++) {
1199 FILE *status;
John Beppuf95ca971999-12-09 22:10:18 +00001200
Erik Andersene49d5ec2000-02-08 19:58:47 +00001201 sprintf(filename, "/proc/%d/status", init_pid);
1202 status = fopen(filename, "r");
1203 if (!status) {
1204 continue;
1205 }
1206 fgets(buffer, 256, status);
1207 fclose(status);
John Beppuf95ca971999-12-09 22:10:18 +00001208
Erik Andersene49d5ec2000-02-08 19:58:47 +00001209 if ((strstr(buffer, "init\n") != NULL)) {
1210 return init_pid;
1211 }
John Beppuf95ca971999-12-09 22:10:18 +00001212 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001213 return 0;
John Beppuf95ca971999-12-09 22:10:18 +00001214}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001215#endif /* BB_INIT || BB_HALT || BB_REBOOT */
Eric Andersen1792f8c1999-12-09 06:11:36 +00001216
Erik Andersenfac10d72000-02-07 05:29:42 +00001217#if defined BB_GUNZIP \
1218 || defined BB_GZIP \
1219 || defined BB_PRINTF \
1220 || defined BB_TAIL
Erik Andersene49d5ec2000-02-08 19:58:47 +00001221extern void *xmalloc(size_t size)
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001222{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001223 void *cp = malloc(size);
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001224
Erik Andersene49d5ec2000-02-08 19:58:47 +00001225 if (cp == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +00001226 errorMsg("out of memory");
Erik Andersene49d5ec2000-02-08 19:58:47 +00001227 }
1228 return cp;
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001229}
1230
Erik Andersene49d5ec2000-02-08 19:58:47 +00001231#endif /* BB_GUNZIP || BB_GZIP || BB_PRINTF || BB_TAIL */
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001232
Erik Andersen7dc16072000-01-04 01:10:25 +00001233#if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
1234extern int vdprintf(int d, const char *format, va_list ap)
1235{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001236 char buf[BUF_SIZE];
1237 int len;
Erik Andersen7dc16072000-01-04 01:10:25 +00001238
Erik Andersene49d5ec2000-02-08 19:58:47 +00001239 len = vsprintf(buf, format, ap);
1240 return write(d, buf, len);
Erik Andersen7dc16072000-01-04 01:10:25 +00001241}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001242#endif /* BB_SYSLOGD */
Erik Andersen7dc16072000-01-04 01:10:25 +00001243
Erik Andersen5cbdd712000-01-26 20:06:48 +00001244#if defined BB_FEATURE_MOUNT_LOOP
1245extern int del_loop(const char *device)
1246{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001247 int fd;
Erik Andersen5cbdd712000-01-26 20:06:48 +00001248
Erik Andersene49d5ec2000-02-08 19:58:47 +00001249 if ((fd = open(device, O_RDONLY)) < 0) {
1250 perror(device);
1251 return (FALSE);
1252 }
1253 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
1254 perror("ioctl: LOOP_CLR_FD");
1255 return (FALSE);
1256 }
1257 close(fd);
1258 return (TRUE);
Erik Andersen5cbdd712000-01-26 20:06:48 +00001259}
Erik Andersende7965c2000-01-26 23:49:21 +00001260
Erik Andersene49d5ec2000-02-08 19:58:47 +00001261extern int set_loop(const char *device, const char *file, int offset,
1262 int *loopro)
Erik Andersende7965c2000-01-26 23:49:21 +00001263{
1264 struct loop_info loopinfo;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001265 int fd, ffd, mode;
1266
Erik Andersende7965c2000-01-26 23:49:21 +00001267 mode = *loopro ? O_RDONLY : O_RDWR;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001268 if ((ffd = open(file, mode)) < 0 && !*loopro
1269 && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
1270 perror(file);
1271 return 1;
Erik Andersende7965c2000-01-26 23:49:21 +00001272 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001273 if ((fd = open(device, mode)) < 0) {
1274 close(ffd);
1275 perror(device);
1276 return 1;
Erik Andersende7965c2000-01-26 23:49:21 +00001277 }
1278 *loopro = (mode == O_RDONLY);
1279
1280 memset(&loopinfo, 0, sizeof(loopinfo));
1281 strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001282 loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
Erik Andersende7965c2000-01-26 23:49:21 +00001283
1284 loopinfo.lo_offset = offset;
1285
1286 loopinfo.lo_encrypt_key_size = 0;
1287 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
1288 perror("ioctl: LOOP_SET_FD");
1289 close(fd);
1290 close(ffd);
1291 return 1;
1292 }
1293 if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
1294 (void) ioctl(fd, LOOP_CLR_FD, 0);
1295 perror("ioctl: LOOP_SET_STATUS");
1296 close(fd);
1297 close(ffd);
1298 return 1;
1299 }
1300 close(fd);
1301 close(ffd);
1302 return 0;
1303}
1304
Erik Andersene49d5ec2000-02-08 19:58:47 +00001305extern char *find_unused_loop_device(void)
Erik Andersende7965c2000-01-26 23:49:21 +00001306{
1307 char dev[20];
1308 int i, fd;
1309 struct stat statbuf;
1310 struct loop_info loopinfo;
1311
Erik Andersene49d5ec2000-02-08 19:58:47 +00001312 for (i = 0; i <= 7; i++) {
1313 sprintf(dev, "/dev/loop%d", i);
1314 if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
1315 if ((fd = open(dev, O_RDONLY)) >= 0) {
1316 if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == -1) {
1317 if (errno == ENXIO) { /* probably free */
1318 close(fd);
1319 return strdup(dev);
1320 }
1321 }
1322 close(fd);
Erik Andersende7965c2000-01-26 23:49:21 +00001323 }
Erik Andersende7965c2000-01-26 23:49:21 +00001324 }
Erik Andersende7965c2000-01-26 23:49:21 +00001325 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001326 return NULL;
Erik Andersende7965c2000-01-26 23:49:21 +00001327}
Erik Andersene49d5ec2000-02-08 19:58:47 +00001328#endif /* BB_FEATURE_MOUNT_LOOP */
Erik Andersende7965c2000-01-26 23:49:21 +00001329
Erik Andersene132f4b2000-02-09 04:16:43 +00001330#if defined BB_MTAB
1331#define whine_if_fstab_is_missing() {}
1332#else
1333extern void whine_if_fstab_is_missing()
1334{
1335 struct stat statBuf;
1336
1337 if (stat("/etc/fstab", &statBuf) < 0)
1338 fprintf(stderr,
1339 "/etc/fstab file missing -- install one to name /dev/root.\n\n");
1340}
1341#endif
1342
1343
Erik Andersen5cbdd712000-01-26 20:06:48 +00001344
Eric Andersencc8ed391999-10-05 16:24:54 +00001345/* END CODE */