#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdarg.h>
#include <unistd.h>
#include <defs.h>
#include <strbuf.h>
#include <system.h>
#define SYSTEM_ERRMSG_SIZE 4096
void system_error( const char *fmt, ... )
{
va_list arg_ptr;
char buf[SYSTEM_ERRMSG_SIZE];
char msg[SYSTEM_ERRMSG_SIZE];
char *format = "%s: %s\n";
va_start( arg_ptr, fmt );
vsnprintf( msg, SYSTEM_ERRMSG_SIZE, (const void *)fmt, arg_ptr );
va_end( arg_ptr ); /* Reset variable arguments. */
snprintf( buf, SYSTEM_ERRMSG_SIZE, format, "system", msg );
(void)write( STDERR_FILENO, buf, strlen( buf ) );
exit( 1 );
}
system_errfunc system_fatal = system_error;
static void xexec( const char *cmd )
{
char *argv[4];
const char *shell = getenv ("SHELL");
if( !shell ) shell = "/bin/sh";
argv[0] = (char *) shell;
argv[1] = (char *) "-c";
argv[2] = (char *) cmd;
argv[3] = NULL;
execv( shell, argv );
/******************************************
xexec() is called by child process, and
here child process faced to FATAL error:
*/
system_fatal( "Cannot exec '%s'\n", cmd );
}
static pid_t xfork( void )
{
pid_t p = fork();
if( p == (pid_t) -1 )
{
system_fatal( "Cannot %s: %s\n", "fork()", strerror( errno ) );
}
return p;
}
pid_t sys_exec_command( struct strbuf *sb, const char *cmd )
{
int pipe_fh[2];
pid_t pid = -1;
if( sb )
{
if( pipe(pipe_fh ) == -1 )
{
system_fatal( "Cannot create pipe: %s\n", strerror( errno ) );
}
}
pid = xfork();
if( pid != 0 )
{
if( sb )
{
ssize_t ret;
close(pipe_fh[1]);
ret = strbuf_read( sb, pipe_fh[0], 1024 );
if( ret < 0 )
system_fatal( "Cannot read pipe: %s\n", strerror( errno ) );
close(pipe_fh[0]);
}
return pid;
}
if( sb )
{
dup2(pipe_fh[1], STDOUT_FILENO);
close(pipe_fh[1]);
close(pipe_fh[0]);
}
xexec( cmd );
return pid; /* only to avoid compilaton warning */
}
/*****************************************************************
sys_wait_command() - Wait for pid.
Return values:
-------------
0 - SUCCESS
>=1 - status returned by child process
-1 - Child terminated on signal
-2 - Child terminated on unknown reason
-3 - Cannot waitpid: waitpid() retusrs -1
Error message with SIZE length saved into *ERRMSG buffer.
*****************************************************************/
int sys_wait_command( pid_t pid, struct strbuf *errmsg )
{
int status;
if( pid < 0 ) return (pid_t) -1;
while( waitpid( pid, &status, 0 ) == -1 )
if( errno != EINTR )
{
if( errmsg ) {
strbuf_addf( errmsg, "PID %lu: Cannot %s", (unsigned long)pid, "waitpid" );
}
return (int) -3;
}
if( WIFEXITED( status ) )
{
if( WEXITSTATUS (status) )
{
if( errmsg ) {
strbuf_addf( errmsg, "PID %lu: Child returned status %d", (unsigned long)pid, WEXITSTATUS( status ) );
}
return (int) WEXITSTATUS( status );
}
}
else if( WIFSIGNALED( status ) )
{
if( errmsg ) {
strbuf_addf( errmsg, "PID %lu: Child terminated on signal %d", (unsigned long)pid, WTERMSIG( status ) );
}
return (int) -1;
}
else
{
if( errmsg ) {
strbuf_addf( errmsg, "PID %lu: Child terminated on unknown reason", (unsigned long)pid );
}
return (int) -2;
}
return 0;
}