]>
git.proxmox.com Git - pve-common.git/blob - data/PVE/Daemon.pm
538ecaf3532dd94ebad70d26b4f372872766ba41
3 # Abstract class to implement Daemons
6 # * lock and write PID file /var/run/$name.pid to make sure onyl
7 # one instance is running.
8 # * correctly daemonize (redirect STDIN/STDOUT)
9 # * daemon restart (option 'restart_on_error')
16 use POSIX
":sys_wait_h";
19 use Time
::HiRes qw
(gettimeofday
);
21 use base
qw(PVE::CLIHandler);
23 $SIG{'__WARN__'} = sub {
28 syslog
('warning', "WARNING: %s", $t);
32 $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
34 my $daemon_initialized = 0; # we only allow one instance
36 my $lockpidfile = sub {
39 my $lkfn = $self->{pidfile
} . ".lock";
41 if (!open (FLCK
, ">>$lkfn")) {
42 my $msg = "can't aquire lock on file '$lkfn' - $!";
47 if (!flock (FLCK
, LOCK_EX
|LOCK_NB
)) {
49 my $msg = "can't aquire lock '$lkfn' - $!";
55 my $writepidfile = sub {
58 my $pidfile = $self->{pidfile
};
60 if (!open (PIDFH
, ">$pidfile")) {
61 my $msg = "can't open pid file '$pidfile' - $!";
69 my $server_cleanup = sub {
72 unlink $self->{pidfile
} . ".lock";
73 unlink $self->{pidfile
};
76 my $server_run = sub {
77 my ($self, $debug) = @_;
84 my $restart = $ENV{RESTART_PVE_DAEMON
};
86 delete $ENV{RESTART_PVE_DAEMON
};
88 $self->{debug
} = 1 if $debug;
93 open STDIN
, '</dev/null' || die "can't read /dev/null";
94 open STDOUT
, '>/dev/null' || die "can't write /dev/null";
97 if (!$restart && !$debug) {
98 PVE
::INotify
::inotify_close
();
100 if (!defined ($spid)) {
101 my $msg = "can't put server into background - fork failed";
104 } elsif ($spid) { # parent
107 PVE
::INotify
::inotify_init
();
110 &$writepidfile($self);
115 syslog
('info' , "restarting server");
117 syslog
('info' , "starting server");
120 open STDERR
, '>&STDOUT' || die "can't close STDERR\n";
122 $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = sub {
123 $SIG{INT
} = 'DEFAULT';
125 eval { $self->shutdown(); };
128 &$server_cleanup($self);
131 if ($self->can('hup')) {
133 eval { $self->hup() };
138 eval { $self->run() };
142 syslog
('err', "ERROR: $err");
143 if (my $wait_time = $self->{restart_on_error
}) {
144 $self->restart_daemon($wait_time);
146 $self->exit_daemon(-1);
150 $self->exit_daemon(0);
154 my ($this, $name, $cmdline, %params) = @_;
156 die "please run as root\n" if $> != 0;
158 die "missing name" if !$name;
160 die "can't create more that one PVE::Daemon" if $daemon_initialized;
161 $daemon_initialized = 1;
163 PVE
::INotify
::inotify_init
();
167 my $class = ref($this) || $this;
171 run_dir
=> '/var/run',
174 foreach my $opt (keys %params) {
175 my $value = $params{$opt};
176 if ($opt eq 'restart_on_error') {
177 $self->{$opt} = $value;
178 } elsif ($opt eq 'stop_wait_time') {
179 $self->{$opt} = $value;
180 } elsif ($opt eq 'run_dir') {
181 $self->{$opt} = $value;
183 die "unknown option '$opt'";
187 $self->{pidfile
} = "$self->{run_dir}/${name}.pid";
189 $self->{nodename
} = PVE
::INotify
::nodename
();
191 $self->{cmdline
} = $cmdline;
200 my ($self, $status) = @_;
202 syslog
("info", "server stopped");
204 &$server_cleanup($self);
210 my ($self, $waittime) = @_;
212 syslog
('info', "server shutdown (restart)");
214 $ENV{RESTART_PVE_DAEMON
} = 1;
216 sleep($waittime) if $waittime; # avoid high server load due to restarts
218 PVE
::INotify
::inotify_close
();
220 exec (@{$self->{cmdline
}});
222 exit (-1); # never reached?
225 # please overwrite in subclass
226 # this is called at startup - before forking
232 # please overwrite in subclass
236 syslog
('info' , "server closing");
239 1 while (waitpid(-1, POSIX
::WNOHANG
()) > 0);
242 # please define in subclass
246 # syslog('info' , "received signal HUP (restart)");
249 # please overwrite in subclass
254 syslog
('info' , "server is running");
260 my ($self, $debug) = @_;
262 &$server_run($self, $debug);
268 my $pid_str = PVE
::Tools
::file_read_firstline
($self->{pidfile
});
270 return 0 if !$pid_str;
272 return 0 if $pid_str !~ m/^(\d+)$/; # untaint
282 my $pid = &$read_pid($self);
285 my $res = PVE
::ProcFSTools
::check_process_running
($pid) ?
1 : 0;
286 return wantarray ?
($res, $pid) : $res;
289 return wantarray ?
(0, 0) : 0;
295 my $pid = &$read_pid($self);
299 if (PVE
::ProcFSTools
::check_process_running
($pid)) {
300 kill(15, $pid); # send TERM signal
302 my $wait_time = $self->{stop_wait_time
} || 5;
304 for (my $i = 0; $i < $wait_time; $i++) {
305 $running = PVE
::ProcFSTools
::check_process_running
($pid);
310 syslog
('err', "server still running - send KILL") if $running;
317 if (-f
$self->{pidfile
}) {
318 # try to get the lock
319 &$lockpidfile($self);
320 &$server_cleanup($self);
324 sub register_start_command
{
325 my ($self, $class, $description) = @_;
327 $class->register_method({
331 description
=> $description || "Start the daemon.",
333 additionalProperties
=> 0,
336 description
=> "Debug mode - stay in foreground",
343 returns
=> { type
=> 'null' },
348 $self->start($param->{debug
});
354 my $reload_daemon = sub {
355 my ($self, $use_hup) = @_;
357 if (my $restart = $ENV{RESTART_PVE_DAEMON
}) {
360 my ($running, $pid) = $self->running();
374 sub register_restart_command
{
375 my ($self, $class, $use_hup, $description) = @_;
377 $class->register_method({
381 description
=> $description || "Restart the daemon (or start if not running).",
383 additionalProperties
=> 0,
386 returns
=> { type
=> 'null' },
391 &$reload_daemon($self, $use_hup);
397 sub register_reload_command
{
398 my ($self, $class, $description) = @_;
400 $class->register_method({
404 description
=> $description || "Reload daemon configuration (or start if not running).",
406 additionalProperties
=> 0,
409 returns
=> { type
=> 'null' },
414 &$reload_daemon($self, 1);
420 sub register_stop_command
{
421 my ($self, $class, $description) = @_;
423 $class->register_method({
427 description
=> $description || "Stop the daemon.",
429 additionalProperties
=> 0,
432 returns
=> { type
=> 'null' },
443 sub register_status_command
{
444 my ($self, $class, $description) = @_;
446 $class->register_method({
450 description
=> "Get daemon status.",
452 additionalProperties
=> 0,
457 enum
=> ['stopped', 'running'],
462 return $self->running() ?
'running' : 'stopped';