Advertisement
Guest User

Untitled

a guest
Dec 10th, 2019
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.15 KB | None | 0 0
  1. extern crate libc;
  2. extern crate log;
  3. extern crate tokio;
  4. extern crate zstd;
  5.  
  6. use std::ffi::OsString;
  7. use std::fs::{File, OpenOptions};
  8. use std::io::Write;
  9. use std::os::unix::fs::PermissionsExt;
  10. use std::os::unix::io::AsRawFd;
  11. use std::path::{Path, PathBuf};
  12. use std::sync::Mutex;
  13.  
  14. use tokio::prelude::*;
  15.  
  16. use log::{info, warn};
  17. use log::{Level, Log, Metadata, Record, SetLoggerError};
  18.  
  19. /// Kernel logger implementation
  20. pub struct KernelLog {
  21.     kmsg: Mutex<File>,
  22.     level: Level,
  23. }
  24.  
  25. impl KernelLog {
  26.     /// Create new kernel logger
  27.     pub fn new() -> KernelLog {
  28.         KernelLog::with_level(Level::Trace)
  29.     }
  30.  
  31.     /// Create new kernel logger with error level filter
  32.     pub fn with_level(level: Level) -> KernelLog {
  33.         KernelLog {
  34.             kmsg: Mutex::new(OpenOptions::new().write(true).open("/dev/kmsg").unwrap()),
  35.             level: level,
  36.         }
  37.     }
  38.  
  39.     pub fn init_with_level(level: Level) -> Result<(), SetLoggerError> {
  40.         let logger = KernelLog::with_level(level);
  41.         log::set_boxed_logger(Box::new(logger))
  42.     }
  43.  
  44.     pub fn init() -> Result<(), SetLoggerError> {
  45.         KernelLog::init_with_level(Level::Trace)
  46.     }
  47. }
  48.  
  49. impl Log for KernelLog {
  50.     fn enabled(&self, meta: &Metadata) -> bool {
  51.         meta.level() <= self.level
  52.     }
  53.  
  54.     fn log(&self, record: &Record) {
  55.         if !self.enabled(record.metadata()) {
  56.             return;
  57.         }
  58.  
  59.         let level: u8 = match record.level() {
  60.             Level::Error => 3,
  61.             Level::Warn => 4,
  62.             Level::Info => 5,
  63.             Level::Debug => 6,
  64.             Level::Trace => 7,
  65.         };
  66.  
  67.         let mut buf = Vec::new();
  68.         writeln!(
  69.             buf,
  70.             "<{}>{}[{}]: {}",
  71.             level,
  72.             record.target(),
  73.             unsafe { libc::getpid() },
  74.             record.args()
  75.         )
  76.         .unwrap();
  77.  
  78.         let mut kmsg = self.kmsg.lock().unwrap();
  79.         let _ = kmsg.write(&buf);
  80.     }
  81.  
  82.     fn flush(&self) {
  83.         let mut kmsg = self.kmsg.lock().unwrap();
  84.         let _ = kmsg.flush();
  85.     }
  86. }
  87.  
  88. fn app_path() -> String {
  89.     match std::env::current_exe() {
  90.         Ok(exe) => String::from(exe.to_str().unwrap()),
  91.         Err(_) => String::from("rustdump"),
  92.     }
  93. }
  94.  
  95. fn app_name() -> String {
  96.     match std::env::current_exe() {
  97.         Ok(exe) => String::from(Path::new(&exe).file_name().unwrap().to_str().unwrap()),
  98.         Err(_) => String::from("rustdump"),
  99.     }
  100. }
  101.  
  102. fn usage() -> ! {
  103.     eprintln!(
  104.         "Usage: set /proc/sys/kernel/core_pattern to '|{} %P %u %g %s %t %c %h %e",
  105.         app_path()
  106.     );
  107.     std::process::exit(1);
  108. }
  109.  
  110. fn parse_str(opts: &[OsString], i: usize) -> &str {
  111.     match opts[i].to_str() {
  112.         Some(v) => v,
  113.         None => {
  114.             eprintln!("FATAL: can't decode argument {}", i);
  115.             usage();
  116.         }
  117.     }
  118. }
  119.  
  120. fn parse_int(opts: &[OsString], i: usize) -> u64 {
  121.     match parse_str(opts, i).parse::<u64>() {
  122.         Ok(v) => v,
  123.         Err(e) => {
  124.             eprintln!("FATAL: can't parse argument {}: {:?}", i, e);
  125.             usage();
  126.         }
  127.     }
  128. }
  129.  
  130. // default pattern %P %u %g %s %t %c %h %e
  131. //                  1  2  3  4  5  6  7  8
  132. fn process_args() -> (String, u64, u64) {
  133.     match std::env::args_os().len() {
  134.         9 => {
  135.             let args: Vec<_> = std::env::args_os().collect();
  136.             let pid = parse_int(&args, 1);
  137.             let uid = parse_int(&args, 2);
  138.             let gid = parse_int(&args, 3);
  139.             let _sig = parse_int(&args, 4);
  140.             let ts = parse_str(&args, 5);
  141.             let _lim = parse_int(&args, 6);
  142.             let host = parse_str(&args, 7);
  143.             let exe = parse_str(&args, 8);
  144.             (format!("{}.{}.{}.{}.zst", exe, pid, host, ts), uid, gid)
  145.         }
  146.         _ => usage(),
  147.     }
  148. }
  149.  
  150. fn dump(dest: std::fs::File) {
  151.     let stdin = tokio::io::stdin();
  152.     let z = zstd::Encoder::new(
  153.         tokio::fs::File::from_std(dest),
  154.         zstd::DEFAULT_COMPRESSION_LEVEL,
  155.     )
  156.     .unwrap();
  157.     let future = tokio::io::copy(stdin, z)
  158.         .map_err(|e| {
  159.             warn!("dump failed: {}", e);
  160.         })
  161.         .and_then(|copied| {
  162.             info!("processed {} bytes", copied.0);
  163.             Ok(())
  164.         });
  165.  
  166.     tokio::run(future);
  167. }
  168.  
  169. fn main() {
  170.     unsafe {
  171.         libc::prctl(libc::PR_SET_DUMPABLE, 0);
  172.     }
  173.  
  174.     // If argument parsing is not successful, exit and don't initialize anything
  175.     let (name, uid, gid) = process_args();
  176.  
  177.     // Setup kernel logger as a default logger
  178.     KernelLog::init().unwrap();
  179.     log::set_max_level(log::LevelFilter::Trace);
  180.  
  181.     let mut corepath = PathBuf::from("/var/core");
  182.     // Ensure target directory exists
  183.     std::fs::create_dir_all(&corepath).unwrap();
  184.  
  185.     // Append filename and open destination file
  186.     corepath.push(name);
  187.     let dest = std::fs::File::create(corepath).unwrap();
  188.  
  189.     // Adjust file ownership and permissions
  190.     unsafe {
  191.         let fd = dest.as_raw_fd();
  192.         libc::fchmod(fd, 0o640);
  193.         libc::fchown(fd, uid as u32, gid as u32);
  194.     }
  195.  
  196.     // Compress and write stdin to file
  197.     dump(dest);
  198. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement