utils.c revision 284106
1/*- 2 * Copyright (c) 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#ifndef lint 31#if 0 32static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; 33#endif 34#endif /* not lint */ 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/bin/cp/utils.c 284106 2015-06-07 06:30:25Z bdrewery $"); 37 38#include <sys/types.h> 39#include <sys/acl.h> 40#include <sys/param.h> 41#include <sys/stat.h> 42#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED 43#include <sys/mman.h> 44#endif 45 46#include <err.h> 47#include <errno.h> 48#include <fcntl.h> 49#include <fts.h> 50#include <limits.h> 51#include <stdio.h> 52#include <stdlib.h> 53#include <sysexits.h> 54#include <unistd.h> 55 56#include "extern.h" 57 58#define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y))) 59 60/* Memory strategy threshold, in pages: if physmem is larger then this, use a 61 * large buffer */ 62#define PHYSPAGES_THRESHOLD (32*1024) 63 64/* Maximum buffer size in bytes - do not allow it to grow larger than this */ 65#define BUFSIZE_MAX (2*1024*1024) 66 67/* Small (default) buffer size in bytes. It's inefficient for this to be 68 * smaller than MAXPHYS */ 69#define BUFSIZE_SMALL (MAXPHYS) 70 71int 72copy_file(const FTSENT *entp, int dne) 73{ 74 static char *buf = NULL; 75 static size_t bufsize; 76 struct stat *fs; 77 ssize_t wcount; 78 size_t wresid; 79 off_t wtotal; 80 int ch, checkch, from_fd, rcount, rval, to_fd; 81 char *bufp; 82#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED 83 char *p; 84#endif 85 86 from_fd = to_fd = -1; 87 if (!lflag && !sflag && 88 (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { 89 warn("%s", entp->fts_path); 90 return (1); 91 } 92 93 fs = entp->fts_statp; 94 95 /* 96 * If the file exists and we're interactive, verify with the user. 97 * If the file DNE, set the mode to be the from file, minus setuid 98 * bits, modified by the umask; arguably wrong, but it makes copying 99 * executables work right and it's been that way forever. (The 100 * other choice is 666 or'ed with the execute bits on the from file 101 * modified by the umask.) 102 */ 103 if (!dne) { 104#define YESNO "(y/n [n]) " 105 if (nflag) { 106 if (vflag) 107 printf("%s not overwritten\n", to.p_path); 108 rval = 1; 109 goto done; 110 } else if (iflag) { 111 (void)fprintf(stderr, "overwrite %s? %s", 112 to.p_path, YESNO); 113 checkch = ch = getchar(); 114 while (ch != '\n' && ch != EOF) 115 ch = getchar(); 116 if (checkch != 'y' && checkch != 'Y') { 117 (void)fprintf(stderr, "not overwritten\n"); 118 rval = 1; 119 goto done; 120 } 121 } 122 123 if (fflag) { 124 /* remove existing destination file name, 125 * create a new file */ 126 (void)unlink(to.p_path); 127 if (!lflag && !sflag) { 128 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, 129 fs->st_mode & ~(S_ISUID | S_ISGID)); 130 } 131 } else if (!lflag && !sflag) { 132 /* overwrite existing destination file name */ 133 to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); 134 } 135 } else if (!lflag && !sflag) { 136 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, 137 fs->st_mode & ~(S_ISUID | S_ISGID)); 138 } 139 140 if (!lflag && !sflag && to_fd == -1) { 141 warn("%s", to.p_path); 142 rval = 1; 143 goto done; 144 } 145 146 rval = 0; 147 148 if (!lflag && !sflag) { 149 /* 150 * Mmap and write if less than 8M (the limit is so we don't totally 151 * trash memory on big files. This is really a minor hack, but it 152 * wins some CPU back. 153 * Some filesystems, such as smbnetfs, don't support mmap, 154 * so this is a best-effort attempt. 155 */ 156#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED 157 if (S_ISREG(fs->st_mode) && fs->st_size > 0 && 158 fs->st_size <= 8 * 1024 * 1024 && 159 (p = mmap(NULL, (size_t)fs->st_size, PROT_READ, 160 MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) { 161 wtotal = 0; 162 for (bufp = p, wresid = fs->st_size; ; 163 bufp += wcount, wresid -= (size_t)wcount) { 164 wcount = write(to_fd, bufp, wresid); 165 if (wcount <= 0) 166 break; 167 wtotal += wcount; 168 if (info) { 169 info = 0; 170 (void)fprintf(stderr, 171 "%s -> %s %3d%%\n", 172 entp->fts_path, to.p_path, 173 cp_pct(wtotal, fs->st_size)); 174 } 175 if (wcount >= (ssize_t)wresid) 176 break; 177 } 178 if (wcount != (ssize_t)wresid) { 179 warn("%s", to.p_path); 180 rval = 1; 181 } 182 /* Some systems don't unmap on close(2). */ 183 if (munmap(p, fs->st_size) < 0) { 184 warn("%s", entp->fts_path); 185 rval = 1; 186 } 187 } else 188#endif 189 { 190 if (buf == NULL) { 191 /* 192 * Note that buf and bufsize are static. If 193 * malloc() fails, it will fail at the start 194 * and not copy only some files. 195 */ 196 if (sysconf(_SC_PHYS_PAGES) > 197 PHYSPAGES_THRESHOLD) 198 bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 199 else 200 bufsize = BUFSIZE_SMALL; 201 buf = malloc(bufsize); 202 if (buf == NULL) 203 err(1, "Not enough memory"); 204 } 205 wtotal = 0; 206 while ((rcount = read(from_fd, buf, bufsize)) > 0) { 207 for (bufp = buf, wresid = rcount; ; 208 bufp += wcount, wresid -= wcount) { 209 wcount = write(to_fd, bufp, wresid); 210 if (wcount <= 0) 211 break; 212 wtotal += wcount; 213 if (info) { 214 info = 0; 215 (void)fprintf(stderr, 216 "%s -> %s %3d%%\n", 217 entp->fts_path, to.p_path, 218 cp_pct(wtotal, fs->st_size)); 219 } 220 if (wcount >= (ssize_t)wresid) 221 break; 222 } 223 if (wcount != (ssize_t)wresid) { 224 warn("%s", to.p_path); 225 rval = 1; 226 break; 227 } 228 } 229 if (rcount < 0) { 230 warn("%s", entp->fts_path); 231 rval = 1; 232 } 233 } 234 } else if (lflag) { 235 if (link(entp->fts_path, to.p_path)) { 236 warn("%s", to.p_path); 237 rval = 1; 238 } 239 } else if (sflag) { 240 if (symlink(entp->fts_path, to.p_path)) { 241 warn("%s", to.p_path); 242 rval = 1; 243 } 244 } 245 246 /* 247 * Don't remove the target even after an error. The target might 248 * not be a regular file, or its attributes might be important, 249 * or its contents might be irreplaceable. It would only be safe 250 * to remove it if we created it and its length is 0. 251 */ 252 253 if (!lflag && !sflag) { 254 if (pflag && setfile(fs, to_fd)) 255 rval = 1; 256 if (pflag && preserve_fd_acls(from_fd, to_fd) != 0) 257 rval = 1; 258 if (close(to_fd)) { 259 warn("%s", to.p_path); 260 rval = 1; 261 } 262 } 263 264done: 265 if (from_fd != -1) 266 (void)close(from_fd); 267 return (rval); 268} 269 270int 271copy_link(const FTSENT *p, int exists) 272{ 273 int len; 274 char llink[PATH_MAX]; 275 276 if (exists && nflag) { 277 if (vflag) 278 printf("%s not overwritten\n", to.p_path); 279 return (1); 280 } 281 if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) { 282 warn("readlink: %s", p->fts_path); 283 return (1); 284 } 285 llink[len] = '\0'; 286 if (exists && unlink(to.p_path)) { 287 warn("unlink: %s", to.p_path); 288 return (1); 289 } 290 if (symlink(llink, to.p_path)) { 291 warn("symlink: %s", llink); 292 return (1); 293 } 294 return (pflag ? setfile(p->fts_statp, -1) : 0); 295} 296 297int 298copy_fifo(struct stat *from_stat, int exists) 299{ 300 301 if (exists && nflag) { 302 if (vflag) 303 printf("%s not overwritten\n", to.p_path); 304 return (1); 305 } 306 if (exists && unlink(to.p_path)) { 307 warn("unlink: %s", to.p_path); 308 return (1); 309 } 310 if (mkfifo(to.p_path, from_stat->st_mode)) { 311 warn("mkfifo: %s", to.p_path); 312 return (1); 313 } 314 return (pflag ? setfile(from_stat, -1) : 0); 315} 316 317int 318copy_special(struct stat *from_stat, int exists) 319{ 320 321 if (exists && nflag) { 322 if (vflag) 323 printf("%s not overwritten\n", to.p_path); 324 return (1); 325 } 326 if (exists && unlink(to.p_path)) { 327 warn("unlink: %s", to.p_path); 328 return (1); 329 } 330 if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { 331 warn("mknod: %s", to.p_path); 332 return (1); 333 } 334 return (pflag ? setfile(from_stat, -1) : 0); 335} 336 337int 338setfile(struct stat *fs, int fd) 339{ 340 static struct timespec tspec[2]; 341 struct stat ts; 342 int rval, gotstat, islink, fdval; 343 344 rval = 0; 345 fdval = fd != -1; 346 islink = !fdval && S_ISLNK(fs->st_mode); 347 fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | 348 S_IRWXU | S_IRWXG | S_IRWXO; 349 350 tspec[0] = fs->st_atim; 351 tspec[1] = fs->st_mtim; 352 if (fdval ? futimens(fd, tspec) : utimensat(AT_FDCWD, to.p_path, tspec, 353 islink ? AT_SYMLINK_NOFOLLOW : 0)) { 354 warn("utimensat: %s", to.p_path); 355 rval = 1; 356 } 357 if (fdval ? fstat(fd, &ts) : 358 (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) 359 gotstat = 0; 360 else { 361 gotstat = 1; 362 ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | 363 S_IRWXU | S_IRWXG | S_IRWXO; 364 } 365 /* 366 * Changing the ownership probably won't succeed, unless we're root 367 * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting 368 * the mode; current BSD behavior is to remove all setuid bits on 369 * chown. If chown fails, lose setuid/setgid bits. 370 */ 371 if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) 372 if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : 373 (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) : 374 chown(to.p_path, fs->st_uid, fs->st_gid))) { 375 if (errno != EPERM) { 376 warn("chown: %s", to.p_path); 377 rval = 1; 378 } 379 fs->st_mode &= ~(S_ISUID | S_ISGID); 380 } 381 382 if (!gotstat || fs->st_mode != ts.st_mode) 383 if (fdval ? fchmod(fd, fs->st_mode) : 384 (islink ? lchmod(to.p_path, fs->st_mode) : 385 chmod(to.p_path, fs->st_mode))) { 386 warn("chmod: %s", to.p_path); 387 rval = 1; 388 } 389 390 if (!gotstat || fs->st_flags != ts.st_flags) 391 if (fdval ? 392 fchflags(fd, fs->st_flags) : 393 (islink ? lchflags(to.p_path, fs->st_flags) : 394 chflags(to.p_path, fs->st_flags))) { 395 warn("chflags: %s", to.p_path); 396 rval = 1; 397 } 398 399 return (rval); 400} 401 402int 403preserve_fd_acls(int source_fd, int dest_fd) 404{ 405 acl_t acl; 406 acl_type_t acl_type; 407 int acl_supported = 0, ret, trivial; 408 409 ret = fpathconf(source_fd, _PC_ACL_NFS4); 410 if (ret > 0 ) { 411 acl_supported = 1; 412 acl_type = ACL_TYPE_NFS4; 413 } else if (ret < 0 && errno != EINVAL) { 414 warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path); 415 return (1); 416 } 417 if (acl_supported == 0) { 418 ret = fpathconf(source_fd, _PC_ACL_EXTENDED); 419 if (ret > 0 ) { 420 acl_supported = 1; 421 acl_type = ACL_TYPE_ACCESS; 422 } else if (ret < 0 && errno != EINVAL) { 423 warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s", 424 to.p_path); 425 return (1); 426 } 427 } 428 if (acl_supported == 0) 429 return (0); 430 431 acl = acl_get_fd_np(source_fd, acl_type); 432 if (acl == NULL) { 433 warn("failed to get acl entries while setting %s", to.p_path); 434 return (1); 435 } 436 if (acl_is_trivial_np(acl, &trivial)) { 437 warn("acl_is_trivial() failed for %s", to.p_path); 438 acl_free(acl); 439 return (1); 440 } 441 if (trivial) { 442 acl_free(acl); 443 return (0); 444 } 445 if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) { 446 warn("failed to set acl entries for %s", to.p_path); 447 acl_free(acl); 448 return (1); 449 } 450 acl_free(acl); 451 return (0); 452} 453 454int 455preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir) 456{ 457 acl_t (*aclgetf)(const char *, acl_type_t); 458 int (*aclsetf)(const char *, acl_type_t, acl_t); 459 struct acl *aclp; 460 acl_t acl; 461 acl_type_t acl_type; 462 int acl_supported = 0, ret, trivial; 463 464 ret = pathconf(source_dir, _PC_ACL_NFS4); 465 if (ret > 0) { 466 acl_supported = 1; 467 acl_type = ACL_TYPE_NFS4; 468 } else if (ret < 0 && errno != EINVAL) { 469 warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir); 470 return (1); 471 } 472 if (acl_supported == 0) { 473 ret = pathconf(source_dir, _PC_ACL_EXTENDED); 474 if (ret > 0) { 475 acl_supported = 1; 476 acl_type = ACL_TYPE_ACCESS; 477 } else if (ret < 0 && errno != EINVAL) { 478 warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s", 479 source_dir); 480 return (1); 481 } 482 } 483 if (acl_supported == 0) 484 return (0); 485 486 /* 487 * If the file is a link we will not follow it 488 */ 489 if (S_ISLNK(fs->st_mode)) { 490 aclgetf = acl_get_link_np; 491 aclsetf = acl_set_link_np; 492 } else { 493 aclgetf = acl_get_file; 494 aclsetf = acl_set_file; 495 } 496 if (acl_type == ACL_TYPE_ACCESS) { 497 /* 498 * Even if there is no ACL_TYPE_DEFAULT entry here, a zero 499 * size ACL will be returned. So it is not safe to simply 500 * check the pointer to see if the default ACL is present. 501 */ 502 acl = aclgetf(source_dir, ACL_TYPE_DEFAULT); 503 if (acl == NULL) { 504 warn("failed to get default acl entries on %s", 505 source_dir); 506 return (1); 507 } 508 aclp = &acl->ats_acl; 509 if (aclp->acl_cnt != 0 && aclsetf(dest_dir, 510 ACL_TYPE_DEFAULT, acl) < 0) { 511 warn("failed to set default acl entries on %s", 512 dest_dir); 513 acl_free(acl); 514 return (1); 515 } 516 acl_free(acl); 517 } 518 acl = aclgetf(source_dir, acl_type); 519 if (acl == NULL) { 520 warn("failed to get acl entries on %s", source_dir); 521 return (1); 522 } 523 if (acl_is_trivial_np(acl, &trivial)) { 524 warn("acl_is_trivial() failed on %s", source_dir); 525 acl_free(acl); 526 return (1); 527 } 528 if (trivial) { 529 acl_free(acl); 530 return (0); 531 } 532 if (aclsetf(dest_dir, acl_type, acl) < 0) { 533 warn("failed to set acl entries on %s", dest_dir); 534 acl_free(acl); 535 return (1); 536 } 537 acl_free(acl); 538 return (0); 539} 540 541void 542usage(void) 543{ 544 545 (void)fprintf(stderr, "%s\n%s\n", 546"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file target_file", 547" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] source_file ... " 548"target_directory"); 549 exit(EX_USAGE); 550} 551