1*0112f8c4SRick Parrish /*-
2*0112f8c4SRick Parrish * SPDX-License-Identifier: BSD-2-Clause
3*0112f8c4SRick Parrish *
4*0112f8c4SRick Parrish * Copyright (c) 2024 Rick Parrish <unitrunker@unitrunker.net>.
5*0112f8c4SRick Parrish *
6*0112f8c4SRick Parrish * Redistribution and use in source and binary forms, with or without
7*0112f8c4SRick Parrish * modification, are permitted provided that the following conditions
8*0112f8c4SRick Parrish * are met:
9*0112f8c4SRick Parrish * 1. Redistributions of source code must retain the above copyright
10*0112f8c4SRick Parrish * notice, this list of conditions and the following disclaimer.
11*0112f8c4SRick Parrish * 2. Redistributions in binary form must reproduce the above copyright
12*0112f8c4SRick Parrish * notice, this list of conditions and the following disclaimer in the
13*0112f8c4SRick Parrish * documentation and/or other materials provided with the distribution.
14*0112f8c4SRick Parrish *
15*0112f8c4SRick Parrish * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*0112f8c4SRick Parrish * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*0112f8c4SRick Parrish * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*0112f8c4SRick Parrish * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*0112f8c4SRick Parrish * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*0112f8c4SRick Parrish * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*0112f8c4SRick Parrish * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*0112f8c4SRick Parrish * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*0112f8c4SRick Parrish * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*0112f8c4SRick Parrish * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*0112f8c4SRick Parrish * SUCH DAMAGE.
26*0112f8c4SRick Parrish */
27*0112f8c4SRick Parrish
28*0112f8c4SRick Parrish #include <sys/queue.h>
29*0112f8c4SRick Parrish #include <sys/stat.h>
30*0112f8c4SRick Parrish #include <err.h>
31*0112f8c4SRick Parrish #include <errno.h>
32*0112f8c4SRick Parrish #include <fcntl.h>
33*0112f8c4SRick Parrish #include <grp.h>
34*0112f8c4SRick Parrish #include <limits.h>
35*0112f8c4SRick Parrish #include <mqueue.h>
36*0112f8c4SRick Parrish #include <pwd.h>
37*0112f8c4SRick Parrish #include <stdbool.h>
38*0112f8c4SRick Parrish #include <stdio.h>
39*0112f8c4SRick Parrish #include <stdlib.h>
40*0112f8c4SRick Parrish #include <string.h>
41*0112f8c4SRick Parrish #include <sysexits.h>
42*0112f8c4SRick Parrish #include <unistd.h>
43*0112f8c4SRick Parrish
44*0112f8c4SRick Parrish struct Creation {
45*0112f8c4SRick Parrish /* true if the queue exists. */
46*0112f8c4SRick Parrish bool exists;
47*0112f8c4SRick Parrish /* true if a mode value was specified. */
48*0112f8c4SRick Parrish bool set_mode;
49*0112f8c4SRick Parrish /* access mode with rwx permission bits. */
50*0112f8c4SRick Parrish mode_t mode;
51*0112f8c4SRick Parrish /* maximum queue depth. default to an invalid depth. */
52*0112f8c4SRick Parrish long depth;
53*0112f8c4SRick Parrish /* maximum message size. default to an invalid size. */
54*0112f8c4SRick Parrish long size;
55*0112f8c4SRick Parrish /* true for blocking I/O and false for non-blocking I/O. */
56*0112f8c4SRick Parrish bool block;
57*0112f8c4SRick Parrish /* true if a group ID was specified. */
58*0112f8c4SRick Parrish bool set_group;
59*0112f8c4SRick Parrish /* group ID. */
60*0112f8c4SRick Parrish gid_t group;
61*0112f8c4SRick Parrish /* true if a user ID was specified. */
62*0112f8c4SRick Parrish bool set_user;
63*0112f8c4SRick Parrish /* user ID. */
64*0112f8c4SRick Parrish uid_t user;
65*0112f8c4SRick Parrish };
66*0112f8c4SRick Parrish
67*0112f8c4SRick Parrish struct element {
68*0112f8c4SRick Parrish STAILQ_ENTRY(element) links;
69*0112f8c4SRick Parrish const char *text;
70*0112f8c4SRick Parrish };
71*0112f8c4SRick Parrish
72*0112f8c4SRick Parrish static struct element *
malloc_element(const char * context)73*0112f8c4SRick Parrish malloc_element(const char *context)
74*0112f8c4SRick Parrish {
75*0112f8c4SRick Parrish struct element *item = malloc(sizeof(struct element));
76*0112f8c4SRick Parrish
77*0112f8c4SRick Parrish if (item == NULL)
78*0112f8c4SRick Parrish /* the only non-EX_* prefixed exit code. */
79*0112f8c4SRick Parrish err(1, "malloc(%s)", context);
80*0112f8c4SRick Parrish return (item);
81*0112f8c4SRick Parrish }
82*0112f8c4SRick Parrish
83*0112f8c4SRick Parrish static STAILQ_HEAD(tqh, element)
84*0112f8c4SRick Parrish queues = STAILQ_HEAD_INITIALIZER(queues),
85*0112f8c4SRick Parrish contents = STAILQ_HEAD_INITIALIZER(contents);
86*0112f8c4SRick Parrish /* send defaults to medium priority. */
87*0112f8c4SRick Parrish static long priority = MQ_PRIO_MAX / 2;
88*0112f8c4SRick Parrish static struct Creation creation = {
89*0112f8c4SRick Parrish .exists = false,
90*0112f8c4SRick Parrish .set_mode = false,
91*0112f8c4SRick Parrish .mode = 0755,
92*0112f8c4SRick Parrish .depth = -1,
93*0112f8c4SRick Parrish .size = -1,
94*0112f8c4SRick Parrish .block = true,
95*0112f8c4SRick Parrish .set_group = false,
96*0112f8c4SRick Parrish .group = 0,
97*0112f8c4SRick Parrish .set_user = false,
98*0112f8c4SRick Parrish .user = 0
99*0112f8c4SRick Parrish };
100*0112f8c4SRick Parrish static const mqd_t fail = (mqd_t)-1;
101*0112f8c4SRick Parrish static const mode_t accepted_mode_bits =
102*0112f8c4SRick Parrish S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISTXT;
103*0112f8c4SRick Parrish
104*0112f8c4SRick Parrish /* OPTIONS parsing utilitarian */
105*0112f8c4SRick Parrish
106*0112f8c4SRick Parrish static void
parse_long(const char * text,long * capture,const char * knob,const char * name)107*0112f8c4SRick Parrish parse_long(const char *text, long *capture, const char *knob, const char *name)
108*0112f8c4SRick Parrish {
109*0112f8c4SRick Parrish char *cursor = NULL;
110*0112f8c4SRick Parrish long value = strtol(text, &cursor, 10);
111*0112f8c4SRick Parrish
112*0112f8c4SRick Parrish if (cursor > text && *cursor == 0) {
113*0112f8c4SRick Parrish *capture = value;
114*0112f8c4SRick Parrish } else {
115*0112f8c4SRick Parrish warnx("%s %s invalid format [%s].", knob, name, text);
116*0112f8c4SRick Parrish }
117*0112f8c4SRick Parrish }
118*0112f8c4SRick Parrish
119*0112f8c4SRick Parrish static void
parse_unsigned(const char * text,bool * set,unsigned * capture,const char * knob,const char * name)120*0112f8c4SRick Parrish parse_unsigned(const char *text, bool *set,
121*0112f8c4SRick Parrish unsigned *capture, const char *knob, const char *name)
122*0112f8c4SRick Parrish {
123*0112f8c4SRick Parrish char *cursor = NULL;
124*0112f8c4SRick Parrish unsigned value = strtoul(text, &cursor, 8);
125*0112f8c4SRick Parrish
126*0112f8c4SRick Parrish if (cursor > text && *cursor == 0) {
127*0112f8c4SRick Parrish *set = true;
128*0112f8c4SRick Parrish *capture = value;
129*0112f8c4SRick Parrish } else {
130*0112f8c4SRick Parrish warnx("%s %s format [%s] ignored.", knob, name, text);
131*0112f8c4SRick Parrish }
132*0112f8c4SRick Parrish }
133*0112f8c4SRick Parrish
134*0112f8c4SRick Parrish static bool
sane_queue(const char * queue)135*0112f8c4SRick Parrish sane_queue(const char *queue)
136*0112f8c4SRick Parrish {
137*0112f8c4SRick Parrish int size = 0;
138*0112f8c4SRick Parrish
139*0112f8c4SRick Parrish if (queue[size] != '/') {
140*0112f8c4SRick Parrish warnx("queue name [%-.*s] must start with '/'.", NAME_MAX, queue);
141*0112f8c4SRick Parrish return (false);
142*0112f8c4SRick Parrish }
143*0112f8c4SRick Parrish
144*0112f8c4SRick Parrish for (size++; queue[size] != 0 && size < NAME_MAX; size++) {
145*0112f8c4SRick Parrish if (queue[size] == '/') {
146*0112f8c4SRick Parrish warnx("queue name [%-.*s] - only one '/' permitted.",
147*0112f8c4SRick Parrish NAME_MAX, queue);
148*0112f8c4SRick Parrish return (false);
149*0112f8c4SRick Parrish }
150*0112f8c4SRick Parrish }
151*0112f8c4SRick Parrish
152*0112f8c4SRick Parrish if (size == NAME_MAX && queue[size] != 0) {
153*0112f8c4SRick Parrish warnx("queue name [%-.*s...] may not be longer than %d.",
154*0112f8c4SRick Parrish NAME_MAX, queue, NAME_MAX);
155*0112f8c4SRick Parrish return (false);
156*0112f8c4SRick Parrish }
157*0112f8c4SRick Parrish return (true);
158*0112f8c4SRick Parrish }
159*0112f8c4SRick Parrish
160*0112f8c4SRick Parrish /* OPTIONS parsers */
161*0112f8c4SRick Parrish
162*0112f8c4SRick Parrish static void
parse_block(const char * text)163*0112f8c4SRick Parrish parse_block(const char *text)
164*0112f8c4SRick Parrish {
165*0112f8c4SRick Parrish if (strcmp(text, "true") == 0 || strcmp(text, "yes") == 0) {
166*0112f8c4SRick Parrish creation.block = true;
167*0112f8c4SRick Parrish } else if (strcmp(text, "false") == 0 || strcmp(text, "no") == 0) {
168*0112f8c4SRick Parrish creation.block = false;
169*0112f8c4SRick Parrish } else {
170*0112f8c4SRick Parrish char *cursor = NULL;
171*0112f8c4SRick Parrish long value = strtol(text, &cursor, 10);
172*0112f8c4SRick Parrish if (cursor > text) {
173*0112f8c4SRick Parrish creation.block = value != 0;
174*0112f8c4SRick Parrish } else {
175*0112f8c4SRick Parrish warnx("bad -b block format [%s] ignored.", text);
176*0112f8c4SRick Parrish }
177*0112f8c4SRick Parrish }
178*0112f8c4SRick Parrish }
179*0112f8c4SRick Parrish
180*0112f8c4SRick Parrish static void
parse_content(const char * content)181*0112f8c4SRick Parrish parse_content(const char *content)
182*0112f8c4SRick Parrish {
183*0112f8c4SRick Parrish struct element *n1 = malloc_element("content");
184*0112f8c4SRick Parrish
185*0112f8c4SRick Parrish n1->text = content;
186*0112f8c4SRick Parrish STAILQ_INSERT_TAIL(&contents, n1, links);
187*0112f8c4SRick Parrish }
188*0112f8c4SRick Parrish
189*0112f8c4SRick Parrish static void
parse_depth(const char * text)190*0112f8c4SRick Parrish parse_depth(const char *text)
191*0112f8c4SRick Parrish {
192*0112f8c4SRick Parrish parse_long(text, &creation.depth, "-d", "depth");
193*0112f8c4SRick Parrish }
194*0112f8c4SRick Parrish
195*0112f8c4SRick Parrish static void
parse_group(const char * text)196*0112f8c4SRick Parrish parse_group(const char *text)
197*0112f8c4SRick Parrish {
198*0112f8c4SRick Parrish struct group *entry = getgrnam(text);
199*0112f8c4SRick Parrish
200*0112f8c4SRick Parrish if (entry == NULL) {
201*0112f8c4SRick Parrish parse_unsigned(text, &creation.set_group,
202*0112f8c4SRick Parrish &creation.group, "-g", "group");
203*0112f8c4SRick Parrish } else {
204*0112f8c4SRick Parrish creation.set_group = true;
205*0112f8c4SRick Parrish creation.group = entry->gr_gid;
206*0112f8c4SRick Parrish }
207*0112f8c4SRick Parrish }
208*0112f8c4SRick Parrish
209*0112f8c4SRick Parrish static void
parse_mode(const char * text)210*0112f8c4SRick Parrish parse_mode(const char *text)
211*0112f8c4SRick Parrish {
212*0112f8c4SRick Parrish char *cursor = NULL;
213*0112f8c4SRick Parrish long value = strtol(text, &cursor, 8);
214*0112f8c4SRick Parrish
215*0112f8c4SRick Parrish // verify only accepted mode bits are set.
216*0112f8c4SRick Parrish if (cursor > text && *cursor == 0 && (value & accepted_mode_bits) == value) {
217*0112f8c4SRick Parrish creation.set_mode = true;
218*0112f8c4SRick Parrish creation.mode = (mode_t)value;
219*0112f8c4SRick Parrish } else {
220*0112f8c4SRick Parrish warnx("impossible -m mode value [%s] ignored.", text);
221*0112f8c4SRick Parrish }
222*0112f8c4SRick Parrish }
223*0112f8c4SRick Parrish
224*0112f8c4SRick Parrish static void
parse_priority(const char * text)225*0112f8c4SRick Parrish parse_priority(const char *text)
226*0112f8c4SRick Parrish {
227*0112f8c4SRick Parrish char *cursor = NULL;
228*0112f8c4SRick Parrish long value = strtol(text, &cursor, 10);
229*0112f8c4SRick Parrish
230*0112f8c4SRick Parrish if (cursor > text && *cursor == 0) {
231*0112f8c4SRick Parrish if (value >= 0 && value < MQ_PRIO_MAX) {
232*0112f8c4SRick Parrish priority = value;
233*0112f8c4SRick Parrish } else {
234*0112f8c4SRick Parrish warnx("bad -p priority range [%s] ignored.", text);
235*0112f8c4SRick Parrish }
236*0112f8c4SRick Parrish } else {
237*0112f8c4SRick Parrish warnx("bad -p priority format [%s] ignored.", text);
238*0112f8c4SRick Parrish }
239*0112f8c4SRick Parrish }
240*0112f8c4SRick Parrish
241*0112f8c4SRick Parrish static void
parse_queue(const char * queue)242*0112f8c4SRick Parrish parse_queue(const char *queue)
243*0112f8c4SRick Parrish {
244*0112f8c4SRick Parrish if (sane_queue(queue)) {
245*0112f8c4SRick Parrish struct element *n1 = malloc_element("queue name");
246*0112f8c4SRick Parrish
247*0112f8c4SRick Parrish n1->text = queue;
248*0112f8c4SRick Parrish STAILQ_INSERT_TAIL(&queues, n1, links);
249*0112f8c4SRick Parrish }
250*0112f8c4SRick Parrish }
251*0112f8c4SRick Parrish
252*0112f8c4SRick Parrish static void
parse_single_queue(const char * queue)253*0112f8c4SRick Parrish parse_single_queue(const char *queue)
254*0112f8c4SRick Parrish {
255*0112f8c4SRick Parrish if (sane_queue(queue)) {
256*0112f8c4SRick Parrish if (STAILQ_EMPTY(&queues)) {
257*0112f8c4SRick Parrish struct element *n1 = malloc_element("queue name");
258*0112f8c4SRick Parrish
259*0112f8c4SRick Parrish n1->text = queue;
260*0112f8c4SRick Parrish STAILQ_INSERT_TAIL(&queues, n1, links);
261*0112f8c4SRick Parrish } else
262*0112f8c4SRick Parrish warnx("ignoring extra -q queue [%s].", queue);
263*0112f8c4SRick Parrish }
264*0112f8c4SRick Parrish }
265*0112f8c4SRick Parrish
266*0112f8c4SRick Parrish static void
parse_size(const char * text)267*0112f8c4SRick Parrish parse_size(const char *text)
268*0112f8c4SRick Parrish {
269*0112f8c4SRick Parrish parse_long(text, &creation.size, "-s", "size");
270*0112f8c4SRick Parrish }
271*0112f8c4SRick Parrish
272*0112f8c4SRick Parrish static void
parse_user(const char * text)273*0112f8c4SRick Parrish parse_user(const char *text)
274*0112f8c4SRick Parrish {
275*0112f8c4SRick Parrish struct passwd *entry = getpwnam(text);
276*0112f8c4SRick Parrish if (entry == NULL) {
277*0112f8c4SRick Parrish parse_unsigned(text, &creation.set_user,
278*0112f8c4SRick Parrish &creation.user, "-u", "user");
279*0112f8c4SRick Parrish } else {
280*0112f8c4SRick Parrish creation.set_user = true;
281*0112f8c4SRick Parrish creation.user = entry->pw_uid;
282*0112f8c4SRick Parrish }
283*0112f8c4SRick Parrish }
284*0112f8c4SRick Parrish
285*0112f8c4SRick Parrish /* OPTIONS validators */
286*0112f8c4SRick Parrish
287*0112f8c4SRick Parrish static bool
validate_always_true(void)288*0112f8c4SRick Parrish validate_always_true(void)
289*0112f8c4SRick Parrish {
290*0112f8c4SRick Parrish return (true);
291*0112f8c4SRick Parrish }
292*0112f8c4SRick Parrish
293*0112f8c4SRick Parrish static bool
validate_content(void)294*0112f8c4SRick Parrish validate_content(void)
295*0112f8c4SRick Parrish {
296*0112f8c4SRick Parrish bool valid = !STAILQ_EMPTY(&contents);
297*0112f8c4SRick Parrish
298*0112f8c4SRick Parrish if (!valid)
299*0112f8c4SRick Parrish warnx("no content to send.");
300*0112f8c4SRick Parrish return (valid);
301*0112f8c4SRick Parrish }
302*0112f8c4SRick Parrish
303*0112f8c4SRick Parrish static bool
validate_depth(void)304*0112f8c4SRick Parrish validate_depth(void)
305*0112f8c4SRick Parrish {
306*0112f8c4SRick Parrish bool valid = creation.exists || creation.depth > 0;
307*0112f8c4SRick Parrish
308*0112f8c4SRick Parrish if (!valid)
309*0112f8c4SRick Parrish warnx("-d maximum queue depth not provided.");
310*0112f8c4SRick Parrish return (valid);
311*0112f8c4SRick Parrish }
312*0112f8c4SRick Parrish
313*0112f8c4SRick Parrish static bool
validate_queue(void)314*0112f8c4SRick Parrish validate_queue(void)
315*0112f8c4SRick Parrish {
316*0112f8c4SRick Parrish bool valid = !STAILQ_EMPTY(&queues);
317*0112f8c4SRick Parrish
318*0112f8c4SRick Parrish if (!valid)
319*0112f8c4SRick Parrish warnx("missing -q, or no sane queue name given.");
320*0112f8c4SRick Parrish return (valid);
321*0112f8c4SRick Parrish }
322*0112f8c4SRick Parrish
323*0112f8c4SRick Parrish static bool
validate_single_queue(void)324*0112f8c4SRick Parrish validate_single_queue(void)
325*0112f8c4SRick Parrish {
326*0112f8c4SRick Parrish bool valid = !STAILQ_EMPTY(&queues) &&
327*0112f8c4SRick Parrish STAILQ_NEXT(STAILQ_FIRST(&queues), links) == NULL;
328*0112f8c4SRick Parrish
329*0112f8c4SRick Parrish if (!valid)
330*0112f8c4SRick Parrish warnx("expected one queue.");
331*0112f8c4SRick Parrish return (valid);
332*0112f8c4SRick Parrish }
333*0112f8c4SRick Parrish
334*0112f8c4SRick Parrish static bool
validate_size(void)335*0112f8c4SRick Parrish validate_size(void)
336*0112f8c4SRick Parrish {
337*0112f8c4SRick Parrish bool valid = creation.exists || creation.size > 0;
338*0112f8c4SRick Parrish
339*0112f8c4SRick Parrish if (!valid)
340*0112f8c4SRick Parrish warnx("-s maximum message size not provided.");
341*0112f8c4SRick Parrish return (valid);
342*0112f8c4SRick Parrish }
343*0112f8c4SRick Parrish
344*0112f8c4SRick Parrish /* OPTIONS table handling. */
345*0112f8c4SRick Parrish
346*0112f8c4SRick Parrish struct Option {
347*0112f8c4SRick Parrish /* points to array of string pointers terminated by a null pointer. */
348*0112f8c4SRick Parrish const char **pattern;
349*0112f8c4SRick Parrish /* parse argument. */
350*0112f8c4SRick Parrish void (*parse)(const char *);
351*0112f8c4SRick Parrish /*
352*0112f8c4SRick Parrish * displays an error and returns false if this parameter is not valid.
353*0112f8c4SRick Parrish * returns true otherwise.
354*0112f8c4SRick Parrish */
355*0112f8c4SRick Parrish bool (*validate)(void);
356*0112f8c4SRick Parrish };
357*0112f8c4SRick Parrish
358*0112f8c4SRick Parrish /*
359*0112f8c4SRick Parrish * parse options by table.
360*0112f8c4SRick Parrish * index - current index into argv list.
361*0112f8c4SRick Parrish * argc, argv - command line parameters.
362*0112f8c4SRick Parrish * options - null terminated list of pointers to options.
363*0112f8c4SRick Parrish */
364*0112f8c4SRick Parrish static void
parse_options(int index,int argc,const char * argv[],const struct Option ** options)365*0112f8c4SRick Parrish parse_options(int index, int argc,
366*0112f8c4SRick Parrish const char *argv[], const struct Option **options)
367*0112f8c4SRick Parrish {
368*0112f8c4SRick Parrish while ((index + 1) < argc) {
369*0112f8c4SRick Parrish const struct Option **cursor = options;
370*0112f8c4SRick Parrish bool match = false;
371*0112f8c4SRick Parrish while (*cursor != NULL && !match) {
372*0112f8c4SRick Parrish const struct Option *option = cursor[0];
373*0112f8c4SRick Parrish const char **pattern = option->pattern;
374*0112f8c4SRick Parrish
375*0112f8c4SRick Parrish while (*pattern != NULL && !match) {
376*0112f8c4SRick Parrish const char *knob = *pattern;
377*0112f8c4SRick Parrish
378*0112f8c4SRick Parrish match = strcmp(knob, argv[index]) == 0;
379*0112f8c4SRick Parrish if (!match)
380*0112f8c4SRick Parrish pattern++;
381*0112f8c4SRick Parrish }
382*0112f8c4SRick Parrish
383*0112f8c4SRick Parrish if (match) {
384*0112f8c4SRick Parrish option->parse(argv[index + 1]);
385*0112f8c4SRick Parrish index += 2;
386*0112f8c4SRick Parrish break;
387*0112f8c4SRick Parrish }
388*0112f8c4SRick Parrish cursor++;
389*0112f8c4SRick Parrish }
390*0112f8c4SRick Parrish
391*0112f8c4SRick Parrish if (!match && index < argc) {
392*0112f8c4SRick Parrish warnx("skipping [%s].", argv[index]);
393*0112f8c4SRick Parrish index++;
394*0112f8c4SRick Parrish }
395*0112f8c4SRick Parrish }
396*0112f8c4SRick Parrish
397*0112f8c4SRick Parrish if (index < argc) {
398*0112f8c4SRick Parrish warnx("skipping [%s].", argv[index]);
399*0112f8c4SRick Parrish }
400*0112f8c4SRick Parrish }
401*0112f8c4SRick Parrish
402*0112f8c4SRick Parrish /* options - null terminated list of pointers to options. */
403*0112f8c4SRick Parrish static bool
validate_options(const struct Option ** options)404*0112f8c4SRick Parrish validate_options(const struct Option **options)
405*0112f8c4SRick Parrish {
406*0112f8c4SRick Parrish bool valid = true;
407*0112f8c4SRick Parrish
408*0112f8c4SRick Parrish while (*options != NULL) {
409*0112f8c4SRick Parrish const struct Option *option = options[0];
410*0112f8c4SRick Parrish
411*0112f8c4SRick Parrish if (!option->validate())
412*0112f8c4SRick Parrish valid = false;
413*0112f8c4SRick Parrish options++;
414*0112f8c4SRick Parrish }
415*0112f8c4SRick Parrish return (valid);
416*0112f8c4SRick Parrish }
417*0112f8c4SRick Parrish
418*0112f8c4SRick Parrish /* SUBCOMMANDS */
419*0112f8c4SRick Parrish
420*0112f8c4SRick Parrish /*
421*0112f8c4SRick Parrish * queue: name of queue to be created.
422*0112f8c4SRick Parrish * q_creation: creation parameters (copied by value).
423*0112f8c4SRick Parrish */
424*0112f8c4SRick Parrish static int
create(const char * queue,struct Creation q_creation)425*0112f8c4SRick Parrish create(const char *queue, struct Creation q_creation)
426*0112f8c4SRick Parrish {
427*0112f8c4SRick Parrish int flags = O_RDWR;
428*0112f8c4SRick Parrish struct mq_attr stuff = {
429*0112f8c4SRick Parrish .mq_curmsgs = 0,
430*0112f8c4SRick Parrish .mq_maxmsg = q_creation.depth,
431*0112f8c4SRick Parrish .mq_msgsize = q_creation.size,
432*0112f8c4SRick Parrish .mq_flags = 0
433*0112f8c4SRick Parrish };
434*0112f8c4SRick Parrish
435*0112f8c4SRick Parrish if (!q_creation.block) {
436*0112f8c4SRick Parrish flags |= O_NONBLOCK;
437*0112f8c4SRick Parrish stuff.mq_flags |= O_NONBLOCK;
438*0112f8c4SRick Parrish }
439*0112f8c4SRick Parrish
440*0112f8c4SRick Parrish mqd_t handle = mq_open(queue, flags);
441*0112f8c4SRick Parrish q_creation.exists = handle != fail;
442*0112f8c4SRick Parrish if (!q_creation.exists) {
443*0112f8c4SRick Parrish /*
444*0112f8c4SRick Parrish * apply size and depth checks here.
445*0112f8c4SRick Parrish * if queue exists, we can default to existing depth and size.
446*0112f8c4SRick Parrish * but for a new queue, we require that input.
447*0112f8c4SRick Parrish */
448*0112f8c4SRick Parrish if (validate_size() && validate_depth()) {
449*0112f8c4SRick Parrish /* no need to re-apply mode. */
450*0112f8c4SRick Parrish q_creation.set_mode = false;
451*0112f8c4SRick Parrish flags |= O_CREAT;
452*0112f8c4SRick Parrish handle = mq_open(queue, flags, q_creation.mode, &stuff);
453*0112f8c4SRick Parrish }
454*0112f8c4SRick Parrish }
455*0112f8c4SRick Parrish
456*0112f8c4SRick Parrish if (handle == fail) {
457*0112f8c4SRick Parrish errno_t what = errno;
458*0112f8c4SRick Parrish
459*0112f8c4SRick Parrish warnc(what, "mq_open(create)");
460*0112f8c4SRick Parrish return (what);
461*0112f8c4SRick Parrish }
462*0112f8c4SRick Parrish
463*0112f8c4SRick Parrish #ifdef __FreeBSD__
464*0112f8c4SRick Parrish /*
465*0112f8c4SRick Parrish * undocumented.
466*0112f8c4SRick Parrish * See https://bugs.freebsd.org/bugzilla//show_bug.cgi?id=273230
467*0112f8c4SRick Parrish */
468*0112f8c4SRick Parrish int fd = mq_getfd_np(handle);
469*0112f8c4SRick Parrish
470*0112f8c4SRick Parrish if (fd < 0) {
471*0112f8c4SRick Parrish errno_t what = errno;
472*0112f8c4SRick Parrish
473*0112f8c4SRick Parrish warnc(what, "mq_getfd_np(create)");
474*0112f8c4SRick Parrish mq_close(handle);
475*0112f8c4SRick Parrish return (what);
476*0112f8c4SRick Parrish }
477*0112f8c4SRick Parrish struct stat status = {0};
478*0112f8c4SRick Parrish int result = fstat(fd, &status);
479*0112f8c4SRick Parrish if (result != 0) {
480*0112f8c4SRick Parrish errno_t what = errno;
481*0112f8c4SRick Parrish
482*0112f8c4SRick Parrish warnc(what, "fstat(create)");
483*0112f8c4SRick Parrish mq_close(handle);
484*0112f8c4SRick Parrish return (what);
485*0112f8c4SRick Parrish }
486*0112f8c4SRick Parrish
487*0112f8c4SRick Parrish /* do this only if group and / or user given. */
488*0112f8c4SRick Parrish if (q_creation.set_group || q_creation.set_user) {
489*0112f8c4SRick Parrish q_creation.user =
490*0112f8c4SRick Parrish q_creation.set_user ? q_creation.user : status.st_uid;
491*0112f8c4SRick Parrish q_creation.group =
492*0112f8c4SRick Parrish q_creation.set_group ? q_creation.group : status.st_gid;
493*0112f8c4SRick Parrish result = fchown(fd, q_creation.user, q_creation.group);
494*0112f8c4SRick Parrish if (result != 0) {
495*0112f8c4SRick Parrish errno_t what = errno;
496*0112f8c4SRick Parrish
497*0112f8c4SRick Parrish warnc(what, "fchown(create)");
498*0112f8c4SRick Parrish mq_close(handle);
499*0112f8c4SRick Parrish return (what);
500*0112f8c4SRick Parrish }
501*0112f8c4SRick Parrish }
502*0112f8c4SRick Parrish
503*0112f8c4SRick Parrish /* do this only if altering mode of an existing queue. */
504*0112f8c4SRick Parrish if (q_creation.exists && q_creation.set_mode &&
505*0112f8c4SRick Parrish q_creation.mode != (status.st_mode & accepted_mode_bits)) {
506*0112f8c4SRick Parrish result = fchmod(fd, q_creation.mode);
507*0112f8c4SRick Parrish if (result != 0) {
508*0112f8c4SRick Parrish errno_t what = errno;
509*0112f8c4SRick Parrish
510*0112f8c4SRick Parrish warnc(what, "fchmod(create)");
511*0112f8c4SRick Parrish mq_close(handle);
512*0112f8c4SRick Parrish return (what);
513*0112f8c4SRick Parrish }
514*0112f8c4SRick Parrish }
515*0112f8c4SRick Parrish #endif /* __FreeBSD__ */
516*0112f8c4SRick Parrish
517*0112f8c4SRick Parrish return (mq_close(handle));
518*0112f8c4SRick Parrish }
519*0112f8c4SRick Parrish
520*0112f8c4SRick Parrish /* queue: name of queue to be removed. */
521*0112f8c4SRick Parrish static int
rm(const char * queue)522*0112f8c4SRick Parrish rm(const char *queue)
523*0112f8c4SRick Parrish {
524*0112f8c4SRick Parrish int result = mq_unlink(queue);
525*0112f8c4SRick Parrish
526*0112f8c4SRick Parrish if (result != 0) {
527*0112f8c4SRick Parrish errno_t what = errno;
528*0112f8c4SRick Parrish
529*0112f8c4SRick Parrish warnc(what, "mq_unlink");
530*0112f8c4SRick Parrish return (what);
531*0112f8c4SRick Parrish }
532*0112f8c4SRick Parrish
533*0112f8c4SRick Parrish return (result);
534*0112f8c4SRick Parrish }
535*0112f8c4SRick Parrish
536*0112f8c4SRick Parrish /* Return the display character for non-zero mode. */
537*0112f8c4SRick Parrish static char
dual(mode_t mode,char display)538*0112f8c4SRick Parrish dual(mode_t mode, char display)
539*0112f8c4SRick Parrish {
540*0112f8c4SRick Parrish return (mode != 0 ? display : '-');
541*0112f8c4SRick Parrish }
542*0112f8c4SRick Parrish
543*0112f8c4SRick Parrish /* Select one of four display characters based on mode and modifier. */
544*0112f8c4SRick Parrish static char
quad(mode_t mode,mode_t modifier)545*0112f8c4SRick Parrish quad(mode_t mode, mode_t modifier)
546*0112f8c4SRick Parrish {
547*0112f8c4SRick Parrish static const char display[] = "-xSs";
548*0112f8c4SRick Parrish unsigned index = 0;
549*0112f8c4SRick Parrish if (mode != 0)
550*0112f8c4SRick Parrish index += 1;
551*0112f8c4SRick Parrish if (modifier)
552*0112f8c4SRick Parrish index += 2;
553*0112f8c4SRick Parrish return (display[index]);
554*0112f8c4SRick Parrish }
555*0112f8c4SRick Parrish
556*0112f8c4SRick Parrish /* queue: name of queue to be inspected. */
557*0112f8c4SRick Parrish static int
info(const char * queue)558*0112f8c4SRick Parrish info(const char *queue)
559*0112f8c4SRick Parrish {
560*0112f8c4SRick Parrish mqd_t handle = mq_open(queue, O_RDONLY);
561*0112f8c4SRick Parrish
562*0112f8c4SRick Parrish if (handle == fail) {
563*0112f8c4SRick Parrish errno_t what = errno;
564*0112f8c4SRick Parrish
565*0112f8c4SRick Parrish warnc(what, "mq_open(info)");
566*0112f8c4SRick Parrish return (what);
567*0112f8c4SRick Parrish }
568*0112f8c4SRick Parrish
569*0112f8c4SRick Parrish struct mq_attr actual;
570*0112f8c4SRick Parrish
571*0112f8c4SRick Parrish int result = mq_getattr(handle, &actual);
572*0112f8c4SRick Parrish if (result != 0) {
573*0112f8c4SRick Parrish errno_t what = errno;
574*0112f8c4SRick Parrish
575*0112f8c4SRick Parrish warnc(what, "mq_getattr(info)");
576*0112f8c4SRick Parrish return (what);
577*0112f8c4SRick Parrish }
578*0112f8c4SRick Parrish
579*0112f8c4SRick Parrish fprintf(stdout,
580*0112f8c4SRick Parrish "queue: '%s'\nQSIZE: %lu\nMSGSIZE: %ld\nMAXMSG: %ld\n"
581*0112f8c4SRick Parrish "CURMSG: %ld\nflags: %03ld\n",
582*0112f8c4SRick Parrish queue, actual.mq_msgsize * actual.mq_curmsgs, actual.mq_msgsize,
583*0112f8c4SRick Parrish actual.mq_maxmsg, actual.mq_curmsgs, actual.mq_flags);
584*0112f8c4SRick Parrish #ifdef __FreeBSD__
585*0112f8c4SRick Parrish
586*0112f8c4SRick Parrish int fd = mq_getfd_np(handle);
587*0112f8c4SRick Parrish struct stat status;
588*0112f8c4SRick Parrish
589*0112f8c4SRick Parrish result = fstat(fd, &status);
590*0112f8c4SRick Parrish if (result != 0) {
591*0112f8c4SRick Parrish warn("fstat(info)");
592*0112f8c4SRick Parrish } else {
593*0112f8c4SRick Parrish mode_t mode = status.st_mode;
594*0112f8c4SRick Parrish
595*0112f8c4SRick Parrish fprintf(stdout, "UID: %u\nGID: %u\n", status.st_uid, status.st_gid);
596*0112f8c4SRick Parrish fprintf(stdout, "MODE: %c%c%c%c%c%c%c%c%c%c\n",
597*0112f8c4SRick Parrish dual(mode & S_ISVTX, 's'),
598*0112f8c4SRick Parrish dual(mode & S_IRUSR, 'r'),
599*0112f8c4SRick Parrish dual(mode & S_IWUSR, 'w'),
600*0112f8c4SRick Parrish quad(mode & S_IXUSR, mode & S_ISUID),
601*0112f8c4SRick Parrish dual(mode & S_IRGRP, 'r'),
602*0112f8c4SRick Parrish dual(mode & S_IWGRP, 'w'),
603*0112f8c4SRick Parrish quad(mode & S_IXGRP, mode & S_ISGID),
604*0112f8c4SRick Parrish dual(mode & S_IROTH, 'r'),
605*0112f8c4SRick Parrish dual(mode & S_IWOTH, 'w'),
606*0112f8c4SRick Parrish dual(mode & S_IXOTH, 'x'));
607*0112f8c4SRick Parrish }
608*0112f8c4SRick Parrish #endif /* __FreeBSD__ */
609*0112f8c4SRick Parrish
610*0112f8c4SRick Parrish return (mq_close(handle));
611*0112f8c4SRick Parrish }
612*0112f8c4SRick Parrish
613*0112f8c4SRick Parrish /* queue: name of queue to drain one message. */
614*0112f8c4SRick Parrish static int
recv(const char * queue)615*0112f8c4SRick Parrish recv(const char *queue)
616*0112f8c4SRick Parrish {
617*0112f8c4SRick Parrish mqd_t handle = mq_open(queue, O_RDONLY);
618*0112f8c4SRick Parrish
619*0112f8c4SRick Parrish if (handle == fail) {
620*0112f8c4SRick Parrish errno_t what = errno;
621*0112f8c4SRick Parrish
622*0112f8c4SRick Parrish warnc(what, "mq_open(recv)");
623*0112f8c4SRick Parrish return (what);
624*0112f8c4SRick Parrish }
625*0112f8c4SRick Parrish
626*0112f8c4SRick Parrish struct mq_attr actual;
627*0112f8c4SRick Parrish
628*0112f8c4SRick Parrish int result = mq_getattr(handle, &actual);
629*0112f8c4SRick Parrish
630*0112f8c4SRick Parrish if (result != 0) {
631*0112f8c4SRick Parrish errno_t what = errno;
632*0112f8c4SRick Parrish
633*0112f8c4SRick Parrish warnc(what, "mq_attr(recv)");
634*0112f8c4SRick Parrish mq_close(handle);
635*0112f8c4SRick Parrish return (what);
636*0112f8c4SRick Parrish }
637*0112f8c4SRick Parrish
638*0112f8c4SRick Parrish char *text = malloc(actual.mq_msgsize + 1);
639*0112f8c4SRick Parrish unsigned q_priority = 0;
640*0112f8c4SRick Parrish
641*0112f8c4SRick Parrish memset(text, 0, actual.mq_msgsize + 1);
642*0112f8c4SRick Parrish result = mq_receive(handle, text, actual.mq_msgsize, &q_priority);
643*0112f8c4SRick Parrish if (result < 0) {
644*0112f8c4SRick Parrish errno_t what = errno;
645*0112f8c4SRick Parrish
646*0112f8c4SRick Parrish warnc(what, "mq_receive");
647*0112f8c4SRick Parrish mq_close(handle);
648*0112f8c4SRick Parrish return (what);
649*0112f8c4SRick Parrish }
650*0112f8c4SRick Parrish
651*0112f8c4SRick Parrish fprintf(stdout, "[%u]: %-*.*s\n", q_priority, result, result, text);
652*0112f8c4SRick Parrish return (mq_close(handle));
653*0112f8c4SRick Parrish }
654*0112f8c4SRick Parrish
655*0112f8c4SRick Parrish /*
656*0112f8c4SRick Parrish * queue: name of queue to send one message.
657*0112f8c4SRick Parrish * text: message text.
658*0112f8c4SRick Parrish * q_priority: message priority in range of 0 to 63.
659*0112f8c4SRick Parrish */
660*0112f8c4SRick Parrish static int
send(const char * queue,const char * text,unsigned q_priority)661*0112f8c4SRick Parrish send(const char *queue, const char *text, unsigned q_priority)
662*0112f8c4SRick Parrish {
663*0112f8c4SRick Parrish mqd_t handle = mq_open(queue, O_WRONLY);
664*0112f8c4SRick Parrish
665*0112f8c4SRick Parrish if (handle == fail) {
666*0112f8c4SRick Parrish errno_t what = errno;
667*0112f8c4SRick Parrish
668*0112f8c4SRick Parrish warnc(what, "mq_open(send)");
669*0112f8c4SRick Parrish return (what);
670*0112f8c4SRick Parrish }
671*0112f8c4SRick Parrish
672*0112f8c4SRick Parrish struct mq_attr actual;
673*0112f8c4SRick Parrish
674*0112f8c4SRick Parrish int result = mq_getattr(handle, &actual);
675*0112f8c4SRick Parrish
676*0112f8c4SRick Parrish if (result != 0) {
677*0112f8c4SRick Parrish errno_t what = errno;
678*0112f8c4SRick Parrish
679*0112f8c4SRick Parrish warnc(what, "mq_attr(send)");
680*0112f8c4SRick Parrish mq_close(handle);
681*0112f8c4SRick Parrish return (what);
682*0112f8c4SRick Parrish }
683*0112f8c4SRick Parrish
684*0112f8c4SRick Parrish int size = strlen(text);
685*0112f8c4SRick Parrish
686*0112f8c4SRick Parrish if (size > actual.mq_msgsize) {
687*0112f8c4SRick Parrish warnx("truncating message to %ld characters.\n", actual.mq_msgsize);
688*0112f8c4SRick Parrish size = actual.mq_msgsize;
689*0112f8c4SRick Parrish }
690*0112f8c4SRick Parrish
691*0112f8c4SRick Parrish result = mq_send(handle, text, size, q_priority);
692*0112f8c4SRick Parrish
693*0112f8c4SRick Parrish if (result != 0) {
694*0112f8c4SRick Parrish errno_t what = errno;
695*0112f8c4SRick Parrish
696*0112f8c4SRick Parrish warnc(what, "mq_send");
697*0112f8c4SRick Parrish mq_close(handle);
698*0112f8c4SRick Parrish return (what);
699*0112f8c4SRick Parrish }
700*0112f8c4SRick Parrish
701*0112f8c4SRick Parrish return (mq_close(handle));
702*0112f8c4SRick Parrish }
703*0112f8c4SRick Parrish
704*0112f8c4SRick Parrish static void
usage(FILE * file)705*0112f8c4SRick Parrish usage(FILE *file)
706*0112f8c4SRick Parrish {
707*0112f8c4SRick Parrish fprintf(file,
708*0112f8c4SRick Parrish "usage:\n\tposixmqcontrol [rm|info|recv] -q <queue>\n"
709*0112f8c4SRick Parrish "\tposixmqcontrol create -q <queue> -s <maxsize> -d <maxdepth> "
710*0112f8c4SRick Parrish "[ -m <mode> ] [ -b <block> ] [-u <uid> ] [ -g <gid> ]\n"
711*0112f8c4SRick Parrish "\tposixmqcontrol send -q <queue> -c <content> "
712*0112f8c4SRick Parrish "[-p <priority> ]\n");
713*0112f8c4SRick Parrish }
714*0112f8c4SRick Parrish
715*0112f8c4SRick Parrish /* end of SUBCOMMANDS */
716*0112f8c4SRick Parrish
717*0112f8c4SRick Parrish #define _countof(arg) ((sizeof(arg)) / (sizeof((arg)[0])))
718*0112f8c4SRick Parrish
719*0112f8c4SRick Parrish /* convert an errno style error code to a sysexits code. */
720*0112f8c4SRick Parrish static int
grace(int err_number)721*0112f8c4SRick Parrish grace(int err_number)
722*0112f8c4SRick Parrish {
723*0112f8c4SRick Parrish static const int xlat[][2] = {
724*0112f8c4SRick Parrish /* generally means the mqueuefs driver is not loaded. */
725*0112f8c4SRick Parrish {ENOSYS, EX_UNAVAILABLE},
726*0112f8c4SRick Parrish /* no such queue name. */
727*0112f8c4SRick Parrish {ENOENT, EX_OSFILE},
728*0112f8c4SRick Parrish {EIO, EX_IOERR},
729*0112f8c4SRick Parrish {ENODEV, EX_IOERR},
730*0112f8c4SRick Parrish {ENOTSUP, EX_TEMPFAIL},
731*0112f8c4SRick Parrish {EAGAIN, EX_IOERR},
732*0112f8c4SRick Parrish {EPERM, EX_NOPERM},
733*0112f8c4SRick Parrish {EACCES, EX_NOPERM},
734*0112f8c4SRick Parrish {0, EX_OK}
735*0112f8c4SRick Parrish };
736*0112f8c4SRick Parrish
737*0112f8c4SRick Parrish for (unsigned i = 0; i < _countof(xlat); i++) {
738*0112f8c4SRick Parrish if (xlat[i][0] == err_number)
739*0112f8c4SRick Parrish return (xlat[i][1]);
740*0112f8c4SRick Parrish }
741*0112f8c4SRick Parrish
742*0112f8c4SRick Parrish return (EX_OSERR);
743*0112f8c4SRick Parrish }
744*0112f8c4SRick Parrish
745*0112f8c4SRick Parrish /* OPTIONS tables */
746*0112f8c4SRick Parrish
747*0112f8c4SRick Parrish /* careful: these 'names' arrays must be terminated by a null pointer. */
748*0112f8c4SRick Parrish static const char *names_queue[] = {"-q", "--queue", "-t", "--topic", NULL};
749*0112f8c4SRick Parrish static const struct Option option_queue = {
750*0112f8c4SRick Parrish .pattern = names_queue,
751*0112f8c4SRick Parrish .parse = parse_queue,
752*0112f8c4SRick Parrish .validate = validate_queue};
753*0112f8c4SRick Parrish static const struct Option option_single_queue = {
754*0112f8c4SRick Parrish .pattern = names_queue,
755*0112f8c4SRick Parrish .parse = parse_single_queue,
756*0112f8c4SRick Parrish .validate = validate_single_queue};
757*0112f8c4SRick Parrish static const char *names_depth[] = {"-d", "--depth", "--maxmsg", NULL};
758*0112f8c4SRick Parrish static const struct Option option_depth = {
759*0112f8c4SRick Parrish .pattern = names_depth,
760*0112f8c4SRick Parrish .parse = parse_depth,
761*0112f8c4SRick Parrish .validate = validate_always_true};
762*0112f8c4SRick Parrish static const char *names_size[] = {"-s", "--size", "--msgsize", NULL};
763*0112f8c4SRick Parrish static const struct Option option_size = {
764*0112f8c4SRick Parrish .pattern = names_size,
765*0112f8c4SRick Parrish .parse = parse_size,
766*0112f8c4SRick Parrish .validate = validate_always_true};
767*0112f8c4SRick Parrish static const char *names_block[] = {"-b", "--block", NULL};
768*0112f8c4SRick Parrish static const struct Option option_block = {
769*0112f8c4SRick Parrish .pattern = names_block,
770*0112f8c4SRick Parrish .parse = parse_block,
771*0112f8c4SRick Parrish .validate = validate_always_true};
772*0112f8c4SRick Parrish static const char *names_content[] = {
773*0112f8c4SRick Parrish "-c", "--content", "--data", "--message", NULL};
774*0112f8c4SRick Parrish static const struct Option option_content = {
775*0112f8c4SRick Parrish .pattern = names_content,
776*0112f8c4SRick Parrish .parse = parse_content,
777*0112f8c4SRick Parrish .validate = validate_content};
778*0112f8c4SRick Parrish static const char *names_priority[] = {"-p", "--priority", NULL};
779*0112f8c4SRick Parrish static const struct Option option_priority = {
780*0112f8c4SRick Parrish .pattern = names_priority,
781*0112f8c4SRick Parrish .parse = parse_priority,
782*0112f8c4SRick Parrish .validate = validate_always_true};
783*0112f8c4SRick Parrish static const char *names_mode[] = {"-m", "--mode", NULL};
784*0112f8c4SRick Parrish static const struct Option option_mode = {
785*0112f8c4SRick Parrish .pattern = names_mode,
786*0112f8c4SRick Parrish .parse = parse_mode,
787*0112f8c4SRick Parrish .validate = validate_always_true};
788*0112f8c4SRick Parrish static const char *names_group[] = {"-g", "--gid", NULL};
789*0112f8c4SRick Parrish static const struct Option option_group = {
790*0112f8c4SRick Parrish .pattern = names_group,
791*0112f8c4SRick Parrish .parse = parse_group,
792*0112f8c4SRick Parrish .validate = validate_always_true};
793*0112f8c4SRick Parrish static const char *names_user[] = {"-u", "--uid", NULL};
794*0112f8c4SRick Parrish static const struct Option option_user = {
795*0112f8c4SRick Parrish .pattern = names_user,
796*0112f8c4SRick Parrish .parse = parse_user,
797*0112f8c4SRick Parrish .validate = validate_always_true};
798*0112f8c4SRick Parrish
799*0112f8c4SRick Parrish /* careful: these arrays must be terminated by a null pointer. */
800*0112f8c4SRick Parrish #ifdef __FreeBSD__
801*0112f8c4SRick Parrish static const struct Option *create_options[] = {
802*0112f8c4SRick Parrish &option_queue, &option_depth, &option_size, &option_block,
803*0112f8c4SRick Parrish &option_mode, &option_group, &option_user, NULL};
804*0112f8c4SRick Parrish #else /* !__FreeBSD__ */
805*0112f8c4SRick Parrish static const struct Option *create_options[] = {
806*0112f8c4SRick Parrish &option_queue, &option_depth, &option_size, &option_block,
807*0112f8c4SRick Parrish &option_mode, NULL};
808*0112f8c4SRick Parrish #endif /* __FreeBSD__ */
809*0112f8c4SRick Parrish static const struct Option *info_options[] = {&option_queue, NULL};
810*0112f8c4SRick Parrish static const struct Option *unlink_options[] = {&option_queue, NULL};
811*0112f8c4SRick Parrish static const struct Option *recv_options[] = {&option_single_queue, NULL};
812*0112f8c4SRick Parrish static const struct Option *send_options[] = {
813*0112f8c4SRick Parrish &option_queue, &option_content, &option_priority, NULL};
814*0112f8c4SRick Parrish
815*0112f8c4SRick Parrish int
main(int argc,const char * argv[])816*0112f8c4SRick Parrish main(int argc, const char *argv[])
817*0112f8c4SRick Parrish {
818*0112f8c4SRick Parrish STAILQ_INIT(&queues);
819*0112f8c4SRick Parrish STAILQ_INIT(&contents);
820*0112f8c4SRick Parrish
821*0112f8c4SRick Parrish if (argc > 1) {
822*0112f8c4SRick Parrish const char *verb = argv[1];
823*0112f8c4SRick Parrish int index = 2;
824*0112f8c4SRick Parrish
825*0112f8c4SRick Parrish if (strcmp("create", verb) == 0 || strcmp("attr", verb) == 0) {
826*0112f8c4SRick Parrish parse_options(index, argc, argv, create_options);
827*0112f8c4SRick Parrish if (validate_options(create_options)) {
828*0112f8c4SRick Parrish int worst = 0;
829*0112f8c4SRick Parrish struct element *itq;
830*0112f8c4SRick Parrish
831*0112f8c4SRick Parrish STAILQ_FOREACH(itq, &queues, links) {
832*0112f8c4SRick Parrish const char *queue = itq->text;
833*0112f8c4SRick Parrish
834*0112f8c4SRick Parrish int result = create(queue, creation);
835*0112f8c4SRick Parrish if (result != 0)
836*0112f8c4SRick Parrish worst = result;
837*0112f8c4SRick Parrish }
838*0112f8c4SRick Parrish
839*0112f8c4SRick Parrish return (grace(worst));
840*0112f8c4SRick Parrish }
841*0112f8c4SRick Parrish
842*0112f8c4SRick Parrish return (EX_USAGE);
843*0112f8c4SRick Parrish } else if (strcmp("info", verb) == 0 || strcmp("cat", verb) == 0) {
844*0112f8c4SRick Parrish parse_options(index, argc, argv, info_options);
845*0112f8c4SRick Parrish if (validate_options(info_options)) {
846*0112f8c4SRick Parrish int worst = 0;
847*0112f8c4SRick Parrish struct element *itq;
848*0112f8c4SRick Parrish
849*0112f8c4SRick Parrish STAILQ_FOREACH(itq, &queues, links) {
850*0112f8c4SRick Parrish const char *queue = itq->text;
851*0112f8c4SRick Parrish int result = info(queue);
852*0112f8c4SRick Parrish
853*0112f8c4SRick Parrish if (result != 0)
854*0112f8c4SRick Parrish worst = result;
855*0112f8c4SRick Parrish }
856*0112f8c4SRick Parrish
857*0112f8c4SRick Parrish return (grace(worst));
858*0112f8c4SRick Parrish }
859*0112f8c4SRick Parrish
860*0112f8c4SRick Parrish return (EX_USAGE);
861*0112f8c4SRick Parrish } else if (strcmp("send", verb) == 0) {
862*0112f8c4SRick Parrish parse_options(index, argc, argv, send_options);
863*0112f8c4SRick Parrish if (validate_options(send_options)) {
864*0112f8c4SRick Parrish int worst = 0;
865*0112f8c4SRick Parrish struct element *itq;
866*0112f8c4SRick Parrish
867*0112f8c4SRick Parrish STAILQ_FOREACH(itq, &queues, links) {
868*0112f8c4SRick Parrish const char *queue = itq->text;
869*0112f8c4SRick Parrish struct element *itc;
870*0112f8c4SRick Parrish
871*0112f8c4SRick Parrish STAILQ_FOREACH(itc, &contents, links) {
872*0112f8c4SRick Parrish const char *content = itc->text;
873*0112f8c4SRick Parrish int result = send(queue, content, priority);
874*0112f8c4SRick Parrish
875*0112f8c4SRick Parrish if (result != 0)
876*0112f8c4SRick Parrish worst = result;
877*0112f8c4SRick Parrish }
878*0112f8c4SRick Parrish }
879*0112f8c4SRick Parrish
880*0112f8c4SRick Parrish return (grace(worst));
881*0112f8c4SRick Parrish }
882*0112f8c4SRick Parrish return (EX_USAGE);
883*0112f8c4SRick Parrish } else if (strcmp("recv", verb) == 0 ||
884*0112f8c4SRick Parrish strcmp("receive", verb) == 0) {
885*0112f8c4SRick Parrish parse_options(index, argc, argv, recv_options);
886*0112f8c4SRick Parrish if (validate_options(recv_options)) {
887*0112f8c4SRick Parrish const char *queue = STAILQ_FIRST(&queues)->text;
888*0112f8c4SRick Parrish int worst = recv(queue);
889*0112f8c4SRick Parrish
890*0112f8c4SRick Parrish return (grace(worst));
891*0112f8c4SRick Parrish }
892*0112f8c4SRick Parrish
893*0112f8c4SRick Parrish return (EX_USAGE);
894*0112f8c4SRick Parrish } else if (strcmp("unlink", verb) == 0 ||
895*0112f8c4SRick Parrish strcmp("rm", verb) == 0) {
896*0112f8c4SRick Parrish parse_options(index, argc, argv, unlink_options);
897*0112f8c4SRick Parrish if (validate_options(unlink_options)) {
898*0112f8c4SRick Parrish int worst = 0;
899*0112f8c4SRick Parrish struct element *itq;
900*0112f8c4SRick Parrish
901*0112f8c4SRick Parrish STAILQ_FOREACH(itq, &queues, links) {
902*0112f8c4SRick Parrish const char *queue = itq->text;
903*0112f8c4SRick Parrish int result = rm(queue);
904*0112f8c4SRick Parrish
905*0112f8c4SRick Parrish if (result != 0)
906*0112f8c4SRick Parrish worst = result;
907*0112f8c4SRick Parrish }
908*0112f8c4SRick Parrish
909*0112f8c4SRick Parrish return (grace(worst));
910*0112f8c4SRick Parrish }
911*0112f8c4SRick Parrish
912*0112f8c4SRick Parrish return (EX_USAGE);
913*0112f8c4SRick Parrish } else if (strcmp("help", verb) == 0) {
914*0112f8c4SRick Parrish usage(stdout);
915*0112f8c4SRick Parrish return (EX_OK);
916*0112f8c4SRick Parrish } else {
917*0112f8c4SRick Parrish warnx("Unknown verb [%s]", verb);
918*0112f8c4SRick Parrish return (EX_USAGE);
919*0112f8c4SRick Parrish }
920*0112f8c4SRick Parrish }
921*0112f8c4SRick Parrish
922*0112f8c4SRick Parrish usage(stdout);
923*0112f8c4SRick Parrish return (EX_OK);
924*0112f8c4SRick Parrish }
925