162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This application is Copyright 2012 Red Hat, Inc.
362306a36Sopenharmony_ci *	Doug Ledford <dledford@redhat.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * mq_open_tests is free software: you can redistribute it and/or modify
662306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
762306a36Sopenharmony_ci * the Free Software Foundation, version 3.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * mq_open_tests is distributed in the hope that it will be useful,
1062306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
1162306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1262306a36Sopenharmony_ci * GNU General Public License for more details.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * For the full text of the license, see <http://www.gnu.org/licenses/>.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * mq_open_tests.c
1762306a36Sopenharmony_ci *   Tests the various situations that should either succeed or fail to
1862306a36Sopenharmony_ci *   open a posix message queue and then reports whether or not they
1962306a36Sopenharmony_ci *   did as they were supposed to.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#include <stdio.h>
2362306a36Sopenharmony_ci#include <stdlib.h>
2462306a36Sopenharmony_ci#include <unistd.h>
2562306a36Sopenharmony_ci#include <fcntl.h>
2662306a36Sopenharmony_ci#include <string.h>
2762306a36Sopenharmony_ci#include <limits.h>
2862306a36Sopenharmony_ci#include <errno.h>
2962306a36Sopenharmony_ci#include <sys/types.h>
3062306a36Sopenharmony_ci#include <sys/time.h>
3162306a36Sopenharmony_ci#include <sys/resource.h>
3262306a36Sopenharmony_ci#include <sys/stat.h>
3362306a36Sopenharmony_ci#include <mqueue.h>
3462306a36Sopenharmony_ci#include <error.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include "../kselftest.h"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic char *usage =
3962306a36Sopenharmony_ci"Usage:\n"
4062306a36Sopenharmony_ci"  %s path\n"
4162306a36Sopenharmony_ci"\n"
4262306a36Sopenharmony_ci"	path	Path name of the message queue to create\n"
4362306a36Sopenharmony_ci"\n"
4462306a36Sopenharmony_ci"	Note: this program must be run as root in order to enable all tests\n"
4562306a36Sopenharmony_ci"\n";
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cichar *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
4862306a36Sopenharmony_cichar *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
4962306a36Sopenharmony_cichar *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
5062306a36Sopenharmony_cichar *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint default_settings;
5362306a36Sopenharmony_cistruct rlimit saved_limits, cur_limits;
5462306a36Sopenharmony_ciint saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
5562306a36Sopenharmony_ciint cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
5662306a36Sopenharmony_ciFILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
5762306a36Sopenharmony_cichar *queue_path;
5862306a36Sopenharmony_cichar *default_queue_path = "/test1";
5962306a36Sopenharmony_cimqd_t queue = -1;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic inline void __set(FILE *stream, int value, char *err_msg);
6262306a36Sopenharmony_civoid shutdown(int exit_val, char *err_cause, int line_no);
6362306a36Sopenharmony_cistatic inline int get(FILE *stream);
6462306a36Sopenharmony_cistatic inline void set(FILE *stream, int value);
6562306a36Sopenharmony_cistatic inline void getr(int type, struct rlimit *rlim);
6662306a36Sopenharmony_cistatic inline void setr(int type, struct rlimit *rlim);
6762306a36Sopenharmony_civoid validate_current_settings();
6862306a36Sopenharmony_cistatic inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
6962306a36Sopenharmony_cistatic inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic inline void __set(FILE *stream, int value, char *err_msg)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	rewind(stream);
7462306a36Sopenharmony_ci	if (fprintf(stream, "%d", value) < 0)
7562306a36Sopenharmony_ci		perror(err_msg);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid shutdown(int exit_val, char *err_cause, int line_no)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	static int in_shutdown = 0;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* In case we get called recursively by a set() call below */
8462306a36Sopenharmony_ci	if (in_shutdown++)
8562306a36Sopenharmony_ci		return;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (seteuid(0) == -1)
8862306a36Sopenharmony_ci		perror("seteuid() failed");
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (queue != -1)
9162306a36Sopenharmony_ci		if (mq_close(queue))
9262306a36Sopenharmony_ci			perror("mq_close() during shutdown");
9362306a36Sopenharmony_ci	if (queue_path)
9462306a36Sopenharmony_ci		/*
9562306a36Sopenharmony_ci		 * Be silent if this fails, if we cleaned up already it's
9662306a36Sopenharmony_ci		 * expected to fail
9762306a36Sopenharmony_ci		 */
9862306a36Sopenharmony_ci		mq_unlink(queue_path);
9962306a36Sopenharmony_ci	if (default_settings) {
10062306a36Sopenharmony_ci		if (saved_def_msgs)
10162306a36Sopenharmony_ci			__set(def_msgs, saved_def_msgs,
10262306a36Sopenharmony_ci			      "failed to restore saved_def_msgs");
10362306a36Sopenharmony_ci		if (saved_def_msgsize)
10462306a36Sopenharmony_ci			__set(def_msgsize, saved_def_msgsize,
10562306a36Sopenharmony_ci			      "failed to restore saved_def_msgsize");
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	if (saved_max_msgs)
10862306a36Sopenharmony_ci		__set(max_msgs, saved_max_msgs,
10962306a36Sopenharmony_ci		      "failed to restore saved_max_msgs");
11062306a36Sopenharmony_ci	if (saved_max_msgsize)
11162306a36Sopenharmony_ci		__set(max_msgsize, saved_max_msgsize,
11262306a36Sopenharmony_ci		      "failed to restore saved_max_msgsize");
11362306a36Sopenharmony_ci	if (exit_val)
11462306a36Sopenharmony_ci		error(exit_val, errno, "%s at %d", err_cause, line_no);
11562306a36Sopenharmony_ci	exit(0);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline int get(FILE *stream)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	int value;
12162306a36Sopenharmony_ci	rewind(stream);
12262306a36Sopenharmony_ci	if (fscanf(stream, "%d", &value) != 1)
12362306a36Sopenharmony_ci		shutdown(4, "Error reading /proc entry", __LINE__ - 1);
12462306a36Sopenharmony_ci	return value;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic inline void set(FILE *stream, int value)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	int new_value;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	rewind(stream);
13262306a36Sopenharmony_ci	if (fprintf(stream, "%d", value) < 0)
13362306a36Sopenharmony_ci		return shutdown(5, "Failed writing to /proc file",
13462306a36Sopenharmony_ci				__LINE__ - 1);
13562306a36Sopenharmony_ci	new_value = get(stream);
13662306a36Sopenharmony_ci	if (new_value != value)
13762306a36Sopenharmony_ci		return shutdown(5, "We didn't get what we wrote to /proc back",
13862306a36Sopenharmony_ci				__LINE__ - 1);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline void getr(int type, struct rlimit *rlim)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	if (getrlimit(type, rlim))
14462306a36Sopenharmony_ci		shutdown(6, "getrlimit()", __LINE__ - 1);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic inline void setr(int type, struct rlimit *rlim)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	if (setrlimit(type, rlim))
15062306a36Sopenharmony_ci		shutdown(7, "setrlimit()", __LINE__ - 1);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_civoid validate_current_settings()
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	int rlim_needed;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (cur_limits.rlim_cur < 4096) {
15862306a36Sopenharmony_ci		printf("Current rlimit value for POSIX message queue bytes is "
15962306a36Sopenharmony_ci		       "unreasonably low,\nincreasing.\n\n");
16062306a36Sopenharmony_ci		cur_limits.rlim_cur = 8192;
16162306a36Sopenharmony_ci		cur_limits.rlim_max = 16384;
16262306a36Sopenharmony_ci		setr(RLIMIT_MSGQUEUE, &cur_limits);
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (default_settings) {
16662306a36Sopenharmony_ci		rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
16762306a36Sopenharmony_ci						    2 * sizeof(void *));
16862306a36Sopenharmony_ci		if (rlim_needed > cur_limits.rlim_cur) {
16962306a36Sopenharmony_ci			printf("Temporarily lowering default queue parameters "
17062306a36Sopenharmony_ci			       "to something that will work\n"
17162306a36Sopenharmony_ci			       "with the current rlimit values.\n\n");
17262306a36Sopenharmony_ci			set(def_msgs, 10);
17362306a36Sopenharmony_ci			cur_def_msgs = 10;
17462306a36Sopenharmony_ci			set(def_msgsize, 128);
17562306a36Sopenharmony_ci			cur_def_msgsize = 128;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci	} else {
17862306a36Sopenharmony_ci		rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
17962306a36Sopenharmony_ci						    2 * sizeof(void *));
18062306a36Sopenharmony_ci		if (rlim_needed > cur_limits.rlim_cur) {
18162306a36Sopenharmony_ci			printf("Temporarily lowering maximum queue parameters "
18262306a36Sopenharmony_ci			       "to something that will work\n"
18362306a36Sopenharmony_ci			       "with the current rlimit values in case this is "
18462306a36Sopenharmony_ci			       "a kernel that ties the default\n"
18562306a36Sopenharmony_ci			       "queue parameters to the maximum queue "
18662306a36Sopenharmony_ci			       "parameters.\n\n");
18762306a36Sopenharmony_ci			set(max_msgs, 10);
18862306a36Sopenharmony_ci			cur_max_msgs = 10;
18962306a36Sopenharmony_ci			set(max_msgsize, 128);
19062306a36Sopenharmony_ci			cur_max_msgsize = 128;
19162306a36Sopenharmony_ci		}
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/*
19662306a36Sopenharmony_ci * test_queue - Test opening a queue, shutdown if we fail.  This should
19762306a36Sopenharmony_ci * only be called in situations that should never fail.  We clean up
19862306a36Sopenharmony_ci * after ourselves and return the queue attributes in *result.
19962306a36Sopenharmony_ci */
20062306a36Sopenharmony_cistatic inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	int flags = O_RDWR | O_EXCL | O_CREAT;
20362306a36Sopenharmony_ci	int perms = DEFFILEMODE;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
20662306a36Sopenharmony_ci		shutdown(1, "mq_open()", __LINE__);
20762306a36Sopenharmony_ci	if (mq_getattr(queue, result))
20862306a36Sopenharmony_ci		shutdown(1, "mq_getattr()", __LINE__);
20962306a36Sopenharmony_ci	if (mq_close(queue))
21062306a36Sopenharmony_ci		shutdown(1, "mq_close()", __LINE__);
21162306a36Sopenharmony_ci	queue = -1;
21262306a36Sopenharmony_ci	if (mq_unlink(queue_path))
21362306a36Sopenharmony_ci		shutdown(1, "mq_unlink()", __LINE__);
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/*
21762306a36Sopenharmony_ci * Same as test_queue above, but failure is not fatal.
21862306a36Sopenharmony_ci * Returns:
21962306a36Sopenharmony_ci * 0 - Failed to create a queue
22062306a36Sopenharmony_ci * 1 - Created a queue, attributes in *result
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int flags = O_RDWR | O_EXCL | O_CREAT;
22562306a36Sopenharmony_ci	int perms = DEFFILEMODE;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
22862306a36Sopenharmony_ci		return 0;
22962306a36Sopenharmony_ci	if (mq_getattr(queue, result))
23062306a36Sopenharmony_ci		shutdown(1, "mq_getattr()", __LINE__);
23162306a36Sopenharmony_ci	if (mq_close(queue))
23262306a36Sopenharmony_ci		shutdown(1, "mq_close()", __LINE__);
23362306a36Sopenharmony_ci	queue = -1;
23462306a36Sopenharmony_ci	if (mq_unlink(queue_path))
23562306a36Sopenharmony_ci		shutdown(1, "mq_unlink()", __LINE__);
23662306a36Sopenharmony_ci	return 1;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint main(int argc, char *argv[])
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct mq_attr attr, result;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	if (argc != 2) {
24462306a36Sopenharmony_ci		printf("Using Default queue path - %s\n", default_queue_path);
24562306a36Sopenharmony_ci		queue_path = default_queue_path;
24662306a36Sopenharmony_ci	} else {
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * Although we can create a msg queue with a non-absolute path name,
25062306a36Sopenharmony_ci	 * unlink will fail.  So, if the name doesn't start with a /, add one
25162306a36Sopenharmony_ci	 * when we save it.
25262306a36Sopenharmony_ci	 */
25362306a36Sopenharmony_ci		if (*argv[1] == '/')
25462306a36Sopenharmony_ci			queue_path = strdup(argv[1]);
25562306a36Sopenharmony_ci		else {
25662306a36Sopenharmony_ci			queue_path = malloc(strlen(argv[1]) + 2);
25762306a36Sopenharmony_ci			if (!queue_path) {
25862306a36Sopenharmony_ci				perror("malloc()");
25962306a36Sopenharmony_ci				exit(1);
26062306a36Sopenharmony_ci			}
26162306a36Sopenharmony_ci			queue_path[0] = '/';
26262306a36Sopenharmony_ci			queue_path[1] = 0;
26362306a36Sopenharmony_ci			strcat(queue_path, argv[1]);
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (getuid() != 0)
26862306a36Sopenharmony_ci		ksft_exit_skip("Not running as root, but almost all tests "
26962306a36Sopenharmony_ci			"require root in order to modify\nsystem settings.  "
27062306a36Sopenharmony_ci			"Exiting.\n");
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Find out what files there are for us to make tweaks in */
27362306a36Sopenharmony_ci	def_msgs = fopen(DEF_MSGS, "r+");
27462306a36Sopenharmony_ci	def_msgsize = fopen(DEF_MSGSIZE, "r+");
27562306a36Sopenharmony_ci	max_msgs = fopen(MAX_MSGS, "r+");
27662306a36Sopenharmony_ci	max_msgsize = fopen(MAX_MSGSIZE, "r+");
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (!max_msgs)
27962306a36Sopenharmony_ci		shutdown(2, "Failed to open msg_max", __LINE__);
28062306a36Sopenharmony_ci	if (!max_msgsize)
28162306a36Sopenharmony_ci		shutdown(2, "Failed to open msgsize_max", __LINE__);
28262306a36Sopenharmony_ci	if (def_msgs || def_msgsize)
28362306a36Sopenharmony_ci		default_settings = 1;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Load up the current system values for everything we can */
28662306a36Sopenharmony_ci	getr(RLIMIT_MSGQUEUE, &saved_limits);
28762306a36Sopenharmony_ci	cur_limits = saved_limits;
28862306a36Sopenharmony_ci	if (default_settings) {
28962306a36Sopenharmony_ci		saved_def_msgs = cur_def_msgs = get(def_msgs);
29062306a36Sopenharmony_ci		saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
29162306a36Sopenharmony_ci	}
29262306a36Sopenharmony_ci	saved_max_msgs = cur_max_msgs = get(max_msgs);
29362306a36Sopenharmony_ci	saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* Tell the user our initial state */
29662306a36Sopenharmony_ci	printf("\nInitial system state:\n");
29762306a36Sopenharmony_ci	printf("\tUsing queue path:\t\t%s\n", queue_path);
29862306a36Sopenharmony_ci	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
29962306a36Sopenharmony_ci		(long) saved_limits.rlim_cur);
30062306a36Sopenharmony_ci	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
30162306a36Sopenharmony_ci		(long) saved_limits.rlim_max);
30262306a36Sopenharmony_ci	printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
30362306a36Sopenharmony_ci	printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
30462306a36Sopenharmony_ci	if (default_settings) {
30562306a36Sopenharmony_ci		printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
30662306a36Sopenharmony_ci		printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
30762306a36Sopenharmony_ci	} else {
30862306a36Sopenharmony_ci		printf("\tDefault Message Size:\t\tNot Supported\n");
30962306a36Sopenharmony_ci		printf("\tDefault Queue Size:\t\tNot Supported\n");
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci	printf("\n");
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	validate_current_settings();
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	printf("Adjusted system state for testing:\n");
31662306a36Sopenharmony_ci	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
31762306a36Sopenharmony_ci	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
31862306a36Sopenharmony_ci	printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
31962306a36Sopenharmony_ci	printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
32062306a36Sopenharmony_ci	if (default_settings) {
32162306a36Sopenharmony_ci		printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
32262306a36Sopenharmony_ci		printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	printf("\n\nTest series 1, behavior when no attr struct "
32662306a36Sopenharmony_ci	       "passed to mq_open:\n");
32762306a36Sopenharmony_ci	if (!default_settings) {
32862306a36Sopenharmony_ci		test_queue(NULL, &result);
32962306a36Sopenharmony_ci		printf("Given sane system settings, mq_open without an attr "
33062306a36Sopenharmony_ci		       "struct succeeds:\tPASS\n");
33162306a36Sopenharmony_ci		if (result.mq_maxmsg != cur_max_msgs ||
33262306a36Sopenharmony_ci		    result.mq_msgsize != cur_max_msgsize) {
33362306a36Sopenharmony_ci			printf("Kernel does not support setting the default "
33462306a36Sopenharmony_ci			       "mq attributes,\nbut also doesn't tie the "
33562306a36Sopenharmony_ci			       "defaults to the maximums:\t\t\tPASS\n");
33662306a36Sopenharmony_ci		} else {
33762306a36Sopenharmony_ci			set(max_msgs, ++cur_max_msgs);
33862306a36Sopenharmony_ci			set(max_msgsize, ++cur_max_msgsize);
33962306a36Sopenharmony_ci			test_queue(NULL, &result);
34062306a36Sopenharmony_ci			if (result.mq_maxmsg == cur_max_msgs &&
34162306a36Sopenharmony_ci			    result.mq_msgsize == cur_max_msgsize)
34262306a36Sopenharmony_ci				printf("Kernel does not support setting the "
34362306a36Sopenharmony_ci				       "default mq attributes and\n"
34462306a36Sopenharmony_ci				       "also ties system wide defaults to "
34562306a36Sopenharmony_ci				       "the system wide maximums:\t\t"
34662306a36Sopenharmony_ci				       "FAIL\n");
34762306a36Sopenharmony_ci			else
34862306a36Sopenharmony_ci				printf("Kernel does not support setting the "
34962306a36Sopenharmony_ci				       "default mq attributes,\n"
35062306a36Sopenharmony_ci				       "but also doesn't tie the defaults to "
35162306a36Sopenharmony_ci				       "the maximums:\t\t\tPASS\n");
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci	} else {
35462306a36Sopenharmony_ci		printf("Kernel supports setting defaults separately from "
35562306a36Sopenharmony_ci		       "maximums:\t\tPASS\n");
35662306a36Sopenharmony_ci		/*
35762306a36Sopenharmony_ci		 * While we are here, go ahead and test that the kernel
35862306a36Sopenharmony_ci		 * properly follows the default settings
35962306a36Sopenharmony_ci		 */
36062306a36Sopenharmony_ci		test_queue(NULL, &result);
36162306a36Sopenharmony_ci		printf("Given sane values, mq_open without an attr struct "
36262306a36Sopenharmony_ci		       "succeeds:\t\tPASS\n");
36362306a36Sopenharmony_ci		if (result.mq_maxmsg != cur_def_msgs ||
36462306a36Sopenharmony_ci		    result.mq_msgsize != cur_def_msgsize)
36562306a36Sopenharmony_ci			printf("Kernel supports setting defaults, but does "
36662306a36Sopenharmony_ci			       "not actually honor them:\tFAIL\n\n");
36762306a36Sopenharmony_ci		else {
36862306a36Sopenharmony_ci			set(def_msgs, ++cur_def_msgs);
36962306a36Sopenharmony_ci			set(def_msgsize, ++cur_def_msgsize);
37062306a36Sopenharmony_ci			/* In case max was the same as the default */
37162306a36Sopenharmony_ci			set(max_msgs, ++cur_max_msgs);
37262306a36Sopenharmony_ci			set(max_msgsize, ++cur_max_msgsize);
37362306a36Sopenharmony_ci			test_queue(NULL, &result);
37462306a36Sopenharmony_ci			if (result.mq_maxmsg != cur_def_msgs ||
37562306a36Sopenharmony_ci			    result.mq_msgsize != cur_def_msgsize)
37662306a36Sopenharmony_ci				printf("Kernel supports setting defaults, but "
37762306a36Sopenharmony_ci				       "does not actually honor them:\t"
37862306a36Sopenharmony_ci				       "FAIL\n");
37962306a36Sopenharmony_ci			else
38062306a36Sopenharmony_ci				printf("Kernel properly honors default setting "
38162306a36Sopenharmony_ci				       "knobs:\t\t\t\tPASS\n");
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci		set(def_msgs, cur_max_msgs + 1);
38462306a36Sopenharmony_ci		cur_def_msgs = cur_max_msgs + 1;
38562306a36Sopenharmony_ci		set(def_msgsize, cur_max_msgsize + 1);
38662306a36Sopenharmony_ci		cur_def_msgsize = cur_max_msgsize + 1;
38762306a36Sopenharmony_ci		if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
38862306a36Sopenharmony_ci		    cur_limits.rlim_cur) {
38962306a36Sopenharmony_ci			cur_limits.rlim_cur = (cur_def_msgs + 2) *
39062306a36Sopenharmony_ci				(cur_def_msgsize + 2 * sizeof(void *));
39162306a36Sopenharmony_ci			cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
39262306a36Sopenharmony_ci			setr(RLIMIT_MSGQUEUE, &cur_limits);
39362306a36Sopenharmony_ci		}
39462306a36Sopenharmony_ci		if (test_queue_fail(NULL, &result)) {
39562306a36Sopenharmony_ci			if (result.mq_maxmsg == cur_max_msgs &&
39662306a36Sopenharmony_ci			    result.mq_msgsize == cur_max_msgsize)
39762306a36Sopenharmony_ci				printf("Kernel properly limits default values "
39862306a36Sopenharmony_ci				       "to lesser of default/max:\t\tPASS\n");
39962306a36Sopenharmony_ci			else
40062306a36Sopenharmony_ci				printf("Kernel does not properly set default "
40162306a36Sopenharmony_ci				       "queue parameters when\ndefaults > "
40262306a36Sopenharmony_ci				       "max:\t\t\t\t\t\t\t\tFAIL\n");
40362306a36Sopenharmony_ci		} else
40462306a36Sopenharmony_ci			printf("Kernel fails to open mq because defaults are "
40562306a36Sopenharmony_ci			       "greater than maximums:\tFAIL\n");
40662306a36Sopenharmony_ci		set(def_msgs, --cur_def_msgs);
40762306a36Sopenharmony_ci		set(def_msgsize, --cur_def_msgsize);
40862306a36Sopenharmony_ci		cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
40962306a36Sopenharmony_ci			cur_def_msgsize;
41062306a36Sopenharmony_ci		setr(RLIMIT_MSGQUEUE, &cur_limits);
41162306a36Sopenharmony_ci		if (test_queue_fail(NULL, &result))
41262306a36Sopenharmony_ci			printf("Kernel creates queue even though defaults "
41362306a36Sopenharmony_ci			       "would exceed\nrlimit setting:"
41462306a36Sopenharmony_ci			       "\t\t\t\t\t\t\t\tFAIL\n");
41562306a36Sopenharmony_ci		else
41662306a36Sopenharmony_ci			printf("Kernel properly fails to create queue when "
41762306a36Sopenharmony_ci			       "defaults would\nexceed rlimit:"
41862306a36Sopenharmony_ci			       "\t\t\t\t\t\t\t\tPASS\n");
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/*
42262306a36Sopenharmony_ci	 * Test #2 - open with an attr struct that exceeds rlimit
42362306a36Sopenharmony_ci	 */
42462306a36Sopenharmony_ci	printf("\n\nTest series 2, behavior when attr struct is "
42562306a36Sopenharmony_ci	       "passed to mq_open:\n");
42662306a36Sopenharmony_ci	cur_max_msgs = 32;
42762306a36Sopenharmony_ci	cur_max_msgsize = cur_limits.rlim_max >> 4;
42862306a36Sopenharmony_ci	set(max_msgs, cur_max_msgs);
42962306a36Sopenharmony_ci	set(max_msgsize, cur_max_msgsize);
43062306a36Sopenharmony_ci	attr.mq_maxmsg = cur_max_msgs;
43162306a36Sopenharmony_ci	attr.mq_msgsize = cur_max_msgsize;
43262306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
43362306a36Sopenharmony_ci		printf("Queue open in excess of rlimit max when euid = 0 "
43462306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
43562306a36Sopenharmony_ci	else
43662306a36Sopenharmony_ci		printf("Queue open in excess of rlimit max when euid = 0 "
43762306a36Sopenharmony_ci		       "failed:\t\tPASS\n");
43862306a36Sopenharmony_ci	attr.mq_maxmsg = cur_max_msgs + 1;
43962306a36Sopenharmony_ci	attr.mq_msgsize = 10;
44062306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
44162306a36Sopenharmony_ci		printf("Queue open with mq_maxmsg > limit when euid = 0 "
44262306a36Sopenharmony_ci		       "succeeded:\t\tPASS\n");
44362306a36Sopenharmony_ci	else
44462306a36Sopenharmony_ci		printf("Queue open with mq_maxmsg > limit when euid = 0 "
44562306a36Sopenharmony_ci		       "failed:\t\tFAIL\n");
44662306a36Sopenharmony_ci	attr.mq_maxmsg = 1;
44762306a36Sopenharmony_ci	attr.mq_msgsize = cur_max_msgsize + 1;
44862306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
44962306a36Sopenharmony_ci		printf("Queue open with mq_msgsize > limit when euid = 0 "
45062306a36Sopenharmony_ci		       "succeeded:\t\tPASS\n");
45162306a36Sopenharmony_ci	else
45262306a36Sopenharmony_ci		printf("Queue open with mq_msgsize > limit when euid = 0 "
45362306a36Sopenharmony_ci		       "failed:\t\tFAIL\n");
45462306a36Sopenharmony_ci	attr.mq_maxmsg = 65536;
45562306a36Sopenharmony_ci	attr.mq_msgsize = 65536;
45662306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
45762306a36Sopenharmony_ci		printf("Queue open with total size > 2GB when euid = 0 "
45862306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
45962306a36Sopenharmony_ci	else
46062306a36Sopenharmony_ci		printf("Queue open with total size > 2GB when euid = 0 "
46162306a36Sopenharmony_ci		       "failed:\t\t\tPASS\n");
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (seteuid(99) == -1) {
46462306a36Sopenharmony_ci		perror("seteuid() failed");
46562306a36Sopenharmony_ci		exit(1);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	attr.mq_maxmsg = cur_max_msgs;
46962306a36Sopenharmony_ci	attr.mq_msgsize = cur_max_msgsize;
47062306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
47162306a36Sopenharmony_ci		printf("Queue open in excess of rlimit max when euid = 99 "
47262306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
47362306a36Sopenharmony_ci	else
47462306a36Sopenharmony_ci		printf("Queue open in excess of rlimit max when euid = 99 "
47562306a36Sopenharmony_ci		       "failed:\t\tPASS\n");
47662306a36Sopenharmony_ci	attr.mq_maxmsg = cur_max_msgs + 1;
47762306a36Sopenharmony_ci	attr.mq_msgsize = 10;
47862306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
47962306a36Sopenharmony_ci		printf("Queue open with mq_maxmsg > limit when euid = 99 "
48062306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
48162306a36Sopenharmony_ci	else
48262306a36Sopenharmony_ci		printf("Queue open with mq_maxmsg > limit when euid = 99 "
48362306a36Sopenharmony_ci		       "failed:\t\tPASS\n");
48462306a36Sopenharmony_ci	attr.mq_maxmsg = 1;
48562306a36Sopenharmony_ci	attr.mq_msgsize = cur_max_msgsize + 1;
48662306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
48762306a36Sopenharmony_ci		printf("Queue open with mq_msgsize > limit when euid = 99 "
48862306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
48962306a36Sopenharmony_ci	else
49062306a36Sopenharmony_ci		printf("Queue open with mq_msgsize > limit when euid = 99 "
49162306a36Sopenharmony_ci		       "failed:\t\tPASS\n");
49262306a36Sopenharmony_ci	attr.mq_maxmsg = 65536;
49362306a36Sopenharmony_ci	attr.mq_msgsize = 65536;
49462306a36Sopenharmony_ci	if (test_queue_fail(&attr, &result))
49562306a36Sopenharmony_ci		printf("Queue open with total size > 2GB when euid = 99 "
49662306a36Sopenharmony_ci		       "succeeded:\t\tFAIL\n");
49762306a36Sopenharmony_ci	else
49862306a36Sopenharmony_ci		printf("Queue open with total size > 2GB when euid = 99 "
49962306a36Sopenharmony_ci		       "failed:\t\t\tPASS\n");
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	shutdown(0,"",0);
50262306a36Sopenharmony_ci}
503