Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Aug 2003 20:18:45 -0400
From:      Mike Makonnen <mtm@identd.net>
To:        freebsd-arch@FreeBSD.Org
Subject:   A general mechanism for specifying devfs(8) rules
Message-ID:  <20030804001815.GA17137@kokeb.ambesa.net>

next in thread | raw e-mail | index | archive | help

--OgqxwSJOaUobr8KG
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hello folks,

While polishing up an enhanced jail script submitted by
"Scot W. Hetzel" <hetzels@westbend.net> it became necessary
to introduce mechanism to specify devfs(8) rules. The script
needed to provide a default set of rules, but it also needed
to accept rules specified by the user. So, after some testing
and suggestions by Jens Rehsack <rehsack@liwing.de> I decided
I might as well make it work for the general case also. Attached
is a patch that should do just that. Similarly to rc.conf(5),
there's a src/etc/defaults/devfs.rules file. But an user can
include local rules by adding the file to a devfs_rulesets
variable in rc.conf. The format of the file is simple. Essentially,
it goes like this:

[ruleset_name=#some_number]
action
action
...

[another_ruleset_name=#some_other_number]
action
action
...

To use a specific rule, you specify it by name in the
devfs_system_ruleset variable in your rc.conf.

I have tried to do two things with this patch:
1. Remove, from the user's point of view, the necessity to
   know ruleset numbers. The ruleset numbers are used in only
   one place, devfs.rules. So, if you rearrange the ruleset
   numbers you don't need to change any rc.conf settings. Even
   in the rules file, if you change the number of a ruleset
   you don't have to change any rulesets that refer to it
   because they use the name instead.

2. Keep the things that are different from the real devfs(8)
   command as few as possible. So, with one small exception
   (to allow you to use ruleset names instead of numbers) the
   action lines for each ruleset are passed directly to the
   devfs(8) command.

Comments ?

Cheers.
-- 
Mike Makonnen  | GPG-KEY: http://www.identd.net/~mtm/mtm.asc
mtm@identd.net | D228 1A6F C64E 120A A1C9  A3AA DAE1 E2AF DBCC 68B9
mtm@FreeBSD.Org| FreeBSD - Unleash the Daemon!

--OgqxwSJOaUobr8KG
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="devfsall.diff"

Index: etc/rc.subr
===================================================================
RCS file: /home/ncvs/src/etc/rc.subr,v
retrieving revision 1.13
diff -u -r1.13 rc.subr
--- etc/rc.subr	9 Jun 2003 17:31:06 -0000	1.13
+++ etc/rc.subr	4 Aug 2003 00:06:46 -0000
@@ -1033,3 +1033,218 @@
 		esac
 	fi
 }
+
+# devfs_link dir src link
+#	Make a symbolic link 'link' to src in chroot/dev.
+#	Returns 0 on sucess.
+#
+devfs_link()
+{
+	local dir src link _me
+	dir="$1"
+	src="$2"
+	link="$3"
+	_me="devfs_link"
+
+	if [ -z "$dir" -o -z "$src" -o -z "$link" ]; then
+		warn "devfs_link(): requires three arguments."
+		return 1
+	fi
+	if [ -z "$dir" ]; then
+		warn "$_me: the directory ($dir) does not exist"
+		return 1
+	fi
+	cd ${chroot}/dev
+	if ! ln -sf $src $link ; then
+		warn "$_me: unable to link $link --> $src in $dir"
+		return 1
+	fi
+	return 0
+}
+
+# devfs_init_rulesets
+#	Initializes rulesets from configuration files. Returns
+#	non-zero if there was an error.
+#
+devfs_init_rulesets()
+{
+	local file _me
+	_me="devfs_init_rulesets"
+
+	# Go through this only once
+	if [ -n "$devfs_rulesets_init" ]; then
+		debug "$_me: devfs rulesets already initialized"
+		return
+	fi
+	for file in $devfs_rulesets ; do
+		devfs_rulesets_from_file $file || return 1
+	done
+	devfs_rulesets_init=1
+	debug "$_me: devfs rulesets initialized"
+	return 0
+}
+
+# devfs_set_ruleset ruleset [dir]
+#	Sets the default ruleset of dir to ruleset.
+#	Returns non-zero if it could not set it successfully.
+#
+devfs_set_ruleset()
+{
+	local devdir rs _me
+	[ -n "$1" ] && eval rs=\$$1 || rs=
+	[ -n "$2" ] && devdir="-m "$2"" || devdir=
+	_me="devfs_set_ruleset"
+
+	if [ -z "$rs" ]; then
+		warn "$_me: you must specify a ruleset number"
+		return 1
+	fi
+	debug "$_me: setting ruleset ($rs) on mount-point (${devdir#-m })"
+	if ! /sbin/devfs $devdir ruleset $rs ; then
+		warn "$_me: unable to set ruleset $rs to ${devdir#-m }"
+		return 1
+	fi
+	return 0
+}
+
+# devfs_apply_ruleset ruleset [dir]
+#	Apply ruleset number $ruleset to the devfs mountpoint $dir.
+#	Returns 0 on success or non-zero if it could not apply
+#	the ruleset.
+#
+devfs_apply_ruleset()
+{
+	local devdir rs _me
+	[ -n "$1" ] && eval rs=\$$1 || rs=
+	[ -n "$2" ] && devdir="-m "$2"" || devdir=
+	_me="devfs_apply_ruleset"
+
+	if [ -z "$rs" ]; then
+		warn "$_me: you must specify a ruleset"
+		return 1
+	fi
+	debug "$_me: applying ruleset ($rs) to mount-point (${devdir#-m })"
+	if ! /sbin/devfs $devdir rule -s $rs applyset ; then
+		warn "$_me: unable to apply ruleset $rs to ${devdir#-m }"
+		return 1
+	fi
+	return 0
+}
+
+# devfs_domount dir [ruleset]
+#	Mount devfs on dir. If ruleset is specified it is set
+#	on the mount-point. Returns 0 on success.
+#
+devfs_domount()
+{
+	local devdir rs _me
+	devdir="$1"
+	[ -n "$2" ] && rs=$2 || rs=
+	_me="devfs_domount()"
+
+	if [ -z "$devdir" ]; then
+		warn "$_me: you must specify a mount-point"
+		return 1
+	fi
+	debug "$_me: mount-point is ($devdir), ruleset is ($rs)"
+	if ! mount -t devfs dev "$devdir" ; then
+		warn "$_me: Unable to mount devfs on $devdir"
+		return 1
+	fi
+	if [ -n "$rs" ]; then
+		devfs_init_rulesets
+		devfs_set_ruleset $rs $devdir
+	fi
+	return 0
+}
+
+# devfs_mount_jail dir [name]
+#	Mounts a devfs file system appropriate for jails
+#	on the directory dir. If name is specified, the ruleset
+#	it names will be used instead.  The argument name must
+#	be the name of a ruleset as defined in a devfs.rules file.
+#	This function returns non-zero if an error occurs.
+#
+devfs_mount_jail()
+{
+	local jdev rs _me
+	jdev="$1"
+	[ -n "$2" ] && rs=$2 || rs=
+	_me="devfs_mount_jail"
+
+	devfs_init_rulesets
+	if ! devfs_domount "$jdev" $rs ; then
+		warn "$_me: devfs was not mounted on $jdev"
+		return 1
+	fi
+	return 0
+}
+
+# devfs_rulesets_from_file file
+#	Reads a set of devfs commands from file, and creates
+#	the specified rulesets with their rules. Returns non-zero
+#	if there was an error.
+#
+devfs_rulesets_from_file()
+{
+	local file _err _me
+	file="$1"
+	_me="devfs_rulesets_from_file"
+	_err=0
+
+	if [ -z "$file" ]; then
+		warn "$_me: you must specify a file"
+		return 1
+	fi
+	if [ ! -e "$file" ]; then
+		warn "$_me: no such file ($file)"
+		return 1
+	fi
+	debug "reading rulesets from file ($file)"
+	{ while read line
+	do
+		case $line in
+		\#*)
+			continue
+			;;
+		\[*\]*)
+			rulenum=`expr "$line" : "\[.*=\([0-9]*\)\]"`
+			if [ -z "$rulenum" ]; then
+				warn "$_me: cannot extract rule number ($line)"
+				_err=1
+				break
+			fi
+			rulename=`expr "$line" : "\[\(.*\)=[0-9]*\]"`
+			if [ -z "$rulename" ]; then
+				warn "$_me: cannot extract rule name ($line)"
+				_err=1
+				break;
+			fi
+			eval $rulename=\$rulenum
+			debug "found ruleset: $rulename=$rulenum"
+			if ! /sbin/devfs rule -s $rulenum delset ; then
+				_err=1
+				break
+			fi
+			;;
+		*)
+			rulecmd="${line%%"\#*"}"
+			# evaluate the command incase it includes
+			# other rules
+			if [ -n "$rulecmd" ]; then
+				debug "adding rule ($rulecmd)"
+				if ! eval /sbin/devfs rule -s $rulenum $rulecmd
+				then
+					_err=1
+					break
+				fi
+			fi
+			;;
+		esac
+		if [ $_err -ne 0 ]; then
+			debug "error in $_me"
+			break
+		fi
+	done } < $file
+	return $_err
+}
Index: etc/defaults/devfs.rules
===================================================================
RCS file: etc/defaults/devfs.rules
diff -N etc/defaults/devfs.rules
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ etc/defaults/devfs.rules	3 Aug 2003 22:52:18 -0000
@@ -0,0 +1,64 @@
+#
+# The following are some default rules for devfs(5) mounts.
+# The format is very simple. Empty lines and lines begining
+# with a hash '#' are ignored. If the hash mark occurs anywhere
+# other than the beginning of a line, it and any subsequent
+# characters will be ignored.  A line in between brackets '[]'
+# denotes the beginning of a ruleset. In the brackets should
+# be a name for the rule and its ruleset number. Any other lines
+# will be considered to be the 'action' part of a rule
+# passed to the devfs(8) command. These will be passed
+# "as-is" to the devfs(8) command with the exception that
+# any references to other rulesets will be expanded first. These
+# references must include a dollar sign '$' in-front of the
+# name to be expanded properly.
+#
+# $FreeBSD$
+#
+
+# Very basic and secure ruleset: Hide everything.
+# Used as a basis for other rules.
+#
+[devfs_ruleset_hide=1]
+add hide
+
+# Basic devices typically necessary.
+#
+[devfs_ruleset_basic=2] #halloc
+add include $devfs_ruleset_hide
+add path null unhide	# test # test1
+add path zero unhide
+add path random unhide
+add path urandom unhide
+
+# Devices typically needed to support logged-in users.
+#
+[devfs_ruleset_login=3]
+add include $devfs_ruleset_hide
+add path 'ptyp*' unhide
+add path 'ptyq*' unhide
+add path 'ptyr*' unhide
+add path 'ptys*' unhide
+add path 'ptyP*' unhide
+add path 'ptyQ*' unhide
+add path 'ptyR*' unhide
+add path 'ptyS*' unhide
+add path 'ttyp*' unhide
+add path 'ttyq*' unhide
+add path 'ttyr*' unhide
+add path 'ttys*' unhide
+add path 'ttyP*' unhide
+add path 'ttyQ*' unhide
+add path 'ttyR*' unhide
+add path 'ttyS*' unhide
+add path 'fd/*' unhide
+add path stdin unhide
+add path stdout unhide
+add path stderr unhide
+
+# Devices usually found in a jail.
+#
+[devfs_ruleset_jail=123]
+add include $devfs_ruleset_hide
+add include $devfs_ruleset_basic
+add include $devfs_ruleset_login
Index: etc/defaults/rc.conf
===================================================================
RCS file: /home/ncvs/src/etc/defaults/rc.conf,v
retrieving revision 1.179
diff -u -r1.179 rc.conf
--- etc/defaults/rc.conf	14 Jun 2003 22:26:30 -0000	1.179
+++ etc/defaults/rc.conf	3 Aug 2003 23:45:02 -0000
@@ -430,6 +430,8 @@
 jail_set_hostname_allow="YES" # Allow root user in a jail to change its hostname
 jail_socket_unixiproute_only="YES" # Route only TCP/IP within a jail
 jail_sysvipc_allow="NO"       # Allow SystemV IPC use from within a jail
+devfs_rulesets="/etc/defaults/devfs.rules" # List of files of devfs(8) rules
+devfs_system_ruleset=""	# The name of the ruleset (devfs.rules) to apply to /dev
 
 ##############################################################
 ### Define source_rc_confs, the mechanism used by /etc/rc.* ##
Index: etc/rc.d/devfs
===================================================================
RCS file: /home/ncvs/src/etc/rc.d/devfs,v
retrieving revision 1.5
diff -u -r1.5 devfs
--- etc/rc.d/devfs	6 May 2003 01:10:33 -0000	1.5
+++ etc/rc.d/devfs	4 Aug 2003 00:14:14 -0000
@@ -11,8 +11,18 @@
 . /etc/rc.subr
 
 name="devfs"
-start_cmd='read_devfs_conf'
+start_cmd='devfs_start'
 stop_cmd=':'
+
+devfs_start()
+{
+	if [ -n "$devfs_system_ruleset" ]; then
+		devfs_init_rulesets
+		devfs_set_ruleset $devfs_system_ruleset /dev
+		devfs_apply_ruleset $devfs_system_ruleset /dev
+	fi
+	read_devfs_conf
+}
 
 read_devfs_conf()
 {

--OgqxwSJOaUobr8KG--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030804001815.GA17137>