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; }
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); }
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; }
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; }
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"); } }
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); } }
/* 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 }
/* 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; }
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); }