/
boot-update
executable file
·234 lines (195 loc) · 6.66 KB
/
boot-update
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
#!/usr/bin/python
# -*- coding: ascii -*-
""" Runs the boot-update program from command line """
import os
import sys
# This is needed for testing from the root of the git repo - must come before
# funtoo imports
if os.path.isdir(".git") and os.path.basename(os.getcwd()) == "boot-update":
sys.path = [ "python/modules" ] + sys.path
# Import Funtoo extensions that we use:
import funtoo.boot.config
import funtoo.boot.helper
import funtoo.boot.extensions
from funtoo.boot.extension import ExtensionError
from funtoo.core.config import ConfigFileError
BLUE = "\x1b[34;01m"
CYAN = "\x1b[36;01m"
CYANN = "\x1b[36m"
GREEN = "\x1b[32;01m"
RED = "\x1b[31;01m"
PURP = "\x1b[35;01m"
OFF = "\x1b[0m"
version = "1.7.2"
verbose = False
def banner(extra=True):
""" prints the banner message """
print("")
print("{P}boot-update {O}{C}{ver}{O} /".format(P = PURP, O = OFF, C = CYANN, ver = version))
print("Copyright 2009-2012 Funtoo Technologies")
if extra:
print("")
print(" [use option \"-l\" for license info, \"-h\" for help]")
print("")
def versinfo():
""" prints version information """
banner(extra=False)
print("")
print(""" This program is free software; you can redistribute and/or modify
it under the terms of the GNU General Public License version 3 as published by
the Free Software Foundation. Alternatively you may (at your option) use any
other license that has been publicly approved for use with this program by
Funtoo Technologies, LLC. (or its successors, if any.)
""" )
def printhelp():
""" prints the help message """
banner(extra=False)
print("")
print(""" Usage: boot-update [options]
Uses settings in /etc/boot.conf to generate new grub, grub-legacy or
lilo config file.
Options:
--showdefaults Show hard-coded (user-overrideable) settings
--show <sect/var> Display variable "var" defined in section "sect"
-C, --check Validate configuration file, but do nothing else
-V, --verbose Verbose mode
-h, --help Display this information
-l, --license Display license information
""" )
def mesg(msgtype, msg):
""" prints different types of messages to the console """
if verbose and msgtype == "info":
print("{G} *{O} {m}".format(G = GREEN, O = OFF, m = msg))
elif msgtype == "norm":
print("{G} *{O} {m}".format(G = GREEN, O = OFF, m = msg))
elif msgtype == "boot":
print(" {m}".format(m = msg))
elif msgtype == "defboot":
print("{C} DEFAULT > {G}{m}{O}".format(C = CYAN, G = GREEN, m = msg, O = OFF))
elif msgtype == "warn":
print("{R} * WARN :{O} {m}".format(R = RED, O = OFF, m = msg))
elif msgtype == "fatal":
print("{R} * ERROR :{O} {m}".format(R = RED, O = OFF, m = msg))
def cleanup(success, messages, ext = None):
""" prints accumulated errors and warnings and exits appropriately """
if ext != None:
# unmounts any non-/boot filesystems we may have mounted for scanning.
# /boot unmounting is handled via another process.
mesgs = ext.r.UnmountIfNecessary()
messages += mesgs
warnings = False
for msgtype, msg in messages:
if msgtype == "warn":
warnings = True
mesg(msgtype, msg)
if not success:
print(RED + " * Did not complete successfully." + OFF)
print("")
sys.exit(1)
else:
out = GREEN + " * " + OFF + "Completed successfully"
if warnings:
print(out + " with warnings.")
else:
print(out + ".")
print("")
sys.exit(0)
def update(config, success, messages):
""" update configuration """
# Generate warnings for any invalid config file entries...
for invalid in config.validate():
messages.append(["warn", "invalid config setting \"{iv}\"; ignored.".format(iv = invalid)])
# Figure out what extension we should be loading...
generate = config["boot/generate"]
if generate == "":
success = False
messages.append(["fatal", "boot/generate does not specify a valid boot loader to generate a config for."])
if generate not in funtoo.boot.extensions.__all__:
success = False
messages.append(["fatal", "extension for boot loader \"{gen}\" (specified in boot/generate) not found.".format(g = generate)])
if ("-C" in sys.argv) or ("--check" in sys.argv):
messages.append(["norm","Configuration file {cf} checked.".format(cf = cfile)])
cleanup(success, messages)
mesg("norm","Generating config for {gen}...".format(gen = generate))
print("")
if not success:
cleanup(success, messages)
# Before loading extension, we want to auto-mount boot if it isn't
# already mounted:
imountedit = False
if funtoo.boot.helper.fstabHasEntry("/boot"):
if not os.path.ismount("/boot"):
mesg("info","Mounting filesystem /boot...")
os.system("mount /boot")
imountedit = True
else:
mesg("info", "No /etc/fstab entry for /boot; not mounting.")
# Dynamically import the proper extension module (ie. grub.py,
# grub-legacy.py, lilo.py):
extname = "funtoo.boot.extensions.{gen}".format(gen = generate)
__import__(extname)
extmodule = sys.modules[extname]
# Create Boot Loader Extension object: and regenerate config file
ext = None
try:
ext = extmodule.getExtension(config)
ext.mesg = mesg
success, msgs = ext.regenerate()[1:]
except ExtensionError as e:
success = False
messages.append(["fatal", e])
else:
messages += msgs
if success:
pos = 0
while pos < len(ext.bootitems):
if pos == ext.defpos:
mesg("defboot", ext.bootitems[pos])
else:
mesg("boot", ext.bootitems[pos])
pos += 1
print
# If we mounted /boot, we should unmount it:
if imountedit:
mesg("info","Unmounting /boot")
os.system("umount /boot")
cleanup(success, allmsgs, ext)
if os.geteuid() != 0:
print("")
mesg("fatal", "boot-update requires root privileges")
print("")
else:
if len(sys.argv)>=2 and (( "-l" in sys.argv ) or ( "--license" in sys.argv )):
versinfo()
sys.exit(0)
if "-V" in sys.argv or ("--verbose" in sys.argv):
verbose = True
ok = True
allmsgs = []
cfile = "/etc/boot.conf"
# Load /etc/boot.conf master configuration file:
try:
c = funtoo.boot.config.BootConfigFile(cfile)
if not c.fileExists():
ok = False
allmsgs.append(["fatal", "Master configuration file \"{cf}\" does not exist.".format(cf = cfile)])
except ConfigFileError as e:
ok = False
banner()
allmsgs.append(["fatal", "Parse Error: {err}".format(err = e)])
if not ok:
cleanup(ok, allmsgs)
if len(sys.argv)>=3 and sys.argv[1] == "--show":
print(c[sys.argv[2]])
elif len(sys.argv)>=2 and sys.argv[1] == "--showdefaults":
print("# These are the default settings that can be overridden by")
print("# the /etc/boot.conf file.")
print("")
for line in c.parent.dump():
if not line.startswith("#"):
sys.stdout.write(line)
elif len(sys.argv)>=2 and (sys.argv[1] in [ "-h", "--help"]):
printhelp()
else:
banner()
update(c, ok, allmsgs)