pen.c revision 33427
1132720Skan#ifndef lint
2132720Skanstatic const char rcsid[] =
3169691Skan	"$Id: pen.c,v 1.26 1998/01/09 14:52:18 jkh Exp $";
4132720Skan#endif
5132720Skan
6132720Skan/*
7132720Skan * FreeBSD install - a package for the installation and maintainance
8132720Skan * of non-core utilities.
9132720Skan *
10132720Skan * Redistribution and use in source and binary forms, with or without
11132720Skan * modification, are permitted provided that the following conditions
12132720Skan * are met:
13132720Skan * 1. Redistributions of source code must retain the above copyright
14132720Skan *    notice, this list of conditions and the following disclaimer.
15132720Skan * 2. Redistributions in binary form must reproduce the above copyright
16132720Skan *    notice, this list of conditions and the following disclaimer in the
17132720Skan *    documentation and/or other materials provided with the distribution.
18169691Skan *
19132720Skan * Jordan K. Hubbard
20132720Skan * 18 July 1993
21132720Skan *
22132720Skan * Routines for managing the "play pen".
23132720Skan *
24132720Skan */
25132720Skan
26132720Skan#include <err.h>
27132720Skan#include "lib.h"
28132720Skan#include <sys/signal.h>
29132720Skan#include <sys/param.h>
30132720Skan#include <sys/mount.h>
31132720Skan
32132720Skan/* For keeping track of where we are */
33132720Skanstatic char PenLocation[FILENAME_MAX];
34132720Skanstatic char Previous[FILENAME_MAX];
35132720Skan
36132720Skanchar *
37132720Skanwhere_playpen(void)
38132720Skan{
39132720Skan    return PenLocation;
40132720Skan}
41132720Skan
42132720Skan/* Find a good place to play. */
43132720Skanstatic char *
44132720Skanfind_play_pen(char *pen, size_t sz)
45132720Skan{
46132720Skan    char *cp;
47132720Skan    struct stat sb;
48132720Skan
49132720Skan    if (pen[0] && stat(pen, &sb) != FAIL && (min_free(pen) >= sz))
50132720Skan	return pen;
51169691Skan    else if ((cp = getenv("PKG_TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
52132720Skan	sprintf(pen, "%s/instmp.XXXXXX", cp);
53169691Skan    else if ((cp = getenv("TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
54169691Skan	sprintf(pen, "%s/instmp.XXXXXX", cp);
55169691Skan    else if (stat("/var/tmp", &sb) != FAIL && min_free("/var/tmp") >= sz)
56169691Skan	strcpy(pen, "/var/tmp/instmp.XXXXXX");
57132720Skan    else if (stat("/tmp", &sb) != FAIL && min_free("/tmp") >= sz)
58132720Skan	strcpy(pen, "/tmp/instmp.XXXXXX");
59132720Skan    else if ((stat("/usr/tmp", &sb) == SUCCESS || mkdir("/usr/tmp", 01777) == SUCCESS) && min_free("/usr/tmp") >= sz)
60132720Skan	strcpy(pen, "/usr/tmp/instmp.XXXXXX");
61132720Skan    else {
62132720Skan	cleanup(0);
63132720Skan	errx(2,
64132720Skan"can't find enough temporary space to extract the files, please set your\n"
65132720Skan"PKG_TMPDIR environment variable to a location with at least %d bytes\n"
66132720Skan"free", sz);
67132720Skan	return NULL;
68132720Skan    }
69132720Skan    return pen;
70132720Skan}
71132720Skan
72132720Skan/*
73132720Skan * Make a temporary directory to play in and chdir() to it, returning
74132720Skan * pathname of previous working directory.
75132720Skan */
76132720Skanchar *
77132720Skanmake_playpen(char *pen, size_t sz)
78132720Skan{
79132720Skan    if (PenLocation[0]) {
80132720Skan	errx(2, "make_playpen() called before closing previous pen: %s", pen);
81132720Skan	return NULL;
82132720Skan    }
83132720Skan    if (!find_play_pen(pen, sz))
84132720Skan	return NULL;
85132720Skan
86132720Skan    if (!mktemp(pen)) {
87132720Skan	cleanup(0);
88132720Skan	errx(2, "can't mktemp '%s'", pen);
89132720Skan    }
90132720Skan    if (mkdir(pen, 0755) == FAIL) {
91132720Skan	cleanup(0);
92132720Skan	errx(2, "can't mkdir '%s'", pen);
93132720Skan    }
94132720Skan    if (Verbose) {
95132720Skan	if (sz)
96132720Skan	    fprintf(stderr, "Requested space: %d bytes, free space: %qd bytes in %s\n", (int)sz, min_free(pen), pen);
97132720Skan    }
98132720Skan    if (min_free(pen) < sz) {
99132720Skan	rmdir(pen);
100132720Skan	cleanup(0);
101132720Skan	errx(2, "not enough free space to create '%s'.\n"
102132720Skan	     "Please set your PKG_TMPDIR environment variable to a location\n"
103132720Skan	     "with more space and\ntry the command again", pen);
104132720Skan    }
105132720Skan    if (!getcwd(Previous, FILENAME_MAX)) {
106132720Skan	upchuck("getcwd");
107132720Skan	return NULL;
108132720Skan    }
109132720Skan    if (chdir(pen) == FAIL)
110132720Skan	cleanup(0), errx(2, "can't chdir to '%s'", pen);
111169691Skan    strcpy(PenLocation, pen);
112169691Skan    return Previous;
113169691Skan}
114169691Skan
115169691Skan/* Convenience routine for getting out of playpen */
116169691Skanvoid
117169691Skanleave_playpen()
118169691Skan{
119169691Skan    void (*oldsig)(int);
120169691Skan
121169691Skan    /* Don't interrupt while we're cleaning up */
122169691Skan    oldsig = signal(SIGINT, SIG_IGN);
123132720Skan    if (Previous[0] && chdir(Previous) == FAIL)
124132720Skan	cleanup(0), errx(2, "can't chdir back to '%s'", Previous);
125132720Skan    else if (PenLocation[0]) {
126169691Skan	if (PenLocation[0] == '/' && vsystem("rm -rf %s", PenLocation))
127169691Skan	    warnx("couldn't remove temporary dir '%s'", PenLocation);
128132720Skan    }
129    Previous[0] = PenLocation[0] = '\0';
130    signal(SIGINT, oldsig);
131}
132
133off_t
134min_free(char *tmpdir)
135{
136    struct statfs buf;
137
138    if (statfs(tmpdir, &buf) != 0) {
139	warn("statfs");
140	return -1;
141    }
142    return (off_t)buf.f_bavail * (off_t)buf.f_bsize;
143}
144