Advertisement
Guest User

Untitled

a guest
Jun 1st, 2017
566
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.57 KB | None | 0 0
  1. ''' distro-installer core. '''
  2. ''' Author: Ikey Doherty <contactjfreak@gmail.com> '''
  3.  
  4. import os
  5. import subprocess
  6. from subprocess import Popen
  7. import time
  8. import shutil
  9. import gettext
  10. import stat
  11.  
  12. gettext.install("distro-installer", "/usr/share/locale")
  13.  
  14. class mINIFile():
  15.         def load_from_string(self, line):
  16.                 if(line.find(":")):
  17.                         l = line.split(":")
  18.                         if(len(l) >= 2):
  19.                                 tmp = ":".join(l[1:]).rstrip("\r\n")
  20.                                 setattr(self, l[0], tmp)
  21.                 elif(line.find("=")):
  22.                         l = line.split("=")
  23.                         if(len(l) >= 2):
  24.                                 tmp = "=".join(l[1:]).rstrip("\r\n")
  25.                                 setattr(self, l[0], tmp)
  26.                                
  27.         def load_from_list(self, list):
  28.                 for line in list:
  29.                         self.load_from_string(line)
  30.         def load_from_file(self, filename):
  31.                 try:
  32.                         fi = open(filename, "r")
  33.                         self.load_from_list(fi.readlines())
  34.                         fi.close()
  35.                 except:
  36.                         pass
  37.  
  38.         def has_key(self, key):
  39.             return hasattr(self, key)
  40.            
  41. class SystemUser:
  42.     ''' Represents the main user '''
  43.    
  44.     def __init__(self, username=None, realname=None, password=None, sudo=False):
  45.         ''' create new SystemUser '''
  46.         self.username = username
  47.         self.realname = realname
  48.         self.password = password
  49.        
  50. class InstallerEngine:
  51.     ''' This is central to the distro installer '''
  52.    
  53.     # some noice definitions..
  54.     PROGRESS_START      = "start"
  55.     PROGRESS_UPDATE     = "update"
  56.     PROGRESS_COMPLETE   = "complete"
  57.     PROGRESS_ERROR      = "error"
  58.    
  59.     def __init__(self):
  60.         # set up stuffhs
  61.         self.conf_file = '/etc/distro-installer/distro.conf'
  62.         configuration = mINIFile()
  63.         configuration.load_from_file(self.conf_file)
  64.         if(not configuration.has_key("Distro")):
  65.             self.distro_name = "GNU/Linux"
  66.         else:
  67.             self.distro_name = configuration.Distro
  68.         if(not configuration.has_key("Version")):
  69.             self.distro_version = "1"
  70.         else:
  71.             self.distro_version = configuration.Version
  72.         self.user = None
  73.  
  74.     def set_main_user(self, user):
  75.         ''' Set the main user to be used by the installer '''
  76.         if(user is not None):
  77.             self.user = user
  78.        
  79.     def get_main_user(self):
  80.         ''' Return the main user '''
  81.         return self.user
  82.        
  83.     def format_device(self, device, filesystem):
  84.         ''' Format the given device to the specified filesystem '''
  85.         cmd = "mkfs -t %s %s" % (filesystem, device)
  86.         p = Popen(cmd, shell=True)
  87.         p.wait() # this blocks
  88.         return p.returncode
  89.        
  90.     def set_install_media(self, media=None, type=None):
  91.         ''' Sets the location of our install source '''
  92.         self.media = media
  93.         self.media_type = type
  94.        
  95.     def add_to_blacklist(self, blacklistee):
  96.         ''' This will add a directory or file to the blacklist, so that '''
  97.         ''' it is not copied onto the new filesystem '''
  98.         try:
  99.             self.blacklist.index(blacklistee)
  100.             self.blacklist.append(blacklistee)
  101.         except:
  102.             # We haven't got this item yet
  103.             pass
  104.  
  105.     def set_progress_hook(self, progresshook):
  106.         ''' Set a callback to be called on progress updates '''
  107.         ''' i.e. def my_callback(progress_type, message, current_progress, total) '''
  108.         ''' Where progress_type is any off PROGRESS_START, PROGRESS_UPDATE, PROGRESS_COMPLETE, PROGRESS_ERROR '''
  109.         self.update_progress = progresshook
  110.  
  111.     def get_distro_name(self):
  112.         return self.distro_name
  113.        
  114.     def get_distro_version(self):
  115.         return self.distro_version
  116.        
  117.     def get_locale(self):
  118.         ''' Return the locale we're setting '''
  119.         return self.locale
  120.    
  121.     def set_locale(self, newlocale):
  122.         ''' Set the locale '''
  123.         self.locale = newlocale
  124.        
  125.     def install(self):
  126.         ''' Install this baby to disk '''
  127.         # mount the media location.
  128.         try:
  129.             if(not os.path.exists("/target")):
  130.                 os.mkdir("/target")
  131.             if(not os.path.exists("/source")):
  132.                 os.mkdir("/source")
  133.             # find the squashfs..
  134.             root = self.media
  135.             root_type = self.media_type
  136.             if(not os.path.exists(root)):
  137.                 print _("Base filesystem does not exist! Bailing")
  138.                 sys.exit(1) # change to report
  139.             self.do_mount(root, "/source/", root_type, options="loop")
  140.             root_device = None
  141.             # format partitions as appropriate
  142.             for item in self.fstab.get_entries():
  143.                 if(item.mountpoint == "/"):
  144.                     root_device = item
  145.                     item.format = True
  146.                 if(item.format):
  147.                     # well now, we gets to nuke stuff.
  148.                     # report it. should grab the total count of filesystems to be formatted ..
  149.                     self.update_progress(total=10, current=2, message=_("Formatting %s to %s..." % (item.device, item.filesystem)))
  150.                     self.format_device(item.device, item.filesystem)
  151.             # mount filesystem
  152.             self.do_mount(root_device.device, "/target", root_device.filesystem, None)
  153.             # walk root filesystem. we're too lazy though :P
  154.             SOURCE = "/source/"
  155.             DEST = "/target/"
  156.             timestamps = list()
  157.             our_total = -1
  158.             our_current = 0
  159.             os.chdir(SOURCE)
  160.             # index the files
  161.             for top,dirs,files in os.walk(SOURCE, topdown=False):
  162.                 our_total += len(files)
  163.                 self.update_progress(pulse=True, message=_("Indexing files to be copied.."))
  164.                
  165.             for top,dirs,files in os.walk(SOURCE, topdown=False):
  166.                 for f in files:
  167.                     try:
  168.                         our_current += 1
  169.                         filename = os.path.join(top, f)
  170.                         rpath = os.path.relpath(filename)
  171.                         target = os.path.join(DEST, rpath)
  172.                         dir = os.path.split(target)[0]
  173.                         # make the directories..
  174.                         if(not os.path.exists(dir)):
  175.                             os.makedirs(dir)
  176.                         if(os.path.islink(filename)):
  177.                             continue
  178.                             try:
  179.                                 link_dest = os.readlink(filename)
  180.                                 if(link_dest != filename):
  181.                                     # oh look, a real symlink.
  182.                                     os.chdir(dir)
  183.                                 #   os.symlink(link_dest, target) # if this doesnt work I'm going to murder a small goat.
  184.                                     print "Symlink: " + link_dest + " (" + filename + ") ->" + target
  185.                            
  186.                                     os.chdir(DEST)
  187.                                     continue
  188.                             except:
  189.                                 pass # who cares.. wasn't a symlink.
  190.                         # no copy.
  191.                         continue
  192.                         if(not os.path.exists(filename)):
  193.                             continue # skip broken links
  194.                         self.update_progress(total=our_total, current=our_current, message="Copying %s" % filename)
  195.                         self.copy_file(filename, target)
  196.                     except Exception, detail:
  197.                         print detail
  198.                 for d in dirs:
  199.                     try:
  200.                         directory = os.path.join(top, d)
  201.                         filename = directory
  202.                         rpath = os.path.relpath(directory)
  203.                         target = os.path.join(DEST, rpath)
  204.                         if(os.path.islink(directory)):
  205.                             try:
  206.                                 link_dest = os.readlink(filename)
  207.                                 if(link_dest != filename):
  208.                                     # oh look, a real symlink.
  209.                                 #   os.symlink(link_dest, target) # if this doesnt work I'm going to murder a small goat.
  210.                                     print "Symlink: " + link_dest + " (" + filename + ") ->" + target
  211.                                     continue
  212.                             except:
  213.                                 pass # who cares.. wasn't a symlink.
  214.                         continue # dont copy file mmk?
  215.                         if(not os.path.exists(directory)):
  216.                             continue # skip broken links
  217.                         if(not os.path.exists(target)):
  218.                             os.makedirs(target)
  219.                         # copy dir attributes
  220.                         finfo = os.stat(filename)
  221.                         owner = finfo[stat.ST_UID]
  222.                         group = finfo[stat.ST_GID]
  223.                         os.chown(target, owner, group)
  224.                         shutil.copymode(filename, target) # copy permissions.
  225.                         timestamps.append((directory, finfo))
  226.                         pass
  227.                     except Exception, detail:
  228.                         print detail
  229.             for directories in timestamps:
  230.                 directory = directories[0]
  231.                 timestamp = directories[1]
  232.                 os.utime(directory, (timestamp.st_ctime, timestamp.st_mtime))
  233.                
  234.             # Steps:
  235.             total = 7
  236.             current = 0
  237.             # chroot
  238.             self.update_progress(total=total, current=current, message=_("Entering new system.."))
  239.             child_pid = os.fork()
  240.             if(child_pid == 0):
  241.                 # we be the child.
  242.                 if(not os.chroot(DEST)):
  243.                     self.update_progress(fail=True, message=_("Could not chroot into /target"))
  244.                     return
  245.                 # remove live user
  246.                 live_user = "mint" # make this come from config..
  247.                 current += 1
  248.                 self.update_progress(total=total, current=current, message=_("Removing live configuration (user)"))
  249.                 os.system("deluser %s" % live_user)
  250.                 os.system("rm -rf /home/%s" % live_user)
  251.                 # remove live-initramfs (or w/e)
  252.                 current += 1
  253.                 self.update_progress(total=total, current=current, message=_("Removing live configuration (packages)"))
  254.                 os.system("apt-get remove --purge live-initramfs distro-installer")
  255.                 # add new user
  256.                 current += 1
  257.                 self.update_progress(total=total, current=current, message=_("Adding new user to system"))
  258.                 newusers = open("/tmp/newusers.conf", "w")
  259.                 shell = "/bin/bash"
  260.                 newusers.write("%s:%s:::%s,,,:/home/%s:%s\n" % (username, password, realname, username, shell))
  261.                 # add root's password
  262.                 current += 1
  263.                 self.update_progress(total=total, current=current, message=_("Setting root password"))
  264.                 newusers.write("root:%s:::::\n") % (root_password)
  265.                 newusers.close()
  266.                 os.system("newusers /tmp/newusers.conf")
  267.                 os.system("rm -rf /tmp/newusers.conf")
  268.                 # write the /etc/fstab
  269.                 current += 1
  270.                 self.update_progress(total=total, current=current, message=_("Writing filesystem mount information"))
  271.                 # make sure fstab has default /proc and /sys entries
  272.                 if(not os.path.exists("%s/etc/fstab" % "/target")):
  273.                     os.system("echo \"#### Static Filesystem Table File\" > %s/etc/fstab" % "/target")
  274.                 fstabber = open("%s/etc/fstab" % "/target", "a")
  275.                 fstabber.write("proc\t/proc\tproc\tnodev,noexec,nosuid\t0\t0\n")
  276.                 for item in self.fstab.get_entries():
  277.                     fstabber.write("%s\t%s\t%s\t%s\t%s\t%s" % (item.device, item.mount_point, item.filesystem, item.options, "0", "0"))
  278.                 fstabber.close()
  279.                 # write MBR (grub)
  280.                 current += 1
  281.                 self.update_progress(total=total, current=current, message=_("Installing bootloader"))
  282.                 os.system("grub-install %s" % root_device.device)
  283.                 os.system("update-grub")
  284.                 # ^ needs to be done in a chroot ._.
  285.                 # notify that we be finished now.
  286.                 current += 1
  287.                 self.update_progress(done=True, total=total, current=current, message=_("Done."))
  288.                 # write a file to this chroot indicating we've finished..
  289.                 fdone = open("/installed.log", "w")
  290.                 fdone.write("---INSTALLED---")
  291.                 fdone.close()
  292.             else:
  293.                 while(True):
  294.                     # check for /installed.log in the chroot
  295.                     if(not os.path.exists(os.path.join(DEST, "installed.log"))):
  296.                         time.sleep(0.5) # sleep half a second then check again
  297.                     else:
  298.                         os.remove(os.path.join(DEST, "installed.log"))
  299.                         break
  300.                    
  301.             # now unmount it
  302.             self.do_unmount("/target")
  303.             self.do_unmount("/source")
  304.         except Exception,detail:
  305.             print detail
  306.        
  307.     def do_mount(self, device, dest, type, options=None):
  308.         ''' Mount a filesystem '''
  309.         p = None
  310.         if(options is not None):
  311.             p = Popen("mount -o %s -t %s %s %s" % (options, type, device, dest),shell=True)
  312.         else:
  313.             p = Popen("mount -t %s %s %s" % (type, device, dest),shell=True)
  314.         p.wait()
  315.         return p.returncode
  316.        
  317.     def do_unmount(self, mountpoint):
  318.         ''' Unmount a filesystem '''
  319.         p = Popen("umount %s" % mountpoint, shell=True)
  320.         p.wait()
  321.         return p.returncode
  322.        
  323.     def copy_file(self, source, dest):
  324.         BUF_SIZE = 16 * 1048
  325.         input = open(source, "r")
  326.         dst = open(dest, "w")
  327.         while(True):
  328.             read = input.read(BUF_SIZE)
  329.             if not read:
  330.                 break
  331.             dst.write(read)
  332.         fd = dst.fileno()
  333.         # set permissions
  334.         shutil.copymode(source, dest) # copy permission bits
  335.         finfo = os.stat(source)
  336.         owner = finfo[stat.ST_UID]
  337.         group = finfo[stat.ST_GID]
  338.         os.fchown(fd, owner, group)
  339.         dst.flush()
  340.         os.fsync(fd)
  341.         dst.close()
  342.         finfo = os.stat(source)
  343.         atime = finfo[stat.ST_ATIME]
  344.         mtime = finfo[stat.ST_MTIME]
  345.         os.utime(dest, (atime, mtime))
  346.         pass
  347.                
  348. class fstab(object):
  349.     ''' This represents the filesystem table (/etc/fstab) '''
  350.     def __init__(self):
  351.         self.mapping = dict()
  352.        
  353.     def add_mount(self, device=None, mountpoint=None, filesystem=None, options=None):
  354.         if(not self.mapping.has_key(device)):
  355.             self.mapping[device] = fstab_entry(device, mountpoint, filesystem, options)
  356.    
  357.     def remove_mount(self, device):
  358.         if(self.mapping.has_key(device)):
  359.             del self.mapping[device]
  360.  
  361.     def get_entries(self):
  362.         ''' Return our list '''
  363.         return self.mapping.values()
  364.  
  365. class fstab_entry(object):
  366.     ''' Represents an entry in fstab '''
  367.    
  368.     def __init__(self, device, mountpoint, filesystem, options):
  369.         ''' Creates a new fstab entry '''
  370.         self.device = device
  371.         self.mountpoint = mountpoint
  372.         self.filesystem = filesystem
  373.         self.options = options
  374.         self.format = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement