Subject: mv(1) and signals
To: None <>
From: None <>
List: tech-userlevel
Date: 10/17/2006 16:55:33

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
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