Upgrading ports while processes are running.

Mark Shroyer subscriber+freebsd at markshroyer.com
Tue Aug 17 02:29:41 UTC 2010

On Tue, 17 Aug 2010 03:23:27 +0200, Polytropon <freebsd at edvax.de> wrote:
> At least, the step that wants to write will fail, and this will
> mostly be (finally) signaled by a make error.

This is sort of pedantic for me to bring up, but I wouldn't count on the
install failing.  Because Unix makes a distinction between unlinking and
file deletion, you can generally unlink the binary of a running
executable without any problem; the filesystem won't actually delete it
at least until the process in question stops running and the inode's
reference count drops to zero.  See Advanced Programming in the Unix
Environment for details.

Here's a quick example on FreeBSD:

    $ cat hello.c
    #include <stdio.h>

    int main(int argc, char* argv[])
      while (1) {

      return 0;
    $ cc -o hello hello.c
    $ ./hello

This simple program will start printing "Hello" repeatedly.  Now if I
switch to another terminal, I can delete the hello binary:

    $ rm hello

But switching back to the first terminal, I see the program is still
running just fine.  Running programs can be unlinked.

And this is what the install program used by FreeBSD ports appears to
do; from /usr/src/usr.bin/xinstall/install.c:

    create_newfile(const char *path, int target, struct stat *sbp)
        char backup[MAXPATHLEN];
        int saved_errno = 0;
        int newfd;

        if (target) {
             * Unlink now... avoid ETXTBSY errors later.  Try to turn
             * off the append/immutable bits -- if we fail, go ahead,
             * it might work.
            if (sbp->st_flags & NOCHANGEBITS)
                (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS);

            if (dobackup) {
                if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s",
                path, suffix) != strlen(path) + strlen(suffix))
                    errx(EX_OSERR, "%s: backup filename too long",
                (void)snprintf(backup, MAXPATHLEN, "%s%s",
                path, suffix);
                if (verbose)
                    (void)printf("install: %s -> %s\n",
                    path, backup);
                if (rename(path, backup) < 0)
                    err(EX_OSERR, "rename: %s to %s", path, backup);
            } else
                if (unlink(path) < 0)
                    saved_errno = errno;

        newfd = open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
        if (newfd < 0 && saved_errno != 0)
            errno = saved_errno;
        return newfd;

That isn't to say you won't see any negative consequences from
overwriting a running port with a newer version.  Hypothetically, you
might install a new Python including a new standard library, and if your
running (old) Python process tries to load one of its deleted modules
from disk something could break.  Or not; I'm no expert on the ports
system, they might have some way of working around this.  But as for a
pragmatic answer to your question, I err on the side of caution with
this stuff :)

Mark Shroyer

More information about the freebsd-questions mailing list