rustpython_stdlib/
syslog.rs1pub(crate) use syslog::make_module;
4
5#[pymodule(name = "syslog")]
6mod syslog {
7 use crate::common::lock::PyRwLock;
8 use crate::vm::{
9 builtins::{PyStr, PyStrRef},
10 function::{OptionalArg, OptionalOption},
11 utils::ToCString,
12 PyObjectRef, PyPayload, PyResult, VirtualMachine,
13 };
14 use std::{ffi::CStr, os::raw::c_char};
15
16 #[pyattr]
17 use libc::{
18 LOG_ALERT, LOG_AUTH, LOG_CONS, LOG_CRIT, LOG_DAEMON, LOG_DEBUG, LOG_EMERG, LOG_ERR,
19 LOG_INFO, LOG_KERN, LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5,
20 LOG_LOCAL6, LOG_LOCAL7, LOG_LPR, LOG_MAIL, LOG_NDELAY, LOG_NEWS, LOG_NOTICE, LOG_NOWAIT,
21 LOG_ODELAY, LOG_PID, LOG_SYSLOG, LOG_USER, LOG_UUCP, LOG_WARNING,
22 };
23
24 #[cfg(not(target_os = "redox"))]
25 #[pyattr]
26 use libc::{LOG_AUTHPRIV, LOG_CRON, LOG_PERROR};
27
28 fn get_argv(vm: &VirtualMachine) -> Option<PyStrRef> {
29 if let Some(argv) = vm.state.settings.argv.first() {
30 if !argv.is_empty() {
31 return Some(
32 PyStr::from(match argv.find('\\') {
33 Some(value) => &argv[value..],
34 None => argv,
35 })
36 .into_ref(&vm.ctx),
37 );
38 }
39 }
40 None
41 }
42
43 #[derive(Debug)]
44 enum GlobalIdent {
45 Explicit(Box<CStr>),
46 Implicit,
47 }
48
49 impl GlobalIdent {
50 fn as_ptr(&self) -> *const c_char {
51 match self {
52 GlobalIdent::Explicit(ref cstr) => cstr.as_ptr(),
53 GlobalIdent::Implicit => std::ptr::null(),
54 }
55 }
56 }
57
58 fn global_ident() -> &'static PyRwLock<Option<GlobalIdent>> {
59 rustpython_common::static_cell! {
60 static IDENT: PyRwLock<Option<GlobalIdent>>;
61 };
62 IDENT.get_or_init(|| PyRwLock::new(None))
63 }
64
65 #[derive(Default, FromArgs)]
66 struct OpenLogArgs {
67 #[pyarg(any, optional)]
68 ident: OptionalOption<PyStrRef>,
69 #[pyarg(any, optional)]
70 logoption: OptionalArg<i32>,
71 #[pyarg(any, optional)]
72 facility: OptionalArg<i32>,
73 }
74
75 #[pyfunction]
76 fn openlog(args: OpenLogArgs, vm: &VirtualMachine) -> PyResult<()> {
77 let logoption = args.logoption.unwrap_or(0);
78 let facility = args.facility.unwrap_or(LOG_USER);
79 let ident = match args.ident.flatten() {
80 Some(args) => Some(args.to_cstring(vm)?),
81 None => get_argv(vm).map(|argv| argv.to_cstring(vm)).transpose()?,
82 }
83 .map(|ident| ident.into_boxed_c_str());
84
85 let ident = match ident {
86 Some(ident) => GlobalIdent::Explicit(ident),
87 None => GlobalIdent::Implicit,
88 };
89
90 {
91 let mut locked_ident = global_ident().write();
92 unsafe { libc::openlog(ident.as_ptr(), logoption, facility) };
93 *locked_ident = Some(ident);
94 }
95 Ok(())
96 }
97
98 #[derive(FromArgs)]
99 struct SysLogArgs {
100 #[pyarg(positional)]
101 priority: PyObjectRef,
102 #[pyarg(positional, optional)]
103 message_object: OptionalOption<PyStrRef>,
104 }
105
106 #[pyfunction]
107 fn syslog(args: SysLogArgs, vm: &VirtualMachine) -> PyResult<()> {
108 let (priority, msg) = match args.message_object.flatten() {
109 Some(s) => (args.priority.try_into_value(vm)?, s),
110 None => (LOG_INFO, args.priority.try_into_value(vm)?),
111 };
112
113 if global_ident().read().is_none() {
114 openlog(OpenLogArgs::default(), vm)?;
115 }
116
117 let (cformat, cmsg) = ("%s".to_cstring(vm)?, msg.to_cstring(vm)?);
118 unsafe { libc::syslog(priority, cformat.as_ptr(), cmsg.as_ptr()) };
119 Ok(())
120 }
121
122 #[pyfunction]
123 fn closelog() {
124 if global_ident().read().is_some() {
125 let mut locked_ident = global_ident().write();
126 unsafe { libc::closelog() };
127 *locked_ident = None;
128 }
129 }
130
131 #[pyfunction]
132 fn setlogmask(maskpri: i32) -> i32 {
133 unsafe { libc::setlogmask(maskpri) }
134 }
135
136 #[inline]
137 #[pyfunction(name = "LOG_MASK")]
138 fn log_mask(pri: i32) -> i32 {
139 pri << 1
140 }
141
142 #[inline]
143 #[pyfunction(name = "LOG_UPTO")]
144 fn log_upto(pri: i32) -> i32 {
145 (1 << (pri + 1)) - 1
146 }
147}