~cfuhrman/+junk/netbsd-othersrc-trunk

« back to all changes in this revision

Viewing changes to bin/ln/ln.c

  • Committer: stacktic
  • Date: 2009-03-23 21:04:00 UTC
  • Revision ID: svn-v4:288d5a72-fed7-e111-8680-000c29dcf8fe:trunk:1946
ImportedĀ fs-utilsĀ binaries

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $NetBSD$ */
 
2
/* from */
 
3
/* NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp */
 
4
 
 
5
/*
 
6
 * Copyright (c) 1987, 1993, 1994
 
7
 *      The Regents of the University of California.  All rights reserved.
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted provided that the following conditions
 
11
 * are met:
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer.
 
14
 * 2. Redistributions in binary form must reproduce the above copyright
 
15
 *    notice, this list of conditions and the following disclaimer in the
 
16
 *    documentation and/or other materials provided with the distribution.
 
17
 * 3. Neither the name of the University nor the names of its contributors
 
18
 *    may be used to endorse or promote products derived from this software
 
19
 *    without specific prior written permission.
 
20
 *
 
21
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
31
 * SUCH DAMAGE.
 
32
 */
 
33
 
 
34
#include <sys/cdefs.h>
 
35
#ifndef lint
 
36
__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
 
37
 The Regents of the University of California.  All rights reserved.");
 
38
#endif /* not lint */
 
39
 
 
40
#ifndef lint
 
41
#if 0
 
42
static char sccsid[] = "@(#)ln.c        8.2 (Berkeley) 3/31/94";
 
43
#else
 
44
__RCSID("$NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $");
 
45
#endif
 
46
#endif /* not lint */
 
47
 
 
48
#include <sys/param.h>
 
49
#include <sys/stat.h>
 
50
 
 
51
#include <err.h>
 
52
#include <errno.h>
 
53
#include <locale.h>
 
54
#include <stdio.h>
 
55
#include <stdlib.h>
 
56
#include <string.h>
 
57
#include <unistd.h>
 
58
 
 
59
#ifdef USE_UKFS
 
60
#include <rump/ukfs.h>
 
61
 
 
62
#include <fsu_mount.h>
 
63
 
 
64
DECLARE_UKFS(ukfs)
 
65
 
 
66
#define stat(a, b) ukfs_stat(ukfs, a, b)
 
67
#define lstat(a, b) ukfs_lstat(ukfs, a, b)
 
68
#define unlink(a) ukfs_remove(ukfs, a)
 
69
 
 
70
int
 
71
link(const char *name1, const char *name2)
 
72
{
 
73
 
 
74
        return ukfs_link(ukfs, name1, name2);
 
75
}
 
76
 
 
77
int
 
78
symlink(const char *name1, const char *name2)
 
79
{
 
80
 
 
81
        return ukfs_symlink(ukfs, name1, name2);
 
82
}
 
83
#endif
 
84
 
 
85
int     fflag;                          /* Unlink existing files. */
 
86
int     hflag;                          /* Check new name for symlink first. */
 
87
int     iflag;                          /* Interactive mode. */
 
88
int     sflag;                          /* Symbolic, not hard, link. */
 
89
int     vflag;                          /* Verbose output */
 
90
 
 
91
                                        /* System link call. */
 
92
int (*linkf)(const char *, const char *);
 
93
char   linkch;
 
94
 
 
95
int     linkit(const char *, const char *, int);
 
96
void    usage(void);
 
97
int     main(int, char *[]);
 
98
 
 
99
int
 
100
main(int argc, char *argv[])
 
101
{
 
102
        struct stat sb;
 
103
        int ch, exitval;
 
104
        char *sourcedir;
 
105
 
 
106
        setprogname(argv[0]);
 
107
        (void)setlocale(LC_ALL, "");
 
108
 
 
109
#ifdef USE_UKFS
 
110
        FSU_MOUNT(argc, argv, ukfs);
 
111
#endif /* USE_UKFS */
 
112
 
 
113
        while ((ch = getopt(argc, argv, "fhinsv")) != -1)
 
114
                switch (ch) {
 
115
                case 'f':
 
116
                        fflag = 1;
 
117
                        iflag = 0;
 
118
                        break;
 
119
                case 'h':
 
120
                case 'n':
 
121
                        hflag = 1;
 
122
                        break;
 
123
                case 'i':
 
124
                        iflag = 1;
 
125
                        fflag = 0;
 
126
                        break;
 
127
                case 's':
 
128
                        sflag = 1;
 
129
                        break;
 
130
                case 'v':               
 
131
                        vflag = 1;
 
132
                        break;
 
133
                case '?':
 
134
                default:
 
135
                        usage();
 
136
                        /* NOTREACHED */
 
137
                }
 
138
 
 
139
        argv += optind;
 
140
        argc -= optind;
 
141
 
 
142
        if (sflag) {
 
143
                linkf  = symlink;
 
144
                linkch = '-';
 
145
        } else {
 
146
                linkf  = link;
 
147
                linkch = '=';
 
148
        }
 
149
 
 
150
        switch(argc) {
 
151
        case 0:
 
152
                usage();
 
153
                /* NOTREACHED */
 
154
        case 1:                         /* ln target */
 
155
                exit(linkit(argv[0], ".", 1));
 
156
                /* NOTREACHED */
 
157
        case 2:                         /* ln target source */
 
158
                exit(linkit(argv[0], argv[1], 0));
 
159
                /* NOTREACHED */
 
160
        }
 
161
 
 
162
                                        /* ln target1 target2 directory */
 
163
        sourcedir = argv[argc - 1];
 
164
        if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
 
165
                /* we were asked not to follow symlinks, but found one at
 
166
                   the target--simulate "not a directory" error */
 
167
                errno = ENOTDIR;
 
168
                err(EXIT_FAILURE, "%s", sourcedir);
 
169
                /* NOTREACHED */
 
170
        }
 
171
        if (stat(sourcedir, &sb)) {
 
172
                err(EXIT_FAILURE, "%s", sourcedir);
 
173
                /* NOTREACHED */
 
174
        }
 
175
        if (!S_ISDIR(sb.st_mode)) {
 
176
                usage();
 
177
                /* NOTREACHED */
 
178
        }
 
179
        for (exitval = 0; *argv != sourcedir; ++argv)
 
180
                exitval |= linkit(*argv, sourcedir, 1);
 
181
        exit(exitval);
 
182
        /* NOTREACHED */
 
183
}
 
184
 
 
185
int
 
186
linkit(const char *target, const char *source, int isdir)
 
187
{
 
188
        struct stat sb;
 
189
        const char *p;
 
190
        char path[MAXPATHLEN];
 
191
        int ch, exists, first;
 
192
 
 
193
        if (!sflag) {
 
194
                /* If target doesn't exist, quit now. */
 
195
                if (stat(target, &sb)) {
 
196
                        warn("%s", target);
 
197
                        return (1);
 
198
                }
 
199
        }
 
200
 
 
201
        /* If the source is a directory (and not a symlink if hflag),
 
202
           append the target's name. */
 
203
        if (isdir ||
 
204
            (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
 
205
            (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
 
206
                if ((p = strrchr(target, '/')) == NULL)
 
207
                        p = target;
 
208
                else
 
209
                        ++p;
 
210
                (void)snprintf(path, sizeof(path), "%s/%s", source, p);
 
211
                source = path;
 
212
        }
 
213
 
 
214
        exists = !lstat(source, &sb);
 
215
 
 
216
        /*
 
217
         * If the file exists, then unlink it forcibly if -f was specified
 
218
         * and interactively if -i was specified.
 
219
         */
 
220
        if (fflag && exists) {
 
221
                if (unlink(source)) {
 
222
                        warn("%s", source);
 
223
                        return (1);
 
224
                }
 
225
        } else if (iflag && exists) {
 
226
                fflush(stdout);
 
227
                (void)fprintf(stderr, "replace %s? ", source);
 
228
 
 
229
                first = ch = getchar();
 
230
                while (ch != '\n' && ch != EOF)
 
231
                        ch = getchar();
 
232
                if (first != 'y' && first != 'Y') {
 
233
                        (void)fprintf(stderr, "not replaced\n");
 
234
                        return (1);
 
235
                }
 
236
 
 
237
                if (unlink(source)) {
 
238
                        warn("%s", source);
 
239
                        return (1);
 
240
                }
 
241
        }
 
242
 
 
243
        /* Attempt the link. */
 
244
        if ((*linkf)(target, source)) {
 
245
                warn("%s", source);
 
246
                return (1);
 
247
        }
 
248
        if (vflag)
 
249
                (void)printf("%s %c> %s\n", source, linkch, target);
 
250
 
 
251
        return (0);
 
252
}
 
253
 
 
254
void
 
255
usage(void)
 
256
{
 
257
#ifndef USE_UKFS
 
258
        (void)fprintf(stderr,
 
259
            "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n",
 
260
            getprogname(), getprogname());
 
261
#else
 
262
        fprintf(stderr,
 
263
                "usage:\t%s %s [-fhinsv] file1 file2\n"
 
264
                "usage:\t%s %s [-fhinsv] file ... directory\n",
 
265
                getprogname(), fsu_mount_usage(),
 
266
                getprogname(), fsu_mount_usage());
 
267
#endif
 
268
        exit(1);
 
269
        /* NOTREACHED */
 
270
}