Home | History | Annotate | Download | only in ipc
      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 
     12 struct 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 
     24 struct 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 
     33 int 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 
     74 destroy:
     75 	if (msgctl(id, IPC_RMID, 0))
     76 		printf("Failed to destroy queue: %d\n", -errno);
     77 	return ret;
     78 }
     79 
     80 int 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;
    121 err:
    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 
    129 int 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 
    171 int 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 
    193 int 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 
    247 err_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 	}
    252 err_out:
    253 	return ksft_exit_fail();
    254 }
    255