예제 #1
0
파일: utils_nix.c 프로젝트: ychaim/vifm
int
run_in_shell_no_cls(char command[])
{
	typedef void (*sig_handler)(int);

	int pid;
	int result;
	extern char **environ;
	sig_handler sigtstp_handler;

	if(command == NULL)
		return 1;

	sigtstp_handler = signal(SIGTSTP, SIG_DFL);

	/* We need to block SIGCHLD signal.  One can't just set it to SIG_DFL, because
	 * it will possibly cause missing of SIGCHLD from a background process
	 * (job). */
	(void)set_sigchld(1);

	pid = fork();
	if(pid == -1)
	{
		signal(SIGTSTP, sigtstp_handler);
		(void)set_sigchld(0);
		return -1;
	}
	if(pid == 0)
	{
		char *args[4];

		signal(SIGTSTP, SIG_DFL);
		signal(SIGINT, SIG_DFL);
		(void)set_sigchld(0);

		args[0] = cfg.shell;
		args[1] = "-c";
		args[2] = command;
		args[3] = NULL;
		execve(cfg.shell, args, environ);
		exit(127);
	}

	result = get_proc_exit_status(pid);

	signal(SIGTSTP, sigtstp_handler);
	(void)set_sigchld(0);

	return result;
}
예제 #2
0
int
background_and_wait_for_errors(char cmd[], int cancellable)
{
#ifndef _WIN32
	pid_t pid;
	int error_pipe[2];
	int result = 0;

	if(pipe(error_pipe) != 0)
	{
		error_msg("File pipe error", "Error creating pipe");
		return -1;
	}

	(void)set_sigchld(1);

	if((pid = fork()) == -1)
	{
		(void)set_sigchld(0);
		return -1;
	}

	if(pid == 0)
	{
		(void)set_sigchld(0);
		run_from_fork(error_pipe, 1, cmd);
	}
	else
	{
		char buf[80*10];
		char linebuf[80];
		int nread = 0;

		close(error_pipe[1]); /* Close write end of pipe. */

		if(cancellable)
		{
			ui_cancellation_enable();
		}

		wait_for_data_from(pid, NULL, error_pipe[0]);

		buf[0] = '\0';
		while((nread = read(error_pipe[0], linebuf, sizeof(linebuf) - 1)) > 0)
		{
			const int read_empty_line = nread == 1 && linebuf[0] == '\n';
			result = -1;
			linebuf[nread] = '\0';

			if(!read_empty_line)
			{
				strncat(buf, linebuf, sizeof(buf) - strlen(buf) - 1);
			}

			wait_for_data_from(pid, NULL, error_pipe[0]);
		}
		close(error_pipe[0]);

		if(cancellable)
		{
			ui_cancellation_disable();
		}

		if(result != 0)
		{
			error_msg("Background Process Error", buf);
		}
		else
		{
			/* Don't use "const int" variables with WEXITSTATUS() as they cause
			 * compilation errors in case __USE_BSD is defined.  Anonymous type with
			 * "const int" is composed via compound literal expression. */
			int status = get_proc_exit_status(pid);
			result = (status != -1 && WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
		}
	}

	(void)set_sigchld(0);

	return result;
#else
	return -1;
#endif
}
예제 #3
0
/* Checks status of the job.  Processes error stream or checks whether process
 * is still running. */
static void
job_check(job_t *const job)
{
#ifndef _WIN32
	fd_set ready;
	int max_fd = 0;
	struct timeval ts = { .tv_sec = 0, .tv_usec = 1000 };

	/* Setup pipe for reading */
	FD_ZERO(&ready);
	if(job->fd >= 0)
	{
		FD_SET(job->fd, &ready);
		max_fd = job->fd;
	}

	if(job->error != NULL)
	{
		if(!job->skip_errors)
		{
			job->skip_errors = prompt_error_msg("Background Process Error",
					job->error);
		}
		free(job->error);
		job->error = NULL;
	}

	while(select(max_fd + 1, &ready, NULL, NULL, &ts) > 0)
	{
		char err_msg[ERR_MSG_LEN];

		const ssize_t nread = read(job->fd, err_msg, sizeof(err_msg) - 1);
		if(nread == 0)
		{
			break;
		}
		else if(nread > 0 && !job->skip_errors)
		{
			err_msg[nread] = '\0';
			job->skip_errors = prompt_error_msg("Background Process Error", err_msg);
		}
	}
#else
	DWORD retcode;
	if(GetExitCodeProcess(job->hprocess, &retcode) != 0)
	{
		if(retcode != STILL_ACTIVE)
		{
			job->running = 0;
		}
	}
#endif
}

/* Frees resources allocated by the job as well as the job_t structure itself.
 * The job can be NULL. */
static void
job_free(job_t *const job)
{
	if(job == NULL)
	{
		return;
	}

	if(job->type != BJT_COMMAND)
	{
		pthread_mutex_destroy(&job->bg_op_guard);
	}

#ifndef _WIN32
	if(job->fd != NO_JOB_ID)
	{
		close(job->fd);
	}
#else
	if(job->hprocess != NO_JOB_ID)
	{
		CloseHandle(job->hprocess);
	}
#endif
	free(job->bg_op.descr);
	free(job->cmd);
	free(job);
}

/* Used for FUSE mounting and unmounting only. */
int
background_and_wait_for_status(char cmd[], int cancellable, int *cancelled)
{
#ifndef _WIN32
	pid_t pid;
	int status;

	if(cancellable)
	{
		*cancelled = 0;
	}

	if(cmd == NULL)
	{
		return 1;
	}

	(void)set_sigchld(1);

	pid = fork();
	if(pid == (pid_t)-1)
	{
		(void)set_sigchld(0);
		LOG_SERROR_MSG(errno, "Forking has failed.");
		return -1;
	}

	if(pid == (pid_t)0)
	{
		extern char **environ;

		(void)set_sigchld(0);

		(void)execve(get_execv_path(cfg.shell), make_execv_array(cfg.shell, cmd),
				environ);
		_Exit(127);
	}

	if(cancellable)
	{
		ui_cancellation_enable();
	}

	while(waitpid(pid, &status, 0) == -1)
	{
		if(errno != EINTR)
		{
			LOG_SERROR_MSG(errno, "Failed waiting for process: %" PRINTF_ULL,
					(unsigned long long)pid);
			status = -1;
			break;
		}
		process_cancel_request(pid);
	}

	if(cancellable)
	{
		if(ui_cancellation_requested())
		{
			*cancelled = 1;
		}
		ui_cancellation_disable();
	}

	(void)set_sigchld(0);

	return status;

#else
	return -1;
#endif
}