]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/pkg_install/lib/pen.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / pkg_install / lib / pen.c
1 /*
2  * FreeBSD install - a package for the installation and maintenance
3  * of non-core utilities.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * Jordan K. Hubbard
15  * 18 July 1993
16  *
17  * Routines for managing the "play pen".
18  *
19  */
20
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD$");
23
24 #include "lib.h"
25 #include <err.h>
26 #include <libutil.h>
27 #include <libgen.h>
28 #include <sys/signal.h>
29 #include <sys/param.h>
30 #include <sys/mount.h>
31
32 /* For keeping track of where we are */
33 static char PenLocation[FILENAME_MAX];
34
35 char *
36 where_playpen(void)
37 {
38     return PenLocation;
39 }
40
41 /* Find a good place to play. */
42 static char *
43 find_play_pen(char *pen, off_t sz)
44 {
45     char *cp;
46     struct stat sb;
47     char humbuf[6];
48
49     if (pen[0] && isdir(dirname(pen)) == TRUE && (min_free(dirname(pen)) >= sz))
50         return pen;
51     else if ((cp = getenv("PKG_TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
52         sprintf(pen, "%s/instmp.XXXXXX", cp);
53     else if ((cp = getenv("TMPDIR")) != NULL && stat(cp, &sb) != FAIL && (min_free(cp) >= sz))
54         sprintf(pen, "%s/instmp.XXXXXX", cp);
55     else if (stat("/var/tmp", &sb) != FAIL && min_free("/var/tmp") >= sz)
56         strcpy(pen, "/var/tmp/instmp.XXXXXX");
57     else if (stat("/tmp", &sb) != FAIL && min_free("/tmp") >= sz)
58         strcpy(pen, "/tmp/instmp.XXXXXX");
59     else if ((stat("/usr/tmp", &sb) == SUCCESS || mkdir("/usr/tmp", 01777) == SUCCESS) && min_free("/usr/tmp") >= sz)
60         strcpy(pen, "/usr/tmp/instmp.XXXXXX");
61     else {
62         cleanup(0);
63         humanize_number(humbuf, sizeof humbuf, sz, "", HN_AUTOSCALE,
64             HN_NOSPACE);
65         errx(2,
66 "%s: can't find enough temporary space to extract the files, please set your\n"
67 "PKG_TMPDIR environment variable to a location with at least %s bytes\n"
68 "free", __func__, humbuf);
69         return NULL;
70     }
71     return pen;
72 }
73
74 #define MAX_STACK       20
75 static char *pstack[MAX_STACK];
76 static int pdepth = -1;
77
78 static const char *
79 pushPen(const char *pen)
80 {
81     if (++pdepth == MAX_STACK)
82         errx(2, "%s: stack overflow.\n", __func__);
83     pstack[pdepth] = strdup(pen);
84
85     return pstack[pdepth];
86 }
87
88 static void
89 popPen(char *pen)
90 {
91     if (pdepth == -1) {
92         pen[0] = '\0';
93         return;
94     }
95     strcpy(pen, pstack[pdepth]);
96     free(pstack[pdepth--]);
97 }
98     
99 /*
100  * Make a temporary directory to play in and chdir() to it, returning
101  * pathname of previous working directory.
102  */
103 const char *
104 make_playpen(char *pen, off_t sz)
105 {
106     char humbuf1[6], humbuf2[6];
107     char cwd[FILENAME_MAX];
108
109     if (!find_play_pen(pen, sz))
110         return NULL;
111
112     if (!mkdtemp(pen)) {
113         cleanup(0);
114         errx(2, "%s: can't mktemp '%s'", __func__, pen);
115     }
116
117     if (Verbose) {
118         if (sz) {
119             humanize_number(humbuf1, sizeof humbuf1, sz, "", HN_AUTOSCALE,
120                 HN_NOSPACE);
121             humanize_number(humbuf2, sizeof humbuf2, min_free(pen),
122                 "", HN_AUTOSCALE, HN_NOSPACE);
123             fprintf(stderr, "Requested space: %s bytes, free space: %s bytes in %s\n", humbuf1, humbuf2, pen);
124         }
125     }
126
127     if (min_free(pen) < sz) {
128         rmdir(pen);
129         cleanup(0);
130         errx(2, "%s: not enough free space to create '%s'.\n"
131              "Please set your PKG_TMPDIR environment variable to a location\n"
132              "with more space and\ntry the command again", __func__, pen);
133     }
134
135     if (!getcwd(cwd, FILENAME_MAX)) {
136         upchuck("getcwd");
137         return NULL;
138     }
139
140     if (chdir(pen) == FAIL) {
141         cleanup(0);
142         errx(2, "%s: can't chdir to '%s'", __func__, pen);
143     }
144
145     strcpy(PenLocation, pen);
146     return pushPen(cwd);
147 }
148
149 /* Convenience routine for getting out of playpen */
150 int
151 leave_playpen()
152 {
153     static char left[FILENAME_MAX];
154     void (*oldsig)(int);
155
156     if (!PenLocation[0])
157         return 0;
158
159     /* Don't interrupt while we're cleaning up */
160     oldsig = signal(SIGINT, SIG_IGN);
161     strcpy(left, PenLocation);
162     popPen(PenLocation);
163
164     if (chdir(PenLocation) == FAIL) {
165         cleanup(0);
166         errx(2, "%s: can't chdir back to '%s'", __func__, PenLocation);
167     }
168
169     if (left[0] == '/' && vsystem("/bin/rm -rf %s", left))
170         warnx("couldn't remove temporary dir '%s'", left);
171     signal(SIGINT, oldsig);
172
173     return 1;
174 }
175
176 off_t
177 min_free(const char *tmpdir)
178 {
179     struct statfs buf;
180
181     if (statfs(tmpdir, &buf) != 0) {
182         warn("statfs");
183         return -1;
184     }
185     return (off_t)buf.f_bavail * (off_t)buf.f_bsize;
186 }