blob: 061ba64236ef15d54593ba7594f032e0ad543ab3 [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
Eric Andersen9f16d612000-06-12 23:11:16 +000037#define bb_need_memory_exhausted
Erik Andersenfac10d72000-02-07 05:29:42 +000038#define BB_DECLARE_EXTERN
39#include "messages.c"
40
Eric Andersen2b69c401999-10-05 22:58:32 +000041#include <stdio.h>
42#include <string.h>
43#include <errno.h>
44#include <fcntl.h>
Eric Andersen2b69c401999-10-05 22:58:32 +000045#include <dirent.h>
46#include <time.h>
47#include <utime.h>
Eric Andersenf811e071999-10-09 00:25:00 +000048#include <sys/stat.h>
49#include <unistd.h>
Eric Andersence8f3b91999-10-20 07:03:36 +000050#include <ctype.h>
Erik Andersend07ee462000-02-21 21:26:32 +000051#include <sys/utsname.h> /* for uname(2) */
Eric Andersencc8ed391999-10-05 16:24:54 +000052
Erik Andersen5cbdd712000-01-26 20:06:48 +000053#if defined BB_FEATURE_MOUNT_LOOP
54#include <fcntl.h>
55#include <sys/ioctl.h>
56#include <linux/loop.h>
57#endif
58
Erik Andersen246cc6d2000-03-07 07:41:42 +000059/* Busybox mount uses either /proc/filesystems or /dev/mtab to get the
60 * list of available filesystems used for the -t auto option */
Erik Andersen269bba22000-03-08 14:50:47 +000061#if defined BB_FEATURE_USE_PROCFS && defined BB_FEATURE_USE_DEVPS_PATCH
Erik Andersen246cc6d2000-03-07 07:41:42 +000062//#error Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again.
63#error "Sorry, but busybox can't use both /proc and /dev/ps at the same time -- Pick one and try again."
64#endif
65
Erik Andersen5cbdd712000-01-26 20:06:48 +000066
Eric Andersend0246fb1999-11-04 21:18:07 +000067#if defined BB_MOUNT || defined BB_UMOUNT || defined BB_DF
Eric Andersen0ecb54a1999-12-05 23:24:55 +000068# if defined BB_FEATURE_USE_PROCFS
Eric Andersend0246fb1999-11-04 21:18:07 +000069const char mtab_file[] = "/proc/mounts";
Eric Andersen0ecb54a1999-12-05 23:24:55 +000070# else
71# if defined BB_MTAB
72const char mtab_file[] = "/etc/mtab";
73# else
Erik Andersen269bba22000-03-08 14:50:47 +000074# if defined BB_FEATURE_USE_DEVPS_PATCH
Erik Andersen246cc6d2000-03-07 07:41:42 +000075const char mtab_file[] = "/dev/mtab";
76# else
Erik Andersen269bba22000-03-08 14:50:47 +000077# error With (BB_MOUNT||BB_UMOUNT||BB_DF) defined, you must define either BB_MTAB or ( BB_FEATURE_USE_PROCFS | BB_FEATURE_USE_DEVPS_PATCH)
Eric Andersen0ecb54a1999-12-05 23:24:55 +000078# endif
79# endif
Erik Andersen246cc6d2000-03-07 07:41:42 +000080# endif
Eric Andersend0246fb1999-11-04 21:18:07 +000081#endif
82
83
Eric Andersend73dc5b1999-11-10 23:13:02 +000084extern void usage(const char *usage)
Eric Andersenb0e9a701999-10-18 22:28:26 +000085{
Erik Andersene49d5ec2000-02-08 19:58:47 +000086 fprintf(stderr, "BusyBox v%s (%s) multi-call binary -- GPL2\n\n",
87 BB_VER, BB_BT);
88 fprintf(stderr, "Usage: %s\n", usage);
89 exit FALSE;
Eric Andersenb0e9a701999-10-18 22:28:26 +000090}
91
Erik Andersen1ad302a2000-03-24 00:54:46 +000092extern void errorMsg(const char *s, ...)
Erik Andersen9ffdaa62000-02-11 21:55:04 +000093{
94 va_list p;
95
96 va_start(p, s);
97 fflush(stdout);
Erik Andersen9ffdaa62000-02-11 21:55:04 +000098 vfprintf(stderr, s, p);
Erik Andersen9ffdaa62000-02-11 21:55:04 +000099 va_end(p);
Erik Andersen3522eb12000-03-12 23:49:18 +0000100 fflush(stderr);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000101}
102
Erik Andersen1ad302a2000-03-24 00:54:46 +0000103extern void fatalError(const char *s, ...)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000104{
105 va_list p;
106
107 va_start(p, s);
108 fflush(stdout);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000109 vfprintf(stderr, s, p);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000110 va_end(p);
Erik Andersen3522eb12000-03-12 23:49:18 +0000111 fflush(stderr);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000112 exit( FALSE);
113}
Eric Andersenb0e9a701999-10-18 22:28:26 +0000114
Erik Andersen23dea9b2000-05-13 00:28:25 +0000115#if defined BB_INIT
Eric Andersend23f9ba1999-10-20 19:18:15 +0000116/* Returns kernel version encoded as major*65536 + minor*256 + patch,
117 * so, for example, to check if the kernel is greater than 2.2.11:
Erik Andersen298854f2000-03-23 01:09:18 +0000118 * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
Eric Andersend23f9ba1999-10-20 19:18:15 +0000119 */
Erik Andersen1ad302a2000-03-24 00:54:46 +0000120extern int get_kernel_revision(void)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000121{
Erik Andersend07ee462000-02-21 21:26:32 +0000122 struct utsname name;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123 int major = 0, minor = 0, patch = 0;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000124
Erik Andersend07ee462000-02-21 21:26:32 +0000125 if (uname(&name) == -1) {
126 perror("cannot get system information");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000127 return (0);
128 }
Erik Andersend07ee462000-02-21 21:26:32 +0000129 sscanf(name.version, "%d.%d.%d", &major, &minor, &patch);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000130 return major * 65536 + minor * 256 + patch;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000131}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000132#endif /* BB_INIT */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000133
Eric Andersen10dc9d42000-06-26 10:45:52 +0000134
135
136#if defined BB_FREE || defined BB_INIT || defined BB_UNAME || defined BB_UPTIME
137#include <sys/syscall.h>
138_syscall1(int, sysinfo, struct sysinfo *, info);
139#endif /* BB_INIT */
140
141
142
Erik Andersen23dea9b2000-05-13 00:28:25 +0000143#if defined (BB_CP_MV) || defined (BB_DU)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000144
Erik Andersen029011b2000-03-04 21:19:32 +0000145#define HASH_SIZE 311 /* Should be prime */
146#define hash_inode(i) ((i) % HASH_SIZE)
147
148static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE];
149
150/*
151 * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in
152 * `ino_dev_hashtable', else return 0
153 *
154 * If NAME is a non-NULL pointer to a character pointer, and there is
155 * a match, then set *NAME to the value of the name slot in that
156 * bucket.
157 */
158int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name)
159{
160 ino_dev_hashtable_bucket_t *bucket;
161
162 bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)];
163 while (bucket != NULL) {
164 if ((bucket->ino == statbuf->st_ino) &&
165 (bucket->dev == statbuf->st_dev))
166 {
167 if (name) *name = bucket->name;
168 return 1;
169 }
170 bucket = bucket->next;
171 }
172 return 0;
173}
174
175/* Add statbuf to statbuf hash table */
176void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name)
177{
178 int i;
179 size_t s;
180 ino_dev_hashtable_bucket_t *bucket;
181
182 i = hash_inode(statbuf->st_ino);
183 s = name ? strlen(name) : 0;
Erik Andersen0d068a22000-03-21 22:32:57 +0000184 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s);
Erik Andersen029011b2000-03-04 21:19:32 +0000185 bucket->ino = statbuf->st_ino;
186 bucket->dev = statbuf->st_dev;
187 if (name)
188 strcpy(bucket->name, name);
189 else
190 bucket->name[0] = '\0';
191 bucket->next = ino_dev_hashtable[i];
192 ino_dev_hashtable[i] = bucket;
193}
194
195/* Clear statbuf hash table */
196void reset_ino_dev_hashtable(void)
197{
198 int i;
199 ino_dev_hashtable_bucket_t *bucket;
200
201 for (i = 0; i < HASH_SIZE; i++) {
202 while (ino_dev_hashtable[i] != NULL) {
203 bucket = ino_dev_hashtable[i]->next;
204 free(ino_dev_hashtable[i]);
205 ino_dev_hashtable[i] = bucket;
206 }
207 }
208}
209
Erik Andersen23dea9b2000-05-13 00:28:25 +0000210#endif /* BB_CP_MV || BB_DU */
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000211
Erik Andersen23dea9b2000-05-13 00:28:25 +0000212#if defined (BB_CP_MV) || defined (BB_DU) || defined (BB_LN)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000213/*
214 * Return TRUE if a fileName is a directory.
215 * Nonexistant files return FALSE.
216 */
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000217int isDirectory(const char *fileName, const int followLinks, struct stat *statBuf)
Eric Andersencc8ed391999-10-05 16:24:54 +0000218{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000219 int status;
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000220 int didMalloc = 0;
221
222 if (statBuf == NULL) {
223 statBuf = (struct stat *)xmalloc(sizeof(struct stat));
224 ++didMalloc;
225 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000226
Erik Andersene49d5ec2000-02-08 19:58:47 +0000227 if (followLinks == TRUE)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000228 status = stat(fileName, statBuf);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000229 else
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000230 status = lstat(fileName, statBuf);
Erik Andersenfac10d72000-02-07 05:29:42 +0000231
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000232 if (status < 0 || !(S_ISDIR(statBuf->st_mode))) {
233 status = FALSE;
234 }
235 else status = TRUE;
236
237 if (didMalloc) {
238 free(statBuf);
239 statBuf = NULL;
240 }
241 return status;
Eric Andersencc8ed391999-10-05 16:24:54 +0000242}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000243#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000244
Erik Andersen23dea9b2000-05-13 00:28:25 +0000245#if defined (BB_CP_MV)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000246/*
Erik Andersen59b9e872000-05-10 05:05:45 +0000247 * Copy one file to another, while possibly preserving its modes, times, and
248 * modes. Returns TRUE if successful, or FALSE on a failure with an error
249 * message output. (Failure is not indicated if attributes cannot be set.)
250 * -Erik Andersen
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000251 */
252int
Erik Andersene49d5ec2000-02-08 19:58:47 +0000253copyFile(const char *srcName, const char *destName,
Erik Andersen59b9e872000-05-10 05:05:45 +0000254 int setModes, int followLinks, int forceFlag)
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000255{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000256 int rfd;
257 int wfd;
258 int rcc;
259 int status;
260 char buf[BUF_SIZE];
261 struct stat srcStatBuf;
262 struct stat dstStatBuf;
263 struct utimbuf times;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000264
Erik Andersene49d5ec2000-02-08 19:58:47 +0000265 if (followLinks == TRUE)
266 status = stat(srcName, &srcStatBuf);
267 else
268 status = lstat(srcName, &srcStatBuf);
Erik Andersenfac10d72000-02-07 05:29:42 +0000269
Erik Andersenfac10d72000-02-07 05:29:42 +0000270 if (status < 0) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000271 perror(srcName);
272 return FALSE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000273 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000274
275 if (followLinks == TRUE)
276 status = stat(destName, &dstStatBuf);
277 else
278 status = lstat(destName, &dstStatBuf);
279
Erik Andersen59b9e872000-05-10 05:05:45 +0000280 if (status < 0 || forceFlag==TRUE) {
281 unlink(destName);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000282 dstStatBuf.st_ino = -1;
283 dstStatBuf.st_dev = -1;
284 }
285
286 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
287 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
288 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
289 return FALSE;
290 }
291
292 if (S_ISDIR(srcStatBuf.st_mode)) {
293 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
294 /* Make sure the directory is writable */
295 status = mkdir(destName, 0777777 ^ umask(0));
296 if (status < 0 && errno != EEXIST) {
297 perror(destName);
298 return FALSE;
299 }
300 } else if (S_ISLNK(srcStatBuf.st_mode)) {
Erik Andersen4f3f7572000-04-28 00:18:56 +0000301 char link_val[BUFSIZ + 1];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000302 int link_size;
303
304 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
Erik Andersen4f3f7572000-04-28 00:18:56 +0000305 /* Warning: This could possibly truncate silently, to BUFSIZ chars */
306 link_size = readlink(srcName, &link_val[0], BUFSIZ);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000307 if (link_size < 0) {
308 perror(srcName);
309 return FALSE;
310 }
311 link_val[link_size] = '\0';
312 status = symlink(link_val, destName);
313 if (status < 0) {
314 perror(destName);
315 return FALSE;
316 }
Erik Andersen8e759aa2000-01-29 05:52:40 +0000317#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000318 if (setModes == TRUE) {
Erik Andersen59b9e872000-05-10 05:05:45 +0000319 /* Try to set owner, but fail silently like GNU cp */
320 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000321 }
Erik Andersen8e759aa2000-01-29 05:52:40 +0000322#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000323 return TRUE;
324 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
325 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
326 if (mkfifo(destName, 0644) < 0) {
327 perror(destName);
328 return FALSE;
329 }
330 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
331 || S_ISSOCK(srcStatBuf.st_mode)) {
332 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
333 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
334 perror(destName);
335 return FALSE;
336 }
337 } else if (S_ISREG(srcStatBuf.st_mode)) {
338 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
339 rfd = open(srcName, O_RDONLY);
340 if (rfd < 0) {
341 perror(srcName);
342 return FALSE;
343 }
344
345 wfd =
346 open(destName, O_WRONLY | O_CREAT | O_TRUNC,
347 srcStatBuf.st_mode);
348 if (wfd < 0) {
349 perror(destName);
350 close(rfd);
351 return FALSE;
352 }
353
354 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
355 if (fullWrite(wfd, buf, rcc) < 0)
356 goto error_exit;
357 }
358 if (rcc < 0) {
359 goto error_exit;
360 }
361
362 close(rfd);
363 if (close(wfd) < 0) {
364 return FALSE;
365 }
366 }
367
368 if (setModes == TRUE) {
369 /* This is fine, since symlinks never get here */
370 if (chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) {
371 perror(destName);
372 exit FALSE;
373 }
374 if (chmod(destName, srcStatBuf.st_mode) < 0) {
375 perror(destName);
376 exit FALSE;
377 }
378 times.actime = srcStatBuf.st_atime;
379 times.modtime = srcStatBuf.st_mtime;
380 if (utime(destName, &times) < 0) {
381 perror(destName);
382 exit FALSE;
383 }
384 }
385
Erik Andersenfac10d72000-02-07 05:29:42 +0000386 return TRUE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000387
Erik Andersene49d5ec2000-02-08 19:58:47 +0000388 error_exit:
389 perror(destName);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000390 close(rfd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000391 close(wfd);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000392
Erik Andersene49d5ec2000-02-08 19:58:47 +0000393 return FALSE;
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000394}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000395#endif /* BB_CP_MV */
Eric Andersencc8ed391999-10-05 16:24:54 +0000396
397
398
Erik Andersen23dea9b2000-05-13 00:28:25 +0000399#if defined BB_TAR || defined BB_LS
400
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000401#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
402#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
403
404/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */
405static const mode_t SBIT[] = {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000406 0, 0, S_ISUID,
407 0, 0, S_ISGID,
408 0, 0, S_ISVTX
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000409};
410
411/* The 9 mode bits to test */
412static const mode_t MBIT[] = {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000413 S_IRUSR, S_IWUSR, S_IXUSR,
414 S_IRGRP, S_IWGRP, S_IXGRP,
415 S_IROTH, S_IWOTH, S_IXOTH
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000416};
417
418#define MODE1 "rwxrwxrwx"
419#define MODE0 "---------"
420#define SMODE1 "..s..s..t"
421#define SMODE0 "..S..S..T"
422
Eric Andersencc8ed391999-10-05 16:24:54 +0000423/*
424 * Return the standard ls-like mode string from a file mode.
425 * This is static and so is overwritten on each call.
426 */
Eric Andersenf811e071999-10-09 00:25:00 +0000427const char *modeString(int mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000428{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000429 static char buf[12];
Eric Andersencc8ed391999-10-05 16:24:54 +0000430
Erik Andersene49d5ec2000-02-08 19:58:47 +0000431 int i;
432
433 buf[0] = TYPECHAR(mode);
434 for (i = 0; i < 9; i++) {
435 if (mode & SBIT[i])
436 buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i];
437 else
438 buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i];
439 }
440 return buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000441}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000442#endif /* BB_TAR || BB_LS */
Eric Andersencc8ed391999-10-05 16:24:54 +0000443
444
Erik Andersen23dea9b2000-05-13 00:28:25 +0000445#if defined BB_TAR
Eric Andersencc8ed391999-10-05 16:24:54 +0000446/*
Eric Andersen3d8dbe11999-11-09 01:51:02 +0000447 * Return the standard ls-like time string from a time_t
448 * This is static and so is overwritten on each call.
Eric Andersen17d49ef1999-10-06 20:25:32 +0000449 */
Eric Andersenf811e071999-10-09 00:25:00 +0000450const char *timeString(time_t timeVal)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000451{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000452 time_t now;
453 char *str;
454 static char buf[26];
Eric Andersen17d49ef1999-10-06 20:25:32 +0000455
Erik Andersene49d5ec2000-02-08 19:58:47 +0000456 time(&now);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000457
Erik Andersene49d5ec2000-02-08 19:58:47 +0000458 str = ctime(&timeVal);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000459
Erik Andersene49d5ec2000-02-08 19:58:47 +0000460 strcpy(buf, &str[4]);
461 buf[12] = '\0';
Eric Andersen17d49ef1999-10-06 20:25:32 +0000462
Erik Andersene49d5ec2000-02-08 19:58:47 +0000463 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
464 strcpy(&buf[7], &str[20]);
465 buf[11] = '\0';
466 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000467
Erik Andersene49d5ec2000-02-08 19:58:47 +0000468 return buf;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000469}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000470#endif /* BB_TAR */
Eric Andersen17d49ef1999-10-06 20:25:32 +0000471
Erik Andersen23dea9b2000-05-13 00:28:25 +0000472#if defined BB_TAR || defined BB_CP_MV
Eric Andersen17d49ef1999-10-06 20:25:32 +0000473/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000474 * Write all of the supplied buffer out to a file.
475 * This does multiple writes as necessary.
476 * Returns the amount written, or -1 on an error.
477 */
Eric Andersenf811e071999-10-09 00:25:00 +0000478int fullWrite(int fd, const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000479{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000480 int cc;
481 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000482
Erik Andersene49d5ec2000-02-08 19:58:47 +0000483 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000484
Erik Andersene49d5ec2000-02-08 19:58:47 +0000485 while (len > 0) {
486 cc = write(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000487
Erik Andersene49d5ec2000-02-08 19:58:47 +0000488 if (cc < 0)
489 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000490
Erik Andersene49d5ec2000-02-08 19:58:47 +0000491 buf += cc;
492 total += cc;
493 len -= cc;
494 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000495
Erik Andersene49d5ec2000-02-08 19:58:47 +0000496 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000497}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000498#endif /* BB_TAR || BB_CP_MV */
Eric Andersencc8ed391999-10-05 16:24:54 +0000499
500
Erik Andersen23dea9b2000-05-13 00:28:25 +0000501#if defined BB_TAR || defined BB_TAIL
Eric Andersencc8ed391999-10-05 16:24:54 +0000502/*
503 * Read all of the supplied buffer from a file.
504 * This does multiple reads as necessary.
505 * Returns the amount read, or -1 on an error.
506 * A short read is returned on an end of file.
507 */
Eric Andersenf811e071999-10-09 00:25:00 +0000508int fullRead(int fd, char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000509{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000510 int cc;
511 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000512
Erik Andersene49d5ec2000-02-08 19:58:47 +0000513 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000514
Erik Andersene49d5ec2000-02-08 19:58:47 +0000515 while (len > 0) {
516 cc = read(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000517
Erik Andersene49d5ec2000-02-08 19:58:47 +0000518 if (cc < 0)
519 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000520
Erik Andersene49d5ec2000-02-08 19:58:47 +0000521 if (cc == 0)
522 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000523
Erik Andersene49d5ec2000-02-08 19:58:47 +0000524 buf += cc;
525 total += cc;
526 len -= cc;
527 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000528
Erik Andersene49d5ec2000-02-08 19:58:47 +0000529 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000530}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000531#endif /* BB_TAR || BB_TAIL */
Eric Andersencc8ed391999-10-05 16:24:54 +0000532
533
Erik Andersen23dea9b2000-05-13 00:28:25 +0000534#if defined (BB_CHMOD_CHOWN_CHGRP) \
535 || defined (BB_CP_MV) \
536 || defined (BB_FIND) \
537 || defined (BB_INSMOD) \
538 || defined (BB_RM) \
539 || defined (BB_TAR)
540
Eric Andersencc8ed391999-10-05 16:24:54 +0000541/*
Eric Andersen2b69c401999-10-05 22:58:32 +0000542 * Walk down all the directories under the specified
543 * location, and do something (something specified
544 * by the fileAction and dirAction function pointers).
Eric Andersenb7a1a751999-10-19 23:37:14 +0000545 *
Eric Andersen63a0e531999-10-22 05:12:14 +0000546 * Unfortunatly, while nftw(3) could replace this and reduce
547 * code size a bit, nftw() wasn't supported before GNU libc 2.1,
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000548 * and so isn't sufficiently portable to take over since glibc2.1
549 * is so stinking huge.
Eric Andersencc8ed391999-10-05 16:24:54 +0000550 */
Erik Andersenfac10d72000-02-07 05:29:42 +0000551int recursiveAction(const char *fileName,
Erik Andersene49d5ec2000-02-08 19:58:47 +0000552 int recurse, int followLinks, int depthFirst,
553 int (*fileAction) (const char *fileName,
Erik Andersen3364d782000-03-28 00:58:14 +0000554 struct stat * statbuf,
555 void* userData),
Erik Andersene49d5ec2000-02-08 19:58:47 +0000556 int (*dirAction) (const char *fileName,
Erik Andersen3364d782000-03-28 00:58:14 +0000557 struct stat * statbuf,
558 void* userData),
559 void* userData)
Eric Andersencc8ed391999-10-05 16:24:54 +0000560{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000561 int status;
562 struct stat statbuf;
563 struct dirent *next;
Eric Andersen9d3aba71999-10-06 09:04:55 +0000564
Erik Andersene49d5ec2000-02-08 19:58:47 +0000565 if (followLinks == TRUE)
566 status = stat(fileName, &statbuf);
Eric Andersen50d63601999-11-09 01:47:36 +0000567 else
Erik Andersene49d5ec2000-02-08 19:58:47 +0000568 status = lstat(fileName, &statbuf);
Eric Andersencf8c9cf1999-11-05 00:31:46 +0000569
Eric Andersen2b69c401999-10-05 22:58:32 +0000570 if (status < 0) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000571#ifdef BB_DEBUG_PRINT_SCAFFOLD
572 fprintf(stderr,
573 "status=%d followLinks=%d TRUE=%d\n",
574 status, followLinks, TRUE);
575#endif
Eric Andersenbed30e91999-10-18 19:02:32 +0000576 perror(fileName);
Erik Andersenfac10d72000-02-07 05:29:42 +0000577 return FALSE;
Eric Andersenbed30e91999-10-18 19:02:32 +0000578 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000579
580 if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) {
581 if (fileAction == NULL)
582 return TRUE;
583 else
Erik Andersen3364d782000-03-28 00:58:14 +0000584 return fileAction(fileName, &statbuf, userData);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000585 }
586
587 if (recurse == FALSE) {
588 if (S_ISDIR(statbuf.st_mode)) {
589 if (dirAction != NULL)
Erik Andersen3364d782000-03-28 00:58:14 +0000590 return (dirAction(fileName, &statbuf, userData));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000591 else
592 return TRUE;
593 }
594 }
595
596 if (S_ISDIR(statbuf.st_mode)) {
597 DIR *dir;
598
599 dir = opendir(fileName);
600 if (!dir) {
601 perror(fileName);
602 return FALSE;
603 }
604 if (dirAction != NULL && depthFirst == FALSE) {
Erik Andersen3364d782000-03-28 00:58:14 +0000605 status = dirAction(fileName, &statbuf, userData);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000606 if (status == FALSE) {
607 perror(fileName);
608 return FALSE;
609 }
610 }
611 while ((next = readdir(dir)) != NULL) {
Erik Andersen4f3f7572000-04-28 00:18:56 +0000612 char nextFile[BUFSIZ + 1];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000613
614 if ((strcmp(next->d_name, "..") == 0)
615 || (strcmp(next->d_name, ".") == 0)) {
616 continue;
617 }
Erik Andersen4f3f7572000-04-28 00:18:56 +0000618 if (strlen(fileName) + strlen(next->d_name) + 1 > BUFSIZ) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000619 fprintf(stderr, name_too_long, "ftw");
620 return FALSE;
621 }
Erik Andersenc3660502000-04-18 21:18:57 +0000622 memset(nextFile, 0, sizeof(nextFile));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000623 sprintf(nextFile, "%s/%s", fileName, next->d_name);
624 status =
625 recursiveAction(nextFile, TRUE, followLinks, depthFirst,
Erik Andersen3364d782000-03-28 00:58:14 +0000626 fileAction, dirAction, userData);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000627 if (status < 0) {
628 closedir(dir);
629 return FALSE;
630 }
631 }
632 status = closedir(dir);
633 if (status < 0) {
634 perror(fileName);
635 return FALSE;
636 }
637 if (dirAction != NULL && depthFirst == TRUE) {
Erik Andersen3364d782000-03-28 00:58:14 +0000638 status = dirAction(fileName, &statbuf, userData);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000639 if (status == FALSE) {
640 perror(fileName);
641 return FALSE;
642 }
643 }
644 } else {
645 if (fileAction == NULL)
646 return TRUE;
647 else
Erik Andersen3364d782000-03-28 00:58:14 +0000648 return fileAction(fileName, &statbuf, userData);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000649 }
650 return TRUE;
Eric Andersencc8ed391999-10-05 16:24:54 +0000651}
652
Erik Andersen23dea9b2000-05-13 00:28:25 +0000653#endif /* BB_CHMOD_CHOWN_CHGRP || BB_CP_MV || BB_FIND || BB_LS || BB_INSMOD */
Eric Andersencc8ed391999-10-05 16:24:54 +0000654
Eric Andersenf6be9441999-10-13 21:12:06 +0000655
656
Erik Andersen23dea9b2000-05-13 00:28:25 +0000657#if defined (BB_TAR) || defined (BB_MKDIR)
Eric Andersenf6be9441999-10-13 21:12:06 +0000658/*
659 * Attempt to create the directories along the specified path, except for
660 * the final component. The mode is given for the final directory only,
661 * while all previous ones get default protections. Errors are not reported
662 * here, as failures to restore files can be reported later.
663 */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000664extern int createPath(const char *name, int mode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000665{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000666 char *cp;
667 char *cpOld;
Erik Andersen4f3f7572000-04-28 00:18:56 +0000668 char buf[BUFSIZ + 1];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000669 int retVal = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000670
Erik Andersene49d5ec2000-02-08 19:58:47 +0000671 strcpy(buf, name);
672 for (cp = buf; *cp == '/'; cp++);
673 cp = strchr(cp, '/');
674 while (cp) {
675 cpOld = cp;
676 cp = strchr(cp + 1, '/');
677 *cpOld = '\0';
678 retVal = mkdir(buf, cp ? 0777 : mode);
679 if (retVal != 0 && errno != EEXIST) {
680 perror(buf);
681 return FALSE;
682 }
683 *cpOld = '/';
Erik Andersen06936df2000-01-23 02:14:20 +0000684 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000685 return TRUE;
Eric Andersenf6be9441999-10-13 21:12:06 +0000686}
Erik Andersen23dea9b2000-05-13 00:28:25 +0000687#endif /* BB_TAR || BB_MKDIR */
Eric Andersenf6be9441999-10-13 21:12:06 +0000688
689
690
Erik Andersen23dea9b2000-05-13 00:28:25 +0000691#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
Eric Andersence8f3b91999-10-20 07:03:36 +0000692/* [ugoa]{+|-|=}[rwxst] */
Erik Andersen23dea9b2000-05-13 00:28:25 +0000693
694
695
Erik Andersene49d5ec2000-02-08 19:58:47 +0000696extern int parse_mode(const char *s, mode_t * theMode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000697{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000698 mode_t andMode =
699
700 S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersence8f3b91999-10-20 07:03:36 +0000701 mode_t orMode = 0;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000702 mode_t mode = 0;
703 mode_t groups = 0;
704 char type;
705 char c;
Eric Andersenf6be9441999-10-13 21:12:06 +0000706
707 do {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000708 for (;;) {
709 switch (c = *s++) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000710 case '\0':
Eric Andersence8f3b91999-10-20 07:03:36 +0000711 return -1;
Eric Andersenf6be9441999-10-13 21:12:06 +0000712 case 'u':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000713 groups |= S_ISUID | S_IRWXU;
Eric Andersenf6be9441999-10-13 21:12:06 +0000714 continue;
715 case 'g':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000716 groups |= S_ISGID | S_IRWXG;
Eric Andersenf6be9441999-10-13 21:12:06 +0000717 continue;
718 case 'o':
719 groups |= S_IRWXO;
720 continue;
721 case 'a':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000722 groups |= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersenf6be9441999-10-13 21:12:06 +0000723 continue;
724 case '+':
725 case '=':
726 case '-':
727 type = c;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000728 if (groups == 0) /* The default is "all" */
729 groups |=
730 S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
Eric Andersenf6be9441999-10-13 21:12:06 +0000731 break;
732 default:
Erik Andersene49d5ec2000-02-08 19:58:47 +0000733 if (isdigit(c) && c >= '0' && c <= '7' &&
734 mode == 0 && groups == 0) {
Eric Andersenfa0540f1999-10-22 18:18:31 +0000735 *theMode = strtol(--s, NULL, 8);
Eric Andersenf6be9441999-10-13 21:12:06 +0000736 return (TRUE);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000737 } else
Eric Andersenf6be9441999-10-13 21:12:06 +0000738 return (FALSE);
739 }
740 break;
741 }
742
Erik Andersene49d5ec2000-02-08 19:58:47 +0000743 while ((c = *s++) != '\0') {
744 switch (c) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000745 case ',':
746 break;
747 case 'r':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000748 mode |= S_IRUSR | S_IRGRP | S_IROTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000749 continue;
750 case 'w':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000751 mode |= S_IWUSR | S_IWGRP | S_IWOTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000752 continue;
753 case 'x':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000754 mode |= S_IXUSR | S_IXGRP | S_IXOTH;
Eric Andersenf6be9441999-10-13 21:12:06 +0000755 continue;
756 case 's':
Erik Andersene49d5ec2000-02-08 19:58:47 +0000757 mode |= S_IXGRP | S_ISUID | S_ISGID;
Eric Andersenf6be9441999-10-13 21:12:06 +0000758 continue;
759 case 't':
Eric Andersence8f3b91999-10-20 07:03:36 +0000760 mode |= 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000761 continue;
762 default:
Eric Andersence8f3b91999-10-20 07:03:36 +0000763 *theMode &= andMode;
764 *theMode |= orMode;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000765 return (TRUE);
Eric Andersenf6be9441999-10-13 21:12:06 +0000766 }
767 break;
768 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000769 switch (type) {
Eric Andersenf6be9441999-10-13 21:12:06 +0000770 case '=':
Eric Andersence8f3b91999-10-20 07:03:36 +0000771 andMode &= ~(groups);
Eric Andersenf6be9441999-10-13 21:12:06 +0000772 /* fall through */
773 case '+':
Eric Andersence8f3b91999-10-20 07:03:36 +0000774 orMode |= mode & groups;
Eric Andersenf6be9441999-10-13 21:12:06 +0000775 break;
776 case '-':
Eric Andersence8f3b91999-10-20 07:03:36 +0000777 andMode &= ~(mode & groups);
778 orMode &= andMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000779 break;
780 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000781 } while (c == ',');
Eric Andersence8f3b91999-10-20 07:03:36 +0000782 *theMode &= andMode;
783 *theMode |= orMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000784 return (TRUE);
785}
Eric Andersence8f3b91999-10-20 07:03:36 +0000786
787
Erik Andersen23dea9b2000-05-13 00:28:25 +0000788#endif /* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR */
Eric Andersenf6be9441999-10-13 21:12:06 +0000789
Eric Andersene674eb71999-10-19 20:52:57 +0000790
791
Erik Andersen23dea9b2000-05-13 00:28:25 +0000792
793
794#if defined BB_CHMOD_CHOWN_CHGRP || defined BB_PS || defined BB_LS || defined BB_TAR || defined BB_ID
795
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000796/* This parses entries in /etc/passwd and /etc/group. This is desirable
797 * for BusyBox, since we want to avoid using the glibc NSS stuff, which
798 * increases target size and is often not needed or wanted for embedded
799 * systems.
800 *
801 * /etc/passwd entries look like this:
802 * root:x:0:0:root:/root:/bin/bash
803 * and /etc/group entries look like this:
804 * root:x:0:
805 *
806 * This uses buf as storage to hold things.
807 *
808 */
Erik Andersen5b46d792000-05-17 05:24:24 +0000809unsigned long my_getid(const char *filename, char *name, unsigned long id, unsigned long *gid)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000810{
Eric Andersenaa0765e1999-10-22 04:30:20 +0000811 FILE *file;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000812 char *rname, *start, *end, buf[128];
Erik Andersen330fd2b2000-05-19 05:35:19 +0000813 unsigned long rid;
Erik Andersen5b46d792000-05-17 05:24:24 +0000814 unsigned long rgid = 0;
Eric Andersend23f9ba1999-10-20 19:18:15 +0000815
Erik Andersene49d5ec2000-02-08 19:58:47 +0000816 file = fopen(filename, "r");
Eric Andersenaa0765e1999-10-22 04:30:20 +0000817 if (file == NULL) {
Eric Andersen3199bda2000-06-02 17:38:18 +0000818 /* Do not complain. It is ok for /etc/passwd and
Erik Andersen330fd2b2000-05-19 05:35:19 +0000819 * friends to be missing... */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000820 return (-1);
Eric Andersenaa0765e1999-10-22 04:30:20 +0000821 }
Eric Andersend23f9ba1999-10-20 19:18:15 +0000822
Erik Andersene49d5ec2000-02-08 19:58:47 +0000823 while (fgets(buf, 128, file) != NULL) {
Eric Andersend23f9ba1999-10-20 19:18:15 +0000824 if (buf[0] == '#')
825 continue;
826
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000827 /* username/group name */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000828 start = buf;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000829 end = strchr(start, ':');
Eric Andersend23f9ba1999-10-20 19:18:15 +0000830 if (end == NULL)
831 continue;
832 *end = '\0';
833 rname = start;
834
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000835 /* password */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000836 start = end + 1;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000837 end = strchr(start, ':');
Eric Andersend23f9ba1999-10-20 19:18:15 +0000838 if (end == NULL)
839 continue;
840
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000841 /* uid in passwd, gid in group */
Eric Andersend23f9ba1999-10-20 19:18:15 +0000842 start = end + 1;
Erik Andersen5b46d792000-05-17 05:24:24 +0000843 rid = (unsigned long) strtol(start, &end, 10);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000844 if (end == start)
845 continue;
846
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000847 /* gid in passwd */
848 start = end + 1;
Erik Andersen5b46d792000-05-17 05:24:24 +0000849 rgid = (unsigned long) strtol(start, &end, 10);
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000850
Eric Andersend23f9ba1999-10-20 19:18:15 +0000851 if (name) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000852 if (0 == strcmp(rname, name)) {
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000853 if (gid) *gid = rgid;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000854 fclose(file);
855 return (rid);
856 }
857 }
858 if (id != -1 && id == rid) {
859 strncpy(name, rname, 8);
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000860 if (gid) *gid = rgid;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000861 fclose(file);
862 return (TRUE);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000863 }
864 }
Eric Andersenaa0765e1999-10-22 04:30:20 +0000865 fclose(file);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000866 return (-1);
867}
868
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000869/* returns a uid given a username */
Erik Andersen5b46d792000-05-17 05:24:24 +0000870unsigned long my_getpwnam(char *name)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000871{
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000872 return my_getid("/etc/passwd", name, -1, NULL);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000873}
874
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000875/* returns a gid given a group name */
Erik Andersen5b46d792000-05-17 05:24:24 +0000876unsigned long my_getgrnam(char *name)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000877{
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000878 return my_getid("/etc/group", name, -1, NULL);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000879}
880
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000881/* gets a username given a uid */
Erik Andersen5b46d792000-05-17 05:24:24 +0000882void my_getpwuid(char *name, unsigned long uid)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000883{
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000884 my_getid("/etc/passwd", name, uid, NULL);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000885}
886
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000887/* gets a groupname given a gid */
Erik Andersen5b46d792000-05-17 05:24:24 +0000888void my_getgrgid(char *group, unsigned long gid)
Eric Andersend23f9ba1999-10-20 19:18:15 +0000889{
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000890 my_getid("/etc/group", group, gid, NULL);
Eric Andersend23f9ba1999-10-20 19:18:15 +0000891}
892
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000893/* gets a gid given a user name */
Erik Andersen5b46d792000-05-17 05:24:24 +0000894unsigned long my_getpwnamegid(char *name)
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000895{
Erik Andersen5b46d792000-05-17 05:24:24 +0000896 unsigned long gid;
Erik Andersen94f5e0b2000-05-01 19:10:52 +0000897 my_getid("/etc/passwd", name, -1, &gid);
898 return gid;
899}
Eric Andersend23f9ba1999-10-20 19:18:15 +0000900
Erik Andersen23dea9b2000-05-13 00:28:25 +0000901#endif /* BB_CHMOD_CHOWN_CHGRP || BB_PS || BB_LS || BB_TAR || BB_ID */
902
903
904#if (defined BB_CHVT) || (defined BB_DEALLOCVT)
Eric Andersen0460ff21999-10-25 23:32:44 +0000905
906
907#include <linux/kd.h>
908#include <sys/ioctl.h>
909
Erik Andersene49d5ec2000-02-08 19:58:47 +0000910int is_a_console(int fd)
Eric Andersen0460ff21999-10-25 23:32:44 +0000911{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000912 char arg;
913
914 arg = 0;
915 return (ioctl(fd, KDGKBTYPE, &arg) == 0
916 && ((arg == KB_101) || (arg == KB_84)));
Eric Andersen0460ff21999-10-25 23:32:44 +0000917}
918
Erik Andersene49d5ec2000-02-08 19:58:47 +0000919static int open_a_console(char *fnam)
Eric Andersen0460ff21999-10-25 23:32:44 +0000920{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000921 int fd;
922
923 /* try read-only */
924 fd = open(fnam, O_RDWR);
925
926 /* if failed, try read-only */
927 if (fd < 0 && errno == EACCES)
928 fd = open(fnam, O_RDONLY);
929
930 /* if failed, try write-only */
931 if (fd < 0 && errno == EACCES)
932 fd = open(fnam, O_WRONLY);
933
934 /* if failed, fail */
935 if (fd < 0)
936 return -1;
937
938 /* if not a console, fail */
939 if (!is_a_console(fd)) {
940 close(fd);
941 return -1;
942 }
943
944 /* success */
945 return fd;
Eric Andersen0460ff21999-10-25 23:32:44 +0000946}
947
948/*
949 * Get an fd for use with kbd/console ioctls.
950 * We try several things because opening /dev/console will fail
951 * if someone else used X (which does a chown on /dev/console).
952 *
953 * if tty_name is non-NULL, try this one instead.
954 */
955
Erik Andersene49d5ec2000-02-08 19:58:47 +0000956int get_console_fd(char *tty_name)
Eric Andersen0460ff21999-10-25 23:32:44 +0000957{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000958 int fd;
Eric Andersen0460ff21999-10-25 23:32:44 +0000959
Erik Andersene49d5ec2000-02-08 19:58:47 +0000960 if (tty_name) {
961 if (-1 == (fd = open_a_console(tty_name)))
962 return -1;
963 else
964 return fd;
965 }
966
967 fd = open_a_console("/dev/tty");
968 if (fd >= 0)
969 return fd;
970
971 fd = open_a_console("/dev/tty0");
972 if (fd >= 0)
973 return fd;
974
975 fd = open_a_console("/dev/console");
976 if (fd >= 0)
977 return fd;
978
979 for (fd = 0; fd < 3; fd++)
980 if (is_a_console(fd))
981 return fd;
982
983 fprintf(stderr,
984 "Couldnt get a file descriptor referring to the console\n");
985 return -1; /* total failure */
Eric Andersen0460ff21999-10-25 23:32:44 +0000986}
987
988
Erik Andersen23dea9b2000-05-13 00:28:25 +0000989#endif /* BB_CHVT || BB_DEALLOCVT */
Eric Andersen0460ff21999-10-25 23:32:44 +0000990
991
Erik Andersen23dea9b2000-05-13 00:28:25 +0000992#if !defined BB_REGEXP && (defined BB_GREP || defined BB_SED)
993
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000994/* Do a case insensitive strstr() */
Erik Andersene49d5ec2000-02-08 19:58:47 +0000995char *stristr(char *haystack, const char *needle)
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000996{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000997 int len = strlen(needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +0000998
Erik Andersene49d5ec2000-02-08 19:58:47 +0000999 while (*haystack) {
1000 if (!strncasecmp(haystack, needle, len))
1001 break;
1002 haystack++;
1003 }
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001004
Erik Andersene49d5ec2000-02-08 19:58:47 +00001005 if (!(*haystack))
1006 haystack = NULL;
1007
1008 return haystack;
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001009}
1010
Eric Andersenc1525e81999-10-29 00:07:31 +00001011/* This tries to find a needle in a haystack, but does so by
1012 * only trying to match literal strings (look 'ma, no regexps!)
1013 * This is short, sweet, and carries _very_ little baggage,
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001014 * unlike its beefier cousin in regexp.c
Eric Andersenc1525e81999-10-29 00:07:31 +00001015 * -Erik Andersen
1016 */
1017extern int find_match(char *haystack, char *needle, int ignoreCase)
1018{
1019
Erik Andersene49d5ec2000-02-08 19:58:47 +00001020 if (ignoreCase == FALSE)
1021 haystack = strstr(haystack, needle);
1022 else
1023 haystack = stristr(haystack, needle);
1024 if (haystack == NULL)
1025 return FALSE;
1026 return TRUE;
Eric Andersenc1525e81999-10-29 00:07:31 +00001027}
1028
1029
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001030/* This performs substitutions after a string match has been found. */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001031extern int replace_match(char *haystack, char *needle, char *newNeedle,
1032 int ignoreCase)
Eric Andersenc1525e81999-10-29 00:07:31 +00001033{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001034 int foundOne = 0;
1035 char *where, *slider, *slider1, *oldhayStack;
Eric Andersenc1525e81999-10-29 00:07:31 +00001036
Erik Andersene49d5ec2000-02-08 19:58:47 +00001037 if (ignoreCase == FALSE)
1038 where = strstr(haystack, needle);
1039 else
1040 where = stristr(haystack, needle);
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001041
Erik Andersene49d5ec2000-02-08 19:58:47 +00001042 if (strcmp(needle, newNeedle) == 0)
1043 return FALSE;
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001044
Erik Andersen0d068a22000-03-21 22:32:57 +00001045 oldhayStack = (char *) xmalloc((unsigned) (strlen(haystack)));
Erik Andersene49d5ec2000-02-08 19:58:47 +00001046 while (where != NULL) {
1047 foundOne++;
1048 strcpy(oldhayStack, haystack);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001049 for (slider = haystack, slider1 = oldhayStack; slider != where;
1050 slider++, slider1++);
1051 *slider = 0;
1052 haystack = strcat(haystack, newNeedle);
1053 slider1 += strlen(needle);
1054 haystack = strcat(haystack, slider1);
1055 where = strstr(slider, needle);
1056 }
1057 free(oldhayStack);
Eric Andersen24d8e7d1999-10-29 06:50:17 +00001058
Erik Andersene49d5ec2000-02-08 19:58:47 +00001059 if (foundOne > 0)
1060 return TRUE;
1061 else
1062 return FALSE;
Eric Andersenc1525e81999-10-29 00:07:31 +00001063}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001064
1065#endif /* ! BB_REGEXP && (BB_GREP || BB_SED) */
Eric Andersen29d2e361999-11-06 06:07:27 +00001066
1067
Eric Andersen9f16d612000-06-12 23:11:16 +00001068#if defined BB_FIND || defined BB_INSMOD
Eric Andersenb186d981999-12-03 09:19:54 +00001069/*
1070 * Routine to see if a text string is matched by a wildcard pattern.
1071 * Returns TRUE if the text is matched, or FALSE if it is not matched
1072 * or if the pattern is invalid.
1073 * * matches zero or more characters
1074 * ? matches a single character
1075 * [abc] matches 'a', 'b' or 'c'
1076 * \c quotes character c
1077 * Adapted from code written by Ingo Wilken, and
1078 * then taken from sash, Copyright (c) 1999 by David I. Bell
1079 * Permission is granted to use, distribute, or modify this source,
1080 * provided that this copyright notice remains intact.
1081 * Permission to distribute this code under the GPL has been granted.
1082 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001083extern int check_wildcard_match(const char *text, const char *pattern)
Eric Andersenb186d981999-12-03 09:19:54 +00001084{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001085 const char *retryPat;
1086 const char *retryText;
1087 int ch;
1088 int found;
Erik Andersen632bb572000-04-18 22:09:06 +00001089 int len;
Eric Andersenb186d981999-12-03 09:19:54 +00001090
Erik Andersene49d5ec2000-02-08 19:58:47 +00001091 retryPat = NULL;
1092 retryText = NULL;
Eric Andersenb186d981999-12-03 09:19:54 +00001093
Erik Andersene49d5ec2000-02-08 19:58:47 +00001094 while (*text || *pattern) {
Eric Andersenb186d981999-12-03 09:19:54 +00001095 ch = *pattern++;
1096
Erik Andersene49d5ec2000-02-08 19:58:47 +00001097 switch (ch) {
1098 case '*':
1099 retryPat = pattern;
1100 retryText = text;
1101 break;
1102
1103 case '[':
1104 found = FALSE;
1105
1106 while ((ch = *pattern++) != ']') {
1107 if (ch == '\\')
1108 ch = *pattern++;
1109
1110 if (ch == '\0')
1111 return FALSE;
1112
1113 if (*text == ch)
1114 found = TRUE;
1115 }
Erik Andersen632bb572000-04-18 22:09:06 +00001116 len=strlen(text);
1117 if (found == FALSE && len!=0) {
1118 return FALSE;
1119 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001120 if (found == TRUE) {
Erik Andersen632bb572000-04-18 22:09:06 +00001121 if (strlen(pattern)==0 && len==1) {
1122 return TRUE;
1123 }
1124 if (len!=0) {
1125 text++;
1126 continue;
Erik Andersenc3660502000-04-18 21:18:57 +00001127 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001128 }
1129
1130 /* fall into next case */
1131
1132 case '?':
1133 if (*text++ == '\0')
1134 return FALSE;
1135
1136 break;
1137
1138 case '\\':
1139 ch = *pattern++;
1140
1141 if (ch == '\0')
1142 return FALSE;
1143
1144 /* fall into next case */
1145
1146 default:
1147 if (*text == ch) {
1148 if (*text)
1149 text++;
1150 break;
1151 }
1152
1153 if (*text) {
1154 pattern = retryPat;
1155 text = ++retryText;
1156 break;
1157 }
1158
Eric Andersenb186d981999-12-03 09:19:54 +00001159 return FALSE;
Eric Andersenb186d981999-12-03 09:19:54 +00001160 }
1161
Erik Andersene49d5ec2000-02-08 19:58:47 +00001162 if (pattern == NULL)
1163 return FALSE;
Eric Andersenb186d981999-12-03 09:19:54 +00001164 }
1165
Erik Andersene49d5ec2000-02-08 19:58:47 +00001166 return TRUE;
Eric Andersenb186d981999-12-03 09:19:54 +00001167}
Eric Andersen9f16d612000-06-12 23:11:16 +00001168#endif /* BB_FIND || BB_INSMOD */
Eric Andersenb186d981999-12-03 09:19:54 +00001169
1170
Eric Andersen29d2e361999-11-06 06:07:27 +00001171
1172
Erik Andersen23dea9b2000-05-13 00:28:25 +00001173#if defined BB_DF || defined BB_MTAB
Eric Andersen29d2e361999-11-06 06:07:27 +00001174/*
1175 * Given a block device, find the mount table entry if that block device
1176 * is mounted.
1177 *
1178 * Given any other file (or directory), find the mount table entry for its
1179 * filesystem.
1180 */
1181extern struct mntent *findMountPoint(const char *name, const char *table)
1182{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001183 struct stat s;
1184 dev_t mountDevice;
1185 FILE *mountTable;
1186 struct mntent *mountEntry;
Eric Andersen29d2e361999-11-06 06:07:27 +00001187
Erik Andersene49d5ec2000-02-08 19:58:47 +00001188 if (stat(name, &s) != 0)
1189 return 0;
Eric Andersen29d2e361999-11-06 06:07:27 +00001190
Erik Andersene49d5ec2000-02-08 19:58:47 +00001191 if ((s.st_mode & S_IFMT) == S_IFBLK)
1192 mountDevice = s.st_rdev;
1193 else
1194 mountDevice = s.st_dev;
Eric Andersen29d2e361999-11-06 06:07:27 +00001195
1196
Erik Andersene49d5ec2000-02-08 19:58:47 +00001197 if ((mountTable = setmntent(table, "r")) == 0)
1198 return 0;
Eric Andersen29d2e361999-11-06 06:07:27 +00001199
Erik Andersene49d5ec2000-02-08 19:58:47 +00001200 while ((mountEntry = getmntent(mountTable)) != 0) {
Eric Andersen10dc9d42000-06-26 10:45:52 +00001201 if (strcmp(mountEntry->mnt_fsname, "none") == 0) {
1202 continue;
1203 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001204 if (strcmp(name, mountEntry->mnt_dir) == 0
1205 || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */
1206 break;
1207 if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */
1208 break;
1209 if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */
1210 break;
1211 }
1212 endmntent(mountTable);
1213 return mountEntry;
Eric Andersen29d2e361999-11-06 06:07:27 +00001214}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001215#endif /* BB_DF || BB_MTAB */
Eric Andersen29d2e361999-11-06 06:07:27 +00001216
1217
1218
Erik Andersen23dea9b2000-05-13 00:28:25 +00001219#if defined BB_DD || defined BB_TAIL
Eric Andersen1792f8c1999-12-09 06:11:36 +00001220/*
1221 * Read a number with a possible multiplier.
1222 * Returns -1 if the number format is illegal.
1223 */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001224extern long getNum(const char *cp)
Eric Andersen1792f8c1999-12-09 06:11:36 +00001225{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001226 long value;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001227
Erik Andersene49d5ec2000-02-08 19:58:47 +00001228 if (!isDecimal(*cp))
1229 return -1;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001230
Erik Andersene49d5ec2000-02-08 19:58:47 +00001231 value = 0;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001232
Erik Andersene49d5ec2000-02-08 19:58:47 +00001233 while (isDecimal(*cp))
1234 value = value * 10 + *cp++ - '0';
Eric Andersen1792f8c1999-12-09 06:11:36 +00001235
Erik Andersene49d5ec2000-02-08 19:58:47 +00001236 switch (*cp++) {
1237 case 'M':
1238 case 'm': /* `tail' uses it traditionally */
1239 value *= 1048576;
1240 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001241
Erik Andersene49d5ec2000-02-08 19:58:47 +00001242 case 'k':
1243 value *= 1024;
1244 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001245
Erik Andersene49d5ec2000-02-08 19:58:47 +00001246 case 'b':
1247 value *= 512;
1248 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001249
Erik Andersene49d5ec2000-02-08 19:58:47 +00001250 case 'w':
1251 value *= 2;
1252 break;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001253
Erik Andersene49d5ec2000-02-08 19:58:47 +00001254 case '\0':
1255 return value;
1256
1257 default:
1258 return -1;
1259 }
1260
1261 if (*cp)
1262 return -1;
1263
Eric Andersen1792f8c1999-12-09 06:11:36 +00001264 return value;
Eric Andersen1792f8c1999-12-09 06:11:36 +00001265}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001266#endif /* BB_DD || BB_TAIL */
Eric Andersen1792f8c1999-12-09 06:11:36 +00001267
Eric Andersen6805d5d1999-12-09 22:39:55 +00001268
Erik Andersen23dea9b2000-05-13 00:28:25 +00001269#if defined BB_INIT || defined BB_SYSLOGD
Erik Andersen31cf8e02000-02-07 20:31:19 +00001270/* try to open up the specified device */
1271extern int device_open(char *device, int mode)
1272{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001273 int m, f, fd = -1;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001274
Erik Andersene49d5ec2000-02-08 19:58:47 +00001275 m = mode | O_NONBLOCK;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001276
Erik Andersene49d5ec2000-02-08 19:58:47 +00001277 /* Retry up to 5 times */
1278 for (f = 0; f < 5; f++)
1279 if ((fd = open(device, m, 0600)) >= 0)
1280 break;
1281 if (fd < 0)
1282 return fd;
1283 /* Reset original flags. */
1284 if (m != mode)
1285 fcntl(fd, F_SETFL, mode);
Erik Andersen31cf8e02000-02-07 20:31:19 +00001286 return fd;
Erik Andersen31cf8e02000-02-07 20:31:19 +00001287}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001288#endif /* BB_INIT BB_SYSLOGD */
Erik Andersen31cf8e02000-02-07 20:31:19 +00001289
1290
Erik Andersen23dea9b2000-05-13 00:28:25 +00001291#if defined BB_KILLALL || ( defined BB_FEATURE_LINUXRC && ( defined BB_HALT || defined BB_REBOOT || defined BB_POWEROFF ))
Erik Andersen269bba22000-03-08 14:50:47 +00001292#ifdef BB_FEATURE_USE_DEVPS_PATCH
Erik Andersen246cc6d2000-03-07 07:41:42 +00001293#include <linux/devps.h>
Erik Andersen23dea9b2000-05-13 00:28:25 +00001294#endif
Erik Andersen246cc6d2000-03-07 07:41:42 +00001295
Erik Andersen23dea9b2000-05-13 00:28:25 +00001296#if defined BB_FEATURE_USE_DEVPS_PATCH
Erik Andersen246cc6d2000-03-07 07:41:42 +00001297/* findPidByName()
John Beppuf95ca971999-12-09 22:10:18 +00001298 *
Erik Andersen246cc6d2000-03-07 07:41:42 +00001299 * This finds the pid of the specified process,
1300 * by using the /dev/ps device driver.
John Beppuf95ca971999-12-09 22:10:18 +00001301 *
Erik Andersen825aead2000-04-07 06:00:07 +00001302 * Returns a list of all matching PIDs
John Beppuf95ca971999-12-09 22:10:18 +00001303 */
Erik Andersen825aead2000-04-07 06:00:07 +00001304extern pid_t* findPidByName( char* pidName)
John Beppuf95ca971999-12-09 22:10:18 +00001305{
Erik Andersen825aead2000-04-07 06:00:07 +00001306 int fd, i, j;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001307 char device[] = "/dev/ps";
Erik Andersen246cc6d2000-03-07 07:41:42 +00001308 pid_t num_pids;
1309 pid_t* pid_array = NULL;
Erik Andersen825aead2000-04-07 06:00:07 +00001310 pid_t* pidList=NULL;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001311
1312 /* open device */
1313 fd = open(device, O_RDONLY);
1314 if (fd < 0)
1315 fatalError( "open failed for `%s': %s\n", device, strerror (errno));
1316
1317 /* Find out how many processes there are */
1318 if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0)
1319 fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
1320
1321 /* Allocate some memory -- grab a few extras just in case
1322 * some new processes start up while we wait. The kernel will
1323 * just ignore any extras if we give it too many, and will trunc.
1324 * the list if we give it too few. */
1325 pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t));
1326 pid_array[0] = num_pids+10;
1327
1328 /* Now grab the pid list */
1329 if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0)
1330 fatalError( "\nDEVPS_GET_PID_LIST: %s\n", strerror (errno));
1331
1332 /* Now search for a match */
1333 for (i=1; i<pid_array[0] ; i++) {
Erik Andersen0a64de92000-04-18 20:00:03 +00001334 char* p;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001335 struct pid_info info;
1336
1337 info.pid = pid_array[i];
1338 if (ioctl (fd, DEVPS_GET_PID_INFO, &info)<0)
1339 fatalError( "\nDEVPS_GET_PID_INFO: %s\n", strerror (errno));
1340
Erik Andersen0a64de92000-04-18 20:00:03 +00001341 /* Make sure we only match on the process name */
1342 p=info.command_line+1;
1343 while ((*p != 0) && !isspace(*(p)) && (*(p-1) != '\\')) {
1344 (p)++;
1345 }
1346 if (isspace(*(p)))
1347 *p='\0';
1348
Erik Andersenb9167cb2000-04-18 22:41:30 +00001349 if ((strstr(info.command_line, pidName) != NULL)
1350 && (strlen(pidName) == strlen(info.command_line))) {
Erik Andersen825aead2000-04-07 06:00:07 +00001351 pidList=realloc( pidList, sizeof(pid_t) * (j+2));
1352 if (pidList==NULL)
Erik Andersen7ab9c7e2000-05-12 19:41:47 +00001353 fatalError(memory_exhausted, "");
Erik Andersen825aead2000-04-07 06:00:07 +00001354 pidList[j++]=info.pid;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001355 }
1356 }
Erik Andersen0a64de92000-04-18 20:00:03 +00001357 if (pidList)
1358 pidList[j]=0;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001359
1360 /* Free memory */
1361 free( pid_array);
1362
1363 /* close device */
1364 if (close (fd) != 0)
1365 fatalError( "close failed for `%s': %s\n",device, strerror (errno));
1366
Erik Andersen825aead2000-04-07 06:00:07 +00001367 return pidList;
Erik Andersen246cc6d2000-03-07 07:41:42 +00001368}
Erik Andersen269bba22000-03-08 14:50:47 +00001369#else /* BB_FEATURE_USE_DEVPS_PATCH */
Erik Andersen246cc6d2000-03-07 07:41:42 +00001370#if ! defined BB_FEATURE_USE_PROCFS
1371#error Sorry, I depend on the /proc filesystem right now.
1372#endif
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001373
Erik Andersen246cc6d2000-03-07 07:41:42 +00001374/* findPidByName()
1375 *
1376 * This finds the pid of the specified process.
1377 * Currently, it's implemented by rummaging through
1378 * the proc filesystem.
1379 *
Erik Andersen825aead2000-04-07 06:00:07 +00001380 * Returns a list of all matching PIDs
Erik Andersen246cc6d2000-03-07 07:41:42 +00001381 */
Erik Andersen825aead2000-04-07 06:00:07 +00001382extern pid_t* findPidByName( char* pidName)
Erik Andersen246cc6d2000-03-07 07:41:42 +00001383{
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001384 DIR *dir;
1385 struct dirent *next;
Erik Andersen825aead2000-04-07 06:00:07 +00001386 pid_t* pidList=NULL;
1387 int i=0;
John Beppuf95ca971999-12-09 22:10:18 +00001388
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001389 dir = opendir("/proc");
1390 if (!dir)
1391 fatalError( "Cannot open /proc: %s\n", strerror (errno));
1392
1393 while ((next = readdir(dir)) != NULL) {
Erik Andersene49d5ec2000-02-08 19:58:47 +00001394 FILE *status;
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001395 char filename[256];
1396 char buffer[256];
Erik Andersenb9167cb2000-04-18 22:41:30 +00001397 char* p;
John Beppuf95ca971999-12-09 22:10:18 +00001398
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001399 /* If it isn't a number, we don't want it */
1400 if (!isdigit(*next->d_name))
1401 continue;
1402
Erik Andersen825aead2000-04-07 06:00:07 +00001403 /* Now open the status file */
Erik Andersen2ac2fae2000-03-07 23:32:17 +00001404 sprintf(filename, "/proc/%s/status", next->d_name);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001405 status = fopen(filename, "r");
1406 if (!status) {
1407 continue;
1408 }
1409 fgets(buffer, 256, status);
1410 fclose(status);
John Beppuf95ca971999-12-09 22:10:18 +00001411
Erik Andersen0a64de92000-04-18 20:00:03 +00001412 /* Make sure we only match on the process name */
1413 p=buffer+5; /* Skip the name */
1414 while ((p)++) {
1415 if (*p==0 || *p=='\n') {
1416 *p='\0';
1417 break;
1418 }
1419 }
1420 p=buffer+6; /* Skip the "Name:\t" */
1421
Erik Andersenb9167cb2000-04-18 22:41:30 +00001422 if ((strstr(p, pidName) != NULL)
1423 && (strlen(pidName) == strlen(p))) {
Erik Andersen825aead2000-04-07 06:00:07 +00001424 pidList=realloc( pidList, sizeof(pid_t) * (i+2));
1425 if (pidList==NULL)
Erik Andersen7ab9c7e2000-05-12 19:41:47 +00001426 fatalError(memory_exhausted, "");
Erik Andersen825aead2000-04-07 06:00:07 +00001427 pidList[i++]=strtol(next->d_name, NULL, 0);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001428 }
John Beppuf95ca971999-12-09 22:10:18 +00001429 }
Erik Andersen0a64de92000-04-18 20:00:03 +00001430 if (pidList)
Erik Andersena6c75222000-04-18 00:00:52 +00001431 pidList[i]=0;
Erik Andersen825aead2000-04-07 06:00:07 +00001432 return pidList;
John Beppuf95ca971999-12-09 22:10:18 +00001433}
Erik Andersen269bba22000-03-08 14:50:47 +00001434#endif /* BB_FEATURE_USE_DEVPS_PATCH */
Erik Andersen23dea9b2000-05-13 00:28:25 +00001435#endif /* BB_KILLALL || ( BB_FEATURE_LINUXRC && ( BB_HALT || BB_REBOOT || BB_POWEROFF )) */
Eric Andersen1792f8c1999-12-09 06:11:36 +00001436
Erik Andersen0d068a22000-03-21 22:32:57 +00001437/* this should really be farmed out to libbusybox.a */
Erik Andersene49d5ec2000-02-08 19:58:47 +00001438extern void *xmalloc(size_t size)
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001439{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001440 void *cp = malloc(size);
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001441
Erik Andersen0d068a22000-03-21 22:32:57 +00001442 if (cp == NULL)
Erik Andersen7ab9c7e2000-05-12 19:41:47 +00001443 fatalError(memory_exhausted, "");
Erik Andersene49d5ec2000-02-08 19:58:47 +00001444 return cp;
Erik Andersen3fe39dc2000-01-25 18:13:53 +00001445}
1446
Erik Andersen23dea9b2000-05-13 00:28:25 +00001447#if (__GLIBC__ < 2) && (defined BB_SYSLOGD || defined BB_INIT)
Erik Andersen7dc16072000-01-04 01:10:25 +00001448extern int vdprintf(int d, const char *format, va_list ap)
1449{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001450 char buf[BUF_SIZE];
1451 int len;
Erik Andersen7dc16072000-01-04 01:10:25 +00001452
Erik Andersene49d5ec2000-02-08 19:58:47 +00001453 len = vsprintf(buf, format, ap);
1454 return write(d, buf, len);
Erik Andersen7dc16072000-01-04 01:10:25 +00001455}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001456#endif /* BB_SYSLOGD */
Erik Andersen7dc16072000-01-04 01:10:25 +00001457
Erik Andersen23dea9b2000-05-13 00:28:25 +00001458#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersen5cbdd712000-01-26 20:06:48 +00001459extern int del_loop(const char *device)
1460{
Erik Andersene49d5ec2000-02-08 19:58:47 +00001461 int fd;
Erik Andersen5cbdd712000-01-26 20:06:48 +00001462
Erik Andersene49d5ec2000-02-08 19:58:47 +00001463 if ((fd = open(device, O_RDONLY)) < 0) {
1464 perror(device);
1465 return (FALSE);
1466 }
1467 if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
1468 perror("ioctl: LOOP_CLR_FD");
1469 return (FALSE);
1470 }
1471 close(fd);
1472 return (TRUE);
Erik Andersen5cbdd712000-01-26 20:06:48 +00001473}
Erik Andersende7965c2000-01-26 23:49:21 +00001474
Erik Andersene49d5ec2000-02-08 19:58:47 +00001475extern int set_loop(const char *device, const char *file, int offset,
1476 int *loopro)
Erik Andersende7965c2000-01-26 23:49:21 +00001477{
1478 struct loop_info loopinfo;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001479 int fd, ffd, mode;
1480
Erik Andersende7965c2000-01-26 23:49:21 +00001481 mode = *loopro ? O_RDONLY : O_RDWR;
Erik Andersene49d5ec2000-02-08 19:58:47 +00001482 if ((ffd = open(file, mode)) < 0 && !*loopro
1483 && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) {
1484 perror(file);
1485 return 1;
Erik Andersende7965c2000-01-26 23:49:21 +00001486 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001487 if ((fd = open(device, mode)) < 0) {
1488 close(ffd);
1489 perror(device);
1490 return 1;
Erik Andersende7965c2000-01-26 23:49:21 +00001491 }
1492 *loopro = (mode == O_RDONLY);
1493
1494 memset(&loopinfo, 0, sizeof(loopinfo));
1495 strncpy(loopinfo.lo_name, file, LO_NAME_SIZE);
Erik Andersene49d5ec2000-02-08 19:58:47 +00001496 loopinfo.lo_name[LO_NAME_SIZE - 1] = 0;
Erik Andersende7965c2000-01-26 23:49:21 +00001497
1498 loopinfo.lo_offset = offset;
1499
1500 loopinfo.lo_encrypt_key_size = 0;
1501 if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
1502 perror("ioctl: LOOP_SET_FD");
1503 close(fd);
1504 close(ffd);
1505 return 1;
1506 }
1507 if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
1508 (void) ioctl(fd, LOOP_CLR_FD, 0);
1509 perror("ioctl: LOOP_SET_STATUS");
1510 close(fd);
1511 close(ffd);
1512 return 1;
1513 }
1514 close(fd);
1515 close(ffd);
1516 return 0;
1517}
1518
Erik Andersene49d5ec2000-02-08 19:58:47 +00001519extern char *find_unused_loop_device(void)
Erik Andersende7965c2000-01-26 23:49:21 +00001520{
1521 char dev[20];
1522 int i, fd;
1523 struct stat statbuf;
1524 struct loop_info loopinfo;
1525
Erik Andersene49d5ec2000-02-08 19:58:47 +00001526 for (i = 0; i <= 7; i++) {
1527 sprintf(dev, "/dev/loop%d", i);
1528 if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
1529 if ((fd = open(dev, O_RDONLY)) >= 0) {
1530 if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == -1) {
1531 if (errno == ENXIO) { /* probably free */
1532 close(fd);
1533 return strdup(dev);
1534 }
1535 }
1536 close(fd);
Erik Andersende7965c2000-01-26 23:49:21 +00001537 }
Erik Andersende7965c2000-01-26 23:49:21 +00001538 }
Erik Andersende7965c2000-01-26 23:49:21 +00001539 }
Erik Andersene49d5ec2000-02-08 19:58:47 +00001540 return NULL;
Erik Andersende7965c2000-01-26 23:49:21 +00001541}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001542#endif /* BB_FEATURE_MOUNT_LOOP */
Erik Andersende7965c2000-01-26 23:49:21 +00001543
Erik Andersen23dea9b2000-05-13 00:28:25 +00001544#if defined BB_MOUNT || defined BB_DF || ( defined BB_UMOUNT && ! defined BB_MTAB)
Erik Andersenec5bd902000-03-22 07:12:05 +00001545extern int find_real_root_device_name(char* name)
Erik Andersen016ffe92000-03-22 00:58:54 +00001546{
Erik Andersen016ffe92000-03-22 00:58:54 +00001547 DIR *dir;
1548 struct dirent *entry;
1549 struct stat statBuf, rootStat;
1550 char fileName[BUFSIZ];
1551
Erik Andersenec5bd902000-03-22 07:12:05 +00001552 if (stat("/", &rootStat) != 0) {
1553 errorMsg("could not stat '/'\n");
1554 return( FALSE);
1555 }
Erik Andersen016ffe92000-03-22 00:58:54 +00001556
Erik Andersenec5bd902000-03-22 07:12:05 +00001557 dir = opendir("/dev");
1558 if (!dir) {
1559 errorMsg("could not open '/dev'\n");
1560 return( FALSE);
1561 }
Erik Andersen016ffe92000-03-22 00:58:54 +00001562
1563 while((entry = readdir(dir)) != NULL) {
Erik Andersenec5bd902000-03-22 07:12:05 +00001564
Erik Andersen016ffe92000-03-22 00:58:54 +00001565 /* Must skip ".." since that is "/", and so we
1566 * would get a false positive on ".." */
Erik Andersen016ffe92000-03-22 00:58:54 +00001567 if (strcmp(entry->d_name, "..") == 0)
1568 continue;
1569
1570 sprintf( fileName, "/dev/%s", entry->d_name);
1571
1572 if (stat(fileName, &statBuf) != 0)
1573 continue;
Erik Andersenec5bd902000-03-22 07:12:05 +00001574 /* Some char devices have the same dev_t as block
1575 * devices, so make sure this is a block device */
1576 if (! S_ISBLK(statBuf.st_mode))
1577 continue;
Erik Andersen016ffe92000-03-22 00:58:54 +00001578 if (statBuf.st_rdev == rootStat.st_rdev) {
Erik Andersenec5bd902000-03-22 07:12:05 +00001579 strcpy(name, fileName);
1580 return ( TRUE);
Erik Andersen016ffe92000-03-22 00:58:54 +00001581 }
1582 }
1583
Erik Andersenec5bd902000-03-22 07:12:05 +00001584 return( FALSE);
Erik Andersen016ffe92000-03-22 00:58:54 +00001585}
Erik Andersen23dea9b2000-05-13 00:28:25 +00001586#endif
Erik Andersen016ffe92000-03-22 00:58:54 +00001587
John Beppuc7ccfc92000-06-12 23:39:04 +00001588const unsigned int CSTRING_BUFFER_LENGTH = 1024;
John Beppu5a728cf2000-04-17 04:22:09 +00001589/* recursive parser that returns cstrings of arbitrary length
1590 * from a FILE*
1591 */
1592static char *
1593cstring_alloc(FILE* f, int depth)
1594{
1595 char *cstring;
1596 char buffer[CSTRING_BUFFER_LENGTH];
1597 int target = CSTRING_BUFFER_LENGTH * depth;
Eric Andersen86ab8a32000-06-02 03:21:42 +00001598 int c, i, len, size;
John Beppu5a728cf2000-04-17 04:22:09 +00001599
1600 /* fill buffer */
1601 i = 0;
Eric Andersen86ab8a32000-06-02 03:21:42 +00001602 while ((c = fgetc(f)) != EOF) {
1603 buffer[i] = (char) c;
John Beppu5a728cf2000-04-17 04:22:09 +00001604 if (buffer[i++] == 0x0a) { break; }
1605 if (i == CSTRING_BUFFER_LENGTH) { break; }
1606 }
1607 len = i;
1608
1609 /* recurse or malloc? */
1610 if (len == CSTRING_BUFFER_LENGTH) {
1611 cstring = cstring_alloc(f, (depth + 1));
1612 } else {
1613 /* [special case] EOF */
1614 if ((depth | len) == 0) { return NULL; }
1615
1616 /* malloc */
1617 size = target + len + 1;
1618 cstring = malloc(size);
1619 if (!cstring) { return NULL; }
1620 cstring[size - 1] = 0;
1621 }
1622
1623 /* copy buffer */
1624 if (cstring) {
1625 memcpy(&cstring[target], buffer, len);
1626 }
1627 return cstring;
1628}
1629
1630/*
1631 * wrapper around recursive cstring_alloc
1632 * it's the caller's responsibility to free the cstring
1633 */
1634char *
1635cstring_lineFromFile(FILE *f)
1636{
1637 return cstring_alloc(f, 0);
1638}
Erik Andersen016ffe92000-03-22 00:58:54 +00001639
Eric Andersencc8ed391999-10-05 16:24:54 +00001640/* END CODE */
Erik Andersen029011b2000-03-04 21:19:32 +00001641/*
1642Local Variables:
1643c-file-style: "linux"
1644c-basic-offset: 4
1645tab-width: 4
1646End:
1647*/