Exemple #1
0
void ExpireProfile(channel_t *channel, dirstat_t *current_stat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) {
int  		size_done, lifetime_done, done;
char 		*expire_timelimit = "";
time_t		now = time(NULL);
uint64_t	sizelimit, num_expired;

	if ( !channel ) 
		return;

	done = 0;
	SetupSignalHandler();

	if ( maxlife ) {
//		time_t t_expire = now - maxlife;
		// build an appropriate string for comparing
		time_t t_watermark = now - (time_t)((maxlife * current_stat->low_water)/100);

//	printf("Expire files before %s", ctime(&t_expire));
		expire_timelimit = strdup(UNIX2ISO(t_watermark));
//	printf("down to %s", ctime(&t_watermark));
//	printf("Diff: %i\n", t_watermark - t_expire );

	}

	size_done 		= maxsize == 0 || current_stat->filesize < maxsize;
	sizelimit 		= (current_stat->low_water * maxsize)/100;
	lifetime_done 	= maxlife == 0 || ( now - current_stat->first ) < maxlife;

	num_expired = 0;

	PrepareDirLists(channel);
	if ( runtime )
		alarm(runtime);
	while ( !done ) {
		char *p;
		int file_removed;

		// search for the channel with oldest file. If all channel have same age, 
		// get the last in the list
		channel_t *expire_channel  = channel;
		channel_t *compare_channel = expire_channel->next;
		while ( compare_channel ) {
			if ( expire_channel->ftsent == NULL ) {
				expire_channel = compare_channel;
			}
			if ( compare_channel->ftsent == NULL ) {
				compare_channel = compare_channel->next;
				continue;
			}
			// at this point expire_channel and current_channel fts entries are valid
			if ( strcmp(expire_channel->ftsent->fts_name, compare_channel->ftsent->fts_name) >= 0 ) {
				expire_channel = compare_channel;
			}
			compare_channel = compare_channel->next;
		}
		if ( !expire_channel->ftsent ) {
			// no more entries in any channel - we are done
			done = 1;
			continue;
		}

		// flag is file got removed
		file_removed = 0;

		// expire_channel now points to the channel with oldest file
		// do expire
		p = &(expire_channel->ftsent->fts_name[7]);
//	printf("File: %s\n", expire_channel->ftsent->fts_path);

		if ( !size_done ) {
			// expire size-wise if needed
//	printf("	Size expire %llu %llu\n", current_stat->filesize, sizelimit);
			if ( current_stat->filesize > sizelimit ) {
				// need to delete this file
				if ( unlink(expire_channel->ftsent->fts_path) == 0 ) {
					// Update profile stat
					current_stat->filesize 			  -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
					current_stat->numfiles--;

					// Update channel stat
					expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
					expire_channel->dirstat->numfiles--;

					// decrement number of files seen in this directory
					expire_channel->ftsent->fts_number--;

					file_removed = 1;
					num_expired++;
				} else {
					LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
				}
			} else {
				// we are done size-wise
				// time of first file not expired = start time of channel/profile
				expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);	
				size_done = 1;
			}
		} else if ( !lifetime_done ) {
//	printf("	Time expire \n");
			// expire time-wise if needed
			// this part of the code is executed only when size-wise is already fullfilled
			if ( strcmp(p, expire_timelimit) < 0  ) {
				// need to delete this file
				if ( unlink(expire_channel->ftsent->fts_path) == 0 ) {
					// Update profile stat
					current_stat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
					current_stat->numfiles--;

					// Update channel stat
					expire_channel->dirstat->filesize -= 512 * expire_channel->ftsent->fts_statp->st_blocks;
					expire_channel->dirstat->numfiles--;

					// decrement number of files seen in this directory
					expire_channel->ftsent->fts_number--;

					file_removed = 1;
					num_expired++;
				} else {
					LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
				}
			} else {
				// we are done time-wise
				// time of first file not expired = start time of channel/profile
				expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);	
				lifetime_done = 1;
			}
		} else 
			// all done
			done = 1;
		if ( timeout ) 
			done = 1;

		// advance fts entry in expire channel to next file, if file was removed
		if ( file_removed ) {
			expire_channel->ftsent = fts_read(expire_channel->fts);
			while ( expire_channel->ftsent ) {
				if ( expire_channel->ftsent->fts_info == FTS_F ) { // entry is a file
					expire_channel->ftsent->fts_number++;
					if ( expire_channel->ftsent->fts_namelen == 19 && 
					 	strncmp(expire_channel->ftsent->fts_name, "nfcapd.", 7) == 0 ) {
						// if ftsent points to next valid file
						char *p = &(expire_channel->ftsent->fts_name[7]);
						// next file is first (oldest) for channel and for profile - update first mark
						expire_channel->dirstat->first = current_stat->first = ISO2UNIX(p);	
						break;
					}
				} else {
	
					switch (expire_channel->ftsent->fts_info) {
						case FTS_D:	// entry is a directory
							// set number of files seen in this directory = 0
							expire_channel->ftsent->fts_number = 0;
							// skip all '.' entries as well as hidden directories
							if ( expire_channel->ftsent->fts_level > 0 && expire_channel->ftsent->fts_name[0] == '.' ) 
								fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP);
							// any valid directory needs to start with a digit ( %Y -> year )
							if ( expire_channel->ftsent->fts_level > 0 && !isdigit(expire_channel->ftsent->fts_name[0]) ) 
								fts_set(expire_channel->fts, expire_channel->ftsent, FTS_SKIP);
							break;
						case FTS_DP:
							// do not delete base data directory ( level == 0 )
							if ( expire_channel->ftsent->fts_number == 0 && expire_channel->ftsent->fts_level > 0 ) {
								// directory is empty and can be deleted
//	printf("Will remove directory %s\n", expire_channel->ftsent->fts_path);
								if ( rmdir(expire_channel->ftsent->fts_path) != 0 ) {
									LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
								}
							}
							break;
					}
				}
				// otherwise loop
				expire_channel->ftsent = fts_read(expire_channel->fts);
			} // end advance fts entry
			file_removed = 0;
		}

		if ( expire_channel->ftsent == NULL ) {
			// this channel has no more files now
			expire_channel->dirstat->first 			= expire_channel->dirstat->last;
			if ( expire_channel->dirstat->numfiles ) {	
				// if channel is empty, no files must be reported, but rebuild is done anyway
				LogError( "Inconsitency detected in channel %s. Will rebuild automatically.\n", expire_channel->datadir);
				LogError( "No more files found, but %llu expected.\n", expire_channel->dirstat->numfiles);
			}
			expire_channel->dirstat->numfiles 	= 0;
			expire_channel->dirstat->status		= FORCE_REBUILD;
		}
	} // while ( !done )

	if ( runtime )
		alarm(0);
	if ( timeout ) {
		LogError( "Maximum execution time reached! Interrupt expire.\n");
	}

} // End of ExpireProfile
Exemple #2
0
void
cwalk(void)
{
	FTS *t;
	FTSENT *p;
	time_t cl;
	char *argv[2], host[MAXHOSTNAMELEN];
	char dot[] = ".";
	int indent = 0;

	if (!nflag) {
		(void)time(&cl);
		(void)gethostname(host, sizeof(host));
		(void)printf(
		    "#\t   user: %s\n#\tmachine: %s\n",
		    getlogin(), host);
		(void)printf(
		    "#\t   tree: %s\n#\t   date: %s",
		    fullpath, ctime(&cl));
	}

	argv[0] = dot;
	argv[1] = NULL;
	if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
		err(1, "fts_open()");
	while ((p = fts_read(t))) {
		if (iflag)
			indent = p->fts_level * 4;
		if (check_excludes(p->fts_name, p->fts_path)) {
			fts_set(t, p, FTS_SKIP);
			continue;
		}
		switch(p->fts_info) {
		case FTS_D:
			if (!dflag)
				(void)printf("\n");
			if (!nflag)
				(void)printf("# %s\n", p->fts_path);
			statd(t, p, &uid, &gid, &mode, &flags);
			statf(indent, p);
			break;
		case FTS_DP:
			if (!nflag && (p->fts_level > 0))
				(void)printf("%*s# %s\n", indent, "", p->fts_path);
			(void)printf("%*s..\n", indent, "");
			if (!dflag)
				(void)printf("\n");
			break;
		case FTS_DNR:
		case FTS_ERR:
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			break;
		default:
			if (!dflag)
				statf(indent, p);
			break;

		}
	}
	(void)fts_close(t);
	if (sflag && keys & F_CKSUM)
		warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
}
Exemple #3
0
int
main(int argc, char **argv)
{
	FTS *ftsp;
	FTSENT *p;
	int Hflag, Lflag, Pflag, ch, fts_options, hflag, rval;
	char *cp;

	myname = (cp = strrchr(*argv, '/')) ? cp + 1 : *argv;
	ischown = myname[2] == 'o';

	Hflag = Lflag = Pflag = hflag = vflag = 0;
	while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = Pflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = Pflag = 0;
			break;
		case 'P':
			Pflag = 1;
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'v':
			vflag++;
			break;
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	fts_options = FTS_PHYSICAL;
	if (Rflag) {
		if (hflag && (Lflag || Hflag))
			errx(1, "the -R and -h options may not be specified together");
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	}

	uid = gid = -1;
	if (ischown) {
		if ((cp = strchr(*argv, ':')) != NULL) {
			*cp++ = '\0';
			a_gid(cp);
		}
#ifdef SUPPORT_DOT
		else if ((cp = strchr(*argv, '.')) != NULL) {
			warnx("separation of user and group with a period is deprecated");
			*cp++ = '\0';
			a_gid(cp);
		}
#endif
		a_uid(*argv);
	} else
		a_gid(*argv);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, NULL);

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D: 			/* Change it at FTS_DP. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chown, continue. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		case FTS_SL:			/* Ignore. */
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything and ones that we found
			 * doing a physical walk.
			 */
			if (hflag)
				break;
			else
				continue;
		default:
			break;
		}
		if ((uid == (uid_t)(-1) || uid == p->fts_statp->st_uid) &&
		    (gid == (gid_t)(-1) || gid == p->fts_statp->st_gid))
			continue;
		if (hflag) {
			if (lchown(p->fts_accpath, uid, gid) && !fflag) {
				chownerr(p->fts_path);
				rval = 1;
			} else {
			    	if (vflag)
					printf("%s\n", p->fts_accpath);
			}
		} else {
			if (chown(p->fts_accpath, uid, gid) && !fflag) {
				chownerr(p->fts_path);
				rval = 1;
			} else {
			    	if (vflag) {
					printf("%s", p->fts_accpath);
					 if (vflag > 1) {
						if (ischown) {
							printf(": %d:%d -> %d:%d",
								(int)p->fts_statp->st_uid,
								(int)p->fts_statp->st_gid,
								(uid == (uid_t)-1) ?
								(int)p->fts_statp->st_uid :
								(int)uid,
								(gid == (gid_t)-1) ?
								(int) p->fts_statp->st_gid :
								(int)gid);
						} else {
							printf(": %d -> %d",
								(int)p->fts_statp->st_gid,
								(gid == (gid_t)-1) ?
								(int)p->fts_statp->st_gid :
								(int)gid);
  	                                         }
  	                                 }
  	                                 printf("\n");
				}
			}
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #4
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *entry;
	const struct compressor *method;
	const char *s;
	char *p, *infile;
	char outfile[MAXPATHLEN], _infile[MAXPATHLEN], suffix[16];
	char *nargv[512];	/* some estimate based on ARG_MAX */
	int bits, ch, error, i, rc, cflag, oflag;
	static const char *optstr[3] = {
		"123456789ab:cdfghlLnNOo:qrS:tvV",
		"cfhlNno:qrtv",
		"fghqr"
	};

	bits = cflag = oflag = 0;
	storename = -1;
	p = __progname;
	if (p[0] == 'g') {
		method = M_DEFLATE;
		bits = 6;
		p++;
	} else
#ifdef SMALL
		method = M_DEFLATE;
#else
		method = M_COMPRESS;
#endif /* SMALL */

	decomp = 0;
	pmode = MODE_COMP;
	if (!strcmp(p, "zcat")) {
		decomp++;
		cflag = 1;
		pmode = MODE_CAT;
	} else {
		if (p[0] == 'u' && p[1] == 'n') {
			p += 2;
			decomp++;
			pmode = MODE_DECOMP;
		}

		if (strcmp(p, "zip") &&
		    strcmp(p, "compress"))
			errx(1, "unknown program name");
	}

	strlcpy(suffix, method->suffix, sizeof(suffix));

	nargv[0] = NULL;
	if (method == M_DEFLATE && (p = getenv("GZIP")) != NULL) {
		char *last;

		nargv[0] = *argv++;
		for (i = 1, (p = strtok_r(p, " ", &last)); p != NULL;
		    (p = strtok_r(NULL, " ", &last)), i++)
			if (i < sizeof(nargv)/sizeof(nargv[1]) - argc - 1)
				nargv[i] = p;
			else
				errx(1, "GZIP is too long");
		argc += i - 1;
		while ((nargv[i++] = *argv++))
			;
		argv = nargv;
	}

	while ((ch = getopt_long(argc, argv, optstr[pmode], longopts, NULL)) != -1)
		switch(ch) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			method = M_DEFLATE;
			strlcpy(suffix, method->suffix, sizeof(suffix));
			bits = ch - '0';
			break;
		case 'a':
			warnx("option -a is ignored on this system");
			break;
		case 'b':
			bits = strtol(optarg, &p, 10);
			/*
			 * POSIX 1002.3 says 9 <= bits <= 14 for portable
			 * apps, but says the implementation may allow
			 * greater.
			 */
			if (*p)
				errx(1, "illegal bit count -- %s", optarg);
			break;
		case 'c':
			cflag = 1;
			break;
		case 'd':		/* Backward compatible. */
			decomp++;
			break;
		case 'f':
			force++;
			break;
		case 'g':
			method = M_DEFLATE;
			strlcpy(suffix, method->suffix, sizeof(suffix));
			bits = 6;
			break;
		case 'l':
			list++;
			testmode = 1;
			decomp++;
			break;
		case 'n':
			storename = 0;
			break;
		case 'N':
			storename = 1;
			break;
#ifndef SMALL
		case 'O':
			method = M_COMPRESS;
			strlcpy(suffix, method->suffix, sizeof(suffix));
			break;
#endif /* SMALL */
		case 'o':
			if (strlcpy(outfile, optarg,
			    sizeof(outfile)) >= sizeof(outfile))
				errx(1, "-o argument is too long");
			oflag = 1;
			break;
		case 'q':
			verbose = -1;
			break;
		case 'S':
			p = suffix;
			if (optarg[0] != '.')
				*p++ = '.';
			strlcpy(p, optarg, sizeof(suffix) - (p - suffix));
			p = optarg;
			break;
		case 't':
			testmode = 1;
			decomp++;
			break;
#ifndef SMALL
		case 'V':
			printf("%s\n%s\n", main_rcsid, gz_rcsid);
			printf("%s\n%s\n", z_rcsid, null_rcsid);
#endif
			exit (0);
		case 'v':
			verbose++;
			break;
#ifndef SMALL
		case 'L':
			fputs(copyright, stderr);
			fputs(license, stderr);
#endif
			exit (0);
		case 'r':
			recurse++;
			break;

		case 'h':
			usage(0);
			break;
		default:
			usage(1);
		}
	argc -= optind;
	argv += optind;

	if (argc == 0) {
		if (nargv[0] == NULL)
			argv = nargv;
		/* XXX - make sure we don't oflow nargv in $GZIP case (millert) */
		argv[0] = "-";
		argv[1] = NULL;
	}
	if (oflag && (recurse || argc > 1))
		errx(1, "-o option may only be used with a single input file");

	if ((cat && argc) + testmode + oflag > 1)
		errx(1, "may not mix -o, -c, or -t options");
	/*
	 * By default, when compressing store the original name and timestamp
	 * in the header.  Do not restore these when decompressing unless
	 * the -N option is given.
	 */
	if (storename == -1)
		storename = !decomp;

	if ((ftsp = fts_open(argv, FTS_PHYSICAL|FTS_NOCHDIR, 0)) == NULL)
		err(1, NULL);
	for (rc = SUCCESS; (entry = fts_read(ftsp)) != NULL;) {
		cat = cflag;
		pipin = 0;
		infile = entry->fts_path;
		if (infile[0] == '-' && infile[1] == '\0') {
			infile = "stdin";
			pipin++;
			if (!oflag)
				cat = 1;
		}
		else
			switch (entry->fts_info) {
			case FTS_D:
				if (!recurse) {
					warnx("%s is a directory: ignored",
					    infile);
					fts_set(ftsp, entry, FTS_SKIP);
				}
				continue;
			case FTS_DP:
				continue;
			case FTS_NS:
				/*
				 * If file does not exist and has no suffix,
				 * tack on the default suffix and try that.
				 */
				if (entry->fts_errno == ENOENT) {
					p = strrchr(entry->fts_accpath, '.');
					if ((p == NULL ||
					    strcmp(p, suffix) != 0) &&
					    snprintf(_infile, sizeof(_infile),
					    "%s%s", infile, suffix) <
					    sizeof(_infile) &&
					    stat(_infile, entry->fts_statp) ==
					    0 &&
					    S_ISREG(entry->fts_statp->st_mode)) {
						infile = _infile;
						break;
					}
				}
			case FTS_ERR:
			case FTS_DNR:
				warnx("%s: %s", infile,
				    strerror(entry->fts_errno));
				rc = rc ? rc : WARNING;
				continue;
			default:
				if (!S_ISREG(entry->fts_statp->st_mode) &&
				    !(S_ISLNK(entry->fts_statp->st_mode) &&
				    cat)) {
					warnx("%s not a regular file%s",
					    infile, cat ? "" : ": unchanged");
					rc = rc ? rc : WARNING;
					continue;
				}
				break;
			}

		if (!decomp && !pipin && (s = check_suffix(infile)) != NULL) {
			warnx("%s already has %s suffix -- unchanged",
			    infile, s);
			rc = rc ? rc : WARNING;
			continue;
		}

		if (!oflag) {
			if (cat)
				strlcpy(outfile, "stdout", sizeof(outfile));
			else if (decomp) {
				if (set_outfile(infile, outfile,
				    sizeof outfile) == NULL) {
					if (!recurse) {
						warnx("%s: unknown suffix: "
						    "ignored", infile);
						rc = rc ? rc : WARNING;
					}
					continue;
				}
			} else {
				if (snprintf(outfile, sizeof(outfile),
				    "%s%s", infile, suffix) >= sizeof(outfile)) {
					warnx("%s%s: name too long",
					    infile, suffix);
					rc = rc ? rc : WARNING;
					continue;
				}
			}
		}

		if (verbose > 0 && !pipin && !list)
			fprintf(stderr, "%s:\t", infile);

		error = (decomp ? dodecompress : docompress)
		    (infile, outfile, method, bits, entry->fts_statp);

		switch (error) {
		case SUCCESS:
			if (!cat && !testmode) {
				if (!pipin && unlink(infile) && verbose >= 0)
					warn("input: %s", infile);
			}
			break;
		case WARNING:
			rc = rc ? rc : WARNING;
			break;
		default:
			rc = FAILURE;
			break;
		}
	}
	if (list)
		list_stats(NULL, NULL, NULL);

	exit(rc);
}
Exemple #5
0
/*
 * Traverse() walks the logical directory structure specified by the argv list
 * in the order specified by the mastercmp() comparison function.  During the
 * traversal it passes linked lists of structures to display() which represent
 * a superset (may be exact set) of the files to be displayed.
 */
static void
traverse(int argc, char *argv[], int options)
{
	FTS *ftsp;
	FTSENT *p, *chp;
	int ch_options;

	if ((ftsp =
	    fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
		err(1, "fts_open");

	/*
	 * We ignore errors from fts_children here since they will be
	 * replicated and signalled on the next call to fts_read() below.
	 */
	chp = fts_children(ftsp, 0);
	if (chp != NULL)
		display(NULL, chp, options);
	if (f_listdir)
		return;

	/*
	 * If not recursing down this tree and don't need stat info, just get
	 * the names.
	 */
	ch_options = !f_recursive && !f_label &&
	    options & FTS_NOSTAT ? FTS_NAMEONLY : 0;

	while ((p = fts_read(ftsp)) != NULL)
		switch (p->fts_info) {
		case FTS_DC:
			warnx("%s: directory causes a cycle", p->fts_name);
			break;
		case FTS_DNR:
		case FTS_ERR:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_D:
			if (p->fts_level != FTS_ROOTLEVEL &&
			    p->fts_name[0] == '.' && !f_listdot)
				break;

			/*
			 * If already output something, put out a newline as
			 * a separator.  If multiple arguments, precede each
			 * directory with its name.
			 */
			if (output) {
				putchar('\n');
				(void)printname(p->fts_path);
				puts(":");
			} else if (argc > 1) {
				(void)printname(p->fts_path);
				puts(":");
				output = 1;
			}
			chp = fts_children(ftsp, ch_options);
			display(p, chp, options);

			if (!f_recursive && chp != NULL)
				(void)fts_set(ftsp, p, FTS_SKIP);
			break;
		default:
			break;
		}
	if (errno)
		err(1, "fts_read");
}
Exemple #6
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *p;
	void *set;
	int Hflag, Lflag, Rflag, ch, fflag;
	int fts_options, hflag, rval, vflag;
	char *mode;
	mode_t newmode;

	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
	while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			/*
			 * In System V (and probably POSIX.2) the -h option
			 * causes chmod to change the mode of the symbolic
			 * link.  4.4BSD's symbolic links didn't have modes,
			 * so it was an undocumented noop.  In FreeBSD 3.0,
			 * lchmod(2) is introduced and this option does real
			 * work.
			 */
			hflag = 1;
			break;
		/*
		 * XXX
		 * "-[rwx]" are valid mode commands.  If they are the entire
		 * argument, getopt has moved past them, so decrement optind.
		 * Regardless, we're done argument processing.
		 */
		case 'g': case 'o': case 'r': case 's':
		case 't': case 'u': case 'w': case 'X': case 'x':
			if (argv[optind - 1][0] == '-' &&
			    argv[optind - 1][1] == ch &&
			    argv[optind - 1][2] == '\0')
				--optind;
			goto done;
		case 'v':
			vflag++;
			break;
		case '?':
		default:
			usage();
		}
done:	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		if (hflag)
			errx(1, "the -R and -h options may not be "
			    "specified together.");
		if (Lflag) {
			fts_options = FTS_LOGICAL;
		} else {
			fts_options = FTS_PHYSICAL;

			if (Hflag) {
				fts_options |= FTS_COMFOLLOW;
			}
		}
	} else if (hflag) {
		fts_options = FTS_PHYSICAL;
	} else {
		fts_options = FTS_LOGICAL;
	}

	mode = *argv;
	errno = 0;
	if ((set = setmode(mode)) == NULL) {
		if (!errno)
			errx(1, "invalid file mode: %s", mode);
		else
			/* malloc for setmode() failed */
			err(1, "setmode failed");
	}

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, "fts_open");
	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		int atflag;

		if ((fts_options & FTS_LOGICAL) ||
		    ((fts_options & FTS_COMFOLLOW) &&
		    p->fts_level == FTS_ROOTLEVEL))
			atflag = 0;
		else
			atflag = AT_SYMLINK_NOFOLLOW;

		switch (p->fts_info) {
		case FTS_D:
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			break;
		case FTS_DNR:			/* Warn, chmod. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_DP:			/* Already changed at FTS_D. */
			continue;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		default:
			break;
		}
		newmode = getmode(set, p->fts_statp->st_mode);
		if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
			continue;
		if (fchmodat(AT_FDCWD, p->fts_accpath, newmode, atflag) == -1
		    && !fflag) {
			warn("%s", p->fts_path);
			rval = 1;
		} else if (vflag) {
			printf("%s", p->fts_path);

			if (vflag > 1) {
				char m1[12], m2[12];

				strmode(p->fts_statp->st_mode, m1);
				strmode((p->fts_statp->st_mode &
				    S_IFMT) | newmode, m2);
				printf(": 0%o [%s] -> 0%o [%s]",
				    p->fts_statp->st_mode, m1,
				    (p->fts_statp->st_mode & S_IFMT) |
				    newmode, m2);
			}
			printf("\n");
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #7
0
void
ftree_notsel()
{
    if (ftent != NULL)
        (void)fts_set(ftsp, ftent, FTS_SKIP);
}
Exemple #8
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *p;
	u_long clear, newflags, set;
	long val;
	int Hflag, Lflag, Rflag, fflag, hflag, vflag;
	int ch, fts_options, oct, rval;
	char *flags, *ep;

	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
	while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'v':
			vflag++;
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		if (hflag)
			errx(1, "the -R and -h options may not be "
			    "specified together.");
		if (Lflag) {
			fts_options = FTS_LOGICAL;
		} else {
			fts_options = FTS_PHYSICAL;

			if (Hflag) {
				fts_options |= FTS_COMFOLLOW;
			}
		}
	} else if (hflag) {
		fts_options = FTS_PHYSICAL;
	} else {
		fts_options = FTS_LOGICAL;
	}

	flags = *argv;
	if (*flags >= '0' && *flags <= '7') {
		errno = 0;
		val = strtol(flags, &ep, 8);
		if (val < 0)
			errno = ERANGE;
		if (errno)
                        err(1, "invalid flags: %s", flags);
                if (*ep)
                        errx(1, "invalid flags: %s", flags);
		set = val;
                oct = 1;
	} else {
		if (strtofflags(&flags, &set, &clear))
                        errx(1, "invalid flag: %s", flags);
		clear = ~clear;
		oct = 0;
	}

	if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
		err(1, NULL);

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		int atflag;

		if ((fts_options & FTS_LOGICAL) ||
		    ((fts_options & FTS_COMFOLLOW) &&
		    p->fts_level == FTS_ROOTLEVEL))
			atflag = 0;
		else
			atflag = AT_SYMLINK_NOFOLLOW;

		switch (p->fts_info) {
		case FTS_D:	/* Change it at FTS_DP if we're recursive. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chflags. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		default:
			break;
		}
		if (oct)
			newflags = set;
		else
			newflags = (p->fts_statp->st_flags | set) & clear;
		if (newflags == p->fts_statp->st_flags)
			continue;
		if (chflagsat(AT_FDCWD, p->fts_accpath, newflags,
		    atflag) == -1 && !fflag) {
			warn("%s", p->fts_path);
			rval = 1;
		} else if (vflag) {
			printf("%s", p->fts_path);
			if (vflag > 1)
				printf(": 0%lo -> 0%lo",
				    (u_long)p->fts_statp->st_flags,
				    newflags);
			printf("\n");
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #9
0
int
copy(rtems_shell_cp_globals* cp_globals,
     char *argv[], enum op type, int fts_options)
{
	struct stat to_stat;
	FTS *ftsp;
	FTSENT *curr;
	int base = 0, dne, badcp, rval;
	size_t nlen;
	char *p, *target_mid;
	mode_t mask, mode;

	/*
	 * Keep an inverted copy of the umask, for use in correcting
	 * permissions on created directories when not using -p.
	 */
	mask = ~umask(0777);
	umask(~mask);

	if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
		err(exit_jump, 1, "fts_open");
	for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
		switch (curr->fts_info) {
		case FTS_NS:
		case FTS_DNR:
		case FTS_ERR:
			warnx("%s: %s",
			    curr->fts_path, strerror(curr->fts_errno));
			badcp = rval = 1;
			continue;
		case FTS_DC:			/* Warn, continue. */
			warnx("%s: directory causes a cycle", curr->fts_path);
			badcp = rval = 1;
			continue;
		default:
			;
		}

		/*
		 * If we are in case (2) or (3) above, we need to append the
                 * source name to the target name.
                 */
		if (type != FILE_TO_FILE) {
			/*
			 * Need to remember the roots of traversals to create
			 * correct pathnames.  If there's a directory being
			 * copied to a non-existent directory, e.g.
			 *	cp -R a/dir noexist
			 * the resulting path name should be noexist/foo, not
			 * noexist/dir/foo (where foo is a file in dir), which
			 * is the case where the target exists.
			 *
			 * Also, check for "..".  This is for correct path
			 * concatenation for paths ending in "..", e.g.
			 *	cp -R .. /tmp
			 * Paths ending in ".." are changed to ".".  This is
			 * tricky, but seems the easiest way to fix the problem.
			 *
			 * XXX
			 * Since the first level MUST be FTS_ROOTLEVEL, base
			 * is always initialized.
			 */
			if (curr->fts_level == FTS_ROOTLEVEL) {
				if (type != DIR_TO_DNE) {
					p = strrchr(curr->fts_path, '/');
					base = (p == NULL) ? 0 :
					    (int)(p - curr->fts_path + 1);

					if (!strcmp(&curr->fts_path[base],
					    ".."))
						base += 1;
				} else
					base = curr->fts_pathlen;
			}

			p = &curr->fts_path[base];
			nlen = curr->fts_pathlen - base;
			target_mid = to.target_end;
			if (*p != '/' && target_mid[-1] != '/')
				*target_mid++ = '/';
			*target_mid = 0;
			if (target_mid - to.p_path + nlen >= PATH_MAX) {
				warnx("%s%s: name too long (not copied)",
				    to.p_path, p);
				badcp = rval = 1;
				continue;
			}
			(void)strncat(target_mid, p, nlen);
			to.p_end = target_mid + nlen;
			*to.p_end = 0;
			STRIP_TRAILING_SLASH(to);
		}

		if (curr->fts_info == FTS_DP) {
			/*
			 * We are nearly finished with this directory.  If we
			 * didn't actually copy it, or otherwise don't need to
			 * change its attributes, then we are done.
			 */
			if (!curr->fts_number)
				continue;
			/*
			 * If -p is in effect, set all the attributes.
			 * Otherwise, set the correct permissions, limited
			 * by the umask.  Optimise by avoiding a chmod()
			 * if possible (which is usually the case if we
			 * made the directory).  Note that mkdir() does not
			 * honour setuid, setgid and sticky bits, but we
			 * normally want to preserve them on directories.
			 */
			if (pflag) {
				if (setfile(cp_globals, curr->fts_statp, -1))
					rval = 1;
				if (preserve_dir_acls(curr->fts_statp,
				    curr->fts_accpath, to.p_path) != 0)
					rval = 1;
			} else {
				mode = curr->fts_statp->st_mode;
				if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
				    ((mode | S_IRWXU) & mask) != (mode & mask))
					if (chmod(to.p_path, mode & mask) != 0){
						warn("chmod: %s", to.p_path);
						rval = 1;
					}
			}
			continue;
		}

		/* Not an error but need to remember it happened */
		if (stat(to.p_path, &to_stat) == -1)
			dne = 1;
		else {
			if (to_stat.st_dev == curr->fts_statp->st_dev &&
			    to_stat.st_ino == curr->fts_statp->st_ino) {
				warnx("%s and %s are identical (not copied).",
				    to.p_path, curr->fts_path);
				badcp = rval = 1;
				if (S_ISDIR(curr->fts_statp->st_mode))
					(void)fts_set(ftsp, curr, FTS_SKIP);
				continue;
			}
			if (!S_ISDIR(curr->fts_statp->st_mode) &&
			    S_ISDIR(to_stat.st_mode)) {
				warnx("cannot overwrite directory %s with "
				    "non-directory %s",
				    to.p_path, curr->fts_path);
				badcp = rval = 1;
				continue;
			}
			dne = 0;
		}

		switch (curr->fts_statp->st_mode & S_IFMT) {
		case S_IFLNK:
			/* Catch special case of a non-dangling symlink */
			if ((fts_options & FTS_LOGICAL) ||
			    ((fts_options & FTS_COMFOLLOW) &&
			    curr->fts_level == 0)) {
				if (copy_file(cp_globals, curr, dne))
					badcp = rval = 1;
			} else {
				if (copy_link(cp_globals, curr, !dne))
					badcp = rval = 1;
			}
			break;
		case S_IFDIR:
			if (!Rflag) {
				warnx("%s is a directory (not copied).",
				    curr->fts_path);
				(void)fts_set(ftsp, curr, FTS_SKIP);
				badcp = rval = 1;
				break;
			}
			/*
			 * If the directory doesn't exist, create the new
			 * one with the from file mode plus owner RWX bits,
			 * modified by the umask.  Trade-off between being
			 * able to write the directory (if from directory is
			 * 555) and not causing a permissions race.  If the
			 * umask blocks owner writes, we fail..
			 */
			if (dne) {
				if (mkdir(to.p_path,
				    curr->fts_statp->st_mode | S_IRWXU) < 0)
					err(exit_jump, 1, "%s", to.p_path);
			} else if (!S_ISDIR(to_stat.st_mode)) {
				errno = ENOTDIR;
				err(exit_jump, 1, "%s", to.p_path);
			}
			/*
			 * Arrange to correct directory attributes later
			 * (in the post-order phase) if this is a new
			 * directory, or if the -p flag is in effect.
			 */
			curr->fts_number = pflag || dne;
			break;
		case S_IFBLK:
		case S_IFCHR:
			if (Rflag) {
				if (copy_special(cp_globals, curr->fts_statp, !dne))
					badcp = rval = 1;
			} else {
				if (copy_file(cp_globals, curr, dne))
					badcp = rval = 1;
			}
			break;
		case S_IFSOCK:
			warnx("%s is a socket (not copied).",
				    curr->fts_path);
		case S_IFIFO:
			if (Rflag) {
				if (copy_fifo(cp_globals, curr->fts_statp, !dne))
					badcp = rval = 1;
			} else {
				if (copy_file(cp_globals, curr, dne))
					badcp = rval = 1;
			}
			break;
		default:
			if (copy_file(cp_globals, curr, dne))
				badcp = rval = 1;
			break;
		}
		if (vflag && !badcp)
			(void)printf("%s -> %s\n", curr->fts_path, to.p_path);
	}
	if (errno)
		err(exit_jump, 1, "fts_read");
	fts_close(ftsp);
	return (rval);
}
Exemple #10
0
int restorecon_main(int argc, char **argv) {
	int recurse = 0, ftsflags = FTS_PHYSICAL;

	progname = argv[0];

	while(1) {
		int ch = getopt(argc, argv, "hnrRv");
		if(ch == EOF) break;
		switch(ch) {
			case 'h':
				usage();
				return 0;
			case 'n':
				nochange = 1;
				break;
			case 'r':
			case 'R':
				recurse = 1;
				break;
			case 'v':
				verbose = 1;
				break;
			default:
				usage();
				return 1;
		}
	}

	argc -= optind;
	argv += optind;
	if(!argc) {
		usage();
		return -1;
	}
	if(recurse) {
		FTS *fts;
		FTSENT *ftsent;
		fts = fts_open(argv, ftsflags, NULL);
		if(!fts) {
			fprintf(stderr, "Could not traverse filesystems (first was %s):  %s\n",
					argv[0], strerror(errno));
			return -1;
		}
		while((ftsent = fts_read(fts))) {
			switch (ftsent->fts_info) {
				case FTS_DP:
					break;
				case FTS_DNR:
				case FTS_ERR:
				case FTS_NS:
					fprintf(stderr, "Could not access %s:  %s\n", ftsent->fts_path,
							strerror(errno));
					fts_set(fts, ftsent, FTS_SKIP);
					break;
				default:
					if (restore(ftsent->fts_path, ftsent->fts_statp) < 0)
						fts_set(fts, ftsent, FTS_SKIP);
					break;
			}
		}
	} else {
		int i, rc;
		struct stat sb;

		for(i = 0; i < argc; i++) {
			rc = lstat(argv[i], &sb);
			if(rc < 0) {
				fprintf(stderr, "Could not stat %s:  %s\n", argv[i], strerror(errno));
				continue;
			}
			restore(argv[i], &sb);
		}
	}

	return 0;
}
Exemple #11
0
void
cwalk(void)
{
	FTS *t;
	FTSENT *p;
	time_t clocktime;
	char host[MAXHOSTNAMELEN + 1];
	const char *user;
	char *argv[2];
	char  dot[] = ".";
	int indent = 0;

	argv[0] = dot;
	argv[1] = NULL;

	time(&clocktime);
	gethostname(host, sizeof(host));
	host[sizeof(host) - 1] = '\0';
	if ((user = getlogin()) == NULL) {
		struct passwd *pw;
		user = (pw = getpwuid(getuid())) == NULL ? pw->pw_name :
		    "<unknown>";
	}

	if (!nflag)
		printf(
	    	    "#\t   user: %s\n#\tmachine: %s\n#\t   tree: %s\n"
		    "#\t   date: %s",
		    user, host, fullpath, ctime(&clocktime));

	if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL)
		mtree_err("fts_open: %s", strerror(errno));
	while ((p = fts_read(t)) != NULL) {
		if (jflag)
			indent = p->fts_level * 4;
		if (check_excludes(p->fts_name, p->fts_path)) {
			fts_set(t, p, FTS_SKIP);
			continue;
		}
		if (!find_only(p->fts_path)) {
			fts_set(t, p, FTS_SKIP);
			continue;
		}
		switch(p->fts_info) {
		case FTS_D:
			if (!bflag)
				printf("\n");
			if (!nflag)
				printf("# %s\n", p->fts_path);
			statd(t, p, &uid, &gid, &mode, &flags);
			statf(indent, p);
			break;
		case FTS_DP:
			if (p->fts_level > 0)
				if (!nflag)
					printf("%*s# %s\n", indent, "",
					    p->fts_path);
			if (p->fts_level > 0 || flavor == F_FREEBSD9) {
				printf("%*s..\n", indent, "");
				if (!bflag)
					printf("\n");
			}
			break;
		case FTS_DNR:
		case FTS_ERR:
		case FTS_NS:
			mtree_err("%s: %s",
			    p->fts_path, strerror(p->fts_errno));
			break;
		default:
			if (!dflag)
				statf(indent, p);
			break;

		}
	}
	fts_close(t);
	if (sflag && keys & F_CKSUM)
		mtree_err("%s checksum: %u", fullpath, crc_total);
}
Exemple #12
0
rm_tree(char **argv)
#endif
{
	FTS *fts;
	FTSENT *p;
	int needstat;
	int rval;

	/*
	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
	 */
	needstat = !uid || !fflag && !iflag && stdin_ok;

	/*
	 * If the -i option is specified, the user can skip on the pre-order
	 * visit.  The fts_number field flags skipped directories.
	 */
#define	SKIPPED	1

	if (!(fts = fts_open(argv,
	    needstat ? FTS_PHYSICAL|FTS_NOCHDIR :
		FTS_PHYSICAL|FTS_NOSTAT|FTS_NOCHDIR, (int (*)())NULL)))
		err(1, NULL);
	while ((p = fts_read(fts)) != NULL) {
		switch (p->fts_info) {
		case FTS_DNR:
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_ERR:
			errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
		case FTS_NS:
			/*
			 * FTS_NS: assume that if can't stat the file, it
			 * can't be unlinked.
			 */
			if (!needstat)
				break;
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_D:
			/* Pre-order: give user chance to skip. */
			if (iflag && !check(p->fts_path, p->fts_accpath,
			    p->fts_statp)) {
				(void)fts_set(fts, p, FTS_SKIP);
				p->fts_number = SKIPPED;
			}
#ifndef __GNO__
			else if (!uid &&
				 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
				 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
				 chflags(p->fts_accpath,
					 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
				goto err;
#endif
			continue;
		case FTS_DP:
			/* Post-order: see if user skipped. */
			if (p->fts_number == SKIPPED)
				continue;
			break;
		}
		if (!fflag &&
		    !check(p->fts_path, p->fts_accpath, p->fts_statp))
			continue;

		rval = 0;
#ifndef __GNO__
		if (!uid &&
		    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
		    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
			rval = chflags(p->fts_accpath,
				       p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
#endif
		if (!rval) {
			/*
			 * If we can't read or search the directory, may still be
			 * able to remove it.  Don't print out the un{read,search}able
			 * message unless the remove fails.
			 */
			if (p->fts_info == FTS_DP || p->fts_info == FTS_DNR) {
				if (!rmdir(p->fts_accpath))
					continue;
				if (errno == ENOENT) {
					if (fflag)
						continue;
				} else if (p->fts_info != FTS_DP)
					warnx("%s: unable to read", p->fts_path);
			} else {
				if (Pflag)
					rm_overwrite(p->fts_accpath, NULL);
				if (!unlink(p->fts_accpath) || (fflag && errno == ENOENT))
					continue;
			}
		}
err:
		warn("%s", p->fts_path);
		eval = 1;
	}
	if (errno)
		err(1, "fts_read");
}
Exemple #13
0
int
main(int argc, char **argv)
{
	FTS *ftsp;
	FTSENT *p;
	int Hflag, Lflag, Rflag, fflag, hflag, vflag, xflag;
	int ch, fts_options, rval;
	char *cp;

	ischown = (strcmp(basename(argv[0]), "chown") == 0);

	Hflag = Lflag = Rflag = fflag = hflag = vflag = xflag = 0;
	while ((ch = getopt(argc, argv, "HLPRfhvx")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'v':
			vflag++;
			break;
		case 'x':
			xflag = 1;
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		fts_options = FTS_PHYSICAL;
		if (hflag && (Hflag || Lflag))
			errx(1, "the -R%c and -h options may not be "
			    "specified together", Hflag ? 'H' : 'L');
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		else if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	} else
		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
	if (xflag)
		fts_options |= FTS_XDEV;

	uid = (uid_t)-1;
	gid = (gid_t)-1;
	if (ischown) {
		if ((cp = strchr(*argv, ':')) != NULL) {
			*cp++ = '\0';
			a_gid(cp);
		}
#ifdef SUPPORT_DOT
		else if ((cp = strchr(*argv, '.')) != NULL) {
			warnx("separation of user and group with a period is deprecated");
			*cp++ = '\0';
			a_gid(cp);
		}
#endif
		a_uid(*argv);
	} else
		a_gid(*argv);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, NULL);

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D:			/* Change it at FTS_DP. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chown. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		case FTS_SL:
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything and ones that we found
			 * doing a physical walk.
			 */
			if (hflag)
				break;
			else
				continue;
		default:
			break;
		}
		if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
		    (gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
			continue;
		if ((hflag ? lchown : chown)(p->fts_accpath, uid, gid) == -1) {
			if (!fflag) {
				chownerr(p->fts_path);
				rval = 1;
			}
		} else {
			if (vflag) {
				printf("%s", p->fts_path);
				if (vflag > 1) {
					if (ischown) {
						printf(": %ju:%ju -> %ju:%ju",
						    (uintmax_t)
						    p->fts_statp->st_uid, 
						    (uintmax_t)
						    p->fts_statp->st_gid,
						    (uid == (uid_t)-1) ? 
						    (uintmax_t)
						    p->fts_statp->st_uid : 
						    (uintmax_t)uid,
						    (gid == (gid_t)-1) ? 
						    (uintmax_t)
						    p->fts_statp->st_gid :
						    (uintmax_t)gid);
					} else {
						printf(": %ju -> %ju",
						    (uintmax_t)
						    p->fts_statp->st_gid,
						    (gid == (gid_t)-1) ? 
						    (uintmax_t)
						    p->fts_statp->st_gid : 
						    (uintmax_t)gid);
					}
				}
				printf("\n");
			}
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #14
0
int
copy(char *argv[], enum op type, int fts_options)
{
	struct stat to_stat;
	FTS *ftsp;
	FTSENT *curr;
	int base, dne, sval;
	int this_failed, any_failed;
	size_t nlen;
	char *p, *target_mid;

	dne = 0;
	base = 0;	/* XXX gcc -Wuninitialized (see comment below) */

	if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
		err(EXIT_FAILURE, "%s", argv[0]);
		/* NOTREACHED */
	for (any_failed = 0; (curr = fts_read(ftsp)) != NULL;) {
		this_failed = 0;
		switch (curr->fts_info) {
		case FTS_NS:
		case FTS_DNR:
		case FTS_ERR:
			warnx("%s: %s", curr->fts_path,
					strerror(curr->fts_errno));
			this_failed = any_failed = 1;
			continue;
		case FTS_DC:			/* Warn, continue. */
			warnx("%s: directory causes a cycle", curr->fts_path);
			this_failed = any_failed = 1;
			continue;
		}

		/*
		 * If we are in case (2) or (3) above, we need to append the 
                 * source name to the target name.  
                 */
		if (type != FILE_TO_FILE) {
			if ((curr->fts_namelen +
			    to.target_end - to.p_path + 1) > MAXPATHLEN) {
				warnx("%s/%s: name too long (not copied)",
						to.p_path, curr->fts_name);
				this_failed = any_failed = 1;
				continue;
			}

			/*
			 * Need to remember the roots of traversals to create
			 * correct pathnames.  If there's a directory being
			 * copied to a non-existent directory, e.g.
			 *	cp -R a/dir noexist
			 * the resulting path name should be noexist/foo, not
			 * noexist/dir/foo (where foo is a file in dir), which
			 * is the case where the target exists.
			 *
			 * Also, check for "..".  This is for correct path
			 * concatentation for paths ending in "..", e.g.
			 *	cp -R .. /tmp
			 * Paths ending in ".." are changed to ".".  This is
			 * tricky, but seems the easiest way to fix the problem.
			 *
			 * XXX
			 * Since the first level MUST be FTS_ROOTLEVEL, base
			 * is always initialized.
			 */
			if (curr->fts_level == FTS_ROOTLEVEL) {
				if (type != DIR_TO_DNE) {
					p = strrchr(curr->fts_path, '/');
					base = (p == NULL) ? 0 : 
					    (int)(p - curr->fts_path + 1);

					if (!strcmp(&curr->fts_path[base], 
					    ".."))
						base += 1;
				} else
					base = curr->fts_pathlen;
			}

			p = &curr->fts_path[base];
			nlen = curr->fts_pathlen - base;
			target_mid = to.target_end;
			if (*p != '/' && target_mid[-1] != '/')
				*target_mid++ = '/';
			*target_mid = 0;

			if (target_mid - to.p_path + nlen >= PATH_MAX) {
				warnx("%s%s: name too long (not copied)",
				    to.p_path, p);
				this_failed = any_failed = 1;
				continue;
			}
			(void)strncat(target_mid, p, nlen);
			to.p_end = target_mid + nlen;
			*to.p_end = 0;
			STRIP_TRAILING_SLASH(to);
		}

		sval = Pflag ? lstat(to.p_path, &to_stat) : stat(to.p_path, &to_stat);
		/* Not an error but need to remember it happened */
		if (sval == -1)
			dne = 1;
		else {
			if (to_stat.st_dev == curr->fts_statp->st_dev &&
			    to_stat.st_ino == curr->fts_statp->st_ino) {
				warnx("%s and %s are identical (not copied).",
				    to.p_path, curr->fts_path);
				this_failed = any_failed = 1;
				if (S_ISDIR(curr->fts_statp->st_mode))
					(void)fts_set(ftsp, curr, FTS_SKIP);
				continue;
			}
			if (!S_ISDIR(curr->fts_statp->st_mode) &&
			    S_ISDIR(to_stat.st_mode)) {
		warnx("cannot overwrite directory %s with non-directory %s",
				    to.p_path, curr->fts_path);
				this_failed = any_failed = 1;
				continue;
			}
			if (!S_ISDIR(curr->fts_statp->st_mode))
				dne = 0;
		}

		switch (curr->fts_statp->st_mode & S_IFMT) {
		case S_IFLNK:
			/* Catch special case of a non dangling symlink */
			if((fts_options & FTS_LOGICAL) ||
			   ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
				if (copy_file(curr, dne))
					this_failed = any_failed = 1;
			} else {	
				if (copy_link(curr, !dne))
					this_failed = any_failed = 1;
			}
			break;
		case S_IFDIR:
			if (!Rflag && !rflag) {
				if (curr->fts_info == FTS_D)
					warnx("%s is a directory (not copied).",
					    curr->fts_path);
				(void)fts_set(ftsp, curr, FTS_SKIP);
				this_failed = any_failed = 1;
				break;
			}

                        /*
                         * Directories get noticed twice:
                         *  In the first pass, create it if needed.
                         *  In the second pass, after the children have been copied, set the permissions.
                         */
			if (curr->fts_info == FTS_D) /* First pass */
			{
				/*
				 * If the directory doesn't exist, create the new
				 * one with the from file mode plus owner RWX bits,
				 * modified by the umask.  Trade-off between being
				 * able to write the directory (if from directory is
				 * 555) and not causing a permissions race.  If the
				 * umask blocks owner writes, we fail..
				 */
				if (dne) {
					if (mkdir(to.p_path, 
					    curr->fts_statp->st_mode | S_IRWXU) < 0)
						err(EXIT_FAILURE, "%s",
						    to.p_path);
						/* NOTREACHED */
				} else if (!S_ISDIR(to_stat.st_mode)) {
					errno = ENOTDIR;
					err(EXIT_FAILURE, "%s",
						to.p_path);
					/* NOTREACHED */
				}
			}
			else if (curr->fts_info == FTS_DP) /* Second pass */
			{
	                        /*
				 * If not -p and directory didn't exist, set it to be
				 * the same as the from directory, umodified by the 
                        	 * umask; arguably wrong, but it's been that way 
                        	 * forever.
				 */
				if (pflag && setfile(curr->fts_statp, 0))
					this_failed = any_failed = 1;
				else if (dne)
					(void)chmod(to.p_path, 
					    curr->fts_statp->st_mode);

				/*
				 * Since this is the second pass, we already
				 * noted (and acted on) the existence of the
				 * directory.
				 */
				dne = 0;
			}
			else
			{
				warnx("directory %s encountered when not expected.",
				    curr->fts_path);
				this_failed = any_failed = 1;
				break;
			}

			break;
		case S_IFBLK:
		case S_IFCHR:
			if (Rflag) {
				if (copy_special(curr->fts_statp, !dne))
					this_failed = any_failed = 1;
			} else
				if (copy_file(curr, dne))
					this_failed = any_failed = 1;
			break;
		case S_IFIFO:
			if (Rflag) {
				if (copy_fifo(curr->fts_statp, !dne))
					this_failed = any_failed = 1;
			} else 
				if (copy_file(curr, dne))
					this_failed = any_failed = 1;
			break;
		default:
			if (copy_file(curr, dne))
				this_failed = any_failed = 1;
			break;
		}
		if (vflag && !this_failed)
			(void)printf("%s -> %s\n", curr->fts_path, to.p_path);
	}
	if (errno) {
		err(EXIT_FAILURE, "fts_read");
		/* NOTREACHED */
	}
	(void)fts_close(ftsp);
	return (any_failed);
}
Exemple #15
0
static void GetFileList(char *path) {
struct stat stat_buf;
char *last_file_ptr, *first_path, *last_path;
int levels_first_file, levels_last_file, file_list_level;
int	sub_index;

FTS *fts;
FTSENT *ftsent;

	CleanPath(path);

	// Check for last_file option
	last_file_ptr = strchr(path, ':');
	first_path = last_path = NULL;
	levels_first_file =  levels_last_file = 0;
	if ( last_file_ptr ) {
		// make sure we have only a single ':' in path
		if ( strrchr(path, ':') != last_file_ptr ) {
			fprintf(stderr, "Multiple file separators ':' in path not allowed!\n");
			exit(250);
		}
		*last_file_ptr++ = '\0';
		// last_file_ptr points to last_file

		if ( strlen(last_file_ptr) == 0 ) {
			fprintf(stderr, "Missing last file option after ':'!\n");
			exit(250);
		}
	
		CleanPath(last_file_ptr);
		// make sure last_file option is not a full path
		if ( last_file_ptr[0] == '/') {
			fprintf(stderr, "Last file name in -R list must not start with '/'\n");
			exit(250);
		}
		// how may sub dir levels has last_file option?
		levels_last_file  = dirlevels(last_file_ptr);

		// if no subdirs are given for last_file, try to find out, if the last_file
		// exists in any possible subdirs
		if ( levels_last_file == 0 ) {
			char s[MAXPATHLEN];
			char *r = VerifyFileRange(path, last_file_ptr);

			if ( r != last_file_ptr && r[0] != '\0' ) {
				snprintf(s, MAXPATHLEN-1, "%s/%s", r, last_file_ptr);
				s[MAXPATHLEN-1] = '\0';
				last_file_ptr = strdup(s);
				levels_last_file  = dirlevels(last_file_ptr);
			}
		}

	}

	levels_first_file = dirlevels(path);

	if ( source_dirs.num_strings == 0 ) {
		// No multiple sources option -M

		// path contains the path to a file/directory
		// stat this entry
		if ( stat(path, &stat_buf) ) {
			fprintf(stderr, "stat() error '%s': %s\n", path, strerror(errno));
			exit(250);
		}
		if ( !S_ISDIR(stat_buf.st_mode) && !S_ISREG(stat_buf.st_mode) ) {
			fprintf(stderr, "Not a file or directory: '%s'\n", path);
			exit(250);
		}

		// Check, how many levels of directory in path
		levels_first_file = dirlevels(path);

		if ( last_file_ptr ) {
			// path is [/]path/to/any/dir|file:last_file_ptr

			// make sure first_file is a file
			if ( S_ISDIR(stat_buf.st_mode) ) {
				fprintf(stderr, "Not a file: '%s'\n", path);
				exit(250);
			}

			if ( levels_last_file ) {
				// we have levels_last_file number of sub dirs 
	
				// sub dir levels of first_file mus have at least the same number of levels as last_file
				if ( levels_first_file < levels_last_file ) {
					fprintf(stderr, "Number of sub dirs for sub level hierarchy for file list -R do not match\n");
					exit(250);
				}
				if ( levels_first_file == levels_last_file ) {
					char *p, *q;
					// path = [/]sub1[/..]/first_file:sub1[/...]/last_file
					if ( path[0] == '/' ) {
						// this is rather strange, but strctly spoken, valid anyway
						InsertString(&source_dirs, "/");
						path++;
					} else {
						InsertString(&source_dirs, ".");
					}

					// path = sub_first[/..]/first_file:sub_last[/...]/last_file
					p = strrchr(path, '/');
					q = strrchr(last_file_ptr, '/');
					if ( !p || !q ) {
						// this should never happen
						fprintf(stderr, "software error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
						exit(250);
					}
					*p++ = '\0';
					*q++ = '\0';
					first_file = strdup(p);
					last_file = strdup(q);
					file_list_level = levels_last_file + 1;
					first_path = path;
					last_path  = last_file_ptr;
					
				} else {
					// path = [/]path/to/sub_first[/..]/first_file:sub_last[/...]/last_file
					int i;
					char *p, *r, *s;

					p = strrchr(path, '/');
					// levels_first_file > levels_last_file

					// step back the number of sub dirs in first_file
					for ( i=0; i<levels_last_file; i++ ) {
						do {
							p--;
						} while ( p >= path && *p != '/');
					}
					*p++ = '\0';
					
					InsertString(&source_dirs, path);

					r = strrchr(p, '/');
					s = strrchr(last_file_ptr, '/');
					if ( !r || !s ) {
						// this must never happen
						fprintf(stderr, "software error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
						exit(250);
					}
					*r++ = '\0';
					*s++ = '\0';
					first_file = strdup(r);
					last_file = strdup(s);
					// files are listed at this sub dir level
					file_list_level = levels_last_file + 1;
					first_path = p;
					last_path  = last_file_ptr;

				}

			} else {
				// we have no sub dir levels given

				// path is [/]path/to/any/file
				char *p = strrchr(path, '/');

				if ( p ) {
					// path is [/]path/to/any/first_file:last_file
					*p++ = '\0';
					// path is the direcory containing all the files
					InsertString(&source_dirs, path);
					first_file = strdup(p);
				} else {
					// path is first_file:last_file
					InsertString(&source_dirs, ".");
					first_file = strdup(path);
				}
				// set last_file filter
				last_file  = strdup(last_file_ptr);
				// in any case we list the files of directory level 1
				file_list_level = 1;
			}
		} else {
			// path is [/]path/to/any/dir|file
			if ( S_ISDIR(stat_buf.st_mode) ) {
				// path is [/]path/to/any/dir
				// list all files in this directory
				InsertString(&source_dirs, path);
				first_file = NULL;
				file_list_level = 0;
			} else {
				// path is [/]path/to/any/file
				char *p = strrchr(path, '/');
				if ( p ) {
					// path is [/]path/to/any/file
					*p++ = '\0';
					// path is the direcory containing all the files
					InsertString(&source_dirs, path);
					first_file = strdup(p);
				} else {
					// path is file
					InsertString(&source_dirs, ".");
					first_file = strdup(path);
				}
				// in any case we list the files of directory level 1
				file_list_level = 1;
			}
			// in any case, no last_file filter
			last_file  = NULL;
		}

	} else {
		char pathbuff[MAXPATHLEN];
		// multiple sources option -M given
		if ( path[0] == '/') {
			fprintf(stderr, "File list -R must not start with '/' when combined with a source list -M\n");
			exit(250);
		}

		// special case for all files in directory
		if ( strcmp(path, ".") == 0 ) {
			first_file = NULL;
			last_file  = NULL;
			file_list_level = 0;
		} else {
			// pathbuff contains the path to a file/directory, compiled using the first entry
			// in the source_dirs
			snprintf(pathbuff, MAXPATHLEN-1, "%s/%s", source_dirs.list[0], path);
			pathbuff[MAXPATHLEN-1] = '\0';
	
			// pathbuff must point to a file
			if ( stat(pathbuff, &stat_buf) ) {
				if ( errno == ENOENT ) {
					// file not found - try to guess a possible subdir
					char *sub_dir = GuessSubDir(source_dirs.list[0], path);
					if ( sub_dir ) {	// subdir found
						snprintf(pathbuff, MAXPATHLEN-1, "%s/%s", sub_dir, path);
						pathbuff[MAXPATHLEN-1] = '\0';
						// update path
						path = strdup(pathbuff);
						free(sub_dir);
	
						// need guessing subdir with last_file too
						if ( last_file_ptr ) {
							sub_dir = GuessSubDir(source_dirs.list[0], last_file_ptr);
							if ( sub_dir ) {	// subdir found
								snprintf(pathbuff, MAXPATHLEN-1, "%s/%s", sub_dir, last_file_ptr);
								pathbuff[MAXPATHLEN-1] = '\0';
								last_file_ptr = strdup(pathbuff);
								free(sub_dir);
	
								// update dir levels of extended file path
								levels_last_file  = dirlevels(last_file_ptr);
							} else {
								fprintf(stderr, "'%s': %s\n", last_file_ptr, "File not found!");
								exit(250);
							}
						}
	
					} else {	// no file in any possible subdir found
						fprintf(stderr, "stat() error '%s': %s\n", pathbuff, "File not found!");
						exit(250);
					}
				} else {	// Any other stat error
					fprintf(stderr, "stat() error '%s': %s\n", pathbuff, strerror(errno));
					exit(250);
				}
			} else if ( !S_ISREG(stat_buf.st_mode) ) {
				fprintf(stderr, "Not a file : '%s'\n", pathbuff);
				exit(250);
			}

			// Check, how many levels of directory in path
			levels_first_file = dirlevels(path);

			if ( last_file_ptr ) {
				// path is path/to/any/first_file:last_file_ptr
				char *p, *q;
	
				// the number of sub dirs must be eqal for first_file and last_file
				if ( levels_first_file != levels_last_file ) {
					fprintf(stderr, "Number of sub dirs must agree in '%s' and '%s'\n", path, last_file_ptr);
					exit(250);
				}
	
				p = strrchr(path, '/');
				if ( p ) {
					// path is fist_sub/to/any/first_file
					// recursive all files in sub dirs
					file_list_level = dirlevels(path) + 1;
					*p++ = '\0';
					first_file = strdup(p);
					first_path = path;
				} else {
					// path is first_file
					first_file = strdup(path);
					file_list_level = 1;
				}

				q = strrchr(last_file_ptr, '/');
				if ( q ) {
					*q++ = '\0';
					last_file = strdup(q);
					last_path  = last_file_ptr;
				} else {
					last_file = strdup(last_file_ptr);
				}
	
			} else {
				// path is path/to/any/first_file
				char *p = strrchr(path, '/');
				if ( p ) {
					// path is fist_sub/to/any/first_file
					// recursive all files in sub dirs
					file_list_level = dirlevels(path) + 1;
					*p++ = '\0';
					first_file = strdup(p);
					first_path = path;
				} else {
					// path is first_file
					first_file = strdup(path);
					file_list_level = 1;
				}
				last_file  = NULL;
			}
		}
	}

/*
printf("first_file %s\n", first_file ? first_file : "<none>");
printf("last_file %s\n", last_file ? last_file : "<none>");
printf("first_path %s\n", first_path ? first_path : "<none>");
printf("last_path %s\n", last_path ? last_path : "<none>");
printf("file_list_level: %i\n", file_list_level);
*/
	CreateDirListFilter(first_path, last_path, file_list_level );

	// last entry must be NULL
	InsertString(&source_dirs, NULL);
	fts = fts_open(source_dirs.list, FTS_LOGICAL,  compare);
	sub_index = 0;
	while ( (ftsent = fts_read(fts)) != NULL) {
		int fts_level = ftsent->fts_level;
		char *fts_path;

// printf("DBG: %u %i %s %s\n", ftsent->fts_info, ftsent->fts_level, ftsent->fts_path, ftsent->fts_name);

		if ( fts_level == 0 ) {
			sub_index = ftsent->fts_pathlen + 1;
			continue;
		}

		if ( ftsent->fts_pathlen < sub_index ) {
			printf("ERROR: fts_pathlen error at %s line %d\n", __FILE__, __LINE__);
			exit(250);
		}
		fts_path = &ftsent->fts_path[sub_index];

/*
if ( file_list_level ) 
printf("DGB: short fts: '%s', filer_first: '%s', filter_last: '%s'\n", 
					fts_path, dir_entry_filter[fts_level].first_entry , dir_entry_filter[fts_level].last_entry);
*/
		switch (ftsent->fts_info) {
			case FTS_D:
				// dir entry pre descend
				if ( file_list_level && file_list_level && (
					( dir_entry_filter[fts_level].first_entry &&
						( strcmp(fts_path, dir_entry_filter[fts_level].first_entry ) < 0 ) ) ||
					( dir_entry_filter[fts_level].last_entry && 
					  	( strcmp(fts_path, dir_entry_filter[fts_level].last_entry ) > 0 ) ) 
				   ))
					fts_set(fts, ftsent, FTS_SKIP );

				break;
			case FTS_DP:
				break;
			case FTS_F:
				// file entry
// printf("==> Check: %s\n", ftsent->fts_name);

				// skip stat file
				if ( strcmp(ftsent->fts_name, ".nfstat") == 0 ||
					 strncmp(ftsent->fts_name, NF_DUMPFILE , strlen(NF_DUMPFILE)) == 0)
					continue;
				if ( strstr(ftsent->fts_name, ".stat") != NULL )
					continue;
				// skip pcap file
				if ( strstr(ftsent->fts_name, "pcap") != NULL )
					continue;

				if ( file_list_level && (
					( fts_level != file_list_level ) ||
					( dir_entry_filter[fts_level].first_entry && 
						( strcmp(ftsent->fts_name, dir_entry_filter[fts_level].first_entry) < 0 ) ) ||
					( dir_entry_filter[fts_level].last_entry &&
					  	( strcmp(ftsent->fts_name, dir_entry_filter[fts_level].last_entry) > 0 ) )
				   ) )
					continue;

// printf("==> Listed: %s\n", ftsent->fts_path);
				InsertString(&file_list, ftsent->fts_path);

				break;
		}

	}
    fts_close(fts);

} // End of GetFileList
Exemple #16
0
int
kmk_builtin_chmod(int argc, char *argv[], char **envp)
{
	FTS *ftsp;
	FTSENT *p;
	mode_t *set;
	int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval;
	int vflag;
	char *mode;
	mode_t newmode;
	int (*change_mode)(const char *, mode_t);

	/* kmk: reset getopt and set progname */
	g_progname = argv[0];
	opterr = 1;
	optarg = NULL;
	optopt = 0;
	optind = 0; /* init */

	set = NULL;
	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
	while ((ch = getopt_long(argc, argv, "HLPRXfghorstuvwx", long_options, NULL)) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			/*
			 * In System V (and probably POSIX.2) the -h option
			 * causes chmod to change the mode of the symbolic
			 * link.  4.4BSD's symbolic links didn't have modes,
			 * so it was an undocumented noop.  In FreeBSD 3.0,
			 * lchmod(2) is introduced and this option does real
			 * work.
			 */
			hflag = 1;
			break;
		/*
		 * XXX
		 * "-[rwx]" are valid mode commands.  If they are the entire
		 * argument, getopt has moved past them, so decrement optind.
		 * Regardless, we're done argument processing.
		 */
		case 'g': case 'o': case 'r': case 's':
		case 't': case 'u': case 'w': case 'X': case 'x':
			if (argv[optind - 1][0] == '-' &&
			    argv[optind - 1][1] == ch &&
			    argv[optind - 1][2] == '\0')
				--optind;
			goto done;
		case 'v':
			vflag++;
			break;
		case 261:
			usage(stdout);
			return 0;
		case 262:
			return kbuild_version(argv[0]);
		case '?':
		default:
			return usage(stderr);
		}
done:	argv += optind;
	argc -= optind;

	if (argc < 2)
		return usage(stderr);

	if (Rflag) {
		fts_options = FTS_PHYSICAL;
		if (hflag)
			return errx(1,
		"the -R and -h options may not be specified together.");
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	} else
		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;

	if (hflag)
		change_mode = lchmod;
	else
		change_mode = chmod;

	mode = *argv;
	if ((set = bsd_setmode(mode)) == NULL)
		return errx(1, "invalid file mode: %s", mode);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		return err(1, "fts_open");
	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D:			/* Change it at FTS_DP. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chmod, continue. */
			warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		case FTS_SL:			/* Ignore. */
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything and ones that we found
			 * doing a physical walk.
			 */
			if (!hflag)
				continue;
			/* else */
			/* FALLTHROUGH */
		default:
			break;
		}
		newmode = bsd_getmode(set, p->fts_statp->st_mode);
		if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
			continue;
		if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
			warn("%schmod: %s", hflag ? "l" : "", p->fts_path);
			rval = 1;
		} else {
			if (vflag) {
				(void)printf("%s", p->fts_path);

				if (vflag > 1) {
					char m1[12], m2[12];

					bsd_strmode(p->fts_statp->st_mode, m1);
					bsd_strmode((p->fts_statp->st_mode &
					    S_IFMT) | newmode, m2);

					(void)printf(": 0%o [%s] -> 0%o [%s]",
					    (unsigned int)p->fts_statp->st_mode, m1,
					    (unsigned int)((p->fts_statp->st_mode & S_IFMT) | newmode), m2);
				}
				(void)printf("\n");
			}

		}
	}
	if (errno)
		rval = err(1, "fts_read");
	free(set);
	fts_close(ftsp);
	return rval;
}
Exemple #17
0
/*
 * Processes a directory when a recursive search is performed with
 * the -R option.  Each appropriate file is passed to procfile().
 */
int
grep_tree(char **argv)
{
	FTS *fts;
	FTSENT *p;
	int c, fts_flags;
	bool ok;

	c = fts_flags = 0;

	switch(linkbehave) {
	case LINK_EXPLICIT:
		fts_flags = FTS_COMFOLLOW;
		break;
	case LINK_SKIP:
		fts_flags = FTS_PHYSICAL;
		break;
	default:
		fts_flags = FTS_LOGICAL;
			
	}

	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;

	if (!(fts = fts_open(argv, fts_flags, NULL)))
		err(2, "fts_open");
	while ((p = fts_read(fts)) != NULL) {
		switch (p->fts_info) {
		case FTS_DNR:
			/* FALLTHROUGH */
		case FTS_ERR:
			file_err = true;
			if(!sflag)
				warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			break;
		case FTS_D:
			/* FALLTHROUGH */
		case FTS_DP:
			if (dexclude || dinclude)
				if (!dir_matching(p->fts_name) ||
				    !dir_matching(p->fts_path))
					fts_set(fts, p, FTS_SKIP);
			break;
		case FTS_DC:
			/* Print a warning for recursive directory loop */
			warnx("warning: %s: recursive directory loop",
				p->fts_path);
			break;
		default:
			/* Check for file exclusion/inclusion */
			ok = true;
			if (fexclude || finclude)
				ok &= file_matching(p->fts_path);

			if (ok)
				c += procfile(p->fts_path);
			break;
		}
	}

	fts_close(fts);
	return (c);
}
Exemple #18
0
void
rm_tree(char **argv)
{
	FTS *fts;
	FTSENT *p;
	int needstat;
	int flags;

	/*
	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
	 */
	needstat = !fflag && !iflag && stdin_ok;

	/*
	 * If the -i option is specified, the user can skip on the pre-order
	 * visit.  The fts_number field flags skipped directories.
	 */
#define	SKIPPED	1

	flags = FTS_PHYSICAL;
	if (!needstat)
		flags |= FTS_NOSTAT;
	if (xflag)
		flags |= FTS_XDEV;
	if (!(fts = fts_open(argv, flags, NULL)))
		err(1, NULL);
	while ((p = fts_read(fts)) != NULL) {
		switch (p->fts_info) {
		case FTS_DNR:
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_ERR:
			errc(1, p->fts_errno, "%s", p->fts_path);
		case FTS_NS:
			/*
			 * FTS_NS: assume that if can't stat the file, it
			 * can't be unlinked.
			 */
			if (!needstat)
				break;
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_D:
			/* Pre-order: give user chance to skip. */
			if (!fflag && !check(p->fts_path, p->fts_accpath,
			    p->fts_statp)) {
				(void)fts_set(fts, p, FTS_SKIP);
				p->fts_number = SKIPPED;
			}
			continue;
		case FTS_DP:
			/* Post-order: see if user skipped. */
			if (p->fts_number == SKIPPED)
				continue;
			break;
		default:
			if (!fflag &&
			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
				continue;
		}

		/*
		 * If we can't read or search the directory, may still be
		 * able to remove it.  Don't print out the un{read,search}able
		 * message unless the remove fails.
		 */
		switch (p->fts_info) {
		case FTS_DP:
		case FTS_DNR:
			if (!rmdir(p->fts_accpath) ||
			    (fflag && errno == ENOENT))
				continue;
			break;

		case FTS_F:
		case FTS_NSOK:
			if (Pflag)
				rm_overwrite(p->fts_accpath, p->fts_info ==
				    FTS_NSOK ? NULL : p->fts_statp);
			/* FALLTHROUGH */
		default:
			if (!unlink(p->fts_accpath) ||
			    (fflag && errno == ENOENT))
				continue;
		}
		warn("%s", p->fts_path);
		eval = 1;
	}
	if (errno)
		err(1, "fts_read");
	fts_close(fts);
}
Exemple #19
0
static int
vwalk(void)
{
	FTS *t;
	FTSENT *p;
	NODE *ep, *level;
	int specdepth, rval;
	char *argv[2];
	char dot[] = ".";

	argv[0] = dot;
	argv[1] = NULL;
	if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
		err(1, "line %d: fts_open", lineno);
	level = root;
	specdepth = rval = 0;
	while ((p = fts_read(t))) {
		if (check_excludes(p->fts_name, p->fts_path)) {
			fts_set(t, p, FTS_SKIP);
			continue;
		}
		switch(p->fts_info) {
		case FTS_D:
		case FTS_SL:
			break;
		case FTS_DP:
			if (level == NULL) {
				errx(1 , "invalid root in vwalk");
			}
			if (specdepth > p->fts_level) {
				for (level = level->parent; level->prev;
				      level = level->prev);
				--specdepth;
			}
			continue;
		case FTS_DNR:
		case FTS_ERR:
		case FTS_NS:
			warnx("%s: %s", RP(p), strerror(p->fts_errno));
			continue;
		default:
			if (dflag)
				continue;
		}

		if (specdepth != p->fts_level)
			goto extra;
		for (ep = level; ep; ep = ep->next)
			if ((ep->flags & F_MAGIC &&
			    !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
			    !strcmp(ep->name, p->fts_name)) {
				ep->flags |= F_VISIT;
				if ((ep->flags & F_NOCHANGE) == 0 &&
				    compare(ep->name, ep, p))
					rval = MISMATCHEXIT;
				if (ep->flags & F_IGN)
					(void)fts_set(t, p, FTS_SKIP);
				else if (ep->child && ep->type == F_DIR &&
				    p->fts_info == FTS_D) {
					level = ep->child;
					++specdepth;
				}
				break;
			}

		if (ep)
			continue;
extra:
		if (!eflag) {
			(void)printf("%s extra", RP(p));
			if (rflag) {
				if ((S_ISDIR(p->fts_statp->st_mode)
				    ? rmdir : unlink)(p->fts_accpath)) {
					(void)printf(", not removed: %s",
					    strerror(errno));
				} else
					(void)printf(", removed");
			}
			(void)putchar('\n');
		}
		(void)fts_set(t, p, FTS_SKIP);
	}
	(void)fts_close(t);
	if (sflag)
		warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
	return (rval);
}
Exemple #20
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *p;
	mode_t *set;
	int Hflag, Lflag, Rflag, ch, error, fflag, fts_options, hflag, rval;
	int vflag;
	char *mode;
	mode_t newmode;

	set = NULL;
	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
	while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			/*
			 * In System V (and probably POSIX.2) the -h option
			 * causes chmod to change the mode of the symbolic
			 * link.  4.4BSD's symbolic links didn't have modes,
			 * so it was an undocumented noop.  In FreeBSD 3.0,
			 * lchmod(2) is introduced and this option does real
			 * work.
			 */
			hflag = 1;
			break;
		/*
		 * XXX
		 * "-[rwx]" are valid mode commands.  If they are the entire
		 * argument, getopt has moved past them, so decrement optind.
		 * Regardless, we're done argument processing.
		 */
		case 'g': case 'o': case 'r': case 's':
		case 't': case 'u': case 'w': case 'X': case 'x':
			if (argv[optind - 1][0] == '-' &&
			    argv[optind - 1][1] == ch &&
			    argv[optind - 1][2] == '\0')
				--optind;
			goto done;
		case 'v':
			vflag++;
			break;
		case '?':
		default:
			usage();
		}
done:	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		fts_options = FTS_PHYSICAL;
		if (hflag)
			errx(1,
		"the -R and -h options may not be specified together.");
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	} else
		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;

	mode = *argv;
	if ((set = setmode(mode)) == NULL)
		errx(1, "invalid file mode: %s", mode);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, "fts_open");
	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D:			/* Change it at FTS_DP. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chmod, continue. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		case FTS_SL:			/* Ignore. */
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything and ones that we found
			 * doing a physical walk.
			 */
			if (!hflag)
				continue;
			/* FALLTHROUGH */
		default:
			break;
		}
		newmode = getmode(set, p->fts_statp->st_mode);
		/*
		 * With NFSv4 ACLs, it is possible that applying a mode
		 * identical to the one computed from an ACL will change
		 * that ACL.
		 */
		if (may_have_nfs4acl(p, hflag) == 0 &&
		    (newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
				continue;
		if (hflag)
			error = lchmod(p->fts_accpath, newmode);
		else
			error = chmod(p->fts_accpath, newmode);
		if (error) {
			if (!fflag) {
				warn("%s", p->fts_path);
				rval = 1;
			}
		} else {
			if (vflag) {
				(void)printf("%s", p->fts_path);

				if (vflag > 1) {
					char m1[12], m2[12];

					strmode(p->fts_statp->st_mode, m1);
					strmode((p->fts_statp->st_mode &
					    S_IFMT) | newmode, m2);
					(void)printf(": 0%o [%s] -> 0%o [%s]",
					    p->fts_statp->st_mode, m1,
					    (p->fts_statp->st_mode & S_IFMT) |
					    newmode, m2);
				}
				(void)printf("\n");
			}
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #21
0
int vde_modules_load(vde_context *ctx, char **path)
{
  FTS *ftsp;
  FTSENT *p;

  // symlinks in root path are followed
  // follow symlinks
  // don't chdir
  // don't stat
  int fts_options = FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_NOSTAT;
  int rv = 0;
  int tmp_errno;

  if (!path) {
    path = vde_modules_default_path();
  }

  ftsp = fts_open(path, fts_options, NULL);
  if (!ftsp) {
    tmp_errno = errno;
    vde_error("%s: unable to open modules path", __PRETTY_FUNCTION__);
    errno = tmp_errno;
    return -1;
  }

  while ((p = fts_read(ftsp)) != NULL) {
    switch (p->fts_info) {
    case FTS_F:
      // fts_path has the path prependend
      //vde_debug("examining file %s", p->fts_path);
      if (p->fts_pathlen > 3 &&
          strncmp(p->fts_path + p->fts_pathlen - 3, ".so", 3) == 0 &&
          access(p->fts_path, R_OK) == 0) {
        vde_debug("loading module %s", p->fts_path);

        // XXX define semantics for final rv, see include/vde3/module.h
        module_try_load(ctx, p->fts_path);
      }
      break;
    case FTS_ERR:
    case FTS_DNR:
    case FTS_NS:
      vde_warning("%s: error loading modules path %s: %s", __PRETTY_FUNCTION__,
                  p->fts_path, strerror(p->fts_errno));
      break;
    case FTS_D:
      //vde_debug("examining dir %s", p->fts_path);

      // do not recurse into subdirs
      if (p->fts_level > 0) {
        fts_set(ftsp, p, FTS_SKIP);
      }
      break;
    default:
      break;
    }
  }

  if(fts_close(ftsp)) {
    tmp_errno = errno;
    vde_error("%s: error while closing module path", __PRETTY_FUNCTION__);
    errno = tmp_errno;
    return -1;
  }

  return rv;
}
Exemple #22
0
int
main(int argc, char *argv[])
{
	FTS		*fts;
	FTSENT		*p;
	off_t		savednumber, curblocks;
	off_t		threshold, threshold_sign;
	int		ftsoptions;
	int		listall;
	int		depth;
	int		Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag;
	int		hflag, lflag, ch, notused, rval;
	char 		**save;
	static char	dot[] = ".";

	setlocale(LC_ALL, "");

	Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag =
	    lflag = Aflag = 0;

	save = argv;
	ftsoptions = 0;
	savednumber = 0;
	threshold = 0;
	threshold_sign = 1;
	cblocksize = DEV_BSIZE;
	blocksize = 0;
	depth = INT_MAX;
	SLIST_INIT(&ignores);

	while ((ch = getopt(argc, argv, "AB:HI:LPasd:chklmnrt:x")) != -1)
		switch (ch) {
		case 'A':
			Aflag = 1;
			break;
		case 'B':
			errno = 0;
			cblocksize = atoi(optarg);
			if (errno == ERANGE || cblocksize <= 0) {
				warnx("invalid argument to option B: %s",
				    optarg);
				usage();
			}
			break;
		case 'H':
			Hflag = 1;
			break;
		case 'I':
			ignoreadd(optarg);
			break;
		case 'L':
			if (Pflag)
				usage();
			Lflag = 1;
			break;
		case 'P':
			if (Lflag)
				usage();
			Pflag = 1;
			break;
		case 'a':
			aflag = 1;
			break;
		case 's':
			sflag = 1;
			break;
		case 'd':
			dflag = 1;
			errno = 0;
			depth = atoi(optarg);
			if (errno == ERANGE || depth < 0) {
				warnx("invalid argument to option d: %s",
				    optarg);
				usage();
			}
			break;
		case 'c':
			cflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'k':
			hflag = 0;
			blocksize = 1024;
			break;
		case 'l':
			lflag = 1;
			break;
		case 'm':
			hflag = 0;
			blocksize = 1048576;
			break;
		case 'n':
			nodumpflag = 1;
			break;
		case 'r':		 /* Compatibility. */
			break;
		case 't' :
			if (expand_number(optarg, &threshold) != 0 ||
			    threshold == 0) {
				warnx("invalid threshold: %s", optarg);
				usage();
			} else if (threshold < 0)
				threshold_sign = -1;
			break;
		case 'x':
			ftsoptions |= FTS_XDEV;
			break;
		case '?':
		default:
			usage();
			/* NOTREACHED */
		}

	argc -= optind;
	argv += optind;

	/*
	 * XXX
	 * Because of the way that fts(3) works, logical walks will not count
	 * the blocks actually used by symbolic links.  We rationalize this by
	 * noting that users computing logical sizes are likely to do logical
	 * copies, so not counting the links is correct.  The real reason is
	 * that we'd have to re-implement the kernel's symbolic link traversing
	 * algorithm to get this right.  If, for example, you have relative
	 * symbolic links referencing other relative symbolic links, it gets
	 * very nasty, very fast.  The bottom line is that it's documented in
	 * the man page, so it's a feature.
	 */

	if (Hflag + Lflag + Pflag > 1)
		usage();

	if (Hflag + Lflag + Pflag == 0)
		Pflag = 1;			/* -P (physical) is default */

	if (Hflag)
		ftsoptions |= FTS_COMFOLLOW;

	if (Lflag)
		ftsoptions |= FTS_LOGICAL;

	if (Pflag)
		ftsoptions |= FTS_PHYSICAL;

	if (!Aflag && (cblocksize % DEV_BSIZE) != 0)
		cblocksize = howmany(cblocksize, DEV_BSIZE) * DEV_BSIZE;

	listall = 0;

	if (aflag) {
		if (sflag || dflag)
			usage();
		listall = 1;
	} else if (sflag) {
		if (dflag)
			usage();
		depth = 0;
	}

	if (!*argv) {
		argv = save;
		argv[0] = dot;
		argv[1] = NULL;
	}

	if (blocksize == 0)
		(void)getbsize(&notused, &blocksize);

	if (!Aflag) {
		cblocksize /= DEV_BSIZE;
		blocksize /= DEV_BSIZE;
	}

	if (threshold != 0)
		threshold = howmany(threshold / DEV_BSIZE * cblocksize,
		    blocksize);

	rval = 0;

	(void)signal(SIGINFO, siginfo);

	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
		err(1, "fts_open");

	while ((p = fts_read(fts)) != NULL) {
		switch (p->fts_info) {
		case FTS_D:			/* Ignore. */
			if (ignorep(p))
				fts_set(fts, p, FTS_SKIP);
			break;
		case FTS_DP:
			if (ignorep(p))
				break;

			curblocks = Aflag ?
			    howmany(p->fts_statp->st_size, cblocksize) :
			    howmany(p->fts_statp->st_blocks, cblocksize);
			p->fts_parent->fts_bignum += p->fts_bignum +=
			    curblocks;

			if (p->fts_level <= depth && threshold <=
			    threshold_sign * howmany(p->fts_bignum *
			    cblocksize, blocksize)) {
				if (hflag) {
					prthumanval(p->fts_bignum);
					(void)printf("\t%s\n", p->fts_path);
				} else {
					(void)printf("%jd\t%s\n",
					    (intmax_t)howmany(p->fts_bignum *
					    cblocksize, blocksize),
					    p->fts_path);
				}
			}
			if (info) {
				info = 0;
				(void)printf("\t%s\n", p->fts_path);
			}
			break;
		case FTS_DC:			/* Ignore. */
			break;
		case FTS_DNR:			/* Warn, continue. */
		case FTS_ERR:
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		default:
			if (ignorep(p))
				break;

			if (lflag == 0 && p->fts_statp->st_nlink > 1 &&
			    linkchk(p))
				break;

			curblocks = Aflag ?
			    howmany(p->fts_statp->st_size, cblocksize) :
			    howmany(p->fts_statp->st_blocks, cblocksize);

			if (listall || p->fts_level == 0) {
				if (hflag) {
					prthumanval(curblocks);
					(void)printf("\t%s\n", p->fts_path);
				} else {
					(void)printf("%jd\t%s\n",
					    (intmax_t)howmany(curblocks *
					    cblocksize, blocksize),
					    p->fts_path);
				}
			}

			p->fts_parent->fts_bignum += curblocks;
		}
		savednumber = p->fts_parent->fts_bignum;
	}

	if (errno)
		err(1, "fts_read");

	if (cflag) {
		if (hflag) {
			prthumanval(savednumber);
			(void)printf("\ttotal\n");
		} else {
			(void)printf("%jd\ttotal\n", (intmax_t)howmany(
			    savednumber * cblocksize, blocksize));
		}
	}

	ignoreclean();
	exit(rval);
}
Exemple #23
0
/* Change the owner and/or group of the file specified by FTS and ENT
   to UID and/or GID as appropriate.
   If REQUIRED_UID is not -1, then skip files with any other user ID.
   If REQUIRED_GID is not -1, then skip files with any other group ID.
   CHOPT specifies additional options.
   Return true if successful.  */
static bool
change_file_owner (FTS *fts, FTSENT *ent,
                   uid_t uid, gid_t gid,
                   uid_t required_uid, gid_t required_gid,
                   struct Chown_option const *chopt)
{
  char const *file_full_name = ent->fts_path;
  char const *file = ent->fts_accpath;
  struct stat const *file_stats;
  struct stat stat_buf;
  bool ok = true;
  bool do_chown;
  bool symlink_changed = true;

  switch (ent->fts_info)
    {
    case FTS_D:
      if (chopt->recurse)
        {
          if (ROOT_DEV_INO_CHECK (chopt->root_dev_ino, ent->fts_statp))
            {
              /* This happens e.g., with "chown -R --preserve-root 0 /"
                 and with "chown -RH --preserve-root 0 symlink-to-root".  */
              ROOT_DEV_INO_WARN (file_full_name);
              /* Tell fts not to traverse into this hierarchy.  */
              fts_set (fts, ent, FTS_SKIP);
              /* Ensure that we do not process "/" on the second visit.  */
              ignore_ptr (fts_read (fts));
              return false;
            }
          return true;
        }
      break;

    case FTS_DP:
      if (! chopt->recurse)
        return true;
      break;

    case FTS_NS:
      /* For a top-level file or directory, this FTS_NS (stat failed)
         indicator is determined at the time of the initial fts_open call.
         With programs like chmod, chown, and chgrp, that modify
         permissions, it is possible that the file in question is
         accessible when control reaches this point.  So, if this is
         the first time we've seen the FTS_NS for this file, tell
         fts_read to stat it "again".  */
      if (ent->fts_level == 0 && ent->fts_number == 0)
        {
          ent->fts_number = 1;
          fts_set (fts, ent, FTS_AGAIN);
          return true;
        }
      if (! chopt->force_silent)
        error (0, ent->fts_errno, _("cannot access %s"),
               quote (file_full_name));
      ok = false;
      break;

    case FTS_ERR:
      if (! chopt->force_silent)
        error (0, ent->fts_errno, _("%s"), quote (file_full_name));
      ok = false;
      break;

    case FTS_DNR:
      if (! chopt->force_silent)
        error (0, ent->fts_errno, _("cannot read directory %s"),
               quote (file_full_name));
      ok = false;
      break;

    case FTS_DC:		/* directory that causes cycles */
      if (cycle_warning_required (fts, ent))
        {
          emit_cycle_warning (file_full_name);
          return false;
        }
      break;

    default:
      break;
    }

  if (!ok)
    {
      do_chown = false;
      file_stats = NULL;
    }
  else if (required_uid == (uid_t) -1 && required_gid == (gid_t) -1
           && chopt->verbosity == V_off
           && ! chopt->root_dev_ino
           && ! chopt->affect_symlink_referent)
    {
      do_chown = true;
      file_stats = ent->fts_statp;
    }
  else
    {
      file_stats = ent->fts_statp;

      /* If this is a symlink and we're dereferencing them,
         stat it to get info on the referent.  */
      if (chopt->affect_symlink_referent && S_ISLNK (file_stats->st_mode))
        {
          if (fstatat (fts->fts_cwd_fd, file, &stat_buf, 0) != 0)
            {
              if (! chopt->force_silent)
                error (0, errno, _("cannot dereference %s"),
                       quote (file_full_name));
              ok = false;
            }

          file_stats = &stat_buf;
        }

      do_chown = (ok
                  && (required_uid == (uid_t) -1
                      || required_uid == file_stats->st_uid)
                  && (required_gid == (gid_t) -1
                      || required_gid == file_stats->st_gid));
    }

  /* This happens when chown -LR --preserve-root encounters a symlink-to-/.  */
  if (ok
      && FTSENT_IS_DIRECTORY (ent)
      && ROOT_DEV_INO_CHECK (chopt->root_dev_ino, file_stats))
    {
      ROOT_DEV_INO_WARN (file_full_name);
      return false;
    }

  if (do_chown)
    {
      if ( ! chopt->affect_symlink_referent)
        {
          ok = (lchownat (fts->fts_cwd_fd, file, uid, gid) == 0);

          /* Ignore any error due to lack of support; POSIX requires
             this behavior for top-level symbolic links with -h, and
             implies that it's required for all symbolic links.  */
          if (!ok && errno == EOPNOTSUPP)
            {
              ok = true;
              symlink_changed = false;
            }
        }
      else
        {
          /* If possible, avoid a race condition with --from=O:G and without the
             (-h) --no-dereference option.  If fts's stat call determined
             that the uid/gid of FILE matched the --from=O:G-selected
             owner and group IDs, blindly using chown(2) here could lead
             chown(1) or chgrp(1) mistakenly to dereference a *symlink*
             to an arbitrary file that an attacker had moved into the
             place of FILE during the window between the stat and
             chown(2) calls.  If FILE is a regular file or a directory
             that can be opened, this race condition can be avoided safely.  */

          enum RCH_status err
            = restricted_chown (fts->fts_cwd_fd, file, file_stats, uid, gid,
                                required_uid, required_gid);
          switch (err)
            {
            case RC_ok:
              break;

            case RC_do_ordinary_chown:
              ok = (chownat (fts->fts_cwd_fd, file, uid, gid) == 0);
              break;

            case RC_error:
              ok = false;
              break;

            case RC_inode_changed:
              /* FIXME: give a diagnostic in this case?  */
            case RC_excluded:
              do_chown = false;
              ok = false;
              break;

            default:
              abort ();
            }
        }

      /* On some systems (e.g., GNU/Linux 2.4.x),
         the chown function resets the `special' permission bits.
         Do *not* restore those bits;  doing so would open a window in
         which a malicious user, M, could subvert a chown command run
         by some other user and operating on files in a directory
         where M has write access.  */

      if (do_chown && !ok && ! chopt->force_silent)
        error (0, errno, (uid != (uid_t) -1
                          ? _("changing ownership of %s")
                          : _("changing group of %s")),
               quote (file_full_name));
    }

  if (chopt->verbosity != V_off)
    {
      bool changed =
        ((do_chown && ok && symlink_changed)
         && ! ((uid == (uid_t) -1 || uid == file_stats->st_uid)
               && (gid == (gid_t) -1 || gid == file_stats->st_gid)));

      if (changed || chopt->verbosity == V_high)
        {
          enum Change_status ch_status =
            (!ok ? CH_FAILED
             : !symlink_changed ? CH_NOT_APPLIED
             : !changed ? CH_NO_CHANGE_REQUESTED
             : CH_SUCCEEDED);
          describe_change (file_full_name, ch_status,
                           chopt->user_name, chopt->group_name);
        }
    }

  if ( ! chopt->recurse)
    fts_set (fts, ent, FTS_SKIP);

  return ok;
}
Exemple #24
0
/*
 * Traverse() walks the logical directory structure specified by the argv list
 * in the order specified by the mastercmp() comparison function.  During the
 * traversal it passes linked lists of structures to display() which represent
 * a superset (may be exact set) of the files to be displayed.
 */
static void
traverse(int argc, char *argv[], int options)
{
	FTS *ftsp;
	FTSENT *p, *chp;
	int ch_options, error;

	if ((ftsp =
	    fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
		err(EXIT_FAILURE, NULL);

	display(NULL, fts_children(ftsp, 0));
	if (f_listdir) {
		(void)fts_close(ftsp);
		return;
	}

	/*
	 * If not recursing down this tree and don't need stat info, just get
	 * the names.
	 */
	ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;

	while ((p = fts_read(ftsp)) != NULL)
		switch (p->fts_info) {
		case FTS_DC:
			warnx("%s: directory causes a cycle", p->fts_name);
			break;
		case FTS_DNR:
		case FTS_ERR:
			warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
			rval = EXIT_FAILURE;
			break;
		case FTS_D:
			if (p->fts_level != FTS_ROOTLEVEL &&
			    p->fts_name[0] == '.' && !f_listdot)
				break;

			/*
			 * If already output something, put out a newline as
			 * a separator.  If multiple arguments, precede each
			 * directory with its name.
			 */
			if (!f_leafonly) {
				if (output)
					(void)printf("\n%s:\n", p->fts_path);
				else if (argc > 1) {
					(void)printf("%s:\n", p->fts_path);
					output = 1;
				}
			}

			chp = fts_children(ftsp, ch_options);
			display(p, chp);

			if (!f_recursive && chp != NULL)
				(void)fts_set(ftsp, p, FTS_SKIP);
			break;
		}
	error = errno;
	(void)fts_close(ftsp);
	errno = error;
	if (errno)
		err(EXIT_FAILURE, "fts_read");
}
Exemple #25
0
void
rm_tree(char **argv)
{
	FTS *fts;
	FTSENT *p;
	int needstat;
	int flags;
	int rval;

	/*
	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
	 */
	needstat = !uid || (!fflag && !iflag && stdin_ok);

	/*
	 * If the -i option is specified, the user can skip on the pre-order
	 * visit.  The fts_number field flags skipped directories.
	 */
#define	SKIPPED	1

	flags = FTS_PHYSICAL;
	if (!needstat)
		flags |= FTS_NOSTAT;
	if (Wflag)
		flags |= FTS_WHITEOUT;
	if (!(fts = fts_open(argv, flags, NULL))) {
		if (fflag && errno == ENOENT)
			return;
		err(1, "fts_open");
	}
	while ((p = fts_read(fts)) != NULL) {
		switch (p->fts_info) {
		case FTS_DNR:
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_ERR:
			errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
		case FTS_NS:
			/*
			 * Assume that since fts_read() couldn't stat the
			 * file, it can't be unlinked.
			 */
			if (!needstat)
				break;
			if (!fflag || p->fts_errno != ENOENT) {
				warnx("%s: %s",
				    p->fts_path, strerror(p->fts_errno));
				eval = 1;
			}
			continue;
		case FTS_D:
			/* Pre-order: give user chance to skip. */
			if (!fflag && !check(p->fts_path, p->fts_accpath,
			    p->fts_statp)) {
				(void)fts_set(fts, p, FTS_SKIP);
				p->fts_number = SKIPPED;
			}
			else if (!uid &&
				 (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
				 !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
				 lchflags(p->fts_accpath,
					 p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
				goto err;
			continue;
		case FTS_DP:
			/* Post-order: see if user skipped. */
			if (p->fts_number == SKIPPED)
				continue;
			break;
		default:
			if (!fflag &&
			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
				continue;
		}

		rval = 0;
		if (!uid &&
		    (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
		    !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
			rval = lchflags(p->fts_accpath,
				       p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
		if (rval == 0) {
			/*
			 * If we can't read or search the directory, may still be
			 * able to remove it.  Don't print out the un{read,search}able
			 * message unless the remove fails.
			 */
			switch (p->fts_info) {
			case FTS_DP:
			case FTS_DNR:
				rval = rmdir(p->fts_accpath);
				if (rval == 0 || (fflag && errno == ENOENT)) {
					if (rval == 0 && vflag)
						(void)printf("%s\n",
						    p->fts_path);
					if (rval == 0 && info) {
						info = 0;
						(void)printf("%s\n",
						    p->fts_path);
					}
					continue;
				}
				break;

			case FTS_W:
				rval = undelete(p->fts_accpath);
				if (rval == 0 && (fflag && errno == ENOENT)) {
					if (vflag)
						(void)printf("%s\n",
						    p->fts_path);
					if (info) {
						info = 0;
						(void)printf("%s\n",
						    p->fts_path);
					}
					continue;
				}
				break;

			case FTS_NS:
				/*
				 * Assume that since fts_read() couldn't stat
				 * the file, it can't be unlinked.
				 */
				if (fflag)
					continue;
				/* FALLTHROUGH */
			default:
				if (Pflag)
					if (!rm_overwrite(p->fts_accpath, NULL))
						continue;
				rval = unlink(p->fts_accpath);
				if (rval == 0 || (fflag && errno == ENOENT)) {
					if (rval == 0 && vflag)
						(void)printf("%s\n",
						    p->fts_path);
					if (rval == 0 && info) {
						info = 0;
						(void)printf("%s\n",
						    p->fts_path);
					}
					continue;
				}
			}
		}
err:
		warn("%s", p->fts_path);
		eval = 1;
	}
	if (errno)
		err(1, "fts_read");
	fts_close(fts);
}
Exemple #26
0
int
copy(char *argv[], enum op type, int fts_options)
{
    struct stat to_stat;
    FTS *ftsp;
    FTSENT *curr;
    int base, nlen, rval;
    char *p, *target_mid;
    base = 0;

    if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
        err(1, NULL);
    for (rval = 0; (curr = fts_read(ftsp)) != NULL;) {
        switch (curr->fts_info) {
        case FTS_NS:
        case FTS_DNR:
        case FTS_ERR:
            warnx("%s: %s",
                  curr->fts_path, strerror(curr->fts_errno));
            rval = 1;
            continue;
        case FTS_DC:
            warnx("%s: directory causes a cycle", curr->fts_path);
            rval = 1;
            continue;
        }

        /*
         * If we are in case (2) or (3) above, we need to append the
         * source name to the target name.
         */
        if (type != FILE_TO_FILE) {
            /*
             * Need to remember the roots of traversals to create
             * correct pathnames.  If there's a directory being
             * copied to a non-existent directory, e.g.
             *	cp -R a/dir noexist
             * the resulting path name should be noexist/foo, not
             * noexist/dir/foo (where foo is a file in dir), which
             * is the case where the target exists.
             *
             * Also, check for "..".  This is for correct path
             * concatenation for paths ending in "..", e.g.
             *	cp -R .. /tmp
             * Paths ending in ".." are changed to ".".  This is
             * tricky, but seems the easiest way to fix the problem.
             *
             * XXX
             * Since the first level MUST be FTS_ROOTLEVEL, base
             * is always initialized.
             */
            if (curr->fts_level == FTS_ROOTLEVEL) {
                if (type != DIR_TO_DNE) {
                    p = find_last_component(curr->fts_path);
                    base = p - curr->fts_path;

                    if (!strcmp(&curr->fts_path[base],
                                ".."))
                        base += 1;
                } else
                    base = curr->fts_pathlen;
            }

            p = &curr->fts_path[base];
            nlen = curr->fts_pathlen - base;
            target_mid = to.target_end;
            if (*p != '/' && target_mid[-1] != '/')
                *target_mid++ = '/';
            *target_mid = '\0';
            if (target_mid - to.p_path + nlen >= MAXPATHLEN) {
                warnx("%s%s: name too long (not copied)",
                      to.p_path, p);
                rval = 1;
                continue;
            }
            (void)strncat(target_mid, p, nlen);
            to.p_end = target_mid + nlen;
            *to.p_end = '\0';
        }

        /* Not an error but need to remember it happened */
        if (stat(to.p_path, &to_stat) == -1) {
            if (curr->fts_info == FTS_DP)
                continue;
            /*
             * We use fts_pointer as a boolean to indicate that
             * we created this directory ourselves.  We'll use
             * this later on via the fts_dne macro to decide
             * whether or not to set the directory mode during
             * the post-order pass.
             */
            curr->fts_pointer = (void *)1;
        } else {
            /*
             * Set directory mode/user/times on the post-order
             * pass.  We can't do this earlier because the mode
             * may not allow us write permission.  Furthermore,
             * if we set the times during the pre-order pass,
             * they will get changed later when the directory
             * is populated.
             */
            if (curr->fts_info == FTS_DP) {
                if (!S_ISDIR(to_stat.st_mode))
                    continue;
                /*
                 * If not -p and directory didn't exist, set
                 * it to be the same as the from directory,
                 * unmodified by the umask; arguably wrong,
                 * but it's been that way forever.
                 */
                if (pflag && setfile(curr->fts_statp, 0))
                    rval = 1;
                else if (fts_dne(curr))
                    (void)chmod(to.p_path,
                                curr->fts_statp->st_mode);
                continue;
            }
            if (to_stat.st_dev == curr->fts_statp->st_dev &&
                    to_stat.st_ino == curr->fts_statp->st_ino) {
                warnx("%s and %s are identical (not copied).",
                      to.p_path, curr->fts_path);
                rval = 1;
                if (S_ISDIR(curr->fts_statp->st_mode))
                    (void)fts_set(ftsp, curr, FTS_SKIP);
                continue;
            }
            if (!S_ISDIR(curr->fts_statp->st_mode) &&
                    S_ISDIR(to_stat.st_mode)) {
                warnx("cannot overwrite directory %s with non-directory %s",
                      to.p_path, curr->fts_path);
                rval = 1;
                continue;
            }
        }

        switch (curr->fts_statp->st_mode & S_IFMT) {
        case S_IFLNK:
            if (copy_link(curr, !fts_dne(curr)))
                rval = 1;
            break;
        case S_IFDIR:
            if (!Rflag && !rflag) {
                warnx("%s is a directory (not copied).",
                      curr->fts_path);
                (void)fts_set(ftsp, curr, FTS_SKIP);
                rval = 1;
                break;
            }
            /*
             * If the directory doesn't exist, create the new
             * one with the from file mode plus owner RWX bits,
             * modified by the umask.  Trade-off between being
             * able to write the directory (if from directory is
             * 555) and not causing a permissions race.  If the
             * umask blocks owner writes, we fail..
             */
            if (fts_dne(curr)) {
                if (mkdir(to.p_path,
                          curr->fts_statp->st_mode | S_IRWXU) < 0)
                    err(1, "%s", to.p_path);
            } else if (!S_ISDIR(to_stat.st_mode)) {
                errno = ENOTDIR;
                err(1, "%s", to.p_path);
            }
            break;
        case S_IFBLK:
        case S_IFCHR:
            if (Rflag) {
                if (copy_special(curr->fts_statp, !fts_dne(curr)))
                    rval = 1;
            } else if (copy_file(curr, fts_dne(curr)))
                rval = 1;
            break;
        case S_IFIFO:
            if (Rflag) {
                if (copy_fifo(curr->fts_statp, !fts_dne(curr)))
                    rval = 1;
            } else if (copy_file(curr, fts_dne(curr)))
                rval = 1;
            break;
        case S_IFSOCK:
            warnx("%s: %s", curr->fts_path, strerror(EOPNOTSUPP));
            break;
        default:
            if (copy_file(curr, fts_dne(curr)))
                rval = 1;
            break;
        }
    }
    if (errno)
        err(1, "fts_read");
    (void)fts_close(ftsp);
    return (rval);
}
Exemple #27
0
vwalk()
{
	extern int ftsoptions, dflag, eflag, rflag;
	register FTS *t;
	register FTSENT *p;
	register NODE *ep, *level;
	char *argv[2];
	int ftsdepth = 0, specdepth = 0;

	argv[0] = ".";
	argv[1] = (char *)NULL;
	if (!(t = fts_open(argv, ftsoptions, (int (*)())NULL))) {
		(void)fprintf(stderr,
		    "mtree: fts_open: %s.\n", strerror(errno));
		exit(1);
	}
	level = root;
	while (p = fts_read(t)) {
		switch(p->fts_info) {
		case FTS_D:
			if (!strcmp(p->fts_name, "."))
				continue;
			ftsdepth++; 
			break;
		case FTS_DP:
			ftsdepth--; 
			if (specdepth > ftsdepth) {
				for (level = level->parent; level->prev;
				      level = level->prev);  
				specdepth--;
			}
			continue;
		case FTS_DNR:
		case FTS_ERR:
		case FTS_NS:
			(void)fprintf(stderr, "mtree: %s: %s.\n",
			    RP(p), strerror(errno));
			continue;
		default:
			if (dflag)
				continue;
		}

		for (ep = level; ep; ep = ep->next)
			if (ep->flags & F_MAGIC && fnmatch(ep->name,
			    p->fts_name, FNM_PATHNAME|FNM_QUOTE) ||
			    !strcmp(ep->name, p->fts_name)) {
				ep->flags |= F_VISIT;
				if (ep->flags & F_IGN) {
					(void)fts_set(t, p, FTS_SKIP);
					continue;
				}
				compare(ep->name, ep, p);
				if (ep->child && ep->type == F_DIR &&
				    p->fts_info == FTS_D) {
					level = ep->child;
					specdepth++;
				}
				break;
			}

		if (ep)
			continue;
		if (!eflag) {
			(void)printf("extra: %s", RP(p));
			if (rflag) {
				if (unlink(p->fts_accpath)) {
					(void)printf(", not removed: %s",
					    strerror(errno));
				} else
					(void)printf(", removed");
			}
			(void)putchar('\n');
		}
		(void)fts_set(t, p, FTS_SKIP);
	}
	(void)fts_close(t);
}
Exemple #28
0
/* 
 * Traverse the file hierarchy by specified options.  single_argc is used
 * for formatting output. 
 */
static void
traverse(int single_argc, char * const *argv, int options)
{
	FTS    *handle;
	FTSENT *file, *child;

	if ((handle = fts_open(argv, options, f_nosort ? NULL : fts_cmp))
	    == NULL) {
		err(EXIT_FAILURE, "Failed to traverse");	
	}

	if ((child = fts_children(handle, 0)) == NULL) {
		if (errno != 0)
			err(EXIT_FAILURE, "Failed to search the operands");
	}

	print_file(ROOT, child);

	if (f_dir)
		goto end;

	while ((file = fts_read(handle)) != NULL) {
		if (file->fts_info == FTS_ERR || file->fts_info == FTS_NS) {
			warnx("%s: file error: %s", file->fts_name,
				strerror(file->fts_errno));

			return_val = EXIT_FAILURE;
		} else if (file->fts_info == FTS_DC) {
			warnx("%s: directory error: %s", file->fts_name,
				strerror(file->fts_errno));

			return_val = EXIT_FAILURE;
		} else if (file->fts_info == FTS_D) {
			/*
			 * Skip hidden directories if -a or -A not specified,
			 * except the hidden directories are the operands.
			 */
			if (!f_listall && file->fts_level != ROOT &&
			    file->fts_name[0] == '.') {
				if (fts_set(handle, file, FTS_SKIP) == -1) {
					warn("%s: failed to skip", 
					     file->fts_name);
					return_val = EXIT_FAILURE;
				}
				continue;
			}

			if (single_argc != SINGLE_ARG)
				printf("\n%s:\n",file->fts_path);
			else
				single_argc = 0;

			if ((child = fts_children(handle, 0)) == NULL) {
				if (errno != 0) {
					warn("%s: failed to search",
						file->fts_name);

					return_val = EXIT_FAILURE;
					continue;
				}
			}

			print_file(CHILD, child);

			/* stop searching subdirectories when -R not set */
			if (!f_recursive)
				if (fts_set(handle, file, FTS_SKIP) == -1) {
					warn("%s: failed to skip", 
					     file->fts_name);
					return_val = EXIT_FAILURE;
				}
		}

	}

	/* fts_read return NULL and errno is set */
	if (errno != 0) {
		warn("FTS read error");
		return_val = EXIT_FAILURE;
	}

end:	(void)fts_close(handle);

}
Exemple #29
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *p;
	u_long clear, newflags, set;
	long val;
	int Hflag, Lflag, Rflag, fflag, hflag, vflag;
	int ch, fts_options, oct, rval;
	char *flags, *ep;
	int (*change_flags)(const char *, unsigned long);

	Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
	while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'v':
			vflag++;
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		fts_options = FTS_PHYSICAL;
		if (hflag)
			errx(1, "the -R and -h options "
			        "may not be specified together");
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	} else
		fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;

	change_flags = hflag ? lchflags : chflags;

	flags = *argv;
	if (*flags >= '0' && *flags <= '7') {
		errno = 0;
		val = strtol(flags, &ep, 8);
		if (val < 0)
			errno = ERANGE;
		if (errno)
                        err(1, "invalid flags: %s", flags);
                if (*ep)
                        errx(1, "invalid flags: %s", flags);
		set = val;
                oct = 1;
	} else {
		if (strtofflags(&flags, &set, &clear))
                        errx(1, "invalid flag: %s", flags);
		clear = ~clear;
		oct = 0;
	}

	if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
		err(1, NULL);

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D:	/* Change it at FTS_DP if we're recursive. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chflag, continue. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		case FTS_SL:			/* Ignore. */
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything and ones that we found
			 * doing a physical walk.
			 */
			if (!hflag)
				continue;
			/* FALLTHROUGH */
		default:
			break;
		}
		if (oct)
			newflags = set;
		else
			newflags = (p->fts_statp->st_flags | set) & clear;
		if (newflags == p->fts_statp->st_flags)
			continue;
		if ((*change_flags)(p->fts_accpath, newflags) && !fflag) {
			warn("%s", p->fts_path);
			rval = 1;
		} else if (vflag) {
			(void)printf("%s", p->fts_path);
			if (vflag > 1)
				(void)printf(": 0%lo -> 0%lo",
				    (u_long)p->fts_statp->st_flags,
				    newflags);
			(void)printf("\n");
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Exemple #30
0
void ExpireDir(char *dir, dirstat_t *dirstat, uint64_t maxsize, uint64_t maxlife, uint32_t runtime ) {
FTS 		*fts;
FTSENT 		*ftsent;
uint64_t	sizelimit, num_expired;
int			done, size_done, lifetime_done, dir_files;
char *const path[] = { dir, NULL };
char		*expire_timelimit = NULL;
time_t 		now = time(NULL);

	dir_files = 0;
	if ( dirstat->low_water == 0 )
		dirstat->low_water = 95;

	if ( runtime ) {
		SetupSignalHandler();
		alarm(runtime);
	}

	if ( maxlife ) {
		// build an appropriate string for comparing
		time_t t_expire = now - maxlife;
		
		time_t t_watermark = now - (time_t)((maxlife * dirstat->low_water)/100);

// printf("Expire files before %s", ctime(&t_expire));
		expire_timelimit = strdup(UNIX2ISO(t_watermark));
// printf("down to %s", ctime(&t_watermark));
// printf("Diff: %i\n", t_watermark - t_expire );

		if ( dirstat->last < t_expire && (isatty(STDIN_FILENO) ) ) {
			// this means all files will get expired - are you sure ?
			char *s, s1[32], s2[32];
			time_t	t;
			struct tm *when;

			t = t_expire;
			when = localtime(&t);
			strftime(s1, 31, "%Y-%m-%d %H:%M:%S", when);
			s1[31] = '\0';
			
			t = dirstat->last;
			when = localtime(&t);
			strftime(s2, 31, "%Y-%m-%d %H:%M:%S", when);
			s2[31] = '\0';
			
			printf("Your max lifetime of %s will expire all file before %s\n", ScaleTime(maxlife), s1);
			printf("Your latest files are dated %s. This means all files will be deleted!\n", s2);
			printf("Are you sure? yes/[no] ");
			s = fgets(s1, 31, stdin);
			s1[31] = '\0';
			if ( s && strncasecmp(s1, "yes\n", 31) == 0 ) {
				printf("Ok - you've beeen warned!\n");
			} else {
				printf("Expire canceled!\n");
				return;
			}
		}
	}

	done 		  = 0;
	size_done 	  = maxsize == 0 || dirstat->filesize < maxsize;
	lifetime_done = maxlife == 0 || ( now - dirstat->first ) < maxlife;
	sizelimit = (dirstat->low_water * maxsize)/100;
	num_expired = 0;
	fts = fts_open(path, FTS_LOGICAL,  compare);
	while ( !done && ((ftsent = fts_read(fts)) != NULL) ) {
		if ( ftsent->fts_info == FTS_F ) {
			dir_files++;	// count files in directories
			if ( ftsent->fts_namelen == 19 && strncmp(ftsent->fts_name, "nfcapd.", 7) == 0 ) {
				// nfcapd.200604301200 strlen = 19
				char *s, *p = &(ftsent->fts_name[7]);
	
				// process only nfcapd. files
				// make sure it's really an nfcapd. file and we have 
				// only digits in the rest of the file name
				s = p;
				while ( *s ) {
					if ( *s < '0' || *s > '9' ) 
						break;
					s++;
				}
				// otherwise skip
				if ( *s )
					continue;

				// expire size-wise if needed
				if ( !size_done ) {
					if ( dirstat->filesize > sizelimit ) {
						if ( unlink(ftsent->fts_path) == 0 ) {
							dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks;
							num_expired++;
							dir_files--;
						} else {
							LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
						}
						continue;	// next file if file was unlinked
					} else {
						dirstat->first = ISO2UNIX(p);	// time of first file not expired
						size_done = 1;
					}
				}

				// expire time-wise if needed
				// this part of the code is executed only when size-wise is fullfilled
				if ( !lifetime_done ) {
					if ( expire_timelimit && strcmp(p, expire_timelimit) < 0  ) {
						if ( unlink(ftsent->fts_path) == 0 ) {
							dirstat->filesize -= 512 * ftsent->fts_statp->st_blocks;
							num_expired++;
							dir_files--;
						} else {
							LogError( "unlink() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
						}
						lifetime_done = 0;
					} else {
						dirstat->first = ISO2UNIX(p);	// time of first file not expired
						lifetime_done = 1;
					}
				}
				done = (size_done && lifetime_done) || timeout;

			}
		} else {
			switch (ftsent->fts_info) {
				case FTS_D:
					// set pre-order flag
					dir_files = 0;
					// skip all '.' entries as well as hidden directories
					if ( ftsent->fts_level > 0 && ftsent->fts_name[0] == '.' ) 
						fts_set(fts, ftsent, FTS_SKIP);
					// any valid directory needs to start with a digit ( %Y -> year )
					if ( ftsent->fts_level > 0 && !isdigit(ftsent->fts_name[0]) ) 
						fts_set(fts, ftsent, FTS_SKIP);
					break;
				case FTS_DP:
					// do not delete base data directory ( level == 0 )
					if ( dir_files == 0 && ftsent->fts_level > 0 ) {
						// directory is empty and can be deleted
// printf("Will remove directory %s\n", ftsent->fts_path);
						if ( rmdir(ftsent->fts_path) != 0 ) {
							LogError( "rmdir() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
						}
					}
					break;
			}
		}
	}
	fts_close(fts);
	if ( !done ) {
		// all files expired and limits not reached
		// this may be possible, when files get time-wise expired and
		// the time limit is shorter than the latest file
		dirstat->first = dirstat->last;
	}
	if ( runtime )
		alarm(0);
	if ( timeout ) {
		LogError( "Maximum execution time reached! Interrupt expire.\n");
	}
	if ( num_expired > dirstat->numfiles ) {
		LogError( "Error updating stat record: Number of files inconsistent!\n");
		LogError( "Will automatically rebuild this directory next time\n");
		dirstat->numfiles = 0;
		dirstat->status = FORCE_REBUILD;
	} else {
		dirstat->numfiles -= num_expired;
	}
	if ( dirstat->numfiles == 0 ) {
		dirstat->first  = dirstat->last = time(NULL);
		dirstat->status = FORCE_REBUILD;
	}

	free(expire_timelimit);

} // End of ExpireDir