blob: e188ecdcd6f946c98210a4fb3c13773537aeb794 [file] [log] [blame]
Eric Andersencc8ed391999-10-05 16:24:54 +00001/*
2 * Utility routines.
3 *
Eric Andersenc4996011999-10-20 22:08:37 +00004 * Copyright (C) tons of folks. Tracking down who wrote what
5 * isn't something I'm going to worry about... If you wrote something
6 * here, please feel free to acknowledge your work.
Eric Andersencc8ed391999-10-05 16:24:54 +00007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
23 * Permission has been granted to redistribute this code under the GPL.
24 *
25 */
26
Eric Andersen2b69c401999-10-05 22:58:32 +000027#include "internal.h"
28#include <stdio.h>
29#include <string.h>
30#include <errno.h>
31#include <fcntl.h>
Eric Andersen2b69c401999-10-05 22:58:32 +000032#include <dirent.h>
33#include <time.h>
34#include <utime.h>
Eric Andersenf811e071999-10-09 00:25:00 +000035#include <sys/stat.h>
36#include <unistd.h>
Eric Andersence8f3b91999-10-20 07:03:36 +000037#include <ctype.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000038
Eric Andersenb0e9a701999-10-18 22:28:26 +000039/* volatile so gcc knows this is the enod of the line */
40volatile void usage(const char *usage)
41{
42 fprintf(stderr, "Usage: %s\n", usage);
43 exit(FALSE);
44}
45
46
Eric Andersend23f9ba1999-10-20 19:18:15 +000047#if defined (BB_INIT) || defined (BB_PS)
48
49/* Returns kernel version encoded as major*65536 + minor*256 + patch,
50 * so, for example, to check if the kernel is greater than 2.2.11:
51 * if (get_kernel_revision() <= 2*65536+2*256+11) { <stuff> }
52 */
53int
54get_kernel_revision()
55{
56 FILE *f;
57 int major=0, minor=0, patch=0;
58
59 f = fopen("/proc/sys/kernel/osrelease","r");
60 fscanf(f,"%d.%d.%d",&major,&minor,&patch);
61 fclose(f);
62 return major*65536 + minor*256 + patch;
63}
64
65#endif
66
67
Eric Andersenc6cb79d1999-10-13 18:01:10 +000068
69#if defined (BB_CP) || defined (BB_MV)
70/*
71 * Return TRUE if a fileName is a directory.
72 * Nonexistant files return FALSE.
73 */
74int isDirectory(const char *name)
Eric Andersencc8ed391999-10-05 16:24:54 +000075{
Eric Andersenc6cb79d1999-10-13 18:01:10 +000076 struct stat statBuf;
Eric Andersencc8ed391999-10-05 16:24:54 +000077
Eric Andersenc6cb79d1999-10-13 18:01:10 +000078 if (stat(name, &statBuf) < 0)
79 return FALSE;
Eric Andersen9b587181999-10-17 05:43:39 +000080 if (S_ISDIR(statBuf.st_mode))
81 return TRUE;
82 return(FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +000083}
84
Eric Andersenc6cb79d1999-10-13 18:01:10 +000085
86/*
87 * Copy one file to another, while possibly preserving its modes, times,
88 * and modes. Returns TRUE if successful, or FALSE on a failure with an
89 * error message output. (Failure is not indicted if the attributes cannot
90 * be set.)
Eric Andersenc4996011999-10-20 22:08:37 +000091 * -Erik Andersen
Eric Andersenc6cb79d1999-10-13 18:01:10 +000092 */
93int
Eric Andersen3c163821999-10-14 22:16:57 +000094copyFile( const char *srcName, const char *destName,
95 int setModes, int followLinks)
Eric Andersenc6cb79d1999-10-13 18:01:10 +000096{
97 int rfd;
98 int wfd;
99 int rcc;
100 int result;
101 char buf[BUF_SIZE];
102 struct stat srcStatBuf;
103 struct stat dstStatBuf;
104 struct utimbuf times;
105
106 if (followLinks == FALSE)
107 result = stat(srcName, &srcStatBuf);
108 else
109 result = lstat(srcName, &srcStatBuf);
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000110 if (result < 0) {
111 perror(srcName);
112 return FALSE;
113 }
114
115 if (followLinks == FALSE)
116 result = stat(destName, &dstStatBuf);
117 else
118 result = lstat(destName, &dstStatBuf);
119 if (result < 0) {
120 dstStatBuf.st_ino = -1;
121 dstStatBuf.st_dev = -1;
122 }
123
124 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
125 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
126 fprintf(stderr, "Copying file \"%s\" to itself\n", srcName);
127 return FALSE;
128 }
129
130 if (S_ISDIR(srcStatBuf.st_mode)) {
131 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
132 /* Make sure the directory is writable */
133 if (mkdir(destName, 0777777 ^ umask(0))) {
134 perror(destName);
135 return (FALSE);
136 }
137 } else if (S_ISLNK(srcStatBuf.st_mode)) {
138 char *link_val;
139 int link_size;
140
141 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
142 link_val = (char *) alloca(PATH_MAX + 2);
143 link_size = readlink(srcName, link_val, PATH_MAX + 1);
144 if (link_size < 0) {
145 perror(srcName);
146 return (FALSE);
147 }
148 link_val[link_size] = '\0';
Eric Andersen3c163821999-10-14 22:16:57 +0000149 link_size = symlink(link_val, destName);
150 if (link_size != 0) {
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000151 perror(destName);
152 return (FALSE);
153 }
154 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
155 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
156 if (mkfifo(destName, 644)) {
157 perror(destName);
158 return (FALSE);
159 }
160 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
161 || S_ISSOCK (srcStatBuf.st_mode)) {
162 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
163 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev)) {
164 perror(destName);
165 return (FALSE);
166 }
167 } else if (S_ISREG(srcStatBuf.st_mode)) {
168 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
169 rfd = open(srcName, O_RDONLY);
170 if (rfd < 0) {
171 perror(srcName);
172 return FALSE;
173 }
174
175 wfd = creat(destName, srcStatBuf.st_mode);
176 if (wfd < 0) {
177 perror(destName);
178 close(rfd);
179 return FALSE;
180 }
181
182 while ((rcc = read(rfd, buf, sizeof(buf))) > 0) {
183 if (fullWrite(wfd, buf, rcc) < 0)
184 goto error_exit;
185 }
186 if (rcc < 0) {
187 goto error_exit;
188 }
189
190 close(rfd);
191 if (close(wfd) < 0) {
192 return FALSE;
193 }
194 }
195
196 if (setModes == TRUE) {
197 //fprintf(stderr, "Setting permissions for %s\n", destName);
198 chmod(destName, srcStatBuf.st_mode);
199 if (followLinks == TRUE)
200 chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
201 else
202 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
203
204 times.actime = srcStatBuf.st_atime;
205 times.modtime = srcStatBuf.st_mtime;
206
207 utime(destName, &times);
208 }
209
210 return TRUE;
211
212
213 error_exit:
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000214 perror(destName);
215 close(rfd);
216 close(wfd);
217
218 return FALSE;
219}
Eric Andersencc8ed391999-10-05 16:24:54 +0000220#endif
221
222
223
Eric Andersenbed30e91999-10-18 19:02:32 +0000224#ifdef BB_TAR
Eric Andersencc8ed391999-10-05 16:24:54 +0000225/*
226 * Return the standard ls-like mode string from a file mode.
227 * This is static and so is overwritten on each call.
228 */
Eric Andersenf811e071999-10-09 00:25:00 +0000229const char *modeString(int mode)
Eric Andersencc8ed391999-10-05 16:24:54 +0000230{
Eric Andersenf811e071999-10-09 00:25:00 +0000231 static char buf[12];
Eric Andersencc8ed391999-10-05 16:24:54 +0000232
Eric Andersenf811e071999-10-09 00:25:00 +0000233 strcpy(buf, "----------");
Eric Andersencc8ed391999-10-05 16:24:54 +0000234
Eric Andersenf811e071999-10-09 00:25:00 +0000235 /*
236 * Fill in the file type.
237 */
238 if (S_ISDIR(mode))
239 buf[0] = 'd';
240 if (S_ISCHR(mode))
241 buf[0] = 'c';
242 if (S_ISBLK(mode))
243 buf[0] = 'b';
244 if (S_ISFIFO(mode))
245 buf[0] = 'p';
Eric Andersenf811e071999-10-09 00:25:00 +0000246 if (S_ISLNK(mode))
247 buf[0] = 'l';
Eric Andersenf811e071999-10-09 00:25:00 +0000248 if (S_ISSOCK(mode))
249 buf[0] = 's';
Eric Andersenf811e071999-10-09 00:25:00 +0000250 /*
251 * Now fill in the normal file permissions.
252 */
253 if (mode & S_IRUSR)
254 buf[1] = 'r';
255 if (mode & S_IWUSR)
256 buf[2] = 'w';
257 if (mode & S_IXUSR)
258 buf[3] = 'x';
259 if (mode & S_IRGRP)
260 buf[4] = 'r';
261 if (mode & S_IWGRP)
262 buf[5] = 'w';
263 if (mode & S_IXGRP)
264 buf[6] = 'x';
265 if (mode & S_IROTH)
266 buf[7] = 'r';
267 if (mode & S_IWOTH)
268 buf[8] = 'w';
269 if (mode & S_IXOTH)
270 buf[9] = 'x';
Eric Andersencc8ed391999-10-05 16:24:54 +0000271
Eric Andersenf811e071999-10-09 00:25:00 +0000272 /*
273 * Finally fill in magic stuff like suid and sticky text.
274 */
275 if (mode & S_ISUID)
276 buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
277 if (mode & S_ISGID)
278 buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
279 if (mode & S_ISVTX)
280 buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
Eric Andersencc8ed391999-10-05 16:24:54 +0000281
Eric Andersenf811e071999-10-09 00:25:00 +0000282 return buf;
Eric Andersencc8ed391999-10-05 16:24:54 +0000283}
284
285
Eric Andersencc8ed391999-10-05 16:24:54 +0000286/*
Eric Andersen17d49ef1999-10-06 20:25:32 +0000287 * Get the time string to be used for a file.
288 * This is down to the minute for new files, but only the date for old files.
289 * The string is returned from a static buffer, and so is overwritten for
290 * each call.
291 */
Eric Andersenf811e071999-10-09 00:25:00 +0000292const char *timeString(time_t timeVal)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000293{
Eric Andersenf811e071999-10-09 00:25:00 +0000294 time_t now;
295 char *str;
296 static char buf[26];
Eric Andersen17d49ef1999-10-06 20:25:32 +0000297
Eric Andersenf811e071999-10-09 00:25:00 +0000298 time(&now);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000299
Eric Andersenf811e071999-10-09 00:25:00 +0000300 str = ctime(&timeVal);
Eric Andersen17d49ef1999-10-06 20:25:32 +0000301
Eric Andersenf811e071999-10-09 00:25:00 +0000302 strcpy(buf, &str[4]);
303 buf[12] = '\0';
Eric Andersen17d49ef1999-10-06 20:25:32 +0000304
Eric Andersenf811e071999-10-09 00:25:00 +0000305 if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) {
306 strcpy(&buf[7], &str[20]);
307 buf[11] = '\0';
308 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000309
Eric Andersenf811e071999-10-09 00:25:00 +0000310 return buf;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000311}
312
313
314/*
315 * Routine to see if a text string is matched by a wildcard pattern.
316 * Returns TRUE if the text is matched, or FALSE if it is not matched
317 * or if the pattern is invalid.
318 * * matches zero or more characters
319 * ? matches a single character
320 * [abc] matches 'a', 'b' or 'c'
321 * \c quotes character c
322 * Adapted from code written by Ingo Wilken.
323 */
Eric Andersenf811e071999-10-09 00:25:00 +0000324int match(const char *text, const char *pattern)
Eric Andersen17d49ef1999-10-06 20:25:32 +0000325{
Eric Andersenf811e071999-10-09 00:25:00 +0000326 const char *retryPat;
327 const char *retryText;
328 int ch;
329 int found;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000330
Eric Andersenf811e071999-10-09 00:25:00 +0000331 retryPat = NULL;
332 retryText = NULL;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000333
Eric Andersenf811e071999-10-09 00:25:00 +0000334 while (*text || *pattern) {
335 ch = *pattern++;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000336
Eric Andersenf811e071999-10-09 00:25:00 +0000337 switch (ch) {
338 case '*':
339 retryPat = pattern;
340 retryText = text;
341 break;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000342
Eric Andersenf811e071999-10-09 00:25:00 +0000343 case '[':
344 found = FALSE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000345
Eric Andersenf811e071999-10-09 00:25:00 +0000346 while ((ch = *pattern++) != ']') {
347 if (ch == '\\')
348 ch = *pattern++;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000349
Eric Andersenf811e071999-10-09 00:25:00 +0000350 if (ch == '\0')
351 return FALSE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000352
Eric Andersenf811e071999-10-09 00:25:00 +0000353 if (*text == ch)
354 found = TRUE;
355 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000356
Eric Andersenf811e071999-10-09 00:25:00 +0000357 if (!found) {
358 pattern = retryPat;
359 text = ++retryText;
360 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000361
Eric Andersenf811e071999-10-09 00:25:00 +0000362 /* fall into next case */
Eric Andersen17d49ef1999-10-06 20:25:32 +0000363
Eric Andersenf811e071999-10-09 00:25:00 +0000364 case '?':
365 if (*text++ == '\0')
366 return FALSE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000367
Eric Andersenf811e071999-10-09 00:25:00 +0000368 break;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000369
Eric Andersenf811e071999-10-09 00:25:00 +0000370 case '\\':
371 ch = *pattern++;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000372
Eric Andersenf811e071999-10-09 00:25:00 +0000373 if (ch == '\0')
374 return FALSE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000375
Eric Andersenf811e071999-10-09 00:25:00 +0000376 /* fall into next case */
Eric Andersen17d49ef1999-10-06 20:25:32 +0000377
Eric Andersenf811e071999-10-09 00:25:00 +0000378 default:
379 if (*text == ch) {
380 if (*text)
381 text++;
382 break;
383 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000384
Eric Andersenf811e071999-10-09 00:25:00 +0000385 if (*text) {
386 pattern = retryPat;
387 text = ++retryText;
388 break;
389 }
Eric Andersen17d49ef1999-10-06 20:25:32 +0000390
Eric Andersenf811e071999-10-09 00:25:00 +0000391 return FALSE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000392 }
393
Eric Andersenf811e071999-10-09 00:25:00 +0000394 if (pattern == NULL)
395 return FALSE;
396 }
397
398 return TRUE;
Eric Andersen17d49ef1999-10-06 20:25:32 +0000399}
400
401
402/*
Eric Andersencc8ed391999-10-05 16:24:54 +0000403 * Write all of the supplied buffer out to a file.
404 * This does multiple writes as necessary.
405 * Returns the amount written, or -1 on an error.
406 */
Eric Andersenf811e071999-10-09 00:25:00 +0000407int fullWrite(int fd, const char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000408{
Eric Andersenf811e071999-10-09 00:25:00 +0000409 int cc;
410 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000411
Eric Andersenf811e071999-10-09 00:25:00 +0000412 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000413
Eric Andersenf811e071999-10-09 00:25:00 +0000414 while (len > 0) {
415 cc = write(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000416
Eric Andersenf811e071999-10-09 00:25:00 +0000417 if (cc < 0)
418 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000419
Eric Andersenf811e071999-10-09 00:25:00 +0000420 buf += cc;
421 total += cc;
422 len -= cc;
423 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000424
Eric Andersenf811e071999-10-09 00:25:00 +0000425 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000426}
427
428
429/*
430 * Read all of the supplied buffer from a file.
431 * This does multiple reads as necessary.
432 * Returns the amount read, or -1 on an error.
433 * A short read is returned on an end of file.
434 */
Eric Andersenf811e071999-10-09 00:25:00 +0000435int fullRead(int fd, char *buf, int len)
Eric Andersencc8ed391999-10-05 16:24:54 +0000436{
Eric Andersenf811e071999-10-09 00:25:00 +0000437 int cc;
438 int total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000439
Eric Andersenf811e071999-10-09 00:25:00 +0000440 total = 0;
Eric Andersencc8ed391999-10-05 16:24:54 +0000441
Eric Andersenf811e071999-10-09 00:25:00 +0000442 while (len > 0) {
443 cc = read(fd, buf, len);
Eric Andersencc8ed391999-10-05 16:24:54 +0000444
Eric Andersenf811e071999-10-09 00:25:00 +0000445 if (cc < 0)
446 return -1;
Eric Andersencc8ed391999-10-05 16:24:54 +0000447
Eric Andersenf811e071999-10-09 00:25:00 +0000448 if (cc == 0)
449 break;
Eric Andersencc8ed391999-10-05 16:24:54 +0000450
Eric Andersenf811e071999-10-09 00:25:00 +0000451 buf += cc;
452 total += cc;
453 len -= cc;
454 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000455
Eric Andersenf811e071999-10-09 00:25:00 +0000456 return total;
Eric Andersencc8ed391999-10-05 16:24:54 +0000457}
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000458#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000459
460
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000461#if defined (BB_CHOWN) || defined (BB_CP) || defined (BB_FIND) || defined (BB_LS)
Eric Andersencc8ed391999-10-05 16:24:54 +0000462/*
Eric Andersen2b69c401999-10-05 22:58:32 +0000463 * Walk down all the directories under the specified
464 * location, and do something (something specified
465 * by the fileAction and dirAction function pointers).
Eric Andersenb7a1a751999-10-19 23:37:14 +0000466 *
467 * TODO: check if ftw(3) can replace this to reduce code size...
Eric Andersencc8ed391999-10-05 16:24:54 +0000468 */
469int
Eric Andersenbed30e91999-10-18 19:02:32 +0000470recursiveAction(const char *fileName, int recurse, int followLinks, int delayDirAction,
Eric Andersen9b587181999-10-17 05:43:39 +0000471 int (*fileAction) (const char *fileName, struct stat* statbuf),
472 int (*dirAction) (const char *fileName, struct stat* statbuf))
Eric Andersencc8ed391999-10-05 16:24:54 +0000473{
Eric Andersenf811e071999-10-09 00:25:00 +0000474 int status;
475 struct stat statbuf;
476 struct dirent *next;
Eric Andersen9d3aba71999-10-06 09:04:55 +0000477
Eric Andersen3c163821999-10-14 22:16:57 +0000478 if (followLinks == FALSE)
Eric Andersenf811e071999-10-09 00:25:00 +0000479 status = stat(fileName, &statbuf);
Eric Andersen3c163821999-10-14 22:16:57 +0000480 else
481 status = lstat(fileName, &statbuf);
482
Eric Andersencc8ed391999-10-05 16:24:54 +0000483 if (status < 0) {
484 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000485 return (FALSE);
486 }
487
488 if (recurse == FALSE) {
489 if (S_ISDIR(statbuf.st_mode)) {
Eric Andersen3c163821999-10-14 22:16:57 +0000490 if (dirAction != NULL)
Eric Andersen9b587181999-10-17 05:43:39 +0000491 return (dirAction(fileName, &statbuf));
Eric Andersenf811e071999-10-09 00:25:00 +0000492 else
Eric Andersen3c163821999-10-14 22:16:57 +0000493 return (TRUE);
494 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000495 }
496
Eric Andersen2b69c401999-10-05 22:58:32 +0000497 if (S_ISDIR(statbuf.st_mode)) {
498 DIR *dir;
499 dir = opendir(fileName);
500 if (!dir) {
501 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000502 return (FALSE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000503 }
Eric Andersenbed30e91999-10-18 19:02:32 +0000504 if (dirAction != NULL && delayDirAction == FALSE) {
Eric Andersen9b587181999-10-17 05:43:39 +0000505 status = dirAction(fileName, &statbuf);
Eric Andersenf811e071999-10-09 00:25:00 +0000506 if (status == FALSE) {
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000507 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000508 return (FALSE);
509 }
Eric Andersencc8ed391999-10-05 16:24:54 +0000510 }
Eric Andersenf811e071999-10-09 00:25:00 +0000511 while ((next = readdir(dir)) != NULL) {
512 char nextFile[NAME_MAX];
513 if ((strcmp(next->d_name, "..") == 0)
514 || (strcmp(next->d_name, ".") == 0)) {
515 continue;
516 }
517 sprintf(nextFile, "%s/%s", fileName, next->d_name);
518 status =
Eric Andersenbed30e91999-10-18 19:02:32 +0000519 recursiveAction(nextFile, TRUE, followLinks, delayDirAction,
520 fileAction, dirAction);
Eric Andersenf811e071999-10-09 00:25:00 +0000521 if (status < 0) {
522 closedir(dir);
523 return (FALSE);
524 }
525 }
526 status = closedir(dir);
Eric Andersen2b69c401999-10-05 22:58:32 +0000527 if (status < 0) {
528 perror(fileName);
Eric Andersenf811e071999-10-09 00:25:00 +0000529 return (FALSE);
Eric Andersen2b69c401999-10-05 22:58:32 +0000530 }
Eric Andersenbed30e91999-10-18 19:02:32 +0000531 if (dirAction != NULL && delayDirAction == TRUE) {
532 status = dirAction(fileName, &statbuf);
533 if (status == FALSE) {
534 perror(fileName);
535 return (FALSE);
536 }
537 }
Eric Andersenf811e071999-10-09 00:25:00 +0000538 } else {
Eric Andersenf811e071999-10-09 00:25:00 +0000539 if (fileAction == NULL)
540 return (TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000541 else
Eric Andersen9b587181999-10-17 05:43:39 +0000542 return (fileAction(fileName, &statbuf));
Eric Andersencc8ed391999-10-05 16:24:54 +0000543 }
Eric Andersenf811e071999-10-09 00:25:00 +0000544 return (TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000545}
546
Eric Andersenc6cb79d1999-10-13 18:01:10 +0000547#endif
Eric Andersencc8ed391999-10-05 16:24:54 +0000548
Eric Andersenf6be9441999-10-13 21:12:06 +0000549
550
551#if defined (BB_TAR) || defined (BB_MKDIR)
552/*
553 * Attempt to create the directories along the specified path, except for
554 * the final component. The mode is given for the final directory only,
555 * while all previous ones get default protections. Errors are not reported
556 * here, as failures to restore files can be reported later.
557 */
558extern void createPath (const char *name, int mode)
559{
560 char *cp;
561 char *cpOld;
562 char buf[NAME_MAX];
563
564 strcpy (buf, name);
565
566 cp = strchr (buf, '/');
567
568 while (cp) {
569 cpOld = cp;
570 cp = strchr (cp + 1, '/');
571
572 *cpOld = '\0';
573
574 if (mkdir (buf, cp ? 0777 : mode) == 0)
575 printf ("Directory \"%s\" created\n", buf);
576
577 *cpOld = '/';
578 }
579}
580#endif
581
582
583
584#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_MKDIR)
Eric Andersence8f3b91999-10-20 07:03:36 +0000585/* [ugoa]{+|-|=}[rwxst] */
586
587
588
589extern int
590parse_mode( const char* s, mode_t* theMode)
Eric Andersenf6be9441999-10-13 21:12:06 +0000591{
Eric Andersence8f3b91999-10-20 07:03:36 +0000592 mode_t andMode = S_ISVTX|S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
593 mode_t orMode = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000594 mode_t mode = 0;
Eric Andersence8f3b91999-10-20 07:03:36 +0000595 mode_t groups = 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000596 char type;
597 char c;
598
599 do {
600 for ( ; ; ) {
601 switch ( c = *s++ ) {
602 case '\0':
Eric Andersence8f3b91999-10-20 07:03:36 +0000603 return -1;
Eric Andersenf6be9441999-10-13 21:12:06 +0000604 case 'u':
605 groups |= S_ISUID|S_IRWXU;
606 continue;
607 case 'g':
608 groups |= S_ISGID|S_IRWXG;
609 continue;
610 case 'o':
611 groups |= S_IRWXO;
612 continue;
613 case 'a':
614 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
615 continue;
616 case '+':
617 case '=':
618 case '-':
619 type = c;
Eric Andersence8f3b91999-10-20 07:03:36 +0000620 if ( groups == 0 ) /* The default is "all" */
Eric Andersenf6be9441999-10-13 21:12:06 +0000621 groups |= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
622 break;
623 default:
Eric Andersence8f3b91999-10-20 07:03:36 +0000624 if ( isdigit(c) && c >= '0' && c <= '7' && mode == 0 && groups == 0 ) {
625 andMode = 0;
626 orMode = strtol(--s, NULL, 8);
627 *theMode &= andMode;
628 *theMode |= orMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000629 return (TRUE);
630 }
631 else
632 return (FALSE);
633 }
634 break;
635 }
636
637 while ( (c = *s++) != '\0' ) {
638 switch ( c ) {
639 case ',':
640 break;
641 case 'r':
642 mode |= S_IRUSR|S_IRGRP|S_IROTH;
643 continue;
644 case 'w':
645 mode |= S_IWUSR|S_IWGRP|S_IWOTH;
646 continue;
647 case 'x':
648 mode |= S_IXUSR|S_IXGRP|S_IXOTH;
649 continue;
650 case 's':
651 mode |= S_IXGRP|S_ISUID|S_ISGID;
652 continue;
653 case 't':
Eric Andersence8f3b91999-10-20 07:03:36 +0000654 mode |= 0;
Eric Andersenf6be9441999-10-13 21:12:06 +0000655 continue;
656 default:
Eric Andersence8f3b91999-10-20 07:03:36 +0000657 *theMode &= andMode;
658 *theMode |= orMode;
659 return( TRUE);
Eric Andersenf6be9441999-10-13 21:12:06 +0000660 }
661 break;
662 }
663 switch ( type ) {
664 case '=':
Eric Andersence8f3b91999-10-20 07:03:36 +0000665 andMode &= ~(groups);
Eric Andersenf6be9441999-10-13 21:12:06 +0000666 /* fall through */
667 case '+':
Eric Andersence8f3b91999-10-20 07:03:36 +0000668 orMode |= mode & groups;
Eric Andersenf6be9441999-10-13 21:12:06 +0000669 break;
670 case '-':
Eric Andersence8f3b91999-10-20 07:03:36 +0000671 andMode &= ~(mode & groups);
672 orMode &= andMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000673 break;
674 }
675 } while ( c == ',' );
Eric Andersence8f3b91999-10-20 07:03:36 +0000676 *theMode &= andMode;
677 *theMode |= orMode;
Eric Andersenf6be9441999-10-13 21:12:06 +0000678 return (TRUE);
679}
Eric Andersence8f3b91999-10-20 07:03:36 +0000680
681
Eric Andersenf6be9441999-10-13 21:12:06 +0000682#endif
683
Eric Andersene674eb71999-10-19 20:52:57 +0000684
685
Eric Andersend23f9ba1999-10-20 19:18:15 +0000686
687
688
689
690#if defined (BB_CHMOD_CHOWN_CHGRP) || defined (BB_PS)
691
692/* Use this to avoid needing the glibc NSS stuff
693 * This uses storage buf to hold things.
694 * */
695uid_t
696my_getid(const char *filename, char *name, uid_t id)
697{
698 FILE *stream;
699 char *rname, *start, *end, buf[128];
700 uid_t rid;
701
702 stream=fopen(filename,"r");
703
704 while (fgets (buf, 128, stream) != NULL) {
705 if (buf[0] == '#')
706 continue;
707
708 start = buf;
709 end = strchr (start, ':');
710 if (end == NULL)
711 continue;
712 *end = '\0';
713 rname = start;
714
715 start = end + 1;
716 end = strchr (start, ':');
717 if (end == NULL)
718 continue;
719
720 start = end + 1;
721 rid = (uid_t) strtol (start, &end, 10);
722 if (end == start)
723 continue;
724
725 if (name) {
726 if (0 == strcmp(rname, name))
727 return( rid);
728 }
729 if ( id != -1 && id == rid ) {
730 strncpy(name, rname, 8);
731 return( TRUE);
732 }
733 }
734 fclose(stream);
735 return (-1);
736}
737
738uid_t
739my_getpwnam(char *name)
740{
741 return my_getid("/etc/passwd", name, -1);
742}
743
744gid_t
745my_getgrnam(char *name)
746{
747 return my_getid("/etc/group", name, -1);
748}
749
750void
751my_getpwuid(char* name, uid_t uid)
752{
753 my_getid("/etc/passwd", name, uid);
754}
755
756void
757my_getgrgid(char* group, gid_t gid)
758{
759 my_getid("/etc/group", group, gid);
760}
761
762
763#endif
764
765
Eric Andersencc8ed391999-10-05 16:24:54 +0000766/* END CODE */