1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <time.h>
15 #include <fcntl.h>
16 #include <fts.h>
17 #include <dirent.h>
18 #include <grp.h>
19 #include <pwd.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include "mtree.h"
24 #include "extern.h"
25
26 #define INDENTNAMELEN 15
27 #define MAXLINELEN 80
28
29 extern int crc_total, ftsoptions;
30 extern int dflag, sflag;
31 extern u_short keys;
32 extern char fullpath[MAXPATHLEN];
33
34 static gid_t gid;
35 static uid_t uid;
36 static mode_t mode;
37
38 static int dsort __P((const FTSENT **, const FTSENT **));
39 static void output __P((int *, const char *, ...));
40 static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
41 static void statf __P((FTSENT *));
42
43 void
cwalk()44 cwalk()
45 {
46 register FTS *t;
47 register FTSENT *p;
48 time_t clock;
49 char *argv[2], host[MAXHOSTNAMELEN];
50
51 (void)time(&clock);
52 (void)gethostname(host, sizeof(host));
53 (void)printf(
54 "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s",
55 getlogin(), host, fullpath, ctime(&clock));
56
57 argv[0] = ".";
58 argv[1] = NULL;
59 if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
60 err("fts_open: %s", strerror(errno));
61 while (p = fts_read(t))
62 switch(p->fts_info) {
63 case FTS_D:
64 (void)printf("\n# %s\n", p->fts_path);
65 statd(t, p, &uid, &gid, &mode);
66 statf(p);
67 break;
68 case FTS_DP:
69 if (p->fts_level > 0)
70 (void)printf("# %s\n..\n\n", p->fts_path);
71 break;
72 case FTS_DNR:
73 case FTS_ERR:
74 case FTS_NS:
75 (void)fprintf(stderr,
76 "mtree: %s: %s\n", p->fts_path, strerror(errno));
77 break;
78 default:
79 if (!dflag)
80 statf(p);
81 break;
82
83 }
84 (void)fts_close(t);
85 if (sflag && keys & F_CKSUM)
86 (void)fprintf(stderr,
87 "mtree: %s checksum: %lu\n", fullpath, crc_total);
88 }
89
90 static void
statf(p)91 statf(p)
92 FTSENT *p;
93 {
94 struct group *gr;
95 struct passwd *pw;
96 u_long len, val;
97 int fd, indent;
98
99 if (S_ISDIR(p->fts_statp->st_mode))
100 indent = printf("%s", p->fts_name);
101 else
102 indent = printf(" %s", p->fts_name);
103
104 if (indent > INDENTNAMELEN)
105 indent = MAXLINELEN;
106 else
107 indent += printf("%*s", INDENTNAMELEN - indent, "");
108
109 if (!S_ISREG(p->fts_statp->st_mode))
110 output(&indent, "type=%s", inotype(p->fts_statp->st_mode));
111 if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid)
112 if (keys & F_UNAME && (pw = getpwuid(p->fts_statp->st_uid)))
113 output(&indent, "uname=%s", pw->pw_name);
114 else /* if (keys & F_UID) */
115 output(&indent, "uid=%u", p->fts_statp->st_uid);
116 if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid)
117 if (keys & F_GNAME && (gr = getgrgid(p->fts_statp->st_gid)))
118 output(&indent, "gname=%s", gr->gr_name);
119 else /* if (keys & F_GID) */
120 output(&indent, "gid=%u", p->fts_statp->st_gid);
121 if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
122 output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS);
123 if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
124 output(&indent, "nlink=%u", p->fts_statp->st_nlink);
125 if (keys & F_SIZE)
126 output(&indent, "size=%qd", p->fts_statp->st_size);
127 if (keys & F_TIME)
128 output(&indent, "time=%ld.%ld",
129 p->fts_statp->st_mtimespec.ts_sec,
130 p->fts_statp->st_mtimespec.ts_nsec);
131 if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
132 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
133 crc(fd, &val, &len))
134 err("%s: %s", p->fts_accpath, strerror(errno));
135 (void)close(fd);
136 output(&indent, "cksum=%lu", val);
137 }
138 if (keys & F_SLINK &&
139 (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
140 output(&indent, "link=%s", rlink(p->fts_accpath));
141 (void)putchar('\n');
142 }
143
144 #define MAXGID 5000
145 #define MAXUID 5000
146 #define MAXMODE MBITS + 1
147
148 static int
statd(t,parent,puid,pgid,pmode)149 statd(t, parent, puid, pgid, pmode)
150 FTS *t;
151 FTSENT *parent;
152 uid_t *puid;
153 gid_t *pgid;
154 mode_t *pmode;
155 {
156 register FTSENT *p;
157 register gid_t sgid;
158 register uid_t suid;
159 register mode_t smode;
160 struct group *gr;
161 struct passwd *pw;
162 gid_t savegid;
163 uid_t saveuid;
164 mode_t savemode;
165 u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
166
167 if ((p = fts_children(t, 0)) == NULL) {
168 if (errno)
169 err("%s: %s", RP(parent), strerror(errno));
170 return (1);
171 }
172
173 bzero(g, sizeof(g));
174 bzero(u, sizeof(u));
175 bzero(m, sizeof(m));
176
177 maxuid = maxgid = maxmode = 0;
178 for (; p; p = p->fts_link) {
179 smode = p->fts_statp->st_mode & MBITS;
180 if (smode < MAXMODE && ++m[smode] > maxmode) {
181 savemode = smode;
182 maxmode = m[smode];
183 }
184 sgid = p->fts_statp->st_gid;
185 if (sgid < MAXGID && ++g[sgid] > maxgid) {
186 savegid = sgid;
187 maxgid = g[sgid];
188 }
189 suid = p->fts_statp->st_uid;
190 if (suid < MAXUID && ++u[suid] > maxuid) {
191 saveuid = suid;
192 maxuid = u[suid];
193 }
194 }
195 (void)printf("/set type=file");
196 if (keys & F_GID)
197 (void)printf(" gid=%u", savegid);
198 if (keys & F_GNAME)
199 if ((gr = getgrgid(savegid)) != NULL)
200 (void)printf(" gname=%s", gr->gr_name);
201 else
202 (void)printf(" gid=%u", savegid);
203 if (keys & F_UNAME)
204 if ((pw = getpwuid(saveuid)) != NULL)
205 (void)printf(" uname=%s", pw->pw_name);
206 else
207 (void)printf(" uid=%u", saveuid);
208 if (keys & F_UID)
209 (void)printf(" uid=%u", saveuid);
210 if (keys & F_MODE)
211 (void)printf(" mode=%#o", savemode);
212 if (keys & F_NLINK)
213 (void)printf(" nlink=1");
214 (void)printf("\n");
215 *puid = saveuid;
216 *pgid = savegid;
217 *pmode = savemode;
218 return (0);
219 }
220
221 static int
dsort(a,b)222 dsort(a, b)
223 const FTSENT **a, **b;
224 {
225 if (S_ISDIR((*a)->fts_statp->st_mode)) {
226 if (!S_ISDIR((*b)->fts_statp->st_mode))
227 return (1);
228 } else if (S_ISDIR((*b)->fts_statp->st_mode))
229 return (-1);
230 return (strcmp((*a)->fts_name, (*b)->fts_name));
231 }
232
233 #if __STDC__
234 #include <stdarg.h>
235 #else
236 #include <varargs.h>
237 #endif
238
239 void
240 #if __STDC__
output(int * offset,const char * fmt,...)241 output(int *offset, const char *fmt, ...)
242 #else
243 output(offset, fmt, va_alist)
244 int *offset;
245 char *fmt;
246 va_dcl
247 #endif
248 {
249 va_list ap;
250 char buf[1024];
251 #if __STDC__
252 va_start(ap, fmt);
253 #else
254 va_start(ap);
255 #endif
256 (void)vsnprintf(buf, sizeof(buf), fmt, ap);
257 va_end(ap);
258
259 if (*offset + strlen(buf) > MAXLINELEN - 3) {
260 (void)printf(" \\\n%*s", INDENTNAMELEN, "");
261 *offset = INDENTNAMELEN;
262 }
263 *offset += printf(" %s", buf) + 1;
264 }
265