root/tools/testing/selftests/ipc/msgque.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. restore_queue
  2. check_and_destroy_queue
  3. dump_queue
  4. fill_msgque
  5. main

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

/* [<][>][^][v][top][bottom][index][help] */