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