freebsd-dev/usr.sbin/pkg_manage/pkg_manage.c
1995-06-11 19:33:05 +00:00

539 lines
12 KiB
C

/***************************************************************
*
* Program: pkg_manage.c
* Author: Marc van Kempen
* Desc: Add, delete packages with the pkg_* binaries
* Get info about installed packages
* Review about to be installed packages
*
* 1. View installed packages
* 2. Delete installed packages
* 3. Preview package install
* 4. Install packages
*
* Copyright (c) 1995, Marc van Kempen
*
* All rights reserved.
*
* This software may be used, modified, copied, distributed, and
* sold, in both source and binary form provided that the above
* copyright and these terms are retained, verbatim, as the first
* lines of this file. Under no circumstances is the author
* responsible for the proper functioning of this software, nor does
* the author assume any responsibility for damages incurred with
* its use.
*
***************************************************************/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include "pkg_manage.h"
#include "ui_objects.h"
#include "dialog.priv.h"
#include "dir.h"
PKG_info p_inf = { 0, 0, NULL, NULL, NULL, NULL, NULL };
/*******************************************************************
*
* Misc Functions
*
*******************************************************************/
void
FreeInfo(void)
/*
* Desc: free the space allocated to p_inf
*/
{
int i;
free(p_inf.buf);
free(p_inf.name);
free(p_inf.comment);
free(p_inf.description);
p_inf.Nitems = 0;
for (i=0; i<2*p_inf.Nitems; i++) {
free(p_inf.mnu[i]);
}
free(p_inf.mnu);
return;
} /* FreeInfo() */
int
file_exists(char *fname)
/*
* Desc: check if the file <fname> exists (and is readable)
*/
{
FILE *f;
if (strlen(fname) == 0) return(FALSE); /* apparently opening an empty */
/* file for reading succeeds always */
f = fopen(fname, "r");
if (f) {
fclose(f);
return(TRUE);
} else {
return(FALSE);
}
} /* file_exists() */
int
exec_catch_errors(char *prog, char *arg, char *fout)
/*
* Desc: run the program <prog> with arguments <arg> and catch its output
* in <fout> and display it in case of an error. specify NULL,
* if you don't want output.
*/
{
char *execstr, *tmp, msg[MAXPATHLEN];
int ret, yesno, unlink_fout;
execstr = (char *) malloc( strlen(prog) + strlen(arg) + 30 );
if (!execstr) {
fprintf(stderr, "exec_catch_errors: Error while mallocing memory\n");
exit(-1);
}
/* when fout == NULL, allocate a temporary file name and unlink it */
/* when done */
if (!fout) {
fout = tempnam(NULL, "pkg.");
if (!fout) {
fprintf(stderr, "exec_catch_errors: Error allocating temp.name\n");
exit(-1);
}
unlink_fout = TRUE;
} else {
unlink_fout = FALSE;
}
sprintf(execstr, "%s %s > %s 2>&1", prog, arg, fout);
ret = system(execstr);
if (ret) {
yesno = dialog_yesno("Error", "An error occured, view output?", 8, 40);
if (yesno == 0) {
/* disable helpline */
tmp = get_helpline();
use_helpline("use arrowkeys, PgUp, PgDn to move, press enter when done");
sprintf(msg, "Error output from %s", prog);
dialog_textbox(msg, fout, LINES-2, COLS-4);
restore_helpline(tmp);
}
}
if (unlink_fout) {
unlink(fout);
free(fout);
}
free(execstr);
return(ret);
} /* exec_catch_errors() */
void
get_pkginfo(void)
/*
* Desc: get info about installed packages
*/
{
FILE *f;
char *p;
struct stat sb;
int i, j, n, lsize;
int newline, ret;
int state;
char *tmp_file;
#define R_NAME 1
#define R_COMMENT 2
#define R_DESC 3
if (p_inf.Nitems > 0) {
FreeInfo();
}
/* p_inf.Nitems == 0 */
dialog_msgbox("PKG INFO", "Reading info, please wait ...", 4, 35, FALSE);
tmp_file = tempnam(NULL, "pkg.");
ret = exec_catch_errors(PKG_INFO, "-a", tmp_file);
if (ret) {
dialog_notify("Could not get package info\nexiting!");
unlink(tmp_file);
free(tmp_file);
return;
}
dialog_clear_norefresh();
f = fopen(tmp_file, "r");
if (!f) {
dialog_notify("Could not open temporary file");
unlink(tmp_file);
free(tmp_file);
return;
}
if (stat(tmp_file, &sb)) { /* stat file to get filesize */
dialog_notify("Could not stat temporary file");
fclose(f);
unlink(tmp_file);
free(tmp_file);
return;
}
if (sb.st_size == 0) {
#if 0
dialog_notify("No packages installed or no info available");
#endif
fclose(f);
unlink(tmp_file);
free(tmp_file);
return;
}
/* Allocate a buffer with sufficient space to hold the entire file */
p_inf.buf = (char *) malloc( sb.st_size + 1);
p_inf.N = sb.st_size;
if (fread(p_inf.buf, 1, p_inf.N, f) != p_inf.N) {
dialog_notify("Could not read entire temporary file");
free(p_inf.buf);
fclose(f);
unlink(tmp_file);
free(tmp_file);
return;
}
p_inf.buf[p_inf.N] = 0;
fclose(f);
unlink(tmp_file);
free(tmp_file);
/* make one sweep through the buffer to determine the # of entries */
/* Look for "Information for" in the first column */
i = p_inf.N - strlen("Information for") - 1;
p = p_inf.buf;
if (strncmp(p_inf.buf, "Information for", 15) == 0) {
n = 1;
} else {
n = 0;
}
while (i-- > 0) {
if (*p == '\n') {
if (strncmp(p+1, "Information for", 15) == 0) {
n++;
}
}
p++;
}
/* malloc space for PKG_info */
p_inf.name = (char **) malloc( n * sizeof(char *) );
p_inf.comment = (char **) malloc( n * sizeof(char *) );
p_inf.description = (char **) malloc( n * sizeof(char *) );
p_inf.Nitems = n;
/* parse pkg_info output */
/* use a finite state automate to parse the file */
i = 0;
p = p_inf.buf;
newline = TRUE;
state = R_NAME;
while (*p) {
if (newline) {
newline = FALSE;
switch(state) {
case R_NAME:
if (strncmp(p, "Information for", 15) == 0) {
if (p>p_inf.buf) *(p-1) = '\0';
p_inf.name[i] = (char *) p+16;
while (*p && *p != ':') p++;
if (*p) *p = '\0';
state = R_COMMENT;
}
break;
case R_COMMENT:
if (strncmp(p, "Comment:", 8) == 0) {
while (*p && *p != '\n') p++;
if (*p) p_inf.comment[i] = (char *) p+1;
p++;
while (*p && *p != '\n') p++;
if (*p) {
*p = '\0';
newline = TRUE;
}
state = R_DESC;
}
break;
case R_DESC:
if (strncmp(p, "Description:", 12) == 0) {
while (*p && *p != '\n') p++;
if (*p) {
p_inf.description[i] = (char *) p+1;
newline = TRUE;
}
state = R_NAME;
i++;
}
break;
}
}
if (*p == '\n') newline = TRUE;
p++;
}
/* build menu entries */
p_inf.mnu = (unsigned char **) malloc( 2 * p_inf.Nitems * sizeof(char *) );
lsize = COLS-30;
j=0;
for (i=0; i<p_inf.Nitems; i++) {
/* tag */
p_inf.mnu[j] = (char *) malloc( lsize );
strncpy(p_inf.mnu[j], p_inf.name[i], lsize-1);
p_inf.mnu[j++][lsize-1] = 0;
/* description */
p_inf.mnu[j] = (char *) malloc( lsize );
strncpy(p_inf.mnu[j], p_inf.comment[i], lsize-1);
p_inf.mnu[j++][lsize-1] = 0;
}
return;
} /* get_pkginfo() */
int
get_pkg_index(char *selection)
/*
* desc: get the index i, for which p_inf.name[i] == selection
*/
{
int i, found = FALSE, index = -1;
for (i=0; i<p_inf.Nitems && !found; i++) {
if (strcmp(selection, p_inf.name[i]) == 0) {
found = TRUE;
index = i;
}
}
return(index);
} /* get_pkg_index() */
void
install_package(char *fname)
/*
* Desc: install the package <fname>
*/
{
char *tmp_file;
tmp_file = tempnam(NULL, "pkg.");
if (!tmp_file) {
fprintf(stderr, "install_package(): Error malloc'ing tmp_file\n");
exit(-1);
}
exec_catch_errors(PKG_ADD, fname, tmp_file);
unlink(tmp_file);
free(tmp_file);
return;
} /* install_package() */
int
get_desc(char *fname, char **name, char **comment,
char **desc, long *size, char *tmp_dir)
/*
* Desc: get the description and comment from the files
* DESC, CONTENT and COMMENT from fname
* Pre: the current working directory is a temporary,
* empty directory.
* Post: name = the name of the package
* comment = the comment for the package
* desc = the description for the package
*/
{
char msg[80], args[512], *buf, *p, tmp[MAXPATHLEN];
FILE *f, *pf;
struct stat sb;
int i, N, ret, found;
*comment = NULL;
*desc = NULL;
*name = NULL;
sprintf(args, "--fast-read -zxvf %s -C %s %s %s %s", fname,
tmp_dir, CONTENTS, DESC, COMMENT);
ret = exec_catch_errors(TAR, args, NULL);
if (ret) {
sprintf(msg, "Could not get info for <%s>", fname);
dialog_notify(msg);
return(FALSE);
}
/* Read CONTENTS */
sprintf(tmp, "%s/%s", tmp_dir, CONTENTS);
f = fopen(tmp, "r");
if (f == NULL) {
/* No contents file in package, propably not a package */
return(FALSE);
}
if (stat(tmp, &sb)) { /* stat file to get filesize */
dialog_notify("Could not stat CONTENTS file");
fclose(f);
return(FALSE);
}
if (sb.st_size == 0) {
dialog_notify("CONTENTS file has zero length");
fclose(f);
return(FALSE);
}
/* Allocate a buffer with sufficient space to hold the entire file */
buf = (char *) malloc( sb.st_size + 1);
N = sb.st_size;
if (fread(buf, 1, N, f) != N) {
sprintf(msg, "Could not read CONTENT file for <%s>", fname);
dialog_notify(msg);
free(buf);
fclose(f);
return(FALSE);
}
fclose(f);
buf[N] = 0;
/* look for the name of the package */
p = buf;
found = FALSE;
while (*p && !found) {
if (strncmp(p, "@name ", 6) == 0) {
i=0;
p += 6;
while (*p && p[i] != '\n' && p[i] != '\r') i++;
*name = (char *) malloc( i+1 );
strncpy(*name, p, i);
(*name)[i] = 0;
found = TRUE;
} else {
p++;
}
}
unlink(tmp);
/* Read COMMENT file */
sprintf(tmp, "%s/%s", tmp_dir, COMMENT);
f = fopen(tmp, "r");
if (f == NULL) {
/* No comment file in package, propably not a package */
return(FALSE);
}
if (stat(tmp, &sb)) { /* stat file to get filesize */
dialog_notify("Could not stat COMMENT file");
fclose(f);
return(FALSE);
}
if (sb.st_size == 0) {
dialog_notify("COMMENT file has zero length");
fclose(f);
return(FALSE);
}
/* Allocate a buffer with sufficient space to hold the entire file */
*comment = (char *) malloc( sb.st_size + 1);
N = sb.st_size;
if (fread(*comment, 1, N, f) != N) {
sprintf(msg, "Could not read COMMENT file for <%s>", fname);
dialog_notify(msg);
free(*comment);
fclose(f);
return(FALSE);
}
fclose(f);
(*comment)[N] = 0;
unlink(tmp);
/* Read DESC */
sprintf(tmp, "%s/%s", tmp_dir, DESC);
f = fopen(tmp, "r");
if (f == NULL) {
/* No description file in package, propably not a package */
return(FALSE);
}
if (stat(tmp, &sb)) { /* stat file to get filesize */
dialog_notify("Could not stat DESC file");
fclose(f);
return(FALSE);
}
if (sb.st_size == 0) {
dialog_notify("DESC file has zero length");
fclose(f);
return(FALSE);
}
/* Allocate a buffer with sufficient space to hold the entire file */
*desc = (char *) malloc( sb.st_size + 1);
N = sb.st_size;
if (fread(*desc, 1, N, f) != N) {
sprintf(msg, "Could not read CONTENT file for <%s>", fname);
dialog_notify(msg);
free(*desc);
fclose(f);
return(FALSE);
}
fclose(f);
(*desc)[N] = 0;
unlink(tmp);
/* get the size from the uncompressed package */
sprintf(tmp, "%s -l %s", GUNZIP, fname);
pf = popen(tmp, "r");
if (!pf) {
dialog_notify("Could not popen gunzip to get package size");
*size = 0;
} else {
while (!feof(pf)) {
fgets(tmp, 80, pf);
}
sscanf(tmp, "%*s %ld", size);
pclose(pf);
}
if (found) {
return(TRUE);
} else {
return(FALSE);
}
} /* get_desc() */
int
already_installed(char *name)
/*
* Desc: check if <name> is already installed as a package
*/
{
int i, found;
found = FALSE;
for (i=0; i<p_inf.Nitems && !found; i++) {
if (strcmp(name, p_inf.name[i]) == 0) {
found = TRUE;
}
}
return(found);
} /* already_installed() */