| 1 | /* |
| 2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms are permitted |
| 6 | * provided that the above copyright notice and this paragraph are |
| 7 | * duplicated in all such forms and that any documentation, |
| 8 | * advertising materials, and other materials related to such |
| 9 | * distribution and use acknowledge that the software was developed |
| 10 | * by the University of California, Berkeley. The name of the |
| 11 | * University may not be used to endorse or promote products derived |
| 12 | * from this software without specific prior written permission. |
| 13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
| 14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
| 15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| 16 | * |
| 17 | * @(#)kern_exit.c 7.7 (Berkeley) %G% |
| 18 | */ |
| 19 | |
| 20 | #include "param.h" |
| 21 | #include "systm.h" |
| 22 | #include "map.h" |
| 23 | #include "user.h" |
| 24 | #include "kernel.h" |
| 25 | #include "proc.h" |
| 26 | #include "buf.h" |
| 27 | #include "wait.h" |
| 28 | #include "vm.h" |
| 29 | #include "file.h" |
| 30 | #include "vnode.h" |
| 31 | #include "tty.h" |
| 32 | #include "syslog.h" |
| 33 | #include "malloc.h" |
| 34 | |
| 35 | #include "machine/reg.h" |
| 36 | #ifdef COMPAT_43 |
| 37 | #include "machine/psl.h" |
| 38 | #endif |
| 39 | |
| 40 | /* |
| 41 | * Exit system call: pass back caller's arg |
| 42 | */ |
| 43 | rexit() |
| 44 | { |
| 45 | register struct a { |
| 46 | int rval; |
| 47 | } *uap; |
| 48 | union wait status; |
| 49 | |
| 50 | uap = (struct a *)u.u_ap; |
| 51 | status.w_status = 0; |
| 52 | status.w_retcode = uap->rval; |
| 53 | exit(status.w_status); |
| 54 | } |
| 55 | |
| 56 | /* |
| 57 | * Release resources. |
| 58 | * Save u. area for parent to look at. |
| 59 | * Enter zombie state. |
| 60 | * Wake up parent and init processes, |
| 61 | * and dispose of children. |
| 62 | */ |
| 63 | exit(rv) |
| 64 | int rv; /* should be union wait (XXX) */ |
| 65 | { |
| 66 | register int i; |
| 67 | register struct proc *p, *q, *nq; |
| 68 | register int x; |
| 69 | |
| 70 | #ifdef PGINPROF |
| 71 | vmsizmon(); |
| 72 | #endif |
| 73 | p = u.u_procp; |
| 74 | MALLOC(p->p_ru, struct rusage *, sizeof(struct rusage), |
| 75 | M_ZOMBIE, M_WAITOK); |
| 76 | p->p_flag &= ~(STRC|SULOCK); |
| 77 | p->p_flag |= SWEXIT; |
| 78 | p->p_sigignore = ~0; |
| 79 | p->p_cpticks = 0; |
| 80 | p->p_pctcpu = 0; |
| 81 | for (i = 0; i < NSIG; i++) |
| 82 | u.u_signal[i] = SIG_IGN; |
| 83 | untimeout(realitexpire, (caddr_t)p); |
| 84 | /* |
| 85 | * Release virtual memory. If we resulted from |
| 86 | * a vfork(), instead give the resources back to |
| 87 | * the parent. |
| 88 | */ |
| 89 | if ((p->p_flag & SVFORK) == 0) |
| 90 | vrelvm(); |
| 91 | else { |
| 92 | p->p_flag &= ~SVFORK; |
| 93 | wakeup((caddr_t)p); |
| 94 | while ((p->p_flag & SVFDONE) == 0) |
| 95 | sleep((caddr_t)p, PZERO - 1); |
| 96 | p->p_flag &= ~SVFDONE; |
| 97 | } |
| 98 | for (i = 0; i <= u.u_lastfile; i++) { |
| 99 | struct file *f; |
| 100 | |
| 101 | f = u.u_ofile[i]; |
| 102 | if (f) { |
| 103 | u.u_ofile[i] = NULL; |
| 104 | u.u_pofile[i] = 0; |
| 105 | closef(f); |
| 106 | } |
| 107 | } |
| 108 | if (SESS_LEADER(p)) { |
| 109 | p->p_session->s_leader = 0; |
| 110 | /* TODO: vhangup(); */ |
| 111 | if (u.u_ttyp) { |
| 112 | u.u_ttyp->t_session = 0; |
| 113 | u.u_ttyp->t_pgid = 0; |
| 114 | } |
| 115 | } |
| 116 | VOP_LOCK(u.u_cdir); |
| 117 | vput(u.u_cdir); |
| 118 | if (u.u_rdir) { |
| 119 | VOP_LOCK(u.u_rdir); |
| 120 | vput(u.u_rdir); |
| 121 | } |
| 122 | u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; |
| 123 | acct(); |
| 124 | #ifdef QUOTA |
| 125 | qclean(); |
| 126 | #endif |
| 127 | crfree(u.u_cred); |
| 128 | #ifdef KTRACE |
| 129 | /* |
| 130 | * release trace file |
| 131 | */ |
| 132 | if (p->p_tracep) |
| 133 | vrele(p->p_tracep); |
| 134 | #endif |
| 135 | /* |
| 136 | /* |
| 137 | * Freeing the user structure and kernel stack |
| 138 | * for the current process: have to run a bit longer |
| 139 | * using the pages which are about to be freed... |
| 140 | * vrelu will block memory allocation by raising ipl. |
| 141 | */ |
| 142 | vrelu(u.u_procp, 0); |
| 143 | vrelpt(u.u_procp); |
| 144 | if (*p->p_prev = p->p_nxt) /* off allproc queue */ |
| 145 | p->p_nxt->p_prev = p->p_prev; |
| 146 | if (p->p_nxt = zombproc) /* onto zombproc */ |
| 147 | p->p_nxt->p_prev = &p->p_nxt; |
| 148 | p->p_prev = &zombproc; |
| 149 | zombproc = p; |
| 150 | multprog--; |
| 151 | p->p_stat = SZOMB; |
| 152 | noproc = 1; |
| 153 | i = PIDHASH(p->p_pid); |
| 154 | x = p - proc; |
| 155 | if (pidhash[i] == x) |
| 156 | pidhash[i] = p->p_idhash; |
| 157 | else { |
| 158 | for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) |
| 159 | if (proc[i].p_idhash == x) { |
| 160 | proc[i].p_idhash = p->p_idhash; |
| 161 | goto done; |
| 162 | } |
| 163 | panic("exit"); |
| 164 | } |
| 165 | if (p->p_pid == 1) { |
| 166 | if (p->p_dsize == 0) { |
| 167 | printf("Can't exec init (errno %d)\n", rv >> 8); |
| 168 | for (;;) |
| 169 | ; |
| 170 | } else |
| 171 | panic("init died"); |
| 172 | } |
| 173 | done: |
| 174 | p->p_xstat = rv; |
| 175 | *p->p_ru = u.u_ru; |
| 176 | ruadd(p->p_ru, &u.u_cru); |
| 177 | if (p->p_cptr) /* only need this if any child is S_ZOMB */ |
| 178 | wakeup((caddr_t)&proc[1]); |
| 179 | if (PGRP_JOBC(p)) |
| 180 | p->p_pgrp->pg_jobc--; |
| 181 | for (q = p->p_cptr; q != NULL; q = nq) { |
| 182 | if (PGRP_JOBC(q)) |
| 183 | q->p_pgrp->pg_jobc--; |
| 184 | nq = q->p_osptr; |
| 185 | if (nq != NULL) |
| 186 | nq->p_ysptr = NULL; |
| 187 | if (proc[1].p_cptr) |
| 188 | proc[1].p_cptr->p_ysptr = q; |
| 189 | q->p_osptr = proc[1].p_cptr; |
| 190 | q->p_ysptr = NULL; |
| 191 | proc[1].p_cptr = q; |
| 192 | |
| 193 | q->p_pptr = &proc[1]; |
| 194 | q->p_ppid = 1; |
| 195 | /* |
| 196 | * Traced processes are killed |
| 197 | * since their existence means someone is screwing up. |
| 198 | * Stopped processes are sent a hangup and a continue. |
| 199 | * This is designed to be ``safe'' for setuid |
| 200 | * processes since they must be willing to tolerate |
| 201 | * hangups anyways. |
| 202 | */ |
| 203 | if (q->p_flag&STRC) { |
| 204 | q->p_flag &= ~STRC; |
| 205 | psignal(q, SIGKILL); |
| 206 | } else if (q->p_stat == SSTOP) { |
| 207 | psignal(q, SIGHUP); |
| 208 | psignal(q, SIGCONT); |
| 209 | } |
| 210 | /* |
| 211 | * Protect this process from future |
| 212 | * tty signals, clear TSTP/TTIN/TTOU if pending. |
| 213 | */ |
| 214 | (void) spgrp(q); |
| 215 | } |
| 216 | p->p_cptr = NULL; |
| 217 | psignal(p->p_pptr, SIGCHLD); |
| 218 | wakeup((caddr_t)p->p_pptr); |
| 219 | #if defined(tahoe) |
| 220 | dkeyrelease(p->p_dkey), p->p_dkey = 0; |
| 221 | ckeyrelease(p->p_ckey), p->p_ckey = 0; |
| 222 | u.u_pcb.pcb_savacc.faddr = (float *)NULL; |
| 223 | #endif |
| 224 | swtch(); |
| 225 | } |
| 226 | |
| 227 | #ifdef COMPAT_43 |
| 228 | owait() |
| 229 | { |
| 230 | struct a { |
| 231 | int pid; |
| 232 | union wait *status; |
| 233 | int options; |
| 234 | struct rusage *rusage; |
| 235 | } *uap = (struct a *)u.u_ap; |
| 236 | |
| 237 | if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { |
| 238 | uap->options = WSIGRESTART; |
| 239 | uap->rusage = 0; |
| 240 | } else { |
| 241 | uap->options = u.u_ar0[R0] | WSIGRESTART; |
| 242 | uap->rusage = (struct rusage *)u.u_ar0[R1]; |
| 243 | } |
| 244 | uap->pid = WAIT_ANY; |
| 245 | uap->status = 0; |
| 246 | wait1(1); |
| 247 | } |
| 248 | |
| 249 | wait4() |
| 250 | { |
| 251 | wait1(0); |
| 252 | } |
| 253 | #endif |
| 254 | |
| 255 | /* |
| 256 | * Wait system call. |
| 257 | * Search for a terminated (zombie) child, |
| 258 | * finally lay it to rest, and collect its status. |
| 259 | * Look also for stopped (traced) children, |
| 260 | * and pass back status from them. |
| 261 | */ |
| 262 | #ifdef COMPAT_43 |
| 263 | wait1(compat) |
| 264 | int compat; |
| 265 | #else |
| 266 | wait4() |
| 267 | #endif |
| 268 | { |
| 269 | register struct a { |
| 270 | int pid; |
| 271 | union wait *status; |
| 272 | int options; |
| 273 | struct rusage *rusage; |
| 274 | } *uap = (struct a *)u.u_ap; |
| 275 | register f; |
| 276 | register struct proc *p, *q; |
| 277 | union wait status; |
| 278 | |
| 279 | f = 0; |
| 280 | q = u.u_procp; |
| 281 | if (uap->pid == 0) |
| 282 | uap->pid = -q->p_pgid; |
| 283 | if (uap->options &~ (WUNTRACED|WNOHANG|WSIGRESTART)) { |
| 284 | u.u_error = EINVAL; |
| 285 | return; |
| 286 | } |
| 287 | loop: |
| 288 | for (p = q->p_cptr; p; p = p->p_osptr) { |
| 289 | if (uap->pid != WAIT_ANY && |
| 290 | p->p_pid != uap->pid && p->p_pgid != -uap->pid) |
| 291 | continue; |
| 292 | f++; |
| 293 | if (p->p_stat == SZOMB) { |
| 294 | pgrm(p); /* off pgrp */ |
| 295 | u.u_r.r_val1 = p->p_pid; |
| 296 | #ifdef COMPAT_43 |
| 297 | if (compat) |
| 298 | u.u_r.r_val2 = p->p_xstat; |
| 299 | else |
| 300 | #endif |
| 301 | if (uap->status) { |
| 302 | status.w_status = p->p_xstat; |
| 303 | if (u.u_error = copyout((caddr_t)&status, |
| 304 | (caddr_t)uap->status, sizeof(status))) |
| 305 | return; |
| 306 | } |
| 307 | p->p_xstat = 0; |
| 308 | if (uap->rusage) |
| 309 | u.u_error = copyout((caddr_t)p->p_ru, |
| 310 | (caddr_t)uap->rusage, |
| 311 | sizeof (struct rusage)); |
| 312 | ruadd(&u.u_cru, p->p_ru); |
| 313 | FREE(p->p_ru, M_ZOMBIE); |
| 314 | p->p_ru = 0; |
| 315 | p->p_stat = NULL; |
| 316 | p->p_pid = 0; |
| 317 | p->p_ppid = 0; |
| 318 | if (*p->p_prev = p->p_nxt) /* off zombproc */ |
| 319 | p->p_nxt->p_prev = p->p_prev; |
| 320 | p->p_nxt = freeproc; /* onto freeproc */ |
| 321 | freeproc = p; |
| 322 | if (q = p->p_ysptr) |
| 323 | q->p_osptr = p->p_osptr; |
| 324 | if (q = p->p_osptr) |
| 325 | q->p_ysptr = p->p_ysptr; |
| 326 | if ((q = p->p_pptr)->p_cptr == p) |
| 327 | q->p_cptr = p->p_osptr; |
| 328 | p->p_pptr = 0; |
| 329 | p->p_ysptr = 0; |
| 330 | p->p_osptr = 0; |
| 331 | p->p_cptr = 0; |
| 332 | p->p_sig = 0; |
| 333 | p->p_sigcatch = 0; |
| 334 | p->p_sigignore = 0; |
| 335 | p->p_sigmask = 0; |
| 336 | /*p->p_pgrp = 0;*/ |
| 337 | p->p_flag = 0; |
| 338 | p->p_wchan = 0; |
| 339 | p->p_cursig = 0; |
| 340 | return; |
| 341 | } |
| 342 | if (p->p_stat == SSTOP && (p->p_flag & SWTED) == 0 && |
| 343 | (p->p_flag & STRC || uap->options & WUNTRACED)) { |
| 344 | p->p_flag |= SWTED; |
| 345 | u.u_r.r_val1 = p->p_pid; |
| 346 | #ifdef COMPAT_43 |
| 347 | if (compat) |
| 348 | u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; |
| 349 | else |
| 350 | #endif |
| 351 | if (uap->status) { |
| 352 | status.w_status = 0; |
| 353 | status.w_stopval = WSTOPPED; |
| 354 | status.w_stopsig = p->p_cursig; |
| 355 | u.u_error = copyout((caddr_t)&status, |
| 356 | (caddr_t)uap->status, sizeof(status)); |
| 357 | } |
| 358 | return; |
| 359 | } |
| 360 | } |
| 361 | if (f == 0) { |
| 362 | u.u_error = ECHILD; |
| 363 | return; |
| 364 | } |
| 365 | if (uap->options & WNOHANG) { |
| 366 | u.u_r.r_val1 = 0; |
| 367 | return; |
| 368 | } |
| 369 | if (uap->options & WSIGRESTART && setjmp(&u.u_qsave)) { |
| 370 | p = u.u_procp; |
| 371 | if ((u.u_sigintr & sigmask(p->p_cursig)) != 0) { |
| 372 | u.u_error = EINTR; |
| 373 | return; |
| 374 | } |
| 375 | u.u_eosys = RESTARTSYS; |
| 376 | return; |
| 377 | } |
| 378 | sleep((caddr_t)u.u_procp, PWAIT); |
| 379 | goto loop; |
| 380 | } |