Subject: mv(1) and signals
To: None <tech-userlevel@netbsd.org>
From: None <jklowden@schemamania.org>
List: tech-userlevel
Date: 10/17/2006 16:55:33
Hi,
Today I tried to move a directory across file systems with mv(1).
The source filesystem was ffs; the target was smbfs. The directory
tree had hundreds of large files.
Then I changed my mind and pressed ^C.
I did that because I noticed that it was copying one subtree of
useless information (the .OLD directory). To save time, I deleted
the source files. A moment later, I had an inkling of trouble when
I got messages from mv, which I thought I had already killed with
my ^C:
mv: dat/.OLD/f_company.1.dat.err: No such file or directory
mv: dat/.OLD/f_security.1.asc: No such file or directory
It's not every day I get messages from a dead process....
When I tried to delete the target .OLD directory that mv had
created, I got a permission in error; when I tried to delete it
from the Windows, it said the file [sic] was in use by another
process. Hmm.
Back in NetBSD, ps(1) told me this:
$ ps | grep mv 13718 p7 D 0:23.08
mv -PRp dat /usr/users/home[...]
Hmm. Those aren't documented options, and I hadn't typed them.
No amount of 'kill -9' had any effect. In fact, process 13718 kept
right on trucking, moving the other files. I saw them appear on
the target.
Now, I understand that mv(1) is supposed to be atomic, and I know
from the manpage moving files across filesystems employs magic
under the covers. But think atomic is different from irreversible,
and I think irreversible is suboptimal.
Without looking at the code, I would guess that mv(1) is masking
signals, perhaps in an effort to achieve atomicity. Yet of course
it can't make a non-atomic action (moving a set of files over a
network) atomic, and preventing kill(8) from terminating the task
looks to be more annoying than anything else.
From my reading of the standard
(http://www.opengroup.org/onlinepubs/009695399/utilities/mv.html),
there's no atomic requirement. It says only that errors should be
handled in such a way that either the source or target tree should
be intact (as in, don't delete the source tree until it's been
copied completely).
As far as I can tell, the only effect of my ^C was to prevent
deletion of the source tree. When the process finished, I seemed
to have two complete copies. Sort of an undocumented feature, in
a way.
Does anyone else think ^C should kill mv(1), first time, every
time?
--jkl