msgque.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <linux/msg.h>
  6. #include <fcntl.h>
  7. #define MAX_MSG_SIZE 32
  8. struct msg1 {
  9. int msize;
  10. long mtype;
  11. char mtext[MAX_MSG_SIZE];
  12. };
  13. #define TEST_STRING "Test sysv5 msg"
  14. #define MSG_TYPE 1
  15. #define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
  16. #define ANOTHER_MSG_TYPE 26538
  17. struct msgque_data {
  18. key_t key;
  19. int msq_id;
  20. int qbytes;
  21. int qnum;
  22. int mode;
  23. struct msg1 *messages;
  24. };
  25. int restore_queue(struct msgque_data *msgque)
  26. {
  27. int fd, ret, id, i;
  28. char buf[32];
  29. fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
  30. if (fd == -1) {
  31. printf("Failed to open /proc/sys/kernel/msg_next_id\n");
  32. return -errno;
  33. }
  34. sprintf(buf, "%d", msgque->msq_id);
  35. ret = write(fd, buf, strlen(buf));
  36. if (ret != strlen(buf)) {
  37. printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
  38. return -errno;
  39. }
  40. id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
  41. if (id == -1) {
  42. printf("Failed to create queue\n");
  43. return -errno;
  44. }
  45. if (id != msgque->msq_id) {
  46. printf("Restored queue has wrong id (%d instead of %d)\n",
  47. id, msgque->msq_id);
  48. ret = -EFAULT;
  49. goto destroy;
  50. }
  51. for (i = 0; i < msgque->qnum; i++) {
  52. if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
  53. msgque->messages[i].msize, IPC_NOWAIT) != 0) {
  54. printf("msgsnd failed (%m)\n");
  55. ret = -errno;
  56. goto destroy;
  57. };
  58. }
  59. return 0;
  60. destroy:
  61. if (msgctl(id, IPC_RMID, 0))
  62. printf("Failed to destroy queue: %d\n", -errno);
  63. return ret;
  64. }
  65. int check_and_destroy_queue(struct msgque_data *msgque)
  66. {
  67. struct msg1 message;
  68. int cnt = 0, ret;
  69. while (1) {
  70. ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
  71. 0, IPC_NOWAIT);
  72. if (ret < 0) {
  73. if (errno == ENOMSG)
  74. break;
  75. printf("Failed to read IPC message: %m\n");
  76. ret = -errno;
  77. goto err;
  78. }
  79. if (ret != msgque->messages[cnt].msize) {
  80. printf("Wrong message size: %d (expected %d)\n", ret,
  81. msgque->messages[cnt].msize);
  82. ret = -EINVAL;
  83. goto err;
  84. }
  85. if (message.mtype != msgque->messages[cnt].mtype) {
  86. printf("Wrong message type\n");
  87. ret = -EINVAL;
  88. goto err;
  89. }
  90. if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
  91. printf("Wrong message content\n");
  92. ret = -EINVAL;
  93. goto err;
  94. }
  95. cnt++;
  96. }
  97. if (cnt != msgque->qnum) {
  98. printf("Wrong message number\n");
  99. ret = -EINVAL;
  100. goto err;
  101. }
  102. ret = 0;
  103. err:
  104. if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
  105. printf("Failed to destroy queue: %d\n", -errno);
  106. return -errno;
  107. }
  108. return ret;
  109. }
  110. int dump_queue(struct msgque_data *msgque)
  111. {
  112. struct msqid64_ds ds;
  113. int kern_id;
  114. int i, ret;
  115. for (kern_id = 0; kern_id < 256; kern_id++) {
  116. ret = msgctl(kern_id, MSG_STAT, &ds);
  117. if (ret < 0) {
  118. if (errno == -EINVAL)
  119. continue;
  120. printf("Failed to get stats for IPC queue with id %d\n",
  121. kern_id);
  122. return -errno;
  123. }
  124. if (ret == msgque->msq_id)
  125. break;
  126. }
  127. msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
  128. if (msgque->messages == NULL) {
  129. printf("Failed to get stats for IPC queue\n");
  130. return -ENOMEM;
  131. }
  132. msgque->qnum = ds.msg_qnum;
  133. msgque->mode = ds.msg_perm.mode;
  134. msgque->qbytes = ds.msg_qbytes;
  135. for (i = 0; i < msgque->qnum; i++) {
  136. ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
  137. MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
  138. if (ret < 0) {
  139. printf("Failed to copy IPC message: %m (%d)\n", errno);
  140. return -errno;
  141. }
  142. msgque->messages[i].msize = ret;
  143. }
  144. return 0;
  145. }
  146. int fill_msgque(struct msgque_data *msgque)
  147. {
  148. struct msg1 msgbuf;
  149. msgbuf.mtype = MSG_TYPE;
  150. memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
  151. if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
  152. IPC_NOWAIT) != 0) {
  153. printf("First message send failed (%m)\n");
  154. return -errno;
  155. };
  156. msgbuf.mtype = ANOTHER_MSG_TYPE;
  157. memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
  158. if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
  159. IPC_NOWAIT) != 0) {
  160. printf("Second message send failed (%m)\n");
  161. return -errno;
  162. };
  163. return 0;
  164. }
  165. int main(int argc, char **argv)
  166. {
  167. int msg, pid, err;
  168. struct msgque_data msgque;
  169. msgque.key = ftok(argv[0], 822155650);
  170. if (msgque.key == -1) {
  171. printf("Can't make key\n");
  172. return -errno;
  173. }
  174. msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
  175. if (msgque.msq_id == -1) {
  176. printf("Can't create queue\n");
  177. goto err_out;
  178. }
  179. err = fill_msgque(&msgque);
  180. if (err) {
  181. printf("Failed to fill queue\n");
  182. goto err_destroy;
  183. }
  184. err = dump_queue(&msgque);
  185. if (err) {
  186. printf("Failed to dump queue\n");
  187. goto err_destroy;
  188. }
  189. err = check_and_destroy_queue(&msgque);
  190. if (err) {
  191. printf("Failed to check and destroy queue\n");
  192. goto err_out;
  193. }
  194. err = restore_queue(&msgque);
  195. if (err) {
  196. printf("Failed to restore queue\n");
  197. goto err_destroy;
  198. }
  199. err = check_and_destroy_queue(&msgque);
  200. if (err) {
  201. printf("Failed to test queue\n");
  202. goto err_out;
  203. }
  204. return 0;
  205. err_destroy:
  206. if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
  207. printf("Failed to destroy queue: %d\n", -errno);
  208. return -errno;
  209. }
  210. err_out:
  211. return err;
  212. }