elf: Fix _dl_debug_vdprintf to work before self-relocation
[glibc.git] / sysdeps / unix / sysv / linux / tst-sysvmsg-linux.c
blobf18464e3f5ee6238e6ece512f02075ff4e26f7fa
1 /* Basic tests for Linux SYSV message queue extensions.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <sys/ipc.h>
20 #include <sys/msg.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <stdio.h>
26 #include <support/check.h>
27 #include <support/temp_file.h>
29 #define MSGQ_MODE 0644
31 /* These are for the temporary file we generate. */
32 static char *name;
33 static int msqid;
35 static void
36 remove_msq (void)
38 /* Enforce message queue removal in case of early test failure.
39 Ignore error since the msg may already have being removed. */
40 msgctl (msqid, IPC_RMID, NULL);
43 static void
44 do_prepare (int argc, char *argv[])
46 TEST_VERIFY_EXIT (create_temp_file ("tst-sysvmsg.", &name) != -1);
49 #define PREPARE do_prepare
51 struct test_msginfo
53 int msgmax;
54 int msgmnb;
55 int msgmni;
58 /* It tries to obtain some system-wide SysV message queue information from
59 /proc to check against IPC_INFO/MSG_INFO. The /proc only returns the
60 tunables value of MSGMAX, MSGMNB, and MSGMNI.
62 The kernel also returns constant value for MSGSSZ, MSGSEG and also MSGMAP,
63 MSGPOOL, and MSGTQL (for IPC_INFO). The issue to check them is they might
64 change over kernel releases. */
66 static int
67 read_proc_file (const char *file)
69 FILE *f = fopen (file, "r");
70 if (f == NULL)
71 FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file);
73 int v;
74 int r = fscanf (f, "%d", & v);
75 TEST_VERIFY_EXIT (r == 1);
77 fclose (f);
78 return v;
82 /* Check if the message queue with IDX (index into the kernel's internal
83 array) matches the one with KEY. The CMD is either MSG_STAT or
84 MSG_STAT_ANY. */
86 static bool
87 check_msginfo (int idx, key_t key, int cmd)
89 struct msqid_ds msginfo;
90 int mid = msgctl (idx, cmd, &msginfo);
91 /* Ignore unused array slot returned by the kernel or information from
92 unknown message queue. */
93 if ((mid == -1 && errno == EINVAL) || mid != msqid)
94 return false;
96 if (mid == -1)
97 FAIL_EXIT1 ("msgctl with %s failed: %m",
98 cmd == MSG_STAT ? "MSG_STAT" : "MSG_STAT_ANY");
100 TEST_COMPARE (msginfo.msg_perm.__key, key);
101 TEST_COMPARE (msginfo.msg_perm.mode, MSGQ_MODE);
102 TEST_COMPARE (msginfo.msg_qnum, 0);
104 return true;
107 static int
108 do_test (void)
110 atexit (remove_msq);
112 key_t key = ftok (name, 'G');
113 if (key == -1)
114 FAIL_EXIT1 ("ftok failed: %m");
116 msqid = msgget (key, MSGQ_MODE | IPC_CREAT);
117 if (msqid == -1)
118 FAIL_EXIT1 ("msgget failed: %m");
120 struct test_msginfo tipcinfo;
121 tipcinfo.msgmax = read_proc_file ("/proc/sys/kernel/msgmax");
122 tipcinfo.msgmnb = read_proc_file ("/proc/sys/kernel/msgmnb");
123 tipcinfo.msgmni = read_proc_file ("/proc/sys/kernel/msgmni");
125 int msqidx;
128 struct msginfo ipcinfo;
129 msqidx = msgctl (msqid, IPC_INFO, (struct msqid_ds *) &ipcinfo);
130 if (msqidx == -1)
131 FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m");
133 TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax);
134 TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb);
135 TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni);
138 /* Same as before but with MSG_INFO. */
140 struct msginfo ipcinfo;
141 msqidx = msgctl (msqid, MSG_INFO, (struct msqid_ds *) &ipcinfo);
142 if (msqidx == -1)
143 FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m");
145 TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax);
146 TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb);
147 TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni);
150 /* We check if the created message queue shows in global list. */
151 bool found = false;
152 for (int i = 0; i <= msqidx; i++)
154 /* We can't tell apart if MSG_STAT_ANY is not supported (kernel older
155 than 4.17) or if the index used is invalid. So it just check if the
156 value returned from a valid call matches the created message
157 queue. */
158 check_msginfo (i, key, MSG_STAT_ANY);
160 if (check_msginfo (i, key, MSG_STAT))
162 found = true;
163 break;
167 if (!found)
168 FAIL_EXIT1 ("msgctl with MSG_STAT/MSG_STAT_ANY could not find the "
169 "created message queue");
171 if (msgctl (msqid, IPC_RMID, NULL) == -1)
172 FAIL_EXIT1 ("msgctl failed");
174 return 0;
177 #include <support/test-driver.c>