]> git.ipfire.org Git - thirdparty/util-linux.git/blob - misc-utils/rename.c
rename: continue despite something failed
[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 do_rename(char *from, char *to, char *s, int verbose, int symtarget)
35 {
36 char *newname = NULL, *where, *p, *q, *target = NULL;
37 int flen, tlen, slen, ret = 1;
38 struct stat sb;
39
40 if (symtarget) {
41 if (lstat(s, &sb) == -1) {
42 warn(_("%s: lstat failed"), s);
43 return 2;
44 }
45 if (!S_ISLNK(sb.st_mode)) {
46 warnx(_("%s: not a symbolic link"), s);
47 return 2;
48 }
49
50 target = xmalloc(sb.st_size + 1);
51 if (readlink(s, target, sb.st_size + 1) < 0) {
52 warn(_("%s: readlink failed"), s);
53 ret = 2;
54 goto out;
55 }
56
57 target[sb.st_size] = '\0';
58 where = strstr(target, from);
59 } else {
60 char *file;
61
62 file = rindex(s, '/');
63 if (file == NULL)
64 file = s;
65 where = strstr(file, from);
66 }
67 if (where == NULL) {
68 free(target);
69 return 0;
70 }
71
72 flen = strlen(from);
73 tlen = strlen(to);
74 if (symtarget) {
75 slen = strlen(target);
76 p = target;
77 } else {
78 slen = strlen(s);
79 p = s;
80 }
81 newname = xmalloc(tlen + slen + 1);
82
83 q = newname;
84 while (p < where)
85 *q++ = *p++;
86 p = to;
87 while (*p)
88 *q++ = *p++;
89 p = where + flen;
90 while (*p)
91 *q++ = *p++;
92 *q = 0;
93
94 if (symtarget) {
95 if (0 > unlink(s)) {
96 warn(_("%s: unlink failed"), s);
97 ret = 2;
98 goto out;
99 }
100 if (symlink(newname, s) != 0) {
101 warn(_("%s: symlinking to %s failed"), s, newname);
102 ret = 2;
103 goto out;
104 }
105 if (verbose)
106 printf("%s: `%s' -> `%s'\n", s, target, newname);
107 } else {
108 if (rename(s, newname) != 0) {
109 warn(_("%s: rename to %s failed"), s, newname);
110 ret = 2;
111 goto out;
112 }
113 if (verbose)
114 printf("`%s' -> `%s'\n", s, newname);
115 }
116 out:
117 free(newname);
118 free(target);
119 return ret;
120 }
121
122 static void __attribute__ ((__noreturn__)) usage(FILE * out)
123 {
124 fputs(USAGE_HEADER, out);
125 fprintf(out,
126 _(" %s [options] expression replacement file...\n"),
127 program_invocation_short_name);
128 fputs(USAGE_OPTIONS, out);
129 fputs(_(" -v, --verbose explain what is being done\n"), out);
130 fputs(_(" -s, --symlink act on symlink target\n"), out);
131 fputs(USAGE_SEPARATOR, out);
132 fputs(USAGE_HELP, out);
133 fputs(USAGE_VERSION, out);
134 fprintf(out, USAGE_MAN_TAIL("rename(1)"));
135 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
136 }
137
138 int main(int argc, char **argv)
139 {
140 char *from, *to;
141 int i, c, ret = 0, symtarget = 0, verbose = 0;
142
143 static const struct option longopts[] = {
144 {"verbose", no_argument, NULL, 'v'},
145 {"version", no_argument, NULL, 'V'},
146 {"help", no_argument, NULL, 'h'},
147 {"symlink", no_argument, NULL, 's'},
148 {NULL, 0, NULL, 0}
149 };
150
151 setlocale(LC_ALL, "");
152 bindtextdomain(PACKAGE, LOCALEDIR);
153 textdomain(PACKAGE);
154 atexit(close_stdout);
155
156 while ((c = getopt_long(argc, argv, "vsVh", longopts, NULL)) != -1)
157 switch (c) {
158 case 'v':
159 verbose = 1;
160 break;
161 case 's':
162 symtarget = 1;
163 break;
164 case 'V':
165 printf(UTIL_LINUX_VERSION);
166 return EXIT_SUCCESS;
167 case 'h':
168 usage(stdout);
169 default:
170 usage(stderr);
171 }
172
173 argc -= optind;
174 argv += optind;
175
176 if (argc < 3) {
177 warnx(_("not enough arguments"));
178 usage(stderr);
179 }
180
181 from = argv[0];
182 to = argv[1];
183
184 for (i = 2; i < argc; i++)
185 ret |= do_rename(from, to, argv[i], verbose, symtarget);
186
187 switch (ret) {
188 case 0:
189 return RENAME_EXIT_NOTHING;
190 case 1:
191 return EXIT_SUCCESS;
192 case 2:
193 return EXIT_FAILURE;
194 case 3:
195 return RENAME_EXIT_SOMEOK;
196 default:
197 return RENAME_EXIT_UNEXPLAINED;
198 }
199 }