wgnd-watch.pl
changeset 30 c5026a0ae757
parent 29 a589fb3599fb
equal deleted inserted replaced
29:a589fb3599fb 30:c5026a0ae757
     1 #!/usr/bin/perl
       
     2 
       
     3 #    Copyright (C) 2012-2017  Matthias Förste
       
     4 #
       
     5 #    This program is free software: you can redistribute it and/or modify
       
     6 #    it under the terms of the GNU General Public License as published by
       
     7 #    the Free Software Foundation, either version 3 of the License, or
       
     8 #    (at your option) any later version.
       
     9 #
       
    10 #    This program is distributed in the hope that it will be useful,
       
    11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    13 #    GNU General Public License for more details.
       
    14 #
       
    15 #    You should have received a copy of the GNU General Public License
       
    16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    17 #
       
    18 #    Matthias Förste <foerste@schlittermann.de>
       
    19 
       
    20 =encoding utf8
       
    21 =cut
       
    22 
       
    23 use strict;
       
    24 use warnings;
       
    25 
       
    26 my $VERSION = '0.1';
       
    27 my $ME      = $0;
       
    28 
       
    29 use File::Basename;
       
    30 
       
    31 # File::Rsync in squeeze does not support --xattrs yet
       
    32 #use File::Rsync;
       
    33 use Getopt::Long;
       
    34 use Pod::Usage;
       
    35 use Linux::Inotify2;
       
    36 use Sys::Syslog;
       
    37 
       
    38 my $master;
       
    39 
       
    40 BEGIN {
       
    41 
       
    42     openlog($ME, 'ndelay,nowait,pid', 'LOG_USER');
       
    43     $SIG{__WARN__} = sub {
       
    44         warn @_ if not defined $^S;
       
    45         print STDERR "@_";
       
    46         syslog('warning', "@_");
       
    47     };
       
    48     $SIG{__DIE__} = sub {
       
    49         die @_ if not defined $^S;
       
    50         print STDERR "@_";
       
    51         syslog('err', "@_");
       
    52         exit $?;
       
    53     };
       
    54     sub dolog { print "@_"; syslog('info', "@_"); }
       
    55     sub trace { print @_ if $ENV{DEBUG}; }
       
    56 
       
    57     use sigtrap qw(die normal-signals);
       
    58 
       
    59 }
       
    60 
       
    61 my %opts = (
       
    62     daemon  => 1,
       
    63     map     => 'wgnd-watch.map.pl',
       
    64     pidfile => '/var/run/wgnd-watch.pid',
       
    65     'rsync-args' => [ qw(-ihv -aAX --no-times) ],
       
    66     'rsync-cmd' => '/usr/bin/rsync'
       
    67 );
       
    68 
       
    69 GetOptions(
       
    70     "map=s"     => \$opts{map},
       
    71     "daemon!"   => \$opts{daemon},
       
    72     "pidfile=s" => \$opts{pidfile},
       
    73     "rsync-args=s@" => \$opts{'rsync-args'},
       
    74     "rsync-cmd=s" => \$opts{'rsync-cmd'},
       
    75     "h|help!"   => sub { pod2usage(-verbose => 0, -exitval => 0) },
       
    76     "m|man!"    => sub {
       
    77         pod2usage(
       
    78             -verbose   => 2,
       
    79             -exitval   => 0,
       
    80             -noperldoc => (`perldoc -V 2>/dev/null`, $? != 0)[-1]
       
    81         );
       
    82     },
       
    83 ) or pod2usage();
       
    84 
       
    85 our $source;
       
    86 use lib grep { defined } ('.', $ENV{HOME}, '/etc');
       
    87 require $opts{map};
       
    88 
       
    89 $0 = "$ME @ARGV";
       
    90 
       
    91 chdir("/") or die "Can't chdir to /: $!\n";
       
    92 
       
    93 if ($opts{daemon}) {
       
    94 
       
    95     open STDIN,  "</dev/null" or die "Can't redir STDIN: $!\n";
       
    96     open STDOUT, ">/dev/null" or die "Can't redir STDOUT: $!\n";
       
    97 
       
    98     defined(my $pid = fork) or die "Can't fork: $!\n";
       
    99     if ($pid) {
       
   100         dolog "Child is [$pid]";
       
   101         exit 0;
       
   102     }
       
   103     POSIX::setsid()
       
   104       or die "Can't setsid: $!\n";
       
   105     open(STDERR, ">&STDOUT") or die "Can't dup stdout: $!\n";
       
   106 
       
   107     open(P, '>', $opts{pidfile})
       
   108       or die "Can't open '>', '$opts{pidfile}': $!\n";
       
   109     print P $$;
       
   110     close P;
       
   111     $master = $$;
       
   112 
       
   113 }
       
   114 
       
   115 my $inotify = new Linux::Inotify2
       
   116   or die "Can't create new inotify object: $!\n";
       
   117 my @rsync = ($opts{'rsync-cmd'}, @{$opts{'rsync-args'}});
       
   118 
       
   119 for (keys %{$source}) {
       
   120 
       
   121     # add watchers
       
   122     $inotify->watch(
       
   123         "$_",
       
   124         IN_CREATE,
       
   125         sub {
       
   126 
       
   127             my $pid = fork;
       
   128 
       
   129             if (not defined $pid) {
       
   130                 warn "Can't fork: $!\n";
       
   131             } elsif ($pid == 0) {
       
   132                 my $e    = shift;
       
   133                 my $name = $e->fullname;
       
   134                 dolog "$name was created\n"               if $e->IN_CREATE;
       
   135                 dolog "$name is no longer mounted\n"      if $e->IN_UNMOUNT;
       
   136                 dolog "$name is gone\n"                   if $e->IN_IGNORED;
       
   137                 dolog "events for $name have been lost\n" if $e->IN_Q_OVERFLOW;
       
   138                 exec @rsync, $source->{ $e->{w}->{name} }, $name;
       
   139                 warn "Can't exec: $!\n";
       
   140             }
       
   141 
       
   142         }
       
   143     ) or die "Can't add watch: $!\n";
       
   144 }
       
   145 
       
   146 while (1) {
       
   147 
       
   148     $inotify->poll;
       
   149     while (-1 != (my $pid = wait)) {
       
   150         my $e = $? >> 8;
       
   151         dolog "Child ${ME}[$pid]: exit $e\n";
       
   152     }
       
   153 
       
   154 }
       
   155 
       
   156 END {
       
   157 
       
   158     unlink $opts{pidfile}
       
   159       if $opts{daemon}
       
   160           and defined $master
       
   161           and $master eq $$;
       
   162     dolog "exit";
       
   163     closelog;
       
   164 
       
   165 }
       
   166 
       
   167 __END__
       
   168 
       
   169 =pod
       
   170 
       
   171 =head1 NAME
       
   172 
       
   173 wgnd-watch - inotify actions for wiegand
       
   174 
       
   175 =head1 SYNOPSIS
       
   176 
       
   177 wgnd-watch [--map filename]
       
   178 
       
   179 wgnd-watch -m|--man
       
   180            -h|--help
       
   181 
       
   182 =head1 DESCRIPTION
       
   183 
       
   184 wgnd-watch currently watches some directories for newly created subdirectories
       
   185 and synchronises these from a given template directory.
       
   186 
       
   187 =head1 OPTIONS
       
   188 
       
   189 =over
       
   190 
       
   191 =item B<--[no]daemon>
       
   192 
       
   193 [Don't] run as a daemon. Default: do.
       
   194 
       
   195 =item B<--map> I<filename>
       
   196 
       
   197 Name of a file containing mappings between templates and directories. Defaults
       
   198 to F<wgnd-watch.map.pl>.
       
   199 
       
   200 =item B<--pidfile> I<filename>
       
   201 
       
   202 Location of the pid file. This is ignored unless we are running as a daemon.
       
   203 Defaults to F</var/run/wgnd-watch.pid>.
       
   204 
       
   205 =item B<--pidfile> I<filename>
       
   206 
       
   207 Location of the pid file. This is ignored unless we are running as a daemon.
       
   208 Defaults to F</var/run/wgnd-watch.pid>.
       
   209 
       
   210 =item B<--rsync-args> I<args>
       
   211 
       
   212 Arguments to pass to the rsync command. May be given multiple times. Defaults to B<-ihv -aAX --no-times>.
       
   213 
       
   214 =item B<--rsync-cmd> I<cmd>
       
   215 
       
   216 Rsync Command. Defaults to F</usr/bin/rsync>.
       
   217 
       
   218 =back
       
   219 
       
   220 =head1 FILES
       
   221 
       
   222 =over
       
   223 
       
   224 =item F<wgnd-watch.map.pl>
       
   225 
       
   226 default for B<--map>
       
   227 
       
   228 =item F</var/run/wgnd-watch.pid>
       
   229 
       
   230 default for B<--pidfile>
       
   231 
       
   232 =back
       
   233 
       
   234 =head1 AUTHOR
       
   235 
       
   236 Matthias Förste <foerste@schlittermann.de>
       
   237 
       
   238 =cut