package Systemd::Daemon;

use 5.006;
use strict;
use warnings FATAL => 'all';

=encoding UTF-8

=head1 NAME

Systemd::Daemon — __ABSTRACT__.

=head1 VERSION

Version __VERSION__.

=cut

our $VERSION = '__VERSION__';

=head1 SYNOPSIS

Functions:

    use Systemd::Daemon qw{ :funcs };

    notify( RELOADING => 1 );

    while ( ... ) {
        notify( STATUS => "Loading, $percent% done" );
        ...
    };

    notify( READY => 1, STATUS => "Ready" );
    ...

    notify( STOPPING => 1 );
    ...

Low-level bare C functions:

    use Systemd::Daemon qw{ :bare };

    sd_notify( 0, "READY=1\nSTATUS=Ready\n" );
    sd_pid_notify( $pid, 0, "READ=1\nSTATUS=Ready\n" );
    if ( sd_booted() > 0 ) { ... };

=cut

use Inline
    C         => 'DATA',
    filters   => 'Strip_POD',
    libs      => '-lsystemd',   # TODO: Use pkg-config.
    name      => __PACKAGE__,
    version   => '__VERSION__',
    autowrap  => 1,
    clean_after_build => 1,
        #   Is this comment still valid?
        #   `clean_after_build => 0` causes `make install` to fail, see
        #       https://github.com/ingydotnet/inline-pm/issues/53
        #   `clean_after_build => 1` causes errors when building RPM: rpmbuild
        #   tries to extract debug information from files which were wiped out.
    ;

Inline->init();

=head1 EXPORT

No functions are exported by default. There are 3 import tags:

=over

=item :funcs

Import higher-level Perl wrappers.

=item :bare

Import low-level bare C functions.

=item :all

Import all the functions.

=back

Also, each function can be imported individually, e. g.:

    use Systemd::Daemon qw{ notify };

=cut

use Exporter qw{ import };
our %EXPORT_TAGS;
our @EXPORT_OK;
BEGIN {
    %EXPORT_TAGS = (
        funcs   => [ qw{ notify } ],
        bare    => [ qw{ sd_notify sd_pid_notify sd_booted sd_watchdog_enabled } ],
    );
    Exporter::export_ok_tags( qw{ funcs bare } );
    $EXPORT_TAGS{ all } = \@EXPORT_OK;
}; # BEGIN

=head1 SUBROUTINES

=head2 Perl subroutines

=head3 notify( VAR => VALUE, ... )

C<notify> is Perl wrapper for C functions C<sd_notify> and C<sd_pid_notify>, so read
L<sd_notify(3)> first.

C functions accept status as one string of newline-separated variable assignments, e. g.:

    sd_notify( 0, "RELOADING=1\nSTATUS=50% done\n" );

Unlike to C functions, C<notify> accepts each variable separately as Perl "named arguments", e. g.:

    notify( RELOADING => 1, STATUS => "50% done" );

C<unset_environment> and C<pid> parameters can be specified as named arguments C<unset> and C<pid>
respectively, e. g.:

    notify( pid => $pid, unset => 1, ... );

If C<pid> value is defined and not zero, C<notify> calls C<sd_pid_notify>, otherwise C<sd_notify>
is called. C<unset> is defaulted to zero.

L<sd_notify(3)> describes some "well-known" variable assignments, for example, C<RELOADING=1>.
Systemd's reaction on assignment C<RELOADING=2> is not defined. In my experiments with systemd v217
any value but C<1> does not have any effect. To make C<notify> more Perlish, C<READY>,
C<RELOADING>, C<STOPPING>, and C<WATCHDOG> arguments are normalized: if its value is false (e. g.
undef, zero or empty string), the respective variable is not passed to underlying C function; if
its value is true (not false), the respective variable is set to C<1>.

C<notify> returns result of underlying C<sd_notify> (or C<sd_pid_notify>). It should be negative
integer in case of error, zero if C<$ENV{ NOTIFY_SOCKET }> is not set (and so, systemd cannot be
notified), and some positive value in case of success. However, L<sd_notify(3)> recommends to
ignore return value.

=cut

sub notify(@) {
    my ( %args ) = @_;
    my $pid   = ( delete( $args{ pid   } ) or 0 );
    my $unset = ( delete( $args{ unset } ) or 0 );
    foreach my $k ( qw{ READY RELOADING STOPPING WATCHDOG } ) {
        delete( $args{ $k } ) and $args{ $k } = 1;
    }; # foreach
    my $state = join( '', map( "$_=$args{ $_ }\n", keys( %args ) ) );
    my $rc;
    if ( $pid != 0  ) {
        $rc = sd_pid_notify( $pid, $unset, $state );
    } else {
        $rc = sd_notify( $unset, $state );
    }; # if
    return $rc;
}; # sub notify

1;

__DATA__

__C__

=head2 C subroutines

Low-level bare C functions:

=over

=item int sd_notify( int unset_environment, const char * state );

=item int sd_pid_notify( int pid, int unset_environment, const char * state );

See L<sd_notify(3)>.

=item int sd_booted( void );

See L<sd_booted(3)>.

=item int sd_watchdog_enabled( int unset_environment, uint64_t * usec );

See L<sd_watchdog_enabled(3)>.

=back

=cut

int sd_notify( int unset_environment, const char * state );
int sd_pid_notify( int pid, int unset_environment, const char * state );
int sd_booted( void );
int sd_watchdog_enabled( int unset_environment, uint64_t * usec );

=head1 AUTHOR

Van de Bugger, <van.de.bugger@liamg.moc>

=head1 BUGS

Please report any bugs or feature requests to C<bug-systemd-daemon at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Systemd-Daemon>.
I will be notified, and then you'll automatically be notified of progress on your bug as I make
changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Systemd::Daemon

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker (report bugs here)

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Systemd-Daemon>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Systemd-Daemon>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Systemd-Daemon>

=item * Search CPAN

L<http://search.cpan.org/dist/Systemd-Daemon/>

=back

=head1 ACKNOWLEDGEMENTS

TODO

=head1 LICENSE AND COPYRIGHT

This program 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 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see L<http://www.gnu.org/licenses/>.

Copyright © 2015 Van de Bugger.

=cut

// end of file //
