create.c revision 50479
11195Srgrimes/*- 250472Speter * Copyright (c) 1989, 1993 337Srgrimes * The Regents of the University of California. All rights reserved. 473251Sgshapiro * 538103Speter * Redistribution and use in source and binary forms, with or without 673251Sgshapiro * modification, are permitted provided that the following conditions 738103Speter * are met: 899451Sru * 1. Redistributions of source code must retain the above copyright 955230Speter * notice, this list of conditions and the following disclaimer. 10108983Simp * 2. Redistributions in binary form must reproduce the above copyright 1165532Snectar * notice, this list of conditions and the following disclaimer in the 1255230Speter * documentation and/or other materials provided with the distribution. 13107318Sru * 3. All advertising materials mentioning features or use of this software 1489364Sdes * must display the following acknowledgement: 15108002Sgreen * This product includes software developed by the University of 16108002Sgreen * California, Berkeley and its contributors. 1798187Sgordon * 4. Neither the name of the University nor the names of its contributors 1898187Sgordon * may be used to endorse or promote products derived from this software 1955230Speter * without specific prior written permission. 2055230Speter * 2155230Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221734Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2317639Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2417639Swosch * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2537Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2677041Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2777041Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2877041Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2977041Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3098548Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3198548Sru * SUCH DAMAGE. 3257488Speter */ 3374837Sgreen 3492898Sdes#ifndef lint 3557459Smarkm#if 0 3660677Skrisstatic char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 3760677Skris#endif 3860677Skrisstatic const char rcsid[] = 3982521Salex "$FreeBSD: head/usr.sbin/mtree/create.c 50479 1999-08-28 01:35:59Z peter $"; 40108002Sgreen#endif /* not lint */ 41147Srgrimes 4299449Sru#include <sys/param.h> 4399449Sru#include <sys/stat.h> 4427487Sasami#include <dirent.h> 4565168Sasami#include <err.h> 4695144Sgshapiro#include <errno.h> 4795144Sgshapiro#include <fcntl.h> 4895144Sgshapiro#include <fts.h> 4999451Sru#include <grp.h> 5099451Sru#ifdef MD5 5190281Sume#include <md5.h> 5299451Sru#endif 5399451Sru#ifdef SHA1 5499451Sru#include <sha.h> 5564598Sgshapiro#endif 5664598Sgshapiro#ifdef RMD160 5737Srgrimes#include <ripemd.h> 58263Srgrimes#endif 5999449Sru#include <pwd.h> 60263Srgrimes#include <stdio.h> 614487Sphk#include <time.h> 6295327Sobrien#include <unistd.h> 63100872Sru#include <vis.h> 6495509Sru#include "mtree.h" 6595509Sru#include "extern.h" 665948Sjkh 674487Sphk#define INDENTNAMELEN 15 6899449Sru#define MAXLINELEN 80 69100872Sru 7099451Sruextern long int crc_total; 71100872Sruextern int ftsoptions; 7299451Sruextern int dflag, iflag, nflag, sflag; 73100872Sruextern u_int keys; 7499451Sruextern char fullpath[MAXPATHLEN]; 7599451Sruextern int lineno; 76100872Sru 7799449Srustatic gid_t gid; 7899449Srustatic uid_t uid; 7999449Srustatic mode_t mode; 8099449Sru 8199449Srustatic int dsort __P((const FTSENT **, const FTSENT **)); 8299449Srustatic void output __P((int, int *, const char *, ...)); 8399449Srustatic int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *)); 8477041Srustatic void statf __P((int, FTSENT *)); 8599449Sru 8677041Sruvoid 8773251Sgshapirocwalk() 8899449Sru{ 8973251Sgshapiro register FTS *t; 9098548Sru register FTSENT *p; 9198548Sru time_t clock; 92100872Sru char *argv[2], host[MAXHOSTNAMELEN]; 9399451Sru int indent = 0; 9457488Speter 95100872Sru (void)time(&clock); 9699451Sru (void)gethostname(host, sizeof(host)); 9760677Skris (void)printf( 9899449Sru "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", 99100872Sru getlogin(), host, fullpath, ctime(&clock)); 10099451Sru 101100872Sru argv[0] = "."; 10299451Sru argv[1] = NULL; 103100872Sru if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) 10499451Sru err(1, "line %d: fts_open", lineno); 105100872Sru while ((p = fts_read(t))) { 10699451Sru if (iflag) 10799451Sru indent = p->fts_level * 4; 10899451Sru switch(p->fts_info) { 10999451Sru case FTS_D: 110100872Sru if (!dflag) 1111731Sjkh (void)printf("\n"); 112100872Sru if (!nflag) 1131731Sjkh (void)printf("# %s\n", p->fts_path); 114100872Sru statd(t, p, &uid, &gid, &mode); 1156177Samurai statf(indent, p); 116100872Sru break; 11764598Sgshapiro case FTS_DP: 11864629Sgshapiro if (!nflag && (p->fts_level > 0)) 11964629Sgshapiro (void)printf("%*s# %s\n", indent, "", p->fts_path); 12064629Sgshapiro (void)printf("%*s..\n", indent, ""); 12164629Sgshapiro if (!dflag) 12264629Sgshapiro (void)printf("\n"); 123100872Sru break; 12437Srgrimes case FTS_DNR: 125100872Sru case FTS_ERR: 126147Srgrimes case FTS_NS: 127100872Sru warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); 12892100Srwatson break; 129100872Sru default: 13099449Sru if (!dflag) 131103720Smarkm statf(indent, p); 132103738Smarkm break; 133100872Sru 134147Srgrimes } 135100872Sru } 13637Srgrimes (void)fts_close(t); 137100872Sru if (sflag && keys & F_CKSUM) 138288Srgrimes warnx("%s checksum: %lu", fullpath, crc_total); 139100872Sru} 140147Srgrimes 141100872Srustatic void 14250126Sgreenstatf(indent, p) 143100872Sru int indent; 14413378Sache FTSENT *p; 145100872Sru{ 14617104Spst struct group *gr; 147100872Sru struct passwd *pw; 148147Srgrimes u_long len, val; 149100872Sru int fd, offset; 15037Srgrimes char *escaped_name; 151100872Sru 1521759Sjkh escaped_name = calloc(1, p->fts_namelen * 4 + 1); 153100872Sru if (escaped_name == NULL) 15499451Sru errx(1, "statf(): calloc() failed"); 15561888Sasmodai strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL); 15699449Sru 15761888Sasmodai if (iflag || S_ISDIR(p->fts_statp->st_mode)) 15837Srgrimes offset = printf("%*s%s", indent, "", escaped_name); 159147Srgrimes else 16089074Sphantom offset = printf("%*s %s", indent, "", escaped_name); 16189074Sphantom 16289074Sphantom free(escaped_name); 16389074Sphantom 16489074Sphantom if (offset > (INDENTNAMELEN + indent)) 16589074Sphantom offset = MAXLINELEN; 16689074Sphantom else 16789074Sphantom offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); 16889074Sphantom 16989074Sphantom if (!S_ISREG(p->fts_statp->st_mode) && !dflag) 17089074Sphantom output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode)); 17189074Sphantom if (p->fts_statp->st_uid != uid) { 17289074Sphantom if (keys & F_UNAME) { 17365884Sache if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) { 17465884Sache output(indent, &offset, "uname=%s", pw->pw_name); 17565884Sache } else { 17665884Sache errx(1, 1777129Srgrimes "line %d: could not get uname for uid=%u", 17895144Sgshapiro lineno, p->fts_statp->st_uid); 17995144Sgshapiro } 18095144Sgshapiro } 181410Srgrimes if (keys & F_UID) 18277993Sache output(indent, &offset, "uid=%u", p->fts_statp->st_uid); 18377993Sache } 18477993Sache if (p->fts_statp->st_gid != gid) { 18577993Sache if (keys & F_GNAME) { 18677993Sache if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) { 18777993Sache output(indent, &offset, "gname=%s", gr->gr_name); 18877993Sache } else { 18977993Sache errx(1, 19077993Sache "line %d: could not get gname for gid=%u", 191110663Sache lineno, p->fts_statp->st_gid); 192110663Sache } 193110663Sache } 194110663Sache if (keys & F_GID) 195110663Sache output(indent, &offset, "gid=%u", p->fts_statp->st_gid); 196110663Sache } 197110663Sache if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 198110663Sache output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS); 1997129Srgrimes if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 20077976Sache output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); 20111635Sache if (keys & F_SIZE) 20211635Sache output(indent, &offset, "size=%qd", p->fts_statp->st_size); 20311635Sache if (keys & F_TIME) 20411635Sache output(indent, &offset, "time=%ld.%ld", 20511635Sache p->fts_statp->st_mtimespec.tv_sec, 2067129Srgrimes p->fts_statp->st_mtimespec.tv_nsec); 207110655Snectar if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 20811635Sache if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 20977999Sache crc(fd, &val, &len)) 21011635Sache err(1, "line %d: %s", lineno, p->fts_accpath); 21111635Sache (void)close(fd); 21211635Sache output(indent, &offset, "cksum=%lu", val); 21311635Sache } 21411635Sache#ifdef MD5 21577999Sache if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 216147Srgrimes char *digest, buf[33]; 21748185Ssheldonh 218100872Sru digest = MD5File(p->fts_accpath, buf); 21999451Sru if (!digest) { 22099451Sru err(1, "line %d: %s", lineno, p->fts_accpath); 221100872Sru } else { 22299451Sru output(indent, &offset, "md5digest=%s", digest); 22348185Ssheldonh } 22437Srgrimes } 225#endif /* MD5 */ 226#ifdef SHA1 227 if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 228 char *digest, buf[41]; 229 230 digest = SHA1_File(p->fts_accpath, buf); 231 if (!digest) { 232 err(1, "line %d: %s", lineno, p->fts_accpath); 233 } else { 234 output(indent, &offset, "sha1digest=%s", digest); 235 } 236 } 237#endif /* SHA1 */ 238#ifdef RMD160 239 if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 240 char *digest, buf[41]; 241 242 digest = RIPEMD160_File(p->fts_accpath, buf); 243 if (!digest) { 244 err(1, "line %d: %s", lineno, p->fts_accpath); 245 } else { 246 output(indent, &offset, "ripemd160digest=%s", digest); 247 } 248 } 249#endif /* RMD160 */ 250 if (keys & F_SLINK && 251 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 252 output(indent, &offset, "link=%s", rlink(p->fts_accpath)); 253 (void)putchar('\n'); 254} 255 256#define MAXGID 5000 257#define MAXUID 5000 258#define MAXMODE MBITS + 1 259 260static int 261statd(t, parent, puid, pgid, pmode) 262 FTS *t; 263 FTSENT *parent; 264 uid_t *puid; 265 gid_t *pgid; 266 mode_t *pmode; 267{ 268 register FTSENT *p; 269 register gid_t sgid; 270 register uid_t suid; 271 register mode_t smode; 272 struct group *gr; 273 struct passwd *pw; 274 gid_t savegid = *pgid; 275 uid_t saveuid = *puid; 276 mode_t savemode = *pmode; 277 u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE]; 278 static int first = 1; 279 280 if ((p = fts_children(t, 0)) == NULL) { 281 if (errno) 282 err(1, "line %d: %s", lineno, RP(parent)); 283 return (1); 284 } 285 286 bzero(g, sizeof(g)); 287 bzero(u, sizeof(u)); 288 bzero(m, sizeof(m)); 289 290 maxuid = maxgid = maxmode = 0; 291 for (; p; p = p->fts_link) { 292 if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) { 293 smode = p->fts_statp->st_mode & MBITS; 294 if (smode < MAXMODE && ++m[smode] > maxmode) { 295 savemode = smode; 296 maxmode = m[smode]; 297 } 298 sgid = p->fts_statp->st_gid; 299 if (sgid < MAXGID && ++g[sgid] > maxgid) { 300 savegid = sgid; 301 maxgid = g[sgid]; 302 } 303 suid = p->fts_statp->st_uid; 304 if (suid < MAXUID && ++u[suid] > maxuid) { 305 saveuid = suid; 306 maxuid = u[suid]; 307 } 308 } 309 } 310 /* 311 * If the /set record is the same as the last one we do not need to output 312 * a new one. So first we check to see if anything changed. Note that we 313 * always output a /set record for the first directory. 314 */ 315 if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) || 316 (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) || 317 ((keys & F_MODE) && (*pmode != savemode)) || (first)) { 318 first = 0; 319 if (dflag) 320 (void)printf("/set type=dir"); 321 else 322 (void)printf("/set type=file"); 323 if (keys & F_UNAME) 324 if ((pw = getpwuid(saveuid)) != NULL) 325 (void)printf(" uname=%s", pw->pw_name); 326 else 327 errx(1, 328 "line %d: could not get uname for uid=%u", 329 lineno, saveuid); 330 if (keys & F_UID) 331 (void)printf(" uid=%lu", (u_long)saveuid); 332 if (keys & F_GNAME) 333 if ((gr = getgrgid(savegid)) != NULL) 334 (void)printf(" gname=%s", gr->gr_name); 335 else 336 errx(1, 337 "line %d: could not get gname for gid=%u", 338 lineno, savegid); 339 if (keys & F_GID) 340 (void)printf(" gid=%lu", (u_long)savegid); 341 if (keys & F_MODE) 342 (void)printf(" mode=%#o", savemode); 343 if (keys & F_NLINK) 344 (void)printf(" nlink=1"); 345 (void)printf("\n"); 346 *puid = saveuid; 347 *pgid = savegid; 348 *pmode = savemode; 349 } 350 return (0); 351} 352 353static int 354dsort(a, b) 355 const FTSENT **a, **b; 356{ 357 if (S_ISDIR((*a)->fts_statp->st_mode)) { 358 if (!S_ISDIR((*b)->fts_statp->st_mode)) 359 return (1); 360 } else if (S_ISDIR((*b)->fts_statp->st_mode)) 361 return (-1); 362 return (strcmp((*a)->fts_name, (*b)->fts_name)); 363} 364 365#if __STDC__ 366#include <stdarg.h> 367#else 368#include <varargs.h> 369#endif 370 371void 372#if __STDC__ 373output(int indent, int *offset, const char *fmt, ...) 374#else 375output(indent, offset, fmt, va_alist) 376 int indent; 377 int *offset; 378 char *fmt; 379 va_dcl 380#endif 381{ 382 va_list ap; 383 char buf[1024]; 384#if __STDC__ 385 va_start(ap, fmt); 386#else 387 va_start(ap); 388#endif 389 (void)vsnprintf(buf, sizeof(buf), fmt, ap); 390 va_end(ap); 391 392 if (*offset + strlen(buf) > MAXLINELEN - 3) { 393 (void)printf(" \\\n%*s", INDENTNAMELEN + indent, ""); 394 *offset = INDENTNAMELEN + indent; 395 } 396 *offset += printf(" %s", buf) + 1; 397} 398