xref: /illumos-gate/usr/src/cmd/svr4pkg/pkgproto/main.c (revision 5c51f124)
1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * CDDL HEADER START
3*5c51f124SMoriah Waterland  *
4*5c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
5*5c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
6*5c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
7*5c51f124SMoriah Waterland  *
8*5c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
10*5c51f124SMoriah Waterland  * See the License for the specific language governing permissions
11*5c51f124SMoriah Waterland  * and limitations under the License.
12*5c51f124SMoriah Waterland  *
13*5c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
14*5c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
16*5c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
17*5c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5c51f124SMoriah Waterland  *
19*5c51f124SMoriah Waterland  * CDDL HEADER END
20*5c51f124SMoriah Waterland  */
21*5c51f124SMoriah Waterland 
22*5c51f124SMoriah Waterland /*
23*5c51f124SMoriah Waterland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*5c51f124SMoriah Waterland  * Use is subject to license terms.
25*5c51f124SMoriah Waterland  */
26*5c51f124SMoriah Waterland 
27*5c51f124SMoriah Waterland /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28*5c51f124SMoriah Waterland /* All Rights Reserved */
29*5c51f124SMoriah Waterland 
30*5c51f124SMoriah Waterland 
31*5c51f124SMoriah Waterland #include <stdio.h>
32*5c51f124SMoriah Waterland #include <ctype.h>
33*5c51f124SMoriah Waterland #include <dirent.h>
34*5c51f124SMoriah Waterland #include <limits.h>
35*5c51f124SMoriah Waterland #include <stdlib.h>
36*5c51f124SMoriah Waterland #include <unistd.h>
37*5c51f124SMoriah Waterland #include <string.h>
38*5c51f124SMoriah Waterland #include <sys/types.h>
39*5c51f124SMoriah Waterland #include <sys/stat.h>
40*5c51f124SMoriah Waterland #include <pkgstrct.h>
41*5c51f124SMoriah Waterland #include <errno.h>
42*5c51f124SMoriah Waterland #include <locale.h>
43*5c51f124SMoriah Waterland #include <libintl.h>
44*5c51f124SMoriah Waterland #include <pkglib.h>
45*5c51f124SMoriah Waterland #include "libadm.h"
46*5c51f124SMoriah Waterland #include "libinst.h"
47*5c51f124SMoriah Waterland 
48*5c51f124SMoriah Waterland extern int	holdcinfo;
49*5c51f124SMoriah Waterland 
50*5c51f124SMoriah Waterland #define	WRN_SCARYLINK	"WARNING: <%s>, target of symlink <%s>, does not exist."
51*5c51f124SMoriah Waterland 
52*5c51f124SMoriah Waterland #define	ERR_PATHLONG	"path argument too long"
53*5c51f124SMoriah Waterland #define	ERR_CLASSLONG	"classname argument too long"
54*5c51f124SMoriah Waterland #define	ERR_CLASSCHAR	"bad character in classname"
55*5c51f124SMoriah Waterland #define	ERR_STAT	"unable to stat <%s>"
56*5c51f124SMoriah Waterland #define	ERR_WRITE	"write of entry failed"
57*5c51f124SMoriah Waterland #define	ERR_POPEN	"unable to create pipe to <%s>"
58*5c51f124SMoriah Waterland #define	ERR_PCLOSE	"unable to close pipe to <%s>"
59*5c51f124SMoriah Waterland #define	ERR_RDLINK	"unable to read link for <%s>"
60*5c51f124SMoriah Waterland #define	ERR_MEMORY	"memory allocation failure, errno=%d"
61*5c51f124SMoriah Waterland 
62*5c51f124SMoriah Waterland #define	LINK	1
63*5c51f124SMoriah Waterland 
64*5c51f124SMoriah Waterland struct link {
65*5c51f124SMoriah Waterland 	char	*path;
66*5c51f124SMoriah Waterland 	ino_t	ino;
67*5c51f124SMoriah Waterland 	dev_t	dev;
68*5c51f124SMoriah Waterland 	struct link *next;
69*5c51f124SMoriah Waterland };
70*5c51f124SMoriah Waterland 
71*5c51f124SMoriah Waterland static struct link *firstlink = (struct link *)0;
72*5c51f124SMoriah Waterland static struct link *lastlink = (struct link *)0;
73*5c51f124SMoriah Waterland static char *scan_raw_ln(char *targ_name, char *link_name);
74*5c51f124SMoriah Waterland 
75*5c51f124SMoriah Waterland static char	*def_class = "none";
76*5c51f124SMoriah Waterland 
77*5c51f124SMoriah Waterland static int	errflg = 0;
78*5c51f124SMoriah Waterland static int	iflag = 0;	/* follow symlinks */
79*5c51f124SMoriah Waterland static int	xflag = 0;	/* confirm contents of files */
80*5c51f124SMoriah Waterland static int	nflag = 0;
81*5c51f124SMoriah Waterland static char	construction[PATH_MAX], mylocal[PATH_MAX];
82*5c51f124SMoriah Waterland 
83*5c51f124SMoriah Waterland static void	findlink(struct cfent *ept, char *path, char *svpath);
84*5c51f124SMoriah Waterland static void	follow(char *path);
85*5c51f124SMoriah Waterland static void	output(char *path, int n, char *local);
86*5c51f124SMoriah Waterland static void	usage(void);
87*5c51f124SMoriah Waterland 
88*5c51f124SMoriah Waterland int
main(int argc,char * argv[])89*5c51f124SMoriah Waterland main(int argc, char *argv[])
90*5c51f124SMoriah Waterland {
91*5c51f124SMoriah Waterland 	int c;
92*5c51f124SMoriah Waterland 	char *pt, path[PATH_MAX];
93*5c51f124SMoriah Waterland 	char	*abi_sym_ptr;
94*5c51f124SMoriah Waterland 	extern char	*optarg;
95*5c51f124SMoriah Waterland 	extern int	optind;
96*5c51f124SMoriah Waterland 
97*5c51f124SMoriah Waterland 	(void) setlocale(LC_ALL, "");
98*5c51f124SMoriah Waterland 
99*5c51f124SMoriah Waterland #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
100*5c51f124SMoriah Waterland #define	TEXT_DOMAIN "SYS_TEST"
101*5c51f124SMoriah Waterland #endif
102*5c51f124SMoriah Waterland 	(void) textdomain(TEXT_DOMAIN);
103*5c51f124SMoriah Waterland 
104*5c51f124SMoriah Waterland 	(void) set_prog_name(argv[0]);
105*5c51f124SMoriah Waterland 
106*5c51f124SMoriah Waterland 	while ((c = getopt(argc, argv, "xnic:?")) != EOF) {
107*5c51f124SMoriah Waterland 		switch (c) {
108*5c51f124SMoriah Waterland 		    case 'x':	/* include content info */
109*5c51f124SMoriah Waterland 			xflag++;
110*5c51f124SMoriah Waterland 			break;
111*5c51f124SMoriah Waterland 
112*5c51f124SMoriah Waterland 		    case 'n':
113*5c51f124SMoriah Waterland 			nflag++;
114*5c51f124SMoriah Waterland 			break;
115*5c51f124SMoriah Waterland 
116*5c51f124SMoriah Waterland 		    case 'c':	/* assign class */
117*5c51f124SMoriah Waterland 			def_class = optarg;
118*5c51f124SMoriah Waterland 			/* validate that classname is acceptable */
119*5c51f124SMoriah Waterland 			if (strlen(def_class) > (size_t)CLSSIZ) {
120*5c51f124SMoriah Waterland 				progerr(gettext(ERR_CLASSLONG));
121*5c51f124SMoriah Waterland 				exit(1);
122*5c51f124SMoriah Waterland 			}
123*5c51f124SMoriah Waterland 			for (pt = def_class; *pt; pt++) {
124*5c51f124SMoriah Waterland 				if (!isalpha(*pt) && !isdigit(*pt)) {
125*5c51f124SMoriah Waterland 					progerr(gettext(ERR_CLASSCHAR));
126*5c51f124SMoriah Waterland 					exit(1);
127*5c51f124SMoriah Waterland 				}
128*5c51f124SMoriah Waterland 			}
129*5c51f124SMoriah Waterland 			break;
130*5c51f124SMoriah Waterland 
131*5c51f124SMoriah Waterland 		    case 'i':	/* follow symlinks */
132*5c51f124SMoriah Waterland 			iflag++;
133*5c51f124SMoriah Waterland 			break;
134*5c51f124SMoriah Waterland 
135*5c51f124SMoriah Waterland 		    default:
136*5c51f124SMoriah Waterland 			usage();
137*5c51f124SMoriah Waterland 		}
138*5c51f124SMoriah Waterland 	}
139*5c51f124SMoriah Waterland 
140*5c51f124SMoriah Waterland 	if (iflag) {
141*5c51f124SMoriah Waterland 		/* follow symlinks */
142*5c51f124SMoriah Waterland 		set_nonABI_symlinks();
143*5c51f124SMoriah Waterland 	} else {
144*5c51f124SMoriah Waterland 		/* bug id 4244631, not ABI compliant */
145*5c51f124SMoriah Waterland 		abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
146*5c51f124SMoriah Waterland 		if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) {
147*5c51f124SMoriah Waterland 			set_nonABI_symlinks();
148*5c51f124SMoriah Waterland 		}
149*5c51f124SMoriah Waterland 	}
150*5c51f124SMoriah Waterland 	holdcinfo = !xflag;
151*5c51f124SMoriah Waterland 	if (optind == argc) {
152*5c51f124SMoriah Waterland 		/* take path list from stdin */
153*5c51f124SMoriah Waterland 		while (fgets(path, sizeof (path), stdin) != (char *)NULL) {
154*5c51f124SMoriah Waterland 			output(path, 0, NULL);
155*5c51f124SMoriah Waterland 		}
156*5c51f124SMoriah Waterland 	} else {
157*5c51f124SMoriah Waterland 		while (optind < argc) {
158*5c51f124SMoriah Waterland 			follow(argv[optind++]);
159*5c51f124SMoriah Waterland 		}
160*5c51f124SMoriah Waterland 	}
161*5c51f124SMoriah Waterland 
162*5c51f124SMoriah Waterland 	return (errflg ? 1 : 0);
163*5c51f124SMoriah Waterland }
164*5c51f124SMoriah Waterland 
165*5c51f124SMoriah Waterland static void
output(char * path,int n,char * local)166*5c51f124SMoriah Waterland output(char *path, int n, char *local)
167*5c51f124SMoriah Waterland {
168*5c51f124SMoriah Waterland 	char		mypath[PATH_MAX];
169*5c51f124SMoriah Waterland 	int		len;
170*5c51f124SMoriah Waterland 	int		s;
171*5c51f124SMoriah Waterland 	struct cfent	entry;
172*5c51f124SMoriah Waterland 
173*5c51f124SMoriah Waterland 	/*
174*5c51f124SMoriah Waterland 	 * remove any trailing newline characters from the end of path
175*5c51f124SMoriah Waterland 	 */
176*5c51f124SMoriah Waterland 
177*5c51f124SMoriah Waterland 	len = strlen(path);
178*5c51f124SMoriah Waterland 	while ((len > 0) && (path[len-1] == '\n')) {
179*5c51f124SMoriah Waterland 		path[--len] = '\0';
180*5c51f124SMoriah Waterland 	}
181*5c51f124SMoriah Waterland 
182*5c51f124SMoriah Waterland 	entry.volno = 0;
183*5c51f124SMoriah Waterland 	entry.ftype = '?';
184*5c51f124SMoriah Waterland 	entry.path = mypath;
185*5c51f124SMoriah Waterland 	(void) strlcpy(entry.pkg_class, def_class, sizeof (entry.pkg_class));
186*5c51f124SMoriah Waterland 	(void) strlcpy(entry.path, path, PATH_MAX);
187*5c51f124SMoriah Waterland 	entry.ainfo.local = NULL;
188*5c51f124SMoriah Waterland 	entry.ainfo.mode = BADMODE;
189*5c51f124SMoriah Waterland 	(void) strlcpy(entry.ainfo.owner, BADOWNER, sizeof (entry.ainfo.owner));
190*5c51f124SMoriah Waterland 	(void) strlcpy(entry.ainfo.group, BADGROUP, sizeof (entry.ainfo.group));
191*5c51f124SMoriah Waterland 	errflg = 0;
192*5c51f124SMoriah Waterland 
193*5c51f124SMoriah Waterland 	if (xflag) {
194*5c51f124SMoriah Waterland 		entry.ftype = '?';
195*5c51f124SMoriah Waterland 		if (cverify(0, &entry.ftype, path, &entry.cinfo, 1)) {
196*5c51f124SMoriah Waterland 			errflg++;
197*5c51f124SMoriah Waterland 			logerr(gettext("ERROR: %s"), path);
198*5c51f124SMoriah Waterland 			logerr(getErrbufAddr());
199*5c51f124SMoriah Waterland 			return;
200*5c51f124SMoriah Waterland 		}
201*5c51f124SMoriah Waterland 	}
202*5c51f124SMoriah Waterland 
203*5c51f124SMoriah Waterland 	/*
204*5c51f124SMoriah Waterland 	 * Use averify to figure out the attributes. This has trouble
205*5c51f124SMoriah Waterland 	 * divining the identity of a symlink which points to a
206*5c51f124SMoriah Waterland 	 * non-existant target. For that reason, if it comes back as
207*5c51f124SMoriah Waterland 	 * an existence problem, we fake in a symlink and see if averify
208*5c51f124SMoriah Waterland 	 * likes that. If it does, all we have is a risky symlink.
209*5c51f124SMoriah Waterland 	 */
210*5c51f124SMoriah Waterland 	if ((s = averify(0, &entry.ftype, path, &entry.ainfo)) == VE_EXIST &&
211*5c51f124SMoriah Waterland 	    !iflag) {
212*5c51f124SMoriah Waterland 		entry.ftype = 's';	/* try again assuming symlink */
213*5c51f124SMoriah Waterland 		/* try to read what it points to */
214*5c51f124SMoriah Waterland 		if ((s = readlink(path, mylocal, PATH_MAX)) > 0) {
215*5c51f124SMoriah Waterland 			mylocal[s] = '\000';	/* terminate it */
216*5c51f124SMoriah Waterland 			entry.ainfo.local = mylocal;
217*5c51f124SMoriah Waterland 			if (averify(0, &entry.ftype, path, &entry.ainfo)) {
218*5c51f124SMoriah Waterland 				errflg++;
219*5c51f124SMoriah Waterland 			} else
220*5c51f124SMoriah Waterland 				/* It's a link to a file not in this package. */
221*5c51f124SMoriah Waterland 				ptext(stderr, gettext(WRN_SCARYLINK),
222*5c51f124SMoriah Waterland 				    mylocal, path);
223*5c51f124SMoriah Waterland 		} else {
224*5c51f124SMoriah Waterland 			errflg++;
225*5c51f124SMoriah Waterland 		}
226*5c51f124SMoriah Waterland 	} else if (s != 0 && s != VE_CONT)
227*5c51f124SMoriah Waterland 		errflg++;
228*5c51f124SMoriah Waterland 
229*5c51f124SMoriah Waterland 	if (errflg) {
230*5c51f124SMoriah Waterland 		logerr(gettext("ERROR: %s"), path);
231*5c51f124SMoriah Waterland 		logerr(getErrbufAddr());
232*5c51f124SMoriah Waterland 		return;
233*5c51f124SMoriah Waterland 	}
234*5c51f124SMoriah Waterland 
235*5c51f124SMoriah Waterland 	if (n) {
236*5c51f124SMoriah Waterland 		/* replace first n characters with 'local' */
237*5c51f124SMoriah Waterland 		if (strchr("fev", entry.ftype)) {
238*5c51f124SMoriah Waterland 			entry.ainfo.local = mylocal;
239*5c51f124SMoriah Waterland 			(void) strlcpy(entry.ainfo.local, entry.path,
240*5c51f124SMoriah Waterland 				PATH_MAX);
241*5c51f124SMoriah Waterland 			canonize(entry.ainfo.local);
242*5c51f124SMoriah Waterland 		}
243*5c51f124SMoriah Waterland 		if (local[0]) {
244*5c51f124SMoriah Waterland 			entry.ainfo.local = mylocal;
245*5c51f124SMoriah Waterland 			(void) strlcpy(entry.path, local, PATH_MAX);
246*5c51f124SMoriah Waterland 			(void) strcat(entry.path, path+n);
247*5c51f124SMoriah Waterland 		} else
248*5c51f124SMoriah Waterland 			(void) strlcpy(entry.path,
249*5c51f124SMoriah Waterland 				(path[n] == '/') ? path+n+1 : path+n,
250*5c51f124SMoriah Waterland 				PATH_MAX);
251*5c51f124SMoriah Waterland 	}
252*5c51f124SMoriah Waterland 
253*5c51f124SMoriah Waterland 	canonize(entry.path);
254*5c51f124SMoriah Waterland 	if (entry.path[0]) {
255*5c51f124SMoriah Waterland 		findlink(&entry, path, entry.path);
256*5c51f124SMoriah Waterland 		if (strchr("dcbp", entry.ftype) ||
257*5c51f124SMoriah Waterland 		(nflag && !strchr("sl", entry.ftype)))
258*5c51f124SMoriah Waterland 			entry.ainfo.local = NULL;
259*5c51f124SMoriah Waterland 		if (ppkgmap(&entry, stdout)) {
260*5c51f124SMoriah Waterland 			progerr(gettext(ERR_WRITE));
261*5c51f124SMoriah Waterland 			exit(99);
262*5c51f124SMoriah Waterland 		}
263*5c51f124SMoriah Waterland 	}
264*5c51f124SMoriah Waterland }
265*5c51f124SMoriah Waterland 
266*5c51f124SMoriah Waterland static void
follow(char * path)267*5c51f124SMoriah Waterland follow(char *path)
268*5c51f124SMoriah Waterland {
269*5c51f124SMoriah Waterland 	struct stat stbuf;
270*5c51f124SMoriah Waterland 	FILE	*pp;
271*5c51f124SMoriah Waterland 	char	*pt,
272*5c51f124SMoriah Waterland 		local[PATH_MAX],
273*5c51f124SMoriah Waterland 		newpath[PATH_MAX],
274*5c51f124SMoriah Waterland 		cmd[PATH_MAX+32];
275*5c51f124SMoriah Waterland 	int n;
276*5c51f124SMoriah Waterland 
277*5c51f124SMoriah Waterland 	errflg = 0;
278*5c51f124SMoriah Waterland 
279*5c51f124SMoriah Waterland 	if (pt = strchr(path, '=')) {
280*5c51f124SMoriah Waterland 		*pt++ = '\0';
281*5c51f124SMoriah Waterland 		n = ((unsigned int)pt - (unsigned int)path - 1);
282*5c51f124SMoriah Waterland 		if (n >= PATH_MAX) {
283*5c51f124SMoriah Waterland 			progerr(gettext(ERR_PATHLONG));
284*5c51f124SMoriah Waterland 			errflg++;
285*5c51f124SMoriah Waterland 			return;
286*5c51f124SMoriah Waterland 		}
287*5c51f124SMoriah Waterland 
288*5c51f124SMoriah Waterland 		n = strlen(pt);
289*5c51f124SMoriah Waterland 
290*5c51f124SMoriah Waterland 		if (n < PATH_MAX) {
291*5c51f124SMoriah Waterland 			(void) strlcpy(local, pt, sizeof (local));
292*5c51f124SMoriah Waterland 			n = strlen(path);
293*5c51f124SMoriah Waterland 		} else {
294*5c51f124SMoriah Waterland 			progerr(gettext(ERR_PATHLONG));
295*5c51f124SMoriah Waterland 			errflg++;
296*5c51f124SMoriah Waterland 			return;
297*5c51f124SMoriah Waterland 		}
298*5c51f124SMoriah Waterland 	} else {
299*5c51f124SMoriah Waterland 		n = 0;
300*5c51f124SMoriah Waterland 		local[0] = '\0';
301*5c51f124SMoriah Waterland 	}
302*5c51f124SMoriah Waterland 
303*5c51f124SMoriah Waterland 	if (stat(path, &stbuf)) {
304*5c51f124SMoriah Waterland 		progerr(gettext(ERR_STAT), path);
305*5c51f124SMoriah Waterland 		errflg++;
306*5c51f124SMoriah Waterland 		return;
307*5c51f124SMoriah Waterland 	}
308*5c51f124SMoriah Waterland 
309*5c51f124SMoriah Waterland 	if (stbuf.st_mode & S_IFDIR) {
310*5c51f124SMoriah Waterland 		(void) snprintf(cmd, sizeof (cmd), "find %s -print", path);
311*5c51f124SMoriah Waterland 		if ((pp = popen(cmd, "r")) == NULL) {
312*5c51f124SMoriah Waterland 			progerr(gettext(ERR_POPEN), cmd);
313*5c51f124SMoriah Waterland 			exit(1);
314*5c51f124SMoriah Waterland 		}
315*5c51f124SMoriah Waterland 		while (fscanf(pp, "%[^\n]\n", newpath) == 1)
316*5c51f124SMoriah Waterland 			output(newpath, n, local);
317*5c51f124SMoriah Waterland 		if (pclose(pp)) {
318*5c51f124SMoriah Waterland 			progerr(gettext(ERR_PCLOSE), cmd);
319*5c51f124SMoriah Waterland 			errflg++;
320*5c51f124SMoriah Waterland 		}
321*5c51f124SMoriah Waterland 	} else
322*5c51f124SMoriah Waterland 		output(path, n, local);
323*5c51f124SMoriah Waterland }
324*5c51f124SMoriah Waterland 
325*5c51f124SMoriah Waterland /*
326*5c51f124SMoriah Waterland  * Scan a raw link for origination errors. Given
327*5c51f124SMoriah Waterland  *	targ_name = hlink/path/file1
328*5c51f124SMoriah Waterland  *		and
329*5c51f124SMoriah Waterland  *	link_name = hlink/path/file2
330*5c51f124SMoriah Waterland  * we don't want the link to be verbatim since link_name must be relative
331*5c51f124SMoriah Waterland  * to it's source. This functions checks for identical directory paths
332*5c51f124SMoriah Waterland  * and if it's clearly a misplaced relative path, the duplicate
333*5c51f124SMoriah Waterland  * directories are stripped. This is necessary because pkgadd is actually
334*5c51f124SMoriah Waterland  * in the source directory (hlink/path) when it creates the link.
335*5c51f124SMoriah Waterland  *
336*5c51f124SMoriah Waterland  * NOTE : The buffer we get with targ_name is going to be used later
337*5c51f124SMoriah Waterland  * and cannot be modified. That's why we have yet another PATH_MAX
338*5c51f124SMoriah Waterland  * size buffer in this function.
339*5c51f124SMoriah Waterland  */
340*5c51f124SMoriah Waterland static char *
scan_raw_ln(char * targ_name,char * link_name)341*5c51f124SMoriah Waterland scan_raw_ln(char *targ_name, char *link_name)
342*5c51f124SMoriah Waterland {
343*5c51f124SMoriah Waterland 	char *const_ptr;	/* what we return */
344*5c51f124SMoriah Waterland 	char *file_name;	/* name of the file in link_name */
345*5c51f124SMoriah Waterland 	char *this_dir;		/* current directory in targ_name */
346*5c51f124SMoriah Waterland 	char *next_dir;		/* next directory in targ_name  */
347*5c51f124SMoriah Waterland 	char *targ_ptr;		/* current character in targ_name */
348*5c51f124SMoriah Waterland 
349*5c51f124SMoriah Waterland 	const_ptr = targ_name;	/* Point to here 'til we know it's different. */
350*5c51f124SMoriah Waterland 
351*5c51f124SMoriah Waterland 	/*
352*5c51f124SMoriah Waterland 	 * If the link is absolute or it is in the current directory, no
353*5c51f124SMoriah Waterland 	 * further testing necessary.
354*5c51f124SMoriah Waterland 	 */
355*5c51f124SMoriah Waterland 	if (RELATIVE(targ_name) &&
356*5c51f124SMoriah Waterland 	    (file_name = strrchr(link_name, '/')) != NULL) {
357*5c51f124SMoriah Waterland 
358*5c51f124SMoriah Waterland 		/*
359*5c51f124SMoriah Waterland 		 * This will be walked down to the highest directory
360*5c51f124SMoriah Waterland 		 * not common to both the link and the target.
361*5c51f124SMoriah Waterland 		 */
362*5c51f124SMoriah Waterland 		targ_ptr = targ_name;
363*5c51f124SMoriah Waterland 
364*5c51f124SMoriah Waterland 		/*
365*5c51f124SMoriah Waterland 		 * At this point targ_name is a relative path through at
366*5c51f124SMoriah Waterland 		 * least one directory.
367*5c51f124SMoriah Waterland 		 */
368*5c51f124SMoriah Waterland 		this_dir = targ_ptr;	/* first directory in targ_name */
369*5c51f124SMoriah Waterland 		file_name++;		/* point to the name not the '/' */
370*5c51f124SMoriah Waterland 
371*5c51f124SMoriah Waterland 		/*
372*5c51f124SMoriah Waterland 		 * Scan across the pathname until we reach a different
373*5c51f124SMoriah Waterland 		 * directory or the final file name.
374*5c51f124SMoriah Waterland 		 */
375*5c51f124SMoriah Waterland 		do {
376*5c51f124SMoriah Waterland 			size_t str_size;
377*5c51f124SMoriah Waterland 
378*5c51f124SMoriah Waterland 			next_dir = strchr(targ_ptr, '/');
379*5c51f124SMoriah Waterland 			if (next_dir)
380*5c51f124SMoriah Waterland 				next_dir++;	/* point to name not '/' */
381*5c51f124SMoriah Waterland 			else	/* point to the end of the string */
382*5c51f124SMoriah Waterland 				next_dir = targ_ptr+strlen(targ_ptr);
383*5c51f124SMoriah Waterland 
384*5c51f124SMoriah Waterland 			/* length to compare */
385*5c51f124SMoriah Waterland 			str_size = ((ptrdiff_t)next_dir - (ptrdiff_t)this_dir);
386*5c51f124SMoriah Waterland 
387*5c51f124SMoriah Waterland 			/*
388*5c51f124SMoriah Waterland 			 * If both paths begin with the same directory, then
389*5c51f124SMoriah Waterland 			 * skip that common directory in both the link and
390*5c51f124SMoriah Waterland 			 * the target.
391*5c51f124SMoriah Waterland 			 */
392*5c51f124SMoriah Waterland 			if (strncmp(this_dir, link_name, str_size) == 0) {
393*5c51f124SMoriah Waterland 				/* point to the target so far */
394*5c51f124SMoriah Waterland 				const_ptr = this_dir = next_dir;
395*5c51f124SMoriah Waterland 				/* Skip past it in the target */
396*5c51f124SMoriah Waterland 				targ_ptr = (char *)(targ_ptr+str_size);
397*5c51f124SMoriah Waterland 				/* Skip past it in the link */
398*5c51f124SMoriah Waterland 				link_name = (char *)(link_name+str_size);
399*5c51f124SMoriah Waterland 			/*
400*5c51f124SMoriah Waterland 			 * If these directories don't match then the
401*5c51f124SMoriah Waterland 			 * directory above is the lowest common directory. We
402*5c51f124SMoriah Waterland 			 * need to construct a relative path from the lowest
403*5c51f124SMoriah Waterland 			 * child up to that directory.
404*5c51f124SMoriah Waterland 			 */
405*5c51f124SMoriah Waterland 			} else {
406*5c51f124SMoriah Waterland 				int d = 0;
407*5c51f124SMoriah Waterland 				char *dptr = link_name;
408*5c51f124SMoriah Waterland 
409*5c51f124SMoriah Waterland 				/* Count the intermediate directories. */
410*5c51f124SMoriah Waterland 				while ((dptr = strchr(dptr, '/')) != NULL) {
411*5c51f124SMoriah Waterland 					dptr++;
412*5c51f124SMoriah Waterland 					d++;
413*5c51f124SMoriah Waterland 				}
414*5c51f124SMoriah Waterland 				/*
415*5c51f124SMoriah Waterland 				 * Now targ_ptr is pointing to the fork in
416*5c51f124SMoriah Waterland 				 * the path and dptr is pointing to the lowest
417*5c51f124SMoriah Waterland 				 * child in the link. We now insert the
418*5c51f124SMoriah Waterland 				 * appropriate number of "../'s" to get to
419*5c51f124SMoriah Waterland 				 * the first common directory. We'll
420*5c51f124SMoriah Waterland 				 * construct this in the construction
421*5c51f124SMoriah Waterland 				 * buffer.
422*5c51f124SMoriah Waterland 				 */
423*5c51f124SMoriah Waterland 				if (d) {
424*5c51f124SMoriah Waterland 					char *tptr;
425*5c51f124SMoriah Waterland 
426*5c51f124SMoriah Waterland 					const_ptr = tptr = construction;
427*5c51f124SMoriah Waterland 					while (d--) {
428*5c51f124SMoriah Waterland 						(void) strlcpy(tptr,
429*5c51f124SMoriah Waterland 							"../", PATH_MAX);
430*5c51f124SMoriah Waterland 						tptr += 3;
431*5c51f124SMoriah Waterland 					}
432*5c51f124SMoriah Waterland 					(void) strlcpy(tptr, targ_ptr,
433*5c51f124SMoriah Waterland 						PATH_MAX);
434*5c51f124SMoriah Waterland 				}
435*5c51f124SMoriah Waterland 				break;		/* done */
436*5c51f124SMoriah Waterland 			}
437*5c51f124SMoriah Waterland 		} while (link_name != file_name);	/* at file name */
438*5c51f124SMoriah Waterland 	}
439*5c51f124SMoriah Waterland 
440*5c51f124SMoriah Waterland 	return (const_ptr);
441*5c51f124SMoriah Waterland }
442*5c51f124SMoriah Waterland 
443*5c51f124SMoriah Waterland static void
findlink(struct cfent * ept,char * path,char * svpath)444*5c51f124SMoriah Waterland findlink(struct cfent *ept, char *path, char *svpath)
445*5c51f124SMoriah Waterland {
446*5c51f124SMoriah Waterland 	struct stat	statbuf;
447*5c51f124SMoriah Waterland 	struct link	*link, *new;
448*5c51f124SMoriah Waterland 	char		buf[PATH_MAX];
449*5c51f124SMoriah Waterland 	int		n;
450*5c51f124SMoriah Waterland 
451*5c51f124SMoriah Waterland 	if (lstat(path, &statbuf)) {
452*5c51f124SMoriah Waterland 		progerr(gettext(ERR_STAT), path);
453*5c51f124SMoriah Waterland 		errflg++;
454*5c51f124SMoriah Waterland 	}
455*5c51f124SMoriah Waterland 	if ((statbuf.st_mode & S_IFMT) == S_IFLNK) {
456*5c51f124SMoriah Waterland 		if (!iflag) {
457*5c51f124SMoriah Waterland 			ept->ainfo.local = mylocal;
458*5c51f124SMoriah Waterland 			ept->ftype = 's';
459*5c51f124SMoriah Waterland 			n = readlink(path, buf, PATH_MAX);
460*5c51f124SMoriah Waterland 			if (n <= 0) {
461*5c51f124SMoriah Waterland 				progerr(gettext(ERR_RDLINK), path);
462*5c51f124SMoriah Waterland 				errflg++;
463*5c51f124SMoriah Waterland 				(void) strlcpy(ept->ainfo.local,
464*5c51f124SMoriah Waterland 					"unknown", PATH_MAX);
465*5c51f124SMoriah Waterland 			} else {
466*5c51f124SMoriah Waterland 				(void) strncpy(ept->ainfo.local, buf, n);
467*5c51f124SMoriah Waterland 				ept->ainfo.local[n] = '\0';
468*5c51f124SMoriah Waterland 			}
469*5c51f124SMoriah Waterland 		}
470*5c51f124SMoriah Waterland 		return;
471*5c51f124SMoriah Waterland 	}
472*5c51f124SMoriah Waterland 
473*5c51f124SMoriah Waterland 	if (stat(path, &statbuf))
474*5c51f124SMoriah Waterland 		return;
475*5c51f124SMoriah Waterland 	if (statbuf.st_nlink <= 1)
476*5c51f124SMoriah Waterland 		return;
477*5c51f124SMoriah Waterland 
478*5c51f124SMoriah Waterland 	for (link = firstlink; link; link = link->next) {
479*5c51f124SMoriah Waterland 		if ((statbuf.st_ino == link->ino) &&
480*5c51f124SMoriah Waterland 		(statbuf.st_dev == link->dev)) {
481*5c51f124SMoriah Waterland 			ept->ftype = 'l';
482*5c51f124SMoriah Waterland 			ept->ainfo.local = mylocal;
483*5c51f124SMoriah Waterland 			(void) strlcpy(ept->ainfo.local,
484*5c51f124SMoriah Waterland 					scan_raw_ln(link->path, ept->path),
485*5c51f124SMoriah Waterland 					PATH_MAX);
486*5c51f124SMoriah Waterland 			return;
487*5c51f124SMoriah Waterland 		}
488*5c51f124SMoriah Waterland 	}
489*5c51f124SMoriah Waterland 	if ((new = (struct link *)calloc(1, sizeof (struct link))) == NULL) {
490*5c51f124SMoriah Waterland 		progerr(gettext(ERR_MEMORY), errno);
491*5c51f124SMoriah Waterland 		exit(1);
492*5c51f124SMoriah Waterland 	}
493*5c51f124SMoriah Waterland 
494*5c51f124SMoriah Waterland 	if (firstlink) {
495*5c51f124SMoriah Waterland 		lastlink->next = new;
496*5c51f124SMoriah Waterland 		lastlink = new;
497*5c51f124SMoriah Waterland 	} else
498*5c51f124SMoriah Waterland 		firstlink = lastlink = new;
499*5c51f124SMoriah Waterland 
500*5c51f124SMoriah Waterland 	new->path = strdup(svpath);
501*5c51f124SMoriah Waterland 	new->ino = statbuf.st_ino;
502*5c51f124SMoriah Waterland 	new->dev = statbuf.st_dev;
503*5c51f124SMoriah Waterland }
504*5c51f124SMoriah Waterland 
505*5c51f124SMoriah Waterland static void
usage(void)506*5c51f124SMoriah Waterland usage(void)
507*5c51f124SMoriah Waterland {
508*5c51f124SMoriah Waterland 	(void) fprintf(stderr,
509*5c51f124SMoriah Waterland 	    gettext("usage: %s [-i] [-c class] [path ...]\n"), get_prog_name());
510*5c51f124SMoriah Waterland 	exit(1);
511*5c51f124SMoriah Waterland 	/*NOTREACHED*/
512*5c51f124SMoriah Waterland }
513