1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
14 */
15
16 /*
17 * This file exercises the various err(3C)/warn(3C) functions and produces
18 * output that is checked by the corresponding err.ksh script.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <errno.h>
25 #include <err.h>
26 #include <sys/debug.h>
27
28 static FILE *stream = stderr;
29
30 typedef enum variant {
31 VARIANT_ = 0, /* warn(), err() */
32 VARIANT_C, /* warnc(), errc() */
33 VARIANT_X, /* warnx(), errx() */
34 VARIANT_V, /* vwarn(), verr() */
35 VARIANT_VC, /* vwarnc(), verrc() */
36 VARIANT_VX, /* vwarnx(), verrx() */
37 } variant_t;
38
39 void
usage(void)40 usage(void)
41 {
42 (void) fprintf(stderr,
43 "usage: err [-e errno] [-x code] [-v variant]\n");
44 exit(EXIT_FAILURE);
45 }
46
47 void
callback_func(int code)48 callback_func(int code)
49 {
50 (void) fprintf(stream, "CALLBACK %d\n", code);
51 }
52
53 void
xtest(variant_t variant,int errcode,int exitcode,const char * fmt,...)54 xtest(variant_t variant, int errcode, int exitcode, const char *fmt, ...)
55 {
56 va_list va;
57
58 va_start(va, fmt);
59
60 switch (variant) {
61 case VARIANT_V:
62 errno = errcode;
63 if (exitcode != 0)
64 verr(exitcode, fmt, va);
65 else
66 vwarn(fmt, va);
67 break;
68 case VARIANT_VC:
69 errno = 0;
70 if (exitcode != 0)
71 verrc(exitcode, errcode, fmt, va);
72 else
73 vwarnc(errcode, fmt, va);
74 break;
75 case VARIANT_VX:
76 if (exitcode != 0)
77 verrx(exitcode, fmt, va);
78 else
79 vwarnx(fmt, va);
80 break;
81 default:
82 errx(EXIT_FAILURE, "Unhandled variant in %s", __func__);
83 }
84
85 va_end(va);
86 }
87
88 int
main(int argc,char ** argv)89 main(int argc, char **argv)
90 {
91 int errcode = 0;
92 int exitcode = 0;
93 variant_t variant = VARIANT_;
94 const char *errstr;
95 long long num;
96 int ch;
97
98 /*
99 * -e specify errno for the test
100 * -v select variant to test
101 * -x specify exit code for the test
102 */
103 while ((ch = getopt(argc, argv, "e:v:x:")) != -1) {
104 switch (ch) {
105 case 'e':
106 num = strtonum(optarg, 0, 127, &errstr);
107 if (errstr != NULL)
108 errx(EXIT_FAILURE, "-x: %s", errstr);
109 errcode = (int)num;
110 break;
111 case 'v':
112 num = strtonum(optarg, 0, VARIANT_VX, &errstr);
113 if (errstr != NULL)
114 errx(EXIT_FAILURE, "-v: %s", errstr);
115 switch (num) {
116 case VARIANT_:
117 variant = VARIANT_;
118 break;
119 case VARIANT_C:
120 variant = VARIANT_C;
121 break;
122 case VARIANT_X:
123 variant = VARIANT_X;
124 break;
125 case VARIANT_V:
126 variant = VARIANT_V;
127 break;
128 case VARIANT_VC:
129 variant = VARIANT_VC;
130 break;
131 case VARIANT_VX:
132 variant = VARIANT_VX;
133 break;
134 default:
135 errx(EXIT_FAILURE, "Unknown variant %lld", num);
136 }
137 break;
138 case 'x':
139 num = strtonum(optarg, 0, 127, &errstr);
140 if (errstr != NULL)
141 errx(EXIT_FAILURE, "-x: %s", errstr);
142 exitcode = (int)num;
143 break;
144 default:
145 usage();
146 break;
147 }
148 }
149
150 argc -= optind;
151 argv += optind;
152
153 if (argc > 0)
154 errx(EXIT_FAILURE, "Unexpected argument '%s'.", argv[1]);
155
156 switch (variant) {
157 case VARIANT_:
158 errno = errcode;
159 if (exitcode != 0)
160 err(exitcode, "E/%d/%d", variant, exitcode);
161 else
162 warn("W/%d", variant);
163 break;
164 case VARIANT_C:
165 errno = 0;
166 if (exitcode != 0)
167 errc(exitcode, errcode, "E/%d/%d", variant, exitcode);
168 else
169 warnc(errcode, "W/%d", variant);
170 break;
171 case VARIANT_X:
172 if (exitcode != 0)
173 errx(exitcode, "E/%d/%d", variant, exitcode);
174 else
175 warnx("W/%d", variant);
176 break;
177 case VARIANT_V:
178 case VARIANT_VC:
179 case VARIANT_VX:
180 if (exitcode != 0) {
181 xtest(variant, errcode, exitcode, "E/%d/%d", variant,
182 exitcode);
183 } else {
184 xtest(variant, errcode, exitcode, "W/%d", variant);
185 }
186 break;
187 }
188
189 return (0);
190 }
191