brintos

brintos / linux-shallow public Read only

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