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