xref: /original-bsd/usr.sbin/mtree/mtree.c (revision b485b642)
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 char copyright[] =
20 "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)mtree.c	5.3 (Berkeley) 09/06/89";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <dirent.h>
31 #include <stdio.h>
32 #include <strings.h>
33 #include "mtree.h"
34 
35 extern int errno;
36 ENTRY *root;
37 dev_t device;
38 int cflag, dflag, eflag, rflag, uflag, xflag, exitval;
39 char path[MAXPATHLEN];
40 
41 main(argc, argv)
42 	int argc;
43 	char **argv;
44 {
45 	extern char *optarg;
46 	struct stat sbuf;
47 	int ch;
48 	char *p;
49 
50 	p = NULL;
51 	while ((ch = getopt(argc, argv, "cdef:p:rux")) != EOF)
52 		switch((char)ch) {
53 		case 'c':
54 			cflag = 1;
55 			break;
56 		case 'd':
57 			dflag = 1;
58 			break;
59 		case 'e':
60 			eflag = 1;
61 			break;
62 		case 'f':
63 			if (!(freopen(optarg, "r", stdin))) {
64 				(void)fprintf(stderr,
65 				    "mtree: can't read %s.\n", optarg);
66 				exit(1);
67 			}
68 			break;
69 		case 'p':
70 			p = optarg;
71 			break;
72 		case 'r':
73 			rflag = 1;
74 			break;
75 		case 'u':
76 			uflag = 1;
77 			break;
78 		case 'x':
79 			xflag = 1;
80 			break;
81 		case '?':
82 		default:
83 			(void)fprintf(stderr,
84 			    "usage: mtree [-cderux] [-p path] [-f spec]\n");
85 			exit(1);
86 		}
87 	if (!cflag)
88 		spec();
89 	if (p && chdir(p)) {
90 		(void)fprintf(stderr,
91 		    "mtree: %s: %s\n", p, strerror(errno));
92 		exit(1);
93 	}
94 	path[0] = '.';
95 	if (cflag) {
96 		headers();
97 		cwalk((ENTRY *)NULL, path + 1);
98 		shostats();
99 		pwalk(root, 0);
100 	} else {
101 		if (xflag) {
102 			if (lstat(".", &sbuf)) {
103 				(void)fprintf(stderr, "mtree: root: %s\n",
104 				    strerror(errno));
105 				exit(1);
106 			}
107 			device = sbuf.st_dev;
108 		}
109 		vwalk(root, path + 1);
110 		miss(root, path + 1);
111 	}
112 	exit(exitval);
113 }
114 
115 vwalk(level, tail)
116 	register ENTRY *level;
117 	register char *tail;
118 {
119 	register ENTRY *ep;
120 	register DIR *dirp;
121 	register struct dirent *dp;
122 	struct stat sbuf;
123 
124 	if (!(dirp = opendir("."))) {
125 		(void)fprintf(stderr, "mtree: %s: %s\n",
126 		    level == root ? "root" : path, strerror(errno));
127 		exit(1);
128 	}
129 	*tail++ = '/';
130 	while ((dp = readdir(dirp))) {
131 		if (dp->d_name[0] == '.' &&
132 		    (!dp->d_name[1] || dp->d_name[1] == '.' && !dp->d_name[2]))
133 			continue;
134 		bcopy(dp->d_name, tail, dp->d_namlen + 1);
135 		for (ep = level; ep; ep = ep->next)
136 			if (!strcmp(ep->name, dp->d_name))
137 				break;
138 		if (ep && ep->flags&F_IGN) {
139 			ep->flags |= F_VISIT;
140 			continue;
141 		}
142 		if (lstat(dp->d_name, &sbuf)) {
143 			(void)fprintf(stderr, "mtree: %s: %s\n",
144 			    path + 2, strerror(errno));
145 			exit(1);
146 		}
147 		if (!dflag || S_ISDIR(sbuf.st_mode))
148 			if (ep) {
149 				compare(ep->name, &ep->info, &sbuf);
150 				ep->flags |= F_VISIT;
151 			} else if (!eflag) {
152 				(void)printf("extra: %s%s",
153 				    path + 2, rflag ? "" : "\n");
154 				if (rflag)
155 					if (unlink(path))
156 					    (void)printf(", not removed: %s\n",
157 						strerror(errno));
158 					else
159 					    (void)printf(", removed\n");
160 			}
161 		if (S_ISDIR(sbuf.st_mode) &&
162 		    (!xflag || device == sbuf.st_dev)) {
163 			if (chdir(dp->d_name)) {
164 				(void)fprintf(stderr, "mtree: %s: %s\n",
165 				    path + 2, strerror(errno));
166 				exit(1);
167 			}
168 			vwalk(ep ? ep->child : ep, tail + dp->d_namlen);
169 			if (chdir("..")) {
170 				(void)fprintf(stderr, "mtree: ..: %s\n",
171 				    strerror(errno));
172 				exit(1);
173 			}
174 		}
175 	}
176 	(void)closedir(dirp);
177 }
178 
179 miss(level, tail)
180 	register ENTRY *level;
181 	register char *tail;
182 {
183 	register int create;
184 	register char *p;
185 
186 	for (*tail++ = '/'; level; level = level->next) {
187 		if (level->info.type != F_DIR &&
188 			(dflag || level->flags&F_VISIT))
189 				continue;
190 		(void)strcpy(tail, level->name);
191 		if (!(level->flags&F_VISIT))
192 			(void)printf("missing: %s%s", path + 2,
193 			    uflag ? "" : "\n");
194 		if (level->info.type != F_DIR)
195 			continue;
196 		create = 0;
197 		if (uflag)
198 			if (mkdir(path, 0777))
199 				(void)printf(" (not created: %s)\n",
200 				    strerror(errno));
201 			else {
202 				create = 1;
203 				(void)printf(" (created)\n");
204 			}
205 		for (p = tail; *p; ++p);
206 		miss(level->child, p);
207 		if (create) {
208 			*p = '\0';
209 			dirset(&level->info);
210 		}
211 	}
212 }
213 
214 dirset(s1)
215 	register INFO *s1;
216 {
217 	extern int errno;
218 	register struct stat *s2;
219 	struct stat sbuf;
220 
221 	if (stat(path, &sbuf)) {
222 		(void)fprintf(stderr,
223 		    "mtree: %s: %s\n", path, strerror(errno));
224 		return;
225 	}
226 	s2 = &sbuf;
227 
228 	if (s1->flags&F_MODE && s1->st_mode != (s2->st_mode&07777) &&
229 	    chmod(path, s1->st_mode))
230 		(void)printf("%s: permissions not set: %s\n",
231 		    path + 2, strerror(errno));
232 	if (s1->flags&F_OWNER && s1->st_uid != s2->st_uid &&
233 	    chown(path, s1->st_uid, -1))
234 		(void)printf("%s: owner not modified: %s\n",
235 		    path + 2, strerror(errno));
236 	if (s1->flags&F_GROUP && s1->st_gid != s2->st_gid &&
237 	    chown(path, -1, s1->st_gid))
238 		(void)printf("%s: group not modified: %s\n",
239 		    path + 2, strerror(errno));
240 }
241