void cwalk(void) { FTS *t; FTSENT *p; time_t clocktime; char host[MAXHOSTNAMELEN + 1]; char *argv[2]; char dot[] = "."; argv[0] = dot; argv[1] = NULL; time(&clocktime); gethostname(host, sizeof(host)); host[sizeof(host) - 1] = '\0'; printf( "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", getlogin(), host, fullpath, ctime(&clocktime)); if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) mtree_err("fts_open: %s", strerror(errno)); while ((p = fts_read(t)) != NULL) { if (check_excludes(p->fts_name, p->fts_path)) { fts_set(t, p, FTS_SKIP); continue; } switch(p->fts_info) { case FTS_D: printf("\n# %s\n", p->fts_path); statd(t, p, &uid, &gid, &mode, &flags); statf(p); break; case FTS_DP: if (p->fts_level > 0) printf("# %s\n..\n\n", p->fts_path); 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(p); break; } } fts_close(t); if (sflag && keys & F_CKSUM) mtree_err("%s checksum: %u", fullpath, crc_total); }
void read_excludes_file(const char *name) { FILE *fp; char *line; struct exclude *e; fp = fopen(name, "r"); if (fp == 0) err(1, "%s", name); while ((line = fparseln(fp, NULL, NULL, NULL, FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT | FPARSELN_UNESCESC)) != NULL) { if (line[0] == '\0') continue; if ((e = malloc(sizeof *e)) == NULL) mtree_err("memory allocation error"); e->glob = line; if (strchr(e->glob, '/') != NULL) e->pathname = 1; else e->pathname = 0; LIST_INSERT_HEAD(&excludes, e, link); } fclose(fp); }
const char * rlink(const char *name) { static char lbuf[MAXPATHLEN]; int len; if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) mtree_err("%s: %s", name, strerror(errno)); lbuf[len] = '\0'; return (lbuf); }
static dev_t parsedev(char *arg) { #define MAX_PACK_ARGS 3 u_long numbers[MAX_PACK_ARGS]; char *p, *ep, *dev; int argc; pack_t *pack; dev_t result; const char *error = NULL; if ((dev = strchr(arg, ',')) != NULL) { *dev++='\0'; if ((pack = pack_find(arg)) == NULL) mtree_err("unknown format `%s'", arg); argc = 0; while ((p = strsep(&dev, ",")) != NULL) { if (*p == '\0') mtree_err("missing number"); numbers[argc++] = strtoul(p, &ep, 0); if (*ep != '\0') mtree_err("invalid number `%s'", p); if (argc > MAX_PACK_ARGS) mtree_err("too many arguments"); } if (argc < 2) mtree_err("not enough arguments"); result = (*pack)(argc, numbers, &error); if (error != NULL) mtree_err("%s", error); } else { result = (dev_t)strtoul(arg, &ep, 0); if (*ep != '\0') mtree_err("invalid device `%s'", arg); } return (result); }
/* * dump_nodes -- * dump the NODEs from `cur', based in the directory `dir'. * if pathlast is none zero, print the path last, otherwise print * it first. */ void dump_nodes(const char *dir, NODE *root, int pathlast) { NODE *cur; char path[MAXPATHLEN]; const char *name; char *str; char *p, *q; for (cur = root; cur != NULL; cur = cur->next) { if (cur->type != F_DIR && !matchtags(cur)) continue; if (snprintf(path, sizeof(path), "%s%s%s", dir, *dir ? "/" : "", cur->name) >= (int)sizeof(path)) mtree_err("Pathname too long."); if (!pathlast) printf("%s", vispath(path)); #define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f))) if (MATCHFLAG(F_TYPE)) appendfield(pathlast, "type=%s", nodetype(cur->type)); if (MATCHFLAG(F_UID | F_UNAME)) { if (keys & F_UNAME && (name = user_from_uid(cur->st_uid, 1)) != NULL) appendfield(pathlast, "uname=%s", name); else appendfield(pathlast, "uid=%u", cur->st_uid); } if (MATCHFLAG(F_GID | F_GNAME)) { if (keys & F_GNAME && (name = group_from_gid(cur->st_gid, 1)) != NULL) appendfield(pathlast, "gname=%s", name); else appendfield(pathlast, "gid=%u", cur->st_gid); } if (MATCHFLAG(F_MODE)) appendfield(pathlast, "mode=%#o", cur->st_mode); if (MATCHFLAG(F_DEV) && (cur->type == F_BLOCK || cur->type == F_CHAR)) appendfield(pathlast, "device=%#llx", (long long)cur->st_rdev); if (MATCHFLAG(F_NLINK)) appendfield(pathlast, "nlink=%d", cur->st_nlink); if (MATCHFLAG(F_SLINK)) appendfield(pathlast, "link=%s", vispath(cur->slink)); if (MATCHFLAG(F_SIZE)) appendfield(pathlast, "size=%lld", (long long)cur->st_size); if (MATCHFLAG(F_TIME)) appendfield(pathlast, "time=%lld.%09ld", (long long)cur->st_mtimespec.tv_sec, cur->st_mtimespec.tv_nsec); if (MATCHFLAG(F_CKSUM)) appendfield(pathlast, "cksum=%lu", cur->cksum); if (MATCHFLAG(F_MD5)) appendfield(pathlast, "%s=%s", MD5KEY, cur->md5digest); if (MATCHFLAG(F_RMD160)) appendfield(pathlast, "%s=%s", RMD160KEY, cur->rmd160digest); if (MATCHFLAG(F_SHA1)) appendfield(pathlast, "%s=%s", SHA1KEY, cur->sha1digest); if (MATCHFLAG(F_SHA256)) appendfield(pathlast, "%s=%s", SHA256KEY, cur->sha256digest); if (MATCHFLAG(F_SHA384)) appendfield(pathlast, "%s=%s", SHA384KEY, cur->sha384digest); if (MATCHFLAG(F_SHA512)) appendfield(pathlast, "%s=%s", SHA512KEY, cur->sha512digest); if (MATCHFLAG(F_FLAGS)) { str = flags_to_string(cur->st_flags, "none"); appendfield(pathlast, "flags=%s", str); free(str); } if (MATCHFLAG(F_IGN)) appendfield(pathlast, "ignore"); if (MATCHFLAG(F_OPT)) appendfield(pathlast, "optional"); if (MATCHFLAG(F_TAGS)) { /* don't output leading or trailing commas */ p = cur->tags; while (*p == ',') p++; q = p + strlen(p); while(q > p && q[-1] == ',') q--; appendfield(pathlast, "tags=%.*s", (int)(q - p), p); } puts(pathlast ? vispath(path) : ""); if (cur->child) dump_nodes(path, cur->child, pathlast); } }
NODE * spec(FILE *fp) { NODE *centry, *last, *pathparent, *cur; char *p, *e, *next; NODE ginfo, *root; char *buf, *tname, *ntname; size_t tnamelen, plen; root = NULL; centry = last = NULL; tname = NULL; tnamelen = 0; memset(&ginfo, 0, sizeof(ginfo)); for (mtree_lineno = 0; (buf = fparseln(fp, NULL, &mtree_lineno, NULL, FPARSELN_UNESCCOMM)); free(buf)) { /* Skip leading whitespace. */ for (p = buf; *p && isspace((unsigned char)*p); ++p) continue; /* If nothing but whitespace, continue. */ if (!*p) continue; #ifdef DEBUG fprintf(stderr, "line %lu: {%s}\n", (u_long)mtree_lineno, p); #endif /* Grab file name, "$", "set", or "unset". */ next = buf; while ((p = strsep(&next, " \t")) != NULL && *p == '\0') continue; if (p == NULL) mtree_err("missing field"); if (p[0] == '/') { if (strcmp(p + 1, "set") == 0) set(next, &ginfo); else if (strcmp(p + 1, "unset") == 0) unset(next, &ginfo); else mtree_err("invalid specification `%s'", p); continue; } if (strcmp(p, "..") == 0) { /* Don't go up, if haven't gone down. */ if (root == NULL) goto noparent; if (last->type != F_DIR || last->flags & F_DONE) { if (last == root) goto noparent; last = last->parent; } last->flags |= F_DONE; continue; noparent: mtree_err("no parent node"); } plen = strlen(p) + 1; if (plen > tnamelen) { if ((ntname = realloc(tname, plen)) == NULL) mtree_err("realloc: %s", strerror(errno)); tname = ntname; tnamelen = plen; } if (strunvis(tname, p) == -1) mtree_err("strunvis failed on `%s'", p); p = tname; pathparent = NULL; if (strchr(p, '/') != NULL) { cur = root; for (; (e = strchr(p, '/')) != NULL; p = e+1) { if (p == e) continue; /* handle // */ *e = '\0'; if (strcmp(p, ".") != 0) { while (cur && strcmp(cur->name, p) != 0) { cur = cur->next; } } if (cur == NULL || cur->type != F_DIR) { mtree_err("%s: %s", tname, "missing directory in specification"); } *e = '/'; pathparent = cur; cur = cur->child; } if (*p == '\0') mtree_err("%s: empty leaf element", tname); } if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) mtree_err("%s", strerror(errno)); *centry = ginfo; centry->lineno = mtree_lineno; strcpy(centry->name, p); #define MAGIC "?*[" if (strpbrk(p, MAGIC)) centry->flags |= F_MAGIC; set(next, centry); if (root == NULL) { /* * empty tree */ if (strcmp(centry->name, ".") != 0 || centry->type != F_DIR) mtree_err( "root node must be the directory `.'"); last = root = centry; root->parent = root; } else if (pathparent != NULL) { /* * full path entry; add or replace */ centry->parent = pathparent; addchild(pathparent, centry); last = centry; } else if (strcmp(centry->name, ".") == 0) { /* * duplicate "." entry; always replace */ replacenode(root, centry); } else if (last->type == F_DIR && !(last->flags & F_DONE)) { /* * new relative child in current dir; * add or replace */ centry->parent = last; addchild(last, centry); last = centry; } else { /* * new relative child in parent dir * (after encountering ".." entry); * add or replace */ centry->parent = last->parent; addchild(last->parent, centry); last = centry; } } return (root); }
static int statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags) { FTSENT *p; gid_t sgid; uid_t suid; mode_t smode; u_long sflags = 0; const char *name; gid_t savegid; uid_t saveuid; mode_t savemode; u_long saveflags; u_short maxgid, maxuid, maxmode, maxflags; u_short g[MTREE_MAXGID], u[MTREE_MAXUID], m[MTREE_MAXMODE], f[MTREE_MAXFLAGS]; static int first = 1; savegid = *pgid; saveuid = *puid; savemode = *pmode; saveflags = *pflags; if ((p = fts_children(t, 0)) == NULL) { if (errno) mtree_err("%s: %s", RP(parent), strerror(errno)); return (1); } memset(g, 0, sizeof(g)); memset(u, 0, sizeof(u)); memset(m, 0, sizeof(m)); memset(f, 0, sizeof(f)); maxuid = maxgid = maxmode = maxflags = 0; for (; p; p = p->fts_link) { smode = p->fts_statp->st_mode & MBITS; if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) { savemode = smode; maxmode = m[smode]; } sgid = p->fts_statp->st_gid; if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) { savegid = sgid; maxgid = g[sgid]; } suid = p->fts_statp->st_uid; if (suid < MTREE_MAXUID && ++u[suid] > maxuid) { saveuid = suid; maxuid = u[suid]; } #if HAVE_STRUCT_STAT_ST_FLAGS sflags = FLAGS2INDEX(p->fts_statp->st_flags); if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) { saveflags = p->fts_statp->st_flags; maxflags = f[sflags]; } #endif } /* * If the /set record is the same as the last one we do not need to * output a new one. So first we check to see if anything changed. * Note that we always output a /set record for the first directory. */ if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) || ((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) || ((keys & F_MODE) && (*pmode != savemode)) || ((keys & F_FLAGS) && (*pflags != saveflags)) || first) { first = 0; printf("/set type=file"); if (keys & (F_UID | F_UNAME)) { if (keys & F_UNAME && (name = user_from_uid(saveuid, 1)) != NULL) printf(" uname=%s", name); else /* if (keys & F_UID) */ printf(" uid=%lu", (u_long)saveuid); } if (keys & (F_GID | F_GNAME)) { if (keys & F_GNAME && (name = group_from_gid(savegid, 1)) != NULL) printf(" gname=%s", name); else /* if (keys & F_UID) */ printf(" gid=%lu", (u_long)savegid); } if (keys & F_MODE) printf(" mode=%#lo", (u_long)savemode); if (keys & F_NLINK) printf(" nlink=1"); if (keys & F_FLAGS) printf(" flags=%s", flags_to_string(saveflags, "none")); printf("\n"); *puid = saveuid; *pgid = savegid; *pmode = savemode; *pflags = saveflags; } return (0); }
static void statf(FTSENT *p) { u_int32_t len, val; int fd, indent; const char *name; #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) char *digestbuf; #endif indent = printf("%s%s", S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); if (indent > INDENTNAMELEN) indent = MAXLINELEN; else indent += printf("%*s", INDENTNAMELEN - indent, ""); if (!S_ISREG(p->fts_statp->st_mode)) output(&indent, "type=%s", inotype(p->fts_statp->st_mode)); if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { if (keys & F_UNAME && (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) output(&indent, "uname=%s", name); else /* if (keys & F_UID) */ output(&indent, "uid=%u", p->fts_statp->st_uid); } if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { if (keys & F_GNAME && (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) output(&indent, "gname=%s", name); else /* if (keys & F_GID) */ output(&indent, "gid=%u", p->fts_statp->st_gid); } if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS); if (keys & F_DEV && (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) output(&indent, "device=%#llx", (long long)p->fts_statp->st_rdev); if (keys & F_NLINK && p->fts_statp->st_nlink != 1) output(&indent, "nlink=%u", p->fts_statp->st_nlink); if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode)) output(&indent, "size=%lld", (long long)p->fts_statp->st_size); if (keys & F_TIME) #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) output(&indent, "time=%ld.%ld", (long)p->fts_statp->st_mtimespec.tv_sec, p->fts_statp->st_mtimespec.tv_nsec); #else output(&indent, "time=%ld.%ld", (long)p->fts_statp->st_mtime, (long)0); #endif if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || crc(fd, &val, &len)) mtree_err("%s: %s", p->fts_accpath, strerror(errno)); close(fd); output(&indent, "cksum=%lu", (long)val); } #ifndef NO_MD5 if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: MD5File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "md5=%s", digestbuf); free(digestbuf); } #endif /* ! NO_MD5 */ #ifndef NO_RMD160 if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: RMD160File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "rmd160=%s", digestbuf); free(digestbuf); } #endif /* ! NO_RMD160 */ #ifndef NO_SHA1 if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA1File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "sha1=%s", digestbuf); free(digestbuf); } #endif /* ! NO_SHA1 */ #ifndef NO_SHA2 if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "sha256=%s", digestbuf); free(digestbuf); } if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "sha384=%s", digestbuf); free(digestbuf); } if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, strerror(errno)); output(&indent, "sha512=%s", digestbuf); free(digestbuf); } #endif /* ! NO_SHA2 */ if (keys & F_SLINK && (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) output(&indent, "link=%s", vispath(rlink(p->fts_accpath))); #if HAVE_STRUCT_STAT_ST_FLAGS if (keys & F_FLAGS && p->fts_statp->st_flags != flags) output(&indent, "flags=%s", flags_to_string(p->fts_statp->st_flags, "none")); #endif putchar('\n'); }
int main(int argc, char **argv) { int ch, status; unsigned int i; int cflag, Cflag, Dflag, Uflag, wflag; char *dir, *p; FILE *spec1, *spec2; setprogname(argv[0]); cflag = Cflag = Dflag = Uflag = wflag = 0; dir = NULL; init_excludes(); spec1 = stdin; spec2 = NULL; while ((ch = getopt(argc, argv, "bcCdDeE:f:F:I:ijk:K:lLmMnN:O:p:PqrR:s:StuUwWxX:")) != -1) { switch((char)ch) { case 'b': bflag = 1; break; case 'c': cflag = 1; break; case 'C': Cflag = 1; break; case 'd': dflag = 1; break; case 'D': Dflag = 1; break; case 'E': parsetags(&excludetags, optarg); break; case 'e': eflag = 1; break; case 'f': if (spec1 == stdin) { spec1 = fopen(optarg, "r"); if (spec1 == NULL) mtree_err("%s: %s", optarg, strerror(errno)); } else if (spec2 == NULL) { spec2 = fopen(optarg, "r"); if (spec2 == NULL) mtree_err("%s: %s", optarg, strerror(errno)); } else usage(); break; case 'F': for (i = 0; i < __arraycount(flavors); i++) if (strcmp(optarg, flavors[i].name) == 0) { flavor = flavors[i].flavor; break; } if (i == __arraycount(flavors)) usage(); break; case 'i': iflag = 1; break; case 'I': parsetags(&includetags, optarg); break; case 'j': jflag = 1; break; case 'k': keys = F_TYPE; while ((p = strsep(&optarg, " \t,")) != NULL) if (*p != '\0') keys |= parsekey(p, NULL); break; case 'K': while ((p = strsep(&optarg, " \t,")) != NULL) if (*p != '\0') keys |= parsekey(p, NULL); break; case 'l': lflag = 1; break; case 'L': ftsoptions &= ~FTS_PHYSICAL; ftsoptions |= FTS_LOGICAL; break; case 'm': mflag = 1; break; case 'M': mtree_Mflag = 1; break; case 'n': nflag = 1; break; case 'N': if (! setup_getid(optarg)) mtree_err( "Unable to use user and group databases in `%s'", optarg); break; case 'O': load_only(optarg); break; case 'p': dir = optarg; break; case 'P': ftsoptions &= ~FTS_LOGICAL; ftsoptions |= FTS_PHYSICAL; break; case 'q': qflag = 1; break; case 'r': rflag++; break; case 'R': while ((p = strsep(&optarg, " \t,")) != NULL) if (*p != '\0') keys &= ~parsekey(p, NULL); break; case 's': sflag = 1; crc_total = ~strtol(optarg, &p, 0); if (*p) mtree_err("illegal seed value -- %s", optarg); break; case 'S': mtree_Sflag = 1; break; case 't': tflag = 1; break; case 'u': uflag = 1; break; case 'U': Uflag = uflag = 1; break; case 'w': wflag = 1; break; case 'W': mtree_Wflag = 1; break; case 'x': ftsoptions |= FTS_XDEV; break; case 'X': read_excludes_file(optarg); break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc) usage(); switch (flavor) { case F_FREEBSD9: if (cflag && iflag) { warnx("-c and -i passed, replacing -i with -j for " "FreeBSD compatibility"); iflag = 0; jflag = 1; } if (dflag && !bflag) { warnx("Adding -b to -d for FreeBSD compatibility"); bflag = 1; } if (uflag && !iflag) { warnx("Adding -i to -%c for FreeBSD compatibility", Uflag ? 'U' : 'u'); iflag = 1; } if (uflag && !tflag) { warnx("Adding -t to -%c for FreeBSD compatibility", Uflag ? 'U' : 'u'); tflag = 1; } if (wflag) warnx("The -w flag is a no-op"); break; default: if (wflag) usage(); } if (spec2 && (cflag || Cflag || Dflag)) mtree_err("Double -f, -c, -C and -D flags are mutually " "exclusive"); if (dir && spec2) mtree_err("Double -f and -p flags are mutually exclusive"); if (dir && chdir(dir)) mtree_err("%s: %s", dir, strerror(errno)); if ((cflag || sflag) && !getcwd(fullpath, sizeof(fullpath))) mtree_err("%s", strerror(errno)); if ((cflag && Cflag) || (cflag && Dflag) || (Cflag && Dflag)) mtree_err("-c, -C and -D flags are mutually exclusive"); if (iflag && mflag) mtree_err("-i and -m flags are mutually exclusive"); if (lflag && uflag) mtree_err("-l and -u flags are mutually exclusive"); if (cflag) { cwalk(stdout); exit(0); } if (Cflag || Dflag) { dump_nodes(stdout, "", spec(spec1), Dflag); exit(0); } if (spec2 != NULL) status = mtree_specspec(spec1, spec2); else status = verify(spec1); if (Uflag && (status == MISMATCHEXIT)) status = 0; exit(status); }
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) mtree_err("fts_open: %s", strerror(errno)); level = root; specdepth = rval = 0; while ((p = fts_read(t)) != NULL) { 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 (specdepth > p->fts_level) { for (level = level->parent; level->prev; level = level->prev) continue; --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 (compare(ep, p)) rval = MISMATCHEXIT; if (!(ep->flags & F_IGN) && ep->type == F_DIR && p->fts_info == FTS_D) { if (ep->child) { level = ep->child; ++specdepth; } } else fts_set(t, p, FTS_SKIP); break; } if (ep) continue; extra: if (!eflag) { printf("extra: %s", RP(p)); if (rflag) { if ((S_ISDIR(p->fts_statp->st_mode) ? rmdir : unlink)(p->fts_accpath)) { printf(", not removed: %s", strerror(errno)); } else printf(", removed"); } putchar('\n'); } fts_set(t, p, FTS_SKIP); } fts_close(t); if (sflag) warnx("%s checksum: %u", fullpath, crc_total); return (rval); }
static void miss(NODE *p, char *tail) { int create; char *tp; const char *type; u_int32_t flags; for (; p; p = p->next) { if (p->flags & F_OPT && !(p->flags & F_VISIT)) continue; if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) continue; strcpy(tail, p->name); if (!(p->flags & F_VISIT)) printf("missing: %s", path); switch (p->type) { case F_BLOCK: case F_CHAR: type = "device"; break; case F_DIR: type = "directory"; break; case F_LINK: type = "symlink"; break; default: putchar('\n'); continue; } create = 0; if (!(p->flags & F_VISIT) && uflag) { if (mtree_Wflag || p->type == F_LINK) goto createit; if (!(p->flags & (F_UID | F_UNAME))) printf( " (%s not created: user not specified)", type); else if (!(p->flags & (F_GID | F_GNAME))) printf( " (%s not created: group not specified)", type); else if (!(p->flags & F_MODE)) printf( " (%s not created: mode not specified)", type); else createit: switch (p->type) { case F_BLOCK: case F_CHAR: if (mtree_Wflag) continue; if (!(p->flags & F_DEV)) printf( " (%s not created: device not specified)", type); else if (mknod(path, p->st_mode | nodetoino(p->type), p->st_rdev) == -1) printf(" (%s not created: %s)\n", type, strerror(errno)); else create = 1; break; case F_LINK: if (!(p->flags & F_SLINK)) printf( " (%s not created: link not specified)\n", type); else if (symlink(p->slink, path)) printf( " (%s not created: %s)\n", type, strerror(errno)); else create = 1; break; case F_DIR: if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO)) printf(" (not created: %s)", strerror(errno)); else create = 1; break; default: mtree_err("can't create create %s", nodetype(p->type)); } } if (create) printf(" (created)"); if (p->type == F_DIR) { if (!(p->flags & F_VISIT)) putchar('\n'); for (tp = tail; *tp; ++tp) continue; *tp = '/'; miss(p->child, tp + 1); *tp = '\0'; } else putchar('\n'); if (!create || mtree_Wflag) continue; if ((p->flags & (F_UID | F_UNAME)) && (p->flags & (F_GID | F_GNAME)) && (lchown(path, p->st_uid, p->st_gid))) { printf("%s: user/group/mode not modified: %s\n", path, strerror(errno)); printf("%s: warning: file mode %snot set\n", path, (p->flags & F_FLAGS) ? "and file flags " : ""); continue; } if (p->flags & F_MODE) { if (lchmod(path, p->st_mode)) printf("%s: permissions not set: %s\n", path, strerror(errno)); } #if HAVE_STRUCT_STAT_ST_FLAGS if ((p->flags & F_FLAGS) && p->st_flags) { if (iflag) flags = p->st_flags; else flags = p->st_flags & ~SP_FLGS; if (lchflags(path, flags)) printf("%s: file flags not set: %s\n", path, strerror(errno)); } #endif /* HAVE_STRUCT_STAT_ST_FLAGS */ } }
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); }
static void statf(int indent, FTSENT *p) { u_int32_t len, val; int fd, offset; const char *name = NULL; #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) char *digestbuf; #endif offset = printf("%*s%s%s", indent, "", S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); if (offset > (INDENTNAMELEN + indent)) offset = MAXLINELEN; else offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag)) output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { if (keys & F_UNAME && (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) output(indent, &offset, "uname=%s", name); if (keys & F_UID || (keys & F_UNAME && name == NULL)) output(indent, &offset, "uid=%u", p->fts_statp->st_uid); } if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { if (keys & F_GNAME && (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) output(indent, &offset, "gname=%s", name); if (keys & F_GID || (keys & F_GNAME && name == NULL)) output(indent, &offset, "gid=%u", p->fts_statp->st_gid); } if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS); if (keys & F_DEV && (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) output(indent, &offset, "device=%#jx", (uintmax_t)p->fts_statp->st_rdev); if (keys & F_NLINK && p->fts_statp->st_nlink != 1) output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); if (keys & F_SIZE && (flavor == F_FREEBSD9 || S_ISREG(p->fts_statp->st_mode))) output(indent, &offset, "size=%ju", (uintmax_t)p->fts_statp->st_size); if (keys & F_TIME) #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) output(indent, &offset, "time=%jd.%09ld", (intmax_t)p->fts_statp->st_mtimespec.tv_sec, p->fts_statp->st_mtimespec.tv_nsec); #else output(indent, &offset, "time=%jd.%09ld", (intmax_t)p->fts_statp->st_mtime, (long)0); #endif if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || crc(fd, &val, &len)) mtree_err("%s: %s", p->fts_accpath, strerror(errno)); close(fd); output(indent, &offset, "cksum=%lu", (long)val); } #ifndef NO_MD5 if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: MD5File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", MD5KEY, digestbuf); free(digestbuf); } #endif /* ! NO_MD5 */ #ifndef NO_RMD160 if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: RMD160File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", RMD160KEY, digestbuf); free(digestbuf); } #endif /* ! NO_RMD160 */ #ifndef NO_SHA1 if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA1File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", SHA1KEY, digestbuf); free(digestbuf); } #endif /* ! NO_SHA1 */ #ifndef NO_SHA2 if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", SHA256KEY, digestbuf); free(digestbuf); } #ifdef SHA384_BLOCK_LENGTH if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", SHA384KEY, digestbuf); free(digestbuf); } #endif if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, strerror(errno)); output(indent, &offset, "%s=%s", SHA512KEY, digestbuf); free(digestbuf); } #endif /* ! NO_SHA2 */ if (keys & F_SLINK && (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) output(indent, &offset, "link=%s", vispath(rlink(p->fts_accpath))); #if HAVE_STRUCT_STAT_ST_FLAGS if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { char *str = flags_to_string(p->fts_statp->st_flags, "none"); output(indent, &offset, "flags=%s", str); free(str); } #endif putchar('\n'); }
/* * dump_nodes -- * dump the NODEs from `cur', based in the directory `dir'. * if pathlast is none zero, print the path last, otherwise print * it first. */ void dump_nodes(const char *dir, NODE *root, int pathlast) { NODE *cur; char path[MAXPATHLEN]; const char *name; for (cur = root; cur != NULL; cur = cur->next) { if (cur->type != F_DIR && !matchtags(cur)) continue; if (snprintf(path, sizeof(path), "%s%s%s", dir, *dir ? "/" : "", cur->name) >= sizeof(path)) mtree_err("Pathname too long."); if (!pathlast) printf("%s ", vispath(path)); #define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f))) if (MATCHFLAG(F_TYPE)) printf("type=%s ", nodetype(cur->type)); if (MATCHFLAG(F_UID | F_UNAME)) { if (keys & F_UNAME && (name = user_from_uid(cur->st_uid, 1)) != NULL) printf("uname=%s ", name); else printf("uid=%u ", cur->st_uid); } if (MATCHFLAG(F_GID | F_GNAME)) { if (keys & F_GNAME && (name = group_from_gid(cur->st_gid, 1)) != NULL) printf("gname=%s ", name); else printf("gid=%u ", cur->st_gid); } if (MATCHFLAG(F_MODE)) printf("mode=%#o ", cur->st_mode); if (MATCHFLAG(F_DEV) && (cur->type == F_BLOCK || cur->type == F_CHAR)) printf("device=%#x ", cur->st_rdev); if (MATCHFLAG(F_NLINK)) printf("nlink=%d ", cur->st_nlink); if (MATCHFLAG(F_SLINK)) printf("link=%s ", cur->slink); if (MATCHFLAG(F_SIZE)) printf("size=%lld ", (long long)cur->st_size); if (MATCHFLAG(F_TIME)) printf("time=%ld.%ld ", (long)cur->st_mtimespec.tv_sec, cur->st_mtimespec.tv_nsec); if (MATCHFLAG(F_CKSUM)) printf("cksum=%lu ", cur->cksum); if (MATCHFLAG(F_MD5)) printf("md5=%s ", cur->md5digest); if (MATCHFLAG(F_RMD160)) printf("rmd160=%s ", cur->rmd160digest); if (MATCHFLAG(F_SHA1)) printf("sha1=%s ", cur->sha1digest); if (MATCHFLAG(F_FLAGS)) printf("flags=%s ", flags_to_string(cur->st_flags, "none")); if (MATCHFLAG(F_IGN)) printf("ignore "); if (MATCHFLAG(F_OPT)) printf("optional "); if (MATCHFLAG(F_TAGS)) printf("tags=%s ", cur->tags); puts(pathlast ? vispath(path) : ""); if (cur->child) dump_nodes(path, cur->child, pathlast); } }