1/*	$OpenBSD: util.c,v 1.31 2020/12/03 08:58:52 mvs Exp $	*/
2
3/*
4 * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
18 * written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 */
23
24#include <sys/types.h>
25#include <sys/time.h>
26#include <sys/file.h>
27#include <sys/limits.h>
28#include <sys/stat.h>
29
30#include <ctype.h>
31#include <err.h>
32#include <errno.h>
33#ifdef HAVE_FCNTL_H
34#include <fcntl.h>
35#endif
36#include <pcap.h>
37#include <stdio.h>
38#include <stdarg.h>
39#include <stdlib.h>
40#include <string.h>
41#ifdef TIME_WITH_SYS_TIME
42#include <time.h>
43#endif
44#include <unistd.h>
45
46#include "interface.h"
47#include "privsep.h"
48/*
49 * Print out a filename (or other ascii string).
50 * If ep is NULL, assume no truncation check is needed.
51 * Return true if truncated.
52 */
53int
54fn_print(const u_char *s, const u_char *ep)
55{
56	int ret;
57	u_char c;
58
59	ret = 1;			/* assume truncated */
60	while (ep == NULL || s < ep) {
61		c = *s++;
62		if (c == '\0') {
63			ret = 0;
64			break;
65		}
66		if (!isascii(c)) {
67			c = toascii(c);
68			putchar('M');
69			putchar('-');
70		}
71		if (!isprint(c)) {
72			c ^= 0x40;	/* DEL to ?, others to alpha */
73			putchar('^');
74		}
75		putchar(c);
76	}
77	return(ret);
78}
79
80/*
81 * Print out a counted filename (or other ascii string).
82 * If ep is NULL, assume no truncation check is needed.
83 * Return true if truncated.
84 */
85int
86fn_printn(const u_char *s, u_int n, const u_char *ep)
87{
88	int ret;
89	u_char c;
90
91	ret = 1;			/* assume truncated */
92	while (ep == NULL || s < ep) {
93		if (n-- <= 0) {
94			ret = 0;
95			break;
96		}
97		c = *s++;
98		if (!isascii(c)) {
99			c = toascii(c);
100			putchar('M');
101			putchar('-');
102		}
103		if (!isprint(c)) {
104			c ^= 0x40;	/* DEL to ?, others to alpha */
105			putchar('^');
106		}
107		putchar(c);
108	}
109	return(ret);
110}
111
112/*
113 * Print the timestamp
114 */
115void
116ts_print(const struct bpf_timeval *tvp)
117{
118	int s;
119#define TSBUFLEN 32
120	static char buf[TSBUFLEN];
121	static struct timeval last;
122	struct timeval diff, cur;
123	time_t t;
124
125	if (Iflag && device)
126		printf("%s ", device);
127	switch(tflag){
128	case 0:
129		break;
130	case -1:
131		/* Unix timeval style */
132		printf("%u.%06u ", tvp->tv_sec, tvp->tv_usec);
133		break;
134	case -2:
135		t = tvp->tv_sec;
136		strftime(buf, TSBUFLEN, "%b %d %T", priv_localtime(&t));
137		printf("%s.%06u ", buf, tvp->tv_usec);
138		break;
139	case -3: /* last frame time delta  */
140	case -4: /* first frame time delta  */
141		cur.tv_sec = tvp->tv_sec;
142		cur.tv_usec = tvp->tv_usec;
143		timersub(&cur, &last, &diff);
144		printf("%lld.%06ld ", diff.tv_sec, diff.tv_usec);
145		if (!timerisset(&last) || tflag == -3)
146			last = cur;
147		break;
148	default:
149		s = (tvp->tv_sec + thiszone) % 86400;
150		printf("%02d:%02d:%02d.%06u ",
151		    s / 3600, (s % 3600) / 60, s % 60, tvp->tv_usec);
152		break;
153	}
154}
155
156/*
157 * Print a relative number of seconds (e.g. hold time, prune timer)
158 * in the form 5m1s.  This does no truncation, so 32230861 seconds
159 * is represented as 1y1w1d1h1m1s.
160 */
161void
162relts_print(int secs)
163{
164	static char *lengths[] = {"y", "w", "d", "h", "m", "s"};
165	static int seconds[] = {31536000, 604800, 86400, 3600, 60, 1};
166	char **l = lengths;
167	int *s = seconds;
168
169	if (secs <= 0) {
170		printf("0s");
171		return;
172	}
173	while (secs > 0) {
174		if (secs >= *s) {
175			printf("%d%s", secs / *s, *l);
176			secs -= (secs / *s) * *s;
177		}
178		s++;
179		l++;
180	}
181}
182
183/*
184 * Convert a token value to a string; use "fmt" if not found.
185 */
186const char *
187tok2str(const struct tok *lp, const char *fmt, int v)
188{
189	static char buf[128];
190
191	while (lp->s != NULL) {
192		if (lp->v == v)
193			return (lp->s);
194		++lp;
195	}
196	if (fmt == NULL)
197		fmt = "#%d";
198	(void)snprintf(buf, sizeof(buf), fmt, v);
199	return (buf);
200}
201
202
203__dead void
204error(const char *fmt, ...)
205{
206	va_list ap;
207
208	(void)fprintf(stderr, "%s: ", program_name);
209	va_start(ap, fmt);
210	(void)vfprintf(stderr, fmt, ap);
211	va_end(ap);
212	(void)fputc('\n', stderr);
213	exit(1);
214	/* NOTREACHED */
215}
216
217void
218warning(const char *fmt, ...)
219{
220	va_list ap;
221
222	(void)fprintf(stderr, "%s: WARNING: ", program_name);
223	va_start(ap, fmt);
224	(void)vfprintf(stderr, fmt, ap);
225	va_end(ap);
226	(void)fputc('\n', stderr);
227}
228
229
230/*
231 * Copy arg vector into a new buffer, concatenating arguments with spaces.
232 */
233char *
234copy_argv(char * const *argv)
235{
236	size_t len = 0, n;
237	char *buf;
238
239	if (argv == NULL)
240		return (NULL);
241
242	for (n = 0; argv[n]; n++)
243		len += strlen(argv[n])+1;
244	if (len == 0)
245		return (NULL);
246
247	buf = malloc(len);
248	if (buf == NULL)
249		return (NULL);
250
251	strlcpy(buf, argv[0], len);
252	for (n = 1; argv[n]; n++) {
253		strlcat(buf, " ", len);
254		strlcat(buf, argv[n], len);
255	}
256	return (buf);
257}
258
259char *
260read_infile(char *fname)
261{
262	struct stat	 buf;
263	int		 fd;
264	ssize_t		 cc;
265	size_t		 bs;
266	char		*cp;
267
268	fd = open(fname, O_RDONLY);
269	if (fd == -1)
270		error("can't open %s: %s", fname, pcap_strerror(errno));
271
272	if (fstat(fd, &buf) == -1)
273		error("can't stat %s: %s", fname, pcap_strerror(errno));
274
275	if (buf.st_size >= SSIZE_MAX)
276		error("file too long");
277
278	bs = buf.st_size;
279	cp = malloc(bs + 1);
280	if (cp == NULL)
281		err(1, NULL);
282	cc = read(fd, cp, bs);
283	if (cc == -1)
284		error("read %s: %s", fname, pcap_strerror(errno));
285	if (cc != bs)
286		error("short read %s (%ld != %lu)", fname, (long)cc,
287		    (unsigned long)bs);
288	cp[bs] = '\0';
289	close(fd);
290
291	return (cp);
292}
293
294void
295safeputs(const char *s)
296{
297	while (*s) {
298		safeputchar(*s);
299		s++;
300	}
301}
302
303void
304safeputchar(int c)
305{
306	c &= 0xff;
307	if (c < 0x80 && isprint(c))
308		putchar(c);
309	else
310		printf("\\%03o", c);
311}
312
313/*
314 * Print a value a la the %b format of the kernel's printf
315 * (from sbin/ifconfig/ifconfig.c)
316 */
317void
318printb(char *s, unsigned short v, char *bits)
319{
320	int i, any = 0;
321	char c;
322
323	if (bits && *bits == 8)
324		printf("%s=%o", s, v);
325	else
326		printf("%s=%x", s, v);
327
328	if (bits) {
329		bits++;
330		putchar('<');
331		while ((i = *bits++)) {
332			if (v & (1 << (i-1))) {
333				if (any)
334					putchar(',');
335				any = 1;
336				for (; (c = *bits) > 32; bits++)
337					putchar(c);
338			} else
339				for (; *bits > 32; bits++)
340					;
341		}
342		putchar('>');
343	}
344}
345