aboutsummaryrefslogtreecommitdiff
path: root/src/ground.cc
blob: 265a22dfe18de56b1e8b622e145a5efb8a7d5481 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

#include "ground.h"

using namespace std;

namespace ov4
{

pid_t shell_pgid;
int tty_fd;

/* 
 * waitfg - Block until process pid is no longer the foreground process
 */
void waitfg(pid_t pid)
{
    sigset_t prev_with_sigchld_unblocked;
    // get current blocked signals
    sigprocmask(0, nullptr, &prev_with_sigchld_unblocked);
    sigdelset(&prev_with_sigchld_unblocked, SIGCHLD);
    LOG << "waiting for pid "<< fgpid(jobs) << endl;
    while (fgpid(jobs) != 0)
        sigsuspend(&prev_with_sigchld_unblocked);

    // set shell to foreground again
    tcsetpgrp(tty_fd, shell_pgid);
    sigprocmask(SIG_BLOCK, &block_io, nullptr);

    LOG << "finished fg " << endl;
    return;
}

/* 
 * do_bgfg - Execute the builtin bg and fg commands
 */
void do_bgfg(char **argv) 
{
    if ((strcmp(argv[0], "fg") == 0) || (strcmp(argv[0], "bg") == 0))
    {
        int x;
        job_t *j = nullptr;
        sigset_t prev;
        if (argv[1] == nullptr)
        {
            cerr << ((strcmp(argv[0], "fg") == 0) ? "fg" : "bg") << " command requires PID or %jobid argument" << endl;
            return;
        }
        if (argv[1][0] == '%') // jid provided
        {
            if (!isnum(&argv[1][1]))
            {
                cerr << ((strcmp(argv[0], "fg") == 0) ? "fg" : "bg") << ": argument must be a PID or %jobid" << endl;
                return;
            }
            x = atoi(&argv[1][1]); // eat %
            j = getjobjid(jobs, x);
            if (j == nullptr)
            {
                cerr << argv[1] << ": No such job" << endl;
                return;
            }
        } else { // pid
            if (!isnum(&argv[1][0]))
            {
                cerr << ((strcmp(argv[0], "fg") == 0) ? "fg" : "bg") << ": argument must be a PID or %jobid" << endl;
                return;
            }
            x = atoi(&argv[1][0]);
            j = getjobpid(jobs, x);
            if (j == nullptr)
            {
                cerr << "(" << argv[1] << "): No such process" << endl;
                return;
            }
        }


        block_all(&prev);
        if (strcmp(argv[0], "fg") == 0) // fg
        {
            LOG << "fg" << endl;
            j->state = FG;
            
            sigset_t prev_with_sigchld_blocked = prev;
            sigaddset(&prev_with_sigchld_blocked, SIGCHLD);
            sigprocmask(SIG_SETMASK, &prev_with_sigchld_blocked, NULL);
            if (kill(-(j->pid), SIGCONT) < 0) 
            {
                cerr << "Cannot continue process " << j->pid;
                sigprocmask(SIG_SETMASK, &prev, NULL);
                return;
            }

            waitfg(j->pid);

            sigprocmask(SIG_SETMASK, &prev, NULL);
        } else // bg
        {
            LOG << "bg" << endl;
            j->state = BG;
            kill(-(j->pid), SIGCONT);
            sigprocmask(SIG_SETMASK, &prev, NULL);
            // cmdline has nerd '\n' at the end
            // so just flush
            cout << "[" << j->jid << "] (" << j->pid << ") " << j->cmdline << flush;
        }
    }
    else 
        cerr << "not fg/bg" << endl;
}

}