/// Set the new value of the specified resource limit. This function does _not_ multiply the limit // value by the multiplier constant used by the commandline ulimit. static int set(int resource, int hard, int soft, rlim_t value, io_streams_t &streams) { struct rlimit ls; getrlimit(resource, &ls); if (hard) { ls.rlim_max = value; } if (soft) { ls.rlim_cur = value; // Do not attempt to set the soft limit higher than the hard limit. if ((value == RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY) || (value != RLIM_INFINITY && ls.rlim_max != RLIM_INFINITY && value > ls.rlim_max)) { ls.rlim_cur = ls.rlim_max; } } if (setrlimit(resource, &ls)) { if (errno == EPERM) streams.err.append_format( L"ulimit: Permission denied when changing resource of type '%ls'\n", get_desc(resource)); else builtin_wperror(L"ulimit", streams); return 1; } return 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, wcstring_list_t &val, int scope ) { size_t i; int retcode = 0; const wchar_t *val_str=NULL; if( is_path_variable( key ) ) { int error = 0; for( i=0; i< val.size() ; i++ ) { int show_perror = 0; int show_hint = 0; struct stat buff; const wchar_t *dir = val[i].c_str(); if( wstat( dir, &buff ) ) { error = 1; show_perror = 1; } if( !( S_ISDIR(buff.st_mode) ) ) { error = 1; } if( error ) { const wchar_t *colon; append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir, key); colon = wcschr( dir, 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, L':' )+1); } if( error ) { break; } } if( error ) { return 1; } } wcstring sb; if( val.size() ) { 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; }
/** 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, scope); 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_SCOPE: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' with the wrong scope\n"), L"set", key); retcode=1; break; } case ENV_INVALID: { append_format(stderr_buffer, _(L"%ls: Tried to set the special variable '%ls' to an invalid value\n"), L"set", key); retcode=1; break; } } return retcode; }
/// The source builtin, sometimes called `.`. Evaluates the contents of a file in the current /// context. int builtin_source(parser_t &parser, io_streams_t &streams, wchar_t **argv) { ASSERT_IS_MAIN_THREAD(); const wchar_t *cmd = argv[0]; int argc = builtin_count_args(argv); help_only_cmd_opts_t opts; int optind; int retval = parse_help_only_cmd_opts(opts, &optind, argc, argv, parser, streams); if (retval != STATUS_CMD_OK) return retval; if (opts.print_help) { builtin_print_help(parser, streams, cmd, streams.out); return STATUS_CMD_OK; } int fd; struct stat buf; const wchar_t *fn, *fn_intern; if (argc == optind || wcscmp(argv[optind], L"-") == 0) { // Either a bare `source` which means to implicitly read from stdin or an explicit `-`. if (argc == optind && !streams.stdin_is_directly_redirected) { // Don't implicitly read from the terminal. return STATUS_CMD_ERROR; } fn = L"-"; fn_intern = fn; fd = dup(streams.stdin_fd); } else { if ((fd = wopen_cloexec(argv[optind], O_RDONLY)) == -1) { streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), cmd, argv[optind]); builtin_wperror(cmd, streams); return STATUS_CMD_ERROR; } if (fstat(fd, &buf) == -1) { close(fd); streams.err.append_format(_(L"%ls: Error encountered while sourcing file '%ls':\n"), cmd, argv[optind]); builtin_wperror(L"source", streams); return STATUS_CMD_ERROR; } if (!S_ISREG(buf.st_mode)) { close(fd); streams.err.append_format(_(L"%ls: '%ls' is not a file\n"), cmd, argv[optind]); return STATUS_CMD_ERROR; } fn_intern = intern(argv[optind]); } const source_block_t *sb = parser.push_block<source_block_t>(fn_intern); reader_push_current_filename(fn_intern); // This is slightly subtle. If this is a bare `source` with no args then `argv + optind` already // points to the end of argv. Otherwise we want to skip the file name to get to the args if any. env_set_argv(argv + optind + (argc == optind ? 0 : 1)); retval = reader_read(fd, streams.io_chain ? *streams.io_chain : io_chain_t()); parser.pop_block(sb); if (retval != STATUS_CMD_OK) { streams.err.append_format(_(L"%ls: Error while reading file '%ls'\n"), cmd, fn_intern == intern_static(L"-") ? L"<stdin>" : fn_intern); } else { retval = proc_get_last_status(); } // Do not close fd after calling reader_read. reader_read automatically closes it before calling // eval. reader_pop_current_filename(); return retval; }
/** 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; }
/** 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, any_error = false; for( i=0; i< val.size() ; i++ ) { bool show_perror = false; int show_hint = 0; bool error = false; struct stat buff; const wchar_t *dir = val[i].c_str(); if( wstat( dir, &buff ) ) { error = true; show_perror = true; } if( !( S_ISDIR(buff.st_mode) ) ) { error = true; } if( !error ) { any_success = true; } else { any_error = true; const wchar_t *colon; append_format(stderr_buffer, _(BUILTIN_SET_PATH_ERROR), L"set", dir, key); colon = wcschr( dir, 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, 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.size() ) { 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; }