Annotation of src/usr.bin/readlink/readlink.c, Revision 1.10
1.3 kstailey 1: /*
1.10 ! niklas 2: * $OpenBSD: readlink.c,v 1.9 1997/08/18 20:27:53 kstailey Exp $
1.3 kstailey 3: *
4: * Copyright (c) 1997
5: * Kenneth Stailey (hereinafter referred to as the author)
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
1.9 kstailey 30: #include <limits.h>
1.10 ! niklas 31: #include <errno.h>
1.1 kstailey 32: #include <stdio.h>
1.10 ! niklas 33: #include <string.h>
1.1 kstailey 34: #include <unistd.h>
35:
1.10 ! niklas 36: void canonicalize __P((const char *, char *));
! 37:
1.1 kstailey 38: int
39: main(argc, argv)
1.10 ! niklas 40: int argc;
! 41: char **argv;
1.1 kstailey 42: {
43: char buf[PATH_MAX];
1.10 ! niklas 44: int n, ch, nflag = 0, fflag = 0;
1.8 kstailey 45: extern int optind;
1.1 kstailey 46:
1.10 ! niklas 47: while ((ch = getopt(argc, argv, "fn")) != -1)
1.8 kstailey 48: switch (ch) {
1.10 ! niklas 49: case 'f':
! 50: fflag = 1;
! 51: break;
1.8 kstailey 52: case 'n':
53: nflag = 1;
54: break;
55: default:
56: (void)fprintf(stderr,
1.10 ! niklas 57: "usage: readlink [-n] [-f] symlink\n");
1.8 kstailey 58: exit(1);
59: }
60: argc -= optind;
61: argv += optind;
62:
63: if (argc != 1) {
1.10 ! niklas 64: fprintf(stderr, "usage: readlink [-n] [-f] symlink\n");
1.5 deraadt 65: exit(1);
66: }
1.1 kstailey 67:
1.10 ! niklas 68: n = strlen(argv[0]);
! 69: if (n > PATH_MAX - 1)
! 70: errx(1, "filename longer than PATH_MAX-1 (%d)\n",
! 71: PATH_MAX - 1);
! 72:
! 73: if (fflag)
! 74: canonicalize(argv[0], buf);
! 75: else if ((n = readlink(argv[0], buf, PATH_MAX)) < 0)
1.1 kstailey 76: exit(1);
1.4 grr 77:
78: printf("%s", buf);
1.8 kstailey 79: if (!nflag)
80: putchar('\n');
1.1 kstailey 81: exit(0);
1.10 ! niklas 82: }
! 83:
! 84: void
! 85: canonicalize(path, newpath)
! 86: const char *path;
! 87: char *newpath;
! 88: {
! 89: int n;
! 90: char *p, *np, *lp, c ;
! 91: char target[PATH_MAX];
! 92:
! 93: strcpy(newpath, path);
! 94: for (;;) {
! 95: p = np = newpath;
! 96:
! 97: /*
! 98: * If absolute path, skip the root slash now so we won't
! 99: * think of this as a NULL component.
! 100: */
! 101: if (*p == '/')
! 102: p++;
! 103:
! 104: /*
! 105: * loop through all components of the path until a link is
! 106: * found then expand it, if no link is found we are ready.
! 107: */
! 108: for (; *p; lp = ++p) {
! 109: while (*p && *p != '/')
! 110: p++;
! 111: c = *p;
! 112: *p = '\0';
! 113: n = readlink(newpath, target, PATH_MAX);
! 114: *p = c;
! 115: if (n > 0 || errno != EINVAL)
! 116: break;
! 117: }
! 118: if (!*p && n < 0 && errno == EINVAL)
! 119: break;
! 120: if (n < 0)
! 121: err(1, "%s", newpath);
! 122: target[n] = '\0';
! 123: #ifdef DEBUG
! 124: fprintf(stderr, "%.*s -> %s : ", p - newpath, newpath, target);
! 125: #endif
! 126: if (*target == '/') {
! 127: bcopy(p, newpath + n, strlen(p) + 1);
! 128: bcopy(target, newpath, n);
! 129: } else {
! 130: bcopy(p, lp + n, strlen(p) + 1);
! 131: bcopy(target, lp, n);
! 132: }
! 133: #ifdef DEBUG
! 134: fprintf(stderr, "%s\n", newpath);
! 135: #endif
! 136: strcpy(target, newpath);
! 137: path = target;
! 138: }
1.1 kstailey 139: }