#!/usr/bin/env python

#     vim: tabstop=4 noexpandtab
#
#     rootstrap - Quickly and easily build Linux filesystem images
#     Copyright (C) 2002 Matt Zimmerman <mdz@debian.org>
#                   2006 Mattia Dongili <malattia@debian.org>
#
#     This program is free software; you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation; either version 2 of the License, or
#     (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License
#     along with this program; if not, write to the Free Software
#     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

import os
import sys
import getopt
import ConfigParser
import shutil

def usage(exitcode):
    sys.stderr.write("Usage: rootstrap [options] <output image file>\n")
    sys.exit(exitcode)

config = ConfigParser.ConfigParser()
config.readfp(open('/etc/rootstrap/rootstrap.conf'))
config.read(('rootstrap.conf',))

try:
    (optlist,args) = getopt.getopt(sys.argv[1:], 's:u:o:c:',
                                   ['image-size=', 'umlarg=', 'config='])
except getopt.GetoptError:
    usage(1)

if len(args) < 1:
    usage(1)

# So that we can find tune2fs, resize2fs and such
os.environ['PATH'] += ':/sbin:/usr/sbin'
# So that we can find uml_net when installed in /usr/lib/uml
os.environ['PATH'] += ':/usr/lib/uml'

imagefile = args[0]
imagesize = config.getint('global', 'initialsize')
log = sys.stdout
umlargs = ['linux']
umlargs_extra = []

for opt,arg in optlist:
    if opt in ('-s', '--image-size'):
        imagesize = long(arg)
    elif opt in ('-o',):
		if not config.has_option('global', 'debug') or \
						config.get('global', 'debug') != 'true':
				log = open(arg,"w")
				os.dup2(log.fileno(), sys.stdout.fileno())
		else:
				print "Ignoring -o because the debug option is set"
    elif opt in ('-c', '--config'):
        umlargs_extra.append('rsconfig=%s' % os.path.abspath(os.path.expanduser(arg)))
    elif opt in ('-u', '--umlarg'):
        umlargs_extra.extend(arg.split())

if config.has_option('network', 'interface'):
    netif = config.get('network', 'interface', None)
    if netif != None:
        transport = config.get('network', 'transport')
        if transport == 'tuntap':
            if config.has_option('network','host_if'):
                # Preconfigured tap
                host_if = config.get('network','host_if')
            else:
                host_if = ''
            hostaddr = config.get('network', 'host')
            umlargs.append('%s=%s,%s,,%s' % (netif,transport,host_if,hostaddr))
        elif transport == 'slirp':
            umlargs.append('%s=slirp,,%s' % (netif, config.get('network','slirp','slirp')))
        elif transport == 'daemon':
            if config.has_option('network', 'control'):
                umlargs.append('%s=daemon,,,%s' % (netif,
                                                   config.get('network', 'control'),
                                                   ))
            else:
                umlargs.append('%s=daemon' % netif)
        else:
            sys.stderr.write('Unsupported transport: %s' % transport)
            sys.exit(1)

umlargs.extend(umlargs_extra)

umlargs.extend(['con0=fd:0,fd:1',
                'con=pts',
				'root=/dev/root',
				'rootflags=/',
				'rootfstype=hostfs',
                'ubd1=' + imagefile,
                'init=/usr/lib/rootstrap/builder',
                'devfs=nomount',
                'rsworkdir=' + os.getcwd()])
if config.has_option('global', 'umlargs'):
    umlargs.extend(config.get('global', 'umlargs').split())

if os.path.isfile(imagefile):
    os.remove(imagefile)

if not os.path.exists(imagefile):
    image = open(imagefile,'w')
    image.truncate(imagesize * 1048576L)
    image.close()

if os.spawnvpe(os.P_WAIT,umlargs[0], umlargs, os.environ) != 0:
    sys.stderr.write("UML exited with non-zero status, aborting\n")
    sys.exit(1)

if config.has_option('global', 'freespace') and os.path.isfile(imagefile):
    freespace_wanted = long(config.getint('global', 'freespace'))
    if freespace_wanted != 0:
        tune2fs = os.popen('tune2fs -l ' + imagefile)
        freeblocks_natural = -1L
        block_size = -1L
        for line in tune2fs.readlines():
            if line.find(':') == -1:
                continue
            label, value = line.split(':', 1)
            if label == 'Block count':
                size_natural = long(value)
            elif label == 'Free blocks':
                freeblocks_natural = long(value)
            elif label == 'Block size':
                block_size = long(value)
                
        tune2fs.close()
                
        if block_size == -1:
            sys.stderr.write("Warning: Unable to determine block size, not resizing\n")
        else:
            print "Resizing filesystem..."
            if freeblocks_natural == -1:
                sys.stderr.write("Warning: Unable to determine free space, not resizing\n")
            else:
                freeblocks_wanted = freespace_wanted * block_size
                if freeblocks_natural != freeblocks_wanted:
                    size_wanted = size_natural - freeblocks_natural + freeblocks_wanted
                    resize2fs = os.popen('resize2fs -f %s %s 2>&1' % (imagefile, size_wanted))
                    sys.stdout.write(resize2fs.read())
                    image = open(imagefile, 'r+')
                    image.truncate(size_wanted * block_size)
                    image.close()
