1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  */
5 //applet:IF_DUMPLEASES(APPLET_NOEXEC(dumpleases, dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP, dumpleases))
6 
7 //kbuild:lib-$(CONFIG_DUMPLEASES) += dumpleases.o
8 
9 //usage:#define dumpleases_trivial_usage
10 //usage:       "[-r|-a] [-d] [-f LEASEFILE]"
11 //usage:#define dumpleases_full_usage "\n\n"
12 //usage:       "Display DHCP leases granted by udhcpd\n"
13 //usage:     "\n	-f FILE	Lease file"
14 //usage:     "\n	-r	Show remaining time"
15 //usage:     "\n	-a	Show expiration time"
16 //usage:     "\n	-d	Show time in seconds"
17 
18 #include "common.h"
19 #include "dhcpd.h"
20 #include "unicode.h"
21 
22 int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
dumpleases_main(int argc UNUSED_PARAM,char ** argv)23 int dumpleases_main(int argc UNUSED_PARAM, char **argv)
24 {
25 	int fd;
26 	int i;
27 	unsigned opt;
28 	int64_t written_at, curr;
29 	const char *file = LEASES_FILE;
30 	struct dyn_lease lease;
31 
32 	enum {
33 		OPT_a = 0x1, // -a
34 		OPT_r = 0x2, // -r
35 		OPT_f = 0x4, // -f
36 		OPT_d = 0x8, // -d
37 	};
38 #if ENABLE_LONG_OPTS
39 	static const char dumpleases_longopts[] ALIGN1 =
40 		"absolute\0"  No_argument       "a"
41 		"remaining\0" No_argument       "r"
42 		"file\0"      Required_argument "f"
43 		"decimal\0"   No_argument       "d"
44 		;
45 
46 #endif
47 	init_unicode();
48 
49 	opt = getopt32long(argv, "^"
50 			"arf:d"
51 			"\0" "=0:a--r:r--a",
52 			dumpleases_longopts,
53 			&file
54 	);
55 
56 	fd = xopen(file, O_RDONLY);
57 
58 	/*     "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
59 	/*     "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
60 	printf("Mac %-14s"       "IP %-13s"      "Host %-15s"        "Expires %s\n",
61 		"Address", "Address", "Name",
62 		(opt & OPT_a) ? "at" : "in"
63 	);
64 
65 	xread(fd, &written_at, sizeof(written_at));
66 	written_at = SWAP_BE64(written_at);
67 	curr = time(NULL);
68 	if (curr < written_at)
69 		written_at = curr; /* lease file from future! :) */
70 
71 	while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
72 		struct in_addr addr;
73 		int64_t expires_abs;
74 
75 		const char *fmt = ":%02x" + 1;
76 		for (i = 0; i < 6; i++) {
77 			printf(fmt, lease.lease_mac[i]);
78 			fmt = ":%02x";
79 		}
80 		addr.s_addr = lease.lease_nip;
81 #if ENABLE_UNICODE_SUPPORT
82 		{
83 			char *uni_name = unicode_conv_to_printable_fixedwidth(/*NULL,*/ lease.hostname, 19);
84 			printf(" %-16s%s ", inet_ntoa(addr), uni_name);
85 			free(uni_name);
86 		}
87 #else
88 		/* actually, 15+1 and 19+1, +1 is a space between columns */
89 		/* lease.hostname is char[20] and is always NUL terminated */
90 		printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
91 #endif
92 		expires_abs = ntohl(lease.expires) + written_at;
93 		if (expires_abs <= curr) {
94 			puts("expired");
95 			continue;
96 		}
97 		if (opt & OPT_d) {
98 			/* -d: decimal time */
99 			if (!(opt & OPT_a))
100 				expires_abs -= curr;
101 			printf("%llu\n", (unsigned long long) expires_abs);
102 			continue;
103 		}
104 		if (!(opt & OPT_a)) { /* no -a */
105 			unsigned d, h, m;
106 			unsigned expires = expires_abs - curr;
107 			d = expires / (24*60*60); expires %= (24*60*60);
108 			h = expires / (60*60); expires %= (60*60);
109 			m = expires / 60; expires %= 60;
110 			if (d)
111 				printf("%u days ", d);
112 			printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
113 		} else { /* -a */
114 			time_t t = expires_abs;
115 			fputs_stdout(ctime(&t));
116 		}
117 	}
118 	/* close(fd); */
119 
120 	return 0;
121 }
122