bin/38854: sysinstall(8): resetting during setup causes the target installation path to change from "/mnt" (new root partition) to "/" (the memory disk)

Garrett Cooper yanegomi at gmail.com
Tue Nov 23 07:08:13 UTC 2010


Hi,
    I prototyped up a solution for this issue by banking on the fact
that the *fork(2) system calls actually do a copy on write of several
process variables, including the current working directory, etc.
Example:

$ ./test_forking_and_chdiring
[0] getwd = /tmp
[1] getwd = /usr/home/gcooper
[2] getwd = /tmp
[3] getwd = /usr/home/gcooper

    So at least now sysinstall is starting from a sane state
consistently, instead of just reexecuting itself via system(3) with
-fakeInit and -restart (ugh). I was concerned about sysinstall closing
file descriptors on exec, etc, but this appears to be mostly baseless.
Cleaning up these dead options should be done in later commits.
    I executed sysinstall from the command line in multiuser given the
following 4 scenarios:
    1. Exit (exit code was 0).
    2. ^C:
        a. Continue (process continued as usual).
        b. Restart (process `restarted' by continuing on in the loop
again -- it was rather amusing when I discovered that it reexecutes
itself and can essentially overload the stack eventually if it gets
into an infinite loop :/).
        c. Abort (process exited with 1 as I designed it to).
    There might be some corner cases with usage, but this focuses on
the primary areas. I was hoping to use vfork(2) (because it would have
made the logic a bit simpler, but unfortunately vfork isn't isolated
enough to do proper signal handling with SIGINT (I think that the
parent process and the child process share the same signal vectors,
but I could be wrong... I should look).
    Ideally sysinstall should be run from a custom /etc/rc script that
sets up all of these variables and ensures that the sysinstall process
is playing by the rules, but that's something else that needs to be
resolved down the line for this particular issue. This is just a quick
and dirty stopgap fix.
    Credit goes to Gavin for pointing me to this annoying problem :).
Thanks,
-Garrett

#include <sys/types.h>
#include <sys/wait.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(void)
{
	int status;

	switch (fork()) {
	case -1:
		err(1, "fork");
	case 0:
		if (chdir("/tmp") == -1)
			err(1, "chroot");
		printf("[0] getwd = %s\n", getwd(NULL));
		exit(0);
	default:
		if (wait(&status) == -1)
			err(1, "wait");
		else if (status)
			errx(1, "exit status != 0");
	}
	printf("[1] getwd = %s\n", getwd(NULL));
	switch (vfork()) {
	case -1:
		err(1, "vfork");
	case 0:
		if (chdir("/tmp") == -1)
			err(1, "chroot");
		printf("[2] getwd = %s\n", getwd(NULL));
		exit(0);
	default:
		if (wait(&status) == -1)
			err(1, "wait");
		else if (status)
			errx(1, "exit status != 0");
	}
	printf("[3] getwd = %s\n", getwd(NULL));

	exit(0);
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: bin.38854.patch
Type: text/x-patch
Size: 3857 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-sysinstall/attachments/20101123/07178071/bin.38854.bin


More information about the freebsd-sysinstall mailing list