Let's see if I can get this closer to right.
The patch is against and tested on -current.
Thank you, Pedro, for your help.

--- sys/dev/vnd.c.orig  Sun Sep 10 19:18:28 2006
+++ sys/dev/vnd.c       Mon Sep 11 15:54:30 2006
@@ -142,7 +142,10 @@
 #define        VNF_HAVELABEL   0x0400
 #define        VNF_BUSY        0x0800
 #define        VNF_SIMPLE      0x1000
+#define        VNF_READONLY    0x2000
 
+#define FLG(vnd) (vnd->sc_flags & VNF_READONLY ? FREAD : FREAD|FWRITE)
+
 struct vnd_softc *vnd_softc;
 int numvnd = 0;
 
@@ -234,6 +237,11 @@
        if ((error = vndlock(sc)) != 0)
                return (error);
 
+       if (flags & FWRITE && sc->sc_flags & VNF_READONLY) {
+               error = EROFS;
+               goto bad;
+       }
+
        if ((sc->sc_flags & VNF_INITED) &&
            (sc->sc_flags & VNF_HAVELABEL) == 0) {
                sc->sc_flags |= VNF_HAVELABEL;
@@ -817,20 +825,25 @@
                }
 
                /*
-                * Always open for read and write.
-                * This is probably bogus, but it lets vn_open()
+                * Open for read and write first.  This lets vn_open()
                 * weed out directories, sockets, etc. so we don't
                 * have to worry about them.
                 */
                NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
-               if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+               vnd->sc_flags &= ~VNF_READONLY;
+               error = vn_open(&nd, FREAD|FWRITE, 0);
+               if (EROFS == error) {
+                       vnd->sc_flags |= VNF_READONLY;
+                       error = vn_open(&nd, FREAD, 0);
+               }
+               if (error) {
                        vndunlock(vnd);
                        return (error);
                }
                error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
                if (error) {
                        VOP_UNLOCK(nd.ni_vp, 0, p);
-                       (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
+                       (void) vn_close(nd.ni_vp, FLG(vnd), p->p_ucred, p);
                        vndunlock(vnd);
                        return (error);
                }
@@ -838,7 +851,7 @@
                vnd->sc_vp = nd.ni_vp;
                vnd->sc_size = btodb(vattr.va_size);    /* note truncation */
                if ((error = vndsetcred(vnd, p->p_ucred)) != 0) {
-                       (void) vn_close(nd.ni_vp, FREAD|FWRITE, p->p_ucred, p);
+                       (void) vn_close(nd.ni_vp, FLG(vnd), p->p_ucred, p);
                        vndunlock(vnd);
                        return (error);
                }
@@ -851,7 +864,7 @@
 
                        if ((error = copyin(vio->vnd_key, key,
                            vio->vnd_keylen)) != 0) {
-                               (void) vn_close(nd.ni_vp, FREAD|FWRITE,
+                               (void) vn_close(nd.ni_vp, FLG(vnd),
                                    p->p_ucred, p);
                                vndunlock(vnd);
                                return (error);
@@ -1087,7 +1100,7 @@
        vnd->sc_flags &= ~VNF_INITED;
        if (vp == (struct vnode *)0)
                panic("vndioctl: null vp");
-       (void) vn_close(vp, FREAD|FWRITE, vnd->sc_cred, p);
+       (void) vn_close(vp, FLG(vnd), vnd->sc_cred, p);
        crfree(vnd->sc_cred);
        vnd->sc_vp = (struct vnode *)0;
        vnd->sc_cred = (struct ucred *)0;
--- usr.sbin/vnconfig/vnconfig.c.orig   Sun Sep 10 19:19:25 2006
+++ usr.sbin/vnconfig/vnconfig.c        Mon Sep 11 15:28:27 2006
@@ -226,7 +226,7 @@
        char *rdev;
        int rv;
 
-       if (opendev(dev, O_RDWR, OPENDEV_PART, &rdev) < 0)
+       if (opendev(dev, O_RDONLY, OPENDEV_PART, &rdev) < 0)
                err(4, "%s", rdev);
        f = fopen(rdev, "rw");
        if (f == NULL) {

Reply via email to