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