1 /******************************************************************************/
2 /* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd */
3 /* Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, */
4 /* Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, */
5 /* Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
15 /* the GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20 /* */
21 /******************************************************************************/
22 /******************************************************************************/
23 /* */
24 /* File: mq_open01.c */
25 /* */
26 /* Description: This tests the mq_open() syscall */
27 /* */
28 /* */
29 /* */
30 /* */
31 /* */
32 /* */
33 /* Usage: <for command-line> */
34 /* mq_open01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */
35 /* where, -c n : Run n copies concurrently. */
36 /* -e : Turn on errno logging. */
37 /* -i n : Execute test n times. */
38 /* -I x : Execute test for x seconds. */
39 /* -P x : Pause for x seconds between iterations. */
40 /* -t : Turn on syscall timing. */
41 /* */
42 /* Total Tests: 1 */
43 /* */
44 /* Test Name: mq_open01 */
45 /* History: Porting from Crackerjack to LTP is done by */
46 /* Manas Kumar Nayak maknayak@in.ibm.com> */
47 /******************************************************************************/
48 #include <sys/syscall.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <sys/uio.h>
52 #include <getopt.h>
53 #include <stdlib.h>
54 #include <errno.h>
55 #include <stdio.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <mqueue.h>
59 #include <limits.h>
60
61 #include "../utils/include_j_h.h"
62 #include "../utils/common_j_h.c"
63
64 #include "test.h"
65 #include "linux_syscall_numbers.h"
66
67 char *TCID = "mq_open01";
68 int testno;
69 int TST_TOTAL = 1;
70
71 /* Extern Global Functions */
72 /******************************************************************************/
73 /* */
74 /* Function: cleanup */
75 /* */
76 /* Description: Performs all one time clean up for this test on successful */
77 /* completion, premature exit or failure. Closes all temporary */
78 /* files, removes all temporary directories exits the test with */
79 /* appropriate return code by calling tst_exit() function. */
80 /* */
81 /* Input: None. */
82 /* */
83 /* Output: None. */
84 /* */
85 /* Return: On failure - Exits calling tst_exit(). Non '0' return code. */
86 /* On success - Exits calling tst_exit(). With '0' return code. */
87 /* */
88 /******************************************************************************/
cleanup(void)89 void cleanup(void)
90 {
91
92 tst_rmdir();
93 }
94
95 /* Local Functions */
96 /******************************************************************************/
97 /* */
98 /* Function: setup */
99 /* */
100 /* Description: Performs all one time setup for this test. This function is */
101 /* typically used to capture signals, create temporary dirs */
102 /* and temporary files that may be used in the course of this */
103 /* test. */
104 /* */
105 /* Input: None. */
106 /* */
107 /* Output: None. */
108 /* */
109 /* Return: On failure - Exits by calling cleanup(). */
110 /* On success - returns 0. */
111 /* */
112 /******************************************************************************/
setup(void)113 void setup(void)
114 {
115 tst_require_root();
116
117 /* Capture signals if any */
118 /* Create temporary directories */
119 TEST_PAUSE;
120 tst_tmpdir();
121 }
122
123 /*
124 * Macros
125 */
126 #define SYSCALL_NAME "mq_open"
127
128 enum test_type {
129 NORMAL,
130 NO_FILE,
131 NO_SPACE,
132 };
133
134 /*
135 * Data Structure
136 */
137 struct test_case {
138 int ttype;
139 char *user;
140 char *qname;
141 int oflag;
142 long mq_maxmsg; // Maximum numebr of messages.
143 long mq_msgsize; // Maximum message size.
144 int ret;
145 int err;
146 };
147
148 #define ULIMIT_FNUM 0
149 #define PROC_MAX_QUEUES "/proc/sys/fs/mqueue/queues_max"
150
151 /* Test cases
152 *
153 * test status of errors on man page
154 *
155 * EACCES v (permission is denied)
156 * EEXIST v (named message queue already exists)
157 * EINTR --- (interrupted by a signal)
158 * EINVAL v (not supported for the given name, or invalid
159 * arguments)
160 * EMFILE v (process file table overflow)
161 * ENAMETOOLONG v (too long name length)
162 * ENFILE can't check because it's difficult to create no-fd
163 * ENOENT v (O_CREAT is not set and the named message queue
164 * does not exist)
165 * ENOSPC v (no space for the new message queue)
166 */
167
168 static struct test_case tcase[] = {
169 #if 1
170 { // case00
171 .ttype = NORMAL,
172 .qname = QUEUE_NAME,
173 .oflag = O_CREAT,
174 .mq_maxmsg = 20,
175 .mq_msgsize = 16384,
176 .ret = 0,
177 .err = 0,
178 },
179 #else
180 { // case00
181 .ttype = NORMAL,
182 .qname = QUEUE_NAME,
183 .oflag = O_CREAT,
184 .ret = 0,
185 .err = 0,
186 },
187 { // case01
188 .ttype = NORMAL,
189 // 0 1 2 3
190 // 0123456789012345678901234567890123456789
191 "aaaaaaaaaaaaaaa",
192 .oflag = O_CREAT,
193 .ret = 0,
194 .err = 0,
195 },
196 { // case02
197 .ttype = NORMAL,
198 // 0 1 2 3
199 // 0123456789012345678901234567890123456789
200 "aaaaaaaaaaaaaaaa",
201 .oflag = O_CREAT,
202 .ret = -1,
203 .err = ENAMETOOLONG,
204 },
205
206 { // case03
207 .ttype = NORMAL,
208 .qname = "",
209 .oflag = O_CREAT,
210 .ret = -1,
211 .err = EINVAL,
212 },
213 { // case04
214 .ttype = NORMAL,
215 .user = "nobody",
216 .qname = QUEUE_NAME,
217 .ret = -1,
218 .err = EACCES,
219 },
220 { // case05
221 .ttype = NORMAL,
222 .qname = QUEUE_NAME,
223 .oflag = O_CREAT | O_EXCL,
224 .ret = -1,
225 .err = EEXIST,
226 },
227 { // case06
228 .ttype = NO_FILE,
229 .qname = QUEUE_NAME,
230 .oflag = O_CREAT,
231 .ret = -1,
232 .err = EMFILE,
233 },
234 { // case07
235 .ttype = NORMAL,
236 .qname = "/notexist",
237 .oflag = 0,
238 .ret = -1,
239 .err = ENOENT,
240 },
241
242 { // case08
243 .ttype = NO_SPACE,
244 .user = "nobody",
245 .qname = QUEUE_NAME,
246 .oflag = O_CREAT,
247 .ret = -1,
248 .err = ENOSPC,
249 },
250 #endif
251 };
252
253 /*
254 * do_test()
255 *
256 * Input : TestCase Data
257 * Return : RESULT_OK(0), RESULT_NG(1)
258 *
259 */
260
do_test(struct test_case * tc)261 static int do_test(struct test_case *tc)
262 {
263 int sys_ret;
264 int sys_errno;
265 int result = RESULT_OK;
266 int rc, fd1 = -1, fd2 = -1, cmp_ok = 1;
267 uid_t old_uid = -1;
268 rlim_t oldlim = -1;
269 int oldval = -1;
270 struct mq_attr new, old, *p_attr;
271
272 /*
273 * When test ended with SIGTERM etc, mq discriptor is left remains.
274 * So we delete it first.
275 */
276 TEST(mq_unlink(QUEUE_NAME));
277
278 /*
279 * Execute system call
280 */
281
282 if (tc->ttype != NO_SPACE && !(tc->oflag & O_CREAT)) {
283 errno = 0;
284 TEST(sys_ret =
285 mq_open(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU,
286 NULL));
287 sys_errno = errno;
288 if (sys_ret < 0)
289 goto TEST_END;
290 fd1 = sys_ret;
291 }
292 if (tc->ttype == NO_FILE) {
293 TEST(rc = setup_ulimit_fnum(ULIMIT_FNUM, &oldlim));
294 if (rc < 0) {
295 result = 1;
296 goto EXIT;
297 }
298 }
299
300 /*
301 * Change /proc/sys/fs/mqueue/queues_max
302 */
303 if (tc->ttype == NO_SPACE) {
304 TEST(rc = setup_proc_fs(PROC_MAX_QUEUES, 0, &oldval));
305 if (rc < 0) {
306 result = 1;
307 goto EXIT;
308 }
309 }
310
311 /*
312 * Change effective user id
313 */
314 if (tc->user != NULL) {
315 TEST(rc = setup_euid(tc->user, &old_uid));
316 if (rc < 0) {
317 result = 1;
318 goto EXIT;
319 }
320 }
321
322 /*
323 * Execute system call
324 */
325 //tst_resm(TINFO,"PATH_MAX: %d\n", PATH_MAX);
326 //tst_resm(TINFO,"NAME_MAX: %d", NAME_MAX);
327 p_attr = NULL;
328 if (tc->mq_maxmsg || tc->mq_msgsize) {
329 new.mq_maxmsg = tc->mq_maxmsg;
330 new.mq_msgsize = tc->mq_msgsize;
331 p_attr = &new;
332 }
333 errno = 0;
334 if (tc->oflag & O_CREAT)
335 TEST(sys_ret = mq_open(tc->qname, tc->oflag, S_IRWXU, p_attr));
336 else
337 TEST(sys_ret = mq_open(tc->qname, tc->oflag));
338 sys_errno = errno;
339 if (sys_ret < 0)
340 goto TEST_END;
341 fd2 = sys_ret;
342
343 if (p_attr) {
344 TEST(rc = ltp_syscall(__NR_mq_getsetattr, fd2, NULL, &old));
345 if (TEST_RETURN < 0) {
346 tst_resm(TFAIL,
347 "mq_getsetattr failed - errno = %d : %s",
348 TEST_ERRNO, strerror(TEST_ERRNO));
349 result = 1;
350 goto EXIT;
351 }
352 tst_resm(TINFO, "mq_maxmsg E:%ld,\tR:%ld", new.mq_maxmsg,
353 old.mq_maxmsg);
354 tst_resm(TINFO, "mq_msgsize E:%ld,\tR:%ld", new.mq_msgsize,
355 old.mq_msgsize);
356 cmp_ok = old.mq_maxmsg == new.mq_maxmsg
357 && old.mq_msgsize == new.mq_msgsize;
358 }
359
360 TEST_END:
361 /*
362 * Check results
363 */
364 result |= (sys_errno != tc->err) || !cmp_ok;
365 PRINT_RESULT_CMP(sys_ret >= 0, tc->ret, tc->err, sys_ret, sys_errno,
366 cmp_ok);
367
368 EXIT:
369 if (tc->user != NULL && old_uid != -1)
370 TEST(cleanup_euid(old_uid));
371
372 if (tc->ttype == NO_SPACE && oldval != -1)
373 TEST(cleanup_proc_fs(PROC_MAX_QUEUES, oldval));
374
375 if (tc->ttype == NO_FILE && oldlim != -1)
376 TEST(cleanup_ulimit_fnum(oldlim));
377 if (fd1 >= 0)
378 TEST(close(fd1));
379 if (fd2 >= 0)
380 TEST(close(fd2));
381 if (fd1 >= 0)
382 TEST(mq_unlink(QUEUE_NAME));
383 if (fd2 >= 0 && strcmp(tc->qname, QUEUE_NAME) != 0)
384 TEST(mq_unlink(tc->qname));
385
386 return result;
387 }
388
389 /*
390 * main()
391 */
392
main(int ac,char ** av)393 int main(int ac, char **av)
394 {
395 int result = RESULT_OK;
396 int i;
397 int lc;
398
399 tst_parse_opts(ac, av, NULL, NULL);
400
401 setup();
402
403 for (lc = 0; TEST_LOOPING(lc); ++lc) {
404 tst_count = 0;
405 for (testno = 0; testno < TST_TOTAL; ++testno) {
406
407 /*
408 * Execute test
409 */
410 for (i = 0; i < (int)ARRAY_SIZE(tcase); i++) {
411 int ret;
412 tst_resm(TINFO, "(case%02d) START", i);
413 ret = do_test(&tcase[i]);
414 tst_resm(TINFO, "(case%02d) END => %s", i,
415 (ret == 0) ? "OK" : "NG");
416 result |= ret;
417 }
418
419 /*
420 * Check results
421 */
422 switch (result) {
423 case RESULT_OK:
424 tst_resm(TPASS, "mq_open call succeeded ");
425 break;
426
427 default:
428 tst_brkm(TFAIL | TTERRNO, cleanup,
429 "mq_open failed");
430 break;
431 }
432
433 }
434 }
435 cleanup();
436 tst_exit();
437 }
438