home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / misc / volume02 / name < prev    next >
Encoding:
Internet Message Format  |  1991-08-27  |  8.7 KB

  1. From mipos3!omepd!intelisc!littlei!uunet!husc6!necntc!ncoast!allbery Fri Mar 11 19:06:22 PST 1988
  2. Article 326 of comp.sources.misc:
  3. Path: td2cad!mipos3!omepd!intelisc!littlei!uunet!husc6!necntc!ncoast!allbery
  4. From: dupuy@westend.columbia.edu (Alexander Dupuy)
  5. Newsgroups: comp.sources.misc
  6. Subject: v02i073: A filename canonicalizer for BSD
  7. Message-ID: <7490@ncoast.UUCP>
  8. Date: 9 Mar 88 23:23:45 GMT
  9. Sender: allbery@ncoast.UUCP
  10. Reply-To: dupuy@westend.columbia.edu (Alexander Dupuy)
  11. Organization: Columbia University Computer Science Dept.
  12. Lines: 388
  13. Approved: allbery@ncoast.UUCP
  14. Comp.sources.misc: Volume 2, Issue 73
  15. Submitted-By: "Alexander Dupuy" <dupuy@westend.columbia.edu>
  16. Archive-Name: name
  17.  
  18. Comp.sources.misc: Volume 2, Issue 73
  19. Submitted-By: "Alexander Dupuy" <dupuy@westend.columbia.edu>
  20. Archive-Name: name
  21.  
  22.  
  23. Have your filesystems become such a mess of symbolic links that you don't know
  24. where a given path really leads?  If so, this program will help.  It takes a
  25. pathname and gives you back the true name of the file.  It has an option [-a]
  26. to give you an absolute name (leading '/'), an option [-n] to give you a
  27. normalized name (all "//", "/./", and "/../" removed, if possible), and even an
  28. option [-i] which ignores symbolic links (this is pretty useless if you don't
  29. also specify the normalize option).
  30.  
  31. The most useful option is the verbose [-v] option, which prints out all
  32. symbolic links encountered while looking up the name.  This helps in figuring
  33. out how it got from here to there.
  34.  
  35. Sorry, no man page.  If you hadn't guessed, this is BSD-only.  However, I was
  36. able to compile it under HP-UX with "-lBSD" for the getwd() call.  How many
  37. System V's have symlinks anyhow?
  38.  
  39. @alex
  40. -- 
  41. inet: dupuy@columbia.edu
  42. uucp: ...!rutgers!columbia!dupuy
  43.  
  44. : This is a shar archive.  Extract with sh, not csh.
  45. : The rest of this file will extract: 
  46. :
  47. :    name.c
  48. :
  49. echo x - name.c
  50. sed 's/^X//' > name.c << '//go.sysin dd *'
  51. X/*
  52. X * name - find a file's real name
  53. X */
  54. X
  55. X#include <stdio.h>
  56. X#include <errno.h>
  57. X#include <strings.h>
  58. X#include <sys/param.h>
  59. X#include <sys/stat.h>
  60. X#include <sys/dir.h>
  61. X
  62. Xchar usage[] = "Usage: name [-ainv] pathname...\n";
  63. X
  64. Xint absolute;                /* print absolute pathnames */
  65. Xint normalize;                /* normalize pathnames */
  66. Xint ignore;                /* ignore symbolic links */
  67. Xint verbose;                /* describe each symbolic link */
  68. X
  69. Xmain (argc, argv)
  70. Xchar **argv;
  71. X{
  72. X    int option;
  73. X    extern int optind;
  74. X    int errors = 0;
  75. X    char realname[MAXPATHLEN + MAXNAMLEN];
  76. X    extern char *name();
  77. X
  78. X    while ((option = getopt (argc, argv, "ainv")) != EOF)
  79. X    switch (option)
  80. X    {
  81. X      case 'a':
  82. X        absolute += 1;
  83. X        break;
  84. X        
  85. X      case 'i':
  86. X        ignore += 1;
  87. X        break;
  88. X        
  89. X      case 'n':
  90. X        normalize += 1;
  91. X        break;
  92. X        
  93. X      case 'v':
  94. X        verbose += 1;
  95. X        break;
  96. X        
  97. X      default:
  98. X        fputs (usage, stderr);
  99. X        exit (1);
  100. X    }
  101. X    
  102. X    argc -= optind;
  103. X    argv += optind;
  104. X    
  105. X    if (argc == 0)            /* have to have a path... */
  106. X    {
  107. X    fputs (usage, stderr);
  108. X    exit (1);
  109. X    }
  110. X
  111. X    while (argc-- > 0)
  112. X    {
  113. X    if (name (*argv++, realname) == 0)
  114. X    {                /* print error returned by name() */
  115. X        fputs (realname, stderr);
  116. X        (void) putc ('\n', stderr);
  117. X        errors++;
  118. X    }
  119. X    else                /* print the real name itself */
  120. X        puts (realname);
  121. X    }
  122. X
  123. X    exit (errors);
  124. X}
  125. X
  126. Xstatic int links;            /* how many symbolic links in path */
  127. X
  128. Xchar *name (path, truename)
  129. Xchar *path;
  130. Xchar *truename;
  131. X{
  132. X    static char prefix[MAXPATHLEN + MAXNAMLEN + 1];
  133. X    extern char *getwd();
  134. X
  135. X    if (*path != '/' && absolute)    /* get absolute pathname of relative */
  136. X    {
  137. X    if (getwd (prefix) == NULL)    /* system five doesn't have this... */
  138. X    {
  139. X        strcpy (truename, prefix);    /* contains error message from getwd */
  140. X        return (NULL);
  141. X    }
  142. X    strcat (prefix, "/");        /* add trailing '/' */
  143. X    }    
  144. X    else
  145. X    prefix[0] = '\0';
  146. X
  147. X    links = 0;
  148. X
  149. X    if (name1 (prefix, path) == 0)    /* an error occurred */
  150. X    {
  151. X    strcpy (truename, prefix);    /* copy back the error message */
  152. X    return (NULL);
  153. X    }    
  154. X    else
  155. X    {
  156. X    strcpy (truename, prefix);    /* copy back the real name */
  157. X    return (truename);
  158. X    }
  159. X}
  160. X
  161. X
  162. X#define rootdir(name) ((name)[0]=='/' && (name)[1]=='\0')
  163. X
  164. X#define dotdir(name) \
  165. X((name)[0]=='.' && ((name)[1]=='\0' || ((name)[1]=='.' && (name)[2]=='\0')))
  166. X
  167. X#define dotdotdir(name) \
  168. X((name)[0]=='.' && (name)[1]=='.' && (name)[2]=='\0')
  169. X
  170. X
  171. X/*
  172. X * Recursively add suffix to prefix, canonicalizing as we go...
  173. X */
  174. X
  175. Xstatic name1 (prefix, suffix)
  176. Xchar *prefix;
  177. Xregister char *suffix;
  178. X{
  179. X    extern char *sys_errlist[];
  180. X    char link[MAXPATHLEN];
  181. X    struct stat status;
  182. X    register char *splice;
  183. X    register char *cut;
  184. X    register int cc;
  185. X    int result;
  186. X
  187. X    splice = prefix + strlen (prefix);
  188. X
  189. X    do
  190. X    {
  191. X    if (!normalize)
  192. X    {
  193. X        if (*suffix == '/')        /* skip one leading "/" */
  194. X        {
  195. X        *splice++ = '/';
  196. X        *splice = '\0';
  197. X        suffix++;
  198. X        }
  199. X    }
  200. X    else
  201. X    {
  202. X        if (*suffix == '/')
  203. X        {
  204. X        while (*suffix == '/')
  205. X            suffix++;        /* treat "//" as "/" */
  206. X
  207. X        if (splice == prefix ||
  208. X            (*suffix != '\0' && splice[-1] != '/'))
  209. X        {
  210. X            *splice++ = '/';
  211. X            *splice = '\0';
  212. X        }
  213. X        }
  214. X
  215. X        if (*suffix == '.')
  216. X        {
  217. X        if (suffix[1] == '\0')
  218. X        {            /* treat "." as "." (not "") */
  219. X            if (splice == prefix)
  220. X            {
  221. X            *splice++ = '.';
  222. X            *splice = '\0';
  223. X            }            /* treat "x/." as "x" */
  224. X            else if (!rootdir (prefix))
  225. X            *--splice = '\0';
  226. X            return (1);        /* treat "/." as "/" */
  227. X        }
  228. X
  229. X        if (suffix[1] == '/')
  230. X        {
  231. X            suffix += 2;    /* treat "/./" as "/" */
  232. X            continue;
  233. X        }
  234. X
  235. X        if (suffix[1] == '.')
  236. X        {
  237. X            if (suffix[2] == '\0')
  238. X            {            /* treat ".." as ".." */
  239. X            if (prefix == splice)
  240. X                strcpy (prefix, "..");
  241. X
  242. X            else if (!rootdir (prefix))
  243. X            {
  244. X                *--splice = '\0';
  245. X            
  246. X                if ((splice = rindex (prefix, '/')) == 0)
  247. X                {
  248. X                if (dotdotdir (prefix))
  249. X                {
  250. X                    strcat (prefix, "/..");
  251. X                    return (1);
  252. X                }
  253. X                else
  254. X                    splice = prefix;
  255. X                }
  256. X                else if (dotdotdir (splice + 1))
  257. X                {
  258. X                strcat (splice, "/..");
  259. X                return (1);
  260. X                }
  261. X
  262. X                *splice= '\0';
  263. X            }            
  264. X
  265. X            return (1);
  266. X            }
  267. X
  268. X            if (suffix[2] == '/')
  269. X            {
  270. X            if (splice == prefix)
  271. X            {
  272. X                strcpy (prefix, "..");
  273. X                splice += 2;
  274. X                suffix += 2;
  275. X            }
  276. X
  277. X            else if (!rootdir (prefix))
  278. X            {        /* don't back up "/" prefix */
  279. X                *--splice = '\0';
  280. X            
  281. X                if ((splice = rindex (prefix, '/')) == 0)
  282. X                {
  283. X                if (dotdotdir (prefix))
  284. X                {
  285. X                    strcat (prefix, "/..");
  286. X                    splice = prefix + strlen (prefix);
  287. X                    suffix += 2;
  288. X                }
  289. X                else
  290. X                {
  291. X                    splice = prefix;
  292. X                    *splice = '\0';
  293. X                    suffix += 3;
  294. X                }
  295. X                }
  296. X                else
  297. X                {
  298. X                if (dotdotdir (splice))
  299. X                {
  300. X                    strcat (splice, "..");
  301. X                    splice += strlen (splice);
  302. X                    suffix += 2;
  303. X                }
  304. X                else
  305. X                {
  306. X                    *splice = '\0';
  307. X                    suffix += 2;
  308. X                }
  309. X                }
  310. X            }            
  311. X            else
  312. X                suffix += 3;
  313. X
  314. X            continue;
  315. X            }
  316. X        }            
  317. X        }            
  318. X    }
  319. X
  320. X    if (!*suffix)
  321. X        break;            /* empty suffix string */
  322. X
  323. X    if ((cut = index (suffix, '/')) == 0)
  324. X    {
  325. X        cc = strlen (suffix);
  326. X        cut = suffix + cc;
  327. X    }
  328. X    else
  329. X        cc = cut - suffix;
  330. X
  331. X    if (cc >= MAXNAMLEN)
  332. X    {
  333. X        (void) sprintf (prefix, "%s: %s",
  334. X                suffix, sys_errlist[ENAMETOOLONG]);
  335. X        return (0);
  336. X    }
  337. X
  338. X    if (cc == 0)            /* suffix has leading '/' */
  339. X    {
  340. X        cut++;
  341. X        cc = 1;            /* so force it to be copied */
  342. X    }
  343. X    
  344. X    strncpy (splice, suffix, cc);
  345. X    splice[cc] = '\0';
  346. X
  347. X    if (!ignore)
  348. X    {
  349. X        if ((result = lstat (prefix, &status)) == -1)
  350. X        {
  351. X        (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
  352. X        return (0);
  353. X        }
  354. X
  355. X        if ((status.st_mode & S_IFMT) == S_IFLNK)
  356. X        {
  357. X        if ((result = readlink (prefix, link, MAXPATHLEN)) == -1)
  358. X        {
  359. X            (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
  360. X            return (0);
  361. X        }
  362. X        link[result] = '\0';
  363. X
  364. X        if (links++ == MAXSYMLINKS &&
  365. X            (result = stat (prefix, &status)) == -1)
  366. X        {
  367. X            (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
  368. X            return (0);
  369. X        }
  370. X
  371. X        if (verbose)
  372. X        {
  373. X            (void) printf ("%s -> %s\n", prefix, link);
  374. X        }
  375. X
  376. X        if (*link == '/')
  377. X            *prefix = '\0';    /* chop prefix if link is absolute */
  378. X        else
  379. X            *splice = '\0';    /* chop just the link name */
  380. X
  381. X        if (name1 (prefix, link) == 0)
  382. X            return (0);        /* recurse */
  383. X
  384. X        splice = prefix + strlen (prefix);
  385. X        }
  386. X    }
  387. X    else if ((result = stat (prefix, &status)) == -1)
  388. X    {
  389. X        (void) sprintf (splice + cc, ": %s", sys_errlist[errno]);
  390. X        return (0);
  391. X    }
  392. X
  393. X    suffix = cut;            /* advance suffix past cut */
  394. X
  395. X    splice += strlen (splice);    /* advance splice to end of prefix */
  396. X    }
  397. X    while (*suffix);
  398. X
  399. X    return (1);
  400. X}
  401. //go.sysin dd *
  402. exit
  403.  
  404. inet: dupuy@columbia.edu
  405. uucp: ...!rutgers!columbia!dupuy
  406.  
  407.  
  408.