Example #1
0
/*
 * This is seriously ugly code following.  Written very fast!
 * [And subsequently made even worse..  Sigh!  This code was just born
 * to be hacked, I guess.. :) -jkh]
 */
static int
pkg_do(char *pkg)
{
    Package Plist;
    char pkg_fullname[FILENAME_MAX];
    char playpen[FILENAME_MAX];
    char extract_contents[FILENAME_MAX];
    char *extract;
    const char *where_to;
    FILE *cfile;
    int code;
    PackingList p;
    struct stat sb;
    int inPlace, conflictsfound, errcode;
    /* support for separate pre/post install scripts */
    int new_m = 0;
    char pre_script[FILENAME_MAX] = INSTALL_FNAME;
    char post_script[FILENAME_MAX];
    char pre_arg[FILENAME_MAX], post_arg[FILENAME_MAX];
    char *conflict[2];
    char **matched;
    int fd;

    conflictsfound = 0;
    code = 0;
    zapLogDir = 0;
    LogDir[0] = '\0';
    strcpy(playpen, FirstPen);
    inPlace = 0;

    memset(&Plist, '\0', sizeof(Plist));

    /* Are we coming in for a second pass, everything already extracted? */
    if (!pkg) {
	fgets(playpen, FILENAME_MAX, stdin);
	playpen[strlen(playpen) - 1] = '\0'; /* pesky newline! */
	if (chdir(playpen) == FAIL) {
	    warnx("pkg_add in SLAVE mode can't chdir to %s", playpen);
	    return 1;
	}
	read_plist(&Plist, stdin);
	where_to = playpen;
    }
    /* Nope - do it now */
    else {
	/* Is it an ftp://foo.bar.baz/file.t[bg]z specification? */
	if (isURL(pkg)) {
	    if (!(where_to = fileGetURL(NULL, pkg, KeepPackage))) {
		warnx("unable to fetch '%s' by URL", pkg);
		return 1;
	    }
	    strcpy(pkg_fullname, pkg);
	    cfile = fopen(CONTENTS_FNAME, "r");
	    if (!cfile) {
		warnx(
		"unable to open table of contents file '%s' - not a package?",
		CONTENTS_FNAME);
		goto bomb;
	    }
	    read_plist(&Plist, cfile);
	    fclose(cfile);
	}
	else {
	    strcpy(pkg_fullname, pkg);		/*
						 * Copy for sanity's sake,
						 * could remove pkg_fullname
						 */
	    if (strcmp(pkg, "-")) {
		if (stat(pkg_fullname, &sb) == FAIL) {
		    warnx("can't stat package file '%s'", pkg_fullname);
		    goto bomb;
		}
		sprintf(extract_contents, "--fast-read %s", CONTENTS_FNAME);
		extract = extract_contents;
	    }
	    else {
		extract = NULL;
		sb.st_size = 100000;	/* Make up a plausible average size */
	    }
	    if (!(where_to = make_playpen(playpen, sb.st_size * 4)))
		errx(1, "unable to make playpen for %lld bytes", (long long)sb.st_size * 4);
	    /* Since we can call ourselves recursively, keep notes on where we came from */
	    if (!getenv("_TOP"))
		setenv("_TOP", where_to, 1);
	    if (unpack(pkg_fullname, extract)) {
		warnx(
	"unable to extract table of contents file from '%s' - not a package?",
		pkg_fullname);
		goto bomb;
	    }
	    cfile = fopen(CONTENTS_FNAME, "r");
	    if (!cfile) {
		warnx(
	"unable to open table of contents file '%s' - not a package?",
		CONTENTS_FNAME);
		goto bomb;
	    }
	    read_plist(&Plist, cfile);
	    fclose(cfile);

	    /* Extract directly rather than moving?  Oh goodie! */
	    if (find_plist_option(&Plist, "extract-in-place")) {
		if (Verbose)
		    printf("Doing in-place extraction for %s\n", pkg_fullname);
		p = find_plist(&Plist, PLIST_CWD);
		if (p) {
		    if (!isdir(p->name) && !Fake) {
			if (Verbose)
			    printf("Desired prefix of %s does not exist, creating..\n", p->name);
			vsystem("/bin/mkdir -p %s", p->name);
			if (chdir(p->name) == -1) {
			    warn("unable to change directory to '%s'", p->name);
			    goto bomb;
			}
		    }
		    where_to = p->name;
		    inPlace = 1;
		}
		else {
		    warnx(
		"no prefix specified in '%s' - this is a bad package!",
			pkg_fullname);
		    goto bomb;
		}
	    }

	    /*
	     * Apply a crude heuristic to see how much space the package will
	     * take up once it's unpacked.  I've noticed that most packages
	     * compress an average of 75%, so multiply by 4 for good measure.
	     */

	    if (!extract && !inPlace && min_free(playpen) < sb.st_size * 4) {
		warnx("projected size of %lld exceeds available free space.\n"
"Please set your PKG_TMPDIR variable to point to a location with more\n"
		       "free space and try again", (long long)sb.st_size * 4);
		warnx("not extracting %s\ninto %s, sorry!",
			pkg_fullname, where_to);
		goto bomb;
	    }

	    /* If this is a direct extract and we didn't want it, stop now */
	    if (inPlace && Fake)
		goto success;

	    /* Finally unpack the whole mess.  If extract is null we
	       already + did so so don't bother doing it again. */
	    if (extract && unpack(pkg_fullname, NULL)) {
		warnx("unable to extract '%s'!", pkg_fullname);
		goto bomb;
	    }
	}

	/* Check for sanity and dependencies */
	if (sanity_check(pkg))
	    goto bomb;

	/* If we're running in MASTER mode, just output the plist and return */
	if (AddMode == MASTER) {
	    printf("%s\n", where_playpen());
	    write_plist(&Plist, stdout);
	    return 0;
	}
    }

    /*
     * If we have a prefix, delete the first one we see and add this
     * one in place of it.
     */
    if (Prefix) {
	delete_plist(&Plist, FALSE, PLIST_CWD, NULL);
	add_plist_top(&Plist, PLIST_CWD, Prefix);
    }

    setenv(PKG_PREFIX_VNAME, (p = find_plist(&Plist, PLIST_CWD)) ? p->name : ".", 1);
    /* Protect against old packages with bogus @name and origin fields */
    if (Plist.name == NULL)
	Plist.name = "anonymous";
    if (Plist.origin == NULL)
	Plist.origin = "anonymous/anonymous";

    /*
     * See if we're already registered either with the same name (the same
     * version) or some other version with the same origin.
     */
    if ((isinstalledpkg(Plist.name) > 0 ||
         matchbyorigin(Plist.origin, NULL) != NULL) && !Force) {
	warnx("package '%s' or its older version already installed%s",
	      Plist.name, FailOnAlreadyInstalled ? "" : " (ignored)");
	code = FailOnAlreadyInstalled != FALSE;
	goto success;	/* close enough for government work */
    }

    /* Now check the packing list for conflicts */
    if (!IgnoreDeps){
    for (p = Plist.head; p != NULL; p = p->next) {
	if (p->type == PLIST_CONFLICTS) {
	    int i;
	    conflict[0] = strdup(p->name);
	    conflict[1] = NULL;
	    matched = matchinstalled(MATCH_GLOB, conflict, &errcode);
	    free(conflict[0]);
	    if (errcode == 0 && matched != NULL)
		for (i = 0; matched[i] != NULL; i++)
		    if (isinstalledpkg(matched[i]) > 0) {
			warnx("package '%s' conflicts with %s", Plist.name,
				matched[i]);
			conflictsfound = 1;
		    }

	    continue;
	}
    }
    if(conflictsfound) {
	if(!Force) {
	    warnx("please use pkg_delete first to remove conflicting package(s) or -f to force installation");
	    code = 1;
	    goto bomb;
	} else
	    warnx("-f specified; proceeding anyway");
    }

#if ENSURE_THAT_ALL_REQUIREMENTS_ARE_MET
    /*
     * Before attempting to do the slave mode bit, ensure that we've
     * downloaded & processed everything we need.
     * It's possible that we haven't already installed all of our
     * dependencies if the dependency list was misgenerated due to
     * other dynamic dependencies or if a dependency was added to a
     * package without all REQUIRED_BY packages being regenerated.
     */
    for (p = pkg ? Plist.head : NULL; p; p = p->next) {
	const char *ext;
	char *deporigin;

	if (p->type != PLIST_PKGDEP)
	    continue;
	deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL;

	if (isinstalledpkg(p->name) <= 0 &&
	    !(deporigin != NULL && matchbyorigin(deporigin, NULL) != NULL)) {
	    char subpkg[FILENAME_MAX], *sep;

	    strlcpy(subpkg, pkg, sizeof subpkg);
	    if ((sep = strrchr(subpkg, '/')) != NULL) {
		*sep = '\0';
		if ((sep = strrchr(subpkg, '/')) != NULL) {
		    *sep = '\0';
		    strlcat(subpkg, "/All/", sizeof subpkg);
		    strlcat(subpkg, p->name, sizeof subpkg);
		    if ((ext = strrchr(pkg, '.')) == NULL) {
			if (getenv("PACKAGESUFFIX"))
			  ext = getenv("PACKAGESUFFIX");
			else
			  ext = ".tbz";
		    }
		    strlcat(subpkg, ext, sizeof subpkg);
		    pkg_do(subpkg);
		}
	    }
	}
    }
#endif

    /* Now check the packing list for dependencies */
    for (p = Plist.head; p ; p = p->next) {
	char *deporigin;

	if (p->type != PLIST_PKGDEP)
	    continue;
	deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name : NULL;
	if (Verbose) {
	    printf("Package '%s' depends on '%s'", Plist.name, p->name);
	    if (deporigin != NULL)
		printf(" with '%s' origin", deporigin);
	    printf(".\n");
	}
	if (isinstalledpkg(p->name) <= 0 &&
	    !(deporigin != NULL && matchbyorigin(deporigin, NULL) != NULL)) {
	    char path[FILENAME_MAX];
	    const char *cp = NULL;

	    if (!Fake) {
		char prefixArg[2 + MAXPATHLEN]; /* "-P" + Prefix */
		if (PrefixRecursive) {
		    strlcpy(prefixArg, "-P", sizeof(prefixArg));
		    strlcat(prefixArg, Prefix, sizeof(prefixArg));
		}
		if (!isURL(pkg) && !getenv("PKG_ADD_BASE")) {
		    const char *ext;

		    ext = strrchr(pkg_fullname, '.');
		    if (ext == NULL) {
			if (getenv("PACKAGESUFFIX")) {
			  ext = getenv("PACKAGESUFFIX");
			} else {
			  ext = ".tbz";
			}
		    }
		    snprintf(path, FILENAME_MAX, "%s/%s%s", getenv("_TOP"), p->name, ext);
		    if (fexists(path))
			cp = path;
		    else
			cp = fileFindByPath(pkg, p->name);
		    if (cp) {
			if (Verbose)
			    printf("Loading it from %s.\n", cp);
			if (vsystem("%s %s %s '%s'", PkgAddCmd, Verbose ? "-v " : "", PrefixRecursive ? prefixArg : "", cp)) {
			    warnx("autoload of dependency '%s' failed%s",
				cp, Force ? " (proceeding anyway)" : "!");
			    if (!Force)
				++code;
			}
		    }
		    else {
			warnx("could not find package %s %s",
			      p->name, Force ? " (proceeding anyway)" : "!");
			if (!Force)
			    ++code;
		    }
		}
		else if ((cp = fileGetURL(pkg, p->name, KeepPackage)) != NULL) {
		    if (Verbose)
			printf("Finished loading %s via a URL\n", p->name);
		    if (!fexists("+CONTENTS")) {
			warnx("autoloaded package %s has no +CONTENTS file?",
				p->name);
			if (!Force)
			    ++code;
		    }
		    else if (vsystem("(pwd; /bin/cat +CONTENTS) | %s %s %s %s -S", PkgAddCmd, Verbose ? "-v" : "", PrefixRecursive ? prefixArg : "", KeepPackage ? "-K" : "")) {
			warnx("pkg_add of dependency '%s' failed%s",
				p->name, Force ? " (proceeding anyway)" : "!");
			if (!Force)
			    ++code;
		    }
		    else if (Verbose)
			printf("\t'%s' loaded successfully.\n", p->name);
		    /* Nuke the temporary playpen */
		    leave_playpen();
		}
	    }
	    else {
		if (Verbose)
		    printf("and was not found%s.\n", Force ? " (proceeding anyway)" : "");
		else
		    printf("Package dependency %s for %s not found%s\n", p->name, pkg,
			   Force ? " (proceeding anyway)" : "!");
		if (!Force)
		    ++code;
	    }
	}
	else if (Verbose)
	    printf(" - already installed.\n");
    }
    } /* if (!IgnoreDeps) */

    if (code != 0)
	goto bomb;

    /* Look for the requirements file */
    if ((fd = open(REQUIRE_FNAME, O_RDWR)) != -1) {
	fstat(fd, &sb);
	fchmod(fd, sb.st_mode | S_IXALL);	/* be sure, chmod a+x */
	close(fd);
	if (Verbose)
	    printf("Running requirements file first for %s..\n", Plist.name);
	if (!Fake && vsystem("./%s %s INSTALL", REQUIRE_FNAME, Plist.name)) {
	    warnx("package %s fails requirements %s", pkg_fullname,
		   Force ? "installing anyway" : "- not installed");
	    if (!Force) {
		code = 1;
		goto success;	/* close enough for government work */
	    }
	}
    }

    /*
     * Test whether to use the old method of passing tokens to installation
     * scripts, and set appropriate variables..
     */

    if (fexists(POST_INSTALL_FNAME)) {
	new_m = 1;
	sprintf(post_script, "%s", POST_INSTALL_FNAME);
	pre_arg[0] = '\0';
	post_arg[0] = '\0';
    } else {
	if (fexists(INSTALL_FNAME)) {
	    sprintf(post_script, "%s", INSTALL_FNAME);
	    sprintf(pre_arg, "PRE-INSTALL");
	    sprintf(post_arg, "POST-INSTALL");
	}
    }

    /* If we're really installing, and have an installation file, run it */
    if (!NoInstall && (fd = open(pre_script, O_RDWR)) != -1) {
	fstat(fd, &sb);
	fchmod(fd, sb.st_mode | S_IXALL);	/* be sure, chmod a+x */
	close(fd);
	if (Verbose)
	    printf("Running pre-install for %s..\n", Plist.name);
	if (!Fake && vsystem("./%s %s %s", pre_script, Plist.name, pre_arg)) {
	    warnx("install script returned error status");
	    unlink(pre_script);
	    code = 1;
	    goto success;		/* nothing to uninstall yet */
	}
    }

    /* Now finally extract the entire show if we're not going direct */
    if (!inPlace && !Fake)
	extract_plist(".", &Plist);

    if (!Fake && fexists(MTREE_FNAME)) {
	if (Verbose)
	    printf("Running mtree for %s..\n", Plist.name);
	p = find_plist(&Plist, PLIST_CWD);
	if (Verbose)
	    printf("mtree -U -f %s -d -e -p %s >%s\n", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL);
	if (!Fake) {
	    if (vsystem("/usr/sbin/mtree -U -f %s -d -e -p %s >%s", MTREE_FNAME, p ? p->name : "/", _PATH_DEVNULL))
		warnx("mtree returned a non-zero status - continuing");
	}
    }

    /* Run the installation script one last time? */
    if (!NoInstall && (fd = open(post_script, O_RDWR)) != -1) {
	fstat(fd, &sb);
	fchmod(fd, sb.st_mode | S_IXALL);	/* be sure, chmod a+x */
	close(fd);
	if (Verbose)
	    printf("Running post-install for %s..\n", Plist.name);
	if (!Fake && vsystem("./%s %s %s", post_script, Plist.name, post_arg)) {
	    warnx("install script returned error status");
	    unlink(post_script);
	    code = 1;
	    goto fail;
	}
    }

    /* Time to record the deed? */
    if (!NoRecord && !Fake) {
	char contents[FILENAME_MAX];
	char **depnames = NULL, **deporigins = NULL, ***depmatches;
	int i, dep_count = 0;
	FILE *contfile;

	if (getuid() != 0)
	    warnx("not running as root - trying to record install anyway");
	sprintf(LogDir, "%s/%s", LOG_DIR, Plist.name);
	zapLogDir = 1;
	if (Verbose)
	    printf("Attempting to record package into %s..\n", LogDir);
	if (make_hierarchy(LogDir, FALSE)) {
	    warnx("can't record package into '%s', you're on your own!",
		   LogDir);
	    bzero(LogDir, FILENAME_MAX);
	    code = 1;
	    goto success;	/* close enough for government work */
	}
	/* Make sure pkg_info can read the entry */
	fd = open(LogDir, O_RDWR);
	fstat(fd, &sb);
	fchmod(fd, sb.st_mode | S_IRALL | S_IXALL);	/* be sure, chmod a+rx */
	close(fd);
	move_file(".", DESC_FNAME, LogDir);
	move_file(".", COMMENT_FNAME, LogDir);
	if (fexists(INSTALL_FNAME))
	    move_file(".", INSTALL_FNAME, LogDir);
	if (fexists(POST_INSTALL_FNAME))
	    move_file(".", POST_INSTALL_FNAME, LogDir);
	if (fexists(DEINSTALL_FNAME))
	    move_file(".", DEINSTALL_FNAME, LogDir);
	if (fexists(POST_DEINSTALL_FNAME))
	    move_file(".", POST_DEINSTALL_FNAME, LogDir);
	if (fexists(REQUIRE_FNAME))
	    move_file(".", REQUIRE_FNAME, LogDir);
	if (fexists(DISPLAY_FNAME))
	    move_file(".", DISPLAY_FNAME, LogDir);
	if (fexists(MTREE_FNAME))
	    move_file(".", MTREE_FNAME, LogDir);
	sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME);
	contfile = fopen(contents, "w");
	if (!contfile) {
	    warnx("can't open new contents file '%s'! can't register pkg",
		contents);
	    goto success; /* can't log, but still keep pkg */
	}
	write_plist(&Plist, contfile);
	fclose(contfile);
	for (p = Plist.head; p ; p = p->next) {
	    char *deporigin;

	    if (p->type != PLIST_PKGDEP)
		continue;
	    deporigin = (p->next->type == PLIST_DEPORIGIN) ? p->next->name :
							     NULL;
	    if (Verbose) {
		printf("Trying to record dependency on package '%s'", p->name);
		if (deporigin != NULL)
		    printf(" with '%s' origin", deporigin);
		printf(".\n");
	    }

	    if (deporigin) {
		/* Defer to origin lookup */
		depnames = realloc(depnames, (dep_count + 1) * sizeof(*depnames));
		depnames[dep_count] = p->name;
		deporigins = realloc(deporigins, (dep_count + 2) * sizeof(*deporigins));
		deporigins[dep_count] = deporigin;
		deporigins[dep_count + 1] = NULL;
		dep_count++;
	    } else {
	       /* No origin recorded, try to register on literal package name */
	       sprintf(contents, "%s/%s/%s", LOG_DIR, p->name,
		     REQUIRED_BY_FNAME);
	       contfile = fopen(contents, "a");
	       if (!contfile) {
		  warnx("can't open dependency file '%s'!\n"
			"dependency registration is incomplete", contents);
	       } else {
		  fprintf(contfile, "%s\n", Plist.name);
		  if (fclose(contfile) == EOF) {
		     warnx("cannot properly close file %s", contents);
		  }
	       }
	    }
	}
	if (dep_count > 0) {
	    depmatches = matchallbyorigin((const char **)deporigins, NULL);
	    free(deporigins);
	    if (!IgnoreDeps && depmatches) {
		for (i = 0; i < dep_count; i++) {
		    if (depmatches[i]) {
			int j;
			char **tmp = depmatches[i];
			for (j = 0; tmp[j] != NULL; j++) {
			    /* Origin looked up */
			    sprintf(contents, "%s/%s/%s", LOG_DIR, tmp[j],
				REQUIRED_BY_FNAME);
			    if (depnames[i] && strcmp(depnames[i], tmp[j]) != 0)
				warnx("warning: package '%s' requires '%s', but '%s' "
				    "is installed", Plist.name, depnames[i], tmp[j]);
			    contfile = fopen(contents, "a");
			    if (!contfile) {
				warnx("can't open dependency file '%s'!\n"
				    "dependency registration is incomplete", contents);
			    } else {
				fprintf(contfile, "%s\n", Plist.name);
				if (fclose(contfile) == EOF)
				    warnx("cannot properly close file %s", contents);
			    }
			}
		    } else if (depnames[i]) {
			/* No package present with this origin, try literal package name */
			sprintf(contents, "%s/%s/%s", LOG_DIR, depnames[i],
			    REQUIRED_BY_FNAME);
			contfile = fopen(contents, "a");
			if (!contfile) {
			    warnx("can't open dependency file '%s'!\n"
				"dependency registration is incomplete", contents);
			} else {
			    fprintf(contfile, "%s\n", Plist.name);
			    if (fclose(contfile) == EOF) {
				warnx("cannot properly close file %s", contents);
			    }
			}
		    }
		}
	    }
	}
	if (Verbose)
	    printf("Package %s registered in %s\n", Plist.name, LogDir);
    }

    if ((p = find_plist(&Plist, PLIST_DISPLAY)) != NULL) {
	FILE *fp;
	char buf[BUFSIZ];

	snprintf(buf, sizeof buf, "%s/%s", LogDir, p->name);
	fp = fopen(buf, "r");
	if (fp) {
	    putc('\n', stdout);
	    while (fgets(buf, sizeof(buf), fp))
		fputs(buf, stdout);
	    putc('\n', stdout);
	    (void) fclose(fp);
	} else {
    	    if (!Fake) {
		warnx("cannot open %s as display file", buf);  
	    }
	}
    }

    goto success;

 bomb:
    code = 1;
    goto success;

 fail:
    /* Nuke the whole (installed) show, XXX but don't clean directories */
    if (!Fake)
	delete_package(FALSE, FALSE, &Plist);

 success:
    /* delete the packing list contents */
    free_plist(&Plist);
    leave_playpen();
    return code;
}
Example #2
0
/*
 * Try and fetch a file by URL, returning the directory name for where
 * it's unpacked, if successful.
 */
const char *
fileGetURL(const char *base, const char *spec, int keep_package)
{
    const char *rp;
    char *cp, *tmp;
    char fname[FILENAME_MAX];
    char pen[FILENAME_MAX];
    char pkg[FILENAME_MAX];
    char buf[8192];
    FILE *ftp;
    pid_t tpid;
    int pfd[2], pstat, r, w = 0;
    char *hint;
    int fd, pkgfd = 0;

    rp = NULL;
    /* Special tip that sysinstall left for us */
    hint = getenv("PKG_ADD_BASE");
    if (!isURL(spec)) {
	if (!base && !hint)
	    return NULL;
	/*
	 * We've been given an existing URL (that's known-good) and now we need
	 * to construct a composite one out of that and the basename we were
	 * handed as a dependency.
	 */
	if (base) {
	    strcpy(fname, base);
	    /*
	     * Advance back two slashes to get to the root of the package
	     * hierarchy
	     */
	    cp = strrchr(fname, '/');
	    if (cp) {
		*cp = '\0';	/* chop name */
		cp = strrchr(fname, '/');
	    }
	    if (cp) {
		*(cp + 1) = '\0';
		strcat(cp, "All/");
		strcat(cp, spec);
		if (getenv("PACKAGESUFFIX"))
		   strcat(cp, getenv("PACKAGESUFFIX"));
                else
		   strcat(cp, ".tbz");
	    }
	    else
		return NULL;
	}
	else {
	    /*
	     * Otherwise, we've been given an environment variable hinting
	     * at the right location from sysinstall
	     */
	    strcpy(fname, hint);
	    strcat(fname, spec);
	    if (getenv("PACKAGESUFFIX"))
	       strcat(fname, getenv("PACKAGESUFFIX"));
            else
	       strcat(fname, ".tbz");
	}
    }
    else
	strcpy(fname, spec);

    if (keep_package) {
	tmp = getenv("PKGDIR");
	strlcpy(pkg, tmp ? tmp : ".", sizeof(pkg));
	tmp = basename(fname);
	strlcat(pkg, "/", sizeof(pkg));
	strlcat(pkg, tmp, sizeof(pkg));
	if ((pkgfd = open(pkg, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
	    printf("Error: Unable to open %s\n", pkg);
	    perror("open");
	    return NULL;
	}
    }

    fetchDebug = (Verbose > 0);
    if ((ftp = fetchGetURL(fname, Verbose ? "v" : NULL)) == NULL) {
	printf("Error: Unable to get %s: %s\n",
	       fname, fetchLastErrString);
	/* If the fetch fails, yank the package. */
	if (keep_package && unlink(pkg) < 0 && Verbose) {
	    warnx("failed to remove partially fetched package: %s", pkg);
	}
	return NULL;
    }

    if (isatty(0) || Verbose)
	printf("Fetching %s...", fname), fflush(stdout);
    pen[0] = '\0';
    if ((rp = make_playpen(pen, 0)) == NULL) {
	printf("Error: Unable to construct a new playpen for FTP!\n");
	fclose(ftp);
	return NULL;
    }
    if (pipe(pfd) == -1) {
	warn("pipe()");
	cleanup(0);
	exit(2);
    }
    if ((tpid = fork()) == -1) {
	warn("pipe()");
	cleanup(0);
	exit(2);
    }
    if (!tpid) {
	dup2(pfd[0], 0);
	for (fd = getdtablesize() - 1; fd >= 3; --fd)
	    close(fd);
	execl("/usr/bin/tar", "tar",
	    Verbose ? "-xpjvf" : "-xpjf",
	    "-", (char *)0);
	_exit(2);
    }
    close(pfd[0]);
    for (;;) {
	if ((r = fread(buf, 1, sizeof buf, ftp)) < 1)
	    break;
	if ((w = write(pfd[1], buf, r)) != r)
	    break;
	if (keep_package) {
	    if ((w = write(pkgfd, buf, r)) != r)
		break;
	}    
    }
    if (ferror(ftp))
	warn("warning: error reading from server");
    fclose(ftp);
    if (keep_package) {
	close(pkgfd);
    } 
    close(pfd[1]);
    if (w == -1)
	warn("warning: error writing to tar");
    tpid = waitpid(tpid, &pstat, 0);
    if (Verbose)
	printf("tar command returns %d status\n", WEXITSTATUS(pstat));
    if (rp && (isatty(0) || Verbose))
	printf(" Done.\n");
    return rp;
}
Example #3
0
int
pkg_perform(char **pkgs)
{
    static const char *home;
    char *pkg = *pkgs;		/* Only one arg to create */
    char *cp;
    FILE *pkg_in, *fp;
    Package plist;
    int len;
    const char *suf;

    /* Preliminary setup */
    if (InstalledPkg == NULL)
	sanity_check();
    if (Verbose && !PlistOnly)
	printf("Creating package %s\n", pkg);

    /* chop suffix off if already specified, remembering if we want to compress  */
    len = strlen(pkg);
    if (len > 4) {
	if (!strcmp(&pkg[len - 4], ".tbz")) {
	    Zipper = BZIP2;
	    pkg[len - 4] = '\0';
	}
	else if (!strcmp(&pkg[len - 4], ".tgz")) {
	    Zipper = GZIP;
	    pkg[len - 4] = '\0';
	}
	else if (!strcmp(&pkg[len - 4], ".txz")) {
	    Zipper = XZ;
	    pkg[len - 4] = '\0';
	}
	else if (!strcmp(&pkg[len - 4], ".tar")) {
	    Zipper = NONE;
	    pkg[len - 4] = '\0';
	}
    }
    if (Zipper == BZIP2) {
	suf = "tbz";
	setenv("BZIP2", "--best", 0);
    } else if (Zipper == GZIP) {
	suf = "tgz";
	setenv("GZIP", "-9", 0);
    } else if (Zipper == XZ) {
	suf = "txz";
    } else
	suf = "tar";

    if (InstalledPkg != NULL) {
	char *pkgglob[] = { InstalledPkg, NULL };
	char **matched, **pkgs;
	int i, error;

	pkgs = pkgglob;
	if (MatchType != MATCH_EXACT) {
		matched = matchinstalled(MatchType, pkgs, &error);
		if (!error && matched != NULL)
			pkgs = matched;
		else if (MatchType != MATCH_GLOB)
	    		errx(1, "no packages match pattern");
	}
	/*
	 * Is there is only one installed package matching the pattern,
	 * we need to respect the optional pkg-filename parameter.  If,
	 * however, the pattern matches several packages, this parameter
	 * makes no sense and is ignored.
	 */
	if (pkgs[1] == NULL) {
	    if (pkg == InstalledPkg)
		pkg = *pkgs;
	    InstalledPkg = *pkgs;
	    if (!Recursive)
		return (create_from_installed(InstalledPkg, pkg, suf));
	    return (create_from_installed_recursive(pkg, suf));
	}
	for (i = 0; pkgs[i] != NULL; i++) {
	    InstalledPkg = pkg = pkgs[i];
	    if (!Recursive)
		create_from_installed(pkg, pkg, suf);
	    else
	        create_from_installed_recursive(pkg, suf);
	}
	return TRUE;
    }

    get_dash_string(&Comment);
    get_dash_string(&Desc);
    if (!strcmp(Contents, "-"))
	pkg_in = stdin;
    else {
	pkg_in = fopen(Contents, "r");
	if (!pkg_in) {
	    cleanup(0);
	    errx(2, "%s: unable to open contents file '%s' for input",
		__func__, Contents);
	}
    }
    plist.head = plist.tail = NULL;

    /* Stick the dependencies, if any, at the top */
    if (Pkgdeps) {
	char **deps, *deporigin;
	int i;
	int ndeps = 0;

	if (Verbose && !PlistOnly)
	    printf("Registering depends:");

	/* Count number of dependencies */
	for (cp = Pkgdeps; cp != NULL && *cp != '\0';
			   cp = strpbrk(++cp, " \t\n")) {
	    ndeps++;
	}

	if (ndeps != 0) {
	    /* Create easy to use NULL-terminated list */
	    deps = alloca(sizeof(*deps) * ndeps + 1);
	    if (deps == NULL) {
		errx(2, "%s: alloca() failed", __func__);
		/* Not reached */
	    }
	    for (i = 0; Pkgdeps;) {
		cp = strsep(&Pkgdeps, " \t\n");
		if (*cp) {
		    deps[i] = cp;
		    i++;
		}
	    }
	    ndeps = i;
	    deps[ndeps] = NULL;

	    sortdeps(deps);
	    for (i = 0; i < ndeps; i++) {
		deporigin = strchr(deps[i], ':');
		if (deporigin != NULL) {
		    *deporigin = '\0';
		    add_plist_top(&plist, PLIST_DEPORIGIN, ++deporigin);
		}
		add_plist_top(&plist, PLIST_PKGDEP, deps[i]);
		if (Verbose && !PlistOnly)
		    printf(" %s", deps[i]);
	    }
	}

	if (Verbose && !PlistOnly)
	    printf(".\n");
    }

    /* Put the conflicts directly after the dependencies, if any */
    if (Conflicts) {
	if (Verbose && !PlistOnly)
	    printf("Registering conflicts:");
	while (Conflicts) {
	   cp = strsep(&Conflicts, " \t\n");
	   if (*cp) {
		add_plist(&plist, PLIST_CONFLICTS, cp);
		if (Verbose && !PlistOnly)
		    printf(" %s", cp);
	   }
	}
	if (Verbose && !PlistOnly)
	    printf(".\n");
    }

    /* If a SrcDir override is set, add it now */
    if (SrcDir) {
	if (Verbose && !PlistOnly)
	    printf("Using SrcDir value of %s\n", SrcDir);
	add_plist(&plist, PLIST_SRC, SrcDir);
    }

    /* Slurp in the packing list */
    read_plist(&plist, pkg_in);

    /* Prefix should add an @cwd to the packing list */
    if (Prefix) {
        char resolved_prefix[PATH_MAX];
        if (realpath(Prefix, resolved_prefix) == NULL)
	    err(EXIT_FAILURE, "couldn't resolve path for prefix: %s", Prefix);
	add_plist_top(&plist, PLIST_CWD, resolved_prefix);
    }

    /* Add the origin if asked, at the top */
    if (Origin)
	add_plist_top(&plist, PLIST_ORIGIN, Origin);

    /*
     * Run down the list and see if we've named it, if not stick in a name
     * at the top.
     */
    if (find_plist(&plist, PLIST_NAME) == NULL)
	add_plist_top(&plist, PLIST_NAME, basename(pkg));

    if (asprintf(&cp, "PKG_FORMAT_REVISION:%d.%d", PLIST_FMT_VER_MAJOR,
		 PLIST_FMT_VER_MINOR) == -1) {
	errx(2, "%s: asprintf() failed", __func__);
    }
    add_plist_top(&plist, PLIST_COMMENT, cp);
    free(cp);

    /*
     * We're just here for to dump out a revised plist for the FreeBSD ports
     * hack.  It's not a real create in progress.
     */
    if (PlistOnly) {
	check_list(home, &plist);
	write_plist(&plist, stdout);
	exit(0);
    }

    /* Make a directory to stomp around in */
    home = make_playpen(PlayPen, 0);
    signal(SIGINT, cleanup);
    signal(SIGHUP, cleanup);

    /* Make first "real contents" pass over it */
    check_list(home, &plist);
    (void) umask(022);	/*
			 * Make sure gen'ed directories, files don't have
			 * group or other write bits.
			 */
    /* copy_plist(home, &plist); */
    /* mark_plist(&plist); */

    /* Now put the release specific items in */
    if (!Prefix) {
	add_plist(&plist, PLIST_CWD, ".");
    }
    write_file(COMMENT_FNAME, Comment);
    add_plist(&plist, PLIST_IGNORE, NULL);
    add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
    add_cksum(&plist, plist.tail, COMMENT_FNAME);
    write_file(DESC_FNAME, Desc);
    add_plist(&plist, PLIST_IGNORE, NULL);
    add_plist(&plist, PLIST_FILE, DESC_FNAME);
    add_cksum(&plist, plist.tail, DESC_FNAME);

    if (Install) {
	copy_file(home, Install, INSTALL_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
	add_cksum(&plist, plist.tail, INSTALL_FNAME);
    }
    if (PostInstall) {
	copy_file(home, PostInstall, POST_INSTALL_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, POST_INSTALL_FNAME);
	add_cksum(&plist, plist.tail, POST_INSTALL_FNAME);
    }
    if (DeInstall) {
	copy_file(home, DeInstall, DEINSTALL_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
	add_cksum(&plist, plist.tail, DEINSTALL_FNAME);
    }
    if (PostDeInstall) {
	copy_file(home, PostDeInstall, POST_DEINSTALL_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, POST_DEINSTALL_FNAME);
	add_cksum(&plist, plist.tail, POST_DEINSTALL_FNAME);
    }
    if (Require) {
	copy_file(home, Require, REQUIRE_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
	add_cksum(&plist, plist.tail, REQUIRE_FNAME);
    }
    if (Display) {
	copy_file(home, Display, DISPLAY_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, DISPLAY_FNAME);
	add_cksum(&plist, plist.tail, DISPLAY_FNAME);
	add_plist(&plist, PLIST_DISPLAY, DISPLAY_FNAME);
    }
    if (Mtree) {
	copy_file(home, Mtree, MTREE_FNAME);
	add_plist(&plist, PLIST_IGNORE, NULL);
	add_plist(&plist, PLIST_FILE, MTREE_FNAME);
	add_cksum(&plist, plist.tail, MTREE_FNAME);
	add_plist(&plist, PLIST_MTREE, MTREE_FNAME);
    }

    /* Finally, write out the packing list */
    fp = fopen(CONTENTS_FNAME, "w");
    if (!fp) {
	cleanup(0);
	errx(2, "%s: can't open file %s for writing",
	    __func__, CONTENTS_FNAME);
    }
    write_plist(&plist, fp);
    if (fclose(fp)) {
	cleanup(0);
	errx(2, "%s: error while closing %s",
	    __func__, CONTENTS_FNAME);
    }

    /* And stick it into a tar ball */
    make_dist(home, pkg, suf, &plist);

    /* Cleanup */
    free(Comment);
    free(Desc);
    free_plist(&plist);
    leave_playpen();
    return TRUE;	/* Success */
}