/*************************************************************** * * 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 #include #include #include #include #include #include #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 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 with arguments and catch its output * in 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 */ { 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 is already installed as a package */ { int i, found; found = FALSE; for (i=0; i