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