1273796Sbrooks/* $NetBSD: create.c,v 1.73 2014/04/24 17:22:41 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 41273796Sbrooks__RCSID("$NetBSD: create.c,v 1.73 2014/04/24 17:22:41 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> 58258437Sbrooks#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 *); 94273796Sbrooksstatic void output(FILE *, int, int *, const char *, ...) 95273796Sbrooks __printflike(4, 5); 96273796Sbrooksstatic int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, 97273796Sbrooks u_long *); 98273796Sbrooksstatic void statf(FILE *, int, FTSENT *); 99244541Sbrooks 100244541Sbrooksvoid 101273796Sbrookscwalk(FILE *fp) 102244541Sbrooks{ 103244541Sbrooks FTS *t; 104244541Sbrooks FTSENT *p; 105244541Sbrooks time_t clocktime; 106244541Sbrooks char host[MAXHOSTNAMELEN + 1]; 107244541Sbrooks const char *user; 108244541Sbrooks char *argv[2]; 109244541Sbrooks char dot[] = "."; 110244541Sbrooks int indent = 0; 111244541Sbrooks 112244541Sbrooks argv[0] = dot; 113244541Sbrooks argv[1] = NULL; 114244541Sbrooks 115244541Sbrooks time(&clocktime); 116244541Sbrooks gethostname(host, sizeof(host)); 117244541Sbrooks host[sizeof(host) - 1] = '\0'; 118244541Sbrooks if ((user = getlogin()) == NULL) { 119244541Sbrooks struct passwd *pw; 120356533Sbdrewery user = (pw = getpwuid(getuid())) != NULL ? pw->pw_name : 121244541Sbrooks "<unknown>"; 122244541Sbrooks } 123244541Sbrooks 124244541Sbrooks if (!nflag) 125273796Sbrooks fprintf(fp, 126244541Sbrooks "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n" 127244541Sbrooks "#\t date: %s", 128244541Sbrooks user, host, fullpath, ctime(&clocktime)); 129244541Sbrooks 130244541Sbrooks if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL) 131244541Sbrooks mtree_err("fts_open: %s", strerror(errno)); 132244541Sbrooks while ((p = fts_read(t)) != NULL) { 133244541Sbrooks if (jflag) 134244541Sbrooks indent = p->fts_level * 4; 135244541Sbrooks if (check_excludes(p->fts_name, p->fts_path)) { 136244541Sbrooks fts_set(t, p, FTS_SKIP); 137244541Sbrooks continue; 138244541Sbrooks } 139249293Sed if (!find_only(p->fts_path)) { 140249293Sed fts_set(t, p, FTS_SKIP); 141249293Sed continue; 142249293Sed } 143244541Sbrooks switch(p->fts_info) { 144244541Sbrooks case FTS_D: 145244541Sbrooks if (!bflag) 146273796Sbrooks fprintf(fp, "\n"); 147244541Sbrooks if (!nflag) 148273796Sbrooks fprintf(fp, "# %s\n", p->fts_path); 149273796Sbrooks statd(fp, t, p, &uid, &gid, &mode, &flags); 150273796Sbrooks statf(fp, indent, p); 151244541Sbrooks break; 152244541Sbrooks case FTS_DP: 153244541Sbrooks if (p->fts_level > 0) 154244541Sbrooks if (!nflag) 155273796Sbrooks fprintf(fp, "%*s# %s\n", indent, "", 156244541Sbrooks p->fts_path); 157244541Sbrooks if (p->fts_level > 0 || flavor == F_FREEBSD9) { 158273796Sbrooks fprintf(fp, "%*s..\n", indent, ""); 159244541Sbrooks if (!bflag) 160273796Sbrooks fprintf(fp, "\n"); 161244541Sbrooks } 162244541Sbrooks break; 163244541Sbrooks case FTS_DNR: 164244541Sbrooks case FTS_ERR: 165244541Sbrooks case FTS_NS: 166244541Sbrooks mtree_err("%s: %s", 167244541Sbrooks p->fts_path, strerror(p->fts_errno)); 168244541Sbrooks break; 169244541Sbrooks default: 170244541Sbrooks if (!dflag) 171273796Sbrooks statf(fp, indent, p); 172244541Sbrooks break; 173244541Sbrooks 174244541Sbrooks } 175244541Sbrooks } 176244541Sbrooks fts_close(t); 177244541Sbrooks if (sflag && keys & F_CKSUM) 178244541Sbrooks mtree_err("%s checksum: %u", fullpath, crc_total); 179244541Sbrooks} 180244541Sbrooks 181244541Sbrooksstatic void 182273796Sbrooksstatf(FILE *fp, int indent, FTSENT *p) 183244541Sbrooks{ 184244541Sbrooks u_int32_t len, val; 185244541Sbrooks int fd, offset; 186244541Sbrooks const char *name = NULL; 187244541Sbrooks#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) 188244541Sbrooks char *digestbuf; 189244541Sbrooks#endif 190244541Sbrooks 191273796Sbrooks offset = fprintf(fp, "%*s%s%s", indent, "", 192244541Sbrooks S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); 193244541Sbrooks 194244541Sbrooks if (offset > (INDENTNAMELEN + indent)) 195244541Sbrooks offset = MAXLINELEN; 196244541Sbrooks else 197273796Sbrooks offset += fprintf(fp, "%*s", 198273796Sbrooks (INDENTNAMELEN + indent) - offset, ""); 199244541Sbrooks 200244541Sbrooks if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag)) 201273796Sbrooks output(fp, indent, &offset, "type=%s", 202244541Sbrooks inotype(p->fts_statp->st_mode)); 203244541Sbrooks if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { 204244541Sbrooks if (keys & F_UNAME && 205244541Sbrooks (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) 206273796Sbrooks output(fp, indent, &offset, "uname=%s", name); 207244541Sbrooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 208273796Sbrooks output(fp, indent, &offset, "uid=%u", 209273796Sbrooks p->fts_statp->st_uid); 210244541Sbrooks } 211244541Sbrooks if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { 212244541Sbrooks if (keys & F_GNAME && 213244541Sbrooks (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) 214273796Sbrooks output(fp, indent, &offset, "gname=%s", name); 215244541Sbrooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 216273796Sbrooks output(fp, indent, &offset, "gid=%u", 217273796Sbrooks p->fts_statp->st_gid); 218244541Sbrooks } 219244541Sbrooks if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 220273796Sbrooks output(fp, indent, &offset, "mode=%#o", 221244541Sbrooks p->fts_statp->st_mode & MBITS); 222244541Sbrooks if (keys & F_DEV && 223244541Sbrooks (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) 224273796Sbrooks output(fp, indent, &offset, "device=%#jx", 225256687Sbrooks (uintmax_t)p->fts_statp->st_rdev); 226244541Sbrooks if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 227312072Skib output(fp, indent, &offset, "nlink=%ju", 228312072Skib (uintmax_t)p->fts_statp->st_nlink); 229244541Sbrooks if (keys & F_SIZE && 230256687Sbrooks (flavor == F_FREEBSD9 || S_ISREG(p->fts_statp->st_mode))) 231273796Sbrooks output(fp, indent, &offset, "size=%ju", 232256687Sbrooks (uintmax_t)p->fts_statp->st_size); 233244541Sbrooks if (keys & F_TIME) 234244541Sbrooks#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) 235273796Sbrooks output(fp, indent, &offset, "time=%jd.%09ld", 236256687Sbrooks (intmax_t)p->fts_statp->st_mtimespec.tv_sec, 237244541Sbrooks p->fts_statp->st_mtimespec.tv_nsec); 238244541Sbrooks#else 239273796Sbrooks output(fp, indent, &offset, "time=%jd.%09ld", 240256687Sbrooks (intmax_t)p->fts_statp->st_mtime, (long)0); 241244541Sbrooks#endif 242244541Sbrooks if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 243244541Sbrooks if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 244244541Sbrooks crc(fd, &val, &len)) 245244541Sbrooks mtree_err("%s: %s", p->fts_accpath, strerror(errno)); 246244541Sbrooks close(fd); 247273796Sbrooks output(fp, indent, &offset, "cksum=%lu", (long)val); 248244541Sbrooks } 249244541Sbrooks#ifndef NO_MD5 250244541Sbrooks if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 251244541Sbrooks if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) 252244541Sbrooks mtree_err("%s: MD5File failed: %s", p->fts_accpath, 253244541Sbrooks strerror(errno)); 254273796Sbrooks output(fp, indent, &offset, "%s=%s", MD5KEY, digestbuf); 255244541Sbrooks free(digestbuf); 256244541Sbrooks } 257244541Sbrooks#endif /* ! NO_MD5 */ 258244541Sbrooks#ifndef NO_RMD160 259244541Sbrooks if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 260244541Sbrooks if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) 261244541Sbrooks mtree_err("%s: RMD160File failed: %s", p->fts_accpath, 262244541Sbrooks strerror(errno)); 263273796Sbrooks output(fp, indent, &offset, "%s=%s", RMD160KEY, digestbuf); 264244541Sbrooks free(digestbuf); 265244541Sbrooks } 266244541Sbrooks#endif /* ! NO_RMD160 */ 267244541Sbrooks#ifndef NO_SHA1 268244541Sbrooks if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 269244541Sbrooks if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) 270244541Sbrooks mtree_err("%s: SHA1File failed: %s", p->fts_accpath, 271244541Sbrooks strerror(errno)); 272273796Sbrooks output(fp, indent, &offset, "%s=%s", SHA1KEY, digestbuf); 273244541Sbrooks free(digestbuf); 274244541Sbrooks } 275244541Sbrooks#endif /* ! NO_SHA1 */ 276244541Sbrooks#ifndef NO_SHA2 277244541Sbrooks if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { 278244541Sbrooks if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) 279244541Sbrooks mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, 280244541Sbrooks strerror(errno)); 281273796Sbrooks output(fp, indent, &offset, "%s=%s", SHA256KEY, digestbuf); 282244541Sbrooks free(digestbuf); 283244541Sbrooks } 284244541Sbrooks#ifdef SHA384_BLOCK_LENGTH 285244541Sbrooks if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { 286244541Sbrooks if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) 287244541Sbrooks mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, 288244541Sbrooks strerror(errno)); 289273796Sbrooks output(fp, indent, &offset, "%s=%s", SHA384KEY, digestbuf); 290244541Sbrooks free(digestbuf); 291244541Sbrooks } 292244541Sbrooks#endif 293244541Sbrooks if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { 294244541Sbrooks if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) 295244541Sbrooks mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, 296244541Sbrooks strerror(errno)); 297273796Sbrooks output(fp, indent, &offset, "%s=%s", SHA512KEY, digestbuf); 298244541Sbrooks free(digestbuf); 299244541Sbrooks } 300244541Sbrooks#endif /* ! NO_SHA2 */ 301244541Sbrooks if (keys & F_SLINK && 302244541Sbrooks (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 303273796Sbrooks output(fp, indent, &offset, "link=%s", 304244541Sbrooks vispath(rlink(p->fts_accpath))); 305244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 306244541Sbrooks if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 307244541Sbrooks char *str = flags_to_string(p->fts_statp->st_flags, "none"); 308273796Sbrooks output(fp, indent, &offset, "flags=%s", str); 309244541Sbrooks free(str); 310244541Sbrooks } 311244541Sbrooks#endif 312244541Sbrooks putchar('\n'); 313244541Sbrooks} 314244541Sbrooks 315244541Sbrooks/* XXX 316244541Sbrooks * FLAGS2INDEX will fail once the user and system settable bits need more 317244541Sbrooks * than one byte, respectively. 318244541Sbrooks */ 319244541Sbrooks#define FLAGS2INDEX(x) (((x >> 8) & 0x0000ff00) | (x & 0x000000ff)) 320244541Sbrooks 321244541Sbrooks#define MTREE_MAXGID 5000 322244541Sbrooks#define MTREE_MAXUID 5000 323244541Sbrooks#define MTREE_MAXMODE (MBITS + 1) 324244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 325244541Sbrooks#define MTREE_MAXFLAGS (FLAGS2INDEX(CH_MASK) + 1) /* 1808 */ 326244541Sbrooks#else 327244541Sbrooks#define MTREE_MAXFLAGS 1 328244541Sbrooks#endif 329244541Sbrooks#define MTREE_MAXS 16 330244541Sbrooks 331244541Sbrooksstatic int 332273796Sbrooksstatd(FILE *fp, FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, 333273796Sbrooks u_long *pflags) 334244541Sbrooks{ 335244541Sbrooks FTSENT *p; 336244541Sbrooks gid_t sgid; 337244541Sbrooks uid_t suid; 338244541Sbrooks mode_t smode; 339244541Sbrooks u_long sflags = 0; 340244541Sbrooks const char *name = NULL; 341244541Sbrooks gid_t savegid; 342244541Sbrooks uid_t saveuid; 343244541Sbrooks mode_t savemode; 344244541Sbrooks u_long saveflags; 345244541Sbrooks u_short maxgid, maxuid, maxmode, maxflags; 346244541Sbrooks u_short g[MTREE_MAXGID], u[MTREE_MAXUID], 347244541Sbrooks m[MTREE_MAXMODE], f[MTREE_MAXFLAGS]; 348244541Sbrooks static int first = 1; 349244541Sbrooks 350244541Sbrooks savegid = *pgid; 351244541Sbrooks saveuid = *puid; 352244541Sbrooks savemode = *pmode; 353244541Sbrooks saveflags = *pflags; 354244541Sbrooks if ((p = fts_children(t, 0)) == NULL) { 355244541Sbrooks if (errno) 356244541Sbrooks mtree_err("%s: %s", RP(parent), strerror(errno)); 357244541Sbrooks return (1); 358244541Sbrooks } 359244541Sbrooks 360244541Sbrooks memset(g, 0, sizeof(g)); 361244541Sbrooks memset(u, 0, sizeof(u)); 362244541Sbrooks memset(m, 0, sizeof(m)); 363244541Sbrooks memset(f, 0, sizeof(f)); 364244541Sbrooks 365244541Sbrooks maxuid = maxgid = maxmode = maxflags = 0; 366244541Sbrooks for (; p; p = p->fts_link) { 367244541Sbrooks if (flavor == F_NETBSD6 || !dflag || 368244541Sbrooks (dflag && S_ISDIR(p->fts_statp->st_mode))) { 369244541Sbrooks smode = p->fts_statp->st_mode & MBITS; 370244541Sbrooks if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) { 371244541Sbrooks savemode = smode; 372244541Sbrooks maxmode = m[smode]; 373244541Sbrooks } 374244541Sbrooks sgid = p->fts_statp->st_gid; 375244541Sbrooks if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) { 376244541Sbrooks savegid = sgid; 377244541Sbrooks maxgid = g[sgid]; 378244541Sbrooks } 379244541Sbrooks suid = p->fts_statp->st_uid; 380244541Sbrooks if (suid < MTREE_MAXUID && ++u[suid] > maxuid) { 381244541Sbrooks saveuid = suid; 382244541Sbrooks maxuid = u[suid]; 383244541Sbrooks } 384244541Sbrooks 385244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS 386244541Sbrooks sflags = FLAGS2INDEX(p->fts_statp->st_flags); 387244541Sbrooks if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) { 388244541Sbrooks saveflags = p->fts_statp->st_flags; 389244541Sbrooks maxflags = f[sflags]; 390244541Sbrooks } 391244541Sbrooks#endif 392244541Sbrooks } 393244541Sbrooks } 394244541Sbrooks /* 395244541Sbrooks * If the /set record is the same as the last one we do not need to 396244541Sbrooks * output a new one. So first we check to see if anything changed. 397244541Sbrooks * Note that we always output a /set record for the first directory. 398244541Sbrooks */ 399244541Sbrooks if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) || 400244541Sbrooks ((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) || 401244541Sbrooks ((keys & F_MODE) && (*pmode != savemode)) || 402244541Sbrooks ((keys & F_FLAGS) && (*pflags != saveflags)) || 403244541Sbrooks first) { 404244541Sbrooks first = 0; 405244541Sbrooks if (flavor != F_NETBSD6 && dflag) 406273796Sbrooks fprintf(fp, "/set type=dir"); 407244541Sbrooks else 408273796Sbrooks fprintf(fp, "/set type=file"); 409244541Sbrooks if (keys & (F_UID | F_UNAME)) { 410244541Sbrooks if (keys & F_UNAME && 411244541Sbrooks (name = user_from_uid(saveuid, 1)) != NULL) 412273796Sbrooks fprintf(fp, " uname=%s", name); 413244541Sbrooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 414273796Sbrooks fprintf(fp, " uid=%lu", (u_long)saveuid); 415244541Sbrooks } 416244541Sbrooks if (keys & (F_GID | F_GNAME)) { 417244541Sbrooks if (keys & F_GNAME && 418244541Sbrooks (name = group_from_gid(savegid, 1)) != NULL) 419273796Sbrooks fprintf(fp, " gname=%s", name); 420244541Sbrooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 421273796Sbrooks fprintf(fp, " gid=%lu", (u_long)savegid); 422244541Sbrooks } 423244541Sbrooks if (keys & F_MODE) 424273796Sbrooks fprintf(fp, " mode=%#lo", (u_long)savemode); 425244541Sbrooks if (keys & F_NLINK) 426273796Sbrooks fprintf(fp, " nlink=1"); 427244541Sbrooks if (keys & F_FLAGS) { 428244541Sbrooks char *str = flags_to_string(saveflags, "none"); 429273796Sbrooks fprintf(fp, " flags=%s", str); 430244541Sbrooks free(str); 431244541Sbrooks } 432273796Sbrooks fprintf(fp, "\n"); 433244541Sbrooks *puid = saveuid; 434244541Sbrooks *pgid = savegid; 435244541Sbrooks *pmode = savemode; 436244541Sbrooks *pflags = saveflags; 437244541Sbrooks } 438244541Sbrooks return (0); 439244541Sbrooks} 440244541Sbrooks 441244541Sbrooks/* 442244541Sbrooks * dcmp -- 443244541Sbrooks * used as a comparison function passed to fts_open() to control 444244541Sbrooks * the order in which fts_read() returns results. We make 445244541Sbrooks * directories sort after non-directories, but otherwise sort in 446244541Sbrooks * strcmp() order. 447244541Sbrooks * 448244541Sbrooks * Keep this in sync with nodecmp() in spec.c. 449244541Sbrooks */ 450244541Sbrooksstatic int 451244541Sbrooksdcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b) 452244541Sbrooks{ 453244541Sbrooks 454244541Sbrooks if (S_ISDIR((*a)->fts_statp->st_mode)) { 455244541Sbrooks if (!S_ISDIR((*b)->fts_statp->st_mode)) 456244541Sbrooks return (1); 457244541Sbrooks } else if (S_ISDIR((*b)->fts_statp->st_mode)) 458244541Sbrooks return (-1); 459244541Sbrooks return (strcmp((*a)->fts_name, (*b)->fts_name)); 460244541Sbrooks} 461244541Sbrooks 462244541Sbrooksvoid 463273796Sbrooksoutput(FILE *fp, int indent, int *offset, const char *fmt, ...) 464244541Sbrooks{ 465244541Sbrooks va_list ap; 466244541Sbrooks char buf[1024]; 467244541Sbrooks 468244541Sbrooks va_start(ap, fmt); 469244541Sbrooks vsnprintf(buf, sizeof(buf), fmt, ap); 470244541Sbrooks va_end(ap); 471244541Sbrooks 472244541Sbrooks if (*offset + strlen(buf) > MAXLINELEN - 3) { 473273796Sbrooks fprintf(fp, " \\\n%*s", INDENTNAMELEN + indent, ""); 474244541Sbrooks *offset = INDENTNAMELEN + indent; 475244541Sbrooks } 476273796Sbrooks *offset += fprintf(fp, " %s", buf) + 1; 477244541Sbrooks} 478