Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #define _GNU_SOURCE
0003 #include <stdlib.h>
0004 #include <stdio.h>
0005 #include <string.h>
0006 #include <errno.h>
0007 #include <sys/msg.h>
0008 #include <fcntl.h>
0009 
0010 #include "../kselftest.h"
0011 
0012 #define MAX_MSG_SIZE        32
0013 
0014 struct msg1 {
0015     int msize;
0016     long mtype;
0017     char mtext[MAX_MSG_SIZE];
0018 };
0019 
0020 #define TEST_STRING "Test sysv5 msg"
0021 #define MSG_TYPE 1
0022 
0023 #define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
0024 #define ANOTHER_MSG_TYPE 26538
0025 
0026 struct msgque_data {
0027     key_t key;
0028     int msq_id;
0029     int qbytes;
0030     int qnum;
0031     int mode;
0032     struct msg1 *messages;
0033 };
0034 
0035 int restore_queue(struct msgque_data *msgque)
0036 {
0037     int fd, ret, id, i;
0038     char buf[32];
0039 
0040     fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
0041     if (fd == -1) {
0042         printf("Failed to open /proc/sys/kernel/msg_next_id\n");
0043         return -errno;
0044     }
0045     sprintf(buf, "%d", msgque->msq_id);
0046 
0047     ret = write(fd, buf, strlen(buf));
0048     if (ret != strlen(buf)) {
0049         printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
0050         return -errno;
0051     }
0052 
0053     id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
0054     if (id == -1) {
0055         printf("Failed to create queue\n");
0056         return -errno;
0057     }
0058 
0059     if (id != msgque->msq_id) {
0060         printf("Restored queue has wrong id (%d instead of %d)\n",
0061                             id, msgque->msq_id);
0062         ret = -EFAULT;
0063         goto destroy;
0064     }
0065 
0066     for (i = 0; i < msgque->qnum; i++) {
0067         if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
0068                msgque->messages[i].msize, IPC_NOWAIT) != 0) {
0069             printf("msgsnd failed (%m)\n");
0070             ret = -errno;
0071             goto destroy;
0072         }
0073     }
0074     return 0;
0075 
0076 destroy:
0077     if (msgctl(id, IPC_RMID, NULL))
0078         printf("Failed to destroy queue: %d\n", -errno);
0079     return ret;
0080 }
0081 
0082 int check_and_destroy_queue(struct msgque_data *msgque)
0083 {
0084     struct msg1 message;
0085     int cnt = 0, ret;
0086 
0087     while (1) {
0088         ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
0089                 0, IPC_NOWAIT);
0090         if (ret < 0) {
0091             if (errno == ENOMSG)
0092                 break;
0093             printf("Failed to read IPC message: %m\n");
0094             ret = -errno;
0095             goto err;
0096         }
0097         if (ret != msgque->messages[cnt].msize) {
0098             printf("Wrong message size: %d (expected %d)\n", ret,
0099                         msgque->messages[cnt].msize);
0100             ret = -EINVAL;
0101             goto err;
0102         }
0103         if (message.mtype != msgque->messages[cnt].mtype) {
0104             printf("Wrong message type\n");
0105             ret = -EINVAL;
0106             goto err;
0107         }
0108         if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
0109             printf("Wrong message content\n");
0110             ret = -EINVAL;
0111             goto err;
0112         }
0113         cnt++;
0114     }
0115 
0116     if (cnt != msgque->qnum) {
0117         printf("Wrong message number\n");
0118         ret = -EINVAL;
0119         goto err;
0120     }
0121 
0122     ret = 0;
0123 err:
0124     if (msgctl(msgque->msq_id, IPC_RMID, NULL)) {
0125         printf("Failed to destroy queue: %d\n", -errno);
0126         return -errno;
0127     }
0128     return ret;
0129 }
0130 
0131 int dump_queue(struct msgque_data *msgque)
0132 {
0133     struct msqid_ds ds;
0134     int kern_id;
0135     int i, ret;
0136 
0137     for (kern_id = 0; kern_id < 256; kern_id++) {
0138         ret = msgctl(kern_id, MSG_STAT, &ds);
0139         if (ret < 0) {
0140             if (errno == EINVAL)
0141                 continue;
0142             printf("Failed to get stats for IPC queue with id %d\n",
0143                     kern_id);
0144             return -errno;
0145         }
0146 
0147         if (ret == msgque->msq_id)
0148             break;
0149     }
0150 
0151     msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
0152     if (msgque->messages == NULL) {
0153         printf("Failed to get stats for IPC queue\n");
0154         return -ENOMEM;
0155     }
0156 
0157     msgque->qnum = ds.msg_qnum;
0158     msgque->mode = ds.msg_perm.mode;
0159     msgque->qbytes = ds.msg_qbytes;
0160 
0161     for (i = 0; i < msgque->qnum; i++) {
0162         ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
0163                 MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
0164         if (ret < 0) {
0165             printf("Failed to copy IPC message: %m (%d)\n", errno);
0166             return -errno;
0167         }
0168         msgque->messages[i].msize = ret;
0169     }
0170     return 0;
0171 }
0172 
0173 int fill_msgque(struct msgque_data *msgque)
0174 {
0175     struct msg1 msgbuf;
0176 
0177     msgbuf.mtype = MSG_TYPE;
0178     memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
0179     if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
0180                 IPC_NOWAIT) != 0) {
0181         printf("First message send failed (%m)\n");
0182         return -errno;
0183     }
0184 
0185     msgbuf.mtype = ANOTHER_MSG_TYPE;
0186     memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
0187     if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
0188                 IPC_NOWAIT) != 0) {
0189         printf("Second message send failed (%m)\n");
0190         return -errno;
0191     }
0192     return 0;
0193 }
0194 
0195 int main(int argc, char **argv)
0196 {
0197     int msg, pid, err;
0198     struct msgque_data msgque;
0199 
0200     if (getuid() != 0)
0201         return ksft_exit_skip(
0202                 "Please run the test as root - Exiting.\n");
0203 
0204     msgque.key = ftok(argv[0], 822155650);
0205     if (msgque.key == -1) {
0206         printf("Can't make key: %d\n", -errno);
0207         return ksft_exit_fail();
0208     }
0209 
0210     msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
0211     if (msgque.msq_id == -1) {
0212         err = -errno;
0213         printf("Can't create queue: %d\n", err);
0214         goto err_out;
0215     }
0216 
0217     err = fill_msgque(&msgque);
0218     if (err) {
0219         printf("Failed to fill queue: %d\n", err);
0220         goto err_destroy;
0221     }
0222 
0223     err = dump_queue(&msgque);
0224     if (err) {
0225         printf("Failed to dump queue: %d\n", err);
0226         goto err_destroy;
0227     }
0228 
0229     err = check_and_destroy_queue(&msgque);
0230     if (err) {
0231         printf("Failed to check and destroy queue: %d\n", err);
0232         goto err_out;
0233     }
0234 
0235     err = restore_queue(&msgque);
0236     if (err) {
0237         printf("Failed to restore queue: %d\n", err);
0238         goto err_destroy;
0239     }
0240 
0241     err = check_and_destroy_queue(&msgque);
0242     if (err) {
0243         printf("Failed to test queue: %d\n", err);
0244         goto err_out;
0245     }
0246     return ksft_exit_pass();
0247 
0248 err_destroy:
0249     if (msgctl(msgque.msq_id, IPC_RMID, NULL)) {
0250         printf("Failed to destroy queue: %d\n", -errno);
0251         return ksft_exit_fail();
0252     }
0253 err_out:
0254     return ksft_exit_fail();
0255 }