blob: 1a7d24e6dc1418d03b220ef181c91931e80102cc [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* `sln' program to create symbolic links between files.
2 Copyright (C) 1998-2015 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#ifdef HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include <error.h>
24#include <errno.h>
25#include <libintl.h>
26#include <locale.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h>
30#include <errno.h>
31#include <ctype.h>
32#include <stdio.h>
33#include <string.h>
34#include <limits.h>
35
36#include "../version.h"
37
38#define PACKAGE _libc_intl_domainname
39
40#if !defined S_ISDIR && defined S_IFDIR
41#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
42#endif
43
44static int makesymlink (const char *src, const char *dest);
45static int makesymlinks (const char *file);
46static void usage (void);
47
48int
49main (int argc, char **argv)
50{
51 /* Set locale via LC_ALL. */
52 setlocale (LC_ALL, "");
53
54 /* Set the text message domain. */
55 textdomain (PACKAGE);
56
57 switch (argc)
58 {
59 case 2:
60 if (strcmp (argv[1], "--version") == 0) {
61 printf ("sln %s%s\n", PKGVERSION, VERSION);
62 return 0;
63 } else if (strcmp (argv[1], "--help") == 0) {
64 usage ();
65 return 0;
66 }
67 return makesymlinks (argv [1]);
68 break;
69
70 case 3:
71 return makesymlink (argv [1], argv [2]);
72 break;
73
74 default:
75 usage ();
76 return 1;
77 break;
78 }
79}
80
81static void
82usage (void)
83{
84 printf (_("Usage: sln src dest|file\n\n"));
85 printf (_("For bug reporting instructions, please see:\n\
86%s.\n"), REPORT_BUGS_TO);
87}
88
89static int
90makesymlinks (file)
91 const char *file;
92{
93#ifndef PATH_MAX
94#define PATH_MAX 4095
95#endif
96 char *buffer = NULL;
97 size_t bufferlen = 0;
98 int ret;
99 int lineno;
100 FILE *fp;
101
102 if (strcmp (file, "-") == 0)
103 fp = stdin;
104 else
105 {
106 fp = fopen (file, "r");
107 if (fp == NULL)
108 {
109 fprintf (stderr, _("%s: file open error: %m\n"), file);
110 return 1;
111 }
112 }
113
114 ret = 0;
115 lineno = 0;
116 while (!feof_unlocked (fp))
117 {
118 ssize_t n = getline (&buffer, &bufferlen, fp);
119 char *src;
120 char *dest;
121 char *cp = buffer;
122
123 if (n < 0)
124 break;
125 if (buffer[n - 1] == '\n')
126 buffer[n - 1] = '\0';
127
128 ++lineno;
129 while (isspace (*cp))
130 ++cp;
131 if (*cp == '\0')
132 /* Ignore empty lines. */
133 continue;
134 src = cp;
135
136 do
137 ++cp;
138 while (*cp != '\0' && ! isspace (*cp));
139 if (*cp != '\0')
140 *cp++ = '\0';
141
142 while (isspace (*cp))
143 ++cp;
144 if (*cp == '\0')
145 {
146 fprintf (stderr, _("No target in line %d\n"), lineno);
147 ret = 1;
148 continue;
149 }
150 dest = cp;
151
152 do
153 ++cp;
154 while (*cp != '\0' && ! isspace (*cp));
155 if (*cp != '\0')
156 *cp++ = '\0';
157
158 ret |= makesymlink (src, dest);
159 }
160 fclose (fp);
161
162 return ret;
163}
164
165static int
166makesymlink (src, dest)
167 const char *src;
168 const char *dest;
169{
170 struct stat stats;
171 const char *error;
172
173 /* Destination must not be a directory. */
174 if (lstat (dest, &stats) == 0)
175 {
176 if (S_ISDIR (stats.st_mode))
177 {
178 fprintf (stderr, _("%s: destination must not be a directory\n"),
179 dest);
180 return 1;
181 }
182 else if (unlink (dest) && errno != ENOENT)
183 {
184 fprintf (stderr, _("%s: failed to remove the old destination\n"),
185 dest);
186 return 1;
187 }
188 }
189 else if (errno != ENOENT)
190 {
191 error = strerror (errno);
192 fprintf (stderr, _("%s: invalid destination: %s\n"), dest, error);
193 return -1;
194 }
195
196#ifdef S_ISLNK
197 if (symlink (src, dest) == 0)
198#else
199 if (link (src, dest) == 0)
200#endif
201 {
202 /* Destination must exist by now. */
203 if (access (dest, F_OK))
204 {
205 error = strerror (errno);
206 unlink (dest);
207 fprintf (stderr, _("Invalid link from \"%s\" to \"%s\": %s\n"),
208 src, dest, error);
209 return 1;
210 }
211 return 0;
212 }
213 else
214 {
215 error = strerror (errno);
216 fprintf (stderr, _("Invalid link from \"%s\" to \"%s\": %s\n"),
217 src, dest, error);
218 return 1;
219 }
220}