This source file includes following definitions.
- send_sig
- release
- bad_task_ptr
- audit_ptree
- session_of_pgrp
- kill_pg
- kill_sl
- kill_proc
- sys_kill
- is_orphaned_pgrp
- has_stopped_jobs
- forget_original_parent
- do_exit
- sys_exit
- sys_wait4
- sys_waitpid
1
2
3
4
5
6
7 #define DEBUG_PROC_TREE
8
9 #include <linux/wait.h>
10 #include <linux/errno.h>
11 #include <linux/signal.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/resource.h>
15 #include <linux/mm.h>
16 #include <linux/tty.h>
17
18 #include <asm/segment.h>
19
20 int sys_close(int fd);
21 int getrusage(struct task_struct *, int, struct rusage *);
22
23 int send_sig(unsigned long sig,struct task_struct * p,int priv)
24 {
25 if (!p || sig > 32)
26 return -EINVAL;
27 if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
28 (current->euid != p->euid) && (current->uid != p->uid) && !suser())
29 return -EPERM;
30 if (!sig)
31 return 0;
32 if ((sig == SIGKILL) || (sig == SIGCONT)) {
33 if (p->state == TASK_STOPPED)
34 p->state = TASK_RUNNING;
35 p->exit_code = 0;
36 p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
37 (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
38 }
39
40 if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
41 p->signal &= ~(1<<(SIGCONT-1));
42
43 p->signal |= (1<<(sig-1));
44 if (p->flags & PF_PTRACED) {
45
46 p->exit_code = sig;
47
48
49 if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
50 p->p_pptr->state = TASK_RUNNING;
51
52
53 if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING)
54 p->state = TASK_STOPPED;
55 }
56 return 0;
57 }
58
59 void release(struct task_struct * p)
60 {
61 int i;
62
63 if (!p)
64 return;
65 if (p == current) {
66 printk("task releasing itself\n");
67 return;
68 }
69 for (i=1 ; i<NR_TASKS ; i++)
70 if (task[i] == p) {
71 task[i] = NULL;
72 REMOVE_LINKS(p);
73 free_page(p->kernel_stack_page);
74 free_page((long) p);
75 return;
76 }
77 panic("trying to release non-existent task");
78 }
79
80 #ifdef DEBUG_PROC_TREE
81
82
83
84
85 int bad_task_ptr(struct task_struct *p)
86 {
87 int i;
88
89 if (!p)
90 return 0;
91 for (i=0 ; i<NR_TASKS ; i++)
92 if (task[i] == p)
93 return 0;
94 return 1;
95 }
96
97
98
99
100
101
102
103
104
105
106 void audit_ptree(void)
107 {
108 int i;
109
110 for (i=1 ; i<NR_TASKS ; i++) {
111 if (!task[i])
112 continue;
113 if (bad_task_ptr(task[i]->p_pptr))
114 printk("Warning, pid %d's parent link is bad\n",
115 task[i]->pid);
116 if (bad_task_ptr(task[i]->p_cptr))
117 printk("Warning, pid %d's child link is bad\n",
118 task[i]->pid);
119 if (bad_task_ptr(task[i]->p_ysptr))
120 printk("Warning, pid %d's ys link is bad\n",
121 task[i]->pid);
122 if (bad_task_ptr(task[i]->p_osptr))
123 printk("Warning, pid %d's os link is bad\n",
124 task[i]->pid);
125 if (task[i]->p_pptr == task[i])
126 printk("Warning, pid %d parent link points to self\n");
127 if (task[i]->p_cptr == task[i])
128 printk("Warning, pid %d child link points to self\n");
129 if (task[i]->p_ysptr == task[i])
130 printk("Warning, pid %d ys link points to self\n");
131 if (task[i]->p_osptr == task[i])
132 printk("Warning, pid %d os link points to self\n");
133 if (task[i]->p_osptr) {
134 if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
135 printk(
136 "Warning, pid %d older sibling %d parent is %d\n",
137 task[i]->pid, task[i]->p_osptr->pid,
138 task[i]->p_osptr->p_pptr->pid);
139 if (task[i]->p_osptr->p_ysptr != task[i])
140 printk(
141 "Warning, pid %d older sibling %d has mismatched ys link\n",
142 task[i]->pid, task[i]->p_osptr->pid);
143 }
144 if (task[i]->p_ysptr) {
145 if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
146 printk(
147 "Warning, pid %d younger sibling %d parent is %d\n",
148 task[i]->pid, task[i]->p_osptr->pid,
149 task[i]->p_osptr->p_pptr->pid);
150 if (task[i]->p_ysptr->p_osptr != task[i])
151 printk(
152 "Warning, pid %d younger sibling %d has mismatched os link\n",
153 task[i]->pid, task[i]->p_ysptr->pid);
154 }
155 if (task[i]->p_cptr) {
156 if (task[i]->p_cptr->p_pptr != task[i])
157 printk(
158 "Warning, pid %d youngest child %d has mismatched parent link\n",
159 task[i]->pid, task[i]->p_cptr->pid);
160 if (task[i]->p_cptr->p_ysptr)
161 printk(
162 "Warning, pid %d youngest child %d has non-NULL ys link\n",
163 task[i]->pid, task[i]->p_cptr->pid);
164 }
165 }
166 }
167 #endif
168
169
170
171
172
173
174 int session_of_pgrp(int pgrp)
175 {
176 struct task_struct **p;
177 int fallback;
178
179 fallback = -1;
180 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
181 if (!*p || (*p)->session <= 0)
182 continue;
183 if ((*p)->pgrp == pgrp)
184 return (*p)->session;
185 if ((*p)->pid == pgrp)
186 fallback = (*p)->session;
187 }
188 return fallback;
189 }
190
191
192
193
194
195 int kill_pg(int pgrp, int sig, int priv)
196 {
197 struct task_struct **p;
198 int err,retval = -ESRCH;
199 int found = 0;
200
201 if (sig<0 || sig>32 || pgrp<=0)
202 return -EINVAL;
203 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
204 if (*p && (*p)->pgrp == pgrp) {
205 if ((err = send_sig(sig,*p,priv)) != 0)
206 retval = err;
207 else
208 found++;
209 }
210 return(found ? 0 : retval);
211 }
212
213
214
215
216
217
218 int kill_sl(int sess, int sig, int priv)
219 {
220 struct task_struct **p;
221 int err,retval = -ESRCH;
222 int found = 0;
223
224 if (sig<0 || sig>32 || sess<=0)
225 return -EINVAL;
226 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
227 if (*p && (*p)->session == sess && (*p)->leader) {
228 if ((err = send_sig(sig,*p,priv)) != 0)
229 retval = err;
230 else
231 found++;
232 }
233 return(found ? 0 : retval);
234 }
235
236 int kill_proc(int pid, int sig, int priv)
237 {
238 struct task_struct **p;
239
240 if (sig<0 || sig>32)
241 return -EINVAL;
242 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
243 if (*p && (*p)->pid == pid)
244 return send_sig(sig,*p,priv);
245 return(-ESRCH);
246 }
247
248
249
250
251
252 int sys_kill(int pid,int sig)
253 {
254 struct task_struct **p = NR_TASKS + task;
255 int err, retval = 0, count = 0;
256
257 if (!pid)
258 return(kill_pg(current->pgrp,sig,0));
259 if (pid == -1) {
260 while (--p > &FIRST_TASK)
261 if (*p && (*p)->pid > 1 && *p != current) {
262 ++count;
263 if ((err = send_sig(sig,*p,0)) != -EPERM)
264 retval = err;
265 }
266 return(count ? retval : -ESRCH);
267 }
268 if (pid < 0)
269 return(kill_pg(-pid,sig,0));
270
271 return(kill_proc(pid,sig,0));
272 }
273
274
275
276
277
278
279
280
281
282 int is_orphaned_pgrp(int pgrp)
283 {
284 struct task_struct **p;
285
286 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
287 if (!(*p) ||
288 ((*p)->pgrp != pgrp) ||
289 ((*p)->state == TASK_ZOMBIE) ||
290 ((*p)->p_pptr->pid == 1))
291 continue;
292 if (((*p)->p_pptr->pgrp != pgrp) &&
293 ((*p)->p_pptr->session == (*p)->session))
294 return 0;
295 }
296 return(1);
297 }
298
299 static int has_stopped_jobs(int pgrp)
300 {
301 struct task_struct ** p;
302
303 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
304 if (!*p || (*p)->pgrp != pgrp)
305 continue;
306 if ((*p)->state == TASK_STOPPED)
307 return(1);
308 }
309 return(0);
310 }
311
312 static void forget_original_parent(struct task_struct * father)
313 {
314 struct task_struct ** p;
315
316 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
317 if (*p && (*p)->p_opptr == father)
318 if (task[1])
319 (*p)->p_opptr = task[1];
320 else
321 (*p)->p_opptr = task[0];
322 }
323
324 volatile void do_exit(long code)
325 {
326 struct task_struct *p;
327 int i;
328
329 fake_volatile:
330 free_page_tables(current);
331 for (i=0 ; i<NR_OPEN ; i++)
332 if (current->filp[i])
333 sys_close(i);
334 forget_original_parent(current);
335 iput(current->pwd);
336 current->pwd = NULL;
337 iput(current->root);
338 current->root = NULL;
339 iput(current->executable);
340 current->executable = NULL;
341 for (i=0; i < current->numlibraries; i++) {
342 iput(current->libraries[i].library);
343 current->libraries[i].library = NULL;
344 }
345 current->state = TASK_ZOMBIE;
346 current->exit_code = code;
347 current->rss = 0;
348
349
350
351
352
353
354
355
356
357 if ((current->p_pptr->pgrp != current->pgrp) &&
358 (current->p_pptr->session == current->session) &&
359 is_orphaned_pgrp(current->pgrp) &&
360 has_stopped_jobs(current->pgrp)) {
361 kill_pg(current->pgrp,SIGHUP,1);
362 kill_pg(current->pgrp,SIGCONT,1);
363 }
364
365 send_sig (SIGCHLD, current->p_pptr, 1);
366
367
368
369
370
371
372
373
374
375 while ((p = current->p_cptr) != NULL) {
376 current->p_cptr = p->p_osptr;
377 p->p_ysptr = NULL;
378 p->flags &= ~(PF_PTRACED|PF_TRACESYS);
379 if (task[1])
380 p->p_pptr = task[1];
381 else
382 p->p_pptr = task[0];
383 p->p_osptr = p->p_pptr->p_cptr;
384 p->p_osptr->p_ysptr = p;
385 p->p_pptr->p_cptr = p;
386 if (p->state == TASK_ZOMBIE)
387 send_sig(SIGCHLD,p->p_pptr,1);
388
389
390
391
392
393
394 if ((p->pgrp != current->pgrp) &&
395 (p->session == current->session) &&
396 is_orphaned_pgrp(p->pgrp) &&
397 has_stopped_jobs(p->pgrp)) {
398 kill_pg(p->pgrp,SIGHUP,1);
399 kill_pg(p->pgrp,SIGCONT,1);
400 }
401 }
402 if (current->leader) {
403 struct task_struct **p;
404 struct tty_struct *tty;
405
406 if (current->tty >= 0) {
407 tty = TTY_TABLE(current->tty);
408 if (tty) {
409 if (tty->pgrp > 0)
410 kill_pg(tty->pgrp, SIGHUP, 1);
411 tty->pgrp = -1;
412 tty->session = 0;
413 }
414 }
415 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
416 if (*p && (*p)->session == current->session)
417 (*p)->tty = -1;
418 }
419 if (last_task_used_math == current)
420 last_task_used_math = NULL;
421 #ifdef DEBUG_PROC_TREE
422 audit_ptree();
423 #endif
424 schedule();
425
426
427
428
429
430
431
432
433
434
435
436
437
438 goto fake_volatile;
439 }
440
441 int sys_exit(int error_code)
442 {
443 do_exit((error_code&0xff)<<8);
444 }
445
446 int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru)
447 {
448 int flag;
449 struct task_struct *p;
450 unsigned long oldblocked;
451
452 if (stat_addr) {
453 flag = verify_area(VERIFY_WRITE, stat_addr, 4);
454 if (flag)
455 return flag;
456 }
457 repeat:
458 current->signal &= ~(1<<(SIGCHLD-1));
459 flag=0;
460 for (p = current->p_cptr ; p ; p = p->p_osptr) {
461 if (pid>0) {
462 if (p->pid != pid)
463 continue;
464 } else if (!pid) {
465 if (p->pgrp != current->pgrp)
466 continue;
467 } else if (pid != -1) {
468 if (p->pgrp != -pid)
469 continue;
470 }
471 switch (p->state) {
472 case TASK_STOPPED:
473 if (!p->exit_code)
474 continue;
475 if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
476 continue;
477 if (stat_addr)
478 put_fs_long((p->exit_code << 8) | 0x7f,
479 stat_addr);
480 p->exit_code = 0;
481 if (ru != NULL)
482 getrusage(p, RUSAGE_BOTH, ru);
483 return p->pid;
484 case TASK_ZOMBIE:
485 current->cutime += p->utime + p->cutime;
486 current->cstime += p->stime + p->cstime;
487 current->cmin_flt += p->min_flt + p->cmin_flt;
488 current->cmaj_flt += p->maj_flt + p->cmaj_flt;
489 if (ru != NULL)
490 getrusage(p, RUSAGE_BOTH, ru);
491 flag = p->pid;
492 if (stat_addr)
493 put_fs_long(p->exit_code, stat_addr);
494 if (p->p_opptr != p->p_pptr) {
495 REMOVE_LINKS(p);
496 p->p_pptr = p->p_opptr;
497 SET_LINKS(p);
498 send_sig(SIGCHLD,p->p_pptr,1);
499 } else
500 release(p);
501 #ifdef DEBUG_PROC_TREE
502 audit_ptree();
503 #endif
504 return flag;
505 default:
506 flag=1;
507 continue;
508 }
509 }
510 if (flag) {
511 if (options & WNOHANG)
512 return 0;
513 current->state=TASK_INTERRUPTIBLE;
514 oldblocked = current->blocked;
515 current->blocked &= ~(1<<(SIGCHLD-1));
516 schedule();
517 current->blocked = oldblocked;
518 if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
519 return -ERESTARTSYS;
520 else
521 goto repeat;
522 }
523 return -ECHILD;
524 }
525
526
527
528
529
530 int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
531 {
532 return sys_wait4(pid, stat_addr, options, NULL);
533 }