xref: /freebsd/contrib/ntp/libntp/statestr.c (revision 2d4e511ca269f1908d27f4e5779c53475527391d)
1c0b746e5SOllivier Robert /*
2c0b746e5SOllivier Robert  * pretty printing of status information
3c0b746e5SOllivier Robert  */
4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
5c0b746e5SOllivier Robert #include <config.h>
6c0b746e5SOllivier Robert #endif
7c0b746e5SOllivier Robert #include <stdio.h>
8c0b746e5SOllivier Robert #include "ntp_stdlib.h"
9c0b746e5SOllivier Robert #include "ntp_fp.h"
10c0b746e5SOllivier Robert #include "ntp.h"
11c0b746e5SOllivier Robert #include "lib_strbuf.h"
12c0b746e5SOllivier Robert #include "ntp_refclock.h"
13c0b746e5SOllivier Robert #include "ntp_control.h"
14c0b746e5SOllivier Robert #include "ntp_string.h"
152b15cb3dSCy Schubert #ifdef KERNEL_PLL
162b15cb3dSCy Schubert # include "ntp_syscall.h"
172b15cb3dSCy Schubert #endif
182b15cb3dSCy Schubert 
19c0b746e5SOllivier Robert 
20c0b746e5SOllivier Robert /*
21c0b746e5SOllivier Robert  * Structure for turning various constants into a readable string.
22c0b746e5SOllivier Robert  */
23c0b746e5SOllivier Robert struct codestring {
24c0b746e5SOllivier Robert 	int code;
2509100258SXin LI 	const char * const string1;
2609100258SXin LI 	const char * const string0;
27c0b746e5SOllivier Robert };
28c0b746e5SOllivier Robert 
29c0b746e5SOllivier Robert /*
302b15cb3dSCy Schubert  * Leap status (leap)
31c0b746e5SOllivier Robert  */
322b15cb3dSCy Schubert static const struct codestring leap_codes[] = {
3309100258SXin LI 	{ LEAP_NOWARNING,	"leap_none",	0 },
3409100258SXin LI 	{ LEAP_ADDSECOND,	"leap_add_sec",	0 },
3509100258SXin LI 	{ LEAP_DELSECOND,	"leap_del_sec",	0 },
3609100258SXin LI 	{ LEAP_NOTINSYNC,	"leap_alarm",	0 },
3709100258SXin LI 	{ -1,			"leap",		0 }
38c0b746e5SOllivier Robert };
39c0b746e5SOllivier Robert 
40c0b746e5SOllivier Robert /*
412b15cb3dSCy Schubert  * Clock source status (sync)
42c0b746e5SOllivier Robert  */
432b15cb3dSCy Schubert static const struct codestring sync_codes[] = {
4409100258SXin LI 	{ CTL_SST_TS_UNSPEC,	"sync_unspec",		0 },
4509100258SXin LI 	{ CTL_SST_TS_ATOM,	"sync_pps",		0 },
4609100258SXin LI 	{ CTL_SST_TS_LF,	"sync_lf_radio",	0 },
4709100258SXin LI 	{ CTL_SST_TS_HF,	"sync_hf_radio",	0 },
4809100258SXin LI 	{ CTL_SST_TS_UHF,	"sync_uhf_radio",	0 },
4909100258SXin LI 	{ CTL_SST_TS_LOCAL,	"sync_local",		0 },
5009100258SXin LI 	{ CTL_SST_TS_NTP,	"sync_ntp",		0 },
5109100258SXin LI 	{ CTL_SST_TS_UDPTIME,	"sync_other",		0 },
5209100258SXin LI 	{ CTL_SST_TS_WRSTWTCH,	"sync_wristwatch",	0 },
5309100258SXin LI 	{ CTL_SST_TS_TELEPHONE,	"sync_telephone",	0 },
5409100258SXin LI 	{ -1,			"sync",			0 }
55c0b746e5SOllivier Robert };
56c0b746e5SOllivier Robert 
57c0b746e5SOllivier Robert /*
582b15cb3dSCy Schubert  * Peer selection status (sel)
59c0b746e5SOllivier Robert  */
602b15cb3dSCy Schubert static const struct codestring select_codes[] = {
6109100258SXin LI 	{ CTL_PST_SEL_REJECT,	"sel_reject",		0 },
6209100258SXin LI 	{ CTL_PST_SEL_SANE,	"sel_falsetick",	0 },
6309100258SXin LI 	{ CTL_PST_SEL_CORRECT,	"sel_excess",		0 },
6409100258SXin LI 	{ CTL_PST_SEL_SELCAND,	"sel_outlier",		0 },
6509100258SXin LI 	{ CTL_PST_SEL_SYNCCAND,	"sel_candidate",	0 },
6609100258SXin LI 	{ CTL_PST_SEL_EXCESS,	"sel_backup",		0 },
6709100258SXin LI 	{ CTL_PST_SEL_SYSPEER,	"sel_sys.peer",		0 },
6809100258SXin LI 	{ CTL_PST_SEL_PPS,	"sel_pps.peer",		0 },
6909100258SXin LI 	{ -1,			"sel",			0 }
70c0b746e5SOllivier Robert };
71c0b746e5SOllivier Robert 
72c0b746e5SOllivier Robert /*
732b15cb3dSCy Schubert  * Clock status (clk)
74c0b746e5SOllivier Robert  */
752b15cb3dSCy Schubert static const struct codestring clock_codes[] = {
7609100258SXin LI 	{ CTL_CLK_OKAY,		"clk_unspec",		0 },
7709100258SXin LI 	{ CTL_CLK_NOREPLY,	"clk_no_reply",		0 },
7809100258SXin LI 	{ CTL_CLK_BADFORMAT,	"clk_bad_format",	0 },
7909100258SXin LI 	{ CTL_CLK_FAULT,	"clk_fault",		0 },
8009100258SXin LI 	{ CTL_CLK_PROPAGATION,	"clk_bad_signal",	0 },
8109100258SXin LI 	{ CTL_CLK_BADDATE,	"clk_bad_date",		0 },
8209100258SXin LI 	{ CTL_CLK_BADTIME,	"clk_bad_time",		0 },
8309100258SXin LI 	{ -1,			"clk",			0 }
84c0b746e5SOllivier Robert };
85c0b746e5SOllivier Robert 
86c0b746e5SOllivier Robert 
872b15cb3dSCy Schubert #ifdef FLASH_CODES_UNUSED
88c0b746e5SOllivier Robert /*
892b15cb3dSCy Schubert  * Flash bits -- see ntpq.c tstflags & tstflagnames
90c0b746e5SOllivier Robert  */
912b15cb3dSCy Schubert static const struct codestring flash_codes[] = {
9209100258SXin LI 	{ TEST1,		"pkt_dup",	0 },
9309100258SXin LI 	{ TEST2,		"pkt_bogus",	0 },
9409100258SXin LI 	{ TEST3,		"pkt_unsync",	0 },
9509100258SXin LI 	{ TEST4,		"pkt_denied",	0 },
9609100258SXin LI 	{ TEST5,		"pkt_auth",	0 },
9709100258SXin LI 	{ TEST6,		"pkt_stratum",	0 },
9809100258SXin LI 	{ TEST7,		"pkt_header",	0 },
9909100258SXin LI 	{ TEST8,		"pkt_autokey",	0 },
10009100258SXin LI 	{ TEST9,		"pkt_crypto",	0 },
10109100258SXin LI 	{ TEST10,		"peer_stratum",	0 },
10209100258SXin LI 	{ TEST11,		"peer_dist",	0 },
10309100258SXin LI 	{ TEST12,		"peer_loop",	0 },
10409100258SXin LI 	{ TEST13,		"peer_unreach",	0 },
10509100258SXin LI 	{ -1,			"flash",	0 }
106c0b746e5SOllivier Robert };
107c0b746e5SOllivier Robert #endif
1082b15cb3dSCy Schubert 
1092b15cb3dSCy Schubert 
1102b15cb3dSCy Schubert /*
1112b15cb3dSCy Schubert  * System events (sys)
1122b15cb3dSCy Schubert  */
1132b15cb3dSCy Schubert static const struct codestring sys_codes[] = {
11409100258SXin LI 	{ EVNT_UNSPEC,		"unspecified",			0 },
11509100258SXin LI 	{ EVNT_NSET,		"freq_not_set",			0 },
11609100258SXin LI 	{ EVNT_FSET,		"freq_set",			0 },
11709100258SXin LI 	{ EVNT_SPIK,		"spike_detect",			0 },
11809100258SXin LI 	{ EVNT_FREQ,		"freq_mode",			0 },
11909100258SXin LI 	{ EVNT_SYNC,		"clock_sync",			0 },
12009100258SXin LI 	{ EVNT_SYSRESTART,	"restart",			0 },
12109100258SXin LI 	{ EVNT_SYSFAULT,	"panic_stop",			0 },
12209100258SXin LI 	{ EVNT_NOPEER,		"no_sys_peer",			0 },
12309100258SXin LI 	{ EVNT_ARMED,		"leap_armed",			0 },
12409100258SXin LI 	{ EVNT_DISARMED,	"leap_disarmed",		0 },
12509100258SXin LI 	{ EVNT_LEAP,		"leap_event",			0 },
12609100258SXin LI 	{ EVNT_CLOCKRESET,	"clock_step",			0 },
12709100258SXin LI 	{ EVNT_KERN,		"kern",				0 },
12809100258SXin LI 	{ EVNT_TAI,		"TAI",				0 },
12909100258SXin LI 	{ EVNT_LEAPVAL,		"stale_leapsecond_values",	0 },
13009100258SXin LI 	{ -1,			"",				0 }
131c0b746e5SOllivier Robert };
132c0b746e5SOllivier Robert 
1339c2daa00SOllivier Robert /*
1342b15cb3dSCy Schubert  * Peer events (peer)
1359c2daa00SOllivier Robert  */
1362b15cb3dSCy Schubert static const struct codestring peer_codes[] = {
13709100258SXin LI 	{ PEVNT_MOBIL & ~PEER_EVENT,	"mobilize",		0 },
13809100258SXin LI 	{ PEVNT_DEMOBIL & ~PEER_EVENT,	"demobilize",		0 },
13909100258SXin LI 	{ PEVNT_UNREACH & ~PEER_EVENT,	"unreachable",		0 },
14009100258SXin LI 	{ PEVNT_REACH & ~PEER_EVENT,	"reachable",		0 },
14109100258SXin LI 	{ PEVNT_RESTART & ~PEER_EVENT,	"restart",		0 },
14209100258SXin LI 	{ PEVNT_REPLY & ~PEER_EVENT,	"no_reply",		0 },
14309100258SXin LI 	{ PEVNT_RATE & ~PEER_EVENT,	"rate_exceeded",	0 },
14409100258SXin LI 	{ PEVNT_DENY & ~PEER_EVENT,	"access_denied",	0 },
14509100258SXin LI 	{ PEVNT_ARMED & ~PEER_EVENT,	"leap_armed",		0 },
14609100258SXin LI 	{ PEVNT_NEWPEER & ~PEER_EVENT,	"sys_peer",		0 },
14709100258SXin LI 	{ PEVNT_CLOCK & ~PEER_EVENT,	"clock_event",		0 },
14809100258SXin LI 	{ PEVNT_AUTH & ~PEER_EVENT,	"bad_auth",		0 },
14909100258SXin LI 	{ PEVNT_POPCORN & ~PEER_EVENT,	"popcorn",		0 },
15009100258SXin LI 	{ PEVNT_XLEAVE & ~PEER_EVENT,	"interleave_mode",	0 },
15109100258SXin LI 	{ PEVNT_XERR & ~PEER_EVENT,	"interleave_error",	0 },
15209100258SXin LI 	{ -1,				"",			0 }
1532b15cb3dSCy Schubert };
1542b15cb3dSCy Schubert 
1552b15cb3dSCy Schubert /*
1562b15cb3dSCy Schubert  * Peer status bits
1572b15cb3dSCy Schubert  */
1582b15cb3dSCy Schubert static const struct codestring peer_st_bits[] = {
15909100258SXin LI 	{ CTL_PST_CONFIG,		"conf",		0 },
16009100258SXin LI 	{ CTL_PST_AUTHENABLE,		"authenb",	0 },
16109100258SXin LI 	{ CTL_PST_AUTHENTIC,		"auth",		0 },
16209100258SXin LI 	{ CTL_PST_REACH,		"reach",	0 },
16309100258SXin LI 	{ CTL_PST_BCAST,		"bcast",	0 },
1642b15cb3dSCy Schubert 	/* not used with getcode(), no terminating entry needed */
1652b15cb3dSCy Schubert };
1662b15cb3dSCy Schubert 
1672b15cb3dSCy Schubert /*
1682b15cb3dSCy Schubert  * Restriction match bits
1692b15cb3dSCy Schubert  */
1702b15cb3dSCy Schubert static const struct codestring res_match_bits[] = {
17109100258SXin LI 	{ RESM_NTPONLY,			"ntpport",	0 },
17209100258SXin LI 	{ RESM_INTERFACE,		"interface",	0 },
17309100258SXin LI 	{ RESM_SOURCE,			"source",	0 },
1742b15cb3dSCy Schubert 	/* not used with getcode(), no terminating entry needed */
1752b15cb3dSCy Schubert };
1762b15cb3dSCy Schubert 
1772b15cb3dSCy Schubert /*
1782b15cb3dSCy Schubert  * Restriction access bits
1792b15cb3dSCy Schubert  */
1802b15cb3dSCy Schubert static const struct codestring res_access_bits[] = {
18109100258SXin LI 	{ RES_IGNORE,			"ignore",	0 },
18209100258SXin LI 	{ RES_DONTSERVE,		"noserve",	"serve" },
18309100258SXin LI 	{ RES_DONTTRUST,		"notrust",	"trust" },
184*2d4e511cSCy Schubert 	{ RES_VERSION,			"version",	0 },
18509100258SXin LI 	{ RES_NOPEER,			"nopeer",	"peer" },
18609100258SXin LI 	{ RES_NOEPEER,			"noepeer",	"epeer" },
187*2d4e511cSCy Schubert 	{ RES_LIMITED,			"limited",	0 },
188*2d4e511cSCy Schubert 
189*2d4e511cSCy Schubert 	{ RES_NOQUERY,			"noquery",	"query" },
190*2d4e511cSCy Schubert 	{ RES_NOMODIFY,			"nomodify",	0 },
19109100258SXin LI 	{ RES_NOTRAP,			"notrap",	"trap" },
19209100258SXin LI 	{ RES_LPTRAP,			"lptrap",	0 },
193*2d4e511cSCy Schubert 
19409100258SXin LI 	{ RES_KOD,			"kod",		0 },
195*2d4e511cSCy Schubert 	{ RES_MSSNTP,			"mssntp",	0 },
19609100258SXin LI 	{ RES_FLAKE,			"flake",	0 },
197*2d4e511cSCy Schubert 	{ RES_NOMRULIST,		"nomrulist",	0 },
198*2d4e511cSCy Schubert 
199*2d4e511cSCy Schubert 	{ RES_SRVRSPFUZ,		"serverresponse fuzz",	0 },
200*2d4e511cSCy Schubert 
2012b15cb3dSCy Schubert 	/* not used with getcode(), no terminating entry needed */
2022b15cb3dSCy Schubert };
2032b15cb3dSCy Schubert 
2042b15cb3dSCy Schubert #ifdef AUTOKEY
2052b15cb3dSCy Schubert /*
2062b15cb3dSCy Schubert  * Crypto events (cryp)
2072b15cb3dSCy Schubert  */
2082b15cb3dSCy Schubert static const struct codestring crypto_codes[] = {
20909100258SXin LI 	{ XEVNT_OK & ~CRPT_EVENT,	"success",			0 },
21009100258SXin LI 	{ XEVNT_LEN & ~CRPT_EVENT,	"bad_field_format_or_length",	0 },
21109100258SXin LI 	{ XEVNT_TSP & ~CRPT_EVENT,	"bad_timestamp",		0 },
21209100258SXin LI 	{ XEVNT_FSP & ~CRPT_EVENT,	"bad_filestamp",		0 },
21309100258SXin LI 	{ XEVNT_PUB & ~CRPT_EVENT,	"bad_or_missing_public_key",	0 },
21409100258SXin LI 	{ XEVNT_MD & ~CRPT_EVENT,	"unsupported_digest_type",	0 },
21509100258SXin LI 	{ XEVNT_KEY & ~CRPT_EVENT,	"unsupported_identity_type",	0 },
21609100258SXin LI 	{ XEVNT_SGL & ~CRPT_EVENT,	"bad_signature_length",		0 },
21709100258SXin LI 	{ XEVNT_SIG & ~CRPT_EVENT,	"signature_not_verified",	0 },
21809100258SXin LI 	{ XEVNT_VFY & ~CRPT_EVENT,	"certificate_not_verified",	0 },
21909100258SXin LI 	{ XEVNT_PER & ~CRPT_EVENT,	"host_certificate_expired",	0 },
22009100258SXin LI 	{ XEVNT_CKY & ~CRPT_EVENT,	"bad_or_missing_cookie",	0 },
22109100258SXin LI 	{ XEVNT_DAT & ~CRPT_EVENT,	"bad_or_missing_leapseconds",	0 },
22209100258SXin LI 	{ XEVNT_CRT & ~CRPT_EVENT,	"bad_or_missing_certificate",	0 },
22309100258SXin LI 	{ XEVNT_ID & ~CRPT_EVENT,	"bad_or_missing_group key",	0 },
22409100258SXin LI 	{ XEVNT_ERR & ~CRPT_EVENT,	"protocol_error",		0 },
22509100258SXin LI 	{ -1,				"",				0 }
2269c2daa00SOllivier Robert };
2272b15cb3dSCy Schubert #endif	/* AUTOKEY */
2282b15cb3dSCy Schubert 
2292b15cb3dSCy Schubert #ifdef KERNEL_PLL
2302b15cb3dSCy Schubert /*
2312b15cb3dSCy Schubert  * kernel discipline status bits
2322b15cb3dSCy Schubert  */
2332b15cb3dSCy Schubert static const struct codestring k_st_bits[] = {
2342b15cb3dSCy Schubert # ifdef STA_PLL
23509100258SXin LI 	{ STA_PLL,			"pll",		0 },
2362b15cb3dSCy Schubert # endif
2372b15cb3dSCy Schubert # ifdef STA_PPSFREQ
23809100258SXin LI 	{ STA_PPSFREQ,			"ppsfreq",	0 },
2392b15cb3dSCy Schubert # endif
2402b15cb3dSCy Schubert # ifdef STA_PPSTIME
24109100258SXin LI 	{ STA_PPSTIME,			"ppstime",	0 },
2422b15cb3dSCy Schubert # endif
2432b15cb3dSCy Schubert # ifdef STA_FLL
24409100258SXin LI 	{ STA_FLL,			"fll",		0 },
2452b15cb3dSCy Schubert # endif
2462b15cb3dSCy Schubert # ifdef STA_INS
24709100258SXin LI 	{ STA_INS,			"ins",		0 },
2482b15cb3dSCy Schubert # endif
2492b15cb3dSCy Schubert # ifdef STA_DEL
25009100258SXin LI 	{ STA_DEL,			"del",		0 },
2512b15cb3dSCy Schubert # endif
2522b15cb3dSCy Schubert # ifdef STA_UNSYNC
25309100258SXin LI 	{ STA_UNSYNC,			"unsync",	0 },
2542b15cb3dSCy Schubert # endif
2552b15cb3dSCy Schubert # ifdef STA_FREQHOLD
25609100258SXin LI 	{ STA_FREQHOLD,			"freqhold",	0 },
2572b15cb3dSCy Schubert # endif
2582b15cb3dSCy Schubert # ifdef STA_PPSSIGNAL
25909100258SXin LI 	{ STA_PPSSIGNAL,		"ppssignal",	0 },
2602b15cb3dSCy Schubert # endif
2612b15cb3dSCy Schubert # ifdef STA_PPSJITTER
26209100258SXin LI 	{ STA_PPSJITTER,		"ppsjitter",	0 },
2632b15cb3dSCy Schubert # endif
2642b15cb3dSCy Schubert # ifdef STA_PPSWANDER
26509100258SXin LI 	{ STA_PPSWANDER,		"ppswander",	0 },
2662b15cb3dSCy Schubert # endif
2672b15cb3dSCy Schubert # ifdef STA_PPSERROR
26809100258SXin LI 	{ STA_PPSERROR,			"ppserror",	0 },
2692b15cb3dSCy Schubert # endif
2702b15cb3dSCy Schubert # ifdef STA_CLOCKERR
27109100258SXin LI 	{ STA_CLOCKERR,			"clockerr",	0 },
2722b15cb3dSCy Schubert # endif
2732b15cb3dSCy Schubert # ifdef STA_NANO
27409100258SXin LI 	{ STA_NANO,			"nano",		0 },
2752b15cb3dSCy Schubert # endif
2762b15cb3dSCy Schubert # ifdef STA_MODE
27709100258SXin LI 	{ STA_MODE,			"mode=fll",	0 },
2782b15cb3dSCy Schubert # endif
2792b15cb3dSCy Schubert # ifdef STA_CLK
28009100258SXin LI 	{ STA_CLK,			"src=B",	0 },
2812b15cb3dSCy Schubert # endif
2822b15cb3dSCy Schubert 	/* not used with getcode(), no terminating entry needed */
2832b15cb3dSCy Schubert };
2842b15cb3dSCy Schubert #endif	/* KERNEL_PLL */
2859c2daa00SOllivier Robert 
286c0b746e5SOllivier Robert /* Forwards */
2872b15cb3dSCy Schubert static const char *	getcode(int, const struct codestring *);
2882b15cb3dSCy Schubert static const char *	getevents(int);
2892b15cb3dSCy Schubert static const char *	peer_st_flags(u_char pst);
290c0b746e5SOllivier Robert 
291c0b746e5SOllivier Robert /*
292c0b746e5SOllivier Robert  * getcode - return string corresponding to code
293c0b746e5SOllivier Robert  */
294c0b746e5SOllivier Robert static const char *
295c0b746e5SOllivier Robert getcode(
296c0b746e5SOllivier Robert 	int				code,
2972b15cb3dSCy Schubert 	const struct codestring *	codetab
298c0b746e5SOllivier Robert 	)
299c0b746e5SOllivier Robert {
3002b15cb3dSCy Schubert 	char *	buf;
301c0b746e5SOllivier Robert 
302c0b746e5SOllivier Robert 	while (codetab->code != -1) {
303c0b746e5SOllivier Robert 		if (codetab->code == code)
30409100258SXin LI 			return codetab->string1;
305c0b746e5SOllivier Robert 		codetab++;
306c0b746e5SOllivier Robert 	}
3072b15cb3dSCy Schubert 
3082b15cb3dSCy Schubert 	LIB_GETBUF(buf);
30909100258SXin LI 	snprintf(buf, LIB_BUFLENGTH, "%s_%d", codetab->string1, code);
3102b15cb3dSCy Schubert 
311c0b746e5SOllivier Robert 	return buf;
312c0b746e5SOllivier Robert }
313c0b746e5SOllivier Robert 
314c0b746e5SOllivier Robert /*
315c0b746e5SOllivier Robert  * getevents - return a descriptive string for the event count
316c0b746e5SOllivier Robert  */
317c0b746e5SOllivier Robert static const char *
318c0b746e5SOllivier Robert getevents(
319c0b746e5SOllivier Robert 	int cnt
320c0b746e5SOllivier Robert 	)
321c0b746e5SOllivier Robert {
3222b15cb3dSCy Schubert 	char *	buf;
323c0b746e5SOllivier Robert 
324c0b746e5SOllivier Robert 	if (cnt == 0)
325c0b746e5SOllivier Robert 		return "no events";
3262b15cb3dSCy Schubert 
3272b15cb3dSCy Schubert 	LIB_GETBUF(buf);
3282b15cb3dSCy Schubert 	snprintf(buf, LIB_BUFLENGTH, "%d event%s", cnt,
3292b15cb3dSCy Schubert 		 (1 == cnt)
3302b15cb3dSCy Schubert 		     ? ""
3312b15cb3dSCy Schubert 		     : "s");
3322b15cb3dSCy Schubert 
333c0b746e5SOllivier Robert 	return buf;
334c0b746e5SOllivier Robert }
335c0b746e5SOllivier Robert 
3362b15cb3dSCy Schubert 
3372b15cb3dSCy Schubert /*
3382b15cb3dSCy Schubert  * decode_bitflags()
3392b15cb3dSCy Schubert  *
3402b15cb3dSCy Schubert  * returns a human-readable string with a keyword from tab for each bit
3412b15cb3dSCy Schubert  * set in bits, separating multiple entries with text of sep2.
3422b15cb3dSCy Schubert  */
3432b15cb3dSCy Schubert static const char *
3442b15cb3dSCy Schubert decode_bitflags(
3452b15cb3dSCy Schubert 	int				bits,
3462b15cb3dSCy Schubert 	const char *			sep2,
3472b15cb3dSCy Schubert 	const struct codestring *	tab,
3482b15cb3dSCy Schubert 	size_t				tab_ct
3492b15cb3dSCy Schubert 	)
3502b15cb3dSCy Schubert {
3512b15cb3dSCy Schubert 	const char *	sep;
3522b15cb3dSCy Schubert 	char *		buf;
3532b15cb3dSCy Schubert 	char *		pch;
3542b15cb3dSCy Schubert 	char *		lim;
3552b15cb3dSCy Schubert 	size_t		b;
3562b15cb3dSCy Schubert 	int		rc;
3572b15cb3dSCy Schubert 	int		saved_errno;	/* for use in DPRINTF with %m */
3582b15cb3dSCy Schubert 
3592b15cb3dSCy Schubert 	saved_errno = errno;
3602b15cb3dSCy Schubert 	LIB_GETBUF(buf);
3612b15cb3dSCy Schubert 	pch = buf;
3622b15cb3dSCy Schubert 	lim = buf + LIB_BUFLENGTH;
3632b15cb3dSCy Schubert 	sep = "";
3642b15cb3dSCy Schubert 
3652b15cb3dSCy Schubert 	for (b = 0; b < tab_ct; b++) {
36609100258SXin LI 		const char * flagstr;
36709100258SXin LI 
3682b15cb3dSCy Schubert 		if (tab[b].code & bits) {
36909100258SXin LI 			flagstr = tab[b].string1;
37009100258SXin LI 		} else {
37109100258SXin LI 			flagstr = tab[b].string0;
37209100258SXin LI 		}
37309100258SXin LI 
37409100258SXin LI 		if (flagstr) {
375f0574f5cSXin LI 			size_t avail = lim - pch;
376f0574f5cSXin LI 			rc = snprintf(pch, avail, "%s%s", sep,
37709100258SXin LI 				      flagstr);
378f0574f5cSXin LI 			if ((size_t)rc >= avail)
3792b15cb3dSCy Schubert 				goto toosmall;
380f0574f5cSXin LI 			pch += rc;
3812b15cb3dSCy Schubert 			sep = sep2;
3822b15cb3dSCy Schubert 		}
3832b15cb3dSCy Schubert 	}
3842b15cb3dSCy Schubert 
3852b15cb3dSCy Schubert 	return buf;
3862b15cb3dSCy Schubert 
3872b15cb3dSCy Schubert     toosmall:
3882b15cb3dSCy Schubert 	snprintf(buf, LIB_BUFLENGTH,
3892b15cb3dSCy Schubert 		 "decode_bitflags(%s) can't decode 0x%x in %d bytes",
3902b15cb3dSCy Schubert 		 (tab == peer_st_bits)
3912b15cb3dSCy Schubert 		     ? "peer_st"
3922b15cb3dSCy Schubert 		     :
3932b15cb3dSCy Schubert #ifdef KERNEL_PLL
3942b15cb3dSCy Schubert 		       (tab == k_st_bits)
3952b15cb3dSCy Schubert 			   ? "kern_st"
3962b15cb3dSCy Schubert 			   :
3972b15cb3dSCy Schubert #endif
3982b15cb3dSCy Schubert 			     "",
3992b15cb3dSCy Schubert 		 bits, (int)LIB_BUFLENGTH);
4002b15cb3dSCy Schubert 	errno = saved_errno;
4012b15cb3dSCy Schubert 
4022b15cb3dSCy Schubert 	return buf;
4032b15cb3dSCy Schubert }
4042b15cb3dSCy Schubert 
4052b15cb3dSCy Schubert 
4062b15cb3dSCy Schubert static const char *
4072b15cb3dSCy Schubert peer_st_flags(
4082b15cb3dSCy Schubert 	u_char pst
4092b15cb3dSCy Schubert 	)
4102b15cb3dSCy Schubert {
4112b15cb3dSCy Schubert 	return decode_bitflags(pst, ", ", peer_st_bits,
4122b15cb3dSCy Schubert 			       COUNTOF(peer_st_bits));
4132b15cb3dSCy Schubert }
4142b15cb3dSCy Schubert 
4152b15cb3dSCy Schubert 
4162b15cb3dSCy Schubert const char *
4172b15cb3dSCy Schubert res_match_flags(
4182b15cb3dSCy Schubert 	u_short mf
4192b15cb3dSCy Schubert 	)
4202b15cb3dSCy Schubert {
4212b15cb3dSCy Schubert 	return decode_bitflags(mf, " ", res_match_bits,
4222b15cb3dSCy Schubert 			       COUNTOF(res_match_bits));
4232b15cb3dSCy Schubert }
4242b15cb3dSCy Schubert 
4252b15cb3dSCy Schubert 
4262b15cb3dSCy Schubert const char *
4272b15cb3dSCy Schubert res_access_flags(
428*2d4e511cSCy Schubert 	u_int32 af
4292b15cb3dSCy Schubert 	)
4302b15cb3dSCy Schubert {
4312b15cb3dSCy Schubert 	return decode_bitflags(af, " ", res_access_bits,
4322b15cb3dSCy Schubert 			       COUNTOF(res_access_bits));
4332b15cb3dSCy Schubert }
4342b15cb3dSCy Schubert 
4352b15cb3dSCy Schubert 
4362b15cb3dSCy Schubert #ifdef KERNEL_PLL
4372b15cb3dSCy Schubert const char *
4382b15cb3dSCy Schubert k_st_flags(
4392b15cb3dSCy Schubert 	u_int32 st
4402b15cb3dSCy Schubert 	)
4412b15cb3dSCy Schubert {
4422b15cb3dSCy Schubert 	return decode_bitflags(st, " ", k_st_bits, COUNTOF(k_st_bits));
4432b15cb3dSCy Schubert }
4442b15cb3dSCy Schubert #endif	/* KERNEL_PLL */
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert 
447c0b746e5SOllivier Robert /*
448c0b746e5SOllivier Robert  * statustoa - return a descriptive string for a peer status
449c0b746e5SOllivier Robert  */
450c0b746e5SOllivier Robert char *
451c0b746e5SOllivier Robert statustoa(
452c0b746e5SOllivier Robert 	int type,
453c0b746e5SOllivier Robert 	int st
454c0b746e5SOllivier Robert 	)
455c0b746e5SOllivier Robert {
456c0b746e5SOllivier Robert 	char *	cb;
4572b15cb3dSCy Schubert 	char *	cc;
458c0b746e5SOllivier Robert 	u_char	pst;
459c0b746e5SOllivier Robert 
460c0b746e5SOllivier Robert 	LIB_GETBUF(cb);
461c0b746e5SOllivier Robert 
462c0b746e5SOllivier Robert 	switch (type) {
4632b15cb3dSCy Schubert 
464c0b746e5SOllivier Robert 	case TYPE_SYS:
4652b15cb3dSCy Schubert 		snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s, %s",
4662b15cb3dSCy Schubert 			 getcode(CTL_SYS_LI(st), leap_codes),
4672b15cb3dSCy Schubert 			 getcode(CTL_SYS_SOURCE(st), sync_codes),
4682b15cb3dSCy Schubert 			 getevents(CTL_SYS_NEVNT(st)),
4692b15cb3dSCy Schubert 			 getcode(CTL_SYS_EVENT(st), sys_codes));
470c0b746e5SOllivier Robert 		break;
471c0b746e5SOllivier Robert 
472c0b746e5SOllivier Robert 	case TYPE_PEER:
473c0b746e5SOllivier Robert 		pst = (u_char)CTL_PEER_STATVAL(st);
4742b15cb3dSCy Schubert 		snprintf(cb, LIB_BUFLENGTH, "%s, %s, %s",
4752b15cb3dSCy Schubert 			 peer_st_flags(pst),
4762b15cb3dSCy Schubert 			 getcode(pst & 0x7, select_codes),
4772b15cb3dSCy Schubert 			 getevents(CTL_PEER_NEVNT(st)));
478c0b746e5SOllivier Robert 		if (CTL_PEER_EVENT(st) != EVNT_UNSPEC) {
4792b15cb3dSCy Schubert 			cc = cb + strlen(cb);
4802b15cb3dSCy Schubert 			snprintf(cc, LIB_BUFLENGTH - (cc - cb), ", %s",
4812b15cb3dSCy Schubert 				 getcode(CTL_PEER_EVENT(st),
482c0b746e5SOllivier Robert 					 peer_codes));
483c0b746e5SOllivier Robert 		}
484c0b746e5SOllivier Robert 		break;
485c0b746e5SOllivier Robert 
486c0b746e5SOllivier Robert 	case TYPE_CLOCK:
4872b15cb3dSCy Schubert 		snprintf(cb, LIB_BUFLENGTH, "%s, %s",
4882b15cb3dSCy Schubert 			 getevents(CTL_SYS_NEVNT(st)),
4892b15cb3dSCy Schubert 			 getcode((st) & 0xf, clock_codes));
490c0b746e5SOllivier Robert 		break;
491c0b746e5SOllivier Robert 	}
4922b15cb3dSCy Schubert 
493c0b746e5SOllivier Robert 	return cb;
494c0b746e5SOllivier Robert }
495c0b746e5SOllivier Robert 
496c0b746e5SOllivier Robert const char *
497c0b746e5SOllivier Robert eventstr(
498c0b746e5SOllivier Robert 	int num
499c0b746e5SOllivier Robert 	)
500c0b746e5SOllivier Robert {
5019c2daa00SOllivier Robert 	if (num & PEER_EVENT)
5029c2daa00SOllivier Robert 		return (getcode(num & ~PEER_EVENT, peer_codes));
5032b15cb3dSCy Schubert #ifdef AUTOKEY
5049c2daa00SOllivier Robert 	else if (num & CRPT_EVENT)
5059c2daa00SOllivier Robert 		return (getcode(num & ~CRPT_EVENT, crypto_codes));
5062b15cb3dSCy Schubert #endif	/* AUTOKEY */
5079c2daa00SOllivier Robert 	else
5089c2daa00SOllivier Robert 		return (getcode(num, sys_codes));
509c0b746e5SOllivier Robert }
510c0b746e5SOllivier Robert 
511c0b746e5SOllivier Robert const char *
512c0b746e5SOllivier Robert ceventstr(
513c0b746e5SOllivier Robert 	int num
514c0b746e5SOllivier Robert 	)
515c0b746e5SOllivier Robert {
516c0b746e5SOllivier Robert 	return getcode(num, clock_codes);
517c0b746e5SOllivier Robert }
518