294 lines
5.7 KiB
C
294 lines
5.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd
|
|
* Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
|
|
* Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
|
|
* Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
|
|
* Copyright (c) 2016 Linux Test Project
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <mqueue.h>
|
|
#include <pwd.h>
|
|
|
|
#include "tst_test.h"
|
|
#include "tst_safe_file_ops.h"
|
|
#include "tst_safe_posix_ipc.h"
|
|
|
|
#define QUEUE_NAME "/test_mqueue"
|
|
#define QUEUE_INIT "/init_mqueue"
|
|
|
|
static uid_t euid;
|
|
static struct passwd *pw;
|
|
static char *qname;
|
|
static struct rlimit rlim;
|
|
|
|
static mqd_t fd, fd2;
|
|
static mqd_t fd3 = -1;
|
|
static int max_queues;
|
|
|
|
struct test_case {
|
|
const char *desc;
|
|
char *qname;
|
|
int oflag;
|
|
struct mq_attr *rq;
|
|
int ret;
|
|
int err;
|
|
void (*setup)(void);
|
|
void (*cleanup)(void);
|
|
};
|
|
|
|
#define PROC_MAX_QUEUES "/proc/sys/fs/mqueue/queues_max"
|
|
|
|
static void create_queue(void);
|
|
static void unlink_queue(void);
|
|
static void set_rlimit(void);
|
|
static void restore_rlimit(void);
|
|
static void set_max_queues(void);
|
|
static void restore_max_queues(void);
|
|
|
|
static struct test_case tcase[] = {
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = QUEUE_NAME,
|
|
.oflag = O_CREAT,
|
|
.rq = &(struct mq_attr){.mq_maxmsg = 20, .mq_msgsize = 16384},
|
|
.ret = 0,
|
|
.err = 0,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = QUEUE_NAME,
|
|
.oflag = O_CREAT,
|
|
.ret = 0,
|
|
.err = 0,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = "/caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaa",
|
|
.oflag = O_CREAT,
|
|
.ret = 0,
|
|
.err = 0,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
"aaaaaaaaaaaaaaaa",
|
|
.oflag = O_CREAT,
|
|
.ret = -1,
|
|
.err = ENAMETOOLONG,
|
|
},
|
|
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = "",
|
|
.oflag = O_CREAT,
|
|
.ret = -1,
|
|
.err = EINVAL,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = QUEUE_NAME,
|
|
.ret = -1,
|
|
.err = EACCES,
|
|
.setup = create_queue,
|
|
.cleanup = unlink_queue,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = QUEUE_NAME,
|
|
.oflag = O_CREAT | O_EXCL,
|
|
.ret = -1,
|
|
.err = EEXIST,
|
|
.setup = create_queue,
|
|
.cleanup = unlink_queue,
|
|
},
|
|
{
|
|
.desc = "NO_FILE",
|
|
.qname = QUEUE_NAME,
|
|
.oflag = O_CREAT,
|
|
.ret = -1,
|
|
.err = EMFILE,
|
|
.setup = set_rlimit,
|
|
.cleanup = restore_rlimit,
|
|
},
|
|
{
|
|
.desc = "NORMAL",
|
|
.qname = "/notexist",
|
|
.oflag = 0,
|
|
.ret = -1,
|
|
.err = ENOENT,
|
|
},
|
|
{
|
|
.desc = "NO_SPACE",
|
|
.qname = QUEUE_NAME,
|
|
.oflag = O_CREAT,
|
|
.ret = -1,
|
|
.err = ENOSPC,
|
|
.setup = set_max_queues,
|
|
.cleanup = restore_max_queues,
|
|
}
|
|
};
|
|
|
|
static void create_queue(void)
|
|
{
|
|
fd2 = SAFE_MQ_OPEN(QUEUE_NAME, O_CREAT | O_EXCL | O_RDWR, S_IRWXU, NULL);
|
|
|
|
SAFE_SETEUID(pw->pw_uid);
|
|
}
|
|
|
|
static void unlink_queue(void)
|
|
{
|
|
SAFE_SETEUID(euid);
|
|
if (fd2 > 0)
|
|
SAFE_CLOSE(fd2);
|
|
|
|
if (mq_unlink(QUEUE_NAME))
|
|
tst_brk(TBROK | TERRNO, "mq_close(" QUEUE_NAME ") failed");
|
|
}
|
|
|
|
|
|
static void set_max_queues(void)
|
|
{
|
|
SAFE_FILE_SCANF(PROC_MAX_QUEUES, "%d", &max_queues);
|
|
SAFE_FILE_PRINTF(PROC_MAX_QUEUES, "%d", 1);
|
|
|
|
SAFE_SETEUID(pw->pw_uid);
|
|
}
|
|
|
|
static void restore_max_queues(void)
|
|
{
|
|
SAFE_SETEUID(euid);
|
|
|
|
SAFE_FILE_PRINTF(PROC_MAX_QUEUES, "%d", max_queues);
|
|
}
|
|
|
|
static void set_rlimit(void)
|
|
{
|
|
if (rlim.rlim_cur > 0) {
|
|
struct rlimit r;
|
|
r.rlim_cur = 0;
|
|
r.rlim_max = rlim.rlim_max;
|
|
SAFE_SETRLIMIT(RLIMIT_NOFILE, &r);
|
|
}
|
|
}
|
|
|
|
static void restore_rlimit(void)
|
|
{
|
|
SAFE_SETRLIMIT(RLIMIT_NOFILE, &rlim);
|
|
}
|
|
|
|
static void setup(void)
|
|
{
|
|
euid = geteuid();
|
|
pw = SAFE_GETPWNAM("nobody");
|
|
SAFE_GETRLIMIT(RLIMIT_NOFILE, &rlim);
|
|
|
|
fd3 = SAFE_MQ_OPEN(QUEUE_INIT, O_CREAT | O_EXCL | O_RDWR, S_IRWXU, NULL);
|
|
}
|
|
|
|
static void cleanup(void)
|
|
{
|
|
if (fd > 0)
|
|
mq_close(fd);
|
|
|
|
if (fd2 > 0)
|
|
mq_close(fd2);
|
|
|
|
if (fd3 > 0 && mq_close(fd3))
|
|
tst_res(TWARN | TERRNO, "mq_close(%s) failed", QUEUE_INIT);
|
|
|
|
if (mq_unlink(QUEUE_INIT))
|
|
tst_res(TWARN | TERRNO, "mq_unlink(%s) failed", QUEUE_INIT);
|
|
|
|
mq_unlink(qname);
|
|
}
|
|
|
|
static void do_test(unsigned int i)
|
|
{
|
|
struct test_case *tc = &tcase[i];
|
|
struct mq_attr oldattr;
|
|
|
|
qname = tc->qname;
|
|
fd = fd2 = -1;
|
|
|
|
tst_res(TINFO, "queue name \"%s\"", qname);
|
|
|
|
if (tc->setup)
|
|
tc->setup();
|
|
|
|
TEST(fd = mq_open(qname, tc->oflag, S_IRWXU, tc->rq));
|
|
|
|
if (fd > 0 && tc->rq) {
|
|
if (mq_getattr(fd, &oldattr) < 0) {
|
|
tst_res(TFAIL | TERRNO, "mq_getattr failed");
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (oldattr.mq_maxmsg != tc->rq->mq_maxmsg
|
|
|| oldattr.mq_msgsize != tc->rq->mq_msgsize) {
|
|
tst_res(TFAIL, "wrong mq_attr: "
|
|
"mq_maxmsg expected %ld return %ld, "
|
|
"mq_msgsize expected %ld return %ld",
|
|
tc->rq->mq_maxmsg, oldattr.mq_maxmsg, tc->rq->mq_msgsize,
|
|
oldattr.mq_msgsize);
|
|
goto CLEANUP;
|
|
}
|
|
}
|
|
|
|
if (tc->ret == 0) {
|
|
if (TST_RET < 0) {
|
|
tst_res(TFAIL | TTERRNO, "%s wrong return code: %ld",
|
|
tc->desc, TST_RET);
|
|
} else {
|
|
tst_res(TPASS | TTERRNO, "%s returned: %ld",
|
|
tc->desc, TST_RET);
|
|
}
|
|
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (TST_ERR != tc->err) {
|
|
tst_res(TFAIL | TTERRNO, "%s expected errno: %d",
|
|
tc->desc, TST_ERR);
|
|
goto CLEANUP;
|
|
}
|
|
|
|
if (TST_RET != tc->ret) {
|
|
tst_res(TFAIL | TTERRNO, "%s wrong return code: %ld",
|
|
tc->desc, TST_RET);
|
|
} else {
|
|
tst_res(TPASS | TTERRNO, "%s returned: %ld",
|
|
tc->desc, TST_RET);
|
|
}
|
|
|
|
CLEANUP:
|
|
if (tc->cleanup)
|
|
tc->cleanup();
|
|
|
|
if (TST_RET != -1) {
|
|
if (fd > 0)
|
|
SAFE_CLOSE(fd);
|
|
mq_unlink(qname);
|
|
}
|
|
}
|
|
|
|
static struct tst_test test = {
|
|
.tcnt = ARRAY_SIZE(tcase),
|
|
.test = do_test,
|
|
.needs_root = 1,
|
|
.setup = setup,
|
|
.cleanup = cleanup,
|
|
};
|