summaryrefslogtreecommitdiffstats
path: root/pacman.c
diff options
context:
space:
mode:
Diffstat (limited to 'pacman.c')
-rw-r--r--pacman.c980
1 files changed, 980 insertions, 0 deletions
diff --git a/pacman.c b/pacman.c
new file mode 100644
index 00000000..60c99726
--- /dev/null
+++ b/pacman.c
@@ -0,0 +1,980 @@
+/**
+ * pacman
+ *
+ * Copyright (c) 2002 by Judd Vinet <jvinet@zeroflux.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include "pacman.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libtar.h>
+#include <zlib.h>
+
+/* borrowed and modifed from Per Liden's pkgutils (http://crux.nu) */
+static int gzopen_frontend(char *pathname, int oflags, int mode)
+{
+ char* gzoflags;
+ int fd;
+ gzFile gzf;
+
+ switch (oflags & O_ACCMODE) {
+ case O_WRONLY:
+ gzoflags = "w";
+ break;
+ case O_RDONLY:
+ gzoflags = "r";
+ break;
+ case O_RDWR:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if((fd = open(pathname, oflags, mode)) == -1) {
+ return -1;
+ }
+ if((oflags & O_CREAT) && fchmod(fd, mode)) {
+ return -1;
+ }
+ if(!(gzf = gzdopen(fd, gzoflags))) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return (int)gzf;
+}
+
+static tartype_t gztype = {
+ (openfunc_t) gzopen_frontend,
+ (closefunc_t)gzclose,
+ (readfunc_t) gzread,
+ (writefunc_t)gzwrite
+};
+
+/*
+ * GLOBALS
+ *
+ */
+FILE* dbfp = NULL;
+char* dbpath = PKGDB;
+char* pkgname = NULL;
+char* pkgver = NULL;
+
+char* pmo_root = NULL;
+unsigned short pmo_verbose = 0;
+unsigned short pmo_force = 0;
+unsigned short pmo_upgrade = 0;
+unsigned short pmo_nosave = 0;
+unsigned short pmo_nofunc = 0;
+unsigned short pmo_q_isfile = 0;
+unsigned short pmo_q_info = 0;
+unsigned short pmo_q_list = 0;
+char* pmo_q_owns = NULL;
+
+pkginfo_t** packages = NULL;
+unsigned int pkgcount = 0;
+
+
+int main(int argc, char* argv[])
+{
+ pm_opfunc_t op_func;
+ char* funcvar = NULL;
+ int ret = 0;
+
+ /* default root */
+ pmo_root = (char*)malloc(2);
+ strcpy(pmo_root, "/");
+
+ if(argc < 2) {
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(0);
+ }
+
+ /* determine the requested operation and pass off to */
+ /* the handler function */
+ if(!strcmp(argv[1], "-A") || !strcmp(argv[1], "--add")) {
+ op_func = pacman_add;
+ funcvar = parseargs(PM_ADD, argc, argv);
+ } else if(!strcmp(argv[1], "-R") || !strcmp(argv[1], "--remove")) {
+ op_func = pacman_remove;
+ funcvar = parseargs(PM_REMOVE, argc, argv);
+ } else if(!strcmp(argv[1], "-Q") || !strcmp(argv[1], "--query")) {
+ op_func = pacman_query;
+ funcvar = parseargs(PM_QUERY, argc, argv);
+ } else if(!strcmp(argv[1], "-U") || !strcmp(argv[1], "--upgrade")) {
+ op_func = pacman_upgrade;
+ funcvar = parseargs(PM_UPGRADE, argc, argv);
+ } else if(!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(1);
+ } else if(!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
+ version();
+ return(1);
+ } else {
+ printf("error: invalid operation\n\n");
+ usage(PM_MAIN, (char*)basename(argv[0]));
+ return(1);
+ }
+
+ if(funcvar == NULL && op_func != pacman_query) {
+ return(1);
+ }
+ vprint("Installation Root: %s\n", pmo_root);
+ vprint("Package Name: %s\n", funcvar);
+
+ /* check for db existence */
+ if(pmo_root != NULL) {
+ /* trim the trailing '/' if there is one */
+ if((int)rindex(pmo_root, '/') == ((int)pmo_root)+strlen(pmo_root)-1) {
+ pmo_root[strlen(pmo_root)-1] = '\0';
+ }
+ free(dbpath);
+ dbpath = (char*)malloc(strlen(pmo_root) + strlen(PKGDB) + 1);
+ strcpy(dbpath, pmo_root);
+ dbpath = (char*)strcat(dbpath, PKGDB);
+ }
+ vprint("Using package DB: %s\n", dbpath);
+
+ ret = db_open(dbpath);
+ if(ret == 1) {
+ printf("error: Could not open package database file!\n");
+ printf(" Check to see that %s exists.\n", dbpath);
+ printf(" If not, you may simply create it by \"touch\"-ing it.\n");
+ return(1);
+ }
+ if(ret == 2) {
+ printf("error: Database is corrupt! You may need to use the backup database.\n");
+ printf(" I hope you like tweaking... ;-)\n");
+ return(1);
+ }
+
+ /* start the requested operation */
+ if(!pmo_nofunc) {
+ ret = op_func(funcvar);
+ if(ret) {
+ printf("There were errors\n");
+ }
+ }
+
+ fclose(dbfp);
+ return(0);
+}
+
+int pacman_add(char* pkgfile)
+{
+ int i, errors = 0;
+ TAR* tar;
+ char* errmsg = NULL;
+ char* expath = NULL;
+ char* newpath = NULL;
+ fileset_t files = NULL;
+ unsigned int filecount = 0;
+ struct stat buf;
+
+ /* Populate the file list */
+ filecount = load_pkg(pkgfile, &files, 0);
+ if(filecount == 0) {
+ return(1);
+ }
+
+ /* Now check for conflicts in the db */
+ vprint("Looking for DB conflicts...\n");
+ if((i = db_find_conflicts(files, filecount)) == 1) {
+ if(pmo_force) {
+ printf("\nInstalling package anyway...\n");
+ printf(" You might have duplicate entries in your package\n");
+ printf(" database now. You may want to edit it and remove\n");
+ printf(" one of the copies.\n\n");
+ } else {
+ printf("Aborting...\n");
+ printf(" (use -f to override)\n\n");
+ return(1);
+ }
+ } else if(i == 2) {
+ return(1);
+ } else {
+ vprint("No DB conflicts found\n");
+ }
+
+ /* see if this is an upgrade. if so, remove the old package first */
+ if(pmo_upgrade) {
+ vprint("Removing old package first...\n");
+ if(pacman_remove(pkgname)) {
+ printf("\nUpgrade aborted.\n");
+ return(1);
+ }
+ }
+
+ /* open the .tar.gz package */
+ if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
+ perror("could not open package");
+ return(1);
+ }
+ vprint("Extracting files...\n");
+ for(i = 0; !th_read(tar); i++) {
+ if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
+ tar_skip_regfile(tar);
+ continue;
+ }
+ /* build the new pathname relative to pmo_root */
+ expath = (char*)malloc(strlen(th_get_pathname(tar))+strlen(pmo_root)+2);
+ strcpy(expath, pmo_root);
+ strcat(expath, "/");
+ strcat(expath, th_get_pathname(tar));
+ vprint(" %s\n", expath);
+ if(!stat(expath, &buf)) {
+ /* if the file ends in .conf, back it up */
+ if(!strcmp((char*)(expath+strlen(expath)-5), ".conf")) {
+ newpath = (char*)realloc(newpath, strlen(expath)+6);
+ strcpy(newpath, expath);
+ strcat(newpath, ".save");
+ rename(expath, newpath);
+ printf("%s renamed to %s\n", expath, newpath);
+ }
+ }
+ if(tar_extract_file(tar, expath)) {
+ errmsg = strerror(errno);
+ printf("could not extract %s: %s\n", th_get_pathname(tar), errmsg);
+ errors = 1;
+ }
+ free(expath);
+ }
+ tar_close(tar);
+ vprint("Done.\n");
+ if(errors) {
+ printf("There were errors. No database update was performed.\n");
+ } else {
+ vprint("Updating database...\n");
+ if(db_update(files, filecount)) {
+ printf("error: Could not update database! The database may not\n");
+ printf(" be in a sane state!\n");
+ return(1);
+ }
+ vprint("Done.\n");
+ }
+ return(0);
+}
+
+int pacman_remove(char* pkgfile)
+{
+ int found = 0, done = 0;
+ int i;
+ char line[255];
+ fileset_t files = NULL;
+ unsigned int filecount = 0;
+ struct stat buf;
+ char* newpath = NULL;
+
+ if(pkgfile == NULL) {
+ return(0);
+ }
+
+ /* find the package's filelist in the db */
+ rewind(dbfp);
+ while(!found && !feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(!strcmp(line, pkgfile)) {
+ /* read the version */
+ fgets(line, 255, dbfp);
+ found = 1;
+ }
+ }
+ if(!found) {
+ printf("Cannot remove %s: Package was not found.\n", pkgfile);
+ return(1);
+ }
+
+ while(!done) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(strlen(line)) {
+ /* add the path to the list */
+ files = (fileset_t)realloc(files, (++filecount) * sizeof(char*));
+ files[filecount-1] = (char*)malloc(strlen(line)+1);
+ strcpy(files[filecount-1], line);
+ } else {
+ done = 1;
+ }
+ }
+ /* iterate through the list backwards, unlinking files */
+ for(i = filecount-1; i >= 0; i--) {
+ if(lstat(files[i], &buf)) {
+ vprint("file %s does not exist\n", files[i]);
+ continue;
+ }
+ if(S_ISDIR(buf.st_mode)) {
+ vprint(" removing directory %s\n", files[i]);
+ if(rmdir(files[i])) {
+ /* this is okay, other packages are probably using it. */
+ /* perror("cannot remove directory"); */
+ }
+ } else {
+ /* if the file ends in .conf, back it up */
+ if(!pmo_nosave && !strcmp((char*)(files[i]+strlen(files[i])-5), ".conf")) {
+ newpath = (char*)realloc(newpath, strlen(files[i])+6);
+ strcpy(newpath, files[i]);
+ strcat(newpath, ".save");
+ rename(files[i], newpath);
+ printf("%s renamed to %s\n", files[i], newpath);
+ } else {
+ vprint(" unlinking %s\n", files[i]);
+ if(unlink(files[i])) {
+ perror("cannot remove file");
+ }
+ }
+ }
+ }
+
+ /* now splice this name out of the packages list */
+ found = 0;
+ for(i = 0; i < pkgcount-1; i++) {
+ if(found) {
+ packages[i] = packages[i+1];
+ } else {
+ if(!strcmp(packages[i]->name, pkgfile)) {
+ found = 1;
+ if(i < pkgcount-1) {
+ packages[i] = packages[i+1];
+ }
+ }
+ }
+ }
+ /* drop the last item */
+ packages = (pkginfo_t**)realloc(packages, (--pkgcount)*sizeof(pkginfo_t*));
+
+ /* and commit the db */
+ return(db_update(NULL, 0));
+}
+
+int pacman_query(char* pkgfile)
+{
+ char *str = NULL;
+ char name[255];
+ char ver[255];
+ char line[255];
+ int found = 0;
+ int done = 0;
+ int i;
+ unsigned int filecount = 0;
+ fileset_t files = NULL;
+
+ /* output info for a .tar.gz package */
+ if(pmo_q_isfile) {
+ filecount = load_pkg(pkgfile, &files, pmo_q_info);
+ if(pmo_q_list) {
+ for(i = 0; i < filecount; i++) {
+ if(strcmp(files[i], ".PKGINFO")) {
+ printf("%s\n", files[i]);
+ }
+ }
+ } else {
+ printf("%s %s\n", pkgname, pkgver);
+ }
+
+ return(0);
+ }
+
+ /* determine the owner of a file */
+ if(pmo_q_owns != NULL) {
+ rewind(dbfp);
+ while(!found && !feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ fgets(ver, 255, dbfp);
+ strcpy(ver, trim(ver));
+ strcpy(line, " ");
+ while(strlen(line) && !feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ str = line;
+ str += strlen(pmo_root);
+ if(!strcmp(line, pmo_q_owns)) {
+ printf("%s %s\n", name, ver);
+ return(0);
+ }
+ }
+ }
+ printf("No package owns this file.\n");
+ return(0);
+ }
+
+ /* find packages in the db */
+ rewind(dbfp);
+ while(!done) {
+ found = 0;
+ while(!found && !feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ if(pkgfile == NULL || (pkgfile != NULL && !strcmp(name, pkgfile))) {
+ /* read the version */
+ fgets(ver, 255, dbfp);
+ strcpy(ver, trim(ver));
+ found = 1;
+ if(pkgfile != NULL) {
+ done = 1;
+ }
+ }
+ }
+ if(feof(dbfp)) {
+ if(pkgfile != NULL && !found) {
+ printf("Package was not found in database.\n");
+ }
+ break;
+ }
+ found = 0;
+ while(!found) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(strlen(line)) {
+ if(pmo_q_list) {
+ printf("%s%s\n", pmo_root, line);
+ }
+ } else {
+ found = 1;
+ }
+ }
+ if(!pmo_q_list) {
+ printf("%s %s\n", name, ver);
+ }
+ if(feof(dbfp)) {
+ done = 1;
+ }
+ }
+
+ return(0);
+}
+
+int pacman_upgrade(char* pkgfile)
+{
+ /* this is basically just a remove,add process. pacman_add() will */
+ /* handle it */
+ pmo_upgrade = 1;
+ pacman_add(pkgfile);
+ return(0);
+}
+
+/*
+ * Populate the package file list
+ * pkgfile: filename of package
+ * listptr: this will be set to the new fileset_t
+ *
+ * Returns: the number of filenames read in the package, or 0 on error
+ *
+ */
+int load_pkg(char* pkgfile, fileset_t* listptr, unsigned short output)
+{
+ char* expath;
+ char* descfile;
+ int i;
+ TAR* tar;
+ unsigned int filecount = 0;
+ fileset_t files = NULL;
+
+ descfile = (char*)malloc(strlen("/tmp/pacman_XXXXXX")+1);
+ strcpy(descfile, "/tmp/pacman_XXXXXX");
+
+ if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
+ perror("could not open package");
+ return(0);
+ }
+ vprint("Loading filelist from package...\n");
+ for(i = 0; !th_read(tar); i++) {
+ if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
+ /* extract this file into /tmp. it has info for us */
+ vprint("Found package description file.\n");
+ mkstemp(descfile);
+ tar_extract_file(tar, descfile);
+ parse_descfile(descfile, output);
+ continue;
+ }
+ /* build the new pathname relative to pmo_root */
+ expath = (char*)malloc(strlen(th_get_pathname(tar))+strlen(pmo_root)+2);
+ strcpy(expath, pmo_root);
+ strcat(expath, "/");
+ strcat(expath, th_get_pathname(tar));
+ /* add the path to the list */
+ files = (fileset_t)realloc(files, (++filecount) * sizeof(char*));
+ files[filecount-1] = expath;
+
+ if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
+ perror("bad package file");
+ return(0);
+ }
+ expath = NULL;
+ }
+ tar_close(tar);
+
+ if(pkgname == NULL || pkgver == NULL) {
+ printf("The current version of Pacman requires a .PKGINFO file\n");
+ printf("present in the .tar.gz archive. This package does not\n");
+ printf("have one.\n");
+ return(0);
+ }
+
+ (*listptr) = files;
+ return(filecount);
+}
+
+/* Open the database file
+ * path: the full pathname of the file
+ */
+int db_open(char* path)
+{
+ char line[255];
+ pkginfo_t* info;
+ dbfp = fopen(path, "r");
+ if(dbfp == NULL) {
+ return(1);
+ }
+ while(!feof(dbfp)) {
+ info = (pkginfo_t*)malloc(sizeof(pkginfo_t));
+ fgets(line, 64, dbfp);
+ if(feof(dbfp)) {
+ break;
+ }
+ strcpy(info->name, trim(line));
+ fgets(line, 32, dbfp);
+ strcpy(info->version, trim(line));
+ /* add to the collective */
+ packages = (pkginfo_t**)realloc(packages, (++pkgcount) * sizeof(pkginfo_t*));
+ packages[pkgcount-1] = info;
+ for(;;) {
+ fgets(line, 255, dbfp);
+ if(feof(dbfp)) {
+ return(2);
+ }
+ if(strlen(trim(line)) == 0) {
+ break;
+ }
+ }
+ }
+
+ return(0);
+}
+
+/* Copy the old database file to a backup and build the
+ * new copy in its place.
+ * files: list of files in the new package, can be null
+ * filecount: number of entries in files
+ *
+ * Returns: 0 on success
+ *
+ */
+int db_update(fileset_t files, unsigned int filecount)
+{
+ FILE* olddb;
+ char* newpath = NULL;
+ char* str = NULL;
+ char name[64];
+ char ver[32];
+ char line[255];
+ int i = 0, found = 0, done = 0;
+
+ /* build the backup pathname */
+ newpath = (char*)malloc(strlen(dbpath)+5);
+ strcpy(newpath, dbpath);
+ strcat(newpath, ".bak");
+
+ /* rename the existing db */
+ fclose(dbfp);
+ rename(dbpath, newpath);
+
+ olddb = fopen(newpath, "r");
+ free(newpath);
+ dbfp = fopen(dbpath, "w");
+ if(olddb == NULL || dbfp == NULL) {
+ return(1);
+ }
+
+ rewind(olddb);
+ while(!feof(olddb)) {
+ if(!fgets(name, 64, olddb)) {
+ break;
+ }
+ strcpy(name, trim(name));
+ fgets(ver, 32, olddb);
+ found = 0;
+ for(i = 0; i < pkgcount && !found; i++) {
+ if(!strcmp(packages[i]->name, name)) {
+ /* it's there... copy the entries over */
+ found = 1;
+ fputs(name, dbfp);
+ fputc('\n', dbfp);
+ fputs(ver, dbfp);
+ for(done = 0; !done;) {
+ fgets(line, 255, olddb);
+ if(found) {
+ fputs(line, dbfp);
+ }
+ if(strlen(trim(line)) == 0 || feof(olddb)) {
+ done = 1;
+ }
+ }
+ }
+ }
+ if(!found) {
+ /* skip through filelist for this package */
+ for(done = 0; !done;) {
+ fgets(line, 255, olddb);
+ if(strlen(trim(line)) == 0 || feof(olddb)) {
+ done = 1;
+ }
+ }
+ }
+ }
+ fclose(olddb);
+
+ /* write the current info */
+ if(files != NULL) {
+ fputs(pkgname, dbfp);
+ fputc('\n', dbfp);
+ fputs(pkgver, dbfp);
+ fputc('\n', dbfp);
+ for(i = 0; i < filecount; i++) {
+ str = files[i];
+ str += strlen(pmo_root);
+ fputs(str, dbfp);
+ fputc('\n', dbfp);
+ }
+ fputs("\n", dbfp);
+ }
+ fclose(dbfp);
+ db_open(dbpath);
+
+ return(0);
+}
+
+/* Check the database for conflicts
+ * files: list of files in the new package
+ * filecount: number of entries in files
+ *
+ * Returns: 0 if no conflicts were found, 1 otherwise
+ *
+ */
+int db_find_conflicts(fileset_t files, unsigned int filecount)
+{
+ int i;
+ char line[255];
+ char name[255];
+ struct stat buf;
+ int conflicts = 0;
+
+ /* CHECK 1: checking db conflicts */
+ rewind(dbfp);
+ while(!feof(dbfp)) {
+ fgets(name, 255, dbfp);
+ strcpy(name, trim(name));
+ if(!pmo_upgrade && !strcmp(name, pkgname)) {
+ printf("error: This package is already installed.\n");
+ printf(" Maybe you should be using --upgrade.\n");
+ return(2);
+ }
+ fgets(line, 255, dbfp);
+ while(!feof(dbfp)) {
+ fgets(line, 255, dbfp);
+ strcpy(line, trim(line));
+ if(!strlen(line)) {
+ break;
+ }
+ if(index(line, '/') == (char*)line && (!pmo_upgrade || strcmp(name,pkgname))) {
+ for(i = 0; i < filecount; i++) {
+ if(!strcmp(line, files[i])) {
+ if(rindex(files[i], '/') == files[i]+strlen(files[i])-1) {
+ /* this filename has a trailing '/', so it's a directory -- skip it. */
+ continue;
+ }
+ printf("conflict: %s already exists in package \"%s\"\n", line, name);
+ conflicts = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* CHECK 2: checking filesystem conflicts */
+ /* TODO: run filesystem checks for upgrades */
+ for(i = 0; i < filecount && !pmo_upgrade; i++) {
+ if(!stat(files[i], &buf) && !S_ISDIR(buf.st_mode)) {
+ printf("conflict: %s already exists in filesystem\n", files[i]);
+ conflicts = 1;
+ }
+ }
+
+ return(conflicts);
+}
+
+/* Parses the package description file for the current package
+ * descfile: the full pathname of the description file
+ *
+ * Returns: 0 on success, 1 on error
+ *
+ */
+int parse_descfile(char* descfile, unsigned short output)
+{
+ FILE* fp;
+ char line[255];
+ char* ptr = NULL;
+ char* key = NULL;
+ int linenum = 0;
+
+ if((fp = fopen(descfile, "r")) == NULL) {
+ perror(descfile);
+ return(1);
+ }
+
+ while(!feof(fp)) {
+ fgets(line, 255, fp);
+ if(output) {
+ printf("%s", line);
+ }
+ linenum++;
+ strcpy(line, trim(line));
+ if(index(line, '#') == (char*)line) {
+ continue;
+ }
+ if(strlen(line) == 0) {
+ continue;
+ }
+ ptr = line;
+ key = strsep(&ptr, "=");
+ if(key == NULL || ptr == NULL) {
+ printf("Syntax error in description file line %d\n", linenum);
+ } else {
+ key = trim(key);
+ key = strtoupper(key);
+ ptr = trim(ptr);
+ if(!strcmp(key, "PKGNAME")) {
+ pkgname = (char*)malloc(strlen(ptr)+1);
+ strcpy(pkgname, ptr);
+ } else if(!strcmp(key, "PKGVER")) {
+ pkgver = (char*)malloc(strlen(ptr)+1);
+ strcpy(pkgver, ptr);
+ } else if(!strcmp(key, "PKGDESC")) {
+ /* Not used yet */
+ } else {
+ printf("Syntax error in description file line %d\n", linenum);
+ }
+ }
+ line[0] = '\0';
+ }
+ fclose(fp);
+ unlink(descfile);
+ return(0);
+}
+
+/* Parse command-line arguments for each operation
+ * op: the operation code requested
+ * argc: argc
+ * argv: argv
+ *
+ * Returns: the functional variable for that operation
+ * (eg, the package file name for PM_ADD)
+ */
+char* parseargs(int op, int argc, char** argv)
+{
+ char* pkg = NULL;
+ int i;
+
+ for(i = 2; i < argc; i++) {
+ if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
+ pmo_nofunc = 1;
+ usage(op, (char*)basename(argv[0]));
+ return(NULL);
+ } else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--verbose")) {
+ pmo_verbose = 1;
+ } else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--force")) {
+ pmo_force = 1;
+ } else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--root")) {
+ i++;
+ if(i >= argc) {
+ printf("error: missing argument for %s\n", argv[i-1]);
+ return(NULL);
+ }
+ free(pmo_root);
+ pmo_root = (char*)malloc(PATH_MAX);
+ if(realpath(argv[i], pmo_root) == NULL) {
+ perror("bad root path");
+ return(NULL);
+ }
+ } else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--nosave")) {
+ pmo_nosave = 1;
+ } else if(!strcmp(argv[i], "-o") || !strcmp(argv[i], "--owns")) {
+ /* PM_QUERY only */
+ i++;
+ if(i >= argc) {
+ printf("error: missing argument for %s\n", argv[i-1]);
+ return(NULL);
+ }
+ free(pmo_q_owns);
+ pmo_q_owns = (char*)malloc(PATH_MAX);
+ if(realpath(argv[i], pmo_q_owns) == NULL) {
+ perror("bad path specified for --owns");
+ pmo_nofunc = 1;
+ return(NULL);
+ }
+ } else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--list")) {
+ /* PM_QUERY only */
+ pmo_q_list = 1;
+ } else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--file")) {
+ /* PM_QUERY only */
+ pmo_q_isfile = 1;
+ } else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) {
+ /* PM_QUERY only */
+ pmo_q_info = 1;
+ } else {
+ pkg = argv[i];
+ }
+ }
+
+ if(op != PM_QUERY && pkg == NULL) {
+ printf("error: no package specified\n\n");
+ usage(op, (char*)basename(argv[0]));
+ return(NULL);
+ }
+ if(op == PM_QUERY && pmo_q_isfile && pkg == NULL) {
+ printf("error: no package file specified\n\n");
+ return(NULL);
+ }
+ return(pkg);
+}
+
+/* Display usage/syntax for the specified operation.
+ * op: the operation code requested
+ * myname: basename(argv[0])
+ */
+void usage(int op, char* myname)
+{
+ if(op == PM_MAIN) {
+ printf("usage: %s {-h --help}\n", myname);
+ printf(" %s {-V --version}\n", myname);
+ printf(" %s {-A --add} [options] <file>\n", myname);
+ printf(" %s {-R --remove} [options] <package>\n", myname);
+ printf(" %s {-U --upgrade} [options] <file>\n", myname);
+ printf(" %s {-Q --query} [options] [package]\n", myname);
+ } else if(op == PM_ADD) {
+ printf("usage: %s {-A --add} [options] <file>\n", myname);
+ printf("options:\n");
+ printf(" -f, --force force install, overwrite conflicting files\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_REMOVE) {
+ printf("usage: %s {-R --remove} [options] <package>\n", myname);
+ printf("options:\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_UPGRADE) {
+ printf("usage: %s {-U --upgrade} [options] <file>\n", myname);
+ printf("options:\n");
+ printf(" -f, --force force install, overwrite conflicting files\n");
+ printf(" -n, --nosave do not save .conf files\n");
+ printf(" -v, --verbose be verbose\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ } else if(op == PM_QUERY) {
+ printf("usage: %s {-Q --query} [options] [package]\n", myname);
+ printf("options:\n");
+ printf(" -r, --root <path> set an alternative installation root\n");
+ printf(" -o, --owns <file> query the package that owns <file>\n");
+ printf(" -l, --list list the contents of the queried package\n");
+ printf(" -i, --info output the .PKGINFO file (only used with -p)\n");
+ printf(" -p, --file if used, then [package] will be the path\n");
+ printf(" to an (uninstalled) package to query\n");
+ }
+}
+
+/* Version
+ */
+void version(void)
+{
+ printf("\n");
+ printf(" .--. Pacman v%s\n", VERSION);
+ printf("/ _.-' .-. .-. .-. Copyright (C) 2002 Judd Vinet <jvinet@zeroflux.org>\n");
+ printf("\\ '-. '-' '-' '-' \n");
+ printf(" '--' This program may be freely redistributed under\n");
+ printf(" the terms of the GNU GPL\n\n");
+}
+
+/* Check verbosity option and, if set, print the
+ * string to stdout
+ */
+int vprint(char* fmt, ...)
+{
+ va_list args;
+ if(pmo_verbose) {
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ fflush(stdout);
+ }
+ return(0);
+}
+
+/* Convert a string to uppercase
+ */
+char* strtoupper(char* str)
+{
+ char* ptr = str;
+
+ while(*ptr) {
+ (*ptr) = toupper(*ptr);
+ ptr++;
+ }
+ return str;
+}
+
+/* Trim whitespace and newlines from a string
+ */
+char* trim(char* str)
+{
+ char* start = str;
+ char* end = str + strlen(str);
+ int mid = 0;
+ char ch;
+
+ while(mid < 2) {
+ if(!mid) {
+ ch = *start;
+ if(ch == 10 || ch == 13 || ch == 9 || ch == 32) {
+ start++;
+ } else {
+ mid = 1;
+ }
+ } else {
+ end--;
+ ch = *end;
+ if(ch == 10 || ch == 13 || ch == 9 || ch == 32) {
+ *end = '\0';
+ } else {
+ mid = 2;
+ }
+ }
+ }
+ return(start);
+}
+
+/* vim: set ts=2 noet: */