signal.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /* $Id: signal.c,v 1.7 2000/09/05 21:44:54 davem Exp $
  2. * signal.c: Signal emulation for Solaris
  3. *
  4. * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  5. */
  6. #include <linux/types.h>
  7. #include <linux/errno.h>
  8. #include <asm/uaccess.h>
  9. #include <asm/svr4.h>
  10. #include <asm/string.h>
  11. #include "conv.h"
  12. #include "signal.h"
  13. #define _S(nr) (1L<<((nr)-1))
  14. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  15. long linux_to_solaris_signals[] = {
  16. 0,
  17. SOLARIS_SIGHUP, SOLARIS_SIGINT,
  18. SOLARIS_SIGQUIT, SOLARIS_SIGILL,
  19. SOLARIS_SIGTRAP, SOLARIS_SIGIOT,
  20. SOLARIS_SIGEMT, SOLARIS_SIGFPE,
  21. SOLARIS_SIGKILL, SOLARIS_SIGBUS,
  22. SOLARIS_SIGSEGV, SOLARIS_SIGSYS,
  23. SOLARIS_SIGPIPE, SOLARIS_SIGALRM,
  24. SOLARIS_SIGTERM, SOLARIS_SIGURG,
  25. SOLARIS_SIGSTOP, SOLARIS_SIGTSTP,
  26. SOLARIS_SIGCONT, SOLARIS_SIGCLD,
  27. SOLARIS_SIGTTIN, SOLARIS_SIGTTOU,
  28. SOLARIS_SIGPOLL, SOLARIS_SIGXCPU,
  29. SOLARIS_SIGXFSZ, SOLARIS_SIGVTALRM,
  30. SOLARIS_SIGPROF, SOLARIS_SIGWINCH,
  31. SOLARIS_SIGUSR1, SOLARIS_SIGUSR1,
  32. SOLARIS_SIGUSR2, -1,
  33. };
  34. long solaris_to_linux_signals[] = {
  35. 0,
  36. SIGHUP, SIGINT, SIGQUIT, SIGILL,
  37. SIGTRAP, SIGIOT, SIGEMT, SIGFPE,
  38. SIGKILL, SIGBUS, SIGSEGV, SIGSYS,
  39. SIGPIPE, SIGALRM, SIGTERM, SIGUSR1,
  40. SIGUSR2, SIGCHLD, -1, SIGWINCH,
  41. SIGURG, SIGPOLL, SIGSTOP, SIGTSTP,
  42. SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM,
  43. SIGPROF, SIGXCPU, SIGXFSZ, -1,
  44. -1, -1, -1, -1,
  45. -1, -1, -1, -1,
  46. -1, -1, -1, -1,
  47. };
  48. static inline long mapsig(long sig)
  49. {
  50. if ((unsigned long)sig > SOLARIS_NSIGNALS)
  51. return -EINVAL;
  52. return solaris_to_linux_signals[sig];
  53. }
  54. asmlinkage int solaris_kill(int pid, int sig)
  55. {
  56. int (*sys_kill)(int,int) =
  57. (int (*)(int,int))SYS(kill);
  58. int s = mapsig(sig);
  59. if (s < 0) return s;
  60. return sys_kill(pid, s);
  61. }
  62. static long sig_handler(int sig, u32 arg, int one_shot)
  63. {
  64. struct sigaction sa, old;
  65. int ret;
  66. mm_segment_t old_fs = get_fs();
  67. int (*sys_sigaction)(int,struct sigaction __user *,struct sigaction __user *) =
  68. (int (*)(int,struct sigaction __user *,struct sigaction __user *))SYS(sigaction);
  69. sigemptyset(&sa.sa_mask);
  70. sa.sa_restorer = NULL;
  71. sa.sa_handler = (__sighandler_t)A(arg);
  72. sa.sa_flags = 0;
  73. if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK;
  74. set_fs (KERNEL_DS);
  75. ret = sys_sigaction(sig, (void __user *)&sa, (void __user *)&old);
  76. set_fs (old_fs);
  77. if (ret < 0) return ret;
  78. return (u32)(unsigned long)old.sa_handler;
  79. }
  80. static inline long solaris_signal(int sig, u32 arg)
  81. {
  82. return sig_handler (sig, arg, 1);
  83. }
  84. static long solaris_sigset(int sig, u32 arg)
  85. {
  86. if (arg != 2) /* HOLD */ {
  87. spin_lock_irq(&current->sighand->siglock);
  88. sigdelsetmask(&current->blocked, _S(sig));
  89. recalc_sigpending();
  90. spin_unlock_irq(&current->sighand->siglock);
  91. return sig_handler (sig, arg, 0);
  92. } else {
  93. spin_lock_irq(&current->sighand->siglock);
  94. sigaddsetmask(&current->blocked, (_S(sig) & ~_BLOCKABLE));
  95. recalc_sigpending();
  96. spin_unlock_irq(&current->sighand->siglock);
  97. return 0;
  98. }
  99. }
  100. static inline long solaris_sighold(int sig)
  101. {
  102. return solaris_sigset(sig, 2);
  103. }
  104. static inline long solaris_sigrelse(int sig)
  105. {
  106. spin_lock_irq(&current->sighand->siglock);
  107. sigdelsetmask(&current->blocked, _S(sig));
  108. recalc_sigpending();
  109. spin_unlock_irq(&current->sighand->siglock);
  110. return 0;
  111. }
  112. static inline long solaris_sigignore(int sig)
  113. {
  114. return sig_handler(sig, (u32)(unsigned long)SIG_IGN, 0);
  115. }
  116. static inline long solaris_sigpause(int sig)
  117. {
  118. printk ("Need to support solaris sigpause\n");
  119. return -ENOSYS;
  120. }
  121. asmlinkage long solaris_sigfunc(int sig, u32 arg)
  122. {
  123. int func = sig & ~0xff;
  124. sig = mapsig(sig & 0xff);
  125. if (sig < 0) return sig;
  126. switch (func) {
  127. case 0: return solaris_signal(sig, arg);
  128. case 0x100: return solaris_sigset(sig, arg);
  129. case 0x200: return solaris_sighold(sig);
  130. case 0x400: return solaris_sigrelse(sig);
  131. case 0x800: return solaris_sigignore(sig);
  132. case 0x1000: return solaris_sigpause(sig);
  133. }
  134. return -EINVAL;
  135. }
  136. typedef struct {
  137. u32 __sigbits[4];
  138. } sol_sigset_t;
  139. static inline int mapin(u32 *p, sigset_t *q)
  140. {
  141. int i;
  142. u32 x;
  143. int sig;
  144. sigemptyset(q);
  145. x = p[0];
  146. for (i = 1; i <= SOLARIS_NSIGNALS; i++) {
  147. if (x & 1) {
  148. sig = solaris_to_linux_signals[i];
  149. if (sig == -1)
  150. return -EINVAL;
  151. sigaddsetmask(q, (1L << (sig - 1)));
  152. }
  153. x >>= 1;
  154. if (i == 32)
  155. x = p[1];
  156. }
  157. return 0;
  158. }
  159. static inline int mapout(sigset_t *q, u32 *p)
  160. {
  161. int i;
  162. int sig;
  163. p[0] = 0;
  164. p[1] = 0;
  165. for (i = 1; i <= 32; i++) {
  166. if (sigismember(q, sigmask(i))) {
  167. sig = linux_to_solaris_signals[i];
  168. if (sig == -1)
  169. return -EINVAL;
  170. if (sig > 32)
  171. p[1] |= 1L << (sig - 33);
  172. else
  173. p[0] |= 1L << (sig - 1);
  174. }
  175. }
  176. return 0;
  177. }
  178. asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out)
  179. {
  180. sigset_t in_s, *ins, out_s, *outs;
  181. mm_segment_t old_fs = get_fs();
  182. int ret;
  183. int (*sys_sigprocmask)(int,sigset_t __user *,sigset_t __user *) =
  184. (int (*)(int,sigset_t __user *,sigset_t __user *))SYS(sigprocmask);
  185. ins = NULL; outs = NULL;
  186. if (in) {
  187. u32 tmp[2];
  188. if (copy_from_user (tmp, (void __user *)A(in), 2*sizeof(u32)))
  189. return -EFAULT;
  190. ins = &in_s;
  191. if (mapin (tmp, ins)) return -EINVAL;
  192. }
  193. if (out) outs = &out_s;
  194. set_fs (KERNEL_DS);
  195. ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how,
  196. (void __user *)ins, (void __user *)outs);
  197. set_fs (old_fs);
  198. if (ret) return ret;
  199. if (out) {
  200. u32 tmp[4];
  201. tmp[2] = 0; tmp[3] = 0;
  202. if (mapout (outs, tmp)) return -EINVAL;
  203. if (copy_to_user((void __user *)A(out), tmp, 4*sizeof(u32)))
  204. return -EFAULT;
  205. }
  206. return 0;
  207. }
  208. asmlinkage long do_sol_sigsuspend(u32 mask)
  209. {
  210. sigset_t s;
  211. u32 tmp[2];
  212. if (copy_from_user (tmp, (sol_sigset_t __user *)A(mask), 2*sizeof(u32)))
  213. return -EFAULT;
  214. if (mapin (tmp, &s)) return -EINVAL;
  215. return (long)s.sig[0];
  216. }
  217. struct sol_sigaction {
  218. int sa_flags;
  219. u32 sa_handler;
  220. u32 sa_mask[4];
  221. int sa_resv[2];
  222. };
  223. asmlinkage int solaris_sigaction(int sig, u32 act, u32 old)
  224. {
  225. u32 tmp, tmp2[4];
  226. struct sigaction s, s2;
  227. int ret;
  228. mm_segment_t old_fs = get_fs();
  229. struct sol_sigaction __user *p = (void __user *)A(old);
  230. int (*sys_sigaction)(int,struct sigaction __user *,struct sigaction __user *) =
  231. (int (*)(int,struct sigaction __user *,struct sigaction __user *))SYS(sigaction);
  232. sig = mapsig(sig);
  233. if (sig < 0) {
  234. /* We cheat a little bit for Solaris only signals */
  235. if (old && clear_user(p, sizeof(struct sol_sigaction)))
  236. return -EFAULT;
  237. return 0;
  238. }
  239. if (act) {
  240. if (get_user (tmp, &p->sa_flags))
  241. return -EFAULT;
  242. s.sa_flags = 0;
  243. if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK;
  244. if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART;
  245. if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK;
  246. if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT;
  247. if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP;
  248. if (get_user (tmp, &p->sa_handler) ||
  249. copy_from_user (tmp2, &p->sa_mask, 2*sizeof(u32)))
  250. return -EFAULT;
  251. s.sa_handler = (__sighandler_t)A(tmp);
  252. if (mapin (tmp2, &s.sa_mask)) return -EINVAL;
  253. s.sa_restorer = NULL;
  254. }
  255. set_fs(KERNEL_DS);
  256. ret = sys_sigaction(sig, act ? (void __user *)&s : NULL,
  257. old ? (void __user *)&s2 : NULL);
  258. set_fs(old_fs);
  259. if (ret) return ret;
  260. if (old) {
  261. if (mapout (&s2.sa_mask, tmp2)) return -EINVAL;
  262. tmp = 0; tmp2[2] = 0; tmp2[3] = 0;
  263. if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK;
  264. if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART;
  265. if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER;
  266. if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND;
  267. if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP;
  268. if (put_user (tmp, &p->sa_flags) ||
  269. __put_user ((u32)(unsigned long)s2.sa_handler, &p->sa_handler) ||
  270. copy_to_user (&p->sa_mask, tmp2, 4*sizeof(u32)))
  271. return -EFAULT;
  272. }
  273. return 0;
  274. }
  275. asmlinkage int solaris_sigpending(int which, u32 set)
  276. {
  277. sigset_t s;
  278. u32 tmp[4];
  279. switch (which) {
  280. case 1: /* sigpending */
  281. spin_lock_irq(&current->sighand->siglock);
  282. sigandsets(&s, &current->blocked, &current->pending.signal);
  283. recalc_sigpending();
  284. spin_unlock_irq(&current->sighand->siglock);
  285. break;
  286. case 2: /* sigfillset - I just set signals which have linux equivalents */
  287. sigfillset(&s);
  288. break;
  289. default: return -EINVAL;
  290. }
  291. if (mapout (&s, tmp)) return -EINVAL;
  292. tmp[2] = 0; tmp[3] = 0;
  293. if (copy_to_user ((u32 __user *)A(set), tmp, sizeof(tmp)))
  294. return -EFAULT;
  295. return 0;
  296. }
  297. asmlinkage int solaris_wait(u32 stat_loc)
  298. {
  299. unsigned __user *p = (unsigned __user *)A(stat_loc);
  300. int (*sys_wait4)(pid_t,unsigned __user *, int, struct rusage __user *) =
  301. (int (*)(pid_t,unsigned __user *, int, struct rusage __user *))SYS(wait4);
  302. int ret, status;
  303. ret = sys_wait4(-1, p, WUNTRACED, NULL);
  304. if (ret >= 0 && stat_loc) {
  305. if (get_user (status, p))
  306. return -EFAULT;
  307. if (((status - 1) & 0xffff) < 0xff)
  308. status = linux_to_solaris_signals[status & 0x7f] & 0x7f;
  309. else if ((status & 0xff) == 0x7f)
  310. status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f;
  311. if (__put_user (status, p))
  312. return -EFAULT;
  313. }
  314. return ret;
  315. }
  316. asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options)
  317. {
  318. int (*sys_wait4)(pid_t,unsigned __user *, int, struct rusage __user *) =
  319. (int (*)(pid_t,unsigned __user *, int, struct rusage __user *))SYS(wait4);
  320. int opts, status, ret;
  321. switch (idtype) {
  322. case 0: /* P_PID */ break;
  323. case 1: /* P_PGID */ pid = -pid; break;
  324. case 7: /* P_ALL */ pid = -1; break;
  325. default: return -EINVAL;
  326. }
  327. opts = 0;
  328. if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED;
  329. if (options & SOLARIS_WNOHANG) opts |= WNOHANG;
  330. current->state = TASK_RUNNING;
  331. ret = sys_wait4(pid, (unsigned int __user *)A(info), opts, NULL);
  332. if (ret < 0) return ret;
  333. if (info) {
  334. struct sol_siginfo __user *s = (void __user *)A(info);
  335. if (get_user (status, (unsigned int __user *)A(info)))
  336. return -EFAULT;
  337. if (__put_user (SOLARIS_SIGCLD, &s->si_signo) ||
  338. __put_user (ret, &s->_data._proc._pid))
  339. return -EFAULT;
  340. switch (status & 0xff) {
  341. case 0: ret = SOLARIS_CLD_EXITED;
  342. status = (status >> 8) & 0xff;
  343. break;
  344. case 0x7f:
  345. status = (status >> 8) & 0xff;
  346. switch (status) {
  347. case SIGSTOP:
  348. case SIGTSTP: ret = SOLARIS_CLD_STOPPED;
  349. default: ret = SOLARIS_CLD_EXITED;
  350. }
  351. status = linux_to_solaris_signals[status];
  352. break;
  353. default:
  354. if (status & 0x80) ret = SOLARIS_CLD_DUMPED;
  355. else ret = SOLARIS_CLD_KILLED;
  356. status = linux_to_solaris_signals[status & 0x7f];
  357. break;
  358. }
  359. if (__put_user (ret, &s->si_code) ||
  360. __put_user (status, &s->_data._proc._pdata._cld._status))
  361. return -EFAULT;
  362. }
  363. return 0;
  364. }
  365. extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs);
  366. extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs);
  367. asmlinkage int solaris_context(struct pt_regs *regs)
  368. {
  369. switch ((unsigned)regs->u_regs[UREG_I0]) {
  370. case 0: /* getcontext */
  371. return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
  372. case 1: /* setcontext */
  373. return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs);
  374. default:
  375. return -EINVAL;
  376. }
  377. }
  378. asmlinkage int solaris_sigaltstack(u32 ss, u32 oss)
  379. {
  380. /* XXX Implement this soon */
  381. return 0;
  382. }