cSvn-UI for SVN Repositories

cGit-UI – is a web interface for Subversion (SVN) Repositories. cSvn CGI script is writen in C and therefore it's fast enough

6 Commits   0 Branches   2 Tags

#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;
}