|
|
1.1 root 1: /*
2: * ln.c
3: * Make a link.
4: */
5:
6: #include <stdio.h>
7: #include <sys/stat.h>
8: #include <errno.h>
9:
10: #define VERSION "2.2"
11: #define USAGE "Usage:\t%s [-f] oldfile newfile\n\t%s [-f] file ... directory\n"
12:
13: /* Externals. */
14: extern int errno;
15: extern char * rindex();
16: extern char * strcpy();
17: extern int strlen();
18:
19: /* Globals. */
20: char *argv0;
21: int fflag;
22: char namebuf[200];
23:
24: /* Functions. */
25: char * basename();
26: int ln();
27: void usage();
28:
29: main(argc, argv) int argc; char *argv[];
30: {
31: register int i, estat;
32: struct stat sb;
33: char *lname, *s;
34:
35: argv0 = *argv;
36: if (argc > 1 && argv[1][0]=='-') {
37: for (s = &argv[1][1]; *s; s++) {
38: switch (*s) {
39: case 'V':
40: fprintf(stderr, "%s: V%s\n", argv0, VERSION);
41: break;
42: case 'f':
43: ++fflag;
44: break;
45: default:
46: usage();
47: }
48: --argc;
49: ++argv;
50: }
51: }
52: if (argc < 3)
53: usage();
54:
55: lname = argv[argc-1];
56: if (stat(lname, &sb)>=0 && (sb.st_mode&S_IFMT)==S_IFDIR) {
57: /* The last arg is a directory. */
58: strcpy(namebuf, lname);
59: s = &namebuf[strlen(namebuf)];
60: *s++ = '/';
61: for (estat = 0, i=1; i<argc-1; i++) {
62: strcpy(s, basename(argv[i]));
63: estat |= ln(argv[i], namebuf);
64: }
65: exit(estat);
66: } else if (argc > 3)
67: usage();
68: else
69: exit(ln(argv[1], argv[2]));
70: }
71:
72: /*
73: * Do the link and check for errors.
74: * Try to force the link if the '-f' is specified.
75: * Return 0 on success, 1 on failure.
76: */
77: int
78: ln(n1, n2) char *n1, *n2;
79: {
80: if (link(n1, n2) == 0)
81: return 0;
82: if (fflag && errno==EEXIST && force(n1, n2) == 0)
83: return 0;
84: perror(argv0);
85: return 1;
86: }
87:
88: /*
89: * The link failed, try to force it while avoiding:
90: * directory unlink
91: * unlinking source == destination
92: * unlinking destination when different device
93: * Return 0 on success, -1 on failure.
94: */
95: int
96: force(n1, n2) char *n1, *n2;
97: {
98: struct stat sb1, sb2;
99:
100: if (stat(n2, &sb2) < 0)
101: return -1; /* e.g. n2 in nonexistent directory */
102: if ((sb2.st_mode&S_IFMT) == S_IFDIR) {
103: errno = EISDIR;
104: return -1; /* n2 is a directory */
105: } else if (stat(n1, &sb1) >= 0) {
106: if (sb1.st_dev != sb2.st_dev) {
107: errno = EXDEV;
108: return -1; /* cross device link */
109: }
110: if (sb1.st_ino == sb2.st_ino)
111: return 0; /* n1 and n2 are already linked, ok */
112: }
113: if (unlink(n2) < 0)
114: return -1; /* cannot unlink */
115: return link(n1, n2);
116: }
117:
118: /*
119: * Find the part of a name past the last '/'.
120: */
121: char *
122: basename(n) register char *n;
123: {
124: register char *s;
125:
126: if ((s = rindex(n, '/')) == NULL)
127: return n;
128: return ++s;
129: }
130:
131: void
132: usage()
133: {
134: fprintf(stderr, USAGE, argv0, argv0);
135: exit(1);
136: }
137:
138: /* end of ln.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.