4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2017 Peter Tribble.
27 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
32 /* All Rights Reserved */
40 #include <sys/types.h>
41 #include <sys/param.h>
43 #include <sys/statvfs.h>
52 #include "pkginstall.h"
54 extern struct cfextra
**extlist
;
56 extern char instdir
[];
59 #define LIM_BFREE 150LL
60 #define LIM_FFREE 25LL
62 #define WRN_STATVFS "WARNING: unable to stat filesystem mounted on <%s>"
64 #define WRN_NOBLKS "The %s filesystem has %llu free blocks. The current " \
65 "installation requires %llu blocks, which includes a " \
66 "required %llu block buffer for open " \
67 "deleted files. %llu more blocks are needed."
69 #define WRN_NOFILES "The %s filesystem has %llu free file nodes. The " \
70 "current installation requires %llu file nodes, " \
71 "which includes a required %llu file node buffer " \
72 "for temporary files. %llu more file nodes " \
77 static void warn(int type
, char *name
, fsblkcnt_t need
, fsblkcnt_t avail
,
79 static int fsys_stat(int n
);
80 static int readmap(int *error
);
81 static int readspace(char *spacefile
, int *error
);
84 dockspace(char *spacefile
)
86 struct fstable
*fs_tab
;
92 * Also, vanilla SVr4 code used the output from popen()
93 * on the "/etc/mount" command. However, we need to get more
94 * information about mounted filesystems, so we use the C
95 * interfaces to the mount table, which also happens to be
96 * much faster than running another process. Since several
97 * of the pkg commands need access to the mount table, this
98 * code is now in libinst. However, mount table info is needed
99 * at the time the base directory is determined, so the call
100 * to get the mount table information is in main.c
103 if (readmap(&error
) || readspace(spacefile
, &error
))
106 for (i
= 0; fs_tab
= get_fs_entry(i
); ++i
) {
107 if ((!fs_tab
->fused
) && (!fs_tab
->bused
))
108 continue; /* not used by us */
110 if (fs_tab
->bfree
< (LIM_BFREE
+ fs_tab
->bused
)) {
111 warn(TYPE_BLCK
, fs_tab
->name
, fs_tab
->bused
,
112 fs_tab
->bfree
, LIM_BFREE
);
117 if ((long)fs_tab
->ffree
== -1L)
119 if (fs_tab
->ffree
< (LIM_FFREE
+ fs_tab
->fused
)) {
120 warn(TYPE_NODE
, fs_tab
->name
, fs_tab
->fused
,
121 fs_tab
->ffree
, LIM_FFREE
);
129 warn(int type
, char *name
, fsblkcnt_t need
, fsblkcnt_t avail
, fsblkcnt_t limit
)
131 logerr(gettext("WARNING:"));
132 if (type
== TYPE_BLCK
) {
133 logerr(gettext(WRN_NOBLKS
), name
, avail
, (need
+ limit
), limit
,
134 (need
+ limit
- avail
));
136 logerr(gettext(WRN_NOFILES
), name
, avail
, (need
+ limit
), limit
,
137 (need
+ limit
- avail
));
144 struct statvfs64 svfsb
;
145 struct fstable
*fs_tab
;
150 fs_tab
= get_fs_entry(n
);
153 * At this point, we know we need information
154 * about a particular filesystem, so we can do the
155 * statvfs() now. For performance reasons, we only want to
156 * stat the filesystem once, at the first time we need to,
157 * and so we can key on whether or not we have the
158 * block size for that filesystem.
160 if (fs_tab
->bsize
!= 0)
163 if (statvfs64(fs_tab
->name
, &svfsb
)) {
164 logerr(gettext(WRN_STATVFS
), fs_tab
->name
);
169 * statvfs returns number of fragment size blocks
170 * so will change this to number of 512 byte blocks
172 fs_tab
->bsize
= svfsb
.f_bsize
;
173 fs_tab
->frsize
= svfsb
.f_frsize
;
174 fs_tab
->bfree
= ((svfsb
.f_frsize
> 0) ?
175 howmany(svfsb
.f_frsize
, DEV_BSIZE
) :
176 howmany(svfsb
.f_bsize
, DEV_BSIZE
)) * svfsb
.f_bavail
;
177 fs_tab
->ffree
= (svfsb
.f_favail
> 0) ? svfsb
.f_favail
: svfsb
.f_ffree
;
182 * This function reads all of the package objects, maps them to their target
183 * filesystems and adds up the amount of space used on each. Wherever you see
184 * "fsys_value", that's the apparent filesystem which could be a temporary
185 * loopback mount for the purpose of constructing the client filesystem. It
186 * isn't necessarily the real target filesystem. Where you see "fsys_base"
187 * that's the real filesystem to which fsys_value may just refer. If this is
188 * installing to a standalone or a server, fsys_value will almost always be
189 * the same as fsys_base.
194 struct fstable
*fs_tab
;
198 char tpath
[PATH_MAX
];
203 * Handle the installation files (ftype i) that are in the
206 for (i
= 0; (ext
= extlist
[i
]) != NULL
; i
++) {
207 ept
= &(ext
->cf_ent
);
209 if (ept
->ftype
!= 'i')
213 * These paths are treated differently from the others
214 * since their full pathnames are not included in the
217 if (strcmp(ept
->path
, "pkginfo") == 0)
218 (void) sprintf(tpath
, "%s/%s", pkgloc
, ept
->path
);
220 (void) sprintf(tpath
, "%s/install/%s", pkgloc
,
223 /* If we haven't done an fsys() series, do one */
224 if (ext
->fsys_value
== BADFSYS
)
225 ext
->fsys_value
= fsys(tpath
);
228 * Now check if this is a base or apparent filesystem. If
229 * it's just apparent, get the resolved filesystem entry,
230 * otherwise, base and value are the same.
232 if (use_srvr_map_n(ext
->fsys_value
))
233 ext
->fsys_base
= resolved_fsys(tpath
);
235 ext
->fsys_base
= ext
->fsys_value
;
237 if (fsys_stat(ext
->fsys_base
)) {
243 * Don't accumulate space requirements on read-only
244 * remote filesystems.
246 if (is_remote_fs_n(ext
->fsys_value
) &&
247 !is_fs_writeable_n(ext
->fsys_value
))
250 fs_tab
= get_fs_entry(ext
->fsys_base
);
253 if (ept
->cinfo
.size
!= BADCONT
)
254 blk
= nblk(ept
->cinfo
.size
,
259 fs_tab
->bused
+= blk
;
263 * Handle the other files in the eptlist.
265 for (i
= 0; (ext
= extlist
[i
]) != NULL
; i
++) {
266 ept
= &(extlist
[i
]->cf_ent
);
268 if (ept
->ftype
== 'i')
272 * Don't recalculate package objects that are already in the
275 if (ext
->mstat
.preloaded
)
279 * Don't accumulate space requirements on read-only
280 * remote filesystems.
282 if (is_remote_fs(ept
->path
, &(ext
->fsys_value
)) &&
283 !is_fs_writeable(ept
->path
, &(ext
->fsys_value
)))
287 * Now check if this is a base or apparent filesystem. If
288 * it's just apparent, get the resolved filesystem entry,
289 * otherwise, base and value are the same.
291 if (use_srvr_map_n(ext
->fsys_value
))
292 ext
->fsys_base
= resolved_fsys(tpath
);
294 ext
->fsys_base
= ext
->fsys_value
;
296 /* At this point we know we have a good fsys_base. */
297 if (fsys_stat(ext
->fsys_base
)) {
303 * We have to stat this path based upon it's real location.
304 * If this is a server-remap, ept->path isn't the real
307 if (use_srvr_map_n(ext
->fsys_value
))
308 strcpy(tpath
, server_map(ept
->path
, ext
->fsys_value
));
310 strcpy(tpath
, ept
->path
);
312 fs_tab
= get_fs_entry(ext
->fsys_base
);
313 if (stat(tpath
, &statbuf
)) {
314 /* path cannot be accessed */
316 if (strchr("dxs", ept
->ftype
))
321 else if (ept
->cinfo
.size
!= BADCONT
)
322 blk
= nblk(ept
->cinfo
.size
,
328 /* path already exists */
329 if (strchr("dxs", ept
->ftype
))
331 else if (ept
->cinfo
.size
!= BADCONT
) {
332 fsblkcnt_t new_size
, old_size
;
333 new_size
= nblk(ept
->cinfo
.size
,
336 old_size
= nblk(statbuf
.st_size
,
340 * negative blocks show room freed, but since
341 * order of installation is uncertain show
344 if (new_size
< old_size
)
347 blk
= new_size
- old_size
;
351 fs_tab
->bused
+= blk
;
357 readspace(char *spacefile
, int *error
)
364 if (spacefile
== NULL
)
367 if ((fp
= fopen(spacefile
, "r")) == NULL
) {
368 progerr(gettext("unable to open spacefile %s"), spacefile
);
372 while (fgets(line
, LSIZE
, fp
)) {
373 struct fstable
*fs_tab
;
374 char *pt
, path
[PATH_MAX
];
377 for (pt
= line
; isspace(*pt
); /* void */)
379 if (*pt
== '#' || *pt
== '\0')
382 (void) sscanf(line
, "%s %ld %ld", path
, &blocks
, &nodes
);
384 basepath(path
, get_basedir(), get_inst_root());
387 n
= resolved_fsys(path
);
394 * Don't accumulate space requirements on read-only
395 * remote filesystems. NOTE: For some reason, this
396 * used to check for !remote && read only. If this
397 * blows up later, then maybe that was correct -- JST
399 if (is_remote_fs_n(n
) && !is_fs_writeable_n(n
))
402 fs_tab
= get_fs_entry(n
);
404 fs_tab
->bused
+= blocks
;
405 fs_tab
->fused
+= nodes
;