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