0d77a49ebe668656481a8240ca58ec33a91aefd7
[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         if (dp->d_name[0] == '.' && dp->d_name[1] == '#') /* 'non-conflict files' left behind by CVS */
211             continue;
212         strcpy (p, dp->d_name);
213
214         if (n_dirs > 0) {
215             if (stat (buf, &sb) < 0) {
216                 mperror (buf);
217                 continue;
218             }
219
220 #ifdef S_ISDIR
221             if(S_ISDIR(sb.st_mode))
222 #else
223             if (sb.st_mode & S_IFDIR) 
224 #endif
225             {
226                 /* directory */
227                 n_dirs--;
228                 if (dp->d_name[0] == '.' &&
229                     (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
230                                                dp->d_name[2] == '\0')))
231                     continue;
232                 if (!strcmp (dp->d_name, "RCS"))
233                     continue;
234                 if (!strcmp (dp->d_name, "SCCS"))
235                     continue;
236                 if (!strcmp (dp->d_name, "CVS"))
237                     continue;
238                 if (!strcmp (dp->d_name, "CVS.adm"))
239                     continue;
240                 ocurdir = rcurdir;
241                 rcurdir = buf;
242                 curdir = silent ? buf : (char *)0;
243                 if (!silent)
244                     printf ("%s:\n", buf);
245                 if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
246                     if (mkdir (dp->d_name, 0777) < 0 ||
247                         stat (dp->d_name, &sc) < 0) {
248                         mperror (dp->d_name);
249                         curdir = rcurdir = ocurdir;
250                         continue;
251                     }
252                 }
253                 if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
254                     msg ("%s: is a link instead of a directory", dp->d_name);
255                     curdir = rcurdir = ocurdir;
256                     continue;
257                 }
258                 if (chdir (dp->d_name) < 0) {
259                     mperror (dp->d_name);
260                     curdir = rcurdir = ocurdir;
261                     continue;
262                 }
263                 dodir (buf, &sb, &sc, (buf[0] != '/'));
264                 if (chdir ("..") < 0)
265                     quiterr (1, "..");
266                 curdir = rcurdir = ocurdir;
267                 continue;
268             }
269         }
270
271         /* non-directory */
272         symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
273         if (symlen >= 0)
274             symbuf[symlen] = '\0';
275
276         /* The option to ignore links exists mostly because
277            checking for them slows us down by 10-20%.
278            But it is off by default because this really is a useful check. */
279         if (!ignore_links) {
280             /* see if the file in the base tree was a symlink */
281             basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
282             if (basesymlen >= 0)
283                 basesym[basesymlen] = '\0';
284         }
285
286         if (symlen >= 0) {
287             /* Link exists in new tree.  Print message if it doesn't match. */
288             if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf))
289                 msg ("%s: %s", dp->d_name, symbuf);
290         } else {
291             if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
292                 mperror (dp->d_name);
293         }
294     }
295
296     closedir (df);
297     return 0;
298 }
299
300
301 main (ac, av)
302 int ac;
303 char **av;
304 {
305     char *prog_name = av[0];
306     char *fn, *tn;
307     struct stat fs, ts;
308
309     while (++av, --ac) {
310         if (strcmp(*av, "-silent") == 0)
311             silent = 1;
312         else if (strcmp(*av, "-ignorelinks") == 0)
313             ignore_links = 1;
314         else if (strcmp(*av, "--") == 0) {
315             ++av, --ac;
316             break;
317         }
318         else
319             break;
320     }
321
322     if (ac < 1 || ac > 2)
323         quit (1, "usage: %s [-silent] [-ignorelinks] fromdir [todir]",
324               prog_name);
325
326     fn = av[0];
327     if (ac == 2)
328         tn = av[1];
329     else
330         tn = ".";
331
332     /* to directory */
333     if (stat (tn, &ts) < 0)
334         quiterr (1, tn);
335 #ifdef S_ISDIR
336     if (!(S_ISDIR(ts.st_mode)))
337 #else
338     if (!(ts.st_mode & S_IFDIR))
339 #endif
340         quit (2, "%s: Not a directory", tn);
341     if (chdir (tn) < 0)
342         quiterr (1, tn);
343
344     /* from directory */
345     if (stat (fn, &fs) < 0)
346         quiterr (1, fn);
347 #ifdef S_ISDIR
348     if (!(S_ISDIR(fs.st_mode)))
349 #else
350     if (!(fs.st_mode & S_IFDIR))
351 #endif
352         quit (2, "%s: Not a directory", fn);
353
354     exit (dodir (fn, &fs, &ts, 0));
355 }