2 use lazy_static
::lazy_static
;
6 use std
::sync
::atomic
::{AtomicUsize, Ordering}
;
8 use proxmox
::sys
::linux
::procfs
;
10 /// Unique Process/Task Identifier
12 /// We use this to uniquely identify worker task. UPIDs have a short
13 /// string repesentaion, which gives additional information about the
14 /// type of the task. for example:
16 /// UPID:{node}:{pid}:{pstart}:{task_id}:{starttime}:{worker_type}:{worker_id}:{username}:
17 /// UPID:elsa:00004F37:0039E469:00000000:5CA78B83:garbage_collection::root@pam:
19 /// Please note that we use tokio, so a single thread can run multiple
21 #[derive(Debug, Clone)]
25 /// The Unix process start time from `/proc/pid/stat`
27 /// The task start time (Epoch)
29 /// The task ID (inside the process/thread)
31 /// Worker type (arbitrary ASCII string)
32 pub worker_type
: String
,
33 /// Worker ID (arbitrary ASCII string)
34 pub worker_id
: Option
<String
>,
35 /// The user who started the task
44 pub fn new(worker_type
: &str, worker_id
: Option
<String
>, username
: &str) -> Result
<Self, Error
> {
46 let pid
= unsafe { libc::getpid() }
;
48 let bad
: &[_
] = &['
/'
, '
:'
, ' '
];
50 if worker_type
.contains(bad
) {
51 bail
!("illegal characters in worker type '{}'", worker_type
);
53 if let Some(ref worker_id
) = worker_id
{
54 if worker_id
.contains(bad
) {
55 bail
!("illegal characters in worker id '{}'", worker_id
);
59 static WORKER_TASK_NEXT_ID
: AtomicUsize
= AtomicUsize
::new(0);
61 let task_id
= WORKER_TASK_NEXT_ID
.fetch_add(1, Ordering
::SeqCst
);
65 pstart
: procfs
::PidStat
::read_from_pid(nix
::unistd
::Pid
::from_raw(pid
))?
.starttime
,
66 starttime
: Local
::now().timestamp(),
68 worker_type
: worker_type
.to_owned(),
70 username
: username
.to_owned(),
71 node
: proxmox
::tools
::nodename().to_owned(),
75 /// Returns the absolute path to the task log file
76 pub fn log_path(&self) -> std
::path
::PathBuf
{
77 let mut path
= std
::path
::PathBuf
::from(super::PROXMOX_BACKUP_TASK_DIR
);
78 path
.push(format
!("{:02X}", self.pstart
% 256));
79 path
.push(self.to_string());
85 impl std
::str::FromStr
for UPID
{
88 fn from_str(s
: &str) -> Result
<Self, Self::Err
> {
91 static ref REGEX
: Regex
= Regex
::new(concat
!(
92 r
"^UPID:(?P<node>[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?):(?P<pid>[0-9A-Fa-f]{8}):",
93 r
"(?P<pstart>[0-9A-Fa-f]{8,9}):(?P<task_id>[0-9A-Fa-f]{8,16}):(?P<starttime>[0-9A-Fa-f]{8}):",
94 r
"(?P<wtype>[^:\s]+):(?P<wid>[^:\s]*):(?P<username>[^:\s]+):$"
98 if let Some(cap
) = REGEX
.captures(s
) {
101 pid
: i32::from_str_radix(&cap
["pid"], 16).unwrap(),
102 pstart
: u64::from_str_radix(&cap
["pstart"], 16).unwrap(),
103 starttime
: i64::from_str_radix(&cap
["starttime"], 16).unwrap(),
104 task_id
: usize::from_str_radix(&cap
["task_id"], 16).unwrap(),
105 worker_type
: cap
["wtype"].to_string(),
106 worker_id
: if cap
["wid"].is_empty() { None }
else { Some(cap["wid"].to_string()) }
,
107 username
: cap
["username"].to_string(),
108 node
: cap
["node"].to_string(),
111 bail
!("unable to parse UPID '{}'", s
);
117 impl std
::fmt
::Display
for UPID
{
119 fn fmt(&self, f
: &mut std
::fmt
::Formatter
) -> std
::fmt
::Result
{
121 let wid
= if let Some(ref id
) = self.worker_id { id }
else { "" }
;
123 // Note: pstart can be > 32bit if uptime > 497 days, so this can result in
124 // more that 8 characters for pstart
126 write
!(f
, "UPID:{}:{:08X}:{:08X}:{:08X}:{:08X}:{}:{}:{}:",
127 self.node
, self.pid
, self.pstart
, self.task_id
, self.starttime
, self.worker_type
, wid
, self.username
)