const char* translate_path_common(const char* path, bool symlink) { static thread_local char resolved_path[1024]; std::string str; std::list<std::string> path_components; if (!path) return nullptr; if (g_prefix.empty()) return path; // std::cout << "\tCWD is " << g_cwd << std::endl; if (path[0] != '/') { pthread_rwlock_rdlock(&g_cwdLock); str = g_cwd; pthread_rwlock_unlock(&g_cwdLock); } str += path; // std::cout << "*** Before explode: " << str << std::endl; path_components = explode_path(str); str = resolve_path(path_components, symlink); strncpy(resolved_path, str.c_str(), sizeof(resolved_path)-1); resolved_path[sizeof(resolved_path)-1] = '\0'; // std::cout << "*** In: " << path << "; out: " << resolved_path << std::endl; return resolved_path; }
void __prefix_cwd(const char* in_path) { if (!*in_path) return; std::string path; std::list<std::string> path_components; // std::cout << "CWD to " << in_path << std::endl; pthread_rwlock_wrlock(&g_cwdLock); if (in_path[0] != '/') { path = g_cwd; path += in_path; } else path = in_path; path_components = explode_path(path); g_cwd = join_path(canonicalize_path(path_components)); if (g_cwd[g_cwd.length()-1] != '/') g_cwd += '/'; // std::cout << "\t+++ CWD In: " << in_path << "; out: " << g_cwd << std::endl; pthread_rwlock_unlock(&g_cwdLock); }
std::string resolve_path(std::list<std::string>& path_components, bool symlink) { std::string path, real_path; bool had_failure = false; real_path = g_prefix; // The resolution process is restarted when a symlink is encountered restart_process: canonicalize_path(path_components); path.clear(); for (std::list<std::string>::iterator it = path_components.begin(); it != path_components.end(); it++) { std::string& comp = *it; path += '/'; if (!had_failure) // check if there is any sense in using opendir() or lstat() again { DIR* dir; struct dirent* ent; struct stat st; bool isLink = false; bool is_system_root; real_path.replace(g_prefix.size(), std::string::npos, path); real_path += comp; // Do NOT perform symlink resolution on /system-root, // because that should look like a bind mount rather than // a symlink from inside the DPREFIX is_system_root = (it == path_components.begin()) && (comp == (SYSTEM_ROOT+1)); // We try an lstat() first as an optimization, // because the opendir() path below is VERY slow on NFS mounts. if (lstat(real_path.c_str(), &st) == 0) { isLink = S_ISLNK(st.st_mode); } else { // std::cout << "*** opendir: " << real_path << std::endl; real_path.resize(real_path.length() - comp.length()); dir = opendir(real_path.c_str()); if (dir != nullptr) { std::string best_match; unsigned char best_match_type; while ((ent = readdir(dir)) != nullptr) { // Commented out: replaced with lstat() above /* if (comp == ent->d_name) break; else*/ if (strcasecmp(comp.c_str(), ent->d_name) == 0) { best_match = ent->d_name; best_match_type = ent->d_type; } } if (ent != nullptr || !best_match.empty()) { if (ent == nullptr) { // correct the case comp = best_match; } else best_match_type = ent->d_type; if (best_match_type == DT_LNK && !is_system_root) { isLink = true; real_path += comp; } } else had_failure = true; closedir(dir); } else had_failure = true; } if (symlink && it == --path_components.end()) isLink = false; // Perform symlink resolution if (isLink && !is_system_root) { char link[4096]; int len; // std::cout << "*** readlink: " << real_path << std::endl; len = readlink(real_path.c_str(), link, sizeof(link)-1); if (len > 0) { std::list<std::string> link_components; link[len] = '\0'; /* if (strncmp(link, "@darling_prefix@", 16) == 0) { std::string copy; copy = link; copy.replace(0, 16, INSTALL_PREFIX); strcpy(link, copy.c_str()); } */ link_components = explode_path(link); if (link[0] == '/') { // absolute symlink it++; it = path_components.erase(path_components.begin(), it); } else { // relative symlink it = path_components.erase(it); } path_components.insert(it, link_components.begin(), link_components.end()); // We always restart the process // 1) For absolute symlinks, because we're moving to a completely different path // 2) For relative symlinks, because they may contain '..' goto restart_process; } } } path += comp; } if (!path_components.empty()) { if (*path_components.begin() == "proc" || path == "/dev/mach") { return path; } else if (*path_components.begin() == (SYSTEM_ROOT+1)) { if (!symlink || path_components.size() > 1) { // Exit virtual prefix path = path.substr(sizeof(SYSTEM_ROOT)-1); if (path.empty()) return "/"; else return path; } } } if (path.compare(0, sizeof(SHARE_PATH "/")-1, SHARE_PATH "/") == 0) { return path; } // Apply virtual prefix real_path.replace(g_prefix.size(), std::string::npos, path); return real_path; }
void init_recv_dcc(const char *filename, const char *addr_in, int port, int server_nr, int channel_nr) { int di = n_dcc; char *addr = NULL; char *real_name = NULL; char *local_filename = NULL; char *dummy = NULL; char *message = NULL; struct stat st; if (strcmp(addr_in, "0") == 0) /* irc bouncer most of the times */ addr = strdup(server_list[server_nr].server_host); else if (strchr(addr_in, '.')) /* dotted ipv4 */ addr = strdup(addr_in); else if (strchr(addr_in, ':')) /* dotted ipv6 */ addr = strdup(addr_in); else { int ip = atoi(addr_in); asprintf(&addr, "%d.%d.%d.%d", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255); } update_statusline(server_nr, channel_nr, "DCC: IPv4 address is [%s]:%d", addr, port); n_dcc++; dcc_list = (DCC_t *)realloc(dcc_list, n_dcc * sizeof(DCC_t)); memset(&dcc_list[di], 0x00, sizeof(DCC_t)); dcc_list[di].server_nr = server_nr; dcc_list[di].channel_nr = channel_nr; dcc_list[di].last_update = 0; dcc_list[di].filename = strdup(filename); if (resolve(addr, port, &dcc_list[di].ri, &message) == FALSE) { update_statusline(server_nr, channel_nr, "Failed converting network address: %s", message); free(message); set_dcc_state(di, DSTATE_ERROR); } else { BOOL first_attempt = TRUE; const char *dcc_path_exploded = (dcc_path && strlen(dcc_path)) ? (char *)explode_path(dcc_path) : NULL; /* strip slashes from filename */ dummy = strrchr(filename, '/'); if (dummy) filename = dummy + 1; dummy = strrchr(filename, '\\'); if (dummy) filename = dummy + 1; for(;;) { local_filename = NULL; if (first_attempt) { if (dcc_path_exploded) asprintf(&local_filename, "%s/%s", dcc_path_exploded, filename); else local_filename = strdup(filename); first_attempt = FALSE; } else { if (dcc_path_exploded) asprintf(&local_filename, "%s/%s.%d", dcc_path_exploded, filename, rand()); else asprintf(&local_filename, "%s.%d", filename, rand()); } if (stat(local_filename, &st) == -1) break; LOG("DCC create file, tested %s: %s\n", local_filename, strerror(errno)); free(local_filename); } myfree(dcc_path_exploded); dcc_list[di].fd_file = open(local_filename, O_WRONLY | O_CREAT | O_EXCL, S_IRWXU | S_IRGRP | S_IROTH); if (dcc_list[di].fd_file == -1) { update_statusline(server_nr, channel_nr, "DCC: failed to create local file %s, reason: %s (%d)", local_filename, strerror(errno), errno); set_dcc_state(di, DSTATE_ERROR); } else { dcc_list[di].mode = DCC_RECEIVE_FILE; set_dcc_state(di, DSTATE_TCP_CONNECT); } myfree(local_filename); free(real_name); free(addr); } }
int load_config(const char *file) { char *description = NULL, *server_host = NULL, *username = NULL, *password = NULL, *nickname = NULL, *user_complete_name = NULL; int server_index = -1; int linenr = 0; int fd = open(file, O_RDONLY); if (fd == -1) { if (errno == ENOENT) return -1; error_exit(TRUE, "Cannot open config file %s\n", file); } conf_file = strdup(file); for(;;) { char *line = read_line_fd(fd); char *cmd, *par; char *is; if (!line) break; linenr++; if (strlen(line) == 0) { myfree(line); continue; } if (line[0] == '#' || line[0] == ';') { myfree(line); continue; } is = strchr(line, '='); if (!is) error_exit(FALSE, "config: line %d is missing either command or parameter! (%s)", linenr, line); /* find parameter */ par = is + 1; while(*par == ' ') par++; /* remove spaces around command */ /* spaces at the start */ cmd = line; while(*cmd == ' ') cmd++; /* spaces at the end */ *is = 0x00; is--; while(*is == ' ') { *is = 0x00; is--; } if (strcmp(cmd, "server") == 0 || strcmp(cmd, "send_after_login") == 0 || strcmp(cmd, "auto_join") == 0 || strcmp(cmd, "channel") == 0 || strcmp(cmd, "rejoin") == 0) { /* all stuff already known? */ if (server_host) { if (nickname == NULL) error_exit(FALSE, "nickname must be set for %s", server_host); server_index = add_server(server_host, username, password, nickname, user_complete_name, description ? description : server_host); myfree(server_host); server_host = NULL; myfree(username); myfree(password); myfree(nickname); myfree(user_complete_name); myfree(description); username = password = nickname = user_complete_name = description = NULL; } } if (strcmp(cmd, "server") == 0) { /* new server */ server_host = strdup(par); } else if (strcmp(cmd, "favorite") == 0) { int n = -1; string_array_t parts; init_string_array(&parts); split_string(par, " ", TRUE, &parts); n = string_array_get_n(&parts); if (n != 1 && n != 2) error_exit(FALSE, "favorite needs either be in format \"server channel\" or \"channel\""); if (n == 2) add_favorite(string_array_get(&parts, 0), string_array_get(&parts, 1)); else add_favorite(NULL, string_array_get(&parts, 0)); free_splitted_string(&parts); } else if (strcmp(cmd, "username") == 0) username = strdup(par); else if (strcmp(cmd, "password") == 0) password = strdup(par); else if (strcmp(cmd, "nick") == 0 || strcmp(cmd, "nickname") == 0) nickname = strdup(par); else if (strcmp(cmd, "name") == 0) user_complete_name = strdup(par); else if (strcmp(cmd, "dictionary_file") == 0) { const char *filename = explode_path(par); if (!filename) error_exit(TRUE, "Path '%s' is not understood\n", par); dictionary_file = filename; if (load_dictionary() == FALSE) error_exit(TRUE, "Failure loading dictionary file %s (%s)", filename, par); } else if (strcmp(cmd, "description") == 0) description = strdup(par); else if (strcmp(cmd, "server_exit_message") == 0) server_exit_message = strdup(par); else if (strcmp(cmd, "log_dir") == 0) log_dir = strdup(par); else if (strcmp(cmd, "part_message") == 0) part_message = strdup(par); else if (strcmp(cmd, "notify_nick") == 0) notify_nick = strdup(par); else if (strcmp(cmd, "userinfo") == 0) userinfo = strdup(par); else if (strcmp(cmd, "finger_str") == 0) finger_str = strdup(par); else if (strcmp(cmd, "mark_personal_messages") == 0) mark_personal_messages = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "meta-colors") == 0) colors_meta = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "headline_matcher") == 0) add_headline_matcher(par); else if (strcmp(cmd, "all-colors") == 0) colors_all = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "dcc_bind_to") == 0) dcc_bind_to = strdup(par); else if (strcmp(cmd, "update_clock_at_data") == 0) update_clock_at_data = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "nick-color") == 0) nick_color = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "use_nonbasic_colors") == 0) use_nonbasic_colors = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "ignore_unknown_irc_protocol_msgs") == 0) ignore_unknown_irc_protocol_msgs = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "auto_markerline") == 0) auto_markerline = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "inverse_window_heading") == 0) inverse_window_heading = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "keep_channels_sorted") == 0) keep_channels_sorted = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "allow_invite") == 0) allow_invite = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "show_headlines") == 0) show_headlines = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "remember_channels") == 0) remember_channels = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "allow_userinfo") == 0) allow_userinfo = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "extra_highlights") == 0) add_to_string_array(&extra_highlights, par); else if (strcmp(cmd, "only_one_markerline") == 0) only_one_markerline = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "auto_rejoin") == 0) auto_rejoin = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "ignore_mouse") == 0) ignore_mouse = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "irc_keepalive") == 0) irc_keepalive = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "space_after_start_marker") == 0) space_after_start_marker = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "jumpy_navigation") == 0) jumpy_navigation = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "mark_meta") == 0) mark_meta = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "user_column") == 0) user_column = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "full_user") == 0) full_user = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "grep_filter") == 0) add_filter(gp, par, linenr); else if (strcmp(cmd, "headline_filter") == 0) add_filter(hlgp, par, linenr); else if (strcmp(cmd, "show_parts") == 0) show_parts = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "show_mode_changes") == 0) show_mode_changes = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "show_nick_change") == 0) show_nick_change = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "show_joins") == 0) show_joins = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "store_config_on_exit") == 0) store_config_on_exit = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "partial_highlight_match") == 0) partial_highlight_match = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "topic_scroll") == 0) topic_scroll = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "notice_in_serverchannel") == 0) notice_in_server_channel = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "highlight") == 0) highlight = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "fuzzy_highlight") == 0) fuzzy_highlight = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "theme") == 0) { struct stat status; const char *filename = explode_path(par); if (!filename) error_exit(TRUE, "Path '%s' is not understood\n", par); if (stat(filename, &status) == -1) /* file doesn't exist, look for it under SYSCONFDIR */ { int len = strlen(SYSCONFDIR) + strlen(par) + 2; char *theme_path = malloc(len * sizeof(char)); snprintf(theme_path, len, "%s/%s", SYSCONFDIR, par); load_theme(theme_path); theme_file = theme_path; } else { load_theme(filename); theme_file = strdup(par); } myfree(filename); } else if (strcmp(cmd, "ignore_file") == 0) { struct stat status; const char *filename = explode_path(par); if (!filename) error_exit(TRUE, "Path '%s' is not understood\n", par); if (load_ignore_list(par) == TRUE) { } else if (load_ignore_list(filename) == TRUE) { } else if (stat(filename, &status) == -1) /* file doesn't exist, look elsewhere */ { int len = strlen(SYSCONFDIR) + strlen(par) + 2; char *ignore_file = malloc(len * sizeof(char)); /* look for it under SYSCONFDIR */ snprintf(ignore_file, len, "%s/%s", SYSCONFDIR, par); /* look for it under ~/.firc location */ if (stat(ignore_file, &status) == -1) snprintf(ignore_file, len, "%s/%s", dirname(conf_file), par); load_ignore_list(ignore_file); myfree(ignore_file); } myfree(filename); } else if (strcmp(cmd, "send_after_login") == 0) { server *ps = &server_list[server_index]; if (server_index == -1) error_exit(FALSE, "send_after_login: you need to define a server first\n"); add_to_string_array(&ps -> send_after_login, par); } else if (strcmp(cmd, "auto_join") == 0 || strcmp(cmd, "channel") == 0) { if (server_index == -1) error_exit(FALSE, "auto_join: you need to define a server first\n"); add_autojoin(server_index, par); } else if (strcmp(cmd, "rejoin") == 0) { add_channel(server_index, par); if (keep_channels_sorted) sort_channels(server_index); } else if (strcmp(cmd, "auto_private_channel") == 0) auto_private_channel = parse_false_true(par, cmd, linenr); else if (strcmp(cmd, "dcc_path") == 0) dcc_path = strdup(par); else if (strcmp(cmd, "default_colorpair") == 0) default_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "markerline_colorpair") == 0) markerline_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "highlight_colorpair") == 0) highlight_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "meta_colorpair") == 0) meta_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "error_colorpair") == 0) error_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "temp_colorpair") == 0) temp_colorpair = parse_color_spec(par, linenr, cmd); else if (strcmp(cmd, "check_for_mail") == 0) check_for_mail = atoi(par); else if (strcmp(cmd, "user_column_width") == 0) user_column_width = atoi(par); else if (strcmp(cmd, "delay_before_reconnect") == 0) delay_before_reconnect = atoi(par); else if (strcmp(cmd, "word_cloud_n") == 0) word_cloud_n = atoi(par); else if (strcmp(cmd, "word_cloud_refresh") == 0) { word_cloud_refresh = atoi(par); word_cloud_last_refresh = time(NULL); } else if (strcmp(cmd, "word_cloud_win_height") == 0) word_cloud_win_height = atoi(par); else if (strcmp(cmd, "max_channel_record_lines") == 0) max_channel_record_lines = atoi(par); else if (strcmp(cmd, "word_cloud_min_word_size") == 0) word_cloud_min_word_size = atoi(par); else { error_exit(FALSE, "'%s=%s' is not understood\n", cmd, par); } myfree(line); } close(fd); if (server_host) { if (nickname == NULL) error_exit(FALSE, "nickname must be set for %s", server_host); add_server(server_host, username, password, nickname, user_complete_name, description); myfree(server_host); myfree(username); myfree(password); myfree(nickname); myfree(user_complete_name); myfree(description); } return 0; }