FTP wildcard depends code, initial commit.

Modulo some code cleanup, this gives NetBSD full wildcard support not
only in pkgsrc, but esp. for binary packages installed from local disk
and via FTP. For more information, see:

	http://www.feyrer.de/NetBSD/wildcards.html
This commit is contained in:
hubertf 2000-01-19 23:28:28 +00:00
parent e92c1387ea
commit 9d0c5bb4ee
13 changed files with 1070 additions and 66 deletions

View File

@ -1,11 +1,11 @@
/* $NetBSD: main.c,v 1.13 1999/11/10 18:51:47 abs Exp $ */
/* $NetBSD: main.c,v 1.14 2000/01/19 23:28:28 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char *rcsid = "from FreeBSD Id: main.c,v 1.16 1997/10/08 07:45:43 charnier Exp";
#else
__RCSID("$NetBSD: main.c,v 1.13 1999/11/10 18:51:47 abs Exp $");
__RCSID("$NetBSD: main.c,v 1.14 2000/01/19 23:28:28 hubertf Exp $");
#endif
#endif
@ -134,24 +134,54 @@ main(int argc, char **argv)
warn("realpath failed for '%s'", *argv);
} else
lpp = alloc_lpkg(cp);
} else if (ispkgpattern(*argv)
&& (s = findbestmatchingname(dirname_of(*argv),
} else if (ispkgpattern(*argv)) {
if ((s = findbestmatchingname(dirname_of(*argv),
basename_of(*argv))) != NULL) {
char tmp[FILENAME_MAX];
snprintf(tmp, sizeof(tmp), "%s/%s", dirname_of(*argv), s);
if (Verbose)
printf("Using %s for %s\n", tmp, *argv);
if (!(cp = realpath(tmp, pkgname))) {
lpp = NULL;
warn("realpath failed for '%s'", tmp);
} else
lpp = alloc_lpkg(cp);
} else {
lpp = NULL;
warnx("can't find package pattern '%s'", *argv);
}
} else {
/* Maybe just a pkg name w/o pattern was given */
char tmp[FILENAME_MAX];
snprintf(tmp, sizeof(tmp), "%s-[0-9]*.tgz", *argv);
s=findbestmatchingname(dirname_of(tmp),
basename_of(tmp));
if (s) {
char tmp2[FILENAME_MAX];
snprintf(tmp2, sizeof(tmp2), "%s/%s", dirname_of(tmp), s);
if (Verbose)
printf("Using %s for %s\n", s, *argv);
printf("Using %s for %s\n", tmp2, *argv);
if (!(cp = realpath(s, pkgname))) {
if (!(cp = realpath(tmp2, pkgname))) {
lpp = NULL;
warn("realpath failed for '%s'", s);
warn("realpath failed for '%s'", tmp2);
} else
lpp = alloc_lpkg(cp);
} else {
/* No go there... */
/* look for the file(pattern) in the expected places */
if (!(cp = fileFindByPath(NULL, *argv))) {
lpp = NULL;
warnx("can't find package '%s'", *argv);
} else
lpp = alloc_lpkg(cp);
}
}
}
if (lpp)

View File

@ -1,11 +1,11 @@
/* $NetBSD: perform.c,v 1.43 2000/01/09 17:21:53 hubertf Exp $ */
/* $NetBSD: perform.c,v 1.44 2000/01/19 23:28:28 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.44 1997/10/13 15:03:46 jkh Exp";
#else
__RCSID("$NetBSD: perform.c,v 1.43 2000/01/09 17:21:53 hubertf Exp $");
__RCSID("$NetBSD: perform.c,v 1.44 2000/01/19 23:28:28 hubertf Exp $");
#endif
#endif
@ -34,6 +34,7 @@ __RCSID("$NetBSD: perform.c,v 1.43 2000/01/09 17:21:53 hubertf Exp $");
#include "add.h"
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
static char LogDir[FILENAME_MAX];
@ -124,19 +125,72 @@ pkg_do(char *pkg)
* specification?
*/
if (IS_URL(pkg)) {
char buf[FILENAME_MAX];
char *tmppkg = pkg;
if (ispkgpattern(pkg)) {
#if 0
warnx("patterns not supported in URLs, "
"please install manually!");
"please install %s manually!", pkg);
/* ... until we come up with a better solution :-/ - HF */
goto bomb;
#else
{
/* Handle wildcard wildcard depends */
char *s;
s=fileFindByPath(NULL, pkg);
if (s == NULL) {
warnx("no pkg found for '%s', sorry.", pkg);
return 1;
}
strcpy(buf, s);
tmppkg = buf;
}
#endif
}
if (!(Home = fileGetURL(NULL, pkg))) {
warnx("unable to fetch `%s' by URL", pkg);
if (!(Home = fileGetURL(NULL, tmppkg))) {
warnx("unable to fetch `%s' by URL", tmppkg);
if (ispkgpattern(pkg))
return 1;
if (strstr(pkg, ".tgz") != NULL) {
/* There already is a ".tgz" - give up
* (We don't want to pretend to be exceedingly
* clever - the user should give something sane!)
*/
return 1;
}
/* Second chance - maybe just a package name was given,
* without even a wildcard as a version. Tack on
* the same pattern as we do for local packages: "-[0-9]*",
* plus a ".tgz" as we're talking binary pkgs here.
* Then retry.
*/
{
char *s;
char buf2[FILENAME_MAX];
snprintf(buf2, sizeof(buf2), "%s-[0-9]*.tgz", tmppkg);
s=fileFindByPath(NULL, buf2);
if (s == NULL) {
warnx("no pkg found for '%s' on 2nd try, sorry.", buf2);
return 1;
}
strcpy(buf, s);
tmppkg = buf;
if (!(Home = fileGetURL(NULL, tmppkg))) {
warnx("unable to fetch `%s' by URL", tmppkg);
return 1;
}
}
}
where_to = Home;
strcpy(pkg_fullname, pkg);
strcpy(pkg_fullname, tmppkg);
cfile = fopen(CONTENTS_FNAME, "r");
if (!cfile) {
warnx("unable to open table of contents file `%s' - not a package?",
@ -341,52 +395,82 @@ pkg_do(char *pkg)
++code;
}
} else {
warnx("add of dependency `%s' failed%s",
p->name, Force ? " (proceeding anyway)" : "!");
warnx("<%s> (1) add of dependency `%s' failed%s",
pkg, p->name, Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
} /* cp */
} else {
/* install depending pkg via FTP */
/* pkg is url -> install depending pkg via FTP */
char *saved_Current; /* allocated/set by save_dirs(), */
char *saved_Previous; /* freed by restore_dirs() */
char *cp, *new_pkg, *new_name;
new_pkg = pkg;
new_name = p->name;
if (ispkgpattern(p->name)) {
#if 0
warnx("can't install dependent pkg '%s' via FTP, "
"please install manually!", p->name);
/* ... until we come up with a better solution - HF */
goto bomb;
} else {
char *saved_Current; /* allocated/set by save_dirs(), */
char *saved_Previous; /* freed by restore_dirs() */
char *cp;
#else
{
/* Might hack stuff for wildcard depends in here - HF */
char *s;
s=fileFindByPath(pkg, p->name);
printf("HF: pkg='%s'\n", pkg);
printf("HF: s='%s'\n", s);
/* adjust new_pkg and new_name */
new_pkg = NULL;
new_name = s;
}
#endif
}
/* makeplaypen() and leave_playpen() clobber Current and
* Previous, save them! */
save_dirs(&saved_Current, &saved_Previous);
if ((cp = fileGetURL(pkg, p->name)) != NULL) {
if ((cp = fileGetURL(new_pkg, new_name)) != NULL) {
if (Verbose)
printf("Finished loading %s over FTP.\n", p->name);
printf("Finished loading %s over FTP.\n", new_name);
if (!fexists(CONTENTS_FNAME)) {
warnx("autoloaded package %s has no %s file?",
p->name, CONTENTS_FNAME);
if (!Force)
++code;
} else if (vsystem("(pwd; cat %s) | pkg_add %s%s%s %s-S",
} else {
if (vsystem("(pwd; cat %s) | pkg_add %s%s%s %s-S",
CONTENTS_FNAME,
Force ? "-f " : "",
Prefix ? "-p " : "",
Prefix ? Prefix : "",
Verbose ? "-v " : "")) {
warnx("add of dependency `%s' failed%s",
p->name, Force ? " (proceeding anyway)" : "!");
warnx("<%s> (2) add of dependency `%s' failed%s",
pkg, p->name, Force ? " (proceeding anyway)" : "!");
if (!Force)
++code;
} else if (Verbose)
printf("\t`%s' loaded successfully.\n", p->name);
} else if (Verbose) {
printf("\t`%s' loaded successfully as `%s'.\n", p->name, new_name);
}
}
/* Nuke the temporary playpen */
leave_playpen(cp);
restore_dirs(saved_Current, saved_Previous);
}
} else {
if (Verbose)
warnx("HF: fileGetURL('%s', '%s') failed", new_pkg, new_name);
if (!Force)
code++;
}
restore_dirs(saved_Current, saved_Previous);
}
} else {
/* fake install (???) */
@ -628,5 +712,8 @@ pkg_perform(lpkg_head_t *pkgs)
free_lpkg(lpp);
}
}
ftp_stop();
return err_cnt;
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pkg_add.1,v 1.18 2000/01/04 22:39:28 hubertf Exp $
.\" $NetBSD: pkg_add.1,v 1.19 2000/01/19 23:28:28 hubertf Exp $
.\"
.\" FreeBSD install - a package for the installation and maintainance
.\" of non-core utilities.
@ -363,10 +363,10 @@ The value of the
is used if a given package can't be found, it's usually set to
.Pa /usr/pkgsrc/packages/All .
The environment variable
should be a series of entries seperated by colons. Each entry
consists of a directory name. The current directory may be indicated
should be a series of entries seperated by semicolons. Each entry
consists of a directory name or URL. The current directory may be indicated
implicitly by an empty directory name, or explicitly by a single
period.
period. FTP URLs may not end with a slash.
.Ss PKG_DBDIR
Where to register packages instead of
.Pa /var/db/pkg .

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pkg_create.1,v 1.21 1999/12/20 03:25:58 hubertf Exp $
.\" $NetBSD: pkg_create.1,v 1.22 2000/01/19 23:28:30 hubertf Exp $
.\"
.\" FreeBSD install - a package for the installation and maintainance
.\" of non-core utilities.
@ -122,12 +122,12 @@ This is assumed to be a whitespace separated list of package names
and is meant as a convenient shorthand for specifying multiple
.Cm @pkgcfl
directives in the packing list (see PACKING LIST DETAILS section below).
.It Fl L Ar SrcDir
This sets the package's @src directive; see below for a description
of what this does.
.It Fl D Ar displayfile
Display the file after installing the package. Useful for things like
legal notices on almost-free software, etc.
.It Fl L Ar SrcDir
This sets the package's @src directive; see below for a description
of what this does.
.It Fl O
Go into a `packing list Only' mode.
This is used to do `fake pkg_add' operations when a package is installed.

View File

@ -1,11 +1,11 @@
/* $NetBSD: perform.c,v 1.29 1999/12/01 14:51:52 hubertf Exp $ */
/* $NetBSD: perform.c,v 1.30 2000/01/19 23:28:30 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.15 1997/10/13 15:03:52 jkh Exp";
#else
__RCSID("$NetBSD: perform.c,v 1.29 1999/12/01 14:51:52 hubertf Exp $");
__RCSID("$NetBSD: perform.c,v 1.30 2000/01/19 23:28:30 hubertf Exp $");
#endif
#endif
@ -539,7 +539,7 @@ pkg_do(char *pkg)
}
/* No match */
warnx("no such package '%s' installed", pkg);
warnx("package '%s' not installed", pkg);
return 1;
}
if (!getcwd(home, FILENAME_MAX)) {

View File

@ -1,11 +1,11 @@
/* $NetBSD: perform.c,v 1.29 1999/11/29 19:48:46 hubertf Exp $ */
/* $NetBSD: perform.c,v 1.30 2000/01/19 23:28:31 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: perform.c,v 1.23 1997/10/13 15:03:53 jkh Exp";
#else
__RCSID("$NetBSD: perform.c,v 1.29 1999/11/29 19:48:46 hubertf Exp $");
__RCSID("$NetBSD: perform.c,v 1.30 2000/01/19 23:28:31 hubertf Exp $");
#endif
#endif
@ -333,5 +333,6 @@ pkg_perform(lpkg_head_t *pkgs)
free_lpkg(lpp);
}
}
ftp_stop();
return err_cnt;
}

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pkg_info.1,v 1.20 2000/01/17 00:48:52 hubertf Exp $
.\" $NetBSD: pkg_info.1,v 1.21 2000/01/19 23:28:31 hubertf Exp $
.\"
.\" FreeBSD install - a package for the installation and maintainance
.\" of non-core utilities.
@ -142,8 +142,7 @@ Show the installation prefix for each package.
Be ``quiet'' in emitting report headers and such, just dump the
raw info (basically, assume a non-human reading).
.It Fl R
Show which packages required by each of the packages given on the
command line.
Show which packages are required by each package.
.It Fl r
Show the requirements script (if any) for each package.
.It Fl S
@ -164,7 +163,7 @@ can be overridden by specifying an alternative directory in the
.Ev PKG_DBDIR
environment variable.
.It Ev PKG_PATH
This can be used to specify a colon-separated list of paths to search for
This can be used to specify a semicolon-separated list of paths and URLs to search for
package files. The current directory is always searched first, even if
.Ev PKG_PATH
is set. If

View File

@ -1,8 +1,9 @@
# $NetBSD: Makefile,v 1.12 1999/03/22 05:02:41 hubertf Exp $
# $NetBSD: Makefile,v 1.13 2000/01/19 23:28:32 hubertf Exp $
# Original from FreeBSD, no rcs id.
LIB= install
SRCS= exec.c file.c global.c lpkg.c pen.c pkgdb.c plist.c str.c
SRCS= exec.c file.c ftpio.c global.c lpkg.c pen.c pkgdb.c \
plist.c str.c
MKLINT= no
MKMAN= no

View File

@ -1,11 +1,11 @@
/* $NetBSD: exec.c,v 1.6 1999/08/24 00:48:39 hubertf Exp $ */
/* $NetBSD: exec.c,v 1.7 2000/01/19 23:28:32 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: exec.c,v 1.6 1997/10/08 07:47:50 charnier Exp";
#else
__RCSID("$NetBSD: exec.c,v 1.6 1999/08/24 00:48:39 hubertf Exp $");
__RCSID("$NetBSD: exec.c,v 1.7 2000/01/19 23:28:32 hubertf Exp $");
#endif
#endif
@ -56,8 +56,8 @@ vsystem(const char *fmt,...)
warnx("vsystem args are too long");
return 1;
}
#ifdef DEBUG
printf("Executing %s\n", cmd);
#ifdef VSYSTEM_DEBUG
printf("vsystem(\"%s\")\n", cmd);
#endif
ret = system(cmd);
va_end(args);

View File

@ -1,11 +1,11 @@
/* $NetBSD: file.c,v 1.35 1999/12/01 14:51:53 hubertf Exp $ */
/* $NetBSD: file.c,v 1.36 2000/01/19 23:28:32 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "from FreeBSD Id: file.c,v 1.29 1997/10/08 07:47:54 charnier Exp";
#else
__RCSID("$NetBSD: file.c,v 1.35 1999/12/01 14:51:53 hubertf Exp $");
__RCSID("$NetBSD: file.c,v 1.36 2000/01/19 23:28:32 hubertf Exp $");
#endif
#endif
@ -40,6 +40,7 @@ __RCSID("$NetBSD: file.c,v 1.35 1999/12/01 14:51:53 hubertf Exp $");
#include <time.h>
#include <fcntl.h>
#if 0
/*
* This is as ftpGetURL from FreeBSD's ftpio.c, except that it uses
* NetBSD's ftp command to do all FTP, which will DTRT for proxies,
@ -83,7 +84,10 @@ ftpGetURL(char *url, int *retcode)
}
}
return ftp;
}
#endif
/*
* Quick check to see if a file (or dir ...) exists
@ -208,7 +212,7 @@ URLlength(char *fname)
}
for (up = urls; up->u_s; up++) {
if (strncmp(fname, up->u_s, up->u_len) == 0) {
return i + up->u_len;
return i + up->u_len; /* ... + sizeof(up->u_s); - HF */
}
}
}
@ -253,7 +257,7 @@ fileURLFilename(char *fname, char *where, int max)
int i;
if ((i = URLlength(fname)) < 0) { /* invalid URL? */
errx(1, "fileURLhost called with a bad URL: `%s'", fname);
errx(1, "fileURLFilename called with a bad URL: `%s'", fname);
}
fname += i;
/* Do we have a place to stick our work? */
@ -284,9 +288,7 @@ fileGetURL(char *base, char *spec)
char *cp, *rp;
char fname[FILENAME_MAX];
char pen[FILENAME_MAX];
FILE *ftp;
pid_t tpid;
int i, status;
int rc;
char *hint;
rp = NULL;
@ -321,12 +323,13 @@ fileGetURL(char *base, char *spec)
}
} else
strcpy(fname, spec);
/* Some sanity checks on the URL */
cp = fileURLHost(fname, host, MAXHOSTNAMELEN);
if (!*cp) {
warnx("URL `%s' has bad host part!", fname);
return NULL;
}
cp = fileURLFilename(fname, file, FILENAME_MAX);
if (!*cp) {
warnx("URL `%s' has bad filename part!", fname);
@ -335,6 +338,8 @@ fileGetURL(char *base, char *spec)
if (Verbose)
printf("Trying to fetch %s.\n", fname);
#if 0
ftp = ftpGetURL(fname, &status);
if (ftp) {
pen[0] = '\0';
@ -363,6 +368,24 @@ fileGetURL(char *base, char *spec)
fname,
status ? "Error while performing FTP" :
hstrerror(h_errno));
#else
pen[0] = '\0';
rp = make_playpen(pen, sizeof(pen), 0);
if (rp == NULL) {
printf("Error: Unable to construct a new playpen for FTP!\n");
return NULL;
}
rp = strdup(pen);
/* printf("fileGetURL: fname='%s', pen='%s'\n", fname, pen); *//*HF*/
rc = unpackURL(fname, pen);
if (rc < 0) {
leave_playpen(rp); /* Don't leave dir hang around! */
printf("Error on unpackURL('%s', '%s')\n", fname, pen);
return NULL;
}
#endif
return rp;
}
@ -378,6 +401,10 @@ fileFindByPath(char *base, char *fname)
static char tmp[FILENAME_MAX];
char *cp;
/* printf("HF: fileFindByPath(\"%s\", \"%s\")\n", base, fname); *//*HF*/
/* The following code won't return a match if base is an URL
* Could save some cycles here - HF */
if (ispkgpattern(fname)) {
if ((cp = findbestmatchingname(".", fname)) != NULL) {
strcpy(tmp, cp);
@ -403,7 +430,28 @@ fileFindByPath(char *base, char *fname)
strcat(cp, "All/");
strcat(cp, fname);
strcat(cp, ".tgz");
if (ispkgpattern(tmp)) {
if (IS_URL(tmp)) {
/* some package depends on a wildcard pkg */
int rc;
char url[FILENAME_MAX];
/* save url to expand, as tmp is the static var in which
* we return the result of the expansion.
*/
strcpy(url, tmp);
/* printf("HF: expandURL('%s')'ing #1\n", url);*//*HF*/
rc = expandURL(tmp, url);
if (rc < 0) {
warnx("fileFindByPath: expandURL('%s') failed\n", url);
return NULL;
}
if (Verbose)
printf("'%s' expanded to '%s'\n", url, tmp);
return tmp; /* return expanded URL w/ corrent pkg */
} else {
cp = findbestmatchingname(dirname_of(tmp), basename_of(tmp));
if (cp) {
char *s;
@ -412,19 +460,80 @@ fileFindByPath(char *base, char *fname)
strcpy(s + 1, cp);
return tmp;
}
}
} else {
if (fexists(tmp)) {
return tmp;
}
}
}
} else {
if (IS_URL(fname)) {
/* Wildcard-URL directly specified on command line */
int rc;
/* printf("HF: expandURL('%s')'ing #2\n", fname);*//*HF*/
rc = expandURL(tmp, fname);
if (rc < 0) {
warnx("fileFindByPath: expandURL('%s') failed\n", fname);
return NULL;
}
if (Verbose)
printf("'%s' expanded to '%s'\n", fname, tmp);
return tmp; /* return expanded URL w/ corrent pkg */
}
}
cp = getenv("PKG_PATH");
while (cp) {
char *cp2 = strsep(&cp, ":");
char *cp2 = strsep(&cp, ";");
printf("trying PKG_PATH %s\n", cp2?cp2:cp);
if (strstr(fname, ".tgz")) {
/* There's already a ".tgz" present, probably typed on the command line */
(void) snprintf(tmp, sizeof(tmp), "%s/%s", cp2 ? cp2 : cp, fname);
} else {
/* Try this component, and tack on a ".tgz" */
(void) snprintf(tmp, sizeof(tmp), "%s/%s.tgz", cp2 ? cp2 : cp, fname);
}
if (IS_URL(tmp)) {
char url[FILENAME_MAX];
int rc;
/* save url to expand, as tmp is the static var in which
* we return the result of the expansion.
*/
strcpy(url, tmp);
/* printf("HF: expandURL('%s')'ing #3\n", url);*//*HF*/
rc = expandURL(tmp, url);
if (rc >= 0) {
printf("fileFindByPath: success, expandURL('%s') returns '%s'\n", url, tmp);
return tmp;
}
/* Second chance - maybe just a package name was given, without
* a version number. Remove the ".tgz" we tacked on above, and
* re-add it with a "-[0-9]*" before. Then see if this matches
* something. See also perform.c.
*/
{
char *s;
s=strstr(tmp, ".tgz");
*s = '\0';
snprintf(url, FILENAME_MAX, "%s-[0-9]*.tgz", tmp);
rc = expandURL(tmp, url);
if (rc >= 0) {
printf("fileFindByPath: late success, expandURL('%s') returns '%s'\n",
url, tmp);
return tmp;
}
}
/* No luck with this parth of PKG_PATH - try next one */
} else {
if (ispkgpattern(tmp)) {
char *s;
s = findbestmatchingname(dirname_of(tmp), basename_of(tmp));
@ -437,6 +546,28 @@ fileFindByPath(char *base, char *fname)
} else {
if (fexists(tmp) && isfile(tmp)) {
return tmp;
}
/* Second chance: seems just a pkg name was given,
* no wildcard, no .tgz. Tack something on and retry.
* (see above, and perform.c)
*/
{
char *s;
char buf2[FILENAME_MAX];
s = strstr(tmp, ".tgz");
*s = '\0';
snprintf(buf2, FILENAME_MAX, "%s-[0-9]*.tgz", tmp);
s = findbestmatchingname(dirname_of(buf2), basename_of(buf2));
if (s) {
char *t;
strcpy(tmp, buf2); /* now we can overwrite it */
t = strrchr(tmp, '/');
strcpy(t+1, s);
return tmp;
}
}
}
}
}

View File

@ -0,0 +1,748 @@
/* $NetBSD: ftpio.c,v 1.7 2000/01/19 23:28:33 hubertf Exp $ */
/* Id: foo2.c,v 1.12 1999/12/17 02:31:57 feyrer Exp feyrer */
/*
* Work to implement wildcard dependency processing via FTP for the
* NetBSD pkg_* package tools.
*
* Copyright (c) 1999 Hubert Feyrer <hubertf@netbsd.org>
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <regex.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <vis.h>
#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;
#if EXPECT_DEBUG
static int expect_debug = 1;
#endif /* EXPECT_DEBUG */
#ifdef STANDALONE
int Verbose=1;
#endif
static int needclose=0;
static int ftp_started=0;
static fds ftpio;
/*
* 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[90];
#if EXPECT_DEBUG
char *vstr;
#endif /* EXPECT_DEBUG */
regex_t rstr;
int done;
struct timeval timeout;
int retval;
regmatch_t pmatch;
int verbose_expect=0;
#if EXPECT_DEBUG
vstr=malloc(2*sizeof(buf));
if (vstr == NULL)
err(1, "expect: malloc() failed");
strvis(vstr, str, VIS_NL|VIS_SAFE|VIS_CSTYLE);
#endif /* EXPECT_DEBUG */
if (regcomp(&rstr, str, REG_EXTENDED) != 0)
err(1, "expect: regcomp() failed");
#if EXPECT_DEBUG
if (expect_debug)
printf("expecting \"%s\" on fd %d ...\n", vstr, fd);
#endif /* EXPECT_DEBUG */
if(0) setbuf(stdout, NULL);
memset(buf, '#', sizeof(buf));
timeout.tv_sec=60;
timeout.tv_usec=0;
done=0;
retval=0;
while(!done) {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
rc = select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
switch (rc) {
case -1:
warn("expect: select() failed (probably ftp died because of bad args)");
done = 1;
retval = -1;
break;
case 0:
warnx("expect: select() timeout!");
done = 1; /* hope that's ok */
retval = -1;
break;
default:
rc=read(fd,&buf[sizeof(buf)-1],1);
if (verbose_expect)
putchar(buf[sizeof(buf)-1]);
#if EXPECT_DEBUG
{
char *v=malloc(2*sizeof(buf));
strvis(v, buf, VIS_NL|VIS_SAFE|VIS_CSTYLE);
if (expect_debug)
printf("expect=<%s>, buf=<%*s>\n", vstr, strlen(v), v);
free(v);
}
#endif /* EXPECT_DEBUG */
if (regexec(&rstr, buf, 1, &pmatch, 0) == 0) {
#if EXPECT_DEBUG
if (expect_debug)
printf("Gotcha -> %s!\n", buf+pmatch.rm_so+1);
fflush(stdout);
#endif /* EXPECT_DEBUG */
if (ftprc && isdigit(buf[pmatch.rm_so+1]))
*ftprc = atoi(buf+pmatch.rm_so+1);
done=1;
retval=0;
}
memmove(buf, buf+1, sizeof(buf)-1); /* yes, this is non-performant */
break;
}
}
#if EXPECT_DEBUG
printf("done.\n");
if (str)
free(vstr);
#endif /* EXPECT_DEBUG */
return retval;
}
/*
* send a certain ftp-command "cmd" to our FTP coprocess, and wait for
* "expectstr" to be returned. Return numeric FTP return code.
*/
static int
ftp_cmd(const char *cmd, const char *expectstr)
{
int rc=0, verbose_ftp=0;
if (Verbose)
verbose_ftp=1;
if (verbose_ftp)
fprintf(stderr, "\nftp> %s", cmd);
fflush(stdout);
rc=write(ftpio.command, cmd, strlen(cmd));
if (rc == strlen(cmd)) {
if (expectstr) {
expect(ftpio.answer, expectstr, &rc);
}
} 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];
rc1 = pipe(command_pipe);
rc2 = pipe(answer_pipe);
if(rc1==-1 || rc2==-1) {
warn("setupCoproc: pipe() failed");
return -1;
}
rc1=fork();
switch (rc1) {
case -1:
/* Error */
warn("setupCoproc: fork() failed");
return -1;
break;
case 0:
/* Child */
close(command_pipe[1]);
dup2(command_pipe[0], 0);
close(command_pipe[0]);
close(answer_pipe[0]);
dup2(answer_pipe[1], 1);
close(answer_pipe[1]);
setbuf(stdout, NULL);
if (Verbose)
fprintf(stderr, "ftp -detv %s\n", base);
rc1 = execl("/usr/bin/ftp", "ftp", "-detv", base, NULL);
warn("setupCoproc: execl() failed");
exit(-1);
break;
default:
/* Parent */
close(command_pipe[0]);
close(answer_pipe[1]);
snprintf(buf, sizeof(buf), "%d", command_pipe[1]);
setenv(PKG_FTPIO_COMMAND, buf, 1);
snprintf(buf, sizeof(buf), "%d", answer_pipe[0]);
setenv(PKG_FTPIO_ANSWER, buf, 1);
ftpio.command = command_pipe[1];
ftpio.answer = answer_pipe[0];
fcntl(ftpio.command, F_SETFL, O_NONBLOCK);
fcntl(ftpio.answer , F_SETFL, O_NONBLOCK);
break;
}
return 0;
}
/*
* 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)
{
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 Goodbye.|Not connected.)\n");
close(ftpio.command);
close(ftpio.answer);
}
unsetenv(PKG_FTPIO_COMMAND);
unsetenv(PKG_FTPIO_ANSWER);
}
/*
* (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.
*/
static int
ftp_start(char *base)
{
char *tmp1, *tmp2;
int rc;
char newHost[256];
char newDir[1024];
char *currentHost=getenv(PKG_FTPIO_CURRENTHOST);
char *currentDir=getenv(PKG_FTPIO_CURRENTDIR);
fileURLHost(base, newHost, sizeof(newHost));
strcpy(newDir, strchr(base+URLlength(base), '/') + 1);
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_stgart: 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);
if ((expect(ftpio.answer, "\n(221|250|221|550).*\n", &rc) != 0)
|| rc != 250) {
warnx("expect1 failed, rc=%d", rc);
return -1;
}
rc = ftp_cmd("prompt off\n", "\n(Interactive mode off|221).*\n");
if (rc == 221) {
/* something is wrong */
ftp_started=1; /* not really, but for ftp_stop() */
ftp_stop();
}
ftp_started=1;
} else {
/* get FDs of our coprocess */
ftpio.command = dup(atoi(tmp1));
ftpio.answer = dup(atoi(tmp2));
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 *pkg;
int rc;
char base[FILENAME_MAX];
pkg=strrchr(wildcardurl, '/');
if (pkg == NULL){
warnx("expandURL: no '/' in url %s?!", wildcardurl);
return -1;
}
snprintf(base, FILENAME_MAX, "%*.*s/", pkg-wildcardurl, pkg-wildcardurl, wildcardurl);
pkg++;
rc = ftp_start(base);
if (rc == -1) {
warnx("ftp_start() failed");
return -1; /* error */
}
/* for a given wildcard URL, find the best matching pkg */
{
char *s, buf[FILENAME_MAX];
char tmpname[FILENAME_MAX];
char best[FILENAME_MAX];
strcpy(tmpname, "/tmp/pkg.XXX");
mktemp(tmpname);
assert(tmpname != NULL);
s=strpbrk(pkg, "<>[]?*{"); /* 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.
*/
snprintf(buf,FILENAME_MAX, "ls %s %s\n", pkg, 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 pmatch() */
snprintf(buf, FILENAME_MAX, "ls %*.*s*.tgz %s\n", s-pkg, s-pkg, pkg, tmpname);
}
rc = ftp_cmd(buf, "\n(550|226).*\n"); /* catch errors */
if (rc != 226) {
if (Verbose)
warnx("ls failed!");
return -1;
}
/* Sync - don't remove */
rc = ftp_cmd("cd .\n", "\n(550|250).*\n");
if (rc != 250) {
warnx("chdir failed!");
return -1;
}
best[0]='\0';
if (access(tmpname, R_OK)==0) {
int matches;
FILE *f;
char filename[FILENAME_MAX];
f=fopen(tmpname, "r");
if (f == NULL) {
warn("fopen");
return -1;
}
matches=0;
/* The following loop is basically the same as the readdir() loop
* in findmatchingname() */
while (fgets(filename, FILENAME_MAX, f)) {
filename[strlen(filename)-1] = '\0';
if (pmatch(pkg, filename)) {
matches++;
/* compare findbestmatchingname() */
findbestmatchingname_fn(filename, best);
}
}
fclose(f);
if (matches == 0)
warnx("nothing appropriate found\n");
}
unlink(tmpname);
if (best[0] != '\0') {
if (Verbose)
printf("best match: '%s%s'\n", base, best);
sprintf(expandedurl, "%s%s", base, best);
}
}
return 0;
}
/*
* 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[FILENAME_MAX];
char pkg_path[FILENAME_MAX];
{
/* Verify if the url is really ok */
int rc;
char exp[FILENAME_MAX];
rc=expandURL(exp, url);
if (rc == -1) {
warnx("unpackURL: verification expandURL failed");
return -1;
}
if (strcmp(exp, url) != 0) {
warnx("unpackURL: verificatinon expandURL failed, '%s'!='%s'",
exp, url);
return -1;
}
}
pkg=strrchr(url, '/');
if (pkg == NULL){
warnx("unpackURL: no '/' in url %s?!", url);
return -1;
}
snprintf(base, FILENAME_MAX, "%*.*s/", pkg-url, pkg-url, url);
snprintf(pkg_path, FILENAME_MAX, "%*.*s", pkg-url, 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);
printf("setenv PKG_PATH='%s'\n",pkg_path);
}
rc = ftp_start(base);
if (rc == -1) {
warnx("ftp_start() failed");
return -1; /* error */
}
{
char cmd[1024];
if (Verbose)
printf("unpackURL '%s' to '%s'\n", url, dir);
/* yes, this is gross, but needed for borken ftp(1) */
snprintf(cmd, sizeof(cmd), "get %s \"| ( cd %s ; gunzip 2>/dev/null | tar -%sx -f - )\"\n", pkg, dir, Verbose?"vv":"");
rc = ftp_cmd(cmd, "\n(226|550).*\n");
if (rc != 226) {
warnx("Cannot fetch file (%d!=226)!", rc);
return -1;
}
}
return 0;
}
#if 0
/*
* Some misc stuff not needed yet, but maybe later
*/
int
miscstuff(const char *url)
{
char *pkg;
int rc;
char base[FILENAME_MAX];
pkg=strrchr(url, '/');
if (pkg == NULL){
warnx("miscstuff: no '/' in url %s?!", url);
return -1;
}
snprintf(base, FILENAME_MAX, "%*.*s/", pkg-url, pkg-url, url);
pkg++;
rc = ftp_start(base);
if (rc == -1) {
warnx("ftp_start() failed");
return -1; /* error */
}
/* basic operation */
if (0) {
rc = ftp_cmd("cd ../All\n", "\n(550|250).*\n");
if (rc != 250) {
warnx("chdir failed!");
return -1;
}
}
/* get and extract a file to tmpdir */
if (0) {
char cmd[256];
char tmpdir[256];
snprintf(tmpdir, sizeof(tmpdir), "/tmp/dir%s",
(getenv(PKG_FTPIO_CNT))?getenv(PKG_FTPIO_CNT):"");
mkdir(tmpdir, 0755);
/* yes, this is gross, but needed for borken ftp(1) */
snprintf(cmd, sizeof(cmd), "get xpmroot-1.01.tgz \"| ( cd %s ; gunzip 2>/dev/null | tar -vvx -f - )\"\n", tmpdir);
rc = ftp_cmd(cmd, "\n(226|550).*\n");
if (rc != 226) {
warnx("Cannot fetch file (%d != 226)!", rc);
return -1;
}
}
/* check if one more file(s) exist */
if (0) {
char buf[FILENAME_MAX];
snprintf(buf,FILENAME_MAX, "ls %s /tmp/xxx\n", pkg);
rc = ftp_cmd(buf, "\n(226|550).*\n"); /* catch errors */
if (rc != 226) {
if (Verbose)
warnx("ls failed!");
return -1;
}
/* Sync - don't remove */
rc = ftp_cmd("cd .\n", "\n(550|250).*\n");
if (rc != 250) {
warnx("chdir failed!");
return -1;
}
if (access("/tmp/xxx", R_OK)==0) {
system("cat /tmp/xxx");
{
/* count lines - >0 -> fexists() == true */
int len, count;
FILE *f;
f=fopen("/tmp/xxx", "r");
if (f == NULL) {
warn("fopen");
return -1;
}
count=0;
while (fgetln(f, &len))
count++;
fclose(f);
printf("#lines = %d\n", count);
}
} else
printf("NO MATCH\n");
unlink("/tmp/xxx");
}
/* for a given wildcard URL, find the best matching pkg */
/* spawn child - like pkg_add'ing another package */
/* Here's where the connection caching kicks in */
#if 0
if (0) {
char *s, buf[FILENAME_MAX];
if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){
snprintf(buf,FILENAME_MAX,"%d", atoi(s)-1);
setenv(PKG_FTPIO_CNT, buf, 1);
snprintf(buf, FILENAME_MAX, "%s \"%s/%s\"", argv0, url, pkg);
printf("%s>>> %s\n", s, buf);
system(buf);
}
}
#endif
return 0;
}
#endif
#ifdef STANDALONE
static void
usage(void)
{
errx(1, "Usage: foo [-v] ftp://-pattern\n");
}
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[FILENAME_MAX];
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[FILENAME_MAX];
if ((s=getenv(PKG_FTPIO_CNT)) && atoi(s)>0){
snprintf(buf,FILENAME_MAX,"%d", atoi(s)-1);
setenv(PKG_FTPIO_CNT, buf, 1);
snprintf(buf, FILENAME_MAX, "%s -v '%s'", argv0, argv[0]);
printf("%s>>> %s\n", s, buf);
system(buf);
}
}
printf("\n\n\n");
argv++;
}
ftp_stop();
return 0;
}
#endif /* STANDALONE */

View File

@ -1,4 +1,4 @@
/* $NetBSD: lib.h,v 1.28 1999/11/29 20:09:56 hubertf Exp $ */
/* $NetBSD: lib.h,v 1.29 2000/01/19 23:28:33 hubertf Exp $ */
/* from FreeBSD Id: lib.h,v 1.25 1997/10/08 07:48:03 charnier Exp */
@ -180,7 +180,8 @@ void str_lowercase(char *);
char *basename_of(char *);
char *dirname_of(const char *);
int pmatch(const char *, const char *);
int findmatchingname(const char *, const char *, matchfn, char *); /* doesn't really belong here */
int findmatchingname(const char *, const char *, matchfn, char *); /* doesn't really belong to "strings" */
int findbestmatchingname_fn(const char *pkg, char *data); /* neither */
char *findbestmatchingname(const char *, const char *); /* neither */
int ispkgpattern(const char *);
char *strnncpy(char *to, size_t tosize, char *from, size_t cc);
@ -207,6 +208,11 @@ int delete_hierarchy(char *, Boolean, Boolean);
int unpack(char *, char *);
void format_cmd(char *, size_t, char *, char *, char *);
/* ftpio.c: FTP handling */
int expandURL(char *expandedurl, const char *wildcardurl);
int unpackURL(const char *url, const char *dir);
void ftp_stop(void);
/* Packing list */
plist_t *new_plist_entry(void);
plist_t *last_plist(package_t *);

View File

@ -1,11 +1,11 @@
/* $NetBSD: str.c,v 1.18 1999/12/01 14:51:53 hubertf Exp $ */
/* $NetBSD: str.c,v 1.19 2000/01/19 23:28:34 hubertf Exp $ */
#include <sys/cdefs.h>
#ifndef lint
#if 0
static const char *rcsid = "Id: str.c,v 1.5 1997/10/08 07:48:21 charnier Exp";
#else
__RCSID("$NetBSD: str.c,v 1.18 1999/12/01 14:51:53 hubertf Exp $");
__RCSID("$NetBSD: str.c,v 1.19 2000/01/19 23:28:34 hubertf Exp $");
#endif
#endif
@ -306,8 +306,9 @@ ispkgpattern(const char *pkg)
/*
* Auxiliary function called by findbestmatchingname() if pkg > data
* Also called for FTP matching
*/
static int
int
findbestmatchingname_fn(const char *pkg, char *data)
{
char *s1, *s2;