int command_list_db(int argc, char **argv, int optind, int flags) { struct DBItem dbi = DBITEM_NULL; struct DBItem *e = NULL; char *p = NULL; int do_free_p = 0; int i = 0; for(i = optind; i < argc; ++i) { DBITEM_SET_NULL(dbi); e = NULL; if(access(argv[i], F_OK | R_OK) != 0 || DB_read(argv[i], &dbi) != 0) { log_failure(argv[i], "doesn't exist or isn't a valid database"); continue; } if(dbi.kbuf == NULL) { log_info(argv[i], "is empty"); continue; } e = &dbi; do { p = e->kbuf; if(flags & USE_REALPATH) p = get_realpath((const char*) e->kbuf, &do_free_p); log_success(argv[i], "%s -> %08X", p, e->crc); if(do_free_p == 1) { free(p); do_free_p = 0; } } while((e = e->next) != NULL); if(dbi.next != NULL) DB_item_free(dbi.next); } return EXIT_SUCCESS; }
static struct config_paths_t determine_config_directory_paths(const char *argv0) { struct config_paths_t paths; bool done = false; std::string exec_path = get_executable_path(argv0); if (get_realpath(exec_path)) { debug(2, L"exec_path: '%s'", exec_path.c_str()); if (!done) { // The next check is that we are in a reloctable directory tree const char *installed_suffix = "/bin/fish"; const char *just_a_fish = "/fish"; const char *suffix = NULL; if (has_suffix(exec_path, installed_suffix, false)) { suffix = installed_suffix; } else if (has_suffix(exec_path, just_a_fish, false)) { debug(2, L"'fish' not in a 'bin/', trying paths relative to source tree"); suffix = just_a_fish; } if (suffix) { bool seems_installed = (suffix == installed_suffix); wcstring base_path = str2wcstring(exec_path); base_path.resize(base_path.size() - strlen(suffix)); paths.data = base_path + (seems_installed ? L"/share/fish" : L"/share"); paths.sysconf = base_path + (seems_installed ? L"/etc/fish" : L"/etc"); paths.doc = base_path + (seems_installed ? L"/share/doc/fish" : L"/user_doc/html"); paths.bin = base_path + (seems_installed ? L"/bin" : L""); // Check only that the data and sysconf directories exist. Handle the doc // directories separately. struct stat buf; if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) { // The docs dir may not exist; in that case fall back to the compiled in path. if (0 != wstat(paths.doc, &buf)) { paths.doc = L"" DOCDIR; } done = true; } } } } if (!done) { // Fall back to what got compiled in. debug(2, L"Using compiled in paths:"); paths.data = L"" DATADIR "/fish"; paths.sysconf = L"" SYSCONFDIR "/fish"; paths.doc = L"" DOCDIR; paths.bin = L"" BINDIR; } debug(2, L"determine_config_directory_paths() results:\npaths.data: %ls\npaths.sysconf: " L"%ls\npaths.doc: %ls\npaths.bin: %ls", paths.data.c_str(), paths.sysconf.c_str(), paths.doc.c_str(), paths.bin.c_str()); return paths; }
/* | Converts a relative directory path to an absolute. | | Params on Lua stack: | 1: a relative path to directory | | Returns on Lua stack: | The absolute path of directory */ static int l_realdir( lua_State *L ) { luaL_Buffer b; const char *rdir = luaL_checkstring(L, 1); char *adir = get_realpath(rdir); if( !adir ) { printlogf( L, "Error", "failure getting absolute path of [%s]", rdir ); return 0; } { // makes sure its a directory struct stat st; if( stat( adir, &st ) ) { printlogf( L, "Error", "cannot get absolute path of dir '%s': %s", rdir, strerror( errno ) ); free( adir ); return 0; } if( !S_ISDIR( st.st_mode ) ) { printlogf( L, "Error", "cannot get absolute path of dir '%s': is not a directory", rdir ); free( adir ); return 0; } } // returns absolute path with a concated '/' luaL_buffinit( L, &b ); luaL_addstring( &b, adir ); luaL_addchar( &b, '/' ); luaL_pushresult( &b ); free( adir ); return 1; }
/*=export_func optionMakePath * private: * * what: translate and construct a path * arg: + char * + p_buf + The result buffer + * arg: + int + b_sz + The size of this buffer + * arg: + char const * + fname + The input name + * arg: + char const * + prg_path + The full path of the current program + * * ret-type: bool * ret-desc: true if the name was handled, otherwise false. * If the name does not start with ``$'', then it is handled * simply by copying the input name to the output buffer and * resolving the name with either * @code{canonicalize_file_name(3GLIBC)} or @code{realpath(3C)}. * * doc: * * This routine will copy the @code{pzName} input name into the * @code{pzBuf} output buffer, not exceeding @code{bufSize} bytes. If the * first character of the input name is a @code{'$'} character, then there * is special handling: * @* * @code{$$} is replaced with the directory name of the @code{pzProgPath}, * searching @code{$PATH} if necessary. * @* * @code{$@} is replaced with the AutoGen package data installation directory * (aka @code{pkgdatadir}). * @* * @code{$NAME} is replaced by the contents of the @code{NAME} environment * variable. If not found, the search fails. * * Please note: both @code{$$} and @code{$NAME} must be at the start of the * @code{pzName} string and must either be the entire string or be followed * by the @code{'/'} (backslash on windows) character. * * err: @code{false} is returned if: * @* * @bullet{} The input name exceeds @code{bufSize} bytes. * @* * @bullet{} @code{$$}, @code{$@@} or @code{$NAME} is not the full string * and the next character is not '/'. * @* * @bullet{} libopts was built without PKGDATADIR defined and @code{$@@} * was specified. * @* * @bullet{} @code{NAME} is not a known environment variable * @* * @bullet{} @code{canonicalize_file_name} or @code{realpath} return * errors (cannot resolve the resulting path). =*/ bool optionMakePath(char * p_buf, int b_sz, char const * fname, char const * prg_path) { { size_t len = strlen(fname); if (((size_t)b_sz <= len) || (len == 0)) return false; } /* * IF not an environment variable, just copy the data */ if (*fname != '$') { char const * src = fname; char * dst = p_buf; int ct = b_sz; for (;;) { if ( (*(dst++) = *(src++)) == NUL) break; if (--ct <= 0) return false; } } /* * IF the name starts with "$$", then it must be "$$" or * it must start with "$$/". In either event, replace the "$$" * with the path to the executable and append a "/" character. */ else switch (fname[1]) { case NUL: return false; case '$': if (! add_prog_path(p_buf, b_sz, fname, prg_path)) return false; break; case '@': if (program_pkgdatadir[0] == NUL) return false; if (snprintf(p_buf, (size_t)b_sz, "%s%s", program_pkgdatadir, fname + 2) >= b_sz) return false; break; default: if (! add_env_val(p_buf, b_sz, fname)) return false; } return get_realpath(p_buf, b_sz); }
int main(int argc, char *argv[]) { char *bin, *realpath; pid_t pid; time_t start_time, end_time; int wait_status; char buf[BUF_MAX]; size_t pos = 0; /* suppress INT and TERM signals */ signal(SIGINT, do_nothing); signal(SIGTERM, do_nothing); bin = basename(argv[0]); realpath = get_realpath("ls"); /* fork and execute binary in subprocess */ pid = fork(); if (pid == 0) { /* subprocess: execute binary */ if (execve(realpath, argv, NULL) == -1) { perror(realpath); exit(EXIT_FAILURE); } /* does not return */ } else if (pid > 0) { /* parent process: monitor */ start_time = time(NULL); /* wait on process until it terminated (stops are already ignored) */ waitpid(pid, &wait_status, 0); end_time = time(NULL); /* log info */ pos += snprintf(buf+pos, BUF_MAX-pos, "%s: \"%s\"\n%s:\n", KEY_BINARY_PATH, realpath, KEY_EXIT_INFO); if (pos >= BUF_MAX) { goto buffer_overflow; } if (WIFEXITED(wait_status)) { pos += snprintf(buf+pos, BUF_MAX-pos, " %s: true\n %s: %i\n", KEY_EXIT_NORMAL, KEY_EXIT_SIGNAL, WEXITSTATUS(wait_status)); if (pos >= BUF_MAX) { goto buffer_overflow; } } else { pos += snprintf(buf+pos, BUF_MAX-pos, " %s: false\n %s: %i\n %s: \"%s\"\n", KEY_EXIT_NORMAL, KEY_EXIT_SIGNAL, WTERMSIG(wait_status), KEY_EXIT_SIGNAL_STR, strsignal(WTERMSIG(wait_status))); if (pos >= BUF_MAX) { goto buffer_overflow; } } pos += snprintf(buf+pos, BUF_MAX-pos, "%s:\n %s: %i\n %s: %i\n%s: %s%s: %s", KEY_USER_INFO, KEY_UID, getuid(), KEY_GID, getgid(), KEY_TIME_START, asctime(localtime(&start_time)), KEY_TIME_END, asctime(localtime(&end_time))); if (pos > BUF_MAX) { goto buffer_overflow; } send(buf, pos+1); } else { /* fork() == -1 -> error! */ perror("fork"); exit(EXIT_FAILURE); } /* All is good now */ exit(EXIT_SUCCESS); buffer_overflow: printf("ERROR: Buffer too small."); exit(EXIT_FAILURE); }
/** process_directory * A recursive fuction that processes all directories * * Parameters: * struct Filename *file - the names associated with the file */ void* process_directory(void *val){ DIR *dptr; struct dirent *entry; struct dirent *ent_buf; struct Thread_args *ta; unsigned int my_flags; int max_depth; int path_max; ta = malloc(sizeof(struct Thread_args)); if(ta == NULL){ exit(EXIT_FAILURE); } ta = (struct Thread_args*)val; my_flags = ta->gl->my_flags; max_depth = ta->gl->max_depth; path_max = ta->gl->path_max; errno = 0; if((dptr = opendir(ta->fe->file->realptr)) == NULL){ /* If the file was not opened successfully then print an error and move on to the next file */ if(errno != 0){ /* If an error occurred opening the file then print a message */ if(ta->fe->file->is_cmd_line || (my_flags&QUIET) != QUIET){ /* If the file was specified on the commandline or if the -q flag was not selected then print the error */ pthread_mutex_lock(&mu); if(ta->gl->is_network){ char *output; output = calloc(sizeof(char), ta->gl->path_max); sprintf(output, "%s: %s\n", strerror(errno), ta->fe->file->name); write_error_line(output, ta->gl); free(output); } fprintf(stderr, "%s: %s\n", strerror(errno), ta->fe->file->name); pthread_mutex_unlock(&mu); } else{ /* If the file error was not printed then increment the corresponding counter */ ta->fe->file->counters->err_not_printed++; } if(ta->fe->file->counters->num_recurse == 0){ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))--; pthread_mutex_unlock(&mu); } ta->fe->file->counters->num_recurse--; check_print_counters(ta->fe, ta->gl); return NULL; } } if(deal_with_cstack(ta->fe, dptr, ta->gl) == FAILURE){ /* If an error occurred adding the directory to the stack then return */ if(ta->fe->file->counters->num_recurse == 0){ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))--; pthread_mutex_unlock(&mu); } ta->fe->file->counters->num_recurse--; check_print_counters(ta->fe, ta->gl); return NULL; } ent_buf = malloc(/*sizeof(struct dirent)*/path_max); if(ent_buf == NULL){ /* If memory allocation failed, print an error */ exit(EXIT_FAILURE); } while(1){ int status; struct Filename *newfile; readdir_r(dptr, ent_buf, &entry); if(entry == NULL){ break; } if(entry->d_name[0] == '.'){ /* Handle hidden files separately */ if((my_flags&DO_DOTS) == DO_DOTS){ /* Handles the -a flag if it was selected */ if(strcmp("..", entry->d_name) == 0 || strcmp(".", entry->d_name) == 0){ /* If the hidden directory is . or .. then ignore it */ continue; } ta->fe->file->counters->dot_processed++; } else{ /* If the -a flag wasn't selected then ignore the hidden file */ continue; } } newfile = malloc(sizeof(struct Filename)); if(newfile == NULL){ /* If memory allocation failed, print an error */ exit(EXIT_FAILURE); } newfile->name = malloc(path_max); newfile->realptr = malloc(path_max); newfile->fullptr = malloc(path_max); if(newfile->name == NULL || newfile->realptr == NULL || newfile->fullptr == NULL){ /* If memory allocation failed, print an error */ exit(EXIT_FAILURE); } strcpy(newfile->realptr, ta->fe->file->realptr); strcpy(newfile->name, entry->d_name); newfile->is_cmd_line = false; get_fullpath(newfile, &newfile->fullptr, ta->gl); if(newfile->fullptr == NULL){ /* Continue onto the next file if there was a failure getting the realpath of this one */ combine_counters(newfile->counters, ta->gl); continue; } newfile->counters = NULL; initialize_counters(&(newfile->counters)); if(handle_link(newfile, ta->gl) == true){ /* Try to handle a link. */ combine_counters(newfile->counters, ta->gl); continue; } status = is_directory(newfile->fullptr, newfile, ta->gl); if(status == 1){ /* Processes another directory */ struct Thread_args *newta; pthread_t threadid; DIR *newdptr; newta = malloc(sizeof(struct Thread_args)); if(newta == NULL){ exit(EXIT_FAILURE); } newta->gl = malloc(sizeof(struct Globals)); if(newta->gl == NULL){ exit(EXIT_FAILURE); } /*****HERE UPDATE*****/ newta->gl->my_flags = ta->gl->my_flags; newta->gl->num_chars = ta->gl->num_chars; newta->gl->max_lines = ta->gl->max_lines; newta->gl->max_depth = ta->gl->max_depth; newta->gl->path_max = ta->gl->path_max; newta->gl->allowed_threads = ta->gl->allowed_threads; newta->gl->num_threads = &(*(ta->gl->num_threads)); newta->gl->machine = &(*(ta->gl->machine)); newta->gl->is_printed = &(*(ta->gl->is_printed)); newta->gl->final_counters = &(*(ta->gl->final_counters)); newta->gl->donecmdln = &(*(ta->gl->donecmdln)); newta->gl->is_network = ta->gl->is_network; newta->gl->num_networking = &(*(ta->gl->num_networking)); newta->gl->fd = ta->gl->fd; newta->fe = malloc(sizeof(struct elem)); if(newta->fe == NULL){ exit(EXIT_FAILURE); } strcpy(newfile->realptr, ta->fe->file->name); if(newfile->realptr[strlen(newfile->realptr)-1] != '/') strcat(newfile->realptr, "/"); strcat(newfile->realptr, entry->d_name); strcpy(newfile->name, newfile->realptr); free(newfile->realptr); get_realpath(newfile, &newfile->realptr, ta->gl); if(newfile->realptr == NULL){ /* Continue onto the next file if there was a failure getting the realpath of this one */ combine_counters(newfile->counters, newta->gl); continue; } pthread_mutex_lock(&mu); cstack_add(newfile, ta->fe, &newta->fe); pthread_mutex_unlock(&mu); errno = 0; if((newdptr = opendir(newta->fe->file->realptr)) == NULL){ /* If the file was not opened successfully then print an error and move on to the next file */ if(errno != 0){ /* If an error occurred opening the file then print a message */ if(newta->fe->file->is_cmd_line || (my_flags&QUIET) != QUIET){ /* If the file was specified on the commandline or if the -q flag was not selected then print the error */ pthread_mutex_lock(&mu); if(newta->gl->is_network){ char *output; output = calloc(sizeof(char), newta->gl->path_max); sprintf(output, "%s: %s\n", strerror(errno), newta->fe->file->name); write_error_line(output, newta->gl); free(output); } fprintf(stderr, "%s: %s\n", strerror(errno), newta->fe->file->name); pthread_mutex_unlock(&mu); } else{ /* If the file error was not printed then increment the corresponding counter */ newta->fe->file->counters->err_not_printed++; } if(newta->fe->file->counters->num_recurse == 0){ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))--; pthread_mutex_unlock(&mu); } combine_counters(newfile->counters, newta->gl); check_print_counters(newta->fe, ta->gl); continue; } } if(deal_with_cstack(newta->fe, newdptr, ta->gl) == FAILURE){ /* If an error occurred adding the directory to the stack then return */ if(ta->fe->file->counters->num_recurse == 0){ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))--; pthread_mutex_unlock(&mu); } check_print_counters(newta->fe, ta->gl); continue; } newta->fe->file->counters->dr_opened--; if(max_depth == DEFAULT_DEPTH || ta->fe->file->counters->max_depth < max_depth){ if(*(newta->gl->num_threads) < newta->gl->allowed_threads || newta->gl->allowed_threads == DEFAULT_ALLOWED_THREADS){ if((status = pthread_create(&threadid, NULL, process_directory, (void*)newta))){ if(newta->gl->is_network){ char *output; output = calloc(sizeof(char), newta->gl->path_max); sprintf(output, "Could not create thread: %s\n", strerror(status)); write_error_line(output, newta->gl); free(output); } fprintf(stderr, "Could not create thread: %s\n", strerror(status)); newta->fe->file->counters->num_recurse = ta->fe->file->counters->num_recurse + 1; process_directory((void*)newta); } else{ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))++; if(*(ta->gl->num_threads) > ta->fe->file->counters->max_dt_created) ta->fe->file->counters->max_dt_created = *(ta->gl->num_threads); pthread_mutex_unlock(&mu); pthread_detach(threadid); ta->fe->file->counters->num_dt_created++; } } else{ if((my_flags&QUIET) != QUIET){ /* If the file was specified on the commandline or if the -q flag was not selected then print the error */ if(ta->gl->is_network){ char *output; output = calloc(sizeof(char), ta->gl->path_max); sprintf(output, "Descent thread pruned due to a -t%d flag\n", newta->gl->allowed_threads); write_error_line(output, ta->gl); free(output); } fprintf(stderr, "Descent thread pruned due to a -t%d flag\n", newta->gl->allowed_threads); } else{ /* If the file error was not printed then increment the corresponding counter */ ta->fe->file->counters->err_not_printed++; } ta->fe->file->counters->num_dt_notcreated++; newta->fe->file->counters->num_recurse = ta->fe->file->counters->num_recurse + 1; process_directory((void*)newta); } } else{ process_directory((void*)newta); } } else if(status == 0){ /* Else process the entry as a file */ strcpy(newfile->name, newfile->fullptr); process_file(newfile, ta->gl); combine_counters(newfile->counters, ta->gl); } } if(ta->fe->file->counters->num_recurse == 0){ pthread_mutex_lock(&mu); (*(ta->gl->num_threads))--; pthread_mutex_unlock(&mu); } ta->fe->file->counters->num_recurse--; closedir(dptr); check_print_counters(ta->fe, ta->gl); return NULL; /*process_directory*/ }
/** process_file * Process and finds matches in a single file * * Parameters: * struct Filename *file - the names associated with the file * struct Globals *gl - the "global" variables for this search */ void process_file(struct Filename *file, struct Globals *gl){ FILE *fptr; int count; unsigned int my_flags; my_flags = gl->my_flags; get_realpath(file, &file->realptr, gl); if(file->realptr == NULL){ /* Continue onto the next file if there was a failure getting the realpath of this one */ return; } errno = 0; if((fptr = fopen(file->name, "r")) == NULL){ /* If the file was not opened successfully then print an error and move on to the next file */ if(errno != 0){ /* If an error occurred opening the file then print a message */ if(file->is_cmd_line || (my_flags&QUIET) != QUIET){ /* If the file was specified on the commandline or if the -q flag was not selected then print the error */ pthread_mutex_lock(&mu); if(file->fullptr == NULL){ if(gl->is_network){ char *output; output = calloc(sizeof(char), gl->path_max); sprintf(output, "%s: %s\n", strerror(errno), file->name); write_error_line(output, gl); free(output); } fprintf(stderr, "%s: %s\n", strerror(errno), file->name); } else{ if(gl->is_network){ char *output; output = calloc(sizeof(char), gl->path_max); sprintf(output, "%s: %s\n", strerror(errno), file->fullptr); write_error_line(output, gl); free(output); } fprintf(stderr, "%s: %s\n", strerror(errno), file->fullptr); } pthread_mutex_unlock(&mu); } else{ /* If the file error was not printed then increment the corresponding counter */ file->counters->err_not_printed++; } return; } } count = match_file(fptr, file, gl); if((my_flags&SUMMARY) == SUMMARY && count > 0){ /* Print the summary if the summary flag is set */ pthread_mutex_lock(&mu); if(gl->is_network){ char *output; output = calloc(sizeof(char), gl->path_max); sprintf(output, "%s: %d\n", file->realptr, count); write_output_line(output, gl); free(output); } else{ fprintf(stdout, "%s: %d\n", file->realptr, count); } pthread_mutex_unlock(&mu); } fclose(fptr); /*process_file*/ }
static struct config_paths_t determine_config_directory_paths(const char *argv0) { struct config_paths_t paths; bool done = false; std::string exec_path = get_executable_path(argv0); if (get_realpath(exec_path)) { #if __APPLE__ /* On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't link CF, use this lame approach to test it: see if the resolved path ends with /Contents/MacOS/fish, case insensitive since HFS+ usually is. */ if (! done) { const char *suffix = "/Contents/MacOS/fish"; const size_t suffixlen = strlen(suffix); if (has_suffix(exec_path, suffix, true)) { /* Looks like we're a bundle. Cut the string at the / prefixing /Contents... and then the rest */ wcstring wide_resolved_path = str2wcstring(exec_path); wide_resolved_path.resize(exec_path.size() - suffixlen); wide_resolved_path.append(L"/Contents/Resources/"); /* Append share, etc, doc */ paths.data = wide_resolved_path + L"share/fish"; paths.sysconf = wide_resolved_path + L"etc/fish"; paths.doc = wide_resolved_path + L"doc/fish"; /* But the bin_dir is the resolved_path, minus fish (aka the MacOS directory) */ paths.bin = str2wcstring(exec_path); paths.bin.resize(paths.bin.size() - strlen("/fish")); done = true; } } #endif if (! done) { /* The next check is that we are in a reloctable directory tree like this: bin/fish etc/fish share/fish Check it! */ const char *suffix = "/bin/fish"; if (has_suffix(exec_path, suffix, false)) { wcstring base_path = str2wcstring(exec_path); base_path.resize(base_path.size() - strlen(suffix)); paths.data = base_path + L"/share/fish"; paths.sysconf = base_path + L"/etc/fish"; paths.doc = base_path + L"/share/doc/fish"; paths.bin = base_path + L"/bin"; struct stat buf; if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) { done = true; } } } } if (! done) { /* Fall back to what got compiled in. */ paths.data = L"" DATADIR "/fish"; paths.sysconf = L"" SYSCONFDIR "/fish"; paths.doc = L"" DATADIR "/doc/fish"; paths.bin = L"" PREFIX "/bin"; done = true; } return paths; }
/* * cases like: ./dir, ./dir/ ../dir/.. or ../dir../ * are resolved in this function. * it will be parsed as realpath(../dir/)+ name(..) * Note to myself: ~ is automatically parsed by shell as * absolute path * scan a given directory name * if it start with / it is a absolute path and copy it * if it is a relative name get its parent's realpath * then followed by its name */ static char* scan_dir_name(char *given) { char *full_path,*relative_path,*rptr,*memptr,*real_given; int i,slash,given_length; full_path=NULL; given_length=strlen(given); slash=-1; if (given[0]=='/') /*absolute path*/ { if ((full_path=malloc(given_length+1))==NULL) { perror("malloc():"); }else { strcpy(full_path,given); } }else /* it is a given directory not starting with '/'*/ { /* scan from 1 since we know it is not / at 0 */ for (i=1;i<given_length;i++) { /* record the last appeared slash / * but do not record the slash appeared * at the last character */ if (given[i]=='/' && i!=given_length-1) slash=i; } /* if there is no slash is just the realpath of '.' +/+ given_name*/ if (slash==-1) { relative_path="."; real_given=given; } else /* now we need to parse its realtive path realpath and the real given name*/ { if ((relative_path=malloc(slash+1))==NULL) { perror("malloc():"); }else { strncpy(relative_path,given,slash); relative_path[slash]='\0'; } /* parse the real given name */ if ((real_given=malloc(given_length))==NULL) { perror("malloc():"); }else { /*get the real given name after the parsed relative path name */ for (i=slash+1;i<given_length;i++) real_given[i-slash-1]=given[i]; real_given[i-slash-1]='\0'; } } if ((rptr = get_realpath(relative_path, &memptr, NULL)) == NULL) { /* error report has been done within get_realpath */ if (memptr) { free(memptr); } } else /* generate the full path of level 0 from realpath of '.' followed by given name*/ { full_path = get_fullpath(memptr, real_given,1); free(memptr); } } return full_path; }
static struct config_paths_t determine_config_directory_paths(const char *argv0) { struct config_paths_t paths; bool done = false; std::string exec_path = get_executable_path(argv0); if (get_realpath(exec_path)) { debug(2, L"exec_path: '%s', argv[0]: '%s'", exec_path.c_str(), argv0); // TODO: we should determine program_name from argv0 somewhere in this file #ifdef CMAKE_BINARY_DIR // Detect if we're running right out of the CMAKE build directory if (string_prefixes_string(CMAKE_BINARY_DIR, exec_path.c_str())) { debug(2, "Running out of build directory, using paths relative to CMAKE_SOURCE_DIR:\n %s", CMAKE_SOURCE_DIR); done = true; paths.data = wcstring{L"" CMAKE_SOURCE_DIR} + L"/share"; paths.sysconf = wcstring{L"" CMAKE_SOURCE_DIR} + L"/etc"; paths.doc = wcstring{L"" CMAKE_SOURCE_DIR} + L"/user_doc/html"; paths.bin = wcstring{L"" CMAKE_BINARY_DIR}; } #endif if (!done) { // The next check is that we are in a reloctable directory tree const char *installed_suffix = "/bin/fish"; const char *just_a_fish = "/fish"; const char *suffix = NULL; if (has_suffix(exec_path, installed_suffix, false)) { suffix = installed_suffix; } else if (has_suffix(exec_path, just_a_fish, false)) { debug(2, L"'fish' not in a 'bin/', trying paths relative to source tree"); suffix = just_a_fish; } if (suffix) { bool seems_installed = (suffix == installed_suffix); wcstring base_path = str2wcstring(exec_path); base_path.resize(base_path.size() - std::strlen(suffix)); paths.data = base_path + (seems_installed ? L"/share/fish" : L"/share"); paths.sysconf = base_path + (seems_installed ? L"/etc/fish" : L"/etc"); paths.doc = base_path + (seems_installed ? L"/share/doc/fish" : L"/user_doc/html"); paths.bin = base_path + (seems_installed ? L"/bin" : L""); // Check only that the data and sysconf directories exist. Handle the doc // directories separately. struct stat buf; if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) { // The docs dir may not exist; in that case fall back to the compiled in path. if (0 != wstat(paths.doc, &buf)) { paths.doc = L"" DOCDIR; } done = true; } } } } if (!done) { // Fall back to what got compiled in. debug(2, L"Using compiled in paths:"); paths.data = L"" DATADIR "/fish"; paths.sysconf = L"" SYSCONFDIR "/fish"; paths.doc = L"" DOCDIR; paths.bin = L"" BINDIR; } debug(2, L"determine_config_directory_paths() results:\npaths.data: %ls\npaths.sysconf: " L"%ls\npaths.doc: %ls\npaths.bin: %ls", paths.data.c_str(), paths.sysconf.c_str(), paths.doc.c_str(), paths.bin.c_str()); return paths; }
/* * 실행 path 로 각 config path 들을 유추해보고, * 이름으로 유추할 수 없을 때는 */ static struct config_paths_t determine_config_directory_paths(const char *argv0) { struct config_paths_t paths; bool done = false; std::string exec_path = get_executable_path(argv0); if (get_realpath(exec_path)) { #if __APPLE__ /* On OS X, maybe we're an app bundle, and should use the bundle's files. Since we don't link CF, use this lame approach to test it: see if the resolved path ends with /Contents/MacOS/fish, case insensitive since HFS+ usually is. */ if (! done) { const char *suffix = "/Contents/MacOS/fish"; const size_t suffixlen = strlen(suffix); if (has_suffix(exec_path, suffix, true)) { /* Looks like we're a bundle. Cut the string at the / prefixing /Contents... and then the rest */ wcstring wide_resolved_path = str2wcstring(exec_path); wide_resolved_path.resize(exec_path.size() - suffixlen); wide_resolved_path.append(L"/Contents/Resources/"); /* Append share, etc, doc */ paths.data = wide_resolved_path + L"share/fish"; paths.sysconf = wide_resolved_path + L"etc/fish"; paths.doc = wide_resolved_path + L"doc/fish"; /* But the bin_dir is the resolved_path, minus fish (aka the MacOS directory) */ paths.bin = str2wcstring(exec_path); paths.bin.resize(paths.bin.size() - strlen("/fish")); done = true; } } #endif if (! done) { /* The next check is that we are in a reloctable directory tree like this: bin/fish etc/fish share/fish Check it! */ const char *suffix = "/bin/fish"; /* * exec_path 가 suffix 로 끝나면 config path 를 * 이름만으로 유추해서 설정 가능 */ if (has_suffix(exec_path, suffix, false)) { /* * config path 는 wcstring 으로 이루어져있고, * 그 base path 는 /usr/local 과 같이 위의 * exec_path 에서 추출한 것이다. */ wcstring base_path = str2wcstring(exec_path); base_path.resize(base_path.size() - strlen(suffix)); paths.data = base_path + L"/share/fish"; paths.sysconf = base_path + L"/etc/fish"; paths.doc = base_path + L"/share/doc/fish"; paths.bin = base_path + L"/bin"; /* Check only that the data and sysconf directories exist. Handle the doc directories separately */ struct stat buf; if (0 == wstat(paths.data, &buf) && 0 == wstat(paths.sysconf, &buf)) { /* The docs dir may not exist; in that case fall back to the compiled in path */ if (0 != wstat(paths.doc, &buf)) { paths.doc = L"" DOCDIR; } done = true; } } } } /* * 이름에서 유추할 수 없는 경우 Makefile 에서 미리 결정된 * path 를 사용한다. */ if (! done) { /* Fall back to what got compiled in. */ paths.data = L"" DATADIR "/fish"; paths.sysconf = L"" SYSCONFDIR "/fish"; paths.doc = L"" DOCDIR; paths.bin = L"" BINDIR; done = true; } return paths; }
/* | The effective main for one run. | | HUP signals may cause several runs of the one main. */ int main1( int argc, char *argv[] ) { // the Lua interpreter lua_State * L; // the runner file char * lsyncd_runner_file = NULL; int argp = 1; // load Lua L = luaL_newstate( ); luaL_openlibs( L ); { // checks the lua version const char * version; int major, minor; lua_getglobal( L, "_VERSION" ); version = luaL_checkstring( L, -1 ); if( sscanf( version, "Lua %d.%d", &major, &minor ) != 2 ) { fprintf( stderr, "cannot parse lua library version!\n" ); exit (-1 ); } if( major < 5 || (major == 5 && minor < 1) ) { fprintf( stderr, "Lua library is too old. Needs 5.1 at least" ); exit( -1 ); } lua_pop( L, 1 ); } { // logging is prepared quite early int i = 1; add_logcat( "Normal", LOG_NOTICE ); add_logcat( "Warn", LOG_WARNING ); add_logcat( "Error", LOG_ERR ); while( i < argc ) { if( strcmp( argv[ i ], "-log" ) && strcmp( argv[ i ], "--log" ) ) { // arg is neither -log or --log i++; continue; } if( ++i >= argc ) { // -(-)log was last argument break; } if( !add_logcat( argv[ i ], LOG_NOTICE ) ) { printlogf( L, "Error", "'%s' is not a valid logging category", argv[ i ] ); exit( -1 ); } } } // registers Lsycnd's core library register_lsyncd( L ); if( check_logcat( "Debug" ) <= settings.log_level ) { // printlogf doesnt support %ld :-( printf( "kernels clocks_per_sec=%ld\n", clocks_per_sec ); } // checks if the user overrode the default runner file if( argp < argc && !strcmp( argv[ argp ], "--runner" ) ) { if (argp + 1 >= argc) { logstring( "Error", "Lsyncd Lua-runner file missing after --runner " ); exit( -1 ); } lsyncd_runner_file = argv[ argp + 1 ]; argp += 2; } if( lsyncd_runner_file ) { // checks if the runner file exists struct stat st; if( stat( lsyncd_runner_file, &st ) ) { printlogf( L, "Error", "Cannot see a runner at '%s'.", lsyncd_runner_file ); exit( -1 ); } // loads the runner file if( luaL_loadfile(L, lsyncd_runner_file ) ) { printlogf( L, "Error", "error loading '%s': %s", lsyncd_runner_file, lua_tostring( L, -1 ) ); exit( -1 ); } } else { // loads the runner from binary if( luaL_loadbuffer( L, runner_out, runner_size, "runner" ) ) { printlogf( L, "Error", "error loading precompiled runner: %s", lua_tostring( L, -1 ) ); exit( -1 ); } } // prepares the runner executing the script { if( lua_pcall( L, 0, LUA_MULTRET, 0 ) ) { printlogf( L, "Error", "preparing runner: %s", lua_tostring( L, -1 ) ); exit( -1 ); } lua_pushlightuserdata( L, (void *) & runner ); // switches the value ( result of preparing ) and the key &runner lua_insert( L, 1 ); // saves the table of the runners functions in the lua registry lua_settable( L, LUA_REGISTRYINDEX ); // saves the error function extras // &callError is the key lua_pushlightuserdata ( L, (void *) &callError ); // &runner[ callError ] the value lua_pushlightuserdata ( L, (void *) &runner ); lua_gettable ( L, LUA_REGISTRYINDEX ); lua_pushstring ( L, "callError" ); lua_gettable ( L, -2 ); lua_remove ( L, -2 ); lua_settable ( L, LUA_REGISTRYINDEX ); } // asserts the Lsyncd's version matches // between runner and core { const char *lversion; lua_getglobal( L, "lsyncd_version" ); lversion = luaL_checkstring( L, -1 ); if( strcmp( lversion, PACKAGE_VERSION ) ) { printlogf( L, "Error", "Version mismatch '%s' is '%s', but core is '%s'", lsyncd_runner_file ? lsyncd_runner_file : "( internal runner )", lversion, PACKAGE_VERSION ); exit( -1 ); } lua_pop( L, 1 ); } // loads the defaults from binary { if( luaL_loadbuffer( L, defaults_out, defaults_size, "defaults" ) ) { printlogf( L, "Error", "loading defaults: %s", lua_tostring( L, -1 ) ); exit( -1 ); } // prepares the defaults if( lua_pcall( L, 0, 0, 0 ) ) { printlogf( L, "Error", "preparing defaults: %s", lua_tostring( L, -1 ) ); exit( -1 ); } } // checks if there is a "-help" or "--help" { int i; for( i = argp; i < argc; i++ ) { if ( !strcmp( argv[ i ], "-help" ) || !strcmp( argv[ i ], "--help" ) ) { load_runner_func( L, "help" ); if( lua_pcall( L, 0, 0, -2 ) ) { exit( -1 ); } lua_pop( L, 1 ); exit( 0 ); } } } // starts the option parser in Lua script { int idx = 1; const char *s; // creates a table with all remaining argv option arguments load_runner_func( L, "configure" ); lua_newtable( L ); while( argp < argc ) { lua_pushnumber ( L, idx++ ); lua_pushstring ( L, argv[ argp++ ] ); lua_settable ( L, -3 ); } // creates a table with the cores event monitor interfaces idx = 0; lua_newtable( L ); while( monitors[ idx ] ) { lua_pushnumber ( L, idx + 1 ); lua_pushstring ( L, monitors[ idx++ ] ); lua_settable ( L, -3 ); } if( lua_pcall( L, 2, 1, -4 ) ) { exit( -1 ); } if( first_time ) { // If not first time, simply retains the config file given s = lua_tostring(L, -1); if( s ) { lsyncd_config_file = s_strdup( s ); } } lua_pop( L, 2 ); } // checks existence of the config file if( lsyncd_config_file ) { struct stat st; // gets the absolute path to the config file // so in case of HUPing the daemon, it finds it again char * apath = get_realpath( lsyncd_config_file ); if( !apath ) { printlogf( L, "Error", "Cannot find config file at '%s'.", lsyncd_config_file ); exit( -1 ); } free( lsyncd_config_file ); lsyncd_config_file = apath; if( stat( lsyncd_config_file, &st ) ) { printlogf( L, "Error", "Cannot find config file at '%s'.", lsyncd_config_file ); exit( -1 ); } // loads and executes the config file if( luaL_loadfile( L, lsyncd_config_file ) ) { printlogf( L, "Error", "error loading %s: %s", lsyncd_config_file, lua_tostring( L, -1 ) ); exit( -1 ); } if( lua_pcall( L, 0, LUA_MULTRET, 0) ) { printlogf( L, "Error", "error preparing %s: %s", lsyncd_config_file, lua_tostring( L, -1 ) ); exit( -1 ); } } #ifdef WITH_INOTIFY open_inotify( L ); #endif #ifdef WITH_FSEVENTS open_fsevents( L ); #endif // adds signal handlers // listens to SIGCHLD, but blocks it until pselect( ) // opens the signal handler up { sigset_t set; sigemptyset( &set ); sigaddset( &set, SIGCHLD ); signal( SIGCHLD, sig_child ); sigprocmask( SIG_BLOCK, &set, NULL ); signal( SIGHUP, sig_handler ); signal( SIGTERM, sig_handler ); signal( SIGINT, sig_handler ); } // runs initializations from runner // it will set the configuration and add watches { load_runner_func( L, "initialize" ); lua_pushboolean( L, first_time ); if( lua_pcall( L, 1, 0, -3 ) ) { exit( -1 ); } lua_pop( L, 1 ); } // // enters the master loop // masterloop( L ); // // cleanup // // tidies up all observances { int i; for( i = 0; i < observances_len; i++ ) { struct observance *obs = observances + i; obs->tidy( obs ); } observances_len = 0; nonobservances_len = 0; } // frees logging categories { int ci; struct logcat *lc; for( ci = 'A'; ci <= 'Z'; ci++ ) { for( lc = logcats[ ci - 'A' ]; lc && lc->name; lc++) { free( lc->name ); lc->name = NULL; } if( logcats[ci - 'A' ] ) { free( logcats[ ci - 'A' ] ); logcats[ ci - 'A' ] = NULL; } } } lua_close( L ); return 0; }
int CommandLine::run(int argc, char *argv[]) { int32_t ret = 0; int32_t err = 0; sigset_t oldMask; bool needWait = false; char pidFile[PATH_MAX + 1] = {0}; char confName[PATH_MAX + 1] = {0}; pid_t curPid = 0; Args args(argc, argv); char *pconf = get_realpath(args.getConfPath(), confName); if (_server) { fprintf(stderr, "%s is running.\n", _name); return -1; } if (args.isForHelp()) { help(); return 0; } else if (args.isForLongVersion()) { showLongVersion(); return 0; } else if (args.isForShortVersion()) { showShortVersion(); return 0; } sigemptyset(&_mask); sigaddset(&_mask, SIGINT); sigaddset(&_mask, SIGTERM); sigaddset(&_mask, SIGUSR1); sigaddset(&_mask, SIGUSR2); sigaddset(&_mask, SIGPIPE); if ((err=pthread_sigmask(SIG_BLOCK, &_mask, &oldMask))!=0) { fprintf(stderr, "Set sigmask error.\n", _name); return -1; } // register_sig(); for (char *pTmp=pconf; *pTmp; pTmp++) { if (*pTmp == '/') { *pTmp='_'; } } snprintf(pidFile, strlen(_name)+strlen(pidFileTMPL)+strlen(pconf)+1, pidFileTMPL, _name, pconf); curPid = getPidFromFile(pidFile); if (args.getCommandType() == cmd_unknown || strlen(args.getConfPath()) == 0) { help(-1); return -1; } else if (args.getCommandType() == cmd_stop) { if (curPid > 0) { if (kill(curPid, SIGTERM)!=0) { fprintf(stderr, "kill process error, pid = %ld\n", curPid); } } else { fprintf(stderr, "process not running.\n"); } return -1; } else if (args.getCommandType() == cmd_restart) { if (curPid > 0) { if (kill(curPid, SIGTERM)!=0) { fprintf(stderr, "kill process error, pid = %ld\n", curPid); return -1; } needWait = true; } else { fprintf(stderr, "process not running.\n"); } } else if (args.getCommandType() == cmd_start) { if (curPid > 0) { fprintf(stderr, "process already running." "stop it first. pid=%ld, pidfile=%s\n", curPid, pidFile); return -1; } } _server = makeServer(); if (unlikely(!_server)) { alog::Logger::shutdown(); fprintf(stderr, "create server failed.\n"); } if (args.asDaemon()) { if (daemon(1, 1) == -1) { fprintf(stderr, "set self process as daemon failed.\n"); } } if ((args.getCommandType()==cmd_restart)&&(needWait)) { int errnum = 0; while (getPidFromFile(pidFile) >= 0) { if (errnum > 3000) { fprintf(stderr, "shutdown previous server failed: too slow\n"); if (_server) { delete _server; } alog::Logger::shutdown(); return -1; } usleep(20); errnum++; } } if (updatePidFile(pidFile) < 0) { fprintf(stderr, "write pid to file %s error\n", pidFile); delete _server; _server = NULL; alog::Logger::shutdown(); return -1; } if (strlen(args.getLogConfPath()) > 0) { try { alog::Configurator::configureLogger(args.getLogConfPath()); } catch(std::exception &e) { fprintf(stderr, "config from '%s' failed, using default root.\n", args.getLogConfPath()); alog::Configurator::configureRootLogger(); } } else { alog::Configurator::configureRootLogger(); } ret = _server->start(args.getConfPath()); if (ret != KS_SUCCESS) { fprintf(stderr, "startting server by `%s' failed(%d).\n", args.getConfPath(), ret); delete _server; _server = NULL; alog::Logger::shutdown(); unlink(pidFile); return -2; } MUTEX_LOCK(G_CMD_LOCK); _next = G_CMD_LIST; G_CMD_LIST = this; MUTEX_UNLOCK(G_CMD_LOCK); waitSig(); _server->wait(); delete _server; _server = NULL; alog::Logger::shutdown(); unlink(pidFile); MUTEX_LOCK(G_CMD_LOCK); if (G_CMD_LIST == this) { G_CMD_LIST = _next; } else { for (CommandLine *prev = G_CMD_LIST; prev; prev = prev->_next) { if (prev->_next == this) { prev->_next = _next; break; } } } MUTEX_UNLOCK(G_CMD_LOCK); return 0; }