#!/bin/sh -
#
#	$OpenBSD: MAKEDEV,v 1.23 2001/09/21 17:58:56 todd Exp $
#
# Copyright (c) 2001 Todd T. Fries <todd@OpenBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
# THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Device "make" file.  Valid arguments:
#	all	makes all known devices, including local devices.
#		Tries to make the ``standard'' number of each type.
#	floppy	devices to be put on install floppies
#	std	standard devices
#	local	configuration specific devices
#
# Tapes:
#	st*	SCSI tapes
#	ch*	SCSI media changer
#
# Disks:
#	wd*	"winchester" disk drives (ST506,IDE,ESDI,RLL,...)
#	fd*	Floppy disk drives (3 1/2", 5 1/4")
#	sd*	SCSI disks
#	cd*	SCSI cdrom drives
#	vnd*	"file" pseudo-disks
#	rd*	"ramdisk" pseudo-disks
#	ccd*	concatenated disk devices
#	raid*	RAIDframe disk devices
#
# Console ports:
#	console	PROM console
#
# Pointing devices:
#	mouse	mouse (provides events, for X11)
#
# Terminal ports:
#	tty[a-z]*	Zilog 8530 Serial Port
#	cua[a-z]*	Zilog 8530 Serial Port
#	com*	NS16x50 serial ports
#
# Pseudo terminals:
#	pty*	set of 16 master and slave pseudo terminals
#
# Special purpose devices:
#	ses*	SES/SAF-TE SCSI devices
#	fd	makes fd/* for the fdescfs
#	bwtwo*	
#	xfs*	XFS filesystem devices
#	cgthree*	
#	ss*	SCSI scanners
#	uk*	SCSI Unknown device
#	audio*	audio device
#	cgsix*	
#	pf*	Packet Filter
#	altq/	ALTQ control interface
#	cgfourteen*	
#	tcx*	
#	bpf*	Berkeley Packet Filter
#	tun*	network tunnel driver
#	lkm	loadable kernel modules interface
#	*random	inkernel random data source
#
PATH=/sbin:/usr/sbin:/bin:/usr/bin
T=$0

# set this to echo for Echo-Only debugging
[ "$eo" ] || eo=

hex()
{
	case $1 in
		[0-9]) echo -n $1;;
		10) echo -n a;;
		11) echo -n b;;
		12) echo -n c;;
		13) echo -n d;;
		14) echo -n e;;
		15) echo -n f;;
	esac
}
trunc()
{
	# XXX pdksh can't seem to deal with locally scoped variables
	# in ${foo#$bar} expansions
	arg1="$1"
	arg2="$2"
	case $3 in
	l)   echo ${arg2#$arg1} ;;
	r|*) echo ${arg1#$arg2} ;;
	esac
}
unt()
{
	# XXX pdksh can't seem to deal with locally scoped variables
	# in ${foo#$bar} expansions
	arg="$1"
	tmp="${arg#[a-zA-Z]*}"
	tmp="${tmp%*[a-zA-Z]}"
	while [ "$tmp" != "$arg" ]
	do
		arg=$tmp
		tmp="${arg#[a-zA-Z]*}"
		tmp="${tmp%*[a-zA-Z]}"
	done
	echo $arg
}
dodisk()
{
	n=$(($((${5}*16))+${6})) count=0
	RMlist="$RMlist $1$2? r$1$2?"
	for d in a b c d e f g h i j k l m n o p
	do
		M $1$2$d	b $3 $(($n+$count)) 640
		M r$1$2$d	c $4 $(($n+$count)) 640
		let count=count+1
	done
	MKlist="$MKlist;chown root.operator $1$2? r$1$2?"
}
dodisk2()
{
	n=$(($(($5*16))+$6))
	M $1$2a b $3 $n 640 operator
	M r$1$2a c $4 $n 640 operator
	n=$(($n+2))
	M $1$2c b $3 $n 640 operator
	M r$1$2c c $4 $n 640 operator
}

# M name b/c major minor [mode] [group]
RMlist="rm -f"
MKlist=":"
mkl() {
 [ "${mklist[$1]}" ] && {
  mklist[$1]="${mklist[$1]};mknod -m $1 $2 $3 $4 $5"
 } || {
  mklist[$1]="mknod -m $1 $2 $3 $4 $5"
  modes="$modes $1"
 }
}
M() {
	RMlist="$RMlist $1"
	mkl ${5-666} $1 $2 $3 $4
	mklist="$mklist $1"
	G=${6:-wheel}
	[ "$7" ] && {
		MKlist="$MKlist;chown $7.$G $1"
	} || {
		case $G in
		wheel)g=0;;kmem)g=2;;operator)g=5;;tty)g=4;;dialer)g=117;;
		esac
		[ "${grplist[$g]}" ] && {
			grplist[$g]="${grplist[$g]} $1"
		} || {
			groups="$groups $g"
			grplist[$g]="chgrp $G $1"
		}
	}
	return 0
}
R() {
for i in "$@"
do
U=`unt $i`
[ "$U" ] || U=0

case $i in
all)
	R std fd wd0 wd1 wd2 wd3 sd0 sd1 sd2
	R pty0 pty1 st0 st1 ch0 cd0 cd1
	R vnd0 vnd1 ccd0 ccd1 ccd2 ccd3
	R raid0 raid1 raid2 raid3
	R bpf0 bpf1 bpf2 bpf3 bpf4 bpf5 bpf6 bpf7 bpf8 bpf9
	R pf altq tun0 tun1 tun2 random ses0 uk0 uk1 ss0 ss1
	R fd0 fd0B fd0C fd0D fd0E fd0F fd0G fd0H
	R fd1 fd1B fd1C fd1D fd1E fd1F fd1G fd1H
	R xfs0 tcx0 lkm audio0 local
	R ttya ttyb ttyc ttyd cuaa cuab cuac cuad
	R tty00 tty01 tty02 tty03
	;;
floppy)
	R std fd0 wd0 wd1 sd0 sd1
	R st0 cd0 random
	;;
ramdisk)
	R std lkm random
	R fd0 rd0 wd0 wd1 wd2 wd3 bpf0
	R sd0 sd1 sd2 sd3 st0 st1 cd0 cd1
	;;
std)M console	c 0 0 600
	M tty		c 2 0
	M null		c 3 2
	M zero		c 3 12
	M mouse		c 13 0 666
	M klog		c 16 0 600
	M fb		c 22 0 666
	M stdin		c 24 0
	M stdout	c 24 1
	M stderr	c 24 2
	M kbd		c 29 0 666
	M mem		c 3 0 640 kmem
	M kmem		c 3 1 640 kmem
	M ksyms		c 76 0 640 kmem
	M drum		c 7 0 640 kmem
	M openprom	c 70 0 644
	;;
mouse*)name=${i##mouse-}
	if [ ! -c $name ]; then
		$0 $name	# make the appropriate device
	fi
	RMlist="$RMlist mouse"
	MKlist="$MKlist;ln -s $name mouse";;
*random)n=0
	for pre in " " s u p a
	do
		M ${pre}random c 119 $n 644
		n=$(($n+1))
	done;;
lkm)M lkm c 112 0 640 kmem;;tun*)M tun$U c 111 $U 600;;
bpf*)M bpf$U c 105 $U 600;;
tcx*)M tcx$U c 109 $U;;
cgfourteen*)M cgfourteen$U c 99 $U;;
altq)RMlist="mkdir -p altq;$RMlist"
	for d in altq cbq wfq afm fifoq red rio localq hfsc cdnr blue priq; do
		M altq/$d c 74 $U 644
		U=$(($U+1))
	done;;
pf*)M pf c 73 0 600;;
cgsix*)M cgsix$U c 67 $U 666;;
audio*)M sound$U	c 69 $U
	M mixer$U	c 69 $(($U+16))
	M audio$U	c 69 $(($U+128))
	M audioctl$U	c 69 $(($U+192))
	MKlist="$MKlist;[ -e audio ] || ln -s audio$U audio"
	MKlist="$MKlist;[ -e mixer ] || ln -s mixer$U mixer"
	MKlist="$MKlist;[ -e sound ] || ln -s sound$U sound"
	MKlist="$MKlist;[ -e audioctl ] || ln -s audioctl$U audioctl";;
uk*)M uk$U c 60 $U 640 operator;;
ss*)M ss$U c 59 $U 440 operator
	RMlist="$RMlist scan$U"
	MKlist="$MKlist;umask 77;ln -s ss$U scan$U";;
cgthree*)M cgthree$U c 55 $U 666;;
xfs*)M xfs$U c 51 $U 600;;
bwtwo*)M bwtwo$U c 27 $U 666;;
fd)RMlist="mkdir -p fd;$RMlist" n=0
	while [ $n -lt 64 ];do M fd/$n c 24 $n;n=$(($n+1));done
	MKlist="$MKlist;chmod 555 fd";;
ses*)M ses$U c 4 $U 640 operator;;
pty*)case $U in
	0) off=0 name=p;;
	1) off=16 name=q;;
	2) off=32 name=r;;
	3) off=48 name=s;;
# Note that telnetd, rlogind, and xterm (at least) only look at p-s.
	4) off=64 name=t;;
	5) off=80 name=u;;
	6) off=96 name=v;;
	7) off=112 name=w;;
	8) off=128 name=x;;
	9) off=144 name=y;;
	10) off=160 name=z;;
	11) off=176 name=P;;
	12) off=192 name=Q;;
	13) off=206 name=R;;
	14) off=224 name=S;;
	15) off=240 name=T;;
	*) echo bad unit for pty in: $i; continue;;
	esac
	n=0
	while [ $n -lt 16 ]
	do
		nam=$name$(hex $n)
		M tty$nam c 20 $(($off+$n))
		M pty$nam c 21 $(($off+$n))
		n=$(($n+1))
	done;;
tty0*)M tty$U c 36 $U 660 dialer uucp
	M cua$U c 36 $(($U+128)) 660 dialer uucp;;
cua[a-z])u=${i#cua*}
	case $u in
	a) n=0 ;;
	b) n=1 ;;
	c) n=4 ;;
	d) n=5 ;;
	*) echo unknown cua device $i ;;  
	esac
	M cua$u c 12 $(($n+128)) 660 dialer uucp;;
tty[a-z])u=${i#tty*}
	case $u in
	a) n=0 ;;
	b) n=1 ;;
	c) n=4 ;;
	d) n=5 ;;
	*) echo unknown tty device $i ;;
	esac
	M tty$u c 12 $n 660 dialer uucp;;
mouse)M mouse c 30 0 666 ;;rd*)dodisk2 rd $U 5 61 $U 0;;
vnd*)dodisk vnd $U 8 110 $U 0
	dodisk svnd $U 8 110 $U 128;;
cd*)dodisk2 cd $U 18 58 $U 0;;
fd*)typnam=$U${i#fd[01]*}
	case $typnam in
	0|1)	typnum=0;; # no type specified, assume A
	*A)		typnam=0; typnum=0;;
	*B)		typnum=1;;
	*C)		typnum=2;;
	*D)		typnum=3;;
	*E)		typnum=4;;
	*F)		typnum=5;;
	*G)		typnum=6;;
	*H)		typnum=7;;
	*)		echo bad type $typnam for $i; exit 1;;
	esac
	case $U in
	0|1)	blk=16; chr=54;;
	*)	echo bad unit $U for $i; exit 1;;
	esac
	nam=fd${typnam}
	n=$(($(($U*128))+$(($typnum*16))))
	M ${nam}a	b $blk $n 640 operator
	M ${nam}b	b $blk $(($n+1)) 640 operator
	M ${nam}c	b $blk $(($n+2)) 640 operator
	M r${nam}a	c $chr $n 640 operator
	M r${nam}b	c $chr $(($n+1)) 640 operator
	M r${nam}c	c $chr $(($n+2)) 640 operator;;
ch*)M ch$U c 19 $U 660 operator;;
st*)n=$(($U*16))
	for pre in " " n e en
	do
		M ${pre}st$U	b 11 $n 660 operator
		M ${pre}rst$U	c 18 $n 660 operator
		n=$(($n+1))
	done;;
local)test -s $T.local && sh $T.local;;
sd*|ccd*|raid*|wd*)case $i in
	sd*) n=sd b=7 c=17;;
	ccd*) n=ccd b=9 c=23;;
	raid*) n=raid b=25 c=121;;
	wd*) n=wd b=12 c=26;;
	esac
	dodisk $n $U $b $c $U 0;;
*)
	echo $i: unknown device
	;;
esac
done
}
R "$@"
if [ "$os" = "SunOS" ]; then
	eo=transform
	transform() {
		case $mode in
		600)mask=077;;
		640)mask=027;;
		660)mask=007;;
		644)mask=022;;
		666)mask=0;;
		440)mask=227;;
		esac
		echo `echo "$@"|sed \
			's/mknod -m \([0-9]*\) /umask '$mask';mknod /;s/-m [0-9]* //g;\
			 s/operator/5/g;s/root.kmem/root.2/g;s/root\./root:/g'`
	}
fi
list="$RMlist"
for mode in $modes; do
	list="$list;${mklist[$mode]}"
done
for group in $groups; do
	list="$list;${grplist[$group]}"
done
list="$list;$MKlist"
if [ "$eo" = "echo" -o "$eo" = "transform" ]; then
	$eo "$list"
else
	echo "$list" | sh
fi
