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