efibootdude 0.0__py3-none-any.whl → 0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of efibootdude might be problematic. Click here for more details.

efibootdude/main.py CHANGED
@@ -18,7 +18,7 @@ from types import SimpleNamespace
18
18
  import subprocess
19
19
  import traceback
20
20
  import curses as cs
21
- import xml.etree.ElementTree as ET
21
+ # import xml.etree.ElementTree as ET
22
22
  from efibootdude.PowerWindow import Window, OptionSpinner
23
23
 
24
24
 
@@ -26,20 +26,21 @@ class EfiBootDude:
26
26
  """ Main class for curses atop efibootmgr"""
27
27
  singleton = None
28
28
 
29
- def __init__(self):
29
+ def __init__(self, testfile=None):
30
30
  # self.cmd_loop = CmdLoop(db=False) # just running as command
31
31
  assert not EfiBootDude.singleton
32
32
  EfiBootDude.singleton = self
33
+ self.testfile = testfile
33
34
 
34
35
  spin = self.spin = OptionSpinner()
35
36
  spin.add_key('help_mode', '? - toggle help screen', vals=[False, True])
36
37
  spin.add_key('verbose', 'v - toggle verbose', vals=[False, True])
37
38
 
38
39
  # FIXME: keys
39
- other = 'tudrnmwf*zqx'
40
+ other = 'tudrnmw*zqx'
40
41
  other_keys = set(ord(x) for x in other)
41
42
  other_keys.add(cs.KEY_ENTER)
42
- # other_keys.add(27) # ESCAPE
43
+ other_keys.add(27) # ESCAPE
43
44
  other_keys.add(10) # another form of ENTER
44
45
  self.opts = spin.default_obj
45
46
 
@@ -88,35 +89,50 @@ class EfiBootDude:
88
89
 
89
90
  def get_part_uuids(self):
90
91
  """ Get all the Partition UUIDS"""
92
+ # uuids = {}
93
+ # with open('/run/blkid/blkid.tab', encoding='utf8') as fh:
94
+ # # sample: <device ... TYPE="vfat"
95
+ # # PARTUUID="25d2dea1-9f68-1644-91dd-4836c0b3a30a">/dev/nvme0n1p1</device>
96
+ # for xml_line in fh:
97
+ # element = ET.fromstring(xml_line)
98
+ # if 'PARTUUID' in element.attrib:
99
+ # device=element.text.strip()
100
+ # name = self.mounts.get(device, device)
101
+ # uuids[element.attrib['PARTUUID'].lower()] = name
102
+ # return uuids
103
+
91
104
  uuids = {}
92
- with open('/run/blkid/blkid.tab', encoding='utf8') as fh:
93
- # sample: <device ... TYPE="vfat"
94
- # PARTUUID="25d2dea1-9f68-1644-91dd-4836c0b3a30a">/dev/nvme0n1p1</device>
95
- for xml_line in fh:
96
- element = ET.fromstring(xml_line)
97
- if 'PARTUUID' in element.attrib:
98
- device=element.text.strip()
99
- name = self.mounts.get(device, device)
100
- uuids[element.attrib['PARTUUID'].lower()] = name
105
+ partuuid_path = '/dev/disk/by-partuuid/'
106
+
107
+ if not os.path.exists(partuuid_path):
108
+ return uuids
109
+ for entry in os.listdir(partuuid_path):
110
+ full_path = os.path.join(partuuid_path, entry)
111
+ if os.path.islink(full_path):
112
+ device_path = os.path.realpath(full_path)
113
+ uuids[entry] = device_path
101
114
  return uuids
102
115
 
103
116
  @staticmethod
104
- def extract_uuid(line):
117
+ def extract_uuids(line):
105
118
  """ Find uuid string in a line """
106
119
  # Define the regex pattern for UUID (e.g., 25d2dea1-9f68-1644-91dd-4836c0b3a30a)
107
120
  pattern = r'\b[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\b'
108
121
  # Search for the pattern in the line
109
- match = re.search(pattern, line, re.IGNORECASE)
110
- return match.group(0).lower() if match else None
111
-
122
+ mats = re.findall(pattern, line, re.IGNORECASE)
123
+ return mats
112
124
 
113
125
  def digest_boots(self):
114
126
  """ Digest the output of 'efibootmgr'."""
115
127
  # Define the command to run
116
- command = 'efibootmgr'.split()
117
- # Run the command and capture the output
118
- result = subprocess.run(command, stdout=subprocess.PIPE, text=True, check=True)
119
- lines = result.stdout.splitlines()
128
+ lines = []
129
+ if self.testfile:
130
+ with open(self.testfile, 'r', encoding='utf-8') as fh:
131
+ lines = fh.readlines()
132
+ else:
133
+ command = 'efibootmgr'.split()
134
+ result = subprocess.run(command, stdout=subprocess.PIPE, text=True, check=True)
135
+ lines = result.stdout.splitlines()
120
136
  rv = []
121
137
  width1 = 0 # width of info1
122
138
  label_wid = 0
@@ -141,8 +157,8 @@ class EfiBootDude:
141
157
  )
142
158
 
143
159
  mat = re.match(r'\bBoot([0-9a-f]+)\b(\*?)' # Boot0024*
144
- + r'\s+(\w.*\w)\s+' # Linux Boot Manager
145
- + r'\b(\w+\(.*)$', # HD(4,GPT,cd15e3b1-...
160
+ + r'\s+(\S.*\S|\S)\s*\t' # Linux Boot Manager
161
+ + r'\s*(\S.*\S|\S)\s*$', # HD(4,GPT,cd15e3b1-...
146
162
  line, re.IGNORECASE)
147
163
  if not mat:
148
164
  ns.ident = key
@@ -160,16 +176,19 @@ class EfiBootDude:
160
176
  label_wid = max(label_wid, len(ns.label))
161
177
  other = mat.group(4)
162
178
 
163
- mat = re.search(r'/?File\(([^)]*)\)', other, re.IGNORECASE)
179
+ pat = r'(?:/?\b\w*\(|/)(\\[^/()]+)(?:$|[()/])'
180
+ mat = re.search(pat, other, re.IGNORECASE)
164
181
  device, subpath = '', '' # e.g., /boot/efi, \EFI\UBUNTU\SHIMX64.EFI
165
182
  if mat:
166
183
  subpath = mat.group(1) + ' '
167
184
  start, end = mat.span()
168
185
  other = other[:start] + other[end:]
169
186
 
170
- uuid = self.extract_uuid(other)
171
- if uuid and uuid in self.uuids:
172
- device = self.uuids[uuid]
187
+ uuids = self.extract_uuids(other)
188
+ for uuid in uuids:
189
+ if uuid and uuid in self.uuids:
190
+ device = self.uuids[uuid]
191
+ break
173
192
 
174
193
  if device:
175
194
  ns.info1 = device
@@ -227,7 +246,8 @@ class EfiBootDude:
227
246
  cmds.append(f'{prefix} --bootnum {ident} --label "{tag}"')
228
247
  if self.mods.order:
229
248
  orders = [ns.ident for ns in self.digests if ns.is_boot]
230
- cmds.append(f'{prefix} --bootorder {','.join(orders)}')
249
+ orders = ','.join(orders)
250
+ cmds.append(f'{prefix} --bootorder {orders}')
231
251
  if self.mods.next:
232
252
  cmds.append(f'{prefix} --bootnext {self.mods.next}')
233
253
  if self.mods.timeout:
@@ -243,7 +263,7 @@ class EfiBootDude:
243
263
  os.system('/bin/echo; /bin/echo')
244
264
 
245
265
  for cmd in cmds:
246
- os.system(f'set -x; {cmd}; /bin/echo " <<<ExitCode=$?>>>"')
266
+ os.system(f'(set -x; {cmd}); /bin/echo " <<<ExitCode=$?>>>"')
247
267
 
248
268
  os.system(r'/bin/echo -e "\n\n===== Press ENTER for menu ====> \c"; read FOO')
249
269
  self.reinit()
@@ -275,7 +295,7 @@ class EfiBootDude:
275
295
  ' * - toggle whether entry is active'
276
296
  ' m - modify - modify the value'
277
297
  ' w - write - write the changes',
278
- ' f - freshen - clear changes and re-read boot state',
298
+ ' ESC - abandon changes and re-read boot state',
279
299
  ]
280
300
  for line in lines:
281
301
  self.win.put_body(line)
@@ -336,7 +356,6 @@ class EfiBootDude:
336
356
  actions['m'] = 'modify'
337
357
  if self.mods.dirty:
338
358
  actions['w'] = 'write'
339
- actions['f'] = 'fresh'
340
359
 
341
360
  return actions
342
361
 
@@ -380,7 +399,7 @@ class EfiBootDude:
380
399
  answer = 'y'
381
400
  if self.mods.dirty:
382
401
  answer = self.win.answer(
383
- prompt='Enter "y" to abandon edits and exit [then Enter]')
402
+ prompt='Enter "y" to abandon edits and exit')
384
403
  if answer.strip().lower().startswith('y'):
385
404
  self.win.stop_curses()
386
405
  os.system('clear; stty sane')
@@ -394,7 +413,7 @@ class EfiBootDude:
394
413
  seed = ns.label.split()[0]
395
414
  while True:
396
415
  answer = self.win.answer(
397
- prompt='Enter timeout seconds or clear to abort [then Enter]',
416
+ prompt='Enter timeout seconds or clear to abort',
398
417
  seed=seed, width=80)
399
418
  seed = answer = answer.strip()
400
419
  if not answer:
@@ -452,7 +471,7 @@ class EfiBootDude:
452
471
  if key == ord('t') and ns.is_boot:
453
472
  seed = ns.label
454
473
  while True:
455
- answer = self.win.answer(prompt='Enter new label or clear to abort [then Enter], ',
474
+ answer = self.win.answer(prompt='Enter new label or clear to abort',
456
475
  seed=seed, width=80)
457
476
  seed = answer = answer.strip()
458
477
  if not answer:
@@ -463,10 +482,13 @@ class EfiBootDude:
463
482
  self.mods.dirty = True
464
483
  break
465
484
 
466
- if key == ord('f') and self.mods.dirty:
467
- answer = self.win.answer(
468
- prompt='Enter "y" to clear edits and refresh [then Enter]')
469
- if answer.strip().lower().startswith('y'):
485
+ if key == 27: # ESC
486
+ if self.mods.dirty:
487
+ answer = self.win.answer(
488
+ prompt='Enter "y" to clear edits and refresh')
489
+ if answer.strip().lower().startswith('y'):
490
+ self.reinit()
491
+ else:
470
492
  self.reinit()
471
493
  return None
472
494
 
@@ -480,8 +502,12 @@ class EfiBootDude:
480
502
 
481
503
  def main():
482
504
  """ The program """
505
+ import argparse
506
+ parser = argparse.ArgumentParser()
507
+ parser.add_argument('testfile', nargs='?', default=None)
508
+ opts = parser.parse_args()
483
509
 
484
- dude = EfiBootDude()
510
+ dude = EfiBootDude(testfile=opts.testfile)
485
511
  dude.main_loop()
486
512
 
487
513
  if __name__ == '__main__':
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: efibootdude
3
- Version: 0.0
3
+ Version: 0.2
4
4
  Summary: A visual wrapper for efibootmgr
5
5
  Author-email: Joe Defen <joedef@google.com>
6
6
  License: MIT
@@ -32,21 +32,28 @@ boot menu and parameters while running Linux.
32
32
  * setting boot entries active or inactive, and
33
33
  * setting the boot menu timeout value (until it boots the default entry).
34
34
 
35
- To be sure, there are many other esoteric uses of `efibootmanager`.
35
+ To be sure, there are many other esoteric uses of `efibootmanager` including adding
36
+ a new boot entry; for such needs, just use `efibootmgr` directly.
36
37
 
37
38
  ## Usage
38
- After running `efibootdude`, you'll see a screen like this:
39
+ After running `efibootdude` and making some changes, you'll see a screen comparable to this:
40
+
39
41
  ![efibootdude-screenshot](https://github.com/joedefen/efibootdude/blob/main/images/efibootdude-screenshot.png?raw=true).
42
+
40
43
  At this point
41
44
  * The current line starts with `>` and is highlighted.
42
- * The top line shows actions for the current line.
45
+ * The top line shows actions for the current line; type the underscored letter
46
+ to effect the action.
43
47
  * Enter `?` for a more complete explanation of the keys, navigation keys, etc.
48
+ * **ALWAYS** view the help at least once if unfamiliar with this tool,
49
+ it navigation, and/or uncertain of keys not shown on top line.
44
50
  * With this current line, we can:
45
51
  * Use `u` or `d` to move it up or down in the boot order.
46
52
  * Use `t` to relabel the boot entry.
47
53
  * Use `r` to remove it.
48
54
  * And so forth.
49
- * When ready to write the changes to the BIOS, enter 'w'.
55
+ * Use the `ESC` key to abandon any changes and reload the boot information.
56
+ * When ready to write the changes to the BIOS, enter `w`.
50
57
  * When writing the changes, `efibootdude` drops out of menu mode so you can
51
58
  verify the underlying commands, error codes, and error messages.
52
59
 
@@ -0,0 +1,9 @@
1
+ efibootdude/PowerWindow.py,sha256=pQGXsAMeuiHn-vtEiVG0rgW1eCslh3ukC-VrPhH_j3k,28587
2
+ efibootdude/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ efibootdude/main.py,sha256=opKAafTuw9BpwZl-Q99BmMGVarsf_fEgY-aLjbpeZtA,18460
4
+ efibootdude-0.2.dist-info/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
5
+ efibootdude-0.2.dist-info/METADATA,sha256=HuHORtrDzLH0ItVDm_UbRXsRVRSgBtyBcVEkzODKNCY,3380
6
+ efibootdude-0.2.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
7
+ efibootdude-0.2.dist-info/entry_points.txt,sha256=3KZ_86ZSy4f-weuSruTlMGaQ96jZUm7mjyITVnjE184,54
8
+ efibootdude-0.2.dist-info/top_level.txt,sha256=BrMsK3JmOrVJUNkHX1dicqWrdjbm4itRtmXJMxte-VU,12
9
+ efibootdude-0.2.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- efibootdude/PowerWindow.py,sha256=pQGXsAMeuiHn-vtEiVG0rgW1eCslh3ukC-VrPhH_j3k,28587
2
- efibootdude/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- efibootdude/main.py,sha256=xl6_bKWJVxzbN31SUWUAWWI5DH5F_iX5HpR-i23JjJ0,17609
4
- efibootdude-0.0.dist-info/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
5
- efibootdude-0.0.dist-info/METADATA,sha256=hNAKcQp31odNUlDLHVZ41ngqLq19Y0WuttYgXw08ZtY,2995
6
- efibootdude-0.0.dist-info/WHEEL,sha256=mguMlWGMX-VHnMpKOjjQidIo1ssRlCFu4a4mBpz1s2M,91
7
- efibootdude-0.0.dist-info/entry_points.txt,sha256=3KZ_86ZSy4f-weuSruTlMGaQ96jZUm7mjyITVnjE184,54
8
- efibootdude-0.0.dist-info/top_level.txt,sha256=BrMsK3JmOrVJUNkHX1dicqWrdjbm4itRtmXJMxte-VU,12
9
- efibootdude-0.0.dist-info/RECORD,,