0001
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 }