blob: 16514ee708188102c9bc98f3e7542444f9ca1583 [file] [log] [blame]
Jari Aaltob72432f1999-02-19 17:11:39 +00001/* ln - make links */
2
3/* See Makefile for compilation details. */
4
Jari Aalto31859422009-01-12 13:36:28 +00005/*
6 Copyright (C) 1999-2009 Free Software Foundation, Inc.
7
8 This file is part of GNU Bash.
9 Bash is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Bash is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21*/
22
Jari Aaltob72432f1999-02-19 17:11:39 +000023#include "config.h"
24
25#include "bashtypes.h"
26
27#if defined (HAVE_UNISTD_H)
28# include <unistd.h>
29#endif
30
31#include "posixstat.h"
32
33#include <stdio.h>
34#include <errno.h>
35
36#include "builtins.h"
37#include "shell.h"
38#include "bashgetopt.h"
Jari Aalto31859422009-01-12 13:36:28 +000039#include "common.h"
Jari Aaltob72432f1999-02-19 17:11:39 +000040
41#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010042#include <errno.h>
Jari Aaltob72432f1999-02-19 17:11:39 +000043#endif
44
Jari Aaltof73dda02001-11-13 17:56:06 +000045typedef int unix_link_syscall_t __P((const char *, const char *));
46
Jari Aaltob72432f1999-02-19 17:11:39 +000047#define LN_SYMLINK 0x01
48#define LN_UNLINK 0x02
49
Jari Aaltof73dda02001-11-13 17:56:06 +000050static unix_link_syscall_t *linkfn;
Jari Aaltob72432f1999-02-19 17:11:39 +000051static int dolink ();
52
53ln_builtin (list)
54 WORD_LIST *list;
55{
56 int rval, opt, flags;
57 WORD_LIST *l;
58 char *sdir;
59 struct stat sb;
60
61 flags = 0;
62 reset_internal_getopt ();
63 while ((opt = internal_getopt (list, "fs")) != -1)
64 {
65 switch (opt)
66 {
67 case 'f':
68 flags |= LN_UNLINK;
69 break;
70 case 's':
71 flags |= LN_SYMLINK;
72 break;
73 default:
74 builtin_usage ();
75 return (EX_USAGE);
76 }
77 }
78 list = loptend;
79
80 if (list == 0)
81 {
82 builtin_usage ();
83 return (EX_USAGE);
84 }
85
86 linkfn = (flags & LN_SYMLINK) ? symlink : link;
87
88 if (list->next == 0) /* ln target, equivalent to ln target . */
89 return (dolink (list->word->word, ".", flags));
90
91 if (list->next->next == 0) /* ln target source */
92 return (dolink (list->word->word, list->next->word->word, flags));
93
94 /* ln target1 target2 ... directory */
95
96 /* find last argument: target directory, and make sure it's an existing
97 directory. */
98 for (l = list; l->next; l = l->next)
99 ;
100 sdir = l->word->word;
101
102 if (stat(sdir, &sb) < 0)
103 {
104 builtin_error ("%s", sdir);
105 return (EXECUTION_FAILURE);
106 }
107
108 if (S_ISDIR (sb.st_mode) == 0)
109 {
110 builtin_usage ();
111 return (EX_USAGE);
112 }
113
114 for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
115 rval += dolink (list->word->word, sdir, flags);
116
117 return rval;
118}
119
120static char *
121mkdirpath (dir, file)
122 char *dir, *file;
123{
124 int dlen, flen;
125 char *ret;
126
127 dlen = strlen (dir);
128 flen = strlen (file);
129
130 ret = xmalloc (2 + dlen + flen);
131
132 strcpy (ret, dir);
133 if (ret[dlen - 1] != '/')
134 ret[dlen++] = '/';
135 strcpy (ret + dlen, file);
136 return ret;
137}
138
139#if defined (HAVE_LSTAT)
140# define LSTAT lstat
141#else
142# define LSTAT stat
143#endif
144
145static int
146dolink (src, dst, flags)
147 char *src, *dst;
148 int flags;
149{
150 struct stat ssb, dsb;
151 int exists;
152 char *dst_path, *p;
153
154 /* If we're not doing symlinks, the source must exist and not be a
155 directory. */
156 if ((flags & LN_SYMLINK) == 0)
157 {
158 if (stat (src, &ssb) != 0)
159 {
160 builtin_error ("%s: %s", src, strerror (errno));
161 return (EXECUTION_FAILURE);
162 }
163 if (S_ISDIR (ssb.st_mode))
164 {
165 errno = EISDIR;
166 builtin_error ("%s: %s", src, strerror (errno));
167 return (EXECUTION_FAILURE);
168 }
169 }
170
171 /* If the destination is a directory, create the final filename by appending
172 the basename of the source to the destination. */
173 dst_path = 0;
174 if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
175 {
176 if ((p = strrchr (src, '/')) == 0)
177 p = src;
178 else
179 p++;
180
181 dst_path = mkdirpath (dst, p);
182 dst = dst_path;
183 }
184
185 exists = LSTAT (dst, &dsb) == 0;
186
187 /* If -f was specified, and the destination exists, unlink it. */
188 if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
189 {
190 builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
191 FREE (dst_path);
192 return (EXECUTION_FAILURE);
193 }
194
195 /* Perform the link. */
196 if ((*linkfn) (src, dst) != 0)
197 {
198 builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
199 FREE (dst_path);
200 return (EXECUTION_FAILURE);
201 }
202
203 FREE (dst_path);
204 return (EXECUTION_SUCCESS);
205}
206
207char *ln_doc[] = {
Jari Aalto31859422009-01-12 13:36:28 +0000208 "Link files.",
209 "",
Jari Aaltob72432f1999-02-19 17:11:39 +0000210 "Create a new directory entry with the same modes as the original",
211 "file. The -f option means to unlink any existing file, permitting",
212 "the link to occur. The -s option means to create a symbolic link.",
213 "By default, ln makes hard links.",
214 (char *)NULL
215};
216
217/* The standard structure describing a builtin command. bash keeps an array
218 of these structures. */
219struct builtin ln_struct = {
220 "ln", /* builtin name */
221 ln_builtin, /* function implementing the builtin */
222 BUILTIN_ENABLED, /* initial flags for builtin */
223 ln_doc, /* array of long documentation strings. */
224 "ln [-fs] file1 [file2] OR ln [-fs] file ... directory", /* usage synopsis; becomes short_doc */
225 0 /* reserved for internal use */
226};