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 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 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 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 * 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 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 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