-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathlist_partitions.py
367 lines (272 loc) · 13.4 KB
/
list_partitions.py
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# -*- coding: utf-8 -*-
# list_partitions.py
# Load and display partitions for selected device
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties 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., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): Vojtech Trefny <[email protected]>
#
# ---------------------------------------------------------------------------- #
class ListPartitions(object):
""" List of children of selected device
"""
def __init__(self, blivet_gui):
self.blivet_gui = blivet_gui
self.installer_mode = self.blivet_gui.installer_mode
self.partitions_list = self.blivet_gui.builder.get_object("liststore_logical")
self.partitions_view = self.blivet_gui.builder.get_object("treeview_logical")
self.partitions_view.connect("button-release-event", self.on_right_click_event)
self.select = self.partitions_view.get_selection()
self.select.connect("changed", self.on_partition_selection_changed)
self.selected_partition = None
def update_partitions_list(self, selected_device):
""" Update partition view with selected disc children (partitions)
:param selected_device: selected device from list (eg. disk or VG)
:type device_name: blivet.Device
"""
self.partitions_list.clear()
def _get_real_child(child):
""" When adding a child device, we actually might want to add one
of its children instead -- e.g. when adding a partition that
is a PV we want to add the VG ("group device") etc.
"""
if self._is_group_device(child):
return self.blivet_gui.client.remote_call("get_group_device", child)
elif child.format and child.format.type in ("luks", "integrity") and child.children:
return self.blivet_gui.client.remote_call("get_luks_device", child)
else:
return child
def _add_chilren(childs, parent_iter=None):
for child in childs:
if child.children:
child_iter = self._add_to_store(child, parent_iter)
_add_chilren(self.blivet_gui.client.remote_call("get_children", child), child_iter)
else:
new_child = _get_real_child(child)
self._add_to_store(new_child, parent_iter)
if selected_device.is_disk:
childs = self.blivet_gui.client.remote_call("get_disk_children", selected_device)
for child in childs.partitions:
child = _get_real_child(child)
child_iter = self._add_to_store(child)
if hasattr(child, "is_extended") and child.is_extended:
for logical in childs.logicals:
logical = _get_real_child(logical)
self._add_to_store(logical, child_iter)
# lvmvg always has some children, at least a free space
elif selected_device.type == "lvmvg":
childs = self.blivet_gui.client.remote_call("get_children", selected_device)
_add_chilren(childs, None)
# for btrfs volumes and mdarrays its necessary to add the device itself to the view
# because these devices don't need to have children (only btrfs volume or only mdarray
# is a valid, usable device)
elif selected_device.type == "btrfs volume" or (selected_device.type == "mdarray" and not selected_device.children):
parent_iter = self._add_to_store(selected_device)
childs = self.blivet_gui.client.remote_call("get_children", selected_device)
_add_chilren(childs, parent_iter)
else:
childs = self.blivet_gui.client.remote_call("get_children", selected_device)
_add_chilren(childs, None)
# select first line in partitions view
self.select.select_path("0")
# expand all expanders
self.partitions_view.expand_all()
def _is_group_device(self, blivet_device):
# btrfs volume on raw disk
if blivet_device.type in ("btrfs volume", "lvmvg"):
return True
if blivet_device.format and blivet_device.format.type in ("lvmpv", "btrfs", "mdmember"):
return (len(blivet_device.children) > 0)
# encrypted group device
if blivet_device.format and blivet_device.format.type in ("luks", "integrity") and blivet_device.children:
luks_device = self.blivet_gui.client.remote_call("get_luks_device", blivet_device)
if luks_device.format and luks_device.format.type in ("lvmpv", "btrfs", "mdmember"):
return (len(luks_device.children) > 0)
return False
def _add_to_store(self, device, parent_iter=None):
""" Add new device to partitions list
:param device: device to add
:type device: blivet.device.Device
:param parent_iter: parent iter for this device
:type parent_iter: Gtk.TreeIter or None
"""
devtype = "lvm" if device.type == "lvmvg" else "raid" if device.type == "mdarray" else device.type
if device.format.type:
fmt = device.format.type
else:
if device.format.name != "Unknown":
# format recognized by blkid but not supported by blivet
fmt = device.format.name
else:
fmt = None
if self.installer_mode:
mnt = device.format.mountpoint if (device.format and device.format.mountable) else None
else:
is_mounted = bool(device.format.system_mountpoint) if (device.format and device.format.mountable) else False
if is_mounted:
mnts = self.blivet_gui.client.remote_call("get_system_mountpoints", device)
mnt = ", ".join(mnts)
else:
mnt = None
if device.format.type and hasattr(device.format, "label") and device.format.label:
label = device.format.label if len(device.format.label) < 18 else device.format.label[:15] + "..."
else:
label = ""
device_iter = self.partitions_list.append(parent_iter, [device, device.name, devtype, fmt, str(device.size), label, mnt])
return device_iter
def _allow_recursive_delete_device(self, device):
if device.type not in ("btrfs volume", "mdarray", "lvmvg"):
return False
def _device_descendants(device):
descendants = []
for child in device.children:
descendants.append(child)
descendants.extend(_device_descendants(child))
return descendants
for d in _device_descendants(device):
if not self._allow_delete_device(d, recursive=True):
return False
return True
def _allow_delete_device(self, device, recursive=False):
if device.protected:
return False
if device.type in ("free space",):
return False
elif not recursive and not device.isleaf:
return False
else:
if not device.format.type:
return True
elif device.format.type == "swap":
return not device.format.status
else:
if not device.format.mountable:
return True
else:
return not device.format.status
def _allow_resize_device(self, device):
if device.protected or device.children or device.format_immutable:
return False
if not device._resizable:
return False
return True
def _allow_format_device(self, device):
if device.protected or device.children:
return False
if device.type not in ("partition", "lvmlv", "luks/dm-crypt", "mdarray"):
return False
if device.type == "partition" and device.is_extended:
return False
if device.format.type in ("mdmember", "btrfs"):
return False
return not device.format.status
def _allow_set_mountpoint(self, device):
if not self.blivet_gui.installer_mode:
return False
if device.type in ("lvmthinsnapshot", "lvmsnapshot") and not device.exists:
return False
# do not allow to set mountpoints for devices that are not "direct"
# (e.g. partition formatted to btrfs -- the mountpoint must be set for
# the btrfs volume on top of it)
if not device.direct:
return False
return device.format.mountable
def _allow_set_partition_table(self, device):
# there is no special "device" representing disks in the UI
# so we are "editing" a free space
if device.type != "free space":
return False
# empty disk without disklabel
if device.is_uninitialized_disk:
return True
# empty disk with disklabel
if device.is_empty_disk and device.disk.format.type == "disklabel":
return True
return False
def _allow_relabel_device(self, device):
if device.protected or device.format.status:
return False
return device.format.labeling() and device.format.relabels()
def _allow_add_device(self, device):
if device.protected:
return False
if device.type in ("free space", "btrfs volume", "btrfs subvolume", "lvmthinpool"):
return True
# empty lvmpv
if device.format and device.format.type == "lvmpv":
return not device.children
# snapshot of thin lv -- only if exists
if device.type == "lvmthinlv":
return device.exists
# snapshot of lvmlv -- only if there is free space in the vg and if exists
if device.type == "lvmlv":
return device.vg.free_space >= device.vg.pe_size and device.exists
return False
def activate_action_buttons(self, selected_device):
""" Activate buttons in toolbar based on selected device
:param selected_device: Selected partition
:type selected_device: Gtk.TreeModelRow
"""
device = selected_device[0]
self.blivet_gui.deactivate_all_actions()
if device.type != "free space":
self.blivet_gui.activate_device_actions(["info"])
if self._allow_delete_device(device) or self._allow_recursive_delete_device(device):
self.blivet_gui.activate_device_actions(["delete"])
if self._allow_resize_device(device):
self.blivet_gui.activate_device_actions(["resize"])
if self._allow_format_device(device):
self.blivet_gui.activate_device_actions(["format"])
if self._allow_relabel_device(device):
self.blivet_gui.activate_device_actions(["label"])
if self._allow_add_device(device):
self.blivet_gui.activate_device_actions(["add"])
if self._allow_set_mountpoint(device):
self.blivet_gui.activate_device_actions(["mountpoint"])
if self._allow_set_partition_table(device):
self.blivet_gui.activate_device_actions(["partitiontable"])
if device.type == "lvmvg":
self.blivet_gui.activate_device_actions(["parents"])
if device.format:
if device.format.type == "luks" and not device.format.status and device.format.exists:
self.blivet_gui.activate_device_actions(["decrypt"])
elif device.format.mountable and device.format.system_mountpoint:
self.blivet_gui.activate_device_actions(["unmount"])
def select_device(self, device):
""" Select device from list """
def _search(model, path, treeiter, device):
if model[treeiter][0] == device:
self.select.select_path(path)
self.partitions_list.foreach(_search, device)
def on_partition_selection_changed(self, selection):
""" On selected partition action
"""
model, treeiter = selection.get_selected()
if treeiter:
self.blivet_gui.deactivate_all_actions()
self.activate_action_buttons(model[treeiter])
self.selected_partition = model[treeiter]
self.blivet_gui.logical_view.select_rectanlge(device=self.selected_partition[0])
else:
self.blivet_gui.deactivate_all_actions()
def on_right_click_event(self, treeview, event):
""" Right click event on partition treeview
"""
if event.button == 3:
selection = treeview.get_selection()
if selection:
self.blivet_gui.popup_menu.menu.popup_at_pointer(None)