diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 88 |
1 files changed, 40 insertions, 48 deletions
diff --git a/src/main.rs b/src/main.rs index 22c2937..d0a2763 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -24,8 +24,8 @@ impl std::fmt::Display for PidFileReadError { | |||
| 24 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | 24 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 25 | match self { | 25 | match self { |
| 26 | PidFileReadError::FileNotFound => write!(f, "PID file not found"), | 26 | PidFileReadError::FileNotFound => write!(f, "PID file not found"), |
| 27 | PidFileReadError::FileInvalid(reason) => write!(f, "PID file invalid: {}", reason), | 27 | PidFileReadError::FileInvalid(reason) => write!(f, "PID file invalid: {reason}"), |
| 28 | PidFileReadError::IoError(err) => write!(f, "IO error reading PID file: {}", err), | 28 | PidFileReadError::IoError(err) => write!(f, "IO error reading PID file: {err}"), |
| 29 | } | 29 | } |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
| @@ -59,7 +59,7 @@ impl PidFile { | |||
| 59 | let mut file = File::create(path)?; | 59 | let mut file = File::create(path)?; |
| 60 | writeln!(file, "{}", self.pid)?; | 60 | writeln!(file, "{}", self.pid)?; |
| 61 | for arg in &self.command { | 61 | for arg in &self.command { |
| 62 | writeln!(file, "{}", arg)?; | 62 | writeln!(file, "{arg}")?; |
| 63 | } | 63 | } |
| 64 | Ok(()) | 64 | Ok(()) |
| 65 | } | 65 | } |
| @@ -397,7 +397,7 @@ fn resolve_root_dir(global: &Global) -> Result<PathBuf> { | |||
| 397 | } | 397 | } |
| 398 | 398 | ||
| 399 | fn build_file_path(root_dir: &Path, id: &str, extension: &str) -> PathBuf { | 399 | fn build_file_path(root_dir: &Path, id: &str, extension: &str) -> PathBuf { |
| 400 | root_dir.join(format!("{}.{}", id, extension)) | 400 | root_dir.join(format!("{id}.{extension}")) |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | fn run_daemon(id: &str, command: &[String], root_dir: &Path) -> Result<()> { | 403 | fn run_daemon(id: &str, command: &[String], root_dir: &Path) -> Result<()> { |
| @@ -434,7 +434,7 @@ fn run_daemon(id: &str, command: &[String], root_dir: &Path) -> Result<()> { | |||
| 434 | .stderr(Stdio::from(stderr_redirect)) | 434 | .stderr(Stdio::from(stderr_redirect)) |
| 435 | .stdin(Stdio::null()) | 435 | .stdin(Stdio::null()) |
| 436 | .spawn() | 436 | .spawn() |
| 437 | .with_context(|| format!("Failed to start process '{}' with args {:?}", program, args))?; | 437 | .with_context(|| format!("Failed to start process '{program}' with args {args:?}"))?; |
| 438 | 438 | ||
| 439 | // Write PID and command to file | 439 | // Write PID and command to file |
| 440 | let pid_file_data = PidFile::new(child.id(), command.to_vec()); | 440 | let pid_file_data = PidFile::new(child.id(), command.to_vec()); |
| @@ -462,7 +462,7 @@ fn is_process_running<P: AsRef<Path>>(pid_file: P) -> Result<bool> { | |||
| 462 | 462 | ||
| 463 | // Check if process is still running using kill -0 | 463 | // Check if process is still running using kill -0 |
| 464 | let output = Command::new("kill") | 464 | let output = Command::new("kill") |
| 465 | .args(&["-0", &pid_file_data.pid.to_string()]) | 465 | .args(["-0", &pid_file_data.pid.to_string()]) |
| 466 | .output()?; | 466 | .output()?; |
| 467 | 467 | ||
| 468 | Ok(output.status.success()) | 468 | Ok(output.status.success()) |
| @@ -475,11 +475,11 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 475 | let pid_file_data = match PidFile::read_from_file(&pid_file) { | 475 | let pid_file_data = match PidFile::read_from_file(&pid_file) { |
| 476 | Ok(data) => data, | 476 | Ok(data) => data, |
| 477 | Err(PidFileReadError::FileNotFound) => { | 477 | Err(PidFileReadError::FileNotFound) => { |
| 478 | println!("Process '{}' is not running (no PID file found)", id); | 478 | println!("Process '{id}' is not running (no PID file found)"); |
| 479 | return Ok(()); | 479 | return Ok(()); |
| 480 | } | 480 | } |
| 481 | Err(PidFileReadError::FileInvalid(_)) => { | 481 | Err(PidFileReadError::FileInvalid(_)) => { |
| 482 | println!("Process '{}': invalid PID file, removing it", id); | 482 | println!("Process '{id}': invalid PID file, removing it"); |
| 483 | std::fs::remove_file(&pid_file)?; | 483 | std::fs::remove_file(&pid_file)?; |
| 484 | return Ok(()); | 484 | return Ok(()); |
| 485 | } | 485 | } |
| @@ -499,10 +499,7 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 499 | 499 | ||
| 500 | // Check if process is running | 500 | // Check if process is running |
| 501 | if !is_process_running_by_pid(pid) { | 501 | if !is_process_running_by_pid(pid) { |
| 502 | println!( | 502 | println!("Process '{id}' (PID: {pid}) is not running, cleaning up PID file"); |
| 503 | "Process '{}' (PID: {}) is not running, cleaning up PID file", | ||
| 504 | id, pid | ||
| 505 | ); | ||
| 506 | std::fs::remove_file(&pid_file)?; | 503 | std::fs::remove_file(&pid_file)?; |
| 507 | return Ok(()); | 504 | return Ok(()); |
| 508 | } | 505 | } |
| @@ -510,7 +507,7 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 510 | // Send SIGTERM | 507 | // Send SIGTERM |
| 511 | tracing::info!("Sending SIGTERM to PID {}", pid); | 508 | tracing::info!("Sending SIGTERM to PID {}", pid); |
| 512 | let output = Command::new("kill") | 509 | let output = Command::new("kill") |
| 513 | .args(&["-TERM", &pid.to_string()]) | 510 | .args(["-TERM", &pid.to_string()]) |
| 514 | .output()?; | 511 | .output()?; |
| 515 | 512 | ||
| 516 | if !output.status.success() { | 513 | if !output.status.success() { |
| @@ -520,7 +517,7 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 520 | // Wait for the process to terminate | 517 | // Wait for the process to terminate |
| 521 | for i in 0..timeout { | 518 | for i in 0..timeout { |
| 522 | if !is_process_running_by_pid(pid) { | 519 | if !is_process_running_by_pid(pid) { |
| 523 | println!("Process '{}' (PID: {}) terminated gracefully", id, pid); | 520 | println!("Process '{id}' (PID: {pid}) terminated gracefully"); |
| 524 | std::fs::remove_file(&pid_file)?; | 521 | std::fs::remove_file(&pid_file)?; |
| 525 | return Ok(()); | 522 | return Ok(()); |
| 526 | } | 523 | } |
| @@ -539,7 +536,7 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 539 | timeout | 536 | timeout |
| 540 | ); | 537 | ); |
| 541 | let output = Command::new("kill") | 538 | let output = Command::new("kill") |
| 542 | .args(&["-KILL", &pid.to_string()]) | 539 | .args(["-KILL", &pid.to_string()]) |
| 543 | .output()?; | 540 | .output()?; |
| 544 | 541 | ||
| 545 | if !output.status.success() { | 542 | if !output.status.success() { |
| @@ -556,16 +553,14 @@ fn stop_daemon(id: &str, timeout: u64, root_dir: &Path) -> Result<()> { | |||
| 556 | )); | 553 | )); |
| 557 | } | 554 | } |
| 558 | 555 | ||
| 559 | println!("Process '{}' (PID: {}) terminated forcefully", id, pid); | 556 | println!("Process '{id}' (PID: {pid}) terminated forcefully"); |
| 560 | std::fs::remove_file(&pid_file)?; | 557 | std::fs::remove_file(&pid_file)?; |
| 561 | 558 | ||
| 562 | Ok(()) | 559 | Ok(()) |
| 563 | } | 560 | } |
| 564 | 561 | ||
| 565 | fn is_process_running_by_pid(pid: u32) -> bool { | 562 | fn is_process_running_by_pid(pid: u32) -> bool { |
| 566 | let output = Command::new("kill") | 563 | let output = Command::new("kill").args(["-0", &pid.to_string()]).output(); |
| 567 | .args(&["-0", &pid.to_string()]) | ||
| 568 | .output(); | ||
| 569 | 564 | ||
| 570 | match output { | 565 | match output { |
| 571 | Ok(output) => output.status.success(), | 566 | Ok(output) => output.status.success(), |
| @@ -586,7 +581,7 @@ fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool, root_dir: &Path) -> | |||
| 586 | if show_stderr { | 581 | if show_stderr { |
| 587 | println!("==> {} <==", stdout_file.display()); | 582 | println!("==> {} <==", stdout_file.display()); |
| 588 | } | 583 | } |
| 589 | print!("{}", contents); | 584 | print!("{contents}"); |
| 590 | } | 585 | } |
| 591 | } else { | 586 | } else { |
| 592 | tracing::warn!("Could not read {}", stdout_file.display()); | 587 | tracing::warn!("Could not read {}", stdout_file.display()); |
| @@ -600,7 +595,7 @@ fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool, root_dir: &Path) -> | |||
| 600 | if show_stdout { | 595 | if show_stdout { |
| 601 | println!("==> {} <==", stderr_file.display()); | 596 | println!("==> {} <==", stderr_file.display()); |
| 602 | } | 597 | } |
| 603 | print!("{}", contents); | 598 | print!("{contents}"); |
| 604 | } | 599 | } |
| 605 | } else { | 600 | } else { |
| 606 | tracing::warn!("Could not read {}", stderr_file.display()); | 601 | tracing::warn!("Could not read {}", stderr_file.display()); |
| @@ -608,7 +603,7 @@ fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool, root_dir: &Path) -> | |||
| 608 | } | 603 | } |
| 609 | 604 | ||
| 610 | if !files_found { | 605 | if !files_found { |
| 611 | println!("No log files found for daemon '{}'", id); | 606 | println!("No log files found for daemon '{id}'"); |
| 612 | } | 607 | } |
| 613 | 608 | ||
| 614 | Ok(()) | 609 | Ok(()) |
| @@ -636,7 +631,7 @@ fn tail_logs( | |||
| 636 | if show_stderr { | 631 | if show_stderr { |
| 637 | println!("==> {} <==", stdout_file.display()); | 632 | println!("==> {} <==", stdout_file.display()); |
| 638 | } | 633 | } |
| 639 | print!("{}", content); | 634 | print!("{content}"); |
| 640 | } | 635 | } |
| 641 | } | 636 | } |
| 642 | 637 | ||
| @@ -647,12 +642,12 @@ fn tail_logs( | |||
| 647 | if show_stdout { | 642 | if show_stdout { |
| 648 | println!("==> {} <==", stderr_file.display()); | 643 | println!("==> {} <==", stderr_file.display()); |
| 649 | } | 644 | } |
| 650 | print!("{}", content); | 645 | print!("{content}"); |
| 651 | } | 646 | } |
| 652 | } | 647 | } |
| 653 | 648 | ||
| 654 | if !files_found { | 649 | if !files_found { |
| 655 | println!("No log files found for daemon '{}'", id); | 650 | println!("No log files found for daemon '{id}'"); |
| 656 | } | 651 | } |
| 657 | 652 | ||
| 658 | return Ok(()); | 653 | return Ok(()); |
| @@ -669,9 +664,9 @@ fn tail_logs( | |||
| 669 | if show_stderr { | 664 | if show_stderr { |
| 670 | println!("==> {} <==", stdout_file.display()); | 665 | println!("==> {} <==", stdout_file.display()); |
| 671 | } | 666 | } |
| 672 | print!("{}", initial_content); | 667 | print!("{initial_content}"); |
| 673 | } | 668 | } |
| 674 | let position = file.seek(SeekFrom::Current(0))?; | 669 | let position = file.stream_position()?; |
| 675 | file_positions.insert(stdout_file.clone(), position); | 670 | file_positions.insert(stdout_file.clone(), position); |
| 676 | } | 671 | } |
| 677 | 672 | ||
| @@ -679,22 +674,19 @@ fn tail_logs( | |||
| 679 | let mut file = File::open(&stderr_file)?; | 674 | let mut file = File::open(&stderr_file)?; |
| 680 | let initial_content = read_file_content(&mut file)?; | 675 | let initial_content = read_file_content(&mut file)?; |
| 681 | if !initial_content.is_empty() { | 676 | if !initial_content.is_empty() { |
| 682 | if show_stdout && file_positions.len() > 0 { | 677 | if show_stdout && !file_positions.is_empty() { |
| 683 | println!("\n==> {} <==", stderr_file.display()); | 678 | println!("\n==> {} <==", stderr_file.display()); |
| 684 | } else if show_stdout { | 679 | } else if show_stdout { |
| 685 | println!("==> {} <==", stderr_file.display()); | 680 | println!("==> {} <==", stderr_file.display()); |
| 686 | } | 681 | } |
| 687 | print!("{}", initial_content); | 682 | print!("{initial_content}"); |
| 688 | } | 683 | } |
| 689 | let position = file.seek(SeekFrom::Current(0))?; | 684 | let position = file.stream_position()?; |
| 690 | file_positions.insert(stderr_file.clone(), position); | 685 | file_positions.insert(stderr_file.clone(), position); |
| 691 | } | 686 | } |
| 692 | 687 | ||
| 693 | if file_positions.is_empty() { | 688 | if file_positions.is_empty() { |
| 694 | println!( | 689 | println!("No log files found for daemon '{id}'. Watching for new files..."); |
| 695 | "No log files found for daemon '{}'. Watching for new files...", | ||
| 696 | id | ||
| 697 | ); | ||
| 698 | } | 690 | } |
| 699 | 691 | ||
| 700 | tracing::info!("Watching for changes to log files... Press Ctrl+C to stop."); | 692 | tracing::info!("Watching for changes to log files... Press Ctrl+C to stop."); |
| @@ -816,11 +808,11 @@ fn handle_file_change( | |||
| 816 | if show_headers { | 808 | if show_headers { |
| 817 | println!("==> {} <==", file_path.display()); | 809 | println!("==> {} <==", file_path.display()); |
| 818 | } | 810 | } |
| 819 | print!("{}", new_content); | 811 | print!("{new_content}"); |
| 820 | std::io::Write::flush(&mut std::io::stdout())?; | 812 | std::io::Write::flush(&mut std::io::stdout())?; |
| 821 | 813 | ||
| 822 | // Update position | 814 | // Update position |
| 823 | let new_pos = file.seek(SeekFrom::Current(0))?; | 815 | let new_pos = file.stream_position()?; |
| 824 | positions.insert(file_path.to_path_buf(), new_pos); | 816 | positions.insert(file_path.to_path_buf(), new_pos); |
| 825 | } | 817 | } |
| 826 | 818 | ||
| @@ -829,7 +821,7 @@ fn handle_file_change( | |||
| 829 | 821 | ||
| 830 | fn list_daemons(quiet: bool, root_dir: &Path) -> Result<()> { | 822 | fn list_daemons(quiet: bool, root_dir: &Path) -> Result<()> { |
| 831 | if !quiet { | 823 | if !quiet { |
| 832 | println!("{:<20} {:<8} {:<10} {}", "ID", "PID", "STATUS", "COMMAND"); | 824 | println!("{:<20} {:<8} {:<10} COMMAND", "ID", "PID", "STATUS"); |
| 833 | println!("{}", "-".repeat(50)); | 825 | println!("{}", "-".repeat(50)); |
| 834 | } | 826 | } |
| 835 | 827 | ||
| @@ -869,28 +861,28 @@ fn list_daemons(quiet: bool, root_dir: &Path) -> Result<()> { | |||
| 869 | Err(PidFileReadError::FileNotFound) => { | 861 | Err(PidFileReadError::FileNotFound) => { |
| 870 | // This shouldn't happen since we found the file, but handle gracefully | 862 | // This shouldn't happen since we found the file, but handle gracefully |
| 871 | if quiet { | 863 | if quiet { |
| 872 | println!("{}:NOTFOUND:ERROR", id); | 864 | println!("{id}:NOTFOUND:ERROR"); |
| 873 | } else { | 865 | } else { |
| 874 | println!( | 866 | println!( |
| 875 | "{:<20} {:<8} {:<10} {}", | 867 | "{:<20} {:<8} {:<10} PID file disappeared", |
| 876 | id, "NOTFOUND", "ERROR", "PID file disappeared" | 868 | id, "NOTFOUND", "ERROR" |
| 877 | ); | 869 | ); |
| 878 | } | 870 | } |
| 879 | } | 871 | } |
| 880 | Err(PidFileReadError::FileInvalid(reason)) => { | 872 | Err(PidFileReadError::FileInvalid(reason)) => { |
| 881 | if quiet { | 873 | if quiet { |
| 882 | println!("{}:INVALID:ERROR", id); | 874 | println!("{id}:INVALID:ERROR"); |
| 883 | } else { | 875 | } else { |
| 884 | println!("{:<20} {:<8} {:<10} {}", id, "INVALID", "ERROR", reason); | 876 | println!("{:<20} {:<8} {:<10} {}", id, "INVALID", "ERROR", reason); |
| 885 | } | 877 | } |
| 886 | } | 878 | } |
| 887 | Err(PidFileReadError::IoError(_)) => { | 879 | Err(PidFileReadError::IoError(_)) => { |
| 888 | if quiet { | 880 | if quiet { |
| 889 | println!("{}:ERROR:ERROR", id); | 881 | println!("{id}:ERROR:ERROR"); |
| 890 | } else { | 882 | } else { |
| 891 | println!( | 883 | println!( |
| 892 | "{:<20} {:<8} {:<10} {}", | 884 | "{:<20} {:<8} {:<10} Cannot read PID file", |
| 893 | id, "ERROR", "ERROR", "Cannot read PID file" | 885 | id, "ERROR", "ERROR" |
| 894 | ); | 886 | ); |
| 895 | } | 887 | } |
| 896 | } | 888 | } |
| @@ -909,7 +901,7 @@ fn status_daemon(id: &str, root_dir: &Path) -> Result<()> { | |||
| 909 | let stdout_file = build_file_path(root_dir, id, "stdout"); | 901 | let stdout_file = build_file_path(root_dir, id, "stdout"); |
| 910 | let stderr_file = build_file_path(root_dir, id, "stderr"); | 902 | let stderr_file = build_file_path(root_dir, id, "stderr"); |
| 911 | 903 | ||
| 912 | println!("Daemon: {}", id); | 904 | println!("Daemon: {id}"); |
| 913 | println!("PID file: {}", pid_file.display()); | 905 | println!("PID file: {}", pid_file.display()); |
| 914 | 906 | ||
| 915 | // Read PID data from file | 907 | // Read PID data from file |
| @@ -952,10 +944,10 @@ fn status_daemon(id: &str, root_dir: &Path) -> Result<()> { | |||
| 952 | println!("Status: NOT FOUND (no PID file)"); | 944 | println!("Status: NOT FOUND (no PID file)"); |
| 953 | } | 945 | } |
| 954 | Err(PidFileReadError::FileInvalid(reason)) => { | 946 | Err(PidFileReadError::FileInvalid(reason)) => { |
| 955 | println!("Status: ERROR (invalid PID file: {})", reason); | 947 | println!("Status: ERROR (invalid PID file: {reason})"); |
| 956 | } | 948 | } |
| 957 | Err(PidFileReadError::IoError(err)) => { | 949 | Err(PidFileReadError::IoError(err)) => { |
| 958 | println!("Status: ERROR (cannot read PID file: {})", err); | 950 | println!("Status: ERROR (cannot read PID file: {err})"); |
| 959 | } | 951 | } |
| 960 | } | 952 | } |
| 961 | 953 | ||
| @@ -1045,7 +1037,7 @@ fn clean_orphaned_files(root_dir: &Path) -> Result<()> { | |||
| 1045 | if cleaned_count == 0 { | 1037 | if cleaned_count == 0 { |
| 1046 | println!("No orphaned files found."); | 1038 | println!("No orphaned files found."); |
| 1047 | } else { | 1039 | } else { |
| 1048 | println!("Cleaned up {} orphaned daemon(s).", cleaned_count); | 1040 | println!("Cleaned up {cleaned_count} orphaned daemon(s)."); |
| 1049 | } | 1041 | } |
| 1050 | 1042 | ||
| 1051 | Ok(()) | 1043 | Ok(()) |
