Annotation of src/usr.bin/lndir/lndir.c, Revision 1.2
1.2 ! downsj 1: /* $OpenBSD: lndir.c,v 1.1 1996/08/19 05:47:26 downsj Exp $ */
1.1 downsj 2: /* $XConsortium: lndir.c /main/15 1995/08/30 10:56:18 gildea $ */
3: /* Create shadow link tree (after X11R4 script of the same name)
4: Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */
5:
6: /*
7: Copyright (c) 1990, X Consortium
8:
9: Permission is hereby granted, free of charge, to any person obtaining a copy
10: of this software and associated documentation files (the "Software"), to deal
11: in the Software without restriction, including without limitation the rights
12: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13: copies of the Software, and to permit persons to whom the Software is
14: furnished to do so, subject to the following conditions:
15:
16: The above copyright notice and this permission notice shall be included in
17: all copies or substantial portions of the Software.
18:
19: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22: X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23: AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25:
26: Except as contained in this notice, the name of the X Consortium shall not be
27: used in advertising or otherwise to promote the sale, use or other dealings
28: in this Software without prior written authorization from the X Consortium.
29:
30: */
31:
32: /* From the original /bin/sh script:
33:
34: Used to create a copy of the a directory tree that has links for all
35: non-directories (except those named RCS, SCCS or CVS.adm). If you are
36: building the distribution on more than one machine, you should use
37: this technique.
38:
39: If your master sources are located in /usr/local/src/X and you would like
40: your link tree to be in /usr/local/src/new-X, do the following:
41:
42: % mkdir /usr/local/src/new-X
43: % cd /usr/local/src/new-X
44: % lndir ../X
45: */
46:
47: #include <stdio.h>
48: #include <sys/types.h>
49: #include <sys/stat.h>
50: #include <sys/param.h>
51: #include <errno.h>
52: #include <dirent.h>
53: #include <stdarg.h>
54: #include <string.h>
55:
56: int silent = 0; /* -silent */
57: int ignore_links = 0; /* -ignorelinks */
58:
59: char *rcurdir;
60: char *curdir;
61:
62: struct except {
63: char *name;
64:
65: struct except *next;
66: };
67: struct except *exceptions = (struct except *)NULL;
68:
69: void
70: quit (int code, char * fmt, ...)
71: {
72: va_list args;
73: va_start(args, fmt);
74: vfprintf (stderr, fmt, args);
75: va_end(args);
76: putc ('\n', stderr);
77: exit (code);
78: }
79:
80: void
81: quiterr (code, s)
82: char *s;
83: {
84: perror (s);
85: exit (code);
86: }
87:
88: void
89: msg (char * fmt, ...)
90: {
91: va_list args;
92: if (curdir) {
93: fprintf (stderr, "%s:\n", curdir);
94: curdir = 0;
95: }
96: va_start(args, fmt);
97: vfprintf (stderr, fmt, args);
98: va_end(args);
99: putc ('\n', stderr);
100: }
101:
102: void
103: mperror (s)
104: char *s;
105: {
106: if (curdir) {
107: fprintf (stderr, "%s:\n", curdir);
108: curdir = 0;
109: }
110: perror (s);
111: }
112:
113:
114: int equivalent(lname, rname)
115: char *lname;
116: char *rname;
117: {
118: char *s;
119:
120: if (!strcmp(lname, rname))
121: return 1;
122: for (s = lname; *s && (s = strchr(s, '/')); s++) {
123: while (s[1] == '/')
124: strcpy(s+1, s+2);
125: }
126: return !strcmp(lname, rname);
127: }
128:
129:
130: addexcept(name)
131: char *name;
132: {
133: struct except *new;
134:
135: new = (struct except *)malloc(sizeof(struct except));
136: if (new == (struct except *)NULL)
137: quiterr(1, "addexcept");
138: new->name = strdup(name);
139: if (new->name == (char *)NULL)
140: quiterr(1, "addexcept");
141:
142: new->next = exceptions;
143: exceptions = new;
144: }
145:
146:
147: /* Recursively create symbolic links from the current directory to the "from"
148: directory. Assumes that files described by fs and ts are directories. */
149:
150: dodir (fn, fs, ts, rel)
151: char *fn; /* name of "from" directory, either absolute or
152: relative to cwd */
153: struct stat *fs, *ts; /* stats for the "from" directory and cwd */
154: int rel; /* if true, prepend "../" to fn before using */
155: {
156: DIR *df;
157: struct dirent *dp;
158: char buf[MAXPATHLEN + 1], *p;
159: char symbuf[MAXPATHLEN + 1];
160: char basesym[MAXPATHLEN + 1];
161: struct stat sb, sc;
162: int n_dirs;
163: int symlen;
164: int basesymlen = -1;
165: char *ocurdir;
166: struct except *cur;
167:
168: if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
169: msg ("%s: From and to directories are identical!", fn);
170: return 1;
171: }
172:
173: if (rel)
174: strcpy (buf, "../");
175: else
176: buf[0] = '\0';
177: strcat (buf, fn);
178:
179: if (!(df = opendir (buf))) {
180: msg ("%s: Cannot opendir", buf);
181: return 1;
182: }
183:
184: p = buf + strlen (buf);
185: *p++ = '/';
186: n_dirs = fs->st_nlink;
187: while (dp = readdir (df)) {
188: if (dp->d_name[strlen(dp->d_name) - 1] == '~')
189: continue;
190: strcpy (p, dp->d_name);
191:
192: if (n_dirs > 0) {
193: if (stat (buf, &sb) < 0) {
194: mperror (buf);
195: continue;
196: }
197:
198: if(S_ISDIR(sb.st_mode)) {
199: /* directory */
200: n_dirs--;
201: if (dp->d_name[0] == '.' &&
202: (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
203: dp->d_name[2] == '\0')))
204: continue;
205: for (cur = exceptions; cur != (struct except *)NULL;
206: cur = cur->next) {
207: if (!strcmp (dp->d_name, cur->name))
208: goto next; /* can't continue */
209: }
210: if (!strcmp (dp->d_name, "RCS"))
211: continue;
212: if (!strcmp (dp->d_name, "SCCS"))
213: continue;
214: if (!strcmp (dp->d_name, "CVS"))
215: continue;
216: if (!strcmp (dp->d_name, "CVS.adm"))
217: continue;
218: ocurdir = rcurdir;
219: rcurdir = buf;
220: curdir = silent ? buf : (char *)0;
221: if (!silent)
222: printf ("%s:\n", buf);
223: if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
224: if (mkdir (dp->d_name, 0777) < 0 ||
225: stat (dp->d_name, &sc) < 0) {
226: mperror (dp->d_name);
227: curdir = rcurdir = ocurdir;
228: continue;
229: }
230: }
231: if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
232: msg ("%s: is a link instead of a directory", dp->d_name);
233: curdir = rcurdir = ocurdir;
234: continue;
235: }
236: if (chdir (dp->d_name) < 0) {
237: mperror (dp->d_name);
238: curdir = rcurdir = ocurdir;
239: continue;
240: }
241: dodir (buf, &sb, &sc, (buf[0] != '/'));
242: if (chdir ("..") < 0)
243: quiterr (1, "..");
244: curdir = rcurdir = ocurdir;
245: continue;
246: }
247: }
248:
249: /* non-directory */
250: symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
251: if (symlen >= 0)
252: symbuf[symlen] = '\0';
253:
254: /* The option to ignore links exists mostly because
255: checking for them slows us down by 10-20%.
256: But it is off by default because this really is a useful check. */
257: if (!ignore_links) {
258: /* see if the file in the base tree was a symlink */
259: basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
260: if (basesymlen >= 0)
261: basesym[basesymlen] = '\0';
262: }
263:
264: if (symlen >= 0) {
265: /* Link exists in new tree. Print message if it doesn't match. */
266: if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
267: msg ("%s: %s", dp->d_name, symbuf);
268: } else {
269: if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
270: mperror (dp->d_name);
271: }
272: next:
273: }
274:
275: closedir (df);
276: return 0;
277: }
278:
279:
280: main (ac, av)
281: int ac;
282: char **av;
283: {
284: char *prog_name = av[0];
285: char *fn, *tn;
286: struct stat fs, ts;
287:
288: while (++av, --ac) {
289: if ((strcmp(*av, "-silent") == 0) || (strcmp(*av, "-s") == 0))
290: silent = 1;
291: else if ((strcmp(*av, "-ignorelinks") == 0) || (strcmp(*av, "-i") == 0))
292: ignore_links = 1;
293: else if (strcmp(*av, "-e") == 0) {
294: ++av, --ac;
295:
296: if (ac < 2)
297: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
298: prog_name);
299: addexcept(*av);
300: }
301: else if (strcmp(*av, "--") == 0) {
302: ++av, --ac;
303: break;
304: }
305: else
306: break;
307: }
308:
309: if (ac < 1 || ac > 2)
310: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
311: prog_name);
312:
313: fn = av[0];
314: if (ac == 2)
315: tn = av[1];
316: else
317: tn = ".";
318:
319: /* to directory */
320: if (stat (tn, &ts) < 0)
321: quiterr (1, tn);
322: if (!(S_ISDIR(ts.st_mode)))
323: quit (2, "%s: Not a directory", tn);
324: if (chdir (tn) < 0)
325: quiterr (1, tn);
326:
327: /* from directory */
328: if (stat (fn, &fs) < 0)
329: quiterr (1, fn);
330: if (!(S_ISDIR(fs.st_mode)))
331: quit (2, "%s: Not a directory", fn);
332:
333: exit (dodir (fn, &fs, &ts, 0));
334: }