* mountall: make the "console output" Upstart stanza do its work. We

were redirecting output to /var/log/upstart/<job>, so it didn't work
  properly.
* mountall-ip-up: send the USR1 signal to the mountall process by
  looking up its PID, rather than doing "pkill -USR1 mountall".  This
  prevents a very subtle race condition where USR1 is delivered to a
  child process of mountall (such as fsck), if pkill sees the child
  just before its execve().  There is actually still a race condition
  because mountall installs its USR1 handler *after* daemonising, so
  mountall-ip-up could accidentally kill mountall.  Should report this
  to upstream.

svn path=/nixos/trunk/; revision=33236
This commit is contained in:
Eelco Dolstra 2012-03-18 17:48:19 +00:00
parent b82c253b24
commit 362d1389d3
2 changed files with 53 additions and 14 deletions

View file

@ -42,8 +42,12 @@ let
${concatMapStrings (n: "env ${n}=\"${getAttr n env}\"\n") (attrNames env)}
${optionalString (job.console != "") "console ${job.console}"}
pre-start script
exec >> ${log} 2>&1
${optionalString (job.console == "") ''
exec >> ${log} 2>&1
''}
ln -sfn "$(readlink -f "/etc/init/${job.name}.conf")" /var/run/upstart-jobs/${job.name}
${optionalString (job.preStart != "") ''
source ${jobHelpers}
@ -56,24 +60,32 @@ let
else if job.script != "" then
''
script
exec >> ${log} 2>&1
${optionalString (job.console == "") ''
exec >> ${log} 2>&1
''}
source ${jobHelpers}
${job.script}
end script
''
else if job.exec != "" then
else if job.exec != "" && job.console == "" then
''
script
exec >> ${log} 2>&1
exec ${job.exec}
end script
''
else if job.exec != "" then
''
exec ${job.exec}
''
else ""
}
${optionalString (job.postStart != "") ''
post-start script
exec >> ${log} 2>&1
${optionalString (job.console == "") ''
exec >> ${log} 2>&1
''}
source ${jobHelpers}
${job.postStart}
end script
@ -88,7 +100,9 @@ let
# (upstart 0.6.5, job.c:562)
optionalString (job.preStop != "") (assert hasMain; ''
pre-stop script
exec >> ${log} 2>&1
${optionalString (job.console == "") ''
exec >> ${log} 2>&1
''}
source ${jobHelpers}
${job.preStop}
end script
@ -96,7 +110,9 @@ let
${optionalString (job.postStop != "") ''
post-stop script
exec >> ${log} 2>&1
${optionalString (job.console == "") ''
exec >> ${log} 2>&1
''}
source ${jobHelpers}
${job.postStop}
end script
@ -364,6 +380,18 @@ let
'';
};
console = mkOption {
default = "";
example = "console";
description = ''
If set to <literal>output</literal>, job output is written to
the console. If it's <literal>owner</literal>, additionally
the job becomes owner of the console. It it's empty (the
default), output is written to
<filename>/var/log/upstart/<replaceable>jobname</replaceable></filename>
'';
};
};

View file

@ -178,7 +178,9 @@ in
path = [ pkgs.utillinux pkgs.mountall ] ++ config.system.fsPackages;
script =
console = "output";
preStart =
''
# Ensure that this job is restarted when fstab changed:
# ${fstab}
@ -186,11 +188,13 @@ in
${optionalString config.services.nfs.client.enable ''
ensure statd || true
''}
exec > /dev/console 2>&1
echo "mounting filesystems..."
exec mountall
'';
daemonType = "daemon";
exec = "mountall --daemon";
};
# The `mount-failed' event is emitted synchronously, but we don't
@ -223,19 +227,26 @@ in
startOn = "ip-up";
script =
''
${pkgs.procps}/bin/pkill -USR1 -u root mountall || true
# Send USR1 to the mountall process. Can't use "pkill
# mountall" here because that has a race condition: we may
# accidentally send USR1 to children of mountall (such as
# fsck) just before they do execve().
status="$(status mountall)"
if [[ "$status" =~ "start/running, process "([0-9]+) ]]; then
pid=''${BASH_REMATCH[1]}
echo "sending USR1 to $pid..."
kill -USR1 "$pid"
fi
'';
};
jobs."emergency-shell" =
{ task = true;
extraConfig = "console owner";
console = "owner";
script =
''
exec < /dev/console > /dev/console 2>&1
cat <<EOF
<<< Emergency shell >>>