source: rtems/cpukit/libmisc/shell/main_ln.c @ 6cdaa85

5
Last change on this file since 6cdaa85 was 6cdaa85, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 4, 2018 at 6:16:45 PM

shell: Use #include "..." for local header files

Update #3375.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1/* $NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $ */
2
3/*
4 * Copyright (c) 1987, 1993, 1994
5 *      The Regents of the University of California.  All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#if 0
37#ifndef lint
38__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
39 The Regents of the University of California.  All rights reserved.");
40#endif /* not lint */
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)ln.c        8.2 (Berkeley) 3/31/94";
45#else
46__RCSID("$NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $");
47#endif
48#endif /* not lint */
49#endif
50
51#include <rtems.h>
52#include <rtems/shell.h>
53#include <rtems/shellconfig.h>
54#define __need_getopt_newlib
55#include <getopt.h>
56
57#include <sys/cdefs.h>
58#include <sys/param.h>
59#include <sys/stat.h>
60
61#include "err.h"
62#include <errno.h>
63#include <locale.h>
64#include <stdio.h>
65#include <stdlib.h>
66#include <string.h>
67#include <unistd.h>
68
69#include <setjmp.h>
70
71typedef struct {
72  int   fflag;                          /* Unlink existing files. */
73  int   hflag;                          /* Check new name for symlink first. */
74  int   iflag;                          /* Interactive mode. */
75  int   sflag;                          /* Symbolic, not hard, link. */
76  int   vflag;                          /* Verbose output */
77  char   linkch;
78
79  int exit_code;
80  jmp_buf exit_jmp;
81} rtems_shell_ln_globals;
82
83#define fflag  globals->fflag
84#define hflag  globals->hflag
85#define iflag  globals->iflag
86#define sflag  globals->sflag
87#define vflag  globals->vflag
88#define linkch globals->linkch
89
90#define exit_jump &(globals->exit_jmp)
91
92#define exit(ec) rtems_shell_ln_exit(globals, ec)
93
94static int      main_ln(rtems_shell_ln_globals* , int, char *[]);
95
96static void
97rtems_shell_ln_exit (rtems_shell_ln_globals* globals, int code)
98{
99  globals->exit_code = code;
100  longjmp (globals->exit_jmp, 1);
101}
102
103static int main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[]);
104
105static int rtems_shell_main_ln(int argc, char *argv[])
106{
107  rtems_shell_ln_globals  ln_globals;
108  rtems_shell_ln_globals* globals = &ln_globals;
109  memset (globals, 0, sizeof (ln_globals));
110  ln_globals.exit_code = 1;
111  if (setjmp (ln_globals.exit_jmp) == 0)
112    return main_ln (globals, argc, argv);
113  return ln_globals.exit_code;
114}
115
116#if RTEMS_REMOVED
117int     fflag;                          /* Unlink existing files. */
118int     hflag;                          /* Check new name for symlink first. */
119int     iflag;                          /* Interactive mode. */
120int     sflag;                          /* Symbolic, not hard, link. */
121int     vflag;                          /* Verbose output */
122
123                                        /* System link call. */
124int (*linkf)(const char *, const char *);
125char   linkch;
126#endif
127
128int (*linkf)(const char *, const char *);
129
130static int      linkit(rtems_shell_ln_globals* , const char *, const char *, int);
131static void     usage(rtems_shell_ln_globals* );
132
133static int
134main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[])
135{
136        struct stat sb;
137        int ch, exitval;
138        char *sourcedir;
139
140        struct getopt_data getopt_reent;
141        memset(&getopt_reent, 0, sizeof(getopt_data));
142
143#if RTEMS_REMOVED
144        setprogname(argv[0]);
145        (void)setlocale(LC_ALL, "");
146#endif
147
148        while ((ch = getopt_r(argc, argv, "fhinsv", &getopt_reent)) != -1)
149                switch (ch) {
150                case 'f':
151                        fflag = 1;
152                        iflag = 0;
153                        break;
154                case 'h':
155                case 'n':
156                        hflag = 1;
157                        break;
158                case 'i':
159                        iflag = 1;
160                        fflag = 0;
161                        break;
162                case 's':
163                        sflag = 1;
164                        break;
165                case 'v':
166                        vflag = 1;
167                        break;
168                case '?':
169                default:
170                        usage(globals);
171                        /* NOTREACHED */
172                }
173
174        argv += getopt_reent.optind;
175        argc -= getopt_reent.optind;
176
177        if (sflag) {
178                linkf  = symlink;
179                linkch = '-';
180        } else {
181                linkf  = link;
182                linkch = '=';
183        }
184
185        switch(argc) {
186        case 0:
187                usage(globals);
188                /* NOTREACHED */
189        case 1:                         /* ln target */
190                exit(linkit(globals, argv[0], ".", 1));
191                /* NOTREACHED */
192        case 2:                         /* ln target source */
193                exit(linkit(globals, argv[0], argv[1], 0));
194                /* NOTREACHED */
195        }
196
197                                        /* ln target1 target2 directory */
198        sourcedir = argv[argc - 1];
199        if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
200                /* we were asked not to follow symlinks, but found one at
201                   the target--simulate "not a directory" error */
202                errno = ENOTDIR;
203                err(exit_jump, EXIT_FAILURE, "%s", sourcedir);
204                /* NOTREACHED */
205        }
206        if (stat(sourcedir, &sb)) {
207                err(exit_jump, EXIT_FAILURE, "%s", sourcedir);
208                /* NOTREACHED */
209        }
210        if (!S_ISDIR(sb.st_mode)) {
211                usage(globals);
212                /* NOTREACHED */
213        }
214        for (exitval = 0; *argv != sourcedir; ++argv)
215                exitval |= linkit(globals, *argv, sourcedir, 1);
216        exit(exitval);
217        /* NOTREACHED */
218  return 0;
219}
220
221int
222linkit(rtems_shell_ln_globals* globals, const char *source, const char *target, int isdir)
223{
224        struct stat sb;
225        const char *p;
226        char path[MAXPATHLEN];
227        int ch, exists, first;
228
229        if (!sflag) {
230                /* If target doesn't exist, quit now. */
231                if (stat(target, &sb)) {
232                        warn("%s", target);
233                        return (1);
234                }
235        }
236
237        /* If the source is a directory (and not a symlink if hflag),
238           append the target's name. */
239        if (isdir ||
240            (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
241            (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
242                if ((p = strrchr(target, '/')) == NULL)
243                        p = target;
244                else
245                        ++p;
246                (void)snprintf(path, sizeof(path), "%s/%s", source, p);
247                source = path;
248        }
249
250        exists = !lstat(source, &sb);
251
252        /*
253         * If the file exists, then unlink it forcibly if -f was specified
254         * and interactively if -i was specified.
255         */
256        if (fflag && exists) {
257                if (unlink(source)) {
258                        warn("%s", source);
259                        return (1);
260                }
261        } else if (iflag && exists) {
262                fflush(stdout);
263                (void)fprintf(stderr, "replace %s? ", source);
264
265                first = ch = getchar();
266                while (ch != '\n' && ch != EOF)
267                        ch = getchar();
268                if (first != 'y' && first != 'Y') {
269                        (void)fprintf(stderr, "not replaced\n");
270                        return (1);
271                }
272
273                if (unlink(source)) {
274                        warn("%s", source);
275                        return (1);
276                }
277        }
278
279        /* Attempt the link. */
280        if ((*linkf)(target, source)) {
281                warn("%s", source);
282                return (1);
283        }
284        if (vflag)
285                (void)printf("%s %c> %s\n", source, linkch, target);
286
287        return (0);
288}
289
290void
291usage(rtems_shell_ln_globals* globals)
292{
293#define getprogname() "ln"
294        (void)fprintf(stderr,
295            "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n",
296            getprogname(), getprogname());
297        exit(1);
298        /* NOTREACHED */
299}
300
301rtems_shell_cmd_t rtems_shell_LN_Command = {
302  "ln",                                         /* name */
303  "ln ln [-fhinsv] source_file [target_file]",  /* usage */
304  "files",                                      /* topic */
305  rtems_shell_main_ln,                          /* command */
306  NULL,                                         /* alias */
307  NULL                                          /* next */
308};
Note: See TracBrowser for help on using the repository browser.