Exemple #1
0
/* Runs the command in shell and returns its output (joined standard output and
 * standard error streams).  All trailing newline characters are stripped to
 * allow easy appending to command output.  Returns the output. */
static var_t
system_builtin(const call_info_t *call_info)
{
	var_t result;
	char *cmd;
	FILE *cmd_stream;
	size_t cmd_out_len;
	var_val_t var_val;

	cmd = var_to_string(call_info->argv[0]);
	cmd_stream = read_cmd_output(cmd);
	free(cmd);

	ui_cancellation_enable();
	var_val.string = read_nonseekable_stream(cmd_stream, &cmd_out_len);
	ui_cancellation_disable();
	fclose(cmd_stream);

	if(var_val.string == NULL)
	{
		var_val.string = "";
		return var_new(VTYPE_STRING, var_val);
	}

	/* Remove trailing new line characters. */
	while(cmd_out_len != 0U && var_val.string[cmd_out_len - 1] == '\n')
	{
		var_val.string[cmd_out_len - 1] = '\0';
		--cmd_out_len;
	}

	result = var_new(VTYPE_STRING, var_val);
	free(var_val.string);
	return result;
}
Exemple #2
0
int
capture_output_to_menu(FileView *view, const char cmd[], menu_info *m)
{
	FILE *file, *err;
	char *line = NULL;
	int x;
	pid_t pid;

	LOG_INFO_MSG("Capturing output of the command to a menu: %s", cmd);

	pid = background_and_capture((char *)cmd, &file, &err);
	if(pid == (pid_t)-1)
	{
		show_error_msgf("Trouble running command", "Unable to run: %s", cmd);
		return 0;
	}

	show_progress("", 0);

	ui_cancellation_reset();
	ui_cancellation_enable();

	wait_for_data_from(pid, file, 0);

	x = 0;
	while((line = read_line(file, line)) != NULL)
	{
		char *expanded_line;
		show_progress("Loading menu", 1000);
		m->items = realloc(m->items, sizeof(char *)*(x + 1));
		expanded_line = expand_tabulation_a(line, cfg.tab_stop);
		if(expanded_line != NULL)
		{
			m->items[x++] = expanded_line;
		}

		wait_for_data_from(pid, file, 0);
	}
	m->len = x;

	ui_cancellation_disable();

	fclose(file);
	print_errors(err);

	if(ui_cancellation_requested())
	{
		append_to_string(&m->title, "(cancelled) ");
		append_to_string(&m->empty_msg, " (cancelled)");
	}

	return display_menu(m, view);
}
Exemple #3
0
/* Deletes current item from the trash. */
static KHandlerResponse
delete_current(menu_data_t *m)
{
	int ret;

	io_args_t args = {
		.arg1.path = trash_list[m->pos].trash_name,

		.cancellation.hook = &ui_cancellation_hook,
	};
	ioe_errlst_init(&args.result.errors);

	ui_cancellation_enable();
	ret = ior_rm(&args);
	ui_cancellation_disable();

	if(ret != 0)
	{
		char *const errors = ioe_errlst_to_str(&args.result.errors);
		ioe_errlst_free(&args.result.errors);

		show_error_msg("File deletion error", errors);

		free(errors);
		return KHR_UNHANDLED;
	}

	ioe_errlst_free(&args.result.errors);
	remove_current_item(m->state);
	return KHR_REFRESH_WINDOW;
}

/* Implementation of cancellation hook for I/O unit. */
static int
ui_cancellation_hook(void *arg)
{
	return ui_cancellation_requested();
}
Exemple #4
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
}
Exemple #5
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
}
Exemple #6
0
int
compare_two_panes(CompareType ct, ListType lt, int group_paths, int skip_empty)
{
	int next_id = 1;
	entries_t curr, other;

	trie_t *const trie = trie_create();
	ui_cancellation_reset();
	ui_cancellation_enable();

	curr = make_diff_list(trie, curr_view, &next_id, ct, skip_empty, 0);
	other = make_diff_list(trie, other_view, &next_id, ct, skip_empty,
			lt == LT_DUPS);

	ui_cancellation_disable();
	trie_free_with_data(trie, &free_compare_records);

	/* Clear progress message displayed by make_diff_list(). */
	ui_sb_quick_msg_clear();

	if(ui_cancellation_requested())
	{
		free_dir_entries(curr_view, &curr.entries, &curr.nentries);
		free_dir_entries(other_view, &other.entries, &other.nentries);
		status_bar_message("Comparison has been cancelled");
		return 1;
	}

	if(!group_paths || lt != LT_ALL)
	{
		/* Sort both lists according to unique file numbers to group identical files
		 * (sorting is stable, tags are set in make_diff_list()). */
		qsort(curr.entries, curr.nentries, sizeof(*curr.entries), &id_sorter);
		qsort(other.entries, other.nentries, sizeof(*other.entries), &id_sorter);
	}

	if(lt == LT_UNIQUE)
	{
		make_unique_lists(curr, other);
		return 0;
	}

	if(lt == LT_DUPS)
	{
		leave_only_dups(&curr, &other);
	}

	flist_custom_start(curr_view, lt == LT_ALL ? "diff" : "dups diff");
	flist_custom_start(other_view, lt == LT_ALL ? "diff" : "dups diff");

	fill_side_by_side(curr, other, group_paths);

	if(flist_custom_finish(curr_view, CV_DIFF, 0) != 0)
	{
		show_error_msg("Comparison", "No results to display");
		return 0;
	}
	if(flist_custom_finish(other_view, CV_DIFF, 0) != 0)
	{
		assert(0 && "The error shouldn't be happening here.");
	}

	curr_view->list_pos = 0;
	other_view->list_pos = 0;
	curr_view->custom.diff_cmp_type = ct;
	other_view->custom.diff_cmp_type = ct;
	curr_view->custom.diff_path_group = group_paths;
	other_view->custom.diff_path_group = group_paths;

	assert(curr_view->list_rows == other_view->list_rows &&
			"Diff views must be in sync!");

	ui_view_schedule_redraw(curr_view);
	ui_view_schedule_redraw(other_view);
	return 0;
}
Exemple #7
0
int
compare_one_pane(FileView *view, CompareType ct, ListType lt, int skip_empty)
{
	int i, dup_id;
	FileView *other = (view == curr_view) ? other_view : curr_view;
	const char *const title = (lt == LT_ALL)  ? "compare"
	                        : (lt == LT_DUPS) ? "dups" : "nondups";

	int next_id = 1;
	entries_t curr;

	trie_t *trie = trie_create();
	ui_cancellation_reset();
	ui_cancellation_enable();

	curr = make_diff_list(trie, view, &next_id, ct, skip_empty, 0);

	ui_cancellation_disable();
	trie_free_with_data(trie, &free_compare_records);

	/* Clear progress message displayed by make_diff_list(). */
	ui_sb_quick_msg_clear();

	if(ui_cancellation_requested())
	{
		free_dir_entries(view, &curr.entries, &curr.nentries);
		status_bar_message("Comparison has been cancelled");
		return 1;
	}

	qsort(curr.entries, curr.nentries, sizeof(*curr.entries), &id_sorter);

	flist_custom_start(view, title);

	dup_id = -1;
	next_id = 0;
	for(i = 0; i < curr.nentries; ++i)
	{
		dir_entry_t *entry = &curr.entries[i];

		if(lt == LT_ALL)
		{
			flist_custom_put(view, entry);
			continue;
		}

		if(entry->id == dup_id)
		{
			put_or_free(view, entry, next_id, lt == LT_DUPS);
			continue;
		}

		dup_id = (i < curr.nentries - 1 && entry[0].id == entry[1].id)
		       ? entry->id
		       : -1;

		if(entry->id == dup_id)
		{
			put_or_free(view, entry, ++next_id, lt == LT_DUPS);
			continue;
		}

		put_or_free(view, entry, next_id, lt == LT_UNIQUE);
	}

	/* Entries' data has been moved out of them or freed, so need to free only the
	 * list. */
	dynarray_free(curr.entries);

	if(flist_custom_finish(view, lt == LT_UNIQUE ? CV_REGULAR : CV_COMPARE,
				0) != 0)
	{
		show_error_msg("Comparison", "No results to display");
		return 0;
	}

	/* Leave the other pane, if it's in the CV_DIFF mode, two panes are needed for
	 * this. */
	if(other->custom.type == CV_DIFF)
	{
		cd_updir(other, 1);
	}

	view->list_pos = 0;
	ui_view_schedule_redraw(view);
	return 0;
}