move to /var
[unix-history] / usr / src / bin / mv / mv.c
CommitLineData
bcf1365c 1/*
50da9e1a
KB
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Ken Smith of The State University of New York at Buffalo.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
bcf1365c
DF
19 */
20
21#ifndef lint
22char copyright[] =
50da9e1a 23"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
bcf1365c 24 All rights reserved.\n";
8161a03a 25#endif /* not lint */
bcf1365c 26
d53fe8dd 27#ifndef lint
50da9e1a 28static char sccsid[] = "@(#)mv.c 5.8 (Berkeley) %G%";
8161a03a 29#endif /* not lint */
2a7e674d 30
d53fe8dd 31#include <sys/param.h>
465786e2 32#include <sys/time.h>
50da9e1a
KB
33#include <sys/wait.h>
34#include <sys/stat.h>
c7911f92 35#include <sys/file.h>
50da9e1a 36#include <sys/errno.h>
3880b4a9 37#include <stdio.h>
50da9e1a
KB
38#include <string.h>
39#include "pathnames.h"
3880b4a9 40
50da9e1a
KB
41extern int errno;
42int fflg, iflg;
3880b4a9
BJ
43
44main(argc, argv)
50da9e1a
KB
45 int argc;
46 char **argv;
3880b4a9 47{
50da9e1a 48 extern char *optarg;
8161a03a 49 extern int optind;
50da9e1a
KB
50 register int baselen, exitval, len;
51 register char *p, *endp;
52 struct stat sbuf;
53 int ch;
54 char path[MAXPATHLEN + 1];
3880b4a9 55
50da9e1a 56 while (((ch = getopt(argc, argv, "-if")) != EOF))
8161a03a 57 switch((char)ch) {
d53fe8dd 58 case 'i':
50da9e1a
KB
59 ++iflg;
60 break;
61 case 'f':
62 ++fflg;
d53fe8dd 63 break;
50da9e1a
KB
64 case '-': /* undocumented; for compatibility */
65 goto endarg;
8161a03a 66 case '?':
d53fe8dd 67 default:
8161a03a 68 usage();
d53fe8dd 69 }
50da9e1a
KB
70endarg: argc -= optind;
71 argv += optind;
8161a03a
KB
72
73 if (argc < 2)
74 usage();
d53fe8dd 75
50da9e1a
KB
76 /*
77 * if stat fails on target, it doesn't exist (or can't be accessed
78 * by the user, doesn't matter which) try the move. If target exists,
79 * and isn't a directory, try the move. More than 2 arguments is an
80 * error.
81 */
82 if (stat(argv[argc - 1], &sbuf) || !S_ISDIR(sbuf.st_mode)) {
83 if (argc > 2)
84 usage();
85 exit(do_move(argv[0], argv[1]));
86 }
d53fe8dd 87
50da9e1a
KB
88 /* got a directory, move each file into it */
89 (void)strcpy(path, argv[argc - 1]);
90 baselen = strlen(path);
91 endp = &path[baselen];
92 *endp++ = '/';
93 ++baselen;
94 for (exitval = 0; --argc; ++argv) {
95 if ((p = rindex(*argv, '/')) == NULL)
96 p = *argv;
97 else
98 ++p;
99 if ((baselen + (len = strlen(p))) >= MAXPATHLEN)
100 (void)fprintf(stderr,
101 "mv: %s: destination pathname too long\n", *argv);
102 else {
103 bcopy(p, endp, len + 1);
104 exitval |= do_move(*argv, path);
105 }
d53fe8dd 106 }
50da9e1a 107 exit(exitval);
3880b4a9
BJ
108}
109
50da9e1a
KB
110do_move(from, to)
111 char *from, *to;
3880b4a9 112{
50da9e1a
KB
113 struct stat sbuf;
114 int ask, ch;
3880b4a9 115
d53fe8dd 116 /*
50da9e1a
KB
117 * Check access. If interactive and file exists ask user if it
118 * should be replaced. Otherwise if file exists but isn't writable
119 * make sure the user wants to clobber it.
d53fe8dd 120 */
50da9e1a
KB
121 if (!fflg && !access(to, F_OK)) {
122 ask = 0;
123 if (iflg) {
124 (void)fprintf(stderr, "overwrite %s? ", to);
125 ask = 1;
126 }
127 else if (access(to, W_OK) && !stat(to, &sbuf)) {
128 (void)fprintf(stderr, "override mode %o on %s? ",
129 sbuf.st_mode & 07777, to);
130 ask = 1;
131 }
132 if (ask) {
133 if ((ch = getchar()) != EOF && ch != '\n')
134 while (getchar() != '\n');
135 if (ch != 'y')
136 return(0);
3880b4a9 137 }
b07dfbb8 138 }
50da9e1a
KB
139 if (!rename(from, to))
140 return(0);
b07dfbb8 141 if (errno != EXDEV) {
50da9e1a
KB
142 (void)fprintf(stderr,
143 "mv: rename %s to %s: %s\n", from, to, strerror(errno));
144 return(1);
3880b4a9 145 }
d53fe8dd 146 /*
50da9e1a
KB
147 * if rename fails, and it's a regular file, do the copy
148 * internally; otherwise, use cp and rm.
d53fe8dd 149 */
50da9e1a
KB
150 if (stat(from, &sbuf)) {
151 (void)fprintf(stderr,
152 "mv: %s: %s\n", from, strerror(errno));
153 return(1);
d53fe8dd 154 }
50da9e1a
KB
155 return(S_ISREG(sbuf.st_mode) ?
156 fastcopy(from, to, &sbuf) : copy(from, to));
157}
465786e2 158
50da9e1a
KB
159fastcopy(from, to, sbp)
160 char *from, *to;
161 struct stat *sbp;
162{
163 struct timeval tval[2];
164 static u_int blen;
165 static char *bp;
166 register int nread, from_fd, to_fd;
167 char *malloc();
168
169 if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
170 (void)fprintf(stderr,
171 "mv: %s: %s\n", from, strerror(errno));
172 return(1);
d53fe8dd 173 }
50da9e1a
KB
174 if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) {
175 (void)fprintf(stderr,
176 "mv: %s: %s\n", to, strerror(errno));
177 (void)close(from_fd);
178 return(1);
3880b4a9 179 }
50da9e1a
KB
180 if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
181 (void)fprintf(stderr, "mv: %s: out of memory.\n", from);
182 return(1);
3880b4a9 183 }
50da9e1a
KB
184 while ((nread = read(from_fd, bp, blen)) > 0)
185 if (write(to_fd, bp, nread) != nread) {
186 (void)fprintf(stderr, "mv: %s: %s\n",
187 to, strerror(errno));
188 goto err;
189 }
190 if (nread < 0) {
191 (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno));
192err: (void)unlink(to);
193 (void)close(from_fd);
194 (void)close(to_fd);
195 return(1);
196 }
197 (void)fchown(to_fd, sbp->st_uid, sbp->st_gid);
198 (void)fchmod(to_fd, sbp->st_mode);
199
200 (void)close(from_fd);
201 (void)close(to_fd);
202
203 tval[0].tv_sec = sbp->st_atime;
204 tval[1].tv_sec = sbp->st_mtime;
205 tval[0].tv_usec = tval[1].tv_usec = 0;
206 (void)utimes(to, tval);
207 (void)unlink(from);
208 return(0);
3880b4a9
BJ
209}
210
50da9e1a
KB
211copy(from, to)
212 char *from, *to;
3880b4a9 213{
50da9e1a 214 int pid, status;
d53fe8dd 215
50da9e1a
KB
216 if (!(pid = vfork())) {
217 execlp(_PATH_CP, "mv", "-pr", from, to);
218 (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_CP);
219 _exit(1);
220 }
221 (void)waitpid(pid, &status, 0);
222 if (!WIFEXITED(status) || WEXITSTATUS(status))
223 return(1);
224 if (!(pid = vfork())) {
225 execlp(_PATH_RM, "mv", "-rf", from);
226 (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_RM);
227 _exit(1);
228 }
229 (void)waitpid(pid, &status, 0);
230 return(!WIFEXITED(status) || WEXITSTATUS(status));
3880b4a9 231}
8161a03a
KB
232
233usage()
234{
50da9e1a
KB
235 (void)fprintf(stderr,
236"usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n");
8161a03a
KB
237 exit(1);
238}