#!/usr/bin/perl -w

use strict;
use warnings;

use Pod::Usage;
use Getopt::Long;
use File::Lock::ParentLock;

#my $verbose=0;
my $help=0;

my ($lockfile,$pid);
my ($lock,$unlock,$status);
my ($is_locked_by_others,$is_locked_by_us);
my $verbose=1;

my $result = GetOptions (
    'q|quiet'=> sub {$verbose=0},
    "v|verbose+"  => \$verbose,
    "help"  => \$help,
    "pid=s"  => \$pid,
    "f|file|lockfile=s"  => \$lockfile,
    "l|lock"  => \$lock,
    "unlock"  => \$unlock,
    "status"  => \$status,
    "is-locked-by-others"  => \$is_locked_by_others,
    "is-locked-by-us"  => \$is_locked_by_us,
);

if ($help) {
    pod2usage();
}

$lockfile=shift @ARGV if @ARGV and not $lockfile;
$pid=shift @ARGV if @ARGV and not $pid;
if (@ARGV) {
    warn "ERROR: too many command line arguments! ".join(' ',@ARGV)."\n";
    pod2usage();
} elsif ($lock and $unlock) {
    warn "ERROR: both --lock and --unlock options are present!\n";
    pod2usage();
} elsif (not $lock and not $unlock and not $status and not $is_locked_by_us and not $is_locked_by_others) {
    warn "ERROR: one of --lock, --unlock, --status or is-locked-by-* options should be present!\n";
    pod2usage();
}

my $locker= File::Lock::ParentLock->new(
	-lockfile=>$lockfile,
	-pid=>$pid,
    );

my $exit_code=0;
if ($lock) {
    $exit_code=2 if !$locker->lock();
} elsif ($unlock) {
    $exit_code=2 if !$locker->unlock();
} elsif ($is_locked_by_others) {
    $exit_code=1 if !$locker->is_locked_by_others();
} elsif ($is_locked_by_us) {
    $exit_code=1 if !$locker->is_locked_by_us();
}
if ($status or $verbose and $exit_code==2) {
    print "ParentLock status: ", $locker->status_string(),"\n";
}
exit $exit_code;


__END__



=head1	NAME

parentlock - share parent's lock with child processes.

=head1	SYNOPSIS

B<parentlock>
[B<-v>]
[B<--lock> | B<--unlock> | B<--is-locked-by-us> | B<--is-locked-by-others>]
[B<--status>]
[B<--lockfile>] I<lockfile>
[B<-p|--pid>] I<PID>

=head1	DESCRIPTION

B<parentlock> is useful for shell scripting where there are lots of 
nested script calls and we want to share a lock from the main wrapper
script for its subprocesses through the parent - child relationship.

Note that unlocking is optional because the lock becomes invalid
when the process whose pid is contained in the lock dies.

=head1	EXAMPLES

In each chell script add at the beginning

 #!/bin/sh
 LOCKFILE=/workdir/.lock
 parentlock --lock --lockfile $LOCKFILE $$ || exit 1
 ...

Optionally, add at the end of the script, to clean up stale lock file:

 ...
 parentlock --unlock --lockfile $LOCKFILE $$

=head1	OPTIONS

=over

=item	B<-l,--lock>

Lock

=item	B<-u,--unlock>

Unlock

=item	B<--is-locked-by-us>

Query about existing lock. Returns true if it is locked by I<PID> or its parent.
Return false ottherwise.

=item	B<--is-locked-by-others>

Query about existing lock. Returns true if is locked by a live process not related to I<PID>.
Return false ottherwise.

=item	B<--status>

Print the lock status against the parent pid I<PID>.

=item	B<-p,--pid>

PID to lock with.

=item	B<-f,--file,--lockfile> I<path>

Lockfile name to be created. A relative path will be converted
to the absolute path at the moment script called.

=item	B<-v,--verbose>

Increase verbosity level.

=item	B<-q,--quiet>

Silent mode.

=back

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	ACKNOWLEGEMENTS

To Alexey Torbin <at@altlinux.org>, whose qa-robot package
had a strong influence on repocop. 

=head1	COPYING

Copyright (c) 2008-2018 Igor Vlasenko, ALT Linux Team.

This is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

=cut
