Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add syslog supports #2537

Merged
merged 26 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ resource = []
sched = ["process"]
signal = ["process"]
socket = ["memoffset"]
syslog = []
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
term = []
time = []
ucontext = ["signal"]
Expand All @@ -80,7 +81,7 @@ semver = "1.0.7"
nix = { path = ".", features = ["acct", "aio", "dir", "env", "event", "fanotify",
"feature", "fs", "hostname", "inotify", "ioctl", "kmod", "mman", "mount", "mqueue",
"net", "personality", "poll", "pthread", "ptrace", "quota", "process", "reboot",
"resource", "sched", "signal", "socket", "term", "time", "ucontext", "uio",
"resource", "sched", "signal", "socket", "syslog", "term", "time", "ucontext", "uio",
"user", "zerocopy"] }

[target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
Expand Down
1 change: 1 addition & 0 deletions changelog/2537.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for `syslog`, `openlog`, `closelog` on all `unix`.
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
//! * `sched` - Manipulate process's scheduling
//! * `socket` - Sockets, whether for networking or local use
//! * `signal` - Send and receive signals to processes
//! * `syslog` - System logging
//! * `term` - Terminal control APIs
//! * `time` - Query the operating system's clocks
//! * `ucontext` - User thread context
Expand Down Expand Up @@ -79,6 +80,7 @@
feature = "sched",
feature = "socket",
feature = "signal",
feature = "syslog",
feature = "term",
feature = "time",
feature = "ucontext",
Expand Down Expand Up @@ -200,6 +202,11 @@ feature! {
pub mod spawn;
}

feature! {
#![feature = "syslog"]
pub mod syslog;
}

use std::ffi::{CStr, CString, OsStr};
use std::mem::MaybeUninit;
use std::os::unix::ffi::OsStrExt;
Expand Down
178 changes: 178 additions & 0 deletions src/syslog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
//! Interfaces for controlling system log.

use crate::{NixPath, Result};
use std::ffi::{CStr, OsStr};
use std::ptr;

/// Logging options of subsequent [`syslog`] calls can be set by calling [`openlog`].
///
/// The parameter `ident` is a string that will be prepended to every message. The `logopt`
/// argument specifies logging options. The `facility` parameter encodes a default facility to be
/// assigned to all messages that do not have an explicit facility encoded.
pub fn openlog(
ident: Option<&'static CStr>,
logopt: LogFlags,
facility: Facility,
) -> Result<()> {
let ident = ident.map_or(ptr::null(), |ident| ident.as_ptr());
let logopt = logopt.bits();
let facility = facility as libc::c_int;
unsafe {
libc::openlog(ident, logopt, facility);
}
Ok(())
}

/// Writes message to the system message logger.
///
/// The message is then written to the system console, log files, logged-in users, or forwarded
/// to other machines as appropriate.
///
/// # Examples
///
/// ```rust
/// use nix::syslog::{openlog, syslog, Facility, LogFlags, Severity};
///
/// let flags = LogFlags::LOG_PID;
/// openlog(None, flags, Facility::LOG_USER).unwrap();
/// syslog(Severity::LOG_EMERG, "Hello, nix!").unwrap();
///
/// // use `format!` to format the message
/// let name = "syslog";
/// syslog(Severity::LOG_EMERG, &format!("Hello, {name}!")).unwrap();
/// ```
pub fn syslog<P, S>(priority: P, message: &S) -> Result<()>
where
P: Into<Priority>,
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
S: AsRef<OsStr> + ?Sized,
{
let priority = priority.into();
let formatter = OsStr::new("%s");
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
let message = OsStr::new(message);
formatter.with_nix_path(|formatter| {
message.with_nix_path(|message| unsafe {
libc::syslog(priority.0, formatter.as_ptr(), message.as_ptr())
})
})??;
Ok(())
}

/// Closes the log file.
pub fn closelog() {
unsafe { libc::closelog() }
}

/// The priority for a log message.
#[derive(Debug, Clone, Copy)]
pub struct Priority(libc::c_int);

impl Priority {
/// Create a new priority from a facility and severity level.
pub fn new(severity: Severity, facility: Facility) -> Self {
let priority = (facility as libc::c_int) | (severity as libc::c_int);
Priority(priority)
}
}

impl From<Severity> for Priority {
fn from(severity: Severity) -> Self {
let priority = severity as libc::c_int;
Priority(priority)
}
}

libc_bitflags! {
/// Options for system logging.
pub struct LogFlags: libc::c_int {
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
/// Log the process id with each message: useful for identifying instantiations of
/// daemons.
LOG_PID;
/// If syslog() cannot pass the message to syslogd(8) it will attempt to write the
/// message to the console ("/dev/console").
LOG_CONS;
/// The converse of [`LOG_NDELAY`][LogFlags::LOG_NDELAY]; opening of the connection is
/// delayed until `syslog` is called.
///
/// This is the default, and need not be specified.
LOG_ODELAY;
/// Open the connection to syslogd(8) immediately. Normally the open is delayed until
/// the first message is logged. Useful for programs that need to manage the order in
/// which file descriptors are allocated.
LOG_NDELAY;
/// Write the message to standard error output as well to the system log.
#[cfg(all(not(target_os = "redox"), not(target_os = "illumos")))]
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
LOG_PERROR;
}
}

libc_enum! {
/// Severity levels for log messages.
#[repr(i32)]
#[non_exhaustive]
pub enum Severity {
tisonkun marked this conversation as resolved.
Show resolved Hide resolved
/// A panic condition.
///
/// This is normally broadcast to all users.
LOG_EMERG,
/// A condition that should be corrected immediately, such as a corrupted system database.
LOG_ALERT,
/// Critical conditions, e.g., hard device errors.
LOG_CRIT,
/// Errors.
LOG_ERR,
/// Warning messages.
LOG_WARNING,
/// Conditions that are not error conditions, but should possibly be handled specially.
LOG_NOTICE,
/// Informational messages.
LOG_INFO,
/// Messages that contain information normally of use only when debugging a program.
LOG_DEBUG,
}
}

libc_enum! {
/// Facilities for log messages.
#[repr(i32)]
#[non_exhaustive]
pub enum Facility {
/// Messages generated by the kernel.
///
/// These cannot be generated by any user processes.
LOG_KERN,
/// Messages generated by random user processes.
///
/// This is the default facility identifier if none is specified.
LOG_USER,
/// The mail system.
LOG_MAIL,
/// System daemons, such as routed(8), that are not provided for explicitly by other facilities.
LOG_DAEMON,
/// The authorization system: login(1), su(1), getty(8), etc.
LOG_AUTH,
/// Messages generated internally by syslogd(8).
LOG_SYSLOG,
/// The line printer spooling system: cups-lpd(8), cupsd(8), etc.
LOG_LPR,
/// The network news system.
LOG_NEWS,
/// The uucp system.
LOG_UUCP,
/// Reserved for local use.
LOG_LOCAL0,
/// Reserved for local use.
LOG_LOCAL1,
/// Reserved for local use.
LOG_LOCAL2,
/// Reserved for local use.
LOG_LOCAL3,
/// Reserved for local use.
LOG_LOCAL4,
/// Reserved for local use.
LOG_LOCAL5,
/// Reserved for local use.
LOG_LOCAL6,
/// Reserved for local use.
LOG_LOCAL7,
}
}
2 changes: 2 additions & 0 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ mod test_sendfile;
))]
mod test_spawn;

mod test_syslog;

mod test_time;
mod test_unistd;

Expand Down
23 changes: 23 additions & 0 deletions test/test_syslog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use nix::syslog::{openlog, syslog, Facility, LogFlags, Severity};
use std::ffi::CStr;

#[test]
fn test_syslog_hello_world() {
let flags = LogFlags::LOG_PID;
openlog(None, flags, Facility::LOG_USER).unwrap();
syslog(Severity::LOG_EMERG, "Hello, nix!").unwrap();

let name = "syslog";
syslog(Severity::LOG_NOTICE, &format!("Hello, {name}!")).unwrap();
}

#[test]
fn test_openlog_with_ident() {
const IDENT: &CStr = unsafe {
CStr::from_bytes_with_nul_unchecked(b"test_openlog_with_ident\0")
};

let flags = LogFlags::LOG_PID;
openlog(Some(IDENT), flags, Facility::LOG_USER).unwrap();
syslog(Severity::LOG_EMERG, "Hello, ident!").unwrap();
}