--- ../../lib/libc/gen/getmntinfo.c 2017-05-04 22:24:30.080948000 +0200 +++ getmntinfo.c 2017-08-23 17:40:49.501527000 +0200 @@ -38,6 +38,9 @@ #include #include +#define MAX_ATTEMPTS 3 +#define EXTRA_FS 16 + /* * Return information about mounted filesystems. */ @@ -45,22 +48,56 @@ getmntinfo(struct statfs **mntbufp, int mode) { static struct statfs *mntbuf; - static int mntsize; static long bufsize; + struct statfs *newbuf; + long newsize; + int n_fs; + int n_try = 0; + - if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0) - return (0); - if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) + /* Get the current list of available filesystems */ + n_fs = getfsstat(NULL, 0, MNT_NOWAIT); + if (n_fs < 0) return (0); - while (bufsize <= mntsize * sizeof(struct statfs)) { - if (mntbuf) - free(mntbuf); - bufsize = (mntsize + 1) * sizeof(struct statfs); - if ((mntbuf = malloc(bufsize)) == NULL) - return (0); - if ((mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) + + do { + int rc; + + /* Need room for more statfs in order to detect a growing list */ + newsize = (n_fs+EXTRA_FS) * sizeof(struct statfs); + + if (!mntbuf || bufsize < newsize) { + /* Current buffer is too small -> grow it */ + + if (mntbuf) + newbuf = realloc(mntbuf, newsize); + else + newbuf = malloc(newsize); + + if (!newbuf) { + return (0); + } + + /* Update stored buf pointer(s) and current size */ + *mntbufp = mntbuf = newbuf; + bufsize = newsize; + } + + /* Load filesystem information into buffer */ + if ((rc = getfsstat(mntbuf, bufsize, mode)) < 0) return (0); - } + + if (rc <= n_fs) { + /* Got the list of filesystem information */ + *mntbufp = mntbuf; + return (rc); + } + + n_fs = rc; + /* Retry the lookup (more filesystems found) */ + } while (n_try++ < MAX_ATTEMPTS); + + /* The list keeps on growing, give up and just return the ones we found so far */ *mntbufp = mntbuf; - return (mntsize); + return (n_fs); }