Add a -h flag similar to the -h flag for ln to force mv(1) to treat a

symbolic link to a directory for the target as a symbolic link instead of
a directory.  This makes it possible to atomically update a symbolic
link using rename().

Reviewed by:	gj
MFC after:	2 weeks
This commit is contained in:
John Baldwin 2012-08-31 14:35:01 +00:00
parent 9e8100e77c
commit 6ce6b6c1d4
2 changed files with 36 additions and 6 deletions

View File

@ -32,7 +32,7 @@
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
.\" $FreeBSD$
.\"
.Dd May 12, 2007
.Dd August 28, 2012
.Dt MV 1
.Os
.Sh NAME
@ -41,7 +41,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl f | i | n
.Op Fl v
.Op Fl hv
.Ar source target
.Nm
.Op Fl f | i | n
@ -81,6 +81,21 @@ option overrides any previous
or
.Fl n
options.)
.It Fl h
If the
.Ar target
operand is a symbolic link to a directory,
do not follow it.
This causes the
.Nm
utility to rename the file
.Ar source
to the destination path
.Ar target
rather than moving
.Ar source
into the directory referenced by
.Ar target .
.It Fl i
Cause
.Nm
@ -142,7 +157,8 @@ rm -rf source_file
.Ex -std
.Sh COMPATIBILITY
The
.Fl n
.Fl h ,
.Fl n ,
and
.Fl v
options are non-standard and their use in scripts is not recommended.

View File

@ -68,7 +68,7 @@ __FBSDID("$FreeBSD$");
/* Exit code for a failed exec. */
#define EXEC_FAILED 127
static int fflg, iflg, nflg, vflg;
static int fflg, hflg, iflg, nflg, vflg;
static int copy(const char *, const char *);
static int do_move(const char *, const char *);
@ -87,8 +87,11 @@ main(int argc, char *argv[])
int ch;
char path[PATH_MAX];
while ((ch = getopt(argc, argv, "finv")) != -1)
while ((ch = getopt(argc, argv, "fhinv")) != -1)
switch (ch) {
case 'h':
hflg = 1;
break;
case 'i':
iflg = 1;
fflg = nflg = 0;
@ -123,6 +126,17 @@ main(int argc, char *argv[])
exit(do_move(argv[0], argv[1]));
}
/*
* If -h was specified, treat the target as a symlink instead of
* directory.
*/
if (hflg) {
if (argc > 2)
usage();
if (lstat(argv[1], &sb) == 0 && S_ISLNK(sb.st_mode))
exit(do_move(argv[0], argv[1]));
}
/* It's a directory, move each file into it. */
if (strlen(argv[argc - 1]) > sizeof(path) - 1)
errx(1, "%s: destination pathname too long", *argv);
@ -483,7 +497,7 @@ usage(void)
{
(void)fprintf(stderr, "%s\n%s\n",
"usage: mv [-f | -i | -n] [-v] source target",
"usage: mv [-f | -i | -n] [-hv] source target",
" mv [-f | -i | -n] [-v] source ... directory");
exit(EX_USAGE);
}