Пример #1
0
static void
g_cancellable_open_pipe (GCancellable *cancellable)
{
  GCancellablePrivate *priv;

  priv = cancellable->priv;
  if (pipe (priv->cancel_pipe) == 0)
    {
      /* Make them nonblocking, just to be sure we don't block
       * on errors and stuff
       */
      set_fd_nonblocking (priv->cancel_pipe[0]);
      set_fd_nonblocking (priv->cancel_pipe[1]);
      set_fd_close_exec (priv->cancel_pipe[0]);
      set_fd_close_exec (priv->cancel_pipe[1]);
      
      if (priv->cancelled)
        {
          const char ch = 'x';
          gssize c;

          do
            c = write (priv->cancel_pipe[1], &ch, 1);
          while (c == -1 && errno == EINTR);
        }
    }
}
Пример #2
0
int main(int argc, char **argv)
{
	struct sigaction sigact;
	sigset_t sigmask;
	pid_t pid;
	int   status;
	int   exitcode, myexitcode;
	int   opt;
	char *arg;
	int   i, r, fd_out, newcmd, argsize = 0;
	int   pipe_fd[MAX_CMDS][2];
	int   progout_pipe_fd[MAX_CMDS][2];

	progname = argv[0];

	/* Parse command-line options */
	be_verbose = show_help = show_version = 0;
	opterr = 0;
	while ( (opt = getopt_long(argc,argv,"+o:M:v",long_opts,(int *) 0))!=-1 ) {
		switch ( opt ) {
		case 0:   /* long-only option */
			break;
		case 'v': /* verbose option */
			be_verbose = 1;
			verb("verbose mode enabled");
			break;
		case 'o': /* outprog option */
			write_progout = 1;
			progoutfilename = strdup(optarg);
			verb("writing program #2 output to '%s'", progoutfilename);
			break;
		case 'M': /* outmeta option */
			outputmeta = 1;
			metafilename = strdup(optarg);
			verb("writing metadata to '%s'", metafilename);
			break;
		case ':': /* getopt error */
		case '?':
			error(0,"unknown option or missing argument `%c'",optopt);
			break;
		default:
			error(0,"getopt returned character code `%c' ??",(char)opt);
		}
	}

	if ( show_help ) usage();
	if ( show_version ) version(PROGRAM,VERSION);

	if ( argc<=optind ) error(0,"no command specified");

	/* Parse commands to be executed */
	ncmds = 0; /* Zero-based index to current command in loop,
	              contains #commands specified after loop */
	newcmd = 1; /* Is current command newly started? */
	for(i=optind; i<argc; i++) {
		/* Check for commands separator */
		if ( strcmp(argv[i],"=")==0 ) {
			ncmds++;
			if ( newcmd ) error(0,"empty command #%d specified", ncmds);
			newcmd = 1;
			if ( ncmds+1>MAX_CMDS ) {
				error(0,"too many commands specified: %d > %d", ncmds+1, MAX_CMDS);
			}
			continue;
		}

		/* Un-escape multiple = at start of argument */
		arg = argv[i];
		if ( strncmp(arg,"==",2)==0 ) arg++;

		if ( newcmd ) {
			newcmd = 0;
			cmd_name[ncmds] = arg;
			cmd_nargs[ncmds] = 0;
			argsize = 5;
			cmd_args[ncmds] = malloc(argsize*sizeof(void *));
			if ( cmd_args[ncmds]==NULL ) error(0,"cannot allocate memory");
		} else {
			if ( cmd_nargs[ncmds]+1>argsize ) {
				argsize += 10;
				cmd_args[ncmds] = realloc(cmd_args[ncmds],argsize*sizeof(void *));
				if ( cmd_args[ncmds]==NULL ) error(0,"cannot allocate memory");
			}
			cmd_args[ncmds][cmd_nargs[ncmds]++] = arg;
		}
	}
	ncmds++;
	if ( newcmd ) error(0,"empty command #%d specified", ncmds);
	if ( ncmds!=2 ) {
		error(0,"%d commands specified, 2 required", ncmds);
	}

	/* Install TERM signal handler */
	if ( sigemptyset(&sigmask)!=0 ) error(errno,"creating signal mask");
	if ( sigprocmask(SIG_SETMASK, &sigmask, NULL)!=0 ) {
		error(errno,"unmasking signals");
	}
	if ( sigaddset(&sigmask,SIGTERM)!=0 ) error(errno,"setting signal mask");

	sigact.sa_handler = terminate;
	sigact.sa_flags   = SA_RESETHAND | SA_RESTART;
	sigact.sa_mask    = sigmask;
	if ( sigaction(SIGTERM,&sigact,NULL)!=0 ) {
		error(errno,"installing signal handler");
	}

	validator_exited_first = 0;
	submission_still_alive = 1;

	/* Create pipes and by default close all file descriptors when
	   executing a forked subcommand, required ones are reset below. */
	for(i=0; i<ncmds; i++) {
		if ( pipe(pipe_fd[i])!=0 ) error(errno,"creating pipes");
		verb("command #%d: read fd=%d, write fd=%d", i, pipe_fd[i][0], pipe_fd[i][1]);
		set_fd_close_exec(pipe_fd[i][0], 1);
		set_fd_close_exec(pipe_fd[i][1], 1);
#ifdef PROC_MAX_PIPE_SIZE
		resize_pipe(pipe_fd[i][1]);
#endif
	}

	/* Setup file and extra pipe for writing program output. */
	if ( write_progout ) {
		if ( (progoutfile = fopen(progoutfilename,"w"))==NULL ) {
			error(errno,"cannot open `%s'",progoutfilename);
		}
		for(i=0; i<ncmds; i++) {
			if ( pipe(progout_pipe_fd[i])!=0 ) error(errno,"creating pipes");
			set_fd_close_exec(progout_pipe_fd[i][0], 1);
			set_fd_close_exec(progout_pipe_fd[i][1], 1);
#ifdef PROC_MAX_PIPE_SIZE
			resize_pipe(progout_pipe_fd[i][1]);
#endif
			verb("writing program #%d output via pipe %d -> %d",
			     i, progout_pipe_fd[i][1], progout_pipe_fd[i][0]);
		}
	}

	/* Execute commands as subprocesses and connect pipes as required. */
	for(i=0; i<ncmds; i++) {
		fd_out = write_progout ? progout_pipe_fd[i][1] : pipe_fd[1-i][1];
		cmd_fds[i][0] = pipe_fd[i][0];
		cmd_fds[i][1] = fd_out;
		cmd_fds[i][2] = FDREDIR_NONE;
		verb("pipes for command #%d are %d and %d", i, cmd_fds[i][0], cmd_fds[i][1]);

		set_fd_close_exec(pipe_fd[i][0], 0);
		set_fd_close_exec(fd_out, 0);

		cmd_exit[i] = -1;
		cmd_pid[i] = execute(cmd_name[i], (const char **)cmd_args[i],
		                     cmd_nargs[i], cmd_fds[i], 0);
		if ( cmd_pid[i]==-1 ) error(errno,"failed to execute command #%d",i+1);
		verb("started #%d, pid %d: %s",i+1,cmd_pid[i],cmd_name[i]);

		set_fd_close_exec(pipe_fd[i][0], 1);
		set_fd_close_exec(fd_out, 1);
	}
	gettimeofday(&start_time, NULL);

	if ( write_progout ) {
		if ( close(pipe_fd[1][0])!=0 ) error(errno,"closing pipe read end");
		if ( close(pipe_fd[0][0])!=0 ) error(errno,"closing pipe read end");
		if ( close(progout_pipe_fd[0][1])!=0 ) error(errno,"closing pipe write end");
		if ( close(progout_pipe_fd[1][1])!=0 ) error(errno,"closing pipe write end");
	} else {
		for(i=0; i<ncmds; i++) {
			if ( close(pipe_fd[i][0])!=0 ) error(errno,"closing pipe read end");
			if ( close(pipe_fd[i][1])!=0 ) error(errno,"closing pipe write end");
		}
	}

	/* Wait for running child commands and check exit status. */
	while ( 1 ) {

		if ( write_progout ) {
			for(i=0; i<ncmds; i++) {
				pump_pipes(&progout_pipe_fd[i][0], &pipe_fd[1-i][1], 1-i);
			}

			pid = 0;
			for(i=0; i<ncmds; i++) {
				if ( cmd_exit[i]==-1 ) {
					pid = waitpid(cmd_pid[i], &status, WNOHANG);
					if ( pid != 0 ) break;
				}
			}
			if ( pid==0 ) continue;
		} else {
			pid = waitpid(-1, &status, 0);
		}

		if ( pid<0 ) {
			/* No more child processes, we're done. */
			if ( errno==ECHILD ) break;
			error(errno,"waiting for children");
		}

		/* Pump pipes one more time to improve detection which program exited first. */
		if ( write_progout ) {
			for(i=0; i<ncmds; i++) {
				pump_pipes(&progout_pipe_fd[i][0], &pipe_fd[1-i][1], 1-i);
			}
		}

		for(i=0; i<ncmds; i++) if ( cmd_pid[i]==pid ) {
			if (i == 1) {
				submission_still_alive = 0;
			}
			warning(0, "command #%d, pid %d has exited (with status %d)",i+1,pid,status);
			break;
		}
		if ( i>=ncmds ) error(0, "waited for unknown child");

		cmd_exit[i] = status;
		verb("command #%d, pid %d has exited (with status %d)",i+1,pid,status);
		if (cmd_exit[0] != -1 && cmd_exit[1] != -1) {
			/* Both child processes are done. */
			if (validator_exited_first && WIFEXITED(cmd_exit[0])) {
				exitcode = WEXITSTATUS(cmd_exit[0]);
				if ( outputmeta && (metafile = fopen(metafilename,"w"))==NULL ) {
					error(errno,"cannot open `%s'",metafilename);
				}
				write_meta("exitcode","%d", exitcode);
				/* TODO: add more meta data like run time. */
				if ( outputmeta && fclose(metafile)!=0 ) {
					error(errno,"closing file `%s'",metafilename);
				}
			}
			break;
		}
	};

	/* Reset pipe filedescriptors to use blocking I/O. */
	for(i=0; i<ncmds; i++) {
		if ( write_progout && progout_pipe_fd[i][0]>=0 ) {
			r = fcntl(progout_pipe_fd[i][0], F_GETFL);
			if (r == -1) error(errno, "fcntl, getting flags");

			r = fcntl(progout_pipe_fd[i][0], F_SETFL, r ^ O_NONBLOCK);
			if (r == -1) error(errno, "fcntl, setting flags");

			do {
				pump_pipes(&progout_pipe_fd[i][0], &pipe_fd[1-i][1], 1-i);
			} while ( progout_pipe_fd[i][0]>=0 );
		}
	}

	/* Check exit status of commands and report back the exit code of the first. */
	myexitcode = exitcode = 0;
	for(i=0; i<ncmds; i++) {
		if ( cmd_exit[i]!=0 ) {
			status = cmd_exit[i];
			/* Test whether command has finished abnormally */
			if ( ! WIFEXITED(status) ) {
				if ( WIFSIGNALED(status) ) {
					warning(0,"command #%d terminated with signal %d",i+1,WTERMSIG(status));
					exitcode = 128+WTERMSIG(status);
				} else {
					error(0,"command #%d exit status unknown: %d",i+1,status);
				}
			} else {
				/* Log the exitstatus of the failed commands */
				exitcode = WEXITSTATUS(status);
				if ( exitcode!=0 ) {
					warning(0,"command #%d exited with exitcode %d",i+1,exitcode);
				}
			}
			/* Only report it for the first command. */
			if ( i==0 ) myexitcode = exitcode;
		}
	}

	return myexitcode;
}