Annotation of src/usr.bin/lndir/lndir.c, Revision 1.4
1.4 ! niklas 1: /* $OpenBSD: lndir.c,v 1.3 1996/08/19 06:50:16 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>
1.4 ! niklas 48: #include <stdlib.h>
1.1 downsj 49: #include <sys/types.h>
50: #include <sys/stat.h>
51: #include <sys/param.h>
52: #include <errno.h>
53: #include <dirent.h>
54: #include <stdarg.h>
55: #include <string.h>
56:
57: int silent = 0; /* -silent */
58: int ignore_links = 0; /* -ignorelinks */
59:
60: char *rcurdir;
61: char *curdir;
62:
63: struct except {
64: char *name;
65:
66: struct except *next;
67: };
68: struct except *exceptions = (struct except *)NULL;
69:
70: void
71: quit (int code, char * fmt, ...)
72: {
73: va_list args;
74: va_start(args, fmt);
75: vfprintf (stderr, fmt, args);
76: va_end(args);
77: putc ('\n', stderr);
78: exit (code);
79: }
80:
81: void
82: quiterr (code, s)
83: char *s;
84: {
85: perror (s);
86: exit (code);
87: }
88:
89: void
90: msg (char * fmt, ...)
91: {
92: va_list args;
93: if (curdir) {
94: fprintf (stderr, "%s:\n", curdir);
95: curdir = 0;
96: }
97: va_start(args, fmt);
98: vfprintf (stderr, fmt, args);
99: va_end(args);
100: putc ('\n', stderr);
101: }
102:
103: void
104: mperror (s)
105: char *s;
106: {
107: if (curdir) {
108: fprintf (stderr, "%s:\n", curdir);
109: curdir = 0;
110: }
111: perror (s);
112: }
113:
114:
115: int equivalent(lname, rname)
116: char *lname;
117: char *rname;
118: {
119: char *s;
120:
121: if (!strcmp(lname, rname))
122: return 1;
123: for (s = lname; *s && (s = strchr(s, '/')); s++) {
124: while (s[1] == '/')
125: strcpy(s+1, s+2);
126: }
127: return !strcmp(lname, rname);
128: }
129:
130:
131: addexcept(name)
132: char *name;
133: {
134: struct except *new;
135:
136: new = (struct except *)malloc(sizeof(struct except));
137: if (new == (struct except *)NULL)
138: quiterr(1, "addexcept");
139: new->name = strdup(name);
140: if (new->name == (char *)NULL)
141: quiterr(1, "addexcept");
142:
143: new->next = exceptions;
144: exceptions = new;
145: }
146:
147:
148: /* Recursively create symbolic links from the current directory to the "from"
149: directory. Assumes that files described by fs and ts are directories. */
150:
151: dodir (fn, fs, ts, rel)
152: char *fn; /* name of "from" directory, either absolute or
153: relative to cwd */
154: struct stat *fs, *ts; /* stats for the "from" directory and cwd */
155: int rel; /* if true, prepend "../" to fn before using */
156: {
157: DIR *df;
158: struct dirent *dp;
159: char buf[MAXPATHLEN + 1], *p;
160: char symbuf[MAXPATHLEN + 1];
161: char basesym[MAXPATHLEN + 1];
162: struct stat sb, sc;
163: int n_dirs;
164: int symlen;
165: int basesymlen = -1;
166: char *ocurdir;
167: struct except *cur;
168:
169: if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
170: msg ("%s: From and to directories are identical!", fn);
171: return 1;
172: }
173:
174: if (rel)
175: strcpy (buf, "../");
176: else
177: buf[0] = '\0';
178: strcat (buf, fn);
179:
180: if (!(df = opendir (buf))) {
181: msg ("%s: Cannot opendir", buf);
182: return 1;
183: }
184:
185: p = buf + strlen (buf);
186: *p++ = '/';
187: n_dirs = fs->st_nlink;
188: while (dp = readdir (df)) {
189: if (dp->d_name[strlen(dp->d_name) - 1] == '~')
190: continue;
1.3 downsj 191: for (cur = exceptions; cur != (struct except *)NULL;
192: cur = cur->next) {
193: if (!strcmp (dp->d_name, cur->name))
194: goto next; /* can't continue */
195: }
1.1 downsj 196: strcpy (p, dp->d_name);
197:
198: if (n_dirs > 0) {
199: if (stat (buf, &sb) < 0) {
200: mperror (buf);
201: continue;
202: }
203:
204: if(S_ISDIR(sb.st_mode)) {
205: /* directory */
206: n_dirs--;
207: if (dp->d_name[0] == '.' &&
208: (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
209: dp->d_name[2] == '\0')))
210: continue;
211: if (!strcmp (dp->d_name, "RCS"))
212: continue;
213: if (!strcmp (dp->d_name, "SCCS"))
214: continue;
215: if (!strcmp (dp->d_name, "CVS"))
216: continue;
217: if (!strcmp (dp->d_name, "CVS.adm"))
218: continue;
219: ocurdir = rcurdir;
220: rcurdir = buf;
221: curdir = silent ? buf : (char *)0;
222: if (!silent)
223: printf ("%s:\n", buf);
224: if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
225: if (mkdir (dp->d_name, 0777) < 0 ||
226: stat (dp->d_name, &sc) < 0) {
227: mperror (dp->d_name);
228: curdir = rcurdir = ocurdir;
229: continue;
230: }
231: }
232: if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
233: msg ("%s: is a link instead of a directory", dp->d_name);
234: curdir = rcurdir = ocurdir;
235: continue;
236: }
237: if (chdir (dp->d_name) < 0) {
238: mperror (dp->d_name);
239: curdir = rcurdir = ocurdir;
240: continue;
241: }
242: dodir (buf, &sb, &sc, (buf[0] != '/'));
243: if (chdir ("..") < 0)
244: quiterr (1, "..");
245: curdir = rcurdir = ocurdir;
246: continue;
247: }
248: }
249:
250: /* non-directory */
251: symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
252: if (symlen >= 0)
253: symbuf[symlen] = '\0';
254:
255: /* The option to ignore links exists mostly because
256: checking for them slows us down by 10-20%.
257: But it is off by default because this really is a useful check. */
258: if (!ignore_links) {
259: /* see if the file in the base tree was a symlink */
260: basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
261: if (basesymlen >= 0)
262: basesym[basesymlen] = '\0';
263: }
264:
265: if (symlen >= 0) {
266: /* Link exists in new tree. Print message if it doesn't match. */
267: if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
268: msg ("%s: %s", dp->d_name, symbuf);
269: } else {
270: if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
271: mperror (dp->d_name);
272: }
273: next:
274: }
275:
276: closedir (df);
277: return 0;
278: }
279:
280:
281: main (ac, av)
282: int ac;
283: char **av;
284: {
285: char *prog_name = av[0];
286: char *fn, *tn;
287: struct stat fs, ts;
288:
289: while (++av, --ac) {
290: if ((strcmp(*av, "-silent") == 0) || (strcmp(*av, "-s") == 0))
291: silent = 1;
292: else if ((strcmp(*av, "-ignorelinks") == 0) || (strcmp(*av, "-i") == 0))
293: ignore_links = 1;
294: else if (strcmp(*av, "-e") == 0) {
295: ++av, --ac;
296:
297: if (ac < 2)
298: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
299: prog_name);
300: addexcept(*av);
301: }
302: else if (strcmp(*av, "--") == 0) {
303: ++av, --ac;
304: break;
305: }
306: else
307: break;
308: }
309:
310: if (ac < 1 || ac > 2)
311: quit (1, "usage: %s [-e except] [-s] [-i] fromdir [todir]",
312: prog_name);
313:
314: fn = av[0];
315: if (ac == 2)
316: tn = av[1];
317: else
318: tn = ".";
319:
320: /* to directory */
321: if (stat (tn, &ts) < 0)
322: quiterr (1, tn);
323: if (!(S_ISDIR(ts.st_mode)))
324: quit (2, "%s: Not a directory", tn);
325: if (chdir (tn) < 0)
326: quiterr (1, tn);
327:
328: /* from directory */
329: if (stat (fn, &fs) < 0)
330: quiterr (1, fn);
331: if (!(S_ISDIR(fs.st_mode)))
332: quit (2, "%s: Not a directory", fn);
333:
334: exit (dodir (fn, &fs, &ts, 0));
335: }