Linux Audio

Check our new training course

Loading...
v4.10.11
  1/*
  2 * This application is Copyright 2012 Red Hat, Inc.
  3 *	Doug Ledford <dledford@redhat.com>
  4 *
  5 * mq_open_tests is free software: you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation, version 3.
  8 *
  9 * mq_open_tests is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
 15 *
 16 * mq_open_tests.c
 17 *   Tests the various situations that should either succeed or fail to
 18 *   open a posix message queue and then reports whether or not they
 19 *   did as they were supposed to.
 20 *
 21 */
 22#include <stdio.h>
 23#include <stdlib.h>
 24#include <unistd.h>
 25#include <fcntl.h>
 26#include <string.h>
 27#include <limits.h>
 28#include <errno.h>
 29#include <sys/types.h>
 30#include <sys/time.h>
 31#include <sys/resource.h>
 32#include <sys/stat.h>
 33#include <mqueue.h>
 34#include <error.h>
 35
 36static char *usage =
 37"Usage:\n"
 38"  %s path\n"
 39"\n"
 40"	path	Path name of the message queue to create\n"
 41"\n"
 42"	Note: this program must be run as root in order to enable all tests\n"
 43"\n";
 44
 45char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
 46char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
 47char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
 48char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
 49
 50int default_settings;
 51struct rlimit saved_limits, cur_limits;
 52int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
 53int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
 54FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
 55char *queue_path;
 56mqd_t queue = -1;
 57
 58static inline void __set(FILE *stream, int value, char *err_msg);
 59void shutdown(int exit_val, char *err_cause, int line_no);
 60static inline int get(FILE *stream);
 61static inline void set(FILE *stream, int value);
 62static inline void getr(int type, struct rlimit *rlim);
 63static inline void setr(int type, struct rlimit *rlim);
 64void validate_current_settings();
 65static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
 66static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
 67
 68static inline void __set(FILE *stream, int value, char *err_msg)
 69{
 70	rewind(stream);
 71	if (fprintf(stream, "%d", value) < 0)
 72		perror(err_msg);
 73}
 74
 75
 76void shutdown(int exit_val, char *err_cause, int line_no)
 77{
 78	static int in_shutdown = 0;
 79
 80	/* In case we get called recursively by a set() call below */
 81	if (in_shutdown++)
 82		return;
 83
 84	if (seteuid(0) == -1)
 85		perror("seteuid() failed");
 86
 87	if (queue != -1)
 88		if (mq_close(queue))
 89			perror("mq_close() during shutdown");
 90	if (queue_path)
 91		/*
 92		 * Be silent if this fails, if we cleaned up already it's
 93		 * expected to fail
 94		 */
 95		mq_unlink(queue_path);
 96	if (default_settings) {
 97		if (saved_def_msgs)
 98			__set(def_msgs, saved_def_msgs,
 99			      "failed to restore saved_def_msgs");
100		if (saved_def_msgsize)
101			__set(def_msgsize, saved_def_msgsize,
102			      "failed to restore saved_def_msgsize");
103	}
104	if (saved_max_msgs)
105		__set(max_msgs, saved_max_msgs,
106		      "failed to restore saved_max_msgs");
107	if (saved_max_msgsize)
108		__set(max_msgsize, saved_max_msgsize,
109		      "failed to restore saved_max_msgsize");
110	if (exit_val)
111		error(exit_val, errno, "%s at %d", err_cause, line_no);
112	exit(0);
113}
114
115static inline int get(FILE *stream)
116{
117	int value;
118	rewind(stream);
119	if (fscanf(stream, "%d", &value) != 1)
120		shutdown(4, "Error reading /proc entry", __LINE__ - 1);
121	return value;
122}
123
124static inline void set(FILE *stream, int value)
125{
126	int new_value;
127
128	rewind(stream);
129	if (fprintf(stream, "%d", value) < 0)
130		return shutdown(5, "Failed writing to /proc file",
131				__LINE__ - 1);
132	new_value = get(stream);
133	if (new_value != value)
134		return shutdown(5, "We didn't get what we wrote to /proc back",
135				__LINE__ - 1);
136}
137
138static inline void getr(int type, struct rlimit *rlim)
139{
140	if (getrlimit(type, rlim))
141		shutdown(6, "getrlimit()", __LINE__ - 1);
142}
143
144static inline void setr(int type, struct rlimit *rlim)
145{
146	if (setrlimit(type, rlim))
147		shutdown(7, "setrlimit()", __LINE__ - 1);
148}
149
150void validate_current_settings()
151{
152	int rlim_needed;
153
154	if (cur_limits.rlim_cur < 4096) {
155		printf("Current rlimit value for POSIX message queue bytes is "
156		       "unreasonably low,\nincreasing.\n\n");
157		cur_limits.rlim_cur = 8192;
158		cur_limits.rlim_max = 16384;
159		setr(RLIMIT_MSGQUEUE, &cur_limits);
160	}
161
162	if (default_settings) {
163		rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
164						    2 * sizeof(void *));
165		if (rlim_needed > cur_limits.rlim_cur) {
166			printf("Temporarily lowering default queue parameters "
167			       "to something that will work\n"
168			       "with the current rlimit values.\n\n");
169			set(def_msgs, 10);
170			cur_def_msgs = 10;
171			set(def_msgsize, 128);
172			cur_def_msgsize = 128;
173		}
174	} else {
175		rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
176						    2 * sizeof(void *));
177		if (rlim_needed > cur_limits.rlim_cur) {
178			printf("Temporarily lowering maximum queue parameters "
179			       "to something that will work\n"
180			       "with the current rlimit values in case this is "
181			       "a kernel that ties the default\n"
182			       "queue parameters to the maximum queue "
183			       "parameters.\n\n");
184			set(max_msgs, 10);
185			cur_max_msgs = 10;
186			set(max_msgsize, 128);
187			cur_max_msgsize = 128;
188		}
189	}
190}
191
192/*
193 * test_queue - Test opening a queue, shutdown if we fail.  This should
194 * only be called in situations that should never fail.  We clean up
195 * after ourselves and return the queue attributes in *result.
196 */
197static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
198{
199	int flags = O_RDWR | O_EXCL | O_CREAT;
200	int perms = DEFFILEMODE;
201
202	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
203		shutdown(1, "mq_open()", __LINE__);
204	if (mq_getattr(queue, result))
205		shutdown(1, "mq_getattr()", __LINE__);
206	if (mq_close(queue))
207		shutdown(1, "mq_close()", __LINE__);
208	queue = -1;
209	if (mq_unlink(queue_path))
210		shutdown(1, "mq_unlink()", __LINE__);
211}
212
213/*
214 * Same as test_queue above, but failure is not fatal.
215 * Returns:
216 * 0 - Failed to create a queue
217 * 1 - Created a queue, attributes in *result
218 */
219static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
220{
221	int flags = O_RDWR | O_EXCL | O_CREAT;
222	int perms = DEFFILEMODE;
223
224	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
225		return 0;
226	if (mq_getattr(queue, result))
227		shutdown(1, "mq_getattr()", __LINE__);
228	if (mq_close(queue))
229		shutdown(1, "mq_close()", __LINE__);
230	queue = -1;
231	if (mq_unlink(queue_path))
232		shutdown(1, "mq_unlink()", __LINE__);
233	return 1;
234}
235
236int main(int argc, char *argv[])
237{
238	struct mq_attr attr, result;
239
240	if (argc != 2) {
241		fprintf(stderr, "Must pass a valid queue name\n\n");
242		fprintf(stderr, usage, argv[0]);
243		exit(1);
244	}
245
246	/*
247	 * Although we can create a msg queue with a non-absolute path name,
248	 * unlink will fail.  So, if the name doesn't start with a /, add one
249	 * when we save it.
250	 */
251	if (*argv[1] == '/')
252		queue_path = strdup(argv[1]);
253	else {
254		queue_path = malloc(strlen(argv[1]) + 2);
255		if (!queue_path) {
256			perror("malloc()");
257			exit(1);
258		}
259		queue_path[0] = '/';
260		queue_path[1] = 0;
261		strcat(queue_path, argv[1]);
262	}
263
264	if (getuid() != 0) {
265		fprintf(stderr, "Not running as root, but almost all tests "
266			"require root in order to modify\nsystem settings.  "
267			"Exiting.\n");
268		exit(1);
269	}
270
271	/* Find out what files there are for us to make tweaks in */
272	def_msgs = fopen(DEF_MSGS, "r+");
273	def_msgsize = fopen(DEF_MSGSIZE, "r+");
274	max_msgs = fopen(MAX_MSGS, "r+");
275	max_msgsize = fopen(MAX_MSGSIZE, "r+");
276
277	if (!max_msgs)
278		shutdown(2, "Failed to open msg_max", __LINE__);
279	if (!max_msgsize)
280		shutdown(2, "Failed to open msgsize_max", __LINE__);
281	if (def_msgs || def_msgsize)
282		default_settings = 1;
283
284	/* Load up the current system values for everything we can */
285	getr(RLIMIT_MSGQUEUE, &saved_limits);
286	cur_limits = saved_limits;
287	if (default_settings) {
288		saved_def_msgs = cur_def_msgs = get(def_msgs);
289		saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
290	}
291	saved_max_msgs = cur_max_msgs = get(max_msgs);
292	saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
293
294	/* Tell the user our initial state */
295	printf("\nInitial system state:\n");
296	printf("\tUsing queue path:\t\t%s\n", queue_path);
297	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
298		(long) saved_limits.rlim_cur);
299	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
300		(long) saved_limits.rlim_max);
301	printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
302	printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
303	if (default_settings) {
304		printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
305		printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
306	} else {
307		printf("\tDefault Message Size:\t\tNot Supported\n");
308		printf("\tDefault Queue Size:\t\tNot Supported\n");
309	}
310	printf("\n");
311
312	validate_current_settings();
313
314	printf("Adjusted system state for testing:\n");
315	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
316	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
317	printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
318	printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
319	if (default_settings) {
320		printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
321		printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
322	}
323
324	printf("\n\nTest series 1, behavior when no attr struct "
325	       "passed to mq_open:\n");
326	if (!default_settings) {
327		test_queue(NULL, &result);
328		printf("Given sane system settings, mq_open without an attr "
329		       "struct succeeds:\tPASS\n");
330		if (result.mq_maxmsg != cur_max_msgs ||
331		    result.mq_msgsize != cur_max_msgsize) {
332			printf("Kernel does not support setting the default "
333			       "mq attributes,\nbut also doesn't tie the "
334			       "defaults to the maximums:\t\t\tPASS\n");
335		} else {
336			set(max_msgs, ++cur_max_msgs);
337			set(max_msgsize, ++cur_max_msgsize);
338			test_queue(NULL, &result);
339			if (result.mq_maxmsg == cur_max_msgs &&
340			    result.mq_msgsize == cur_max_msgsize)
341				printf("Kernel does not support setting the "
342				       "default mq attributes and\n"
343				       "also ties system wide defaults to "
344				       "the system wide maximums:\t\t"
345				       "FAIL\n");
346			else
347				printf("Kernel does not support setting the "
348				       "default mq attributes,\n"
349				       "but also doesn't tie the defaults to "
350				       "the maximums:\t\t\tPASS\n");
351		}
352	} else {
353		printf("Kernel supports setting defaults separately from "
354		       "maximums:\t\tPASS\n");
355		/*
356		 * While we are here, go ahead and test that the kernel
357		 * properly follows the default settings
358		 */
359		test_queue(NULL, &result);
360		printf("Given sane values, mq_open without an attr struct "
361		       "succeeds:\t\tPASS\n");
362		if (result.mq_maxmsg != cur_def_msgs ||
363		    result.mq_msgsize != cur_def_msgsize)
364			printf("Kernel supports setting defaults, but does "
365			       "not actually honor them:\tFAIL\n\n");
366		else {
367			set(def_msgs, ++cur_def_msgs);
368			set(def_msgsize, ++cur_def_msgsize);
369			/* In case max was the same as the default */
370			set(max_msgs, ++cur_max_msgs);
371			set(max_msgsize, ++cur_max_msgsize);
372			test_queue(NULL, &result);
373			if (result.mq_maxmsg != cur_def_msgs ||
374			    result.mq_msgsize != cur_def_msgsize)
375				printf("Kernel supports setting defaults, but "
376				       "does not actually honor them:\t"
377				       "FAIL\n");
378			else
379				printf("Kernel properly honors default setting "
380				       "knobs:\t\t\t\tPASS\n");
381		}
382		set(def_msgs, cur_max_msgs + 1);
383		cur_def_msgs = cur_max_msgs + 1;
384		set(def_msgsize, cur_max_msgsize + 1);
385		cur_def_msgsize = cur_max_msgsize + 1;
386		if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
387		    cur_limits.rlim_cur) {
388			cur_limits.rlim_cur = (cur_def_msgs + 2) *
389				(cur_def_msgsize + 2 * sizeof(void *));
390			cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
391			setr(RLIMIT_MSGQUEUE, &cur_limits);
392		}
393		if (test_queue_fail(NULL, &result)) {
394			if (result.mq_maxmsg == cur_max_msgs &&
395			    result.mq_msgsize == cur_max_msgsize)
396				printf("Kernel properly limits default values "
397				       "to lesser of default/max:\t\tPASS\n");
398			else
399				printf("Kernel does not properly set default "
400				       "queue parameters when\ndefaults > "
401				       "max:\t\t\t\t\t\t\t\tFAIL\n");
402		} else
403			printf("Kernel fails to open mq because defaults are "
404			       "greater than maximums:\tFAIL\n");
405		set(def_msgs, --cur_def_msgs);
406		set(def_msgsize, --cur_def_msgsize);
407		cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
408			cur_def_msgsize;
409		setr(RLIMIT_MSGQUEUE, &cur_limits);
410		if (test_queue_fail(NULL, &result))
411			printf("Kernel creates queue even though defaults "
412			       "would exceed\nrlimit setting:"
413			       "\t\t\t\t\t\t\t\tFAIL\n");
414		else
415			printf("Kernel properly fails to create queue when "
416			       "defaults would\nexceed rlimit:"
417			       "\t\t\t\t\t\t\t\tPASS\n");
418	}
419
420	/*
421	 * Test #2 - open with an attr struct that exceeds rlimit
422	 */
423	printf("\n\nTest series 2, behavior when attr struct is "
424	       "passed to mq_open:\n");
425	cur_max_msgs = 32;
426	cur_max_msgsize = cur_limits.rlim_max >> 4;
427	set(max_msgs, cur_max_msgs);
428	set(max_msgsize, cur_max_msgsize);
429	attr.mq_maxmsg = cur_max_msgs;
430	attr.mq_msgsize = cur_max_msgsize;
431	if (test_queue_fail(&attr, &result))
432		printf("Queue open in excess of rlimit max when euid = 0 "
433		       "succeeded:\t\tFAIL\n");
434	else
435		printf("Queue open in excess of rlimit max when euid = 0 "
436		       "failed:\t\tPASS\n");
437	attr.mq_maxmsg = cur_max_msgs + 1;
438	attr.mq_msgsize = 10;
439	if (test_queue_fail(&attr, &result))
440		printf("Queue open with mq_maxmsg > limit when euid = 0 "
441		       "succeeded:\t\tPASS\n");
442	else
443		printf("Queue open with mq_maxmsg > limit when euid = 0 "
444		       "failed:\t\tFAIL\n");
445	attr.mq_maxmsg = 1;
446	attr.mq_msgsize = cur_max_msgsize + 1;
447	if (test_queue_fail(&attr, &result))
448		printf("Queue open with mq_msgsize > limit when euid = 0 "
449		       "succeeded:\t\tPASS\n");
450	else
451		printf("Queue open with mq_msgsize > limit when euid = 0 "
452		       "failed:\t\tFAIL\n");
453	attr.mq_maxmsg = 65536;
454	attr.mq_msgsize = 65536;
455	if (test_queue_fail(&attr, &result))
456		printf("Queue open with total size > 2GB when euid = 0 "
457		       "succeeded:\t\tFAIL\n");
458	else
459		printf("Queue open with total size > 2GB when euid = 0 "
460		       "failed:\t\t\tPASS\n");
461
462	if (seteuid(99) == -1) {
463		perror("seteuid() failed");
464		exit(1);
465	}
466
467	attr.mq_maxmsg = cur_max_msgs;
468	attr.mq_msgsize = cur_max_msgsize;
469	if (test_queue_fail(&attr, &result))
470		printf("Queue open in excess of rlimit max when euid = 99 "
471		       "succeeded:\t\tFAIL\n");
472	else
473		printf("Queue open in excess of rlimit max when euid = 99 "
474		       "failed:\t\tPASS\n");
475	attr.mq_maxmsg = cur_max_msgs + 1;
476	attr.mq_msgsize = 10;
477	if (test_queue_fail(&attr, &result))
478		printf("Queue open with mq_maxmsg > limit when euid = 99 "
479		       "succeeded:\t\tFAIL\n");
480	else
481		printf("Queue open with mq_maxmsg > limit when euid = 99 "
482		       "failed:\t\tPASS\n");
483	attr.mq_maxmsg = 1;
484	attr.mq_msgsize = cur_max_msgsize + 1;
485	if (test_queue_fail(&attr, &result))
486		printf("Queue open with mq_msgsize > limit when euid = 99 "
487		       "succeeded:\t\tFAIL\n");
488	else
489		printf("Queue open with mq_msgsize > limit when euid = 99 "
490		       "failed:\t\tPASS\n");
491	attr.mq_maxmsg = 65536;
492	attr.mq_msgsize = 65536;
493	if (test_queue_fail(&attr, &result))
494		printf("Queue open with total size > 2GB when euid = 99 "
495		       "succeeded:\t\tFAIL\n");
496	else
497		printf("Queue open with total size > 2GB when euid = 99 "
498		       "failed:\t\t\tPASS\n");
499
500	shutdown(0,"",0);
501}
v3.15
  1/*
  2 * This application is Copyright 2012 Red Hat, Inc.
  3 *	Doug Ledford <dledford@redhat.com>
  4 *
  5 * mq_open_tests is free software: you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation, version 3.
  8 *
  9 * mq_open_tests is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
 15 *
 16 * mq_open_tests.c
 17 *   Tests the various situations that should either succeed or fail to
 18 *   open a posix message queue and then reports whether or not they
 19 *   did as they were supposed to.
 20 *
 21 */
 22#include <stdio.h>
 23#include <stdlib.h>
 24#include <unistd.h>
 25#include <fcntl.h>
 26#include <string.h>
 27#include <limits.h>
 28#include <errno.h>
 29#include <sys/types.h>
 30#include <sys/time.h>
 31#include <sys/resource.h>
 32#include <sys/stat.h>
 33#include <mqueue.h>
 
 34
 35static char *usage =
 36"Usage:\n"
 37"  %s path\n"
 38"\n"
 39"	path	Path name of the message queue to create\n"
 40"\n"
 41"	Note: this program must be run as root in order to enable all tests\n"
 42"\n";
 43
 44char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
 45char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
 46char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
 47char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
 48
 49int default_settings;
 50struct rlimit saved_limits, cur_limits;
 51int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
 52int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
 53FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
 54char *queue_path;
 55mqd_t queue = -1;
 56
 57static inline void __set(FILE *stream, int value, char *err_msg);
 58void shutdown(int exit_val, char *err_cause, int line_no);
 59static inline int get(FILE *stream);
 60static inline void set(FILE *stream, int value);
 61static inline void getr(int type, struct rlimit *rlim);
 62static inline void setr(int type, struct rlimit *rlim);
 63void validate_current_settings();
 64static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
 65static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
 66
 67static inline void __set(FILE *stream, int value, char *err_msg)
 68{
 69	rewind(stream);
 70	if (fprintf(stream, "%d", value) < 0)
 71		perror(err_msg);
 72}
 73
 74
 75void shutdown(int exit_val, char *err_cause, int line_no)
 76{
 77	static int in_shutdown = 0;
 78
 79	/* In case we get called recursively by a set() call below */
 80	if (in_shutdown++)
 81		return;
 82
 83	seteuid(0);
 
 84
 85	if (queue != -1)
 86		if (mq_close(queue))
 87			perror("mq_close() during shutdown");
 88	if (queue_path)
 89		/*
 90		 * Be silent if this fails, if we cleaned up already it's
 91		 * expected to fail
 92		 */
 93		mq_unlink(queue_path);
 94	if (default_settings) {
 95		if (saved_def_msgs)
 96			__set(def_msgs, saved_def_msgs,
 97			      "failed to restore saved_def_msgs");
 98		if (saved_def_msgsize)
 99			__set(def_msgsize, saved_def_msgsize,
100			      "failed to restore saved_def_msgsize");
101	}
102	if (saved_max_msgs)
103		__set(max_msgs, saved_max_msgs,
104		      "failed to restore saved_max_msgs");
105	if (saved_max_msgsize)
106		__set(max_msgsize, saved_max_msgsize,
107		      "failed to restore saved_max_msgsize");
108	if (exit_val)
109		error(exit_val, errno, "%s at %d", err_cause, line_no);
110	exit(0);
111}
112
113static inline int get(FILE *stream)
114{
115	int value;
116	rewind(stream);
117	if (fscanf(stream, "%d", &value) != 1)
118		shutdown(4, "Error reading /proc entry", __LINE__ - 1);
119	return value;
120}
121
122static inline void set(FILE *stream, int value)
123{
124	int new_value;
125
126	rewind(stream);
127	if (fprintf(stream, "%d", value) < 0)
128		return shutdown(5, "Failed writing to /proc file",
129				__LINE__ - 1);
130	new_value = get(stream);
131	if (new_value != value)
132		return shutdown(5, "We didn't get what we wrote to /proc back",
133				__LINE__ - 1);
134}
135
136static inline void getr(int type, struct rlimit *rlim)
137{
138	if (getrlimit(type, rlim))
139		shutdown(6, "getrlimit()", __LINE__ - 1);
140}
141
142static inline void setr(int type, struct rlimit *rlim)
143{
144	if (setrlimit(type, rlim))
145		shutdown(7, "setrlimit()", __LINE__ - 1);
146}
147
148void validate_current_settings()
149{
150	int rlim_needed;
151
152	if (cur_limits.rlim_cur < 4096) {
153		printf("Current rlimit value for POSIX message queue bytes is "
154		       "unreasonably low,\nincreasing.\n\n");
155		cur_limits.rlim_cur = 8192;
156		cur_limits.rlim_max = 16384;
157		setr(RLIMIT_MSGQUEUE, &cur_limits);
158	}
159
160	if (default_settings) {
161		rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
162						    2 * sizeof(void *));
163		if (rlim_needed > cur_limits.rlim_cur) {
164			printf("Temporarily lowering default queue parameters "
165			       "to something that will work\n"
166			       "with the current rlimit values.\n\n");
167			set(def_msgs, 10);
168			cur_def_msgs = 10;
169			set(def_msgsize, 128);
170			cur_def_msgsize = 128;
171		}
172	} else {
173		rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
174						    2 * sizeof(void *));
175		if (rlim_needed > cur_limits.rlim_cur) {
176			printf("Temporarily lowering maximum queue parameters "
177			       "to something that will work\n"
178			       "with the current rlimit values in case this is "
179			       "a kernel that ties the default\n"
180			       "queue parameters to the maximum queue "
181			       "parameters.\n\n");
182			set(max_msgs, 10);
183			cur_max_msgs = 10;
184			set(max_msgsize, 128);
185			cur_max_msgsize = 128;
186		}
187	}
188}
189
190/*
191 * test_queue - Test opening a queue, shutdown if we fail.  This should
192 * only be called in situations that should never fail.  We clean up
193 * after ourselves and return the queue attributes in *result.
194 */
195static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
196{
197	int flags = O_RDWR | O_EXCL | O_CREAT;
198	int perms = DEFFILEMODE;
199
200	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
201		shutdown(1, "mq_open()", __LINE__);
202	if (mq_getattr(queue, result))
203		shutdown(1, "mq_getattr()", __LINE__);
204	if (mq_close(queue))
205		shutdown(1, "mq_close()", __LINE__);
206	queue = -1;
207	if (mq_unlink(queue_path))
208		shutdown(1, "mq_unlink()", __LINE__);
209}
210
211/*
212 * Same as test_queue above, but failure is not fatal.
213 * Returns:
214 * 0 - Failed to create a queue
215 * 1 - Created a queue, attributes in *result
216 */
217static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
218{
219	int flags = O_RDWR | O_EXCL | O_CREAT;
220	int perms = DEFFILEMODE;
221
222	if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
223		return 0;
224	if (mq_getattr(queue, result))
225		shutdown(1, "mq_getattr()", __LINE__);
226	if (mq_close(queue))
227		shutdown(1, "mq_close()", __LINE__);
228	queue = -1;
229	if (mq_unlink(queue_path))
230		shutdown(1, "mq_unlink()", __LINE__);
231	return 1;
232}
233
234int main(int argc, char *argv[])
235{
236	struct mq_attr attr, result;
237
238	if (argc != 2) {
239		fprintf(stderr, "Must pass a valid queue name\n\n");
240		fprintf(stderr, usage, argv[0]);
241		exit(1);
242	}
243
244	/*
245	 * Although we can create a msg queue with a non-absolute path name,
246	 * unlink will fail.  So, if the name doesn't start with a /, add one
247	 * when we save it.
248	 */
249	if (*argv[1] == '/')
250		queue_path = strdup(argv[1]);
251	else {
252		queue_path = malloc(strlen(argv[1]) + 2);
253		if (!queue_path) {
254			perror("malloc()");
255			exit(1);
256		}
257		queue_path[0] = '/';
258		queue_path[1] = 0;
259		strcat(queue_path, argv[1]);
260	}
261
262	if (getuid() != 0) {
263		fprintf(stderr, "Not running as root, but almost all tests "
264			"require root in order to modify\nsystem settings.  "
265			"Exiting.\n");
266		exit(1);
267	}
268
269	/* Find out what files there are for us to make tweaks in */
270	def_msgs = fopen(DEF_MSGS, "r+");
271	def_msgsize = fopen(DEF_MSGSIZE, "r+");
272	max_msgs = fopen(MAX_MSGS, "r+");
273	max_msgsize = fopen(MAX_MSGSIZE, "r+");
274
275	if (!max_msgs)
276		shutdown(2, "Failed to open msg_max", __LINE__);
277	if (!max_msgsize)
278		shutdown(2, "Failed to open msgsize_max", __LINE__);
279	if (def_msgs || def_msgsize)
280		default_settings = 1;
281
282	/* Load up the current system values for everything we can */
283	getr(RLIMIT_MSGQUEUE, &saved_limits);
284	cur_limits = saved_limits;
285	if (default_settings) {
286		saved_def_msgs = cur_def_msgs = get(def_msgs);
287		saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
288	}
289	saved_max_msgs = cur_max_msgs = get(max_msgs);
290	saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
291
292	/* Tell the user our initial state */
293	printf("\nInitial system state:\n");
294	printf("\tUsing queue path:\t\t%s\n", queue_path);
295	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
296	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
 
 
297	printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
298	printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
299	if (default_settings) {
300		printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
301		printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
302	} else {
303		printf("\tDefault Message Size:\t\tNot Supported\n");
304		printf("\tDefault Queue Size:\t\tNot Supported\n");
305	}
306	printf("\n");
307
308	validate_current_settings();
309
310	printf("Adjusted system state for testing:\n");
311	printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
312	printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
313	printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
314	printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
315	if (default_settings) {
316		printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
317		printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
318	}
319
320	printf("\n\nTest series 1, behavior when no attr struct "
321	       "passed to mq_open:\n");
322	if (!default_settings) {
323		test_queue(NULL, &result);
324		printf("Given sane system settings, mq_open without an attr "
325		       "struct succeeds:\tPASS\n");
326		if (result.mq_maxmsg != cur_max_msgs ||
327		    result.mq_msgsize != cur_max_msgsize) {
328			printf("Kernel does not support setting the default "
329			       "mq attributes,\nbut also doesn't tie the "
330			       "defaults to the maximums:\t\t\tPASS\n");
331		} else {
332			set(max_msgs, ++cur_max_msgs);
333			set(max_msgsize, ++cur_max_msgsize);
334			test_queue(NULL, &result);
335			if (result.mq_maxmsg == cur_max_msgs &&
336			    result.mq_msgsize == cur_max_msgsize)
337				printf("Kernel does not support setting the "
338				       "default mq attributes and\n"
339				       "also ties system wide defaults to "
340				       "the system wide maximums:\t\t"
341				       "FAIL\n");
342			else
343				printf("Kernel does not support setting the "
344				       "default mq attributes,\n"
345				       "but also doesn't tie the defaults to "
346				       "the maximums:\t\t\tPASS\n");
347		}
348	} else {
349		printf("Kernel supports setting defaults separately from "
350		       "maximums:\t\tPASS\n");
351		/*
352		 * While we are here, go ahead and test that the kernel
353		 * properly follows the default settings
354		 */
355		test_queue(NULL, &result);
356		printf("Given sane values, mq_open without an attr struct "
357		       "succeeds:\t\tPASS\n");
358		if (result.mq_maxmsg != cur_def_msgs ||
359		    result.mq_msgsize != cur_def_msgsize)
360			printf("Kernel supports setting defaults, but does "
361			       "not actually honor them:\tFAIL\n\n");
362		else {
363			set(def_msgs, ++cur_def_msgs);
364			set(def_msgsize, ++cur_def_msgsize);
365			/* In case max was the same as the default */
366			set(max_msgs, ++cur_max_msgs);
367			set(max_msgsize, ++cur_max_msgsize);
368			test_queue(NULL, &result);
369			if (result.mq_maxmsg != cur_def_msgs ||
370			    result.mq_msgsize != cur_def_msgsize)
371				printf("Kernel supports setting defaults, but "
372				       "does not actually honor them:\t"
373				       "FAIL\n");
374			else
375				printf("Kernel properly honors default setting "
376				       "knobs:\t\t\t\tPASS\n");
377		}
378		set(def_msgs, cur_max_msgs + 1);
379		cur_def_msgs = cur_max_msgs + 1;
380		set(def_msgsize, cur_max_msgsize + 1);
381		cur_def_msgsize = cur_max_msgsize + 1;
382		if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
383		    cur_limits.rlim_cur) {
384			cur_limits.rlim_cur = (cur_def_msgs + 2) *
385				(cur_def_msgsize + 2 * sizeof(void *));
386			cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
387			setr(RLIMIT_MSGQUEUE, &cur_limits);
388		}
389		if (test_queue_fail(NULL, &result)) {
390			if (result.mq_maxmsg == cur_max_msgs &&
391			    result.mq_msgsize == cur_max_msgsize)
392				printf("Kernel properly limits default values "
393				       "to lesser of default/max:\t\tPASS\n");
394			else
395				printf("Kernel does not properly set default "
396				       "queue parameters when\ndefaults > "
397				       "max:\t\t\t\t\t\t\t\tFAIL\n");
398		} else
399			printf("Kernel fails to open mq because defaults are "
400			       "greater than maximums:\tFAIL\n");
401		set(def_msgs, --cur_def_msgs);
402		set(def_msgsize, --cur_def_msgsize);
403		cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
404			cur_def_msgsize;
405		setr(RLIMIT_MSGQUEUE, &cur_limits);
406		if (test_queue_fail(NULL, &result))
407			printf("Kernel creates queue even though defaults "
408			       "would exceed\nrlimit setting:"
409			       "\t\t\t\t\t\t\t\tFAIL\n");
410		else
411			printf("Kernel properly fails to create queue when "
412			       "defaults would\nexceed rlimit:"
413			       "\t\t\t\t\t\t\t\tPASS\n");
414	}
415
416	/*
417	 * Test #2 - open with an attr struct that exceeds rlimit
418	 */
419	printf("\n\nTest series 2, behavior when attr struct is "
420	       "passed to mq_open:\n");
421	cur_max_msgs = 32;
422	cur_max_msgsize = cur_limits.rlim_max >> 4;
423	set(max_msgs, cur_max_msgs);
424	set(max_msgsize, cur_max_msgsize);
425	attr.mq_maxmsg = cur_max_msgs;
426	attr.mq_msgsize = cur_max_msgsize;
427	if (test_queue_fail(&attr, &result))
428		printf("Queue open in excess of rlimit max when euid = 0 "
429		       "succeeded:\t\tFAIL\n");
430	else
431		printf("Queue open in excess of rlimit max when euid = 0 "
432		       "failed:\t\tPASS\n");
433	attr.mq_maxmsg = cur_max_msgs + 1;
434	attr.mq_msgsize = 10;
435	if (test_queue_fail(&attr, &result))
436		printf("Queue open with mq_maxmsg > limit when euid = 0 "
437		       "succeeded:\t\tPASS\n");
438	else
439		printf("Queue open with mq_maxmsg > limit when euid = 0 "
440		       "failed:\t\tFAIL\n");
441	attr.mq_maxmsg = 1;
442	attr.mq_msgsize = cur_max_msgsize + 1;
443	if (test_queue_fail(&attr, &result))
444		printf("Queue open with mq_msgsize > limit when euid = 0 "
445		       "succeeded:\t\tPASS\n");
446	else
447		printf("Queue open with mq_msgsize > limit when euid = 0 "
448		       "failed:\t\tFAIL\n");
449	attr.mq_maxmsg = 65536;
450	attr.mq_msgsize = 65536;
451	if (test_queue_fail(&attr, &result))
452		printf("Queue open with total size > 2GB when euid = 0 "
453		       "succeeded:\t\tFAIL\n");
454	else
455		printf("Queue open with total size > 2GB when euid = 0 "
456		       "failed:\t\t\tPASS\n");
457	seteuid(99);
 
 
 
 
 
458	attr.mq_maxmsg = cur_max_msgs;
459	attr.mq_msgsize = cur_max_msgsize;
460	if (test_queue_fail(&attr, &result))
461		printf("Queue open in excess of rlimit max when euid = 99 "
462		       "succeeded:\t\tFAIL\n");
463	else
464		printf("Queue open in excess of rlimit max when euid = 99 "
465		       "failed:\t\tPASS\n");
466	attr.mq_maxmsg = cur_max_msgs + 1;
467	attr.mq_msgsize = 10;
468	if (test_queue_fail(&attr, &result))
469		printf("Queue open with mq_maxmsg > limit when euid = 99 "
470		       "succeeded:\t\tFAIL\n");
471	else
472		printf("Queue open with mq_maxmsg > limit when euid = 99 "
473		       "failed:\t\tPASS\n");
474	attr.mq_maxmsg = 1;
475	attr.mq_msgsize = cur_max_msgsize + 1;
476	if (test_queue_fail(&attr, &result))
477		printf("Queue open with mq_msgsize > limit when euid = 99 "
478		       "succeeded:\t\tFAIL\n");
479	else
480		printf("Queue open with mq_msgsize > limit when euid = 99 "
481		       "failed:\t\tPASS\n");
482	attr.mq_maxmsg = 65536;
483	attr.mq_msgsize = 65536;
484	if (test_queue_fail(&attr, &result))
485		printf("Queue open with total size > 2GB when euid = 99 "
486		       "succeeded:\t\tFAIL\n");
487	else
488		printf("Queue open with total size > 2GB when euid = 99 "
489		       "failed:\t\t\tPASS\n");
490
491	shutdown(0,"",0);
492}