xref: /openbsd-src/usr.bin/rdistd/filesys.c (revision f59ead6eb5b76421d44dbbc2c0e7f44d9d348873)
1*f59ead6eSguenther /*	$OpenBSD: filesys.c,v 1.19 2015/01/21 04:08:37 guenther Exp $	*/
21258a77dSderaadt 
3fdd8ad51Sdm /*
4fdd8ad51Sdm  * Copyright (c) 1983 Regents of the University of California.
5fdd8ad51Sdm  * All rights reserved.
6fdd8ad51Sdm  *
7fdd8ad51Sdm  * Redistribution and use in source and binary forms, with or without
8fdd8ad51Sdm  * modification, are permitted provided that the following conditions
9fdd8ad51Sdm  * are met:
10fdd8ad51Sdm  * 1. Redistributions of source code must retain the above copyright
11fdd8ad51Sdm  *    notice, this list of conditions and the following disclaimer.
12fdd8ad51Sdm  * 2. Redistributions in binary form must reproduce the above copyright
13fdd8ad51Sdm  *    notice, this list of conditions and the following disclaimer in the
14fdd8ad51Sdm  *    documentation and/or other materials provided with the distribution.
15f75387cbSmillert  * 3. Neither the name of the University nor the names of its contributors
16fdd8ad51Sdm  *    may be used to endorse or promote products derived from this software
17fdd8ad51Sdm  *    without specific prior written permission.
18fdd8ad51Sdm  *
19fdd8ad51Sdm  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20fdd8ad51Sdm  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21fdd8ad51Sdm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22fdd8ad51Sdm  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23fdd8ad51Sdm  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24fdd8ad51Sdm  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25fdd8ad51Sdm  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26fdd8ad51Sdm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27fdd8ad51Sdm  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28fdd8ad51Sdm  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29fdd8ad51Sdm  * SUCH DAMAGE.
30fdd8ad51Sdm  */
31fdd8ad51Sdm 
32b9fc9a72Sderaadt #include <sys/types.h>
33a59aa421Sguenther #include <sys/mount.h>
34e06ba677Sguenther #include <errno.h>
35e06ba677Sguenther #include <string.h>
36e06ba677Sguenther #include <unistd.h>
37a59aa421Sguenther 
38e06ba677Sguenther #include "server.h"
3940934732Smillert 
40fdd8ad51Sdm /*
41fdd8ad51Sdm  * This file contains functions dealing with getting info
42fdd8ad51Sdm  * about mounted filesystems.
43fdd8ad51Sdm  */
44fdd8ad51Sdm 
45fdd8ad51Sdm 
46fdd8ad51Sdm jmp_buf env;
47fdd8ad51Sdm 
48fdd8ad51Sdm /*
49fdd8ad51Sdm  * Given a pathname, find the fullest component that exists.
50fdd8ad51Sdm  * If statbuf is not NULL, set it to point at our stat buffer.
51fdd8ad51Sdm  */
5240934732Smillert char *
find_file(char * pathname,struct stat * statbuf,int * isvalid)5340934732Smillert find_file(char *pathname, struct stat *statbuf, int *isvalid)
54fdd8ad51Sdm {
55b9fc9a72Sderaadt 	static char last_pathname[PATH_MAX];
56b9fc9a72Sderaadt 	static char file[PATH_MAX + 3];
57fdd8ad51Sdm 	static struct stat filestat;
58c0932ef1Smpech 	char *p;
59fdd8ad51Sdm 
60fdd8ad51Sdm 	/*
61fdd8ad51Sdm 	 * Mark the statbuf as invalid to start with.
62fdd8ad51Sdm 	 */
63fdd8ad51Sdm 	*isvalid = 0;
64fdd8ad51Sdm 
65fdd8ad51Sdm 	/*
66fdd8ad51Sdm 	 * If this is the same pathname as the last time, and
67fdd8ad51Sdm 	 * the file buffer is valid and we're doing the same stat()
68fdd8ad51Sdm 	 * or lstat(), then set statbuf to the last filestat and
69fdd8ad51Sdm 	 * return the last file we found.
70fdd8ad51Sdm 	 */
71fdd8ad51Sdm 	if (strcmp(pathname, last_pathname) == 0 && file[0]) {
72fdd8ad51Sdm 		if (statbuf)
73fdd8ad51Sdm 			statbuf = &filestat;
74fdd8ad51Sdm 		if (strcmp(pathname, file) == 0)
75fdd8ad51Sdm 			*isvalid = 1;
76fdd8ad51Sdm 		return(file);
77fdd8ad51Sdm 	}
78fdd8ad51Sdm 
7940934732Smillert 	if (strlen(pathname) > sizeof(file) + 3) {
80fdd8ad51Sdm 		error("%s: Name to large for buffer.", pathname);
81b0f9517bSmillert 	        return(NULL);
82fdd8ad51Sdm 	}
83fdd8ad51Sdm 
84fdd8ad51Sdm 	/*
85fdd8ad51Sdm 	 * Save for next time
86fdd8ad51Sdm 	 */
8740934732Smillert 	(void) strlcpy(last_pathname, pathname, sizeof(last_pathname));
88fdd8ad51Sdm 
89fdd8ad51Sdm 	if (*pathname == '/')
9040934732Smillert 	        (void) strlcpy(file, pathname, sizeof(file));
91fdd8ad51Sdm 	else {
92fdd8ad51Sdm 		/*
93fdd8ad51Sdm 		 * Ensure we have a directory (".") in our path
94fdd8ad51Sdm 		 * so we have something to stat in case the file
95fdd8ad51Sdm 		 * does not exist.
96fdd8ad51Sdm 		 */
9740934732Smillert 	        (void) strlcpy(file, "./", sizeof(file));
9840934732Smillert 		(void) strlcat(file, pathname, sizeof(file));
99fdd8ad51Sdm 	}
100fdd8ad51Sdm 
101fdd8ad51Sdm 	while (lstat(file, &filestat) != 0) {
102fdd8ad51Sdm 		/*
103fdd8ad51Sdm 		 * Trim the last part of the pathname to try next level up
104fdd8ad51Sdm 		 */
105fdd8ad51Sdm 		if (errno == ENOENT) {
106fdd8ad51Sdm 			/*
107fdd8ad51Sdm 			 * Trim file name to get directory name.
108fdd8ad51Sdm 			 * Normally we want to change /dir1/dir2/file
109fdd8ad51Sdm 			 * into "/dir1/dir2/."
110fdd8ad51Sdm 			 */
111*f59ead6eSguenther 			if ((p = strrchr(file, '/')) != NULL) {
1121f3f6ebaSmillert 				if (strcmp(p, "/.") == 0) {
1131f3f6ebaSmillert 					*p = CNULL;
1141f3f6ebaSmillert 				} else {
115fdd8ad51Sdm 					*++p = '.';
116fdd8ad51Sdm 					*++p = CNULL;
1171f3f6ebaSmillert 				}
118fdd8ad51Sdm 			} else {
119fdd8ad51Sdm 				/*
120fdd8ad51Sdm 				 * Couldn't find anything, so give up.
121fdd8ad51Sdm 				 */
122fdd8ad51Sdm 				debugmsg(DM_MISC, "Cannot find dir of `%s'",
123fdd8ad51Sdm 					 pathname);
124b0f9517bSmillert 				return(NULL);
125fdd8ad51Sdm 			}
126fdd8ad51Sdm 			continue;
127fdd8ad51Sdm 		} else {
128fdd8ad51Sdm 			error("%s: lstat failed: %s", pathname, SYSERR);
129b0f9517bSmillert 			return(NULL);
130fdd8ad51Sdm 		}
131fdd8ad51Sdm 	}
132fdd8ad51Sdm 
133fdd8ad51Sdm 	if (statbuf)
134*f59ead6eSguenther 		bcopy(&filestat, statbuf, sizeof(filestat));
135fdd8ad51Sdm 
136fdd8ad51Sdm 	/*
137fdd8ad51Sdm 	 * Trim the "/." that we added.
138fdd8ad51Sdm 	 */
139fdd8ad51Sdm 	p = &file[strlen(file) - 1];
140fdd8ad51Sdm 	if (*p == '.')
141fdd8ad51Sdm 		*p-- = CNULL;
142fdd8ad51Sdm 	for ( ; p && *p && *p == '/' && p != file; --p)
143fdd8ad51Sdm 		*p = CNULL;
144fdd8ad51Sdm 
145fdd8ad51Sdm 	/*
146fdd8ad51Sdm 	 * If this file is a symlink we really want the parent directory
147fdd8ad51Sdm 	 * name in case the symlink points to another filesystem.
148fdd8ad51Sdm 	 */
149fdd8ad51Sdm 	if (S_ISLNK(filestat.st_mode))
150*f59ead6eSguenther 		if ((p = strrchr(file, '/')) && *p+1) {
151fdd8ad51Sdm 			/* Is this / (root)? */
152fdd8ad51Sdm 			if (p == file)
153fdd8ad51Sdm 				file[1] = CNULL;
154fdd8ad51Sdm 			else
155fdd8ad51Sdm 				*p = CNULL;
156fdd8ad51Sdm 		}
157fdd8ad51Sdm 
158fdd8ad51Sdm 	if (strcmp(pathname, file) == 0)
159fdd8ad51Sdm 		*isvalid = 1;
160fdd8ad51Sdm 
16172db5e53Sguenther 	return(*file ? file : NULL);
162fdd8ad51Sdm }
163fdd8ad51Sdm 
164fdd8ad51Sdm 
165fdd8ad51Sdm /*
166fdd8ad51Sdm  * Find the device that "filest" is on in the "mntinfo" linked list.
167fdd8ad51Sdm  */
16840934732Smillert mntent_t *
findmnt(struct stat * filest,struct mntinfo * mntinfo)16940934732Smillert findmnt(struct stat *filest, struct mntinfo *mntinfo)
170fdd8ad51Sdm {
171c0932ef1Smpech 	struct mntinfo *mi;
172fdd8ad51Sdm 
173fdd8ad51Sdm 	for (mi = mntinfo; mi; mi = mi->mi_nxt) {
174fdd8ad51Sdm 		if (mi->mi_mnt->me_flags & MEFLAG_IGNORE)
175fdd8ad51Sdm 			continue;
176*f59ead6eSguenther 		if (filest->st_dev == mi->mi_dev)
177fdd8ad51Sdm 			return(mi->mi_mnt);
178fdd8ad51Sdm 	}
179fdd8ad51Sdm 
180b0f9517bSmillert 	return(NULL);
181fdd8ad51Sdm }
182fdd8ad51Sdm 
183fdd8ad51Sdm /*
184fdd8ad51Sdm  * Is "mnt" a duplicate of any of the mntinfo->mi_mnt elements?
185fdd8ad51Sdm  */
18640934732Smillert int
isdupmnt(mntent_t * mnt,struct mntinfo * mntinfo)18740934732Smillert isdupmnt(mntent_t *mnt, struct mntinfo *mntinfo)
188fdd8ad51Sdm {
189c0932ef1Smpech 	struct mntinfo *m;
190fdd8ad51Sdm 
191fdd8ad51Sdm 	for (m = mntinfo; m; m = m->mi_nxt)
192fdd8ad51Sdm 		if (strcmp(m->mi_mnt->me_path, mnt->me_path) == 0)
193fdd8ad51Sdm 			return(1);
194fdd8ad51Sdm 
195fdd8ad51Sdm 	return(0);
196fdd8ad51Sdm }
197fdd8ad51Sdm 
198fdd8ad51Sdm /*
199fdd8ad51Sdm  * Alarm clock
200fdd8ad51Sdm  */
20140934732Smillert void
wakeup(int dummy)20240934732Smillert wakeup(int dummy)
203fdd8ad51Sdm {
204fdd8ad51Sdm 	debugmsg(DM_CALL, "wakeup() in filesys.c called");
205fdd8ad51Sdm 	longjmp(env, 1);
206fdd8ad51Sdm }
207fdd8ad51Sdm 
208fdd8ad51Sdm /*
209fdd8ad51Sdm  * Make a linked list of mntinfo structures.
210fdd8ad51Sdm  * Use "mi" as the base of the list if it's non NULL.
211fdd8ad51Sdm  */
21240934732Smillert struct mntinfo *
makemntinfo(struct mntinfo * mi)21340934732Smillert makemntinfo(struct mntinfo *mi)
214fdd8ad51Sdm {
21524288699Smillert 	static struct mntinfo *mntinfo;
21624288699Smillert 	struct mntinfo *newmi, *m;
217fdd8ad51Sdm 	struct stat mntstat;
218fdd8ad51Sdm 	mntent_t *mnt;
219fdd8ad51Sdm 	int timeo = 310;
220fdd8ad51Sdm 
22141c54e56Sguenther 	if (!setmountent()) {
222a59aa421Sguenther 		message(MT_NERROR, "setmntent failed: %s", SYSERR);
223b0f9517bSmillert 		return(NULL);
224fdd8ad51Sdm 	}
225fdd8ad51Sdm 
226fdd8ad51Sdm 	(void) signal(SIGALRM, wakeup);
227fdd8ad51Sdm 	(void) alarm(timeo);
228fdd8ad51Sdm 	if (setjmp(env)) {
229fdd8ad51Sdm 		message(MT_NERROR, "Timeout getting mount info");
230b0f9517bSmillert 		return(NULL);
231fdd8ad51Sdm 	}
232fdd8ad51Sdm 
233fdd8ad51Sdm 	mntinfo = mi;
234a59aa421Sguenther 	while ((mnt = getmountent()) != NULL) {
235e06ba677Sguenther 		debugmsg(DM_MISC, "mountent = '%s'", mnt->me_path);
236fdd8ad51Sdm 
237fdd8ad51Sdm 		/*
238fdd8ad51Sdm 		 * Make sure we don't already have it for some reason
239fdd8ad51Sdm 		 */
240fdd8ad51Sdm 		if (isdupmnt(mnt, mntinfo))
241fdd8ad51Sdm 			continue;
242fdd8ad51Sdm 
243fdd8ad51Sdm 		/*
244fdd8ad51Sdm 		 * Get stat info
245fdd8ad51Sdm 		 */
246fdd8ad51Sdm 		if (stat(mnt->me_path, &mntstat) != 0) {
247fdd8ad51Sdm 			message(MT_WARNING, "%s: Cannot stat filesystem: %s",
248fdd8ad51Sdm 				mnt->me_path, SYSERR);
249fdd8ad51Sdm 			continue;
250fdd8ad51Sdm 		}
251fdd8ad51Sdm 
252fdd8ad51Sdm 		/*
253fdd8ad51Sdm 		 * Create new entry
254fdd8ad51Sdm 		 */
255*f59ead6eSguenther 		newmi = xcalloc(1, sizeof(*newmi));
256fdd8ad51Sdm 		newmi->mi_mnt = newmountent(mnt);
257*f59ead6eSguenther 		newmi->mi_dev = mntstat.st_dev;
258fdd8ad51Sdm 
259fdd8ad51Sdm 		/*
260fdd8ad51Sdm 		 * Add entry to list
261fdd8ad51Sdm 		 */
262fdd8ad51Sdm 		if (mntinfo) {
26340934732Smillert 			for (m = mntinfo; m->mi_nxt; m = m->mi_nxt)
26440934732Smillert 				continue;
265fdd8ad51Sdm 			m->mi_nxt = newmi;
266fdd8ad51Sdm 		} else
267fdd8ad51Sdm 			mntinfo = newmi;
268fdd8ad51Sdm 	}
269fdd8ad51Sdm 
270a59aa421Sguenther 	alarm(0);
271a59aa421Sguenther 	endmountent();
272fdd8ad51Sdm 
273fdd8ad51Sdm 	return(mntinfo);
274fdd8ad51Sdm }
275fdd8ad51Sdm 
276fdd8ad51Sdm /*
277fdd8ad51Sdm  * Given a name like /usr/src/etc/foo.c returns the mntent
278fdd8ad51Sdm  * structure for the file system it lives in.
279fdd8ad51Sdm  *
280fdd8ad51Sdm  * If "statbuf" is not NULL it is used as the stat buffer too avoid
281fdd8ad51Sdm  * stat()'ing the file again back in server.c.
282fdd8ad51Sdm  */
28340934732Smillert mntent_t *
getmntpt(char * pathname,struct stat * statbuf,int * isvalid)28440934732Smillert getmntpt(char *pathname, struct stat *statbuf, int *isvalid)
285fdd8ad51Sdm {
286fdd8ad51Sdm 	static struct mntinfo *mntinfo = NULL;
287fdd8ad51Sdm 	static struct stat filestat;
288fdd8ad51Sdm 	struct stat *pstat;
289fdd8ad51Sdm 	struct mntinfo *tmpmi;
290c0932ef1Smpech 	mntent_t *mnt;
291fdd8ad51Sdm 
292fdd8ad51Sdm 	/*
293fdd8ad51Sdm 	 * Use the supplied stat buffer if not NULL or our own.
294fdd8ad51Sdm 	 */
295fdd8ad51Sdm 	if (statbuf)
296fdd8ad51Sdm 		pstat = statbuf;
297fdd8ad51Sdm 	else
298fdd8ad51Sdm 		pstat = &filestat;
299fdd8ad51Sdm 
300fdd8ad51Sdm 	if (!find_file(pathname, pstat, isvalid))
301b0f9517bSmillert 	        return(NULL);
302fdd8ad51Sdm 
303fdd8ad51Sdm 	/*
304fdd8ad51Sdm 	 * Make mntinfo if it doesn't exist.
305fdd8ad51Sdm 	 */
306fdd8ad51Sdm 	if (!mntinfo)
307b0f9517bSmillert 		mntinfo = makemntinfo(NULL);
308fdd8ad51Sdm 
309fdd8ad51Sdm 	/*
310fdd8ad51Sdm 	 * Find the mnt that pathname is on.
311fdd8ad51Sdm 	 */
31240934732Smillert 	if ((mnt = findmnt(pstat, mntinfo)) != NULL)
313fdd8ad51Sdm 		return(mnt);
314fdd8ad51Sdm 
315fdd8ad51Sdm 	/*
316fdd8ad51Sdm 	 * We failed to find correct mnt, so maybe it's a newly
317fdd8ad51Sdm 	 * mounted filesystem.  We rebuild mntinfo and try again.
318fdd8ad51Sdm 	 */
31940934732Smillert 	if ((tmpmi = makemntinfo(mntinfo)) != NULL) {
320fdd8ad51Sdm 		mntinfo = tmpmi;
32140934732Smillert 		if ((mnt = findmnt(pstat, mntinfo)) != NULL)
322fdd8ad51Sdm 			return(mnt);
323fdd8ad51Sdm 	}
324fdd8ad51Sdm 
325fdd8ad51Sdm 	error("%s: Could not find mount point", pathname);
326b0f9517bSmillert 	return(NULL);
327fdd8ad51Sdm }
328fdd8ad51Sdm 
329fdd8ad51Sdm 
330fdd8ad51Sdm /*
331fdd8ad51Sdm  * Is "path" NFS mounted?  Return 1 if it is, 0 if not, or -1 on error.
332fdd8ad51Sdm  */
33340934732Smillert int
is_nfs_mounted(char * path,struct stat * statbuf,int * isvalid)33440934732Smillert is_nfs_mounted(char *path, struct stat *statbuf, int *isvalid)
335fdd8ad51Sdm {
336fdd8ad51Sdm 	mntent_t *mnt;
337fdd8ad51Sdm 
338e06ba677Sguenther 	if ((mnt = getmntpt(path, statbuf, isvalid)) == NULL)
339fdd8ad51Sdm 		return(-1);
340fdd8ad51Sdm 
341e06ba677Sguenther 	if (mnt->me_flags & MEFLAG_NFS)
342fdd8ad51Sdm 		return(1);
343fdd8ad51Sdm 
344fdd8ad51Sdm 	return(0);
345fdd8ad51Sdm }
346fdd8ad51Sdm 
347fdd8ad51Sdm /*
348fdd8ad51Sdm  * Is "path" on a read-only mounted filesystem?
349fdd8ad51Sdm  * Return 1 if it is, 0 if not, or -1 on error.
350fdd8ad51Sdm  */
35140934732Smillert int
is_ro_mounted(char * path,struct stat * statbuf,int * isvalid)35240934732Smillert is_ro_mounted(char *path, struct stat *statbuf, int *isvalid)
353fdd8ad51Sdm {
354fdd8ad51Sdm 	mntent_t *mnt;
355fdd8ad51Sdm 
356*f59ead6eSguenther 	if ((mnt = getmntpt(path, statbuf, isvalid)) == NULL)
357fdd8ad51Sdm 		return(-1);
358fdd8ad51Sdm 
359fdd8ad51Sdm 	if (mnt->me_flags & MEFLAG_READONLY)
360fdd8ad51Sdm 		return(1);
361fdd8ad51Sdm 
362fdd8ad51Sdm 	return(0);
363fdd8ad51Sdm }
364fdd8ad51Sdm 
365fdd8ad51Sdm /*
366fdd8ad51Sdm  * Is "path" a symlink?
367fdd8ad51Sdm  * Return 1 if it is, 0 if not, or -1 on error.
368fdd8ad51Sdm  */
36940934732Smillert int
is_symlinked(char * path,struct stat * statbuf,int * isvalid)37040934732Smillert is_symlinked(char *path, struct stat *statbuf, int *isvalid)
371fdd8ad51Sdm {
372fdd8ad51Sdm 	static struct stat stb;
373fdd8ad51Sdm 
374fdd8ad51Sdm 	if (!(*isvalid)) {
375fdd8ad51Sdm 		if (lstat(path, &stb) != 0)
376fdd8ad51Sdm 			return(-1);
377fdd8ad51Sdm 		statbuf = &stb;
378fdd8ad51Sdm 	}
379fdd8ad51Sdm 
380fdd8ad51Sdm 	if (S_ISLNK(statbuf->st_mode))
381fdd8ad51Sdm 		return(1);
382fdd8ad51Sdm 
383fdd8ad51Sdm 	return(0);
384fdd8ad51Sdm }
385fdd8ad51Sdm 
386fdd8ad51Sdm /*
387fdd8ad51Sdm  * Get filesystem information for "file".  Set freespace
388fdd8ad51Sdm  * to the amount of free (available) space and number of free
389fdd8ad51Sdm  * files (inodes) on the filesystem "file" resides on.
390fdd8ad51Sdm  * Returns 0 on success or -1 on failure.
391fdd8ad51Sdm  * Filesystem values < 0 indicate unsupported or unavailable
392fdd8ad51Sdm  * information.
393fdd8ad51Sdm  */
39440934732Smillert int
getfilesysinfo(char * file,int64_t * freespace,int64_t * freefiles)3954e245ff6Skrw getfilesysinfo(char *file, int64_t *freespace, int64_t *freefiles)
396fdd8ad51Sdm {
39752e4cda2Sguenther 	struct statfs statfsbuf;
398fdd8ad51Sdm 	char *mntpt;
39952e4cda2Sguenther 	int64_t val;
400fdd8ad51Sdm 	int t, r;
401fdd8ad51Sdm 
402fdd8ad51Sdm 	/*
403fdd8ad51Sdm 	 * Get the mount point of the file.
404fdd8ad51Sdm 	 */
405fdd8ad51Sdm 	mntpt = find_file(file, NULL, &t);
406fdd8ad51Sdm 	if (!mntpt) {
407fdd8ad51Sdm 		debugmsg(DM_MISC, "unknown mount point for `%s'", file);
408fdd8ad51Sdm 		return(-1);
409fdd8ad51Sdm 	}
410fdd8ad51Sdm 
411fdd8ad51Sdm 	r = statfs(mntpt, &statfsbuf);
412fdd8ad51Sdm 	if (r < 0) {
413fdd8ad51Sdm 		error("%s: Cannot statfs filesystem: %s.", mntpt, SYSERR);
414fdd8ad51Sdm 		return(-1);
415fdd8ad51Sdm 	}
416fdd8ad51Sdm 
417fdd8ad51Sdm 	/*
418fdd8ad51Sdm 	 * If values are < 0, then assume the value is unsupported
419fdd8ad51Sdm 	 * or unavailable for that filesystem type.
420fdd8ad51Sdm 	 */
42152e4cda2Sguenther 	val = -1;
422fdd8ad51Sdm 	if (statfsbuf.f_bavail >= 0)
42352e4cda2Sguenther 		val = (statfsbuf.f_bavail * (statfsbuf.f_bsize / 512)) / 2;
42452e4cda2Sguenther 	*freespace = val;
425fdd8ad51Sdm 
42652e4cda2Sguenther 	val = -1;
4274e245ff6Skrw 	if (statfsbuf.f_favail >= 0)
42852e4cda2Sguenther 		val = statfsbuf.f_favail;
42952e4cda2Sguenther 	*freefiles = val;
430fdd8ad51Sdm 
431fdd8ad51Sdm 	return(0);
432fdd8ad51Sdm }
433