11553Srgrimes/*- 21553Srgrimes * Copyright (c) 1989, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * Redistribution and use in source and binary forms, with or without 61553Srgrimes * modification, are permitted provided that the following conditions 71553Srgrimes * are met: 81553Srgrimes * 1. Redistributions of source code must retain the above copyright 91553Srgrimes * notice, this list of conditions and the following disclaimer. 101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111553Srgrimes * notice, this list of conditions and the following disclaimer in the 121553Srgrimes * documentation and/or other materials provided with the distribution. 13121300Sphk * 3. Neither the name of the University nor the names of its contributors 141553Srgrimes * may be used to endorse or promote products derived from this software 151553Srgrimes * without specific prior written permission. 161553Srgrimes * 171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271553Srgrimes * SUCH DAMAGE. 281553Srgrimes */ 291553Srgrimes 30114601Sobrien#if 0 311553Srgrimes#ifndef lint 321553Srgrimesstatic char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 33114601Sobrien#endif /* not lint */ 3430027Scharnier#endif 35114601Sobrien#include <sys/cdefs.h> 36114601Sobrien__FBSDID("$FreeBSD$"); 371553Srgrimes 381553Srgrimes#include <sys/param.h> 391553Srgrimes#include <sys/stat.h> 4030027Scharnier#include <dirent.h> 4130027Scharnier#include <err.h> 4230027Scharnier#include <errno.h> 431553Srgrimes#include <fcntl.h> 441553Srgrimes#include <fts.h> 451553Srgrimes#include <grp.h> 4644303Swollman#ifdef MD5 4730027Scharnier#include <md5.h> 4844303Swollman#endif 4944303Swollman#ifdef SHA1 5044303Swollman#include <sha.h> 5144303Swollman#endif 5244303Swollman#ifdef RMD160 5344303Swollman#include <ripemd.h> 5444303Swollman#endif 55144295Stobez#ifdef SHA256 56144295Stobez#include <sha256.h> 57144295Stobez#endif 581553Srgrimes#include <pwd.h> 59100070Sdes#include <stdint.h> 6030027Scharnier#include <stdio.h> 6130027Scharnier#include <time.h> 621553Srgrimes#include <unistd.h> 6342561Sjkoshy#include <vis.h> 641553Srgrimes#include "mtree.h" 651553Srgrimes#include "extern.h" 661553Srgrimes 671553Srgrimes#define INDENTNAMELEN 15 681553Srgrimes#define MAXLINELEN 80 691553Srgrimes 701553Srgrimesstatic gid_t gid; 711553Srgrimesstatic uid_t uid; 721553Srgrimesstatic mode_t mode; 7366584Sphkstatic u_long flags = 0xffffffff; 741553Srgrimes 75103726Swollmanstatic int dsort(const FTSENT * const *, const FTSENT * const *); 7699800Salfredstatic void output(int, int *, const char *, ...) __printflike(3, 4); 7799800Salfredstatic int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *); 7899800Salfredstatic void statf(int, FTSENT *); 791553Srgrimes 801553Srgrimesvoid 81121299Sphkcwalk(void) 821553Srgrimes{ 83121299Sphk FTS *t; 84121299Sphk FTSENT *p; 8599802Salfred time_t cl; 861553Srgrimes char *argv[2], host[MAXHOSTNAMELEN]; 8799802Salfred char dot[] = "."; 882860Srgrimes int indent = 0; 891553Srgrimes 90124265Sphk if (!nflag) { 91124265Sphk (void)time(&cl); 92124265Sphk (void)gethostname(host, sizeof(host)); 93124265Sphk (void)printf( 94124265Sphk "#\t user: %s\n#\tmachine: %s\n", 95124265Sphk getlogin(), host); 96124265Sphk (void)printf( 97124265Sphk "#\t tree: %s\n#\t date: %s", 98124265Sphk fullpath, ctime(&cl)); 99124265Sphk } 1001553Srgrimes 10199802Salfred argv[0] = dot; 1021553Srgrimes argv[1] = NULL; 1031553Srgrimes if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) 104124389Sphk err(1, "fts_open()"); 1052860Srgrimes while ((p = fts_read(t))) { 1062860Srgrimes if (iflag) 1072860Srgrimes indent = p->fts_level * 4; 10860418Swollman if (check_excludes(p->fts_name, p->fts_path)) { 10960418Swollman fts_set(t, p, FTS_SKIP); 11060418Swollman continue; 11160418Swollman } 1121553Srgrimes switch(p->fts_info) { 1131553Srgrimes case FTS_D: 1142860Srgrimes if (!dflag) 1152860Srgrimes (void)printf("\n"); 1162860Srgrimes if (!nflag) 1172860Srgrimes (void)printf("# %s\n", p->fts_path); 11854375Sjoe statd(t, p, &uid, &gid, &mode, &flags); 1192860Srgrimes statf(indent, p); 1201553Srgrimes break; 1211553Srgrimes case FTS_DP: 1222860Srgrimes if (!nflag && (p->fts_level > 0)) 1232860Srgrimes (void)printf("%*s# %s\n", indent, "", p->fts_path); 1242860Srgrimes (void)printf("%*s..\n", indent, ""); 1252860Srgrimes if (!dflag) 1262860Srgrimes (void)printf("\n"); 1271553Srgrimes break; 1281553Srgrimes case FTS_DNR: 1291553Srgrimes case FTS_ERR: 1301553Srgrimes case FTS_NS: 13130027Scharnier warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 1321553Srgrimes break; 1331553Srgrimes default: 1341553Srgrimes if (!dflag) 1352860Srgrimes statf(indent, p); 1361553Srgrimes break; 1378857Srgrimes 1381553Srgrimes } 1392860Srgrimes } 1401553Srgrimes (void)fts_close(t); 1411553Srgrimes if (sflag && keys & F_CKSUM) 142112214Srobert warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total); 1431553Srgrimes} 1441553Srgrimes 1451553Srgrimesstatic void 146121299Sphkstatf(int indent, FTSENT *p) 1471553Srgrimes{ 1481553Srgrimes struct group *gr; 1491553Srgrimes struct passwd *pw; 150112214Srobert uint32_t val; 151112214Srobert off_t len; 1522860Srgrimes int fd, offset; 15361749Sjoe char *fflags; 15442561Sjkoshy char *escaped_name; 1551553Srgrimes 15642561Sjkoshy escaped_name = calloc(1, p->fts_namelen * 4 + 1); 15742561Sjkoshy if (escaped_name == NULL) 15842561Sjkoshy errx(1, "statf(): calloc() failed"); 159121731Sphk strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB); 16042561Sjkoshy 1612860Srgrimes if (iflag || S_ISDIR(p->fts_statp->st_mode)) 16242561Sjkoshy offset = printf("%*s%s", indent, "", escaped_name); 1631553Srgrimes else 16442561Sjkoshy offset = printf("%*s %s", indent, "", escaped_name); 165121300Sphk 16642561Sjkoshy free(escaped_name); 1671553Srgrimes 1682860Srgrimes if (offset > (INDENTNAMELEN + indent)) 1692860Srgrimes offset = MAXLINELEN; 1701553Srgrimes else 1712860Srgrimes offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); 1721553Srgrimes 1732860Srgrimes if (!S_ISREG(p->fts_statp->st_mode) && !dflag) 1742860Srgrimes output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); 1752860Srgrimes if (p->fts_statp->st_uid != uid) { 1762860Srgrimes if (keys & F_UNAME) { 177124389Sphk pw = getpwuid(p->fts_statp->st_uid); 178124389Sphk if (pw != NULL) 179124389Sphk output(indent, &offset, "uname=%s", pw->pw_name); 180124389Sphk else if (wflag) 181124389Sphk warnx("Could not get uname for uid=%u", 182124389Sphk p->fts_statp->st_uid); 183124389Sphk else 18430027Scharnier errx(1, 185124389Sphk "Could not get uname for uid=%u", 186124389Sphk p->fts_statp->st_uid); 1872860Srgrimes } 1882860Srgrimes if (keys & F_UID) 1892860Srgrimes output(indent, &offset, "uid=%u", p->fts_statp->st_uid); 1902860Srgrimes } 1912860Srgrimes if (p->fts_statp->st_gid != gid) { 1922860Srgrimes if (keys & F_GNAME) { 193124389Sphk gr = getgrgid(p->fts_statp->st_gid); 194124389Sphk if (gr != NULL) 195124389Sphk output(indent, &offset, "gname=%s", gr->gr_name); 196124389Sphk else if (wflag) 197124389Sphk warnx("Could not get gname for gid=%u", 198124389Sphk p->fts_statp->st_gid); 199124389Sphk else 20030027Scharnier errx(1, 201124389Sphk "Could not get gname for gid=%u", 202124389Sphk p->fts_statp->st_gid); 2032860Srgrimes } 2042860Srgrimes if (keys & F_GID) 2052860Srgrimes output(indent, &offset, "gid=%u", p->fts_statp->st_gid); 2062860Srgrimes } 2071553Srgrimes if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 2082860Srgrimes output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS); 2091553Srgrimes if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 2102860Srgrimes output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); 211255483Sdelphij if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode)) 212100070Sdes output(indent, &offset, "size=%jd", 213100070Sdes (intmax_t)p->fts_statp->st_size); 2141553Srgrimes if (keys & F_TIME) 215187940Skientzle output(indent, &offset, "time=%ld.%09ld", 216205793Sed (long)p->fts_statp->st_mtim.tv_sec, 217205793Sed p->fts_statp->st_mtim.tv_nsec); 2181553Srgrimes if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 2191553Srgrimes if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 2201553Srgrimes crc(fd, &val, &len)) 221124389Sphk err(1, "%s", p->fts_accpath); 2221553Srgrimes (void)close(fd); 223112214Srobert output(indent, &offset, "cksum=%lu", (unsigned long)val); 2241553Srgrimes } 22544303Swollman#ifdef MD5 2266286Swollman if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 22744303Swollman char *digest, buf[33]; 2286286Swollman 22944303Swollman digest = MD5File(p->fts_accpath, buf); 230122134Sphk if (!digest) 231124389Sphk err(1, "%s", p->fts_accpath); 232122134Sphk output(indent, &offset, "md5digest=%s", digest); 2336286Swollman } 23444303Swollman#endif /* MD5 */ 23544303Swollman#ifdef SHA1 23644303Swollman if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 23744303Swollman char *digest, buf[41]; 23844303Swollman 23944303Swollman digest = SHA1_File(p->fts_accpath, buf); 240122134Sphk if (!digest) 241124389Sphk err(1, "%s", p->fts_accpath); 242122134Sphk output(indent, &offset, "sha1digest=%s", digest); 24344303Swollman } 24444303Swollman#endif /* SHA1 */ 24544303Swollman#ifdef RMD160 24644303Swollman if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 24744303Swollman char *digest, buf[41]; 24844303Swollman 24944303Swollman digest = RIPEMD160_File(p->fts_accpath, buf); 250122134Sphk if (!digest) 251124389Sphk err(1, "%s", p->fts_accpath); 252122134Sphk output(indent, &offset, "ripemd160digest=%s", digest); 25344303Swollman } 25444303Swollman#endif /* RMD160 */ 255144295Stobez#ifdef SHA256 256144295Stobez if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { 257144295Stobez char *digest, buf[65]; 258144295Stobez 259144295Stobez digest = SHA256_File(p->fts_accpath, buf); 260144295Stobez if (!digest) 261144295Stobez err(1, "%s", p->fts_accpath); 262144295Stobez output(indent, &offset, "sha256digest=%s", digest); 263144295Stobez } 264144295Stobez#endif /* SHA256 */ 2651553Srgrimes if (keys & F_SLINK && 2661553Srgrimes (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 2672860Srgrimes output(indent, &offset, "link=%s", rlink(p->fts_accpath)); 26861749Sjoe if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 26961749Sjoe fflags = flags_to_string(p->fts_statp->st_flags); 27061749Sjoe output(indent, &offset, "flags=%s", fflags); 27161749Sjoe free(fflags); 27261749Sjoe } 2731553Srgrimes (void)putchar('\n'); 2741553Srgrimes} 2751553Srgrimes 2761553Srgrimes#define MAXGID 5000 2771553Srgrimes#define MAXUID 5000 2781553Srgrimes#define MAXMODE MBITS + 1 27954375Sjoe#define MAXFLAGS 256 28054375Sjoe#define MAXS 16 2811553Srgrimes 2821553Srgrimesstatic int 283121299Sphkstatd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags) 2841553Srgrimes{ 285121299Sphk FTSENT *p; 286121299Sphk gid_t sgid; 287121299Sphk uid_t suid; 288121299Sphk mode_t smode; 289121299Sphk u_long sflags; 2901553Srgrimes struct group *gr; 2911553Srgrimes struct passwd *pw; 2922860Srgrimes gid_t savegid = *pgid; 2932860Srgrimes uid_t saveuid = *puid; 2942860Srgrimes mode_t savemode = *pmode; 29566584Sphk u_long saveflags = *pflags; 29654375Sjoe u_short maxgid, maxuid, maxmode, maxflags; 29754375Sjoe u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS]; 29861749Sjoe char *fflags; 2992877Srgrimes static int first = 1; 3001553Srgrimes 3011553Srgrimes if ((p = fts_children(t, 0)) == NULL) { 3021553Srgrimes if (errno) 303124389Sphk err(1, "%s", RP(parent)); 3041553Srgrimes return (1); 3051553Srgrimes } 3061553Srgrimes 3071553Srgrimes bzero(g, sizeof(g)); 3081553Srgrimes bzero(u, sizeof(u)); 3091553Srgrimes bzero(m, sizeof(m)); 31054375Sjoe bzero(f, sizeof(f)); 3111553Srgrimes 31254375Sjoe maxuid = maxgid = maxmode = maxflags = 0; 3131553Srgrimes for (; p; p = p->fts_link) { 3142860Srgrimes if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) { 3152860Srgrimes smode = p->fts_statp->st_mode & MBITS; 3162860Srgrimes if (smode < MAXMODE && ++m[smode] > maxmode) { 3172860Srgrimes savemode = smode; 3182860Srgrimes maxmode = m[smode]; 3192860Srgrimes } 3202860Srgrimes sgid = p->fts_statp->st_gid; 3212860Srgrimes if (sgid < MAXGID && ++g[sgid] > maxgid) { 3222860Srgrimes savegid = sgid; 3232860Srgrimes maxgid = g[sgid]; 3242860Srgrimes } 3252860Srgrimes suid = p->fts_statp->st_uid; 3262860Srgrimes if (suid < MAXUID && ++u[suid] > maxuid) { 3272860Srgrimes saveuid = suid; 3282860Srgrimes maxuid = u[suid]; 3292860Srgrimes } 33054375Sjoe 33154375Sjoe /* 33254375Sjoe * XXX 33354375Sjoe * note that the below will break when file flags 33454375Sjoe * are extended beyond the first 4 bytes of each 33554375Sjoe * half word of the flags 33654375Sjoe */ 33754375Sjoe#define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0)) 33854375Sjoe sflags = p->fts_statp->st_flags; 33954375Sjoe if (FLAGS2IDX(sflags) < MAXFLAGS && 34054375Sjoe ++f[FLAGS2IDX(sflags)] > maxflags) { 34154375Sjoe saveflags = sflags; 34266584Sphk maxflags = f[FLAGS2IDX(sflags)]; 34354375Sjoe } 3441553Srgrimes } 3451553Srgrimes } 3462860Srgrimes /* 3472860Srgrimes * If the /set record is the same as the last one we do not need to output 3482877Srgrimes * a new one. So first we check to see if anything changed. Note that we 3492877Srgrimes * always output a /set record for the first directory. 3502860Srgrimes */ 3512860Srgrimes if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) || 3522860Srgrimes (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) || 353121300Sphk ((keys & F_MODE) && (*pmode != savemode)) || 35466584Sphk ((keys & F_FLAGS) && (*pflags != saveflags)) || 35566584Sphk (first)) { 3562877Srgrimes first = 0; 3572860Srgrimes if (dflag) 3582860Srgrimes (void)printf("/set type=dir"); 3591553Srgrimes else 3602860Srgrimes (void)printf("/set type=file"); 36151705Sbillf if (keys & F_UNAME) { 362124389Sphk pw = getpwuid(saveuid); 363124389Sphk if (pw != NULL) 3642860Srgrimes (void)printf(" uname=%s", pw->pw_name); 365124389Sphk else if (wflag) 366124389Sphk warnx( "Could not get uname for uid=%u", saveuid); 3672860Srgrimes else 368124389Sphk errx(1, "Could not get uname for uid=%u", saveuid); 36951705Sbillf } 3702860Srgrimes if (keys & F_UID) 37138020Sbde (void)printf(" uid=%lu", (u_long)saveuid); 37251705Sbillf if (keys & F_GNAME) { 373124389Sphk gr = getgrgid(savegid); 374124389Sphk if (gr != NULL) 3752860Srgrimes (void)printf(" gname=%s", gr->gr_name); 376124389Sphk else if (wflag) 377124389Sphk warnx("Could not get gname for gid=%u", savegid); 3782860Srgrimes else 379124389Sphk errx(1, "Could not get gname for gid=%u", savegid); 38051705Sbillf } 3812860Srgrimes if (keys & F_GID) 38238020Sbde (void)printf(" gid=%lu", (u_long)savegid); 3832860Srgrimes if (keys & F_MODE) 3842860Srgrimes (void)printf(" mode=%#o", savemode); 3852860Srgrimes if (keys & F_NLINK) 3862860Srgrimes (void)printf(" nlink=1"); 38766584Sphk if (keys & F_FLAGS) { 38861749Sjoe fflags = flags_to_string(saveflags); 38961749Sjoe (void)printf(" flags=%s", fflags); 39061749Sjoe free(fflags); 39161749Sjoe } 3922860Srgrimes (void)printf("\n"); 3932860Srgrimes *puid = saveuid; 3942860Srgrimes *pgid = savegid; 3952860Srgrimes *pmode = savemode; 39654375Sjoe *pflags = saveflags; 3972860Srgrimes } 3981553Srgrimes return (0); 3991553Srgrimes} 4001553Srgrimes 4011553Srgrimesstatic int 402121299Sphkdsort(const FTSENT * const *a, const FTSENT * const *b) 4031553Srgrimes{ 4041553Srgrimes if (S_ISDIR((*a)->fts_statp->st_mode)) { 4051553Srgrimes if (!S_ISDIR((*b)->fts_statp->st_mode)) 4061553Srgrimes return (1); 4071553Srgrimes } else if (S_ISDIR((*b)->fts_statp->st_mode)) 4081553Srgrimes return (-1); 4091553Srgrimes return (strcmp((*a)->fts_name, (*b)->fts_name)); 4101553Srgrimes} 4111553Srgrimes 4121553Srgrimes#include <stdarg.h> 4131553Srgrimes 4141553Srgrimesvoid 4152860Srgrimesoutput(int indent, int *offset, const char *fmt, ...) 4161553Srgrimes{ 4171553Srgrimes va_list ap; 4181553Srgrimes char buf[1024]; 4191553Srgrimes va_start(ap, fmt); 4201553Srgrimes (void)vsnprintf(buf, sizeof(buf), fmt, ap); 4211553Srgrimes va_end(ap); 4221553Srgrimes 4231553Srgrimes if (*offset + strlen(buf) > MAXLINELEN - 3) { 4242860Srgrimes (void)printf(" \\\n%*s", INDENTNAMELEN + indent, ""); 4252860Srgrimes *offset = INDENTNAMELEN + indent; 4261553Srgrimes } 4271553Srgrimes *offset += printf(" %s", buf) + 1; 4281553Srgrimes} 429