Skip to content
API Documentation
BastionGuard™
TeeJee.ProcessHelper Namespace Reference

Functions

static void init_tmp ()
int exec_sync (string cmd, out string? std_out=null, out string? std_err=null)
int exec_script_sync (string script, out string? std_out=null, out string? std_err=null, bool supress_errors=false, bool run_as_admin=false, bool cleanup_tmp=true, bool print_to_terminal=false)
int exec_script_async (string script)
static int exec_user_async (string command)
string? save_bash_script_temp (string commands, string? script_path=null, bool force_locale=true, bool supress_errors=false)
string get_temp_file_path ()
static bool cmd_exists (string cmd_tool)
string get_process_exe_name (long pid=-1)
Pid get_process_parent (Pid process=-1)
int get_euid_of_process (Pid process)
Pid get_user_process ()
string?[] get_process_env (Pid pid)
string? get_env (string[] env, string name, string? default_value=null)
Pid[] get_process_children (Pid parent_pid)
void process_quit (Pid process_pid, bool killChildren=true)
void process_kill (Pid process_pid, bool killChildren=true)
void process_send_signal (Pid process_pid, Posix.Signal sig, bool children=true)
void process_set_priority (Pid procID, int prio)
int process_get_priority (Pid procID)
void process_set_priority_normal (Pid procID)
void process_set_priority_low (Pid procID)

Variables

string TEMP_DIR

Function Documentation

◆ cmd_exists()

bool TeeJee.ProcessHelper.cmd_exists ( string cmd_tool)
static

Definition at line 283 of file TeeJee.Process.vala.

283 {
284 string? path = Environment.find_program_in_path(cmd_tool);
285 return (path != null) && (path.length > 0);
286 }

References cmd_exists().

Referenced by cmd_exists(), and TeeJee.System.exo_open_folder().

◆ exec_script_async()

int TeeJee.ProcessHelper.exec_script_async ( string script)

Definition at line 171 of file TeeJee.Process.vala.

171 {
172
173 /* Executes commands synchronously.
174 * Pipes and multiple commands are fully supported.
175 * Commands are written to a temporary bash script and executed.
176 * Return value indicates if script was started successfully.
177 * */
178
179 try {
180
181 string scriptfile = save_bash_script_temp (script);
182
183 string[] argv = new string[1];
184 argv[0] = scriptfile;
185
186 string[] env = Environ.get();
187
188 Pid child_pid;
189 Process.spawn_async_with_pipes(
190 TEMP_DIR, //working dir
191 argv, //argv
192 env, //environment
193 SpawnFlags.SEARCH_PATH,
194 null,
195 out child_pid);
196
197 return 0;
198 }
199 catch (Error e){
200 log_error (e.message);
201 return 1;
202 }
203 }
void log_error(string message, bool highlight=false, bool is_warning=false)
string? save_bash_script_temp(string commands, string? script_path=null, bool force_locale=true, bool supress_errors=false)

References Error, exec_script_async(), TeeJee.Logging.log_error(), save_bash_script_temp(), and TEMP_DIR.

Referenced by exec_script_async(), and TeeJee.System.exo_open_folder().

◆ exec_script_sync()

int TeeJee.ProcessHelper.exec_script_sync ( string script,
out string? std_out = null,
out string? std_err = null,
bool supress_errors = false,
bool run_as_admin = false,
bool cleanup_tmp = true,
bool print_to_terminal = false )

Definition at line 84 of file TeeJee.Process.vala.

87 {
88
89 /* Executes commands synchronously.
90 * Pipes and multiple commands are fully supported.
91 * Commands are written to a temporary bash script and executed.
92 * std_out, std_err can be null. Output will be written to terminal if null.
93 * */
94
95 string? sh_file = save_bash_script_temp(script, null, true, supress_errors);
96 if (sh_file == null) {
97 // saving the script failed
98 return -1;
99 }
100
101 string sh_file_admin = "";
102
103 if (run_as_admin){
104
105 var script_admin = "#!/usr/bin/env bash\n";
106 script_admin += "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY";
107 script_admin += " '%s'".printf(escape_single_quote(sh_file));
108
109 sh_file_admin = GLib.Path.build_filename(file_parent(sh_file),"script-admin.sh");
110
111 save_bash_script_temp(script_admin, sh_file_admin, true, supress_errors);
112 }
113
114 try {
115 string[] argv = new string[1];
116 if (run_as_admin){
117 argv[0] = sh_file_admin;
118 }
119 else{
120 argv[0] = sh_file;
121 }
122
123 string[] env = Environ.get();
124
125 int exit_code;
126
127 if (print_to_terminal){
128
129 Process.spawn_sync (
130 TEMP_DIR, //working dir
131 argv, //argv
132 env, //environment
133 SpawnFlags.SEARCH_PATH,
134 null, // child_setup
135 null,
136 null,
137 out exit_code
138 );
139 }
140 else{
141
142 Process.spawn_sync (
143 TEMP_DIR, //working dir
144 argv, //argv
145 env, //environment
146 SpawnFlags.SEARCH_PATH,
147 null, // child_setup
148 out std_out,
149 out std_err,
150 out exit_code
151 );
152 }
153
154 if (cleanup_tmp){
155 file_delete(sh_file);
156 if (run_as_admin){
157 file_delete(sh_file_admin);
158 }
159 }
160
161 return exit_code;
162 }
163 catch (Error e){
164 if (!supress_errors){
165 log_error (e.message);
166 }
167 return -1;
168 }
169 }
string escape_single_quote(string file_path)
string file_parent(string file_path)
bool file_delete(string file_path)

References Error, TeeJee.FileSystem.escape_single_quote(), exec_script_sync(), TeeJee.FileSystem.file_delete(), TeeJee.FileSystem.file_parent(), TeeJee.Logging.log_error(), save_bash_script_temp(), and TEMP_DIR.

Referenced by Main.check_and_repair_filesystems(), exec_script_sync(), Device.get_block_devices_using_blkid(), init_tmp(), Device.luks_lock(), Device.luks_unlock(), Main.restore_current_console(), Main.restore_execute_btrfs(), Main.restore_other_console(), Main.restore_other_gui(), Main.run_post_backup_hooks(), and Device.unmount().

◆ exec_sync()

int TeeJee.ProcessHelper.exec_sync ( string cmd,
out string? std_out = null,
out string? std_err = null )

Definition at line 67 of file TeeJee.Process.vala.

67 {
68
69 /* Executes single command synchronously.
70 * Pipes and multiple commands are not supported.
71 * std_out, std_err can be null. Output will be written to terminal if null. */
72
73 try {
74 int status;
75 Process.spawn_command_line_sync(cmd, out std_out, out std_err, out status);
76 return status;
77 }
78 catch (Error e){
79 log_error (e.message);
80 return -1;
81 }
82 }

References Error, exec_sync(), and TeeJee.Logging.log_error().

Referenced by CronTab.add_job(), Device.automount_udisks_iso(), SnapshotRepo.build_synthetic_device_for_path(), Main.check_and_remove_timeshift_btrfs(), Main.cleanup_unmount_devices(), Main.create_pre_restore_snapshot_btrfs(), Main.create_snapshot_with_btrfs(), CronTab.crontab_read_all(), exec_sync(), TeeJee.FileSystem.file_gzip(), Device.find_child_devices_using_dmsetup(), Device.get_block_devices_using_lsblk(), Device.get_disk_space_using_df(), CronTab.install(), Device.mount(), SmbMount.mount(), Main.query_subvolume_id(), Main.query_subvolume_quota(), Subvolume.remove(), CronTab.remove_job(), Subvolume.restore(), and Device.test_lsblk_version().

◆ exec_user_async()

int TeeJee.ProcessHelper.exec_user_async ( string command)
static

executes a command as the "normal" unprivileged user async may execute the command as root if the user could not be determined or the name could not be resolved

Definition at line 209 of file TeeJee.Process.vala.

209 {
210 // find correct user
211 int uid = TeeJee.System.get_user_id();
212 string cmd = command;
213 if(uid > 0) {
214 // non root
215 string? user = TeeJee.System.get_username_from_uid(uid);
216 if(user != null) {
217 cmd = "pkexec --user %s env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS ".printf(user) + cmd;
218 }
219 }
220
221 log_debug(cmd);
222 return TeeJee.ProcessHelper.exec_script_async(cmd);
223 }
void log_debug(string message)

References exec_user_async(), and TeeJee.Logging.log_debug().

Referenced by exec_user_async(), and TeeJee.System.xdg_open().

◆ get_env()

string? TeeJee.ProcessHelper.get_env ( string[] env,
string name,
string? default_value = null )

Definition at line 356 of file TeeJee.Process.vala.

356 {
357 foreach(string env_var in env) {
358 string[] splitted = env_var.split("=", 2);
359 if(splitted[0] == name) {
360 if (splitted.length == 2) {
361 return splitted[1];
362 }
363 }
364 }
365 return default_value;
366 }

References get_env().

Referenced by get_env().

◆ get_euid_of_process()

int TeeJee.ProcessHelper.get_euid_of_process ( Pid process)

Definition at line 320 of file TeeJee.Process.vala.

320 {
321 GLib.File file = GLib.File.new_for_path("/proc/%d".printf(process));
322 try {
323 GLib.FileInfo info = file.query_info(FileAttribute.UNIX_UID, GLib.FileQueryInfoFlags.NONE);
324 return (int) info.get_attribute_uint32(FileAttribute.UNIX_UID);
325 } catch(GLib.Error e) {
326 log_debug("failed to fetch user of process %i %s".printf(process, e.message));
327 }
328 return -1;
329 }

References get_euid_of_process(), and TeeJee.Logging.log_debug().

Referenced by get_euid_of_process(), and get_user_process().

◆ get_process_children()

Pid[] TeeJee.ProcessHelper.get_process_children ( Pid parent_pid)

Definition at line 368 of file TeeJee.Process.vala.

368 {
369
370 /* Returns the list of child processes owned by a given process */
371
372 // no explicit check for the existence of /proc/ as this might be a time-of-check-time-of-use bug.
373 File procfs = File.new_for_path("/proc/");
374
375 try {
376 FileEnumerator enumerator = procfs.enumerate_children(FileAttribute.STANDARD_NAME, FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
377 FileInfo info;
378 Pid[] childList = {};
379 while ((info = enumerator.next_file()) != null) {
380 if(info.get_file_type() != FileType.DIRECTORY) {
381 // only interested in directories
382 continue;
383 }
384
385 string name = info.get_name();
386
387 uint64 pid;
388 if(!uint64.try_parse(name, out pid)) {
389 // make sure to not access any other directories that may be present in /proc for some reason
390 continue;
391 }
392
393 string? fileCont = file_read("/proc/%s/stat".printf(name));
394 if(fileCont == null) {
395 // stat file of pid might not be readable (because of permissions or the process died since we got its pid)
396 continue;
397 }
398
399 // the format of the stat file is documented in man 5 proc
400 // it begging is: pid (comm) status ppid ...
401
402 // the process name could contain a space or ) and confuse the parsing.
403 // so we make sure to take the last ) and only parse the stuff after that.
404 int index = fileCont.last_index_of_char(')');
405 string parseline = fileCont.substring(index);
406 string[] split = parseline.split(" ", 4); // we are not interested in the part after ppid so just leave it a big string
407 if(split.length != 4) {
408 // format of stat file is not matching - should never happen
409 log_error("can not parse state of %ld".printf((long) pid));
410 continue;
411 }
412
413 uint64 ppid = uint64.parse(split[2]);
414 if(ppid != 0 && ppid == parent_pid) {
415 // the process is a child of the target parent process
416 childList += (Pid) pid;
417 }
418 }
419 return childList;
420 } catch (Error e) {
421 log_error(e.message);
422 log_error("Failed to get child processes of %ld".printf(parent_pid));
423 }
424 return {};
425 }
string? file_read(string file_path)

References Error, TeeJee.FileSystem.file_read(), get_process_children(), and TeeJee.Logging.log_error().

Referenced by get_process_children(), and process_send_signal().

◆ get_process_env()

string?[] TeeJee.ProcessHelper.get_process_env ( Pid pid)

Definition at line 348 of file TeeJee.Process.vala.

348 {
349 if(pid < 1) {
350 return null;
351 }
352 return file_read_array("/proc/%i/environ".printf(pid), '\0');
353 }
string?[] file_read_array(string file_path, char delimiter='\n')

References TeeJee.FileSystem.file_read_array(), and get_process_env().

Referenced by get_process_env().

◆ get_process_exe_name()

string TeeJee.ProcessHelper.get_process_exe_name ( long pid = -1)

Definition at line 290 of file TeeJee.Process.vala.

290 {
291 string pidStr = (pid <= 0 ? "self" : pid.to_string());
292 string path = "/proc/%s/exe".printf(pidStr);
293 string link;
294 try {
295 link = GLib.FileUtils.read_link(path);
296 } catch (Error e) {
297 return "";
298 }
299
300 return GLib.Path.get_basename(link);
301 }

References Error, and get_process_exe_name().

Referenced by AppLock.create(), and get_process_exe_name().

◆ get_process_parent()

Pid TeeJee.ProcessHelper.get_process_parent ( Pid process = -1)

Definition at line 304 of file TeeJee.Process.vala.

304 {
305 string pidStr = (process <= 0 ? "self" : process.to_string());
306 string path = "/proc/%s/stat".printf(pidStr);
307 string stats = file_read(path);
308 string details = stats.split(")", 2)[1];
309 string[] splitted = details.split(" ", 3);
310 if(splitted.length == 3) {
311 return int.parse(splitted[2]);
312 }
313
314 log_debug("can not parse process stat %s".printf(stats));
315 return -1;
316 }

References TeeJee.FileSystem.file_read(), get_process_parent(), and TeeJee.Logging.log_debug().

Referenced by get_process_parent(), and get_user_process().

◆ get_temp_file_path()

string TeeJee.ProcessHelper.get_temp_file_path ( )

Definition at line 274 of file TeeJee.Process.vala.

274 {
275
276 /* Generates temporary file path */
277
278 return TEMP_DIR + "/" + timestamp_numeric() + (new Rand()).next_int().to_string();
279 }
string timestamp_numeric()

References get_temp_file_path(), TEMP_DIR, and TeeJee.Misc.timestamp_numeric().

Referenced by CronTab.add_job(), get_temp_file_path(), CronTab.remove_job(), and save_bash_script_temp().

◆ get_user_process()

Pid TeeJee.ProcessHelper.get_user_process ( )

Definition at line 332 of file TeeJee.Process.vala.

332 {
333 Pid ppid = -1;
334 int targetUser = TeeJee.System.get_user_id();
335 int user = 0;
336
337 do {
338 ppid = get_process_parent(ppid);
339 user = get_euid_of_process (ppid);
340 } while(user != targetUser && ppid > 1);
341 if(user == targetUser) {
342 return ppid;
343 }
344 return -1;
345 }
Pid get_process_parent(Pid process=-1)
int get_euid_of_process(Pid process)

References get_euid_of_process(), get_process_parent(), and get_user_process().

Referenced by get_user_process().

◆ init_tmp()

void TeeJee.ProcessHelper.init_tmp ( )
static

Definition at line 37 of file TeeJee.Process.vala.

37 {
38
39 // a list of folders where temp files could be stored
40 string[] tempPlaces = {
41 Environment.get_tmp_dir(), // system temp dir
42 "/var/tmp", // another system temp dir, if the first one failed, this one is likely to fail too
43 Environment.get_home_dir() + "/.temp", // user temp dir
44 "/dev/shm", // shared memory
45 };
46
47 foreach (string tempPlace in tempPlaces) {
48 string std_out, std_err;
49
50 TEMP_DIR = tempPlace + "/bastionguard-backup-" + random_string();
51 dir_create(TEMP_DIR);
52 Posix.chmod(TEMP_DIR, 0750);
53 exec_script_sync("echo 'ok'",out std_out,out std_err, true);
54
55 if ((std_out == null) || (std_out.strip() != "ok")){
56 // this dir does not work for some reason - probably no disk space
57 dir_delete(TEMP_DIR);
58 } else {
59 // script worked - we have found a tempdir to use
60 return;
61 }
62 }
63
64 stderr.printf("No usable temp directory was found!\n");
65 }
bool dir_create(string dir_path, bool show_message=false)
string random_string(int length=8, string charset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")
int exec_script_sync(string script, out string? std_out=null, out string? std_err=null, bool supress_errors=false, bool run_as_admin=false, bool cleanup_tmp=true, bool print_to_terminal=false)

References TeeJee.FileSystem.dir_create(), TeeJee.FileSystem.dir_delete(), exec_script_sync(), init_tmp(), TeeJee.Misc.random_string(), and TEMP_DIR.

Referenced by init_tmp().

◆ process_get_priority()

int TeeJee.ProcessHelper.process_get_priority ( Pid procID)

Definition at line 473 of file TeeJee.Process.vala.

473 {
474
475 /* Get process priority */
476
477 return Posix.getpriority (Posix.PRIO_PROCESS, procID);
478 }

References process_get_priority().

Referenced by process_get_priority().

◆ process_kill()

void TeeJee.ProcessHelper.process_kill ( Pid process_pid,
bool killChildren = true )

Definition at line 438 of file TeeJee.Process.vala.

438 {
439
440 /* Kills specified process and its children (optional).
441 * Sends signal SIGKILL to the process to kill it forcefully.
442 * It is recommended to use the function process_quit() instead.
443 * */
444
445 process_send_signal(process_pid, Posix.Signal.KILL, killChildren);
446 }
void process_send_signal(Pid process_pid, Posix.Signal sig, bool children=true)

References process_kill(), and process_send_signal().

Referenced by process_kill().

◆ process_quit()

void TeeJee.ProcessHelper.process_quit ( Pid process_pid,
bool killChildren = true )

Definition at line 429 of file TeeJee.Process.vala.

429 {
430
431 /* Terminates specified process and its children (optional).
432 * Sends signal SIGTERM to the process to allow it to quit gracefully.
433 * */
434
435 process_send_signal(process_pid, Posix.Signal.TERM, killChildren);
436 }

References process_quit(), and process_send_signal().

Referenced by process_quit(), and AsyncTask.stop().

◆ process_send_signal()

void TeeJee.ProcessHelper.process_send_signal ( Pid process_pid,
Posix.Signal sig,
bool children = true )

Definition at line 448 of file TeeJee.Process.vala.

448 {
449
450 /* Sends a signal to a process and its children (optional). */
451
452 // get the childs before sending the signal, as the childs might not be accessible afterwards
453 Pid[] child_pids = get_process_children (process_pid);
454 Posix.kill (process_pid, sig);
455
456 if (children){
457 foreach (Pid pid in child_pids){
458 Posix.kill (pid, sig);
459 }
460 }
461 }
Pid[] get_process_children(Pid parent_pid)

References get_process_children(), and process_send_signal().

Referenced by process_kill(), process_quit(), and process_send_signal().

◆ process_set_priority()

void TeeJee.ProcessHelper.process_set_priority ( Pid procID,
int prio )

Definition at line 465 of file TeeJee.Process.vala.

465 {
466
467 /* Set process priority */
468
469 if (Posix.getpriority (Posix.PRIO_PROCESS, procID) != prio)
470 Posix.setpriority (Posix.PRIO_PROCESS, procID, prio);
471 }

References process_set_priority().

Referenced by process_set_priority(), process_set_priority_low(), and process_set_priority_normal().

◆ process_set_priority_low()

void TeeJee.ProcessHelper.process_set_priority_low ( Pid procID)

Definition at line 487 of file TeeJee.Process.vala.

487 {
488
489 /* Set low priority for process */
490
491 process_set_priority (procID, 5);
492 }
void process_set_priority(Pid procID, int prio)

References process_set_priority(), and process_set_priority_low().

Referenced by process_set_priority_low().

◆ process_set_priority_normal()

void TeeJee.ProcessHelper.process_set_priority_normal ( Pid procID)

Definition at line 480 of file TeeJee.Process.vala.

480 {
481
482 /* Set normal priority for process */
483
484 process_set_priority (procID, 0);
485 }

References process_set_priority(), and process_set_priority_normal().

Referenced by process_set_priority_normal().

◆ save_bash_script_temp()

string? TeeJee.ProcessHelper.save_bash_script_temp ( string commands,
string? script_path = null,
bool force_locale = true,
bool supress_errors = false )

Definition at line 225 of file TeeJee.Process.vala.

226 {
227
228 string sh_path = script_path;
229
230 /* Creates a temporary bash script with given commands
231 * Returns the script file path */
232
233 var script = new StringBuilder();
234 script.append ("#!/usr/bin/env bash\n");
235 script.append ("\n");
236 if (force_locale){
237 script.append("LANG=C\n");
238 script.append("LC_ALL=C.UTF-8\n");
239 }
240 script.append ("\n");
241 script.append ("%s\n".printf(commands));
242 script.append ("\n\nexitCode=$?\n");
243 script.append ("echo ${exitCode} > status\n");
244
245 if ((sh_path == null) || (sh_path.length == 0)){
246 sh_path = get_temp_file_path();
247 }
248
249 try{
250 //write script file
251 var file = File.new_for_path (sh_path);
252 if (file.query_exists ()) {
253 file.delete ();
254 }
255 var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION);
256 var data_stream = new DataOutputStream (file_stream);
257 data_stream.put_string (script.str);
258 data_stream.close();
259
260 // set execute permission
261 Posix.chmod (sh_path, 0744);
262
263 return sh_path;
264 }
265 catch (Error e) {
266 if (!supress_errors){
267 log_error (e.message);
268 }
269 }
270
271 return null;
272 }

References Error, get_temp_file_path(), TeeJee.Logging.log_error(), and save_bash_script_temp().

Referenced by exec_script_async(), exec_script_sync(), AsyncTask.prepare(), Main.restore_current_gui(), and save_bash_script_temp().

Variable Documentation

◆ TEMP_DIR