1 /* $NetBSD: util.c,v 1.123 2005/05/14 18:56:45 dsl Exp $ */
4 * Copyright (c) 1997-2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
12 * NASA Ames Research Center.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the NetBSD
25 * Foundation, Inc. and its contributors.
26 * 4. Neither the name of The NetBSD Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
44 * Copyright (c) 1985, 1989, 1993, 1994
45 * The Regents of the University of California. All rights reserved.
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 #include <sys/cdefs.h>
75 * FTP User Program -- Misc support routines
77 #include <sys/param.h>
78 #include <sys/socket.h>
79 #include <sys/ioctl.h>
81 #include <netinet/in.h>
101 #define TM_YEAR_BASE 1900
104 * Connect to peer server and auto-login, if possible.
107 setpeer(int argc
, char *argv
[])
115 fprintf(ttyout
, "Already connected to %s, use close first.\n",
121 (void)another(&argc
, &argv
, "to");
122 if (argc
< 2 || argc
> 3) {
124 fprintf(ttyout
, "usage: %s host-name [port]\n", argv
[0]);
136 if (gateserver
== NULL
|| *gateserver
== '\0')
137 errx(1, "gateserver not defined (shouldn't happen)");
138 host
= hookup(gateserver
, port
);
140 host
= hookup(argv
[1], port
);
143 if (gatemode
&& verbose
) {
145 "Connecting via pass-through server %s\n",
151 * Set up defaults for FTP.
153 (void)strlcpy(typename
, "ascii", sizeof(typename
));
156 (void)strlcpy(formname
, "non-print", sizeof(formname
));
158 (void)strlcpy(modename
, "stream", sizeof(modename
));
160 (void)strlcpy(structname
, "file", sizeof(structname
));
162 (void)strlcpy(bytename
, "8", sizeof(bytename
));
165 (void)ftp_login(argv
[1], NULL
, NULL
);
170 parse_feat(const char *line
)
174 * work-around broken ProFTPd servers that can't
175 * even obey RFC 2389.
177 while (*line
&& isspace((int)*line
))
180 if (strcasecmp(line
, "MDTM") == 0)
181 features
[FEAT_MDTM
] = 1;
182 else if (strncasecmp(line
, "MLST", sizeof("MLST") - 1) == 0) {
183 features
[FEAT_MLST
] = 1;
184 } else if (strcasecmp(line
, "REST STREAM") == 0)
185 features
[FEAT_REST_STREAM
] = 1;
186 else if (strcasecmp(line
, "SIZE") == 0)
187 features
[FEAT_SIZE
] = 1;
188 else if (strcasecmp(line
, "TVFS") == 0)
189 features
[FEAT_TVFS
] = 1;
193 * Determine the remote system type (SYST) and features (FEAT).
194 * Call after a successful login (i.e, connected = -1)
205 /* determine remote system type */
206 if (command("SYST") == COMPLETE
) {
211 cp
= strchr(reply_string
+ 4, ' ');
213 cp
= strchr(reply_string
+ 4, '\r');
221 fprintf(ttyout
, "Remote system type is %s.\n",
226 if (!strncmp(reply_string
, "215 UNIX Type: L8", 17)) {
232 * Set type to 0 (not specified by user),
233 * meaning binary by default, but don't bother
234 * telling server. We can use binary
235 * for text files unless changed by the user.
238 (void)strlcpy(typename
, "binary", sizeof(typename
));
241 "Using %s mode to transfer files.\n",
249 !strncmp(reply_string
, "215 TOPS20", 10))
251 "Remember to set tenex mode when transferring binary files from this machine.\n",
256 /* determine features (if any) */
257 for (i
= 0; i
< FEAT_max
; i
++)
259 reply_callback
= parse_feat
;
260 if (command("FEAT") == COMPLETE
) {
261 for (i
= 0; i
< FEAT_max
; i
++) {
262 if (features
[i
] == -1)
265 features
[FEAT_FEAT
] = 1;
267 features
[FEAT_FEAT
] = 0;
269 #define DEBUG_FEAT(x) fprintf(ttyout, "features[" #x "] = %d\n", features[(x)])
270 DEBUG_FEAT(FEAT_FEAT
);
271 DEBUG_FEAT(FEAT_MDTM
);
272 DEBUG_FEAT(FEAT_MLST
);
273 DEBUG_FEAT(FEAT_REST_STREAM
);
274 DEBUG_FEAT(FEAT_SIZE
);
275 DEBUG_FEAT(FEAT_TVFS
);
278 reply_callback
= NULL
;
284 * Reset the various variables that indicate connection state back to
285 * disconnected settings.
286 * The caller is responsible for issuing any commands to the remote server
287 * to perform a clean shutdown before this is invoked.
300 * determine if anonftp was specifically set with -a
301 * (1), or implicitly set by auto_fetch() (2). in the
302 * latter case, disable after the current xfer
316 * Top-level signal handler for interrupted commands.
325 write(fileno(ttyout
), "\n", 1);
326 siglongjmp(toplevel
, 1);
330 * Signal handler for lost connections; cleanup various elements of
331 * the connection state, and call cleanuppeer() to finish it off.
341 (void)shutdown(fileno(cout
), 1+1);
346 (void)shutdown(data
, 1+1);
355 (void)shutdown(fileno(cout
), 1+1);
369 * Login to remote host, using given username & password if supplied.
370 * Return non-zero if successful.
373 ftp_login(const char *host
, const char *user
, const char *pass
)
377 int n
, aflag
, rval
, freeuser
, freepass
, freeacct
;
380 aflag
= rval
= freeuser
= freepass
= freeacct
= 0;
383 fprintf(ttyout
, "ftp_login: user `%s' pass `%s' host `%s'\n",
384 user
? user
: "<null>", pass
? pass
: "<null>",
385 host
? host
: "<null>");
389 * Set up arguments for an anonymous FTP session, if necessary.
392 user
= "anonymous"; /* as per RFC 1635 */
393 pass
= getoptionvalue("anonpass");
401 if (ruserpass(host
, &user
, &pass
, &acct
) < 0) {
403 goto cleanup_ftp_login
;
406 while (user
== NULL
) {
408 fprintf(ttyout
, "Name (%s:%s): ", host
, localname
);
410 fprintf(ttyout
, "Name (%s): ", host
);
412 if (fgets(tmp
, sizeof(tmp
) - 1, stdin
) == NULL
) {
413 fprintf(ttyout
, "\nEOF received; login aborted.\n");
416 goto cleanup_ftp_login
;
418 tmp
[strlen(tmp
) - 1] = '\0';
430 len
= strlen(user
) + 1 + strlen(host
) + 1;
431 nuser
= xmalloc(len
);
432 (void)strlcpy(nuser
, user
, len
);
433 (void)strlcat(nuser
, "@", len
);
434 (void)strlcat(nuser
, host
, len
);
439 n
= command("USER %s", user
);
443 pass
= getpass("Password:");
445 n
= command("PASS %s", pass
);
451 acct
= getpass("Account:");
453 if (acct
[0] == '\0') {
454 warnx("Login failed.");
455 goto cleanup_ftp_login
;
457 n
= command("ACCT %s", acct
);
459 if ((n
!= COMPLETE
) ||
460 (!aflag
&& acct
!= NULL
&& command("ACCT %s", acct
) != COMPLETE
)) {
461 warnx("Login failed.");
462 goto cleanup_ftp_login
;
465 username
= xstrdup(user
);
467 goto cleanup_ftp_login
;
471 for (n
= 0; n
< macnum
; ++n
) {
472 if (!strcmp("init", macros
[n
].mac_name
)) {
473 (void)strlcpy(line
, "$init", sizeof(line
));
475 domacro(margc
, margv
);
483 if (user
!= NULL
&& freeuser
)
485 if (pass
!= NULL
&& freepass
)
487 if (acct
!= NULL
&& freeacct
)
493 * `another' gets another argument, and stores the new argc and argv.
494 * It reverts to the top level (via intr()) on EOF/error.
496 * Returns false if no new arguments have been added.
499 another(int *pargc
, char ***pargv
, const char *prompt
)
501 int len
= strlen(line
), ret
;
503 if (len
>= sizeof(line
) - 3) {
504 fputs("sorry, arguments too long.\n", ttyout
);
507 fprintf(ttyout
, "(%s) ", prompt
);
509 if (fgets(&line
[len
], sizeof(line
) - len
, stdin
) == NULL
) {
513 len
+= strlen(&line
[len
]);
514 if (len
> 0 && line
[len
- 1] == '\n')
515 line
[len
- 1] = '\0';
517 ret
= margc
> *pargc
;
524 * glob files given in argv[] from the remote server.
525 * if errbuf isn't NULL, store error messages there instead
526 * of writing to the screen.
529 remglob(char *argv
[], int doswitch
, char **errbuf
)
531 char temp
[MAXPATHLEN
];
532 static char buf
[MAXPATHLEN
];
533 static FILE *ftemp
= NULL
;
535 int oldverbose
, oldhash
, oldprogress
, fd
, len
;
538 if (!mflag
|| !connected
) {
552 if ((cp
= *++args
) == NULL
)
557 len
= strlcpy(temp
, tmpdir
, sizeof(temp
));
558 if (temp
[len
- 1] != '/')
559 (void)strlcat(temp
, "/", sizeof(temp
));
560 (void)strlcat(temp
, TMPFILE
, sizeof(temp
));
561 if ((fd
= mkstemp(temp
)) < 0) {
562 warn("unable to create temporary file %s", temp
);
566 oldverbose
= verbose
;
567 verbose
= (errbuf
!= NULL
) ? -1 : 0;
569 oldprogress
= progress
;
574 for (mode
= "w"; *++argv
!= NULL
; mode
= "a")
575 recvrequest("NLST", temp
, *argv
, mode
, 0, 0);
576 if ((code
/ 100) != COMPLETE
) {
578 *errbuf
= reply_string
;
582 verbose
= oldverbose
;
584 progress
= oldprogress
;
585 ftemp
= fopen(temp
, "r");
590 "can't find list of remote files, oops.\n",
594 "can't find list of remote files, oops.";
598 if (fgets(buf
, sizeof(buf
), ftemp
) == NULL
) {
603 if ((cp
= strchr(buf
, '\n')) != NULL
)
609 * Glob a local file name specification with the expectation of a single
610 * return value. Can't control multiple values being expanded from the
611 * expression, we return only the first.
612 * Returns NULL on error, or a pointer to a buffer containing the filename
613 * that's the caller's responsiblity to free(3) when finished with.
616 globulize(const char *pattern
)
623 return (xstrdup(pattern
));
625 flags
= GLOB_BRACE
|GLOB_NOCHECK
|GLOB_TILDE
;
626 memset(&gl
, 0, sizeof(gl
));
627 if (glob(pattern
, flags
, NULL
, &gl
) || gl
.gl_pathc
== 0) {
628 warnx("%s: not found", pattern
);
632 p
= xstrdup(gl
.gl_pathv
[0]);
638 * determine size of remote file
641 remotesize(const char *file
, int noisy
)
650 if (! features
[FEAT_SIZE
]) {
653 "SIZE is not supported by remote server.\n");
654 goto cleanup_remotesize
;
656 r
= command("SIZE %s", file
);
660 cp
= strchr(reply_string
, ' ');
663 size
= STRTOLL(cp
, &ep
, 10);
664 if (*ep
!= '\0' && !isspace((unsigned char)*ep
))
668 if (r
== ERROR
&& code
== 500 && features
[FEAT_SIZE
] == -1)
669 features
[FEAT_SIZE
] = 0;
670 if (noisy
&& debug
== 0) {
671 fputs(reply_string
, ttyout
);
681 * determine last modification time (in GMT) of remote file
684 remotemodtime(const char *file
, int noisy
)
686 int overbose
, ocode
, r
;
694 if (! features
[FEAT_MDTM
]) {
697 "MDTM is not supported by remote server.\n");
698 goto cleanup_parse_time
;
700 r
= command("MDTM %s", file
);
703 char *timestr
, *frac
;
704 int yy
, mo
, day
, hour
, min
, sec
;
707 * time-val = 14DIGIT [ "." 1*DIGIT ]
708 * YYYYMMDDHHMMSS[.sss]
709 * mdtm-response = "213" SP time-val CRLF / error-response
711 timestr
= reply_string
+ 4;
715 * XXX: ignored for now
717 frac
= strchr(timestr
, '\r');
720 frac
= strchr(timestr
, '.');
723 if (strlen(timestr
) == 15 && strncmp(timestr
, "191", 3) == 0) {
725 * XXX: Workaround for lame ftpd's that return
726 * `19100' instead of `2000'
729 "Y2K warning! Incorrect time-val `%s' received from server.\n",
734 fprintf(ttyout
, "Converted to `%s'\n", timestr
);
736 if (strlen(timestr
) != 14 ||
737 sscanf(timestr
, "%04d%02d%02d%02d%02d%02d",
738 &yy
, &mo
, &day
, &hour
, &min
, &sec
) != 6) {
740 fprintf(ttyout
, "Can't parse time `%s'.\n", timestr
);
741 goto cleanup_parse_time
;
743 memset(&timebuf
, 0, sizeof(timebuf
));
744 timebuf
.tm_sec
= sec
;
745 timebuf
.tm_min
= min
;
746 timebuf
.tm_hour
= hour
;
747 timebuf
.tm_mday
= day
;
748 timebuf
.tm_mon
= mo
- 1;
749 timebuf
.tm_year
= yy
- TM_YEAR_BASE
;
750 timebuf
.tm_isdst
= -1;
751 rtime
= timegm(&timebuf
);
753 if (noisy
|| debug
!= 0)
756 goto cleanup_parse_time
;
758 fprintf(ttyout
, "parsed date as: %s", ctime(&rtime
));
760 if (r
== ERROR
&& code
== 500 && features
[FEAT_MDTM
] == -1)
761 features
[FEAT_MDTM
] = 0;
762 if (noisy
&& debug
== 0) {
763 fputs(reply_string
, ttyout
);
775 * Update global `localcwd', which contains the state of the local cwd
781 if (getcwd(localcwd
, sizeof(localcwd
)) == NULL
)
784 fprintf(ttyout
, "got localcwd as `%s'\n", localcwd
);
788 * Update global `remotecwd', which contains the state of the remote cwd
791 updateremotecwd(void)
793 int overbose
, ocode
, i
;
800 if (command("PWD") != COMPLETE
)
802 cp
= strchr(reply_string
, ' ');
803 if (cp
== NULL
|| cp
[0] == '\0' || cp
[1] != '"')
806 for (i
= 0; *cp
&& i
< sizeof(remotecwd
) - 1; i
++, cp
++) {
817 fprintf(ttyout
, "got remotecwd as `%s'\n", remotecwd
);
818 goto cleanupremotecwd
;
827 * Ensure file is in or under dir.
828 * Returns 1 if so, 0 if not (or an error occurred).
831 fileindir(const char *file
, const char *dir
)
833 char realfile
[PATH_MAX
+1];
836 if (realpath(file
, realfile
) == NULL
) {
839 if (errno
== ENOENT
) {
840 /* Check if the parent directory exist which is all we need */
841 const char* last
= strrchr(file
, '/');
843 char parent
[PATH_MAX
+1];
844 strlcpy(parent
, file
, last
- file
);
846 if (realpath(parent
, realfile
) != NULL
) {
847 strlcat(realfile
, last
, sizeof(realfile
));
851 /* This already is the last component */
852 strlcpy(realfile
, file
, sizeof(realfile
));
858 warn("Unable to determine real path of `%s'", file
);
862 if (realfile
[0] != '/') /* relative result */
864 dirlen
= strlen(dir
);
866 printf("file %s realfile %s dir %s [%d]\n", file
, realfile
, dir
, dirlen
);
868 if (strncmp(realfile
, dir
, dirlen
) == 0 && realfile
[dirlen
] == '/')
874 * List words in stringlist, vertically arranged
877 list_vertical(StringList
*sl
)
880 int columns
, width
, lines
;
885 for (i
= 0 ; i
< sl
->sl_cur
; i
++) {
886 w
= strlen(sl
->sl_str
[i
]);
890 width
= (width
+ 8) &~ 7;
892 columns
= ttywidth
/ width
;
895 lines
= (sl
->sl_cur
+ columns
- 1) / columns
;
896 for (i
= 0; i
< lines
; i
++) {
897 for (j
= 0; j
< columns
; j
++) {
898 p
= sl
->sl_str
[j
* lines
+ i
];
901 if (j
* lines
+ i
+ lines
>= sl
->sl_cur
) {
908 (void)putc('\t', ttyout
);
915 * Update the global ttywidth value, using TIOCGWINSZ.
920 struct winsize winsize
;
923 if (ioctl(fileno(ttyout
), TIOCGWINSZ
, &winsize
) != -1 &&
925 ttywidth
= winsize
.ws_col
;
932 * Change the rate limit up (SIGUSR1) or down (SIGUSR2)
941 rate_get
+= rate_get_incr
;
943 rate_put
+= rate_put_incr
;
946 if (rate_get
&& rate_get
> rate_get_incr
)
947 rate_get
-= rate_get_incr
;
948 if (rate_put
&& rate_put
> rate_put_incr
)
949 rate_put
-= rate_put_incr
;
952 err(1, "crankrate invoked with unknown signal: %d", sig
);
958 * Setup or cleanup EditLine structures
960 #ifndef NO_EDITCOMPLETE
964 if (editing
&& el
== NULL
&& hist
== NULL
) {
968 el
= el_init(getprogname(), stdin
, ttyout
, stderr
);
970 hist
= history_init(); /* init the builtin history */
971 history(hist
, &ev
, H_SETSIZE
, 100);/* remember 100 events */
972 el_set(el
, EL_HIST
, history
, hist
); /* use history */
974 el_set(el
, EL_EDITOR
, "emacs"); /* default editor is emacs */
975 el_set(el
, EL_PROMPT
, prompt
); /* set the prompt functions */
976 el_set(el
, EL_RPROMPT
, rprompt
);
978 /* add local file completion, bind to TAB */
979 el_set(el
, EL_ADDFN
, "ftp-complete",
980 "Context sensitive argument completion",
982 el_set(el
, EL_BIND
, "^I", "ftp-complete", NULL
);
983 el_source(el
, NULL
); /* read ~/.editrc */
984 if ((el_get(el
, EL_EDITMODE
, &editmode
) != -1) && editmode
== 0)
985 editing
= 0; /* the user doesn't want editing,
986 * so disable, and let statement
989 el_set(el
, EL_SIGNAL
, 1);
1002 #endif /* !NO_EDITCOMPLETE */
1005 * Convert the string `arg' to an int, which may have an optional SI suffix
1006 * (`b', `k', `m', `g'). Returns the number for success, -1 otherwise.
1009 strsuftoi(const char *arg
)
1014 if (!isdigit((unsigned char)arg
[0]))
1017 val
= strtol(arg
, &cp
, 10);
1019 if (cp
[0] != '\0' && cp
[1] != '\0')
1021 switch (tolower((unsigned char)cp
[0])) {
1038 if (val
< 0 || val
> INT_MAX
)
1045 * Set up socket buffer sizes before a connection is made.
1048 setupsockbufsize(int sock
)
1051 if (setsockopt(sock
, SOL_SOCKET
, SO_SNDBUF
,
1052 (void *)&sndbuf_size
, sizeof(sndbuf_size
)) == -1)
1053 warn("unable to set sndbuf size %d", sndbuf_size
);
1055 if (setsockopt(sock
, SOL_SOCKET
, SO_RCVBUF
,
1056 (void *)&rcvbuf_size
, sizeof(rcvbuf_size
)) == -1)
1057 warn("unable to set rcvbuf size %d", rcvbuf_size
);
1061 * Copy characters from src into dst, \ quoting characters that require it
1064 ftpvis(char *dst
, size_t dstlen
, const char *src
, size_t srclen
)
1069 src
[si
] != '\0' && di
< dstlen
&& si
< srclen
;
1090 * Copy src into buf (which is len bytes long), expanding % sequences.
1093 formatbuf(char *buf
, size_t len
, const char *src
)
1097 int i
, op
, updirs
, pdirs
;
1099 #define ADDBUF(x) do { \
1106 for (i
= 0; *p
; p
++) {
1118 p2
= connected
? remotecwd
: "";
1121 /* option to determine fixed # of dirs from path */
1122 if (op
== '.' || op
== 'c') {
1126 while (*p2
) /* calc # of /'s */
1129 if (p
[1] == '0') { /* print <x> or ... */
1133 if (p
[1] >= '1' && p
[1] <= '9') {
1134 /* calc # to skip */
1141 while (skip
-- > 0) {
1142 while ((p2
> q
) && (*p2
!= '/'))
1147 if (*p2
== '/' && p2
!= q
)
1151 if (updirs
> 0 && pdirs
) {
1165 ADDBUF('0' + updirs
);
1175 for (p2
= connected
&& username
? username
: "-";
1177 if (op
== 'm' && *p2
== '.')
1184 for (p2
= connected
? username
: "-"; *p2
; p2
++)
1192 default: /* display unknown codes literally */
1204 * Parse `port' into a TCP port number, defaulting to `defport' if `port' is
1205 * an unknown service name. If defport != -1, print a warning upon bad parse.
1208 parseport(const char *port
, int defport
)
1215 nport
= strtol(p
, &ep
, 10);
1216 if (*ep
!= '\0' && ep
== p
) {
1217 struct servent
*svp
;
1219 svp
= getservbyname(port
, "tcp");
1223 warnx("Unknown port `%s', using port %d",
1227 rv
= ntohs(svp
->s_port
);
1228 } else if (nport
< 1 || nport
> MAX_IN_PORT_T
|| *ep
!= '\0')
1237 * Determine if given string is an IPv6 address or not.
1238 * Return 1 for yes, 0 for no
1241 isipv6addr(const char *addr
)
1245 struct addrinfo hints
, *res
;
1247 memset(&hints
, 0, sizeof(hints
));
1248 hints
.ai_family
= PF_INET6
;
1249 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1250 hints
.ai_flags
= AI_NUMERICHOST
;
1251 if (getaddrinfo(addr
, "0", &hints
, &res
) != 0)
1258 fprintf(ttyout
, "isipv6addr: got %d for %s\n", rv
, addr
);
1260 return (rv
== 1) ? 1 : 0;
1265 * Internal version of connect(2); sets socket buffer sizes first and
1266 * supports a connection timeout using a non-blocking connect(2) with
1268 * Socket fcntl flags are temporarily updated to include O_NONBLOCK;
1269 * these will not be reverted on connection failure.
1270 * Returns -1 upon failure (with errno set to the problem), or 0 on success.
1273 xconnect(int sock
, const struct sockaddr
*name
, socklen_t namelen
)
1275 int flags
, rv
, timeout
, error
;
1277 struct timeval endtime
, now
, td
;
1278 struct pollfd pfd
[1];
1280 setupsockbufsize(sock
);
1282 if ((flags
= fcntl(sock
, F_GETFL
, 0)) == -1)
1283 return -1; /* get current socket flags */
1284 if (fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
) == -1)
1285 return -1; /* set non-blocking connect */
1287 /* NOTE: we now must restore socket flags on successful exit */
1290 pfd
[0].events
= POLLIN
|POLLOUT
;
1292 if (quit_time
> 0) { /* want a non default timeout */
1293 (void)gettimeofday(&endtime
, NULL
);
1294 endtime
.tv_sec
+= quit_time
; /* determine end time */
1297 rv
= connect(sock
, name
, namelen
); /* inititate the connection */
1298 if (rv
== -1) { /* connection error */
1299 if (errno
!= EINPROGRESS
) /* error isn't "please wait" */
1302 /* connect EINPROGRESS; wait */
1304 if (quit_time
> 0) { /* determine timeout */
1305 (void)gettimeofday(&now
, NULL
);
1306 timersub(&endtime
, &now
, &td
);
1307 timeout
= td
.tv_sec
* 1000 + td
.tv_usec
/1000;
1314 rv
= xpoll(pfd
, 1, timeout
);
1315 /* loop until poll ! EINTR */
1316 } while (rv
== -1 && errno
== EINTR
);
1318 if (rv
== 0) { /* poll (connect) timed out */
1323 if (rv
== -1) { /* poll error */
1325 } else if (pfd
[0].revents
& (POLLIN
|POLLOUT
)) {
1326 slen
= sizeof(error
); /* OK, or pending error */
1327 if (getsockopt(sock
, SOL_SOCKET
, SO_ERROR
,
1328 &error
, &slen
) == -1)
1329 return -1; /* Solaris pending error */
1331 errno
= error
; /* BSD pending error */
1335 errno
= EBADF
; /* this shouldn't happen ... */
1340 if (fcntl(sock
, F_SETFL
, flags
) == -1) /* restore socket flags */
1346 * Internal version of listen(2); sets socket buffer sizes first.
1349 xlisten(int sock
, int backlog
)
1352 setupsockbufsize(sock
);
1353 return (listen(sock
, backlog
));
1357 * Internal version of poll(2), to allow reimplementation by select(2)
1358 * on platforms without the former.
1361 xpoll(struct pollfd
*fds
, int nfds
, int timeout
)
1363 return poll(fds
, nfds
, timeout
);
1367 * malloc() with inbuilt error checking
1370 xmalloc(size_t size
)
1376 err(1, "Unable to allocate %ld bytes of memory", (long)size
);
1381 * sl_init() with inbuilt error checking
1390 err(1, "Unable to allocate memory for stringlist");
1395 * sl_add() with inbuilt error checking
1398 xsl_add(StringList
*sl
, char *i
)
1401 if (sl_add(sl
, i
) == -1)
1402 err(1, "Unable to add `%s' to stringlist", i
);
1406 * strdup() with inbuilt error checking
1409 xstrdup(const char *str
)
1414 errx(1, "xstrdup() called with NULL argument");
1417 err(1, "Unable to allocate memory for string copy");