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
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=239951
2 changed files with 36 additions and 6 deletions

View File

@ -32,7 +32,7 @@
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93 .\" @(#)mv.1 8.1 (Berkeley) 5/31/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd May 12, 2007 .Dd August 28, 2012
.Dt MV 1 .Dt MV 1
.Os .Os
.Sh NAME .Sh NAME
@ -41,7 +41,7 @@
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl f | i | n .Op Fl f | i | n
.Op Fl v .Op Fl hv
.Ar source target .Ar source target
.Nm .Nm
.Op Fl f | i | n .Op Fl f | i | n
@ -81,6 +81,21 @@ option overrides any previous
or or
.Fl n .Fl n
options.) 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 .It Fl i
Cause Cause
.Nm .Nm
@ -142,7 +157,8 @@ rm -rf source_file
.Ex -std .Ex -std
.Sh COMPATIBILITY .Sh COMPATIBILITY
The The
.Fl n .Fl h ,
.Fl n ,
and and
.Fl v .Fl v
options are non-standard and their use in scripts is not recommended. 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. */ /* Exit code for a failed exec. */
#define EXEC_FAILED 127 #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 copy(const char *, const char *);
static int do_move(const char *, const char *); static int do_move(const char *, const char *);
@ -87,8 +87,11 @@ main(int argc, char *argv[])
int ch; int ch;
char path[PATH_MAX]; char path[PATH_MAX];
while ((ch = getopt(argc, argv, "finv")) != -1) while ((ch = getopt(argc, argv, "fhinv")) != -1)
switch (ch) { switch (ch) {
case 'h':
hflg = 1;
break;
case 'i': case 'i':
iflg = 1; iflg = 1;
fflg = nflg = 0; fflg = nflg = 0;
@ -123,6 +126,17 @@ main(int argc, char *argv[])
exit(do_move(argv[0], argv[1])); 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. */ /* It's a directory, move each file into it. */
if (strlen(argv[argc - 1]) > sizeof(path) - 1) if (strlen(argv[argc - 1]) > sizeof(path) - 1)
errx(1, "%s: destination pathname too long", *argv); errx(1, "%s: destination pathname too long", *argv);
@ -483,7 +497,7 @@ usage(void)
{ {
(void)fprintf(stderr, "%s\n%s\n", (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"); " mv [-f | -i | -n] [-v] source ... directory");
exit(EX_USAGE); exit(EX_USAGE);
} }