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); }
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); }
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); }
/* * 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); }
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); }
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); }
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; }
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); }
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(¬used, &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); }
/* 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); }
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); }
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)); }