linux/tools/testing/selftests/ipc/msgque.c
<<
>>
Prefs
   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
  14struct 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
  26struct 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
  35int 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
  76destroy:
  77        if (msgctl(id, IPC_RMID, NULL))
  78                printf("Failed to destroy queue: %d\n", -errno);
  79        return ret;
  80}
  81
  82int 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;
 123err:
 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
 131int 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
 173int 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
 195int 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
 248err_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        }
 253err_out:
 254        return ksft_exit_fail();
 255}
 256