@@ -7,7 +7,6 @@ use getopts::Options;
77use netpulse:: store:: Store ;
88use netpulse:: { DAEMON_LOG_ERR , DAEMON_LOG_INF , DAEMON_PID_FILE , DAEMON_USER } ;
99use nix:: errno:: Errno ;
10- use nix:: libc:: ESRCH ;
1110use nix:: sys:: signal:: { self , Signal } ;
1211use nix:: unistd:: Pid ;
1312
@@ -19,7 +18,13 @@ fn main() {
1918 let program = & args[ 0 ] ;
2019 let mut opts = Options :: new ( ) ;
2120 opts. optflag ( "h" , "help" , "print this help menu" ) ;
21+ opts. optflag ( "V" , "version" , "print the version" ) ;
2222 opts. optflag ( "s" , "start" , "start the netpulse daemon" ) ;
23+ opts. optflag (
24+ "d" ,
25+ "daemon" ,
26+ "run directly as the daemon, do not setup a pidfile or drop privileges" ,
27+ ) ;
2328 opts. optflag ( "i" , "info" , "info about the running netpulse daemon" ) ;
2429 opts. optflag ( "e" , "end" , "stop the running netpulse daemon" ) ;
2530 let matches = match opts. parse ( & args[ 1 ..] ) {
@@ -31,12 +36,16 @@ fn main() {
3136
3237 if matches. opt_present ( "help" ) {
3338 print_usage ( program, opts) ;
39+ } else if matches. opt_present ( "version" ) {
40+ println ! ( "{} {}" , env!( "CARGO_BIN_NAME" ) , env!( "CARGO_PKG_VERSION" ) )
3441 } else if matches. opt_present ( "start" ) {
3542 startd ( ) ;
3643 } else if matches. opt_present ( "info" ) {
3744 infod ( ) ;
3845 } else if matches. opt_present ( "end" ) {
3946 endd ( ) ;
47+ } else if matches. opt_present ( "test" ) {
48+ daemon ( ) ;
4049 } else {
4150 print_usage ( program, opts) ;
4251 }
@@ -81,6 +90,7 @@ fn pid_runs(pid: i32) -> bool {
8190}
8291
8392fn endd ( ) {
93+ root_guard ( ) ;
8494 let mut terminated = false ;
8595 let pid: Pid = match getpid ( ) {
8696 None => {
@@ -102,7 +112,10 @@ fn endd() {
102112 Errno :: ESRCH => {
103113 terminated = true ;
104114 }
105- _ => panic ! ( "Failed to terminate netpulsed: {e}" ) ,
115+ _ => {
116+ eprintln ! ( "Failed to terminate netpulsed: {e}" ) ;
117+ std:: process:: exit ( 1 )
118+ }
106119 }
107120 }
108121 }
@@ -139,7 +152,15 @@ fn print_usage(program: &str, opts: Options) {
139152 print ! ( "{}" , opts. usage( & brief) ) ;
140153}
141154
155+ fn root_guard ( ) {
156+ if !nix:: unistd:: getuid ( ) . is_root ( ) {
157+ eprintln ! ( "This needs to be run as root" ) ;
158+ std:: process:: exit ( 1 )
159+ }
160+ }
161+
142162fn startd ( ) {
163+ root_guard ( ) ;
143164 let path = Store :: path ( ) ;
144165 let parent_path = path. parent ( ) . expect ( "store file has no parent directory" ) ;
145166 println ! ( "Parent: {parent_path:?}" ) ;
@@ -166,6 +187,13 @@ fn startd() {
166187 )
167188 . expect ( "could not set permissions for the netpulse run directory" ) ;
168189
190+ // NOTE: Daemonize is the defacto standard way of becoming a daemon in rust (besides extra
191+ // tools like systemd or writing it all yourself with nix or just the libc).
192+ // Sadly, Daemonize just drops all capabilities when we become a daemon, including an important
193+ // one: CAP_NET_RAW. This capability allows us to use raw sockets, which are required for
194+ // things like ICMP (ping) messages.
195+ // I have implemented ICMP checks, but the daemon drops the CAP_NET_RAW capability and then is
196+ // no longer allowed to make the custom pings.
169197 let daemonize = Daemonize :: new ( )
170198 . pid_file ( pid_path)
171199 . chown_pid_file ( true )
0 commit comments