Daemon-Control

 view release on metacpan or  search on metacpan

lib/Daemon/Control.pm  view on Meta::CPAN


    # Shortcut caused by setting foreground or using the ENV to do it.
    if ( ( $self->foreground == 1 ) || ( $ENV{DC_FOREGROUND} ) ) {
        $self->fork( 0 );
        $self->quiet( 1 );
    }

    die "Unknown arguments to the constructor: " . join( " ", keys %$args )
        if keys( %$args );

    return $self;
}

sub with_plugins {
    my ( $class, @in ) = @_;

    # ->with_plugins()->new is just ->new...
    return $class unless @in;

    # Make sure we have Role::Tiny installed.
    local $@;
    eval "require Role::Tiny";
    if ( $@ ) {
        die "Error: Role::Tiny is required for with_plugins to function.\n";
    }

    # Take an array or arrayref as an argument
    # and mutate it into a list like this:
    #   'Module'  -> Becomes -> 'Root::Module'
    #   '+Module' ->  Becomes -> 'Module'
    my @plugins = map {
        substr( $_, 0, 1 ) eq '+'
            ? substr( $_, 1 )
            : "Daemon::Control::Plugin::$_"
    } ref $in[0] eq 'ARRAY' ? @{ $in[0] } : @in;


    # Compose the plugins into our class, and return for the user
    # to call ->new().
    return Role::Tiny->create_class_with_roles( $class, @plugins );
}

# Set the uid, triggered from getting the uid if the user has changed.
sub _set_uid_from_name {
    my ( $self ) = @_;
    return unless defined $self->user;

    my $uid = getpwnam( $self->user );
    die "Error: Couldn't get uid for non-existent user " . $self->user
        unless defined $uid;
    $self->trace( "Set UID => $uid" );
    $self->uid( $uid );
}

# Set the uid, triggered from getting the gid if the group has changed.
sub _set_gid_from_name {
    my ( $self ) = @_;

    # Grab the GID if we have a UID but no GID.
    if ( !defined $self->group && defined $self->uid ) {
        my ( $gid ) = ( (getpwuid( $self->uid ))[3] );
        $self->gid( $gid );
        $self->trace( "Implicit GID => $gid" );
        return $gid;
    }

    return unless defined $self->group;

    my $gid = getgrnam( $self->group );
    die "Error: Couldn't get gid for non-existent group " . $self->group
        unless defined $gid;
    $self->trace( "Set GID => $gid" );
    $self->gid( $gid );

}

sub redirect_filehandles {
    my ( $self ) = @_;

    if ( $self->stdout_file ) {
        my $file = $self->stdout_file;
        $file = $file eq '/dev/null' ? File::Spec->devnull : $file;

        if ( ref $file eq 'ARRAY' ) {
            my $mode = shift @$file;
            open STDOUT, $mode, @$file ? @$file : ()
                or die "Failed to open STDOUT with args $mode @$file: $!";

            $self->trace("STDOUT redirected to open(STDOUT $mode @$file)");
        }
        else {
            open STDOUT, ">>", $file
                or die "Failed to open STDOUT to $file: $!";
            $self->trace( "STDOUT redirected to $file" );
        }
    }
    if ( $self->stderr_file ) {
        my $file = $self->stderr_file;
        $file = $file eq '/dev/null' ? File::Spec->devnull : $file;

        if ( ref $file eq 'ARRAY' ) {
            my $mode = shift @$file;
            open STDERR, $mode, @$file ? @$file : ()
                or die "Failed to open STDERR with args $mode @$file: $!";

            $self->trace("STDERR redirected to open(STDERR $mode @$file)");
        }
        else {
            open STDERR, ">>", $file
                or die "Failed to open STDERR to $file: $!";
            $self->trace("STDERR redirected to $file");
        }
    }
}

sub _create_resource_dir {
    my ( $self ) = @_;
    $self->_create_dir($self->resource_dir);
}

sub _create_dir {
    my ( $self, $dir ) = @_;

    return 0 unless defined $dir;
    return 1 unless length($dir);

    if ( -d $dir ) {
        $self->trace( "Dir exists (" . $dir . ") - no need to create" );
        return 1;
    }

    my ( $created ) = make_path(
        $dir,
        {
            uid => $self->uid,
            group => $self->gid,
            error => \my $errors,
        }
    );

    if ( @$errors ) {
        for my $error ( @$errors ) {
            my ( $file, $msg ) = %$error;
            die "Error creating $file: $msg";
        }
    }

    if ( $created eq $dir ) {
        $self->trace( "Created dir (" . $dir . ")" );
        return 1;
    }

    $self->trace( "_create_dir() for $dir failed and I don't know why" );
    return 0;
}

sub _double_fork {
    my ( $self ) = @_;
    my $pid = fork();

    $self->trace( "_double_fork()" );
    if ( $pid == 0 ) { # Child, launch the process here.
        setsid(); # Become the process leader.
        my $new_pid = fork();
        if ( $new_pid == 0 ) { # Our double fork.

            if ( $self->gid ) {
                setgid( $self->gid );
                $self->trace( "setgid(" . $self->gid . ")" );
            }

            if ( $self->uid ) {
                setuid( $self->uid );

                $ENV{USER} = $self->user || getpwuid($self->uid);
                $ENV{HOME} = ((getpwuid($self->uid))[7]);

                $self->trace( "setuid(" . $self->uid . ")" );
                $self->trace( "\$ENV{USER} => " . $ENV{USER} );
                $self->trace( "\$ENV{HOME} => " . $ENV{HOME} );
            }

            if ( $self->umask ) {
                umask( $self->umask);
                $self->trace( "umask(" . $self->umask . ")" );
            }

            open( STDIN, "<", File::Spec->devnull );

            if ( $self->redirect_before_fork ) {
                $self->redirect_filehandles;
            }

            $self->_launch_program;
        } elsif ( not defined $new_pid ) {
            warn "Cannot fork: $!";
        } else {
            $self->pid( $new_pid );
            $self->trace("Set PID => $new_pid" );
            $self->write_pid;
            _exit 0;
        }
    } elsif ( not defined $pid ) { # We couldn't fork.  =(
        warn "Cannot fork: $!";
    } else { # In the parent, $pid = child's PID, return it.
        waitpid( $pid, 0 );
    }
    return $self;
}

sub _foreground { shift->_launch_program }

sub _fork {
    my ( $self ) = @_;
    my $pid = fork();

    $self->trace( "_fork()" );
    if ( $pid == 0 ) { # Child, launch the process here.
        $self->_launch_program;
    } elsif ( not defined $pid ) {
        warn "Cannot fork: $!";
    } else { # In the parent, $pid = child's PID, return it.
        $self->pid( $pid );
        $self->trace("Set PID => $pid" );
        $self->write_pid;
    }
    return $self;
}

sub _launch_program {
    my ($self) = @_;

    if ( $self->directory ) {
        chdir( $self->directory );
        $self->trace( "chdir(" . $self->directory . ")" );
    }



( run in 0.380 second using v1.01-cache-2.11-cpan-39bf76dae61 )