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