162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define _GNU_SOURCE 362306a36Sopenharmony_ci#include <stdlib.h> 462306a36Sopenharmony_ci#include <stdio.h> 562306a36Sopenharmony_ci#include <string.h> 662306a36Sopenharmony_ci#include <errno.h> 762306a36Sopenharmony_ci#include <sys/msg.h> 862306a36Sopenharmony_ci#include <fcntl.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "../kselftest.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define MAX_MSG_SIZE 32 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistruct msg1 { 1562306a36Sopenharmony_ci int msize; 1662306a36Sopenharmony_ci long mtype; 1762306a36Sopenharmony_ci char mtext[MAX_MSG_SIZE]; 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define TEST_STRING "Test sysv5 msg" 2162306a36Sopenharmony_ci#define MSG_TYPE 1 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define ANOTHER_TEST_STRING "Yet another test sysv5 msg" 2462306a36Sopenharmony_ci#define ANOTHER_MSG_TYPE 26538 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct msgque_data { 2762306a36Sopenharmony_ci key_t key; 2862306a36Sopenharmony_ci int msq_id; 2962306a36Sopenharmony_ci int qbytes; 3062306a36Sopenharmony_ci int qnum; 3162306a36Sopenharmony_ci int mode; 3262306a36Sopenharmony_ci struct msg1 *messages; 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ciint restore_queue(struct msgque_data *msgque) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci int fd, ret, id, i; 3862306a36Sopenharmony_ci char buf[32]; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY); 4162306a36Sopenharmony_ci if (fd == -1) { 4262306a36Sopenharmony_ci printf("Failed to open /proc/sys/kernel/msg_next_id\n"); 4362306a36Sopenharmony_ci return -errno; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci sprintf(buf, "%d", msgque->msq_id); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci ret = write(fd, buf, strlen(buf)); 4862306a36Sopenharmony_ci if (ret != strlen(buf)) { 4962306a36Sopenharmony_ci printf("Failed to write to /proc/sys/kernel/msg_next_id\n"); 5062306a36Sopenharmony_ci return -errno; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL); 5462306a36Sopenharmony_ci if (id == -1) { 5562306a36Sopenharmony_ci printf("Failed to create queue\n"); 5662306a36Sopenharmony_ci return -errno; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (id != msgque->msq_id) { 6062306a36Sopenharmony_ci printf("Restored queue has wrong id (%d instead of %d)\n", 6162306a36Sopenharmony_ci id, msgque->msq_id); 6262306a36Sopenharmony_ci ret = -EFAULT; 6362306a36Sopenharmony_ci goto destroy; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci for (i = 0; i < msgque->qnum; i++) { 6762306a36Sopenharmony_ci if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype, 6862306a36Sopenharmony_ci msgque->messages[i].msize, IPC_NOWAIT) != 0) { 6962306a36Sopenharmony_ci printf("msgsnd failed (%m)\n"); 7062306a36Sopenharmony_ci ret = -errno; 7162306a36Sopenharmony_ci goto destroy; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cidestroy: 7762306a36Sopenharmony_ci if (msgctl(id, IPC_RMID, NULL)) 7862306a36Sopenharmony_ci printf("Failed to destroy queue: %d\n", -errno); 7962306a36Sopenharmony_ci return ret; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint check_and_destroy_queue(struct msgque_data *msgque) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct msg1 message; 8562306a36Sopenharmony_ci int cnt = 0, ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci while (1) { 8862306a36Sopenharmony_ci ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE, 8962306a36Sopenharmony_ci 0, IPC_NOWAIT); 9062306a36Sopenharmony_ci if (ret < 0) { 9162306a36Sopenharmony_ci if (errno == ENOMSG) 9262306a36Sopenharmony_ci break; 9362306a36Sopenharmony_ci printf("Failed to read IPC message: %m\n"); 9462306a36Sopenharmony_ci ret = -errno; 9562306a36Sopenharmony_ci goto err; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci if (ret != msgque->messages[cnt].msize) { 9862306a36Sopenharmony_ci printf("Wrong message size: %d (expected %d)\n", ret, 9962306a36Sopenharmony_ci msgque->messages[cnt].msize); 10062306a36Sopenharmony_ci ret = -EINVAL; 10162306a36Sopenharmony_ci goto err; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci if (message.mtype != msgque->messages[cnt].mtype) { 10462306a36Sopenharmony_ci printf("Wrong message type\n"); 10562306a36Sopenharmony_ci ret = -EINVAL; 10662306a36Sopenharmony_ci goto err; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) { 10962306a36Sopenharmony_ci printf("Wrong message content\n"); 11062306a36Sopenharmony_ci ret = -EINVAL; 11162306a36Sopenharmony_ci goto err; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci cnt++; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (cnt != msgque->qnum) { 11762306a36Sopenharmony_ci printf("Wrong message number\n"); 11862306a36Sopenharmony_ci ret = -EINVAL; 11962306a36Sopenharmony_ci goto err; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci ret = 0; 12362306a36Sopenharmony_cierr: 12462306a36Sopenharmony_ci if (msgctl(msgque->msq_id, IPC_RMID, NULL)) { 12562306a36Sopenharmony_ci printf("Failed to destroy queue: %d\n", -errno); 12662306a36Sopenharmony_ci return -errno; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci return ret; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciint dump_queue(struct msgque_data *msgque) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct msqid_ds ds; 13462306a36Sopenharmony_ci int kern_id; 13562306a36Sopenharmony_ci int i, ret; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (kern_id = 0; kern_id < 256; kern_id++) { 13862306a36Sopenharmony_ci ret = msgctl(kern_id, MSG_STAT, &ds); 13962306a36Sopenharmony_ci if (ret < 0) { 14062306a36Sopenharmony_ci if (errno == EINVAL) 14162306a36Sopenharmony_ci continue; 14262306a36Sopenharmony_ci printf("Failed to get stats for IPC queue with id %d\n", 14362306a36Sopenharmony_ci kern_id); 14462306a36Sopenharmony_ci return -errno; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (ret == msgque->msq_id) 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum); 15262306a36Sopenharmony_ci if (msgque->messages == NULL) { 15362306a36Sopenharmony_ci printf("Failed to get stats for IPC queue\n"); 15462306a36Sopenharmony_ci return -ENOMEM; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci msgque->qnum = ds.msg_qnum; 15862306a36Sopenharmony_ci msgque->mode = ds.msg_perm.mode; 15962306a36Sopenharmony_ci msgque->qbytes = ds.msg_qbytes; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci for (i = 0; i < msgque->qnum; i++) { 16262306a36Sopenharmony_ci ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype, 16362306a36Sopenharmony_ci MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY); 16462306a36Sopenharmony_ci if (ret < 0) { 16562306a36Sopenharmony_ci printf("Failed to copy IPC message: %m (%d)\n", errno); 16662306a36Sopenharmony_ci return -errno; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci msgque->messages[i].msize = ret; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci return 0; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ciint fill_msgque(struct msgque_data *msgque) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct msg1 msgbuf; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci msgbuf.mtype = MSG_TYPE; 17862306a36Sopenharmony_ci memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING)); 17962306a36Sopenharmony_ci if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING), 18062306a36Sopenharmony_ci IPC_NOWAIT) != 0) { 18162306a36Sopenharmony_ci printf("First message send failed (%m)\n"); 18262306a36Sopenharmony_ci return -errno; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci msgbuf.mtype = ANOTHER_MSG_TYPE; 18662306a36Sopenharmony_ci memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING)); 18762306a36Sopenharmony_ci if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING), 18862306a36Sopenharmony_ci IPC_NOWAIT) != 0) { 18962306a36Sopenharmony_ci printf("Second message send failed (%m)\n"); 19062306a36Sopenharmony_ci return -errno; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ciint main(int argc, char **argv) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int msg, pid, err; 19862306a36Sopenharmony_ci struct msgque_data msgque; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (getuid() != 0) 20162306a36Sopenharmony_ci return ksft_exit_skip( 20262306a36Sopenharmony_ci "Please run the test as root - Exiting.\n"); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci msgque.key = ftok(argv[0], 822155650); 20562306a36Sopenharmony_ci if (msgque.key == -1) { 20662306a36Sopenharmony_ci printf("Can't make key: %d\n", -errno); 20762306a36Sopenharmony_ci return ksft_exit_fail(); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); 21162306a36Sopenharmony_ci if (msgque.msq_id == -1) { 21262306a36Sopenharmony_ci err = -errno; 21362306a36Sopenharmony_ci printf("Can't create queue: %d\n", err); 21462306a36Sopenharmony_ci goto err_out; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci err = fill_msgque(&msgque); 21862306a36Sopenharmony_ci if (err) { 21962306a36Sopenharmony_ci printf("Failed to fill queue: %d\n", err); 22062306a36Sopenharmony_ci goto err_destroy; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci err = dump_queue(&msgque); 22462306a36Sopenharmony_ci if (err) { 22562306a36Sopenharmony_ci printf("Failed to dump queue: %d\n", err); 22662306a36Sopenharmony_ci goto err_destroy; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci err = check_and_destroy_queue(&msgque); 23062306a36Sopenharmony_ci if (err) { 23162306a36Sopenharmony_ci printf("Failed to check and destroy queue: %d\n", err); 23262306a36Sopenharmony_ci goto err_out; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci err = restore_queue(&msgque); 23662306a36Sopenharmony_ci if (err) { 23762306a36Sopenharmony_ci printf("Failed to restore queue: %d\n", err); 23862306a36Sopenharmony_ci goto err_destroy; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci err = check_and_destroy_queue(&msgque); 24262306a36Sopenharmony_ci if (err) { 24362306a36Sopenharmony_ci printf("Failed to test queue: %d\n", err); 24462306a36Sopenharmony_ci goto err_out; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci return ksft_exit_pass(); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cierr_destroy: 24962306a36Sopenharmony_ci if (msgctl(msgque.msq_id, IPC_RMID, NULL)) { 25062306a36Sopenharmony_ci printf("Failed to destroy queue: %d\n", -errno); 25162306a36Sopenharmony_ci return ksft_exit_fail(); 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_cierr_out: 25462306a36Sopenharmony_ci return ksft_exit_fail(); 25562306a36Sopenharmony_ci} 256