1258655Sbrooks/* $NetBSD: create.c,v 1.72 2013/10/17 17:22:59 christos Exp $ */ 2244541Sbrooks 3244541Sbrooks/*- 4244541Sbrooks * Copyright (c) 1989, 1993 5244541Sbrooks * The Regents of the University of California. All rights reserved. 6244541Sbrooks * 7244541Sbrooks * Redistribution and use in source and binary forms, with or without 8244541Sbrooks * modification, are permitted provided that the following conditions 9244541Sbrooks * are met: 10244541Sbrooks * 1. Redistributions of source code must retain the above copyright 11244541Sbrooks * notice, this list of conditions and the following disclaimer. 12244541Sbrooks * 2. Redistributions in binary form must reproduce the above copyright 13244541Sbrooks * notice, this list of conditions and the following disclaimer in the 14244541Sbrooks * documentation and/or other materials provided with the distribution. 15244541Sbrooks * 3. Neither the name of the University nor the names of its contributors 16244541Sbrooks * may be used to endorse or promote products derived from this software 17244541Sbrooks * without specific prior written permission. 18244541Sbrooks * 19244541Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20244541Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21244541Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22244541Sbrooks * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23244541Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24244541Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25244541Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26244541Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27244541Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28244541Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29244541Sbrooks * SUCH DAMAGE. 30244541Sbrooks */ 31244541Sbrooks 32244541Sbrooks#if HAVE_NBTOOL_CONFIG_H 33244541Sbrooks#include "nbtool_config.h" 34244541Sbrooks#endif 35244541Sbrooks 36244541Sbrooks#include <sys/cdefs.h> 37244541Sbrooks#if defined(__RCSID) && !defined(lint) 38244541Sbrooks#if 0 39244541Sbrooksstatic char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 40244541Sbrooks#else 41258655Sbrooks__RCSID("$NetBSD: create.c,v 1.72 2013/10/17 17:22:59 christos Exp $"); 42244541Sbrooks#endif 43244541Sbrooks#endif /* not lint */ 44244541Sbrooks 45244541Sbrooks#include <sys/param.h> 46244541Sbrooks#include <sys/stat.h> 47244541Sbrooks 48244541Sbrooks#if ! HAVE_NBTOOL_CONFIG_H 49244541Sbrooks#include <dirent.h> 50244541Sbrooks#endif 51244541Sbrooks 52244541Sbrooks#include <errno.h> 53244541Sbrooks#include <fcntl.h> 54244541Sbrooks#include <grp.h> 55244541Sbrooks#include <pwd.h> 56244541Sbrooks#include <stdio.h> 57244541Sbrooks#include <stdarg.h> 58258655Sbrooks#include <stdint.h> 59244541Sbrooks#include <stdlib.h> 60244541Sbrooks#include <string.h> 61244541Sbrooks#include <time.h> 62244541Sbrooks#include <unistd.h> 63244541Sbrooks 64244541Sbrooks#ifndef NO_MD5 65244541Sbrooks#include <md5.h> 66244541Sbrooks#endif 67244541Sbrooks#ifndef NO_RMD160 68244541Sbrooks#include <rmd160.h> 69244541Sbrooks#endif 70244541Sbrooks#ifndef NO_SHA1 71244541Sbrooks#include <sha1.h> 72244541Sbrooks#endif 73244541Sbrooks#ifndef NO_SHA2 74244541Sbrooks#include <sha2.h> 75244541Sbrooks#endif 76244541Sbrooks 77244541Sbrooks#include "extern.h" 78244541Sbrooks 79244541Sbrooks#define INDENTNAMELEN 15 80244541Sbrooks#define MAXLINELEN 80 81244541Sbrooks 82244541Sbrooksstatic gid_t gid; 83244541Sbrooksstatic uid_t uid; 84244541Sbrooksstatic mode_t mode; 85244541Sbrooksstatic u_long flags; 86244541Sbrooks 87244541Sbrooks#ifdef __FreeBSD__ 88244541Sbrooks#define FTS_CONST const 89244541Sbrooks#else 90244541Sbrooks#define FTS_CONST 91244541Sbrooks#endif 92244541Sbrooks 93244541Sbrooksstatic int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *); 94244541Sbrooksstatic void output(int, int *, const char *, ...) 95244541Sbrooks __attribute__((__format__(__printf__, 3, 4))); 96244541Sbrooksstatic int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *); 97244541Sbrooksstatic void statf(int, FTSENT *); 98244541Sbrooks 99244541Sbrooksvoid 100244541Sbrookscwalk(void) 101244541Sbrooks{ 102244541Sbrooks FTS *t; 103244541Sbrooks FTSENT *p; 104244541Sbrooks time_t clocktime; 105244541Sbrooks char host[MAXHOSTNAMELEN + 1]; 106244541Sbrooks const char *user; 107244541Sbrooks char *argv[2]; 108244541Sbrooks char dot[] = "."; 109244541Sbrooks int indent = 0; 110244541Sbrooks 111244541Sbrooks argv[0] = dot; 112244541Sbrooks argv[1] = NULL; 113244541Sbrooks 114244541Sbrooks time(&clocktime); 115244541Sbrooks gethostname(host, sizeof(host)); 116244541Sbrooks host[sizeof(host) - 1] = '\0'; 117244541Sbrooks if ((user = getlogin()) == NULL) { 118244541Sbrooks struct passwd *pw; 119244541Sbrooks user = (pw = getpwuid(getuid())) == NULL ? pw->pw_name : 120244541Sbrooks "<unknown>"; 121244541Sbrooks } 122244541Sbrooks 123244541Sbrooks if (!nflag) 124244541Sbrooks printf( 125244541Sbrooks "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n" 126244541Sbrooks "#\t date: %s", 127244541Sbrooks user, host, fullpath, ctime(&clocktime)); 128244541Sbrooks 129244541Sbrooks if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL) 130244541Sbrooks mtree_err("fts_open: %s", strerror(errno)); 131244541Sbrooks while ((p = fts_read(t)) != NULL) { 132244541Sbrooks if (jflag) 133244541Sbrooks indent = p->fts_level * 4; 134244541Sbrooks if (check_excludes(p->fts_name, p->fts_path)) { 135244541Sbrooks fts_set(t, p, FTS_SKIP); 136244541Sbrooks continue; 137244541Sbrooks } 138249293Sed if (!find_only(p->fts_path)) { 139249293Sed fts_set(t, p, FTS_SKIP); 140249293Sed continue; 141249293Sed } 142244541Sbrooks switch(p->fts_info) { 143244541Sbrooks case FTS_D: 144244541Sbrooks if (!bflag) 145244541Sbrooks printf("\n"); 146244541Sbrooks if (!nflag) 147244541Sbrooks printf("# %s\n", p->fts_path); 148244541Sbrooks statd(t, p, &uid, &gid, &mode, &flags); 149244541Sbrooks statf(indent, p); 150244541Sbrooks break; 151244541Sbrooks case FTS_DP: 152244541Sbrooks if (p->fts_level > 0) 153244541Sbrooks if (!nflag) 154244541Sbrooks printf("%*s# %s\n", indent, "", 155244541Sbrooks p->fts_path); 156244541Sbrooks if (p->fts_level > 0 || flavor == F_FREEBSD9) { 157244541Sbrooks printf("%*s..\n", indent, ""); 158244541Sbrooks if (!bflag) 159244541Sbrooks printf("\n"); 160244541Sbrooks } 161244541Sbrooks break; 162244541Sbrooks case FTS_DNR: 163244541Sbrooks case FTS_ERR: 164244541Sbrooks case FTS_NS: 165244541Sbrooks mtree_err("%s: %s", 166244541Sbrooks p->fts_path, strerror(p->fts_errno)); 167244541Sbrooks break; 168244541Sbrooks default: 169244541Sbrooks if (!dflag) 170244541Sbrooks statf(indent, p); 171244541Sbrooks break; 172244541Sbrooks 173244541Sbrooks } 174244541Sbrooks } 175244541Sbrooks fts_close(t); 176244541Sbrooks if (sflag && keys & F_CKSUM) 177244541Sbrooks mtree_err("%s checksum: %u", fullpath, crc_total); 178244541Sbrooks} 179244541Sbrooks 180244541Sbrooksstatic void 181244541Sbrooksstatf(int indent, FTSENT *p) 182244541Sbrooks{ 183244541Sbrooks u_int32_t len, val; 184244541Sbrooks int fd, offset; 185244541Sbrooks const char *name = NULL; 186244541Sbrooks#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) 187244541Sbrooks char *digestbuf; 188244541Sbrooks#endif 189244541Sbrooks 190244541Sbrooks offset = printf("%*s%s%s", indent, "", 191244541Sbrooks S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); 192244541Sbrooks 193244541Sbrooks if (offset > (INDENTNAMELEN + indent)) 194244541Sbrooks offset = MAXLINELEN; 195244541Sbrooks else 196244541Sbrooks offset += printf("%*s", (INDENTNAMELEN + indent) - offset, ""); 197244541Sbrooks 198244541Sbrooks if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag)) 199244541Sbrooks output(indent, &offset, "type=%s", 200244541Sbrooks inotype(p->fts_statp->st_mode)); 201244541Sbrooks if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { 202244541Sbrooks if (keys & F_UNAME && 203244541Sbrooks (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) 204244541Sbrooks output(indent, &offset, "uname=%s", name); 205244541Sbrooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 206244541Sbrooks output(indent, &offset, "uid=%u", p->fts_statp->st_uid); 207244541Sbrooks } 208244541Sbrooks if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { 209244541Sbrooks if (keys & F_GNAME && 210244541Sbrooks (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) 211244541Sbrooks output(indent, &offset, "gname=%s", name); 212244541Sbrooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 213244541Sbrooks output(indent, &offset, "gid=%u", p->fts_statp->st_gid); 214244541Sbrooks } 215244541Sbrooks if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 216244541Sbrooks output(indent, &offset, "mode=%#o", 217244541Sbrooks p->fts_statp->st_mode & MBITS); 218244541Sbrooks if (keys & F_DEV && 219244541Sbrooks (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) 220256996Sbrooks output(indent, &offset, "device=%#jx", 221256996Sbrooks (uintmax_t)p->fts_statp->st_rdev); 222244541Sbrooks if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 223244541Sbrooks output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink); 224244541Sbrooks if (keys & F_SIZE && 225256996Sbrooks (flavor == F_FREEBSD9 || S_ISREG(p->fts_statp->st_mode))) 226256996Sbrooks output(indent, &offset, "size=%ju", 227256996Sbrooks (uintmax_t)p->fts_statp->st_size); 228244541Sbrooks if (keys & F_TIME) 229244541Sbrooks#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) 230256996Sbrooks output(indent, &offset, "time=%jd.%09ld", 231256996Sbrooks (intmax_t)p->fts_statp->st_mtimespec.tv_sec, 232244541Sbrooks p->fts_statp->st_mtimespec.tv_nsec); 233244541Sbrooks#else 234256996Sbrooks output(indent, &offset, "time=%jd.%09ld", 235256996Sbrooks (intmax_t)p->fts_statp->st_mtime, (long)0); 236244541Sbrooks#endif 237244541Sbrooks if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 238244541Sbrooks if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 239244541Sbrooks crc(fd, &val, &len)) 240244541Sbrooks mtree_err("%s: %s", p->fts_accpath, strerror(errno)); 241244541Sbrooks close(fd); 242244541Sbrooks output(indent, &offset, "cksum=%lu", (long)val); 243244541Sbrooks } 244244541Sbrooks#ifndef NO_MD5 245244541Sbrooks if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 246244541Sbrooks if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) 247244541Sbrooks mtree_err("%s: MD5File failed: %s", p->fts_accpath, 248244541Sbrooks strerror(errno)); 249244541Sbrooks output(indent, &offset, "%s=%s", MD5KEY, digestbuf); 250244541Sbrooks free(digestbuf); 251244541Sbrooks } 252244541Sbrooks#endif /* ! NO_MD5 */ 253244541Sbrooks#ifndef NO_RMD160 254244541Sbrooks if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 255244541Sbrooks if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) 256244541Sbrooks mtree_err("%s: RMD160File failed: %s", p->fts_accpath, 257244541Sbrooks strerror(errno)); 258244541Sbrooks output(indent, &offset, "%s=%s", RMD160KEY, digestbuf); 259244541Sbrooks free(digestbuf); 260244541Sbrooks } 261244541Sbrooks#endif /* ! NO_RMD160 */ 262244541Sbrooks#ifndef NO_SHA1 263244541Sbrooks if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 264244541Sbrooks if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) 265244541Sbrooks mtree_err("%s: SHA1File failed: %s", p->fts_accpath, 266244541Sbrooks strerror(errno)); 267244541Sbrooks output(indent, &offset, "%s=%s", SHA1KEY, digestbuf); 268244541Sbrooks free(digestbuf); 269244541Sbrooks } 270244541Sbrooks#endif /* ! NO_SHA1 */ 271244541Sbrooks#ifndef NO_SHA2 272244541Sbrooks if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { 273244541Sbrooks if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) 274244541Sbrooks mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, 275244541Sbrooks strerror(errno)); 276244541Sbrooks output(indent, &offset, "%s=%s", SHA256KEY, digestbuf); 277244541Sbrooks free(digestbuf); 278244541Sbrooks } 279244541Sbrooks#ifdef SHA384_BLOCK_LENGTH 280244541Sbrooks if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { 281244541Sbrooks if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) 282244541Sbrooks mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, 283244541Sbrooks strerror(errno)); 284244541Sbrooks output(indent, &offset, "%s=%s", SHA384KEY, digestbuf); 285244541Sbrooks free(digestbuf); 286244541Sbrooks } 287244541Sbrooks#endif 288244541Sbrooks if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { 289244541Sbrooks if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) 290244541Sbrooks mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, 291244541Sbrooks strerror(errno)); 292244541Sbrooks output(indent, &offset, "%s=%s", SHA512KEY, digestbuf); 293244541Sbrooks free(digestbuf); 294244541Sbrooks } 295244541Sbrooks#endif /* ! NO_SHA2 */ 296244541Sbrooks if (keys & F_SLINK && 297244541Sbrooks (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 298244541Sbrooks output(indent, &offset, "link=%s", 299244541Sbrooks vispath(rlink(p->fts_accpath))); 300244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 301244541Sbrooks if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 302244541Sbrooks char *str = flags_to_string(p->fts_statp->st_flags, "none"); 303244541Sbrooks output(indent, &offset, "flags=%s", str); 304244541Sbrooks free(str); 305244541Sbrooks } 306244541Sbrooks#endif 307244541Sbrooks putchar('\n'); 308244541Sbrooks} 309244541Sbrooks 310244541Sbrooks/* XXX 311244541Sbrooks * FLAGS2INDEX will fail once the user and system settable bits need more 312244541Sbrooks * than one byte, respectively. 313244541Sbrooks */ 314244541Sbrooks#define FLAGS2INDEX(x) (((x >> 8) & 0x0000ff00) | (x & 0x000000ff)) 315244541Sbrooks 316244541Sbrooks#define MTREE_MAXGID 5000 317244541Sbrooks#define MTREE_MAXUID 5000 318244541Sbrooks#define MTREE_MAXMODE (MBITS + 1) 319244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 320244541Sbrooks#define MTREE_MAXFLAGS (FLAGS2INDEX(CH_MASK) + 1) /* 1808 */ 321244541Sbrooks#else 322244541Sbrooks#define MTREE_MAXFLAGS 1 323244541Sbrooks#endif 324244541Sbrooks#define MTREE_MAXS 16 325244541Sbrooks 326244541Sbrooksstatic int 327244541Sbrooksstatd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, 328244541Sbrooks u_long *pflags) 329244541Sbrooks{ 330244541Sbrooks FTSENT *p; 331244541Sbrooks gid_t sgid; 332244541Sbrooks uid_t suid; 333244541Sbrooks mode_t smode; 334244541Sbrooks u_long sflags = 0; 335244541Sbrooks const char *name = NULL; 336244541Sbrooks gid_t savegid; 337244541Sbrooks uid_t saveuid; 338244541Sbrooks mode_t savemode; 339244541Sbrooks u_long saveflags; 340244541Sbrooks u_short maxgid, maxuid, maxmode, maxflags; 341244541Sbrooks u_short g[MTREE_MAXGID], u[MTREE_MAXUID], 342244541Sbrooks m[MTREE_MAXMODE], f[MTREE_MAXFLAGS]; 343244541Sbrooks static int first = 1; 344244541Sbrooks 345244541Sbrooks savegid = *pgid; 346244541Sbrooks saveuid = *puid; 347244541Sbrooks savemode = *pmode; 348244541Sbrooks saveflags = *pflags; 349244541Sbrooks if ((p = fts_children(t, 0)) == NULL) { 350244541Sbrooks if (errno) 351244541Sbrooks mtree_err("%s: %s", RP(parent), strerror(errno)); 352244541Sbrooks return (1); 353244541Sbrooks } 354244541Sbrooks 355244541Sbrooks memset(g, 0, sizeof(g)); 356244541Sbrooks memset(u, 0, sizeof(u)); 357244541Sbrooks memset(m, 0, sizeof(m)); 358244541Sbrooks memset(f, 0, sizeof(f)); 359244541Sbrooks 360244541Sbrooks maxuid = maxgid = maxmode = maxflags = 0; 361244541Sbrooks for (; p; p = p->fts_link) { 362244541Sbrooks if (flavor == F_NETBSD6 || !dflag || 363244541Sbrooks (dflag && S_ISDIR(p->fts_statp->st_mode))) { 364244541Sbrooks smode = p->fts_statp->st_mode & MBITS; 365244541Sbrooks if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) { 366244541Sbrooks savemode = smode; 367244541Sbrooks maxmode = m[smode]; 368244541Sbrooks } 369244541Sbrooks sgid = p->fts_statp->st_gid; 370244541Sbrooks if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) { 371244541Sbrooks savegid = sgid; 372244541Sbrooks maxgid = g[sgid]; 373244541Sbrooks } 374244541Sbrooks suid = p->fts_statp->st_uid; 375244541Sbrooks if (suid < MTREE_MAXUID && ++u[suid] > maxuid) { 376244541Sbrooks saveuid = suid; 377244541Sbrooks maxuid = u[suid]; 378244541Sbrooks } 379244541Sbrooks 380244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 381244541Sbrooks sflags = FLAGS2INDEX(p->fts_statp->st_flags); 382244541Sbrooks if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) { 383244541Sbrooks saveflags = p->fts_statp->st_flags; 384244541Sbrooks maxflags = f[sflags]; 385244541Sbrooks } 386244541Sbrooks#endif 387244541Sbrooks } 388244541Sbrooks } 389244541Sbrooks /* 390244541Sbrooks * If the /set record is the same as the last one we do not need to 391244541Sbrooks * output a new one. So first we check to see if anything changed. 392244541Sbrooks * Note that we always output a /set record for the first directory. 393244541Sbrooks */ 394244541Sbrooks if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) || 395244541Sbrooks ((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) || 396244541Sbrooks ((keys & F_MODE) && (*pmode != savemode)) || 397244541Sbrooks ((keys & F_FLAGS) && (*pflags != saveflags)) || 398244541Sbrooks first) { 399244541Sbrooks first = 0; 400244541Sbrooks if (flavor != F_NETBSD6 && dflag) 401244541Sbrooks printf("/set type=dir"); 402244541Sbrooks else 403244541Sbrooks printf("/set type=file"); 404244541Sbrooks if (keys & (F_UID | F_UNAME)) { 405244541Sbrooks if (keys & F_UNAME && 406244541Sbrooks (name = user_from_uid(saveuid, 1)) != NULL) 407244541Sbrooks printf(" uname=%s", name); 408244541Sbrooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 409244541Sbrooks printf(" uid=%lu", (u_long)saveuid); 410244541Sbrooks } 411244541Sbrooks if (keys & (F_GID | F_GNAME)) { 412244541Sbrooks if (keys & F_GNAME && 413244541Sbrooks (name = group_from_gid(savegid, 1)) != NULL) 414244541Sbrooks printf(" gname=%s", name); 415244541Sbrooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 416244541Sbrooks printf(" gid=%lu", (u_long)savegid); 417244541Sbrooks } 418244541Sbrooks if (keys & F_MODE) 419244541Sbrooks printf(" mode=%#lo", (u_long)savemode); 420244541Sbrooks if (keys & F_NLINK) 421244541Sbrooks printf(" nlink=1"); 422244541Sbrooks if (keys & F_FLAGS) { 423244541Sbrooks char *str = flags_to_string(saveflags, "none"); 424244541Sbrooks printf(" flags=%s", str); 425244541Sbrooks free(str); 426244541Sbrooks } 427244541Sbrooks printf("\n"); 428244541Sbrooks *puid = saveuid; 429244541Sbrooks *pgid = savegid; 430244541Sbrooks *pmode = savemode; 431244541Sbrooks *pflags = saveflags; 432244541Sbrooks } 433244541Sbrooks return (0); 434244541Sbrooks} 435244541Sbrooks 436244541Sbrooks/* 437244541Sbrooks * dcmp -- 438244541Sbrooks * used as a comparison function passed to fts_open() to control 439244541Sbrooks * the order in which fts_read() returns results. We make 440244541Sbrooks * directories sort after non-directories, but otherwise sort in 441244541Sbrooks * strcmp() order. 442244541Sbrooks * 443244541Sbrooks * Keep this in sync with nodecmp() in spec.c. 444244541Sbrooks */ 445244541Sbrooksstatic int 446244541Sbrooksdcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b) 447244541Sbrooks{ 448244541Sbrooks 449244541Sbrooks if (S_ISDIR((*a)->fts_statp->st_mode)) { 450244541Sbrooks if (!S_ISDIR((*b)->fts_statp->st_mode)) 451244541Sbrooks return (1); 452244541Sbrooks } else if (S_ISDIR((*b)->fts_statp->st_mode)) 453244541Sbrooks return (-1); 454244541Sbrooks return (strcmp((*a)->fts_name, (*b)->fts_name)); 455244541Sbrooks} 456244541Sbrooks 457244541Sbrooksvoid 458244541Sbrooksoutput(int indent, int *offset, const char *fmt, ...) 459244541Sbrooks{ 460244541Sbrooks va_list ap; 461244541Sbrooks char buf[1024]; 462244541Sbrooks 463244541Sbrooks va_start(ap, fmt); 464244541Sbrooks vsnprintf(buf, sizeof(buf), fmt, ap); 465244541Sbrooks va_end(ap); 466244541Sbrooks 467244541Sbrooks if (*offset + strlen(buf) > MAXLINELEN - 3) { 468244541Sbrooks printf(" \\\n%*s", INDENTNAMELEN + indent, ""); 469244541Sbrooks *offset = INDENTNAMELEN + indent; 470244541Sbrooks } 471244541Sbrooks *offset += printf(" %s", buf) + 1; 472244541Sbrooks} 473