home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume2 / name < prev    next >
Internet Message Format  |  1991-08-07  |  8KB

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