Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
/*
| 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;
}
Example #4
0
/*=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);
}
Example #5
0
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);
}
Example #6
0
/** 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*/
}
Example #7
0
/** 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*/
}
Example #8
0
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;
}
Example #9
0
/*
 * 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;
}
Example #10
0
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;
}
Example #11
0
/*
 * 실행 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;
}
Example #12
0
/*
| 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;
}
Example #13
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;
}