xref: /original-bsd/usr.sbin/mtree/create.c (revision 35293e0f)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)create.c	5.3 (Berkeley) 09/06/89";
20 #endif /* not lint */
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <stdio.h>
26 #include <strings.h>
27 #include "mtree.h"
28 
29 cwalk(parent, tail)
30 	ENTRY *parent;
31 	register char *tail;
32 {
33 	extern ENTRY *root;
34 	extern dev_t device;
35 	extern int dflag, xflag, errno, alphasort();
36 	extern char path[];
37 	register ENTRY *centry, *level;
38 	struct dirent *dp, **dir_list;
39 	struct stat sbuf;
40 	int cnt, dir_cnt;
41 	char *emalloc(), *rlink();
42 
43 	*tail++ = '/';
44 	dir_cnt = scandir(".", &dir_list, NULL, alphasort);
45 	if (dir_cnt == -1 || xflag && lstat(".", &sbuf)) {
46 		(void)fprintf(stderr, "mtree: %s: %s\n", path + 2,
47 		    strerror(errno));
48 			exit(1);
49 	}
50 	device = sbuf.st_dev;
51 	for (cnt = 0; cnt < dir_cnt; ++cnt) {
52 		dp = dir_list[cnt];
53 		if (dp->d_name[0] == '.' &&
54 		    (!dp->d_name[1] || dp->d_name[1] == '.' && !dp->d_name[2]))
55 			continue;
56 		bcopy(dp->d_name, tail, dp->d_namlen + 1);
57 		if (lstat(dp->d_name, &sbuf)) {
58 			(void)fprintf(stderr, "mtree: %s: %s\n",
59 			    path + 2, strerror(errno));
60 			exit(1);
61 		}
62 		if (dflag && !S_ISDIR(sbuf.st_mode))
63 			continue;
64 
65 		centry = (ENTRY *)emalloc(sizeof(ENTRY));
66 		if (!(centry->name = strdup(dp->d_name)))
67 			nomem();
68 		centry->nlen = dp->d_namlen;
69 
70 		switch(sbuf.st_mode&S_IFMT) {
71 		case S_IFDIR:
72 			centry->info.type = F_DIR;
73 			break;
74 		case S_IFCHR:
75 			centry->info.type = F_CHAR;
76 			break;
77 		case S_IFBLK:
78 			centry->info.type = F_BLOCK;
79 			break;
80 		case S_IFREG:
81 			centry->info.type = F_FILE;
82 			break;
83 		case S_IFLNK:
84 			centry->info.type = F_LINK;
85 			centry->info.slink = strdup(rlink(dp->d_name));
86 			break;
87 		case S_IFSOCK:
88 			centry->info.type = F_SOCK;
89 			break;
90 		default:
91 			(void)fprintf(stderr, "mtree: unknown file type %s.\n",
92 			    path + 2);
93 			exit(1);
94 		}
95 		centry->info.st_uid = sbuf.st_uid;
96 		centry->info.st_gid = sbuf.st_gid;
97 		centry->info.st_size = sbuf.st_size;
98 		centry->info.st_mode = sbuf.st_mode&07777;
99 		centry->info.st_nlink = sbuf.st_nlink;
100 		centry->info.st_uid = sbuf.st_uid;
101 
102 		if (!root) {
103 			level = root = centry;
104 			root->parent = root->child = NULL;
105 		}
106 		else if (parent) {
107 			centry->parent = parent;
108 			parent->child = centry;
109 			level = centry;
110 			parent = NULL;
111 		}
112 		else {
113 			centry->parent = level->parent;
114 			level = level->next = centry;
115 		}
116 		stats(&centry->info);
117 		if (!S_ISDIR(sbuf.st_mode) || xflag && device != sbuf.st_dev)
118 			continue;
119 		if (chdir(dp->d_name)) {
120 			(void)fprintf(stderr, "mtree: %s: %s\n", path + 2,
121 			    strerror(errno));
122 			exit(1);
123 		}
124 		cwalk(level, tail + dp->d_namlen);
125 		if (chdir("..")) {
126 			(void)fprintf(stderr, "mtree: ..: %s\n",
127 			    strerror(errno));
128 			exit(1);
129 		}
130 	}
131 }
132 
133 #define	LABEL { \
134 	if (!label++) \
135 		(void)printf("%s", level->nlen > 7 ? "\t" : "\t\t"); \
136 	else \
137 		(void)putchar(' '); \
138 }
139 
140 extern mode_t dmode;				/* default directory mode */
141 extern mode_t fmode;				/* default file mode */
142 uid_t uid, gid;					/* default owner, group */
143 u_int type;
144 pwalk(level, tabs)
145 	ENTRY *level;
146 	int tabs;
147 {
148 	INFO *ip;
149 	register int cnt;
150 	int label;
151 	char *ftype();
152 
153 	for (; level; level = level->next) {
154 		for (cnt = tabs; cnt--; )
155 			(void)putchar('\t');
156 		(void)printf("%s", level->name);
157 		label = 0;
158 		if ((ip = &level->info)->type != type) {
159 			LABEL;
160 			(void)printf("type=%s", ftype(ip->type));
161 		}
162 		if (ip->st_uid != uid) {
163 			LABEL;
164 			(void)printf("owner=%u", ip->st_uid);
165 		}
166 		if (ip->st_gid != gid) {
167 			LABEL;
168 			(void)printf("group=%u", ip->st_gid);
169 		}
170 		if (ip->type == F_DIR) {
171 			if (ip->st_mode != dmode) {
172 				LABEL;
173 				(void)printf("mode=%o", ip->st_mode);
174 			}
175 		} else {
176 			if (ip->st_mode != fmode) {
177 				LABEL;
178 				(void)printf("mode=%o", ip->st_mode);
179 			}
180 			if (ip->st_nlink != 1) {
181 				LABEL;
182 				(void)printf("nlink=%u", ip->st_nlink);
183 			}
184 		}
185 		LABEL;
186 		(void)printf("size=%ld", ip->st_size);
187 		if (ip->slink)
188 			(void)printf(" link=%s", ip->slink);
189 		(void)putchar('\n');
190 		if (level->child)
191 			pwalk(level->child, tabs + 1);
192 		if (ip->type == F_DIR) {
193 			for (cnt = tabs; cnt--; )
194 				(void)putchar('\t');
195 			(void)printf("..\n");
196 		}
197 	}
198 }
199 
200 ID *uhead;
201 ID *ghead;
202 u_long dmodes[0777 + 1];
203 u_long fmodes[0777 + 1];
204 
205 stats(ip)
206 	INFO *ip;
207 {
208 	register ID *p;
209 
210 	if (ip->type == F_DIR)
211 		++dmodes[ip->st_mode&0777];
212 	else
213 		++fmodes[ip->st_mode&0777];
214 	for (p = uhead;; p = p->next)
215 		if (!p) {
216 			p = (ID *)emalloc(sizeof(ID));
217 			p->id = ip->st_uid;
218 			p->next = uhead;
219 			uhead = p;
220 			break;
221 		} else if (p->id == ip->st_uid) {
222 			++p->cnt;
223 			break;
224 		}
225 	for (p = ghead;; p = p->next)
226 		if (!p) {
227 			p = (ID *)emalloc(sizeof(ID));
228 			p->id = ip->st_gid;
229 			p->next = ghead;
230 			ghead = p;
231 			break;
232 		} else if (p->id == ip->st_gid) {
233 			++p->cnt;
234 			break;
235 		}
236 }
237 
238 shostats()
239 {
240 	register ID *p;
241 	register mode_t cnt;
242 	register u_long max;
243 
244 	for (max = 0, cnt = 0777; cnt; --cnt)
245 		if (dmodes[cnt] > max) {
246 			max = dmodes[cnt];
247 			dmode = cnt;
248 		}
249 	(void)printf("/set dmode=%o\n", dmode);
250 	for (max = 0, cnt = 0777; cnt; --cnt)
251 		if (fmodes[cnt] > max) {
252 			max = dmodes[cnt];
253 			fmode = cnt;
254 		}
255 	(void)printf("/set fmode=%o\n", fmode);
256 	for (max = 0, p = uhead; p; p = p->next)
257 		if (p->cnt > max) {
258 			max = p->cnt;
259 			uid = p->id;
260 		}
261 	(void)printf("/set owner=%u\n", uid);
262 	for (max = 0, p = ghead; p; p = p->next)
263 		if (p->cnt > max) {
264 			max = p->cnt;
265 			gid = p->id;
266 		}
267 	(void)printf("/set group=%u\n", gid);
268 	(void)printf("/set nlink=1\n");
269 	if (dflag) {
270 		type = F_DIR;
271 		(void)printf("/set type=dir\n\n");
272 	} else {
273 		type = F_FILE;
274 		(void)printf("/set type=file\n\n");
275 	}
276 }
277