1/* ln - make links */ 2 3/* See Makefile for compilation details. */ 4 5#include "config.h" 6 7#include "bashtypes.h" 8 9#if defined (HAVE_UNISTD_H) 10# include <unistd.h> 11#endif 12 13#include "posixstat.h" 14 15#include <stdio.h> 16#include <errno.h> 17 18#include "builtins.h" 19#include "shell.h" 20#include "bashgetopt.h" 21 22#if !defined (errno) 23extern int errno; 24#endif 25 26typedef int unix_link_syscall_t __P((const char *, const char *)); 27 28#define LN_SYMLINK 0x01 29#define LN_UNLINK 0x02 30 31static unix_link_syscall_t *linkfn; 32static int dolink (); 33 34ln_builtin (list) 35 WORD_LIST *list; 36{ 37 int rval, opt, flags; 38 WORD_LIST *l; 39 char *sdir; 40 struct stat sb; 41 42 flags = 0; 43 reset_internal_getopt (); 44 while ((opt = internal_getopt (list, "fs")) != -1) 45 { 46 switch (opt) 47 { 48 case 'f': 49 flags |= LN_UNLINK; 50 break; 51 case 's': 52 flags |= LN_SYMLINK; 53 break; 54 default: 55 builtin_usage (); 56 return (EX_USAGE); 57 } 58 } 59 list = loptend; 60 61 if (list == 0) 62 { 63 builtin_usage (); 64 return (EX_USAGE); 65 } 66 67 linkfn = (flags & LN_SYMLINK) ? symlink : link; 68 69 if (list->next == 0) /* ln target, equivalent to ln target . */ 70 return (dolink (list->word->word, ".", flags)); 71 72 if (list->next->next == 0) /* ln target source */ 73 return (dolink (list->word->word, list->next->word->word, flags)); 74 75 /* ln target1 target2 ... directory */ 76 77 /* find last argument: target directory, and make sure it's an existing 78 directory. */ 79 for (l = list; l->next; l = l->next) 80 ; 81 sdir = l->word->word; 82 83 if (stat(sdir, &sb) < 0) 84 { 85 builtin_error ("%s", sdir); 86 return (EXECUTION_FAILURE); 87 } 88 89 if (S_ISDIR (sb.st_mode) == 0) 90 { 91 builtin_usage (); 92 return (EX_USAGE); 93 } 94 95 for (rval = EXECUTION_SUCCESS; list != l; list = list->next) 96 rval += dolink (list->word->word, sdir, flags); 97 98 return rval; 99} 100 101static char * 102mkdirpath (dir, file) 103 char *dir, *file; 104{ 105 int dlen, flen; 106 char *ret; 107 108 dlen = strlen (dir); 109 flen = strlen (file); 110 111 ret = xmalloc (2 + dlen + flen); 112 113 strcpy (ret, dir); 114 if (ret[dlen - 1] != '/') 115 ret[dlen++] = '/'; 116 strcpy (ret + dlen, file); 117 return ret; 118} 119 120#if defined (HAVE_LSTAT) 121# define LSTAT lstat 122#else 123# define LSTAT stat 124#endif 125 126static int 127dolink (src, dst, flags) 128 char *src, *dst; 129 int flags; 130{ 131 struct stat ssb, dsb; 132 int exists; 133 char *dst_path, *p; 134 135 /* If we're not doing symlinks, the source must exist and not be a 136 directory. */ 137 if ((flags & LN_SYMLINK) == 0) 138 { 139 if (stat (src, &ssb) != 0) 140 { 141 builtin_error ("%s: %s", src, strerror (errno)); 142 return (EXECUTION_FAILURE); 143 } 144 if (S_ISDIR (ssb.st_mode)) 145 { 146 errno = EISDIR; 147 builtin_error ("%s: %s", src, strerror (errno)); 148 return (EXECUTION_FAILURE); 149 } 150 } 151 152 /* If the destination is a directory, create the final filename by appending 153 the basename of the source to the destination. */ 154 dst_path = 0; 155 if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode)) 156 { 157 if ((p = strrchr (src, '/')) == 0) 158 p = src; 159 else 160 p++; 161 162 dst_path = mkdirpath (dst, p); 163 dst = dst_path; 164 } 165 166 exists = LSTAT (dst, &dsb) == 0; 167 168 /* If -f was specified, and the destination exists, unlink it. */ 169 if ((flags & LN_UNLINK) && exists && unlink (dst) != 0) 170 { 171 builtin_error ("%s: cannot unlink: %s", dst, strerror (errno)); 172 FREE (dst_path); 173 return (EXECUTION_FAILURE); 174 } 175 176 /* Perform the link. */ 177 if ((*linkfn) (src, dst) != 0) 178 { 179 builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno)); 180 FREE (dst_path); 181 return (EXECUTION_FAILURE); 182 } 183 184 FREE (dst_path); 185 return (EXECUTION_SUCCESS); 186} 187 188char *ln_doc[] = { 189 "Create a new directory entry with the same modes as the original", 190 "file. The -f option means to unlink any existing file, permitting", 191 "the link to occur. The -s option means to create a symbolic link.", 192 "By default, ln makes hard links.", 193 (char *)NULL 194}; 195 196/* The standard structure describing a builtin command. bash keeps an array 197 of these structures. */ 198struct builtin ln_struct = { 199 "ln", /* builtin name */ 200 ln_builtin, /* function implementing the builtin */ 201 BUILTIN_ENABLED, /* initial flags for builtin */ 202 ln_doc, /* array of long documentation strings. */ 203 "ln [-fs] file1 [file2] OR ln [-fs] file ... directory", /* usage synopsis; becomes short_doc */ 204 0 /* reserved for internal use */ 205}; 206