aa1478bbd2
full directory hierarchy, as is the format of the new ports collection. It used the old "all packages in one directory" paradigm, which is wrong for ports now. Submitted by: Marc van Kempen <wmbfmk@urc.tue.nl>
537 lines
12 KiB
C
537 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) {
|
|
dialog_notify("No packages installed or no info available");
|
|
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() */
|
|
|
|
|