Пример #1
0
int
main(int argc, char *argv[])
{
	int ret_val;

	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
		(void)signal(SIGINT, terminate);
	ret_val = setup(argc, argv);
	first_char = (COMPAT_MODE("bin/pr", "Unix2003") ? ochar : ' ');
	if (!ret_val) {
		/*
		 * select the output format based on options
		 */
		if (merge)
			ret_val = mulfile(argc, argv);
		else if (clcnt == 1)
			ret_val = onecol(argc, argv);
		else if (across)
			ret_val = horzcol(argc, argv);
		else
			ret_val = vertcol(argc, argv);
	} else
		usage();
	flsh_errs();
	if (errcnt || ret_val)
		exit(1);
	return(0);
}
Пример #2
0
void
usage(void)
{

	char *t_flag = COMPAT_MODE("bin/df", "unix2003") ? "[-t]" : "[-t type]";
	(void)fprintf(stderr,
	    "usage: df [-b | -H | -h | -k | -m | -g | -P] [-ailn] [-T type] %s [filesystem ...]\n", t_flag);
	exit(EX_USAGE);
}
Пример #3
0
int
msearch(char ***argvp, struct info *ip)
{
	struct modes *mp;
	char *name;

	name = **argvp;

	for (mp = cmodes; mp->name; ++mp)
		if (CHK(mp->name)) {
			ip->t.c_cflag &= ~mp->unset;
			ip->t.c_cflag |= mp->set;
			ip->set = 1;
			return (1);
		}
	for (mp = imodes; mp->name; ++mp)
		if (CHK(mp->name)) {
			ip->t.c_iflag &= ~mp->unset;
			ip->t.c_iflag |= mp->set;
			ip->set = 1;
			return (1);
		}
	for (mp = lmodes; mp->name; ++mp)
		if (CHK(mp->name)) {
			ip->t.c_lflag &= ~mp->unset;
			ip->t.c_lflag |= mp->set;
			ip->set = 1;
			return (1);
		}
	for (mp = omodes; mp->name; ++mp)
		if (CHK(mp->name)) {
			ip->t.c_oflag &= ~mp->unset;
			ip->t.c_oflag |= mp->set;
			ip->set = 1;
			return (1);
		}
	if (COMPAT_MODE("bin/stty", "Unix2003")) {
		for (mp = umodes; mp->name; ++mp)
			if (CHK(mp->name)) {
				ip->t.c_oflag &= ~mp->unset;
				ip->t.c_oflag |= mp->set;
				ip->set = 1;
				return (1);
		}
	}
	return (0);
}
Пример #4
0
/*
 * Print out status about a filesystem.
 */
void
prtstat(struct statfs *sfsp, struct maxwidths *mwp)
{
	static long blocksize;
	static int headerlen, timesthrough;
	static const char *header;
	uint64_t used, availblks, inodes;
	char * avail_str;

	if (++timesthrough == 1) {
		mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem"));
		if (hflag) {
			header = "  Size";
			mwp->total = mwp->used = mwp->avail = (int)strlen(header);
		} else {
			header = getbsize(&headerlen, &blocksize);
			mwp->total = imax(mwp->total, headerlen);
		}
		mwp->used = imax(mwp->used, (int)strlen("Used"));
		if (COMPAT_MODE("bin/df", "unix2003") && !hflag) {
			avail_str = "Available";
		} else {
			avail_str = "Avail";
		}
		mwp->avail = imax(mwp->avail, (int)strlen(avail_str));

		(void)printf("%-*s %*s %*s %*s Capacity", mwp->mntfrom,
		    "Filesystem", mwp->total, header, mwp->used, "Used",
		    mwp->avail, avail_str);
		if (iflag) {
			mwp->iused = imax(mwp->iused, (int)strlen("  iused"));
			mwp->ifree = imax(mwp->ifree, (int)strlen("ifree"));
			(void)printf(" %*s %*s %%iused", mwp->iused - 2,
			    "iused", mwp->ifree, "ifree");
		}
		(void)printf("  Mounted on\n");
	}

	(void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
	if (sfsp->f_blocks > sfsp->f_bfree)
		used = sfsp->f_blocks - sfsp->f_bfree;
	else
		used = 0;
	availblks = sfsp->f_bavail + used;
	if (hflag) {
		prthuman(sfsp, used);
	} else {
		(void)printf(" %*jd %*jd %*jd", mwp->total,
			     fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize, sfsp->f_mntonname),
			     mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize, sfsp->f_mntonname),
			     mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize, sfsp->f_mntonname));
	}
	if (COMPAT_MODE("bin/df", "unix2003")) {
		/* Standard says percentage must be rounded UP to next
		   integer value, not truncated */
		double value;
		if (availblks == 0)
			value = 100.0;
		else {
			value = (double)used / (double)availblks * 100.0;
			if ((value-(int)value) > 0.0) value = value + 1.0;
		}
		(void)printf(" %5.0f%%", trunc(value));
	} else {
		(void)printf(" %5.0f%%",
		    availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
	}
	if (iflag) {
		inodes = sfsp->f_files;
		used = inodes - sfsp->f_ffree;
		(void)printf(" %*llu %*lu %4.0f%% ", mwp->iused, used,
		    mwp->ifree, (unsigned long)sfsp->f_ffree, inodes == 0 ? 100.0 :
		    (double)used / (double)inodes * 100.0);
	} else
		(void)printf("  ");
	(void)printf("  %s\n", sfsp->f_mntonname);
}
Пример #5
0
int
main(int argc, char *argv[])
{
	struct stat stbuf;
	struct statfs statfsbuf, *mntbuf;
	struct maxwidths maxwidths;
	char *mntpt, **vfslist;
	long mntsize;
	int ch, i, rv, tflag = 0, kludge_tflag = 0;
	int kflag = 0;
	const char *options = "abgHhiklmnPt:T:";
	if (COMPAT_MODE("bin/df", "unix2003")) {
		/* Unix2003 requires -t be "include total capacity". which df
		  already does, but it conflicts with the old -t so we need to
		  *not* expect a string after -t (we provide -T in both cases
		  to cover the old use of -t) */
		options = "abgHhiklmnPtT:";
		iflag = 1;
	}

	vfslist = NULL;
	while ((ch = getopt(argc, argv, options)) != -1)
		switch (ch) {
		case 'a':
			aflag = 1;
			break;
		case 'b':
				/* FALLTHROUGH */
		case 'P':
			if (COMPAT_MODE("bin/df", "unix2003")) {
				if (!kflag) {
					/* -k overrides -P */
					putenv("BLOCKSIZE=512");
				}
				iflag = 0;
			} else {
				putenv("BLOCKSIZE=512");
			}
			hflag = 0;
			break;
		case 'g':
			putenv("BLOCKSIZE=1g");
			hflag = 0;
			break;
		case 'H':
			hflag = UNITS_SI;
			valp = vals_si;
			break;
		case 'h':
			hflag = UNITS_2;
			valp = vals_base2;
			break;
		case 'i':
			iflag = 1;
			break;
		case 'k':
			if (COMPAT_MODE("bin/df", "unix2003")) {
				putenv("BLOCKSIZE=1024");
			} else {
				putenv("BLOCKSIZE=1k");
			}
			kflag = 1;
			hflag = 0;
			break;
		case 'l':
			if (tflag)
				errx(1, "-l and -T are mutually exclusive.");
			if (vfslist != NULL)
				break;
			vfslist = makevfslist(makenetvfslist());
			break;
		case 'm':
			putenv("BLOCKSIZE=1m");
			hflag = 0;
			break;
		case 'n':
			nflag = 1;
			break;
		case 't':
			/* Unix2003 uses -t for something we do by default */
			if (COMPAT_MODE("bin/df", "unix2003")) {
			    kludge_tflag = 1;
			    break;
			}
		case 'T':
			if (vfslist != NULL) {
				if (tflag)
					errx(1, "only one -%c option may be specified", ch);
				else
					errx(1, "-l and -%c are mutually exclusive.", ch);
			}
			tflag++;
			vfslist = makevfslist(optarg);
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	/* If we are in unix2003 mode, have seen a -t but no -T and the first
	  non switch arg isn't a file, let's pretend they used -T on it.
	  This makes the Lexmark printer installer happy (PR-3918471) */
	if (tflag == 0 && kludge_tflag && *argv && stat(*argv, &stbuf) < 0
	  && errno == ENOENT) {
	    vfslist = makevfslist(*argv++);
	}

	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
	bzero(&maxwidths, sizeof(maxwidths));
	for (i = 0; i < mntsize; i++)
		update_maxwidths(&maxwidths, &mntbuf[i]);

	rv = 0;
	if (!*argv) {
		mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
		bzero(&maxwidths, sizeof(maxwidths));
		for (i = 0; i < mntsize; i++)
			update_maxwidths(&maxwidths, &mntbuf[i]);
		for (i = 0; i < mntsize; i++) {
			if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
				prtstat(&mntbuf[i], &maxwidths);
		}
		exit(rv);
	}

	for (; *argv; argv++) {
		if (stat(*argv, &stbuf) < 0) {
			if ((mntpt = getmntpt(*argv)) == 0) {
				warn("%s", *argv);
				rv = 1;
				continue;
			}
		} else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) {
			warnx("%s: Raw devices not supported", *argv);
			rv = 1;
			continue;
		} else
			mntpt = *argv;
		/*
		 * Statfs does not take a `wait' flag, so we cannot
		 * implement nflag here.
		 */
		if (statfs(mntpt, &statfsbuf) < 0) {
			warn("%s", mntpt);
			rv = 1;
			continue;
		}
		/* Check to make sure the arguments we've been
		 * given are satisfied.  Return an error if we
		 * have been asked to list a mount point that does
		 * not match the other args we've been given (-l, -t, etc.)
		 */
		if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
			rv++;
			continue;
		}

		if (argc == 1) {
		        bzero(&maxwidths, sizeof(maxwidths));
			update_maxwidths(&maxwidths, &statfsbuf);
		}
		prtstat(&statfsbuf, &maxwidths);
	}
	return (rv);
}
Пример #6
0
int
main(int argc, char *argv[])
{
	long arg_max;
	int ch, Jflag, nflag, nline;
	size_t nargs;
	size_t linelen;
	char *endptr;

	inpline = replstr = NULL;
	ep = environ;
	eofstr = "";
	Jflag = nflag = 0;

	(void)setlocale(LC_ALL, "");

	/*
	 * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
	 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
	 * that the smallest argument is 2 bytes in length, this means that
	 * the number of arguments is limited to:
	 *
	 *	 (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
	 *
	 * We arbitrarily limit the number of arguments to 5000.  This is
	 * allowed by POSIX.2 as long as the resulting minimum exec line is
	 * at least LINE_MAX.  Realloc'ing as necessary is possible, but
	 * probably not worthwhile.
	 */
	nargs = 5000;
	if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
		errx(1, "sysconf(_SC_ARG_MAX) failed");
	nline = arg_max - MAXPATHLEN; /* for argv[0] from execvp() */
	pad9314053 = sizeof(char *); /* reserve for string area rounding */
	while (*ep != NULL) {
		/* 1 byte for each '\0' */
		nline -= strlen(*ep++) + 1 + sizeof(*ep);
	}
	nline -= pad9314053;
	maxprocs = 1;
	while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:s:tx")) != -1)
		switch(ch) {
		case 'E':
			eofstr = optarg;
			break;
		case 'I':
			Jflag = 0;
			Iflag = 1;
			Lflag = 1;
			replstr = optarg;
			break;
		case 'J':
			Iflag = 0;
			Jflag = 1;
			replstr = optarg;
			break;
		case 'L':
			Lflag = atoi(optarg);
			if (COMPAT_MODE("bin/xargs", "Unix2003")) {
				nflag = 0; /* Override */
				nargs = 5000;
			}
			break;
		case 'n':
			nflag = 1;
			if ((nargs = strtol(optarg, NULL, 10)) <= 0)
				errx(1, "illegal argument count");
			if (COMPAT_MODE("bin/xargs", "Unix2003")) {
				Lflag = 0; /* Override */
			}
			break;
		case 'o':
			oflag = 1;
			break;
		case 'P':
			if ((maxprocs = atoi(optarg)) <= 0)
				errx(1, "max. processes must be >0");
			break;
		case 'p':
			pflag = 1;
			break;
		case 'R':
			Rflag = strtol(optarg, &endptr, 10);
			if (*endptr != '\0')
				errx(1, "replacements must be a number");
			break;
		case 's':
			nline = atoi(optarg);
			pad9314053 = 0; /* assume the -s value is valid */
			break;
		case 't':
			tflag = 1;
			break;
		case 'x':
			xflag = 1;
			break;
		case '0':
			zflag = 1;
			break;
		case '?':
		default:
			usage();
	}
	argc -= optind;
	argv += optind;

	if (!Iflag && Rflag)
		usage();
	if (Iflag && !Rflag)
		Rflag = 5;
	if (xflag && !nflag)
		usage();
	if (Iflag || Lflag)
		xflag = 1;
	if (replstr != NULL && *replstr == '\0')
		errx(1, "replstr may not be empty");

	/*
	 * Allocate pointers for the utility name, the utility arguments,
	 * the maximum arguments to be read from stdin and the trailing
	 * NULL.
	 */
	linelen = 1 + argc + nargs + 1;
	if ((av = bxp = malloc(linelen * sizeof(char **))) == NULL)
		errx(1, "malloc failed");

	/*
	 * Use the user's name for the utility as argv[0], just like the
	 * shell.  Echo is the default.  Set up pointers for the user's
	 * arguments.
	 */
	if (*argv == NULL)
		cnt = strlen(*bxp++ = echo) + pad9314053;
	else {
		do {
			if (Jflag && strcmp(*argv, replstr) == 0) {
				char **avj;
				jfound = 1;
				argv++;
				for (avj = argv; *avj; avj++)
					cnt += strlen(*avj) + 1 + pad9314053;
				break;
			}
			cnt += strlen(*bxp++ = *argv) + 1 + pad9314053;
		} while (*++argv != NULL);
	}

	/*
	 * Set up begin/end/traversing pointers into the array.  The -n
	 * count doesn't include the trailing NULL pointer, so the malloc
	 * added in an extra slot.
	 */
	endxp = (xp = bxp) + nargs;

	/*
	 * Allocate buffer space for the arguments read from stdin and the
	 * trailing NULL.  Buffer space is defined as the default or specified
	 * space, minus the length of the utility name and arguments.  Set up
	 * begin/end/traversing pointers into the array.  The -s count does
	 * include the trailing NULL, so the malloc didn't add in an extra
	 * slot.
	 */
	nline -= cnt;
	if (nline <= 0)
		errx(1, "insufficient space for command");

	if ((bbp = malloc((size_t)(nline + 1))) == NULL)
		errx(1, "malloc failed");
	ebp = (argp = p = bbp) + nline - 1;
	for (;;)
		parse_input(argc, argv);
}
Пример #7
0
static void
parse_input(int argc, char *argv[])
{
	int ch, foundeof;
	char **avj;
	int last_was_backslashed = 0;

	foundeof = 0;

	switch(ch = getchar()) {
	case EOF:
		/* No arguments since last exec. */
		if (p == bbp) {
			waitchildren(*argv, 1);
			exit(rval);
		}
		goto arg1;
	case ' ':
		last_was_blank = 1;
	case '\t':
		/* Quotes escape tabs and spaces. */
		if (insingle || indouble || zflag)
			goto addch;
		goto arg2;
	case '\0':
		if (zflag) {
			/*
			 * Increment 'count', so that nulls will be treated
			 * as end-of-line, as well as end-of-argument.  This
			 * is needed so -0 works properly with -I and -L.
			 */
			count++;
			goto arg2;
		}
		goto addch;
	case '\n':
		if (zflag)
			goto addch;
		if (COMPAT_MODE("bin/xargs", "Unix2003")) {
			if (last_was_newline) {
				/* don't count empty line */
				break;
			}
			if (!last_was_blank ) {
				/* only count if NOT continuation line */
				count++;
			} 
		} else {
			count++;
		}
		last_was_newline = 1;

		/* Quotes do not escape newlines. */
arg1:		if (insingle || indouble)
			errx(1, "unterminated quote");
arg2:
		foundeof = *eofstr != '\0' &&
		    strcmp(argp, eofstr) == 0;

#ifdef __APPLE__
		/* 6591323: -I specifies that it processes the entire line,
		 * so only recognize eofstr at the end of a line. */
		if (Iflag && !last_was_newline)
			foundeof = 0;

		/* 6591323: Essentially the same as the EOF handling above. */
		if (foundeof && (p - strlen(eofstr) == bbp)) {
			waitchildren(*argv, 1);
			exit(rval);
		}
#endif

		/* Do not make empty args unless they are quoted */
		if ((argp != p || wasquoted) && !foundeof) {
			*p++ = '\0';
			*xp++ = argp;
			if (Iflag) {
				size_t curlen;

				if (inpline == NULL)
					curlen = 0;
				else {
					/*
					 * If this string is not zero
					 * length, append a space for
					 * separation before the next
					 * argument.
					 */
					if ((curlen = strlen(inpline)))
						strcat(inpline, " ");
				}
				curlen++;
				/*
				 * Allocate enough to hold what we will
				 * be holding in a second, and to append
				 * a space next time through, if we have
				 * to.
				 */
				inpline = realloc(inpline, curlen + 2 +
				    strlen(argp));
				if (inpline == NULL)
					errx(1, "realloc failed");
				if (curlen == 1)
					strcpy(inpline, argp);
				else
					strcat(inpline, argp);
			}
		}

		/*
		 * If max'd out on args or buffer, or reached EOF,
		 * run the command.  If xflag and max'd out on buffer
		 * but not on args, object.  Having reached the limit
		 * of input lines, as specified by -L is the same as
		 * maxing out on arguments.
		 */
		if (xp == endxp || p + (count * pad9314053) > ebp || ch == EOF ||
		    (Lflag <= count && xflag) || foundeof) {
			if (xflag && xp != endxp && p + (count * pad9314053) > ebp)
				errx(1, "insufficient space for arguments");
			if (jfound) {
				for (avj = argv; *avj; avj++)
					*xp++ = *avj;
			}
			prerun(argc, av);
			if (ch == EOF || foundeof) {
				waitchildren(*argv, 1);
				exit(rval);
			}
			p = bbp;
			xp = bxp;
			count = 0;
		}
		argp = p;
		wasquoted = 0;
		break;
	case '\'':
		if (indouble || zflag)
			goto addch;
		insingle = !insingle;
		wasquoted = 1;
		break;
	case '"':
		if (insingle || zflag)
			goto addch;
		indouble = !indouble;
		wasquoted = 1;
		break;
	case '\\':
		last_was_backslashed = 1;
		if (zflag)
			goto addch;
		/* Backslash escapes anything, is escaped by quotes. */
		if (!insingle && !indouble && (ch = getchar()) == EOF)
			errx(1, "backslash at EOF");
		/* FALLTHROUGH */
	default:
addch:		if (p < ebp) {
			*p++ = ch;
			break;
		}

		/* If only one argument, not enough buffer space. */
		if (bxp == xp)
			errx(1, "insufficient space for argument");
		/* Didn't hit argument limit, so if xflag object. */
		if (xflag)
			errx(1, "insufficient space for arguments");

		if (jfound) {
			for (avj = argv; *avj; avj++)
				*xp++ = *avj;
		}
		prerun(argc, av);
		xp = bxp;
		cnt = ebp - argp;
		memcpy(bbp, argp, (size_t)cnt);
		p = (argp = bbp) + cnt;
		*p++ = ch;
		break;
	}
	if (ch != ' ')
		last_was_blank = 0;
	if (ch != '\n' || last_was_backslashed)
		last_was_newline = 0;
}
Пример #8
0
int
main(int argc, char **argv)
{
	FTS *ftsp;
	FTSENT *p;
	int Hflag, Lflag, Pflag, Rflag, fflag, hflag, vflag;
	int ch, fts_options, rval;
	char *cp;
	int unix2003_compat = 0;
	int symlink_found = 0;

	if (argc < 1)
		usage();
	cp = strrchr(argv[0], '/');
	cp = (cp != NULL) ? cp + 1 : argv[0];
	ischown = (strcmp(cp, "chown") == 0);

	Hflag = Lflag = Pflag = Rflag = fflag = 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 = 1;
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();
	if (!Rflag && (Hflag || Lflag || Pflag))
		warnx("options -H, -L, -P only useful with -R");

	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;

	uid = (uid_t)-1;
	gid = (gid_t)-1;
	if (ischown) {
		unix2003_compat = COMPAT_MODE("bin/chown", "Unix2003");
		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 {
		unix2003_compat = COMPAT_MODE("bin/chgrp", "Unix2003");
		a_gid(*argv);
	}

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

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		symlink_found = 0;
		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 {
				symlink_found = 1;
				if (unix2003_compat) {
					if (Hflag || Lflag) {       /* -H or -L was specified */
						if (p->fts_errno) {
							warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
							rval = 1;
							continue;
						}
					}
					break; /* Otherwise symlinks keep going */
				}
				continue;
			}
		default:
			break;
		}
		if (unix2003_compat) {
			/* Can only avoid updating times if both uid and gid are -1 */
			if ((uid == (uid_t)-1) && (gid == (gid_t)-1))
				continue;
		} else {
			if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
			    (gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
				continue;
		}
		if (((hflag || symlink_found) ? lchown : chown)(p->fts_accpath, uid, gid) == -1) {
			if (!fflag) {
				chownerr(p->fts_path);
				rval = 1;
			}
		} else {
			if (vflag)
				printf("%s\n", p->fts_path);
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Пример #9
0
int
main(int argc, char *argv[])
{
	FTS		*fts;
	FTSENT		*p;
	off_t		savednumber = 0;
	long		blocksize;
	int		ftsoptions;
	int		listall;
	int		depth;
	int		Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval;
	char 		**save;
	static char	dot[] = ".";
	off_t           *ftsnum, *ftsparnum;

	setlocale(LC_ALL, "");

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

	save = argv;
	ftsoptions = FTS_NOCHDIR;
	depth = INT_MAX;
	SLIST_INIT(&ignores);

	while ((ch = getopt(argc, argv, "HI:LPasd:cghkmrx")) != -1)
		switch (ch) {
			case 'H':
				Lflag = Pflag = 0;
				Hflag = 1;
				break;
			case 'I':
				ignoreadd(optarg);
				break;
			case 'L':
				Hflag = Pflag = 0;
				Lflag = 1;
				break;
			case 'P':
				Hflag = Lflag = 0;
				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':
				putenv("BLOCKSIZE=512");
				hflag = 1;
				valp = vals_base2;
				break;
			case 'k':
				hflag = 0;
				putenv("BLOCKSIZE=1024");
				break;
			case 'm':
				hflag = 0;
				putenv("BLOCKSIZE=1048576");
				break;
			case 'g':
				hflag = 0;
				putenv("BLOCKSIZE=1g");
				break;
			case 'r':		 /* Compatibility. */
				break;
			case 'x':
				ftsoptions |= FTS_XDEV;
				break;
			case '?':
			default:
				usage();
		}

//	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;

	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;
	}

	(void) getbsize(&notused, &blocksize);
	blocksize /= 512;

	rval = 0;

	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:
				if (ignorep(p) || dirlinkchk(p))
					fts_set(fts, p, FTS_SKIP);
				break;
			case FTS_DP:
				if (ignorep(p))
					break;

				ftsparnum = (off_t *)&p->fts_parent->fts_number;
				ftsnum = (off_t *)&p->fts_number;
				if (p->fts_statp->st_size < TWO_TB) {
				    ftsparnum[0] += ftsnum[0] += p->fts_statp->st_blocks;
				} else {
				    ftsparnum[0] += ftsnum[0] += howmany(p->fts_statp->st_size, 512LL);
				}

				if (p->fts_level <= depth) {
					if (hflag) {
						(void) prthumanval(howmany(*ftsnum, blocksize));
						(void) printf("\t%s\n", p->fts_path);
					} else {
					(void) printf("%jd\t%s\n",
					    (intmax_t)howmany(*ftsnum, blocksize),
					    p->fts_path);
					}
				}
				break;
			case FTS_DC:			/* Ignore. */
				if (COMPAT_MODE("bin/du", "unix2003")) {
					errx(1, "Can't follow symlink cycle from %s to %s", p->fts_path, p->fts_cycle->fts_path);
				}
				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;
			case FTS_SLNONE:
				if (COMPAT_MODE("bin/du", "unix2003")) {
					struct stat sb;
					int rc = stat(p->fts_path, &sb);
					if (rc < 0 && errno == ELOOP) {
						errx(1, "Too many symlinks at %s", p->fts_path);
					}
				}
			default:
				if (ignorep(p))
					break;

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

				if (listall || p->fts_level == 0) {
					if (hflag) {
					    if (p->fts_statp->st_size < TWO_TB) {
						(void) prthumanval(howmany(p->fts_statp->st_blocks,
							blocksize));
					    } else {
						(void) prthumanval(howmany(howmany(p->fts_statp->st_size, 512LL),
							blocksize));
					    }
						(void) printf("\t%s\n", p->fts_path);
					} else {
					    if (p->fts_statp->st_size < TWO_TB) {
						(void) printf("%jd\t%s\n",
							(intmax_t)howmany(p->fts_statp->st_blocks, blocksize),
							p->fts_path);
					    } else {
						(void) printf("%jd\t%s\n",
							(intmax_t)howmany(howmany(p->fts_statp->st_size, 512LL), blocksize),
							p->fts_path);
					    }
					}
				}

				ftsparnum = (off_t *)&p->fts_parent->fts_number;
				if (p->fts_statp->st_size < TWO_TB) {
				    ftsparnum[0] += p->fts_statp->st_blocks;
				} else {
				    ftsparnum[0] += p->fts_statp->st_size / 512LL;
				}
		}
		savednumber = ((off_t *)&p->fts_parent->fts_number)[0];
	}

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

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

	ignoreclean();
	exit(rval);
}
Пример #10
0
/* do what is asked for, for the path name */
static void
handle_pathname(char *path)
{
	char *opath = path, *s = NULL;
	ssize_t len;
	int slen;
	struct stat sb;

	/* check for stdout/stdin */
	if (path[0] == '-' && path[1] == '\0') {
		if (dflag)
			handle_stdin();
		else
			handle_stdout();
		return;
	}

#ifdef __APPLE__
	if (zcat && COMPAT_MODE("bin/zcat", "Unix2003")) {
		char *suffix = strrchr(path, '.');
		if (suffix == NULL || strcmp(suffix, Z_SUFFIX) != 0) {
			len = strlen(path);
			slen = sizeof(Z_SUFFIX) - 1;
			s = malloc(len + slen + 1);
			memcpy(s, path, len);
			memcpy(s + len, Z_SUFFIX, slen + 1);
			path = s;
		}
	}
#endif

retry:
	if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 &&
	    lstat(path, &sb) != 0)) {
		/* lets try <path>.gz if we're decompressing */
		if (dflag && s == NULL && errno == ENOENT) {
			len = strlen(path);
			slen = suffixes[0].ziplen;
			s = malloc(len + slen + 1);
			if (s == NULL)
				maybe_err("malloc");
			memcpy(s, path, len);
			memcpy(s + len, suffixes[0].zipped, slen + 1);
			path = s;
			goto retry;
		}
#ifdef __APPLE__
		/* Include actual path for clarity. */
		maybe_warn("can't stat: %s (%s)", opath, path);
#else
		maybe_warn("can't stat: %s", opath);
#endif
		goto out;
	}

	if (S_ISDIR(sb.st_mode)) {
#ifndef SMALL
		if (rflag)
			handle_dir(path);
		else
#endif
			maybe_warnx("%s is a directory", path);
		goto out;
	}

	if (S_ISREG(sb.st_mode))
		handle_file(path, &sb);
	else
		maybe_warnx("%s is not a regular file", path);

out:
	if (s)
		free(s);
}
Пример #11
0
static int
copy(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, NULL)) == NULL)
		err(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));
			rval = 1;
			continue;
		case FTS_DC:			/* Warn, continue. */
			warnx("%s: directory causes a cycle", curr->fts_path);
			rval = 1;
			continue;
		default:
			;
		}
#ifdef __APPLE__

#ifdef __clang__
#pragma clang diagnostic push
/* clang doesn't like fts_name[1], but we know better... */
#pragma clang diagnostic ignored "-Warray-bounds"
#endif
		/* Skip ._<file> when using copyfile and <file> exists */
		if ((pflag || !Xflag) && (curr->fts_level != FTS_ROOTLEVEL) &&
		    (curr->fts_namelen > 2) && /* ._\0 is not AppleDouble */
		    (curr->fts_name[0] == '.') && (curr->fts_name[1] == '_')) {
#ifdef __clang__
#pragma clang diagnostic pop
#endif
			struct stat statbuf;
			char path[PATH_MAX];
			char *p = strrchr(curr->fts_path, '/');
			if (p) {
				size_t s = p + 2 - curr->fts_path;
				if (s > sizeof(path)) s = sizeof(path);
				strlcpy(path, curr->fts_path, s);
				strlcat(path, curr->fts_name+2, sizeof(path));
			} else {
				strlcpy(path, curr->fts_name+2, sizeof(path));
			}
			if (!lstat(path, &statbuf)) {
				continue;
			}
		}
#endif /* __APPLE__ */
		/*
		 * 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);
				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(curr->fts_statp, -1))
					rval = 1;
#ifdef __APPLE__
				/* setfile will fail if writeattr is denied */
				if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_ACL)<0)
					warn("%s: unable to copy ACL to %s", curr->fts_path, to.p_path);
#else  /* !__APPLE__ */
				if (preserve_dir_acls(curr->fts_statp,
				    curr->fts_accpath, to.p_path) != 0)
					rval = 1;
#endif /* __APPLE__ */
			} 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);
				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;
			}
			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))
					badcp = rval = 1;
			} else {	
				if (copy_link(curr, !dne))
					badcp = 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);
				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) {
					if (COMPAT_MODE("bin/cp", "unix2003")) {
						warn("%s", to.p_path);
					} else {
						err(1, "%s", to.p_path);
					}
				}
			} else if (!S_ISDIR(to_stat.st_mode)) {
				errno = ENOTDIR;
				if (COMPAT_MODE("bin/cp", "unix2003")) {
					warn("%s", to.p_path);
				} else {
					err(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;
#ifdef __APPLE__
			if (!Xflag) {
				if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_XATTR) < 0)
					warn("%s: unable to copy extended attributes to %s", curr->fts_path, to.p_path);
				/* ACL and mtime set in postorder traversal */
			}
#endif /* __APPLE__ */
			break;
		case S_IFBLK:
		case S_IFCHR:
			if (Rflag) {
				if (copy_special(curr->fts_statp, !dne))
					badcp = rval = 1;
			} else {
				if (copy_file(curr, dne))
					badcp = rval = 1;
			}
			break;
		case S_IFIFO:
			if (Rflag) {
				if (copy_fifo(curr->fts_statp, !dne))
					badcp = rval = 1;
			} else {
				if (copy_file(curr, dne))
					badcp = rval = 1;
			}
			break;
		default:
			if (copy_file(curr, dne))
				badcp = rval = 1;
			break;
		}
		if (vflag && !badcp)
			(void)printf("%s -> %s\n", curr->fts_path, to.p_path);
	}
	if (errno)
		err(1, "fts_read");
	fts_close(ftsp);
	return (rval);
}
Пример #12
0
int
main(int argc, char *argv[])
{
	struct stat to_stat, tmp_stat;
	enum op type;
	int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
	char *target;

	Hflag = Lflag = Pflag = 0;
	while ((ch = getopt(argc, argv, "HLPRXafinprv")) != -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 'X':
			Xflag = 1;
			break;
		case 'f':
			fflag = 1;
			/* Determine if the STD is SUSv3 or Legacy */
			if (COMPAT_MODE("bin/cp", "unix2003"))
				nflag = 0;	/* reset nflag, but not iflag */
			else
				iflag = nflag = 0;	/* reset both */
			break;
		case 'i':
			iflag = 1;
			if (COMPAT_MODE("bin/cp", "unix2003"))
				nflag = 0;	/* reset nflag, but not fflag */
			else
				fflag = nflag = 0;
			break;
		case 'n':
			nflag = 1;
			fflag = iflag = 0;
			break;
		case 'p':
			pflag = 1;
			break;
		case 'r':
			rflag = 1;
			break;
		case 'v':
			vflag = 1;
			break;
		case 'a':
			pflag = 1;
			Pflag = 1;
			Rflag = 1;
			break;
		default:
			usage();
			break;
		}
	argc -= optind;
	argv += optind;

	if (argc < 2)
		usage();

	fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
	if (rflag) {
		if (Rflag)
			errx(1,
		    "the -R and -r options may not be specified together.");
		if (Hflag || Lflag || Pflag)
			errx(1,
	"the -H, -L, and -P options may not be specified with the -r option.");
		fts_options &= ~FTS_PHYSICAL;
		fts_options |= FTS_LOGICAL;
	}
	if (Rflag) {
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
		}
	} else {
		fts_options &= ~FTS_PHYSICAL;
		fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
	}
	(void)signal(SIGINFO, siginfo);

	/* Save the target base in "to". */
	target = argv[--argc];
	if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
		errx(1, "%s: name too long", target);
	to.p_end = to.p_path + strlen(to.p_path);
        if (to.p_path == to.p_end) {
		*to.p_end++ = '.';
		*to.p_end = 0;
	}
	have_trailing_slash = (to.p_end[-1] == '/');
	if (have_trailing_slash)
		STRIP_TRAILING_SLASH(to);
	to.target_end = to.p_end;

	/* Set end of argument list for fts(3). */
	argv[argc] = NULL;

	/*
	 * Cp has two distinct cases:
	 *
	 * cp [-R] source target
	 * cp [-R] source1 ... sourceN directory
	 *
	 * In both cases, source can be either a file or a directory.
	 *
	 * In (1), the target becomes a copy of the source. That is, if the
	 * source is a file, the target will be a file, and likewise for
	 * directories.
	 *
	 * In (2), the real target is not directory, but "directory/source".
	 */
	r = stat(to.p_path, &to_stat);
	if (r == -1 && errno != ENOENT)
		err(1, "%s", to.p_path);
	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
		/*
		 * Case (1).  Target is not a directory.
		 */
		if (argc > 1) {
			usage();
			exit(1);
		}
		/*
		 * Need to detect the case:
		 *	cp -R dir foo
		 * Where dir is a directory and foo does not exist, where
		 * we want pathname concatenations turned on but not for
		 * the initial mkdir().
		 */
		if (r == -1) {
			if (rflag || (Rflag && (Lflag || Hflag)))
				stat(*argv, &tmp_stat);
			else
				lstat(*argv, &tmp_stat);

			if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
				type = DIR_TO_DNE;
			else
				type = FILE_TO_FILE;
		} else
			type = FILE_TO_FILE;

		if (have_trailing_slash && type == FILE_TO_FILE) {
			if (r == -1)
				errx(1, "directory %s does not exist",
				     to.p_path);
			else
				errx(1, "%s is not a directory", to.p_path);
		}
	} else
		/*
		 * Case (2).  Target is a directory.
		 */
		type = FILE_TO_DIR;

	exit (copy(argv, type, fts_options));
}