create.c revision 121731
1254721Semaste/*- 2254721Semaste * Copyright (c) 1989, 1993 3254721Semaste * The Regents of the University of California. All rights reserved. 4254721Semaste * 5254721Semaste * Redistribution and use in source and binary forms, with or without 6254721Semaste * modification, are permitted provided that the following conditions 7254721Semaste * are met: 8254721Semaste * 1. Redistributions of source code must retain the above copyright 9254721Semaste * notice, this list of conditions and the following disclaimer. 10254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 11254721Semaste * notice, this list of conditions and the following disclaimer in the 12254721Semaste * documentation and/or other materials provided with the distribution. 13254721Semaste * 3. Neither the name of the University nor the names of its contributors 14254721Semaste * may be used to endorse or promote products derived from this software 15254721Semaste * without specific prior written permission. 16254721Semaste * 17254721Semaste * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20254721Semaste * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27254721Semaste * SUCH DAMAGE. 28254721Semaste */ 29254721Semaste 30254721Semaste#if 0 31254721Semaste#ifndef lint 32254721Semastestatic char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 33254721Semaste#endif /* not lint */ 34254721Semaste#endif 35254721Semaste#include <sys/cdefs.h> 36254721Semaste__FBSDID("$FreeBSD: head/usr.sbin/mtree/create.c 121731 2003-10-30 10:48:43Z phk $"); 37254721Semaste 38254721Semaste#include <sys/param.h> 39254721Semaste#include <sys/stat.h> 40254721Semaste#include <dirent.h> 41254721Semaste#include <err.h> 42269024Semaste#include <errno.h> 43269024Semaste#include <fcntl.h> 44254721Semaste#include <fts.h> 45254721Semaste#include <grp.h> 46254721Semaste#ifdef MD5 47269024Semaste#include <md5.h> 48269024Semaste#endif 49269024Semaste#ifdef SHA1 50254721Semaste#include <sha.h> 51254721Semaste#endif 52254721Semaste#ifdef RMD160 53254721Semaste#include <ripemd.h> 54254721Semaste#endif 55254721Semaste#include <pwd.h> 56269024Semaste#include <stdint.h> 57269024Semaste#include <stdio.h> 58269024Semaste#include <time.h> 59269024Semaste#include <unistd.h> 60269024Semaste#include <vis.h> 61269024Semaste#include "mtree.h" 62269024Semaste#include "extern.h" 63269024Semaste 64269024Semaste#define INDENTNAMELEN 15 65254721Semaste#define MAXLINELEN 80 66254721Semaste 67254721Semasteextern int ftsoptions; 68254721Semasteextern int dflag, iflag, nflag, sflag; 69254721Semasteextern u_int keys; 70254721Semasteextern char fullpath[MAXPATHLEN]; 71254721Semasteextern int lineno; 72254721Semaste 73254721Semastestatic gid_t gid; 74254721Semastestatic uid_t uid; 75254721Semastestatic mode_t mode; 76254721Semastestatic u_long flags = 0xffffffff; 77254721Semaste 78254721Semastestatic int dsort(const FTSENT * const *, const FTSENT * const *); 79254721Semastestatic void output(int, int *, const char *, ...) __printflike(3, 4); 80254721Semastestatic int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *); 81254721Semastestatic void statf(int, FTSENT *); 82254721Semaste 83254721Semastevoid 84254721Semastecwalk(void) 85254721Semaste{ 86254721Semaste FTS *t; 87254721Semaste FTSENT *p; 88254721Semaste time_t cl; 89254721Semaste char *argv[2], host[MAXHOSTNAMELEN]; 90254721Semaste char dot[] = "."; 91254721Semaste int indent = 0; 92254721Semaste 93254721Semaste (void)time(&cl); 94254721Semaste (void)gethostname(host, sizeof(host)); 95254721Semaste (void)printf( 96254721Semaste "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", 97254721Semaste getlogin(), host, fullpath, ctime(&cl)); 98254721Semaste 99254721Semaste argv[0] = dot; 100254721Semaste argv[1] = NULL; 101254721Semaste if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) 102254721Semaste err(1, "line %d: fts_open", lineno); 103254721Semaste while ((p = fts_read(t))) { 104254721Semaste if (iflag) 105254721Semaste indent = p->fts_level * 4; 106254721Semaste if (check_excludes(p->fts_name, p->fts_path)) { 107254721Semaste fts_set(t, p, FTS_SKIP); 108254721Semaste continue; 109254721Semaste } 110254721Semaste switch(p->fts_info) { 111254721Semaste case FTS_D: 112254721Semaste if (!dflag) 113254721Semaste (void)printf("\n"); 114254721Semaste if (!nflag) 115254721Semaste (void)printf("# %s\n", p->fts_path); 116254721Semaste statd(t, p, &uid, &gid, &mode, &flags); 117254721Semaste statf(indent, p); 118254721Semaste break; 119254721Semaste case FTS_DP: 120254721Semaste if (!nflag && (p->fts_level > 0)) 121254721Semaste (void)printf("%*s# %s\n", indent, "", p->fts_path); 122254721Semaste (void)printf("%*s..\n", indent, ""); 123254721Semaste if (!dflag) 124254721Semaste (void)printf("\n"); 125254721Semaste break; 126254721Semaste case FTS_DNR: 127254721Semaste case FTS_ERR: 128254721Semaste case FTS_NS: 129254721Semaste warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 130254721Semaste break; 131254721Semaste default: 132254721Semaste if (!dflag) 133254721Semaste statf(indent, p); 134254721Semaste break; 135254721Semaste 136254721Semaste } 137254721Semaste } 138254721Semaste (void)fts_close(t); 139254721Semaste if (sflag && keys & F_CKSUM) 140254721Semaste warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total); 141254721Semaste} 142254721Semaste 143254721Semastestatic void 144254721Semastestatf(int indent, FTSENT *p) 145254721Semaste{ 146254721Semaste struct group *gr; 147254721Semaste struct passwd *pw; 148254721Semaste uint32_t val; 149254721Semaste off_t len; 150254721Semaste int fd, offset; 151254721Semaste char *fflags; 152254721Semaste char *escaped_name; 153254721Semaste 154254721Semaste escaped_name = calloc(1, p->fts_namelen * 4 + 1); 155254721Semaste if (escaped_name == NULL) 156254721Semaste errx(1, "statf(): calloc() failed"); 157254721Semaste strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB); 158254721Semaste 159254721Semaste if (iflag || S_ISDIR(p->fts_statp->st_mode)) 160254721Semaste offset = printf("%*s%s", indent, "", escaped_name); 161254721Semaste else 162254721Semaste offset = printf("%*s %s", indent, "", escaped_name); 163254721Semaste 164254721Semaste free(escaped_name); 165254721Semaste 166254721Semaste if (offset > (INDENTNAMELEN + indent)) 167254721Semaste offset = MAXLINELEN; 168254721Semaste else 169254721Semaste offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); 170254721Semaste 171254721Semaste if (!S_ISREG(p->fts_statp->st_mode) && !dflag) 172254721Semaste output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); 173254721Semaste if (p->fts_statp->st_uid != uid) { 174254721Semaste if (keys & F_UNAME) { 175254721Semaste if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { 176254721Semaste output(indent, &offset, "uname=%s", pw->pw_name); 177254721Semaste } else { 178254721Semaste errx(1, 179254721Semaste "line %d: could not get uname for uid=%u", 180254721Semaste lineno, p->fts_statp->st_uid); 181254721Semaste } 182254721Semaste } 183254721Semaste if (keys & F_UID) 184254721Semaste output(indent, &offset, "uid=%u", p->fts_statp->st_uid); 185254721Semaste } 186254721Semaste if (p->fts_statp->st_gid != gid) { 187254721Semaste if (keys & F_GNAME) { 188254721Semaste if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { 189254721Semaste output(indent, &offset, "gname=%s", gr->gr_name); 190254721Semaste } else { 191254721Semaste errx(1, 192254721Semaste "line %d: could not get gname for gid=%u", 193254721Semaste lineno, p->fts_statp->st_gid); 194254721Semaste } 195254721Semaste } 196254721Semaste if (keys & F_GID) 197254721Semaste output(indent, &offset, "gid=%u", p->fts_statp->st_gid); 198254721Semaste } 199254721Semaste if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 200254721Semaste output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS); 201254721Semaste if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 202254721Semaste output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); 203254721Semaste if (keys & F_SIZE) 204254721Semaste output(indent, &offset, "size=%jd", 205254721Semaste (intmax_t)p->fts_statp->st_size); 206254721Semaste if (keys & F_TIME) 207254721Semaste output(indent, &offset, "time=%ld.%ld", 208254721Semaste (long)p->fts_statp->st_mtimespec.tv_sec, 209254721Semaste p->fts_statp->st_mtimespec.tv_nsec); 210254721Semaste if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 211254721Semaste if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 212254721Semaste crc(fd, &val, &len)) 213254721Semaste err(1, "line %d: %s", lineno, p->fts_accpath); 214254721Semaste (void)close(fd); 215254721Semaste output(indent, &offset, "cksum=%lu", (unsigned long)val); 216254721Semaste } 217254721Semaste#ifdef MD5 218254721Semaste if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 219254721Semaste char *digest, buf[33]; 220254721Semaste 221254721Semaste digest = MD5File(p->fts_accpath, buf); 222254721Semaste if (!digest) { 223254721Semaste err(1, "line %d: %s", lineno, p->fts_accpath); 224254721Semaste } else { 225254721Semaste output(indent, &offset, "md5digest=%s", digest); 226254721Semaste } 227254721Semaste } 228254721Semaste#endif /* MD5 */ 229254721Semaste#ifdef SHA1 230254721Semaste if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 231254721Semaste char *digest, buf[41]; 232254721Semaste 233254721Semaste digest = SHA1_File(p->fts_accpath, buf); 234254721Semaste if (!digest) { 235254721Semaste err(1, "line %d: %s", lineno, p->fts_accpath); 236254721Semaste } else { 237254721Semaste output(indent, &offset, "sha1digest=%s", digest); 238254721Semaste } 239254721Semaste } 240254721Semaste#endif /* SHA1 */ 241254721Semaste#ifdef RMD160 242254721Semaste if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 243254721Semaste char *digest, buf[41]; 244254721Semaste 245254721Semaste digest = RIPEMD160_File(p->fts_accpath, buf); 246254721Semaste if (!digest) { 247254721Semaste err(1, "line %d: %s", lineno, p->fts_accpath); 248254721Semaste } else { 249254721Semaste output(indent, &offset, "ripemd160digest=%s", digest); 250254721Semaste } 251254721Semaste } 252254721Semaste#endif /* RMD160 */ 253254721Semaste if (keys & F_SLINK && 254254721Semaste (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 255254721Semaste output(indent, &offset, "link=%s", rlink(p->fts_accpath)); 256254721Semaste if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 257254721Semaste fflags = flags_to_string(p->fts_statp->st_flags); 258254721Semaste output(indent, &offset, "flags=%s", fflags); 259254721Semaste free(fflags); 260254721Semaste } 261254721Semaste (void)putchar('\n'); 262254721Semaste} 263254721Semaste 264254721Semaste#define MAXGID 5000 265254721Semaste#define MAXUID 5000 266254721Semaste#define MAXMODE MBITS + 1 267254721Semaste#define MAXFLAGS 256 268254721Semaste#define MAXS 16 269254721Semaste 270254721Semastestatic int 271254721Semastestatd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags) 272254721Semaste{ 273254721Semaste FTSENT *p; 274254721Semaste gid_t sgid; 275254721Semaste uid_t suid; 276254721Semaste mode_t smode; 277254721Semaste u_long sflags; 278254721Semaste struct group *gr; 279254721Semaste struct passwd *pw; 280254721Semaste gid_t savegid = *pgid; 281254721Semaste uid_t saveuid = *puid; 282254721Semaste mode_t savemode = *pmode; 283254721Semaste u_long saveflags = *pflags; 284254721Semaste u_short maxgid, maxuid, maxmode, maxflags; 285254721Semaste u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS]; 286254721Semaste char *fflags; 287254721Semaste static int first = 1; 288254721Semaste 289254721Semaste if ((p = fts_children(t, 0)) == NULL) { 290254721Semaste if (errno) 291254721Semaste err(1, "line %d: %s", lineno, RP(parent)); 292254721Semaste return (1); 293254721Semaste } 294254721Semaste 295254721Semaste bzero(g, sizeof(g)); 296254721Semaste bzero(u, sizeof(u)); 297254721Semaste bzero(m, sizeof(m)); 298254721Semaste bzero(f, sizeof(f)); 299254721Semaste 300254721Semaste maxuid = maxgid = maxmode = maxflags = 0; 301254721Semaste for (; p; p = p->fts_link) { 302254721Semaste if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) { 303254721Semaste smode = p->fts_statp->st_mode & MBITS; 304254721Semaste if (smode < MAXMODE && ++m[smode] > maxmode) { 305254721Semaste savemode = smode; 306254721Semaste maxmode = m[smode]; 307254721Semaste } 308263363Semaste sgid = p->fts_statp->st_gid; 309263363Semaste if (sgid < MAXGID && ++g[sgid] > maxgid) { 310263363Semaste savegid = sgid; 311263367Semaste maxgid = g[sgid]; 312263363Semaste } 313254721Semaste suid = p->fts_statp->st_uid; 314254721Semaste if (suid < MAXUID && ++u[suid] > maxuid) { 315254721Semaste saveuid = suid; 316254721Semaste maxuid = u[suid]; 317254721Semaste } 318254721Semaste 319254721Semaste /* 320254721Semaste * XXX 321254721Semaste * note that the below will break when file flags 322263363Semaste * are extended beyond the first 4 bytes of each 323254721Semaste * half word of the flags 324263363Semaste */ 325254721Semaste#define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0)) 326254721Semaste sflags = p->fts_statp->st_flags; 327254721Semaste if (FLAGS2IDX(sflags) < MAXFLAGS && 328254721Semaste ++f[FLAGS2IDX(sflags)] > maxflags) { 329254721Semaste saveflags = sflags; 330254721Semaste maxflags = f[FLAGS2IDX(sflags)]; 331254721Semaste } 332254721Semaste } 333254721Semaste } 334254721Semaste /* 335254721Semaste * If the /set record is the same as the last one we do not need to output 336254721Semaste * a new one. So first we check to see if anything changed. Note that we 337254721Semaste * always output a /set record for the first directory. 338254721Semaste */ 339254721Semaste if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) || 340254721Semaste (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) || 341254721Semaste ((keys & F_MODE) && (*pmode != savemode)) || 342254721Semaste ((keys & F_FLAGS) && (*pflags != saveflags)) || 343254721Semaste (first)) { 344254721Semaste first = 0; 345254721Semaste if (dflag) 346254721Semaste (void)printf("/set type=dir"); 347254721Semaste else 348254721Semaste (void)printf("/set type=file"); 349254721Semaste if (keys & F_UNAME) { 350254721Semaste if ((pw = getpwuid(saveuid)) != NULL) 351254721Semaste (void)printf(" uname=%s", pw->pw_name); 352254721Semaste else 353254721Semaste errx(1, 354254721Semaste "line %d: could not get uname for uid=%u", 355254721Semaste lineno, saveuid); 356254721Semaste } 357254721Semaste if (keys & F_UID) 358254721Semaste (void)printf(" uid=%lu", (u_long)saveuid); 359254721Semaste if (keys & F_GNAME) { 360254721Semaste if ((gr = getgrgid(savegid)) != NULL) 361254721Semaste (void)printf(" gname=%s", gr->gr_name); 362254721Semaste else 363254721Semaste errx(1, 364254721Semaste "line %d: could not get gname for gid=%u", 365254721Semaste lineno, savegid); 366254721Semaste } 367254721Semaste if (keys & F_GID) 368254721Semaste (void)printf(" gid=%lu", (u_long)savegid); 369254721Semaste if (keys & F_MODE) 370254721Semaste (void)printf(" mode=%#o", savemode); 371254721Semaste if (keys & F_NLINK) 372254721Semaste (void)printf(" nlink=1"); 373254721Semaste if (keys & F_FLAGS) { 374254721Semaste fflags = flags_to_string(saveflags); 375254721Semaste (void)printf(" flags=%s", fflags); 376254721Semaste free(fflags); 377254721Semaste } 378254721Semaste (void)printf("\n"); 379254721Semaste *puid = saveuid; 380254721Semaste *pgid = savegid; 381254721Semaste *pmode = savemode; 382254721Semaste *pflags = saveflags; 383254721Semaste } 384254721Semaste return (0); 385254721Semaste} 386254721Semaste 387254721Semastestatic int 388254721Semastedsort(const FTSENT * const *a, const FTSENT * const *b) 389254721Semaste{ 390254721Semaste if (S_ISDIR((*a)->fts_statp->st_mode)) { 391254721Semaste if (!S_ISDIR((*b)->fts_statp->st_mode)) 392254721Semaste return (1); 393254721Semaste } else if (S_ISDIR((*b)->fts_statp->st_mode)) 394254721Semaste return (-1); 395254721Semaste return (strcmp((*a)->fts_name, (*b)->fts_name)); 396254721Semaste} 397254721Semaste 398254721Semaste#include <stdarg.h> 399254721Semaste 400254721Semastevoid 401254721Semasteoutput(int indent, int *offset, const char *fmt, ...) 402254721Semaste{ 403254721Semaste va_list ap; 404254721Semaste char buf[1024]; 405254721Semaste va_start(ap, fmt); 406254721Semaste (void)vsnprintf(buf, sizeof(buf), fmt, ap); 407254721Semaste va_end(ap); 408254721Semaste 409254721Semaste if (*offset + strlen(buf) > MAXLINELEN - 3) { 410254721Semaste (void)printf(" \\\n%*s", INDENTNAMELEN + indent, ""); 411254721Semaste *offset = INDENTNAMELEN + indent; 412254721Semaste } 413254721Semaste *offset += printf(" %s", buf) + 1; 414254721Semaste} 415254721Semaste