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