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) {