]> git.proxmox.com Git - pve-xtermjs.git/blame - termproxy/src/cli.rs
termproxy: split out CLI stuff to own module
[pve-xtermjs.git] / termproxy / src / cli.rs
CommitLineData
7801b96c
TL
1use std::ffi::OsString;
2use std::os::fd::RawFd;
3
4use anyhow::{bail, Result};
5
6const CMD_HELP: &str = "\
7Usage: proxmox-termproxy [OPTIONS] --path <path> <listen-port> -- <terminal-cmd>...
8
9Arguments:
10 <listen-port> Port or file descriptor to listen for TCP connections
11 <terminal-cmd>... The command to run connected via a proxied PTY
12
13Options:
14 --authport <authport> Port to relay auth-request, default 85
15 --port-as-fd Use <listen-port> as file descriptor.
16 --path <path> ACL object path to test <perm> on.
17 --perm <perm> Permission to test.
18 -h, --help Print help
19";
20
21#[derive(Debug)]
22pub enum PortOrFd {
23 Port(u16),
24 Fd(RawFd),
25}
26
27impl PortOrFd {
28 fn from_cli(value: u64, use_as_fd: bool) -> Result<PortOrFd> {
29 if use_as_fd {
30 if value > RawFd::MAX as u64 {
31 bail!("FD value too big");
32 }
33 Ok(Self::Fd(value as RawFd))
34 } else {
35 if value > u16::MAX as u64 {
36 bail!("invalid port number");
37 }
38 Ok(Self::Port(value as u16))
39 }
40 }
41}
42
43#[derive(Debug)]
44pub struct Options {
45 /// The actual command to run proxied in a pseudo terminal.
46 pub terminal_command: Vec<OsString>,
47 /// The port or FD that termproxy will listen on for an incoming conection
48 pub listen_port: PortOrFd,
49 /// The port of the local privileged daemon that authentication is relayed to. Defaults to `85`
50 pub api_daemon_port: u16,
51 /// The ACL object path the 'acl_permission' is checked on
52 pub acl_path: String,
53 /// The ACL permission that the ticket, read from the stream, is required to have on 'acl_path'
54 pub acl_permission: Option<String>,
55}
56
57impl Options {
58 pub fn from_env() -> Result<Self> {
59 let mut args: Vec<_> = std::env::args_os().collect();
60 args.remove(0); // remove the executable path.
61
62 // handle finding command after `--` first so that we only parse our options later
63 let terminal_command = if let Some(dash_dash) = args.iter().position(|arg| arg == "--") {
64 let later_args = args.drain(dash_dash + 1..).collect();
65 args.pop(); // .. then remove the `--`
66 Some(later_args)
67 } else {
68 None
69 };
70
71 // Now pass the remaining arguments through to `pico_args`.
72 let mut args = pico_args::Arguments::from_vec(args);
73
74 if args.contains(["-h", "--help"]) {
75 print!("{CMD_HELP}");
76 std::process::exit(0);
77 } else if terminal_command.is_none() {
78 bail!("missing terminal command or -- option-end marker, see '-h' for usage");
79 }
80
81 let options = Self {
82 terminal_command: terminal_command.unwrap(), // checked above
83 listen_port: PortOrFd::from_cli(args.free_from_str()?, args.contains("--port-as-fd"))?,
84 api_daemon_port: args.opt_value_from_str("--authport")?.unwrap_or(85),
85 acl_path: args.value_from_str("--path")?,
86 acl_permission: args.opt_value_from_str("--perm")?,
87 };
88
89 if !args.finish().is_empty() {
90 bail!("unexpected extra arguments, use '-h' for usage");
91 }
92
93 Ok(options)
94 }
95
96 pub fn use_listen_port_as_fd(&self) -> bool {
97 match self.listen_port {
98 PortOrFd::Fd(_) => true,
99 _ => false,
100 }
101 }
102}