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