]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/rename.c
cbda638e18faa3a999c0dd645b564ecfa5fc9c86
[thirdparty/util-linux.git] / misc-utils / rename.c
1 /*
2 * rename.c - aeb 2000-01-01
3 *
4 --------------------------------------------------------------
5 #!/bin/sh
6 if [ $# -le 2 ]; then echo call: rename from to files; exit; fi
7 FROM="$1"
8 TO="$2"
9 shift
10 shift
11 for i in $@; do N=`echo "$i" | sed "s/$FROM/$TO/g"`; mv "$i" "$N"; done
12 --------------------------------------------------------------
13 * This shell script will do renames of files, but may fail
14 * in cases involving special characters. Here a C version.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <getopt.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include "nls.h"
26 #include "xalloc.h"
27 #include "c.h"
28 #include "closestream.h"
29
30 #define RENAME_EXIT_SOMEOK 2
31 #define RENAME_EXIT_NOTHING 4
32 #define RENAME_EXIT_UNEXPLAINED 64
33
34 static int string_replace(char *from, char *to, char *s, char *orig, char **newname)
35 {
36 char *p, *q, *where;
37
38 where = strstr(s, from);
39 if (where == NULL)
40 return 1;
41 p = orig;
42 *newname = xmalloc(strlen(orig) + strlen(to) + 1);
43 q = *newname;
44 while (p < where)
45 *q++ = *p++;
46 p = to;
47 while (*p)
48 *q++ = *p++;
49 p = where + strlen(from);
50 while (*p)
51 *q++ = *p++;
52 *q = 0;
53 return 0;
54 }
55
56 static int do_symlink(char *from, char *to, char *s, int verbose, int noact, int nooverwrite)
57 {
58 char *newname = NULL, *target = NULL;
59 int ret = 1;
60 struct stat sb;
61
62 if (lstat(s, &sb) == -1) {
63 warn(_("stat of %s failed"), s);
64 return 2;
65 }
66 if (!S_ISLNK(sb.st_mode)) {
67 warnx(_("%s: not a symbolic link"), s);
68 return 2;
69 }
70 target = xmalloc(sb.st_size + 1);
71 if (readlink(s, target, sb.st_size + 1) < 0) {
72 warn(_("%s: readlink failed"), s);
73 free(target);
74 return 2;
75 }
76 target[sb.st_size] = '\0';
77 if (string_replace(from, to, target, target, &newname))
78 ret = 0;
79
80 if (ret == 1 && nooverwrite && lstat(newname, &sb) == 0) {
81 if (verbose)
82 printf(_("Skipping existing link: `%s'\n"), newname);
83
84 ret = 0;
85 }
86
87 if (ret == 1) {
88 if (!noact && 0 > unlink(s)) {
89 warn(_("%s: unlink failed"), s);
90 ret = 2;
91 } else if (!noact && symlink(newname, s) != 0) {
92 warn(_("%s: symlinking to %s failed"), s, newname);
93 ret = 2;
94 }
95 }
96 if (verbose && (noact || ret == 1))
97 if (verbose)
98 printf("%s: `%s' -> `%s'\n", s, target, newname);
99 free(newname);
100 free(target);
101 return ret;
102 }
103
104 static int do_file(char *from, char *to, char *s, int verbose, int noact, int nooverwrite)
105 {
106 char *newname = NULL, *file=NULL;
107 int ret = 1;
108
109 if (strchr(from, '/') == NULL && strchr(to, '/') == NULL)
110 file = strrchr(s, '/');
111 if (file == NULL)
112 file = s;
113 if (string_replace(from, to, file, s, &newname))
114 return 0;
115 if (nooverwrite && access(newname, F_OK) == 0) {
116 printf(_("Skipping existing file: `%s'\n"), newname);
117 ret = 0;
118 }
119 else if (!noact && rename(s, newname) != 0) {
120 warn(_("%s: rename to %s failed"), s, newname);
121 ret = 2;
122 }
123 if (verbose && (noact || ret == 1))
124 printf("`%s' -> `%s'\n", s, newname);
125 free(newname);
126 return ret;
127 }
128
129 static void __attribute__((__noreturn__)) usage(void)
130 {
131 FILE *out = stdout;
132 fputs(USAGE_HEADER, out);
133 fprintf(out,
134 _(" %s [options] <expression> <replacement> <file>...\n"),
135 program_invocation_short_name);
136
137 fputs(USAGE_SEPARATOR, out);
138 fputs(_("Rename files.\n"), out);
139
140 fputs(USAGE_OPTIONS, out);
141 fputs(_(" -v, --verbose explain what is being done\n"), out);
142 fputs(_(" -s, --symlink act on the target of symlinks\n"), out);
143 fputs(_(" -n, --no-act do not make any changes\n"), out);
144 fputs(_(" -o, --no-overwrite don't overwrite existing files\n"), out);
145 fputs(USAGE_SEPARATOR, out);
146 printf(USAGE_HELP_OPTIONS(21));
147 printf(USAGE_MAN_TAIL("rename(1)"));
148 exit(EXIT_SUCCESS);
149 }
150
151 int main(int argc, char **argv)
152 {
153 char *from, *to;
154 int i, c, ret = 0, verbose = 0, noact = 0, nooverwrite = 0;
155 int (*do_rename)(char *from, char *to, char *s, int verbose, int noact, int nooverwrite) = do_file;
156
157 static const struct option longopts[] = {
158 {"verbose", no_argument, NULL, 'v'},
159 {"version", no_argument, NULL, 'V'},
160 {"help", no_argument, NULL, 'h'},
161 {"no-act", no_argument, NULL, 'n'},
162 {"no-overwrite", no_argument, NULL, 'o'},
163 {"symlink", no_argument, NULL, 's'},
164 {NULL, 0, NULL, 0}
165 };
166
167 setlocale(LC_ALL, "");
168 bindtextdomain(PACKAGE, LOCALEDIR);
169 textdomain(PACKAGE);
170 atexit(close_stdout);
171
172 while ((c = getopt_long(argc, argv, "vsVhno", longopts, NULL)) != -1)
173 switch (c) {
174 case 'n':
175 noact = 1;
176 /* fallthrough */
177 case 'o':
178 nooverwrite = 1;
179 break;
180 case 'v':
181 verbose = 1;
182 break;
183 case 's':
184 do_rename = do_symlink;
185 break;
186 case 'V':
187 printf(UTIL_LINUX_VERSION);
188 return EXIT_SUCCESS;
189 case 'h':
190 usage();
191 default:
192 errtryhelp(EXIT_FAILURE);
193 }
194
195 argc -= optind;
196 argv += optind;
197
198 if (argc < 3) {
199 warnx(_("not enough arguments"));
200 errtryhelp(EXIT_FAILURE);
201 }
202
203 from = argv[0];
204 to = argv[1];
205
206 if (!strcmp(from, to))
207 return RENAME_EXIT_NOTHING;
208
209 for (i = 2; i < argc; i++)
210 ret |= do_rename(from, to, argv[i], verbose, noact, nooverwrite);
211
212 switch (ret) {
213 case 0:
214 return RENAME_EXIT_NOTHING;
215 case 1:
216 return EXIT_SUCCESS;
217 case 2:
218 return EXIT_FAILURE;
219 case 3:
220 return RENAME_EXIT_SOMEOK;
221 default:
222 return RENAME_EXIT_UNEXPLAINED;
223 }
224 }