PERFORCE change 125568 for review
Ivan Voras
ivoras at FreeBSD.org
Wed Aug 22 15:32:10 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=125568
Change 125568 by ivoras at ivoras_finstall on 2007/08/22 22:31:40
Started work on post-install system configuration
Affected files ...
.. //depot/projects/soc2007/ivoras_finstall/installer/finstall.py#13 edit
.. //depot/projects/soc2007/ivoras_finstall/installer/glade/createuser.glade#1 add
.. //depot/projects/soc2007/ivoras_finstall/installer/glade/hostroot.glade#1 add
.. //depot/projects/soc2007/ivoras_finstall/installer/text/createuser.txt#1 add
.. //depot/projects/soc2007/ivoras_finstall/installer/text/hostroot.txt#1 add
.. //depot/projects/soc2007/ivoras_finstall/pybackend/freebsd.py#8 edit
.. //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#11 edit
Differences ...
==== //depot/projects/soc2007/ivoras_finstall/installer/finstall.py#13 (text+ko) ====
@@ -23,7 +23,7 @@
# finstall Installer
import os,sys,time
-import logging
+import logging, base64, random
from types import MethodType
from xmlrpclib import ServerProxy
import gobject, gtk, gtk.gdk, gtk.glade
@@ -45,7 +45,13 @@
{ "tile" : "nparts" },
{ "tile" : "ndefaultfs" },
{ "tile" : "nverify" },
- { "tile" : "ninstall", "glade" : "installprogress.glade" }
+ { "tile" : "ninstall", "glade" : "installprogress.glade" },
+ { "tile" : "hostroot" },
+ { "tile" : "createuser" },
+ { "tile" : "netconf" },
+ { "tile" : "x11conf" },
+ { "tile" : "soundconf" },
+ { "tile" : "nfinish" }
]
@@ -93,7 +99,7 @@
if "on_load" in self.tile_handlers:
try:
if not self.tile_handlers["on_load"]():
- logging.error("On_Load refused by %s, but it's not implemented" % tile_name)
+ logging.error("On_Load refused by %s, but it's ignored (not implemented yet)" % tile_name)
except:
logging.exception("Error executing on_load handler for %s" % tile_name)
@@ -317,8 +323,6 @@
/var
/home
and a symlink from /usr/ports to /usr/local/ports.
- We'll not use the traditional BSD layout of bsdlabels (a=root, b=swap), except
- for the unfortunately special "c" label.
"""
if self["radio_ufs"].get_active():
@@ -359,7 +363,7 @@
# Calculate the partitioning scheme
var_size = min(2048, int(self.trackdata["drive_size"] * 0.1))
- usr_size = min(15*1024, int(self.trackdata["drive_size"] * 0.3))
+ usr_size = min(10*1024, int(self.trackdata["drive_size"] * 0.5))
if fs in ("UFS+SU", "UFS+GJ", "Ext2"):
# "Normal" file systems, unix-like
@@ -527,6 +531,7 @@
self.next_progress_advert()
self.trackdata["part_job"] = self.server.StartPartitionJob(self.trackdata["new_parts"])
gobject.timeout_add(500, self.part_progress)
+ return True
def add_install_list(self, msg):
@@ -559,7 +564,7 @@
self._show_message(result[-1000:], "Error during backend function (part_job)")
return False
self["progressbar"].set_fraction(float(pcnt) / 100)
- if pcnt == 100:
+ if pcnt == 100 and self.server.QueryIsJobFinished(self.trackdata["part_job"]):
result = self.server.QueryJobResult(self.trackdata["part_job"])
self.server.DismantleJob(self.trackdata["part_job"])
del self.trackdata["part_job"]
@@ -567,7 +572,7 @@
self.trackdata["install_job"] = self.server.StartInstallJob(self.trackdata["new_parts"])
self["progressbar"].set_fraction(0)
self.add_install_list("Installing FreeBSD base system...")
- gobject.timeout_add(1000, self.install_progress)
+ gobject.timeout_add(2000, self.install_progress)
self.next_progress_advert()
return False
return True
@@ -582,13 +587,119 @@
self._show_message(result[-1000:], "Error during backend function (install_job)")
return False
self["progressbar"].set_fraction(float(pcnt) / 100)
- if pcnt > 0 and pcnt % 15 == 0:
+ if pcnt > 0 and pcnt % 25 == 0:
+ self.next_progress_advert()
+ if pcnt == 100 and self.server.QueryIsJobFinished(self.trackdata["install_job"]):
+ self.server.DismantleJob(self.trackdata["install_job"])
+ del self.trackdata["install_job"]
+ # Start a new job - install packages
+ self.trackdata["pkginstall_job"] = self.server.StartPkgInstallJob(self.trackdata["new_parts"])
+ self["progressbar"].set_fraction(0)
+ self.add_install_list("Installing packages...")
+ gobject.timeout_add(2000, self.pkginstall_progress)
+ self.next_progress_advert()
+ return False
+ return True
+
+
+ def pkginstall_progress(self):
+ try:
+ pcnt = self.server.QueryJobProgress(self.trackdata["pkginstall_job"])
+ except Exception, e:
+ code, result = self.server.QueryJobError(self.trackdata["pkginstall_job"])
+ print code, result
+ self._show_message(result[-1000:], "Error during backend function (install_job)")
+ return False
+ self["progressbar"].set_fraction(float(pcnt) / 100)
+ if pcnt > 0 and pcnt % 25 == 0:
self.next_progress_advert()
- if pcnt == 100:
+ if pcnt == 100 and self.server.QueryIsJobFinished(self.trackdata["pkginstall_job"]):
+ self.server.DismantleJob(self.trackdata["pkginstall_job"])
+ del self.trackdata["pkginstall_job"]
+ logging.info("PkgInstall finished")
+ self._load_tile("hostusername")
+ return False
+ return True
+
+
+ def hostroot_on_load(self):
+ self._load_label(self["label2"], "hostroot.txt")
+ return True
+
+
+ def on_button_generate_clicked(self, evt):
+ seq = ""
+ for x in xrange(8):
+ seq += chr(random.randint(0, 255))
+ str = base64.b64encode(seq)
+ password = str[0:8]
+ self._show_message("Your generated password is:\n\n"+password+"\n\nPLEASE REMEMBER IT. DO NOT WRITE DOWN YOUR PASSWORDS.", "Generated random password")
+ self["entry_password"].set_text(password)
+ self["entry_confirm_password"].set_text(password)
+
+
+ def hostroot_on_next(self):
+ if self["entry_password"].get_text() != self["entry_confirm_password"].get_text():
+ self._show_message("Passwords do not match! Please enter the same password\nin the Password and Confirm password fields", "Password mismatch")
+ return False
+ code, result = self.server.SetHostName(self["entry_hostname"].get_text())
+ if code != 0:
+ self._show_message(result, "Error")
+ return False
+ code, result = self.server.SetUserPassword("root", self["entry_password"].get_text())
+ return True
+
+
+ def createuser_on_load(self):
+ self._load_label(self["label2"], "createuser.txt")
+ return True
+
+
+ def createuser_on_next(self):
+ if self["entry_password"].get_text() != self["entry_confirm_password"].get_text():
+ self._show_message("Passwords do not match! Please enter the same password\nin the Password and Confirm password fields", "Password mismatch")
+ return False
+ username = self["entry_username"].get_text()
+ if username.find(" ") == -1:
+ self._show_message("Invalid username. No whitespace, please.", "Error")
+ return False
+ code, result = self.server.AddUser(username, self["entry_user"].get_text(), self["entry_password"].get_text())
+ if code != 0:
+ self._show_message(result, "Error")
return False
return True
+ def netconf_on_load(self):
+ pass
+
+
+ def netconf_on_next(self):
+ pass
+
+
+ def x11conf_on_load(self):
+ pass
+
+
+ def x11conf_on_next(self):
+ pass
+
+
+ def soundconf_on_load(self):
+ pass
+
+
+ def soundconf_on_next(self):
+ pass
+
+
+ def nfinish_on_load(self):
+ pass
+
+
+ def nfinish_on_next(self):
+ pass
my_dir = os.path.split(sys.argv[0])[0]
==== //depot/projects/soc2007/ivoras_finstall/pybackend/freebsd.py#8 (text+ko) ====
@@ -26,6 +26,8 @@
import re
import xmldict
+live_root = "/"
+
cmd_sysctl = "/sbin/sysctl"
cmd_geom = "/sbin/geom"
cmd_mount = "/sbin/mount"
@@ -39,6 +41,7 @@
cmd_kldload = "/sbin/kldload"
cmd_mke2fs = "/usr/local/sbin/mke2fs"
cmd_boot0cfg = "/usr/sbin/boot0cfg"
+cmd_pw = "/usr/sbin/pw"
file_dmesg = "/var/run/dmesg.boot"
@@ -62,15 +65,18 @@
def get_cmd_output(name):
+ """Executes a command and returns its output."""
return os.popen(name).read().strip()
def get_dmesg():
+ """Return the contents of the dmesg file."""
global file_dmesg
return [x.strip() for x in file(file_dmesg, "r").readlines()]
def get_geom_xml():
+ """Returns XMLDict object containing the GEOM XML tree."""
return xmldict.buildxmldict(get_sysctl("kern.geom.confxml", True))
@@ -102,6 +108,10 @@
def guess_fs_last_mount(dev, fs_type="UFS"):
+ """
+ Guess where the file system (device) was last mounted on in the
+ file system tree.
+ """
global cmd_file
if not fs_type in ("UFS2", "UFS"): # For now, we only know how to handle UFS
return None
@@ -129,6 +139,7 @@
def geom_sector_size(dev):
+ """Find out sector size of the device."""
xml = get_geom_xml()
for cls in xml["mesh"]["class"]:
if "geom" in cls:
@@ -144,9 +155,13 @@
"""
Convenience function that executes the command specified by
the cmd argument and returns its exit status and its output from both stdout
- and stderr. Optionally, a simple string can be send to the process'
- stdin.
+ and stderr. Optionally, a simple string can be send to the process' stdin.
+ If the cmd starts with "/" (as it should), it will be prepended with
+ global variable live_root, which should point to a FreeBSD live tree.
"""
+ global live_root
+ if cmd.startswith("/") and live_root != "/":
+ cmd = "%s/%d" % (live_root, cmd)
logging.info("Executing %s" %cmd)
p = popen2.Popen4(cmd)
if input != None:
@@ -163,6 +178,9 @@
def create_fdisk_partition(dev, index, offset_sectors, size_sectors, flags=[]):
+ """
+ Create a fdisk partition on the device.
+ """
global cmd_fdisk, cmd_boot0cfg
temp_fname, f = make_temp_script()
# Create the script
@@ -199,6 +217,7 @@
def create_bsdlabel_partition(dev, index, offset_sectors, size_sectors, flags=[], fs_type="4.2BSD"):
+ """Create a bsdlabel partition on the device."""
global cmd_bsdlabel, bsdlabel_map
output = ""
if "init" in flags:
@@ -238,7 +257,7 @@
f.write("\n")
f.close()
code, output = exec_cmd("%s -R %s %s" % (cmd_bsdlabel, dev, script_fname))
- #os.unlink(script_fname)
+ os.unlink(script_fname)
if code != 0:
return (code, output, None)
# Verify the result & fetch the last_offset
@@ -286,6 +305,7 @@
def mount(dev, mount, fs_type, mkdir_mount=True):
+ """Mounts a file system / device on a directory."""
global cmd_mount
if not dev.startswith("/dev/"):
dev = "/dev/"+dev
@@ -303,9 +323,56 @@
def umount(mount):
+ """Umounts a mount point"""
global cmd_umount
return exec_cmd("%s %s" % (cmd_umount, mount))
+
+def fstab_line(dev, mount, fs_type):
+ """Generates a line for the fstab file"""
+ if fs_type == "ZFS":
+ return None
+ if fs_type == "swap":
+ mount = "none"
+ opt = "sw"
+ dump = fpass = 0
+ else:
+ opt = "rw"
+ if mount == "/":
+ dump = fpass = 1
+ else:
+ dump = fpass = 2
+ if fs_type in ("UFS", "UFS+SU"):
+ fs_type = "ufs"
+ elif fs_type == "UFS+GJ":
+ fs_type = "ufs"
+ dev = dev + ".journal"
+ opt += ",async"
+ elif fs_type == "Ext2":
+ fs_type = "ext2fs"
+
+ return "%s\t\%s\t%s\t%s\t%s\t%s" % (dev, mount, fs_type, opt, dump, fpass)
+
+
+def chpasswd(user_name, password, etc_dir="/etc"):
+ """Changes the user's password. The user must exist."""
+ global cmd_pw
+ return exec_cmd("%s -V %s usermod %s -h 0" % (cmd_pw, etc_dir, user_name), password)
+
+
+def useradd(user_name, user, password, shell, groups=[], etc_dir="/etc"):
+ """Adds a user and sets his default shell and member groups"""
+ global cmd_pw
+ guess_root = os.path.split(etc_dir)[0]
+ if guess_root == "/":
+ guess_root = ""
+ guess_home = "%s/home" % guess_root
+ if len(groups) != 0:
+ return exec_cmd("%s -V %s useradd %s -m -s %s -G %s -c \"%s\" -b %s" % (cmd_pw, etc_dir, user_name, shell, ",".join(groups), user, guess_home))
+ else:
+ return exec_cmd("%s -V %s useradd %s -m -s %s -c \"%s\" -b %s" % (cmd_pw, etc_dir, user_name, shell, user, guess_home))
+
+
if __name__ == "__main__":
xml = get_geom_xml()
for cls in xml["mesh"]["class"]:
==== //depot/projects/soc2007/ivoras_finstall/pybackend/systoolengine.py#11 (text+ko) ====
@@ -22,7 +22,7 @@
# SysToolD Engine: implements SysToolD XML-RPC methods
import os, sys, shutil
-import re
+import re, time
import logging, warnings
from threading import Thread, Lock
from StringIO import StringIO
@@ -33,8 +33,10 @@
def logexception(func):
- """Method call decorator that routes exceptions to the logger
- before passing them on"""
+ """
+ Method call decorator that routes exceptions to the logger
+ before passing them on.
+ """
def call(*args, **kwds):
try:
return func(*args, **kwds)
@@ -45,8 +47,10 @@
def tolist(e):
- """Coalesce argument to list (if the argument is not list,
- wrap it in a list of one element)."""
+ """
+ Coalesce argument to list (if the argument is not list,
+ wrap it in a list of one element).
+ """
if type(e) == type([]):
return e
else:
@@ -54,11 +58,17 @@
class SysToolJobException(Exception):
+ """Error in a SysToolJob"""
pass
class SysToolJob(Thread):
- """A generic asynchronous SysTool job"""
+ """A generic asynchronous SysTool job, with common methods"""
+
+ INSTALL_ROOT = "/dist"
+ BASE_MAPTREE_FILE = "/install/base.maptree"
+ USRLOCAL_MAPTREE_FILE = "/install/usrlocal.maptree"
+ VARDBPKG_MAPTREE_FILE = "/install/vardbpkg.maptree"
def __init__(self):
Thread.__init__(self)
@@ -70,7 +80,93 @@
def _calc_percent(self, i, total):
return int((float(i+1) / total) * 100)
+ def MountPartitions(self, part_spec, install_root):
+ """
+ Mount partitions from part_spec. Returnes a (code, result) tuple.
+ """
+ for part in part_spec:
+ if part["fs"] == None or part["fs"] == "swap":
+ continue
+ if part["mount"] == "/":
+ mount = install_root
+ else:
+ mount = "%s/%s" % (install_root, part["mount"])
+ code, result = freebsd.mount(part["name"], mount, part["fs"])
+ if code != 0:
+ return (code, result)
+ return (0, None)
+ def UmountPartitions(self, part_spec, install_root, force=False):
+ """
+ Unmount partitions from part_spec. If force parameter is True, errors
+ from umount are ignored, otherwise, a (code,result) pair is returned.
+ """
+ for part in reversed(part_spec):
+ if part["fs"] == None or part["fs"] == "swap":
+ continue
+ if part["mount"] == "/":
+ mount = install_root
+ else:
+ mount = "%s/%s" % (install_root, part["mount"])
+ code, result = freebsd.umount(mount)
+ if code != 0 and not force:
+ return (code, result)
+ return (0, None)
+
+ def InstallFromMapTree(self, maptree_filename, install_root, from_root):
+ """
+ The method will process the records in maptree and copy the files found
+ there from from_root to install_root. Since this operation normally takes
+ a long time, the method updates self.percent_complete.
+ """
+ if from_root == "/":
+ from_root = ""
+ maptree_size = os.path.getsize(maptree_filename)
+ f = file(maptree_filename, "r")
+ for line in f:
+ self.percent_complete = self._calc_percent(f.tell(), maptree_size)
+ rec = line.strip().split("|")
+ rec_file = rec[-1]
+ dest_file = "%s/%s" % (install_root, rec_file)
+ src_file = "%s/%s" % (from_root, rec_file)
+ if rec[0] == "F":
+ if not os.path.exists(src_file):
+ logging.info("File not found: "+src_file)
+ continue
+ logging.info("copy %s to %s" % (src_file, dest_file))
+ shutil.copyfile(src_file, dest_file)
+ shutil.copystat(src_file, dest_file)
+ elif rec[0] == "D":
+ if not os.path.exists(dest_file):
+ os.mkdir(dest_file)
+ elif rec[0] == "H":
+ if os.path.exists(dest_file):
+ os.unlink(dest_file)
+ try:
+ os.link("%s/%s" % (install_root, rec[1]), dest_file)
+ except:
+ logging.error("Cannot hardlink '%s/%s' to '%s'" % (from_root, rec[1], dest_file))
+ try:
+ shutil.copyfile("/%s" % rec[1], dest_file)
+ except:
+ logging.error("Cannot replace hardlink from '%s/%s' to '%s' with file copy" % (from_root, rec[1], dest_file))
+ elif rec[0] == "L":
+ # symlinks are a special case - they don't need to exist and they can be
+ # embarrasingly relative
+ if os.path.exists(dest_file):
+ if os.path.islink(dest_file):
+ os.unlink(dest_file)
+ os.symlink("%s" % rec[1], dest_file)
+ else:
+ os.symlink("%s" % rec[1], dest_file)
+ else:
+ self.error = 1
+ self.result = "Unknown record type: "+line
+ break
+ f.close()
+
+
+
class PartitionJob(SysToolJob):
"""
A partitioning SysTool job. This one accept a list of partitions
@@ -163,6 +259,15 @@
break
if self.result == None:
self.result = buf.getvalue()
+ if self.error == None:
+ # mount partitions now
+ install_root = self.INSTALL_ROOT
+ if not os.path.exists(install_root):
+ os.mkdir(install_root)
+ code, result = self.MountPartitions(self.part_spec, install_root)
+ if code != 0:
+ self.error = code
+ self.result = result
self.finished = True
del self.part_spec
@@ -170,104 +275,113 @@
class InstallJob(SysToolJob):
"""
The install job. The job progress is:
- - Mount partitions to a temporary tree
- - Parse mtree record and use it as a list of files to install
+ - Mount partitions from part_spec to the temporary tree
+ - Parse maptree record and use it as a list of files to install
+ - Generate /etc/fstab from the part_spec
+ """
+ def __init__(self, part_spec):
+ SysToolJob.__init__(self)
+ self.part_spec = part_spec
+
+ def run(self):
+ install_root = self.INSTALL_ROOT
+ maptree_filename = self.BASE_MAPTREE_FILE
+ if not os.path.exists(maptree_filename):
+ self.error = 1
+ self.result = "No "+maptree_filename
+ self.finished = True
+ return
+ try:
+ self.InstallFromMapTree(maptree_filename, install_root, "/")
+ except Exception, e:
+ self.error = 1
+ self.result = str(e)
+ if self.error == None:
+ # create fstab
+ f = file("%s/etc/fstab" % install_root, "w+")
+ f.write("# Generated by finstall on %s\n" % time.strftime("%c"))
+ f.write("# Device\tMountpoint\tFStype\tOptions\tDump\tPass\n")
+ for part in self.part_spec:
+ if part["mount"] != None:
+ line = freebsd.fstab_line(part["name"], part["mount"], part["fs"])
+ if line != None:
+ f.write("%s\n" % line)
+ f.close()
+
+ self.finished = True
+
+
+class PkgInstallJob(SysToolJob):
+ """
+ This job simply copies /usr/local and /var/pkg trees to the install
+ destination tree. Thus, it's not suitable for all types of packages (those
+ with post-install scripts that do non-trivial stuff) but will work ok
+ for most.
+ The main benefit of this is that it's way faster than going through
+ pkg_create -b + pkg_install sequence.
"""
def __init__(self, part_spec):
SysToolJob.__init__(self)
self.part_spec = part_spec
def run(self):
- install_root = "/dist"
- if not os.path.exists(install_root):
- os.mkdir(install_root)
- buf = StringIO()
- # mount partitions
- for part in self.part_spec:
- if part["fs"] == None or part["fs"] == "swap":
- continue
- if part["mount"] == "/":
- mount = install_root
- else:
- mount = "%s/%s" % (install_root, part["mount"])
- code, result = freebsd.mount(part["name"], mount, part["fs"])
- buf.write(result)
- if code != 0:
- self.error = code
- self.result = buf.getvalue()
- self.finished = True
- return
- maptree_filename = "/maptree.txt"
+ install_root = self.INSTALL_ROOT
+ maptree_filename = self.VARDBPKG_MAPTREE_FILE
+ if not os.path.exists(maptree_filename):
+ self.error = 1
+ self.result = "No "+maptree_filename
+ self.finished = True
+ return
+ try:
+ self.InstallFromMapTree(maptree_filename, "%s/var/db/pkg" % install_root, "/var/db/pkg")
+ except Exception, e:
+ self.error = 1
+ self.result = str(e)
+ self.finished = True
+ return
+ maptree_filename = self.USRLOCAL_MAPTREE_FILE
if not os.path.exists(maptree_filename):
self.error = 1
self.result = "No "+maptree_filename
self.finished = True
return
- maptree_size = os.path.getsize(maptree_filename)
- f = file(maptree_filename, "r")
- for line in f:
- self.percent_complete = self._calc_percent(f.tell(), maptree_size)
- rec = line.strip().split("|")
- rec_file = rec[-1]
- dest_file = "%s/%s" % (install_root, rec_file)
- src_file = "/%s" % rec_file
- if rec[0] == "F":
- if not os.path.exists(src_file):
- logging.info("File not found: "+src_file)
- continue
- shutil.copyfile(src_file, dest_file)
- shutil.copystat(src_file, dest_file)
- logging.info("copy %s to %s" % (src_file, dest_file))
- elif rec[0] == "D":
- if not os.path.exists(dest_file):
- os.mkdir(dest_file)
- elif rec[0] == "H":
- if os.path.exists(dest_file):
- os.unlink(dest_file)
- try:
- os.link("%s/%s" % (install_root, rec[1]), dest_file)
- except:
- logging.error("Cannot hardlink '/%s' to '%s'" % (rec[1], dest_file))
- try:
- shutil.copyfile("/%s" % rec[1], dest_file)
- except:
- logging.error("Cannot replace hardlink from '/%s' to '%s' with file copy" % (rec[1], dest_file))
- elif rec[0] == "L":
- if os.path.exists(dest_file):
- if os.path.islink(dest_file):
- os.unlink(dest_file)
- os.symlink("/%s" % rec[1], dest_file)
- else:
- os.symlink("/%s" % rec[1], dest_file)
- else:
- self.error = 1
- self.result = "Unknown record type: "+line
- break
- for part in reversed(self.part_spec):
- if part["fs"] == None or part["fs"] == "swap":
- continue
- if part["mount"] == "/":
- mount = install_root
- else:
- mount = "%s/%s" % (install_root, part["mount"])
- code, result = freebsd.umount(mount)
- if code != 0:
- self.error = 1
- if self.result != None:
- self.result += "\n"+result
- else:
- self.result = result
+ try:
+ self.InstallFromMapTree(maptree_filename, "%s/usr/local" % install_root, "/usr/local")
+ except Exception, e:
+ self.error = 1
+ self.result = str(e)
+ self.finished = True
+ return
+ self.finished = True
+
+
+class PostInstallJob(SysToolJob):
+ """
+ This job finishes the installation - unmounts the temporary tree, etc.
+ """
+ def __init__(self, part_spec, force):
+ SysToolJob.__init__(self)
+ self.part_spec = part_spec
+ self.force = force
+
+ def run(self):
+ code, result = self.UmountPartitions(self.part_spec, self.INSTALL_ROOT, force)
+ if code != 0:
+ self.error = code
+ self.result = result
self.finished = True
-
+
class SysToolEngine:
def __init__(self):
- self.root_dest = "" # Config file / "new" root, sans final slash
+ self.root_dest = "" # "new" root, sans final slash
self.root_live = "" # Live file system root (for binaries!)
self.job_list = []
self.job_list_lock = Lock()
warnings.simplefilter('ignore', RuntimeWarning)
+ self.SetDestRoot("/dist")
+ self.SetLiveRoot("/")
def GetId(self):
@@ -281,35 +395,44 @@
def SetDestRoot(self, root_dir):
- """Sets internal root directory for installation and config tasks
- (so Get/SetConf can be used with alternative root)"""
+ """
+ Sets internal root directory for installation and config tasks
+ (so Get/SetConf can be used with alternative root)
+ """
self.root_conf = root_dir
+ SysToolJob.INSTALL_ROOT = root_dir
return True
def SetLiveRoot(self, root_dir):
"""Notifies SysTool Engine where to expect utility binaries."""
self.root_live = root_dir
+ freebsd.live_root = root_dir
return True
- def GetConf(self, name):
+ def GetConf(self, name, default=None):
"""Returns configuration variable from /etc/rc.conf"""
cf = ConfFile("%s/etc/rc.conf" % self.root_dest)
- val = cf.GetConf(name, None)
- return val
+ return cf.GetConf(name, default)
def SetConf(self, name, value, description):
"""Sets configuration variable to /etc/rc.conf"""
cf = ConfFile("%s/etc/rc.conf" % self.root_dest)
- cf.SetConf(name, value, description)
- return True
+ return cf.SetConf(name, value, description)
+
+
+ @logexception
+ def GetShells(self):
+ """Returns a list of acceptable shells"""
+ return [x.strip() for x in file("%s/etc/shells" % self.root_dest, "r") if len(x) > 1 and x[0] == "/"]
@logexception
def GetDrives(self):
- """Returns information on drives the kernel knows about.
+ """
+ Returns information on drives the kernel knows about.
Examines "kern.drives" sysctl. This is NOT the list of
valid GEOM leaves which can be mounted, but a list of
found hardware.
@@ -323,7 +446,8 @@
"name": "ACME MegaDrive",
"mediasize": 300000 # (MB)
}
- }"""
+ }
+ """
drive_list = freebsd.get_sysctl("kern.disks", True).split(" ")
dmesg = freebsd.get_dmesg()
drive_dict = {}
@@ -360,7 +484,8 @@
@logexception
def GetDrivePartitions(self, drive):
- """Returns a list of leaf partitions created on the drive.
+ """
+ Returns a list of leaf partitions created on the drive.
ARGUMENTS:
drive : The drive to inspect
RETURN VALUE:
@@ -377,7 +502,8 @@
"fs_type" : "UFS2",
"fs_last_mount", "/usr"
}
- }"""
+ }
+ """
parts = {}
used_parts = []
geomxml = freebsd.get_geom_xml()
@@ -438,8 +564,10 @@
def GetMountPoints(self):
- """Returns a list of dictionaries containing information
- about currently mounted file systems"""
+ """
+ Returns a list of dictionaries containing information
+ about currently mounted file systems
+ """
raw_mounts = freebsd.get_cmd_output("%s -p" % freebsd.cmd_mount).split("\n")
mounts = []
for m in raw_mounts:
@@ -461,6 +589,7 @@
physmem = int(freebsd.get_sysctl("hw.realmem"))
return int(physmem / (1024*1024))
+ # Jobs #######################################################################
@logexception
def StartPartitionJob(self, part_spec):
@@ -492,6 +621,20 @@
@logexception
+ def StartPkgInstallJob(self, part_spec):
+ """
+ Starts the install job. Returns an integer job_id.
+ """
+ self.job_list_lock.acquire()
+ job = PkgInstallJob(part_spec)
+ self.job_list.append(job)
+ job_id = len(self.job_list)
+ job.start()
+ self.job_list_lock.release()
+ return job_id
+
+
+ @logexception
def QueryJobProgress(self, job_id):
"""
Queries the progress of a job, returns percent complete or None
@@ -509,6 +652,18 @@
@logexception
+ def QueryIsJobFinished(self, job_id):
+ """
+ Queries whether the job has finished. Testing for job progress percent == 100
+ is not enough.
+ """
+ self.job_list_lock.acquire()
+ job = self.job_list[job_id-1]
+ self.job_list_lock.release()
+ return job.finished
+
+
+ @logexception
def QueryJobResult(self, job_id):
"""
Queries the result of a job, if the job is finished. Returns
@@ -545,4 +700,32 @@
self.job_list_lock.release()
return True
+# System configuration ########################################################
+
+ @logexception
+ def SetHostName(self, host_name):
+ if self.SetConf("hostname", host_name, "Host name"):
+ return (0, None)
+ else:
+ return (1, "Cannot set host name")
+
+
+ @logexception
+ def GetHostName(self):
+ host_name = self.GetConf("hostname")
+ if host_name == None:
+ return "amnesiac"
+ else:
+ return host_name
+
+
+ @logexception
+ def SetUserPassword(self, user_name, password):
+ return freebsd.chpasswd(user_name, password, "%s/etc" % self.root_dest)
+
+
+ @logexception
+ def AddUser(self, user_name, user, password, shell, groups):
+ return freebsd.useradd(user_name, user, password, shell, groups, "%s/etc" % self.root_dest)
+
More information about the p4-projects
mailing list