The patch adds support for /proc/sys/kernel/osrelease. XXX /proc/sys is visible when not mounted with -o linux. XXX Heavily based on copy/paste, some bugs may sneak in. XXX Probably need further work. Index: sys/miscfs/procfs/procfs.h =================================================================== RCS file: /cvsroot/src/sys/miscfs/procfs/procfs.h,v retrieving revision 1.70 diff -p -u -r1.70 procfs.h --- sys/miscfs/procfs/procfs.h 27 Jul 2014 16:47:26 -0000 1.70 +++ sys/miscfs/procfs/procfs.h 4 Dec 2014 09:42:34 -0000 @@ -110,6 +110,9 @@ typedef enum { PFSstatm, /* process memory info (if -o linux) */ PFSversion, /* kernel version (if -o linux) */ PFStask, /* task subdirector (if -o linux) */ + PFSsys, /* sys subdirectory (if -o linux) */ + PFSsyskern, /* sys/kernel subdirectory (if -o linux) */ + PFSosrelease, /* sys/kernel/osrelease (if -o linux) */ #ifdef __HAVE_PROCFS_MACHDEP PROCFS_MACHDEP_NODE_TYPES #endif @@ -233,6 +236,8 @@ int procfs_doemul(struct lwp *, struct p struct uio *); int procfs_doversion(struct lwp *, struct proc *, struct pfsnode *, struct uio *); +int procfs_doosrelease(struct lwp *, struct proc *, struct pfsnode *, + struct uio *); void procfs_revoke_vnodes(struct proc *, void *); int procfs_getfp(struct pfsnode *, struct proc *, struct file **); Index: sys/miscfs/procfs/procfs_linux.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_linux.c,v retrieving revision 1.70 diff -p -u -r1.70 procfs_linux.c --- sys/miscfs/procfs/procfs_linux.c 10 Aug 2014 06:22:06 -0000 1.70 +++ sys/miscfs/procfs/procfs_linux.c 4 Dec 2014 09:42:35 -0000 @@ -732,3 +732,68 @@ out: sysctl_unlock(); return error; } + +/* + * Linux compatible /proc/sys/kernel/osrelease. Only active + * when the -o linux mountflag is used. + */ +int +procfs_doosrelease(struct lwp *curl, struct proc *p, + struct pfsnode *pfs, struct uio *uio) +{ + char losrelease[20]; + int nm[4]; + char *bf; + const char *posrelease; + const char *emulname = curlwp->l_proc->p_emul->e_name; + size_t buflen; + int len; + int error = 0; + + CTASSERT(EMUL_LINUX_KERN_OSRELEASE == EMUL_LINUX32_KERN_OSRELEASE); + + bf = malloc(LBFSZ, M_TEMP, M_WAITOK); + + sysctl_lock(false); + + if (strncmp(emulname, "linux", 5) == 0) { + /* + * Lookup the emulation osrelease. + * Since compat_linux and compat_linux32 can be built as + * modules, we use sysctl to obtain the values instead of + * using the symbols directly. + */ + + if (strcmp(emulname, "linux32") == 0) { + nm[0] = CTL_EMUL; + nm[1] = EMUL_LINUX32; + nm[2] = EMUL_LINUX32_KERN; + } else { + nm[0] = CTL_EMUL; + nm[1] = EMUL_LINUX; + nm[2] = EMUL_LINUX_KERN; + } + + nm[3] = EMUL_LINUX_KERN_OSRELEASE; + buflen = sizeof(losrelease); + error = sysctl_dispatch(nm, __arraycount(nm), + losrelease, &buflen, + NULL, 0, NULL, NULL, NULL); + if (error) + goto out; + + posrelease = losrelease; + } else { + posrelease = osrelease; + } + + len = snprintf(bf, LBFSZ, "%s\n", posrelease); + if (len == 0) + goto out; + + error = uiomove_frombuf(bf, len, uio); +out: + free(bf, M_TEMP); + sysctl_unlock(); + return error; +} Index: sys/miscfs/procfs/procfs_subr.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_subr.c,v retrieving revision 1.106 diff -p -u -r1.106 procfs_subr.c --- sys/miscfs/procfs/procfs_subr.c 10 Nov 2014 18:46:34 -0000 1.106 +++ sys/miscfs/procfs/procfs_subr.c 4 Dec 2014 09:42:35 -0000 @@ -272,6 +272,10 @@ procfs_rw(void *v) error = procfs_doversion(curl, p, pfs, uio); break; + case PFSosrelease: + error = procfs_doosrelease(curl, p, pfs, uio); + break; + #ifdef __HAVE_PROCFS_MACHDEP PROCFS_MACHDEP_NODETYPE_CASES error = procfs_machdep_rw(curl, l, pfs, uio); Index: sys/miscfs/procfs/procfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_vfsops.c,v retrieving revision 1.94 diff -p -u -r1.94 procfs_vfsops.c --- sys/miscfs/procfs/procfs_vfsops.c 10 Nov 2014 18:46:34 -0000 1.94 +++ sys/miscfs/procfs/procfs_vfsops.c 4 Dec 2014 09:42:35 -0000 @@ -386,6 +386,12 @@ procfs_loadvnode(struct mount *mp, struc vp->v_type = VREG; break; + case PFSsys: /* /proc/sys = dr-xr-xr-x */ + case PFSsyskern: /* /proc/sys/kernel = dr-xr-xr-x */ + pfs->pfs_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; + vp->v_type = VDIR; + break; + case PFSmap: /* /proc/N/map = -r--r--r-- */ case PFSmaps: /* /proc/N/maps = -r--r--r-- */ case PFSstatus: /* /proc/N/status = -r--r--r-- */ @@ -401,6 +407,7 @@ procfs_loadvnode(struct mount *mp, struc case PFSloadavg: /* /proc/loadavg = -r--r--r-- */ case PFSstatm: /* /proc/N/statm = -r--r--r-- */ case PFSversion: /* /proc/version = -r--r--r-- */ + case PFSosrelease: /* /proc/sys/kernel/osrelease = -r--r--r-- */ pfs->pfs_mode = S_IRUSR|S_IRGRP|S_IROTH; vp->v_type = VREG; break; Index: sys/miscfs/procfs/procfs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_vnops.c,v retrieving revision 1.192 diff -p -u -r1.192 procfs_vnops.c --- sys/miscfs/procfs/procfs_vnops.c 5 Sep 2014 09:26:16 -0000 1.192 +++ sys/miscfs/procfs/procfs_vnops.c 4 Dec 2014 09:42:35 -0000 @@ -198,6 +198,7 @@ static const struct proc_target proc_roo { DT_REG, N("stat"), PFScpustat, procfs_validfile_linux }, { DT_REG, N("loadavg"), PFSloadavg, procfs_validfile_linux }, { DT_REG, N("version"), PFSversion, procfs_validfile_linux }, + { DT_DIR, N("sys"), PFSsys, NULL }, #undef N }; static const int nproc_root_targets = @@ -642,6 +643,9 @@ procfs_getattr(void *v) case PFSroot: case PFScurproc: case PFSself: + case PFSsys: + case PFSsyskern: + case PFSosrelease: procp = NULL; break; @@ -837,6 +841,19 @@ procfs_getattr(void *v) vap->va_gid = kauth_cred_getegid(procp->p_cred); vap->va_bytes = vap->va_size = DEV_BSIZE; break; + case PFSsys: + case PFSsyskern: + vap->va_nlink = 2; + vap->va_uid = 0; + vap->va_gid = 0; + vap->va_bytes = vap->va_size = DEV_BSIZE; + break; + case PFSosrelease: + vap->va_nlink = 1; + vap->va_uid = 0; + vap->va_gid = 0; + vap->va_bytes = vap->va_size = sizeof("osrelease") - 1; + break; case PFSfile: error = EOPNOTSUPP; @@ -1186,6 +1203,38 @@ procfs_lookup(void *v) procfs_proc_unlock(p); return error; } + case PFSsys: + if (cnp->cn_flags & ISDOTDOT) { + error = procfs_allocvp(dvp->v_mount, + vpp, 0, PFSroot, -1); + return error; + } + + if (cnp->cn_namelen == 6 && + memcmp(pname, "kernel", 6) == 0) { + error = procfs_allocvp(dvp->v_mount, + vpp, 0, PFSsyskern, -1); + return error; + } + + return ENOENT; + + case PFSsyskern: + if (cnp->cn_flags & ISDOTDOT) { + error = procfs_allocvp(dvp->v_mount, + vpp, 0, PFSsys, -1); + return error; + } + + if (cnp->cn_namelen == 9 && + memcmp(pname, "osrelease", 9) == 0) { + error = procfs_allocvp(dvp->v_mount, + vpp, 0, PFSosrelease, -1); + return error; + } + + return ENOENT; + default: return (ENOTDIR); } @@ -1578,6 +1627,88 @@ procfs_readdir(void *v) break; } + case PFSsys: { + int nc = 0; + + if (ap->a_ncookies) { + /* + * XXX Potentially allocating too much space here, + * but I'm lazy. This loop needs some work. + */ + cookies = malloc(ncookies * sizeof (off_t), + M_TEMP, M_WAITOK); + *ap->a_cookies = cookies; + } + error = 0; + /* 0 ... 2 are static entries. */ + for (; i <= 2 && uio->uio_resid >= UIO_MX; i++) { + switch (i) { + case 0: /* `.' */ + case 1: /* `..' */ + d.d_fileno = PROCFS_FILENO(0, PFSsys, -1); + d.d_namlen = i + 1; + memcpy(d.d_name, "..", d.d_namlen); + d.d_name[i + 1] = '\0'; + d.d_type = DT_DIR; + break; + case 2: + d.d_fileno = PROCFS_FILENO(0, PFSsyskern, -1); + d.d_namlen = sizeof("kernel") - 1; + memcpy(d.d_name, "kernel", d.d_namlen + 1); + d.d_type = DT_DIR; + break; + } + + if ((error = uiomove(&d, UIO_MX, uio)) != 0) + break; + nc++; + if (cookies) + *cookies++ = i + 1; + } + break; + } + + case PFSsyskern: { + int nc = 0; + + if (ap->a_ncookies) { + /* + * XXX Potentially allocating too much space here, + * but I'm lazy. This loop needs some work. + */ + cookies = malloc(ncookies * sizeof (off_t), + M_TEMP, M_WAITOK); + *ap->a_cookies = cookies; + } + error = 0; + /* 0 ... 2 are static entries. */ + for (; i <= 2 && uio->uio_resid >= UIO_MX; i++) { + switch (i) { + case 0: /* `.' */ + case 1: /* `..' */ + d.d_fileno = PROCFS_FILENO(0, PFSsyskern, -1); + d.d_namlen = i + 1; + memcpy(d.d_name, "..", d.d_namlen); + d.d_name[i + 1] = '\0'; + d.d_type = DT_DIR; + break; + case 2: + d.d_fileno = PROCFS_FILENO(0, PFSosrelease, -1); + d.d_namlen = sizeof("osrelease") - 1; + memcpy(d.d_name, "osrelease", d.d_namlen + 1); + d.d_type = DT_REG; + break; + } + + if ((error = uiomove(&d, UIO_MX, uio)) != 0) + break; + nc++; + if (cookies) + *cookies++ = i + 1; + } + break; + } + default: error = ENOTDIR; break;