Ejemplo n.º 1
0
Archivo: path.c Proyecto: jubalh/vifm
int
to_canonic_path(const char path[], char buf[], size_t buf_len)
{
	if(!is_path_absolute(path))
	{
		char cwd[PATH_MAX];
		char full_path[PATH_MAX];

		if(getcwd(cwd, sizeof(cwd)) == NULL)
		{
			/* getcwd() failed, we can't use relative path, so fail. */
			LOG_SERROR_MSG(errno, "Can't get CWD");
			return 1;
		}

		snprintf(full_path, sizeof(full_path), "%s/%s", cwd, path);
		canonicalize_path(full_path, buf, buf_len);
	}
	else
	{
		canonicalize_path(path, buf, buf_len);
	}

	chosp(buf);
	return 0;
}
Ejemplo n.º 2
0
void
vim_write_dir(const char path[])
{
	/* TODO: move this and other non-Vim related code to extern.c unit. */

	FILE *fp;
	const char *const dir_out = curr_stats.chosen_dir_out;

	if(is_null_or_empty(dir_out))
	{
		return;
	}

	if(strcmp(dir_out, "-") == 0)
	{
		fputs(path, curr_stats.original_stdout);
		return;
	}

	fp = os_fopen(dir_out, "w");
	if(fp == NULL)
	{
		LOG_SERROR_MSG(errno, "Can't open file for writing: \"%s\"", dir_out);
		return;
	}

	fputs(path, fp);
	fclose(fp);
}
Ejemplo n.º 3
0
int
vim_write_file_list(const FileView *view, int nfiles, char *files[])
{
	FILE *fp;
	const char *const files_out = curr_stats.chosen_files_out;

	if(is_null_or_empty(files_out))
	{
		return 0;
	}

	if(strcmp(files_out, "-") == 0)
	{
		dump_filenames(view, curr_stats.original_stdout, nfiles, files);
		return 0;
	}

	fp = os_fopen(files_out, "w");
	if(fp == NULL)
	{
		LOG_SERROR_MSG(errno, "Can't open file for writing: \"%s\"", files_out);
		return 1;
	}

	dump_filenames(view, fp, nfiles, files);
	fclose(fp);
	return 0;
}
Ejemplo n.º 4
0
Archivo: fs.c Proyecto: cfillion/vifm
SymLinkType
get_symlink_type(const char path[])
{
	char cwd[PATH_MAX];
	char linkto[PATH_MAX + NAME_MAX];
	int saved_errno;
	char *filename_copy;
	char *p;

	if(get_cwd(cwd, sizeof(cwd)) == NULL)
	{
		/* getcwd() failed, just use "." rather than fail. */
		strcpy(cwd, ".");
	}

	/* Use readlink() (in get_link_target_abs) before realpath() to check for
	 * target at slow file system.  realpath() doesn't fit in this case as it
	 * resolves chains of symbolic links and we want to try only the first one. */
	if(get_link_target_abs(path, cwd, linkto, sizeof(linkto)) != 0)
	{
		LOG_SERROR_MSG(errno, "Can't readlink \"%s\"", path);
		log_cwd();
		return SLT_UNKNOWN;
	}
	if(refers_to_slower_fs(path, linkto))
	{
		return SLT_SLOW;
	}

	filename_copy = strdup(path);
	chosp(filename_copy);

	p = os_realpath(filename_copy, linkto);
	saved_errno = errno;

	free(filename_copy);

	if(p == linkto)
	{
		return is_dir(linkto) ? SLT_DIR : SLT_UNKNOWN;
	}

	LOG_SERROR_MSG(saved_errno, "Can't realpath \"%s\"", path);
	log_cwd();
	return SLT_UNKNOWN;
}
Ejemplo n.º 5
0
static void
try_become_a_server(void)
{
	struct sockaddr_in addr;
#ifdef _WIN32
	BOOL yes = TRUE;
#else
	int yes = 1;
#endif

	if(server)
		return;

	/* FIXME: with SO_REUSEADDR this operation always succeeds...  Which breaks
	 *        client/server relationships. */

#ifdef _WIN32
	if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes,
			sizeof(yes)) != 0)
#else
	if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) != 0)
#endif
	{
		LOG_SERROR_MSG(errno, "Can't set reusable option on a socket");
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(PORT);
	server = bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != -1;
	if(!server)
	{
		if(curr_stats.load_stage < 3)
		{
			LOG_SERROR_MSG(errno, "Can't become an IPC server");
		}
	}
	else
	{
		LOG_INFO_MSG("Successfully became an IPC server");
	}
}
Ejemplo n.º 6
0
void
vim_write_empty_file_list(void)
{
	FILE *fp;
	const char *const files_out = curr_stats.chosen_files_out;

	if(is_null_or_empty(files_out) || strcmp(files_out, "-") == 0)
	{
		return;
	}

	fp = os_fopen(files_out, "w");
	if(fp != NULL)
	{
		fclose(fp);
	}
	else
	{
		LOG_SERROR_MSG(errno, "Can't truncate file: \"%s\"", files_out);
	}
}
Ejemplo n.º 7
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
}
Ejemplo n.º 8
0
Archivo: fuse.c Proyecto: jubalh/vifm
/* mount_point should be an array of at least PATH_MAX characters
 * Returns non-zero on error. */
static int
fuse_mount(FileView *view, char file_full_path[], const char param[],
		const char program[], char mount_point[])
{
	/* TODO: refactor this function fuse_mount(). */

	int mount_point_id;
	char buf[2*PATH_MAX];
	char *escaped_filename;
	int foreground;
	char errors_file[PATH_MAX];
	int status;
	int cancelled;

	escaped_filename = escape_filename(get_current_file_name(view), 0);

	mount_point_id = get_last_mount_point_id(fuse_mounts);
	do
	{
		snprintf(mount_point, PATH_MAX, "%s/%03d_%s", cfg.fuse_home,
				++mount_point_id, get_current_file_name(view));
	}
	while(path_exists(mount_point, DEREF));
	if(os_mkdir(mount_point, S_IRWXU) != 0)
	{
		free(escaped_filename);
		show_error_msg("Unable to create FUSE mount directory", mount_point);
		return -1;
	}
	free(escaped_filename);

	/* Just before running the mount,
		 I need to chdir out temporarily from any FUSE mounted
		 paths, Otherwise the fuse-zip command fails with
		 "fusermount: failed to open current directory: permission denied"
		 (this happens when mounting JARs from mounted JARs) */
	if(vifm_chdir(cfg.fuse_home) != 0)
	{
		show_error_msg("FUSE MOUNT ERROR", "Can't chdir() to FUSE home");
		return -1;
	}

	format_mount_command(mount_point, file_full_path, param, program, sizeof(buf),
			buf, &foreground);

	status_bar_message("FUSE mounting selected file, please stand by..");

	if(foreground)
	{
		def_prog_mode();
		endwin();
	}

	generate_tmp_file_name("vifm.errors", errors_file, sizeof(errors_file));

	strcat(buf, " 2> ");
	strcat(buf, errors_file);
	LOG_INFO_MSG("FUSE mount command: `%s`", buf);
	status = background_and_wait_for_status(buf, !foreground, &cancelled);

	clean_status_bar();

	/* Check child process exit status. */
	if(!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS)
	{
		FILE *ef;

		if(!WIFEXITED(status))
		{
			LOG_ERROR_MSG("FUSE mounter didn't exit!");
		}
		else
		{
			LOG_ERROR_MSG("FUSE mount command exit status: %d", WEXITSTATUS(status));
		}

		ef = os_fopen(errors_file, "r");
		if(ef == NULL)
		{
			LOG_SERROR_MSG(errno, "Failed to open temporary stderr file: %s",
					errors_file);
		}
		show_errors_from_file(ef, "FUSE mounter error");

		werase(status_bar);

		if(cancelled)
		{
			status_bar_message("FUSE mount cancelled");
			curr_stats.save_msg = 1;
		}
		else
		{
			show_error_msg("FUSE MOUNT ERROR", file_full_path);
		}

		if(unlink(errors_file) != 0)
		{
			LOG_SERROR_MSG(errno, "Error file deletion failure: %d", errors_file);
		}

		/* Remove the directory we created for the mount. */
		(void)rmdir(mount_point);

		(void)vifm_chdir(flist_get_dir(view));
		return -1;
	}
	unlink(errors_file);
	status_bar_message("FUSE mount success");

	register_mount(&fuse_mounts, file_full_path, mount_point, mount_point_id);

	return 0;
}
Ejemplo n.º 9
0
void
wait_for_data_from(pid_t pid, FILE *f, int fd)
{
	const struct timeval ts_init = { .tv_sec = 0, .tv_usec = 1000 };
	struct timeval ts;

	fd_set read_ready;
	FD_ZERO(&read_ready);

	fd = (f != NULL) ? fileno(f) : fd;

	do
	{
		process_cancel_request(pid);
		ts = ts_init;
		FD_SET(fd, &read_ready);
	}
	while(select(fd + 1, &read_ready, NULL, NULL, &ts) == 0);

	/* Inform other parts of the application that cancellation took place. */
	if(errno == EINTR)
	{
		ui_cancellation_request();
	}
}

int
set_sigchld(int block)
{
	const int action = block ? SIG_BLOCK : SIG_UNBLOCK;
	sigset_t sigchld_mask;

	return sigemptyset(&sigchld_mask) == -1
	    || sigaddset(&sigchld_mask, SIGCHLD) == -1
	    || sigprocmask(action, &sigchld_mask, NULL) == -1;
}

void
process_cancel_request(pid_t pid)
{
	if(ui_cancellation_requested())
	{
		if(kill(pid, SIGINT) != 0)
		{
			LOG_SERROR_MSG(errno, "Failed to send SIGINT to " PRINTF_PID_T, pid);
		}
	}
}

int
get_proc_exit_status(pid_t pid)
{
	do
	{
		int status;
		if(waitpid(pid, &status, 0) == -1)
		{
			if(errno != EINTR)
			{
				LOG_SERROR_MSG(errno, "waitpid()");
				return -1;
			}
		}
		else
		{
			return status;
		}
	}
	while(1);
}

/* if err == 1 then use stderr and close stdin and stdout */
void _gnuc_noreturn
run_from_fork(int pipe[2], int err, char *cmd)
{
	char *args[4];
	int nullfd;

	/* Redirect stderr or stdout to write end of pipe. */
	if(dup2(pipe[1], err ? STDERR_FILENO : STDOUT_FILENO) == -1)
	{
		exit(1);
	}
	close(pipe[0]);        /* Close read end of pipe. */
	close(STDIN_FILENO);
	close(err ? STDOUT_FILENO : STDERR_FILENO);

	/* Send stdout, stdin to /dev/null */
	if((nullfd = open("/dev/null", O_RDONLY)) != -1)
	{
		if(dup2(nullfd, STDIN_FILENO) == -1)
			exit(1);
		if(dup2(nullfd, err ? STDOUT_FILENO : STDERR_FILENO) == -1)
			exit(1);
	}

	args[0] = cfg.shell;
	args[1] = "-c";
	args[2] = cmd;
	args[3] = NULL;

	execvp(args[0], args);
	exit(1);
}