summaryrefslogtreecommitdiffstats
path: root/build_tools/larch8/larch0/cli/medium.py
blob: 94cb0c9eb80332ef6ae7bde6375fa647ca8d7b38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#!/usr/bin/env python2
#
# medium.py
#
# (c) Copyright 2010 Michael Towers (larch42 at googlemail dot com)
#
# This file is part of the larch project.
#
#    larch 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.
#
#    larch 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 larch; if not, write to the Free Software Foundation, Inc.,
#    51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
#----------------------------------------------------------------------------
# 2010.11.09

"""This is a command line script to place a larch system on a medium.
It can handle a larchified Arch installation for the initial creation of
a larch medium (source=""), but it can also copy from one existing
medium to another, or create a boot-iso for an existing larch medium
(only relevant for partitions).
The source can be a CD/DVD, an iso file or a partition (unmounted), the
output can be an iso file or another (unmounted) partition. In the latter
case the partition detection mode can be selected and data persistence
can be enabled (or disabled). In addition, the volume label of the
destination device can be set.
Parameters are passed as options and arguments.

A further source possiblity is an already mounted larch system, this being
specified by a source path starting with '/' (except '/dev/...'). This
option is provided for use with a running live system.
"""


import os
from backend import *
from media_common import *

def build_medium(options, device):
    """Copy an existing larch medium, specified by the option 'source' to
    the partition specified as argument.
    'device' is the name (e.g. '/dev/sdb1') of the partition to
    receive the larch image.
    """
    # Basic initialisation of the larchified source
    medium = Medium(options)
    build = medium.build
    medium_dir = medium.medium_dir

    if device:      # for destination partition (not iso)
        # This handles the bulk of the destination medium setup
        medium.setup_destination(device)

    if options.testmedium:
        return

    if options.bootiso:
        unmount()
        # Get bootloader configuration file
        fconf = build + '/boot/isolinux/syslinux.cfg'
        if not os.path.isfile(fconf):
            fconf = build + '/boot/isolinux/extlinux.conf'
        ok, res = runcmd('mv %s %s/boot/isolinux/isolinux.cfg' % (fconf, build))
        if not ok:
            errout(_("Couldn't find boot configuration file"))
        medium.mkiso()

    else:           # Now not boot iso!
        runcmd('rm -f %s/boot/isolinux/syslinux.cfg' % build)
        runcmd('rm -f %s/boot/isolinux/extlinux.conf' % build)

        # Now, need to test for overlay.medium and/or mods.sqf - the presence
        # of both is not supported here (although the larch initramfs hook
        # can cope with it).
        if os.path.isfile('%s/larch/overlay.medium' % medium_dir):
            if os.path.isfile('%s/larch/mods.sqf' % medium_dir):
                errout(_("Copying of devices with both 'overlay.medium' and 'mods.sqf'\n"
                        "is not supported."))
            if device and options.persist and (medium.fstype != 'vfat'):
                # Copy the overlay files to the destination medium
                for fd in os.listdir(medium_dir):
                    if (fd[0] != '.') and (fd not in IGNOREDIRS.split()):
                        runcmd('cp -a %s/%s %s' % (medium_dir, fd, MPD))

            else:
                # Create a modifications archive, mods.sqf
                if device:
                    modsdst = MPD
                else:
                    modsdst = build
                    runcomd('mkdir -p %s/larch' % modsdst)
                if not runcmd('%s/boot/support/support mksquashfs %s %s/larch/mods.sqf'
                        ' -wildcards -e %s'
                        % (build, medium_dir, modsdst, IGNOREDIRS),
                        filter=mksquashfs_filter_gen())[0]:
                    errout(_("Squashing mods.sqf failed"))
                # remove execute attrib
                runcmd('chmod oga-x %s/mods.sqf' % modsdst)

        elif device and options.persist and (medium.fstype != 'vfat'):
            # mods.sqf must be unpacked onto the medium
            modsfile = medium_dir + '/larch/mods.sqf'
            if os.path.isfile(modsfile):
                runcmd('rm %s/larch/mods.sqf' % MPD)
                runcmd('%s/boot/support/support unsquashfs -d %s/.mods %s/larch/mods.sqf'
                        % (build, MPD, medium_dir))
                if not os.path.isdir(MPD + '/.mods'):
                    errout(_("Unpacking of modifications archive failed, see log"))
                runcmd('bash -c "mv %s/.mods/* %s"' % (MPD, MPD))
                runcmd('rm -rf %s/.mods' % MPD)
            writefile("The presence of the file 'larch/overlay.medium' causes\n"
                    "the medium to be used as a writeable, persistent overlay\n"
                    "for the larch root file-system.\n",
                    MPD + '/larch/overlay.medium')

        if device:
            # To boot in 'search' mode the file larch/larchboot must be present.
            runcmd('rm -f %s/larch/larchboot' % MPD)
            if options.larchboot:
                add_larchboot(MPD)

            if medium.fstype != 'vfat':
                # extlinux is installed to a mounted partition.
                # The configuration file must be called extlinux.conf:
                runcmd('mv %s/boot/isolinux/isolinux.cfg %s/boot/isolinux/extlinux.conf'
                        % (MPD, MPD))
                # Install extlinux
                runcmd('%s/boot/support/support extlinux -i %s/boot/isolinux'
                        % (build, MPD))
                # Unmount device(s)
                unmount()

            else:
                # syslinux is installed to an unmounted partition.
                # The configuration file must be called syslinux.cfg:
                runcmd('mv %s/boot/isolinux/isolinux.cfg %s/boot/isolinux/syslinux.cfg'
                        % (MPD, MPD))
                unmount()
                # Install syslinux
                runcmd('%s/boot/support/support syslinux -d /boot/isolinux -i %s'
                        % (build, device))

            comment(" *** %s ***" % (_("Completed writing to %s") % device))

        else:   # iso
            # Write bootloader configuration file
            bootconfig(build)
            # At present the 'larchboot' file is not necessary for booting from
            # optical media, but it should probably be present anyway.
            if not os.path.isfile(medium_dir + '/larch/larchboot'):
                add_larchboot(build)

            medium.mkiso(' -x %s/boot %s' % (medium_dir, medium_dir))
            unmount()

    runcmd('rm -rf %s' % build)



if __name__ == '__main__':
    from optparse import OptionParser, OptionGroup
    parser = OptionParser(usage=_("usage: %prog [options] [partition (e.g. /dev/sdb1)]"))

    parser.add_option('-S', '--source', action='store', type="string",
            dest='source', default='',
            help=_("Specify source medium, an iso-file (path ending '.iso'), device"
                    " (starting '/dev/') or volume label"))
    parser.add_option("-l", "--label", action="store", type="string",
            default="", dest="label",
            help=_("Volume label for boot medium (default: %s - or %s if boot iso)")
                    % (LABEL, BOOTISOLABEL))
    parser.add_option("-b", "--bootiso", action="store_true",
            dest="bootiso", default=False,
            help=_("Build a boot iso for the source partition"))

    # Options for building from larchified installation (no -S)
    parser.add_option("-p", "--profile", action="store", type="string",
            default="", dest="profile",
            help=_("Profile: 'user:profile-name' or path to profile directory"))
    parser.add_option("-i", "--installation-dir", action="store", type="string",
            default="", dest="idir",
            help=_("Path to larchified directory (default %s)") % INSTALLATION)

    # Options for iso output
    parser.add_option("-o", "--isofile", action="store", type="string",
            default="", dest="isofile",
            help=_("Specify the output file (default: '%s' in the current "
                    "directory - or '%s' if boot iso)") % (ISOFILE, BOOTISO))

    # Options for writing to partition
    parser.add_option("-d", "--detect", action="store", type="string",
            default="label", dest="detection",
            help=(_("Method for boot partition detection: %s (default: label)")
                    % detection_methods))
    parser.add_option("-n", "--nosearchboot", action="store_false",
            dest="larchboot", default=True,
            help=_("Don't generate 'larch/larchboot' file"))
    parser.add_option("-F", "--noformat", action="store_false",
            default=True, dest="format",
            help=_("Don't format the medium (WARNING: Only for experts)"))
    parser.add_option("-P", "--persist", action="store_true",
            dest="persist", default=False,
            help=_("Enable data persistence (using medium as writeable"
                    " file-system). Default: disabled"))
    parser.add_option("-m", "--noboot", action="store_false",
            dest="mbr", default=True,
            help=_("Don't install the bootloader (to the MBR)"))
    parser.add_option("-j", "--nojournal", action="store_true", dest="nojournal",
            default=False, help=_("Don't use journalling on boot medium"
            " (default: journalling enabled)"))

    # General minor options
    parser.add_option("-q", "--quiet", action="store_true", dest="quiet",
            default=False, help=_("Suppress output messages, except errors"
                    " (no effect if -s specified)"))
    parser.add_option("-s", "--slave", action="store_true", dest="slave",
            default=False, help=_("Run as a slave from a controlling program"
                    " (e.g. from a gui)"))
    parser.add_option('-T', '--testmedium', action='store_true',
            dest='testmedium', default=False,
            help=_("Test source or destination medium only (used by gui)"))

    (options, args) = parser.parse_args()
    options.force = False

    if options.bootiso:
        if args:
            errout(_("Unexpected argument: %s") % args[0])
        if not options.source:
            errout(_("No source specified for boot iso"))
        if not options.isofile:
            options.isofile = BOOTISO
        if not options.label:
            options.label = BOOTISOLABEL
        greet = _("Generating larch boot iso file: %s\n")
    else:
        if not options.isofile:
            options.isofile = ISOFILE
        if not options.label:
            options.label = LABEL
        greet = _("Generating larch iso file: %s\n")

    # Location for the resulting iso, forcing a '.iso' suffix
    if not options.isofile.endswith('.iso'):
        options.isofile += '.iso'

    if args:
        device = args[0]
        if device.startswith('/dev/'):
            print '##', ((_("Testing output medium: %s\n")
                    if options.testmedium
                    else _("Creating larch medium on: %s\n")) % device)
        else:
            print '##', (_("Invalid partition: '%s'") % device)
            sys.exit(1)
    else:
        options.isofile = os.path.join(os.getcwd(), options.isofile)
        print '##', ((_("Testing source medium: %s\n") % options.source)
                if options.testmedium
                else (greet % options.isofile))
        device = ''

    if os.getuid() != 0:
        print _("This application must be run as root")
        sys.exit(1)

    init('live_medium', options)
    build_medium(options, device)