Advertisement
Guest User

Untitled

a guest
Jun 1st, 2017
544
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.18 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. root_device = None
  140. # format partitions as appropriate
  141. for item in self.fstab.get_entries():
  142. if(item.mountpoint == "/"):
  143. root_device = item
  144. item.format = True
  145. if(item.format):
  146. # well now, we gets to nuke stuff.
  147. # report it. should grab the total count of filesystems to be formatted ..
  148. self.update_progress(total=4, current=1, message=_("Formatting %s to %s..." % (item.device, item.filesystem)))
  149. self.format_device(item.device, item.filesystem)
  150. # mount filesystem
  151. self.update_progress(total=4, current=2, message=_("Mounting %s on %s") % (root, "/source/"))
  152. self.do_mount(root, "/source/", root_type, options="loop")
  153. self.update_progress(total=4, current=3, message=_("Mounting %s on %s") % (root_device.device, r"/target/"))
  154. self.do_mount(root_device.device, "/target", root_device.filesystem, None)
  155. # walk root filesystem. we're too lazy though :P
  156. SOURCE = "/source/"
  157. DEST = "/target/"
  158. timestamps = list()
  159. our_total = -1
  160. our_current = 0
  161. os.chdir(SOURCE)
  162. # index the files
  163. for top,dirs,files in os.walk(SOURCE, topdown=False):
  164. our_total += len(files)
  165. self.update_progress(pulse=True, message=_("Indexing files to be copied.."))
  166. our_total += 1 # safenessness
  167. for top,dirs,files in os.walk(SOURCE, topdown=False):
  168. for f in files:
  169. try:
  170. our_current += 1
  171. filename = os.path.join(top, f)
  172. rpath = os.path.relpath(filename)
  173. target = os.path.join(DEST, rpath)
  174. dir = os.path.split(target)[0]
  175. # make the directories..
  176. if(not os.path.exists(dir)):
  177. os.makedirs(dir)
  178. if(os.path.islink(filename)):
  179. try:
  180. link_dest = os.readlink(filename)
  181. if(link_dest != filename):
  182. # oh look, a real symlink.
  183. os.chdir(dir) # make sure relative symlinks work..
  184. newfile = os.path.split(target)[1] # get the tail end
  185. #os.symlink(link_dest, newfile)
  186. os.system("cp -d \"%s\" \"%s\"" % (filename, target)) # uber lazy.. mmhm
  187. os.chdir(SOURCE)
  188. continue
  189. except:
  190. pass # who cares.. wasn't a symlink.
  191. if(not os.path.exists(filename)):
  192. continue # skip broken links
  193. self.update_progress(total=our_total, current=our_current, message="Copying %s" % filename)
  194. self.copy_file(filename, target)
  195. except Exception, detail:
  196. print detail
  197. for d in dirs:
  198. try:
  199. directory = os.path.join(top, d)
  200. filename = directory
  201. rpath = os.path.relpath(directory)
  202. target = os.path.join(DEST, rpath)
  203. if(os.path.islink(directory)):
  204. try:
  205. link_dest = os.readlink(filename)
  206. if(link_dest != filename):
  207. # oh look, a real symlink.
  208. os.chdir(dir) # make sure relative symlinks work..
  209. newfile = os.path.split(target)[1] # get the tail end
  210. #os.symlink(link_dest, newfile)
  211. os.system("cp -d \"%s\" \"%s\"" % (filename, target)) # uber fail.
  212. os.chdir(SOURCE)
  213. continue
  214. except:
  215. pass # who cares.. wasn't a symlink.
  216. if(not os.path.exists(directory)):
  217. continue # skip broken links
  218. if(not os.path.exists(target)):
  219. os.makedirs(target)
  220. # copy dir attributes
  221. finfo = os.stat(filename)
  222. owner = finfo[stat.ST_UID]
  223. group = finfo[stat.ST_GID]
  224. os.chown(target, owner, group)
  225. shutil.copymode(filename, target) # copy permissions.
  226. timestamps.append((target, finfo))
  227. pass
  228. except Exception, detail:
  229. print detail
  230. for directories in timestamps:
  231. directory = directories[0]
  232. timestamp = directories[1]
  233. self.update_progress(pulse=True, message=_("Restoring meta-info on %s") % directory)
  234. os.utime(directory, (timestamp.st_ctime, timestamp.st_mtime))
  235.  
  236. # Steps:
  237. our_total = 8
  238. our_current = 0
  239. # chroot
  240. self.update_progress(total=our_total, current=our_current, message=_("Entering new system.."))
  241. child_pid = os.fork()
  242. if(child_pid == 0):
  243. # we be the child.
  244. os.chroot("/target/")
  245. # remove live user
  246. live_user = "mint" # make this come from config..
  247. our_current += 1
  248. self.update_progress(total=our_total, current=our_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. our_current += 1
  253. self.update_progress(total=our_total, current=our_current, message=_("Removing live configuration (packages)"))
  254. os.system("apt-get remove --purge live-initramfs distro-installer")
  255. # add new user
  256. our_current += 1
  257. self.update_progress(total=our_total, current=our_current, message=_("Adding new user to system"))
  258. newusers = open("/tmp/newusers.conf", "w")
  259. shell = "/bin/bash"
  260. username = "ikey"
  261. password = "czkgj8la"
  262. root_password = "czkgj8la"
  263. shell = "/bin/bash"
  264. realname = "Ikey Doherty"
  265. newusers.write("%s:%s:::%s,,,:/home/%s:%s\n" % (username, password, realname, username, shell))
  266. # add root's password
  267. our_current += 1
  268. self.update_progress(total=our_total, current=our_current, message=_("Setting root password"))
  269. newusers.write("root:%s:::::\n") % (root_password)
  270. newusers.close()
  271. os.system("newusers /tmp/newusers.conf")
  272. os.system("rm -rf /tmp/newusers.conf")
  273. # write the /etc/fstab
  274. our_current += 1
  275. self.update_progress(total=our_total, current=our_current, message=_("Writing filesystem mount information"))
  276. # make sure fstab has default /proc and /sys entries
  277. if(not os.path.exists("%s/etc/fstab" % "/target")):
  278. os.system("echo \"#### Static Filesystem Table File\" > %s/etc/fstab" % "/target")
  279. fstabber = open("%s/etc/fstab" % "/target", "a")
  280. fstabber.write("proc\t/proc\tproc\tnodev,noexec,nosuid\t0\t0\n")
  281. for item in self.fstab.get_entries():
  282. fstabber.write("%s\t%s\t%s\t%s\t%s\t%s" % (item.device, item.mount_point, item.filesystem, item.options, "0", "0"))
  283. fstabber.close()
  284. # write MBR (grub)
  285. our_current += 1
  286. self.update_progress(total=our_total, current=our_current, message=_("Installing bootloader"))
  287. os.system("grub-install %s" % root_device.device)
  288. os.system("update-grub")
  289. # ^ needs to be done in a chroot ._.
  290. # notify that we be finished now.
  291. our_current += 1
  292. self.update_progress(done=True, total=our_total, current=our_current, message=_("Done."))
  293. # write a file to this chroot indicating we've finished..
  294. fdone = open("/installed.log", "w")
  295. fdone.write("---INSTALLED---")
  296. fdone.close()
  297. else:
  298. while(True):
  299. # check for /installed.log in the chroot
  300. if(not os.path.exists(os.path.join(DEST, "installed.log"))):
  301. time.sleep(0.5) # sleep half a second then check again
  302. else:
  303. os.remove(os.path.join(DEST, "installed.log"))
  304. break
  305.  
  306. # now unmount it
  307. self.do_unmount("/target")
  308. self.do_unmount("/source")
  309. except Exception,detail:
  310. print detail
  311.  
  312. def do_mount(self, device, dest, type, options=None):
  313. ''' Mount a filesystem '''
  314. p = None
  315. if(options is not None):
  316. p = Popen("mount -o %s -t %s %s %s" % (options, type, device, dest),shell=True)
  317. else:
  318. p = Popen("mount -t %s %s %s" % (type, device, dest),shell=True)
  319. p.wait()
  320. return p.returncode
  321.  
  322. def do_unmount(self, mountpoint):
  323. ''' Unmount a filesystem '''
  324. p = Popen("umount %s" % mountpoint, shell=True)
  325. p.wait()
  326. return p.returncode
  327.  
  328. def copy_file(self, source, dest):
  329. '''
  330. BUF_SIZE = 16 * 1048
  331. input = open(source, "rb")
  332. dst = open(dest, "wb")
  333. while(True):
  334. read = input.read(BUF_SIZE)
  335. if not read:
  336. break
  337. dst.write(read)
  338. input.close()
  339. fd = dst.fileno()
  340. # set permissions
  341. shutil.copymode(source, dest) # copy permission bits
  342. finfo = os.stat(source)
  343. owner = finfo[stat.ST_UID]
  344. group = finfo[stat.ST_GID]
  345. os.fchown(fd, owner, group)
  346. dst.flush()
  347. os.fsync(fd)
  348. dst.close()
  349. finfo = os.stat(source)
  350. atime = finfo[stat.ST_ATIME]
  351. mtime = finfo[stat.ST_MTIME]
  352. os.utime(dest, (atime, mtime))
  353. '''
  354. os.system("cp -p \"%s\" \"%s\"" % (source, dest))
  355.  
  356. class fstab(object):
  357. ''' This represents the filesystem table (/etc/fstab) '''
  358. def __init__(self):
  359. self.mapping = dict()
  360.  
  361. def add_mount(self, device=None, mountpoint=None, filesystem=None, options=None):
  362. if(not self.mapping.has_key(device)):
  363. self.mapping[device] = fstab_entry(device, mountpoint, filesystem, options)
  364.  
  365. def remove_mount(self, device):
  366. if(self.mapping.has_key(device)):
  367. del self.mapping[device]
  368.  
  369. def get_entries(self):
  370. ''' Return our list '''
  371. return self.mapping.values()
  372.  
  373. class fstab_entry(object):
  374. ''' Represents an entry in fstab '''
  375.  
  376. def __init__(self, device, mountpoint, filesystem, options):
  377. ''' Creates a new fstab entry '''
  378. self.device = device
  379. self.mountpoint = mountpoint
  380. self.filesystem = filesystem
  381. self.options = options
  382. self.format = False
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement