GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/lndir/lndir.c Lines: 0 123 0.0 %
Date: 2016-12-06 Branches: 0 120 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: lndir.c,v 1.22 2015/10/10 14:23:12 deraadt Exp $	*/
2
/* $XConsortium: lndir.c /main/15 1995/08/30 10:56:18 gildea $ */
3
4
/*
5
 * Create shadow link tree (after X11R4 script of the same name)
6
 * Mark Reinhold (mbr@lcs.mit.edu)/3 January 1990
7
 */
8
9
/*
10
Copyright (c) 1990,  X Consortium
11
12
Permission is hereby granted, free of charge, to any person obtaining a copy
13
of this software and associated documentation files (the "Software"), to deal
14
in the Software without restriction, including without limitation the rights
15
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
copies of the Software, and to permit persons to whom the Software is
17
furnished to do so, subject to the following conditions:
18
19
The above copyright notice and this permission notice shall be included in
20
all copies or substantial portions of the Software.
21
22
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
25
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29
Except as contained in this notice, the name of the X Consortium shall not be
30
used in advertising or otherwise to promote the sale, use or other dealings
31
in this Software without prior written authorization from the X Consortium.
32
33
*/
34
35
/* From the original /bin/sh script:
36
37
  Used to create a copy of the a directory tree that has links for all
38
  non-directories (except those named RCS, SCCS or CVS.adm).  If you are
39
  building the distribution on more than one machine, you should use
40
  this technique.
41
42
  If your master sources are located in /usr/local/src/X and you would like
43
  your link tree to be in /usr/local/src/new-X, do the following:
44
45
	%  mkdir /usr/local/src/new-X
46
	%  cd /usr/local/src/new-X
47
	%  lndir ../X
48
*/
49
50
#include <sys/stat.h>
51
52
#include <dirent.h>
53
#include <err.h>
54
#include <errno.h>
55
#include <stdarg.h>
56
#include <stdio.h>
57
#include <stdlib.h>
58
#include <string.h>
59
#include <unistd.h>
60
#include <limits.h>
61
62
extern char *__progname;
63
64
int silent;			/* -silent */
65
int ignore_links;		/* -ignorelinks */
66
67
char *rcurdir;
68
char *curdir;
69
70
int equivalent(char *, char *);
71
void addexcept(char *);
72
int dodir(char *, struct stat *, struct stat *, int);
73
void usage(void);
74
75
struct except {
76
	char *name;
77
	struct except *next;
78
};
79
80
struct except *exceptions;
81
82
int
83
main(int argc, char *argv[])
84
{
85
	struct stat fs, ts;
86
	char *fn, *tn;
87
88
	if (pledge("stdio rpath wpath cpath", NULL) == -1)
89
		err(1, "pledge");
90
91
	while (++argv, --argc) {
92
		if ((strcmp(*argv, "-silent") == 0) ||
93
		    (strcmp(*argv, "-s") == 0))
94
			silent = 1;
95
		else if ((strcmp(*argv, "-ignorelinks") == 0) ||
96
		    (strcmp(*argv, "-i") == 0))
97
			ignore_links = 1;
98
		else if (strcmp(*argv, "-e") == 0) {
99
			++argv, --argc;
100
101
			if (argc < 2)
102
				usage();
103
			addexcept(*argv);
104
		} else if (strcmp(*argv, "--") == 0) {
105
			++argv, --argc;
106
			break;
107
		} else
108
			break;
109
	}
110
111
	if (argc < 1 || argc > 2)
112
		usage();
113
114
	fn = argv[0];
115
	if (argc == 2)
116
		tn = argv[1];
117
	else
118
		tn = ".";
119
120
	/* to directory */
121
	if (stat(tn, &ts) < 0)
122
		err(1, "%s", tn);
123
	if (!(S_ISDIR(ts.st_mode)))
124
		errc(2, ENOTDIR, "%s", tn);
125
	if (chdir(tn) < 0)
126
		err(1, "%s", tn);
127
128
	/* from directory */
129
	if (stat(fn, &fs) < 0)
130
		err(1, "%s", fn);
131
	if (!(S_ISDIR(fs.st_mode)))
132
		errc(2, ENOTDIR, "%s", fn);
133
134
	exit(dodir(fn, &fs, &ts, 0));
135
}
136
137
int
138
equivalent(char *lname, char *rname)
139
{
140
	char *s, *ns;
141
142
	if (strcmp(lname, rname) == 0)
143
		return(1);
144
	for (s = lname; *s && (s = strchr(s, '/')); s++) {
145
		if (s[1] == '/') {
146
			/* collapse multiple slashes in lname */
147
			for (ns = s + 1; *ns == '/'; ns++)
148
				;
149
			memmove(s + 1, ns, strlen(ns) + 1);
150
		}
151
	}
152
	return (strcmp(lname, rname) == 0);
153
}
154
155
void
156
addexcept(char *name)
157
{
158
	struct except *new;
159
160
	new = malloc(sizeof(struct except));
161
	if (new == NULL)
162
		err(1, NULL);
163
	new->name = strdup(name);
164
	if (new->name == NULL)
165
		err(1, NULL);
166
167
	new->next = exceptions;
168
	exceptions = new;
169
}
170
171
172
/*
173
 * Recursively create symbolic links from the current directory to the "from"
174
 * directory.  Assumes that files described by fs and ts are directories.
175
 */
176
#if 0
177
	char *fn;		/* name of "from" directory, either absolute or
178
				   relative to cwd */
179
	struct stat *fs, *ts;	/* stats for the "from" directory and cwd */
180
	int rel;		/* if true, prepend "../" to fn before using */
181
#endif
182
int
183
dodir(char *fn, struct stat *fs, struct stat *ts, int rel)
184
{
185
	char buf[PATH_MAX + 1], symbuf[PATH_MAX + 1];
186
	char basesym[PATH_MAX + 1];
187
	int n_dirs, symlen, basesymlen = -1;
188
	struct stat sb, sc;
189
	struct except *cur;
190
	struct dirent *dp;
191
	char *ocurdir, *p;
192
	DIR *df;
193
194
	if (fs->st_dev == ts->st_dev && fs->st_ino == ts->st_ino) {
195
		warnx("%s: From and to directories are identical!", fn);
196
		return(1);
197
	}
198
199
	if (rel)
200
		strlcpy(buf, "../", sizeof(buf));
201
	else
202
		buf[0] = '\0';
203
	strlcat(buf, fn, sizeof(buf));
204
205
	if (!(df = opendir(buf))) {
206
		warn("%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_namlen == 0 || dp->d_name[dp->d_namlen - 1] == '~' ||
215
		    strncmp(dp->d_name, ".#", 2) == 0)
216
			continue;
217
		for (cur = exceptions; cur != NULL; cur = cur->next) {
218
			if (!strcmp(dp->d_name, cur->name))
219
				goto next;	/* can't continue */
220
		}
221
		strlcpy(p, dp->d_name, buf + sizeof(buf) - p);
222
223
		if (n_dirs > 0) {
224
			if (stat(buf, &sb) < 0) {
225
				warn("%s", buf);
226
				continue;
227
			}
228
229
			if (S_ISDIR(sb.st_mode)) {
230
				/* directory */
231
				n_dirs--;
232
				if (dp->d_name[0] == '.' &&
233
				    (dp->d_name[1] == '\0' ||
234
				    (dp->d_name[1] == '.' &&
235
				    dp->d_name[2] == '\0')))
236
					continue;
237
				if (!strcmp(dp->d_name, "RCS"))
238
					continue;
239
				if (!strcmp(dp->d_name, "SCCS"))
240
					continue;
241
				if (!strcmp(dp->d_name, "CVS"))
242
					continue;
243
				if (!strcmp(dp->d_name, "CVS.adm"))
244
					continue;
245
				ocurdir = rcurdir;
246
				rcurdir = buf;
247
				curdir = silent ? buf : NULL;
248
				if (!silent)
249
					printf("%s:\n", buf);
250
				if (stat(dp->d_name, &sc) < 0 &&
251
				    errno == ENOENT) {
252
					if (mkdir(dp->d_name, 0777) < 0 ||
253
					    stat(dp->d_name, &sc) < 0) {
254
						warn("%s", dp->d_name);
255
						curdir = rcurdir = ocurdir;
256
						continue;
257
					}
258
				}
259
				if (readlink(dp->d_name, symbuf,
260
				    sizeof(symbuf) - 1) >= 0) {
261
					fprintf(stderr,
262
					    "%s: is a link instead of a "
263
					    "directory\n",
264
					    dp->d_name);
265
					curdir = rcurdir = ocurdir;
266
					continue;
267
				}
268
				if (chdir(dp->d_name) < 0) {
269
					warn("%s", dp->d_name);
270
					curdir = rcurdir = ocurdir;
271
					continue;
272
				}
273
				dodir(buf, &sb, &sc, (buf[0] != '/'));
274
				if (chdir("..") < 0)
275
					err(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
		/*
287
		 * The option to ignore links exists mostly because
288
		 * checking for them slows us down by 10-20%.
289
		 * But it is off by default because this is a useful check.
290
		 */
291
		if (!ignore_links) {
292
			/* see if the file in the base tree was a symlink */
293
			basesymlen = readlink(buf, basesym,
294
			    sizeof(basesym) - 1);
295
			if (basesymlen >= 0)
296
				basesym[basesymlen] = '\0';
297
		}
298
299
		if (symlen >= 0) {
300
			/*
301
			 * Link exists in new tree.  Print message if
302
			 * it doesn't match.
303
			 */
304
			if (!equivalent(basesymlen >= 0 ? basesym : buf,
305
			    symbuf))
306
				fprintf(stderr,"%s: %s\n", dp->d_name, symbuf);
307
		} else {
308
			if (symlink(basesymlen >= 0 ? basesym : buf,
309
			    dp->d_name) < 0)
310
				warn("%s", dp->d_name);
311
		}
312
next:
313
	;
314
	}
315
316
	closedir(df);
317
	return (0);
318
}
319
320
void
321
usage(void)
322
{
323
	fprintf(stderr, "usage: %s [-is] [-e exceptfile] fromdir [todir]\n",
324
	    __progname);
325
	exit(1);
326
}