sysv_msg.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /* $OpenBSD: sysv_msg.c,v 1.30 2014/12/19 05:59:21 tedu Exp $ */
  2. /* $NetBSD: sysv_msg.c,v 1.19 1996/02/09 19:00:18 christos Exp $ */
  3. /*
  4. * Copyright (c) 2009 Bret S. Lambert <blambert@openbsd.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*
  19. * Implementation of SVID messages
  20. *
  21. * Author: Daniel Boulet
  22. *
  23. * Copyright 1993 Daniel Boulet and RTMX Inc.
  24. *
  25. * This system call was implemented by Daniel Boulet under contract from RTMX.
  26. *
  27. * Redistribution and use in source forms, with and without modification,
  28. * are permitted provided that this entire comment appears intact.
  29. *
  30. * Redistribution in binary form may occur without any restrictions.
  31. * Obviously, it would be nice if you gave credit where credit is due
  32. * but requiring it would be too onerous.
  33. *
  34. * This software is provided ``AS IS'' without any warranties of any kind.
  35. */
  36. #include <sys/param.h>
  37. #include <sys/malloc.h>
  38. #include <sys/mbuf.h>
  39. #include <sys/mount.h>
  40. #include <sys/msg.h>
  41. #include <sys/pool.h>
  42. #include <sys/proc.h>
  43. #include <sys/queue.h>
  44. #include <sys/syscallargs.h>
  45. #include <sys/sysctl.h>
  46. #include <sys/systm.h>
  47. #include <sys/uio.h>
  48. struct que *que_create(key_t, struct ucred *, int);
  49. struct que *que_lookup(int);
  50. struct que *que_key_lookup(key_t);
  51. void que_wakewriters(void);
  52. void que_free(struct que *);
  53. struct msg *msg_create(struct que *);
  54. void msg_free(struct msg *);
  55. void msg_enqueue(struct que *, struct msg *, struct proc *);
  56. void msg_dequeue(struct que *, struct msg *, struct proc *);
  57. struct msg *msg_lookup(struct que *, int);
  58. int msg_copyin(struct msg *, const char *, size_t, struct proc *);
  59. int msg_copyout(struct msg *, char *, size_t *, struct proc *);
  60. struct pool sysvmsgpl;
  61. struct msginfo msginfo;
  62. TAILQ_HEAD(, que) msg_queues;
  63. int num_ques;
  64. int num_msgs;
  65. int sequence;
  66. int maxmsgs;
  67. void
  68. msginit(void)
  69. {
  70. msginfo.msgmax = MSGMAX;
  71. msginfo.msgmni = MSGMNI;
  72. msginfo.msgmnb = MSGMNB;
  73. msginfo.msgtql = MSGTQL;
  74. msginfo.msgssz = MSGSSZ;
  75. msginfo.msgseg = MSGSEG;
  76. pool_init(&sysvmsgpl, sizeof(struct msg), 0, 0, PR_WAITOK, "sysvmsgpl",
  77. NULL);
  78. TAILQ_INIT(&msg_queues);
  79. num_ques = 0;
  80. num_msgs = 0;
  81. sequence = 1;
  82. maxmsgs = 0;
  83. }
  84. int
  85. sys_msgctl(struct proc *p, void *v, register_t *retval)
  86. {
  87. struct sys_msgctl_args /* {
  88. syscallarg(int) msqid;
  89. syscallarg(int) cmd;
  90. syscallarg(struct msqid_ds *) buf;
  91. } */ *uap = v;
  92. return (msgctl1(p, SCARG(uap, msqid), SCARG(uap, cmd),
  93. (caddr_t)SCARG(uap, buf), copyin, copyout));
  94. }
  95. int
  96. msgctl1(struct proc *p, int msqid, int cmd, caddr_t buf,
  97. int (*ds_copyin)(const void *, void *, size_t),
  98. int (*ds_copyout)(const void *, void *, size_t))
  99. {
  100. struct msqid_ds tmp;
  101. struct ucred *cred = p->p_ucred;
  102. struct que *que;
  103. int error = 0;
  104. if ((que = que_lookup(msqid)) == NULL)
  105. return (EINVAL);
  106. QREF(que);
  107. switch (cmd) {
  108. case IPC_RMID:
  109. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
  110. goto out;
  111. TAILQ_REMOVE(&msg_queues, que, que_next);
  112. que->que_flags |= MSGQ_DYING;
  113. /* lose interest in the queue and wait for others to too */
  114. if (--que->que_references > 0) {
  115. wakeup(que);
  116. tsleep(&que->que_references, PZERO, "msgqrm", 0);
  117. }
  118. que_free(que);
  119. return (0);
  120. case IPC_SET:
  121. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_M)))
  122. goto out;
  123. if ((error = ds_copyin(buf, &tmp, sizeof(struct msqid_ds))))
  124. goto out;
  125. /* only superuser can bump max bytes in queue */
  126. if (tmp.msg_qbytes > que->msqid_ds.msg_qbytes &&
  127. cred->cr_uid != 0) {
  128. error = EPERM;
  129. goto out;
  130. }
  131. /* restrict max bytes in queue to system limit */
  132. if (tmp.msg_qbytes > msginfo.msgmnb)
  133. tmp.msg_qbytes = msginfo.msgmnb;
  134. /* can't reduce msg_bytes to 0 */
  135. if (tmp.msg_qbytes == 0) {
  136. error = EINVAL; /* non-standard errno! */
  137. goto out;
  138. }
  139. que->msqid_ds.msg_perm.uid = tmp.msg_perm.uid;
  140. que->msqid_ds.msg_perm.gid = tmp.msg_perm.gid;
  141. que->msqid_ds.msg_perm.mode =
  142. (que->msqid_ds.msg_perm.mode & ~0777) |
  143. (tmp.msg_perm.mode & 0777);
  144. que->msqid_ds.msg_qbytes = tmp.msg_qbytes;
  145. que->msqid_ds.msg_ctime = time_second;
  146. break;
  147. case IPC_STAT:
  148. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
  149. goto out;
  150. error = ds_copyout(&que->msqid_ds, buf,
  151. sizeof(struct msqid_ds));
  152. break;
  153. default:
  154. error = EINVAL;
  155. break;
  156. }
  157. out:
  158. QRELE(que);
  159. return (error);
  160. }
  161. int
  162. sys_msgget(struct proc *p, void *v, register_t *retval)
  163. {
  164. struct sys_msgget_args /* {
  165. syscallarg(key_t) key;
  166. syscallarg(int) msgflg;
  167. } */ *uap = v;
  168. struct ucred *cred = p->p_ucred;
  169. struct que *que;
  170. key_t key = SCARG(uap, key);
  171. int msgflg = SCARG(uap, msgflg);
  172. int error = 0;
  173. again:
  174. if (key != IPC_PRIVATE) {
  175. que = que_key_lookup(key);
  176. if (que) {
  177. if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL))
  178. return (EEXIST);
  179. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm,
  180. msgflg & 0700)))
  181. return (error);
  182. goto found;
  183. }
  184. }
  185. /* don't create a new message queue if the caller doesn't want to */
  186. if (key != IPC_PRIVATE && !(msgflg & IPC_CREAT))
  187. return (ENOENT);
  188. /* enforce limits on the maximum number of message queues */
  189. if (num_ques >= msginfo.msgmni)
  190. return (ENOSPC);
  191. /*
  192. * if que_create returns NULL, it means that a que with an identical
  193. * key was created while this process was sleeping, so start over
  194. */
  195. if ((que = que_create(key, cred, msgflg & 0777)) == NULL)
  196. goto again;
  197. found:
  198. *retval = IXSEQ_TO_IPCID(que->que_ix, que->msqid_ds.msg_perm);
  199. return (error);
  200. }
  201. #define MSGQ_SPACE(q) ((q)->msqid_ds.msg_qbytes - (q)->msqid_ds.msg_cbytes)
  202. int
  203. sys_msgsnd(struct proc *p, void *v, register_t *retval)
  204. {
  205. struct sys_msgsnd_args /* {
  206. syscallarg(int) msqid;
  207. syscallarg(const void *) msgp;
  208. syscallarg(size_t) msgsz;
  209. syscallarg(int) msgflg;
  210. } */ *uap = v;
  211. struct ucred *cred = p->p_ucred;
  212. struct que *que;
  213. struct msg *msg;
  214. size_t msgsz = SCARG(uap, msgsz);
  215. int error;
  216. if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
  217. return (EINVAL);
  218. if (msgsz > que->msqid_ds.msg_qbytes || msgsz > msginfo.msgmax)
  219. return (EINVAL);
  220. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_W)))
  221. return (error);
  222. QREF(que);
  223. while (MSGQ_SPACE(que) < msgsz || num_msgs >= msginfo.msgtql) {
  224. if (SCARG(uap, msgflg) & IPC_NOWAIT) {
  225. error = EAGAIN;
  226. goto out;
  227. }
  228. /* notify world that process may wedge here */
  229. if (num_msgs >= msginfo.msgtql)
  230. maxmsgs = 1;
  231. que->que_flags |= MSGQ_WRITERS;
  232. if ((error = tsleep(que, PZERO|PCATCH, "msgwait", 0)))
  233. goto out;
  234. if (que->que_flags & MSGQ_DYING) {
  235. error = EIDRM;
  236. goto out;
  237. }
  238. }
  239. /* if msg_create returns NULL, the queue is being removed */
  240. if ((msg = msg_create(que)) == NULL) {
  241. error = EIDRM;
  242. goto out;
  243. }
  244. /* msg_copyin frees msg on error */
  245. if ((error = msg_copyin(msg, (const char *)SCARG(uap, msgp), msgsz, p)))
  246. goto out;
  247. msg_enqueue(que, msg, p);
  248. if (que->que_flags & MSGQ_READERS) {
  249. que->que_flags &= ~MSGQ_READERS;
  250. wakeup(que);
  251. }
  252. if (que->que_flags & MSGQ_DYING) {
  253. error = EIDRM;
  254. wakeup(que);
  255. }
  256. out:
  257. QRELE(que);
  258. return (error);
  259. }
  260. int
  261. sys_msgrcv(struct proc *p, void *v, register_t *retval)
  262. {
  263. struct sys_msgrcv_args /* {
  264. syscallarg(int) msqid;
  265. syscallarg(void *) msgp;
  266. syscallarg(size_t) msgsz;
  267. syscallarg(long) msgtyp;
  268. syscallarg(int) msgflg;
  269. } */ *uap = v;
  270. struct ucred *cred = p->p_ucred;
  271. char *msgp = SCARG(uap, msgp);
  272. struct que *que;
  273. struct msg *msg;
  274. size_t msgsz = SCARG(uap, msgsz);
  275. long msgtyp = SCARG(uap, msgtyp);
  276. int error;
  277. if ((que = que_lookup(SCARG(uap, msqid))) == NULL)
  278. return (EINVAL);
  279. if ((error = ipcperm(cred, &que->msqid_ds.msg_perm, IPC_R)))
  280. return (error);
  281. QREF(que);
  282. /* msg_lookup handles matching; sleeping gets handled here */
  283. while ((msg = msg_lookup(que, msgtyp)) == NULL) {
  284. if (SCARG(uap, msgflg) & IPC_NOWAIT) {
  285. error = ENOMSG;
  286. goto out;
  287. }
  288. que->que_flags |= MSGQ_READERS;
  289. if ((error = tsleep(que, PZERO|PCATCH, "msgwait", 0)))
  290. goto out;
  291. /* make sure the queue still alive */
  292. if (que->que_flags & MSGQ_DYING) {
  293. error = EIDRM;
  294. goto out;
  295. }
  296. }
  297. /* if msg_copyout fails, keep the message around so it isn't lost */
  298. if ((error = msg_copyout(msg, msgp, &msgsz, p)))
  299. goto out;
  300. msg_dequeue(que, msg, p);
  301. msg_free(msg);
  302. if (que->que_flags & MSGQ_WRITERS) {
  303. que->que_flags &= ~MSGQ_WRITERS;
  304. wakeup(que);
  305. }
  306. /* ensure processes waiting on the global limit don't wedge */
  307. if (maxmsgs) {
  308. maxmsgs = 0;
  309. que_wakewriters();
  310. }
  311. *retval = msgsz;
  312. out:
  313. QRELE(que);
  314. return (error);
  315. }
  316. /*
  317. * que management functions
  318. */
  319. struct que *
  320. que_create(key_t key, struct ucred *cred, int mode)
  321. {
  322. struct que *que, *que2;
  323. int nextix = 1;
  324. que = malloc(sizeof(*que), M_TEMP, M_WAIT|M_ZERO);
  325. /* if malloc slept, a queue with the same key may have been created */
  326. if (que_key_lookup(key)) {
  327. free(que, M_TEMP, 0);
  328. return (NULL);
  329. }
  330. /* find next available "index" */
  331. TAILQ_FOREACH(que2, &msg_queues, que_next) {
  332. if (nextix < que2->que_ix)
  333. break;
  334. nextix = que2->que_ix + 1;
  335. }
  336. que->que_ix = nextix;
  337. que->msqid_ds.msg_perm.key = key;
  338. que->msqid_ds.msg_perm.cuid = cred->cr_uid;
  339. que->msqid_ds.msg_perm.uid = cred->cr_uid;
  340. que->msqid_ds.msg_perm.cgid = cred->cr_gid;
  341. que->msqid_ds.msg_perm.gid = cred->cr_gid;
  342. que->msqid_ds.msg_perm.mode = mode & 0777;
  343. que->msqid_ds.msg_perm.seq = ++sequence & 0x7fff;
  344. que->msqid_ds.msg_qbytes = msginfo.msgmnb;
  345. que->msqid_ds.msg_ctime = time_second;
  346. TAILQ_INIT(&que->que_msgs);
  347. /* keep queues in "index" order */
  348. if (que2)
  349. TAILQ_INSERT_BEFORE(que2, que, que_next);
  350. else
  351. TAILQ_INSERT_TAIL(&msg_queues, que, que_next);
  352. num_ques++;
  353. return (que);
  354. }
  355. struct que *
  356. que_lookup(int id)
  357. {
  358. struct que *que;
  359. TAILQ_FOREACH(que, &msg_queues, que_next)
  360. if (que->que_ix == IPCID_TO_IX(id))
  361. break;
  362. /* don't return queues marked for removal */
  363. if (que && que->que_flags & MSGQ_DYING)
  364. return (NULL);
  365. return (que);
  366. }
  367. struct que *
  368. que_key_lookup(key_t key)
  369. {
  370. struct que *que;
  371. if (key == IPC_PRIVATE)
  372. return (NULL);
  373. TAILQ_FOREACH(que, &msg_queues, que_next)
  374. if (que->msqid_ds.msg_perm.key == key)
  375. break;
  376. /* don't return queues marked for removal */
  377. if (que && que->que_flags & MSGQ_DYING)
  378. return (NULL);
  379. return (que);
  380. }
  381. void
  382. que_wakewriters(void)
  383. {
  384. struct que *que;
  385. TAILQ_FOREACH(que, &msg_queues, que_next) {
  386. if (que->que_flags & MSGQ_WRITERS) {
  387. que->que_flags &= ~MSGQ_WRITERS;
  388. wakeup(que);
  389. }
  390. }
  391. }
  392. void
  393. que_free(struct que *que)
  394. {
  395. struct msg *msg;
  396. #ifdef DIAGNOSTIC
  397. if (que->que_references > 0)
  398. panic("freeing message queue with active references");
  399. #endif
  400. while ((msg = TAILQ_FIRST(&que->que_msgs))) {
  401. TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
  402. msg_free(msg);
  403. }
  404. free(que, M_TEMP, 0);
  405. num_ques--;
  406. }
  407. /*
  408. * msg management functions
  409. */
  410. struct msg *
  411. msg_create(struct que *que)
  412. {
  413. struct msg *msg;
  414. msg = pool_get(&sysvmsgpl, PR_WAITOK|PR_ZERO);
  415. /* if the queue has died during allocation, return NULL */
  416. if (que->que_flags & MSGQ_DYING) {
  417. pool_put(&sysvmsgpl, msg);
  418. wakeup(que);
  419. return(NULL);
  420. }
  421. num_msgs++;
  422. return (msg);
  423. }
  424. struct msg *
  425. msg_lookup(struct que *que, int msgtyp)
  426. {
  427. struct msg *msg;
  428. /*
  429. * Three different matches are performed based on the value of msgtyp:
  430. * 1) msgtyp > 0 => match exactly
  431. * 2) msgtyp = 0 => match any
  432. * 3) msgtyp < 0 => match any up to absolute value of msgtyp
  433. */
  434. TAILQ_FOREACH(msg, &que->que_msgs, msg_next)
  435. if (msgtyp == 0 || msgtyp == msg->msg_type ||
  436. (msgtyp < 0 && -msgtyp <= msg->msg_type))
  437. break;
  438. return (msg);
  439. }
  440. void
  441. msg_free(struct msg *msg)
  442. {
  443. m_freem(msg->msg_data);
  444. pool_put(&sysvmsgpl, msg);
  445. num_msgs--;
  446. }
  447. void
  448. msg_enqueue(struct que *que, struct msg *msg, struct proc *p)
  449. {
  450. que->msqid_ds.msg_cbytes += msg->msg_len;
  451. que->msqid_ds.msg_qnum++;
  452. que->msqid_ds.msg_lspid = p->p_p->ps_pid;
  453. que->msqid_ds.msg_stime = time_second;
  454. TAILQ_INSERT_TAIL(&que->que_msgs, msg, msg_next);
  455. }
  456. void
  457. msg_dequeue(struct que *que, struct msg *msg, struct proc *p)
  458. {
  459. que->msqid_ds.msg_cbytes -= msg->msg_len;
  460. que->msqid_ds.msg_qnum--;
  461. que->msqid_ds.msg_lrpid = p->p_p->ps_pid;
  462. que->msqid_ds.msg_rtime = time_second;
  463. TAILQ_REMOVE(&que->que_msgs, msg, msg_next);
  464. }
  465. /*
  466. * The actual I/O routines. A note concerning the layout of SysV msg buffers:
  467. *
  468. * The data to be copied is laid out as a single userspace buffer, with a
  469. * long preceding an opaque buffer of len bytes. The long value ends
  470. * up being the message type, which needs to be copied separately from
  471. * the buffer data, which is stored in in mbufs.
  472. */
  473. int
  474. msg_copyin(struct msg *msg, const char *ubuf, size_t len, struct proc *p)
  475. {
  476. struct mbuf **mm, *m;
  477. size_t xfer;
  478. int error;
  479. if (msg == NULL)
  480. panic ("msg NULL");
  481. if ((error = copyin(ubuf, &msg->msg_type, sizeof(long)))) {
  482. msg_free(msg);
  483. return (error);
  484. }
  485. if (msg->msg_type < 0) {
  486. msg_free(msg);
  487. return (EINVAL);
  488. }
  489. ubuf += sizeof(long);
  490. msg->msg_len = 0;
  491. mm = &msg->msg_data;
  492. while (msg->msg_len < len) {
  493. m = m_get(M_WAIT, MT_DATA);
  494. if (len >= MINCLSIZE) {
  495. MCLGET(m, M_WAIT);
  496. xfer = min(len, MCLBYTES);
  497. } else {
  498. xfer = min(len, MLEN);
  499. }
  500. m->m_len = xfer;
  501. msg->msg_len += xfer;
  502. *mm = m;
  503. mm = &m->m_next;
  504. }
  505. for (m = msg->msg_data; m; m = m->m_next) {
  506. if ((error = copyin(ubuf, mtod(m, void *), m->m_len))) {
  507. msg_free(msg);
  508. return (error);
  509. }
  510. ubuf += m->m_len;
  511. }
  512. return (0);
  513. }
  514. int
  515. msg_copyout(struct msg *msg, char *ubuf, size_t *len, struct proc *p)
  516. {
  517. struct mbuf *m;
  518. size_t xfer;
  519. int error;
  520. #ifdef DIAGNOSTIC
  521. if (msg->msg_len > MSGMAX)
  522. panic("SysV message longer than MSGMAX");
  523. #endif
  524. /* silently truncate messages too large for user buffer */
  525. xfer = min(*len, msg->msg_len);
  526. if ((error = copyout(&msg->msg_type, ubuf, sizeof(long))))
  527. return (error);
  528. ubuf += sizeof(long);
  529. *len = xfer;
  530. for (m = msg->msg_data; m; m = m->m_next) {
  531. if ((error = copyout(mtod(m, void *), ubuf, m->m_len)))
  532. return (error);
  533. ubuf += m->m_len;
  534. }
  535. return (0);
  536. }
  537. int
  538. sysctl_sysvmsg(int *name, u_int namelen, void *where, size_t *sizep)
  539. {
  540. struct msg_sysctl_info *info;
  541. struct que *que;
  542. size_t infolen;
  543. int error;
  544. switch (*name) {
  545. case KERN_SYSVIPC_MSG_INFO:
  546. if (namelen != 1)
  547. return (ENOTDIR);
  548. /*
  549. * The userland ipcs(1) utility expects to be able
  550. * to iterate over at least msginfo.msgmni queues,
  551. * even if those queues don't exist. This is an
  552. * artifact of the previous implementation of
  553. * message queues; for now, emulate this behavior
  554. * until a more thorough fix can be made.
  555. */
  556. infolen = sizeof(msginfo) +
  557. msginfo.msgmni * sizeof(struct msqid_ds);
  558. if (where == NULL) {
  559. *sizep = infolen;
  560. return (0);
  561. }
  562. /*
  563. * More special-casing due to previous implementation:
  564. * if the caller just wants the msginfo struct, then
  565. * sizep will point to the value sizeof(struct msginfo).
  566. * In that case, only copy out the msginfo struct to
  567. * the caller.
  568. */
  569. if (*sizep == sizeof(struct msginfo))
  570. return (copyout(&msginfo, where, sizeof(msginfo)));
  571. info = malloc(infolen, M_TEMP, M_WAIT|M_ZERO);
  572. /* if the malloc slept, this may have changed */
  573. infolen = sizeof(msginfo) +
  574. msginfo.msgmni * sizeof(struct msqid_ds);
  575. if (*sizep < infolen) {
  576. free(info, M_TEMP, 0);
  577. return (ENOMEM);
  578. }
  579. memcpy(&info->msginfo, &msginfo, sizeof(struct msginfo));
  580. /*
  581. * Special case #3: the previous array-based implementation
  582. * exported the array indices and userland has come to rely
  583. * upon these indices, so keep behavior consisitent.
  584. */
  585. TAILQ_FOREACH(que, &msg_queues, que_next)
  586. memcpy(&info->msgids[que->que_ix], &que->msqid_ds,
  587. sizeof(struct msqid_ds));
  588. error = copyout(info, where, infolen);
  589. free(info, M_TEMP, 0);
  590. return (error);
  591. default:
  592. return (EINVAL);
  593. }
  594. }