static int check(char *path, char *name, struct stat *sp) { int ch, first; char modep[15], *flagsp; /* Check -i first. */ if (iflag) (void)fprintf(stderr, "remove %s? ", path); else { /* * If it's not a symbolic link and it's unwritable and we're * talking to a terminal, ask. Symbolic links are excluded * because their permissions are meaningless. Check stdin_ok * first because we may not have stat'ed the file. * Also skip this check if the -P option was specified because * we will not be able to overwrite file contents and will * barf later. */ if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag || (!access(name, W_OK) && #ifdef SF_APPEND !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid)) #else 1) #endif ) return (1); bsd_strmode(sp->st_mode, modep); #ifdef SF_APPEND if ((flagsp = fflagstostr(sp->st_flags)) == NULL) exit(err(1, "fflagstostr")); (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", modep + 1, modep[9] == ' ' ? "" : " ", user_from_uid(sp->st_uid, 0), group_from_gid(sp->st_gid, 0), *flagsp ? flagsp : "", *flagsp ? " " : "", path); free(flagsp); #else (void)flagsp; (void)fprintf(stderr, "override %s%s %d/%d for %s? ", modep + 1, modep[9] == ' ' ? "" : " ", sp->st_uid, sp->st_gid, path); #endif } (void)fflush(stderr); first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); return (first == 'y' || first == 'Y'); }
/* * fflagstostr() wrapper that leaks only once */ char * xfflagstostr(unsigned long fflags) { static char *str = NULL; if (str != NULL) free(str); str = fflagstostr(fflags); if (str == NULL) err(1, "fflagstostr"); return (str); }
char * flags_to_string(u_long fflags) { char *string; string = fflagstostr(fflags); if (string != NULL && *string == '\0') { free(string); string = strdup("none"); } if (string == NULL) err(1, NULL); return string; }
static int check(const char *path, const char *name, struct stat *sp) { int ch, first; char modep[15], *flagsp; /* Check -i first. */ if (iflag) (void)fprintf(stderr, "remove %s? ", path); else { /* * If it's not a symbolic link and it's unwritable and we're * talking to a terminal, ask. Symbolic links are excluded * because their permissions are meaningless. Check stdin_ok * first because we may not have stat'ed the file. */ if (!stdin_ok || S_ISLNK(sp->st_mode) || (!access(name, W_OK) && !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))) return (1); strmode(sp->st_mode, modep); if ((flagsp = fflagstostr(sp->st_flags)) == NULL) err(1, "fflagstostr"); if (Pflag) errx(1, "%s: -P was specified, but file is not writable", path); (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", modep + 1, modep[9] == ' ' ? "" : " ", user_from_uid(sp->st_uid, 0), group_from_gid(sp->st_gid, 0), *flagsp ? flagsp : "", *flagsp ? " " : "", path); free(flagsp); } (void)fflush(stderr); first = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); return (first == 'y' || first == 'Y'); }
/* * Display() takes a linked list of FTSENT structures and passes the list * along with any other necessary information to the print function. P * points to the parent directory of the display list. */ static void display(const FTSENT *p, FTSENT *list, int options) { struct stat *sp; DISPLAY d; FTSENT *cur; NAMES *np; off_t maxsize; long maxblock; uintmax_t maxinode; u_long btotal, labelstrlen, maxlen, maxnlink; u_long maxlabelstr; u_int sizelen; int maxflags; gid_t maxgroup; uid_t maxuser; size_t flen, ulen, glen; char *initmax; int entries, needstats; const char *user, *group; char *flags, *labelstr = NULL; char ngroup[STRBUF_SIZEOF(uid_t) + 1]; char nuser[STRBUF_SIZEOF(gid_t) + 1]; needstats = f_inode || f_longform || f_size; flen = 0; btotal = 0; initmax = getenv("LS_COLWIDTHS"); /* Fields match -lios order. New ones should be added at the end. */ maxlabelstr = maxblock = maxlen = maxnlink = 0; maxuser = maxgroup = maxflags = maxsize = 0; maxinode = 0; if (initmax != NULL && *initmax != '\0') { char *initmax2, *jinitmax; int ninitmax; /* Fill-in "::" as "0:0:0" for the sake of scanf. */ jinitmax = malloc(strlen(initmax) * 2 + 2); if (jinitmax == NULL) err(1, "malloc"); initmax2 = jinitmax; if (*initmax == ':') strcpy(initmax2, "0:"), initmax2 += 2; else *initmax2++ = *initmax, *initmax2 = '\0'; for (initmax++; *initmax != '\0'; initmax++) { if (initmax[-1] == ':' && initmax[0] == ':') { *initmax2++ = '0'; *initmax2++ = initmax[0]; initmax2[1] = '\0'; } else { *initmax2++ = initmax[0]; initmax2[1] = '\0'; } } if (initmax2[-1] == ':') strcpy(initmax2, "0"); ninitmax = sscanf(jinitmax, " %ju : %ld : %lu : %u : %u : %i : %jd : %lu : %lu ", &maxinode, &maxblock, &maxnlink, &maxuser, &maxgroup, &maxflags, &maxsize, &maxlen, &maxlabelstr); f_notabs = 1; switch (ninitmax) { case 0: maxinode = 0; /* FALLTHROUGH */ case 1: maxblock = 0; /* FALLTHROUGH */ case 2: maxnlink = 0; /* FALLTHROUGH */ case 3: maxuser = 0; /* FALLTHROUGH */ case 4: maxgroup = 0; /* FALLTHROUGH */ case 5: maxflags = 0; /* FALLTHROUGH */ case 6: maxsize = 0; /* FALLTHROUGH */ case 7: maxlen = 0; /* FALLTHROUGH */ case 8: maxlabelstr = 0; /* FALLTHROUGH */ #ifdef COLORLS if (!f_color) #endif f_notabs = 0; /* FALLTHROUGH */ default: break; } MAKENINES(maxinode); MAKENINES(maxblock); MAKENINES(maxnlink); MAKENINES(maxsize); free(jinitmax); } d.s_size = 0; sizelen = 0; flags = NULL; for (cur = list, entries = 0; cur; cur = cur->fts_link) { if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { warnx("%s: %s", cur->fts_name, strerror(cur->fts_errno)); cur->fts_number = NO_PRINT; rval = 1; continue; } /* * P is NULL if list is the argv list, to which different rules * apply. */ if (p == NULL) { /* Directories will be displayed later. */ if (cur->fts_info == FTS_D && !f_listdir) { cur->fts_number = NO_PRINT; continue; } } else { /* Only display dot file if -a/-A set. */ if (cur->fts_name[0] == '.' && !f_listdot) { cur->fts_number = NO_PRINT; continue; } } if (cur->fts_namelen > maxlen) maxlen = cur->fts_namelen; if (f_octal || f_octal_escape) { u_long t = len_octal(cur->fts_name, cur->fts_namelen); if (t > maxlen) maxlen = t; } if (needstats) { sp = cur->fts_statp; if (sp->st_blocks > maxblock) maxblock = sp->st_blocks; if (sp->st_ino > maxinode) maxinode = sp->st_ino; if (sp->st_nlink > maxnlink) maxnlink = sp->st_nlink; if (sp->st_size > maxsize) maxsize = sp->st_size; btotal += sp->st_blocks; if (f_longform) { if (f_numericonly) { (void)snprintf(nuser, sizeof(nuser), "%u", sp->st_uid); (void)snprintf(ngroup, sizeof(ngroup), "%u", sp->st_gid); user = nuser; group = ngroup; } else { user = user_from_uid(sp->st_uid, 0); group = group_from_gid(sp->st_gid, 0); } if ((ulen = strlen(user)) > maxuser) maxuser = ulen; if ((glen = strlen(group)) > maxgroup) maxgroup = glen; if (f_flags) { flags = fflagstostr(sp->st_flags); if (flags != NULL && *flags == '\0') { free(flags); flags = strdup("-"); } if (flags == NULL) err(1, "fflagstostr"); flen = strlen(flags); if (flen > (size_t)maxflags) maxflags = flen; } else flen = 0; labelstr = NULL; if (f_label) { char name[PATH_MAX + 1]; mac_t label; int error; error = mac_prepare_file_label(&label); if (error == -1) { warn("MAC label for %s/%s", cur->fts_parent->fts_path, cur->fts_name); goto label_out; } if (cur->fts_level == FTS_ROOTLEVEL) snprintf(name, sizeof(name), "%s", cur->fts_name); else snprintf(name, sizeof(name), "%s/%s", cur->fts_parent-> fts_accpath, cur->fts_name); if (options & FTS_LOGICAL) error = mac_get_file(name, label); else error = mac_get_link(name, label); if (error == -1) { warn("MAC label for %s/%s", cur->fts_parent->fts_path, cur->fts_name); mac_free(label); goto label_out; } error = mac_to_text(label, &labelstr); if (error == -1) { warn("MAC label for %s/%s", cur->fts_parent->fts_path, cur->fts_name); mac_free(label); goto label_out; } mac_free(label); label_out: if (labelstr == NULL) labelstr = strdup("-"); labelstrlen = strlen(labelstr); if (labelstrlen > maxlabelstr) maxlabelstr = labelstrlen; } else labelstrlen = 0; if ((np = malloc(sizeof(NAMES) + labelstrlen + ulen + glen + flen + 4)) == NULL) err(1, "malloc"); np->user = &np->data[0]; (void)strcpy(np->user, user); np->group = &np->data[ulen + 1]; (void)strcpy(np->group, group); if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) { sizelen = snprintf(NULL, 0, "%#jx", (uintmax_t)sp->st_rdev); if (d.s_size < sizelen) d.s_size = sizelen; } if (f_flags) { np->flags = &np->data[ulen + glen + 2]; (void)strcpy(np->flags, flags); free(flags); } if (f_label) { np->label = &np->data[ulen + glen + 2 + (f_flags ? flen + 1 : 0)]; (void)strcpy(np->label, labelstr); free(labelstr); } cur->fts_pointer = np; } } ++entries; } /* * If there are no entries to display, we normally stop right * here. However, we must continue if we have to display the * total block count. In this case, we display the total only * on the second (p != NULL) pass. */ if (!entries && (!(f_longform || f_size) || p == NULL)) return; d.list = list; d.entries = entries; d.maxlen = maxlen; if (needstats) { d.btotal = btotal; d.s_block = snprintf(NULL, 0, "%lu", howmany(maxblock, blocksize)); d.s_flags = maxflags; d.s_label = maxlabelstr; d.s_group = maxgroup; d.s_inode = snprintf(NULL, 0, "%ju", maxinode); d.s_nlink = snprintf(NULL, 0, "%lu", maxnlink); sizelen = f_humanval ? HUMANVALSTR_LEN : snprintf(NULL, 0, "%ju", maxsize); if (d.s_size < sizelen) d.s_size = sizelen; d.s_user = maxuser; } if (f_thousands) /* make space for commas */ d.s_size += (d.s_size - 1) / 3; printfcn(&d); output = 1; if (f_longform) for (cur = list; cur; cur = cur->fts_link) free(cur->fts_pointer); }
/* * Display() takes a linked list of FTSENT structures and passes the list * along with any other necessary information to the print function. P * points to the parent directory of the display list. */ static void display(FTSENT *p, FTSENT *list) { struct stat *sp; DISPLAY d; FTSENT *cur; NAMES *np; off_t maxsize; u_long maxlen, maxnlink; unsigned long long btotal, maxblock; ino_t maxinode; int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; int entries, needstats; char *user, *group, buf[21]; /* 64 bits == 20 digits */ char nuser[12], ngroup[12]; char *flags = NULL; /* * If list is NULL there are two possibilities: that the parent * directory p has no children, or that fts_children() returned an * error. We ignore the error case since it will be replicated * on the next call to fts_read() on the post-order visit to the * directory p, and will be signalled in traverse(). */ if (list == NULL) return; needstats = f_inode || f_longform || f_size; flen = 0; btotal = maxblock = maxinode = maxlen = maxnlink = 0; bcfile = 0; maxuser = maxgroup = maxflags = 0; maxsize = 0; for (cur = list, entries = 0; cur != NULL; cur = cur->fts_link) { if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { warnx("%s: %s", cur->fts_name, strerror(cur->fts_errno)); cur->fts_number = NO_PRINT; rval = 1; continue; } /* * P is NULL if list is the argv list, to which different rules * apply. */ if (p == NULL) { /* Directories will be displayed later. */ if (cur->fts_info == FTS_D && !f_listdir) { cur->fts_number = NO_PRINT; continue; } } else { /* Only display dot file if -a/-A set. */ if (cur->fts_name[0] == '.' && !f_listdot) { cur->fts_number = NO_PRINT; continue; } } if (cur->fts_namelen > maxlen) maxlen = cur->fts_namelen; if (needstats) { sp = cur->fts_statp; if (sp->st_blocks > maxblock) maxblock = sp->st_blocks; if (sp->st_ino > maxinode) maxinode = sp->st_ino; if (sp->st_nlink > maxnlink) maxnlink = sp->st_nlink; if (sp->st_size > maxsize) maxsize = sp->st_size; btotal += sp->st_blocks; if (f_longform) { if (f_numericonly) { snprintf(nuser, 12, "%u", sp->st_uid); snprintf(ngroup, 12, "%u", sp->st_gid); user = nuser; group = ngroup; } else { user = user_from_uid(sp->st_uid, 0); group = group_from_gid(sp->st_gid, 0); } if ((ulen = strlen(user)) > maxuser) maxuser = ulen; if ((glen = strlen(group)) > maxgroup) maxgroup = glen; if (f_flags) { flags = fflagstostr(sp->st_flags); if (*flags == '\0') flags = "-"; if ((flen = strlen(flags)) > maxflags) maxflags = flen; } else flen = 0; if ((np = malloc(sizeof(NAMES) + ulen + 1 + glen + 1 + flen + 1)) == NULL) err(1, NULL); np->user = &np->data[0]; (void)strlcpy(np->user, user, ulen + 1); np->group = &np->data[ulen + 1]; (void)strlcpy(np->group, group, glen + 1); if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) bcfile = 1; if (f_flags) { np->flags = &np->data[ulen + 1 + glen + 1]; (void)strlcpy(np->flags, flags, flen + 1); if (*flags != '-') free(flags); } cur->fts_pointer = np; } } ++entries; } if (!entries) return; d.list = list; d.entries = entries; d.maxlen = maxlen; if (needstats) { d.bcfile = bcfile; d.btotal = btotal; (void)snprintf(buf, sizeof(buf), "%llu", maxblock); d.s_block = strlen(buf); d.s_flags = maxflags; d.s_group = maxgroup; (void)snprintf(buf, sizeof(buf), "%llu", (unsigned long long)maxinode); d.s_inode = strlen(buf); (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); d.s_nlink = strlen(buf); if (!f_humanval) { (void)snprintf(buf, sizeof(buf), "%lld", (long long) maxsize); d.s_size = strlen(buf); } else d.s_size = FMT_SCALED_STRSIZE-2; /* no - or '\0' */ d.s_user = maxuser; } printfcn(&d); output = 1; if (f_longform) for (cur = list; cur != NULL; cur = cur->fts_link) free(cur->fts_pointer); }
static void statf(int indent, FTSENT *p) { struct group *gr; struct passwd *pw; u_int32_t len, val; int fd, offset; char *name, *escaped_name; size_t esc_len; esc_len = p->fts_namelen * 4 + 1; escaped_name = malloc(esc_len); if (escaped_name == NULL) error("statf: %s", strerror(errno)); strnvis(escaped_name, p->fts_name, esc_len, VIS_WHITE | VIS_OCTAL | VIS_GLOB); if (iflag || S_ISDIR(p->fts_statp->st_mode)) offset = printf("%*s%s", indent, "", escaped_name); else offset = printf("%*s %s", indent, "", escaped_name); free(escaped_name); if (offset > (INDENTNAMELEN + indent)) offset = MAXLINELEN; else offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); if (!S_ISREG(p->fts_statp->st_mode) && !dflag) output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); if (p->fts_statp->st_uid != uid) { if (keys & F_UNAME) { if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { output(indent, &offset, "uname=%s", pw->pw_name); } else { error("could not get uname for uid=%u", p->fts_statp->st_uid); } } if (keys & F_UID) output(indent, &offset, "uid=%u", p->fts_statp->st_uid); } if (p->fts_statp->st_gid != gid) { if (keys & F_GNAME) { if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { output(indent, &offset, "gname=%s", gr->gr_name); } else { error("could not get gname for gid=%u", p->fts_statp->st_gid); } } if (keys & F_GID) 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_NLINK && p->fts_statp->st_nlink != 1) output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode)) output(indent, &offset, "size=%qd", p->fts_statp->st_size); if (keys & F_TIME) output(indent, &offset, "time=%lld.%ld", (long long)p->fts_statp->st_mtimespec.tv_sec, p->fts_statp->st_mtimespec.tv_nsec); if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { if ((fd = open(p->fts_accpath, MTREE_O_FLAGS, 0)) < 0 || crc(fd, &val, &len)) error("%s: %s", p->fts_accpath, strerror(errno)); (void)close(fd); output(indent, &offset, "cksum=%u", val); } if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { char *md5digest, buf[MD5_DIGEST_STRING_LENGTH]; md5digest = MD5File(p->fts_accpath,buf); if (!md5digest) error("%s: %s", p->fts_accpath, strerror(errno)); else output(indent, &offset, "md5digest=%s", md5digest); } if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { char *rmd160digest, buf[RMD160_DIGEST_STRING_LENGTH]; rmd160digest = RMD160File(p->fts_accpath,buf); if (!rmd160digest) error("%s: %s", p->fts_accpath, strerror(errno)); else output(indent, &offset, "rmd160digest=%s", rmd160digest); } if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { char *sha1digest, buf[SHA1_DIGEST_STRING_LENGTH]; sha1digest = SHA1File(p->fts_accpath,buf); if (!sha1digest) error("%s: %s", p->fts_accpath, strerror(errno)); else output(indent, &offset, "sha1digest=%s", sha1digest); } if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { char *sha256digest, buf[SHA256_DIGEST_STRING_LENGTH]; sha256digest = SHA256File(p->fts_accpath,buf); if (!sha256digest) error("%s: %s", p->fts_accpath, strerror(errno)); else output(indent, &offset, "sha256digest=%s", sha256digest); } if (keys & F_SLINK && (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { name = rlink(p->fts_accpath); esc_len = strlen(name) * 4 + 1; escaped_name = malloc(esc_len); if (escaped_name == NULL) error("statf: %s", strerror(errno)); strnvis(escaped_name, name, esc_len, VIS_WHITE | VIS_OCTAL); output(indent, &offset, "link=%s", escaped_name); free(escaped_name); } if (keys & F_FLAGS && !S_ISLNK(p->fts_statp->st_mode)) { char *file_flags; file_flags = fflagstostr(p->fts_statp->st_flags); if (file_flags == NULL) error("%s", strerror(errno)); if (*file_flags != '\0') output(indent, &offset, "flags=%s", file_flags); else output(indent, &offset, "flags=none"); free(file_flags); } (void)putchar('\n'); }
static int check(const char *path, const char *name, struct stat *sp) { static int perm_answer = -1; struct choice { int ch; const char *str; int res; int perm; } *choice, choices[] = { { 'y', "yes" , 1, 0 }, { 'n', "no" , 0, 0 }, { 'a', "always", 1, 1 }, { 'v', "never" , 0, 1 }, { 0, NULL, 0, 0 } }; char modep[15], *flagsp; if (perm_answer != -1) return (perm_answer); /* Check -i first. */ if (iflag) fprintf(stderr, "remove %s? ", path); else { /* * If it's not a symbolic link and it's unwritable and we're * talking to a terminal, ask. Symbolic links are excluded * because their permissions are meaningless. Check stdin_ok * first because we may not have stat'ed the file. * Also skip this check if the -P option was specified because * we will not be able to overwrite file contents and will * barf later. */ if (!stdin_ok || S_ISLNK(sp->st_mode) || Pflag || (!access(name, W_OK) && !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) && (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid))) return (1); strmode(sp->st_mode, modep); if ((flagsp = fflagstostr(sp->st_flags)) == NULL) err(1, NULL); fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ", modep + 1, modep[9] == ' ' ? "" : " ", user_from_uid(sp->st_uid, 0), group_from_gid(sp->st_gid, 0), *flagsp ? flagsp : "", *flagsp ? " " : "", path); free(flagsp); } fflush(stderr); for (;;) { size_t len; char *answer; answer = fgetln(stdin, &len); /* clearerr(stdin); */ if (answer == NULL) return (0); if (answer[len - 1] == '\n') len--; if (len == 0) continue; for (choice = choices; choice->str != NULL; choice++) { if (len == 1 && choice->ch == answer[0]) goto valid_choice; if (strncasecmp(answer, choice->str, len) == 0) goto valid_choice; } fprintf(stderr, "invalid answer, try again (y/n/a/v): "); } valid_choice: if (choice->perm) perm_answer = choice->res; return (choice->res); }
int compare(char *name, NODE *s, FTSENT *p) { u_int32_t len, val; int fd, label; char *cp, *tab = ""; label = 0; switch(s->type) { case F_BLOCK: if (!S_ISBLK(p->fts_statp->st_mode)) goto typeerr; break; case F_CHAR: if (!S_ISCHR(p->fts_statp->st_mode)) goto typeerr; break; case F_DIR: if (!S_ISDIR(p->fts_statp->st_mode)) goto typeerr; break; case F_FIFO: if (!S_ISFIFO(p->fts_statp->st_mode)) goto typeerr; break; case F_FILE: if (!S_ISREG(p->fts_statp->st_mode)) goto typeerr; break; case F_LINK: if (!S_ISLNK(p->fts_statp->st_mode)) goto typeerr; break; case F_SOCK: if (!S_ISSOCK(p->fts_statp->st_mode)) { typeerr: LABEL; (void)printf("\ttype (%s, %s)\n", ftype(s->type), inotype(p->fts_statp->st_mode)); } break; } /* Set the uid/gid first, then set the mode. */ if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { LABEL; (void)printf("%suser (%u, %u", tab, s->st_uid, p->fts_statp->st_uid); if (uflag) if (chown(p->fts_accpath, s->st_uid, -1)) (void)printf(", not modified: %s)\n", strerror(errno)); else (void)printf(", modified)\n"); else (void)printf(")\n"); tab = "\t"; } if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { LABEL; (void)printf("%sgid (%u, %u", tab, s->st_gid, p->fts_statp->st_gid); if (uflag) if (chown(p->fts_accpath, -1, s->st_gid)) (void)printf(", not modified: %s)\n", strerror(errno)); else (void)printf(", modified)\n"); else (void)printf(")\n"); tab = "\t"; } if (s->flags & F_MODE && s->st_mode != (p->fts_statp->st_mode & MBITS)) { if (lflag) { mode_t tmode, mode; tmode = s->st_mode; mode = p->fts_statp->st_mode & MBITS; /* * if none of the suid/sgid/etc bits are set, * then if the mode is a subset of the target, * skip. */ if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) || (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)))) if ((mode | tmode) == tmode) goto skip; } LABEL; (void)printf("%spermissions (%#o, %#o", tab, s->st_mode, p->fts_statp->st_mode & MBITS); if (uflag) if (chmod(p->fts_accpath, s->st_mode)) (void)printf(", not modified: %s)\n", strerror(errno)); else (void)printf(", modified)\n"); else (void)printf(")\n"); tab = "\t"; skip: ; } if (s->flags & F_NLINK && s->type != F_DIR && s->st_nlink != p->fts_statp->st_nlink) { LABEL; (void)printf("%slink count (%u, %u)\n", tab, s->st_nlink, p->fts_statp->st_nlink); tab = "\t"; } if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) { LABEL; (void)printf("%ssize (%qd, %qd)\n", tab, s->st_size, p->fts_statp->st_size); tab = "\t"; } /* * XXX * Since utimes(2) only takes a timeval, there's no point in * comparing the low bits of the timespec nanosecond field. This * will only result in mismatches that we can never fix. * * Doesn't display microsecond differences. */ if (s->flags & F_TIME) { struct timeval tv[2]; TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &p->fts_statp->st_mtimespec); if (tv[0].tv_sec != tv[1].tv_sec || tv[0].tv_usec != tv[1].tv_usec) { LABEL; (void)printf("%smodification time (%.24s, ", tab, ctime(&s->st_mtimespec.tv_sec)); (void)printf("%.24s", ctime(&p->fts_statp->st_mtimespec.tv_sec)); if (tflag) { tv[1] = tv[0]; if (utimes(p->fts_accpath, tv)) (void)printf(", not modified: %s)\n", strerror(errno)); else (void)printf(", modified)\n"); } else (void)printf(")\n"); tab = "\t"; } } if (s->flags & F_CKSUM) { if ((fd = open(p->fts_accpath, MTREE_O_FLAGS, 0)) < 0) { LABEL; (void)printf("%scksum: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else if (crc(fd, &val, &len)) { (void)close(fd); LABEL; (void)printf("%scksum: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else { (void)close(fd); if (s->cksum != val) { LABEL; (void)printf("%scksum (%u, %u)\n", tab, s->cksum, val); } tab = "\t"; } } if (s->flags & F_MD5) { char *new_digest, buf[MD5_DIGEST_STRING_LENGTH]; new_digest = MD5File(p->fts_accpath, buf); if (!new_digest) { LABEL; printf("%sMD5File: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else if (strcmp(new_digest, s->md5digest)) { LABEL; printf("%sMD5 (%s, %s)\n", tab, s->md5digest, new_digest); tab = "\t"; } } if (s->flags & F_RMD160) { char *new_digest, buf[RMD160_DIGEST_STRING_LENGTH]; new_digest = RMD160File(p->fts_accpath, buf); if (!new_digest) { LABEL; printf("%sRMD160File: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else if (strcmp(new_digest, s->rmd160digest)) { LABEL; printf("%sRMD160 (%s, %s)\n", tab, s->rmd160digest, new_digest); tab = "\t"; } } if (s->flags & F_SHA1) { char *new_digest, buf[SHA1_DIGEST_STRING_LENGTH]; new_digest = SHA1File(p->fts_accpath, buf); if (!new_digest) { LABEL; printf("%sSHA1File: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else if (strcmp(new_digest, s->sha1digest)) { LABEL; printf("%sSHA1 (%s, %s)\n", tab, s->sha1digest, new_digest); tab = "\t"; } } if (s->flags & F_SHA256) { char *new_digest, buf[SHA256_DIGEST_STRING_LENGTH]; new_digest = SHA256File(p->fts_accpath, buf); if (!new_digest) { LABEL; printf("%sSHA256File: %s: %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; } else if (strcmp(new_digest, s->sha256digest)) { LABEL; printf("%sSHA256 (%s, %s)\n", tab, s->sha256digest, new_digest); tab = "\t"; } } if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) { LABEL; (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink); } if (s->flags & F_FLAGS && s->file_flags != p->fts_statp->st_flags) { char *db_flags = NULL; char *cur_flags = NULL; if ((db_flags = fflagstostr(s->file_flags)) == NULL || (cur_flags = fflagstostr(p->fts_statp->st_flags)) == NULL) { LABEL; (void)printf("%sflags: %s %s\n", tab, p->fts_accpath, strerror(errno)); tab = "\t"; free(db_flags); free(cur_flags); } else { LABEL; REPLACE_COMMA(db_flags); REPLACE_COMMA(cur_flags); printf("%sflags (%s, %s", tab, (*db_flags == '\0') ? "-" : db_flags, (*cur_flags == '\0') ? "-" : cur_flags); tab = "\t"; if (uflag) if (chflags(p->fts_accpath, s->file_flags)) (void)printf(", not modified: %s)\n", strerror(errno)); else (void)printf(", modified)\n"); else (void)printf(")\n"); tab = "\t"; free(db_flags); free(cur_flags); } } return (label); }