Index: head/usr.bin/finger/finger.1 =================================================================== --- head/usr.bin/finger/finger.1 (revision 100520) +++ head/usr.bin/finger/finger.1 (revision 100521) @@ -1,247 +1,255 @@ .\" Copyright (c) 1989, 1990, 1993, 1994 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)finger.1 8.3 (Berkeley) 5/5/94 .\" $FreeBSD$ .\" .Dd August 1, 1997 .Dt FINGER 1 .Os .Sh NAME .Nm finger .Nd user information lookup program .Sh SYNOPSIS .Nm -.Op Fl glmpshoT +.Op Fl 46glmpshoT .Op Ar user ...\& .Op Ar user@host ...\& .Sh DESCRIPTION The .Nm utility displays information about the system users. .Pp Options are: .Bl -tag -width flag +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. .It Fl s Display the user's login name, real name, terminal name and write status (as a ``*'' before the terminal name if write permission is denied), idle time, login time, and either office location and office phone number, or the remote host. If .Fl o is given, the office location and office phone number is printed (the default). If .Fl h is given, the remote host is printed instead. .Pp Idle time is in minutes if it is a single integer, hours and minutes if a ``:'' is present, or days if a ``d'' is present. If it is an .Dq * , the login time indicates the time of last login. Login time is displayed as the day name if less than 6 days, else month, day; hours and minutes, unless more than six months ago, in which case the year is displayed rather than the hours and minutes. .Pp Unknown devices as well as nonexistent idle and login times are displayed as single asterisks. .Pp .It Fl h When used in conjunction with the .Fl s option, the name of the remote host is displayed instead of the office location and office phone. .Pp .It Fl o When used in conjunction with the .Fl s option, the office location and office phone information is displayed instead of the name of the remote host. .Pp .It Fl g This option restricts the gecos output to only the users' real name. It also has the side-effect of restricting the output of the remote host when used in conjunction with the .Fl h option. .Pp .It Fl l Produce a multi-line format displaying all of the information described for the .Fl s option as well as the user's home directory, home phone number, login shell, mail status, and the contents of the files .Dq Pa .forward , .Dq Pa .plan , .Dq Pa .project and .Dq Pa .pubkey from the user's home directory. .Pp If idle time is at least a minute and less than a day, it is presented in the form ``hh:mm''. Idle times greater than a day are presented as ``d day[s]hh:mm''. .Pp Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''. Numbers specified as ten or seven digits are printed as the appropriate subset of that string. Numbers specified as five digits are printed as ``xN-NNNN''. Numbers specified as four digits are printed as ``xNNNN''. .Pp If write permission is denied to the device, the phrase ``(messages off)'' is appended to the line containing the device name. One entry per user is displayed with the .Fl l option; if a user is logged on multiple times, terminal information is repeated once per login. .Pp Mail status is shown as ``No Mail.'' if there is no mail at all, ``Mail last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their mailbox since new mail arriving, or ``New mail received ...'', ``Unread since ...'' if they have new mail. .Pp .It Fl p Prevent the .Fl l option of .Nm from displaying the contents of the .Dq Pa .forward , .Dq Pa .plan , .Dq Pa .project and .Dq Pa .pubkey files. .It Fl m Prevent matching of .Ar user names. .Ar User is usually a login name; however, matching will also be done on the users' real names, unless the .Fl m option is supplied. All name matching performed by .Nm is case insensitive. .Pp .It Fl T Disable the piggybacking of data on the initial connection request. This option is needed to finger hosts with a broken TCP implementation. .El .Pp If no options are specified, .Nm defaults to the .Fl l style output if operands are provided, otherwise to the .Fl s style. Note that some fields may be missing, in either format, if information is not available for them. .Pp If no arguments are specified, .Nm will print an entry for each user currently logged into the system. .Pp The .Nm utility may be used to look up users on a remote machine. The format is to specify a .Ar user as .Dq Li user@host , or .Dq Li @host , where the default output format for the former is the .Fl l style, and the default output format for the latter is the .Fl s style. The .Fl l option is the only option that may be passed to a remote machine. .Pp If the file .Dq Pa .nofinger exists in the user's home directory, .Nm behaves as if the user in question does not exist. .Pp The optional .Xr finger.conf 5 configuration file can be used to specify aliases. Since .Xr finger 1 is invoked by .Xr fingerd 8 , aliases will work for both local and network queries. .Sh ENVIRONMENT The .Nm utility utilizes the following environment variable, if it exists: .Bl -tag -width Fl .It Ev FINGER This variable may be set with favored options to .Nm . .El .Sh FILES .Bl -tag -width /var/log/lastlog -compact .It Pa /etc/finger.conf alias definition data base .It Pa /var/log/lastlog last login data base .El .Sh SEE ALSO .Xr chpass 1 , .Xr w 1 , .Xr who 1 , .Xr finger.conf 5 , .Xr fingerd 8 .Rs .%A D. Zimmerman .%T The Finger User Information Protocol .%R RFC 1288 .%D December, 1991 .Re .Sh HISTORY The .Nm command appeared in .Bx 3.0 . .Sh BUGS The current FINGER protocol RFC requires that the client keep the connection fully open until the server closes. This prevents the use of the optimal three-packet T/TCP exchange. (Servers which depend on this requirement are bogus but have nonetheless been observed in the Internet at large.) Index: head/usr.bin/finger/finger.c =================================================================== --- head/usr.bin/finger/finger.c (revision 100520) +++ head/usr.bin/finger/finger.c (revision 100521) @@ -1,395 +1,404 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Luke Mewburn added the following on 940622: * - mail status ("No Mail", "Mail read:...", or "New Mail ..., * Unread since ...".) * - 4 digit phone extensions (3210 is printed as x3210.) * - host/office toggling in short format with -h & -o. * - short day names (`Tue' printed instead of `Jun 21' if the * login time is < 6 days. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95"; #endif #endif #include __FBSDID("$FreeBSD$"); /* * Finger prints out information about users. It is not portable since * certain fields (e.g. the full user name, office, and phone numbers) are * extracted from the gecos field of the passwd file which other UNIXes * may not have or may use for other things. * * There are currently two output formats; the short format is one line * per user and displays login name, tty, login time, real name, idle time, * and either remote host information (default) or office location/phone * number, depending on if -h or -o is used respectively. * The long format gives the same information (in a more legible format) as * well as home directory, shell, mail info, and .plan/.project files. */ +#include +#include #include #include #include #include #include #include #include #include #include #include #include "finger.h" #include "pathnames.h" DB *db; time_t now; int entries, gflag, lflag, mflag, pplan, sflag, oflag, Tflag; +sa_family_t family = PF_UNSPEC; int d_first = -1; char tbuf[1024]; static void loginlist(void); static int option(int, char **); static void usage(void); static void userlist(int, char **); static int option(argc, argv) int argc; char **argv; { int ch; optind = 1; /* reset getopt */ - while ((ch = getopt(argc, argv, "glmpshoT")) != -1) + while ((ch = getopt(argc, argv, "46glmpshoT")) != -1) switch(ch) { + case '4': + family = AF_INET; + break; + case '6': + family = AF_INET6; + break; case 'g': gflag = 1; break; case 'l': lflag = 1; /* long format */ break; case 'm': mflag = 1; /* force exact match of names */ break; case 'p': pplan = 1; /* don't show .plan/.project */ break; case 's': sflag = 1; /* short format */ break; case 'h': oflag = 0; /* remote host info */ break; case 'o': oflag = 1; /* office info */ break; case 'T': Tflag = 1; /* disable T/TCP */ break; case '?': default: usage(); } return optind; } static void usage() { - (void)fprintf(stderr, "usage: finger [-lmpshoT] [login ...]\n"); + (void)fprintf(stderr, "usage: finger [-46lmpshoT] [login ...]\n"); exit(1); } int main(argc, argv) int argc; char **argv; { int envargc, argcnt; char *envargv[3]; struct passwd *pw; static char myname[] = "finger"; if (getuid() == 0 || geteuid() == 0) { if ((pw = getpwnam(UNPRIV_NAME)) && pw->pw_uid > 0) { setgid(pw->pw_gid); setuid(pw->pw_uid); } else { setgid(UNPRIV_UGID); setuid(UNPRIV_UGID); } } (void) setlocale(LC_ALL, ""); /* remove this line to get remote host */ oflag = 1; /* default to old "office" behavior */ /* * Process environment variables followed by command line arguments. */ if ((envargv[1] = getenv("FINGER"))) { envargc = 2; envargv[0] = myname; envargv[2] = NULL; (void) option(envargc, envargv); } argcnt = option(argc, argv); argc -= argcnt; argv += argcnt; (void)time(&now); setpassent(1); if (!*argv) { /* * Assign explicit "small" format if no names given and -l * not selected. Force the -s BEFORE we get names so proper * screening will be done. */ if (!lflag) sflag = 1; /* if -l not explicit, force -s */ loginlist(); if (entries == 0) (void)printf("No one logged on.\n"); } else { userlist(argc, argv); /* * Assign explicit "large" format if names given and -s not * explicitly stated. Force the -l AFTER we get names so any * remote finger attempts specified won't be mishandled. */ if (!sflag) lflag = 1; /* if -s not explicit, force -l */ } if (entries) { if (lflag) lflag_print(); else sflag_print(); } return (0); } static void loginlist() { PERSON *pn; DBT data, key; struct passwd *pw; struct utmp user; int r, sflag1; char name[UT_NAMESIZE + 1]; if (!freopen(_PATH_UTMP, "r", stdin)) err(1, "%s", _PATH_UTMP); name[UT_NAMESIZE] = '\0'; while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { if (!user.ut_name[0]) continue; if ((pn = find_person(user.ut_name)) == NULL) { bcopy(user.ut_name, name, UT_NAMESIZE); if ((pw = getpwnam(name)) == NULL) continue; if (hide(pw)) continue; pn = enter_person(pw); } enter_where(&user, pn); } if (db && lflag) for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { PERSON *tmp; r = (*db->seq)(db, &key, &data, sflag1); if (r == -1) err(1, "db seq"); if (r == 1) break; memmove(&tmp, data.data, sizeof tmp); enter_lastlog(tmp); } } static void userlist(argc, argv) int argc; char **argv; { PERSON *pn; DBT data, key; struct utmp user; struct passwd *pw; int r, sflag1, *used, *ip; char **ap, **nargv, **np, **p; FILE *conf_fp; char conf_alias[LINE_MAX]; char *conf_realname; int conf_length; if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || (used = calloc(argc, sizeof(int))) == NULL) err(1, NULL); /* Pull out all network requests. */ for (ap = p = argv, np = nargv; *p; ++p) if (index(*p, '@')) *np++ = *p; else *ap++ = *p; *np++ = NULL; *ap++ = NULL; if (!*argv) goto net; /* * Mark any arguments beginning with '/' as invalid so that we * don't accidently confuse them with expansions from finger.conf */ for (p = argv, ip = used; *p; ++p, ++ip) if (**p == '/') { *ip = 1; warnx("%s: no such user", *p); } /* * Traverse the finger alias configuration file of the form * alias:(user|alias), ignoring comment lines beginning '#'. */ if ((conf_fp = fopen(_PATH_FINGERCONF, "r")) != NULL) { while(fgets(conf_alias, sizeof(conf_alias), conf_fp) != NULL) { conf_length = strlen(conf_alias); if (*conf_alias == '#' || conf_alias[--conf_length] != '\n') continue; conf_alias[conf_length] = '\0'; /* Remove trailing LF */ if ((conf_realname = strchr(conf_alias, ':')) == NULL) continue; *conf_realname = '\0'; /* Replace : with NUL */ for (p = argv; *p; ++p) { if (strcmp(*p, conf_alias) == NULL) { if ((*p = strdup(conf_realname+1)) == NULL) { err(1, NULL); } } } } (void)fclose(conf_fp); } /* * Traverse the list of possible login names and check the login name * and real name against the name specified by the user. If the name * begins with a '/', try to read the file of that name instead of * gathering the traditional finger information. */ if (mflag) for (p = argv, ip = used; *p; ++p, ++ip) { if (**p != '/' || *ip == 1 || !show_text("", *p, "")) { if (((pw = getpwnam(*p)) != NULL) && !hide(pw)) enter_person(pw); else if (!*ip) warnx("%s: no such user", *p); } } else { while ((pw = getpwent()) != NULL) { for (p = argv, ip = used; *p; ++p, ++ip) if (**p == '/' && *ip != 1 && show_text("", *p, "")) *ip = 1; else if (match(pw, *p) && !hide(pw)) { enter_person(pw); *ip = 1; } } for (p = argv, ip = used; *p; ++p, ++ip) if (!*ip) warnx("%s: no such user", *p); } /* Handle network requests. */ net: for (p = nargv; *p;) { netfinger(*p++); if (*p || entries) printf("\n"); } if (entries == 0) return; /* * Scan thru the list of users currently logged in, saving * appropriate data whenever a match occurs. */ if (!freopen(_PATH_UTMP, "r", stdin)) err(1, "%s", _PATH_UTMP); while (fread((char *)&user, sizeof(user), 1, stdin) == 1) { if (!user.ut_name[0]) continue; if ((pn = find_person(user.ut_name)) == NULL) continue; enter_where(&user, pn); } if (db) for (sflag1 = R_FIRST;; sflag1 = R_NEXT) { PERSON *tmp; r = (*db->seq)(db, &key, &data, sflag1); if (r == -1) err(1, "db seq"); if (r == 1) break; memmove(&tmp, data.data, sizeof tmp); enter_lastlog(tmp); } } Index: head/usr.bin/finger/net.c =================================================================== --- head/usr.bin/finger/net.c (revision 100520) +++ head/usr.bin/finger/net.c (revision 100521) @@ -1,250 +1,251 @@ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95"; #endif #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "finger.h" extern int lflag; /* XXX finger.h? */ extern int Tflag; /* XXX finger.h? */ +extern sa_family_t family; static void cleanup(int sig);; static int do_protocol(const char *name, const struct addrinfo *ai); static void trying(const struct addrinfo *ai); void netfinger(name) char *name; { int error, multi; char *host; struct addrinfo *ai, *ai0; static struct addrinfo hint; host = strrchr(name, '@'); if (host == 0) return; *host++ = '\0'; signal(SIGALRM, cleanup); alarm(TIME_LIMIT); hint.ai_flags = AI_CANONNAME; - hint.ai_family = PF_UNSPEC; + hint.ai_family = family; hint.ai_socktype = SOCK_STREAM; error = getaddrinfo(host, "finger", &hint, &ai0); if (error) { warnx("%s: %s", host, gai_strerror(error)); return; } multi = (ai0->ai_next) != 0; /* ai_canonname may not be filled in if the user specified an IP. */ if (ai0->ai_canonname == 0) printf("[%s]\n", host); else printf("[%s]\n", ai0->ai_canonname); for (ai = ai0; ai != 0; ai = ai->ai_next) { if (multi) trying(ai); error = do_protocol(name, ai); if (!error) break; } alarm(0); freeaddrinfo(ai0); } static int do_protocol(const char *name, const struct addrinfo *ai) { int cnt, line_len, s; FILE *fp; int c, lastc; struct iovec iov[3]; struct msghdr msg; static char slash_w[] = "/W "; static char neteol[] = "\n\r"; s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (s < 0) { warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype, ai->ai_protocol); return -1; } msg.msg_name = (void *)ai->ai_addr; msg.msg_namelen = ai->ai_addrlen; msg.msg_iov = iov; msg.msg_iovlen = 0; msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; /* -l flag for remote fingerd */ if (lflag) { iov[msg.msg_iovlen].iov_base = slash_w; iov[msg.msg_iovlen++].iov_len = 3; } /* send the name followed by */ iov[msg.msg_iovlen].iov_base = strdup(name); iov[msg.msg_iovlen++].iov_len = strlen(name); iov[msg.msg_iovlen].iov_base = neteol; iov[msg.msg_iovlen++].iov_len = 2; /* * -T disables data-on-SYN: compatibility option to finger broken * hosts. Also, the implicit-open API is broken on IPv6, so do * the explicit connect there, too. */ if ((Tflag || ai->ai_addr->sa_family == AF_INET6) && connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { warn("connect"); close(s); return -1; } if (sendmsg(s, &msg, 0) < 0) { warn("sendmsg"); close(s); return -1; } /* * Read from the remote system; once we're connected, we assume some * data. If none arrives, we hang until the user interrupts. * * If we see a or a with the high bit set, treat it as * a newline; if followed by a newline character, only output one * newline. * * Otherwise, all high bits are stripped; if it isn't printable and * it isn't a space, we can simply set the 7th bit. Every ASCII * character with bit 7 set is printable. */ lastc = 0; if ((fp = fdopen(s, "r")) != NULL) { cnt = 0; line_len = 0; while ((c = getc(fp)) != EOF) { if (++cnt > OUTPUT_MAX) { printf("\n\n Output truncated at %d bytes...\n", cnt - 1); break; } if (c == 0x0d) { if (lastc == '\r') /* ^M^M - skip dupes */ continue; c = '\n'; lastc = '\r'; } else { if (!isprint(c) && !isspace(c)) { c &= 0x7f; c |= 0x40; } if (lastc != '\r' || c != '\n') lastc = c; else { lastc = '\n'; continue; } } putchar(c); if (c != '\n' && ++line_len > _POSIX2_LINE_MAX) { putchar('\\'); putchar('\n'); lastc = '\r'; } if (lastc == '\n' || lastc == '\r') line_len = 0; } if (ferror(fp)) { /* * Assume that whatever it was set errno... */ warn("reading from network"); } if (lastc != '\n') putchar('\n'); fclose(fp); } return 0; } static void trying(const struct addrinfo *ai) { char buf[NI_MAXHOST]; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf, (char *)0, 0, NI_NUMERICHOST) != 0) return; /* XXX can't happen */ printf("Trying %s...\n", buf); } void cleanup(int sig __unused) { #define ERRSTR "Timed out.\n" write(STDERR_FILENO, ERRSTR, sizeof ERRSTR); exit(1); }