]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/tst-sysvshm-linux.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / tst-sysvshm-linux.c
CommitLineData
a49d7fd4 1/* Basic tests for Linux SYSV shared memory extensions.
2b778ceb 2 Copyright (C) 2020-2021 Free Software Foundation, Inc.
a49d7fd4
AZ
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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/>. */
18
19#include <sys/ipc.h>
20#include <sys/shm.h>
21#include <errno.h>
22#include <stdlib.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <inttypes.h>
27#include <limits.h>
28
29#include <support/check.h>
30#include <support/temp_file.h>
31
32#define SHM_MODE 0644
33
34/* These are for the temporary file we generate. */
35static char *name;
36static int shmid;
37static long int pgsz;
38
39static void
40remove_shm (void)
41{
42 /* Enforce message queue removal in case of early test failure.
43 Ignore error since the shm may already have being removed. */
44 shmctl (shmid, IPC_RMID, NULL);
45}
46
47static void
48do_prepare (int argc, char *argv[])
49{
50 TEST_VERIFY_EXIT (create_temp_file ("tst-sysvshm.", &name) != -1);
51}
52
53#define PREPARE do_prepare
54
55struct test_shminfo
56{
602da9de
AZ
57 __syscall_ulong_t shmall;
58 __syscall_ulong_t shmmax;
59 __syscall_ulong_t shmmni;
a49d7fd4
AZ
60};
61
62/* It tries to obtain some system-wide SysV shared memory information from
63 /proc to check against IPC_INFO/SHM_INFO. The /proc only returns the
64 tunables value of SHMALL, SHMMAX, and SHMMNI. */
65
66static uint64_t
67read_proc_file (const char *file)
68{
69 FILE *f = fopen (file, "r");
70 if (f == NULL)
71 FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file);
72
73 /* Handle 32-bit binaries running on 64-bit kernels. */
74 uint64_t v;
75 int r = fscanf (f, "%" SCNu64, &v);
76 TEST_VERIFY_EXIT (r == 1);
77
78 fclose (f);
79 return v;
80}
81
82
83/* Check if the message queue with IDX (index into the kernel's internal
84 array) matches the one with KEY. The CMD is either SHM_STAT or
85 SHM_STAT_ANY. */
86
87static bool
88check_shminfo (int idx, key_t key, int cmd)
89{
90 struct shmid_ds shminfo;
91 int sid = shmctl (idx, cmd, &shminfo);
92 /* Ignore unused array slot returned by the kernel or information from
93 unknown message queue. */
94 if ((sid == -1 && errno == EINVAL) || sid != shmid)
95 return false;
96
97 if (sid == -1)
98 FAIL_EXIT1 ("shmctl with %s failed: %m",
99 cmd == SHM_STAT ? "SHM_STAT" : "SHM_STAT_ANY");
100
101 TEST_COMPARE (shminfo.shm_perm.__key, key);
102 TEST_COMPARE (shminfo.shm_perm.mode, SHM_MODE);
103 TEST_COMPARE (shminfo.shm_segsz, pgsz);
104
105 return true;
106}
107
108static int
109do_test (void)
110{
111 atexit (remove_shm);
112
113 pgsz = sysconf (_SC_PAGESIZE);
114 if (pgsz == -1)
115 FAIL_EXIT1 ("sysconf (_SC_PAGESIZE) failed: %m");
116
117 key_t key = ftok (name, 'G');
118 if (key == -1)
119 FAIL_EXIT1 ("ftok failed: %m");
120
121 shmid = shmget (key, pgsz, IPC_CREAT | IPC_EXCL | SHM_MODE);
122 if (shmid == -1)
123 FAIL_EXIT1 ("shmget failed: %m");
124
125 struct test_shminfo tipcinfo;
126 {
127 uint64_t v = read_proc_file ("/proc/sys/kernel/shmmax");
128#if LONG_MAX == INT_MAX
129 /* Kernel explicit clamp the value for shmmax on compat symbol (32-bit
130 binaries running on 64-bit kernels). */
602da9de
AZ
131 if (sizeof (__syscall_ulong_t) == sizeof (unsigned long int)
132 && v > INT_MAX)
a49d7fd4
AZ
133 v = INT_MAX;
134#endif
135 tipcinfo.shmmax = v;
136 }
137 tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall");
138 tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni");
139
140 int shmidx;
141
142 /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info'.
143 It is tricky to verify its values since the syscall returns system wide
144 resources consumed by shared memory. The shmctl implementation handles
145 SHM_INFO as IPC_INFO, so the IPC_INFO test should validate SHM_INFO as
146 well. */
147
148 {
149 struct shminfo ipcinfo;
150 shmidx = shmctl (shmid, IPC_INFO, (struct shmid_ds *) &ipcinfo);
151 if (shmidx == -1)
152 FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m");
153
154 TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall);
155 TEST_COMPARE (ipcinfo.shmmax, tipcinfo.shmmax);
156 TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni);
157 }
158
159 /* We check if the created shared memory shows in the global list. */
160 bool found = false;
161 for (int i = 0; i <= shmidx; i++)
162 {
163 /* We can't tell apart if SHM_STAT_ANY is not supported (kernel older
164 than 4.17) or if the index used is invalid. So it just check if
165 value returned from a valid call matches the created message
166 queue. */
167 check_shminfo (i, key, SHM_STAT_ANY);
168
169 if (check_shminfo (i, key, SHM_STAT))
170 {
171 found = true;
172 break;
173 }
174 }
175
176 if (!found)
177 FAIL_EXIT1 ("shmctl with SHM_STAT/SHM_STAT_ANY could not find the "
178 "created shared memory");
179
180 if (shmctl (shmid, IPC_RMID, NULL) == -1)
181 FAIL_EXIT1 ("shmctl failed");
182
183 return 0;
184}
185
186#include <support/test-driver.c>