[project @ 2005-12-15 10:36:03 by simonmar]
[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, "_darcs"))
249                     continue;
250                 if (!strcmp (dp->d_name, "CVS.adm"))
251                     continue;
252                 ocurdir = rcurdir;
253                 rcurdir = buf;
254                 curdir = silent ? buf : (char *)0;
255                 if (!silent)
256                     printf ("%s:\n", buf);
257                 if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
258                     if (mkdir (dp->d_name, 0777) < 0 ||
259                         stat (dp->d_name, &sc) < 0) {
260                         mperror (dp->d_name);
261                         curdir = rcurdir = ocurdir;
262                         continue;
263                     }
264                 }
265                 if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
266                     msg ("%s: is a link instead of a directory", dp->d_name);
267                     curdir = rcurdir = ocurdir;
268                     continue;
269                 }
270                 if (chdir (dp->d_name) < 0) {
271                     mperror (dp->d_name);
272                     curdir = rcurdir = ocurdir;
273                     continue;
274                 }
275                 dodir (buf, &sb, &sc, (buf[0] != '/'));
276                 if (chdir ("..") < 0)
277                     quiterr (1, "..");
278                 curdir = rcurdir = ocurdir;
279                 continue;
280             }
281         }
282
283         /* non-directory */
284         symlen = readlink (dp->d_name, symbuf, sizeof(symbuf) - 1);
285         if (symlen >= 0)
286             symbuf[symlen] = '\0';
287
288         /* The option to ignore links exists mostly because
289            checking for them slows us down by 10-20%.
290            But it is off by default because this really is a useful check. */
291         if (!ignore_links) {
292             /* see if the file in the base tree was a symlink */
293             basesymlen = readlink(buf, basesym, sizeof(basesym) - 1);
294             if (basesymlen >= 0)
295                 basesym[basesymlen] = '\0';
296         }
297
298         if (symlen >= 0) {
299           if (!equivalent (basesymlen>=0 ? basesym : buf, symbuf)) {
300             if (force) {
301               unlink(dp->d_name);
302               if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
303                 mperror (dp->d_name);
304             } else {
305               /* Link exists in new tree.  Print message if it doesn't match. */
306               msg ("%s: %s", dp->d_name, symbuf);
307             }
308           }
309         } else {
310           if (symlink (basesymlen>=0 ? basesym : buf, dp->d_name) < 0)
311             mperror (dp->d_name);
312         }
313     }
314     
315     closedir (df);
316     return 0;
317 }
318
319
320 main (ac, av)
321 int ac;
322 char **av;
323 {
324     char *prog_name = av[0];
325     char* tn;
326     struct stat fs, ts;
327 #ifdef __CYGWIN32__
328     /*   
329     The lndir code assumes unix-style paths to work. cygwin
330     lets you get away with using dos'ish paths (e.g., "f:/oo")
331     in most contexts. Using them with 'lndir' will seriously
332     confuse the user though, so under-the-hood, we convert the
333     path into something POSIX-like.
334     */
335     static char fn[MAXPATHLEN+1];
336 #else
337     char *fn;
338 #endif
339
340     while (++av, --ac) {
341       if (strcmp(*av, "-silent") == 0)
342           silent = 1;
343       else if (strcmp(*av, "-f") == 0)
344           force = 1;
345       else if (strcmp(*av, "-ignorelinks") == 0)
346           ignore_links = 1;
347       else if (strcmp(*av, "--") == 0) {
348           ++av, --ac;
349           break;
350       } else
351           break;
352     }
353
354     if (ac < 1 || ac > 2)
355         quit (1, "usage: %s [-f] [-silent] [-ignorelinks] fromdir [todir]",
356               prog_name);
357
358 #ifdef __CYGWIN32__
359     cygwin_conv_to_full_posix_path(av[0], fn);
360 #else
361     fn = av[0];
362 #endif
363
364     if (ac == 2)
365         tn = av[1];
366     else
367         tn = ".";
368
369     /* to directory */
370     if (stat (tn, &ts) < 0) {
371       if (force && (tn[0] != '.' || tn[1] != '\0') ) {
372          mkdir(tn, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH );
373       } 
374       else {
375         quiterr (1, tn);
376 #ifdef S_ISDIR
377         if (!(S_ISDIR(ts.st_mode)))
378 #else
379         if (!(ts.st_mode & S_IFDIR))
380 #endif
381            quit (2, "%s: Not a directory", tn);
382       }
383     }
384     if (chdir (tn) < 0)
385         quiterr (1, tn);
386
387     /* from directory */
388     if (stat (fn, &fs) < 0)
389         quiterr (1, fn);
390 #ifdef S_ISDIR
391     if (!(S_ISDIR(fs.st_mode)))
392 #else
393     if (!(fs.st_mode & S_IFDIR))
394 #endif
395         quit (2, "%s: Not a directory", fn);
396
397     exit (dodir (fn, &fs, &ts, 0));
398 }