119845Sdist /* 239246Sbostic * Copyright (c) 1989 The Regents of the University of California. 339246Sbostic * All rights reserved. 439246Sbostic * 539246Sbostic * This code is derived from software contributed to Berkeley by 639246Sbostic * Ken Smith of The State University of New York at Buffalo. 739246Sbostic * 842536Sbostic * %sccs.include.redist.c% 919845Sdist */ 1019845Sdist 1110047Ssam #ifndef lint 1219845Sdist char copyright[] = 1339246Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1419845Sdist All rights reserved.\n"; 1534045Sbostic #endif /* not lint */ 168839Smckusick 1719845Sdist #ifndef lint 18*56905Sbostic static char sccsid[] = "@(#)mv.c 5.12 (Berkeley) 11/23/92"; 1934045Sbostic #endif /* not lint */ 2019845Sdist 2110047Ssam #include <sys/param.h> 2239246Sbostic #include <sys/time.h> 2339246Sbostic #include <sys/wait.h> 2410047Ssam #include <sys/stat.h> 25*56905Sbostic 26*56905Sbostic #include <errno.h> 2747751Sbostic #include <fcntl.h> 281216Sbill #include <stdio.h> 2947751Sbostic #include <stdlib.h> 3039246Sbostic #include <string.h> 31*56905Sbostic #include <unistd.h> 32*56905Sbostic 3339246Sbostic #include "pathnames.h" 341216Sbill 3539246Sbostic int fflg, iflg; 361216Sbill 37*56905Sbostic int copy __P((char *, char *)); 38*56905Sbostic int do_move __P((char *, char *)); 39*56905Sbostic void err __P((const char *, ...)); 40*56905Sbostic int fastcopy __P((char *, char *, struct stat *)); 41*56905Sbostic void usage __P((void)); 42*56905Sbostic 43*56905Sbostic int 441216Sbill main(argc, argv) 4539246Sbostic int argc; 46*56905Sbostic char *argv[]; 471216Sbill { 4839246Sbostic register int baselen, exitval, len; 4939246Sbostic register char *p, *endp; 5047751Sbostic struct stat sb; 5139246Sbostic int ch; 5239246Sbostic char path[MAXPATHLEN + 1]; 531216Sbill 5439246Sbostic while (((ch = getopt(argc, argv, "-if")) != EOF)) 5534045Sbostic switch((char)ch) { 5639246Sbostic case 'i': 5747751Sbostic iflg = 1; 5839246Sbostic break; 5934045Sbostic case 'f': 6047751Sbostic fflg = 1; 6110047Ssam break; 62*56905Sbostic case '-': /* Undocumented; for compatibility. */ 6339246Sbostic goto endarg; 6434045Sbostic case '?': 6510047Ssam default: 6634045Sbostic usage(); 6710047Ssam } 6839246Sbostic endarg: argc -= optind; 6939246Sbostic argv += optind; 7034045Sbostic 7134045Sbostic if (argc < 2) 7234045Sbostic usage(); 7339246Sbostic 7439246Sbostic /* 7547751Sbostic * If the stat on the target fails or the target isn't a directory, 7647751Sbostic * try the move. More than 2 arguments is an error in this case. 7739246Sbostic */ 7847751Sbostic if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { 7939246Sbostic if (argc > 2) 8039246Sbostic usage(); 8139246Sbostic exit(do_move(argv[0], argv[1])); 821216Sbill } 831216Sbill 8447751Sbostic /* It's a directory, move each file into it. */ 8539246Sbostic (void)strcpy(path, argv[argc - 1]); 8639246Sbostic baselen = strlen(path); 8739246Sbostic endp = &path[baselen]; 8839246Sbostic *endp++ = '/'; 8939246Sbostic ++baselen; 9039246Sbostic for (exitval = 0; --argc; ++argv) { 9139246Sbostic if ((p = rindex(*argv, '/')) == NULL) 9239246Sbostic p = *argv; 9339246Sbostic else 9439246Sbostic ++p; 95*56905Sbostic if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { 96*56905Sbostic err("%s: destination pathname too long", *argv); 97*56905Sbostic exitval = 1; 98*56905Sbostic } else { 9939246Sbostic bcopy(p, endp, len + 1); 10039246Sbostic exitval |= do_move(*argv, path); 10139246Sbostic } 10210047Ssam } 10339246Sbostic exit(exitval); 10410047Ssam } 10510047Ssam 106*56905Sbostic int 10739246Sbostic do_move(from, to) 10839246Sbostic char *from, *to; 1091216Sbill { 11047751Sbostic struct stat sb; 11139246Sbostic int ask, ch; 1121216Sbill 11310047Ssam /* 11447751Sbostic * Check access. If interactive and file exists, ask user if it 11539246Sbostic * should be replaced. Otherwise if file exists but isn't writable 11639246Sbostic * make sure the user wants to clobber it. 11710047Ssam */ 11839246Sbostic if (!fflg && !access(to, F_OK)) { 11939246Sbostic ask = 0; 12039246Sbostic if (iflg) { 12139246Sbostic (void)fprintf(stderr, "overwrite %s? ", to); 12239246Sbostic ask = 1; 1231216Sbill } 12447751Sbostic else if (access(to, W_OK) && !stat(to, &sb)) { 12539246Sbostic (void)fprintf(stderr, "override mode %o on %s? ", 12647751Sbostic sb.st_mode & 07777, to); 12739246Sbostic ask = 1; 12839246Sbostic } 12939246Sbostic if (ask) { 13039246Sbostic if ((ch = getchar()) != EOF && ch != '\n') 13139246Sbostic while (getchar() != '\n'); 13239246Sbostic if (ch != 'y') 133*56905Sbostic return (0); 13439246Sbostic } 1351216Sbill } 13639246Sbostic if (!rename(from, to)) 137*56905Sbostic return (0); 13847751Sbostic 13911642Ssam if (errno != EXDEV) { 140*56905Sbostic err("rename %s to %s: %s", from, to, strerror(errno)); 141*56905Sbostic return (1); 14211642Ssam } 14347751Sbostic 14410047Ssam /* 14547751Sbostic * If rename fails, and it's a regular file, do the copy internally; 14647751Sbostic * otherwise, use cp and rm. 14710047Ssam */ 14847751Sbostic if (stat(from, &sb)) { 149*56905Sbostic err("%s: %s", from, strerror(errno)); 150*56905Sbostic return (1); 15110047Ssam } 152*56905Sbostic return (S_ISREG(sb.st_mode) ? 15347751Sbostic fastcopy(from, to, &sb) : copy(from, to)); 15439246Sbostic } 15510166Ssam 156*56905Sbostic int 15739246Sbostic fastcopy(from, to, sbp) 15839246Sbostic char *from, *to; 15939246Sbostic struct stat *sbp; 16039246Sbostic { 16139246Sbostic struct timeval tval[2]; 16239246Sbostic static u_int blen; 16339246Sbostic static char *bp; 16439246Sbostic register int nread, from_fd, to_fd; 16522601Sserge 16639246Sbostic if ((from_fd = open(from, O_RDONLY, 0)) < 0) { 167*56905Sbostic err("%s: %s", from, strerror(errno)); 168*56905Sbostic return (1); 16910047Ssam } 17047751Sbostic if ((to_fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, sbp->st_mode)) < 0) { 171*56905Sbostic err("%s: %s", to, strerror(errno)); 17239246Sbostic (void)close(from_fd); 173*56905Sbostic return (1); 17439246Sbostic } 17539246Sbostic if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { 176*56905Sbostic err("%s", strerror(errno)); 177*56905Sbostic return (1); 17839246Sbostic } 17939246Sbostic while ((nread = read(from_fd, bp, blen)) > 0) 18039246Sbostic if (write(to_fd, bp, nread) != nread) { 181*56905Sbostic err("%s: %s", to, strerror(errno)); 18239246Sbostic goto err; 1831216Sbill } 18439246Sbostic if (nread < 0) { 185*56905Sbostic err("%s: %s", from, strerror(errno)); 18639246Sbostic err: (void)unlink(to); 18739246Sbostic (void)close(from_fd); 18839246Sbostic (void)close(to_fd); 189*56905Sbostic return (1); 1901216Sbill } 19139246Sbostic (void)fchown(to_fd, sbp->st_uid, sbp->st_gid); 19239246Sbostic (void)fchmod(to_fd, sbp->st_mode); 1931216Sbill 19439246Sbostic (void)close(from_fd); 19539246Sbostic (void)close(to_fd); 1961216Sbill 19739246Sbostic tval[0].tv_sec = sbp->st_atime; 19839246Sbostic tval[1].tv_sec = sbp->st_mtime; 19939246Sbostic tval[0].tv_usec = tval[1].tv_usec = 0; 20039246Sbostic (void)utimes(to, tval); 20139246Sbostic (void)unlink(from); 202*56905Sbostic return (0); 2031216Sbill } 2041216Sbill 205*56905Sbostic int 20639246Sbostic copy(from, to) 20739246Sbostic char *from, *to; 2081216Sbill { 20939246Sbostic int pid, status; 2101216Sbill 21139246Sbostic if (!(pid = vfork())) { 212*56905Sbostic execl(_PATH_CP, "mv", "-pR", from, to, NULL); 213*56905Sbostic err("%s: %s", _PATH_CP, strerror(errno)); 21439246Sbostic _exit(1); 21539246Sbostic } 21639246Sbostic (void)waitpid(pid, &status, 0); 21739246Sbostic if (!WIFEXITED(status) || WEXITSTATUS(status)) 218*56905Sbostic return (1); 21939246Sbostic if (!(pid = vfork())) { 22047754Sbostic execl(_PATH_RM, "mv", "-rf", from, NULL); 221*56905Sbostic err("%s: %s", _PATH_RM, strerror(errno)); 22239246Sbostic _exit(1); 22339246Sbostic } 22439246Sbostic (void)waitpid(pid, &status, 0); 225*56905Sbostic return (!WIFEXITED(status) || WEXITSTATUS(status)); 2261216Sbill } 2271216Sbill 228*56905Sbostic void 22934045Sbostic usage() 23034045Sbostic { 23139246Sbostic (void)fprintf(stderr, 23239246Sbostic "usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n"); 23334045Sbostic exit(1); 23434045Sbostic } 235*56905Sbostic 236*56905Sbostic #if __STDC__ 237*56905Sbostic #include <stdarg.h> 238*56905Sbostic #else 239*56905Sbostic #include <varargs.h> 240*56905Sbostic #endif 241*56905Sbostic 242*56905Sbostic void 243*56905Sbostic #if __STDC__ 244*56905Sbostic err(const char *fmt, ...) 245*56905Sbostic #else 246*56905Sbostic err(fmt, va_alist) 247*56905Sbostic char *fmt; 248*56905Sbostic va_dcl 249*56905Sbostic #endif 250*56905Sbostic { 251*56905Sbostic va_list ap; 252*56905Sbostic #if __STDC__ 253*56905Sbostic va_start(ap, fmt); 254*56905Sbostic #else 255*56905Sbostic va_start(ap); 256*56905Sbostic #endif 257*56905Sbostic (void)fprintf(stderr, "mv: "); 258*56905Sbostic (void)vfprintf(stderr, fmt, ap); 259*56905Sbostic va_end(ap); 260*56905Sbostic (void)fprintf(stderr, "\n"); 261*56905Sbostic } 262