Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /* $NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $ */
0002 
0003 /*
0004  * Copyright (c) 1987, 1993, 1994
0005  *  The Regents of the University of California.  All rights reserved.
0006  *
0007  * Redistribution and use in source and binary forms, with or without
0008  * modification, are permitted provided that the following conditions
0009  * are met:
0010  * 1. Redistributions of source code must retain the above copyright
0011  *    notice, this list of conditions and the following disclaimer.
0012  * 2. Redistributions in binary form must reproduce the above copyright
0013  *    notice, this list of conditions and the following disclaimer in the
0014  *    documentation and/or other materials provided with the distribution.
0015  * 3. Neither the name of the University nor the names of its contributors
0016  *    may be used to endorse or promote products derived from this software
0017  *    without specific prior written permission.
0018  *
0019  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0020  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0021  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0022  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0023  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0024  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0025  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0026  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0027  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0028  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0029  * SUCH DAMAGE.
0030  */
0031 
0032 #ifdef HAVE_CONFIG_H
0033 #include "config.h"
0034 #endif
0035 
0036 #if 0
0037 #ifndef lint
0038 __COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
0039  The Regents of the University of California.  All rights reserved.");
0040 #endif /* not lint */
0041 
0042 #ifndef lint
0043 #if 0
0044 static char sccsid[] = "@(#)ln.c    8.2 (Berkeley) 3/31/94";
0045 #else
0046 __RCSID("$NetBSD: ln.c,v 1.34 2008/07/20 00:52:40 lukem Exp $");
0047 #endif
0048 #endif /* not lint */
0049 #endif
0050 
0051 #include <rtems.h>
0052 #include <rtems/shell.h>
0053 #include <rtems/shellconfig.h>
0054 #define __need_getopt_newlib
0055 #include <getopt.h>
0056 
0057 #include <sys/cdefs.h>
0058 #include <sys/param.h>
0059 #include <sys/stat.h>
0060 
0061 #include "err.h"
0062 #include <errno.h>
0063 #include <locale.h>
0064 #include <stdio.h>
0065 #include <stdlib.h>
0066 #include <string.h>
0067 #include <unistd.h>
0068 
0069 #include <setjmp.h>
0070 
0071 typedef struct {
0072   int   fflag;              /* Unlink existing files. */
0073   int   hflag;              /* Check new name for symlink first. */
0074   int   iflag;              /* Interactive mode. */
0075   int   sflag;              /* Symbolic, not hard, link. */
0076   int   vflag;                          /* Verbose output */
0077   char   linkch;
0078 
0079   int exit_code;
0080   jmp_buf exit_jmp;
0081 } rtems_shell_ln_globals;
0082 
0083 #define fflag  globals->fflag
0084 #define hflag  globals->hflag
0085 #define iflag  globals->iflag
0086 #define sflag  globals->sflag
0087 #define vflag  globals->vflag
0088 #define linkch globals->linkch
0089 
0090 #define exit_jump &(globals->exit_jmp)
0091 
0092 #define exit(ec) rtems_shell_ln_exit(globals, ec)
0093 
0094 static int  main_ln(rtems_shell_ln_globals* , int, char *[]);
0095 
0096 static void
0097 rtems_shell_ln_exit (rtems_shell_ln_globals* globals, int code)
0098 {
0099   globals->exit_code = code;
0100   longjmp (globals->exit_jmp, 1);
0101 }
0102 
0103 static int main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[]);
0104 
0105 static int rtems_shell_main_ln(int argc, char *argv[])
0106 {
0107   rtems_shell_ln_globals  ln_globals;
0108   rtems_shell_ln_globals* globals = &ln_globals;
0109   memset (globals, 0, sizeof (ln_globals));
0110   ln_globals.exit_code = 1;
0111   if (setjmp (ln_globals.exit_jmp) == 0)
0112     return main_ln (globals, argc, argv);
0113   return ln_globals.exit_code;
0114 }
0115 
0116 #if RTEMS_REMOVED
0117 int fflag;              /* Unlink existing files. */
0118 int hflag;              /* Check new name for symlink first. */
0119 int iflag;              /* Interactive mode. */
0120 int sflag;              /* Symbolic, not hard, link. */
0121 int vflag;                          /* Verbose output */
0122 
0123                     /* System link call. */
0124 int (*linkf)(const char *, const char *);
0125 char   linkch;
0126 #endif
0127 
0128 int (*linkf)(const char *, const char *);
0129 
0130 static int  linkit(rtems_shell_ln_globals* , const char *, const char *, int);
0131 static void usage(rtems_shell_ln_globals* );
0132 
0133 static int
0134 main_ln(rtems_shell_ln_globals* globals, int argc, char *argv[])
0135 {
0136     struct stat sb;
0137     int ch, exitval;
0138     char *sourcedir;
0139 
0140     struct getopt_data getopt_reent;
0141     memset(&getopt_reent, 0, sizeof(getopt_data));
0142 
0143 #if RTEMS_REMOVED
0144     setprogname(argv[0]);
0145     (void)setlocale(LC_ALL, "");
0146 #endif
0147 
0148     while ((ch = getopt_r(argc, argv, "fhinsv", &getopt_reent)) != -1)
0149         switch (ch) {
0150         case 'f':
0151             fflag = 1;
0152             iflag = 0;
0153             break;
0154         case 'h':
0155         case 'n':
0156             hflag = 1;
0157             break;
0158         case 'i':
0159             iflag = 1;
0160             fflag = 0;
0161             break;
0162         case 's':
0163             sflag = 1;
0164             break;
0165         case 'v':
0166             vflag = 1;
0167             break;
0168         case '?':
0169         default:
0170             usage(globals);
0171             /* NOTREACHED */
0172         }
0173 
0174     argv += getopt_reent.optind;
0175     argc -= getopt_reent.optind;
0176 
0177     if (sflag) {
0178         linkf  = symlink;
0179         linkch = '-';
0180     } else {
0181         linkf  = link;
0182         linkch = '=';
0183     }
0184 
0185     switch(argc) {
0186     case 0:
0187         usage(globals);
0188         /* NOTREACHED */
0189     case 1:             /* ln target */
0190         exit(linkit(globals, argv[0], ".", 1));
0191         /* NOTREACHED */
0192     case 2:             /* ln target source */
0193         exit(linkit(globals, argv[0], argv[1], 0));
0194         /* NOTREACHED */
0195     }
0196 
0197                     /* ln target1 target2 directory */
0198     sourcedir = argv[argc - 1];
0199     if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
0200         /* we were asked not to follow symlinks, but found one at
0201            the target--simulate "not a directory" error */
0202         errno = ENOTDIR;
0203         err(exit_jump, EXIT_FAILURE, "%s", sourcedir);
0204         /* NOTREACHED */
0205     }
0206     if (stat(sourcedir, &sb)) {
0207         err(exit_jump, EXIT_FAILURE, "%s", sourcedir);
0208         /* NOTREACHED */
0209     }
0210     if (!S_ISDIR(sb.st_mode)) {
0211         usage(globals);
0212         /* NOTREACHED */
0213     }
0214     for (exitval = 0; *argv != sourcedir; ++argv)
0215         exitval |= linkit(globals, *argv, sourcedir, 1);
0216     exit(exitval);
0217     /* NOTREACHED */
0218   return 0;
0219 }
0220 
0221 int
0222 linkit(rtems_shell_ln_globals* globals, const char *source, const char *target, int isdir)
0223 {
0224     struct stat sb;
0225     const char *p;
0226     char path[MAXPATHLEN];
0227     int ch, exists, first;
0228 
0229     if (!sflag) {
0230         /* If target doesn't exist, quit now. */
0231         if (stat(target, &sb)) {
0232             warn("%s", target);
0233             return (1);
0234         }
0235     }
0236 
0237     /* If the source is a directory (and not a symlink if hflag),
0238        append the target's name. */
0239     if (isdir ||
0240         (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
0241         (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
0242         if ((p = strrchr(target, '/')) == NULL)
0243             p = target;
0244         else
0245             ++p;
0246         (void)snprintf(path, sizeof(path), "%s/%s", source, p);
0247         source = path;
0248     }
0249 
0250     exists = !lstat(source, &sb);
0251 
0252     /*
0253      * If the file exists, then unlink it forcibly if -f was specified
0254      * and interactively if -i was specified.
0255      */
0256     if (fflag && exists) {
0257         if (unlink(source)) {
0258             warn("%s", source);
0259             return (1);
0260         }
0261     } else if (iflag && exists) {
0262         fflush(stdout);
0263         (void)fprintf(stderr, "replace %s? ", source);
0264 
0265         first = ch = getchar();
0266         while (ch != '\n' && ch != EOF)
0267             ch = getchar();
0268         if (first != 'y' && first != 'Y') {
0269             (void)fprintf(stderr, "not replaced\n");
0270             return (1);
0271         }
0272 
0273         if (unlink(source)) {
0274             warn("%s", source);
0275             return (1);
0276         }
0277     }
0278 
0279     /* Attempt the link. */
0280     if ((*linkf)(target, source)) {
0281         warn("%s", source);
0282         return (1);
0283     }
0284     if (vflag)
0285         (void)printf("%s %c> %s\n", source, linkch, target);
0286 
0287     return (0);
0288 }
0289 
0290 void
0291 usage(rtems_shell_ln_globals* globals)
0292 {
0293 #define getprogname() "ln"
0294     (void)fprintf(stderr,
0295         "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n",
0296         getprogname(), getprogname());
0297     exit(1);
0298     /* NOTREACHED */
0299 }
0300 
0301 rtems_shell_cmd_t rtems_shell_LN_Command = {
0302   "ln",                                         /* name */
0303   "ln ln [-fhinsv] source_file [target_file]",  /* usage */
0304   "files",                                      /* topic */
0305   rtems_shell_main_ln,                          /* command */
0306   NULL,                                         /* alias */
0307   NULL                                          /* next */
0308 };