jay_config/exec.rs
1//! Tools for spawning programs.
2
3use std::{cell::RefCell, collections::HashMap, os::fd::OwnedFd};
4
5/// Sets an environment variable.
6///
7/// This does not affect the compositor itself but only programs spawned by the compositor.
8pub fn set_env(key: &str, val: &str) {
9 get!().set_env(key, val);
10}
11
12/// Unsets an environment variable.
13///
14/// This does not affect the compositor itself but only programs spawned by the compositor.
15pub fn unset_env(key: &str) {
16 get!().unset_env(key);
17}
18
19/// A command to be spawned.
20pub struct Command {
21 pub(crate) prog: String,
22 pub(crate) args: Vec<String>,
23 pub(crate) env: HashMap<String, String>,
24 pub(crate) fds: RefCell<HashMap<i32, OwnedFd>>,
25}
26
27impl Command {
28 /// Creates a new command to be spawned.
29 ///
30 /// `prog` should be the path to the program being spawned. If `prog` does not contain
31 /// a `/`, then it will be searched in `PATH` similar to how a shell would do it.
32 ///
33 /// The first argument passed to `prog`, `argv[0]`, is `prog` itself.
34 pub fn new(prog: &str) -> Self {
35 Self {
36 prog: prog.to_string(),
37 args: vec![],
38 env: Default::default(),
39 fds: Default::default(),
40 }
41 }
42
43 /// Adds an argument to be passed to the command.
44 pub fn arg(&mut self, arg: &str) -> &mut Self {
45 self.args.push(arg.to_string());
46 self
47 }
48
49 /// Sets an environment variable for this command only.
50 pub fn env(&mut self, key: &str, val: &str) -> &mut Self {
51 self.env.insert(key.to_string(), val.to_string());
52 self
53 }
54
55 /// Sets a file descriptor of the process.
56 ///
57 /// By default, the process starts with exactly stdin, stdout, and stderr open and all
58 /// pointing to `/dev/null`.
59 pub fn fd<F: Into<OwnedFd>>(&mut self, idx: i32, fd: F) -> &mut Self {
60 self.fds.borrow_mut().insert(idx, fd.into());
61 self
62 }
63
64 /// Sets the stdin of the process.
65 ///
66 /// This is equivalent to `fd(0, fd)`.
67 pub fn stdin<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
68 self.fd(0, fd)
69 }
70
71 /// Sets the stdout of the process.
72 ///
73 /// This is equivalent to `fd(1, fd)`.
74 pub fn stdout<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
75 self.fd(1, fd)
76 }
77
78 /// Sets the stderr of the process.
79 ///
80 /// This is equivalent to `fd(2, fd)`.
81 pub fn stderr<F: Into<OwnedFd>>(&mut self, fd: F) -> &mut Self {
82 self.fd(2, fd)
83 }
84
85 /// Runs the application with access to privileged wayland protocols.
86 ///
87 /// The default is `false`.
88 pub fn privileged(&mut self) -> &mut Self {
89 match get!(self).get_socket_path() {
90 Some(path) => {
91 self.env("WAYLAND_DISPLAY", &format!("{path}.jay"));
92 }
93 _ => {
94 log::error!("Compositor did not send the socket path");
95 }
96 }
97 self
98 }
99
100 /// Executes the command.
101 ///
102 /// This consumes all attached file descriptors.
103 pub fn spawn(&self) {
104 get!().spawn(self);
105 }
106}