[project @ 2000-03-01 18:38:45 by keithw]
[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 int force=0;
86
87 void
88 quit (
89 #if NeedVarargsPrototypes
90     int code, char * fmt, ...)
91 #else
92     code, fmt, a1, a2, a3)
93     char *fmt;
94 #endif
95 {
96 #if NeedVarargsPrototypes
97     va_list args;
98     va_start(args, fmt);
99     vfprintf (stderr, fmt, args);
100     va_end(args);
101 #else
102     fprintf (stderr, fmt, a1, a2, a3);
103 #endif
104     putc ('\n', stderr);
105     exit (code);
106 }
107
108 void
109 quiterr (code, s)
110     char *s;
111 {
112     perror (s);
113     exit (code);
114 }
115
116 void
117 msg (
118 #if NeedVarargsPrototypes
119     char * fmt, ...)
120 #else
121     fmt, a1, a2, a3)
122     char *fmt;
123 #endif
124 {
125 #if NeedVarargsPrototypes
126     va_list args;
127 #endif
128     if (curdir) {
129         fprintf (stderr, "%s:\n", curdir);
130         curdir = 0;
131     }
132 #if NeedVarargsPrototypes
133     va_start(args, fmt);
134     vfprintf (stderr, fmt, args);
135     va_end(args);
136 #else
137     fprintf (stderr, fmt, a1, a2, a3);
138 #endif
139     putc ('\n', stderr);
140 }
141
142 void
143 mperror (s)
144     char *s;
145 {
146     if (curdir) {
147         fprintf (stderr, "%s:\n", curdir);
148         curdir = 0;
149     }
150     perror (s);
151 }
152
153
154 int equivalent(lname, rname)
155     char *lname;
156     char *rname;
157 {
158     char *s;
159
160     if (!strcmp(lname, rname))
161         return 1;
162     for (s = lname; *s && (s = strchr(s, '/')); s++) {
163         while (s[1] == '/')
164             strcpy(s+1, s+2);
165     }
166     return !strcmp(lname, rname);
167 }
168
169
170 /* Recursively create symbolic links from the current directory to the "from"
171    directory.  Assumes that files described by fs and ts are directories. */
172
173 dodir (fn, fs, ts, rel)
174 char *fn;                       /* name of "from" directory, either absolute or
175                                    relative to cwd */
176 struct stat *fs, *ts;           /* stats for the "from" directory and cwd */
177 int rel;                        /* if true, prepend "../" to fn before using */
178 {
179     DIR *df;
180     struct dirent *dp;
181     char buf[MAXPATHLEN + 1], *p;
182     char symbuf[MAXPATHLEN + 1];
183     char basesym[MAXPATHLEN + 1];
184     struct stat sb, sc;
185     int n_dirs;
186     int symlen;
187     int basesymlen = -1;
188     char *ocurdir;
189
190     if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
191         msg ("%s: From and to directories are identical!", fn);
192         return 1;
193     }
194
195     if (rel)
196         strcpy (buf, "../");
197     else
198         buf[0] = '\0';
199     strcat (buf, fn);
200     
201     if (!(df = opendir (buf))) {
202         msg ("%s: Cannot opendir", buf);
203         return 1;
204     }
205
206     p = buf + strlen (buf);
207     *p++ = '/';
208     n_dirs = fs->st_nlink;
209     while (dp = readdir (df)) {
210         if (dp->d_name[strlen(dp->d_name) - 1] == '~')
211             continue;
212         if (dp->d_name[0] == '.' && dp->d_name[1] == '#') /* 'non-conflict files' left behind by CVS */
213             continue;
214         strcpy (p, dp->d_name);
215
216         if (n_dirs > 0) {
217             if (stat (buf, &sb) < 0) {
218                 mperror (buf);
219                 continue;
220             }
221
222 #ifdef S_ISDIR
223             if(S_ISDIR(sb.st_mode))
224 #else
225             if (sb.st_mode & S_IFDIR) 
226 #endif
227             {
228                 /* directory */
229                 n_dirs--;
230                 if (dp->d_name[0] == '.' &&
231                     (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
232                                                dp->d_name[2] == '\0')))
233                     continue;
234                 if (!strcmp (dp->d_name, "RCS"))
235                     continue;
236                 if (!strcmp (dp->d_name, "SCCS"))
237                     continue;
238                 if (!strcmp (dp->d_name, "CVS"))
239                     continue;
240                 if (!strcmp (dp->d_name, "CVS.adm"))
241                     continue;
242                 ocurdir = rcurdir;
243                 rcurdir = buf;
244                 curdir = silent ? buf : (char *)0;
245                 if (!silent)
246                     printf ("%s:\n", buf);
247                 if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
248                     if (mkdir (dp->d_name, 0777) < 0 ||
249                         stat (dp->d_name, &sc) < 0) {
250                         mperror (dp->d_name);
251                         curdir = rcurdir = ocurdir;
252                         continue;
253                     }
254                 }
255                 if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
256                     msg ("%s: is a link instead of a directory", dp->d_name);
257                     curdir = rcurdir = ocurdir;
258                     continue;
259                 }
260                 if (chdir (dp->d_name) < 0) {
261                     mperror (dp->d_name);
262                     curdir = rcurdir = ocurdir;
263                     continue;
264                 }
265                 dodir (buf, &sb, &sc, (buf[0] != '/'));
266                 if (chdir ("..") < 0)
267                     quiterr (1, "..");
268                 curdir = rcurdir = ocurdir;
269                 continue;
270             }
271         }
272
273         /* non-directory */
274         symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
275         if (symlen >= 0)
276             symbuf[symlen] = '\0';
277
278         /* The option to ignore links exists mostly because
279            checking for them slows us down by 10-20%.
280            But it is off by default because this really is a useful check. */
281         if (!ignore_links) {
282             /* see if the file in the base tree was a symlink */
283             basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
284             if (basesymlen >= 0)
285                 basesym[basesymlen] = '\0';
286         }
287
288         if (symlen >= 0) {
289           if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) {
290             if (force) {
291               unlink(dp->d_name);
292               if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
293                 mperror (dp->d_name);
294             } else {
295               /* Link exists in new tree.  Print message if it doesn't match. */
296               msg ("%s: %s", dp->d_name, symbuf);
297             }
298           }
299         } else {
300           if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
301             mperror (dp->d_name);
302         }
303     }
304     
305     closedir (df);
306     return 0;
307 }
308
309
310 main (ac, av)
311 int ac;
312 char **av;
313 {
314     char *prog_name = av[0];
315     char *fn, *tn;
316     struct stat fs, ts;
317
318     while (++av, --ac) {
319         if (strcmp(*av, "-silent") == 0)
320             silent = 1;
321         if (strcmp(*av, "-f") == 0)
322             force = 1;
323         else if (strcmp(*av, "-ignorelinks") == 0)
324             ignore_links = 1;
325         else if (strcmp(*av, "--") == 0) {
326             ++av, --ac;
327             break;
328         }
329         else
330             break;
331     }
332
333     if (ac < 1 || ac > 2)
334         quit (1, "usage: %s [-f] [-silent] [-ignorelinks] fromdir [todir]",
335               prog_name);
336
337     fn = av[0];
338     if (ac == 2)
339         tn = av[1];
340     else
341         tn = ".";
342
343     /* to directory */
344     if (stat (tn, &ts) < 0) {
345       if (force && (tn[0] != '.' || tn[1] != '\0') ) {
346          mkdir(tn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
347       } 
348       else {
349         quiterr (1, tn);
350 #ifdef S_ISDIR
351         if (!(S_ISDIR(ts.st_mode)))
352 #else
353         if (!(ts.st_mode & S_IFDIR))
354 #endif
355            quit (2, "%s: Not a directory", tn);
356       }
357     }
358     if (chdir (tn) < 0)
359         quiterr (1, tn);
360
361     /* from directory */
362     if (stat (fn, &fs) < 0)
363         quiterr (1, fn);
364 #ifdef S_ISDIR
365     if (!(S_ISDIR(fs.st_mode)))
366 #else
367     if (!(fs.st_mode & S_IFDIR))
368 #endif
369         quit (2, "%s: Not a directory", fn);
370
371     exit (dodir (fn, &fs, &ts, 0));
372 }