コード例 #1
0
ファイル: builtin_exit.cpp プロジェクト: elnappo/fish-shell
/// The exit builtin. Calls reader_exit to exit and returns the value specified.
int builtin_exit(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    exit_cmd_opts_t opts;

    int optind;
    int retval = parse_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;
    }

    if (optind + 1 < argc) {
        streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
        builtin_print_help(parser, streams, cmd, streams.err);
        return STATUS_INVALID_ARGS;
    }

    if (optind == argc) {
        retval = proc_get_last_status();
    } else {
        retval = fish_wcstoi(argv[optind]);
        if (errno) {
            streams.err.append_format(_(L"%ls: Argument '%ls' must be an integer\n"), cmd,
                                      argv[optind]);
            builtin_print_help(parser, streams, cmd, streams.err);
            return STATUS_INVALID_ARGS;
        }
    }
    reader_exit(1, 0);
    return retval;
}
コード例 #2
0
ファイル: expand.cpp プロジェクト: frogshead/fish-shell
bool process_iterator_t::next_process(wcstring *out_str, pid_t *out_pid)
{
    wcstring cmd;
    pid_t pid = 0;
    while (cmd.empty())
    {
        wcstring name;
        if (! dir || ! wreaddir(dir, name))
            break;

        if (!iswnumeric(name.c_str()))
            continue;

        wcstring path = wcstring(L"/proc/") + name;
        struct stat buf;
        if (wstat(path, &buf))
            continue;

        if (buf.st_uid != getuid())
            continue;

        /* remember the pid */
        pid = fish_wcstoi(name.c_str(), NULL, 10);

        /* the 'cmdline' file exists, it should contain the commandline */
        FILE *cmdfile;
        if ((cmdfile=wfopen(path + L"/cmdline", "r")))
        {
            wcstring full_command_line;
            signal_block();
            fgetws2(&full_command_line, cmdfile);
            signal_unblock();

            /* The command line needs to be escaped */
            cmd = tok_first(full_command_line.c_str());
        }
#ifdef SunOS
        else if ((cmdfile=wfopen(path + L"/psinfo", "r")))
        {
            psinfo_t info;
            if (fread(&info, sizeof(info), 1, cmdfile))
            {
                /* The filename is unescaped */
                cmd = str2wcstring(info.pr_fname);
            }
        }
#endif
        if (cmdfile)
            fclose(cmdfile);
    }

    bool result = ! cmd.empty();
    if (result)
    {
        *out_str = cmd;
        *out_pid = pid;
    }
    return result;
}
コード例 #3
0
ファイル: signal.cpp プロジェクト: bronsen/fish-shell
int wcs2sig(const wchar_t *str) {
    for (const auto &data : signal_table) {
        if (match_signal_name(data.name, str)) {
            return data.signal;
        }
    }

    int res = fish_wcstoi(str);
    if (errno || res < 0) return -1;
    return res;
}
コード例 #4
0
ファイル: signal.cpp プロジェクト: EmuxEvans/fish-shell
int wcs2sig(const wchar_t *str) {
    int i;
    wchar_t *end = 0;

    for (i = 0; lookup[i].desc; i++) {
        if (match_signal_name(lookup[i].name, str)) {
            return lookup[i].signal;
        }
    }
    errno = 0;
    int res = fish_wcstoi(str, &end, 10);
    if (!errno && res >= 0 && !*end) return res;

    return -1;
}
コード例 #5
0
ファイル: builtin_math.cpp プロジェクト: siteshwar/fish-shell
static int parse_cmd_opts(math_cmd_opts_t &opts, int *optind,  //!OCLINT(high ncss method)
                          int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
    const wchar_t *cmd = L"math";
    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 's': {
                opts.scale = fish_wcstoi(w.woptarg);
                if (errno || opts.scale < 0 || opts.scale > 15) {
                    streams.err.append_format(_(L"%ls: '%ls' is not a valid scale value\n"), cmd,
                                              w.woptarg);
                    return STATUS_INVALID_ARGS;
                }
                break;
            }
            case 'h': {
                opts.print_help = true;
                break;
            }
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                // For most commands this is an error. We ignore it because a math expression
                // can begin with a minus sign.
                *optind = w.woptind - 1;
                return STATUS_CMD_OK;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    *optind = w.woptind;
    return STATUS_CMD_OK;
}
コード例 #6
0
ファイル: expand.cpp プロジェクト: frogshead/fish-shell
static int find_process(const wchar_t *proc,
                        expand_flags_t flags,
                        std::vector<completion_t> &out)
{
    int found = 0;

    if (!(flags & EXPAND_SKIP_JOBS))
    {
        ASSERT_IS_MAIN_THREAD();
        const job_t *j;

        if (iswnumeric(proc) || (wcslen(proc)==0))
        {
            /*
              This is a numeric job string, like '%2'
            */

            if (flags & ACCEPT_INCOMPLETE)
            {
                job_iterator_t jobs;
                while ((j = jobs.next()))
                {
                    wchar_t jid[16];
                    if (j->command_is_empty())
                        continue;

                    swprintf(jid, 16, L"%d", j->job_id);

                    if (wcsncmp(proc, jid, wcslen(proc))==0)
                    {
                        wcstring desc_buff = format_string(COMPLETE_JOB_DESC_VAL, j->command_wcstr());
                        append_completion(out,
                                          jid+wcslen(proc),
                                          desc_buff,
                                          0);
                    }
                }

            }
            else
            {

                int jid;
                wchar_t *end;

                errno = 0;
                jid = fish_wcstoi(proc, &end, 10);
                if (jid > 0 && !errno && !*end)
                {
                    j = job_get(jid);
                    if ((j != 0) && (j->command_wcstr() != 0))
                    {
                        {
                            append_completion(out, to_string<long>(j->pgid));
                            found = 1;
                        }
                    }
                }
            }
        }
        if (found)
            return 1;

        job_iterator_t jobs;
        while ((j = jobs.next()))
        {

            if (j->command_is_empty())
                continue;

            size_t offset;
            if (match_pid(j->command(), proc, flags, &offset))
            {
                if (flags & ACCEPT_INCOMPLETE)
                {
                    append_completion(out,
                                      j->command_wcstr() + offset + wcslen(proc),
                                      COMPLETE_JOB_DESC,
                                      0);
                }
                else
                {
                    append_completion(out, to_string<long>(j->pgid));
                    found = 1;
                }
            }
        }

        if (found)
        {
            return 1;
        }

        jobs.reset();
        while ((j = jobs.next()))
        {
            process_t *p;
            if (j->command_is_empty())
                continue;
            for (p=j->first_process; p; p=p->next)
            {
                if (p->actual_cmd.empty())
                    continue;

                size_t offset;
                if (match_pid(p->actual_cmd, proc, flags, &offset))
                {
                    if (flags & ACCEPT_INCOMPLETE)
                    {
                        append_completion(out,
                                          wcstring(p->actual_cmd, offset + wcslen(proc)),
                                          COMPLETE_CHILD_PROCESS_DESC,
                                          0);
                    }
                    else
                    {
                        append_completion(out,
                                          to_string<long>(p->pid),
                                          L"",
                                          0);
                        found = 1;
                    }
                }
            }
        }

        if (found)
        {
            return 1;
        }
    }

    /* Iterate over all processes */
    wcstring process_name;
    pid_t process_pid;
    process_iterator_t iterator;
    while (iterator.next_process(&process_name, &process_pid))
    {
        size_t offset;
        if (match_pid(process_name, proc, flags, &offset))
        {
            if (flags & ACCEPT_INCOMPLETE)
            {
                append_completion(out,
                                  process_name.c_str() + offset + wcslen(proc),
                                  COMPLETE_PROCESS_DESC,
                                  0);
            }
            else
            {
                append_completion(out, to_string<long>(process_pid));
            }
        }
    }

    return 1;
}
コード例 #7
0
/// The following function is invoked on the main thread, because the job operation is not thread
/// safe. It waits for child jobs, not for child processes individually.
int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    ASSERT_IS_MAIN_THREAD();
    int retval = STATUS_CMD_OK;
    const wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    bool any_flag = false;  // flag for -n option

    static const wchar_t *const short_options = L":n";
    static const struct woption long_options[] = {{L"any", no_argument, NULL, 'n'},
                                                  {NULL, 0, NULL, 0}};

    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 'n':
                any_flag = true;
                break;
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    if (w.woptind == argc) {
        // no jobs specified
        retval = wait_for_backgrounds(parser, any_flag);
    } else {
        // jobs specified
        std::vector<job_id_t> waited_job_ids;

        for (int i = w.woptind; i < argc; i++) {
            if (iswnumeric(argv[i])) {
                // argument is pid
                pid_t pid = fish_wcstoi(argv[i]);
                if (errno || pid <= 0) {
                    streams.err.append_format(_(L"%ls: '%ls' is not a valid process id\n"), cmd,
                                              argv[i]);
                    continue;
                }
                if (job_id_t id = get_job_id_from_pid(pid, parser)) {
                    waited_job_ids.push_back(id);
                } else {
                    streams.err.append_format(
                        _(L"%ls: Could not find a job with process id '%d'\n"), cmd, pid);
                }
            } else {
                // argument is process name
                if (!find_job_by_name(argv[i], waited_job_ids, parser)) {
                    streams.err.append_format(
                        _(L"%ls: Could not find child processes with the name '%ls'\n"), cmd,
                        argv[i]);
                }
            }
        }

        if (waited_job_ids.empty()) return STATUS_INVALID_ARGS;

        retval = wait_for_backgrounds_specified(parser, waited_job_ids, any_flag);
    }

    return retval;
}
コード例 #8
0
ファイル: builtin_jobs.cpp プロジェクト: elnappo/fish-shell
/// The jobs builtin. Used for printing running jobs. Defined in builtin_jobs.c.
int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wchar_t *cmd = argv[0];
    int argc = builtin_count_args(argv);
    int found = 0;
    int mode = JOBS_DEFAULT;
    int print_last = 0;

    static const wchar_t *const short_options = L":cghlpq";
    static const struct woption long_options[] = {
        {L"command", no_argument, NULL, 'c'},
        {L"group", no_argument, NULL, 'g'},
        {L"help", no_argument, NULL, 'h'},
        {L"last", no_argument, NULL, 'l'},
        {L"pid", no_argument, NULL, 'p'},
        {L"quiet", no_argument, NULL, 'q'},
        {nullptr, 0, NULL, 0}};

    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 'p': {
                mode = JOBS_PRINT_PID;
                break;
            }
            case 'q': {
                mode = JOBS_PRINT_NOTHING;
                break;
            }
            case 'c': {
                mode = JOBS_PRINT_COMMAND;
                break;
            }
            case 'g': {
                mode = JOBS_PRINT_GROUP;
                break;
            }
            case 'l': {
                print_last = 1;
                break;
            }
            case 'h': {
                builtin_print_help(parser, streams, cmd, streams.out);
                return STATUS_CMD_OK;
            }
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    if (print_last) {
        // Ignore unconstructed jobs, i.e. ourself.
        job_iterator_t jobs;
        const job_t *j;
        while ((j = jobs.next())) {
            if (j->is_constructed() && !j->is_completed()) {
                builtin_jobs_print(j, mode, !streams.out_is_redirected, streams);
                return STATUS_CMD_ERROR;
            }
        }

    } else {
        if (w.woptind < argc) {
            int i;

            for (i = w.woptind; i < argc; i++) {
                const job_t *j = nullptr;

                if (argv[i][0] == L'%') {
                    int jobId = -1;
                    jobId = fish_wcstoi(argv[i] + 1);
                    if (errno || jobId < -1) {
                        streams.err.append_format(_(L"%ls: '%ls' is not a valid job id"), cmd, argv[i]);
                        return STATUS_INVALID_ARGS;
                    }
                    j = job_t::from_job_id(jobId);
                }
                else {
                    int pid = fish_wcstoi(argv[i]);
                    if (errno || pid < 0) {
                        streams.err.append_format(_(L"%ls: '%ls' is not a valid process id\n"), cmd, argv[i]);
                        return STATUS_INVALID_ARGS;
                    }
                    j = job_t::from_pid(pid);
                }

                if (j && !j->is_completed() && j->is_constructed()) {
                    builtin_jobs_print(j, mode, false, streams);
                    found = 1;
                } else {
                    streams.err.append_format(_(L"%ls: No suitable job: %ls\n"), cmd, argv[i]);
                    return STATUS_CMD_ERROR;
                }
            }
        } else {
            job_iterator_t jobs;
            const job_t *j;
            while ((j = jobs.next())) {
                // Ignore unconstructed jobs, i.e. ourself.
                if (j->is_constructed() && !j->is_completed()) {
                    builtin_jobs_print(j, mode, !found && !streams.out_is_redirected, streams);
                    found = 1;
                }
            }
        }
    }

    if (!found) {
        // Do not babble if not interactive.
        if (!streams.out_is_redirected && mode != JOBS_PRINT_NOTHING) {
            streams.out.append_format(_(L"%ls: There are no jobs\n"), argv[0]);
        }
        return STATUS_CMD_ERROR;
    }

    return STATUS_CMD_OK;
}
コード例 #9
0
ファイル: builtin_status.cpp プロジェクト: elnappo/fish-shell
static int parse_cmd_opts(status_cmd_opts_t &opts, int *optind,  //!OCLINT(high ncss method)
                          int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
    wchar_t *cmd = argv[0];
    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case STATUS_IS_FULL_JOB_CTRL: {
                if (!set_status_cmd(cmd, opts, STATUS_IS_FULL_JOB_CTRL, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case STATUS_IS_INTERACTIVE_JOB_CTRL: {
                if (!set_status_cmd(cmd, opts, STATUS_IS_INTERACTIVE_JOB_CTRL, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case STATUS_IS_NO_JOB_CTRL: {
                if (!set_status_cmd(cmd, opts, STATUS_IS_NO_JOB_CTRL, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case STATUS_FISH_PATH: {
                if (!set_status_cmd(cmd, opts, STATUS_FISH_PATH, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'L': {
                opts.level = fish_wcstoi(w.woptarg);
                if (opts.level < 0 || errno == ERANGE) {
                    streams.err.append_format(_(L"%ls: Invalid level value '%ls'\n"), argv[0],
                                              w.woptarg);
                    return STATUS_INVALID_ARGS;
                } else if (errno) {
                    streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, argv[0], w.woptarg);
                    return STATUS_INVALID_ARGS;
                }
                break;
            }
            case 'c': {
                if (!set_status_cmd(cmd, opts, STATUS_IS_COMMAND_SUB, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'b': {
                if (!set_status_cmd(cmd, opts, STATUS_IS_BLOCK, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'i': {
                if (!set_status_cmd(cmd, opts, STATUS_IS_INTERACTIVE, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'l': {
                if (!set_status_cmd(cmd, opts, STATUS_IS_LOGIN, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'f': {
                if (!set_status_cmd(cmd, opts, STATUS_FILENAME, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'n': {
                if (!set_status_cmd(cmd, opts, STATUS_LINE_NUMBER, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'j': {
                if (!set_status_cmd(cmd, opts, STATUS_SET_JOB_CONTROL, streams)) {
                    return STATUS_CMD_ERROR;
                }
                opts.new_job_control_mode = job_control_str_to_mode(w.woptarg, cmd, streams);
                if (opts.new_job_control_mode == -1) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 't': {
                if (!set_status_cmd(cmd, opts, STATUS_STACK_TRACE, streams)) {
                    return STATUS_CMD_ERROR;
                }
                break;
            }
            case 'h': {
                opts.print_help = true;
                break;
            }
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    *optind = w.woptind;
    return STATUS_CMD_OK;
}
コード例 #10
0
static int parse_cmd_opts(function_cmd_opts_t &opts, int *optind,  //!OCLINT(high ncss method)
                          int argc, wchar_t **argv, parser_t &parser, io_streams_t &streams) {
    const wchar_t *cmd = L"function";
    int opt;
    wgetopter_t w;
    while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (opt) {
            case 'd': {
                opts.description = w.woptarg;
                break;
            }
            case 's': {
                int sig = wcs2sig(w.woptarg);
                if (sig == -1) {
                    streams.err.append_format(_(L"%ls: Unknown signal '%ls'"), cmd, w.woptarg);
                    return STATUS_INVALID_ARGS;
                }
                opts.events.push_back(event_t::signal_event(sig));
                break;
            }
            case 'v': {
                if (!valid_var_name(w.woptarg)) {
                    streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, w.woptarg);
                    return STATUS_INVALID_ARGS;
                }

                opts.events.push_back(event_t::variable_event(w.woptarg));
                break;
            }
            case 'e': {
                opts.events.push_back(event_t::generic_event(w.woptarg));
                break;
            }
            case 'j':
            case 'p': {
                pid_t pid;
                event_t e(EVENT_ANY);

                if ((opt == 'j') && (wcscasecmp(w.woptarg, L"caller") == 0)) {
                    job_id_t job_id = -1;

                    if (is_subshell) {
                        size_t block_idx = 0;

                        // Find the outermost substitution block.
                        for (block_idx = 0;; block_idx++) {
                            const block_t *b = parser.block_at_index(block_idx);
                            if (b == NULL || b->type() == SUBST) break;
                        }

                        // Go one step beyond that, to get to the caller.
                        const block_t *caller_block = parser.block_at_index(block_idx + 1);
                        if (caller_block != NULL && caller_block->job != NULL) {
                            job_id = caller_block->job->job_id;
                        }
                    }

                    if (job_id == -1) {
                        streams.err.append_format(
                            _(L"%ls: Cannot find calling job for event handler"), cmd);
                        return STATUS_INVALID_ARGS;
                    }
                    e.type = EVENT_JOB_ID;
                    e.param1.job_id = job_id;
                } else {
                    pid = fish_wcstoi(w.woptarg);
                    if (errno || pid < 0) {
                        streams.err.append_format(_(L"%ls: Invalid process id '%ls'"), cmd,
                                                  w.woptarg);
                        return STATUS_INVALID_ARGS;
                    }

                    e.type = EVENT_EXIT;
                    e.param1.pid = (opt == 'j' ? -1 : 1) * abs(pid);
                }
                opts.events.push_back(e);
                break;
            }
            case 'a': {
                opts.named_arguments.push_back(w.woptarg);
                break;
            }
            case 'S': {
                opts.shadow_scope = false;
                break;
            }
            case 'w': {
                opts.wrap_targets.push_back(w.woptarg);
                break;
            }
            case 'V': {
                if (!valid_var_name(w.woptarg)) {
                    streams.err.append_format(BUILTIN_ERR_VARNAME, cmd, w.woptarg);
                    return STATUS_INVALID_ARGS;
                }
                opts.inherit_vars.push_back(w.woptarg);
                break;
            }
            case 'h': {
                opts.print_help = true;
                break;
            }
            case ':': {
                builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            case '?': {
                builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
                return STATUS_INVALID_ARGS;
            }
            default: {
                DIE("unexpected retval from wgetopt_long");
                break;
            }
        }
    }

    *optind = w.woptind;
    return STATUS_CMD_OK;
}
コード例 #11
0
ファイル: builtin_jobs.cpp プロジェクト: msteed/fish-shell
/// The jobs builtin. Used fopr printing running jobs. Defined in builtin_jobs.c.
int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    wgetopter_t w;
    int argc = 0;
    int found = 0;
    int mode = JOBS_DEFAULT;
    int print_last = 0;

    argc = builtin_count_args(argv);
    w.woptind = 0;

    while (1) {
        static const struct woption long_options[] = {
            {L"pid", no_argument, 0, 'p'},   {L"command", no_argument, 0, 'c'},
            {L"group", no_argument, 0, 'g'}, {L"last", no_argument, 0, 'l'},
            {L"help", no_argument, 0, 'h'},  {0, 0, 0, 0}};

        int opt_index = 0;

        int opt = w.wgetopt_long(argc, argv, L"pclgh", long_options, &opt_index);
        if (opt == -1) break;

        switch (opt) {
            case 0: {
                if (long_options[opt_index].flag != 0) break;
                streams.err.append_format(BUILTIN_ERR_UNKNOWN, argv[0],
                                          long_options[opt_index].name);

                builtin_print_help(parser, streams, argv[0], streams.err);
                return 1;
            }
            case 'p': {
                mode = JOBS_PRINT_PID;
                break;
            }
            case 'c': {
                mode = JOBS_PRINT_COMMAND;
                break;
            }
            case 'g': {
                mode = JOBS_PRINT_GROUP;
                break;
            }
            case 'l': {
                print_last = 1;
                break;
            }
            case 'h': {
                builtin_print_help(parser, streams, argv[0], streams.out);
                return 0;
            }
            case '?': {
                builtin_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
                return 1;
            }
            default: {
                DIE("unexpected opt");
                break;
            }
        }
    }

    if (print_last) {
        // Ignore unconstructed jobs, i.e. ourself.
        job_iterator_t jobs;
        const job_t *j;
        while ((j = jobs.next())) {
            if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j)) {
                builtin_jobs_print(j, mode, !streams.out_is_redirected, streams);
                return 0;
            }
        }

    } else {
        if (w.woptind < argc) {
            int i;

            for (i = w.woptind; i < argc; i++) {
                int pid = fish_wcstoi(argv[i]);
                if (errno || pid < 0) {
                    streams.err.append_format(_(L"%ls: '%ls' is not a job\n"), argv[0], argv[i]);
                    return 1;
                }

                const job_t *j = job_get_from_pid(pid);

                if (j && !job_is_completed(j)) {
                    builtin_jobs_print(j, mode, false, streams);
                    found = 1;
                } else {
                    streams.err.append_format(_(L"%ls: No suitable job: %d\n"), argv[0], pid);
                    return 1;
                }
            }
        } else {
            job_iterator_t jobs;
            const job_t *j;
            while ((j = jobs.next())) {
                // Ignore unconstructed jobs, i.e. ourself.
                if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j)) {
                    builtin_jobs_print(j, mode, !found && !streams.out_is_redirected, streams);
                    found = 1;
                }
            }
        }
    }

    if (!found) {
        // Do not babble if not interactive.
        if (!streams.out_is_redirected) {
            streams.out.append_format(_(L"%ls: There are no jobs\n"), argv[0]);
        }
        return 1;
    }

    return 0;
}
コード例 #12
0
/**
   The jobs builtin. Used fopr printing running jobs. Defined in builtin_jobs.c.
*/
static int builtin_jobs(parser_t &parser, wchar_t **argv)
{
    int argc=0;
    int found=0;
    int mode=JOBS_DEFAULT;
    int print_last = 0;
    const job_t *j;

    argc = builtin_count_args(argv);
    woptind=0;

    while (1)
    {
        static const struct woption
                long_options[] =
        {
            {
                L"pid", no_argument, 0, 'p'
            }
            ,
            {
                L"command", no_argument, 0, 'c'
            }
            ,
            {
                L"group", no_argument, 0, 'g'
            }
            ,
            {
                L"last", no_argument, 0, 'l'
            }
            ,
            {
                L"help", no_argument, 0, 'h'
            }
            ,
            {
                0, 0, 0, 0
            }
        }
        ;

        int opt_index = 0;

        int opt = wgetopt_long(argc,
                               argv,
                               L"pclgh",
                               long_options,
                               &opt_index);
        if (opt == -1)
            break;

        switch (opt)
        {
            case 0:
                if (long_options[opt_index].flag != 0)
                    break;
                append_format(stderr_buffer,
                              BUILTIN_ERR_UNKNOWN,
                              argv[0],
                              long_options[opt_index].name);

                builtin_print_help(parser, argv[0], stderr_buffer);


                return 1;


            case 'p':
                mode=JOBS_PRINT_PID;
                break;

            case 'c':
                mode=JOBS_PRINT_COMMAND;
                break;

            case 'g':
                mode=JOBS_PRINT_GROUP;
                break;

            case 'l':
            {
                print_last = 1;
                break;
            }

            case 'h':
                builtin_print_help(parser, argv[0], stdout_buffer);
                return 0;

            case '?':
                builtin_unknown_option(parser, argv[0], argv[woptind-1]);
                return 1;

        }
    }


    /*
      Do not babble if not interactive
    */
    if (builtin_out_redirect)
    {
        found=1;
    }

    if (print_last)
    {
        /*
          Ignore unconstructed jobs, i.e. ourself.
        */
        job_iterator_t jobs;
        const job_t *j;
        while ((j = jobs.next()))
        {

            if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
            {
                builtin_jobs_print(j, mode, !found);
                return 0;
            }
        }

    }
    else
    {
        if (woptind < argc)
        {
            int i;

            found = 1;

            for (i=woptind; i<argc; i++)
            {
                int pid;
                wchar_t *end;
                errno=0;
                pid=fish_wcstoi(argv[i], &end, 10);
                if (errno || *end)
                {
                    append_format(stderr_buffer,
                                  _(L"%ls: '%ls' is not a job\n"),
                                  argv[0],
                                  argv[i]);
                    return 1;
                }

                j = job_get_from_pid(pid);

                if (j && !job_is_completed(j))
                {
                    builtin_jobs_print(j, mode, !found);
                }
                else
                {
                    append_format(stderr_buffer,
                                  _(L"%ls: No suitable job: %d\n"),
                                  argv[0],
                                  pid);
                    return 1;
                }
            }
        }
        else
        {
            job_iterator_t jobs;
            const job_t *j;
            while ((j = jobs.next()))
            {
                /*
                  Ignore unconstructed jobs, i.e. ourself.
                */
                if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j))
                {
                    builtin_jobs_print(j, mode, !found);
                    found = 1;
                }
            }
        }
    }

    if (!found)
    {
        append_format(stdout_buffer,
                      _(L"%ls: There are no jobs\n"),
                      argv[0]);
    }

    return 0;
}
コード例 #13
0
/// Builtin for removing jobs from the job list.
int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
    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;
    }

    if (argv[1] == 0) {
        // Select last constructed job (ie first job in the job queue) that is possible to disown.
        // Stopped jobs can be disowned (they will be continued).
        // Foreground jobs can be disowned.
        // Even jobs that aren't under job control can be disowned!
        job_t *job = nullptr;
        for (const auto &j : jobs()) {
            if (j->is_constructed() && (!j->is_completed())) {
                job = j.get();
                break;
            }
        }

        if (job) {
            retval = disown_job(cmd, parser, streams, job);
        } else {
            streams.err.append_format(_(L"%ls: There are no suitable jobs\n"), cmd);
            retval = STATUS_CMD_ERROR;
        }
    } else {
        std::set<job_t *> jobs;

        // If one argument is not a valid pid (i.e. integer >= 0), fail without disowning anything,
        // but still print errors for all of them.
        // Non-existent jobs aren't an error, but information about them is useful.
        // Multiple PIDs may refer to the same job; include the job only once by using a set.
        for (int i = 1; argv[i]; i++) {
            int pid = fish_wcstoi(argv[i]);
            if (errno || pid < 0) {
                streams.err.append_format(_(L"%ls: '%ls' is not a valid job specifier\n"), cmd,
                                          argv[i]);
                retval = STATUS_INVALID_ARGS;
            } else {
                if (job_t *j = parser.job_get_from_pid(pid)) {
                    jobs.insert(j);
                } else {
                    streams.err.append_format(_(L"%ls: Could not find job '%d'\n"), cmd, pid);
                }
            }
        }
        if (retval != STATUS_CMD_OK) {
            return retval;
        }

        // Disown all target jobs
        for (const auto &j : jobs) {
            retval |= disown_job(cmd, parser, streams, j);
        }
    }

    return retval;
}