[813] | 1 | /*-
|
---|
| 2 | * Copyright (c) 1989, 1993, 1994
|
---|
| 3 | * The Regents of the University of California. 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, with or without
|
---|
| 9 | * modification, are permitted provided that the following conditions
|
---|
| 10 | * are met:
|
---|
| 11 | * 1. Redistributions of source code must retain the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer.
|
---|
| 13 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
| 14 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 15 | * documentation and/or other materials provided with the distribution.
|
---|
| 16 | * 4. Neither the name of the University nor the names of its contributors
|
---|
| 17 | * may be used to endorse or promote products derived from this software
|
---|
| 18 | * without specific prior written permission.
|
---|
| 19 | *
|
---|
| 20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
---|
| 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
| 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
---|
| 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
| 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
| 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
| 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
| 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
| 30 | * SUCH DAMAGE.
|
---|
| 31 | */
|
---|
| 32 |
|
---|
| 33 | #if 0
|
---|
| 34 | #ifndef lint
|
---|
| 35 | static char const copyright[] =
|
---|
| 36 | "@(#) Copyright (c) 1989, 1993, 1994\n\
|
---|
| 37 | The Regents of the University of California. All rights reserved.\n";
|
---|
| 38 | #endif /* not lint */
|
---|
| 39 |
|
---|
| 40 | #ifndef lint
|
---|
| 41 | static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94";
|
---|
| 42 | #endif /* not lint */
|
---|
| 43 | #endif
|
---|
| 44 | #if 0
|
---|
| 45 | #include <sys/cdefs.h>
|
---|
| 46 | __FBSDID("$FreeBSD: src/bin/mv/mv.c,v 1.46 2005/09/05 04:36:08 csjp Exp $");
|
---|
| 47 | #endif
|
---|
| 48 |
|
---|
[3192] | 49 |
|
---|
| 50 | /*********************************************************************************************************************************
|
---|
| 51 | * Header Files *
|
---|
| 52 | *********************************************************************************************************************************/
|
---|
[3215] | 53 | #define FAKES_NO_GETOPT_H /* bird */
|
---|
[2113] | 54 | #include "config.h"
|
---|
[813] | 55 | #include <sys/types.h>
|
---|
| 56 | #ifndef _MSC_VER
|
---|
[2142] | 57 | # ifdef CROSS_DEVICE_MOVE
|
---|
[813] | 58 | # include <sys/acl.h>
|
---|
| 59 | # endif
|
---|
| 60 | # include <sys/param.h>
|
---|
| 61 | # include <sys/time.h>
|
---|
| 62 | # include <sys/wait.h>
|
---|
[3109] | 63 | # if !defined(__HAIKU__) && !defined(__gnu_hurd__)
|
---|
[2546] | 64 | # include <sys/mount.h>
|
---|
| 65 | # endif
|
---|
[813] | 66 | #endif
|
---|
| 67 | #include <sys/stat.h>
|
---|
| 68 |
|
---|
| 69 | #include "err.h"
|
---|
| 70 | #include <errno.h>
|
---|
| 71 | #include <fcntl.h>
|
---|
| 72 | #include <grp.h>
|
---|
| 73 | #include <limits.h>
|
---|
| 74 | #include <paths.h>
|
---|
| 75 | #include <pwd.h>
|
---|
| 76 | #include <stdio.h>
|
---|
| 77 | #include <stdlib.h>
|
---|
| 78 | #include <string.h>
|
---|
[2546] | 79 | #ifndef __HAIKU__
|
---|
| 80 | # include <sysexits.h>
|
---|
| 81 | #endif
|
---|
[813] | 82 | #include <unistd.h>
|
---|
[3215] | 83 | #include "getopt_r.h"
|
---|
[813] | 84 | #ifdef __sun__
|
---|
| 85 | # include "solfakes.h"
|
---|
| 86 | #endif
|
---|
[2546] | 87 | #ifdef __HAIKU__
|
---|
| 88 | # include "haikufakes.h"
|
---|
| 89 | #endif
|
---|
[813] | 90 | #ifdef _MSC_VER
|
---|
| 91 | # include "mscfakes.h"
|
---|
| 92 | #endif
|
---|
[1183] | 93 | #include "kmkbuiltin.h"
|
---|
[813] | 94 |
|
---|
[1183] | 95 |
|
---|
[3192] | 96 | /*********************************************************************************************************************************
|
---|
| 97 | * Structures and Typedefs *
|
---|
| 98 | *********************************************************************************************************************************/
|
---|
| 99 | typedef struct MVINSTANCE
|
---|
| 100 | {
|
---|
| 101 | PKMKBUILTINCTX pCtx;
|
---|
| 102 | int fflg, iflg, nflg, vflg;
|
---|
| 103 | } MVINSTANCE;
|
---|
| 104 | typedef MVINSTANCE *PMVINSTANCE;
|
---|
| 105 |
|
---|
| 106 |
|
---|
| 107 | /*********************************************************************************************************************************
|
---|
| 108 | * Global Variables *
|
---|
| 109 | *********************************************************************************************************************************/
|
---|
[1183] | 110 | static struct option long_options[] =
|
---|
| 111 | {
|
---|
| 112 | { "help", no_argument, 0, 261 },
|
---|
| 113 | { "version", no_argument, 0, 262 },
|
---|
| 114 | { 0, 0, 0, 0 },
|
---|
| 115 | };
|
---|
[813] | 116 |
|
---|
[1183] | 117 |
|
---|
[3192] | 118 | /*********************************************************************************************************************************
|
---|
| 119 | * Internal Functions *
|
---|
| 120 | *********************************************************************************************************************************/
|
---|
| 121 | extern void bsd_strmode(mode_t mode, char *p); /* strmode.c */
|
---|
| 122 |
|
---|
| 123 | static int do_move(PMVINSTANCE, char *, char *);
|
---|
[3215] | 124 | #if 0 // def CROSS_DEVICE_MOVE
|
---|
[813] | 125 | static int fastcopy(char *, char *, struct stat *);
|
---|
| 126 | static int copy(char *, char *);
|
---|
| 127 | #endif
|
---|
[3192] | 128 | static int usage(PKMKBUILTINCTX, int);
|
---|
[813] | 129 |
|
---|
[1183] | 130 |
|
---|
[813] | 131 | int
|
---|
[3192] | 132 | kmk_builtin_mv(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx)
|
---|
[813] | 133 | {
|
---|
[3192] | 134 | MVINSTANCE This;
|
---|
[3215] | 135 | struct getopt_state_r gos;
|
---|
[813] | 136 | size_t baselen, len;
|
---|
| 137 | int rval;
|
---|
| 138 | char *p, *endp;
|
---|
| 139 | struct stat sb;
|
---|
| 140 | int ch;
|
---|
| 141 | char path[PATH_MAX];
|
---|
| 142 |
|
---|
[3192] | 143 | /* Initialize instance. */
|
---|
| 144 | This.pCtx = pCtx;
|
---|
| 145 | This.fflg = 0;
|
---|
| 146 | This.iflg = 0;
|
---|
| 147 | This.nflg = 0;
|
---|
| 148 | This.vflg = 0;
|
---|
[813] | 149 |
|
---|
[3215] | 150 | getopt_initialize_r(&gos, argc, argv, "finv", long_options, envp, pCtx);
|
---|
| 151 | while ((ch = getopt_long_r(&gos, NULL)) != -1)
|
---|
[813] | 152 | switch (ch) {
|
---|
| 153 | case 'i':
|
---|
[3192] | 154 | This.iflg = 1;
|
---|
| 155 | This.fflg = This.nflg = 0;
|
---|
[813] | 156 | break;
|
---|
| 157 | case 'f':
|
---|
[3192] | 158 | This.fflg = 1;
|
---|
| 159 | This.iflg = This.nflg = 0;
|
---|
[813] | 160 | break;
|
---|
| 161 | case 'n':
|
---|
[3192] | 162 | This.nflg = 1;
|
---|
| 163 | This.fflg = This.iflg = 0;
|
---|
[813] | 164 | break;
|
---|
| 165 | case 'v':
|
---|
[3192] | 166 | This.vflg = 1;
|
---|
[813] | 167 | break;
|
---|
[1183] | 168 | case 261:
|
---|
[3192] | 169 | usage(pCtx, 0);
|
---|
[1183] | 170 | return 0;
|
---|
| 171 | case 262:
|
---|
| 172 | return kbuild_version(argv[0]);
|
---|
[813] | 173 | default:
|
---|
[3192] | 174 | return usage(pCtx, 1);
|
---|
[813] | 175 | }
|
---|
[3215] | 176 | argc -= gos.optind;
|
---|
| 177 | argv += gos.optind;
|
---|
[813] | 178 |
|
---|
| 179 | if (argc < 2)
|
---|
[3192] | 180 | return usage(pCtx, 1);
|
---|
[813] | 181 |
|
---|
| 182 | /*
|
---|
| 183 | * If the stat on the target fails or the target isn't a directory,
|
---|
| 184 | * try the move. More than 2 arguments is an error in this case.
|
---|
| 185 | */
|
---|
| 186 | if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
|
---|
| 187 | if (argc > 2)
|
---|
[3192] | 188 | return usage(pCtx, 1);
|
---|
| 189 | return do_move(&This, argv[0], argv[1]);
|
---|
[813] | 190 | }
|
---|
| 191 |
|
---|
| 192 | /* It's a directory, move each file into it. */
|
---|
[3192] | 193 | baselen = strlen(argv[argc - 1]);
|
---|
| 194 | if (baselen > sizeof(path) - 1)
|
---|
| 195 | return errx(pCtx, 1, "%s: destination pathname too long", *argv);
|
---|
| 196 | memcpy(path, argv[argc - 1], baselen);
|
---|
[813] | 197 | endp = &path[baselen];
|
---|
[3192] | 198 | *endp = '\0';
|
---|
[813] | 199 | #if defined(_MSC_VER) || defined(__EMX__)
|
---|
| 200 | if (!baselen || (*(endp - 1) != '/' && *(endp - 1) != '\\' && *(endp - 1) != ':')) {
|
---|
| 201 | #else
|
---|
| 202 | if (!baselen || *(endp - 1) != '/') {
|
---|
| 203 | #endif
|
---|
| 204 | *endp++ = '/';
|
---|
| 205 | ++baselen;
|
---|
| 206 | }
|
---|
| 207 | for (rval = 0; --argc; ++argv) {
|
---|
| 208 | /*
|
---|
| 209 | * Find the last component of the source pathname. It
|
---|
| 210 | * may have trailing slashes.
|
---|
| 211 | */
|
---|
| 212 | p = *argv + strlen(*argv);
|
---|
| 213 | #if defined(_MSC_VER) || defined(__EMX__)
|
---|
| 214 | while (p != *argv && (p[-1] == '/' || p[-1] == '\\'))
|
---|
| 215 | --p;
|
---|
| 216 | while (p != *argv && p[-1] != '/' && p[-1] != '/' && p[-1] != ':')
|
---|
| 217 | --p;
|
---|
| 218 | #else
|
---|
| 219 | while (p != *argv && p[-1] == '/')
|
---|
| 220 | --p;
|
---|
| 221 | while (p != *argv && p[-1] != '/')
|
---|
| 222 | --p;
|
---|
| 223 | #endif
|
---|
| 224 |
|
---|
| 225 | if ((baselen + (len = strlen(p))) >= PATH_MAX) {
|
---|
[3192] | 226 | warnx(pCtx, "%s: destination pathname too long", *argv);
|
---|
[813] | 227 | rval = 1;
|
---|
| 228 | } else {
|
---|
| 229 | memmove(endp, p, (size_t)len + 1);
|
---|
[3192] | 230 | if (do_move(&This, *argv, path))
|
---|
[813] | 231 | rval = 1;
|
---|
| 232 | }
|
---|
| 233 | }
|
---|
| 234 | return rval;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
[3192] | 237 | #ifdef KMK_BUILTIN_STANDALONE
|
---|
| 238 | int main(int argc, char **argv, char **envp)
|
---|
| 239 | {
|
---|
| 240 | KMKBUILTINCTX Ctx = { "kmk_mv", NULL };
|
---|
| 241 | return kmk_builtin_mv(argc, argv, envp, &Ctx);
|
---|
| 242 | }
|
---|
| 243 | #endif
|
---|
| 244 |
|
---|
[813] | 245 | static int
|
---|
[3192] | 246 | do_move(PMVINSTANCE pThis, char *from, char *to)
|
---|
[813] | 247 | {
|
---|
| 248 | struct stat sb;
|
---|
| 249 | int ask, ch, first;
|
---|
| 250 | char modep[15];
|
---|
| 251 |
|
---|
| 252 | /*
|
---|
| 253 | * Check access. If interactive and file exists, ask user if it
|
---|
| 254 | * should be replaced. Otherwise if file exists but isn't writable
|
---|
| 255 | * make sure the user wants to clobber it.
|
---|
| 256 | */
|
---|
[3192] | 257 | if (!pThis->fflg && !access(to, F_OK)) {
|
---|
[813] | 258 |
|
---|
| 259 | /* prompt only if source exist */
|
---|
| 260 | if (lstat(from, &sb) == -1) {
|
---|
[3192] | 261 | warn(pThis->pCtx, "%s", from);
|
---|
[813] | 262 | return (1);
|
---|
| 263 | }
|
---|
| 264 |
|
---|
| 265 | #define YESNO "(y/n [n]) "
|
---|
| 266 | ask = 0;
|
---|
[3192] | 267 | if (pThis->nflg) {
|
---|
| 268 | if (pThis->vflg)
|
---|
| 269 | kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s not overwritten\n", to);
|
---|
[813] | 270 | return (0);
|
---|
[3192] | 271 | } else if (pThis->iflg) {
|
---|
[813] | 272 | (void)fprintf(stderr, "overwrite %s? %s", to, YESNO);
|
---|
| 273 | ask = 1;
|
---|
| 274 | } else if (access(to, W_OK) && !stat(to, &sb)) {
|
---|
[1710] | 275 | bsd_strmode(sb.st_mode, modep);
|
---|
[3215] | 276 | #if 0 /* probably not thread safe, also BSDism. */
|
---|
[813] | 277 | (void)fprintf(stderr, "override %s%s%s/%s for %s? %s",
|
---|
| 278 | modep + 1, modep[9] == ' ' ? "" : " ",
|
---|
| 279 | user_from_uid((unsigned long)sb.st_uid, 0),
|
---|
| 280 | group_from_gid((unsigned long)sb.st_gid, 0), to, YESNO);
|
---|
[3215] | 281 | #else
|
---|
[3247] | 282 | (void)fprintf(stderr, "override %s%s%lu/%lu for %s? %s",
|
---|
[3215] | 283 | modep + 1, modep[9] == ' ' ? "" : " ",
|
---|
| 284 | (unsigned long)sb.st_uid, (unsigned long)sb.st_gid,
|
---|
| 285 | to, YESNO);
|
---|
| 286 | #endif
|
---|
[813] | 287 | ask = 1;
|
---|
| 288 | }
|
---|
| 289 | if (ask) {
|
---|
[3192] | 290 | fflush(stderr);
|
---|
[813] | 291 | first = ch = getchar();
|
---|
| 292 | while (ch != '\n' && ch != EOF)
|
---|
| 293 | ch = getchar();
|
---|
| 294 | if (first != 'y' && first != 'Y') {
|
---|
[3192] | 295 | kmk_builtin_ctx_printf(pThis->pCtx, 1, "not overwritten\n");
|
---|
[813] | 296 | return (0);
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 | }
|
---|
| 300 | if (!rename(from, to)) {
|
---|
[3192] | 301 | if (pThis->vflg)
|
---|
| 302 | kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
|
---|
[813] | 303 | return (0);
|
---|
| 304 | }
|
---|
| 305 | #ifdef _MSC_VER
|
---|
| 306 | if (errno == EEXIST) {
|
---|
| 307 | remove(to);
|
---|
| 308 | if (!rename(from, to)) {
|
---|
[3192] | 309 | if (pThis->vflg)
|
---|
| 310 | kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
|
---|
[813] | 311 | return (0);
|
---|
| 312 | }
|
---|
| 313 | }
|
---|
| 314 | #endif
|
---|
| 315 |
|
---|
| 316 | if (errno == EXDEV) {
|
---|
[3215] | 317 | #if 1 //ndef CROSS_DEVICE_MOVE
|
---|
[3192] | 318 | warnx(pThis->pCtx, "cannot move `%s' to a different device: `%s'", from, to);
|
---|
[813] | 319 | return (1);
|
---|
| 320 | #else
|
---|
| 321 | struct statfs sfs;
|
---|
| 322 | char path[PATH_MAX];
|
---|
| 323 |
|
---|
| 324 | /*
|
---|
| 325 | * If the source is a symbolic link and is on another
|
---|
| 326 | * filesystem, it can be recreated at the destination.
|
---|
| 327 | */
|
---|
| 328 | if (lstat(from, &sb) == -1) {
|
---|
[3192] | 329 | warn(pThis->pCtx, "%s", from);
|
---|
[813] | 330 | return (1);
|
---|
| 331 | }
|
---|
| 332 | if (!S_ISLNK(sb.st_mode)) {
|
---|
| 333 | /* Can't mv(1) a mount point. */
|
---|
| 334 | if (realpath(from, path) == NULL) {
|
---|
[3192] | 335 | warnx(pThis->pCtx, "cannot resolve %s: %s", from, path);
|
---|
[813] | 336 | return (1);
|
---|
| 337 | }
|
---|
| 338 | if (!statfs(path, &sfs) &&
|
---|
| 339 | !strcmp(path, sfs.f_mntonname)) {
|
---|
[3192] | 340 | warnx(pThis->pCtx, "cannot rename a mount point");
|
---|
[813] | 341 | return (1);
|
---|
| 342 | }
|
---|
| 343 | }
|
---|
| 344 | #endif
|
---|
| 345 | } else {
|
---|
[3192] | 346 | warn(pThis->pCtx, "rename %s to %s", from, to);
|
---|
[813] | 347 | return (1);
|
---|
| 348 | }
|
---|
| 349 |
|
---|
[3215] | 350 | #if 0//def CROSS_DEVICE_MOVE
|
---|
[813] | 351 | /*
|
---|
| 352 | * If rename fails because we're trying to cross devices, and
|
---|
| 353 | * it's a regular file, do the copy internally; otherwise, use
|
---|
| 354 | * cp and rm.
|
---|
| 355 | */
|
---|
| 356 | if (lstat(from, &sb)) {
|
---|
[3192] | 357 | warn(pThis->pCtx, "%s", from);
|
---|
[813] | 358 | return (1);
|
---|
| 359 | }
|
---|
| 360 | return (S_ISREG(sb.st_mode) ?
|
---|
[3192] | 361 | fastcopy(pThis, from, to, &sb) : copy(pThis, from, to));
|
---|
[813] | 362 | #endif
|
---|
| 363 | }
|
---|
| 364 |
|
---|
[3215] | 365 | #if 0 //def CROSS_DEVICE_MOVE - using static buffers and fork.
|
---|
[813] | 366 | int
|
---|
| 367 | static fastcopy(char *from, char *to, struct stat *sbp)
|
---|
| 368 | {
|
---|
| 369 | struct timeval tval[2];
|
---|
| 370 | static u_int blen;
|
---|
| 371 | static char *bp;
|
---|
| 372 | mode_t oldmode;
|
---|
| 373 | int nread, from_fd, to_fd;
|
---|
| 374 | acl_t acl;
|
---|
| 375 |
|
---|
[3219] | 376 | if ((from_fd = open(from, O_RDONLY | KMK_OPEN_NO_INHERIT, 0)) < 0) {
|
---|
[813] | 377 | warn("%s", from);
|
---|
| 378 | return (1);
|
---|
| 379 | }
|
---|
| 380 | if (blen < sbp->st_blksize) {
|
---|
| 381 | if (bp != NULL)
|
---|
| 382 | free(bp);
|
---|
| 383 | if ((bp = malloc((size_t)sbp->st_blksize)) == NULL) {
|
---|
| 384 | blen = 0;
|
---|
| 385 | warnx("malloc failed");
|
---|
| 386 | return (1);
|
---|
| 387 | }
|
---|
| 388 | blen = sbp->st_blksize;
|
---|
| 389 | }
|
---|
| 390 | while ((to_fd =
|
---|
[3219] | 391 | open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY | KMK_OPEN_NO_INHERIT, 0)) < 0) {
|
---|
[813] | 392 | if (errno == EEXIST && unlink(to) == 0)
|
---|
| 393 | continue;
|
---|
| 394 | warn("%s", to);
|
---|
| 395 | (void)close(from_fd);
|
---|
| 396 | return (1);
|
---|
| 397 | }
|
---|
| 398 | while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
|
---|
| 399 | if (write(to_fd, bp, (size_t)nread) != nread) {
|
---|
| 400 | warn("%s", to);
|
---|
| 401 | goto err;
|
---|
| 402 | }
|
---|
| 403 | if (nread < 0) {
|
---|
| 404 | warn("%s", from);
|
---|
| 405 | err: if (unlink(to))
|
---|
| 406 | warn("%s: remove", to);
|
---|
| 407 | (void)close(from_fd);
|
---|
| 408 | (void)close(to_fd);
|
---|
| 409 | return (1);
|
---|
| 410 | }
|
---|
| 411 |
|
---|
| 412 | oldmode = sbp->st_mode & ALLPERMS;
|
---|
| 413 | if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
|
---|
| 414 | warn("%s: set owner/group (was: %lu/%lu)", to,
|
---|
| 415 | (u_long)sbp->st_uid, (u_long)sbp->st_gid);
|
---|
| 416 | if (oldmode & (S_ISUID | S_ISGID)) {
|
---|
| 417 | warnx(
|
---|
| 418 | "%s: owner/group changed; clearing suid/sgid (mode was 0%03o)",
|
---|
| 419 | to, oldmode);
|
---|
| 420 | sbp->st_mode &= ~(S_ISUID | S_ISGID);
|
---|
| 421 | }
|
---|
| 422 | }
|
---|
| 423 | /*
|
---|
| 424 | * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect
|
---|
| 425 | * for dest_file, then it's ACLs shall reflect the ACLs of the
|
---|
| 426 | * source_file.
|
---|
| 427 | */
|
---|
| 428 | if (fpathconf(to_fd, _PC_ACL_EXTENDED) == 1 &&
|
---|
| 429 | fpathconf(from_fd, _PC_ACL_EXTENDED) == 1) {
|
---|
| 430 | acl = acl_get_fd(from_fd);
|
---|
| 431 | if (acl == NULL)
|
---|
| 432 | warn("failed to get acl entries while setting %s",
|
---|
| 433 | from);
|
---|
| 434 | else if (acl_set_fd(to_fd, acl) < 0)
|
---|
| 435 | warn("failed to set acl entries for %s", to);
|
---|
| 436 | }
|
---|
| 437 | (void)close(from_fd);
|
---|
| 438 | if (fchmod(to_fd, sbp->st_mode))
|
---|
| 439 | warn("%s: set mode (was: 0%03o)", to, oldmode);
|
---|
| 440 | /*
|
---|
| 441 | * XXX
|
---|
| 442 | * NFS doesn't support chflags; ignore errors unless there's reason
|
---|
| 443 | * to believe we're losing bits. (Note, this still won't be right
|
---|
| 444 | * if the server supports flags and we were trying to *remove* flags
|
---|
| 445 | * on a file that we copied, i.e., that we didn't create.)
|
---|
| 446 | */
|
---|
| 447 | errno = 0;
|
---|
| 448 | if (fchflags(to_fd, (u_long)sbp->st_flags))
|
---|
| 449 | if (errno != EOPNOTSUPP || sbp->st_flags != 0)
|
---|
| 450 | warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
|
---|
| 451 |
|
---|
| 452 | tval[0].tv_sec = sbp->st_atime;
|
---|
| 453 | tval[1].tv_sec = sbp->st_mtime;
|
---|
| 454 | tval[0].tv_usec = tval[1].tv_usec = 0;
|
---|
| 455 | if (utimes(to, tval))
|
---|
| 456 | warn("%s: set times", to);
|
---|
| 457 |
|
---|
| 458 | if (close(to_fd)) {
|
---|
| 459 | warn("%s", to);
|
---|
| 460 | return (1);
|
---|
| 461 | }
|
---|
| 462 |
|
---|
| 463 | if (unlink(from)) {
|
---|
| 464 | warn("%s: remove", from);
|
---|
| 465 | return (1);
|
---|
| 466 | }
|
---|
| 467 | if (vflg)
|
---|
[3192] | 468 | kmk_builtin_ctx_printf(pThis->pCtx, 0, "%s -> %s\n", from, to);
|
---|
[813] | 469 | return (0);
|
---|
| 470 | }
|
---|
| 471 |
|
---|
| 472 | int
|
---|
| 473 | copy(char *from, char *to)
|
---|
| 474 | {
|
---|
| 475 | int pid, status;
|
---|
| 476 |
|
---|
| 477 | if ((pid = fork()) == 0) {
|
---|
| 478 | execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to,
|
---|
| 479 | (char *)NULL);
|
---|
| 480 | warn("%s", _PATH_CP);
|
---|
| 481 | _exit(1);
|
---|
| 482 | }
|
---|
| 483 | if (waitpid(pid, &status, 0) == -1) {
|
---|
| 484 | warn("%s: waitpid", _PATH_CP);
|
---|
| 485 | return (1);
|
---|
| 486 | }
|
---|
| 487 | if (!WIFEXITED(status)) {
|
---|
| 488 | warnx("%s: did not terminate normally", _PATH_CP);
|
---|
| 489 | return (1);
|
---|
| 490 | }
|
---|
| 491 | if (WEXITSTATUS(status)) {
|
---|
| 492 | warnx("%s: terminated with %d (non-zero) status",
|
---|
| 493 | _PATH_CP, WEXITSTATUS(status));
|
---|
| 494 | return (1);
|
---|
| 495 | }
|
---|
| 496 | if (!(pid = vfork())) {
|
---|
| 497 | execl(_PATH_RM, "mv", "-rf", "--", from, (char *)NULL);
|
---|
| 498 | warn("%s", _PATH_RM);
|
---|
| 499 | _exit(1);
|
---|
| 500 | }
|
---|
| 501 | if (waitpid(pid, &status, 0) == -1) {
|
---|
| 502 | warn("%s: waitpid", _PATH_RM);
|
---|
| 503 | return (1);
|
---|
| 504 | }
|
---|
| 505 | if (!WIFEXITED(status)) {
|
---|
| 506 | warnx("%s: did not terminate normally", _PATH_RM);
|
---|
| 507 | return (1);
|
---|
| 508 | }
|
---|
| 509 | if (WEXITSTATUS(status)) {
|
---|
| 510 | warnx("%s: terminated with %d (non-zero) status",
|
---|
| 511 | _PATH_RM, WEXITSTATUS(status));
|
---|
| 512 | return (1);
|
---|
| 513 | }
|
---|
| 514 | return (0);
|
---|
| 515 | }
|
---|
| 516 | #endif /* CROSS_DEVICE_MOVE */
|
---|
| 517 |
|
---|
| 518 |
|
---|
| 519 | static int
|
---|
[3192] | 520 | usage(PKMKBUILTINCTX pCtx, int fIsErr)
|
---|
[813] | 521 | {
|
---|
[3192] | 522 | kmk_builtin_ctx_printf(pCtx, fIsErr,
|
---|
| 523 | "usage: %s [-f | -i | -n] [-v] source target\n"
|
---|
| 524 | " or: %s [-f | -i | -n] [-v] source ... directory\n"
|
---|
| 525 | " or: %s --help\n"
|
---|
| 526 | " or: %s --version\n",
|
---|
| 527 | pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName, pCtx->pszProgName);
|
---|
[813] | 528 | return EX_USAGE;
|
---|
| 529 | }
|
---|