379 lines
9.4 KiB
C
379 lines
9.4 KiB
C
/* $NetBSD: functions.c,v 1.13 2005/05/07 22:43:21 wiz Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Copyright (c) 2000 Tim Rightnour <garbled@NetBSD.org>
|
|
* Copyright (c) 2000 Hubert Feyrer <hubertf@NetBSD.org>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "sushi.h"
|
|
#include "functions.h"
|
|
|
|
#ifndef NETBSD_PKG_BASE
|
|
#define NETBSD_PKG_BASE "ftp://ftp.NetBSD.org/pub/NetBSD/packages"
|
|
#endif
|
|
|
|
extern int scripting;
|
|
extern int logging;
|
|
extern FILE *logfile;
|
|
extern FILE *script;
|
|
extern nl_catd catalog;
|
|
|
|
char *ftp_base(int);
|
|
void cleanup(void);
|
|
|
|
/* Required by libinstall */
|
|
void cleanup(void){ ; }
|
|
int ftp_cmd(const char *, const char *);
|
|
void ftp_stop(void);
|
|
|
|
func_record func_map[] =
|
|
{
|
|
{ "ftp_pkglist", ftp_pkglist },
|
|
{ "ftp_pkgcats", ftp_pkgcats },
|
|
{ "script_do", script_do },
|
|
{ "log_do", log_do },
|
|
{(char *)NULL, (char **(*)(char *))NULL},
|
|
};
|
|
|
|
/*ARGSUSED*/
|
|
char **
|
|
log_do(char *what)
|
|
{
|
|
int i;
|
|
time_t tloc;
|
|
|
|
i = logging;
|
|
|
|
if (logging == 1)
|
|
logging = 0;
|
|
else if (logging == 0)
|
|
logging = 1;
|
|
|
|
time(&tloc);
|
|
|
|
if (logging && i == 0) { /* open */
|
|
logfile = fopen(LOGFILE_NAME, "w");
|
|
if (logfile == NULL)
|
|
bailout("fopen %s: %s", LOGFILE_NAME, strerror(errno));
|
|
fprintf(logfile, "%s: %s\n",
|
|
catgets(catalog, 4, 3, "Log started at"),
|
|
asctime(localtime(&tloc)));
|
|
fflush(logfile);
|
|
} else { /* close */
|
|
if (logfile == NULL)
|
|
bailout("fopen %s: %s", LOGFILE_NAME, strerror(errno));
|
|
fprintf(logfile, "%s: %s\n",
|
|
catgets(catalog, 4, 10, "Log ended at"),
|
|
asctime(localtime(&tloc)));
|
|
fflush(logfile);
|
|
fclose(logfile);
|
|
}
|
|
return (NULL); /* XXX */
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
char **
|
|
script_do(char *what)
|
|
{
|
|
int i;
|
|
time_t tloc;
|
|
|
|
i = scripting;
|
|
|
|
if (scripting == 0)
|
|
scripting = 1;
|
|
else if (scripting == 1)
|
|
scripting = 0;
|
|
|
|
time(&tloc);
|
|
|
|
if (scripting && i == 0) { /* open */
|
|
script = fopen(SCRIPTFILE_NAME, "w");
|
|
if (script == NULL)
|
|
bailout("fopen %s: %s", SCRIPTFILE_NAME,
|
|
strerror(errno));
|
|
fprintf(script, "#!/bin/sh\n");
|
|
fprintf(script, "# %s: %s\n",
|
|
catgets(catalog, 4, 4, "Script started at"),
|
|
asctime(localtime(&tloc)));
|
|
fflush(script);
|
|
} else { /* close */
|
|
if (script == NULL)
|
|
bailout("fopen %s: %s", SCRIPTFILE_NAME,
|
|
strerror(errno));
|
|
fprintf(script, "# %s: %s\n",
|
|
catgets(catalog, 4, 11, "Script ended at"),
|
|
asctime(localtime(&tloc)));
|
|
fflush(script);
|
|
fclose(script);
|
|
}
|
|
return (NULL); /* XXX */
|
|
}
|
|
|
|
/*
|
|
* Return list of packages available at the given URL
|
|
* or NULL on error. Returned pointer can be free(3)d
|
|
* later.
|
|
*/
|
|
char **
|
|
ftp_pkglist(char *subdir)
|
|
{
|
|
int rc, tfd;
|
|
char tmpname[FILENAME_MAX];
|
|
char buf[FILENAME_MAX];
|
|
char url[FILENAME_MAX];
|
|
char **list;
|
|
FILE *f;
|
|
int nlines;
|
|
|
|
extern int ftp_start(char *); /* pkg_install/lib stuff */
|
|
extern int Verbose; /* pkg_install/lib stuff */
|
|
Verbose = 0; /* debugging */
|
|
|
|
/* ftp(1) must have a trailing '/' for directories */
|
|
snprintf(url, sizeof(url), "%s/%s/", ftp_base(0), subdir);
|
|
|
|
/*
|
|
* Start FTP coprocess
|
|
*/
|
|
rc = ftp_start(url);
|
|
if (rc == -1)
|
|
bailout(catgets(catalog, 1, 3, "ftp_start failed"));
|
|
|
|
/*
|
|
* Generate tmp file
|
|
*/
|
|
strlcpy(tmpname, TMPFILE_NAME, sizeof(tmpname));
|
|
tfd = mkstemp(tmpname);
|
|
if (tfd == -1)
|
|
bailout("mkstemp: %s", strerror(errno));
|
|
|
|
close(tfd); /* We don't need the file descriptor, but will use
|
|
the file in a second */
|
|
/*
|
|
* Setup & run the command for ftp(1)
|
|
*/
|
|
(void)snprintf(buf, sizeof(buf), "nlist *.tgz %s\n", tmpname);
|
|
rc = ftp_cmd(buf, "\n(550|226).*\n"); /* catch errors */
|
|
if (rc != 226) {
|
|
unlink(tmpname); /* remove clutter */
|
|
bailout(catgets(catalog, 1, 4, "nlist failed"));
|
|
}
|
|
|
|
f = fopen(tmpname, "r");
|
|
if (f == NULL)
|
|
bailout("fopen: %s", strerror(errno));
|
|
|
|
/* Read through file once to find out how many lines it has */
|
|
nlines = 0;
|
|
while (fgets(buf, sizeof(buf), f) != NULL)
|
|
nlines++;
|
|
rewind(f);
|
|
|
|
list = malloc((nlines + 1) * sizeof(char *));
|
|
if (list == NULL)
|
|
bailout("malloc: %s", strerror(errno));
|
|
|
|
/* alloc space for each line now */
|
|
nlines = 0;
|
|
while (fgets(buf, sizeof(buf), f) != NULL) {
|
|
list[nlines] = strdup(buf);
|
|
/* XXX 5 to get .tgz */
|
|
list[nlines][strlen(list[nlines])-5] = '\0';
|
|
nlines++;
|
|
}
|
|
list[nlines] = NULL;
|
|
|
|
fclose(f);
|
|
unlink(tmpname);
|
|
|
|
/*
|
|
* Stop FTP coprocess
|
|
*/
|
|
ftp_stop();
|
|
|
|
return (list);
|
|
}
|
|
|
|
/*
|
|
* Return list of package categories available at the given URL
|
|
* or NULL on error. Returned pointer can be free(3)d
|
|
* later.
|
|
*/
|
|
/* ARGSUSED */
|
|
char **
|
|
ftp_pkgcats(char *subdir)
|
|
{
|
|
int rc, tfd;
|
|
char tmpname[FILENAME_MAX];
|
|
char buf[FILENAME_MAX];
|
|
char url[FILENAME_MAX];
|
|
char **list;
|
|
FILE *f;
|
|
int nlines;
|
|
|
|
extern int ftp_start(char *); /* pkg_install/lib stuff */
|
|
extern int Verbose; /* pkg_install/lib stuff */
|
|
Verbose = 0; /* debugging */
|
|
|
|
/* ftp(1) must have a trailing '/' for directories */
|
|
snprintf(url, sizeof(url), "%s/", ftp_base(0));
|
|
|
|
/*
|
|
* Start FTP coprocess
|
|
*/
|
|
rc = ftp_start(url);
|
|
if (rc == -1)
|
|
bailout(catgets(catalog, 1, 3, "ftp_start failed"));
|
|
|
|
/*
|
|
* Generate tmp file
|
|
*/
|
|
strlcpy(tmpname, TMPFILE_NAME, sizeof(tmpname));
|
|
tfd = mkstemp(tmpname);
|
|
if (tfd == -1)
|
|
bailout("mkstemp: %s", strerror(errno));
|
|
|
|
close(tfd); /* We don't need the file descriptor, but will use
|
|
the file in a second */
|
|
/*
|
|
* Setup & run the command for ftp(1)
|
|
*/
|
|
(void)snprintf(buf, sizeof(buf), "ls -1F %s\n", tmpname);
|
|
rc = ftp_cmd(buf, "\n(550|226).*\n"); /* catch errors */
|
|
if (rc != 226) {
|
|
unlink(tmpname); /* remove clutter */
|
|
bailout(catgets(catalog, 1, 4, "nlist failed"));
|
|
}
|
|
|
|
f = fopen(tmpname, "r");
|
|
if (f == NULL)
|
|
bailout("fopen: %s", strerror(errno));
|
|
|
|
/* Read through file once to find out how many lines it has */
|
|
nlines = 0;
|
|
while (fgets(buf, sizeof(buf), f) != NULL)
|
|
nlines++;
|
|
rewind(f);
|
|
|
|
list = malloc((nlines + 1) * sizeof(char *));
|
|
if (list == NULL)
|
|
bailout("malloc: %s", strerror(errno));
|
|
|
|
/* alloc space for each line now */
|
|
nlines = 0;
|
|
while (fgets(buf, sizeof(buf), f) != NULL) {
|
|
if (buf[strlen(buf) - 2] == '/') {
|
|
list[nlines] = malloc(strlen(buf) - 1);
|
|
if (list[nlines] == NULL)
|
|
bailout("malloc: %s", strerror(errno));
|
|
strlcpy(list[nlines], buf, strlen(buf) - 1);
|
|
nlines++;
|
|
}
|
|
}
|
|
list[nlines] = NULL;
|
|
|
|
fclose(f);
|
|
unlink(tmpname);
|
|
|
|
/*
|
|
* Stop FTP coprocess
|
|
*/
|
|
ftp_stop();
|
|
|
|
return (list);
|
|
}
|
|
|
|
/*
|
|
* Return patch where binary packages for this OS version/arch
|
|
* are expected. If mirror is NULL, ftp.NetBSD.org is used.
|
|
* If it's set, it's assumed to be the URL where the OS version
|
|
* dirs are, e.g. ftp://ftp.NetBSD.org/pub/NetBSD/packages.
|
|
* If $PKG_PATH is set, is returned unchanged, overriding everything.
|
|
* In any case, a trailing '/' is *not* passed.
|
|
* See also Appendix C of /usr/pkgsrc/doc/pkgsrc.txt.
|
|
*
|
|
* The returned pointer will be overwritten on next call of
|
|
* this function.
|
|
*/
|
|
char *
|
|
ftp_base(int truename)
|
|
{
|
|
char *pkg_path, *p;
|
|
struct utsname un;
|
|
static char buf[256];
|
|
int rc;
|
|
|
|
pkg_path = getenv("PKG_PATH");
|
|
if (pkg_path != NULL)
|
|
return (pkg_path);
|
|
|
|
strlcpy(buf, NETBSD_PKG_BASE, sizeof(buf));
|
|
|
|
rc = uname(&un);
|
|
if (rc == -1)
|
|
bailout("uname: %s", strerror(errno));
|
|
|
|
strlcat(buf, "/", sizeof(buf));
|
|
if (!truename) {
|
|
if ((p = strchr(un.release, '_')) != NULL) {
|
|
/* -stable or -rc, e.g. 2.0_STABLE */
|
|
*p = '\0';
|
|
} else if ((p = strstr(un.release, "99.")) != NULL) {
|
|
/* -current, e.g. 2.99.14 */
|
|
*p++ = '0';
|
|
*p = '\0';
|
|
} else if (strspn(un.release, ".") > 1) {
|
|
/* security release, e.g. 2.0.1 */
|
|
p = strrchr(un.release, '.');
|
|
*p = '\0';
|
|
}
|
|
}
|
|
strlcat(buf, un.release, sizeof(buf));
|
|
strlcat(buf, "/", sizeof(buf));
|
|
strlcat(buf, un.machine, sizeof(buf)); /* sysctl hw.machine_arch? */
|
|
|
|
return (buf);
|
|
}
|