port should be u_short; bug report 4.3BSD-tahoe/lib/18
[unix-history] / usr / src / bin / cp / cp.c
CommitLineData
1f978f4c
KM
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
5f89032b 13#ifndef lint
ded1b933 14static char sccsid[] = "@(#)cp.c 4.14 (Berkeley) %G%";
1f978f4c 15#endif not lint
5f89032b 16
84592a94 17/*
5f89032b 18 * cp
84592a94 19 */
84592a94 20#include <stdio.h>
f4d092e2 21#include <sys/param.h>
84592a94 22#include <sys/stat.h>
7afd0a98 23#include <sys/dir.h>
0908a03a 24#include <sys/time.h>
5f89032b 25
5f89032b
BJ
26int iflag;
27int rflag;
0908a03a
JL
28int pflag;
29char *rindex();
84592a94
BJ
30
31main(argc, argv)
5f89032b
BJ
32 int argc;
33 char **argv;
84592a94 34{
5f89032b
BJ
35 struct stat stb;
36 int rc, i;
84592a94 37
5f89032b
BJ
38 argc--, argv++;
39 while (argc > 0 && **argv == '-') {
40 (*argv)++;
41 while (**argv) switch (*(*argv)++) {
84592a94 42
5f89032b
BJ
43 case 'i':
44 iflag++; break;
84592a94 45
685d778a 46 case 'R':
5f89032b
BJ
47 case 'r':
48 rflag++; break;
84592a94 49
5884fcc2
JL
50 case 'p': /* preserve mtimes, atimes, and modes */
51 pflag++;
52 (void) umask(0);
53 break;
0908a03a 54
5f89032b
BJ
55 default:
56 goto usage;
57 }
58 argc--; argv++;
84592a94 59 }
5f89032b 60 if (argc < 2)
84592a94 61 goto usage;
685d778a 62 if (argc > 2) {
3e9da018 63 if (stat(argv[argc-1], &stb) < 0)
84592a94 64 goto usage;
5f89032b 65 if ((stb.st_mode&S_IFMT) != S_IFDIR)
84592a94
BJ
66 goto usage;
67 }
5f89032b
BJ
68 rc = 0;
69 for (i = 0; i < argc-1; i++)
70 rc |= copy(argv[i], argv[argc-1]);
71 exit(rc);
84592a94 72usage:
5f89032b 73 fprintf(stderr,
5884fcc2 74 "Usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn d2\n");
84592a94
BJ
75 exit(1);
76}
77
ded1b933
KB
78 /* I/O buffer; guarantee long-word alignment */
79static char buf[MAXBSIZE];
80
84592a94 81copy(from, to)
5f89032b 82 char *from, *to;
84592a94 83{
5884fcc2 84 int fold, fnew, n, exists;
ded1b933 85 char *last, destname[MAXPATHLEN + 1];
5f89032b
BJ
86 struct stat stfrom, stto;
87
88 fold = open(from, 0);
89 if (fold < 0) {
1a4b831f 90 Perror(from);
5f89032b 91 return (1);
84592a94 92 }
5f89032b 93 if (fstat(fold, &stfrom) < 0) {
1a4b831f
SL
94 Perror(from);
95 (void) close(fold);
5f89032b 96 return (1);
84592a94 97 }
3e9da018 98 if (stat(to, &stto) >= 0 &&
5f89032b
BJ
99 (stto.st_mode&S_IFMT) == S_IFDIR) {
100 last = rindex(from, '/');
101 if (last) last++; else last = from;
685d778a 102 if (strlen(to) + strlen(last) >= sizeof destname - 1) {
5f89032b 103 fprintf(stderr, "cp: %s/%s: Name too long", to, last);
1a4b831f 104 (void) close(fold);
84592a94 105 return(1);
5f89032b
BJ
106 }
107 (void) sprintf(destname, "%s/%s", to, last);
108 to = destname;
109 }
110 if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
2b6d53f3
JB
111 int fixmode = 0; /* cleanup mode after rcopy */
112
5f89032b 113 (void) close(fold);
3e9da018 114 if (stat(to, &stto) < 0) {
2b6d53f3 115 if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) {
1a4b831f 116 Perror(to);
5f89032b 117 return (1);
e01c32c9 118 }
2b6d53f3 119 fixmode = 1;
5f89032b
BJ
120 } else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
121 fprintf(stderr, "cp: %s: Not a directory.\n", to);
122 return (1);
5884fcc2 123 } else if (pflag)
2b6d53f3
JB
124 fixmode = 1;
125 n = rcopy(from, to);
126 if (fixmode)
5884fcc2 127 (void) chmod(to, stfrom.st_mode & 07777);
2b6d53f3 128 return (n);
5f89032b 129 }
685d778a
S
130
131 if ((stfrom.st_mode&S_IFMT) == S_IFDIR)
132 fprintf(stderr,
133 "cp: %s: Is a directory (copying as plain file).\n",
134 from);
135
5884fcc2
JL
136 exists = stat(to, &stto) == 0;
137 if (exists) {
5f89032b
BJ
138 if (stfrom.st_dev == stto.st_dev &&
139 stfrom.st_ino == stto.st_ino) {
685d778a
S
140 fprintf(stderr,
141 "cp: %s and %s are identical (not copied).\n",
142 from, to);
1a4b831f 143 (void) close(fold);
5f89032b
BJ
144 return (1);
145 }
685d778a 146 if (iflag && isatty(fileno(stdin))) {
5f89032b
BJ
147 int i, c;
148
84592a94
BJ
149 fprintf (stderr, "overwrite %s? ", to);
150 i = c = getchar();
151 while (c != '\n' && c != EOF)
152 c = getchar();
1a4b831f
SL
153 if (i != 'y') {
154 (void) close(fold);
84592a94 155 return(1);
1a4b831f 156 }
84592a94
BJ
157 }
158 }
685d778a 159 fnew = creat(to, stfrom.st_mode & 07777);
5f89032b 160 if (fnew < 0) {
1a4b831f 161 Perror(to);
5f89032b 162 (void) close(fold); return(1);
84592a94 163 }
5884fcc2
JL
164 if (exists && pflag)
165 (void) fchmod(fnew, stfrom.st_mode & 07777);
166
5f89032b 167 for (;;) {
685d778a 168 n = read(fold, buf, sizeof buf);
5f89032b
BJ
169 if (n == 0)
170 break;
84592a94 171 if (n < 0) {
1a4b831f 172 Perror(from);
5f89032b
BJ
173 (void) close(fold); (void) close(fnew); return (1);
174 }
175 if (write(fnew, buf, n) != n) {
1a4b831f 176 Perror(to);
5f89032b
BJ
177 (void) close(fold); (void) close(fnew); return (1);
178 }
179 }
0908a03a
JL
180 (void) close(fold); (void) close(fnew);
181 if (pflag)
182 return (setimes(to, &stfrom));
183 return (0);
5f89032b
BJ
184}
185
186rcopy(from, to)
187 char *from, *to;
188{
189 DIR *fold = opendir(from);
190 struct direct *dp;
0908a03a 191 struct stat statb;
5f89032b 192 int errs = 0;
685d778a 193 char fromname[MAXPATHLEN + 1];
5f89032b 194
0908a03a 195 if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) {
1a4b831f 196 Perror(from);
5f89032b
BJ
197 return (1);
198 }
199 for (;;) {
200 dp = readdir(fold);
c4ac082c
KM
201 if (dp == 0) {
202 closedir(fold);
0908a03a
JL
203 if (pflag)
204 return (setimes(to, &statb) + errs);
5f89032b 205 return (errs);
c4ac082c 206 }
5f89032b
BJ
207 if (dp->d_ino == 0)
208 continue;
209 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
210 continue;
685d778a 211 if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) {
5f89032b
BJ
212 fprintf(stderr, "cp: %s/%s: Name too long.\n",
213 from, dp->d_name);
214 errs++;
215 continue;
216 }
217 (void) sprintf(fromname, "%s/%s", from, dp->d_name);
218 errs += copy(fromname, to);
219 }
220}
1a4b831f 221
0908a03a
JL
222int
223setimes(path, statp)
224 char *path;
225 struct stat *statp;
226{
227 struct timeval tv[2];
228
229 tv[0].tv_sec = statp->st_atime;
230 tv[1].tv_sec = statp->st_mtime;
231 tv[0].tv_usec = tv[1].tv_usec = 0;
232 if (utimes(path, tv) < 0) {
233 Perror(path);
234 return (1);
235 }
236 return (0);
237}
238
1a4b831f
SL
239Perror(s)
240 char *s;
241{
242
243 fprintf(stderr, "cp: ");
244 perror(s);
245}