summaryrefslogtreecommitdiff
path: root/pkgtools/pkg_install/files/lib/ftpio.c
diff options
context:
space:
mode:
Diffstat (limited to 'pkgtools/pkg_install/files/lib/ftpio.c')
-rw-r--r--pkgtools/pkg_install/files/lib/ftpio.c1259
1 files changed, 0 insertions, 1259 deletions
diff --git a/pkgtools/pkg_install/files/lib/ftpio.c b/pkgtools/pkg_install/files/lib/ftpio.c
deleted file mode 100644
index f23612ee391..00000000000
--- a/pkgtools/pkg_install/files/lib/ftpio.c
+++ /dev/null
@@ -1,1259 +0,0 @@
-/* $NetBSD: ftpio.c,v 1.26 2008/01/29 15:39:31 hubertf Exp $ */
-
-#if HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include <nbcompat.h>
-#if HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#endif
-#ifndef lint
-__RCSID("$NetBSD: ftpio.c,v 1.26 2008/01/29 15:39:31 hubertf Exp $");
-#endif
-
-/*-
- * Copyright (c) 1999-2008 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Hubert Feyrer <hubert@feyrer.de> and Thomas Klausner.
- *
- * 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 NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#endif
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_ASSERT_H
-#include <assert.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#if HAVE_ERR_H
-#include <err.h>
-#endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#if HAVE_REGEX_H
-#include <regex.h>
-#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_TERMCAP_H
-#include <termcap.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "../lib/lib.h"
-
-/*
- * Names of environment variables used to pass things to
- * subprocesses, for connection caching.
- */
-#define PKG_FTPIO_COMMAND "PKG_FTPIO_COMMAND"
-#define PKG_FTPIO_ANSWER "PKG_FTPIO_ANSWER"
-#define PKG_FTPIO_CNT "PKG_FTPIO_CNT"
-#define PKG_FTPIO_CURRENTHOST "PKG_FTPIO_CURRENTHOST"
-#define PKG_FTPIO_CURRENTDIR "PKG_FTPIO_CURRENTDIR"
-
-#undef STANDALONE /* define for standalone debugging */
-
-/* File descriptors */
-typedef struct {
- int command;
- int answer;
-} fds;
-
-
-static int needclose=0;
-static int ftp_started=0;
-static fds ftpio;
-static int ftp_pid;
-static char term[1024];
-static char bold_on[1024];
-static char bold_off[1024];
-
-static char *ftp_expand_URL(const char *, char *);
-static int hexvalue(char);
-static char *http_expand_URL(const char *, char *);
-static int http_extract_fn(char *, char *, size_t);
-static void URL_decode(char *);
-
-/*
- * expect "str" (a regular expression) on file descriptor "fd", storing
- * the FTP return code of the command in the integer "ftprc". The "str"
- * string is expected to match some FTP return codes after a '\n', e.g.
- * "\n(550|226).*\n"
- */
-static int
-expect(int fd, const char *str, int *ftprc)
-{
- int rc;
- char buf[256];
- regex_t rstr;
- int done;
- struct pollfd set[1];
- int retval;
- regmatch_t match;
- int verbose_expect=0;
-
- if (regcomp(&rstr, str, REG_EXTENDED) != 0)
- err(EXIT_FAILURE, "expect: regcomp() failed");
-
- memset(buf, '\n', sizeof(buf));
-
- done=0;
- retval=0;
- set[0].fd = fd;
- set[0].events = POLLIN;
- while(!done) {
- rc = poll(set, 1, 60*60*1000); /* seconds until next message from tar */
- switch (rc) {
- case -1:
- if (errno == EINTR)
- break;
- warn("expect: poll() failed (probably ftp died because of bad args)");
- done = 1;
- retval = -1;
- break;
- case 0:
- warnx("expect: poll() timeout");
- /* need to send ftp coprocess SIGINT to make it stop
- * downloading into dir that we'll blow away in a second */
- kill(ftp_pid, SIGINT);
-
- /* Wait until ftp coprocess is responsive again
- * XXX Entering recursion here!
- */
- rc = ftp_cmd("cd .\n", "\n(550|250).*\n");
- if (rc != 250) {
- /* now we have a really good reason to bail out ;) */
- }
- /* ftp is at command prompt again, and will wait for our
- * next command. If we were downloading, we can now safely
- * continue and remove the dir that the tar command was
- * expanding to */
-
- done = 1; /* hope that's ok */
- retval = -1;
- break;
- default:
- if (set[0].revents & POLLHUP) {
- done = 1;
- retval = -1;
- break;
- }
-
- rc = read(fd, &buf[sizeof(buf) - 1], 1);
- if (rc <= 0) {
- done = 1;
- retval = -1;
- break;
- }
-
- if (verbose_expect)
- putchar(buf[sizeof(buf)-1]);
-
- if (regexec(&rstr, buf, 1, &match, 0) == 0) {
- if (ftprc && isdigit((unsigned char)buf[match.rm_so+1]))
- *ftprc = atoi(buf+match.rm_so+1);
-
- done=1;
- retval=0;
- }
-
- memmove(buf, buf+1, sizeof(buf)-1); /* yes, this is non-performant */
- break;
- }
- }
-
- return retval;
-}
-
-/*
- * send a certain ftp-command "cmd" to our FTP coprocess, and wait for
- * "expectstr" to be returned. Return numeric FTP return code or -1
- * in case of an error (usually expect() timeout)
- */
-int
-ftp_cmd(const char *cmd, const char *expectstr)
-{
- int rc=0, verbose_ftp=0;
- int len;
-
- if (Verbose)
- verbose_ftp=1;
-
- if (verbose_ftp)
- fprintf(stderr, "\n%sftp> %s%s", bold_on, cmd, bold_off);
-
- fflush(stdout);
- len = write(ftpio.command, cmd, strlen(cmd));
- if (len == strlen(cmd)) {
- if (expectstr) {
- /* set "rc" to the FTP error code: */
- if (expect(ftpio.answer, expectstr, &rc) == -1)
- rc = -1; /* some error occurred */
- }
- } else {
- if (Verbose)
- warn("short write");
- }
-
- return rc;
-}
-
-
-/*
- * Really fire up FTP coprocess
- */
-static int
-setupCoproc(const char *base)
-{
- int command_pipe[2];
- int answer_pipe[2];
- int rc1, rc2;
- char buf[20];
- char *argv0 = (char *)strrchr(FTP_CMD, '/');
- if (argv0 == NULL)
- argv0 = FTP_CMD;
- else
- argv0++;
-
- rc1 = pipe(command_pipe);
- rc2 = pipe(answer_pipe);
-
- if(rc1==-1 || rc2==-1) {
- warn("setupCoproc: pipe() failed");
- return -1;
- }
-
- if (command_pipe[0] == -1 || command_pipe[1] == -1 ||
- answer_pipe[0] == -1 || answer_pipe[1] == -1 ) {
- warn("setupCoproc: pipe() returned bogus descriptor");
- return -1;
- }
-
- rc1 = fork();
- switch (rc1) {
- case -1:
- /* Error */
-
- warn("setupCoproc: fork() failed");
- return -1;
- break;
-
- case 0:
- /* Child */
-
- (void) close(command_pipe[1]);
- rc1 = dup2(command_pipe[0], 0);
- if (rc1 == -1) {
- err(EXIT_FAILURE, "setupCoproc: dup2 failed (command_pipe[0])");
- }
- (void) close(command_pipe[0]);
-
- (void) close(answer_pipe[0]);
- rc1 = dup2(answer_pipe[1], 1);
- if (rc1 == -1) {
- err(EXIT_FAILURE, "setupCoproc: dup2 failed (answer_pipe[1])");
- }
- (void) close(answer_pipe[1]);
-
- setbuf(stdout, NULL);
-
- if (Verbose)
- fprintf(stderr, "%sftp -detv %s%s\n", bold_on, base, bold_off);
- rc1 = execlp(FTP_CMD, argv0, "-detv", base, NULL);
- warn("setupCoproc: execlp() failed");
- exit(1);
- break;
- default:
- /* Parent */
- (void) close(command_pipe[0]);
- (void) close(answer_pipe[1]);
-
- (void) snprintf(buf, sizeof(buf), "%d", command_pipe[1]);
- setenv(PKG_FTPIO_COMMAND, buf, 1);
- (void) snprintf(buf, sizeof(buf), "%d", answer_pipe[0]);
- setenv(PKG_FTPIO_ANSWER, buf, 1);
-
- ftpio.command = command_pipe[1];
- ftpio.answer = answer_pipe[0];
- ftp_pid = rc1; /* to ^C transfers */
-
- fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
- fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
-
- break;
- }
-
- return 0;
-}
-
-
-/*
- * Dummy signal handler to detect if the ftp(1) coprocess or
- * and of the processes of the tar/gzip pipeline dies.
- */
-static void
-sigchld_handler (int n)
-{
- /* Make poll(2) return EINTR */
-}
-
-
-/*
- * SIGPIPE only happens when there's something wrong with the FTP
- * coprocess. In that case, set mark to not try to close shut down
- * the coprocess.
- */
-static void
-sigpipe_handler(int n)
-{
- /* aparently our ftp companion died */
- if (Verbose)
- fprintf(stderr, "SIGPIPE!\n");
- needclose = 0;
-}
-
-
-/*
- * Close the FTP coprocess' current connection, but
- * keep the process itself alive.
- */
-void
-ftp_stop(void)
-{
-#if defined(__svr4__) && defined(__sun__)
- char env[BUFSIZ];
-#endif
- const char *tmp1, *tmp2;
-
- if (!ftp_started)
- return;
-
- tmp1=getenv(PKG_FTPIO_COMMAND);
- tmp2=getenv(PKG_FTPIO_ANSWER);
-
- /* (Only) the last one closes the link */
- if (tmp1 != NULL && tmp2 != NULL) {
- if (needclose)
- ftp_cmd("close\n", "\n(221 .*|Not connected.)\n");
-
- (void) close(ftpio.command);
- (void) close(ftpio.answer);
- }
-
-#if defined(__svr4__) && defined(__sun__)
- (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_COMMAND);
- putenv(env);
- (void) snprintf(env, sizeof(env), "%s=", PKG_FTPIO_ANSWER);
- putenv(env);
-#else
- unsetenv(PKG_FTPIO_COMMAND);
- unsetenv(PKG_FTPIO_ANSWER);
-#endif
-}
-
-
-/*
- * (Start and re-)Connect the FTP coprocess to some host/dir.
- * If the requested host/dir is different than the one that the
- * coprocess is currently at, close first.
- */
-int
-ftp_start(const char *base)
-{
- const char *tmp1, *tmp2;
- char *p;
- int rc;
- char newHost[MAXHOSTNAMELEN];
- const char *newDir;
- const char *currentHost=getenv(PKG_FTPIO_CURRENTHOST);
- const char *currentDir=getenv(PKG_FTPIO_CURRENTDIR);
- int urllen;
-
- /* talk to termcap for bold on/off escape sequences */
- if (getenv("TERM") != NULL && tgetent(term, getenv("TERM")) > 0) {
- p = bold_on; tgetstr("md", &p);
- p = bold_off; tgetstr("me", &p);
- } else {
- bold_on[0] = '\0';
- bold_off[0] = '\0';
- }
-
- fileURLHost(base, newHost, sizeof(newHost));
- urllen = URLlength(base);
- if (urllen < 0 || !(newDir = strchr(base + URLlength(base), '/')))
- errx(EXIT_FAILURE, "ftp_start: bad URL '%s'", base);
- newDir++;
- if (currentHost
- && currentDir
- && ( strcmp(newHost, currentHost) != 0
- || strcmp(newDir, currentDir) != 0)) { /* could handle new dir case better here, w/o reconnect */
- if (Verbose) {
- printf("ftp_start: new host or dir, stopping previous connect...\n");
- printf("currentHost='%s', newHost='%s'\n", currentHost, newHost);
- printf("currentDir='%s', newDir='%s'\n", currentDir, newDir);
- }
-
- ftp_stop();
-
- if (Verbose)
- printf("ftp stopped\n");
- }
- setenv(PKG_FTPIO_CURRENTHOST, newHost, 1); /* need to update this in the environment */
- setenv(PKG_FTPIO_CURRENTDIR, newDir, 1); /* for subprocesses to have this available */
-
- tmp1=getenv(PKG_FTPIO_COMMAND);
- tmp2=getenv(PKG_FTPIO_ANSWER);
- if(tmp1==NULL || tmp2==NULL || *tmp1=='\0' || *tmp2=='\0') {
- /* no FTP coprocess running yet */
-
- if (Verbose)
- printf("Spawning FTP coprocess\n");
-
- rc = setupCoproc(base);
- if (rc == -1) {
- warnx("setupCoproc() failed");
- return -1;
- }
-
- needclose=1;
- signal(SIGPIPE, sigpipe_handler);
- signal(SIGCHLD, sigchld_handler);
-
- if ((expect(ftpio.answer, "\n(221|250|221|550).*\n", &rc) != 0)
- || rc != 250) {
- warnx("expect1 failed, rc=%d", rc);
- return -1;
- }
-
- /* nbftp now issues a CWD for each part of the path
- * and will return a code for each of them. No idea how to
- * deal with that other than to issue a 'prompt off' to
- * get something that we can wait for and that does NOT
- * look like a CWD command's output */
- rc = ftp_cmd("prompt off\n", "\n(Interactive mode off|221).*\n");
- if ((rc == 221) || (rc == -1)) {
- /* something is wrong */
- ftp_started=1; /* not really, but for ftp_stop() */
- ftp_stop();
- warnx("prompt failed - wrong dir?");
- return -1;
- }
-
- ftp_started=1;
- } else {
- /* get FDs of our coprocess */
-
- ftpio.command = dup(atoi(tmp1));
- if (ftpio.command == -1 ) {
- warnx("command dup() failed, increase 'descriptors' limit");
- return -1;
- }
- ftpio.answer = dup(atoi(tmp2));
- if (ftpio.answer == -1 ) {
- warnx("answer dup() failed, increase 'descriptors' limit");
- return -1;
- }
-
- if (Verbose)
- printf("Reusing FDs %s/%s for communication to FTP coprocess\n", tmp1, tmp2);
-
- fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
- fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
- }
-
- return 0;
-}
-
-
-/*
- * Expand the given wildcard URL "wildcardurl" if possible, and store the
- * expanded value into "expandedurl". return 0 if successful, -1 else.
- */
-int
-expandURL(char *expandedurl, const char *wildcardurl)
-{
- char *pattern;
- char *bestmatch;
- char base[MaxPathSize];
-
- pattern=strrchr(wildcardurl, '/');
- if (pattern == NULL){
- warnx("expandURL: no '/' in URL %s?!", wildcardurl);
- return -1;
- }
- if (pattern-strchr(wildcardurl, '/') < 2) {
- /* only one or two slashes in total */
- warnx("expandURL: not enough '/' in URL %s", wildcardurl);
- return -1;
- }
- (void) snprintf(base, sizeof(base), "%.*s/",
- (int)(pattern-wildcardurl), wildcardurl);
- pattern++;
-
- if (strncmp(wildcardurl, "ftp://", 6) == 0)
- bestmatch=ftp_expand_URL(base, pattern);
- else if (strncmp(wildcardurl, "http://", 7) == 0)
- bestmatch=http_expand_URL(base, pattern);
- else {
- warnx("expandURL: unknown protocol in URL `%s'", wildcardurl);
- return -1;
- }
-
- /* no match found */
- if (bestmatch == NULL)
- return -1;
-
- snprintf(expandedurl, MaxPathSize, "%s%s", base, bestmatch);
- if (Verbose)
- printf("best match: '%s'\n", expandedurl);
-
- return 0;
-}
-
-/* for a given wildcard ftp:// URL, find the best matching pkg */
-static char *
-ftp_expand_URL(const char *base, char *pattern)
-{
- char *s, buf[MaxPathSize];
- char tmpname[MaxPathSize];
- char best[MaxPathSize];
- char s_best[MaxPathSize];
- int rc, got_list, tfd, retry_tbz;
-
- retry_tbz = 0;
- best[0]='\0';
- s_best[0]='\0';
-
- rc = ftp_start(base);
- if (rc == -1) {
- warnx("ftp_start() failed");
- return NULL;
- }
-
- strlcpy(tmpname, "/var/tmp/pkg.XXXXXX", sizeof(tmpname));
- tfd=mkstemp(tmpname);
- if (tfd == -1) {
- warnx("Cannot generate temp file for ftp(1)'s nlist output");
- return NULL;
- }
- close(tfd); /* We don't need the file descriptor, but will use
- the file in a second */
-
- s=strpbrk(pattern, "<>[]?*{"); /* Could leave out "[]?*" here;
- * ftp(1) is not that stupid */
- if (!s) {
- /* This should only happen when getting here with (only) a package
- * name specified to pkg_add, and PKG_PATH containing some URL.
- */
- (void) snprintf(buf, sizeof(buf), "nlist %s %s\n", pattern, tmpname);
- } else {
- /* replace possible version(wildcard) given with "-*".
- * we can't use the pkg wildcards here as dewey compare
- * and alternates won't be handled by ftp(1); sort
- * out later, using pkg_match() */
- if (retry_tbz) {
-retry_with_tbz:
- (void) snprintf(buf, sizeof(buf), "nlist %.*s*.tbz %s\n",
- (int)(s-pattern), pattern, tmpname);
- retry_tbz = 0;
- } else {
- (void) snprintf(buf, sizeof(buf), "nlist %.*s*.tgz %s\n",
- (int)(s-pattern), pattern, tmpname);
- retry_tbz = 1;
- }
- }
-
- rc = ftp_cmd(buf, "\n(550|450|226).*\n"); /* catch errors */
- if (rc != 226)
- got_list = 0;
- else
- got_list = 1;
-
- /* Sync - don't remove */
- rc = ftp_cmd("cd .\n", "\n(550|250|257).*\n");
- if (rc != 250) {
- warnx("chdir failed!");
- unlink(tmpname); /* remove clutter */
- return NULL;
- }
-
- if (got_list == 1 && access(tmpname, R_OK)==0) {
- FILE *f;
- char filename[MaxPathSize];
-
- f=fopen(tmpname, "r");
- if (f == NULL) {
- warn("fopen");
- unlink(tmpname); /* remove clutter */
- return NULL;
- }
- /* The following loop is basically the same as the readdir() loop
- * in findmatchingname() */
- while (fgets(filename, sizeof(filename), f)) {
-
- /*
- * We need to strip off any .t[bg]z etc.
- * suffix here
- */
-
- char s_filename[MaxPathSize];
- char s_pattern[MaxPathSize];
-
- filename[strlen(filename)-1] = '\0';
-
- strip_txz(s_filename, NULL, filename);
- strip_txz(s_pattern, NULL, pattern);
-
- if (pkg_order(s_pattern, s_filename,
- s_best[0] != '\0' ? s_best : NULL) == 1) {
- strlcpy(s_best, s_filename, sizeof(s_best));
- strlcpy(best, filename, sizeof(best));
- }
- }
- (void) fclose(f);
- }
-
- if (retry_tbz)
- goto retry_with_tbz;
-
- if (best[0] == '\0' && Verbose)
- warnx("nothing appropriate found");
-
- unlink(tmpname);
-
- if (best[0] == '\0')
- return NULL;
-
- return strdup(best);
-}
-
-/* for a given wildcard http:// URL, find the best matching pkg */
-static char *
-http_expand_URL(const char *base, char *pattern)
-{
- char best[MaxPathSize];
- char s_best[MaxPathSize];
- char line[BUFSIZ];
- char filename[MaxPathSize];
- FILE *fp;
- int pipefds[2];
- int state;
- pid_t pid;
-
- *best = '\0';
- *s_best = '\0';
-
- /* Set up a pipe for getting the file list */
- if (pipe(pipefds) == -1) {
- warnx("cannot create pipe");
- return NULL;
- }
- if ((pid = fork()) == -1) {
- warnx("cannot fork ftp process");
- return NULL;
- }
- if (pid == 0) { /* The child */
- if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
- warnx("dup2 failed before starting ftp");
- _exit(2);
- }
- close(pipefds[0]);
- close(pipefds[1]);
- /* get URL contents to stdout and thus to parent,
- * silently */
- execlp("ftp", "ftp", "-V", "-o", "-", base, NULL);
- warnx("failed to execute ftp");
- _exit(2);
- }
-
- /* parent */
- close(pipefds[1]);
-
- if ((fp=fdopen(pipefds[0], "r")) == NULL)
- warn("can't fdopen pipe end");
- else {
- char s_pattern[MaxPathSize];
- int len, offset;
-
- /* strip of .t[bg]z for comparison */
- strip_txz(s_pattern, NULL, pattern);
-
- /* initialize http_extract_fn internal state */
- http_extract_fn(NULL, NULL, 0);
-
- /* read line from HTTP output and extract filenames */
- while (fgets(line, sizeof(line), fp) != NULL) {
- len = offset = 0;
- while ((len=http_extract_fn(line+offset, filename,
- sizeof(filename))) > 0) {
- char s_filename[MaxPathSize];
-
- offset += len;
- strip_txz(s_filename, NULL, filename);
-
- if (pkg_order(s_pattern, s_filename,
- *s_best != '\0' ? s_best : NULL) == 1) {
- strlcpy(best, filename, sizeof(best));
- strlcpy(s_best, s_filename, sizeof(best));
- }
- }
- }
-
- }
-
- fclose(fp);
-
- /* wait for child to exit */
- if (waitpid(pid, &state, 0) < 0) {
- /* error has been reported by child */
- return NULL;
- }
-
- if (best[0] == '\0') {
- if (Verbose)
- warnx("nothing appropriate found");
- return NULL;
- }
-
- return strdup(best);
-
-}
-
-enum http_states {
- ST_NONE,
- ST_LT, ST_LTA, ST_TAGA, ST_H, ST_R, ST_E, ST_F, ST_HREF,
- ST_TAG, ST_TAGAX
-};
-
-/* return any hrefs found */
-static int
-http_extract_fn(char *input, char *outbuf, size_t outbuflen)
-{
- /* partial copied hrefs from previous calls are saved here */
- static char tempbuf[MaxPathSize];
- /* fill state of tempbuf */
- static int tempbuffill = 0;
- /* parsing state information */
- static enum http_states state;
- /* currently in double quotes (in parsing) */
- static int dqflag;
- char p;
- int offset, found;
-
- if (outbuf == NULL) {
- /* init */
- dqflag = tempbuffill = 0;
- state = ST_NONE;
- return 0;
- }
-
- offset = 0;
- found = 0;
- while ((p=input[offset++]) != '\0') {
- /* handle anything that's inside double quotes */
- if (dqflag) {
- /* incomplete href */
- if (state == ST_HREF) {
- /* check if space left in output
- * buffer */
- if (tempbuffill >= sizeof(tempbuf)) {
- warnx("href starting with `%.*s'"
- " too long", 60, tempbuf);
- /* ignore remainder */
- tempbuffill = 0;
- /* need space before "href"
- * can start again (invalidly,
- * of course, but we don't
- * care) */
- state = ST_TAGAX;
- }
-
- /* href complete */
- if (p == '\"') {
- /* complete */
- dqflag = 0;
- tempbuf[tempbuffill++] = '\0';
- /* need space before "href"
- * can start again (invalidly,
- * of course, but we don't
- * care) */
- state = ST_TAGAX;
- found = 1;
- break;
- } else {
- /* copy one more char */
- tempbuf[tempbuffill++] = p;
- }
- } else {
- /* leaving double quotes */
- if (p == '\"')
- dqflag = 0;
- }
- continue;
- }
-
- /*
- * entering double quotes? (only relevant inside a tag)
- */
- if (state != ST_NONE && p == '\"') {
- dqflag = 1;
- continue;
- }
-
- /* other cases */
- switch (state) {
- case ST_NONE:
- /* plain text, not in markup */
- if (p == '<')
- state = ST_LT;
- break;
- case ST_LT:
- /* in tag -- "<" already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == 'a' || p == 'A')
- state = ST_LTA;
- else if (!isspace((unsigned char)p))
- state = ST_TAG;
- break;
- case ST_LTA:
- /* in tag -- "<a" already found */
- if (p == '>')
- state = ST_NONE;
- else if (isspace((unsigned char)p))
- state = ST_TAGA;
- else
- state = ST_TAG;
- break;
- case ST_TAG:
- /* in tag, but not "<a" -- disregard */
- if (p == '>')
- state = ST_NONE;
- break;
- case ST_TAGA:
- /* in a-tag -- "<a " already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == 'h' || p == 'H')
- state = ST_H;
- else if (!isspace((unsigned char)p))
- state = ST_TAGAX;
- break;
- case ST_TAGAX:
- /* in unknown keyword in a-tag */
- if (p == '>')
- state = ST_NONE;
- else if (isspace((unsigned char)p))
- state = ST_TAGA;
- break;
- case ST_H:
- /* in a-tag -- "<a h" already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == 'r' || p == 'R')
- state = ST_R;
- else if (isspace((unsigned char)p))
- state = ST_TAGA;
- else
- state = ST_TAGAX;
- break;
- case ST_R:
- /* in a-tag -- "<a hr" already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == 'e' || p == 'E')
- state = ST_E;
- else if (isspace((unsigned char)p))
- state = ST_TAGA;
- else
- state = ST_TAGAX;
- break;
- case ST_E:
- /* in a-tag -- "<a hre" already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == 'f' || p == 'F')
- state = ST_F;
- else if (isspace((unsigned char)p))
- state = ST_TAGA;
- else
- state = ST_TAGAX;
- break;
- case ST_F:
- /* in a-tag -- "<a href" already found */
- if (p == '>')
- state = ST_NONE;
- else if (p == '=')
- state = ST_HREF;
- else if (!isspace((unsigned char)p))
- state = ST_TAGAX;
- break;
- case ST_HREF:
- /* in a-tag -- "<a href=" already found */
- /* XXX: handle missing double quotes? */
- if (p == '>')
- state = ST_NONE;
- /* skip spaces before URL */
- else if (!isspace((unsigned char)p))
- state = ST_TAGA;
- break;
- /* no default case by purpose */
- }
- }
-
- if (p == '\0')
- return -1;
-
- if (found) {
- char *q;
-
- URL_decode(tempbuf);
-
- /* strip path (XXX) */
- if ((q=strrchr(tempbuf, '/')) == NULL)
- q = tempbuf;
-
- (void)strlcpy(outbuf, q, outbuflen);
- tempbuffill = 0;
- }
-
- return offset;
-}
-
-
-static int
-hexvalue(char p)
-{
- if (p >= '0' && p <= '9')
- return (p-'0');
- else if (p >= 'a' && p <= 'f')
- return (p-'a'+10);
- else if (p >= 'A' && p <= 'F')
- return (p-'A'+10);
- else
- return -1;
-}
-
-/* fetch and extract URL url into directory path */
-static int
-http_fetch(const char *url, const char *path)
-{
- int pipefds[2];
- int stateftp, state;
- pid_t pidftp, pid;
-
- /* Set up a pipe for passing the fetched contents. */
- if (pipe(pipefds) == -1) {
- warn("cannot create pipe");
- return -1;
- }
- /* fork ftp child */
- if ((pidftp = fork()) == -1) {
- warn("cannot fork process for ftp");
- return -1;
- }
- if (pidftp == 0) {
- /* child */
- if (dup2(pipefds[1], STDOUT_FILENO) == -1) {
- warn("dup2 failed before executing ftp");
- _exit(2);
- }
- close(pipefds[0]);
- close(pipefds[1]);
- execlp(FTP_CMD, FTP_CMD, "-o", "-", url, NULL);
- warnx("failed to execute ftp");
- _exit(2);
- }
-
- /* fork unpack child */
- if ((pid = fork()) == -1) {
- warn("cannot fork unpack process");
- return -1;
- }
- if (pid == 0) {
- /* child */
- if (dup2(pipefds[0], STDIN_FILENO) == -1) {
- warn("dup2 failed before unpack");
- _exit(2);
- }
- close(pipefds[0]);
- close(pipefds[1]);
- if ((path != NULL) && (chdir(path) < 0))
- _exit(127);
-
- if (unpack("-", NULL) != 0) {
- warnx("unpack failed");
- _exit(2);
- }
-
- _exit(0);
- }
-
- close(pipefds[0]);
- close(pipefds[1]);
-
- /* wait for unpack to exit */
- while (waitpid(pid, &state, 0) < 0) {
- if (errno != EINTR) {
- (void)waitpid(pidftp, &stateftp, 0);
- return -1;
- }
- }
- while (waitpid(pidftp, &stateftp, 0) < 0) {
- if (errno != EINTR) {
- return -1;
- }
- }
-
- if (!WIFEXITED(state) || !WIFEXITED(stateftp))
- return -1;
-
- if (WEXITSTATUS(state) != 0 || WEXITSTATUS(stateftp) != 0)
- return -1;
-
- return 0;
-}
-
-static void
-URL_decode(char *URL)
-{
- char *in, *out;
-
- in = out = URL;
-
- while (*in != '\0') {
- if (in[0] == '%' && in[1] != '\0' && in[2] != '\0') {
- /* URL-decode character */
- if (hexvalue(in[1]) != -1 && hexvalue(in[2]) != -1) {
- *out++ = hexvalue(in[1])*16+hexvalue(in[2]);
- }
- /* skip invalid encoded signs too */
- in += 3;
- }
- else
- *out++ = *in++;
- }
-
- *out = '\0';
-
- return;
-}
-/*
- * extract the given (expanded) URL "url" to the given directory "dir"
- * return -1 on error, 0 else;
- */
-int
-unpackURL(const char *url, const char *dir)
-{
- char *pkg;
- int rc;
- char base[MaxPathSize];
- char pkg_path[MaxPathSize];
-
- {
- /* Verify if the URL is really ok */
- char expnd[MaxPathSize];
-
- rc=expandURL(expnd, url);
- if (rc == -1) {
- warnx("unpackURL: verification expandURL failed");
- return -1;
- }
- if (strcmp(expnd, url) != 0) {
- warnx("unpackURL: verification expandURL failed, '%s'!='%s'",
- expnd, url);
- return -1;
- }
- }
-
- pkg=strrchr(url, '/');
- if (pkg == NULL){
- warnx("unpackURL: no '/' in URL %s?!", url);
- return -1;
- }
- (void) snprintf(base, sizeof(base), "%.*s/", (int)(pkg-url), url);
- (void) snprintf(pkg_path, sizeof(pkg_path), "%.*s",
- (int)(pkg-url), url); /* no trailing '/' */
- pkg++;
-
- /* Leave a hint for any depending pkgs that may need it */
- if (getenv("PKG_PATH") == NULL) {
- setenv("PKG_PATH", pkg_path, 1);
-#if 0
- path_create(pkg_path); /* XXX */
-#endif
- if (Verbose)
- printf("setenv PKG_PATH='%s'\n", pkg_path);
- }
-
- if (strncmp(url, "http://", 7) == 0)
- return http_fetch(url, dir);
-
- rc = ftp_start(base);
- if (rc == -1) {
- warnx("ftp_start() failed");
- return -1; /* error */
- }
-
- {
- char cmd[1024];
- const char *decompress_cmd = NULL;
- const char *suf;
-
- if (Verbose)
- printf("unpackURL '%s' to '%s'\n", url, dir);
-
- suf = suffix_of(pkg);
- if (!strcmp(suf, "tbz") || !strcmp(suf, "bz2"))
- decompress_cmd = BZIP2_CMD;
- else if (!strcmp(suf, "tgz") || !strcmp(suf, "gz"))
- decompress_cmd = GZIP_CMD;
- else if (!strcmp(suf, "tar"))
- ; /* do nothing */
- else
- errx(EXIT_FAILURE, "don't know how to decompress %s, sorry", pkg);
-
- /* yes, this is gross, but needed for borken ftp(1) */
- (void) snprintf(cmd, sizeof(cmd), "get %s \"| ( cd %s; " TAR_CMD " %s %s -vvxp -f - | tee %s )\"\n",
- pkg, dir,
- decompress_cmd != NULL ? "--use-compress-program" : "",
- decompress_cmd != NULL ? decompress_cmd : "",
- Verbose ? "/dev/stderr" : "/dev/null");
-
- rc = ftp_cmd(cmd, "\n(226|550).*\n");
- if (rc != 226) {
- warnx("Cannot fetch file (%d!=226)!", rc);
- return -1;
- }
- }
-
- return 0;
-}
-
-
-#ifdef STANDALONE
-static void
-usage(void)
-{
- errx(EXIT_FAILURE, "Usage: foo [-v] ftp://-pattern");
-}
-
-
-int
-main(int argc, char *argv[])
-{
- int rc, ch;
- char *argv0 = argv[0];
-
- while ((ch = getopt(argc, argv, "v")) != -1) {
- switch (ch) {
- case 'v':
- Verbose=1;
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc<1)
- usage();
-
- while(argv[0] != NULL) {
- char newurl[MaxPathSize];
-
- printf("Expand %s:\n", argv[0]);
- rc = expandURL(newurl, argv[0]);
- if (rc==-1)
- warnx("Cannot expand %s", argv[0]);
- else
- printf("Expanded URL: %s\n", newurl);
-
- /* test out connection caching */
- if (1) {
- char *s, buf[MaxPathSize];
-
- if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){
- (void) snprintf(buf, sizeof(buf),"%d", atoi(s)-1);
- setenv(PKG_FTPIO_CNT, buf, 1);
-
- printf("%s>>> %s -v %s\n", s, argv0, argv[0]);
- fexec(argv0, "-v", argv[0], NULL);
- }
- }
-
- printf("\n\n\n");
- argv++;
- }
-
- ftp_stop();
-
- return 0;
-}
-
-void
-cleanup(int i)
-{
-}
-#endif /* STANDALONE */