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