Merge branch 'master' of ssh://git.code.sf.net/p/cdesktopenv/code
[oweals/cde.git] / cde / util / progs / lndir.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: lndir.c /main/2 1996/11/01 10:11:58 drk $ */
24 /* Create shadow link tree (after X11R4 script of the same name)
25    Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990 */
26
27 /* Copyright 1990, Massachusetts Institute of Technology
28
29    Permission to use, copy, modify, and distribute this program for any purpose
30    and without fee is hereby granted, provided that this copyright and
31    permission notice appear on all copies and supporting documentation, that
32    the name of MIT not be used in advertising or publicity pertaining to
33    distribution of this program without specific prior permission, and that
34    notice be given in supporting documentation that copying and distribution is
35    by permission of MIT.  MIT makes no representations about the suitability of
36    this software for any purpose.  It is provided "as is" without expressed or
37    implied warranty.
38 */
39
40 /* From the original /bin/sh script:
41
42    Used to create a copy of the a directory tree that has links for all
43    non-directories (except those named RCS or SCCS).  If you are
44    building the distribution on more than one machine, you should use
45    this script.
46
47    If your master sources are located in /usr/local/src/X and you would like
48    your link tree to be in /usr/local/src/new-X, do the following:
49
50         %  mkdir /usr/local/src/new-X
51         %  cd /usr/local/src/new-X
52         %  lndir ../X
53 */
54
55 #include <X11/Xos.h>
56 #include <stdio.h>
57 #include <sys/stat.h>
58 #include <sys/param.h>
59 #include <errno.h>
60
61 #ifndef X_NOT_POSIX
62 #include <dirent.h>
63 #else
64 #ifdef SYSV
65 #include <dirent.h>
66 #else
67 #ifdef USG
68 #include <dirent.h>
69 #else
70 #include <sys/dir.h>
71 #ifndef dirent
72 #define dirent direct
73 #endif
74 #endif
75 #endif
76 #endif
77
78 #ifdef X_NOT_STDC_ENV
79 extern int errno;
80 #endif
81
82 int silent;
83
84 void
85 quit (code, fmt, a1, a2, a3)
86 char *fmt;
87 {
88     fprintf (stderr, fmt, a1, a2, a3);
89     putc ('\n', stderr);
90     exit (code);
91 }
92
93 void
94 quiterr (code, s)
95 char *s;
96 {
97     perror (s);
98     exit (code);
99 }
100
101 void
102 msg (fmt, a1, a2, a3)
103 char *fmt;
104 {
105     fprintf (stderr, fmt, a1, a2, a3);
106     putc ('\n', stderr);
107 }
108
109
110 /* Recursively create symbolic links from the current directory to the "from"
111    directory.  Assumes that files described by fs and ts are directories. */
112
113 dodir (fn, fs, ts, rel)
114 char *fn;                       /* name of "from" directory, either absolute or
115                                    relative to cwd */
116 struct stat *fs, *ts;           /* stats for the "from" directory and cwd */
117 int rel;                        /* if true, prepend "../" to fn before using */
118 {
119     DIR *df;
120     struct dirent *dp;
121     char buf[MAXPATHLEN + 1], *p;
122     char symbuf[MAXPATHLEN + 1];
123     struct stat sb, sc;
124     int n_dirs;
125
126     if ((fs->st_dev == ts->st_dev) && (fs->st_ino == ts->st_ino)) {
127         msg ("%s: From and to directories are identical!", fn);
128         return 1;
129     }
130
131     if (rel)
132         strcpy (buf, "../");
133     else
134         buf[0] = '\0';
135     strcat (buf, fn);
136     
137     if (!(df = opendir (buf))) {
138         msg ("%s: Cannot opendir", buf);
139         return 1;
140     }
141
142     p = buf + strlen (buf);
143     *p++ = '/';
144     n_dirs = fs->st_nlink;
145     while (dp = readdir (df)) {
146         strcpy (p, dp->d_name);
147
148         if (n_dirs > 0) {
149             if (stat (buf, &sb) < 0) {
150                 perror (buf);
151                 continue;
152             }
153
154             if (sb.st_mode & S_IFDIR) {
155                 /* directory */
156                 n_dirs--;
157                 if (dp->d_name[0] == '.' &&
158                     (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' &&
159                                                dp->d_name[2] == '\0')))
160                     continue;
161                 if (!strcmp (dp->d_name, "RCS"))
162                     continue;
163                 if (!strcmp (dp->d_name, "SCCS"))
164                     continue;
165                 if (!silent)
166                     printf ("%s:\n", buf);
167                 if ((stat (dp->d_name, &sc) < 0) && (errno == ENOENT)) {
168                     if (mkdir (dp->d_name, 0777) < 0 ||
169                         stat (dp->d_name, &sc) < 0) {
170                         perror (dp->d_name);
171                         continue;
172                     }
173                 }
174                 if (readlink (dp->d_name, symbuf, sizeof(symbuf) - 1) >= 0) {
175                     msg ("%s: is a link instead of a directory\n", dp->d_name);
176                     continue;
177                 }
178                 if (chdir (dp->d_name) < 0) {
179                     perror (dp->d_name);
180                     continue;
181                 }
182                 dodir (buf, &sb, &sc, (buf[0] != '/'));
183                 if (chdir ("..") < 0)
184                     quiterr (1, "..");
185                 continue;
186             }
187         }
188
189         /* non-directory */
190         if (symlink (buf, dp->d_name) < 0) {
191             int saverrno = errno;
192             int symlen;
193             symlen = readlink(dp->d_name, symbuf, sizeof(symbuf) - 1);
194             errno = saverrno;
195             if (symlen > 0)
196                 symbuf[symlen] = '\0';
197             if (symlen < 0 || strcmp(symbuf, buf))
198                 perror (dp->d_name);
199         }
200     }
201
202     closedir (df);
203     return 0;
204 }
205
206
207 main (ac, av)
208 int ac;
209 char **av;
210 {
211     char *fn, *tn;
212     struct stat fs, ts;
213
214     silent = 0;
215     if (ac > 1 && !strcmp(av[1], "-silent")) {
216         silent = 1;
217     }
218     if (ac < silent + 2 || ac > silent + 3)
219         quit (1, "usage: %s [-silent] fromdir [todir]", av[0]);
220
221     fn = av[silent + 1];
222     if (ac == silent + 3)
223         tn = av[silent + 2];
224     else
225         tn = ".";
226
227     /* to directory */
228     if (stat (tn, &ts) < 0)
229         quiterr (1, tn);
230     if (!(ts.st_mode & S_IFDIR))
231         quit (2, "%s: Not a directory", tn);
232     if (chdir (tn) < 0)
233         quiterr (1, tn);
234
235     /* from directory */
236     if (stat (fn, &fs) < 0)
237         quiterr (1, fn);
238     if (!(fs.st_mode & S_IFDIR))
239         quit (2, "%s: Not a directory", fn);
240
241     exit (dodir (fn, &fs, &ts, 0));
242 }