xref: /titanic_52/usr/src/cmd/cmd-inet/usr.bin/whois.c (revision 1dd3983cc356c3a7dfb198a7226406e01152a352)
17c478bd9Sstevel@tonic-gate /*
2*1dd3983cSYuri Pankov  * Copyright (c) 1980, 1993
3*1dd3983cSYuri Pankov  *	The Regents of the University of California.  All rights reserved.
47c478bd9Sstevel@tonic-gate  *
5*1dd3983cSYuri Pankov  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
67c478bd9Sstevel@tonic-gate  *
7*1dd3983cSYuri Pankov  * Redistribution and use in source and binary forms, with or without
8*1dd3983cSYuri Pankov  * modification, are permitted provided that the following conditions
9*1dd3983cSYuri Pankov  * are met:
10*1dd3983cSYuri Pankov  * 1. Redistributions of source code must retain the above copyright
11*1dd3983cSYuri Pankov  *    notice, this list of conditions and the following disclaimer.
12*1dd3983cSYuri Pankov  * 2. Redistributions in binary form must reproduce the above copyright
13*1dd3983cSYuri Pankov  *    notice, this list of conditions and the following disclaimer in the
14*1dd3983cSYuri Pankov  *    documentation and/or other materials provided with the distribution.
15*1dd3983cSYuri Pankov  * 4. Neither the name of the University nor the names of its contributors
16*1dd3983cSYuri Pankov  *    may be used to endorse or promote products derived from this software
17*1dd3983cSYuri Pankov  *    without specific prior written permission.
187c478bd9Sstevel@tonic-gate  *
19*1dd3983cSYuri Pankov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*1dd3983cSYuri Pankov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*1dd3983cSYuri Pankov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*1dd3983cSYuri Pankov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*1dd3983cSYuri Pankov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*1dd3983cSYuri Pankov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*1dd3983cSYuri Pankov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*1dd3983cSYuri Pankov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*1dd3983cSYuri Pankov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*1dd3983cSYuri Pankov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*1dd3983cSYuri Pankov  * SUCH DAMAGE.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/socket.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <netinet/in.h>
36*1dd3983cSYuri Pankov #include <arpa/inet.h>
37*1dd3983cSYuri Pankov #include <ctype.h>
38*1dd3983cSYuri Pankov #include <err.h>
39*1dd3983cSYuri Pankov #include <limits.h>
407c478bd9Sstevel@tonic-gate #include <netdb.h>
41*1dd3983cSYuri Pankov #include <stdarg.h>
42*1dd3983cSYuri Pankov #include <stdio.h>
43f098c48bSDerek Morr #include <stdlib.h>
44*1dd3983cSYuri Pankov #include <string.h>
45*1dd3983cSYuri Pankov #include <sysexits.h>
46f098c48bSDerek Morr #include <unistd.h>
477c478bd9Sstevel@tonic-gate 
48*1dd3983cSYuri Pankov #define	ABUSEHOST	"whois.abuse.net"
49*1dd3983cSYuri Pankov #define	NICHOST		"whois.crsnic.net"
50*1dd3983cSYuri Pankov #define	INICHOST	"whois.networksolutions.com"
51*1dd3983cSYuri Pankov #define	GNICHOST	"whois.nic.gov"
52*1dd3983cSYuri Pankov #define	ANICHOST	"whois.arin.net"
53*1dd3983cSYuri Pankov #define	LNICHOST	"whois.lacnic.net"
54*1dd3983cSYuri Pankov #define	KNICHOST	"whois.krnic.net"
55*1dd3983cSYuri Pankov #define	RNICHOST	"whois.ripe.net"
56*1dd3983cSYuri Pankov #define	PNICHOST	"whois.apnic.net"
57*1dd3983cSYuri Pankov #define	MNICHOST	"whois.ra.net"
58*1dd3983cSYuri Pankov #define	QNICHOST_TAIL	".whois-servers.net"
59*1dd3983cSYuri Pankov #define	BNICHOST	"whois.registro.br"
60*1dd3983cSYuri Pankov #define	NORIDHOST	"whois.norid.no"
61*1dd3983cSYuri Pankov #define	IANAHOST	"whois.iana.org"
62*1dd3983cSYuri Pankov #define	GERMNICHOST	"de.whois-servers.net"
63*1dd3983cSYuri Pankov #define	FNICHOST	"whois.afrinic.net"
64*1dd3983cSYuri Pankov #define	DEFAULT_PORT	"whois"
65*1dd3983cSYuri Pankov #define	WHOIS_SERVER_ID	"Whois Server: "
66*1dd3983cSYuri Pankov #define	WHOIS_ORG_SERVER_ID	"Registrant Street1:Whois Server:"
67*1dd3983cSYuri Pankov 
68*1dd3983cSYuri Pankov #define	WHOIS_RECURSE		0x01
69*1dd3983cSYuri Pankov #define	WHOIS_QUICK		0x02
70*1dd3983cSYuri Pankov 
71*1dd3983cSYuri Pankov #define	ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
72*1dd3983cSYuri Pankov 
73*1dd3983cSYuri Pankov const char *ip_whois[] = { LNICHOST, RNICHOST, PNICHOST, BNICHOST,
74*1dd3983cSYuri Pankov     FNICHOST, NULL };
75*1dd3983cSYuri Pankov const char *port = DEFAULT_PORT;
76*1dd3983cSYuri Pankov 
77*1dd3983cSYuri Pankov static char *choose_server(char *);
78*1dd3983cSYuri Pankov static struct addrinfo *gethostinfo(char const *host, int exit_on_error);
79*1dd3983cSYuri Pankov static void s_asprintf(char **ret, const char *format, ...);
80*1dd3983cSYuri Pankov static void usage(void);
81*1dd3983cSYuri Pankov static void whois(const char *, const char *, int);
82*1dd3983cSYuri Pankov static char *getln(FILE *in, size_t *lenp);
837c478bd9Sstevel@tonic-gate 
84740638c8Sbw int
85f098c48bSDerek Morr main(int argc, char *argv[])
867c478bd9Sstevel@tonic-gate {
87*1dd3983cSYuri Pankov 	const char *country, *host;
88*1dd3983cSYuri Pankov 	char *qnichost;
89*1dd3983cSYuri Pankov 	int ch, flags, use_qnichost;
907c478bd9Sstevel@tonic-gate 
91*1dd3983cSYuri Pankov 	country = host = qnichost = NULL;
92*1dd3983cSYuri Pankov 	flags = use_qnichost = 0;
93*1dd3983cSYuri Pankov 	while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:Qr")) != -1) {
94*1dd3983cSYuri Pankov 		switch (ch) {
95*1dd3983cSYuri Pankov 		case 'a':
96*1dd3983cSYuri Pankov 			host = ANICHOST;
97f098c48bSDerek Morr 			break;
98*1dd3983cSYuri Pankov 		case 'A':
99*1dd3983cSYuri Pankov 			host = PNICHOST;
100*1dd3983cSYuri Pankov 			break;
101*1dd3983cSYuri Pankov 		case 'b':
102*1dd3983cSYuri Pankov 			host = ABUSEHOST;
103*1dd3983cSYuri Pankov 			break;
104*1dd3983cSYuri Pankov 		case 'c':
105*1dd3983cSYuri Pankov 			country = optarg;
106*1dd3983cSYuri Pankov 			break;
107*1dd3983cSYuri Pankov 		case 'f':
108*1dd3983cSYuri Pankov 			host = FNICHOST;
109*1dd3983cSYuri Pankov 			break;
110*1dd3983cSYuri Pankov 		case 'g':
111*1dd3983cSYuri Pankov 			host = GNICHOST;
112*1dd3983cSYuri Pankov 			break;
113*1dd3983cSYuri Pankov 		case 'h':
114*1dd3983cSYuri Pankov 			host = optarg;
115*1dd3983cSYuri Pankov 			break;
116*1dd3983cSYuri Pankov 		case 'i':
117*1dd3983cSYuri Pankov 			host = INICHOST;
118*1dd3983cSYuri Pankov 			break;
119*1dd3983cSYuri Pankov 		case 'I':
120*1dd3983cSYuri Pankov 			host = IANAHOST;
121*1dd3983cSYuri Pankov 			break;
122*1dd3983cSYuri Pankov 		case 'k':
123*1dd3983cSYuri Pankov 			host = KNICHOST;
124*1dd3983cSYuri Pankov 			break;
125*1dd3983cSYuri Pankov 		case 'l':
126*1dd3983cSYuri Pankov 			host = LNICHOST;
127*1dd3983cSYuri Pankov 			break;
128*1dd3983cSYuri Pankov 		case 'm':
129*1dd3983cSYuri Pankov 			host = MNICHOST;
130*1dd3983cSYuri Pankov 			break;
131*1dd3983cSYuri Pankov 		case 'p':
132*1dd3983cSYuri Pankov 			port = optarg;
133*1dd3983cSYuri Pankov 			break;
134*1dd3983cSYuri Pankov 		case 'Q':
135*1dd3983cSYuri Pankov 			flags |= WHOIS_QUICK;
136*1dd3983cSYuri Pankov 			break;
137*1dd3983cSYuri Pankov 		case 'r':
138*1dd3983cSYuri Pankov 			host = RNICHOST;
139*1dd3983cSYuri Pankov 			break;
140*1dd3983cSYuri Pankov 		case '?':
141*1dd3983cSYuri Pankov 		default:
142*1dd3983cSYuri Pankov 			usage();
143*1dd3983cSYuri Pankov 			/* NOTREACHED */
144f098c48bSDerek Morr 		}
145f098c48bSDerek Morr 	}
146*1dd3983cSYuri Pankov 	argc -= optind;
147*1dd3983cSYuri Pankov 	argv += optind;
148f098c48bSDerek Morr 
149*1dd3983cSYuri Pankov 	if (!argc || (country != NULL && host != NULL))
150*1dd3983cSYuri Pankov 		usage();
151*1dd3983cSYuri Pankov 
152*1dd3983cSYuri Pankov 	/*
153*1dd3983cSYuri Pankov 	 * If no host or country is specified determine the top level domain
154*1dd3983cSYuri Pankov 	 * from the query.  If the TLD is a number, query ARIN.  Otherwise, use
155*1dd3983cSYuri Pankov 	 * TLD.whois-server.net.  If the domain does not contain '.', fall
156*1dd3983cSYuri Pankov 	 * back to NICHOST.
157*1dd3983cSYuri Pankov 	 */
158*1dd3983cSYuri Pankov 	if (host == NULL && country == NULL) {
159*1dd3983cSYuri Pankov 		use_qnichost = 1;
160*1dd3983cSYuri Pankov 		host = NICHOST;
161*1dd3983cSYuri Pankov 		if (!(flags & WHOIS_QUICK))
162*1dd3983cSYuri Pankov 			flags |= WHOIS_RECURSE;
1637c478bd9Sstevel@tonic-gate 	}
164*1dd3983cSYuri Pankov 	while (argc-- > 0) {
165*1dd3983cSYuri Pankov 		if (country != NULL) {
166*1dd3983cSYuri Pankov 			s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
167*1dd3983cSYuri Pankov 			whois(*argv, qnichost, flags);
168*1dd3983cSYuri Pankov 		} else if (use_qnichost)
169*1dd3983cSYuri Pankov 			if ((qnichost = choose_server(*argv)) != NULL)
170*1dd3983cSYuri Pankov 				whois(*argv, qnichost, flags);
171*1dd3983cSYuri Pankov 		if (qnichost == NULL)
172*1dd3983cSYuri Pankov 			whois(*argv, host, flags);
173*1dd3983cSYuri Pankov 		free(qnichost);
174*1dd3983cSYuri Pankov 		qnichost = NULL;
175*1dd3983cSYuri Pankov 		argv++;
176*1dd3983cSYuri Pankov 	}
177*1dd3983cSYuri Pankov 
178*1dd3983cSYuri Pankov 	return (0);
179*1dd3983cSYuri Pankov }
180*1dd3983cSYuri Pankov 
181*1dd3983cSYuri Pankov /*
182*1dd3983cSYuri Pankov  * This function will remove any trailing periods from domain, after which it
183*1dd3983cSYuri Pankov  * returns a pointer to newly allocated memory containing the whois server to
184*1dd3983cSYuri Pankov  * be queried, or a NULL if the correct server couldn't be determined.  The
185*1dd3983cSYuri Pankov  * caller must remember to free(3) the allocated memory.
186*1dd3983cSYuri Pankov  */
187*1dd3983cSYuri Pankov static char *
188*1dd3983cSYuri Pankov choose_server(char *domain)
189*1dd3983cSYuri Pankov {
190*1dd3983cSYuri Pankov 	char *pos, *retval;
191*1dd3983cSYuri Pankov 
192*1dd3983cSYuri Pankov 	if (strchr(domain, ':')) {
193*1dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", ANICHOST);
194*1dd3983cSYuri Pankov 		return (retval);
195*1dd3983cSYuri Pankov 	}
196*1dd3983cSYuri Pankov 	for (pos = strchr(domain, '\0'); pos > domain && *--pos == '.'; )
197*1dd3983cSYuri Pankov 		*pos = '\0';
198*1dd3983cSYuri Pankov 	if (*domain == '\0')
199*1dd3983cSYuri Pankov 		errx(EX_USAGE, "can't search for a null string");
200*1dd3983cSYuri Pankov 	if (strlen(domain) > sizeof ("-NORID")-1 &&
201*1dd3983cSYuri Pankov 	    strcasecmp(domain + strlen(domain) - sizeof ("-NORID") + 1,
202*1dd3983cSYuri Pankov 	    "-NORID") == 0) {
203*1dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", NORIDHOST);
204*1dd3983cSYuri Pankov 		return (retval);
205*1dd3983cSYuri Pankov 	}
206*1dd3983cSYuri Pankov 	while (pos > domain && *pos != '.')
207*1dd3983cSYuri Pankov 		--pos;
208*1dd3983cSYuri Pankov 	if (pos <= domain)
209*1dd3983cSYuri Pankov 		return (NULL);
210*1dd3983cSYuri Pankov 	if (isdigit((unsigned char)*++pos))
211*1dd3983cSYuri Pankov 		s_asprintf(&retval, "%s", ANICHOST);
212*1dd3983cSYuri Pankov 	else
213*1dd3983cSYuri Pankov 		s_asprintf(&retval, "%s%s", pos, QNICHOST_TAIL);
214*1dd3983cSYuri Pankov 	return (retval);
215*1dd3983cSYuri Pankov }
216*1dd3983cSYuri Pankov 
217*1dd3983cSYuri Pankov static struct addrinfo *
218*1dd3983cSYuri Pankov gethostinfo(char const *host, int exit_on_error)
219*1dd3983cSYuri Pankov {
220*1dd3983cSYuri Pankov 	struct addrinfo hints, *res;
221*1dd3983cSYuri Pankov 	int error;
222*1dd3983cSYuri Pankov 
223*1dd3983cSYuri Pankov 	(void) memset(&hints, 0, sizeof (hints));
224*1dd3983cSYuri Pankov 	hints.ai_flags = 0;
225*1dd3983cSYuri Pankov 	hints.ai_family = AF_UNSPEC;
226*1dd3983cSYuri Pankov 	hints.ai_socktype = SOCK_STREAM;
227*1dd3983cSYuri Pankov 	error = getaddrinfo(host, port, &hints, &res);
228*1dd3983cSYuri Pankov 	if (error) {
229*1dd3983cSYuri Pankov 		warnx("%s: %s", host, gai_strerror(error));
230*1dd3983cSYuri Pankov 		if (exit_on_error)
231*1dd3983cSYuri Pankov 			exit(EX_NOHOST);
232*1dd3983cSYuri Pankov 		return (NULL);
233*1dd3983cSYuri Pankov 	}
234*1dd3983cSYuri Pankov 	return (res);
235*1dd3983cSYuri Pankov }
236*1dd3983cSYuri Pankov 
237*1dd3983cSYuri Pankov /*
238*1dd3983cSYuri Pankov  * Wrapper for asprintf(3) that exits on error.
239*1dd3983cSYuri Pankov  */
240*1dd3983cSYuri Pankov /* PRINTFLIKE2 */
241*1dd3983cSYuri Pankov static void
242*1dd3983cSYuri Pankov s_asprintf(char **ret, const char *format, ...)
243*1dd3983cSYuri Pankov {
244*1dd3983cSYuri Pankov 	va_list ap;
245*1dd3983cSYuri Pankov 
246*1dd3983cSYuri Pankov 	va_start(ap, format);
247*1dd3983cSYuri Pankov 	if (vasprintf(ret, format, ap) == -1) {
248*1dd3983cSYuri Pankov 		va_end(ap);
249*1dd3983cSYuri Pankov 		err(EX_OSERR, "vasprintf()");
250*1dd3983cSYuri Pankov 	}
251*1dd3983cSYuri Pankov 	va_end(ap);
252*1dd3983cSYuri Pankov }
253*1dd3983cSYuri Pankov 
254*1dd3983cSYuri Pankov static void
255*1dd3983cSYuri Pankov whois(const char *query, const char *hostname, int flags)
256*1dd3983cSYuri Pankov {
257*1dd3983cSYuri Pankov 	FILE *sfi, *sfo;
258*1dd3983cSYuri Pankov 	struct addrinfo *hostres, *res;
259*1dd3983cSYuri Pankov 	char *buf, *host, *nhost, *p;
260*1dd3983cSYuri Pankov 	int i, s;
261*1dd3983cSYuri Pankov 	size_t c, len;
262*1dd3983cSYuri Pankov 
263*1dd3983cSYuri Pankov 	s = -1;
264*1dd3983cSYuri Pankov 	hostres = gethostinfo(hostname, 1);
265*1dd3983cSYuri Pankov 	for (res = hostres; res; res = res->ai_next) {
266*1dd3983cSYuri Pankov 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
267*1dd3983cSYuri Pankov 		if (s < 0)
268*1dd3983cSYuri Pankov 			continue;
269*1dd3983cSYuri Pankov 		if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
270*1dd3983cSYuri Pankov 			break;
271*1dd3983cSYuri Pankov 		(void) close(s);
272*1dd3983cSYuri Pankov 	}
273*1dd3983cSYuri Pankov 	freeaddrinfo(hostres);
274*1dd3983cSYuri Pankov 	if (res == NULL)
275*1dd3983cSYuri Pankov 		err(EX_OSERR, "connect()");
276f098c48bSDerek Morr 
2777c478bd9Sstevel@tonic-gate 	sfi = fdopen(s, "r");
2787c478bd9Sstevel@tonic-gate 	sfo = fdopen(s, "w");
279*1dd3983cSYuri Pankov 	if (sfi == NULL || sfo == NULL)
280*1dd3983cSYuri Pankov 		err(EX_OSERR, "fdopen()");
281*1dd3983cSYuri Pankov 	if (strcmp(hostname, GERMNICHOST) == 0) {
282*1dd3983cSYuri Pankov 		(void) fprintf(sfo, "-T dn,ace -C US-ASCII %s\r\n", query);
283*1dd3983cSYuri Pankov 	} else if (strcmp(hostname, "dk" QNICHOST_TAIL) == 0) {
284*1dd3983cSYuri Pankov 		(void) fprintf(sfo, "--show-handles %s\r\n", query);
285*1dd3983cSYuri Pankov 	} else {
286*1dd3983cSYuri Pankov 		(void) fprintf(sfo, "%s\r\n", query);
2877c478bd9Sstevel@tonic-gate 	}
28843f842b8SMilan Jurik 	(void) fflush(sfo);
289*1dd3983cSYuri Pankov 	nhost = NULL;
290*1dd3983cSYuri Pankov 	while ((buf = getln(sfi, &len)) != NULL) {
291*1dd3983cSYuri Pankov 		while (len > 0 && isspace((unsigned char)buf[len - 1]))
292*1dd3983cSYuri Pankov 			buf[--len] = '\0';
293*1dd3983cSYuri Pankov 		(void) printf("%.*s\n", (int)len, buf);
294*1dd3983cSYuri Pankov 
295*1dd3983cSYuri Pankov 		if ((flags & WHOIS_RECURSE) && nhost == NULL) {
296*1dd3983cSYuri Pankov 			host = strnstr(buf, WHOIS_SERVER_ID, len);
297*1dd3983cSYuri Pankov 			if (host != NULL) {
298*1dd3983cSYuri Pankov 				host += sizeof (WHOIS_SERVER_ID) - 1;
299*1dd3983cSYuri Pankov 				for (p = host; p < buf + len; p++) {
300*1dd3983cSYuri Pankov 					if (!ishost(*p)) {
301*1dd3983cSYuri Pankov 						*p = '\0';
302*1dd3983cSYuri Pankov 						break;
303*1dd3983cSYuri Pankov 					}
304*1dd3983cSYuri Pankov 				}
305*1dd3983cSYuri Pankov 				s_asprintf(&nhost, "%.*s",
306*1dd3983cSYuri Pankov 				    (int)(buf + len - host), host);
307*1dd3983cSYuri Pankov 			} else if ((host =
308*1dd3983cSYuri Pankov 			    strnstr(buf, WHOIS_ORG_SERVER_ID, len)) != NULL) {
309*1dd3983cSYuri Pankov 				host += sizeof (WHOIS_ORG_SERVER_ID) - 1;
310*1dd3983cSYuri Pankov 				for (p = host; p < buf + len; p++) {
311*1dd3983cSYuri Pankov 					if (!ishost(*p)) {
312*1dd3983cSYuri Pankov 						*p = '\0';
313*1dd3983cSYuri Pankov 						break;
314*1dd3983cSYuri Pankov 					}
315*1dd3983cSYuri Pankov 				}
316*1dd3983cSYuri Pankov 				s_asprintf(&nhost, "%.*s",
317*1dd3983cSYuri Pankov 				    (int)(buf + len - host), host);
318*1dd3983cSYuri Pankov 			} else if (strcmp(hostname, ANICHOST) == 0) {
319*1dd3983cSYuri Pankov 				for (c = 0; c <= len; c++)
320*1dd3983cSYuri Pankov 					buf[c] = tolower((unsigned char)buf[c]);
321*1dd3983cSYuri Pankov 				for (i = 0; ip_whois[i] != NULL; i++) {
322*1dd3983cSYuri Pankov 					if (strnstr(buf, ip_whois[i], len) !=
323*1dd3983cSYuri Pankov 					    NULL) {
324*1dd3983cSYuri Pankov 						s_asprintf(&nhost, "%s",
325*1dd3983cSYuri Pankov 						    ip_whois[i]);
326*1dd3983cSYuri Pankov 						break;
327*1dd3983cSYuri Pankov 					}
328*1dd3983cSYuri Pankov 				}
329*1dd3983cSYuri Pankov 			}
330*1dd3983cSYuri Pankov 		}
331*1dd3983cSYuri Pankov 	}
332*1dd3983cSYuri Pankov 	if (nhost != NULL) {
333*1dd3983cSYuri Pankov 		whois(query, nhost, 0);
334*1dd3983cSYuri Pankov 		free(nhost);
335*1dd3983cSYuri Pankov 	}
336*1dd3983cSYuri Pankov }
337*1dd3983cSYuri Pankov 
338*1dd3983cSYuri Pankov static void
339*1dd3983cSYuri Pankov usage(void)
340*1dd3983cSYuri Pankov {
341*1dd3983cSYuri Pankov 	(void) fprintf(stderr,
342*1dd3983cSYuri Pankov 	    "usage: whois [-aAbfgiIklmQr] [-c country-code | -h hostname] "
343*1dd3983cSYuri Pankov 	    "[-p port] name ...\n");
344*1dd3983cSYuri Pankov 	exit(EX_USAGE);
345*1dd3983cSYuri Pankov }
346*1dd3983cSYuri Pankov 
347*1dd3983cSYuri Pankov static char *
348*1dd3983cSYuri Pankov getln(FILE *in, size_t *lenp)
349*1dd3983cSYuri Pankov {
350*1dd3983cSYuri Pankov 	static char	*buffer = NULL;
351*1dd3983cSYuri Pankov 	static size_t	sz = 0;
352*1dd3983cSYuri Pankov 
353*1dd3983cSYuri Pankov 	size_t		len = 0;
354*1dd3983cSYuri Pankov 
355*1dd3983cSYuri Pankov 	for (;;) {
356*1dd3983cSYuri Pankov 		if (sz <= (len + 1)) {
357*1dd3983cSYuri Pankov 			char *nb;
358*1dd3983cSYuri Pankov 			if ((nb = realloc(buffer, sz + LINE_MAX)) == NULL) {
359*1dd3983cSYuri Pankov 				err(1, "realloc");
360*1dd3983cSYuri Pankov 			}
361*1dd3983cSYuri Pankov 			buffer = nb;
362*1dd3983cSYuri Pankov 			sz += LINE_MAX;
363*1dd3983cSYuri Pankov 		}
364*1dd3983cSYuri Pankov 
365*1dd3983cSYuri Pankov 		buffer[len] = 0;
366*1dd3983cSYuri Pankov 
367*1dd3983cSYuri Pankov 		if (fgets(buffer + len, sz - len, in) == NULL) {
368*1dd3983cSYuri Pankov 			/* END OF FILE */
369*1dd3983cSYuri Pankov 			*lenp = len;
370*1dd3983cSYuri Pankov 			if (len == 0)
371*1dd3983cSYuri Pankov 				return (NULL);
372*1dd3983cSYuri Pankov 			break;
373*1dd3983cSYuri Pankov 		}
374*1dd3983cSYuri Pankov 
375*1dd3983cSYuri Pankov 		len += strlen(buffer + len);
376*1dd3983cSYuri Pankov 
377*1dd3983cSYuri Pankov 		if (buffer[len - 1] == '\n') {
378*1dd3983cSYuri Pankov 			/* got the new line */
379*1dd3983cSYuri Pankov 			*lenp = len;
380*1dd3983cSYuri Pankov 			break;
381*1dd3983cSYuri Pankov 		}
382*1dd3983cSYuri Pankov 	}
383*1dd3983cSYuri Pankov 
384*1dd3983cSYuri Pankov 	return (buffer);
3857c478bd9Sstevel@tonic-gate }
386