Home | History | Annotate | Download | only in syscall
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
     28 
     29 #pragma ident	"@(#)sigqueue.c	1.13	06/04/23 SMI"
     30 
     31 #include <sys/param.h>
     32 #include <sys/types.h>
     33 #include <sys/sysmacros.h>
     34 #include <sys/systm.h>
     35 #include <sys/errno.h>
     36 #include <sys/proc.h>
     37 #include <sys/procset.h>
     38 #include <sys/fault.h>
     39 #include <sys/signal.h>
     40 #include <sys/siginfo.h>
     41 #include <sys/debug.h>
     42 
     43 static int
     44 sigqkill(pid_t pid, sigsend_t *sigsend)
     45 {
     46 	proc_t *p;
     47 	int error;
     48 
     49 	if ((uint_t)sigsend->sig >= NSIG)
     50 		return (EINVAL);
     51 
     52 	if (pid == -1) {
     53 		procset_t set;
     54 
     55 		setprocset(&set, POP_AND, P_ALL, P_MYID, P_ALL, P_MYID);
     56 		error = sigsendset(&set, sigsend);
     57 	} else if (pid > 0) {
     58 		mutex_enter(&pidlock);
     59 		if ((p = prfind(pid)) == NULL || p->p_stat == SIDL)
     60 			error = ESRCH;
     61 		else {
     62 			error = sigsendproc(p, sigsend);
     63 			if (error == 0 && sigsend->perm == 0)
     64 				error = EPERM;
     65 		}
     66 		mutex_exit(&pidlock);
     67 	} else {
     68 		int nfound = 0;
     69 		pid_t pgid;
     70 
     71 		if (pid == 0)
     72 			pgid = ttoproc(curthread)->p_pgrp;
     73 		else
     74 			pgid = -pid;
     75 
     76 		error = 0;
     77 		mutex_enter(&pidlock);
     78 		for (p = pgfind(pgid); p && !error; p = p->p_pglink) {
     79 			if (p->p_stat != SIDL) {
     80 				nfound++;
     81 				error = sigsendproc(p, sigsend);
     82 			}
     83 		}
     84 		mutex_exit(&pidlock);
     85 		if (nfound == 0)
     86 			error = ESRCH;
     87 		else if (error == 0 && sigsend->perm == 0)
     88 			error = EPERM;
     89 	}
     90 
     91 	return (error);
     92 }
     93 
     94 
     95 /*
     96  * for implementations that don't require binary compatibility,
     97  * the kill system call may be made into a library call to the
     98  * sigsend system call
     99  */
    100 int
    101 kill(pid_t pid, int sig)
    102 {
    103 	int error;
    104 	sigsend_t v;
    105 
    106 	bzero(&v, sizeof (v));
    107 	v.sig = sig;
    108 	v.checkperm = 1;
    109 	v.sicode = SI_USER;
    110 	if ((error = sigqkill(pid, &v)) != 0)
    111 		return (set_errno(error));
    112 	return (0);
    113 }
    114 
    115 /*
    116  * The handling of small unions, like the sigval argument to sigqueue,
    117  * is architecture dependent.  We have adopted the convention that the
    118  * value itself is passed in the storage which crosses the kernel
    119  * protection boundary.  This procedure will accept a scalar argument,
    120  * and store it in the appropriate value member of the sigsend_t structure.
    121  */
    122 int
    123 sigqueue(pid_t pid, int sig, /* union sigval */ void *value,
    124 	int si_code, int block)
    125 {
    126 	int error;
    127 	sigsend_t v;
    128 	sigqhdr_t *sqh;
    129 	proc_t *p = curproc;
    130 
    131 	/* The si_code value must indicate the signal will be queued */
    132 	if (pid <= 0 || !sigwillqueue(sig, si_code))
    133 		return (set_errno(EINVAL));
    134 
    135 	if ((sqh = p->p_sigqhdr) == NULL) {
    136 		/* Allocate sigqueue pool first time */
    137 		sqh = sigqhdralloc(sizeof (sigqueue_t), _SIGQUEUE_MAX);
    138 		mutex_enter(&p->p_lock);
    139 		if (p->p_sigqhdr == NULL) {
    140 			/* hang the pool head on proc */
    141 			p->p_sigqhdr = sqh;
    142 		} else {
    143 			/* another lwp allocated the pool, free ours */
    144 			sigqhdrfree(sqh);
    145 			sqh = p->p_sigqhdr;
    146 		}
    147 		mutex_exit(&p->p_lock);
    148 	}
    149 
    150 	do {
    151 		bzero(&v, sizeof (v));
    152 		v.sig = sig;
    153 		v.checkperm = 1;
    154 		v.sicode = si_code;
    155 		v.value.sival_ptr = value;
    156 		if ((error = sigqkill(pid, &v)) != EAGAIN || !block)
    157 			break;
    158 		/* block waiting for another chance to allocate a sigqueue_t */
    159 		mutex_enter(&sqh->sqb_lock);
    160 		while (sqh->sqb_count == 0) {
    161 			if (!cv_wait_sig(&sqh->sqb_cv, &sqh->sqb_lock)) {
    162 				error = EINTR;
    163 				break;
    164 			}
    165 		}
    166 		mutex_exit(&sqh->sqb_lock);
    167 	} while (error == EAGAIN);
    168 
    169 	if (error)
    170 		return (set_errno(error));
    171 	return (0);
    172 }
    173 
    174 #ifdef _SYSCALL32_IMPL
    175 /*
    176  * sigqueue32 - System call entry point for 32-bit callers on LP64 kernel,
    177  * needed to handle the 32-bit sigvals as correctly as we can.  We always
    178  * assume that a 32-bit caller is passing an int. A 64-bit recipient
    179  * that expects an int will therefore get it correctly.  A 32-bit
    180  * recipient will also get it correctly since siginfo_kto32() uses
    181  * sival_int in the conversion.  Since a 32-bit pointer has the same
    182  * size and address in the sigval, it also converts correctly so that
    183  * two 32-bit apps can exchange a pointer value.  However, this means
    184  * that a pointer sent by a 32-bit caller will be seen in the upper half
    185  * by a 64-bit recipient, and only the upper half of a 64-bit pointer will
    186  * be seen by a 32-bit recipient.  This is the best solution that does
    187  * not require severe hacking of the sigval union.  Anyways, what it
    188  * means to be sending pointers between processes with dissimilar
    189  * models is unclear.
    190  */
    191 int
    192 sigqueue32(pid_t pid, int sig, /* union sigval32 */ caddr32_t value,
    193 	int si_code, int block)
    194 {
    195 	union sigval sv;
    196 
    197 	bzero(&sv, sizeof (sv));
    198 	sv.sival_int = (int)value;
    199 	return (sigqueue(pid, sig, sv.sival_ptr, si_code, block));
    200 }
    201 #endif
    202