Skip to content
API Documentation
BastionGuard™
Subvolume Class Reference
Inheritance diagram for Subvolume:

Public Member Functions

 Subvolume (string name, string path, string parent_dev_uuid, SnapshotRepo? parent_repo)
Device? get_device ()
void print_info ()
bool remove ()
bool restore ()

Static Public Member Functions

static Gee.HashMap< string, Subvolume > detect_subvolumes_for_system_by_path (string system_path, SnapshotRepo? repo, Gtk.Window? parent_window)

Public Attributes

string device_uuid
string name = ""
string path = ""
long id = -1
int64 total_bytes = 0
int64 unshared_bytes = 0
string mount_path = ""
SnapshotRepo? repo

Properties

string total_formatted [get]
string unshared_formatted [get]
bool exists_on_disk [get]
bool is_system_subvolume [get]

Detailed Description

Definition at line 32 of file Subvolume.vala.

Constructor & Destructor Documentation

◆ Subvolume()

Subvolume.Subvolume ( string name,
string path,
string parent_dev_uuid,
SnapshotRepo? parent_repo )
inline

Definition at line 46 of file Subvolume.vala.

46 {
47
48 this.name = name;
49 this.path = path;
50 this.device_uuid = parent_dev_uuid;
51 this.repo = parent_repo;
52
53 if (repo != null){
54 this.mount_path = repo.mount_paths[name];
55 }
56 }
Gee.HashMap< string, string > mount_paths
string path
SnapshotRepo? repo
string name

References SnapshotRepo.mount_paths, name, path, and repo.

Referenced by Main.create_pre_restore_snapshot_btrfs(), detect_subvolumes_for_system_by_path(), and Snapshot.read_control_file().

Member Function Documentation

◆ detect_subvolumes_for_system_by_path()

Gee.HashMap< string, Subvolume > Subvolume.detect_subvolumes_for_system_by_path ( string system_path,
SnapshotRepo? repo,
Gtk.Window? parent_window )
inlinestatic

Definition at line 87 of file Subvolume.vala.

88 {
89
90 var map = new Gee.HashMap<string, Subvolume>();
91
92 log_debug("Searching subvolume for system at path: %s".printf(system_path));
93
94 var fstab = FsTabEntry.read_file(path_combine(system_path, "/etc/fstab"));
95 var crypttab = CryptTabEntry.read_file(path_combine(system_path, "/etc/crypttab"));
96
97 foreach(var item in fstab){
98
99 if (!item.is_for_system_directory()){ continue; }
100
101 if (item.subvolume_name().length > 0){
102
103 var dev = item.resolve_device(crypttab, parent_window);
104 var dev_name = (dev == null) ? "" : dev.device;
105 var dev_uuid = (dev == null) ? "" : dev.uuid;
106
107 log_debug("Found subvolume: %s, on device: %s".printf(item.subvolume_name(), dev_name));
108
109 var subvol = new Subvolume(item.subvolume_name(), item.mount_point, dev_uuid, repo);
110 map.set(subvol.name, subvol);
111 }
112 }
113
114 return map;
115 }
Subvolume(string name, string path, string parent_dev_uuid, SnapshotRepo? parent_repo)
string path_combine(string path1, string path2)
void log_debug(string message)

References TeeJee.Logging.log_debug(), TeeJee.FileSystem.path_combine(), repo, and Subvolume().

Referenced by Main.detect_system_devices(), and SnapshotRepo.unlock_and_mount_devices().

◆ get_device()

Device? Subvolume.get_device ( )
inline

Definition at line 70 of file Subvolume.vala.

70 {
71
72 return Device.get_device_by_uuid(device_uuid);
73 }
string device_uuid

References device_uuid, and Device.get_device_by_uuid().

◆ print_info()

void Subvolume.print_info ( )
inline

Definition at line 117 of file Subvolume.vala.

117 {
118
119 log_debug("name=%s, uuid=%s, id=%ld, path=%s".printf(name, device_uuid, id, path));
120 }

References device_uuid, TeeJee.Logging.log_debug(), name, and path.

◆ remove()

bool Subvolume.remove ( )
inline

Definition at line 124 of file Subvolume.vala.

124 {
125
127 if (name == "@"){
128 path = path_combine(App.mount_point_app + "/backup", "@");
129 }
130 else if (name == "@home"){
131 path = path_combine(App.mount_point_app + "/backup-home", "@home");
132 }
133 }
134
135 string cmd = "";
136 string std_out, std_err, subpath;
137 int ret_val;
138
139 if (!dir_exists(path)){ return true; } // ok, item does not exist
140
141 log_msg("%s: %s (Id:%ld)".printf(_("Deleting subvolume"), name, id));
142
143 // always remove subvolumes recursively, this does not affect performance
144 string options = App.use_option_raw ? "--commit-after" : "";
145
146 if (Main.btrfs_version__can_recursive_delete) {
147 options += " --recursive";
148 }
149
150 subpath = path_combine(path, name);
151 if (dir_exists(subpath)) { // possible nested subvolume present, verify before deleting
152 int rc_show = exec_sync("btrfs subvolume show '%s'".printf(subpath), out std_out, out std_err);
153 if (rc_show == 0) {
154 // confirmed nested btrfs subvolume, delete it first
155 cmd = "btrfs subvolume delete %s '%s'".printf(options, subpath);
156 log_debug("Deleting nested subvolume in snapshot");
157 log_debug(cmd);
158 ret_val = exec_sync(cmd, out std_out, out std_err);
159 if (ret_val != 0){
160 log_error(std_err);
161 log_error(_("Failed to delete snapshot nested subvolume") + ": '%s'".printf(subpath));
162 return false;
163 }
164 } else {
165 // path exists but is not a btrfs subvolume, skip nested removal
166 log_debug("Nested path exists but is not a btrfs subvolume, skipping: %s".printf(subpath));
167 }
168 }
169
170 cmd = "btrfs subvolume delete %s '%s'".printf(options, path);
171 log_debug(cmd);
172 ret_val = exec_sync(cmd, out std_out, out std_err);
173 if (ret_val != 0){
174 log_error(std_err);
175 log_error(_("Failed to delete snapshot subvolume") + ": '%s'".printf(path));
176 return false;
177 }
178
179 log_msg("%s: %s (Id:%ld)\n".printf(_("Deleted subvolume"), name, id));
180
182 if ((id > 0) && (repo != null)){
183
184 log_debug("Waiting on btrfs to finish deleting...");
185 while (exec_sync("btrfs subvolume sync %s".printf(mount_path), out std_out, out std_err) != 0) {
186 log_debug("Still waiting for btrfs to finish deleting... %s".printf(std_err));
187 sleep(1000);
188 }
189
190 log_debug("Rescanning quotas...");
191 while (exec_sync("btrfs quota rescan %s".printf(mount_path), out std_out, out std_err) != 0) {
192 log_debug("Still rescanning quotas... %s".printf(std_err));
193 sleep(1000);
194 }
195
196 // Check if qgroup still exists before trying to destroy it.
197 // The qgroup may have been auto-destroyed when the subvolume was deleted.
198 string qgroup_id = "0/%ld".printf(id);
199 cmd = "btrfs qgroup show -f '%s'".printf(repo.mount_paths[name]);
200 log_debug(cmd);
201 ret_val = exec_sync(cmd, out std_out, out std_err);
202
203 bool qgroup_exists = (ret_val == 0) && (std_out.contains(qgroup_id));
204
205 if (!qgroup_exists) {
206 log_debug("Qgroup %s already removed (auto-destroyed with subvolume)".printf(qgroup_id));
207 } else {
208 log_msg("%s: %s".printf(_("Destroying qgroup"), qgroup_id));
209
210 cmd = "btrfs qgroup destroy %s '%s'".printf(qgroup_id, repo.mount_paths[name]);
211 log_debug(cmd);
212 ret_val = exec_sync(cmd, out std_out, out std_err);
213 if (ret_val != 0){
214 // Qgroup may have been destroyed between our check and destroy attempt
215 log_debug("Qgroup %s could not be destroyed (likely already removed): %s".printf(qgroup_id, std_err));
216 } else {
217 log_msg("%s: %s\n".printf(_("Destroyed qgroup"), qgroup_id));
218 }
219 }
220
221 log_debug("Rescanning quotas (post)...");
222 while (exec_sync("btrfs quota rescan %s".printf(mount_path), out std_out, out std_err) != 0) {
223 log_debug("Still rescanning quotas (post)... %s".printf(std_err));
224 sleep(1000);
225 }
226
227 log_debug("Final sync (post)...");
228 while (exec_sync("btrfs subvolume sync %s".printf(mount_path), out std_out, out std_err) != 0) {
229 log_debug("Still syncing (post)... %s".printf(std_err));
230 sleep(1000);
231 }
232
233 }
234 }
235
236 return true;
237 }
Main App
#define _(s)
bool btrfs_qgroups_enabled
Definition Main.vala:182
string mount_point_app
Definition Main.vala:82
string mount_path
bool is_system_subvolume
bool dir_exists(string dir_path)
void log_error(string message, bool highlight=false, bool is_warning=false)
void log_msg(string message, bool highlight=false)
int exec_sync(string cmd, out string? std_out=null, out string? std_err=null)
void sleep(int milliseconds)

References _, App, Main.btrfs_qgroups_enabled, Main.btrfs_version__can_recursive_delete, TeeJee.FileSystem.dir_exists(), TeeJee.ProcessHelper.exec_sync(), is_system_subvolume, TeeJee.Logging.log_debug(), TeeJee.Logging.log_error(), TeeJee.Logging.log_msg(), mount_path, SnapshotRepo.mount_paths, Main.mount_point_app, name, path, TeeJee.FileSystem.path_combine(), repo, and TeeJee.System.sleep().

◆ restore()

bool Subvolume.restore ( )
inline

Definition at line 239 of file Subvolume.vala.

239 {
240
241 if (is_system_subvolume) { return false; }
242
243 // restore snapshot subvolume by creating new subvolume snapshots ----------------------
244
245 string src_path = path;
246 string dst_path = path_combine(mount_path, name);
247
248 if (!dir_exists(src_path)){
249 log_error("%s: %s".printf(_("Not Found"), src_path));
250 return false;
251 }
252
253 if (dir_exists(dst_path)){
254 log_error("%s: %s".printf(_("Subvolume exists at destination"), dst_path));
255 return false;
256 }
257
258 string cmd = "btrfs subvolume snapshot '%s' '%s'".printf(src_path, dst_path);
259 log_debug(cmd);
260
261 string std_out, std_err;
262 int status = exec_sync(cmd, out std_out, out std_err);
263
264 if (status != 0){
265 log_error(std_err);
266 log_error(_("btrfs returned an error") + ": %d".printf(status));
267 log_error(_("Failed to restore system subvolume") + ": %s".printf(name));
268 return false;
269 }
270
271 log_msg(_("Restored system subvolume") + ": %s".printf(name));
272
273 return true;
274 }

References _, TeeJee.FileSystem.dir_exists(), TeeJee.ProcessHelper.exec_sync(), is_system_subvolume, TeeJee.Logging.log_debug(), TeeJee.Logging.log_error(), TeeJee.Logging.log_msg(), mount_path, name, path, and TeeJee.FileSystem.path_combine().

Member Data Documentation

◆ device_uuid

string Subvolume.device_uuid

Definition at line 34 of file Subvolume.vala.

Referenced by get_device(), and print_info().

◆ id

long Subvolume.id = -1

Definition at line 37 of file Subvolume.vala.

◆ mount_path

string Subvolume.mount_path = ""

Definition at line 41 of file Subvolume.vala.

Referenced by remove(), and restore().

◆ name

string Subvolume.name = ""

Definition at line 35 of file Subvolume.vala.

Referenced by print_info(), remove(), restore(), and Subvolume().

◆ path

string Subvolume.path = ""

Definition at line 36 of file Subvolume.vala.

Referenced by print_info(), remove(), restore(), and Subvolume().

◆ repo

SnapshotRepo? Subvolume.repo

Definition at line 44 of file Subvolume.vala.

Referenced by detect_subvolumes_for_system_by_path(), remove(), and Subvolume().

◆ total_bytes

int64 Subvolume.total_bytes = 0

Definition at line 38 of file Subvolume.vala.

◆ unshared_bytes

int64 Subvolume.unshared_bytes = 0

Definition at line 39 of file Subvolume.vala.

Property Documentation

◆ exists_on_disk

bool Subvolume.exists_on_disk
get

Definition at line 75 of file Subvolume.vala.

75 {
76 get {
77 return dir_exists(path);
78 }
79 }

◆ is_system_subvolume

bool Subvolume.is_system_subvolume
get

Definition at line 81 of file Subvolume.vala.

81 {
82 get {
83 return (repo == null);
84 }
85 }

Referenced by remove(), and restore().

◆ total_formatted

string Subvolume.total_formatted
get

Definition at line 58 of file Subvolume.vala.

58 {
59 owned get{
61 }
62 }
int64 total_bytes
string format_file_size(uint64 size, bool binary_units=false, string unit="", bool show_units=true, int decimals=1)

◆ unshared_formatted

string Subvolume.unshared_formatted
get

Definition at line 64 of file Subvolume.vala.

64 {
65 owned get{
67 }
68 }
int64 unshared_bytes

The documentation for this class was generated from the following file: