| WSIGNALED i -> failwith (sprintf "shget: command killed by signal %d" i)
| WSTOPPED i -> failwith (sprintf "shget: command stopped by signal %d" i)
-(* Start an interactive shell. *)
+(* Start an interactive shell. Need to juggle file descriptors a bit
+ * because bash write PS1 to stderr (currently directed to the logfile).
+ *)
let shell () =
- shfailok "PS1='\\u@\\h:\\w\\$ ' bash"
+ match fork () with
+ | 0 -> (* child, runs bash *)
+ close stderr;
+ dup2 stdout stderr;
+ (* Sys.command runs 'sh -c' which blows away PS1, so set it late. *)
+ ignore (
+ Sys.command "PS1='\\u@\\h:\\w\\$ ' /bin/bash --norc --noprofile -i"
+ )
+ | _ -> (* parent, waits *)
+ eprintf "waiting for subshell to exit\n%!";
+ ignore (wait ())
(* Some true if is dir/file, Some false if not, None if not found. *)
let is_dir path =
sh (sprintf "dmsetup create %s --table='0 %Ld snapshot /dev/mapper/%s_org %s n 64'"
snapshot_dev sectors snapshot_dev ramdisk)
-(* Try to perform automatic network configuration, assuming a Fedora or RHEL-
- * like root filesystem mounted on /mnt/root.
+(* Try to perform automatic network configuration, assuming a Fedora or
+ * RHEL-like root filesystem mounted on /mnt/root.
*)
let auto_network state =
(* Fedora gives an error if this file doesn't exist. *)
sh "touch /etc/resolv.conf";
- chdir "/etc/sysconfig";
-
- sh "mv network network.saved";
- sh "mv networking networking.saved";
- sh "mv network-scripts network-scripts.saved";
-
- (* Originally I symlinked these, but that causes dhclient to
- * keep open /mnt/root (as its cwd is in network-scripts subdir).
- * So now we will copy them recursively instead.
+(*
+ (* We can run /mnt/root/etc/init.d/network in a chroot environment,
+ * however this won't work directly because the architecture of the
+ * binaries under /mnt/root (eg. /mnt/root/sbin/ip) might not match
+ * the architecture of the live CD kernel. In particular, a 32 bit
+ * live CD cannot run 64 bit binaries. So we also have to bind-mount
+ * the live CD's /bin, /sbin, /lib etc. over the equivalents in
+ * /mnt/root.
*)
- sh "cp -r /mnt/root/etc/sysconfig/network .";
- sh "cp -r /mnt/root/etc/sysconfig/networking .";
- sh "cp -r /mnt/root/etc/sysconfig/network-scripts .";
-
+ let bind dir =
+ if is_dir dir = Some true then
+ sh ("mount -o bind " ^ quote dir ^ " " ^ quote ("/mnt/root" ^ dir))
+ in
+ let unbind dir =
+ if is_dir dir = Some true then sh ("umount -l " ^ quote ("/mnt/root" ^ dir))
+ in
+ let dirs = [
+ "/bin"; "/sbin"; "/lib"; "/lib64";
+ "/usr/bin"; "/usr/sbin"; "/usr/lib"; "/usr/lib64";
+ "/proc"; "/sys"
+ ] in
+ List.iter bind dirs;
+ let status = shwithstatus "chroot /mnt/root /etc/init.d/network start" in
+ List.iter unbind dirs;
+*)
+
+ (* Simpler way to do the above.
+ * NB. Lazy unmount is required because dhclient keeps its current
+ * directory open on /etc/sysconfig/network-scripts/
+ *)
+ sh "mount -o bind /mnt/root/etc /etc";
let status = shwithstatus "/etc/init.d/network start" in
-
- sh "rm -rf network networking network-scripts";
- sh "mv network.saved network";
- sh "mv networking.saved networking";
- sh "mv network-scripts.saved network-scripts";
-
- chdir "/tmp";
+ sh "umount -l /etc";
(* Try to ping the remote host to see if this worked. *)
shfailok ("ping -c 3 " ^ Option.map_default quote "" state.remote_host);
(* Output of 'file' command for Linux swap file. *)
let swap = Pcre.regexp "Linux.*swap.*file" in
(* Contents of /etc/redhat-release. *)
- let rhel = Pcre.regexp "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)\\.(\\d+)" in
- let fedora = Pcre.regexp "Fedora.*release (\\d+)\\.(\\d+)" in
+ let rhel = Pcre.regexp "(?:Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\\d+)(?:\\.(\\d+))?" in
+ let fedora = Pcre.regexp "Fedora.*release (\\d+)" in
(* Contents of /etc/debian_version. *)
let debian = Pcre.regexp "^(\\d+)\\.(\\d+)" in
(* Output of 'file' on certain executables. *)
match lines with
| [] -> (* empty /etc/redhat-release ...? *)
LinuxRoot (UnknownArch, OtherLinux)
- | line::_ ->
+ | line::_ -> (* try to detect OS from /etc/redhat-release *)
try
let subs = Pcre.exec ~rex:rhel line in
let major = int_of_string (Pcre.get_substring subs 1) in
- let minor = int_of_string (Pcre.get_substring subs 2) in
+ let minor =
+ try int_of_string (Pcre.get_substring subs 2)
+ with Not_found -> 0 in
LinuxRoot (UnknownArch, RHEL (major, minor))
with
Not_found | Failure "int_of_string" ->
match lines with
| [] -> (* empty /etc/debian_version ...? *)
LinuxRoot (UnknownArch, OtherLinux)
- | line::_ ->
+ | line::_ -> (* try to detect version from /etc/debian_version *)
try
let subs = Pcre.exec ~rex:debian line in
let major = int_of_string (Pcre.get_substring subs 1) in