create.c revision 2860
1255736Sdavidch/*-
2255736Sdavidch * Copyright (c) 1989, 1993
3255736Sdavidch *	The Regents of the University of California.  All rights reserved.
4255736Sdavidch *
5255736Sdavidch * Redistribution and use in source and binary forms, with or without
6255736Sdavidch * modification, are permitted provided that the following conditions
7255736Sdavidch * are met:
8255736Sdavidch * 1. Redistributions of source code must retain the above copyright
9255736Sdavidch *    notice, this list of conditions and the following disclaimer.
10255736Sdavidch * 2. Redistributions in binary form must reproduce the above copyright
11255736Sdavidch *    notice, this list of conditions and the following disclaimer in the
12255736Sdavidch *    documentation and/or other materials provided with the distribution.
13255736Sdavidch * 3. All advertising materials mentioning features or use of this software
14255736Sdavidch *    must display the following acknowledgement:
15255736Sdavidch *	This product includes software developed by the University of
16255736Sdavidch *	California, Berkeley and its contributors.
17255736Sdavidch * 4. Neither the name of the University nor the names of its contributors
18255736Sdavidch *    may be used to endorse or promote products derived from this software
19255736Sdavidch *    without specific prior written permission.
20255736Sdavidch *
21255736Sdavidch * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22255736Sdavidch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23255736Sdavidch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24255736Sdavidch * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25255736Sdavidch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26255736Sdavidch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27255736Sdavidch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28255736Sdavidch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29255736Sdavidch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30255736Sdavidch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31255736Sdavidch * SUCH DAMAGE.
32255736Sdavidch */
33255736Sdavidch
34255736Sdavidch#ifndef lint
35255736Sdavidchstatic char sccsid[] = "@(#)create.c	8.1 (Berkeley) 6/6/93";
36255736Sdavidch#endif /* not lint */
37255736Sdavidch
38255736Sdavidch#include <sys/param.h>
39255736Sdavidch#include <sys/stat.h>
40255736Sdavidch#include <time.h>
41255736Sdavidch#include <fcntl.h>
42255736Sdavidch#include <fts.h>
43255736Sdavidch#include <dirent.h>
44255736Sdavidch#include <grp.h>
45255736Sdavidch#include <pwd.h>
46255736Sdavidch#include <errno.h>
47255736Sdavidch#include <unistd.h>
48255736Sdavidch#include <stdio.h>
49255736Sdavidch#include "mtree.h"
50255736Sdavidch#include "extern.h"
51255736Sdavidch
52255736Sdavidch#define	INDENTNAMELEN	15
53255736Sdavidch#define	MAXLINELEN	80
54255736Sdavidch
55255736Sdavidchextern long int crc_total;
56255736Sdavidchextern int ftsoptions;
57255736Sdavidchextern int dflag, iflag, nflag, sflag;
58255736Sdavidchextern u_short keys;
59255736Sdavidchextern char fullpath[MAXPATHLEN];
60255736Sdavidch
61255736Sdavidchstatic gid_t gid;
62255736Sdavidchstatic uid_t uid;
63255736Sdavidchstatic mode_t mode;
64255736Sdavidch
65255736Sdavidchstatic int	dsort __P((const FTSENT **, const FTSENT **));
66255736Sdavidchstatic void	output __P((int, int *, const char *, ...));
67255736Sdavidchstatic int	statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
68255736Sdavidchstatic void	statf __P((int, FTSENT *));
69255736Sdavidch
70255736Sdavidchvoid
71255736Sdavidchcwalk()
72255736Sdavidch{
73255736Sdavidch	register FTS *t;
74255736Sdavidch	register FTSENT *p;
75255736Sdavidch	time_t clock;
76255736Sdavidch	char *argv[2], host[MAXHOSTNAMELEN];
77255736Sdavidch	int indent = 0;
78255736Sdavidch
79255736Sdavidch	(void)time(&clock);
80255736Sdavidch	(void)gethostname(host, sizeof(host));
81255736Sdavidch	(void)printf(
82255736Sdavidch	    "#\t   user: %s\n#\tmachine: %s\n#\t   tree: %s\n#\t   date: %s",
83255736Sdavidch	    getlogin(), host, fullpath, ctime(&clock));
84255736Sdavidch
85255736Sdavidch	argv[0] = ".";
86255736Sdavidch	argv[1] = NULL;
87255736Sdavidch	if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
88255736Sdavidch		err("fts_open: %s", strerror(errno));
89255736Sdavidch	while ((p = fts_read(t))) {
90255736Sdavidch		if (iflag)
91255736Sdavidch			indent = p->fts_level * 4;
92255736Sdavidch		switch(p->fts_info) {
93255736Sdavidch		case FTS_D:
94255736Sdavidch			if (!dflag)
95255736Sdavidch				(void)printf("\n");
96255736Sdavidch			if (!nflag)
97255736Sdavidch				(void)printf("# %s\n", p->fts_path);
98255736Sdavidch			statd(t, p, &uid, &gid, &mode);
99255736Sdavidch			statf(indent, p);
100255736Sdavidch			break;
101255736Sdavidch		case FTS_DP:
102255736Sdavidch			if (!nflag && (p->fts_level > 0))
103255736Sdavidch				(void)printf("%*s# %s\n", indent, "", p->fts_path);
104255736Sdavidch			(void)printf("%*s..\n", indent, "");
105255736Sdavidch			if (!dflag)
106255736Sdavidch				(void)printf("\n");
107255736Sdavidch			break;
108255736Sdavidch		case FTS_DNR:
109255736Sdavidch		case FTS_ERR:
110255736Sdavidch		case FTS_NS:
111255736Sdavidch			(void)fprintf(stderr,
112255736Sdavidch			    "mtree: %s: %s\n", p->fts_path, strerror(errno));
113255736Sdavidch			break;
114255736Sdavidch		default:
115255736Sdavidch			if (!dflag)
116255736Sdavidch				statf(indent, p);
117255736Sdavidch			break;
118255736Sdavidch
119255736Sdavidch		}
120255736Sdavidch	}
121255736Sdavidch	(void)fts_close(t);
122255736Sdavidch	if (sflag && keys & F_CKSUM)
123255736Sdavidch		(void)fprintf(stderr,
124255736Sdavidch		    "mtree: %s checksum: %lu\n", fullpath, crc_total);
125255736Sdavidch}
126255736Sdavidch
127255736Sdavidchstatic void
128255736Sdavidchstatf(indent, p)
129255736Sdavidch	int indent;
130255736Sdavidch	FTSENT *p;
131255736Sdavidch{
132255736Sdavidch	struct group *gr;
133255736Sdavidch	struct passwd *pw;
134255736Sdavidch	u_long len, val;
135255736Sdavidch	int fd, offset;
136255736Sdavidch
137255736Sdavidch	if (iflag || S_ISDIR(p->fts_statp->st_mode))
138255736Sdavidch		offset = printf("%*s%s", indent, "", p->fts_name);
139255736Sdavidch	else
140255736Sdavidch		offset = printf("%*s    %s", indent, "", p->fts_name);
141255736Sdavidch
142255736Sdavidch	if (offset > (INDENTNAMELEN + indent))
143255736Sdavidch		offset = MAXLINELEN;
144255736Sdavidch	else
145255736Sdavidch		offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
146255736Sdavidch
147255736Sdavidch	if (!S_ISREG(p->fts_statp->st_mode) && !dflag)
148255736Sdavidch		output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));
149255736Sdavidch	if (p->fts_statp->st_uid != uid) {
150255736Sdavidch		if (keys & F_UNAME) {
151255736Sdavidch			if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) {
152255736Sdavidch				output(indent, &offset, "uname=%s", pw->pw_name);
153255736Sdavidch			} else {
154255736Sdavidch				err("could not get uname for uid=%u",
155255736Sdavidch				    p->fts_statp->st_uid);
156255736Sdavidch			}
157255736Sdavidch		}
158255736Sdavidch		if (keys & F_UID)
159255736Sdavidch			output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
160255736Sdavidch	}
161255736Sdavidch	if (p->fts_statp->st_gid != gid) {
162255736Sdavidch		if (keys & F_GNAME) {
163255736Sdavidch			if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) {
164255736Sdavidch				output(indent, &offset, "gname=%s", gr->gr_name);
165255736Sdavidch			} else {
166255736Sdavidch				err("could not get gname for gid=%u",
167255736Sdavidch				    p->fts_statp->st_gid);
168255736Sdavidch			}
169255736Sdavidch		}
170255736Sdavidch		if (keys & F_GID)
171255736Sdavidch			output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
172255736Sdavidch	}
173255736Sdavidch	if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
174255736Sdavidch		output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS);
175255736Sdavidch	if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
176255736Sdavidch		output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink);
177255736Sdavidch	if (keys & F_SIZE)
178255736Sdavidch		output(indent, &offset, "size=%qd", p->fts_statp->st_size);
179255736Sdavidch	if (keys & F_TIME)
180255736Sdavidch		output(indent, &offset, "time=%ld.%ld",
181255736Sdavidch		    p->fts_statp->st_mtimespec.ts_sec,
182255736Sdavidch		    p->fts_statp->st_mtimespec.ts_nsec);
183255736Sdavidch	if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
184255736Sdavidch		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
185255736Sdavidch		    crc(fd, &val, &len))
186255736Sdavidch			err("%s: %s", p->fts_accpath, strerror(errno));
187255736Sdavidch		(void)close(fd);
188255736Sdavidch		output(indent, &offset, "cksum=%lu", val);
189255736Sdavidch	}
190255736Sdavidch	if (keys & F_SLINK &&
191255736Sdavidch	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
192255736Sdavidch		output(indent, &offset, "link=%s", rlink(p->fts_accpath));
193255736Sdavidch	(void)putchar('\n');
194255736Sdavidch}
195255736Sdavidch
196255736Sdavidch#define	MAXGID	5000
197255736Sdavidch#define	MAXUID	5000
198255736Sdavidch#define	MAXMODE	MBITS + 1
199255736Sdavidch
200255736Sdavidchstatic int
201255736Sdavidchstatd(t, parent, puid, pgid, pmode)
202255736Sdavidch	FTS *t;
203255736Sdavidch	FTSENT *parent;
204255736Sdavidch	uid_t *puid;
205255736Sdavidch	gid_t *pgid;
206255736Sdavidch	mode_t *pmode;
207255736Sdavidch{
208255736Sdavidch	register FTSENT *p;
209255736Sdavidch	register gid_t sgid;
210255736Sdavidch	register uid_t suid;
211255736Sdavidch	register mode_t smode;
212255736Sdavidch	struct group *gr;
213255736Sdavidch	struct passwd *pw;
214255736Sdavidch	gid_t savegid = *pgid;
215255736Sdavidch	uid_t saveuid = *puid;
216255736Sdavidch	mode_t savemode = *pmode;
217255736Sdavidch	u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
218255736Sdavidch
219255736Sdavidch	if ((p = fts_children(t, 0)) == NULL) {
220255736Sdavidch		if (errno)
221255736Sdavidch			err("%s: %s", RP(parent), strerror(errno));
222255736Sdavidch		return (1);
223255736Sdavidch	}
224255736Sdavidch
225255736Sdavidch	bzero(g, sizeof(g));
226255736Sdavidch	bzero(u, sizeof(u));
227255736Sdavidch	bzero(m, sizeof(m));
228255736Sdavidch
229255736Sdavidch	maxuid = maxgid = maxmode = 0;
230255736Sdavidch	for (; p; p = p->fts_link) {
231255736Sdavidch		if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) {
232255736Sdavidch			smode = p->fts_statp->st_mode & MBITS;
233255736Sdavidch			if (smode < MAXMODE && ++m[smode] > maxmode) {
234255736Sdavidch				savemode = smode;
235255736Sdavidch				maxmode = m[smode];
236255736Sdavidch			}
237255736Sdavidch			sgid = p->fts_statp->st_gid;
238255736Sdavidch			if (sgid < MAXGID && ++g[sgid] > maxgid) {
239255736Sdavidch				savegid = sgid;
240255736Sdavidch				maxgid = g[sgid];
241255736Sdavidch			}
242255736Sdavidch			suid = p->fts_statp->st_uid;
243255736Sdavidch			if (suid < MAXUID && ++u[suid] > maxuid) {
244255736Sdavidch				saveuid = suid;
245255736Sdavidch				maxuid = u[suid];
246255736Sdavidch			}
247255736Sdavidch		}
248255736Sdavidch	}
249255736Sdavidch	/*
250255736Sdavidch	 * If the /set record is the same as the last one we do not need to output
251255736Sdavidch	 * a new one.  So first we check to see if anything changed.
252255736Sdavidch	 */
253255736Sdavidch	if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) ||
254255736Sdavidch	    (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||
255255736Sdavidch	    ((keys & F_MODE) && (*pmode != savemode))) {
256255736Sdavidch		if (dflag)
257255736Sdavidch			(void)printf("/set type=dir");
258255736Sdavidch		else
259255736Sdavidch			(void)printf("/set type=file");
260255736Sdavidch		if (keys & F_UNAME)
261255736Sdavidch			if ((pw = getpwuid(saveuid)) != NULL)
262255736Sdavidch				(void)printf(" uname=%s", pw->pw_name);
263255736Sdavidch			else
264255736Sdavidch				err("could not get uname for uid=%u", saveuid);
265255736Sdavidch		if (keys & F_UID)
266255736Sdavidch			(void)printf(" uid=%lu", saveuid);
267255736Sdavidch		if (keys & F_GNAME)
268255736Sdavidch			if ((gr = getgrgid(savegid)) != NULL)
269255736Sdavidch				(void)printf(" gname=%s", gr->gr_name);
270255736Sdavidch			else
271255736Sdavidch				err("could not get gname for gid=%u", savegid);
272255736Sdavidch		if (keys & F_GID)
273255736Sdavidch			(void)printf(" gid=%lu", savegid);
274255736Sdavidch		if (keys & F_MODE)
275255736Sdavidch			(void)printf(" mode=%#o", savemode);
276255736Sdavidch		if (keys & F_NLINK)
277255736Sdavidch			(void)printf(" nlink=1");
278255736Sdavidch		(void)printf("\n");
279255736Sdavidch		*puid = saveuid;
280255736Sdavidch		*pgid = savegid;
281255736Sdavidch		*pmode = savemode;
282255736Sdavidch	}
283255736Sdavidch	return (0);
284255736Sdavidch}
285255736Sdavidch
286255736Sdavidchstatic int
287255736Sdavidchdsort(a, b)
288255736Sdavidch	const FTSENT **a, **b;
289255736Sdavidch{
290255736Sdavidch	if (S_ISDIR((*a)->fts_statp->st_mode)) {
291255736Sdavidch		if (!S_ISDIR((*b)->fts_statp->st_mode))
292255736Sdavidch			return (1);
293255736Sdavidch	} else if (S_ISDIR((*b)->fts_statp->st_mode))
294255736Sdavidch		return (-1);
295255736Sdavidch	return (strcmp((*a)->fts_name, (*b)->fts_name));
296255736Sdavidch}
297255736Sdavidch
298255736Sdavidch#if __STDC__
299255736Sdavidch#include <stdarg.h>
300255736Sdavidch#else
301255736Sdavidch#include <varargs.h>
302255736Sdavidch#endif
303255736Sdavidch
304255736Sdavidchvoid
305255736Sdavidch#if __STDC__
306255736Sdavidchoutput(int indent, int *offset, const char *fmt, ...)
307255736Sdavidch#else
308255736Sdavidchoutput(indent, offset, fmt, va_alist)
309255736Sdavidch	int indent;
310255736Sdavidch	int *offset;
311255736Sdavidch	char *fmt;
312255736Sdavidch        va_dcl
313255736Sdavidch#endif
314255736Sdavidch{
315255736Sdavidch	va_list ap;
316255736Sdavidch	char buf[1024];
317255736Sdavidch#if __STDC__
318255736Sdavidch	va_start(ap, fmt);
319255736Sdavidch#else
320255736Sdavidch	va_start(ap);
321255736Sdavidch#endif
322255736Sdavidch	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
323255736Sdavidch	va_end(ap);
324255736Sdavidch
325255736Sdavidch	if (*offset + strlen(buf) > MAXLINELEN - 3) {
326255736Sdavidch		(void)printf(" \\\n%*s", INDENTNAMELEN + indent, "");
327255736Sdavidch		*offset = INDENTNAMELEN + indent;
328255736Sdavidch	}
329255736Sdavidch	*offset += printf(" %s", buf) + 1;
330255736Sdavidch}
331255736Sdavidch