Example #1
0
bool path_get_cdpath_string(const wcstring &dir_str, wcstring &result, const env_var_t &cdpath)
{
    wchar_t *res = 0;
    int err = ENOENT;
    bool success = false;

    const wchar_t *const dir = dir_str.c_str();
    if (dir[0] == L'/'|| (wcsncmp(dir, L"./", 2)==0))
    {
        struct stat buf;
        if (wstat(dir, &buf) == 0)
        {
            if (S_ISDIR(buf.st_mode))
            {
                result = dir_str;
                success = true;
            }
            else
            {
                err = ENOTDIR;
            }

        }
    }
    else
    {

        wcstring path = L".";

        // Respect CDPATH
        env_var_t cdpath = env_get_string(L"CDPATH");
        if (! cdpath.missing_or_empty())
        {
            path = cdpath.c_str();
        }

        wcstokenizer tokenizer(path, ARRAY_SEP_STR);
        wcstring next_path;
        while (tokenizer.next(next_path))
        {
            expand_tilde(next_path);
            if (next_path.size() == 0) continue;

            wcstring whole_path = next_path;
            append_path_component(whole_path, dir);

            struct stat buf;
            if (wstat(whole_path, &buf) == 0)
            {
                if (S_ISDIR(buf.st_mode))
                {
                    result = whole_path;
                    success = true;
                    break;
                }
                else
                {
                    err = ENOTDIR;
                }
            }
            else
            {
                if (lwstat(whole_path, &buf) == 0)
                {
                    err = EROTTEN;
                }
            }
        }
    }


    if (!success)
    {
        errno = err;
    }

    return res;
}
Example #2
0
/*
 * login()
 *	Log in as given account
 */
static void
login(struct uinfo *u)
{
	int x;
	port_t port;
	struct perm perm;
	char *p, buf[128];
	extern void zero_ids();

	/*
	 * Activate root abilities
	 */
	zero_ids(&perm, 1);
	perm.perm_len = 0;
	if (perm_ctl(1, &perm, (void *)0) < 0) {
		printf("login: can't enable root\n");
		exit(1);
	}

	/*
	 * Set our ID.  We skip slot 1, which is our superuser slot
	 * used to authorize the manipulation of all others.  Finish
	 * by setting 1--after this, we only hold the abilities of
	 * the user logging on.
	 */
	for (x = 0; x < PROCPERMS; ++x) {
		if (x == 1) {
			continue;
		}
		perm_ctl(x, &u->u_perms[x], (void *)0);
	}

	/*
	 * Initialize our environment.  Slot 0, our default ownership,
	 * is now set, so we will own the nodes which appear.
	 */
	setenv_init(u->u_env);

	/*
	 * Give up our powers
	 */
	perm_ctl(1, &u->u_perms[1], (void *)0);

	/*
	 * Re-initialize.  The /env server otherwise still believes
	 * we have vast privileges.
	 */
	setenv_init(u->u_env);

	/*
	 * Mount system default stuff.  Remove our root-capability
	 * entry from the mount table.
	 */
	port = mount_port("/");
	mount_init(_PATH_SYSMOUNT);
	umount("/", port);

	/*
	 * Put some stuff into our environment.  We place it in the
	 * common part of our environment so all processes under this
	 * login will share it.
	 */
	sprintf(buf, "/%s/USER", u->u_env);
	setenv(buf, u->u_acct);
	sprintf(buf, "/%s/HOME", u->u_env);
	setenv(buf, u->u_home);

	/*
	 * If we can chdir to their home, set up their mount
	 * environment as requested.
	 */
	if (chdir(u->u_home) >= 0) {
		mount_init(_PATH_MOUNTRC);
	} else {
		printf("Note: can not chdir to home: %s\n", u->u_home);
	}

	/*
	 * Scrub TTY.  Create our own signal group and tell our TTY.
	 * We need to re-open the TTY if we have a path to it, so
	 * our server can see our "real" ID's, not the login process's
	 * version.
	 */
	if (tty_dev) {
		open_tty_dev(tty_dev);
	}
	(void)tcsetattr(1, TCSANOW, &torig);
	(void)setsid();
	(void)sprintf(buf, "pgrp=%lu\n", getpid());
	(void)wstat(__fd_port(1), buf);

	/*
	 * Launch their shell with a leading '-' in argv[0] to flag
	 * a login shell.
	 */
	p = strrchr(u->u_shell, '/');
	if (p && (strlen(p)+4 < sizeof(buf))) {
		sprintf(buf, "-%s", p+1);
		p = buf;
	} else {
		p = u->u_shell;
	}
	execl(u->u_shell, p, (char *)0);
	perror(u->u_shell);
	exit(1);
}
Example #3
0
static bool path_get_path_core(const wcstring &cmd, wcstring *out_path,
                               const env_var_t &bin_path_var) {
    int err = ENOENT;
    debug(3, L"path_get_path( '%ls' )", cmd.c_str());

    // If the command has a slash, it must be a full path.
    if (cmd.find(L'/') != wcstring::npos) {
        if (waccess(cmd, X_OK) != 0) {
            return false;
        }

        struct stat buff;
        if (wstat(cmd, &buff)) {
            return false;
        }
        if (S_ISREG(buff.st_mode)) {
            if (out_path) out_path->assign(cmd);
            return true;
        }
        errno = EACCES;
        return false;
    }

    wcstring bin_path;
    if (!bin_path_var.missing()) {
        bin_path = bin_path_var;
    } else {
        // Note that PREFIX is defined in the `Makefile` and is thus defined when this module is
        // compiled. This ensures we always default to "/bin", "/usr/bin" and the bin dir defined
        // for the fish programs. Possibly with a duplicate dir if PREFIX is empty, "/", "/usr" or
        // "/usr/". If the PREFIX duplicates /bin or /usr/bin that is harmless other than a trivial
        // amount of time testing a path we've already tested.
        bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
    }

    std::vector<wcstring> pathsv;
    tokenize_variable_array(bin_path, pathsv);
    for (auto next_path : pathsv) {
        if (next_path.empty()) continue;
        append_path_component(next_path, cmd);
        if (waccess(next_path, X_OK) == 0) {
            struct stat buff;
            if (wstat(next_path, &buff) == -1) {
                if (errno != EACCES) {
                    wperror(L"stat");
                }
                continue;
            }
            if (S_ISREG(buff.st_mode)) {
                if (out_path) *out_path = std::move(next_path);
                return true;
            }
            err = EACCES;
        } else {
            switch (errno) {
                case ENOENT:
                case ENAMETOOLONG:
                case EACCES:
                case ENOTDIR: {
                    break;
                }
                default: {
                    debug(1, MISSING_COMMAND_ERR_MSG, next_path.c_str());
                    wperror(L"access");
                    break;
                }
            }
        }
    }

    errno = err;
    return false;
}
Example #4
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 #5
0
// This function does I/O
static void tokenize( const wchar_t * const buff, std::vector<int> &color, const int pos, wcstring_list_t *error, const wcstring &working_directory, const env_vars_snapshot_t &vars) {
    ASSERT_IS_BACKGROUND_THREAD();
    
	wcstring cmd;    
	int had_cmd=0;
	wcstring last_cmd;
	int len;

	int accept_switches = 1;
	
	int use_function = 1;
	int use_command = 1;
	int use_builtin = 1;
	
	CHECK( buff, );

	len = wcslen(buff);

	if( !len )
		return;

    std::fill(color.begin(), color.end(), -1); 

    tokenizer tok;
	for( tok_init( &tok, buff, TOK_SHOW_COMMENTS | TOK_SQUASH_ERRORS );
		tok_has_next( &tok );
		tok_next( &tok ) )
	{	
		int last_type = tok_last_type( &tok );
		
		switch( last_type )
		{
			case TOK_STRING:
			{
				if( had_cmd )
				{
					
					/*Parameter */
					wchar_t *param = tok_last( &tok );
					if( param[0] == L'-' )
					{
						if (wcscmp( param, L"--" ) == 0 )
						{
							accept_switches = 0;
							color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
						}
						else if( accept_switches )
						{
							if( complete_is_valid_option( last_cmd.c_str(), param, error, false /* no autoload */ ) )
								color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
							else
								color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
						}
						else
						{
							color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
						}
					}
					else
					{
						color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
					}					

					if( cmd == L"cd" )
					{
                        wcstring dir = tok_last( &tok );
                        if (expand_one(dir, EXPAND_SKIP_CMDSUBST))
						{
							int is_help = string_prefixes_string(dir, L"--help") || string_prefixes_string(dir, L"-h");
							if( !is_help && ! is_potential_cd_path(dir, working_directory, PATH_EXPAND_TILDE, NULL))
							{
                                color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;							
							}
						}
					}
					
                    /* Highlight the parameter. highlight_param wants to write one more color than we have characters (hysterical raisins) so allocate one more in the vector. But don't copy it back. */
                    const wcstring param_str = param;
                    int tok_pos = tok_get_pos(&tok);
                    
                    std::vector<int>::const_iterator where = color.begin() + tok_pos;
                    std::vector<int> subcolors(where, where + param_str.size());
                    subcolors.push_back(-1);                
                    highlight_param(param_str, subcolors, pos-tok_pos, error);
                                        
                    /* Copy the subcolors back into our colors array */
                    std::copy(subcolors.begin(), subcolors.begin() + param_str.size(), color.begin() + tok_pos);
				}
				else
				{ 
					/*
					 Command. First check that the command actually exists.
					 */
                    cmd = tok_last( &tok );
                    bool expanded = expand_one(cmd, EXPAND_SKIP_CMDSUBST | EXPAND_SKIP_VARIABLES);
					if (! expanded || has_expand_reserved(cmd.c_str()))
					{
						color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
					}
					else
					{
						bool is_cmd = false;
						int is_subcommand = 0;
						int mark = tok_get_pos( &tok );
						color.at(tok_get_pos( &tok )) = HIGHLIGHT_COMMAND;
						
						if( parser_keywords_is_subcommand( cmd ) )
						{
							
							int sw;
							
							if( cmd == L"builtin")
							{
								use_function = 0;
								use_command  = 0;
								use_builtin  = 1;
							}
							else if( cmd == L"command")
							{
								use_command  = 1;
								use_function = 0;
								use_builtin  = 0;
							}
							
							tok_next( &tok );
							
							sw = parser_keywords_is_switch( tok_last( &tok ) );
							
							if( !parser_keywords_is_block( cmd ) &&
							   sw == ARG_SWITCH )
							{
								/* 
								 The 'builtin' and 'command' builtins
								 are normally followed by another
								 command, but if they are invoked
								 with a switch, they aren't.
								 
								 */
								use_command  = 1;
								use_function = 1;
								use_builtin  = 2;
							}
							else
							{
								if( sw == ARG_SKIP )
								{
									color.at(tok_get_pos( &tok )) = HIGHLIGHT_PARAM;
									mark = tok_get_pos( &tok );
								}
								
								is_subcommand = 1;
							}
							tok_set_pos( &tok, mark );
						}
						
						if( !is_subcommand )
						{
							/*
							 OK, this is a command, it has been
							 successfully expanded and everything
							 looks ok. Lets check if the command
							 exists.
							 */
							
							/*
							 First check if it is a builtin or
							 function, since we don't have to stat
							 any files for that
							 */
							if (! is_cmd && use_builtin )
								is_cmd = builtin_exists( cmd );
							
							if (! is_cmd && use_function )
								is_cmd = function_exists_no_autoload( cmd, vars );
							
							/*
							 Moving on to expensive tests
							 */
							
							/*
							 Check if this is a regular command
							 */
							if (! is_cmd && use_command )
                            {
								is_cmd = path_get_path( cmd, NULL, vars );
                            }
							
                            /* Maybe it is a path for a implicit cd command. */
                            if (! is_cmd)
                            {
                                if (use_builtin || (use_function && function_exists_no_autoload( L"cd", vars)))
                                    is_cmd = path_can_be_implicit_cd(cmd, NULL, working_directory.c_str(), vars);
                            }
                            
							if( is_cmd )
							{								
								color.at(tok_get_pos( &tok )) = HIGHLIGHT_COMMAND;
							}
							else
							{
								if( error ) {
                                    error->push_back(format_string(L"Unknown command \'%ls\'", cmd.c_str()));
                                }
								color.at(tok_get_pos( &tok )) = (HIGHLIGHT_ERROR);
							}
							had_cmd = 1;
						}
						
						if( had_cmd )
						{
							last_cmd = tok_last( &tok );
						}
					}
					
				}
				break;
			}
				
			case TOK_REDIRECT_NOCLOB:
			case TOK_REDIRECT_OUT:
			case TOK_REDIRECT_IN:
			case TOK_REDIRECT_APPEND:
			case TOK_REDIRECT_FD:
			{
				if( !had_cmd )
				{
					color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
					if( error )
                        error->push_back(L"Redirection without a command");
					break;
				}
				
                wcstring target_str;
				const wchar_t *target=NULL;
				
				color.at(tok_get_pos( &tok )) = HIGHLIGHT_REDIRECTION;
				tok_next( &tok );
				
				/*
				 Check that we are redirecting into a file
				 */
				
				switch( tok_last_type( &tok ) )
				{
					case TOK_STRING:
					{
                        target_str = tok_last( &tok );
                        if (expand_one(target_str, EXPAND_SKIP_CMDSUBST)) {
                            target = target_str.c_str();
                        }
						/*
						 Redirect filename may contain a cmdsubst. 
						 If so, it will be ignored/not flagged.
						 */
					}
						break;
					default:
					{
                        size_t pos = tok_get_pos(&tok);
                        if (pos < color.size()) {
                            color.at(pos) = HIGHLIGHT_ERROR;
                        }
						if( error )
                            error->push_back(L"Invalid redirection");
					}
						
				}
				
				if( target != 0 )
				{
                    wcstring dir = target;
                    size_t slash_idx = dir.find_last_of(L'/');
					struct stat buff;
					/* 
					 If file is in directory other than '.', check
					 that the directory exists.
					 */
					if( slash_idx != wcstring::npos )
					{
						dir.resize(slash_idx);
						if( wstat( dir, &buff ) == -1 )
						{
							color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
							if( error )
                                error->push_back(format_string(L"Directory \'%ls\' does not exist", dir.c_str()));
							
						}
					}
					
					/*
					 If the file is read from or appended to, check
					 if it exists.
					 */
					if( last_type == TOK_REDIRECT_IN || 
					   last_type == TOK_REDIRECT_APPEND )
					{
						if( wstat( target, &buff ) == -1 )
						{
							color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
							if( error )
                                error->push_back(format_string(L"File \'%ls\' does not exist", target));
						}
					}
					if( last_type == TOK_REDIRECT_NOCLOB )
					{
						if( wstat( target, &buff ) != -1 )
						{
							color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
							if( error )
                                error->push_back(format_string(L"File \'%ls\' exists", target));
						}
					}
				}
				break;
			}
				
			case TOK_PIPE:
			case TOK_BACKGROUND:
			{
				if( had_cmd )
				{
					color.at(tok_get_pos( &tok )) = HIGHLIGHT_END;
					had_cmd = 0;
					use_command  = 1;
					use_function = 1;
					use_builtin  = 1;
					accept_switches = 1;
				}
				else
				{
					color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;					
					if( error )
                        error->push_back(L"No job to put in background" );
				}
				
				break;
			}
				
			case TOK_END:
			{
				color.at(tok_get_pos( &tok )) = HIGHLIGHT_END;
				had_cmd = 0;
				use_command  = 1;
				use_function = 1;
				use_builtin  = 1;
				accept_switches = 1;
				break;
			}
				
			case TOK_COMMENT:
			{
				color.at(tok_get_pos( &tok )) = HIGHLIGHT_COMMENT;
				break;
			}
				
			case TOK_ERROR:
			default:
			{
				/*
				 If the tokenizer reports an error, highlight it as such.
				 */
				if( error )
                    error->push_back(tok_last( &tok));
				color.at(tok_get_pos( &tok )) = HIGHLIGHT_ERROR;
				break;				
			}			
		}
	}
    tok_destroy( &tok );
}
Example #6
0
static bool path_get_path_core(const wcstring &cmd, wcstring *out_path, const env_var_t &bin_path_var)
{
    int err = ENOENT;

    debug(3, L"path_get_path( '%ls' )", cmd.c_str());

    /* If the command has a slash, it must be a full path */
    if (cmd.find(L'/') != wcstring::npos)
    {
        if (waccess(cmd, X_OK)==0)
        {
            struct stat buff;
            if (wstat(cmd, &buff))
            {
                return false;
            }

            if (S_ISREG(buff.st_mode))
            {
                if (out_path)
                    out_path->assign(cmd);
                return true;
            }
            else
            {
                errno = EACCES;
                return false;
            }
        }
        else
        {
            return false;
        }

    }
    else
    {
        wcstring bin_path;
        if (! bin_path_var.missing())
        {
            bin_path = bin_path_var;
        }
        else
        {
            if (contains(PREFIX L"/bin", L"/bin", L"/usr/bin"))
            {
                bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin";
            }
            else
            {
                bin_path = L"/bin" ARRAY_SEP_STR L"/usr/bin" ARRAY_SEP_STR PREFIX L"/bin";
            }
        }

        wcstring nxt_path;
        wcstokenizer tokenizer(bin_path, ARRAY_SEP_STR);
        while (tokenizer.next(nxt_path))
        {
            if (nxt_path.empty())
                continue;
            append_path_component(nxt_path, cmd);
            if (waccess(nxt_path, X_OK)==0)
            {
                struct stat buff;
                if (wstat(nxt_path, &buff)==-1)
                {
                    if (errno != EACCES)
                    {
                        wperror(L"stat");
                    }
                    continue;
                }
                if (S_ISREG(buff.st_mode))
                {
                    if (out_path)
                        out_path->swap(nxt_path);
                    return true;
                }
                err = EACCES;

            }
            else
            {
                switch (errno)
                {
                    case ENOENT:
                    case ENAMETOOLONG:
                    case EACCES:
                    case ENOTDIR:
                        break;
                    default:
                    {
                        debug(1,
                              MISSING_COMMAND_ERR_MSG,
                              nxt_path.c_str());
                        wperror(L"access");
                    }
                }
            }
        }
    }

    errno = err;
    return false;
}
Example #7
0
/**
   Call env_set. If this is a path variable, e.g. PATH, validate the
   elements. On error, print a description of the problem to stderr.
*/
static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope, io_streams_t &streams)
{
    size_t i;
    int retcode = 0;
    const wchar_t *val_str=NULL;

    if (is_path_variable(key))
    {
        /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */
        bool any_success = false;

        /* Don't bother validating (or complaining about) values that are already present.
           When determining already-present values, use ENV_DEFAULT instead of the passed-in scope because in:
              set -l PATH stuff $PATH
           where we are temporarily shadowing a variable, we want to compare against the shadowed value, not the
           (missing) local value.
           Also don't bother to complain about relative paths, which don't start with /.
        */
        wcstring_list_t existing_values;
        const env_var_t existing_variable = env_get_string(key, ENV_DEFAULT);
        if (! existing_variable.missing_or_empty())
            tokenize_variable_array(existing_variable, existing_values);

        for (i=0; i< val.size() ; i++)
        {
            const wcstring &dir = val.at(i);
            if (!string_prefixes_string(L"/", dir) || list_contains_string(existing_values, dir))
            {
                any_success = true;
                continue;
            }

            bool show_perror = false;
            int show_hint = 0;
            bool error = false;

            struct stat buff;
            if (wstat(dir, &buff))
            {
                error = true;
                show_perror = true;
            }

            if (!(S_ISDIR(buff.st_mode)))
            {
                error = true;
            }

            if (!error)
            {
                any_success = true;
            }
            else
            {
                streams.err.append_format(_(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key);
                const wchar_t *colon = wcschr(dir.c_str(), L':');

                if (colon && *(colon+1))
                {
                    show_hint = 1;
                }

            }

            if (show_perror)
            {
                builtin_wperror(L"set", streams);
            }

            if (show_hint)
            {
                streams.err.append_format(_(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1);
            }

        }

        /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */
        if (! val.empty() && ! any_success)
        {
            return 1;
        }

    }

    wcstring sb;
    if (! val.empty())
    {
        for (i=0; i< val.size() ; i++)
        {
            sb.append(val[i]);
            if (i<val.size() - 1)
            {
                sb.append(ARRAY_SEP_STR);
            }
        }
        val_str = sb.c_str();
    }

    switch (env_set(key, val_str, scope | ENV_USER))
    {
        case ENV_PERM:
        {
            streams.err.append_format(_(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key);
            retcode=1;
            break;
        }

        case ENV_SCOPE:
        {
            streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key);
            retcode=1;
            break;
        }

        case ENV_INVALID:
        {
            streams.err.append_format(_(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key);
            retcode=1;
            break;
        }
    }

    return retcode;
}
Example #8
0
u64 FileSize(const OsPath& pathname)
{
	struct stat s;
	ENSURE(wstat(pathname, &s) == 0);
	return s.st_size;
}
Example #9
0
/*
 * It would be -so- nice just to call _wait4 and mapstatus here.
 */
int
wait4(int pid, int *status, int options, struct rusage *rp)
{
        struct  tms     before_tms;
        struct  tms     after_tms;
        siginfo_t       info;
        int             error;
        int             noptions;
	idtype_t	idtype;
 
        if ((int)status == -1 || (int)rp == -1) {
                errno = EFAULT;
                return(-1);
        }
 
        if (rp)
                memset(rp, 0, sizeof(struct rusage));
	memset(&info, 0, sizeof (siginfo_t));
        if (times(&before_tms) < 0)
                return (-1);            /* errno is set by times() */

	/*
	 * BSD's wait* routines only support WNOHANG & WUNTRACED
	 */
	if (options & ~(WNOHANG|WUNTRACED))
		return (EINVAL);
	noptions = N_WEXITED | N_WTRAPPED;
	if (options & WNOHANG)
		noptions |= N_WNOHANG;
	if (options & WUNTRACED)
		noptions |= N_WUNTRACED;	/* == N_WSTOPPED */

	/*
	 * Emulate undocumented 4.x semantics for 1186845
	 */
	if (pid < 0) {
		pid = -pid;
		idtype = P_PGID;
	} else if (pid == 0)
		idtype = P_ALL;
	else
		idtype = P_PID;

        error = _waitid(idtype, pid, &info, noptions);
        if (error == 0) {
                long diffu;  /* difference in usertime (ticks) */
                long diffs;  /* difference in systemtime (ticks) */

                if ((options & WNOHANG) && (info.si_pid == 0))
                        return (0);     /* no child found */

		if (rp) {
			if (times(&after_tms) < 0)
				return (-1);    /* errno already set by times() */
			/*
			 * The system/user time is an approximation only !!!
			 */
			diffu = after_tms.tms_cutime - before_tms.tms_cutime;
			diffs = after_tms.tms_cstime - before_tms.tms_cstime;
                	rp->ru_utime.tv_sec = diffu / HZ;
                	rp->ru_utime.tv_usec = (diffu % HZ) * (1000000 / HZ);
                	rp->ru_stime.tv_sec = diffs / HZ;
                	rp->ru_stime.tv_usec = (diffs % HZ) * (1000000 / HZ);
		}
                if (status)
                        *status = wstat(info.si_code, info.si_status);
                return (info.si_pid);
         } else {
                return (-1);            /* error number is set by waitid() */
        }
}
Example #10
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 #11
0
/* wcmd

   function fills the datastructure sens

*/
int wcmd (struct sensor sens[], struct cmd *pcmd, int *setno) {
   
  int i;                          /* for array subscription */
  int ndat = 0;                   /* length of array containing the 
                                     data frame */
  int err;                        /* return value of functions, 
                                     useful for errorhandling */
  int retval = 0;                 /* return values for this function */
                                  /*  0 : everythings fine */
                                  /*  1 : no data available */
                                  /* -1 : unknown response of weatherstation */  
  int snum = 0;                   /* number of data sets */
  int command;
  int argcm;

  struct DCFstruct DCF;           /* DCF status and synchronous */
  struct wstatus setting;

  u_char data[MAXBUFF];           /* data array to store the raw dataframe 
                                     and the message datagram */
  char *clk;                      /* display time in reasonable format */

  command = pcmd->command; 
  argcm   = pcmd->argcmd; 

  /* first get status of weatherstation 
     needed to fill sens.status
  */
  pcmd->command = 5;
  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
	return(-1);
  pcmd->command = command;

  syslog(LOG_INFO, "wcmd : check status OK\n");

  /* status weatherstation */
  err = wstat(data, ndat, &DCF, sens, &setting);
  syslog(LOG_INFO, "wcmd : DCF.stat : %d\n", DCF.stat);
  syslog(LOG_INFO, "wcmd : DCF.sync : %d\n", DCF.sync);
  syslog(LOG_INFO, "wcmd : number sensors : %d\n", setting.numsens);
  syslog(LOG_INFO, "wcmd : version : %x\n", setting.version);
  for ( i = 0;  i < MAXSENSORS; i++ ) {
    syslog(LOG_DEBUG, "wcmd : sens[%d].status: %d, type: %s\n", i, sens[i].status, sens[i].type);
  }


  /* command 0 : poll DCF time */
  if (command == 0) {
      /* write command and retrieve data */
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
	     return(-1);

      /* calculate seconds since EPOCH if DCF synchronized */
      DCF.time  = dcftime(data, ndat);
      if (DCF.time == -1) 
		printf("Weatherstation not synchronized\n");
      else { 
		clk = ctime(&DCF.time);
		printf("%s", clk);
      }
  }

  /* command 1 : Request Dataset */
  else if (command == 1)  {

      /* first get DCF time if possible */
      pcmd->command = 0;
      if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		   return(-1);
      pcmd->command = command;

      /* calculate seconds since EPOCH if DCF synchronized */
      DCF.time  = dcftime(data, ndat);

      /* write command and retrieve data */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1)
	     return(-1);

      /* weather station response : no data available: <DLE> */
      if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
	  syslog(LOG_INFO, "wcmd : DLE received : weather station :\"no data available\": exit!\n");
	  retval = 16;
      }
      /* fill data structure sens */
      else {
	  /* get one dataset */
	  err = getone(data, ndat, sens, snum, DCF);
	  syslog(LOG_INFO, "wcmd : returncode getone : %d\n", err);
          snum++;
      }

      /* echo sensor data */
      err = pdata(sens, snum);
  } 


  /* command 2 : Select next dataset */
  else if (command == 2) {
      /* write the command word to the weather station */ 
      /* extract message datagram */
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		return(-1);

      /* if DLE no data available */
      if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
	  syslog(LOG_INFO, \
              "wcmd : DLE received : weather station :\"no data available\"!\n");
          retval = 16; 
      } else if ( ( ndat == 1 ) && ( data[0] == ACK ) ) /* if ACK next dataset is available */ {
	  syslog(LOG_INFO, \
             "wcmd : ACK received : weather station :\"next dataset available\": exit!\n");
          retval = 6;
      }
      /* exit if unknown response */
      else {
	  syslog(LOG_EMERG, "wcmd : error request next dataset : unknown response: exit \n");
          retval = -1;
      }
  }


  /* command 3 : Activate 8 temperature sensors */
  else if (command == 3) {

      /* write the command word to the weather station */ 
      /* extract message datagram */
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		return(-1);

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
          syslog(LOG_INFO, "wcmd : ACK received\n");
          printf("Weatherstation response : <ACK>\n");
      }

  } 


  /* command 4 : Activate 16 temperature sensors */
  else if (command == 4) {

      /* write the command word to the weather station */ 
      /* extract message datagram */
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		return(-1);

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
          syslog(LOG_INFO, "wcmd : ACK received\n");
          printf("Weatherstation response : <ACK>\n");
      }

  } 


  /* command 5 : Request status of weatherstation */
  else if ( command == 5 ) {
      /* check status - this is done at every call of wcmd*/
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		return(-1);

      /* status weatherstation */
      err = wstat(data, ndat, &DCF, sens, &setting);

      syslog(LOG_INFO, "wcmd : DCF.stat : %d\n", DCF.stat);
      syslog(LOG_INFO, "wcmd : DCF.sync : %d\n", DCF.sync);
      syslog(LOG_INFO, "wcmd : number sensors : %d\n", setting.numsens);
      syslog(LOG_INFO, "wcmd : version : %x\n", setting.version);


      for ( i = 0;  i < MAXSENSORS; i++ ) {
	  syslog(LOG_DEBUG, "wcmd : sens[%d].status: %d, type: %s\n", i, sens[i].status, sens[i].type);
      }

      printf("Status weatherstation\n");
      printf("Version : %x\n", setting.version);  
      printf("Interval : %d\n", setting.intv);  
      printf("Numsens : %d\n", setting.numsens);  
      printf("DCF.stat : %d\n", DCF.stat);
      printf("DCF.sync : %d\n", DCF.sync);

  } 


  /* command 6 : Set logging intervall of weatherstation */
  else if (command == 6) {

      /* write the command word to the weather station */ 
      /* extract message datagram */
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
	    return(-1);

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
          syslog(LOG_INFO, "wcmd : ACK received\n");
          printf("Weatherstation response : <ACK>\n");
      }

  } 


  /* command 12 : 
      Recursively, request dataset and select next dataset, 
      recursive combination of command 1 and 2 
  */
  else if (command == 12) {

      
      /* first get DCF time if possible */
      pcmd->command = 0;
      if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		return(-1);
      pcmd->command = command;

      /* calculate seconds since EPOCH if DCF synchronized */
      DCF.time  = dcftime(data, ndat);

      while (retval != 16) {
		  /* write command and retrieve data */
		  pcmd->command = 1;
		  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
		    return(-1);

		  /* weather station response : no data available: <DLE> */
		  if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
			syslog(LOG_INFO, \
              "wcmd : DLE received : weather station :\"no data available\"!\n");
			retval = 16;
		  }
		  /* fill data structure sens */
		  else {
			/* get one dataset */
			err = getone(data, ndat, sens, snum, DCF);
            syslog(LOG_INFO, "wcmd : returncode getone : %d\n", err);

			/* increase dataset number index */
			snum++;
		  }
 
		  /* write the command word to select next dataset and retrieve response*/ 
		  pcmd->command = 2;
		  
		  if ( ( err = getcd( data, &ndat, pcmd)) == -1)
			return(-1);

		  /* if DLE no data available */
		  if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
			syslog(LOG_INFO, \
	          "wcmd : DLE received : weather station :\"no data available\"!\n");

			printf("DLE received : weather station :\"no data available\"!\n");
			retval = 16; 
		  }
		  /* if ACK next dataset is available */
		  else if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
			syslog(LOG_INFO, \
                  "wcmd : ACK received : weather station :\"next dataset available\"!\n");
			retval = 6;
		  }
		  /* exit if unknown response */
		  else {
              syslog(LOG_EMERG, \
	          "wcmd : error request next dataset : unknown response: exit \n");
			  retval = -2;
		  }
          syslog(LOG_INFO, "wcmd : retval : %d\n", retval);
      }

      /* echo sensor data */
      err = pdata(sens, snum);
  } else {

      printf("Unknown command: exit!\n");
      exit(1);
  }

  *setno = snum;
  syslog(LOG_INFO, "wcmd : returncode wcmd : %d, number of sets : %d\n", retval, *setno);
 
  return(retval);

}
Example #12
0
long wfsize(const wchar_t *filename) {
	struct stat st; 
    if (wstat(filename, &st) == 0)
        return st.st_size;
    return -1;
}
Example #13
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards.

   Because this function calls itself recursively with substrings,
   it's important that the parameters be raw pointers instead of wcstring,
   which would be too expensive to construct for all substrings.
 */
static int wildcard_expand_internal(const wchar_t *wc,
                                    const wchar_t * const base_dir,
                                    expand_flags_t flags,
                                    std::vector<completion_t> &out,
                                    std::set<wcstring> &completion_set,
                                    std::set<file_id_t> &visited_files)
{

    /* Variables for traversing a directory */
    DIR *dir;

    /* The result returned */
    int res = 0;

    /* Variables for testing for presense of recursive wildcards */
    const wchar_t *wc_recursive;
    bool is_recursive;

    /* Slightly mangled version of base_dir */
    const wchar_t *dir_string;

    //  debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

    if (is_main_thread() ? reader_interrupted() : reader_thread_job_is_stale())
    {
        return -1;
    }

    if (!wc || !base_dir)
    {
        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
        return 0;
    }

    const size_t base_dir_len = wcslen(base_dir);

    if (flags & ACCEPT_INCOMPLETE)
    {
        /*
           Avoid excessive number of returned matches for wc ending with a *
        */
        size_t len = wcslen(wc);
        if (len > 0 && (wc[len-1]==ANY_STRING))
        {
            wchar_t * foo = wcsdup(wc);
            foo[len-1]=0;
            int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
            free(foo);
            return res;
        }
    }

    /* Initialize various variables */

    dir_string = (base_dir[0] == L'\0') ? L"." : base_dir;

    if (!(dir = wopendir(dir_string)))
    {
        return 0;
    }

    /* Points to the end of the current wildcard segment */
    const wchar_t * const wc_end = wcschr(wc,L'/');

    /*
      Test for recursive match string in current segment
    */
    wc_recursive = wcschr(wc, ANY_STRING_RECURSIVE);
    is_recursive = (wc_recursive && (!wc_end || wc_recursive < wc_end));

    /*
      Is this segment of the wildcard the last?
    */
    if (!wc_end)
    {
        /*
          Wildcard segment is the last segment,

          Insert all matching files/directories
        */
        if (wc[0]=='\0')
        {
            /*
              The last wildcard segment is empty. Insert everything if
              completing, the directory itself otherwise.
            */
            if (flags & ACCEPT_INCOMPLETE)
            {
                wcstring next;
                while (wreaddir(dir, next))
                {
                    if (next[0] != L'.')
                    {
                        wcstring long_name = make_path(base_dir, next);

                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, next, L"", flags);
                        }
                    }
                }
            }
            else
            {
                res = 1;
                insert_completion_if_missing(base_dir, out, completion_set);
            }
        }
        else
        {
            /* This is the last wildcard segment, and it is not empty. Match files/directories. */
            wcstring name_str;
            while (wreaddir(dir, name_str))
            {
                if (flags & ACCEPT_INCOMPLETE)
                {

                    const wcstring long_name = make_path(base_dir, name_str);

                    /* Test for matches before stating file, so as to minimize the number of calls to the much slower stat function. The only expand flag we care about is EXPAND_FUZZY_MATCH; we have no complete flags. */
                    std::vector<completion_t> test;
                    if (wildcard_complete(name_str, wc, L"", NULL, test, flags & EXPAND_FUZZY_MATCH, 0))
                    {
                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out, long_name, name_str, wc, flags);

                        }
                    }
                }
                else
                {
                    if (wildcard_match(name_str, wc, true /* skip files with leading dots */))
                    {
                        const wcstring long_name = make_path(base_dir, name_str);
                        int skip = 0;

                        if (is_recursive)
                        {
                            /*
                              In recursive mode, we are only
                              interested in adding files -directories
                              will be added in the next pass.
                            */
                            struct stat buf;
                            if (!wstat(long_name, &buf))
                            {
                                skip = S_ISDIR(buf.st_mode);
                            }
                        }
                        if (! skip)
                        {
                            insert_completion_if_missing(long_name, out, completion_set);
                        }
                        res = 1;
                    }
                }
            }
        }
    }

    if (wc_end || is_recursive)
    {
        /*
          Wilcard segment is not the last segment.  Recursively call
          wildcard_expand for all matching subdirectories.
        */

        /*
          In recursive mode, we look through the directory twice. If
          so, this rewind is needed.
        */
        rewinddir(dir);

        /*
          wc_str is the part of the wildcarded string from the
          beginning to the first slash
        */
        const wcstring wc_str = wcstring(wc, wc_end ? wc_end - wc : wcslen(wc));

        /* new_dir is a scratch area containing the full path to a file/directory we are iterating over */
        wcstring new_dir = base_dir;

        wcstring name_str;
        while (wreaddir(dir, name_str))
        {
            /*
              Test if the file/directory name matches the whole
              wildcard element, i.e. regular matching.
            */
            int whole_match = wildcard_match(name_str, wc_str, true /* ignore leading dots */);
            int partial_match = 0;

            /*
               If we are doing recursive matching, also check if this
               directory matches the part up to the recusrive
               wildcard, if so, then we can search all subdirectories
               for matches.
            */
            if (is_recursive)
            {
                const wchar_t *end = wcschr(wc, ANY_STRING_RECURSIVE);
                wchar_t *wc_sub = wcsndup(wc, end-wc+1);
                partial_match = wildcard_match(name_str, wc_sub, true /* ignore leading dots */);
                free(wc_sub);
            }

            if (whole_match || partial_match)
            {
                struct stat buf;
                int new_res;

                // new_dir is base_dir + some other path components
                // Replace everything after base_dir with the new path component
                new_dir.replace(base_dir_len, wcstring::npos, name_str);

                int stat_res = wstat(new_dir, &buf);

                if (!stat_res)
                {
                    // Insert a "file ID" into visited_files
                    // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                    // If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
                    const file_id_t file_id = file_id_t::file_id_from_stat(&buf);
                    if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
                    {
                        new_dir.push_back(L'/');

                        /*
                          Regular matching
                        */
                        if (whole_match)
                        {
                            const wchar_t *new_wc = L"";
                            if (wc_end)
                            {
                                new_wc=wc_end+1;
                                /*
                                  Accept multiple '/' as a single direcotry separator
                                */
                                while (*new_wc==L'/')
                                {
                                    new_wc++;
                                }
                            }

                            new_res = wildcard_expand_internal(new_wc,
                                                               new_dir.c_str(),
                                                               flags,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }

                        /*
                          Recursive matching
                        */
                        if (partial_match)
                        {

                            new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
                                                               new_dir.c_str(),
                                                               flags | WILDCARD_RECURSIVE,
                                                               out,
                                                               completion_set,
                                                               visited_files);

                            if (new_res == -1)
                            {
                                res = -1;
                                break;
                            }
                            res |= new_res;

                        }
                    }
                }
            }
        }
    }
    closedir(dir);

    return res;
}
Example #14
0
/* wcmd

   function fills the datastructure rw

*/
char *
wcmd (struct cmd *pcmd, struct wthio *rw) {
  int ndat = 0;                   /* length of array containing the 
                                     data frame */
  int err;                        /* return value of functions, 
                                     useful for errorhandling */
  int retval = 0;                 
  long snum = 0;                   /* current dataset number */
  int command;
  int argcm;
  unsigned char data[MAXBUFF];    /* data array to store the raw dataframe 
                                     and the message datagram */
  char *clk;                      /* display time in reasonable format */
  char *rbuf;                 /* return buffer */
  

  syslog(LOG_DEBUG, "wcmd: called for command request: %d\n",pcmd->command);  
  rw->wstat.ndats = 0;
  command = pcmd->command; 
  argcm   = pcmd->argcmd; 

  /* first get status of weatherstation 
     needed to fill sens.status
  */
  pcmd->command = 5;
  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
	rbuf = mkmsg("wcmd: error data reception\n");
	return (rbuf);
  }
  pcmd->command = command;
  syslog(LOG_DEBUG, "wcmd : check status OK\n");

  /* status weatherstation */
  if ( ( rbuf = wstat(data, ndat, rw)) == NULL) {
	rbuf = mkmsg("wcmd: error in subroutine wstat\n");
	return (rbuf);
  }
  
  /* command 0 : poll DCF time */
  if (command == 0) {
    tzset();
	
    /* write command and retrieve data */
    if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
      rbuf = mkmsg("wcmd: error data reception\n");
      return (rbuf);
    }

    /* calculate seconds since EPOCH if DCF synchronized */
    rw->DCF.time  = dcftime(data, ndat);
    if (rw->DCF.time == -1) {
      rbuf = mkmsg("DCF not synchronized\n");
    }
    else {
      clk = ctime(&rw->DCF.time);
      rbuf = mkmsg("%s", clk);
    }
  }

  /* command 1 : Request Dataset */
  else if (command == 1)  {
      /* first get DCF time if possible */
      pcmd->command = 0;
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }
	  pcmd->command = command;

      /* calculate seconds since EPOCH if DCF synchronized */
      rw->DCF.time  = dcftime(data, ndat);

      /* write command and retrieve data */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }

      /* weather station response : no data available: <DLE> */
      if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
	rbuf = mkmsg("no data available (<DLE> received)\n");
      }
      /* fill data structure sens */
      else {
	/* get one dataset */
	err = datex(data, ndat, rw);
	syslog(LOG_DEBUG, "wcmd : returncode datex : %d\n", err);
	rw->wstat.ndats = rw->wstat.ndats + 1;
	snum++;
      }

      /* echo sensor data */
      if ( rw->wstat.ndats > 0 )
	rbuf = pdata(rw);
  } 


  /* command 2 : Select next dataset */
  else if (command == 2) {
      /* write the command word to the weather station */ 
      /* extract message datagram */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }


      /* if DLE no data available */
      if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
		rbuf = mkmsg("no data available(<DLE> received)\n");
        retval = 16; 
      } else if ( ( ndat == 1 ) && ( data[0] == ACK ) ) /* if ACK next dataset is available */ {
		rbuf = mkmsg("next dataset available (<ACK> received)\n");
        retval = 6;
      }
      /* exit if unknown response */
      else {
		rbuf = mkmsg("error next dataset : \"unknown response\"\n");
        retval = -1;
      }
  }


  /* command 3 : Activate 8 temperature sensors */
  else if (command == 3) {

      /* write the command word to the weather station */ 
      /* extract message datagram */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
		rbuf = mkmsg("set 9 temperature sensors (<ACK> received)\n");
      }

	  /* update status */
	  pcmd->command = 5;
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }
	  if ( ( wstat(data, ndat, rw)) == NULL) {
		rbuf = mkmsg("wcmd: error in subroutine wstat\n");
		return (rbuf);
	  }	  
  } 


  /* command 4 : Activate 16 temperature sensors */
  else if (command == 4) {

      /* write the command word to the weather station */ 
      /* extract message datagram */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
		rbuf = mkmsg("set 16 temperature sensors(<ACK> received)\n");
      }

	  /* update status */
	  pcmd->command = 5;
	  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }
	  if ( ( wstat(data, ndat, rw)) == NULL) {
		rbuf = mkmsg("wcmd: error in subroutine wstat\n");
		return (rbuf);
	  }	  
  } 


  /* command 5 : Request status of weatherstation */
  else if ( command == 5 ) {
	; /* status known, drive thru */
  } 


  /* command 6 : Set logging intervall of weatherstation */
  else if (command == 6) {
      /* write the command word to the weather station */ 
      /* extract message datagram */
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }

      /* weather station response : <ACK> */
      if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
	rbuf = mkmsg("set logging interval to %d [min] (<ACK> received)\n",
		     pcmd->argcmd);
      }

      /* update status */
      pcmd->command = 5;
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
	rbuf = mkmsg("wcmd: error data reception\n");
	return (rbuf);
      }

      if ( ( wstat( data, ndat, rw)) == NULL) {
	rbuf = mkmsg("wcmd: error in subroutine wstat\n");
	return (rbuf);
      }
  } 


  /* command 12 : 
      Recursively, request dataset and select next dataset, 
      recursive combination of command 1 and 2 
  */
  else if (command == 12) {      
      /* first get DCF time if possible */
      pcmd->command = 0;
      if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
		rbuf = mkmsg("wcmd: error data reception\n");
		return (rbuf);
	  }
      pcmd->command = command;

      /* calculate seconds since EPOCH if DCF synchronized */
      rw->DCF.time  = dcftime(data, ndat);

	  
      while (retval != 16) {
		  /* write command and retrieve data */
		  pcmd->command = 1;
		  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
			rbuf = mkmsg("wcmd: error data reception\n");
			return (rbuf);
		  }

		  /* extract dataset from raw dataframe */
		  /* weather station response : no data available: <DLE> */
		  if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
			rbuf = mkmsg("no data available (<DLE> received)\n");
			retval = 16;
		  }
		  /* do extraction */
		  else {
			if ( ( err = datex(data, ndat, rw)) == -1) {
				rbuf = mkmsg("wcmd: error extracting data frame");
				return (rbuf);
			}
			rw->wstat.ndats = rw->wstat.ndats + 1;
		  }
 
		  /* write the command word to select next dataset and 
		     retrieve response*/ 
		  pcmd->command = 2;
		  if ( ( err = getcd( data, &ndat, pcmd)) == -1) {
			rbuf = mkmsg("wcmd: error data reception\n");
			return (rbuf);
		  }

		  /* stop if DLE no data available, */
		  if ( ( ndat == 1 ) && ( data[0] == DLE ) ) {
		    /* rbuf = mkmsg(
		       "<DLE> received :\"no data available\"!"); */
		    retval = 16; 
		  }
		  /* if ACK next dataset is available */
		  else if ( ( ndat == 1 ) && ( data[0] == ACK ) ) {
			syslog(LOG_DEBUG, \
                  "wcmd: next dataset available (<ACK> received)!\n");
			retval = 6;
		  }
		  /* return if unknown response */
		  /* no data is returned, maybe too strict? */
		  else {
		    rbuf = mkmsg(
		      "wcmd: error request next dataset : unknown response\n");
		    return (rbuf);
		  }
          syslog(LOG_DEBUG, "wcmd: retval : %d\n", retval);
      }

      /* echo sensor data */
	  if ( rw->wstat.ndats > 0 )
		rbuf = pdata(rw);
  } else {
      rbuf = mkmsg("unknown command\n");
  }
  syslog(LOG_DEBUG, "wcmd: exit OK\n");
  return(rbuf);
}
Example #15
0
/**
   Call env_set. If this is a path variable, e.g. PATH, validate the
   elements. On error, print a description of the problem to stderr.
*/
static int my_env_set(const wchar_t *key, const wcstring_list_t &val, int scope)
{
    size_t i;
    int retcode = 0;
    const wchar_t *val_str=NULL;

    if (is_path_variable(key))
    {
        /* Fix for https://github.com/fish-shell/fish-shell/issues/199 . Return success if any path setting succeeds. */
        bool any_success = false;

        /* Don't bother validating (or complaining about) values that are already present */
        wcstring_list_t existing_values;
        const env_var_t existing_variable = env_get_string(key);
        if (! existing_variable.missing_or_empty())
            tokenize_variable_array(existing_variable, existing_values);

        for (i=0; i< val.size() ; i++)
        {
            const wcstring &dir = val.at(i);
            if (list_contains_string(existing_values, dir))
            {
                any_success = true;
                continue;
            }

            bool show_perror = false;
            int show_hint = 0;
            bool error = false;

            struct stat buff;
            if (wstat(dir, &buff))
            {
                error = true;
                show_perror = true;
            }

            if (!(S_ISDIR(buff.st_mode)))
            {
                error = true;
            }

            if (!error)
            {
                any_success = true;
            }
            else
            {
                append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir.c_str(), key);
                const wchar_t *colon = wcschr(dir.c_str(), L':');

                if (colon && *(colon+1))
                {
                    show_hint = 1;
                }

            }

            if (show_perror)
            {
                builtin_wperror(L"set");
            }

            if (show_hint)
            {
                append_format(stderr_buffer, _(BUILTIN_SET_PATH_HINT), L"set", key, key, wcschr(dir.c_str(), L':')+1);
            }

        }

        /* Fail at setting the path if we tried to set it to something non-empty, but it wound up empty. */
        if (! val.empty() && ! any_success)
        {
            return 1;
        }

    }

    wcstring sb;
    if (! val.empty())
    {
        for (i=0; i< val.size() ; i++)
        {
            sb.append(val[i]);
            if (i<val.size() - 1)
            {
                sb.append(ARRAY_SEP_STR);
            }
        }
        val_str = sb.c_str();
    }

    switch (env_set(key, val_str, scope | ENV_USER))
    {
        case ENV_PERM:
        {
            append_format(stderr_buffer, _(L"%ls: Tried to change the read-only variable '%ls'\n"), L"set", key);
            retcode=1;
            break;
        }

        case ENV_INVALID:
        {
            append_format(stderr_buffer, _(L"%ls: Unknown error"), L"set");
            retcode=1;
            break;
        }
    }

    return retcode;
}
Example #16
0
bool FileExists(const OsPath& pathname)
{
	struct stat s;
	const bool exists = wstat(pathname, &s) == 0;
	return exists;
}
Example #17
0
/*
 * Return value:
 *   1 - exitlwps() failed, call (or continue) lwp_exit()
 *   0 - restarting init.  Return through system call path
 */
int
proc_exit(int why, int what)
{
	kthread_t *t = curthread;
	klwp_t *lwp = ttolwp(t);
	proc_t *p = ttoproc(t);
	zone_t *z = p->p_zone;
	timeout_id_t tmp_id;
	int rv;
	proc_t *q;
	task_t *tk;
	vnode_t *exec_vp, *execdir_vp, *cdir, *rdir;
	sigqueue_t *sqp;
	lwpdir_t *lwpdir;
	uint_t lwpdir_sz;
	tidhash_t *tidhash;
	uint_t tidhash_sz;
	ret_tidhash_t *ret_tidhash;
	refstr_t *cwd;
	hrtime_t hrutime, hrstime;
	int evaporate;

	/*
	 * Stop and discard the process's lwps except for the current one,
	 * unless some other lwp beat us to it.  If exitlwps() fails then
	 * return and the calling lwp will call (or continue in) lwp_exit().
	 */
	proc_is_exiting(p);
	if (exitlwps(0) != 0)
		return (1);

	mutex_enter(&p->p_lock);
	if (p->p_ttime > 0) {
		/*
		 * Account any remaining ticks charged to this process
		 * on its way out.
		 */
		(void) task_cpu_time_incr(p->p_task, p->p_ttime);
		p->p_ttime = 0;
	}
	mutex_exit(&p->p_lock);

	DTRACE_PROC(lwp__exit);
	DTRACE_PROC1(exit, int, why);

	/*
	 * Will perform any brand specific proc exit processing, since this
	 * is always the last lwp, will also perform lwp_exit and free brand
	 * data
	 */
	if (PROC_IS_BRANDED(p)) {
		lwp_detach_brand_hdlrs(lwp);
		brand_clearbrand(p, B_FALSE);
	}

	/*
	 * Don't let init exit unless zone_start_init() failed its exec, or
	 * we are shutting down the zone or the machine.
	 *
	 * Since we are single threaded, we don't need to lock the
	 * following accesses to zone_proc_initpid.
	 */
	if (p->p_pid == z->zone_proc_initpid) {
		if (z->zone_boot_err == 0 &&
		    zone_status_get(z) < ZONE_IS_SHUTTING_DOWN &&
		    zone_status_get(global_zone) < ZONE_IS_SHUTTING_DOWN &&
		    z->zone_restart_init == B_TRUE &&
		    restart_init(what, why) == 0)
			return (0);
		/*
		 * Since we didn't or couldn't restart init, we clear
		 * the zone's init state and proceed with exit
		 * processing.
		 */
		z->zone_proc_initpid = -1;
	}

	lwp_pcb_exit();

	/*
	 * Allocate a sigqueue now, before we grab locks.
	 * It will be given to sigcld(), below.
	 * Special case:  If we will be making the process disappear
	 * without a trace because it is either:
	 *	* an exiting SSYS process, or
	 *	* a posix_spawn() vfork child who requests it,
	 * we don't bother to allocate a useless sigqueue.
	 */
	evaporate = (p->p_flag & SSYS) || ((p->p_flag & SVFORK) &&
	    why == CLD_EXITED && what == _EVAPORATE);
	if (!evaporate)
		sqp = kmem_zalloc(sizeof (sigqueue_t), KM_SLEEP);

	/*
	 * revoke any doors created by the process.
	 */
	if (p->p_door_list)
		door_exit();

	/*
	 * Release schedctl data structures.
	 */
	if (p->p_pagep)
		schedctl_proc_cleanup();

	/*
	 * make sure all pending kaio has completed.
	 */
	if (p->p_aio)
		aio_cleanup_exit();

	/*
	 * discard the lwpchan cache.
	 */
	if (p->p_lcp != NULL)
		lwpchan_destroy_cache(0);

	/*
	 * Clean up any DTrace helper actions or probes for the process.
	 */
	if (p->p_dtrace_helpers != NULL) {
		ASSERT(dtrace_helpers_cleanup != NULL);
		(*dtrace_helpers_cleanup)();
	}

	/* untimeout the realtime timers */
	if (p->p_itimer != NULL)
		timer_exit();

	if ((tmp_id = p->p_alarmid) != 0) {
		p->p_alarmid = 0;
		(void) untimeout(tmp_id);
	}

	/*
	 * Remove any fpollinfo_t's for this (last) thread from our file
	 * descriptors so closeall() can ASSERT() that they're all gone.
	 */
	pollcleanup();

	if (p->p_rprof_cyclic != CYCLIC_NONE) {
		mutex_enter(&cpu_lock);
		cyclic_remove(p->p_rprof_cyclic);
		mutex_exit(&cpu_lock);
	}

	mutex_enter(&p->p_lock);

	/*
	 * Clean up any DTrace probes associated with this process.
	 */
	if (p->p_dtrace_probes) {
		ASSERT(dtrace_fasttrap_exit_ptr != NULL);
		dtrace_fasttrap_exit_ptr(p);
	}

	while ((tmp_id = p->p_itimerid) != 0) {
		p->p_itimerid = 0;
		mutex_exit(&p->p_lock);
		(void) untimeout(tmp_id);
		mutex_enter(&p->p_lock);
	}

	lwp_cleanup();

	/*
	 * We are about to exit; prevent our resource associations from
	 * being changed.
	 */
	pool_barrier_enter();

	/*
	 * Block the process against /proc now that we have really
	 * acquired p->p_lock (to manipulate p_tlist at least).
	 */
	prbarrier(p);

	sigfillset(&p->p_ignore);
	sigemptyset(&p->p_siginfo);
	sigemptyset(&p->p_sig);
	sigemptyset(&p->p_extsig);
	sigemptyset(&t->t_sig);
	sigemptyset(&t->t_extsig);
	sigemptyset(&p->p_sigmask);
	sigdelq(p, t, 0);
	lwp->lwp_cursig = 0;
	lwp->lwp_extsig = 0;
	p->p_flag &= ~(SKILLED | SEXTKILLED);
	if (lwp->lwp_curinfo) {
		siginfofree(lwp->lwp_curinfo);
		lwp->lwp_curinfo = NULL;
	}

	t->t_proc_flag |= TP_LWPEXIT;
	ASSERT(p->p_lwpcnt == 1 && p->p_zombcnt == 0);
	prlwpexit(t);		/* notify /proc */
	lwp_hash_out(p, t->t_tid);
	prexit(p);

	p->p_lwpcnt = 0;
	p->p_tlist = NULL;
	sigqfree(p);
	term_mstate(t);
	p->p_mterm = gethrtime();

	exec_vp = p->p_exec;
	execdir_vp = p->p_execdir;
	p->p_exec = NULLVP;
	p->p_execdir = NULLVP;
	mutex_exit(&p->p_lock);

	pr_free_watched_pages(p);

	closeall(P_FINFO(p));

	/* Free the controlling tty.  (freectty() always assumes curproc.) */
	ASSERT(p == curproc);
	(void) freectty(B_TRUE);

#if defined(__sparc)
	if (p->p_utraps != NULL)
		utrap_free(p);
#endif
	if (p->p_semacct)			/* IPC semaphore exit */
		semexit(p);
	rv = wstat(why, what);

	acct(rv & 0xff);
	exacct_commit_proc(p, rv);

	/*
	 * Release any resources associated with C2 auditing
	 */
	if (AU_AUDITING()) {
		/*
		 * audit exit system call
		 */
		audit_exit(why, what);
	}

	/*
	 * Free address space.
	 */
	relvm();

	if (exec_vp) {
		/*
		 * Close this executable which has been opened when the process
		 * was created by getproc().
		 */
		(void) VOP_CLOSE(exec_vp, FREAD, 1, (offset_t)0, CRED(), NULL);
		VN_RELE(exec_vp);
	}
	if (execdir_vp)
		VN_RELE(execdir_vp);

	/*
	 * Release held contracts.
	 */
	contract_exit(p);

	/*
	 * Depart our encapsulating process contract.
	 */
	if ((p->p_flag & SSYS) == 0) {
		ASSERT(p->p_ct_process);
		contract_process_exit(p->p_ct_process, p, rv);
	}

	/*
	 * Remove pool association, and block if requested by pool_do_bind.
	 */
	mutex_enter(&p->p_lock);
	ASSERT(p->p_pool->pool_ref > 0);
	atomic_add_32(&p->p_pool->pool_ref, -1);
	p->p_pool = pool_default;
	/*
	 * Now that our address space has been freed and all other threads
	 * in this process have exited, set the PEXITED pool flag.  This
	 * tells the pools subsystems to ignore this process if it was
	 * requested to rebind this process to a new pool.
	 */
	p->p_poolflag |= PEXITED;
	pool_barrier_exit();
	mutex_exit(&p->p_lock);

	mutex_enter(&pidlock);

	/*
	 * Delete this process from the newstate list of its parent. We
	 * will put it in the right place in the sigcld in the end.
	 */
	delete_ns(p->p_parent, p);

	/*
	 * Reassign the orphans to the next of kin.
	 * Don't rearrange init's orphanage.
	 */
	if ((q = p->p_orphan) != NULL && p != proc_init) {

		proc_t *nokp = p->p_nextofkin;

		for (;;) {
			q->p_nextofkin = nokp;
			if (q->p_nextorph == NULL)
				break;
			q = q->p_nextorph;
		}
		q->p_nextorph = nokp->p_orphan;
		nokp->p_orphan = p->p_orphan;
		p->p_orphan = NULL;
	}

	/*
	 * Reassign the children to init.
	 * Don't try to assign init's children to init.
	 */
	if ((q = p->p_child) != NULL && p != proc_init) {
		struct proc	*np;
		struct proc	*initp = proc_init;
		boolean_t	setzonetop = B_FALSE;

		if (!INGLOBALZONE(curproc))
			setzonetop = B_TRUE;

		pgdetach(p);

		do {
			np = q->p_sibling;
			/*
			 * Delete it from its current parent new state
			 * list and add it to init new state list
			 */
			delete_ns(q->p_parent, q);

			q->p_ppid = 1;
			q->p_pidflag &= ~(CLDNOSIGCHLD | CLDWAITPID);
			if (setzonetop) {
				mutex_enter(&q->p_lock);
				q->p_flag |= SZONETOP;
				mutex_exit(&q->p_lock);
			}
			q->p_parent = initp;

			/*
			 * Since q will be the first child,
			 * it will not have a previous sibling.
			 */
			q->p_psibling = NULL;
			if (initp->p_child) {
				initp->p_child->p_psibling = q;
			}
			q->p_sibling = initp->p_child;
			initp->p_child = q;
			if (q->p_proc_flag & P_PR_PTRACE) {
				mutex_enter(&q->p_lock);
				sigtoproc(q, NULL, SIGKILL);
				mutex_exit(&q->p_lock);
			}
			/*
			 * sigcld() will add the child to parents
			 * newstate list.
			 */
			if (q->p_stat == SZOMB)
				sigcld(q, NULL);
		} while ((q = np) != NULL);

		p->p_child = NULL;
		ASSERT(p->p_child_ns == NULL);
	}

	TRACE_1(TR_FAC_PROC, TR_PROC_EXIT, "proc_exit: %p", p);

	mutex_enter(&p->p_lock);
	CL_EXIT(curthread); /* tell the scheduler that curthread is exiting */

	/*
	 * Have our task accummulate our resource usage data before they
	 * become contaminated by p_cacct etc., and before we renounce
	 * membership of the task.
	 *
	 * We do this regardless of whether or not task accounting is active.
	 * This is to avoid having nonsense data reported for this task if
	 * task accounting is subsequently enabled. The overhead is minimal;
	 * by this point, this process has accounted for the usage of all its
	 * LWPs. We nonetheless do the work here, and under the protection of
	 * pidlock, so that the movement of the process's usage to the task
	 * happens at the same time as the removal of the process from the
	 * task, from the point of view of exacct_snapshot_task_usage().
	 */
	exacct_update_task_mstate(p);

	hrutime = mstate_aggr_state(p, LMS_USER);
	hrstime = mstate_aggr_state(p, LMS_SYSTEM);
	p->p_utime = (clock_t)NSEC_TO_TICK(hrutime) + p->p_cutime;
	p->p_stime = (clock_t)NSEC_TO_TICK(hrstime) + p->p_cstime;

	p->p_acct[LMS_USER]	+= p->p_cacct[LMS_USER];
	p->p_acct[LMS_SYSTEM]	+= p->p_cacct[LMS_SYSTEM];
	p->p_acct[LMS_TRAP]	+= p->p_cacct[LMS_TRAP];
	p->p_acct[LMS_TFAULT]	+= p->p_cacct[LMS_TFAULT];
	p->p_acct[LMS_DFAULT]	+= p->p_cacct[LMS_DFAULT];
	p->p_acct[LMS_KFAULT]	+= p->p_cacct[LMS_KFAULT];
	p->p_acct[LMS_USER_LOCK] += p->p_cacct[LMS_USER_LOCK];
	p->p_acct[LMS_SLEEP]	+= p->p_cacct[LMS_SLEEP];
	p->p_acct[LMS_WAIT_CPU]	+= p->p_cacct[LMS_WAIT_CPU];
	p->p_acct[LMS_STOPPED]	+= p->p_cacct[LMS_STOPPED];

	p->p_ru.minflt	+= p->p_cru.minflt;
	p->p_ru.majflt	+= p->p_cru.majflt;
	p->p_ru.nswap	+= p->p_cru.nswap;
	p->p_ru.inblock	+= p->p_cru.inblock;
	p->p_ru.oublock	+= p->p_cru.oublock;
	p->p_ru.msgsnd	+= p->p_cru.msgsnd;
	p->p_ru.msgrcv	+= p->p_cru.msgrcv;
	p->p_ru.nsignals += p->p_cru.nsignals;
	p->p_ru.nvcsw	+= p->p_cru.nvcsw;
	p->p_ru.nivcsw	+= p->p_cru.nivcsw;
	p->p_ru.sysc	+= p->p_cru.sysc;
	p->p_ru.ioch	+= p->p_cru.ioch;

	p->p_stat = SZOMB;
	p->p_proc_flag &= ~P_PR_PTRACE;
	p->p_wdata = what;
	p->p_wcode = (char)why;

	cdir = PTOU(p)->u_cdir;
	rdir = PTOU(p)->u_rdir;
	cwd = PTOU(p)->u_cwd;

	ASSERT(cdir != NULL || p->p_parent == &p0);

	/*
	 * Release resource controls, as they are no longer enforceable.
	 */
	rctl_set_free(p->p_rctls);

	/*
	 * Decrement tk_nlwps counter for our task.max-lwps resource control.
	 * An extended accounting record, if that facility is active, is
	 * scheduled to be written.  We cannot give up task and project
	 * membership at this point because that would allow zombies to escape
	 * from the max-processes resource controls.  Zombies stay in their
	 * current task and project until the process table slot is released
	 * in freeproc().
	 */
	tk = p->p_task;

	mutex_enter(&p->p_zone->zone_nlwps_lock);
	tk->tk_nlwps--;
	tk->tk_proj->kpj_nlwps--;
	p->p_zone->zone_nlwps--;
	mutex_exit(&p->p_zone->zone_nlwps_lock);

	/*
	 * Clear the lwp directory and the lwpid hash table
	 * now that /proc can't bother us any more.
	 * We free the memory below, after dropping p->p_lock.
	 */
	lwpdir = p->p_lwpdir;
	lwpdir_sz = p->p_lwpdir_sz;
	tidhash = p->p_tidhash;
	tidhash_sz = p->p_tidhash_sz;
	ret_tidhash = p->p_ret_tidhash;
	p->p_lwpdir = NULL;
	p->p_lwpfree = NULL;
	p->p_lwpdir_sz = 0;
	p->p_tidhash = NULL;
	p->p_tidhash_sz = 0;
	p->p_ret_tidhash = NULL;

	/*
	 * If the process has context ops installed, call the exit routine
	 * on behalf of this last remaining thread. Normally exitpctx() is
	 * called during thread_exit() or lwp_exit(), but because this is the
	 * last thread in the process, we must call it here. By the time
	 * thread_exit() is called (below), the association with the relevant
	 * process has been lost.
	 *
	 * We also free the context here.
	 */
	if (p->p_pctx) {
		kpreempt_disable();
		exitpctx(p);
		kpreempt_enable();

		freepctx(p, 0);
	}

	/*
	 * curthread's proc pointer is changed to point to the 'sched'
	 * process for the corresponding zone, except in the case when
	 * the exiting process is in fact a zsched instance, in which
	 * case the proc pointer is set to p0.  We do so, so that the
	 * process still points at the right zone when we call the VN_RELE()
	 * below.
	 *
	 * This is because curthread's original proc pointer can be freed as
	 * soon as the child sends a SIGCLD to its parent.  We use zsched so
	 * that for user processes, even in the final moments of death, the
	 * process is still associated with its zone.
	 */
	if (p != t->t_procp->p_zone->zone_zsched)
		t->t_procp = t->t_procp->p_zone->zone_zsched;
	else
		t->t_procp = &p0;

	mutex_exit(&p->p_lock);
	if (!evaporate) {
		p->p_pidflag &= ~CLDPEND;
		sigcld(p, sqp);
	} else {
		/*
		 * Do what sigcld() would do if the disposition
		 * of the SIGCHLD signal were set to be ignored.
		 */
		cv_broadcast(&p->p_srwchan_cv);
		freeproc(p);
	}
	mutex_exit(&pidlock);

	/*
	 * We don't release u_cdir and u_rdir until SZOMB is set.
	 * This protects us against dofusers().
	 */
	if (cdir)
		VN_RELE(cdir);
	if (rdir)
		VN_RELE(rdir);
	if (cwd)
		refstr_rele(cwd);

	/*
	 * task_rele() may ultimately cause the zone to go away (or
	 * may cause the last user process in a zone to go away, which
	 * signals zsched to go away).  So prior to this call, we must
	 * no longer point at zsched.
	 */
	t->t_procp = &p0;

	kmem_free(lwpdir, lwpdir_sz * sizeof (lwpdir_t));
	kmem_free(tidhash, tidhash_sz * sizeof (tidhash_t));
	while (ret_tidhash != NULL) {
		ret_tidhash_t *next = ret_tidhash->rth_next;
		kmem_free(ret_tidhash->rth_tidhash,
		    ret_tidhash->rth_tidhash_sz * sizeof (tidhash_t));
		kmem_free(ret_tidhash, sizeof (*ret_tidhash));
		ret_tidhash = next;
	}

	thread_exit();
	/* NOTREACHED */
}
Example #18
0
/* Tests whether the specified string cpath is the prefix of anything we could cd to. directories is a list of possible parent directories (typically either the working directory, or the cdpath). This does I/O!

   We expect the path to already be unescaped.
*/
bool is_potential_path(const wcstring &const_path, const wcstring_list_t &directories, path_flags_t flags, wcstring *out_path)
{
    ASSERT_IS_BACKGROUND_THREAD();
    
    const bool require_dir = !! (flags & PATH_REQUIRE_DIR);
    wcstring clean_path;
	int has_magic = 0;
	bool result = false;
    
    wcstring path(const_path);
    if (flags & PATH_EXPAND_TILDE)
        expand_tilde(path);    
    
    //	debug( 1, L"%ls -> %ls ->%ls", path, tilde, unescaped );
    
    for( size_t i=0; i < path.size(); i++)
    {
        wchar_t c = path.at(i);
        switch( c )
        {
            case PROCESS_EXPAND:
            case VARIABLE_EXPAND:
            case VARIABLE_EXPAND_SINGLE:
            case BRACKET_BEGIN:
            case BRACKET_END:
            case BRACKET_SEP:
            case ANY_CHAR:
            case ANY_STRING:
            case ANY_STRING_RECURSIVE:
            {
                has_magic = 1;
                break;		
            }
				
            case INTERNAL_SEPARATOR:
            {
                break;
            }
				
            default:
            {
                clean_path.push_back(c);
                break;
            }
				
        }
        
    }
    
    if( ! has_magic && ! clean_path.empty() )
    {
        /* Don't test the same path multiple times, which can happen if the path is absolute and the CDPATH contains multiple entries */
        std::set<wcstring> checked_paths;
        
        /* Keep a cache of which paths / filesystems are case sensitive */
        case_sensitivity_cache_t case_sensitivity_cache;
        
        for (size_t wd_idx = 0; wd_idx < directories.size() && ! result; wd_idx++) {
            const wcstring &wd = directories.at(wd_idx);
            
            const wcstring abs_path = apply_working_directory(clean_path, wd);
            
            /* Skip this if it's empty or we've already checked it */
            if (abs_path.empty() || checked_paths.count(abs_path))
                continue;
            checked_paths.insert(abs_path);
            
            /* If we end with a slash, then it must be a directory */
            bool must_be_full_dir = abs_path.at(abs_path.size()-1) == L'/';
            if (must_be_full_dir) 
            {
                struct stat buf;
                if (0 == wstat(abs_path, &buf) && S_ISDIR(buf.st_mode)) {
                    result = true;
                    /* Return the path suffix, not the whole absolute path */
                    if (out_path)
                        *out_path = clean_path;
                }
            }
            else
            {
                DIR *dir = NULL;
                
                /* We do not end with a slash; it does not have to be a directory */
                const wcstring dir_name = wdirname(abs_path);
                const wcstring base_name = wbasename(abs_path);
                if (dir_name == L"/" && base_name == L"/")
                {
                    result = true;
                    if (out_path)
                        *out_path = clean_path;
                }
                else if ((dir = wopendir(dir_name))) {
                    // We opened the dir_name; look for a string where the base name prefixes it
                    wcstring ent;
                    
                    // Check if we're case insensitive
                    bool case_insensitive = fs_is_case_insensitive(dir_name, dirfd(dir), case_sensitivity_cache);
                    
                    // Don't ask for the is_dir value unless we care, because it can cause extra filesystem acces */
                    bool is_dir = false;
                    while (wreaddir_resolving(dir, dir_name, ent, require_dir ? &is_dir : NULL))
                    {                    

                        /* Determine which function to call to check for prefixes */
                        bool (*prefix_func)(const wcstring &, const wcstring &);
                        if (case_insensitive) {
                            prefix_func = string_prefixes_string_case_insensitive;
                        } else {
                            prefix_func = string_prefixes_string;
                        }

                        if (prefix_func(base_name, ent) && (! require_dir || is_dir))
                        {
                            result = true;
                            if (out_path) {
                                /* We want to return the path in the same "form" as it was given. Take the given path, get its basename. Append that to the output if the basename actually prefixes the path (which it won't if the given path contains no slashes), and isn't a slash (so we don't duplicate slashes). Then append the directory entry. */
                                
                                out_path->clear();
                                const wcstring path_base = wdirname(const_path);
                                
                                
                                if (prefix_func(path_base, const_path)) {
                                    out_path->append(path_base);
                                    if (! string_suffixes_string(L"/", *out_path))
                                        out_path->push_back(L'/');
                                }
                                out_path->append(ent);
                                /* We actually do want a trailing / for directories, since it makes autosuggestion a bit nicer */
                                if (is_dir)
                                    out_path->push_back(L'/');
                            }
                            break;
                        }
                    }
                    closedir(dir);
                }
            }
        }
    }
    return result;
}
Example #19
0
/**
   Add the specified filename if it matches the specified wildcard.

   If the filename matches, first get the description of the specified
   filename. If this is a regular file, append the filesize to the
   description.

   \param list the list to add he completion to
   \param fullname the full filename of the file
   \param completion the completion part of the file name
   \param wc the wildcard to match against
   \param is_cmd whether we are performing command completion
*/
static void wildcard_completion_allocate(std::vector<completion_t> &list,
        const wcstring &fullname,
        const wcstring &completion,
        const wchar_t *wc,
        expand_flags_t expand_flags)
{
    struct stat buf, lbuf;
    wcstring sb;
    wcstring munged_completion;

    int flags = 0;
    int stat_res, lstat_res;
    int stat_errno=0;

    long long sz;

    /*
      If the file is a symlink, we need to stat both the file itself
      _and_ the destination file. But we try to avoid this with
      non-symlinks by first doing an lstat, and if the file is not a
      link we copy the results over to the regular stat buffer.
    */
    if ((lstat_res = lwstat(fullname, &lbuf)))
    {
        /* lstat failed! */
        sz=-1;
        stat_res = lstat_res;
    }
    else
    {
        if (S_ISLNK(lbuf.st_mode))
        {

            if ((stat_res = wstat(fullname, &buf)))
            {
                sz=-1;
            }
            else
            {
                sz = (long long)buf.st_size;
            }

            /*
              In order to differentiate between e.g. rotten symlinks
              and symlink loops, we also need to know the error status of wstat.
            */
            stat_errno = errno;
        }
        else
        {
            stat_res = lstat_res;
            memcpy(&buf, &lbuf, sizeof(struct stat));
            sz = (long long)buf.st_size;
        }
    }


    bool wants_desc = !(expand_flags & EXPAND_NO_DESCRIPTIONS);
    wcstring desc;
    if (wants_desc)
        desc = file_get_desc(fullname, lstat_res, lbuf, stat_res, buf, stat_errno);

    if (sz >= 0 && S_ISDIR(buf.st_mode))
    {
        flags = flags | COMPLETE_NO_SPACE;
        munged_completion = completion;
        munged_completion.push_back(L'/');
        if (wants_desc)
            sb.append(desc);
    }
    else
    {
        if (wants_desc)
        {
            if (! desc.empty())
            {
                sb.append(desc);
                sb.append(L", ");
            }
            sb.append(format_size(sz));
        }
    }

    const wcstring &completion_to_use = munged_completion.empty() ? completion : munged_completion;
    wildcard_complete(completion_to_use, wc, sb.c_str(), NULL, list, flags);
}
Example #20
0
bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd, const env_vars_snapshot_t &env_vars)
{
    int err = ENOENT;
    if (dir.empty())
        return false;

    if (wd)
    {
        size_t len = wcslen(wd);
        assert(wd[len - 1] == L'/');
    }

    wcstring_list_t paths;
    if (dir.at(0) == L'/')
    {
        /* Absolute path */
        paths.push_back(dir);
    }
    else if (string_prefixes_string(L"./", dir) ||
             string_prefixes_string(L"../", dir) ||
             dir == L"." || dir == L"..")
    {
        /* Path is relative to the working directory */
        wcstring path;
        if (wd)
            path.append(wd);
        path.append(dir);
        paths.push_back(path);
    }
    else
    {
        // Respect CDPATH
        env_var_t path = env_vars.get(L"CDPATH");
        if (path.missing_or_empty())
            path = L"."; //We'll change this to the wd if we have one

        wcstring nxt_path;
        wcstokenizer tokenizer(path, ARRAY_SEP_STR);
        while (tokenizer.next(nxt_path))
        {

            if (nxt_path == L"." && wd != NULL)
            {
                // nxt_path is just '.', and we have a working directory, so use the wd instead
                // TODO: if nxt_path starts with ./ we need to replace the . with the wd
                nxt_path = wd;
            }
            expand_tilde(nxt_path);

//      debug( 2, L"woot %ls\n", expanded_path.c_str() );

            if (nxt_path.empty())
                continue;

            wcstring whole_path = nxt_path;
            append_path_component(whole_path, dir);
            paths.push_back(whole_path);
        }
    }

    bool success = false;
    for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter)
    {
        struct stat buf;
        const wcstring &dir = *iter;
        if (wstat(dir, &buf) == 0)
        {
            if (S_ISDIR(buf.st_mode))
            {
                success = true;
                if (out)
                    out->assign(dir);
                break;
            }
            else
            {
                err = ENOTDIR;
            }
        }
    }

    if (! success)
        errno = err;
    return success;
}
Example #21
0
/**
   The real implementation of wildcard expansion is in this
   function. Other functions are just wrappers around this one.

   This function traverses the relevant directory tree looking for
   matches, and recurses when needed to handle wildcrards spanning
   multiple components and recursive wildcards.

   Because this function calls itself recursively with substrings,
   it's important that the parameters be raw pointers instead of wcstring,
   which would be too expensive to construct for all substrings.
 */
static int wildcard_expand_internal(const wchar_t *wc,
                                    const wchar_t *base_dir,
                                    expand_flags_t flags,
                                    std::vector<completion_t> &out,
                                    std::set<wcstring> &completion_set,
                                    std::set<file_id_t> &visited_files
                                   )
{

    /* Points to the end of the current wildcard segment */
    const wchar_t *wc_end;

    /* Variables for traversing a directory */
    DIR *dir;

    /* The result returned */
    int res = 0;

    /* Length of the directory to search in */
    size_t base_len;

    /* Variables for testing for presense of recursive wildcards */
    const wchar_t *wc_recursive;
    bool is_recursive;

    /* Slightly mangled version of base_dir */
    const wchar_t *dir_string;

    //  debug( 3, L"WILDCARD_EXPAND %ls in %ls", wc, base_dir );

    if (is_main_thread() ? reader_interrupted() : reader_thread_job_is_stale())
    {
        return -1;
    }

    if (!wc || !base_dir)
    {
        debug(2, L"Got null string on line %d of file %s", __LINE__, __FILE__);
        return 0;
    }

    if (flags & ACCEPT_INCOMPLETE)
    {
        /*
           Avoid excessive number of returned matches for wc ending with a *
        */
        size_t len = wcslen(wc);
        if (len && (wc[len-1]==ANY_STRING))
        {
            wchar_t * foo = wcsdup(wc);
            foo[len-1]=0;
            int res = wildcard_expand_internal(foo, base_dir, flags, out, completion_set, visited_files);
            free(foo);
            return res;
        }
    }

    /*
      Initialize various variables
    */

    dir_string = base_dir[0]==L'\0'?L".":base_dir;

    if (!(dir = wopendir(dir_string)))
    {
        return 0;
    }

    wc_end = wcschr(wc,L'/');
    base_len = wcslen(base_dir);

    /*
      Test for recursive match string in current segment
    */
    wc_recursive = wcschr(wc, ANY_STRING_RECURSIVE);
    is_recursive = (wc_recursive && (!wc_end || wc_recursive < wc_end));

    /*
      Is this segment of the wildcard the last?
    */
    if (!wc_end)
    {
        /*
          Wildcard segment is the last segment,

          Insert all matching files/directories
        */
        if (wc[0]=='\0')
        {
            /*
              The last wildcard segment is empty. Insert everything if
              completing, the directory itself otherwise.
            */
            if (flags & ACCEPT_INCOMPLETE)
            {
                wcstring next;
                while (wreaddir(dir, next))
                {
                    if (next[0] != L'.')
                    {
                        wcstring long_name = make_path(base_dir, next);

                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out,
                                                         long_name,
                                                         next,
                                                         L"",
                                                         flags);
                        }
                    }
                }
            }
            else
            {
                res = 1;
                insert_completion_if_missing(base_dir, out, completion_set);
            }
        }
        else
        {
            /*
              This is the last wildcard segment, and it is not empty. Match files/directories.
            */
            wcstring next;
            while (wreaddir(dir, next))
            {
                const wchar_t * const name = next.c_str();
                if (flags & ACCEPT_INCOMPLETE)
                {

                    const wcstring long_name = make_path(base_dir, next);

                    /*
                      Test for matches before stating file, so as to minimize the number of calls to the much slower stat function
                    */
                    std::vector<completion_t> test;
                    if (wildcard_complete(name,
                                          wc,
                                          L"",
                                          0,
                                          test,
                                          0))
                    {
                        if (test_flags(long_name.c_str(), flags))
                        {
                            wildcard_completion_allocate(out,
                                                         long_name,
                                                         name,
                                                         wc,
                                                         flags);

                        }
                    }
                }
                else
                {
                    if (wildcard_match2(name, wc, true))
                    {
                        const wcstring long_name = make_path(base_dir, next);
                        int skip = 0;

                        if (is_recursive)
                        {
                            /*
                              In recursive mode, we are only
                              interested in adding files -directories
                              will be added in the next pass.
                            */
                            struct stat buf;
                            if (!wstat(long_name, &buf))
                            {
                                skip = S_ISDIR(buf.st_mode);
                            }
                        }
                        if (! skip)
                        {
                            insert_completion_if_missing(long_name, out, completion_set);
                        }
                        res = 1;
                    }
                }
            }
        }
    }

    if (wc_end || is_recursive)
    {
        /*
          Wilcard segment is not the last segment.  Recursively call
          wildcard_expand for all matching subdirectories.
        */

        /*
          wc_str is the part of the wildcarded string from the
          beginning to the first slash
        */
        wchar_t *wc_str;

        /*
          new_dir is a scratch area containing the full path to a
          file/directory we are iterating over
        */
        wchar_t *new_dir;

        /*
          The maximum length of a file element
        */
        long ln=MAX_FILE_LENGTH;
        char * narrow_dir_string = wcs2str(dir_string);

        /*
          In recursive mode, we look through the directory twice. If
          so, this rewind is needed.
        */
        rewinddir(dir);

        if (narrow_dir_string)
        {
            /*
               Find out how long the filename can be in a worst case
               scenario
            */
            ln = pathconf(narrow_dir_string, _PC_NAME_MAX);

            /*
              If not specified, use som large number as fallback
            */
            if (ln < 0)
                ln = MAX_FILE_LENGTH;
            free(narrow_dir_string);
        }
        new_dir= (wchar_t *)malloc(sizeof(wchar_t)*(base_len+ln+2));

        wc_str = wc_end?wcsndup(wc, wc_end-wc):wcsdup(wc);

        if ((!new_dir) || (!wc_str))
        {
            DIE_MEM();
        }

        wcscpy(new_dir, base_dir);

        wcstring next;
        while (wreaddir(dir, next))
        {
            const wchar_t *name = next.c_str();

            /*
              Test if the file/directory name matches the whole
              wildcard element, i.e. regular matching.
            */
            int whole_match = wildcard_match2(name, wc_str, true);
            int partial_match = 0;

            /*
               If we are doing recursive matching, also check if this
               directory matches the part up to the recusrive
               wildcard, if so, then we can search all subdirectories
               for matches.
            */
            if (is_recursive)
            {
                const wchar_t *end = wcschr(wc, ANY_STRING_RECURSIVE);
                wchar_t *wc_sub = wcsndup(wc, end-wc+1);
                partial_match = wildcard_match2(name, wc_sub, true);
                free(wc_sub);
            }

            if (whole_match || partial_match)
            {
                struct stat buf;
                char *dir_str;
                int stat_res;
                int new_res;

                wcscpy(&new_dir[base_len], name);
                dir_str = wcs2str(new_dir);

                if (dir_str)
                {
                    stat_res = stat(dir_str, &buf);
                    free(dir_str);

                    if (!stat_res)
                    {
                        // Insert a "file ID" into visited_files
                        // If the insertion fails, we've already visited this file (i.e. a symlink loop)
                        // If we're not recursive, insert anyways (in case we loop back around in a future recursive segment), but continue on; the idea being that literal path components should still work
                        const file_id_t file_id(buf.st_dev, buf.st_ino);
                        if (S_ISDIR(buf.st_mode) && (visited_files.insert(file_id).second || ! is_recursive))
                        {
                            size_t new_len = wcslen(new_dir);
                            new_dir[new_len] = L'/';
                            new_dir[new_len+1] = L'\0';

                            /*
                              Regular matching
                            */
                            if (whole_match)
                            {
                                const wchar_t *new_wc = L"";
                                if (wc_end)
                                {
                                    new_wc=wc_end+1;
                                    /*
                                      Accept multiple '/' as a single direcotry separator
                                    */
                                    while (*new_wc==L'/')
                                    {
                                        new_wc++;
                                    }
                                }

                                new_res = wildcard_expand_internal(new_wc,
                                                                   new_dir,
                                                                   flags,
                                                                   out,
                                                                   completion_set,
                                                                   visited_files);

                                if (new_res == -1)
                                {
                                    res = -1;
                                    break;
                                }
                                res |= new_res;

                            }

                            /*
                              Recursive matching
                            */
                            if (partial_match)
                            {

                                new_res = wildcard_expand_internal(wcschr(wc, ANY_STRING_RECURSIVE),
                                                                   new_dir,
                                                                   flags | WILDCARD_RECURSIVE,
                                                                   out,
                                                                   completion_set,
                                                                   visited_files);

                                if (new_res == -1)
                                {
                                    res = -1;
                                    break;
                                }
                                res |= new_res;

                            }
                        }
                    }
                }
            }
        }

        free(wc_str);
        free(new_dir);
    }
    closedir(dir);

    return res;
}
Example #22
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 #23
0
bool path_get_cdpath(const wcstring &dir, wcstring *out, const wchar_t *wd,
                     const env_vars_snapshot_t &env_vars) {
    int err = ENOENT;
    if (dir.empty()) return false;

    if (wd) {
        size_t len = wcslen(wd);
        assert(wd[len - 1] == L'/');
    }

    wcstring_list_t paths;
    if (dir.at(0) == L'/') {
        // Absolute path.
        paths.push_back(dir);
    } else if (string_prefixes_string(L"./", dir) || string_prefixes_string(L"../", dir) ||
               dir == L"." || dir == L"..") {
        // Path is relative to the working directory.
        wcstring path;
        if (wd) path.append(wd);
        path.append(dir);
        paths.push_back(path);
    } else {
        // Respect CDPATH.
        env_var_t cdpaths = env_vars.get(L"CDPATH");
        if (cdpaths.missing_or_empty()) cdpaths = L".";

        std::vector<wcstring> cdpathsv;
        tokenize_variable_array(cdpaths, cdpathsv);
        for (auto next_path : cdpathsv) {
            if (next_path.empty()) next_path = L".";
            if (next_path == L"." && wd != NULL) {
                // next_path is just '.', and we have a working directory, so use the wd instead.
                // TODO: if next_path starts with ./ we need to replace the . with the wd.
                next_path = wd;
            }
            expand_tilde(next_path);
            if (next_path.empty()) continue;

            wcstring whole_path = next_path;
            append_path_component(whole_path, dir);
            paths.push_back(whole_path);
        }
    }

    bool success = false;
    for (wcstring_list_t::const_iterator iter = paths.begin(); iter != paths.end(); ++iter) {
        struct stat buf;
        const wcstring &dir = *iter;
        if (wstat(dir, &buf) == 0) {
            if (S_ISDIR(buf.st_mode)) {
                success = true;
                if (out) out->assign(dir);
                break;
            } else {
                err = ENOTDIR;
            }
        }
    }

    if (!success) errno = err;
    return success;
}