xref: /illumos-gate/usr/src/test/tz-tests/tests/zoneinfo_dump.c (revision 24a03f35583aede6d1aea859d90d76a3e6c2eb22)
1*24a03f35SRobert Mustacchi /*
2*24a03f35SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*24a03f35SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*24a03f35SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*24a03f35SRobert Mustacchi  * 1.0 of the CDDL.
6*24a03f35SRobert Mustacchi  *
7*24a03f35SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*24a03f35SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*24a03f35SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*24a03f35SRobert Mustacchi  */
11*24a03f35SRobert Mustacchi 
12*24a03f35SRobert Mustacchi /*
13*24a03f35SRobert Mustacchi  * Copyright 2025 Oxide Computer Company
14*24a03f35SRobert Mustacchi  */
15*24a03f35SRobert Mustacchi 
16*24a03f35SRobert Mustacchi /*
17*24a03f35SRobert Mustacchi  * Dump all of the information discovered by libzoneinfo in a way that's usable
18*24a03f35SRobert Mustacchi  * for diffing. We use the following directory layout from the root:
19*24a03f35SRobert Mustacchi  *
20*24a03f35SRobert Mustacchi  * dir: <continent-name>
21*24a03f35SRobert Mustacchi  *	file: info
22*24a03f35SRobert Mustacchi  *	dir: <country-name>
23*24a03f35SRobert Mustacchi  *		file: info
24*24a03f35SRobert Mustacchi  *		file: <tz-name>
25*24a03f35SRobert Mustacchi  */
26*24a03f35SRobert Mustacchi 
27*24a03f35SRobert Mustacchi #include <err.h>
28*24a03f35SRobert Mustacchi #include <stdlib.h>
29*24a03f35SRobert Mustacchi #include <unistd.h>
30*24a03f35SRobert Mustacchi #include <sys/types.h>
31*24a03f35SRobert Mustacchi #include <sys/stat.h>
32*24a03f35SRobert Mustacchi #include <fcntl.h>
33*24a03f35SRobert Mustacchi #include <libzoneinfo.h>
34*24a03f35SRobert Mustacchi #include <sys/debug.h>
35*24a03f35SRobert Mustacchi #include <errno.h>
36*24a03f35SRobert Mustacchi #include <string.h>
37*24a03f35SRobert Mustacchi 
38*24a03f35SRobert Mustacchi static void
usage(const char * fmt,...)39*24a03f35SRobert Mustacchi usage(const char *fmt, ...)
40*24a03f35SRobert Mustacchi {
41*24a03f35SRobert Mustacchi 	if (fmt != NULL) {
42*24a03f35SRobert Mustacchi 		va_list ap;
43*24a03f35SRobert Mustacchi 
44*24a03f35SRobert Mustacchi 		va_start(ap, fmt);
45*24a03f35SRobert Mustacchi 		vwarnx(fmt, ap);
46*24a03f35SRobert Mustacchi 		va_end(ap);
47*24a03f35SRobert Mustacchi 	}
48*24a03f35SRobert Mustacchi 
49*24a03f35SRobert Mustacchi 	(void) fprintf(stderr, "Usage:  zoneinfo_dump -d dir\n");
50*24a03f35SRobert Mustacchi }
51*24a03f35SRobert Mustacchi 
52*24a03f35SRobert Mustacchi static void
dump_timezone(int dirfd,const struct tz_continent * cont,const struct tz_country * country,const struct tz_timezone * tz)53*24a03f35SRobert Mustacchi dump_timezone(int dirfd, const struct tz_continent *cont,
54*24a03f35SRobert Mustacchi     const struct tz_country *country, const struct tz_timezone *tz)
55*24a03f35SRobert Mustacchi {
56*24a03f35SRobert Mustacchi 	int fd;
57*24a03f35SRobert Mustacchi 	char *name;
58*24a03f35SRobert Mustacchi 	FILE *f;
59*24a03f35SRobert Mustacchi 
60*24a03f35SRobert Mustacchi 	name = strdup(tz->tz_name);
61*24a03f35SRobert Mustacchi 	if (name == NULL) {
62*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate tz name %s",
63*24a03f35SRobert Mustacchi 		    tz->tz_name);
64*24a03f35SRobert Mustacchi 	}
65*24a03f35SRobert Mustacchi 
66*24a03f35SRobert Mustacchi 	for (size_t i = 0; i < strlen(name); i++) {
67*24a03f35SRobert Mustacchi 		if (name[i] == '/')
68*24a03f35SRobert Mustacchi 			name[i] = '-';
69*24a03f35SRobert Mustacchi 	}
70*24a03f35SRobert Mustacchi 
71*24a03f35SRobert Mustacchi 	if ((fd = openat(dirfd, name, O_RDWR| O_CREAT | O_TRUNC, 0644)) < 0) {
72*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create tz file for %s/%s/%s",
73*24a03f35SRobert Mustacchi 		    cont->ctnt_name, country->ctry_code, name);
74*24a03f35SRobert Mustacchi 	}
75*24a03f35SRobert Mustacchi 
76*24a03f35SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
77*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create stdio stream for "
78*24a03f35SRobert Mustacchi 		    "tz %s/%s/%s file", cont->ctnt_name, country->ctry_code,
79*24a03f35SRobert Mustacchi 		    name);
80*24a03f35SRobert Mustacchi 	}
81*24a03f35SRobert Mustacchi 
82*24a03f35SRobert Mustacchi 	(void) fprintf(f, "name: %s\n", tz->tz_name);
83*24a03f35SRobert Mustacchi 	(void) fprintf(f, "oname: %s\n", tz->tz_oname);
84*24a03f35SRobert Mustacchi 	(void) fprintf(f, "id: %s\n", tz->tz_id_desc);
85*24a03f35SRobert Mustacchi 	(void) fprintf(f, "desc: %s\n", tz->tz_display_desc);
86*24a03f35SRobert Mustacchi 	(void) fprintf(f, "lat: %d.%u.%u.%u\n", tz->tz_coord.lat_sign,
87*24a03f35SRobert Mustacchi 	    tz->tz_coord.lat_degree, tz->tz_coord.lat_minute,
88*24a03f35SRobert Mustacchi 	    tz->tz_coord.lat_second);
89*24a03f35SRobert Mustacchi 	(void) fprintf(f, "long: %d.%u.%u.%u\n", tz->tz_coord.long_sign,
90*24a03f35SRobert Mustacchi 	    tz->tz_coord.long_degree, tz->tz_coord.long_minute,
91*24a03f35SRobert Mustacchi 	    tz->tz_coord.long_second);
92*24a03f35SRobert Mustacchi 
93*24a03f35SRobert Mustacchi 	VERIFY0(fflush(f));
94*24a03f35SRobert Mustacchi 	VERIFY0(fclose(f));
95*24a03f35SRobert Mustacchi 
96*24a03f35SRobert Mustacchi 	free(name);
97*24a03f35SRobert Mustacchi }
98*24a03f35SRobert Mustacchi 
99*24a03f35SRobert Mustacchi static void
dump_country(int cfd,const struct tz_continent * cont,struct tz_country * country)100*24a03f35SRobert Mustacchi dump_country(int cfd, const struct tz_continent *cont,
101*24a03f35SRobert Mustacchi     struct tz_country *country)
102*24a03f35SRobert Mustacchi {
103*24a03f35SRobert Mustacchi 	int dirfd, infofd, ret, found = 0;
104*24a03f35SRobert Mustacchi 	struct tz_timezone *zones;
105*24a03f35SRobert Mustacchi 	FILE *f;
106*24a03f35SRobert Mustacchi 
107*24a03f35SRobert Mustacchi 	if (mkdirat(cfd, country->ctry_code, 0755) != 0 && errno != EEXIST) {
108*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to make country directory %s/%s",
109*24a03f35SRobert Mustacchi 		    cont->ctnt_name, country->ctry_code);
110*24a03f35SRobert Mustacchi 	}
111*24a03f35SRobert Mustacchi 
112*24a03f35SRobert Mustacchi 	if ((dirfd = openat(cfd, country->ctry_code, O_DIRECTORY)) < 0) {
113*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open country %s/%s",
114*24a03f35SRobert Mustacchi 		    cont->ctnt_name, country->ctry_code);
115*24a03f35SRobert Mustacchi 	}
116*24a03f35SRobert Mustacchi 
117*24a03f35SRobert Mustacchi 	if ((infofd = openat(dirfd, "info", O_RDWR| O_CREAT | O_TRUNC, 0644)) <
118*24a03f35SRobert Mustacchi 	    0) {
119*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create info file for country "
120*24a03f35SRobert Mustacchi 		    "%s/%s", cont->ctnt_name, country->ctry_code);
121*24a03f35SRobert Mustacchi 	}
122*24a03f35SRobert Mustacchi 
123*24a03f35SRobert Mustacchi 	if ((f = fdopen(infofd, "w")) == NULL) {
124*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create stdio stream for "
125*24a03f35SRobert Mustacchi 		    "country %s/%s info file", cont->ctnt_name,
126*24a03f35SRobert Mustacchi 		    country->ctry_code);
127*24a03f35SRobert Mustacchi 	}
128*24a03f35SRobert Mustacchi 
129*24a03f35SRobert Mustacchi 	(void) fprintf(f, "name: %s\n", country->ctry_code);
130*24a03f35SRobert Mustacchi 	(void) fprintf(f, "id: %s\n", country->ctry_id_desc);
131*24a03f35SRobert Mustacchi 	(void) fprintf(f, "desc: %s\n", country->ctry_display_desc);
132*24a03f35SRobert Mustacchi 	VERIFY0(country->ctry_status);
133*24a03f35SRobert Mustacchi 	VERIFY0(fflush(f));
134*24a03f35SRobert Mustacchi 	VERIFY0(fclose(f));
135*24a03f35SRobert Mustacchi 
136*24a03f35SRobert Mustacchi 	ret = get_timezones_by_country(&zones, country);
137*24a03f35SRobert Mustacchi 	if (ret < 0) {
138*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get timezones for country %s/%s",
139*24a03f35SRobert Mustacchi 		    cont->ctnt_name, country->ctry_code);
140*24a03f35SRobert Mustacchi 	}
141*24a03f35SRobert Mustacchi 
142*24a03f35SRobert Mustacchi 	for (struct tz_timezone *t = zones; t != NULL; t = t->tz_next,
143*24a03f35SRobert Mustacchi 	    found++) {
144*24a03f35SRobert Mustacchi 		dump_timezone(dirfd, cont, country, t);
145*24a03f35SRobert Mustacchi 	}
146*24a03f35SRobert Mustacchi 
147*24a03f35SRobert Mustacchi 	if (ret != found) {
148*24a03f35SRobert Mustacchi 		errx(EXIT_FAILURE, "zoneinfo said %u timezones should exist "
149*24a03f35SRobert Mustacchi 		    "for country %s/%s, but found %u\n", ret, cont->ctnt_name,
150*24a03f35SRobert Mustacchi 		    country->ctry_code, found);
151*24a03f35SRobert Mustacchi 	}
152*24a03f35SRobert Mustacchi 
153*24a03f35SRobert Mustacchi 	VERIFY0(free_timezones(zones));
154*24a03f35SRobert Mustacchi 	VERIFY0(close(dirfd));
155*24a03f35SRobert Mustacchi }
156*24a03f35SRobert Mustacchi 
157*24a03f35SRobert Mustacchi static void
dump_continent(int root,struct tz_continent * cont)158*24a03f35SRobert Mustacchi dump_continent(int root, struct tz_continent *cont)
159*24a03f35SRobert Mustacchi {
160*24a03f35SRobert Mustacchi 	int dirfd, infofd, ret, found = 0;
161*24a03f35SRobert Mustacchi 	struct tz_country *country;
162*24a03f35SRobert Mustacchi 	FILE *f;
163*24a03f35SRobert Mustacchi 
164*24a03f35SRobert Mustacchi 	if (mkdirat(root, cont->ctnt_name, 0755) != 0 &&
165*24a03f35SRobert Mustacchi 	    errno != EEXIST) {
166*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to make continent %s",
167*24a03f35SRobert Mustacchi 		    cont->ctnt_name);
168*24a03f35SRobert Mustacchi 	}
169*24a03f35SRobert Mustacchi 
170*24a03f35SRobert Mustacchi 	if ((dirfd = openat(root, cont->ctnt_name, O_DIRECTORY)) < 0) {
171*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open continent %s",
172*24a03f35SRobert Mustacchi 		    cont->ctnt_name);
173*24a03f35SRobert Mustacchi 	}
174*24a03f35SRobert Mustacchi 
175*24a03f35SRobert Mustacchi 	if ((infofd = openat(dirfd, "info", O_RDWR| O_CREAT | O_TRUNC, 0644)) <
176*24a03f35SRobert Mustacchi 	    0) {
177*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create info file for continent "
178*24a03f35SRobert Mustacchi 		    "%s", cont->ctnt_name);
179*24a03f35SRobert Mustacchi 	}
180*24a03f35SRobert Mustacchi 
181*24a03f35SRobert Mustacchi 	if ((f = fdopen(infofd, "w")) == NULL) {
182*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create stdio stream for "
183*24a03f35SRobert Mustacchi 		    "continent %s info file", cont->ctnt_name);
184*24a03f35SRobert Mustacchi 	}
185*24a03f35SRobert Mustacchi 
186*24a03f35SRobert Mustacchi 	(void) fprintf(f, "name: %s\n", cont->ctnt_name);
187*24a03f35SRobert Mustacchi 	(void) fprintf(f, "id: %s\n", cont->ctnt_id_desc);
188*24a03f35SRobert Mustacchi 	(void) fprintf(f, "desc: %s\n", cont->ctnt_display_desc);
189*24a03f35SRobert Mustacchi 	VERIFY0(fflush(f));
190*24a03f35SRobert Mustacchi 	VERIFY0(fclose(f));
191*24a03f35SRobert Mustacchi 
192*24a03f35SRobert Mustacchi 	ret = get_tz_countries(&country, cont);
193*24a03f35SRobert Mustacchi 	if (ret < 0) {
194*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get countries for continent %s",
195*24a03f35SRobert Mustacchi 		    cont->ctnt_name);
196*24a03f35SRobert Mustacchi 	}
197*24a03f35SRobert Mustacchi 
198*24a03f35SRobert Mustacchi 	for (struct tz_country *c = country; c != NULL; c = c->ctry_next,
199*24a03f35SRobert Mustacchi 	    found++) {
200*24a03f35SRobert Mustacchi 		dump_country(dirfd, cont, c);
201*24a03f35SRobert Mustacchi 	}
202*24a03f35SRobert Mustacchi 
203*24a03f35SRobert Mustacchi 	if (ret != found) {
204*24a03f35SRobert Mustacchi 		errx(EXIT_FAILURE, "zoneinfo said %u countries should exist "
205*24a03f35SRobert Mustacchi 		    "for continent %s, but found %u\n", ret, cont->ctnt_name,
206*24a03f35SRobert Mustacchi 		    found);
207*24a03f35SRobert Mustacchi 	}
208*24a03f35SRobert Mustacchi 
209*24a03f35SRobert Mustacchi 	/* For each Country */
210*24a03f35SRobert Mustacchi 	VERIFY0(free_tz_countries(country));
211*24a03f35SRobert Mustacchi 	VERIFY0(close(dirfd));
212*24a03f35SRobert Mustacchi }
213*24a03f35SRobert Mustacchi 
214*24a03f35SRobert Mustacchi int
main(int argc,char * argv[])215*24a03f35SRobert Mustacchi main(int argc, char *argv[])
216*24a03f35SRobert Mustacchi {
217*24a03f35SRobert Mustacchi 	int c, dirfd, ret, found = 0;
218*24a03f35SRobert Mustacchi 	const char *base = NULL;
219*24a03f35SRobert Mustacchi 	struct tz_continent *conts;
220*24a03f35SRobert Mustacchi 
221*24a03f35SRobert Mustacchi 	while ((c = getopt(argc, argv, ":d:")) != -1) {
222*24a03f35SRobert Mustacchi 		switch (c) {
223*24a03f35SRobert Mustacchi 		case 'd':
224*24a03f35SRobert Mustacchi 			base = optarg;
225*24a03f35SRobert Mustacchi 			break;
226*24a03f35SRobert Mustacchi 		case '?':
227*24a03f35SRobert Mustacchi 			usage("option -%c requires an argument", optopt);
228*24a03f35SRobert Mustacchi 			exit(EXIT_FAILURE);
229*24a03f35SRobert Mustacchi 		case ':':
230*24a03f35SRobert Mustacchi 			usage("unknown option: -%c", optopt);
231*24a03f35SRobert Mustacchi 			exit(EXIT_FAILURE);
232*24a03f35SRobert Mustacchi 		}
233*24a03f35SRobert Mustacchi 	}
234*24a03f35SRobert Mustacchi 
235*24a03f35SRobert Mustacchi 	if (base == NULL) {
236*24a03f35SRobert Mustacchi 		errx(EXIT_FAILURE, "missing required directory, please use "
237*24a03f35SRobert Mustacchi 		    "the -d flag");
238*24a03f35SRobert Mustacchi 	}
239*24a03f35SRobert Mustacchi 
240*24a03f35SRobert Mustacchi 	if ((dirfd = open(base, O_RDONLY | O_DIRECTORY)) < 0) {
241*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open directory %s", base);
242*24a03f35SRobert Mustacchi 	}
243*24a03f35SRobert Mustacchi 
244*24a03f35SRobert Mustacchi 	ret = get_tz_continents(&conts);
245*24a03f35SRobert Mustacchi 	if (ret < 0) {
246*24a03f35SRobert Mustacchi 		err(EXIT_FAILURE, "failed to get continents");
247*24a03f35SRobert Mustacchi 	}
248*24a03f35SRobert Mustacchi 
249*24a03f35SRobert Mustacchi 	for (struct tz_continent *c = conts; c != NULL; c = c->ctnt_next,
250*24a03f35SRobert Mustacchi 	    found++) {
251*24a03f35SRobert Mustacchi 		dump_continent(dirfd, c);
252*24a03f35SRobert Mustacchi 	}
253*24a03f35SRobert Mustacchi 
254*24a03f35SRobert Mustacchi 	if (found != ret) {
255*24a03f35SRobert Mustacchi 		errx(EXIT_FAILURE, "zoneinfo said %u continents should exist, "
256*24a03f35SRobert Mustacchi 		    "but found %u\n", ret, found);
257*24a03f35SRobert Mustacchi 	}
258*24a03f35SRobert Mustacchi 
259*24a03f35SRobert Mustacchi 	VERIFY0(free_tz_continents(conts));
260*24a03f35SRobert Mustacchi 
261*24a03f35SRobert Mustacchi 	return (0);
262*24a03f35SRobert Mustacchi }
263