1/* jobs.c, created from jobs.def. */
2#line 23 "jobs.def"
3
4#line 38 "jobs.def"
5
6#include <config.h>
7
8#if defined (JOB_CONTROL)
9#include "../bashtypes.h"
10#include <signal.h>
11#if defined (HAVE_UNISTD_H)
12#  include <unistd.h>
13#endif
14
15#include "../bashansi.h"
16#include "../bashintl.h"
17
18#include "../shell.h"
19#include "../jobs.h"
20#include "../execute_cmd.h"
21#include "bashgetopt.h"
22#include "common.h"
23
24#define JSTATE_ANY	0x0
25#define JSTATE_RUNNING	0x1
26#define JSTATE_STOPPED	0x2
27
28static int execute_list_with_replacements __P((WORD_LIST *));
29
30/* The `jobs' command.  Prints outs a list of active jobs.  If the
31   argument `-l' is given, then the process id's are printed also.
32   If the argument `-p' is given, print the process group leader's
33   pid only.  If `-n' is given, only processes that have changed
34   status since the last notification are printed.  If -x is given,
35   replace all job specs with the pid of the appropriate process
36   group leader and execute the command.  The -r and -s options mean
37   to print info about running and stopped jobs only, respectively. */
38int
39jobs_builtin (list)
40     WORD_LIST *list;
41{
42  int form, execute, state, opt, any_failed, job;
43  sigset_t set, oset;
44
45  execute = any_failed = 0;
46  form = JLIST_STANDARD;
47  state = JSTATE_ANY;
48
49  reset_internal_getopt ();
50  while ((opt = internal_getopt (list, "lpnxrs")) != -1)
51    {
52      switch (opt)
53	{
54	case 'l':
55	  form = JLIST_LONG;
56	  break;
57	case 'p':
58	  form = JLIST_PID_ONLY;
59	  break;
60	case 'n':
61	  form = JLIST_CHANGED_ONLY;
62	  break;
63	case 'x':
64	  if (form != JLIST_STANDARD)
65	    {
66	      builtin_error (_("no other options allowed with `-x'"));
67	      return (EXECUTION_FAILURE);
68	    }
69	  execute++;
70	  break;
71	case 'r':
72	  state = JSTATE_RUNNING;
73	  break;
74	case 's':
75	  state = JSTATE_STOPPED;
76	  break;
77
78	default:
79	  builtin_usage ();
80	  return (EX_USAGE);
81	}
82    }
83
84  list = loptend;
85
86  if (execute)
87    return (execute_list_with_replacements (list));
88
89  if (!list)
90    {
91      switch (state)
92	{
93	case JSTATE_ANY:
94	  list_all_jobs (form);
95	  break;
96	case JSTATE_RUNNING:
97	  list_running_jobs (form);
98	  break;
99	case JSTATE_STOPPED:
100	  list_stopped_jobs (form);
101	  break;
102	}
103      return (EXECUTION_SUCCESS);
104    }
105
106  while (list)
107    {
108      BLOCK_CHILD (set, oset);
109      job = get_job_spec (list);
110
111      if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
112	{
113	  sh_badjob (list->word->word);
114	  any_failed++;
115	}
116      else if (job != DUP_JOB)
117	list_one_job ((JOB *)NULL, form, 0, job);
118
119      UNBLOCK_CHILD (oset);
120      list = list->next;
121    }
122  return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
123}
124
125static int
126execute_list_with_replacements (list)
127     WORD_LIST *list;
128{
129  register WORD_LIST *l;
130  int job, result;
131  COMMAND *command;
132  JOB *j;
133
134  /* First do the replacement of job specifications with pids. */
135  for (l = list; l; l = l->next)
136    {
137      if (l->word->word[0] == '%')	/* we have a winner */
138	{
139	  job = get_job_spec (l);
140
141	  /* A bad job spec is not really a job spec! Pass it through. */
142	  if (INVALID_JOB (job))
143	    continue;
144
145	  j = get_job_by_jid (job);
146	  free (l->word->word);
147	  l->word->word = itos (j->pgrp);
148	}
149    }
150
151  /* Next make a new simple command and execute it. */
152  begin_unwind_frame ("jobs_builtin");
153
154  command = make_bare_simple_command ();
155  command->value.Simple->words = copy_word_list (list);
156  command->value.Simple->redirects = (REDIRECT *)NULL;
157  command->flags |= CMD_INHIBIT_EXPANSION;
158  command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
159
160  add_unwind_protect (dispose_command, command);
161  result = execute_command (command);
162  dispose_command (command);
163
164  discard_unwind_frame ("jobs_builtin");
165  return (result);
166}
167#endif /* JOB_CONTROL */
168
169#line 212 "jobs.def"
170
171#if defined (JOB_CONTROL)
172int
173disown_builtin (list)
174     WORD_LIST *list;
175{
176  int opt, job, retval, nohup_only, running_jobs, all_jobs;
177  sigset_t set, oset;
178  intmax_t pid_value;
179
180  nohup_only = running_jobs = all_jobs = 0;
181  reset_internal_getopt ();
182  while ((opt = internal_getopt (list, "ahr")) != -1)
183    {
184      switch (opt)
185	{
186	case 'a':
187	  all_jobs = 1;
188	  break;
189	case 'h':
190	  nohup_only = 1;
191	  break;
192	case 'r':
193	  running_jobs = 1;
194	  break;
195	default:
196	  builtin_usage ();
197	  return (EX_USAGE);
198	}
199    }
200  list = loptend;
201  retval = EXECUTION_SUCCESS;
202
203  /* `disown -a' or `disown -r' */
204  if (list == 0 && (all_jobs || running_jobs))
205    {
206      if (nohup_only)
207	nohup_all_jobs (running_jobs);
208      else
209	delete_all_jobs (running_jobs);
210      return (EXECUTION_SUCCESS);
211    }
212
213  do
214    {
215      BLOCK_CHILD (set, oset);
216      job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
217		? get_job_by_pid ((pid_t) pid_value, 0)
218		: get_job_spec (list);
219
220      if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
221	{
222	  sh_badjob (list ? list->word->word : "current");
223	  retval = EXECUTION_FAILURE;
224	}
225      else if (nohup_only)
226	nohup_job (job);
227      else
228	delete_job (job, 1);
229      UNBLOCK_CHILD (oset);
230
231      if (list)
232	list = list->next;
233    }
234  while (list);
235
236  return (retval);
237}
238#endif /* JOB_CONTROL */
239