| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Working::Daemon; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 2 |  |  | 2 |  | 198878 | use 5.008; | 
|  | 2 |  |  |  |  | 8 |  | 
|  | 2 |  |  |  |  | 83 |  | 
| 4 | 2 |  |  | 2 |  | 13 | use strict; | 
|  | 2 |  |  |  |  | 7 |  | 
|  | 2 |  |  |  |  | 75 |  | 
| 5 | 2 |  |  | 2 |  | 13 | use warnings; | 
|  | 2 |  |  |  |  | 9 |  | 
|  | 2 |  |  |  |  | 86 |  | 
| 6 | 2 |  |  | 2 |  | 2567 | use Data::Dumper; | 
|  | 2 |  |  |  |  | 96059 |  | 
|  | 2 |  |  |  |  | 181 |  | 
| 7 | 2 |  |  | 2 |  | 3173 | use File::Copy; | 
|  | 2 |  |  |  |  | 17356 |  | 
|  | 2 |  |  |  |  | 181 |  | 
| 8 | 2 |  |  | 2 |  | 28759 | use Getopt::Long; | 
|  | 2 |  |  |  |  | 81107 |  | 
|  | 2 |  |  |  |  | 16 |  | 
| 9 | 2 |  |  | 2 |  | 415 | use Carp; | 
|  | 2 |  |  |  |  | 4 |  | 
|  | 2 |  |  |  |  | 44734 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | our $VERSION = 0.31; | 
| 12 |  |  |  |  |  |  | our $SVN = 5236; | 
| 13 |  |  |  |  |  |  | our %config; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | #these are all default configs | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | # perl really need the protocols file to function | 
| 18 | 0 |  |  | 0 | 0 | 0 | sub chroot_files { return ("/etc/protocols") } | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 0 |  |  | 0 | 0 | 0 | sub chroot_dirs { return ("/etc/") } | 
| 21 |  |  |  |  |  |  |  | 
| 22 | 0 |  |  | 0 | 0 | 0 | sub default_action { return "start" } | 
| 23 |  |  |  |  |  |  |  | 
| 24 | 0 |  |  | 0 | 0 | 0 | sub exit_success { exit(0) } | 
| 25 |  |  |  |  |  |  |  | 
| 26 | 0 |  |  | 0 | 0 | 0 | sub exit_error { exit(1) } | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | sub default_options { | 
| 29 |  |  |  |  |  |  | return ( | 
| 30 | 0 |  |  | 0 | 0 | 0 | "help"       => undef() => "This help", | 
| 31 |  |  |  |  |  |  | "version"    => undef() => "Version number", | 
| 32 |  |  |  |  |  |  | "loglevel=i" => undef() => "The higher the loglevel, the more detailed messages. Default to 0", | 
| 33 |  |  |  |  |  |  | "daemon!"    => undef() => "Set to --no-daemon if you don't want it to daemonize. Default is true", | 
| 34 |  |  |  |  |  |  | "chroot!"    => undef() => "Set to --no-chroot if you don't want it to chroot. Default is true", | 
| 35 |  |  |  |  |  |  | "foreground" => undef() => "Inverse of daemonize, default is off", | 
| 36 |  |  |  |  |  |  | "user=s"     => undef() => "User to run this app as. Default is 'nobody'", | 
| 37 |  |  |  |  |  |  | "group=s"    => undef() => "Group to run this app as. Default is 'nobody'", | 
| 38 |  |  |  |  |  |  | "pidfile=s"  => undef() => "Where to store the pidfile. Default is /var/run/\$name.pid", | 
| 39 |  |  |  |  |  |  | "name=s"     => undef() => "Name of this app") | 
| 40 |  |  |  |  |  |  | } | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | sub tmpdir { | 
| 44 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 45 | 0 |  |  |  |  | 0 | return "/tmp/" . $self->name . ".$$"; | 
| 46 |  |  |  |  |  |  | } | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # end of config methods | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | sub standard { | 
| 52 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 53 | 0 |  |  |  |  | 0 | $self->parse_options(@_); | 
| 54 | 0 |  |  |  |  | 0 | $self->do_action(); | 
| 55 | 0 |  |  |  |  | 0 | $self->change_root(); | 
| 56 | 0 |  |  |  |  | 0 | $self->drop_privs(); | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub new { | 
| 60 | 2 |  |  | 2 | 0 | 325 | my $class = shift; | 
| 61 | 2 |  |  |  |  | 8 | my $self = bless {}, $class; | 
| 62 | 2 |  |  |  |  | 8 | return $self; | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | sub do_action { | 
| 67 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 68 | 0 |  | 0 |  |  | 0 | my $action = shift @ARGV || $self->default_action; | 
| 69 | 0 |  |  |  |  | 0 | my $action_method = "action_$action"; | 
| 70 | 0 | 0 |  |  |  | 0 | $self->print_version if($self->options->{version}); | 
| 71 | 0 | 0 |  |  |  | 0 | if ($self->options->{help}) { | 
| 72 | 0 |  |  |  |  | 0 | $self->show_help; | 
| 73 | 0 |  |  |  |  | 0 | exit; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 0 | 0 |  |  |  | 0 | if($self->can($action_method)) { | 
| 77 | 0 |  |  |  |  | 0 | my $exit_value = $self->$action_method; | 
| 78 | 0 | 0 | 0 |  |  | 0 | exit $exit_value unless ($action eq 'start' || $action eq 'restart'); | 
| 79 |  |  |  |  |  |  | } else { | 
| 80 | 0 |  |  |  |  | 0 | print STDERR "Unknown command '$action'\n"; | 
| 81 | 0 |  |  |  |  | 0 | $self->show_help; | 
| 82 | 0 |  |  |  |  | 0 | exit; | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | sub show_help { | 
| 87 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 88 | 0 |  |  |  |  | 0 | my %options_desc = %{$self->options_desc}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 89 | 0 | 0 |  |  |  | 0 | %options_desc = $self->default_options if (!%options_desc); | 
| 90 | 0 |  |  |  |  | 0 | my $max_length = 0; | 
| 91 | 0 |  |  |  |  | 0 | my @commands; | 
| 92 |  |  |  |  |  |  | my @desc; | 
| 93 | 0 |  |  |  |  | 0 | my @values; | 
| 94 | 0 |  |  |  |  | 0 | foreach my $option (keys %options_desc) { | 
| 95 | 0 |  |  |  |  | 0 | my $command = $option; | 
| 96 | 0 | 0 |  |  |  | 0 | if($command =~s/\=(.)%?//g) { | 
| 97 | 0 | 0 |  |  |  | 0 | $command .= "=str" if($1 eq 's'); | 
| 98 | 0 | 0 |  |  |  | 0 | $command .= "=int" if($1 eq 'i'); | 
| 99 |  |  |  |  |  |  | } | 
| 100 | 0 | 0 |  |  |  | 0 | $command = "no-$command" if($command =~s/\!$//); | 
| 101 | 0 | 0 |  |  |  | 0 | $max_length = length($command) if(length($command) > $max_length); | 
| 102 | 0 |  |  |  |  | 0 | push @commands, $command; | 
| 103 | 0 |  |  |  |  | 0 | push @desc, $options_desc{$option}; | 
| 104 | 0 |  |  |  |  | 0 | $option =~s/(\w+)/$1/; | 
| 105 | 0 |  |  |  |  | 0 | my $raw_option = $1; | 
| 106 | 0 | 0 |  |  |  | 0 | if ($self->can($raw_option)) { | 
| 107 | 0 |  |  |  |  | 0 | push @values, $self->$raw_option; | 
| 108 |  |  |  |  |  |  | } else { | 
| 109 | 0 |  | 0 |  |  | 0 | push @values, ($self->options->{$raw_option}||""); | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | } | 
| 112 | 0 |  |  |  |  | 0 | $max_length += 4; | 
| 113 | 0 |  |  |  |  | 0 | print STDERR "[start | stop | restart | status]\n"; | 
| 114 | 0 |  |  |  |  | 0 | foreach my $command (@commands) { | 
| 115 | 0 |  |  |  |  | 0 | my $cmd = sprintf("  --%-${max_length}s", $command); | 
| 116 | 0 |  |  |  |  | 0 | my $desc = shift @desc; | 
| 117 | 0 |  |  |  |  | 0 | my $value = shift @values; | 
| 118 | 0 |  |  |  |  | 0 | print STDERR "$cmd$desc: $value\n"; | 
| 119 |  |  |  |  |  |  | } | 
| 120 | 0 |  |  |  |  | 0 | exit; | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub parse_options { | 
| 124 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 0 |  |  |  |  | 0 | my %options; | 
| 127 |  |  |  |  |  |  | my %option_keys; | 
| 128 | 0 |  |  |  |  | 0 | my @options = ($self->default_options, @_); | 
| 129 | 0 |  |  |  |  | 0 | while(@options) { | 
| 130 | 0 |  |  |  |  | 0 | my $option = shift @options; | 
| 131 | 0 |  |  |  |  | 0 | my $default_value = shift @options; | 
| 132 | 0 |  |  |  |  | 0 | my $help = shift @options; | 
| 133 | 0 |  |  |  |  | 0 | $option_keys{$option} = $help; | 
| 134 | 0 |  |  |  |  | 0 | my ($key) = $option =~/(\w+)/; | 
| 135 | 0 | 0 |  |  |  | 0 | $options{$key} = $default_value if(defined $default_value); | 
| 136 |  |  |  |  |  |  | } | 
| 137 | 0 |  |  |  |  | 0 | GetOptions(\%options, keys %option_keys); | 
| 138 | 0 |  |  |  |  | 0 | $self->options(\%options); | 
| 139 | 0 |  |  |  |  | 0 | $self->options_desc(\%option_keys); | 
| 140 | 0 |  |  |  |  | 0 | $self->assign_options(qw(user group name chroot foreground daemon pidfile)); | 
| 141 | 0 |  |  |  |  | 0 | $self->init(); | 
| 142 | 0 |  |  |  |  | 0 | return \%options; | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 | 0 |  |  | 0 | 0 | 0 | sub init {} | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | sub print_version { | 
| 149 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 150 | 0 |  |  |  |  | 0 | my $name = $self->name; | 
| 151 | 0 |  |  |  |  | 0 | my $version = $self->version; | 
| 152 | 0 |  |  |  |  | 0 | print STDERR "$name $version (Working::Daemon: $VERSION)\n"; | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | sub assign_options { | 
| 157 | 0 |  |  | 0 | 0 | 0 | my ($self, @options) = @_; | 
| 158 | 0 |  |  |  |  | 0 | foreach my $option (@options) { | 
| 159 | 0 | 0 |  |  |  | 0 | $self->$option($self->options->{$option}) | 
| 160 |  |  |  |  |  |  | if (exists $self->options->{$option}); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | sub change_root { | 
| 166 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 167 | 0 | 0 |  |  |  | 0 | return unless $self->chroot; | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 0 |  |  |  |  | 0 | my $tmpdir = $self->tmpdir; | 
| 170 | 0 | 0 |  |  |  | 0 | mkdir ($tmpdir) | 
| 171 |  |  |  |  |  |  | || croak "Cannot create directory '$tmpdir': $!"; | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 0 | 0 |  |  |  | 0 | chown($self->uid,$self->gid, $tmpdir) | 
| 174 |  |  |  |  |  |  | || croak("Cannot chown $tmpdir to (". $self->uid . ":". $self->gid . "): $!"); | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 |  |  |  |  | 0 | my $dirs  = $self->{__PACKAGE__}->{chroot_clean_dirs} = []; | 
| 177 | 0 |  |  |  |  | 0 | my $files = $self->{__PACKAGE__}->{chroot_clean_files} = []; | 
| 178 |  |  |  |  |  |  |  | 
| 179 | 0 |  |  |  |  | 0 | foreach my $dir ($self->chroot_dirs) { | 
| 180 | 0 |  |  |  |  | 0 | push @$dirs, "$tmpdir/$dir"; | 
| 181 | 0 | 0 |  |  |  | 0 | mkdir("$tmpdir/$dir") | 
| 182 |  |  |  |  |  |  | || croak "Cannot create $tmpdir/$dir: $!"; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 | 0 |  |  |  |  | 0 | foreach my $file_to_copy ($self->chroot_files) { | 
| 186 | 0 |  |  |  |  | 0 | push @$files, "$tmpdir/$file_to_copy"; | 
| 187 | 0 | 0 |  |  |  | 0 | copy("$file_to_copy", "$tmpdir/$file_to_copy") | 
| 188 |  |  |  |  |  |  | || croak "Cannot copy $file_to_copy -> $tmpdir/$file_to_copy: $!"; | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 0 | 0 |  |  |  | 0 | chroot("$tmpdir/") | 
| 192 |  |  |  |  |  |  | || croak ("Can't chroot to $tmpdir: $!"); | 
| 193 | 0 | 0 |  |  |  | 0 | chdir("/") | 
| 194 |  |  |  |  |  |  | || croak ("Can't chdir to '/': $!"); | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | sub version { | 
| 198 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 199 | 0 |  |  |  |  | 0 | my $caller = caller(2); | 
| 200 | 2 |  |  | 2 |  | 34 | no strict 'refs'; | 
|  | 2 |  |  |  |  | 5 |  | 
|  | 2 |  |  |  |  | 2521 |  | 
| 201 | 0 |  |  |  |  | 0 | my $varname = "${caller}::VERSION"; | 
| 202 | 0 |  |  |  |  | 0 | my $version = $$varname; | 
| 203 | 0 |  | 0 |  |  | 0 | return $version || ""; | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | sub write_pidfile { | 
| 207 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 208 | 0 |  |  |  |  | 0 | my $pidfile = $self->pidfile; | 
| 209 | 0 | 0 |  |  |  | 0 | open(my $pidfh, "+>$pidfile") || croak "Cannot open '$pidfile': $!"; | 
| 210 | 0 |  |  |  |  | 0 | print $pidfh "$$"; | 
| 211 | 0 |  |  |  |  | 0 | close $pidfh; | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | sub delete_pidfile { | 
| 216 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 217 | 0 | 0 |  |  |  | 0 | unlink($self->pidfile) || croak "Cannot remove pidfile '".$self->pidfile."': $!"; | 
| 218 |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  |  | 
| 221 | 0 |  |  | 0 | 0 | 0 | sub cleanup_chroot { | 
| 222 |  |  |  |  |  |  | #    unlink("/tmp/glbdns.$pid/etc/protocols") || die "$!"; | 
| 223 |  |  |  |  |  |  | #    rmdir("/tmp/glbdns.$pid/etc/") || die; | 
| 224 |  |  |  |  |  |  | #    rmdir("/tmp/glbdns.$pid/") || die; | 
| 225 |  |  |  |  |  |  | #    unlink($config{pidfile}) || die $!; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | sub action_start { | 
| 229 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 230 | 0 |  |  |  |  | 0 | my $name = $self->name; | 
| 231 | 0 | 0 |  |  |  | 0 | if(my $pid = $self->get_pid) { | 
| 232 | 0 |  |  |  |  | 0 | $self->log(0, "fatal", "Cannot start '$name' because it is already running at $pid"); | 
| 233 | 0 |  |  |  |  | 0 | $self->exit_error; | 
| 234 |  |  |  |  |  |  | } | 
| 235 | 0 |  |  |  |  | 0 | $self->log(0, 'info', "Starting '$name'"); | 
| 236 | 0 |  |  |  |  | 0 | $self->daemonize; | 
| 237 | 0 |  |  |  |  | 0 | $self->spawn_worker_child; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | sub spawn_worker_child { | 
| 241 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 242 | 0 | 0 |  |  |  | 0 | if(my $pid = fork()) { | 
| 243 | 0 |  |  |  |  | 0 | my $name = $self->name; | 
| 244 |  |  |  |  |  |  | # this is the master session | 
| 245 |  |  |  |  |  |  | # it makes sure to cleanup from the slave | 
| 246 |  |  |  |  |  |  | # it stays as superuser | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  |  | 
| 249 | 0 |  |  |  |  | 0 | $self->write_pidfile; | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 0 |  |  |  |  | 0 | $self->openlog; | 
| 252 | 0 |  |  |  |  | 0 | $self->log(1, 'info', "started master session $name - child is $pid"); | 
| 253 | 0 |  |  | 0 |  | 0 | $SIG{INT} = sub { kill(2,$pid) }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 254 | 0 |  |  |  |  | 0 | $0 = "$name - waiting for child $pid"; | 
| 255 | 0 |  |  |  |  | 0 | $self->wait_for_worker_child($pid); | 
| 256 | 0 |  |  |  |  | 0 | $self->log(1, 'info', "exiting master session $name - child is $pid"); | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 0 |  |  |  |  | 0 | $self->cleanup_chroot; | 
| 259 |  |  |  |  |  |  |  | 
| 260 | 0 |  |  |  |  | 0 | $self->delete_pidfile; | 
| 261 | 0 |  |  |  |  | 0 | exit; | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  |  | 
| 264 | 0 |  |  |  |  | 0 | return 1; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | sub wait_for_worker_child { | 
| 268 | 0 |  |  | 0 | 0 | 0 | my ($self, $pid) = @_; | 
| 269 | 0 |  |  |  |  | 0 | waitpid($pid, 0); | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | sub action_restart { | 
| 273 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 274 | 0 | 0 |  |  |  | 0 | if ($self->is_running) { | 
| 275 | 0 |  |  |  |  | 0 | $self->action_stop | 
| 276 |  |  |  |  |  |  | } | 
| 277 | 0 |  |  |  |  | 0 | $self->action_start; | 
| 278 |  |  |  |  |  |  | } | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | sub action_status { | 
| 281 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 282 | 0 | 0 |  |  |  | 0 | if (my $pid = $self->is_running) { | 
| 283 | 0 |  |  |  |  | 0 | print STDERR $self->name . " is running on $pid\n"; | 
| 284 | 0 |  |  |  |  | 0 | return 0; | 
| 285 |  |  |  |  |  |  | } else { | 
| 286 | 0 |  |  |  |  | 0 | print STDERR $self->name . " is not running\n"; | 
| 287 | 0 |  |  |  |  | 0 | return 1; | 
| 288 |  |  |  |  |  |  | } | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | sub action_stop { | 
| 292 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 293 | 0 |  |  |  |  | 0 | my $pid = $self->is_running; | 
| 294 | 0 | 0 |  |  |  | 0 | if ($pid) { | 
| 295 | 0 |  |  |  |  | 0 | while($self->is_running) { | 
| 296 | 0 |  |  |  |  | 0 | kill(2, $pid); | 
| 297 | 0 |  |  |  |  | 0 | $self->log(0, 'info', "sent SIGINT to $pid - waiting on stopped pid $pid"); | 
| 298 | 0 |  |  |  |  | 0 | sleep 1; | 
| 299 |  |  |  |  |  |  | } | 
| 300 | 0 |  |  |  |  | 0 | $self->log(0, 'info',"Stopped " . $self->name . " on $pid"); | 
| 301 |  |  |  |  |  |  | } else { | 
| 302 | 0 |  |  |  |  | 0 | $self->log(0, 'info', $self->name . " is not running"); | 
| 303 |  |  |  |  |  |  | } | 
| 304 | 0 |  |  |  |  | 0 | return 0; | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | sub is_running { | 
| 308 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 309 | 0 |  |  |  |  | 0 | my $pid = $self->get_pid; | 
| 310 | 0 | 0 |  |  |  | 0 | return $pid | 
| 311 |  |  |  |  |  |  | if($self->check_pid($pid)); | 
| 312 | 0 |  |  |  |  | 0 | return 0; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 | 0 |  |  | 0 | 0 | 0 | sub openlog { | 
| 316 |  |  |  |  |  |  | #        openlog("$config{name}", 'ndelay,pid', LOG_DAEMON) if($config{syslog});} | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | sub get_pid { | 
| 321 |  |  |  |  |  |  | # pid code needs serious overhaul to use flock | 
| 322 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 323 | 0 |  |  |  |  | 0 | my $pidfile = $self->pidfile; | 
| 324 | 0 | 0 |  |  |  | 0 | if(-r $pidfile) { | 
| 325 | 0 | 0 |  |  |  | 0 | open(my $pidfh, "<$pidfile") || croak "Cannot open pidfile ($pidfile): $!"; | 
| 326 | 0 |  |  |  |  | 0 | my $line = <$pidfh>; | 
| 327 | 0 |  |  |  |  | 0 | close($pidfh); | 
| 328 | 0 |  |  |  |  | 0 | $line =~/(\d+)/; | 
| 329 | 0 | 0 |  |  |  | 0 | if(my $pid_to_check = $1) { | 
| 330 | 0 |  |  |  |  | 0 | $ENV{PATH} = ''; | 
| 331 | 0 | 0 |  |  |  | 0 | return $pid_to_check if($self->check_pid($pid_to_check)); | 
| 332 |  |  |  |  |  |  | } | 
| 333 |  |  |  |  |  |  | } | 
| 334 | 0 |  |  |  |  | 0 | return 0; | 
| 335 |  |  |  |  |  |  | } | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  |  | 
| 338 |  |  |  |  |  |  | sub check_pid { | 
| 339 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 340 | 0 |  |  |  |  | 0 | my $pid  = shift; | 
| 341 | 0 | 0 |  |  |  | 0 | return 0 unless $pid; | 
| 342 | 0 |  |  |  |  | 0 | my $grep = "/bin/grep"; | 
| 343 | 0 | 0 |  |  |  | 0 | $grep = "/usr/bin/grep" if ($^O eq 'darwin'); | 
| 344 | 0 |  |  |  |  | 0 | my $name = $self->name; | 
| 345 | 0 |  |  |  |  | 0 | my $rv = qx{/bin/ps ax | $grep $pid | $grep -v grep | $grep $name}; | 
| 346 | 0 |  |  |  |  | 0 | $rv =~s/\s+$//; | 
| 347 | 0 |  |  |  |  | 0 | print STDERR "$rv\n"; | 
| 348 | 0 |  |  |  |  | 0 | return !$?; | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | sub daemonize { | 
| 353 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 354 | 0 | 0 |  |  |  | 0 | return 0 unless $self->daemon; | 
| 355 | 2 |  |  | 2 |  | 32719 | use POSIX qw(setsid); | 
|  | 2 |  |  |  |  | 84551 |  | 
|  | 2 |  |  |  |  | 20 |  | 
| 356 | 0 |  |  |  |  | 0 | my $name = $self->name; | 
| 357 | 0 | 0 |  |  |  | 0 | defined(my $pid = fork) || croak "Can't fork: $!"; | 
| 358 | 0 | 0 |  |  |  | 0 | if ($pid) { | 
| 359 | 0 |  |  |  |  | 0 | print "$name started on $pid\n"; | 
| 360 | 0 |  |  |  |  | 0 | exit 0; | 
| 361 |  |  |  |  |  |  | } | 
| 362 | 0 | 0 |  |  |  | 0 | setsid() || croak "Can't start a new session: $!"; | 
| 363 | 0 | 0 |  |  |  | 0 | open (STDIN , '/dev/null') || croak "Can't read /dev/null: $!"; | 
| 364 | 0 | 0 |  |  |  | 0 | open (STDOUT, '>/dev/null') || croak "Can't write to /dev/null: $!"; | 
| 365 | 0 | 0 |  |  |  | 0 | open (STDERR, '>/dev/null') || croak "Can't write to /dev/null: $!"; | 
| 366 | 0 |  |  |  |  | 0 | return 1; | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | sub log { | 
| 371 | 0 |  |  | 0 | 0 | 0 | my ($self, $level, $prio, $msg) = @_; | 
| 372 | 0 | 0 |  |  |  | 0 | return if ($level > $self->log_level); | 
| 373 | 0 |  |  |  |  | 0 | $self->do_log($prio, $msg); | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  |  | 
| 376 |  |  |  |  |  |  |  | 
| 377 |  |  |  |  |  |  | sub do_log { | 
| 378 | 0 |  |  | 0 | 0 | 0 | my ($self, $prio, $msg) = @_; | 
| 379 | 0 |  |  |  |  | 0 | print STDERR "$prio - $msg\n"; | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | sub drop_privs { | 
| 384 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 385 |  |  |  |  |  |  | # drop user | 
| 386 | 0 |  |  |  |  | 0 | $< = $self->uid; | 
| 387 | 0 |  |  |  |  | 0 | $> = $self->uid; | 
| 388 |  |  |  |  |  |  | # drop group | 
| 389 | 0 |  |  |  |  | 0 | $( = $self->gid; | 
| 390 | 0 |  |  |  |  | 0 | $) = $self->gid; | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | sub uid { | 
| 395 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 396 | 0 |  |  |  |  | 0 | return scalar getpwnam($self->user); | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | sub gid { | 
| 401 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 402 | 0 |  |  |  |  | 0 | return scalar getpwnam($self->group); | 
| 403 |  |  |  |  |  |  | } | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | # accessors | 
| 408 |  |  |  |  |  |  | # yes they are nearly identical | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | sub user { | 
| 411 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 412 | 0 | 0 |  |  |  | 0 | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 413 | 0 |  |  |  |  | 0 | return $self->{__PACKAGE__}->{user} = shift; | 
| 414 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{user})) { | 
| 415 | 0 |  |  |  |  | 0 | return $self->{__PACKAGE__}->{user}; | 
| 416 |  |  |  |  |  |  | } else { | 
| 417 | 0 |  |  |  |  | 0 | return "nobody"; | 
| 418 |  |  |  |  |  |  | } | 
| 419 |  |  |  |  |  |  | } | 
| 420 |  |  |  |  |  |  |  | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | sub pidfile { | 
| 423 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 424 | 0 | 0 |  |  |  | 0 | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 425 | 0 |  |  |  |  | 0 | return $self->{__PACKAGE__}->{pidfile} = shift; | 
| 426 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{pidfile})) { | 
| 427 | 0 |  |  |  |  | 0 | return $self->{__PACKAGE__}->{pidfile}; | 
| 428 |  |  |  |  |  |  | } else { | 
| 429 | 0 |  |  |  |  | 0 | return "/var/run/". $self->name . ".pid"; | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  | } | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | sub daemon { | 
| 435 | 10 |  |  | 10 | 0 | 26 | my $self = shift; | 
| 436 | 10 | 100 |  |  |  | 56 | if (@_) { | 
|  |  | 100 |  |  |  |  |  | 
| 437 | 2 |  |  |  |  | 13 | return $self->{__PACKAGE__}->{daemon} = shift; | 
| 438 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{daemon})) { | 
| 439 | 4 |  |  |  |  | 28 | return $self->{__PACKAGE__}->{daemon}; | 
| 440 |  |  |  |  |  |  | } else { | 
| 441 | 4 |  |  |  |  | 23 | return 1; | 
| 442 |  |  |  |  |  |  | } | 
| 443 |  |  |  |  |  |  | } | 
| 444 |  |  |  |  |  |  |  | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | sub foreground { | 
| 447 | 5 |  |  | 5 | 0 | 13 | my $self = shift; | 
| 448 | 5 | 100 |  |  |  | 20 | if (@_) { | 
| 449 | 1 |  |  |  |  | 4 | return $self->daemon(!$_[0]); | 
| 450 |  |  |  |  |  |  | } else { | 
| 451 | 4 |  |  |  |  | 14 | return !$self->daemon; | 
| 452 |  |  |  |  |  |  | } | 
| 453 |  |  |  |  |  |  | } | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | sub chroot { | 
| 457 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 458 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 459 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{chroot} = shift; | 
| 460 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{chroot})) { | 
| 461 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{chroot}; | 
| 462 |  |  |  |  |  |  | } else { | 
| 463 | 0 |  |  |  |  |  | return 1; | 
| 464 |  |  |  |  |  |  | } | 
| 465 |  |  |  |  |  |  | } | 
| 466 |  |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | sub log_level { | 
| 469 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 470 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 471 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{log_level} = shift; | 
| 472 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{log_level})) { | 
| 473 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{log_level}; | 
| 474 |  |  |  |  |  |  | } else { | 
| 475 | 0 |  |  |  |  |  | return 1; | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | sub group { | 
| 481 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 482 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 483 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{group} = shift; | 
| 484 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{group})) { | 
| 485 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{group}; | 
| 486 |  |  |  |  |  |  | } else { | 
| 487 | 0 |  |  |  |  |  | return "nobody"; | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  | } | 
| 490 |  |  |  |  |  |  |  | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | sub name { | 
| 493 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 494 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 495 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{name} = shift; | 
| 496 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{name})) { | 
| 497 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{name}; | 
| 498 |  |  |  |  |  |  | } else { | 
| 499 | 0 |  |  |  |  |  | return "unnamed app"; | 
| 500 |  |  |  |  |  |  | } | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  |  | 
| 504 |  |  |  |  |  |  | sub options { | 
| 505 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 506 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 507 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{options} = shift; | 
| 508 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{options})) { | 
| 509 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{options}; | 
| 510 |  |  |  |  |  |  | } else { | 
| 511 | 0 |  |  |  |  |  | return {}; | 
| 512 |  |  |  |  |  |  | } | 
| 513 |  |  |  |  |  |  | } | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | sub options_desc { | 
| 516 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 517 | 0 | 0 |  |  |  |  | if (@_) { | 
|  |  | 0 |  |  |  |  |  | 
| 518 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{options_desc} = shift; | 
| 519 |  |  |  |  |  |  | } elsif (exists($self->{__PACKAGE__}->{options_desc})) { | 
| 520 | 0 |  |  |  |  |  | return $self->{__PACKAGE__}->{options_desc}; | 
| 521 |  |  |  |  |  |  | } else { | 
| 522 | 0 |  |  |  |  |  | return {}; | 
| 523 |  |  |  |  |  |  | } | 
| 524 |  |  |  |  |  |  | } | 
| 525 |  |  |  |  |  |  |  | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  |  | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | # Preloaded methods go here. | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | # Autoload methods go after =cut, and are processed by the autosplit program. | 
| 534 |  |  |  |  |  |  |  | 
| 535 |  |  |  |  |  |  | 1; | 
| 536 |  |  |  |  |  |  | __END__ |