1d288d77brooks/* $NetBSD: create.c,v 1.73 2014/04/24 17:22:41 christos Exp $ */ 20c7fe20brooks 30c7fe20brooks/*- 40c7fe20brooks * Copyright (c) 1989, 1993 50c7fe20brooks * The Regents of the University of California. All rights reserved. 60c7fe20brooks * 70c7fe20brooks * Redistribution and use in source and binary forms, with or without 80c7fe20brooks * modification, are permitted provided that the following conditions 90c7fe20brooks * are met: 100c7fe20brooks * 1. Redistributions of source code must retain the above copyright 110c7fe20brooks * notice, this list of conditions and the following disclaimer. 120c7fe20brooks * 2. Redistributions in binary form must reproduce the above copyright 130c7fe20brooks * notice, this list of conditions and the following disclaimer in the 140c7fe20brooks * documentation and/or other materials provided with the distribution. 150c7fe20brooks * 3. Neither the name of the University nor the names of its contributors 160c7fe20brooks * may be used to endorse or promote products derived from this software 170c7fe20brooks * without specific prior written permission. 180c7fe20brooks * 190c7fe20brooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 200c7fe20brooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 210c7fe20brooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 220c7fe20brooks * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 230c7fe20brooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 240c7fe20brooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 250c7fe20brooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 260c7fe20brooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 270c7fe20brooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 280c7fe20brooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 290c7fe20brooks * SUCH DAMAGE. 300c7fe20brooks */ 310c7fe20brooks 320c7fe20brooks#if HAVE_NBTOOL_CONFIG_H 330c7fe20brooks#include "nbtool_config.h" 340c7fe20brooks#endif 350c7fe20brooks 360c7fe20brooks#include <sys/cdefs.h> 370c7fe20brooks#if defined(__RCSID) && !defined(lint) 380c7fe20brooks#if 0 390c7fe20brooksstatic char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; 400c7fe20brooks#else 41d288d77brooks__RCSID("$NetBSD: create.c,v 1.73 2014/04/24 17:22:41 christos Exp $"); 420c7fe20brooks#endif 430c7fe20brooks#endif /* not lint */ 440c7fe20brooks 450c7fe20brooks#include <sys/param.h> 460c7fe20brooks#include <sys/stat.h> 470c7fe20brooks 480c7fe20brooks#if ! HAVE_NBTOOL_CONFIG_H 490c7fe20brooks#include <dirent.h> 500c7fe20brooks#endif 510c7fe20brooks 520c7fe20brooks#include <errno.h> 530c7fe20brooks#include <fcntl.h> 540c7fe20brooks#include <grp.h> 550c7fe20brooks#include <pwd.h> 560c7fe20brooks#include <stdio.h> 570c7fe20brooks#include <stdarg.h> 582f25661brooks#include <stdint.h> 590c7fe20brooks#include <stdlib.h> 600c7fe20brooks#include <string.h> 610c7fe20brooks#include <time.h> 620c7fe20brooks#include <unistd.h> 630c7fe20brooks 640c7fe20brooks#ifndef NO_MD5 650c7fe20brooks#include <md5.h> 660c7fe20brooks#endif 670c7fe20brooks#ifndef NO_RMD160 680c7fe20brooks#include <rmd160.h> 690c7fe20brooks#endif 700c7fe20brooks#ifndef NO_SHA1 710c7fe20brooks#include <sha1.h> 720c7fe20brooks#endif 730c7fe20brooks#ifndef NO_SHA2 740c7fe20brooks#include <sha2.h> 750c7fe20brooks#endif 760c7fe20brooks 770c7fe20brooks#include "extern.h" 780c7fe20brooks 790c7fe20brooks#define INDENTNAMELEN 15 800c7fe20brooks#define MAXLINELEN 80 810c7fe20brooks 820c7fe20brooksstatic gid_t gid; 830c7fe20brooksstatic uid_t uid; 840c7fe20brooksstatic mode_t mode; 850c7fe20brooksstatic u_long flags; 860c7fe20brooks 870c7fe20brooks#ifdef __FreeBSD__ 880c7fe20brooks#define FTS_CONST const 890c7fe20brooks#else 900c7fe20brooks#define FTS_CONST 910c7fe20brooks#endif 920c7fe20brooks 930c7fe20brooksstatic int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *); 94d288d77brooksstatic void output(FILE *, int, int *, const char *, ...) 95d288d77brooks __printflike(4, 5); 96d288d77brooksstatic int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, 97d288d77brooks u_long *); 98d288d77brooksstatic void statf(FILE *, int, FTSENT *); 990c7fe20brooks 1000c7fe20brooksvoid 101d288d77brookscwalk(FILE *fp) 1020c7fe20brooks{ 1030c7fe20brooks FTS *t; 1040c7fe20brooks FTSENT *p; 1050c7fe20brooks time_t clocktime; 1060c7fe20brooks char host[MAXHOSTNAMELEN + 1]; 1070c7fe20brooks const char *user; 1080c7fe20brooks char *argv[2]; 1090c7fe20brooks char dot[] = "."; 1100c7fe20brooks int indent = 0; 1110c7fe20brooks 1120c7fe20brooks argv[0] = dot; 1130c7fe20brooks argv[1] = NULL; 1140c7fe20brooks 1150c7fe20brooks time(&clocktime); 1160c7fe20brooks gethostname(host, sizeof(host)); 1170c7fe20brooks host[sizeof(host) - 1] = '\0'; 1180c7fe20brooks if ((user = getlogin()) == NULL) { 1190c7fe20brooks struct passwd *pw; 1205abaf1abdrewery user = (pw = getpwuid(getuid())) != NULL ? pw->pw_name : 1210c7fe20brooks "<unknown>"; 1220c7fe20brooks } 1230c7fe20brooks 1240c7fe20brooks if (!nflag) 125d288d77brooks fprintf(fp, 1260c7fe20brooks "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n" 1270c7fe20brooks "#\t date: %s", 1280c7fe20brooks user, host, fullpath, ctime(&clocktime)); 1290c7fe20brooks 1300c7fe20brooks if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL) 1310c7fe20brooks mtree_err("fts_open: %s", strerror(errno)); 1320c7fe20brooks while ((p = fts_read(t)) != NULL) { 1330c7fe20brooks if (jflag) 1340c7fe20brooks indent = p->fts_level * 4; 1350c7fe20brooks if (check_excludes(p->fts_name, p->fts_path)) { 1360c7fe20brooks fts_set(t, p, FTS_SKIP); 1370c7fe20brooks continue; 1380c7fe20brooks } 1396eda686ed if (!find_only(p->fts_path)) { 1406eda686ed fts_set(t, p, FTS_SKIP); 1416eda686ed continue; 1426eda686ed } 1430c7fe20brooks switch(p->fts_info) { 1440c7fe20brooks case FTS_D: 1450c7fe20brooks if (!bflag) 146d288d77brooks fprintf(fp, "\n"); 1470c7fe20brooks if (!nflag) 148d288d77brooks fprintf(fp, "# %s\n", p->fts_path); 149d288d77brooks statd(fp, t, p, &uid, &gid, &mode, &flags); 150d288d77brooks statf(fp, indent, p); 1510c7fe20brooks break; 1520c7fe20brooks case FTS_DP: 1530c7fe20brooks if (p->fts_level > 0) 1540c7fe20brooks if (!nflag) 155d288d77brooks fprintf(fp, "%*s# %s\n", indent, "", 1560c7fe20brooks p->fts_path); 1570c7fe20brooks if (p->fts_level > 0 || flavor == F_FREEBSD9) { 158d288d77brooks fprintf(fp, "%*s..\n", indent, ""); 1590c7fe20brooks if (!bflag) 160d288d77brooks fprintf(fp, "\n"); 1610c7fe20brooks } 1620c7fe20brooks break; 1630c7fe20brooks case FTS_DNR: 1640c7fe20brooks case FTS_ERR: 1650c7fe20brooks case FTS_NS: 1660c7fe20brooks mtree_err("%s: %s", 1670c7fe20brooks p->fts_path, strerror(p->fts_errno)); 1680c7fe20brooks break; 1690c7fe20brooks default: 1700c7fe20brooks if (!dflag) 171d288d77brooks statf(fp, indent, p); 1720c7fe20brooks break; 1730c7fe20brooks 1740c7fe20brooks } 1750c7fe20brooks } 1760c7fe20brooks fts_close(t); 1770c7fe20brooks if (sflag && keys & F_CKSUM) 1780c7fe20brooks mtree_err("%s checksum: %u", fullpath, crc_total); 1790c7fe20brooks} 1800c7fe20brooks 1810c7fe20brooksstatic void 182d288d77brooksstatf(FILE *fp, int indent, FTSENT *p) 1830c7fe20brooks{ 1840c7fe20brooks u_int32_t len, val; 1850c7fe20brooks int fd, offset; 1860c7fe20brooks const char *name = NULL; 1870c7fe20brooks#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) 1880c7fe20brooks char *digestbuf; 1890c7fe20brooks#endif 1900c7fe20brooks 191d288d77brooks offset = fprintf(fp, "%*s%s%s", indent, "", 1920c7fe20brooks S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); 1930c7fe20brooks 1940c7fe20brooks if (offset > (INDENTNAMELEN + indent)) 1950c7fe20brooks offset = MAXLINELEN; 1960c7fe20brooks else 197d288d77brooks offset += fprintf(fp, "%*s", 198d288d77brooks (INDENTNAMELEN + indent) - offset, ""); 1990c7fe20brooks 2000c7fe20brooks if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag)) 201d288d77brooks output(fp, indent, &offset, "type=%s", 2020c7fe20brooks inotype(p->fts_statp->st_mode)); 2030c7fe20brooks if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) { 2040c7fe20brooks if (keys & F_UNAME && 2050c7fe20brooks (name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL) 206d288d77brooks output(fp, indent, &offset, "uname=%s", name); 2070c7fe20brooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 208d288d77brooks output(fp, indent, &offset, "uid=%u", 209d288d77brooks p->fts_statp->st_uid); 2100c7fe20brooks } 2110c7fe20brooks if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) { 2120c7fe20brooks if (keys & F_GNAME && 2130c7fe20brooks (name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL) 214d288d77brooks output(fp, indent, &offset, "gname=%s", name); 2150c7fe20brooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 216d288d77brooks output(fp, indent, &offset, "gid=%u", 217d288d77brooks p->fts_statp->st_gid); 2180c7fe20brooks } 2190c7fe20brooks if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) 220d288d77brooks output(fp, indent, &offset, "mode=%#o", 2210c7fe20brooks p->fts_statp->st_mode & MBITS); 2220c7fe20brooks if (keys & F_DEV && 2230c7fe20brooks (S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode))) 224d288d77brooks output(fp, indent, &offset, "device=%#jx", 225a947356brooks (uintmax_t)p->fts_statp->st_rdev); 2260c7fe20brooks if (keys & F_NLINK && p->fts_statp->st_nlink != 1) 2277c67dd5kib output(fp, indent, &offset, "nlink=%ju", 2287c67dd5kib (uintmax_t)p->fts_statp->st_nlink); 2290c7fe20brooks if (keys & F_SIZE && 230a947356brooks (flavor == F_FREEBSD9 || S_ISREG(p->fts_statp->st_mode))) 231d288d77brooks output(fp, indent, &offset, "size=%ju", 232a947356brooks (uintmax_t)p->fts_statp->st_size); 2330c7fe20brooks if (keys & F_TIME) 2340c7fe20brooks#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H) 235d288d77brooks output(fp, indent, &offset, "time=%jd.%09ld", 236a947356brooks (intmax_t)p->fts_statp->st_mtimespec.tv_sec, 2370c7fe20brooks p->fts_statp->st_mtimespec.tv_nsec); 2380c7fe20brooks#else 239d288d77brooks output(fp, indent, &offset, "time=%jd.%09ld", 240a947356brooks (intmax_t)p->fts_statp->st_mtime, (long)0); 2410c7fe20brooks#endif 2420c7fe20brooks if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { 2430c7fe20brooks if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || 2440c7fe20brooks crc(fd, &val, &len)) 2450c7fe20brooks mtree_err("%s: %s", p->fts_accpath, strerror(errno)); 2460c7fe20brooks close(fd); 247d288d77brooks output(fp, indent, &offset, "cksum=%lu", (long)val); 2480c7fe20brooks } 2490c7fe20brooks#ifndef NO_MD5 2500c7fe20brooks if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { 2510c7fe20brooks if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) 2520c7fe20brooks mtree_err("%s: MD5File failed: %s", p->fts_accpath, 2530c7fe20brooks strerror(errno)); 254d288d77brooks output(fp, indent, &offset, "%s=%s", MD5KEY, digestbuf); 2550c7fe20brooks free(digestbuf); 2560c7fe20brooks } 2570c7fe20brooks#endif /* ! NO_MD5 */ 2580c7fe20brooks#ifndef NO_RMD160 2590c7fe20brooks if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { 2600c7fe20brooks if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) 2610c7fe20brooks mtree_err("%s: RMD160File failed: %s", p->fts_accpath, 2620c7fe20brooks strerror(errno)); 263d288d77brooks output(fp, indent, &offset, "%s=%s", RMD160KEY, digestbuf); 2640c7fe20brooks free(digestbuf); 2650c7fe20brooks } 2660c7fe20brooks#endif /* ! NO_RMD160 */ 2670c7fe20brooks#ifndef NO_SHA1 2680c7fe20brooks if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { 2690c7fe20brooks if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) 2700c7fe20brooks mtree_err("%s: SHA1File failed: %s", p->fts_accpath, 2710c7fe20brooks strerror(errno)); 272d288d77brooks output(fp, indent, &offset, "%s=%s", SHA1KEY, digestbuf); 2730c7fe20brooks free(digestbuf); 2740c7fe20brooks } 2750c7fe20brooks#endif /* ! NO_SHA1 */ 2760c7fe20brooks#ifndef NO_SHA2 2770c7fe20brooks if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { 2780c7fe20brooks if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) 2790c7fe20brooks mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, 2800c7fe20brooks strerror(errno)); 281d288d77brooks output(fp, indent, &offset, "%s=%s", SHA256KEY, digestbuf); 2820c7fe20brooks free(digestbuf); 2830c7fe20brooks } 2840c7fe20brooks#ifdef SHA384_BLOCK_LENGTH 2850c7fe20brooks if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { 2860c7fe20brooks if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) 2870c7fe20brooks mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, 2880c7fe20brooks strerror(errno)); 289d288d77brooks output(fp, indent, &offset, "%s=%s", SHA384KEY, digestbuf); 2900c7fe20brooks free(digestbuf); 2910c7fe20brooks } 2920c7fe20brooks#endif 2930c7fe20brooks if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { 2940c7fe20brooks if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) 2950c7fe20brooks mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, 2960c7fe20brooks strerror(errno)); 297d288d77brooks output(fp, indent, &offset, "%s=%s", SHA512KEY, digestbuf); 2980c7fe20brooks free(digestbuf); 2990c7fe20brooks } 3000c7fe20brooks#endif /* ! NO_SHA2 */ 3010c7fe20brooks if (keys & F_SLINK && 3020c7fe20brooks (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) 303d288d77brooks output(fp, indent, &offset, "link=%s", 3040c7fe20brooks vispath(rlink(p->fts_accpath))); 3050c7fe20brooks#if HAVE_STRUCT_STAT_ST_FLAGS 3060c7fe20brooks if (keys & F_FLAGS && p->fts_statp->st_flags != flags) { 3070c7fe20brooks char *str = flags_to_string(p->fts_statp->st_flags, "none"); 308d288d77brooks output(fp, indent, &offset, "flags=%s", str); 3090c7fe20brooks free(str); 3100c7fe20brooks } 3110c7fe20brooks#endif 3120c7fe20brooks putchar('\n'); 3130c7fe20brooks} 3140c7fe20brooks 3150c7fe20brooks/* XXX 3160c7fe20brooks * FLAGS2INDEX will fail once the user and system settable bits need more 3170c7fe20brooks * than one byte, respectively. 3180c7fe20brooks */ 3190c7fe20brooks#define FLAGS2INDEX(x) (((x >> 8) & 0x0000ff00) | (x & 0x000000ff)) 3200c7fe20brooks 3210c7fe20brooks#define MTREE_MAXGID 5000 3220c7fe20brooks#define MTREE_MAXUID 5000 3230c7fe20brooks#define MTREE_MAXMODE (MBITS + 1) 3240c7fe20brooks#if HAVE_STRUCT_STAT_ST_FLAGS 3250c7fe20brooks#define MTREE_MAXFLAGS (FLAGS2INDEX(CH_MASK) + 1) /* 1808 */ 3260c7fe20brooks#else 3270c7fe20brooks#define MTREE_MAXFLAGS 1 3280c7fe20brooks#endif 3290c7fe20brooks#define MTREE_MAXS 16 3300c7fe20brooks 3310c7fe20brooksstatic int 332d288d77brooksstatd(FILE *fp, FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, 333d288d77brooks u_long *pflags) 3340c7fe20brooks{ 3350c7fe20brooks FTSENT *p; 3360c7fe20brooks gid_t sgid; 3370c7fe20brooks uid_t suid; 3380c7fe20brooks mode_t smode; 3390c7fe20brooks u_long sflags = 0; 3400c7fe20brooks const char *name = NULL; 3410c7fe20brooks gid_t savegid; 3420c7fe20brooks uid_t saveuid; 3430c7fe20brooks mode_t savemode; 3440c7fe20brooks u_long saveflags; 3450c7fe20brooks u_short maxgid, maxuid, maxmode, maxflags; 3460c7fe20brooks u_short g[MTREE_MAXGID], u[MTREE_MAXUID], 3470c7fe20brooks m[MTREE_MAXMODE], f[MTREE_MAXFLAGS]; 3480c7fe20brooks static int first = 1; 3490c7fe20brooks 3500c7fe20brooks savegid = *pgid; 3510c7fe20brooks saveuid = *puid; 3520c7fe20brooks savemode = *pmode; 3530c7fe20brooks saveflags = *pflags; 3540c7fe20brooks if ((p = fts_children(t, 0)) == NULL) { 3550c7fe20brooks if (errno) 3560c7fe20brooks mtree_err("%s: %s", RP(parent), strerror(errno)); 3570c7fe20brooks return (1); 3580c7fe20brooks } 3590c7fe20brooks 3600c7fe20brooks memset(g, 0, sizeof(g)); 3610c7fe20brooks memset(u, 0, sizeof(u)); 3620c7fe20brooks memset(m, 0, sizeof(m)); 3630c7fe20brooks memset(f, 0, sizeof(f)); 3640c7fe20brooks 3650c7fe20brooks maxuid = maxgid = maxmode = maxflags = 0; 3660c7fe20brooks for (; p; p = p->fts_link) { 3670c7fe20brooks if (flavor == F_NETBSD6 || !dflag || 3680c7fe20brooks (dflag && S_ISDIR(p->fts_statp->st_mode))) { 3690c7fe20brooks smode = p->fts_statp->st_mode & MBITS; 3700c7fe20brooks if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) { 3710c7fe20brooks savemode = smode; 3720c7fe20brooks maxmode = m[smode]; 3730c7fe20brooks } 3740c7fe20brooks sgid = p->fts_statp->st_gid; 3750c7fe20brooks if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) { 3760c7fe20brooks savegid = sgid; 3770c7fe20brooks maxgid = g[sgid]; 3780c7fe20brooks } 3790c7fe20brooks suid = p->fts_statp->st_uid; 3800c7fe20brooks if (suid < MTREE_MAXUID && ++u[suid] > maxuid) { 3810c7fe20brooks saveuid = suid; 3820c7fe20brooks maxuid = u[suid]; 3830c7fe20brooks } 3840c7fe20brooks 3850c7fe20brooks#if HAVE_STRUCT_STAT_ST_FLAGS 3860c7fe20brooks sflags = FLAGS2INDEX(p->fts_statp->st_flags); 3870c7fe20brooks if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) { 3880c7fe20brooks saveflags = p->fts_statp->st_flags; 3890c7fe20brooks maxflags = f[sflags]; 3900c7fe20brooks } 3910c7fe20brooks#endif 3920c7fe20brooks } 3930c7fe20brooks } 3940c7fe20brooks /* 3950c7fe20brooks * If the /set record is the same as the last one we do not need to 3960c7fe20brooks * output a new one. So first we check to see if anything changed. 3970c7fe20brooks * Note that we always output a /set record for the first directory. 3980c7fe20brooks */ 3990c7fe20brooks if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) || 4000c7fe20brooks ((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) || 4010c7fe20brooks ((keys & F_MODE) && (*pmode != savemode)) || 4020c7fe20brooks ((keys & F_FLAGS) && (*pflags != saveflags)) || 4030c7fe20brooks first) { 4040c7fe20brooks first = 0; 4050c7fe20brooks if (flavor != F_NETBSD6 && dflag) 406d288d77brooks fprintf(fp, "/set type=dir"); 4070c7fe20brooks else 408d288d77brooks fprintf(fp, "/set type=file"); 4090c7fe20brooks if (keys & (F_UID | F_UNAME)) { 4100c7fe20brooks if (keys & F_UNAME && 4110c7fe20brooks (name = user_from_uid(saveuid, 1)) != NULL) 412d288d77brooks fprintf(fp, " uname=%s", name); 4130c7fe20brooks if (keys & F_UID || (keys & F_UNAME && name == NULL)) 414d288d77brooks fprintf(fp, " uid=%lu", (u_long)saveuid); 4150c7fe20brooks } 4160c7fe20brooks if (keys & (F_GID | F_GNAME)) { 4170c7fe20brooks if (keys & F_GNAME && 4180c7fe20brooks (name = group_from_gid(savegid, 1)) != NULL) 419d288d77brooks fprintf(fp, " gname=%s", name); 4200c7fe20brooks if (keys & F_GID || (keys & F_GNAME && name == NULL)) 421d288d77brooks fprintf(fp, " gid=%lu", (u_long)savegid); 4220c7fe20brooks } 4230c7fe20brooks if (keys & F_MODE) 424d288d77brooks fprintf(fp, " mode=%#lo", (u_long)savemode); 4250c7fe20brooks if (keys & F_NLINK) 426d288d77brooks fprintf(fp, " nlink=1"); 4270c7fe20brooks if (keys & F_FLAGS) { 4280c7fe20brooks char *str = flags_to_string(saveflags, "none"); 429d288d77brooks fprintf(fp, " flags=%s", str); 4300c7fe20brooks free(str); 4310c7fe20brooks } 432d288d77brooks fprintf(fp, "\n"); 4330c7fe20brooks *puid = saveuid; 4340c7fe20brooks *pgid = savegid; 4350c7fe20brooks *pmode = savemode; 4360c7fe20brooks *pflags = saveflags; 4370c7fe20brooks } 4380c7fe20brooks return (0); 4390c7fe20brooks} 4400c7fe20brooks 4410c7fe20brooks/* 4420c7fe20brooks * dcmp -- 4430c7fe20brooks * used as a comparison function passed to fts_open() to control 4440c7fe20brooks * the order in which fts_read() returns results. We make 4450c7fe20brooks * directories sort after non-directories, but otherwise sort in 4460c7fe20brooks * strcmp() order. 4470c7fe20brooks * 4480c7fe20brooks * Keep this in sync with nodecmp() in spec.c. 4490c7fe20brooks */ 4500c7fe20brooksstatic int 4510c7fe20brooksdcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *b) 4520c7fe20brooks{ 4530c7fe20brooks 4540c7fe20brooks if (S_ISDIR((*a)->fts_statp->st_mode)) { 4550c7fe20brooks if (!S_ISDIR((*b)->fts_statp->st_mode)) 4560c7fe20brooks return (1); 4570c7fe20brooks } else if (S_ISDIR((*b)->fts_statp->st_mode)) 4580c7fe20brooks return (-1); 4590c7fe20brooks return (strcmp((*a)->fts_name, (*b)->fts_name)); 4600c7fe20brooks} 4610c7fe20brooks 4620c7fe20brooksvoid 463d288d77brooksoutput(FILE *fp, int indent, int *offset, const char *fmt, ...) 4640c7fe20brooks{ 4650c7fe20brooks va_list ap; 4660c7fe20brooks char buf[1024]; 4670c7fe20brooks 4680c7fe20brooks va_start(ap, fmt); 4690c7fe20brooks vsnprintf(buf, sizeof(buf), fmt, ap); 4700c7fe20brooks va_end(ap); 4710c7fe20brooks 4720c7fe20brooks if (*offset + strlen(buf) > MAXLINELEN - 3) { 473d288d77brooks fprintf(fp, " \\\n%*s", INDENTNAMELEN + indent, ""); 4740c7fe20brooks *offset = INDENTNAMELEN + indent; 4750c7fe20brooks } 476d288d77brooks *offset += fprintf(fp, " %s", buf) + 1; 4770c7fe20brooks} 478