Hello, t...@!

The getmntinfo(3) page says that the mentioned function uses static
storage which cannot be freed, however this storage is being actually
malloced and can be freed without consequences.

I see no real need in doing such weird things (correct me if i'm
wrong) so here's a diff to actually do pass a singly-malloced buffer
to the caller who should free it manually.

I've also converted the essential users of that function:
bin/df sbin/mount sbin/umount sbin/mountd usr.bin/fstat.
If you find this approach good/useful I'll convert the rest (the
manpage will also need some love).

It is good to subsequently replace all static stuff in libc, right?

Index: getmntinfo.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/getmntinfo.c,v
retrieving revision 1.7
diff -u -p -r1.7 getmntinfo.c
--- getmntinfo.c        8 Aug 2005 08:05:34 -0000       1.7
+++ getmntinfo.c        14 Oct 2010 22:28:06 -0000
@@ -38,25 +38,22 @@
 int
 getmntinfo(struct statfs **mntbufp, int flags)
 {
-       static struct statfs *mntbuf;
-       static int mntsize;
-       static size_t bufsize;
+       struct statfs *mntbuf;
+       int mntsize;
+       size_t bufsize = 0;
 
-       if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0)
+       if ((mntsize = getfsstat(NULL, 0, MNT_NOWAIT)) < 0)
                return (0);
-       if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, flags)) < 0)
+
+       bufsize = mntsize * sizeof(struct statfs);
+       if ((mntbuf = malloc(bufsize)) == NULL)
+               return (0);
+
+       if ((mntsize = getfsstat(mntbuf, bufsize, flags)) < 0) {
+               free(mntbuf);
                return (0);
-       while (bufsize <= mntsize * sizeof(struct statfs)) {
-               if (mntbuf)
-                       free(mntbuf);
-               bufsize = (mntsize + 1) * sizeof(struct statfs);
-               if ((mntbuf = (struct statfs *)malloc(bufsize)) == 0) {
-                       bufsize = 0;
-                       return (0);
-               }
-               if ((mntsize = getfsstat(mntbuf, bufsize, flags)) < 0)
-                       return (0);
        }
+
        *mntbufp = mntbuf;
        return (mntsize);
 }

Index: bin/df/df.c
===================================================================
RCS file: /cvs/src/bin/df/df.c,v
retrieving revision 1.50
diff -u -p -r1.50 df.c
--- bin/df/df.c 27 Oct 2009 23:59:21 -0000      1.50
+++ bin/df/df.c 14 Oct 2010 23:19:58 -0000
@@ -74,7 +74,7 @@ int
 main(int argc, char *argv[])
 {
        struct stat stbuf;
-       struct statfs *mntbuf;
+       struct statfs *mntbuf = NULL;
        long mntsize;
        int ch, i;
        int width, maxwidth;
@@ -125,16 +125,19 @@ main(int argc, char *argv[])
        if (!*argv) {
                mntsize = regetmntinfo(&mntbuf, mntsize);
        } else {
+               free(mntbuf);
                mntbuf = calloc(argc, sizeof(struct statfs));
                if (mntbuf == NULL)
                        err(1, NULL);
                mntsize = 0;
                for (; *argv; argv++) {
+                       int freemntpt = 0;
                        if (stat(*argv, &stbuf) < 0) {
-                               if ((mntpt = getmntpt(*argv)) == 0) {
+                               if ((mntpt = getmntpt(*argv)) == NULL) {
                                        warn("%s", *argv);
                                        continue;
                                }
+                               freemntpt = 1;
                        } else if (S_ISCHR(stbuf.st_mode) || 
S_ISBLK(stbuf.st_mode)) {
                                if (!raw_df(*argv, &mntbuf[mntsize]))
                                        ++mntsize;
@@ -156,6 +159,9 @@ main(int argc, char *argv[])
                                        ++mntsize;
                        else
                                warn("%s", *argv);
+
+                       if (freemntpt)
+                               free(mntpt);
                }
        }
 
@@ -176,21 +182,26 @@ main(int argc, char *argv[])
                        bsdprint(mntbuf, mntsize, maxwidth);
        }
 
-       exit(mntsize ? 0 : 1);
+       free(mntbuf);
+       return (mntsize ? 0 : 1);
 }
 
 char *
 getmntpt(char *name)
 {
+       char *s = NULL;
        long mntsize, i;
-       struct statfs *mntbuf;
+       struct statfs *mntbuf = NULL;
 
        mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
        for (i = 0; i < mntsize; i++) {
-               if (!strcmp(mntbuf[i].f_mntfromname, name))
-                       return (mntbuf[i].f_mntonname);
+               if (!strcmp(mntbuf[i].f_mntfromname, name)) {
+                       s = strdup(mntbuf[i].f_mntonname);
+                       break;
+               }
        }
-       return (0);
+       free(mntbuf);
+       return (s);
 }
 
 static enum { IN_LIST, NOT_IN_LIST } which;
@@ -257,7 +268,11 @@ regetmntinfo(struct statfs **mntbufp, lo
        struct statfs *mntbuf;
 
        if (!lflag && typelist == NULL)
-               return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
+               if (!nflag) {
+                       free(*mntbufp);
+                       return (getmntinfo(mntbufp, MNT_WAIT));
+               } else
+                       return (mntsize);
 
        mntbuf = *mntbufp;
        j = 0;
Index: sbin/mount/mount.c
===================================================================
RCS file: /cvs/src/sbin/mount/mount.c,v
retrieving revision 1.50
diff -u -p -r1.50 mount.c
--- sbin/mount/mount.c  27 Oct 2009 23:59:33 -0000      1.50
+++ sbin/mount/mount.c  14 Oct 2010 23:19:58 -0000
@@ -59,7 +59,7 @@ int   selected(const char *);
 char   *catopt(char *, const char *);
 char   *flags2opts(u_int32_t);
 struct statfs
-       *getmntpt(const char *);
+       *getmntpt(struct statfs *, int, const char *);
 int    hasopt(const char *, const char *);
 void   maketypelist(char *);
 void   mangle(char *, int *, const char **, int);
@@ -100,7 +100,7 @@ int
 main(int argc, char * const argv[])
 {
        const char *mntonname, *vfstype;
-       struct fstab *fs;
+       struct fstab *fs, *fsa = NULL;
        struct statfs *mntbuf;
        FILE *mountdfp;
        pid_t pid;
@@ -194,6 +194,7 @@ main(int argc, char * const argv[])
                                        continue;
                                prmount(&mntbuf[i]);
                        }
+                       free(mntbuf);
                        exit(rval);
                }
                break;
@@ -204,32 +205,37 @@ main(int argc, char * const argv[])
                if (realpath(*argv, mntpath) == NULL)
                        err(1, "realpath %s", *argv);
                if (hasopt(options, "update")) {
-                       if ((mntbuf = getmntpt(mntpath)) == NULL)
+                       struct statfs *mntpt;
+
+                       if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
+                               err(1, "getmntinfo");
+
+                       if ((mntpt = getmntpt(mntbuf, mntsize, mntpath)) == 
NULL)
                                errx(1,
                                    "unknown special file or file system %s.",
                                    *argv);
-                       if ((mntbuf->f_flags & MNT_ROOTFS) &&
-                           !strcmp(mntbuf->f_mntfromname, "root_device")) {
+                       if ((mntpt->f_flags & MNT_ROOTFS) &&
+                           !strcmp(mntpt->f_mntfromname, "root_device")) {
                                /* Lookup fstab for name of root device. */
-                               fs = getfsfile(mntbuf->f_mntonname);
+                               fs = getfsfile(mntpt->f_mntonname);
                                if (fs == NULL)
                                        errx(1,
                                            "can't find fstab entry for %s.",
                                            *argv);
                        } else {
-                               fs = malloc(sizeof(*fs));
+                               fsa = fs = malloc(sizeof(*fs));
                                if (fs == NULL)
                                        err(1, "malloc");
-                               fs->fs_vfstype = mntbuf->f_fstypename;
-                               fs->fs_spec = mntbuf->f_mntfromname;
+                               fs->fs_vfstype = mntpt->f_fstypename;
+                               fs->fs_spec = mntpt->f_mntfromname;
                        }
                        /*
                         * It's an update, ignore the fstab file options.
                         * Get the current options, so we can change only
                         * the options which given via a command line.
                         */
-                       fs->fs_mntops = flags2opts(mntbuf->f_flags);
-                       mntonname = mntbuf->f_mntonname;
+                       fs->fs_mntops = flags2opts(mntpt->f_flags);
+                       mntonname = mntpt->f_mntonname;
                } else {
                        if ((fs = getfsfile(mntpath)) == NULL &&
                            (fs = getfsspec(mntpath)) == NULL)
@@ -280,7 +286,9 @@ main(int argc, char * const argv[])
                (void)fclose(mountdfp);
        }
 
-       exit(rval);
+       free(fsa);
+       free(mntbuf);
+       return (rval);
 }
 
 int
@@ -584,12 +592,10 @@ prmount(struct statfs *sf)
 }
 
 struct statfs *
-getmntpt(const char *name)
+getmntpt(struct statfs *mntbuf, int mntsize, const char *name)
 {
-       struct statfs *mntbuf;
-       int i, mntsize;
+       int i;
 
-       mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
        for (i = 0; i < mntsize; i++)
                if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
                    strcmp(mntbuf[i].f_mntonname, name) == 0)
Index: sbin/umount/umount.c
===================================================================
RCS file: /cvs/src/sbin/umount/umount.c,v
retrieving revision 1.21
diff -u -p -r1.21 umount.c
--- sbin/umount/umount.c        27 Oct 2009 23:59:34 -0000      1.21
+++ sbin/umount/umount.c        14 Oct 2010 23:19:58 -0000
@@ -119,7 +119,7 @@ main(int argc, char *argv[])
 int
 umountall(void)
 {
-       struct statfs *fs;
+       struct statfs *fs = NULL;
        int n;
        int rval;
 
@@ -137,6 +137,7 @@ umountall(void)
                if (umountfs(fs[n].f_mntonname))
                        rval = 1;
        }
+       free(fs);
        return (rval);
 }
 
@@ -164,6 +165,7 @@ umountfs(char *oname)
            if (S_ISBLK(sb.st_mode)) {
                if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
                        warnx("%s: not currently mounted", name);
+                       free(mntpt);
                        return (1);
                }
            } else if (!S_ISDIR(sb.st_mode)) {
@@ -177,9 +179,9 @@ umountfs(char *oname)
         * 99.9% of the time the path in the kernel is the one
         * realpath() returns but check the original just in case...
         */
+       newname = mntpt = NULL;
        if (!(newname = getmntname(name, MNTFROM, type)) &&
            !(mntpt = getmntname(name, MNTON, type)) ) {
-               mntpt = oname;
                if (!(newname = getmntname(oname, MNTFROM, type)) &&
                    !(mntpt = getmntname(oname, MNTON, type))) {
                        warnx("%s: not currently mounted", oname);
@@ -245,13 +247,16 @@ umountfs(char *oname)
                auth_destroy(clp->cl_auth);
                clnt_destroy(clp);
        }
+       free(mntpt);
+       free(newname);
        return (0);
 }
 
 char *
 getmntname(char *name, mntwhat what, char *type)
 {
-       struct statfs *mntbuf;
+       char *mntname = NULL;
+       struct statfs *mntbuf = NULL;
        int i, mntsize;
 
        if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
@@ -263,16 +268,19 @@ getmntname(char *name, mntwhat what, cha
                        if (type)
                                memcpy(type, mntbuf[i].f_fstypename,
                                    sizeof(mntbuf[i].f_fstypename));
-                       return (mntbuf[i].f_mntonname);
+                       mntname = strdup(mntbuf[i].f_mntonname);
+                       break;
                }
                if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
                        if (type)
                                memcpy(type, mntbuf[i].f_fstypename,
                                    sizeof(mntbuf[i].f_fstypename));
-                       return (mntbuf[i].f_mntfromname);
+                       mntname = strdup(mntbuf[i].f_mntfromname);
+                       break;
                }
        }
-       return (NULL);
+       free(mntbuf);
+       return (mntname);
 }
 
 static enum { IN_LIST, NOT_IN_LIST } which;
Index: sbin/mountd/mountd.c
===================================================================
RCS file: /cvs/src/sbin/mountd/mountd.c,v
retrieving revision 1.71
diff -u -p -r1.71 mountd.c
--- sbin/mountd/mountd.c        22 Mar 2010 16:35:27 -0000      1.71
+++ sbin/mountd/mountd.c        14 Oct 2010 23:19:58 -0000
@@ -688,7 +688,7 @@ get_exportlist(void)
        struct grouplist *grp, *tgrp;
        struct exportlist **epp;
        struct dirlist *dirhead;
-       struct statfs fsb, *ofsp, *fsp;
+       struct statfs fsb, *ofsp = NULL, *fsp;
        struct hostent *hpe;
        struct ucred anon;
        union {
@@ -738,7 +738,6 @@ get_exportlist(void)
                out_of_mem();
 
        for (i = 0; i < num; i++) {
-
                if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) ||
                    !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) ||
                    !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) ||
@@ -1047,8 +1046,9 @@ nextline:
                        syslog(LOG_ERR, "Can't delete exports for %s: %m",
                            fsp->f_mntonname);
        }
-       free(fstbl);
        fclose(exp_file);
+       free(fstbl);
+       free(ofsp);
 }
 
 /*
Index: usr.bin/fstat/fstat.c
===================================================================
RCS file: /cvs/src/usr.bin/fstat/fstat.c,v
retrieving revision 1.70
diff -u -p -r1.70 fstat.c
--- usr.bin/fstat/fstat.c       27 Oct 2009 23:59:38 -0000      1.70
+++ usr.bin/fstat/fstat.c       14 Oct 2010 23:19:58 -0000
@@ -100,6 +100,7 @@ int         signo;  /* signal to send (fuser onl
 
 kvm_t *kd;
 uid_t uid;
+static struct statfs *mntbuf;
 
 void fstat_dofile(struct kinfo_file2 *);
 void fstat_header(void);
@@ -266,7 +267,8 @@ main(int argc, char *argv[])
        if (fuser)
                fuser_run();
 
-       exit(0);
+       free(mntbuf);
+       return (0);
 }
 
 void
@@ -737,7 +739,6 @@ getinetproto(number)
 int
 getfname(char *filename)
 {
-       static struct statfs *mntbuf;
        static int nmounts;
        int i;
        struct stat sb;
@@ -757,7 +758,7 @@ getfname(char *filename)
        if (fuser && !fsflg && S_ISBLK(sb.st_mode)) {
                if (mntbuf == NULL) {
                        nmounts = getmntinfo(&mntbuf, MNT_NOWAIT);
-                       if (nmounts == -1)
+                       if (nmounts == 0)
                                err(1, "getmntinfo");
                }
                for (i = 0; i < nmounts; i++) {

Reply via email to