summaryrefslogtreecommitdiffstats
path: root/sys-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:32 +0100
committerKarel Zak2006-12-07 00:25:32 +0100
commit6dbe3af945a63f025561abb83275cee9ff06c57b (patch)
tree19e59eac8ac465b5bc409b5adf815b582c92f633 /sys-utils
downloadkernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.gz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.xz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.zip
Imported from util-linux-2.2 tarball.
Diffstat (limited to 'sys-utils')
-rw-r--r--sys-utils/MAKEDEV486
-rw-r--r--sys-utils/MAKEDEV.8147
-rw-r--r--sys-utils/Makefile88
-rw-r--r--sys-utils/README.MAKEDEV22
-rw-r--r--sys-utils/README.setserial73
-rw-r--r--sys-utils/arch.118
-rw-r--r--sys-utils/arch.c35
-rw-r--r--sys-utils/chroot.816
-rw-r--r--sys-utils/chroot.c25
-rw-r--r--sys-utils/clock.8108
-rw-r--r--sys-utils/clock.c490
-rw-r--r--sys-utils/ctrlaltdel.838
-rw-r--r--sys-utils/ctrlaltdel.c38
-rw-r--r--sys-utils/dmesg.849
-rw-r--r--sys-utils/dmesg.c88
-rw-r--r--sys-utils/ipc.info1106
-rw-r--r--sys-utils/ipc.texi1310
-rw-r--r--sys-utils/ipcrm.815
-rw-r--r--sys-utils/ipcrm.c50
-rw-r--r--sys-utils/ipcs.858
-rw-r--r--sys-utils/ipcs.c551
-rw-r--r--sys-utils/kbdrate.857
-rw-r--r--sys-utils/kbdrate.c130
-rw-r--r--sys-utils/lpcntl.830
-rw-r--r--sys-utils/lpcntl.c54
-rw-r--r--sys-utils/ramsize.81
-rw-r--r--sys-utils/rdev.8166
-rw-r--r--sys-utils/rdev.c244
-rw-r--r--sys-utils/readprofile.1159
-rw-r--r--sys-utils/readprofile.c223
-rw-r--r--sys-utils/renice.8131
-rw-r--r--sys-utils/renice.c128
-rw-r--r--sys-utils/rootflags.81
-rw-r--r--sys-utils/setserial.8392
-rw-r--r--sys-utils/setserial.c436
-rw-r--r--sys-utils/setsid.815
-rw-r--r--sys-utils/setsid.c25
-rw-r--r--sys-utils/sln.c72
-rw-r--r--sys-utils/swapdev.81
-rw-r--r--sys-utils/sync.838
-rw-r--r--sys-utils/sync.S21
-rw-r--r--sys-utils/tunelp.884
-rw-r--r--sys-utils/tunelp.c248
-rw-r--r--sys-utils/update_state.835
-rw-r--r--sys-utils/update_state.sh41
-rw-r--r--sys-utils/vidmode.81
46 files changed, 7544 insertions, 0 deletions
diff --git a/sys-utils/MAKEDEV b/sys-utils/MAKEDEV
new file mode 100644
index 000000000..6326edd43
--- /dev/null
+++ b/sys-utils/MAKEDEV
@@ -0,0 +1,486 @@
+#! /bin/sh -
+
+RCSID='MAKEDEV,v 1.1.1.1 1995/02/22 19:09:11 faith Exp'
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+# Customisation:
+# The devices fall into various classes. This section contains the mapping
+# from a class name into a group name and permission.
+# You will almost certainly need to edit the group name to match your
+# system, and you may change the permissions to suit your preference. These
+# lines _must_ be of the format "user group perm".
+
+ public=" root system 666"
+ system=" root system 660"
+ kmem=" root kmem 660"
+ tty=" root tty 666"
+ cons=" root tty 622" # 622 for console?
+dialout=" root uucp 660"
+ mouse=" root system 666"
+printer=" root daemon 660"
+ floppy=" root floppy 660"
+ disk=" root disk 660"
+ scsi=" root system 600"
+ cdrom=" root disk 660"
+ tape=" root disk 660"
+ audio=" root system 666"
+ ibcs2=" root system 666"
+scanner=" root system 666"
+
+#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#---#
+
+procfs=/proc
+
+opt_v=
+opt_d=
+opt_n=
+
+while [ $# -ge 1 ]
+do
+ case $1 in
+ --) shift; break ;;
+ -v) shift; opt_v=1 ;;
+ -d) shift; opt_d=1 ;;
+ -n) shift; opt_n=1; opt_v=1 ;;
+ -V) shift; opt_V=1 ;;
+ -*) echo "$0: unknown flag \"$1\"" >&2; exit 1 ;;
+ *) break ;;
+ esac
+done
+
+if [ "$opt_V" ]
+then
+ echo "$RCSID"
+ exit 0
+fi
+
+opts="${opt_n:+-n} ${opt_v:+-v} ${opt_d:+-d}"
+
+makedev () { # usage: makedev name [bcu] major minor owner group mode
+ if [ "$opt_v" ]
+ then if [ "$opt_d" ]
+ then echo "delete $1"
+ else echo "create $1 $2 $3 $4 $5:$6 $7"
+ fi
+ fi
+ if [ ! "$opt_n" ]
+ then if [ "$opt_d" ]
+ then
+ rm -f $1
+ else
+ mknod $1- $2 $3 $4 &&
+ chown $5:$6 $1- &&
+ chmod $7 $1- &&
+ mv $1- $1
+ fi
+ fi
+}
+symlink () { # usage: symlink name target
+ if [ "$opt_v" ]
+ then if [ "$opt_d" ]
+ then echo "delete $1"
+ else echo "create $1 -> $2"
+ fi
+ fi
+ [ ! "$opt_n" ] && rm -f $1 &&
+ [ ! "$opt_d" ] && ln -s $2 $1
+}
+
+devices=
+if [ ! -f $procfs/devices ]
+then
+ echo "$0: warning: can't read $procfs/devices" >&2
+else
+ exec 3<$procfs/devices
+ while read major device <&3
+ do
+ case "$major" in
+ Character|Block|'')
+ ;;
+ *)
+ eval "major_$device=$major"
+ devices="$devices $device"
+ ;;
+ esac
+ done
+ exec 3<&-
+fi
+
+Major () {
+ device=$2
+ if [ "$opt_d" ]
+ then
+ echo -1 # don't care
+ else
+ eval echo \${major_$1:-\${device:?\"unknown major number for $1\"}}
+ fi
+}
+
+cvt () {
+ while [ $# -ne 0 ]
+ do
+ case "$1" in
+ mem|tty|ttyp|cua|cub) ;;
+ hd) echo hda hdb ;;
+ xd) echo xda xdb ;;
+ fd) echo fd0 fd1 ;;
+ lp) echo lp0 lp1 lp2 ;;
+ mt) echo ftape ;;
+ loop) echo loop ;;
+ ibcs2) echo ibcs2 ;;
+ tpqic02) echo qic ;;
+ sound) echo audio ;;
+ logiscan) echo logiscan ;;
+ ac4096) echo ac4096 ;;
+ idecd) echo idecd ;;
+ hw) echo helloworld ;;
+ sbpcd | sbpcd[123]) echo $1 ;;
+ Joystick) echo js ;;
+ apm_bios) echo apm ;;
+ dcf) echo dcf ;;
+ pcmcia) ;; # taken care of by its own driver
+ ttyC) echo cyclades ;;
+ *) echo "$0: don't know what \"$1\" is" >&2 ;;
+ esac
+ shift
+ done
+}
+
+for arg
+do
+ case $arg in
+ generic)
+ $0 $opts std
+ $0 $opts fd0 fd1
+ $0 $opts hda hdb
+ $0 $opts xda xdb
+ $0 $opts sda sdb
+ $0 $opts ptyp ptyq ptyr ptys
+ $0 $opts console tty1 tty2 tty3 tty4 tty5 tty6 tty7 tty8
+ $0 $opts ttyS0 ttyS1 ttyS2 ttyS3
+ $0 $opts busmice
+ $0 $opts lp0 lp1 lp2
+ $0 $opts par0 par1 par2
+ $0 $opts fd
+ ;;
+ local)
+ $0.local $opts
+ ;;
+ std)
+ makedev mem c 1 1 $kmem
+ makedev kmem c 1 2 $kmem
+ makedev null c 1 3 $public
+ makedev port c 1 4 $kmem
+ makedev zero c 1 5 $public
+ symlink core $procfs/kcore
+ makedev full c 1 7 $public
+ makedev ram b 1 1 $disk
+ makedev tty c 5 0 $tty
+ ;;
+ console|tty0)
+ makedev $arg c 4 0 $cons
+ ;;
+ tty[1-9]|tty[1-5][0-9]|tty[6][0-3])
+ line=`expr $arg : "tty\(.*\)"`
+ makedev tty$line c 4 $line $tty
+ ;;
+ ttyS[0-9]|ttyS[1-5][0-9]|ttyS[6][0-3])
+ line=`expr $arg : "ttyS\(.*\)"`
+ minor=`expr 64 + $line`
+ makedev ttyS$line c 4 $minor $tty
+ makedev cua$line c 5 $minor $dialout
+ ;;
+ pty[p-s])
+ # Currently limited to 64 master/slave pairs.
+ bank=`expr $arg : "pty\(.\)"`
+ base=`expr \( pqrs : ".*$bank" - 1 \) \* 16`
+ for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ do
+ j=`expr 0123456789abcdef : ".*$i" - 1`
+ makedev pty$bank$i c 4 `expr 128 + $base + $j` $tty
+ makedev tty$bank$i c 4 `expr 192 + $base + $j` $tty
+ done
+ ;;
+ cyclades)
+ major1=`Major ttyC` || continue
+ major2=`Major cub` || continue
+ for i in 0 1 2 3 4 5 6 7 # 8 9 10 11 12 13 14 15
+ do
+ makedev ttyC$i c $major1 `expr 32 + $i` $tty
+ makedev cub$i c $major2 `expr 32 + $i` $dialout
+ done
+ ;;
+ par[0-2])
+ major=`Major lp 6` || continue
+ port=`expr $arg : "par\(.\)"`
+ makedev $arg c $major $port $printer
+ ;;
+ lp[0-2])
+ major=`Major lp 6` || continue
+ port=`expr $arg : "lp\(.\)"`
+ makedev $arg c $major $port $printer
+ ;;
+ busmice)
+ major=`Major mouse 10` || continue
+ makedev logibm c $major 0 $mouse
+ makedev psaux c $major 1 $mouse
+ makedev inportbm c $major 2 $mouse
+ makedev atibm c $major 3 $mouse
+ # makedev sejin c $major 4 $mouse
+ ;;
+ js)
+ major=`Major Joystick` || continue
+ makedev js0 c $major 0 $mouse
+ makedev js1 c $major 1 $mouse
+ ;;
+ fd[0-4])
+ major=`Major fd 2` || continue
+ unit=`expr $arg : "fd\(.\)"`
+ makedev fd${unit} b $major $unit $floppy
+ makedev fd${unit}d360 b $major `expr $unit + 4` $floppy
+ makedev fd${unit}h1200 b $major `expr $unit + 8` $floppy
+ makedev fd${unit}D360 b $major `expr $unit + 12` $floppy
+ symlink fd${unit}H360 fd${unit}D360
+ makedev fd${unit}D720 b $major `expr $unit + 16` $floppy
+ symlink fd${unit}H720 fd${unit}D720
+ makedev fd${unit}h360 b $major `expr $unit + 20` $floppy
+ makedev fd${unit}h720 b $major `expr $unit + 24` $floppy
+ makedev fd${unit}H1440 b $major `expr $unit + 28` $floppy
+ makedev fd${unit}E2880 b $major `expr $unit + 32` $floppy
+ makedev fd${unit}CompaQ b $major `expr $unit + 36` $floppy
+
+ makedev fd${unit}h1440 b $major `expr $unit + 40` $floppy
+ makedev fd${unit}H1680 b $major `expr $unit + 44` $floppy
+ makedev fd${unit}h410 b $major `expr $unit + 48` $floppy
+ makedev fd${unit}H820 b $major `expr $unit + 52` $floppy
+ makedev fd${unit}h1476 b $major `expr $unit + 56` $floppy
+ makedev fd${unit}H1722 b $major `expr $unit + 60` $floppy
+ makedev fd${unit}h420 b $major `expr $unit + 64` $floppy
+ makedev fd${unit}H830 b $major `expr $unit + 68` $floppy
+ makedev fd${unit}h1494 b $major `expr $unit + 72` $floppy
+ makedev fd${unit}H1743 b $major `expr $unit + 76` $floppy
+ ;;
+ hd[a-d])
+ major=`Major hd 3` || continue
+ unit=`expr $arg : "hd\(.\)"`
+ base=`expr \( abcd : ".*$unit" - 1 \) \* 64`
+ makedev hd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16
+ do
+ makedev hd$unit$part b $major `expr $base + $part` $disk
+ done
+ ;;
+ hd1[a-d])
+ unit=`expr $arg : "hd1\(.\)"`
+ base=`expr \( abcd : ".*$unit" - 1 \) \* 64`
+ makedev hd1$unit b 22 $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16
+ do
+ makedev hd1$unit$part b 22 `expr $base + $part` $disk
+ done
+ ;;
+ xd[a-d])
+ major=`Major xd 13` || continue
+ unit=`expr $arg : "xd\(.\)"`
+ base=`expr \( abcd : ".*$unit" - 1 \) \* 64`
+ makedev xd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15 16
+ do
+ makedev xd$unit$part b $major `expr $base + $part` $disk
+ done
+ ;;
+ sd[a-h])
+ major=`Major sd 8` || continue
+ unit=`expr $arg : "sd\(.\)"`
+ base=`expr \( abcdefgh : ".*$unit" - 1 \) \* 16`
+ makedev sd$unit b $major $base $disk
+ for part in 1 2 3 4 5 6 7 8 # 9 10 11 12 13 14 15
+ do
+ minor=`expr $base + $part`
+ makedev sd$unit$part b $major $minor $disk
+ done
+ ;;
+ loop)
+ major=`Major loop` || continue
+ for part in 0 1 2 3 4 5 6 7
+ do
+ makedev loop$part b $major $part $disk
+ done
+ ;;
+ st[0-7])
+ major=`Major st 9`
+ unit=`expr $arg : "st\(.\)"`
+ makedev st$unit c $major $unit $tape
+ makedev nst$unit c $major `expr 128 + $unit` $tape
+ ;;
+ qic)
+ major=`Major tpqic02 12`
+ makedev rmt8 c $major 6 $tape
+ makedev rmt16 c $major 8 $tape
+ makedev tape-d c $major 136 $tape
+ makedev tape-reset c $major 255 $tape
+ ;;
+ ftape)
+ major=`Major mt 27` || continue
+ for unit in 0 1 2 3
+ do
+ makedev rft$unit c $major $unit $tape
+ makedev nrft$unit c $major `expr $unit + 4` $tape
+ done
+ symlink ftape rft0
+ symlink nftape nrft0
+ ;;
+ scd[0-7])
+ major=`Major sr 11` || continue
+ unit=`expr $arg : "scd\(.\)"`
+ makedev scd$unit b $major $unit $cdrom
+ ;;
+ sonycd)
+ major=`Major cdu31a` || continue
+ makedev $arg b $major 0 $cdrom
+ ;;
+ mcd)
+ major=`Major mcd 23` || continue
+ makedev $arg b $major 0 $cdrom
+ ;;
+ cdu535)
+ makedev $arg b 24 0 $cdrom
+ ;;
+ lmscd)
+ makedev $arg b 24 0 $cdrom
+ ;;
+ sbpcd|sbpcd[123])
+ major=`Major $arg` || continue
+ base=`expr ${arg}0 : "sbpcd\(.\)"`
+ for minor in 0 1 2 3
+ do
+ unit=`expr substr 0123456789abcdef \( $base \* 4 + $minor + 1 \) 1`
+ makedev spbcd$unit b $major $minor $cdrom
+ done
+ [ $arg = sbpcd ] && symlink $arg ${arg}0
+ ;;
+ idecd)
+ major=`Major idecd` || continue
+ makedev $arg c $major 0 $cdrom
+ ;;
+ logiscan)
+ major=`Major logiscan` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ m105scan)
+ major=`Major m105` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ ac4096)
+ major=`Major ac4096` || continue
+ makedev $arg c $major 0 $scanner
+ ;;
+ audio)
+ major=`Major sound 14`
+ makedev mixer c $major 0 $audio
+ makedev sequencer c $major 1 $audio
+ makedev midi00 c $major 2 $audio
+ makedev dsp c $major 3 $audio
+ makedev audio c $major 4 $audio
+ makedev sndstat c $major 6 $audio
+# makedev sequencer2 c $major 8 $audio
+ makedev mixer1 c $major 16 $audio
+# makedev patmgr0 c $major 17 $audio
+ makedev midi01 c $major 18 $audio
+ makedev dsp1 c $major 19 $audio
+ makedev audio1 c $major 20 $audio
+# makedev patmgr1 c $major 33 $audio
+ makedev midi02 c $major 34 $audio
+ makedev midi03 c $major 50 $audio
+ ;;
+ pcaudio)
+ major=`Major pcsp` || continue
+ makedev pcmixer c $major 0 $audio
+ makedev pcsp c $major 3 $audio
+ makedev pcaudio c $major 4 $audio
+ ;;
+ sg)
+ major=`Major sg 21`
+ for unit in a b c d e f g h
+ do
+ minor=`expr abcdefgh : ".*$unit" - 1`
+ makedev $arg$unit c $major $minor $scsi
+ done
+ ;;
+ fd)
+ # not really devices, we use the /proc filesystem
+ symlink fd $procfs/self/fd
+ symlink stdin fd/0
+ symlink stdout fd/1
+ symlink stderr fd/2
+ ;;
+ ibcs2)
+ major=`Major ibcs2` || continue
+ makedev socksys c $major 0 $ibcs2
+ symlink nfsd socksys
+ makedev spx c $major 1 $ibcs2
+ symlink X0R null
+ ;;
+ apm)
+ major=`Major apm_bios` || continue
+ makedev $arg c $major 0 $system
+ ;;
+ dcf)
+ major=`Major dcf` || continue
+ makedev $arg c $major 0 $system
+ ;;
+ helloworld)
+ major=`Major hw` || continue
+ makedev helloworld c $major 0 $public
+ ;;
+ update)
+ if [ ! "$devices" ]
+ then
+ echo "$0: don't appear to have any devices" >&2
+ continue
+ fi
+ if [ "$opt_d" ]
+ then
+ echo "$0: can't delete an update" >&2
+ continue
+ fi
+ create=
+ delete=
+ devs="$devices"
+ if [ -f DEVICES ]
+ then
+ exec 3<DEVICES
+ while read device major <&3
+ do
+ eval now=\$major_$device
+ if [ "$now" = "" ]
+ then
+ delete="$delete `cvt $device`"
+ continue
+ elif [ "$now" != $major ]
+ then
+ create="$create "`cvt $device`
+ fi
+ devs=`expr "$devs" : "\(.*\) $device"``expr "$devs" : ".* $device\(.*\)"`
+ done
+ exec 3<&-
+ fi
+ create="$create "`cvt $devs`
+ $0 $opts -d $delete
+ $0 $opts $create
+ [ "$opt_n" ] && continue
+ for device in $devices
+ do
+ if [ "`cvt $device`" ]
+ then
+ eval echo $device \$major_$device
+ fi
+ done > DEVICES
+ ;;
+ *)
+ echo "$0: don't know how to make device \"$arg\"" >&2
+ ;;
+ esac
+done
+
+exit 0
diff --git a/sys-utils/MAKEDEV.8 b/sys-utils/MAKEDEV.8
new file mode 100644
index 000000000..fe0c3645e
--- /dev/null
+++ b/sys-utils/MAKEDEV.8
@@ -0,0 +1,147 @@
+.\" MAKEDEV.8,v 1.1.1.1 1995/02/22 19:09:12 faith Exp
+.TH MAKEDEV 8 "14th August 1994" Linux "Linux Programmer's Manual"
+.SH NAME
+MAKEDEV \- create devices
+.SH SYNOPSIS
+.B "cd dev; ./MAKEDEV [ -n ] [ -v ] update"
+.br
+.BI "cd dev; ./MAKEDEV [ -n ] [ -v ]" "device"
+.SH DESCRIPTION
+.B MAKEDEV
+is a script that will create the devices in \fC/dev\fP used to interface
+with drivers in the kernel.
+.PP
+Note that programs giving the error \(*QENOENT: No such file or
+directory\(*U normally means that the device file is missing, whereas
+\(*QENODEV: No such device\(*U normally means the kernel does not have the
+driver configured or loaded.
+.SH OPTIONS
+.TP
+.B \-V
+Print out version (actually RCS version information) and exit.
+.TP
+.B \-n
+Do not actually update the devices, just print the actions that would be
+performed.
+.TP
+.B \-d
+Delete the devices. The main use for this flag is by
+.I MAKEDEV
+itself.
+.TP
+.B \-v
+Be verbose. Print out the actions as they are performed. This is the
+same output as produced by
+.BR \-n .
+.SH CUSTOMISATION
+Since there is no standardisation in what names are used for system users
+and groups, it is possible that you may need to modify
+.B MAKEDEV
+to reflect your site's settings. Near the top of the file is a mapping
+from device type to user, group and permissions (e.g. all CD-ROM devices
+are set from the \fC$cdrom\fP variable). If you wish to change the
+defaults, this is the section to edit.
+.SH DEVICES
+.TP
+.B General Options
+.TP
+.B update
+This only works on kernels which have \fC/proc/interrupts\fP (introduced
+during 1.1.x). This file is scanned to see what devices are currently
+configured into the kernel, and this is compared with the previous
+settings stored in the file called \fCDEVICES\fP.
+Devices which are new since then or have a different major number are
+created, and those which are no longer configured are deleted.
+.TP
+.B generic
+Create a generic subset of devices.
+.TP
+.B
+std
+Standard devices.
+.TP
+.B local
+.TP
+.B Virtual Terminals
+.TP
+.B console
+Also known as tty0.
+.TP
+.B tty{0..63}
+Virtual consoles
+.TP
+.B Serial Devices
+.TP
+.I ttyS{0..63}
+serial ports and corresponding dialout device
+.TP
+.I cyclades
+Dial-in and dial-out devices for the cyclades intelligent I/O serial card.
+.TP
+.B Pseudo Terminals
+.TP
+.I pty[p-s]
+banks of of master and slave pseudo terminals
+.TP
+.B Parallel Ports
+.TP
+.I par[0-3] lp[0-3]
+parallel ports
+.TP
+.B Bus Mice
+.TP
+.I busmice
+The various bus mice devices.
+.TP
+.B Joystick Devices
+.TP
+.I js
+Joystick. Creates \fCjs0\fP and \fCjs1\fP.
+.TP
+.B Disks Devices
+.TP
+.I fd[0-4]
+floppy disks
+.TP
+.I hd[a-d]
+AT hard disks (1st controller)
+.TP
+.I hd1[a-d]
+2nd AT controller hard disks
+.TP
+.I xd[a-d]
+XT hard disks
+.TP
+.I sd[a-i]
+SCSI hard disks
+.TP
+.I loop
+Loopback disk devices
+.TP
+.B Tape Devices
+.TP
+.I st[0-7]
+SCSI tapes
+.TP
+.I qic
+QIC-80 tapes
+.TP
+.I ftape
+floppy driver tapes (QIC-117)
+.TP
+.B CDROM Devices
+.TP
+.I scd[0-7]
+SCSI CD players
+.TP
+.I sonycd
+Sony CDU-31A CD player
+.TP
+.I mcd
+Mitsumi CD player
+.TP
+.I cdu535
+Sony CDU-535 CD player
+.TP
+.I lmscd
+LMS/Philips CD player (nee \ No newline at end of file
diff --git a/sys-utils/Makefile b/sys-utils/Makefile
new file mode 100644
index 000000000..a584f16d1
--- /dev/null
+++ b/sys-utils/Makefile
@@ -0,0 +1,88 @@
+# Makefile -- Makefile for util-linux Linux utilities
+# Created: Sat Dec 26 20:09:40 1992
+# Revised: Sat Feb 11 17:52:09 1995 by faith@cs.unc.edu
+# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu)
+#
+
+include ../MCONFIG
+
+# Where to put man pages?
+
+MAN1= arch.1 readprofile.1
+
+MAN8= MAKEDEV.8 chroot.8 clock.8 ctrlaltdel.8 dmesg.8 ipcrm.8 \
+ ipcs.8 kbdrate.8 lpcntl.8 ramsize.8 rdev.8 renice.8 \
+ rootflags.8 setserial.8 setsid.8 swapdev.8 sync.8 tunelp.8 \
+ update_state.8 vidmode.8
+
+# Where to put binaries?
+# See the "install" rule for the links. . .
+
+DEV= MAKEDEV
+
+SBIN= clock kbdrate sln
+
+BIN= arch dmesg setserial sync
+
+USRSBIN= chroot ctrlaltdel update_state
+
+USRBIN= ipcrm ipcs lpcntl rdev renice readprofile setsid tunelp
+
+# Where to put datebase files?
+
+USRINFO= ipc.info
+
+SCRIPTS= reset update_state
+
+all: $(SBIN) $(BIN) $(USRSBIN) $(USRBIN)
+
+sln: sln.c
+ $(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@
+
+sync: sync.S
+ /lib/cpp sync.S > sync.s
+ as -o sync.o sync.s
+ ld -s -N -e _main sync.o -o sync
+ -rm sync.s
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(SCRIPTS):
+ cp $@.sh $@
+
+# Rules for everything else
+
+arch: arch.o
+chroot: chroot.o
+clock: clock.o
+ctrlaltdel: ctrlaltdel.o
+ipcrm: ipcrm.o
+ipcs: ipcs.o
+kbdrate: kbdrate.o
+lpcntl: lpcntl.o
+rdev: rdev.o
+renice: renice.o
+readprofile: readprofile.o
+setserial: setserial.o
+setsid: setsid.o
+update_state: update_state.sh
+
+install: all
+ $(INSTALLDIR) $(DEVDIR) $(SBINDIR) $(BINDIR) $(USRSBINDIR) $(USRBINDIR)
+ $(INSTALLBIN) $(DEV) $(DEVDIR)
+ $(INSTALLBIN) $(SBIN) $(SBINDIR)
+ $(INSTALLBIN) $(BIN) $(BINDIR)
+ $(INSTALLBIN) $(USRSBIN) $(USRSBINDIR)
+ $(INSTALLBIN) $(USRBIN) $(USRBINDIR)
+ (cd $(RDEVDIR); ln -sf rdev swapdev)
+ (cd $(RDEVDIR); ln -sf rdev ramsize)
+ (cd $(RDEVDIR); ln -sf rdev vidmode)
+ (cd $(RDEVDIR); ln -sf rdev rootflags)
+ $(INSTALLDIR) $(MAN1DIR) $(MAN8DIR) $(INFODIR)
+ $(INSTALLMAN) $(MAN1) $(MAN1DIR)
+ $(INSTALLMAN) $(MAN8) $(MAN8DIR)
+ $(INSTALLMAN) $(USRINFO) $(INFODIR)
+
+clean:
+ -rm -f *.o *~ core $(SBIN) $(BIN) $(USRSBIN) $(USRBIN)
diff --git a/sys-utils/README.MAKEDEV b/sys-utils/README.MAKEDEV
new file mode 100644
index 000000000..0cba83284
--- /dev/null
+++ b/sys-utils/README.MAKEDEV
@@ -0,0 +1,22 @@
+README.MAKEDEV,v 1.1.1.1 1995/02/22 19:09:12 faith Exp
+
+Here is the original comment taken from the MAKEDEV script. One day,
+I'll do this properly.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+This is my attempt at a MAKEDEV script. IMHO it cleans up many areas.
+It can be used to determine the necessary info for a device without
+actually creating it using the '-n' flag.
+
+It makes less individual devices and tends to make classes of devices
+(eg "MAKEDEV hda" will create "hda" and the 8 partitions; "MAKEDEV ptyp"
+will create the ptyp[0-f] master and ttyp[0-f] slave devices).
+
+If you are aware of any glaring omissions or errors, please let me know.
+Also, if you are a developer who wants your devices supported by MAKEDEV,
+let me know.
+
+Thanks to Ian Jackson for the original help and encouragement.
+
+ Nick Holloway <Nick.Holloway@alfie.demon.co.uk>
diff --git a/sys-utils/README.setserial b/sys-utils/README.setserial
new file mode 100644
index 000000000..bf3a5847d
--- /dev/null
+++ b/sys-utils/README.setserial
@@ -0,0 +1,73 @@
+setserial Version 2.10
+
+Setserial is a program which allows you to look at and change various
+attributes of a serial device, including its port, its IRQ, and other
+serial port options.
+
+Starting with Linux 0.99 pl10, only the COM1-4 ports are configured,
+using the default IRQ of 4 and 3. So, if you have any other serial
+ports provided by other boards (such as an AST Fourport), or if COM3-4
+have been a non-standard IRQ so that you can use time simultaneously
+with COM1-2, you *must* use this program in order to configure those
+serial ports.
+
+The simplest way to configure the serial ports is to copy the provided
+rc.serial file to /etc/rc.serial, and then add to /etc/rc the lines:
+
+if [ -f /etc/rc.serial ]; then
+sh /etc/rc.serial
+fi
+
+Take a look at /etc/rc.serial; it was written to be relatively easy to
+modify, and you may need to modify it so that it works best in your
+environment.
+
+
+-------------------------------------------------------
+
+Here is setserial's command line syntax:
+
+usage: ./setserial [-abgqvVW] serial-device [cmd1 [arg]] [cmd2] ...
+
+Available options:
+ -a Display all possible information about the port
+ -b Display boot-time level of information
+ -q Quiet flag
+ -v Verbose flag
+
+ -g Get and display the serial information of all
+ serial ports on the machine
+ -V Display the current Version and then exit
+
+ -W Do wild interrupt initialization and then exit
+
+Available commands: (* = Takes an argument)
+ (^ = can be preceded by a '^' to turn off the option)
+ * port set the I/O port
+ * irq set the interrupt
+ * uart set UART type (none, 8250, 16450, 16550, 16550A
+ * baud_base set base baud rate (CLOCK_FREQ / 16)
+ * divisor set the custom divisor (see spd_custom)
+ ^ fourport configure the port as an AST Fourport
+ autoconfigure automatically configure the serial port
+ ^ auto_irq try to determine irq during autoconfiguration
+ ^ skip_test skip UART test during autoconfiguration
+
+ ^ sak set the break key as the Secure Attention Key
+ ^ session_lockout Lock out callout port across different sessions
+ ^ pgrp_lockout Lock out callout port across different process groups
+ ^ split_termios Use separate termios for callout and dailin lines
+ ^ hup_notify Notify a process blocked on opening a dialin line
+ when a process has finished using a callout
+ line by returning EAGAIN to the open.
+ ^ callout_nohup Don't hangup the tty if carrier detect drops on a
+ callout line.
+
+ spd_hi use 56kb instead of 38.4kb
+ spd_vhi use 115kb instead of 38.4kb
+ spd_cust use the custom divisor to set the speed at 38.4kb
+ (baud rate = baud_base / custom_divisor)
+ spd_normal use 38.4kb when a buad rate of 38.4kb is selected
+
+Use a leading '0x' for hex numbers.
+CAUTION: Using an invalid port can lock up your machine!
diff --git a/sys-utils/arch.1 b/sys-utils/arch.1
new file mode 100644
index 000000000..c465c55fe
--- /dev/null
+++ b/sys-utils/arch.1
@@ -0,0 +1,18 @@
+.\" arch.1 --
+.\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" Public domain: may be freely distributed.
+.TH ARCH 1 "20 December 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+arch \- print machine architecture
+.SH SYNOPSIS
+.B arch
+.SH DESCRIPTION
+.B arch
+is equivalent to
+.B uname -m
+
+On current Linux systems,
+.B arch
+prints "i386" or "i486".
+.SH SEE ALSO
+.BR uname (1) ", " uname (2)
diff --git a/sys-utils/arch.c b/sys-utils/arch.c
new file mode 100644
index 000000000..33dff304b
--- /dev/null
+++ b/sys-utils/arch.c
@@ -0,0 +1,35 @@
+/* arch -- print machine architecture information
+ * Created: Mon Dec 20 12:27:15 1993 by faith@cs.unc.edu
+ * Revised: Mon Dec 20 12:29:23 1993 by faith@cs.unc.edu
+ * Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/utsname.h>
+
+int main (void)
+{
+ struct utsname utsbuf;
+
+ if (uname( &utsbuf )) {
+ perror( "arch" );
+ return 1;
+ }
+
+ printf( "%s\n", utsbuf.machine );
+
+ return 0;
+}
diff --git a/sys-utils/chroot.8 b/sys-utils/chroot.8
new file mode 100644
index 000000000..4beadbfd4
--- /dev/null
+++ b/sys-utils/chroot.8
@@ -0,0 +1,16 @@
+.\" Rick Sladkey <jrs@world.std.com>
+.\" In the public domain.
+.\" Pathname modified by faith@cs.unc.edu
+.TH CHROOT 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+chroot \- change root directory and execute a program there
+.SH SYNOPSIS
+.BI chroot " directory program" " [ " "arg ..." " ]"
+.SH DESCRIPTION
+.B chroot
+changes the root directory for a process to a new directory
+executes a program there.
+.SH "SEE ALSO"
+.BR chroot (2)
+.SH AUTHOR
+Rick Sladkey <jrs@world.std.com>
diff --git a/sys-utils/chroot.c b/sys-utils/chroot.c
new file mode 100644
index 000000000..7ddbe791f
--- /dev/null
+++ b/sys-utils/chroot.c
@@ -0,0 +1,25 @@
+/*
+ * chroot.c -- change root directory and execute a command there
+ * Rick Sladkey <jrs@world.std.com>
+ * In the public domain.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s directory program [arg ...]\n",
+ argv[0]);
+ exit(1);
+ }
+ if (chroot(argv[1]) < 0) {
+ perror("chroot");
+ exit(1);
+ }
+ execvp(argv[2], argv + 2);
+ perror("execvp");
+ exit(1);
+}
diff --git a/sys-utils/clock.8 b/sys-utils/clock.8
new file mode 100644
index 000000000..f4dd83ade
--- /dev/null
+++ b/sys-utils/clock.8
@@ -0,0 +1,108 @@
+.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH CLOCK 8 "24 December 1992" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+clock \- manipulate the CMOS clock
+.SH SYNOPSIS
+.B "/etc/clock [ -u ] -r"
+.br
+.B "/etc/clock [ -u ] -w"
+.br
+.B "/etc/clock [ -u ] -s"
+.br
+.B "/etc/clock [ -u ] -a"
+.SH DESCRIPTION
+.B clock
+manipulates the CMOS clock in variaous ways, allowing it to be read or
+written, and allowing synchronization between the CMOS clock and the
+kernel's version of the system time.
+.SH OPTIONS
+.TP
+.B \-u
+Indicates that the CMOS clock is set to Universal Time.
+.TP
+.B \-r
+Read CMOS clock and print the result to stdout.
+.TP
+.B \-w
+Write the system time into the CMOS clock.
+.TP
+.B \-s
+Set the system time from the CMOS clock.
+.TP
+.B \-a
+Set the system time from the CMOS clock, adjusting the time to correct for
+systematic error, and writting it back into the CMOS clock.
+.sp
+This option uses the file
+.I /etc/adjtime
+to determine how the clock changes. It contains three numbers:
+.RS
+The first number is the correction in seconds per day (for example, if your
+clock runs 5 seconds fast each day, the first number should read -5.0).
+.LP
+The second number tells when
+.B clock
+was last used, in seconds since 1/1/1970.
+.LP
+The third number is the remaining part of a second that was left over after
+the last adjustment.
+.LP
+The following instructions are from the source code:
+.TP
+a)
+create a file
+.I /etc/adjtime
+containing as the first and only line: '0.0 0 0.0'
+.TP
+b)
+run
+.I "clock -au"
+or
+.IR "clock -a" ,
+depending on whether your CMOS is in Universal or Local Time. This updates
+the second number.
+.TP
+c)
+set your system time using the
+.I date
+command.
+.TP
+d)
+update your CMOS time using
+.I "clock -wu"
+or
+.I clock -w
+.TP
+e)
+replace the first number in
+.I /etc/adjtime
+by your correction.
+.TP
+f)
+put the command
+.I "clock -au"
+or
+.I "clock -a"
+in your
+.IR /etc/rc.local ,
+or let
+.BR cron (8)
+start it regularly.
+.RE
+.SH FILES
+.I /etc/adjtime
+.br
+.I /etc/rc.local
+.SH AUTHORS
+.TP
+.B V1.0
+Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
+.TP
+.B V1.1
+Modified for clock adjustments, Rob Hooft, hooft@chem.ruu.nl, Nov 1992
+.TP
+.B V1.2
+Patches by Harald Koenig, koenig@nova.tat.physik.uni-tuebingen.de,
+applied by Rob Hooft, hooft@EMBL-Heidelberg.DE, Oct 1993
+.sp
diff --git a/sys-utils/clock.c b/sys-utils/clock.c
new file mode 100644
index 000000000..15020c260
--- /dev/null
+++ b/sys-utils/clock.c
@@ -0,0 +1,490 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+
+#define USE_INLINE_ASM_IO
+
+#ifdef USE_INLINE_ASM_IO
+#include <asm/io.h>
+#endif
+
+/* V1.0
+ * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
+ *
+ * clock [-u] -r - read cmos clock
+ * clock [-u] -w - write cmos clock from system time
+ * clock [-u] -s - set system time from cmos clock
+ * clock [-u] -a - set system time from cmos clock, adjust the time to
+ * correct for systematic error, and put it back to the cmos.
+ * -u indicates cmos clock is kept in universal time
+ *
+ * The program is designed to run setuid, since we need to be able to
+ * write the CMOS port.
+ *
+ * I don't know what the CMOS clock will do in 2000, so this program
+ * probably won't work past the century boundary.
+ *
+ *********************
+ * V1.1
+ * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992
+ * Also moved error messages to stderr. The program now uses getopt.
+ * Changed some exit codes. Made 'gcc 2.3 -Wall' happy.
+ *
+ * I think a small explanation of the adjustment routine should be given
+ * here. The problem with my machine is that its CMOS clock is 10 seconds
+ * per day slow. With this version of clock.c, and my '/etc/rc.local'
+ * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error
+ * is automatically corrected at every boot.
+ *
+ * To do this job, the program reads and writes the file '/etc/adjtime'
+ * to determine the correction, and to save its data. In this file are
+ * three numbers:
+ *
+ * 1) the correction in seconds per day (So if your clock runs 5
+ * seconds per day fast, the first number should read -5.0)
+ * 2) the number of seconds since 1/1/1970 the last time the program was
+ * used.
+ * 3) the remaining part of a second which was leftover after the last
+ * adjustment
+ *
+ * Installation and use of this program:
+ *
+ * a) create a file '/etc/adjtime' containing as the first and only line:
+ * '0.0 0 0.0'
+ * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in
+ * universal or local time. This updates the second number.
+ * c) set your system time using the 'date' command.
+ * d) update your cmos time using 'clock -wu' or 'clock -w'
+ * e) replace the first number in /etc/adjtime by your correction.
+ * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
+ *
+ * If the adjustment doesn't work for you, try contacting me by E-mail.
+ *
+ ******
+ * V1.2
+ *
+ * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de)
+ * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE)
+ *
+ * A free quote from a MAIL-message (with spelling corrections):
+ *
+ * "I found the explanation and solution for the CMOS reading 0xff problem
+ * in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount
+ * of time for updating. Solution is included in the kernel source
+ * (linux/kernel/time.c)."
+ *
+ * "I modified clock.c to fix this problem and added an option (now default,
+ * look for USE_INLINE_ASM_IO) that I/O instructions are used as inline
+ * code and not via /dev/port (still possible via #undef ...)."
+ *
+ * With the new code, which is partially taken from the kernel sources,
+ * the CMOS clock handling looks much more "official".
+ * Thanks Harald (and Torsten for the kernel code)!
+ *
+ ******
+ * V1.3
+ * Canges from alan@spri.levels.unisa.edu.au (Alan Modra):
+ * a) Fix a few typos in comments and remove reference to making
+ * clock -u a cron job. The kernel adjusts cmos time every 11
+ * minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss().
+ * This means we should really have a cron job updating
+ * /etc/adjtime every 11 mins (set last_time to the current time
+ * and not_adjusted to ???).
+ * b) Swapped arguments of outb() to agree with asm/io.h macro of the
+ * same name. Use outb() from asm/io.h as it's slightly better.
+ * c) Changed CMOS_READ and CMOS_WRITE to inline functions. Inserted
+ * cli()..sti() pairs in appropriate places to prevent possible
+ * errors, and changed ioperm() call to iopl() to allow cli.
+ * d) Moved some variables around to localise them a bit.
+ * e) Fixed bug with clock -ua or clock -us that cleared environment
+ * variable TZ. This fix also cured the annoying display of bogus
+ * day of week on a number of machines. (Use mktime(), ctime()
+ * rather than asctime() )
+ * f) Use settimeofday() rather than stime(). This one is important
+ * as it sets the kernel's timezone offset, which is returned by
+ * gettimeofday(), and used for display of MSDOS and OS2 file
+ * times.
+ * g) faith@cs.unc.edu added -D flag for debugging
+ *
+ * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra)
+ * Wed Feb 8 12:29:08 1995, fix for years > 2000.
+ * faith@cs.unc.edu added -v option to print version.
+ *
+ */
+
+#define VERSION "1.4"
+
+/* Here the information for time adjustments is kept. */
+#define ADJPATH "/etc/adjtime"
+
+
+/* used for debugging the code. */
+/*#define KEEP_OFF */
+
+/* Globals */
+int readit = 0;
+int adjustit = 0;
+int writeit = 0;
+int setit = 0;
+int universal = 0;
+int debug = 0;
+
+volatile void
+usage ()
+{
+ fprintf (stderr,
+ "clock [-u] -r|w|s|a|v\n"
+ " r: read and print CMOS clock\n"
+ " w: write CMOS clock from system time\n"
+ " s: set system time from CMOS clock\n"
+ " a: get system time and adjust CMOS clock\n"
+ " u: CMOS clock is in universal time\n"
+ " v: print version (" VERSION ") and exit\n"
+ );
+ exit (1);
+}
+
+#ifndef USE_INLINE_ASM_IO
+int cmos_fd;
+#endif
+
+static inline unsigned char cmos_read(unsigned char reg)
+{
+ register unsigned char ret;
+ __asm__ volatile ("cli");
+ outb (reg | 0x80, 0x70);
+ ret = inb (0x71);
+ __asm__ volatile ("sti");
+ return ret;
+}
+
+static inline void cmos_write(unsigned char reg, unsigned char val)
+{
+ outb (reg | 0x80, 0x70);
+ outb (val, 0x71);
+}
+
+#ifndef outb
+static inline void
+outb (char val, unsigned short port)
+{
+#ifdef USE_INLINE_ASM_IO
+ __asm__ volatile ("out%B0 %0,%1"::"a" (val), "d" (port));
+#else
+ lseek (cmos_fd, port, 0);
+ write (cmos_fd, &val, 1);
+#endif
+}
+#endif
+
+#ifndef inb
+static inline unsigned char
+inb (unsigned short port)
+{
+ unsigned char ret;
+#ifdef USE_INLINE_ASM_IO
+ __asm__ volatile ("in%B0 %1,%0":"=a" (ret):"d" (port));
+#else
+ lseek (cmos_fd, port, 0);
+ read (cmos_fd, &ret, 1);
+#endif
+ return ret;
+}
+#endif
+
+void
+cmos_init ()
+{
+#ifdef USE_INLINE_ASM_IO
+ if (iopl (3))
+ {
+ fprintf(stderr,"clock: unable to get I/O port access\n");
+ exit (1);
+ }
+#else
+ cmos_fd = open ("/dev/port", 2);
+ if (cmos_fd < 0)
+ {
+ perror ("unable to open /dev/port read/write : ");
+ exit (1);
+ }
+ if (lseek (cmos_fd, 0x70, 0) < 0 || lseek (cmos_fd, 0x71, 0) < 0)
+ {
+ perror ("unable to seek port 0x70 in /dev/port : ");
+ exit (1);
+ }
+#endif
+}
+
+static inline int
+cmos_read_bcd (int addr)
+{
+ int b;
+ b = cmos_read (addr);
+ return (b & 15) + (b >> 4) * 10;
+}
+
+static inline void
+cmos_write_bcd (int addr, int value)
+{
+ cmos_write (addr, ((value / 10) << 4) + value % 10);
+}
+
+int
+main (int argc, char **argv, char **envp)
+{
+ struct tm tm;
+ time_t systime;
+ time_t last_time;
+ char arg;
+ double factor;
+ double not_adjusted;
+ int adjustment = 0;
+ unsigned char save_control, save_freq_select;
+
+ while ((arg = getopt (argc, argv, "rwsuaDv")) != -1)
+ {
+ switch (arg)
+ {
+ case 'r':
+ readit = 1;
+ break;
+ case 'w':
+ writeit = 1;
+ break;
+ case 's':
+ setit = 1;
+ break;
+ case 'u':
+ universal = 1;
+ break;
+ case 'a':
+ adjustit = 1;
+ break;
+ case 'D':
+ debug = 1;
+ break;
+ case 'v':
+ fprintf( stderr, "clock " VERSION "\n" );
+ exit(0);
+ default:
+ usage ();
+ }
+ }
+
+ if (readit + writeit + setit + adjustit > 1)
+ usage (); /* only allow one of these */
+
+ if (!(readit | writeit | setit | adjustit)) /* default to read */
+ readit = 1;
+
+ cmos_init ();
+
+ if (adjustit)
+ { /* Read adjustment parameters first */
+ FILE *adj;
+ if ((adj = fopen (ADJPATH, "r")) == NULL)
+ {
+ perror (ADJPATH);
+ exit (2);
+ }
+ if (fscanf (adj, "%lf %d %lf", &factor, &last_time, &not_adjusted) < 0)
+ {
+ perror (ADJPATH);
+ exit (2);
+ }
+ fclose (adj);
+ if (debug) printf ("Last adjustment done at %d seconds after 1/1/1970\n", last_time);
+ }
+
+ if (readit || setit || adjustit)
+ {
+ int i;
+
+/* read RTC exactly on falling edge of update flag */
+/* Wait for rise.... (may take upto 1 second) */
+
+ for (i = 0; i < 10000000; i++)
+ if (cmos_read (10) & 0x80)
+ break;
+
+/* Wait for fall.... (must try at least 2.228 ms) */
+
+ for (i = 0; i < 1000000; i++)
+ if (!(cmos_read (10) & 0x80))
+ break;
+
+/* The purpose of the "do" loop is called "low-risk programming" */
+/* In theory it should never run more than once */
+ do
+ {
+ tm.tm_sec = cmos_read_bcd (0);
+ tm.tm_min = cmos_read_bcd (2);
+ tm.tm_hour = cmos_read_bcd (4);
+ tm.tm_wday = cmos_read_bcd (6);
+ tm.tm_mday = cmos_read_bcd (7);
+ tm.tm_mon = cmos_read_bcd (8);
+ tm.tm_year = cmos_read_bcd (9);
+ }
+ while (tm.tm_sec != cmos_read_bcd (0));
+ if (tm.tm_year < 70)
+ tm.tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */
+ tm.tm_mon--; /* DOS uses 1 base */
+ tm.tm_wday -= 3; /* DOS uses 3 - 9 for week days */
+ tm.tm_isdst = -1; /* don't know whether it's daylight */
+ if (debug) printf ("Cmos time : %d:%d:%d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);
+ }
+
+ if (readit || setit || adjustit)
+ {
+/*
+ * mktime() assumes we're giving it local time. If the CMOS clock
+ * is in GMT, we have to set up TZ so mktime knows it. tzset() gets
+ * called implicitly by the time code, but only the first time. When
+ * changing the environment variable, better call tzset() explicitly.
+ */
+ if (universal)
+ {
+ char *zone;
+ zone = (char *) getenv ("TZ"); /* save original time zone */
+ (void) putenv ("TZ=");
+ tzset ();
+ systime = mktime (&tm);
+ /* now put back the original zone */
+ if (zone)
+ {
+
+ char *zonebuf;
+ zonebuf = malloc (strlen (zone) + 4);
+ strcpy (zonebuf, "TZ=");
+ strcpy (zonebuf+3, zone);
+ putenv (zonebuf);
+ free (zonebuf);
+ }
+ else
+ { /* wasn't one, so clear it */
+ putenv ("TZ");
+ }
+ tzset ();
+ }
+ else
+ {
+ systime = mktime (&tm);
+ }
+ if (debug) printf ("Number of seconds since 1/1/1970 is %d\n", systime);
+ }
+
+ if (readit)
+ {
+ printf ("%s", ctime (&systime ));
+ }
+
+ if (setit || adjustit)
+ {
+ struct timeval tv;
+ struct timezone tz;
+
+/* program is designed to run setuid, be secure! */
+
+ if (getuid () != 0)
+ {
+ fprintf (stderr, "Sorry, must be root to set or adjust time\n");
+ exit (2);
+ }
+
+ if (adjustit)
+ { /* the actual adjustment */
+ double exact_adjustment;
+
+ exact_adjustment = ((double) (systime - last_time))
+ * factor / (24 * 60 * 60)
+ + not_adjusted;
+ if (exact_adjustment > 0)
+ adjustment = (int) (exact_adjustment + 0.5);
+ else
+ adjustment = (int) (exact_adjustment - 0.5);
+ not_adjusted = exact_adjustment - (double) adjustment;
+ systime += adjustment;
+ if (debug) {
+ printf ("Time since last adjustment is %d seconds\n",
+ (int) (systime - last_time));
+ printf ("Adjusting time by %d seconds\n",
+ adjustment);
+ printf ("remaining adjustment is %.3f seconds\n",
+ not_adjusted);
+ }
+ }
+#ifndef KEEP_OFF
+ tv.tv_sec = systime;
+ tv.tv_usec = 0;
+ tz.tz_minuteswest = timezone / 60;
+ tz.tz_dsttime = daylight;
+
+ if (settimeofday (&tv, &tz) != 0)
+ {
+ fprintf (stderr,
+ "Unable to set time -- probably you are not root\n");
+ exit (1);
+ }
+
+ if (debug) {
+ printf( "Called settimeofday:\n" );
+ printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n",
+ tv.tv_sec, tv.tv_usec );
+ printf( "\ttz.tz_minuteswest = %d, tz.tz_dsttime = %d\n",
+ tz.tz_minuteswest, tz.tz_dsttime );
+ }
+#endif
+ }
+
+ if (writeit || (adjustit && adjustment != 0))
+ {
+ struct tm *tmp;
+ systime = time (NULL);
+ if (universal)
+ tmp = gmtime (&systime);
+ else
+ tmp = localtime (&systime);
+
+#ifndef KEEP_OFF
+ __asm__ volatile ("cli");
+ save_control = cmos_read (11); /* tell the clock it's being set */
+ cmos_write (11, (save_control | 0x80));
+ save_freq_select = cmos_read (10); /* stop and reset prescaler */
+ cmos_write (10, (save_freq_select | 0x70));
+
+ cmos_write_bcd (0, tmp->tm_sec);
+ cmos_write_bcd (2, tmp->tm_min);
+ cmos_write_bcd (4, tmp->tm_hour);
+ cmos_write_bcd (6, tmp->tm_wday + 3);
+ cmos_write_bcd (7, tmp->tm_mday);
+ cmos_write_bcd (8, tmp->tm_mon + 1);
+ cmos_write_bcd (9, tmp->tm_year);
+
+ cmos_write (10, save_freq_select);
+ cmos_write (11, save_control);
+ __asm__ volatile ("sti");
+#endif
+ if (debug) printf ("Set to : %d:%d:%d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ }
+ else
+ if (debug) printf ("CMOS clock unchanged.\n");
+ /* Save data for next 'adjustit' call */
+ if (adjustit)
+ {
+ FILE *adj;
+ if ((adj = fopen (ADJPATH, "w")) == NULL)
+ {
+ perror (ADJPATH);
+ exit (2);
+ }
+ fprintf (adj, "%f %d %f\n", factor, systime, not_adjusted);
+ fclose (adj);
+ }
+ exit (0);
+}
diff --git a/sys-utils/ctrlaltdel.8 b/sys-utils/ctrlaltdel.8
new file mode 100644
index 000000000..488f37c07
--- /dev/null
+++ b/sys-utils/ctrlaltdel.8
@@ -0,0 +1,38 @@
+.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH CTRLALTDEL 8 "25 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+ctrlaltdel \- set the function of the Ctrl-Alt-Del combination
+.SH SYNOPSIS
+.B "ctrlaltdel hard|soft"
+.SH DESCRIPTION
+Based on examination of the
+.I linux/kernel/sys.c
+code, it is clear that there are two supported functions that the
+Ctrl-Alt-Del sequence can perform: a
+.I hard
+reset, which immediately reboots the computer without calling
+.B sync (2)
+and without any other preparation; and a
+.I soft
+reset, which sends the SIGINT (interrupt) signal to the
+.B init
+process (this is always the process with PID 1). If this option is used,
+the
+.B init (8)
+program must support this feature. Since there are now several
+.B init (8)
+programs in the Linux community, please consult the documentation for the
+version that you are currently using.
+
+.B ctrlaltdel
+is usually used in the
+.I /etc/rc.local
+file.
+.SH FILES
+.I /etc/rc.local
+.SH "SEE ALSO"
+.BR simpleinit (8),
+.BR init (8)
+.SH AUTHOR
+Peter Orbaek (poe@daimi.aau.dk)
diff --git a/sys-utils/ctrlaltdel.c b/sys-utils/ctrlaltdel.c
new file mode 100644
index 000000000..e5565d704
--- /dev/null
+++ b/sys-utils/ctrlaltdel.c
@@ -0,0 +1,38 @@
+/*
+ * ctrlaltdel.c - Set the function of the Ctrl-Alt-Del combination
+ * Created 4-Jul-92 by Peter Orbaek <poe@daimi.aau.dk>
+ * ftp://ftp.daimi.aau.dk/pub/linux/poe/
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+int reboot(int magic, int magictoo, int flag);
+
+int
+main(int argc, char *argv[]) {
+
+ if(geteuid()) {
+ fprintf(stderr, "You must be root to set the Ctrl-Alt-Del behaviour.\n");
+ exit(1);
+ }
+
+ if(argc == 2 && !strcmp("hard", argv[1])) {
+ if(reboot(0xfee1dead, 672274793, 0x89abcdef) < 0) {
+ perror("ctrlaltdel: reboot");
+ exit(1);
+ }
+ } else if(argc == 2 && !strcmp("soft", argv[1])) {
+ if(reboot(0xfee1dead, 672274793, 0) < 0) {
+ perror("ctrlaltdel: reboot");
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "Usage: ctrlaltdel hard|soft\n");
+ exit(1);
+ }
+ exit(0);
+}
+
+
diff --git a/sys-utils/dmesg.8 b/sys-utils/dmesg.8
new file mode 100644
index 000000000..d2e4ce1bc
--- /dev/null
+++ b/sys-utils/dmesg.8
@@ -0,0 +1,49 @@
+.\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH DMESG 8 "28 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+dmesg \- print or control the kernel ring buffer
+.SH SYNOPSIS
+.BI "dmesg [ \-c ] [ \-n " level " ]"
+.SH DESCRIPTION
+.B dmesg
+is used to examine or control the kernel ring buffer.
+
+The program helps users to print out their bootup messages. Instead of
+copying the messages by hand, the user need only:
+.RS
+dmesg > boot.messages
+.RE
+and mail the
+.I boot.messages
+file to whoever can debug their problem.
+.SH OPTIONS
+.TP
+.B \-c
+clear the ring buffer contents after printing.
+.TP
+.BI \-n level
+set the
+.I level
+at which logging of messages is done to the console. For example,
+.B \-n 1
+prevents all messages, expect panic messages, from appearing on the
+console. All levels of messages are still written to
+.IR /proc/kmsg ,
+so
+.BR syslogd (8)
+can still be used to control exactly where kernel messages appear. When
+the
+.B \-n
+option is used,
+.B dmesg
+will
+.I not
+print or clear the kernel ring buffer.
+
+When both options are used, only the last option on the command line will
+have an effect.
+.SH SEE ALSO
+.BR syslogd (8)
+.SH AUTHOR
+Theodore Ts'o (tytso@athena.mit.edu)
diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c
new file mode 100644
index 000000000..880528531
--- /dev/null
+++ b/sys-utils/dmesg.c
@@ -0,0 +1,88 @@
+/* dmesg.c -- Print out the contents of the kernel ring buffer
+ * Created: Sat Oct 9 16:19:47 1993
+ * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu
+ * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu)
+ * This program comes with ABSOLUTELY NO WARRANTY.
+ * Modifications by Rick Sladkey (jrs@world.std.com)
+ */
+
+#include <linux/unistd.h>
+#include <stdio.h>
+#include <getopt.h>
+
+#define __NR_klog __NR_syslog
+
+static inline _syscall3(int,klog,int,type,char *,b,int,len)
+
+static char *progname;
+
+usage()
+{
+ fprintf( stderr, "Usage: %s [-c] [-n level]\n", progname );
+}
+
+int main( int argc, char *argv[] )
+{
+ char buf[4096];
+ int i;
+ int n;
+ int c;
+ int level;
+ int lastc;
+ int cmd = 3;
+
+ progname = argv[0];
+ while ((c = getopt( argc, argv, "cn:" )) != EOF) {
+ switch (c) {
+ case 'c':
+ cmd = 4;
+ break;
+ case 'n':
+ cmd = 8;
+ level = atoi(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ exit(1);
+ }
+
+ if (cmd == 8) {
+ n = klog( cmd, NULL, level );
+ if (n < 0) {
+ perror( "klog" );
+ exit( 1 );
+ }
+ exit( 0 );
+ }
+
+ n = klog( cmd, buf, sizeof( buf ) );
+ if (n < 0) {
+ perror( "klog" );
+ exit( 1 );
+ }
+
+ lastc = '\n';
+ for (i = 0; i < n; i++) {
+ if ((i == 0 || buf[i - 1] == '\n') && buf[i] == '<') {
+ i++;
+ while (buf[i] >= '0' && buf[i] <= '9')
+ i++;
+ if (buf[i] == '>')
+ i++;
+ }
+ lastc = buf[i];
+ putchar( lastc );
+ }
+ if (lastc != '\n')
+ putchar( '\n' );
+ return 0;
+}
diff --git a/sys-utils/ipc.info b/sys-utils/ipc.info
new file mode 100644
index 000000000..5d34e18df
--- /dev/null
+++ b/sys-utils/ipc.info
@@ -0,0 +1,1106 @@
+This is Info file ipc.info, produced by Makeinfo-1.47 from the input
+file ipc.texi.
+
+ This file documents the System V style inter process communication
+primitives available under linux.
+
+ Copyright (C) 1992 krishna balasubramanian
+
+ Permission is granted to use this material and the accompanying
+programs within the terms of the GNU GPL.
+
+
+File: ipc.info, Node: top, Next: Overview, Prev: Notes, Up: (dir)
+
+System V IPC.
+*************
+
+ These facilities are provided to maintain compatibility with
+programs developed on system V unix systems and others that rely on
+these system V mechanisms to accomplish inter process communication
+(IPC).
+
+ The specifics described here are applicable to the Linux
+implementation. Other implementations may do things slightly
+differently.
+
+* Menu:
+
+* Overview:: What is system V ipc? Overall mechanisms.
+* Messages:: System calls for message passing.
+* Semaphores:: System calls for semaphores.
+* Shared Memory:: System calls for shared memory access.
+* Notes:: Miscellaneous notes.
+
+
+File: ipc.info, Node: Overview, Next: example, Prev: top, Up: top
+
+Overview
+========
+
+System V IPC consists of three mechanisms:
+
+ * Messages : exchange messages with any process or server.
+
+ * Semaphores : allow unrelated processes to synchronize execution.
+
+ * Shared memory : allow unrelated processes to share memory.
+
+* Menu:
+
+* example:: Using shared memory.
+* perms:: Description of access permissions.
+* syscalls:: Overview of ipc system calls.
+
+ Access to all resources is permitted on the basis of permissions set
+up when the resource was created.
+
+ A resource here consists of message queue, a semaphore set (array)
+or a shared memory segment.
+
+ A resource must first be allocated by a creator before it is used.
+The creator can assign a different owner. After use the resource must
+be explicitly destroyed by the creator or owner.
+
+ A resource is identified by a numeric ID. Typically a creator
+defines a KEY that may be used to access the resource. The user process
+may then use this KEY in the "get" system call to obtain the ID for the
+corresponding resource. This ID is then used for all further access. A
+library call "ftok" is provided to translate pathnames or strings to
+numeric keys.
+
+ There are system and implementation defined limits on the number and
+sizes of resources of any given type. Some of these are imposed by the
+implementation and others by the system administrator when configuring
+the kernel (*Note msglimits::, *Note semlimits::, *Note shmlimits::).
+
+ There is an `msqid_ds', `semid_ds' or `shmid_ds' struct associated
+with each message queue, semaphore array or shared segment. Each ipc
+resource has an associated `ipc_perm' struct which defines the creator,
+owner, access perms ..etc.., for the resource. These structures are
+detailed in the following sections.
+
+
+File: ipc.info, Node: example, Next: perms, Prev: Overview, Up: Overview
+
+example
+=======
+
+ Here is a code fragment with pointers on how to use shared memory.
+The same methods are applicable to other resources.
+
+ In a typical access sequence the creator allocates a new instance of
+the resource with the `get' system call using the IPC_CREAT flag.
+
+creator process:
+ #include <sys/shm.h>
+ int id;
+ key_t key;
+ char proc_id = 'C';
+ int size = 0x5000; /* 20 K */
+ int flags = 0664 | IPC_CREAT; /* read-only for others */
+
+ key = ftok ("~creator/ipckey", proc_id);
+ id = shmget (key, size, flags);
+ exit (0); /* quit leaving resource allocated */
+
+Users then gain access to the resource using the same key.
+Client process:
+ #include <sys/shm.h>
+ char *shmaddr;
+ int id;
+ key_t key;
+ char proc_id = 'C';
+
+ key = ftok ("~creator/ipckey", proc_id);
+
+ id = shmget (key, 0, 004); /* default size */
+ if (id == -1)
+ perror ("shmget ...");
+
+ shmaddr = shmat (id, 0, SHM_RDONLY); /* attach segment for reading */
+ if (shmaddr == (char *) -1)
+ perror ("shmat ...");
+
+ local_var = *(shmaddr + 3); /* read segment etc. */
+
+ shmdt (shmaddr); /* detach segment */
+
+When the resource is no longer needed the creator should remove it.
+Creator/owner process 2:
+ key = ftok ("~creator/ipckey", proc_id)
+ id = shmget (key, 0, 0);
+ shmctl (id, IPC_RMID, NULL);
+
+
+File: ipc.info, Node: perms, Next: syscalls, Prev: example, Up: Overview
+
+Permissions
+===========
+
+ Each resource has an associated `ipc_perm' struct which defines the
+creator, owner and access perms for the resource.
+
+ struct ipc_perm
+ key_t key; /* set by creator */
+ ushort uid; /* owner euid and egid */
+ ushort gid;
+ ushort cuid; /* creator euid and egid */
+ ushort cgid;
+ ushort mode; /* access modes in lower 9 bits */
+ ushort seq; /* sequence number */
+
+ The creating process is the default owner. The owner can be
+reassigned by the creator and has creator perms. Only the owner,
+creator or super-user can delete the resource.
+
+ The lowest nine bits of the flags parameter supplied by the user to
+the system call are compared with the values stored in `ipc_perms.mode'
+to determine if the requested access is allowed. In the case that the
+system call creates the resource, these bits are initialized from the
+user supplied value.
+
+ As for files, access permissions are specified as read, write and
+exec for user, group or other (though the exec perms are unused). For
+example 0624 grants read-write to owner, write-only to group and
+read-only access to others.
+
+ For shared memory, note that read-write access for segments is
+determined by a separate flag which is not stored in the `mode' field.
+Shared memory segments attached with write access can be read.
+
+ The `cuid', `cgid', `key' and `seq' fields cannot be changed by the
+user.
+
+
+File: ipc.info, Node: syscalls, Next: Messages, Prev: perms, Up: Overview
+
+IPC system calls
+================
+
+ This section provides an overview of the IPC system calls. See the
+specific sections on each type of resource for details.
+
+ Each type of mechanism provides a "get", "ctl" and one or more "op"
+system calls that allow the user to create or procure the resource
+(get), define its behaviour or destroy it (ctl) and manipulate the
+resources (op).
+
+The "get" system calls
+----------------------
+
+ The `get' call typically takes a KEY and returns a numeric ID that
+is used for further access. The ID is an index into the resource table.
+A sequence number is maintained and incremented when a resource is
+destroyed so that acceses using an obselete ID is likely to fail.
+
+ The user also specifies the permissions and other behaviour
+charecteristics for the current access. The flags are or-ed with the
+permissions when invoking system calls as in:
+ msgflg = IPC_CREAT | IPC_EXCL | 0666;
+ id = msgget (key, msgflg);
+
+ * `key' : IPC_PRIVATE => new instance of resource is initialized.
+
+ * `flags' :
+ IPC_CREAT : resource created for KEY if it does not exist.
+
+ IPC_CREAT | IPC_EXCL : fail if resource exists for KEY.
+
+ * returns : an identifier used for all further access to the
+ resource.
+
+ Note that IPC_PRIVATE is not a flag but a special `key' that ensures
+(when the call is successful) that a new resource is created.
+
+ Use of IPC_PRIVATE does not make the resource inaccessible to other
+users. For this you must set the access permissions appropriately.
+
+ There is currently no way for a process to ensure exclusive access
+to a resource. IPC_CREAT | IPC_EXCL only ensures (on success) that a new
+resource was initialized. It does not imply exclusive access.
+
+See Also : *Note msgget::, *Note semget::, *Note shmget::.
+
+The "ctl" system calls
+----------------------
+
+ Provides or alters the information stored in the structure that
+describes the resource indexed by ID.
+
+ #include <sys/msg.h>
+ struct msqid_ds buf;
+ err = msgctl (id, IPC_STAT, &buf);
+ if (err)
+ !$#%*
+ else
+ printf ("creator uid = %d\n", buf.msg_perm.cuid);
+ ....
+
+Commands supported by all `ctl' calls:
+ * IPC_STAT : read info on resource specified by id into user
+ allocated buffer. The user must have read access to the resource.
+
+ * IPC_SET : write info from buffer into resource data structure. The
+ user must be owner creator or super-user.
+
+ * IPC_RMID : remove resource. The user must be the owner, creator or
+ super-user.
+
+The IPC_RMID command results in immediate removal of a message queue or
+semaphore array. Shared memory segments however, are only destroyed
+upon the last detach after IPC_RMID is executed.
+
+ The `semctl' call provides a number of command options that allow
+the user to determine or set the values of the semaphores in an array.
+
+See Also: *Note msgctl::, *Note semctl::, *Note shmctl::.
+
+The "op" system calls
+---------------------
+
+ Used to send or receive messages, read or alter semaphore values,
+attach or detach shared memory segments. The IPC_NOWAIT flag will cause
+the operation to fail with error EAGAIN if the process has to wait on
+the call.
+
+`flags' : IPC_NOWAIT => return with error if a wait is required.
+
+See Also: *Note msgsnd::,*Note msgrcv::,*Note semop::,*Note shmat::,
+*Note shmdt::.
+
+
+File: ipc.info, Node: Messages, Next: msgget, Prev: syscalls, Up: top
+
+Messages
+========
+
+ A message resource is described by a struct `msqid_ds' which is
+allocated and initialized when the resource is created. Some fields in
+`msqid_ds' can then be altered (if desired) by invoking `msgctl'. The
+memory used by the resource is released when it is destroyed by a
+`msgctl' call.
+
+ struct msqid_ds
+ struct ipc_perm msg_perm;
+ struct msg *msg_first; /* first message on queue (internal) */
+ struct msg *msg_last; /* last message in queue (internal) */
+ time_t msg_stime; /* last msgsnd time */
+ time_t msg_rtime; /* last msgrcv time */
+ time_t msg_ctime; /* last change time */
+ struct wait_queue *wwait; /* writers waiting (internal) */
+ struct wait_queue *rwait; /* readers waiting (internal) */
+ ushort msg_cbytes; /* number of bytes used on queue */
+ ushort msg_qnum; /* number of messages in queue */
+ ushort msg_qbytes; /* max number of bytes on queue */
+ ushort msg_lspid; /* pid of last msgsnd */
+ ushort msg_lrpid; /* pid of last msgrcv */
+
+ To send or receive a message the user allocates a structure that
+looks like a `msgbuf' but with an array `mtext' of the required size.
+Messages have a type (positive integer) associated with them so that
+(for example) a listener can choose to receive only messages of a given
+type.
+
+ struct msgbuf
+ long mtype; type of message (*Note msgrcv::).
+ char mtext[1]; message text .. why is this not a ptr?
+
+ The user must have write permissions to send and read permissions to
+receive messages on a queue.
+
+ When `msgsnd' is invoked, the user's message is copied into an
+internal struct `msg' and added to the queue. A `msgrcv' will then read
+this message and free the associated struct `msg'.
+
+* Menu:
+
+* msgget::
+* msgsnd::
+* msgrcv::
+* msgctl::
+* msglimits:: Implementation defined limits.
+
+
+File: ipc.info, Node: msgget, Next: msgsnd, Prev: Messages, Up: Messages
+
+msgget
+------
+
+A message queue is allocated by a msgget system call :
+
+ msqid = msgget (key_t key, int msgflg);
+
+ * `key': an integer usually got from `ftok()' or IPC_PRIVATE.
+
+ * `msgflg':
+ IPC_CREAT : used to create a new resource if it does not
+ already exist.
+
+ IPC_EXCL | IPC_CREAT : used to ensure failure of the call if
+ the resource already exists.
+
+ rwxrwxrwx : access permissions.
+
+ * returns: msqid (an integer used for all further access) on success.
+ -1 on failure.
+
+ A message queue is allocated if there is no resource corresponding
+to the given key. The access permissions specified are then copied into
+the `msg_perm' struct and the fields in `msqid_ds' initialized. The
+user must use the IPC_CREAT flag or key = IPC_PRIVATE, if a new
+instance is to be allocated. If a resource corresponding to KEY already
+exists, the access permissions are verified.
+
+Errors:
+EACCES : (procure) Do not have permission for requested access.
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.
+EIDRM : (procure) The resource was removed.
+ENOSPC : All id's are taken (max of MSGMNI id's system-wide).
+ENOENT : Resource does not exist and IPC_CREAT not specified.
+ENOMEM : A new `msqid_ds' was to be created but ... nomem.
+
+
+File: ipc.info, Node: msgsnd, Next: msgrcv, Prev: msgget, Up: Messages
+
+msgsnd
+------
+
+ int msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
+
+ * `msqid' : id obtained by a call to msgget.
+
+ * `msgsz' : size of msg text (`mtext') in bytes.
+
+ * `msgp' : message to be sent. (msgp->mtype must be positive).
+
+ * `msgflg' : IPC_NOWAIT.
+
+ * returns : msgsz on success. -1 on error.
+
+ The message text and type are stored in the internal `msg'
+structure. `msg_cbytes', `msg_qnum', `msg_lspid', and `msg_stime'
+fields are updated. Readers waiting on the queue are awakened.
+
+Errors:
+EACCES : Do not have write permission on queue.
+EAGAIN : IPC_NOWAIT specified and queue is full.
+EFAULT : msgp not accessible.
+EIDRM : The message queue was removed.
+EINTR : Full queue ... would have slept but ... was interrupted.
+EINVAL : mtype < 1, msgsz > MSGMAX, msgsz < 0, msqid < 0 or unused.
+ENOMEM : Could not allocate space for header and text.
+
+File: ipc.info, Node: msgrcv, Next: msgctl, Prev: msgsnd, Up: Messages
+
+msgrcv
+------
+
+ int msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
+ int msgflg);
+
+ * msqid : id obtained by a call to msgget.
+
+ * msgsz : maximum size of message to receive.
+
+ * msgp : allocated by user to store the message in.
+
+ * msgtyp :
+ 0 => get first message on queue.
+
+ > 0 => get first message of matching type.
+
+ < 0 => get message with least type which is <= abs(msgtyp).
+
+ * msgflg :
+ IPC_NOWAIT : Return immediately if message not found.
+
+ MSG_NOERROR : The message is truncated if it is larger than
+ msgsz.
+
+ MSG_EXCEPT : Used with msgtyp > 0 to receive any msg except
+ of specified type.
+
+ * returns : size of message if found. -1 on error.
+
+ The first message that meets the `msgtyp' specification is
+identified. For msgtyp < 0, the entire queue is searched for the
+message with the smallest type.
+
+ If its length is smaller than msgsz or if the user specified the
+MSG_NOERROR flag, its text and type are copied to msgp->mtext and
+msgp->mtype, and it is taken off the queue.
+
+ The `msg_cbytes', `msg_qnum', `msg_lrpid', and `msg_rtime' fields
+are updated. Writers waiting on the queue are awakened.
+
+Errors:
+E2BIG : msg bigger than msgsz and MSG_NOERROR not specified.
+EACCES : Do not have permission for reading the queue.
+EFAULT : msgp not accessible.
+EIDRM : msg queue was removed.
+EINTR : msg not found ... would have slept but ... was interrupted.
+EINVAL : msgsz > msgmax or msgsz < 0, msqid < 0 or unused.
+ENOMSG : msg of requested type not found and IPC_NOWAIT specified.
+
+
+File: ipc.info, Node: msgctl, Next: msglimits, Prev: msgrcv, Up: Messages
+
+msgctl
+------
+
+ int msgctl (int msqid, int cmd, struct msqid_ds *buf);
+
+ * msqid : id obtained by a call to msgget.
+
+ * buf : allocated by user for reading/writing info.
+
+ * cmd : IPC_STAT, IPC_SET, IPC_RMID (*Note syscalls::).
+
+ IPC_STAT results in the copy of the queue data structure into the
+user supplied buffer.
+
+ In the case of IPC_SET, the queue size (`msg_qbytes') and the `uid',
+`gid', `mode' (low 9 bits) fields of the `msg_perm' struct are set from
+the user supplied values. `msg_ctime' is updated.
+
+ Note that only the super user may increase the limit on the size of a
+message queue beyond MSGMNB.
+
+ When the queue is destroyed (IPC_RMID), the sequence number is
+incremented and all waiting readers and writers are awakened. These
+processes will then return with `errno' set to EIDRM.
+
+Errors:
+
+EPERM : Insufficient privilege to increase the size of the queue
+(IPC_SET) or remove it (IPC_RMID).
+EACCES : Do not have permission for reading the queue (IPC_STAT).
+EFAULT : buf not accessible (IPC_STAT, IPC_SET).
+EIDRM : msg queue was removed.
+EINVAL : invalid cmd, msqid < 0 or unused.
+
+
+File: ipc.info, Node: msglimits, Next: Semaphores, Prev: msgctl, Up: Messages
+
+Limis on Message Resources
+--------------------------
+
+Sizeof various structures:
+ msqid_ds 52 /* 1 per message queue .. dynamic */
+
+ msg 16 /* 1 for each message in system .. dynamic */
+
+ msgbuf 8 /* allocated by user */
+
+Limits
+ * MSGMNI : number of message queue identifiers ... policy.
+
+ * MSGMAX : max size of message. Header and message space allocated
+ on one page. MSGMAX = (PAGE_SIZE - sizeof(struct msg)).
+ Implementation maximum MSGMAX = 4080.
+
+ * MSGMNB : default max size of a message queue ... policy. The
+ super-user can increase the size of a queue beyond MSGMNB by a
+ `msgctl' call.
+
+Unused or unimplemented:
+MSGTQL max number of message headers system-wide.
+MSGPOOL total size in bytes of msg pool.
+
+
+File: ipc.info, Node: Semaphores, Next: semget, Prev: msglimits, Up: top
+
+Semaphores
+==========
+
+ Each semaphore has a value >= 0. An id provides access to an array
+of `nsems' semaphores. Operations such as read, increment or decrement
+semaphores in a set are performed by the `semop' call which processes
+`nsops' operations at a time. Each operation is specified in a struct
+`sembuf' described below. The operations are applied only if all of
+them succeed.
+
+ If you do not have a need for such arrays, you are probably better
+off using the `test_bit', `set_bit' and `clear_bit' bit-operations
+defined in <asm/bitops.h>.
+
+ Semaphore operations may also be qualified by a SEM_UNDO flag which
+results in the operation being undone when the process exits.
+
+ If a decrement cannot go through, a process will be put to sleep on
+a queue waiting for the `semval' to increase unless it specifies
+IPC_NOWAIT. A read operation can similarly result in a sleep on a queue
+waiting for `semval' to become 0. (Actually there are two queues per
+semaphore array).
+
+A semaphore array is described by:
+ struct semid_ds
+ struct ipc_perm sem_perm;
+ time_t sem_otime; /* last semop time */
+ time_t sem_ctime; /* last change time */
+ struct wait_queue *eventn; /* wait for a semval to increase */
+ struct wait_queue *eventz; /* wait for a semval to become 0 */
+ struct sem_undo *undo; /* undo entries */
+ ushort sem_nsems; /* no. of semaphores in array */
+
+Each semaphore is described internally by :
+ struct sem
+ short sempid; /* pid of last semop() */
+ ushort semval; /* current value */
+ ushort semncnt; /* num procs awaiting increase in semval */
+ ushort semzcnt; /* num procs awaiting semval = 0 */
+
+* Menu:
+
+* semget::
+* semop::
+* semctl::
+* semlimits:: Limits imposed by this implementation.
+
+
+File: ipc.info, Node: semget, Next: semop, Prev: Semaphores, Up: Semaphores
+
+semget
+------
+
+A semaphore array is allocated by a semget system call:
+
+ semid = semget (key_t key, int nsems, int semflg);
+
+ * `key' : an integer usually got from `ftok' or IPC_PRIVATE
+
+ * `nsems' :
+ # of semaphores in array (0 <= nsems <= SEMMSL <= SEMMNS)
+
+ 0 => dont care can be used when not creating the resource. If
+ successful you always get access to the entire array anyway.
+
+ * semflg :
+ IPC_CREAT used to create a new resource
+
+ IPC_EXCL used with IPC_CREAT to ensure failure if the
+ resource exists.
+
+ rwxrwxrwx access permissions.
+
+ * returns : semid on success. -1 on failure.
+
+ An array of nsems semaphores is allocated if there is no resource
+corresponding to the given key. The access permissions specified are
+then copied into the `sem_perm' struct for the array along with the
+user-id etc. The user must use the IPC_CREAT flag or key = IPC_PRIVATE
+if a new resource is to be created.
+
+Errors:
+EINVAL : nsems not in above range (allocate).
+nsems greater than number in array (procure).
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.
+EIDRM : (procure) The resource was removed.
+ENOMEM : could not allocate space for semaphore array.
+ENOSPC : No arrays available (SEMMNI), too few semaphores available
+(SEMMNS).
+ENOENT : Resource does not exist and IPC_CREAT not specified.
+EACCES : (procure) do not have permission for specified access.
+
+
+File: ipc.info, Node: semop, Next: semctl, Prev: semget, Up: Semaphores
+
+semop
+-----
+
+Operations on semaphore arrays are performed by calling semop :
+
+ int semop (int semid, struct sembuf *sops, unsigned nsops);
+
+ * semid : id obtained by a call to semget.
+
+ * sops : array of semaphore operations.
+
+ * nsops : number of operations in array (0 < nsops < SEMOPM).
+
+ * returns : semval for last operation. -1 on failure.
+
+Operations are described by a structure sembuf:
+ struct sembuf
+ ushort sem_num; /* semaphore index in array */
+ short sem_op; /* semaphore operation */
+ short sem_flg; /* operation flags */
+
+ The value `sem_op' is to be added (signed) to the current value
+semval of the semaphore with index sem_num (0 .. nsems -1) in the set.
+Flags recognized in sem_flg are IPC_NOWAIT and SEM_UNDO.
+
+Two kinds of operations can result in wait:
+ 1. If sem_op is 0 (read operation) and semval is non-zero, the process
+ sleeps on a queue waiting for semval to become zero or returns with
+ error EAGAIN if (IPC_NOWAIT | sem_flg) is true.
+
+ 2. If (sem_op < 0) and (semval + sem_op < 0), the process either
+ sleeps on a queue waiting for semval to increase or returns with
+ error EAGAIN if (sem_flg & IPC_NOWAIT) is true.
+
+ The array sops is first read in and preliminary checks performed on
+the arguments. The operations are parsed to determine if any of them
+needs write permissions or requests an undo operation.
+
+ The operations are then tried and the process sleeps if any operation
+that does not specify IPC_NOWAIT cannot go through. If a process sleeps
+it repeats these checks on waking up. If any operation that requests
+IPC_NOWAIT, cannot go through at any stage, the call returns with errno
+set to EAGAIN.
+
+ Finally, operations are committed when all go through without an
+intervening sleep. Processes waiting on the zero_queue or
+increment_queue are awakened if any of the semval's becomes zero or is
+incremented respectively.
+
+Errors:
+E2BIG : nsops > SEMOPM.
+EACCES : Do not have permission for requested (read/alter) access.
+EAGAIN : An operation with IPC_NOWAIT specified could not go through.
+EFAULT : The array sops is not accessible.
+EFBIG : An operation had semnum >= nsems.
+EIDRM : The resource was removed.
+EINTR : The process was interrupted on its way to a wait queue.
+EINVAL : nsops is 0, semid < 0 or unused.
+ENOMEM : SEM_UNDO requested. Could not allocate space for undo
+structure.
+ERANGE : sem_op + semval > SEMVMX for some operation.
+
+
+File: ipc.info, Node: semctl, Next: semlimits, Prev: semop, Up: Semaphores
+
+semctl
+------
+
+ int semctl (int semid, int semnum, int cmd, union semun arg);
+
+ * semid : id obtained by a call to semget.
+
+ * cmd :
+ GETPID return pid for the process that executed the last
+ semop.
+
+ GETVAL return semval of semaphore with index semnum.
+
+ GETNCNT return number of processes waiting for semval to
+ increase.
+
+ GETZCNT return number of processes waiting for semval to
+ become 0
+
+ SETVAL set semval = arg.val.
+
+ GETALL read all semval's into arg.array.
+
+ SETALL set all semval's with values given in arg.array.
+
+ * returns : 0 on success or as given above. -1 on failure.
+
+ The first 4 operate on the semaphore with index semnum in the set.
+The last two operate on all semaphores in the set.
+
+ `arg' is a union :
+ union semun
+ int val; value for SETVAL.
+ struct semid_ds *buf; buffer for IPC_STAT and IPC_SET.
+ ushort *array; array for GETALL and SETALL
+
+ * IPC_SET, SETVAL, SETALL : sem_ctime is updated.
+
+ * SETVAL, SETALL : Undo entries are cleared for altered semaphores in
+ all processes. Processes sleeping on the wait queues are awakened
+ if a semval becomes 0 or increases.
+
+ * IPC_SET : sem_perm.uid, sem_perm.gid, sem_perm.mode are updated
+ from user supplied values.
+
+Errors:
+
+EACCES : do not have permission for specified access.
+EFAULT : arg is not accessible.
+EIDRM : The resource was removed.
+EINVAL : semid < 0 or semnum < 0 or semnum >= nsems.
+EPERM : IPC_RMID, IPC_SET ... not creator, owner or super-user.
+ERANGE : arg.array[i].semval > SEMVMX or < 0 for some i.
+
+
+File: ipc.info, Node: semlimits, Next: Shared Memory, Prev: semctl, Up: Semaphores
+
+Limits on Semaphore Resources
+-----------------------------
+
+Sizeof various structures:
+ semid_ds 44 /* 1 per semaphore array .. dynamic */
+ sem 8 /* 1 for each semaphore in system .. dynamic */
+ sembuf 6 /* allocated by user */
+ sem_undo 20 /* 1 for each undo request .. dynamic */
+
+Limits :
+ * SEMVMX 32767 semaphore maximum value (short).
+
+ * SEMMNI number of semaphore identifiers (or arrays) system
+ wide...policy.
+
+ * SEMMSL maximum number of semaphores per id. 1 semid_ds per
+ array, 1 struct sem per semaphore => SEMMSL = (PAGE_SIZE -
+ sizeof(semid_ds)) / sizeof(sem). Implementation maximum SEMMSL =
+ 500.
+
+ * SEMMNS maximum number of semaphores system wide ... policy.
+ Setting SEMMNS >= SEMMSL*SEMMNI makes it irrelevent.
+
+ * SEMOPM Maximum number of operations in one semop
+ call...policy.
+
+Unused or unimplemented:
+SEMAEM adjust on exit max value.
+SEMMNU number of undo structures system-wide.
+SEMUME maximum number of undo entries per process.
+
+
+File: ipc.info, Node: Shared Memory, Next: shmget, Prev: semlimits, Up: top
+
+Shared Memory
+=============
+
+ Shared memory is distinct from the sharing of read-only code pages or
+the sharing of unaltered data pages that is available due to the
+copy-on-write mechanism. The essential difference is that the shared
+pages are dirty (in the case of Shared memory) and can be made to
+appear at a convenient location in the process' address space.
+
+A shared segment is described by :
+ struct shmid_ds
+ struct ipc_perm shm_perm;
+ int shm_segsz; /* size of segment (bytes) */
+ time_t shm_atime; /* last attach time */
+ time_t shm_dtime; /* last detach time */
+ time_t shm_ctime; /* last change time */
+ ulong *shm_pages; /* internal page table */
+ ushort shm_cpid; /* pid, creator */
+ ushort shm_lpid; /* pid, last operation */
+ short shm_nattch; /* no. of current attaches */
+
+ A shmget allocates a shmid_ds and an internal page table. A shmat
+maps the segment into the process' address space with pointers into the
+internal page table and the actual pages are faulted in as needed. The
+memory associated with the segment must be explicitly destroyed by
+calling shmctl with IPC_RMID.
+
+* Menu:
+
+* shmget::
+* shmat::
+* shmdt::
+* shmctl::
+* shmlimits:: Limits imposed by this implementation.
+
+
+File: ipc.info, Node: shmget, Next: shmat, Prev: Shared Memory, Up: Shared Memory
+
+shmget
+------
+
+A shared memory segment is allocated by a shmget system call:
+
+ int shmget(key_t key, int size, int shmflg);
+
+ * key : an integer usually got from `ftok' or IPC_PRIVATE
+
+ * size : size of the segment in bytes (SHMMIN <= size <= SHMMAX).
+
+ * shmflg :
+ IPC_CREAT used to create a new resource
+
+ IPC_EXCL used with IPC_CREAT to ensure failure if the
+ resource exists.
+
+ rwxrwxrwx access permissions.
+
+ * returns : shmid on success. -1 on failure.
+
+ A descriptor for a shared memory segment is allocated if there isn't
+one corresponding to the given key. The access permissions specified are
+then copied into the `shm_perm' struct for the segment along with the
+user-id etc. The user must use the IPC_CREAT flag or key = IPC_PRIVATE
+to allocate a new segment.
+
+ If the segment already exists, the access permissions are verified,
+and a check is made to see that it is not marked for destruction.
+
+ `size' is effectively rounded up to a multiple of PAGE_SIZE as shared
+memory is allocated in pages.
+
+Errors:
+EINVAL : (allocate) Size not in range specified above.
+(procure) Size greater than size of segment.
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.
+EIDRM : (procure) The resource is marked destroyed or was removed.
+ENOSPC : (allocate) All id's are taken (max of SHMMNI id's system-wide).
+Allocating a segment of the requested size would exceed the system wide
+limit on total shared memory (SHMALL).
+ENOENT : (procure) Resource does not exist and IPC_CREAT not specified.
+EACCES : (procure) Do not have permission for specified access.
+ENOMEM : (allocate) Could not allocate memory for shmid_ds or pg_table.
+
+
+File: ipc.info, Node: shmat, Next: shmdt, Prev: shmget, Up: Shared Memory
+
+shmat
+-----
+
+Maps a shared segment into the process' address space.
+
+ char *virt_addr;
+ virt_addr = shmat (int shmid, char *shmaddr, int shmflg);
+
+ * shmid : id got from call to shmget.
+
+ * shmaddr : requested attach address.
+ If shmaddr is 0 the system finds an unmapped region.
+ If a non-zero value is indicated the value must be page
+ aligned or the user must specify the SHM_RND flag.
+
+ * shmflg :
+ SHM_RDONLY : request read-only attach.
+ SHM_RND : attach address is rounded DOWN to a multiple of SHMLBA.
+
+ * returns: virtual address of attached segment. -1 on failure.
+
+ When shmaddr is 0, the attach address is determined by finding an
+unmapped region in the address range 1G to 1.5G, starting at 1.5G and
+coming down from there. The algorithm is very simple so you are
+encouraged to avoid non-specific attaches.
+
+Algorithm:
+ Determine attach address as described above.
+ Check region (shmaddr, shmaddr + size) is not mapped and allocate
+ page tables (undocumented SHM_REMAP flag!).
+ Map the region by setting up pointers into the internal page table.
+ Add a descriptor for the attach to the task struct for the process.
+ `shm_nattch', `shm_lpid', `shm_atime' are updated.
+
+Notes:
+The `brk' value is not altered. The segment is automatically detached
+when the process exits. The same segment may be attached as read-only
+or read-write and more than once in the process' address space. A
+shmat can succeed on a segment marked for destruction. The request for
+a particular type of attach is made using the SHM_RDONLY flag. There is
+no notion of a write-only attach. The requested attach permissions
+must fall within those allowed by `shm_perm.mode'.
+
+Errors:
+EACCES : Do not have permission for requested access.
+EINVAL : shmid < 0 or unused, shmaddr not aligned, attach at brk failed.
+EIDRM : resource was removed.
+ENOMEM : Could not allocate memory for descriptor or page tables.
+
+
+File: ipc.info, Node: shmdt, Next: shmctl, Prev: shmat, Up: Shared Memory
+
+shmdt
+-----
+
+ int shmdt (char *shmaddr);
+
+ * shmaddr : attach address of segment (returned by shmat).
+
+ * returns : 0 on success. -1 on failure.
+
+ An attached segment is detached and `shm_nattch' decremented. The
+occupied region in user space is unmapped. The segment is destroyed if
+it is marked for destruction and `shm_nattch' is 0. `shm_lpid' and
+`shm_dtime' are updated.
+
+Errors:
+EINVAL : No shared memory segment attached at shmaddr.
+
+
+File: ipc.info, Node: shmctl, Next: shmlimits, Prev: shmdt, Up: Shared Memory
+
+shmctl
+------
+
+Destroys allocated segments. Reads/Writes the control structures.
+
+ int shmctl (int shmid, int cmd, struct shmid_ds *buf);
+
+ * shmid : id got from call to shmget.
+
+ * cmd : IPC_STAT, IPC_SET, IPC_RMID (*Note syscalls::).
+ IPC_SET : Used to set the owner uid, gid, and shm_perms.mode
+ field.
+
+ IPC_RMID : The segment is marked destroyed. It is only
+ destroyed on the last detach.
+
+ IPC_STAT : The shmid_ds structure is copied into the user
+ allocated buffer.
+
+ * buf : used to read (IPC_STAT) or write (IPC_SET) information.
+
+ * returns : 0 on success, -1 on failure.
+
+ The user must execute an IPC_RMID shmctl call to free the memory
+allocated by the shared segment. Otherwise all the pages faulted in
+will continue to live in memory or swap.
+
+Errors:
+EACCES : Do not have permission for requested access.
+EFAULT : buf is not accessible.
+EINVAL : shmid < 0 or unused.
+EIDRM : identifier destroyed.
+EPERM : not creator, owner or super-user (IPC_SET, IPC_RMID).
+
+
+File: ipc.info, Node: shmlimits, Next: Notes, Prev: shmctl, Up: Shared Memory
+
+Limits on Shared Memory Resources
+---------------------------------
+
+Limits:
+ * SHMMNI max num of shared segments system wide ... 4096.
+
+ * SHMMAX max shared memory segment size (bytes) ... 4M
+
+ * SHMMIN min shared memory segment size (bytes). 1 byte (though
+ PAGE_SIZE is the effective minimum size).
+
+ * SHMALL max shared mem system wide (in pages) ... policy.
+
+ * SHMLBA segment low boundary address multiple. Must be page
+ aligned. SHMLBA = PAGE_SIZE.
+
+Unused or unimplemented:
+SHMSEG : maximum number of shared segments per process.
+
+
+File: ipc.info, Node: Notes, Next: top, Prev: shmlimits, Up: top
+
+Miscellaneous Notes
+===================
+
+ The system calls are mapped into one -- `sys_ipc'. This should be
+transparent to the user.
+
+Semaphore `undo' requests
+-------------------------
+
+ There is one sem_undo structure associated with a process for each
+semaphore which was altered (with an undo request) by the process.
+`sem_undo' structures are freed only when the process exits.
+
+ One major cause for unhappiness with the undo mechanism is that it
+does not fit in with the notion of having an atomic set of operations
+on an array. The undo requests for an array and each semaphore therein
+may have been accumulated over many `semop' calls. Thus use the undo
+mechanism with private semaphores only.
+
+ Should the process sleep in `exit' or should all undo operations be
+applied with the IPC_NOWAIT flag in effect? Currently those undo
+operations which go through immediately are applied and those that
+require a wait are ignored silently.
+
+Shared memory, `malloc' and the `brk'.
+--------------------------------------
+
+ Note that since this section was written the implementation was
+changed so that non-specific attaches are done in the region 1G - 1.5G.
+However much of the following is still worth thinking about so I left
+it in.
+
+ On many systems, the shared memory is allocated in a special region
+of the address space ... way up somewhere. As mentioned earlier, this
+implementation attaches shared segments at the lowest possible address.
+Thus if you plan to use `malloc', it is wise to malloc a large space
+and then proceed to attach the shared segments. This way malloc sets
+the brk sufficiently above the region it will use.
+
+ Alternatively you can use `sbrk' to adjust the `brk' value as you
+make shared memory attaches. The implementation is not very smart about
+selecting attach addresses. Using the system default addresses will
+result in fragmentation if detaches do not occur in the reverse
+sequence as attaches.
+
+ Taking control of the matter is probably best. The rule applied is
+that attaches are allowed in unmapped regions other than in the text
+space (see <a.out.h>). Also remember that attach addresses and segment
+sizes are multiples of PAGE_SIZE.
+
+ One more trap (I quote Bruno on this). If you use malloc() to get
+space for your shared memory (ie. to fix the `brk'), you must ensure you
+get an unmapped address range. This means you must mallocate more memory
+than you had ever allocated before. Memory returned by malloc(), used,
+then freed by free() and then again returned by malloc is no good.
+Neither is calloced memory.
+
+ Note that a shared memory region remains a shared memory region until
+you unmap it. Attaching a segment at the `brk' and calling malloc after
+that will result in an overlap of what malloc thinks is its space with
+what is really a shared memory region. For example in the case of a
+read-only attach, you will not be able to write to the overlapped
+portion.
+
+Fork, exec and exit
+-------------------
+
+ On a fork, the child inherits attached shared memory segments but
+not the semaphore undo information.
+
+ In the case of an exec, the attached shared segments are detached.
+The sem undo information however remains intact.
+
+ Upon exit, all attached shared memory segments are detached. The
+adjust values in the undo structures are added to the relevant semvals
+if the operations are permitted. Disallowed operations are ignored.
+
+Other Features
+--------------
+
+ These features of the current implementation are likely to be
+modified in the future.
+
+ The SHM_LOCK and SHM_UNLOCK flag are available (super-user) for use
+with the `shmctl' call to prevent swapping of a shared segment. The user
+must fault in any pages that are required to be present after locking
+is enabled.
+
+ The IPC_INFO, MSG_STAT, MSG_INFO, SHM_STAT, SHM_INFO, SEM_STAT,
+SEMINFO `ctl' calls are used by the `ipcs' program to provide
+information on allocated resources. These can be modified as needed or
+moved to a proc file system interface.
+
+ Thanks to Ove Ewerlid, Bruno Haible, Ulrich Pegelow and Linus
+Torvalds for ideas, tutorials, bug reports and fixes, and merriment.
+And more thanks to Bruno.
+
+
+
+Tag Table:
+Node: top349
+Node: Overview1049
+Node: example2881
+Node: perms4383
+Node: syscalls5943
+Node: Messages9392
+Node: msgget11426
+Node: msgsnd12810
+Node: msgrcv13778
+Node: msgctl15477
+Node: msglimits16684
+Node: Semaphores17558
+Node: semget19517
+Node: semop21060
+Node: semctl23624
+Node: semlimits25383
+Node: Shared Memory26523
+Node: shmget28008
+Node: shmat29803
+Node: shmdt31851
+Node: shmctl32383
+Node: shmlimits33514
+Node: Notes34161
+
+End Tag Table
diff --git a/sys-utils/ipc.texi b/sys-utils/ipc.texi
new file mode 100644
index 000000000..cd9127167
--- /dev/null
+++ b/sys-utils/ipc.texi
@@ -0,0 +1,1310 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header (This is for running Texinfo on a region.)
+@setfilename ipc.info
+@settitle Inter Process Communication.
+@setchapternewpage odd
+@comment %**end of header (This is for running Texinfo on a region.)
+
+@ifinfo
+This file documents the System V style inter process communication
+primitives available under linux.
+
+Copyright @copyright{} 1992 krishna balasubramanian
+
+Permission is granted to use this material and the accompanying
+programs within the terms of the GNU GPL.
+@end ifinfo
+
+@titlepage
+@sp 10
+@center @titlefont{System V Inter Process Communication}
+@sp 2
+@center krishna balasubramanian,
+
+@comment The following two commands start the copyright page.
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1992 krishna balasubramanian
+
+Permission is granted to use this material and the accompanying
+programs within the terms of the GNU GPL.
+@end titlepage
+
+
+
+@node top, Overview, Notes, (dir)
+@chapter System V IPC.
+
+These facilities are provided to maintain compatibility with
+programs developed on system V unix systems and others
+that rely on these system V mechanisms to accomplish inter
+process communication (IPC).@refill
+
+The specifics described here are applicable to the Linux implementation.
+Other implementations may do things slightly differently.
+
+@menu
+* Overview:: What is system V ipc? Overall mechanisms.
+* Messages:: System calls for message passing.
+* Semaphores:: System calls for semaphores.
+* Shared Memory:: System calls for shared memory access.
+* Notes:: Miscellaneous notes.
+@end menu
+
+@node Overview, example, top, top
+@section Overview
+
+@noindent System V IPC consists of three mechanisms:
+
+@itemize @bullet
+@item
+Messages : exchange messages with any process or server.
+@item
+Semaphores : allow unrelated processes to synchronize execution.
+@item
+Shared memory : allow unrelated processes to share memory.
+@end itemize
+
+@menu
+* example:: Using shared memory.
+* perms:: Description of access permissions.
+* syscalls:: Overview of ipc system calls.
+@end menu
+
+Access to all resources is permitted on the basis of permissions
+set up when the resource was created.@refill
+
+A resource here consists of message queue, a semaphore set (array)
+or a shared memory segment.@refill
+
+A resource must first be allocated by a creator before it is used.
+The creator can assign a different owner. After use the resource
+must be explicitly destroyed by the creator or owner.@refill
+
+A resource is identified by a numeric @var{id}. Typically a creator
+defines a @var{key} that may be used to access the resource. The user
+process may then use this @var{key} in the @dfn{get} system call to obtain
+the @var{id} for the corresponding resource. This @var{id} is then used for
+all further access. A library call @dfn{ftok} is provided to translate
+pathnames or strings to numeric keys.@refill
+
+There are system and implementation defined limits on the number and
+sizes of resources of any given type. Some of these are imposed by the
+implementation and others by the system administrator
+when configuring the kernel (@xref{msglimits}, @xref{semlimits},
+@xref{shmlimits}).@refill
+
+There is an @code{msqid_ds}, @code{semid_ds} or @code{shmid_ds} struct
+associated with each message queue, semaphore array or shared segment.
+Each ipc resource has an associated @code{ipc_perm} struct which defines
+the creator, owner, access perms ..etc.., for the resource.
+These structures are detailed in the following sections.@refill
+
+
+
+@node example, perms, Overview, Overview
+@section example
+
+Here is a code fragment with pointers on how to use shared memory. The
+same methods are applicable to other resources.@refill
+
+In a typical access sequence the creator allocates a new instance
+of the resource with the @code{get} system call using the IPC_CREAT
+flag.@refill
+
+@noindent creator process:@*
+
+@example
+#include <sys/shm.h>
+int id;
+key_t key;
+char proc_id = 'C';
+int size = 0x5000; /* 20 K */
+int flags = 0664 | IPC_CREAT; /* read-only for others */
+
+key = ftok ("~creator/ipckey", proc_id);
+id = shmget (key, size, flags);
+exit (0); /* quit leaving resource allocated */
+@end example
+
+@noindent
+Users then gain access to the resource using the same key.@*
+@noindent
+Client process:
+@example
+#include <sys/shm.h>
+char *shmaddr;
+int id;
+key_t key;
+char proc_id = 'C';
+
+key = ftok ("~creator/ipckey", proc_id);
+
+id = shmget (key, 0, 004); /* default size */
+if (id == -1)
+ perror ("shmget ...");
+
+shmaddr = shmat (id, 0, SHM_RDONLY); /* attach segment for reading */
+if (shmaddr == (char *) -1)
+ perror ("shmat ...");
+
+local_var = *(shmaddr + 3); /* read segment etc. */
+
+shmdt (shmaddr); /* detach segment */
+@end example
+
+@noindent
+When the resource is no longer needed the creator should remove it.@*
+@noindent
+Creator/owner process 2:
+@example
+key = ftok ("~creator/ipckey", proc_id)
+id = shmget (key, 0, 0);
+shmctl (id, IPC_RMID, NULL);
+@end example
+
+
+@node perms, syscalls, example, Overview
+@section Permissions
+
+Each resource has an associated @code{ipc_perm} struct which defines the
+creator, owner and access perms for the resource.@refill
+
+@example
+struct ipc_perm
+ key_t key; /* set by creator */
+ ushort uid; /* owner euid and egid */
+ ushort gid;
+ ushort cuid; /* creator euid and egid */
+ ushort cgid;
+ ushort mode; /* access modes in lower 9 bits */
+ ushort seq; /* sequence number */
+@end example
+
+The creating process is the default owner. The owner can be reassigned
+by the creator and has creator perms. Only the owner, creator or super-user
+can delete the resource.@refill
+
+The lowest nine bits of the flags parameter supplied by the user to the
+system call are compared with the values stored in @code{ipc_perms.mode}
+to determine if the requested access is allowed. In the case
+that the system call creates the resource, these bits are initialized
+from the user supplied value.@refill
+
+As for files, access permissions are specified as read, write and exec
+for user, group or other (though the exec perms are unused). For example
+0624 grants read-write to owner, write-only to group and read-only
+access to others.@refill
+
+For shared memory, note that read-write access for segments is determined
+by a separate flag which is not stored in the @code{mode} field.
+Shared memory segments attached with write access can be read.@refill
+
+The @code{cuid}, @code{cgid}, @code{key} and @code{seq} fields
+cannot be changed by the user.@refill
+
+
+
+@node syscalls, Messages, perms, Overview
+@section IPC system calls
+
+This section provides an overview of the IPC system calls. See the
+specific sections on each type of resource for details.@refill
+
+Each type of mechanism provides a @dfn{get}, @dfn{ctl} and one or more
+@dfn{op} system calls that allow the user to create or procure the
+resource (get), define its behaviour or destroy it (ctl) and manipulate
+the resources (op).@refill
+
+
+
+@subsection The @dfn{get} system calls
+
+The @code{get} call typically takes a @var{key} and returns a numeric
+@var{id} that is used for further access.
+The @var{id} is an index into the resource table. A sequence
+number is maintained and incremented when a resource is
+destroyed so that acceses using an obselete @var{id} is likely to fail.@refill
+
+The user also specifies the permissions and other behaviour
+charecteristics for the current access. The flags are or-ed with the
+permissions when invoking system calls as in:@refill
+@example
+msgflg = IPC_CREAT | IPC_EXCL | 0666;
+id = msgget (key, msgflg);
+@end example
+@itemize @bullet
+@item
+@code{key} : IPC_PRIVATE => new instance of resource is initialized.
+@item
+@code{flags} :
+@itemize @asis
+@item
+IPC_CREAT : resource created for @var{key} if it does not exist.
+@item
+IPC_CREAT | IPC_EXCL : fail if resource exists for @var{key}.
+@end itemize
+@item
+returns : an identifier used for all further access to the resource.
+@end itemize
+
+Note that IPC_PRIVATE is not a flag but a special @code{key}
+that ensures (when the call is successful) that a new resource is
+created.@refill
+
+Use of IPC_PRIVATE does not make the resource inaccessible to other
+users. For this you must set the access permissions appropriately.@refill
+
+There is currently no way for a process to ensure exclusive access to a
+resource. IPC_CREAT | IPC_EXCL only ensures (on success) that a new
+resource was initialized. It does not imply exclusive access.@refill
+
+@noindent
+See Also : @xref{msgget}, @xref{semget}, @xref{shmget}.@refill
+
+
+
+@subsection The @dfn{ctl} system calls
+
+Provides or alters the information stored in the structure that describes
+the resource indexed by @var{id}.@refill
+
+@example
+#include <sys/msg.h>
+struct msqid_ds buf;
+err = msgctl (id, IPC_STAT, &buf);
+if (err)
+ !$#%*
+else
+ printf ("creator uid = %d\n", buf.msg_perm.cuid);
+ ....
+@end example
+
+@noindent
+Commands supported by all @code{ctl} calls:@*
+@itemize @bullet
+@item
+IPC_STAT : read info on resource specified by id into user allocated
+buffer. The user must have read access to the resource.@refill
+@item
+IPC_SET : write info from buffer into resource data structure. The
+user must be owner creator or super-user.@refill
+@item
+IPC_RMID : remove resource. The user must be the owner, creator or
+super-user.@refill
+@end itemize
+
+The IPC_RMID command results in immediate removal of a message
+queue or semaphore array. Shared memory segments however, are
+only destroyed upon the last detach after IPC_RMID is executed.@refill
+
+The @code{semctl} call provides a number of command options that allow
+the user to determine or set the values of the semaphores in an array.@refill
+
+@noindent
+See Also: @xref{msgctl}, @xref{semctl}, @xref{shmctl}.@refill
+
+
+@subsection The @dfn{op} system calls
+
+Used to send or receive messages, read or alter semaphore values,
+attach or detach shared memory segments.
+The IPC_NOWAIT flag will cause the operation to fail with error EAGAIN
+if the process has to wait on the call.@refill
+
+@noindent
+@code{flags} : IPC_NOWAIT => return with error if a wait is required.
+
+@noindent
+See Also: @xref{msgsnd},@xref{msgrcv},@xref{semop},@xref{shmat},
+@xref{shmdt}.@refill
+
+
+
+@node Messages, msgget, syscalls, top
+@section Messages
+
+A message resource is described by a struct @code{msqid_ds} which is
+allocated and initialized when the resource is created. Some fields
+in @code{msqid_ds} can then be altered (if desired) by invoking @code{msgctl}.
+The memory used by the resource is released when it is destroyed by
+a @code{msgctl} call.@refill
+
+@example
+struct msqid_ds
+ struct ipc_perm msg_perm;
+ struct msg *msg_first; /* first message on queue (internal) */
+ struct msg *msg_last; /* last message in queue (internal) */
+ time_t msg_stime; /* last msgsnd time */
+ time_t msg_rtime; /* last msgrcv time */
+ time_t msg_ctime; /* last change time */
+ struct wait_queue *wwait; /* writers waiting (internal) */
+ struct wait_queue *rwait; /* readers waiting (internal) */
+ ushort msg_cbytes; /* number of bytes used on queue */
+ ushort msg_qnum; /* number of messages in queue */
+ ushort msg_qbytes; /* max number of bytes on queue */
+ ushort msg_lspid; /* pid of last msgsnd */
+ ushort msg_lrpid; /* pid of last msgrcv */
+@end example
+
+To send or receive a message the user allocates a structure that looks
+like a @code{msgbuf} but with an array @code{mtext} of the required size.
+Messages have a type (positive integer) associated with them so that
+(for example) a listener can choose to receive only messages of a
+given type.@refill
+
+@example
+struct msgbuf
+ long mtype; type of message (@xref{msgrcv}).
+ char mtext[1]; message text .. why is this not a ptr?
+@end example
+
+The user must have write permissions to send and read permissions
+to receive messages on a queue.@refill
+
+When @code{msgsnd} is invoked, the user's message is copied into
+an internal struct @code{msg} and added to the queue. A @code{msgrcv}
+will then read this message and free the associated struct @code{msg}.@refill
+
+
+@menu
+* msgget::
+* msgsnd::
+* msgrcv::
+* msgctl::
+* msglimits:: Implementation defined limits.
+@end menu
+
+
+@node msgget, msgsnd, Messages, Messages
+@subsection msgget
+
+@noindent
+A message queue is allocated by a msgget system call :
+
+@example
+msqid = msgget (key_t key, int msgflg);
+@end example
+
+@itemize @bullet
+@item
+@code{key}: an integer usually got from @code{ftok()} or IPC_PRIVATE.@refill
+@item
+@code{msgflg}:
+@itemize @asis
+@item
+IPC_CREAT : used to create a new resource if it does not already exist.
+@item
+IPC_EXCL | IPC_CREAT : used to ensure failure of the call if the
+resource already exists.@refill
+@item
+rwxrwxrwx : access permissions.
+@end itemize
+@item
+returns: msqid (an integer used for all further access) on success.
+-1 on failure.@refill
+@end itemize
+
+A message queue is allocated if there is no resource corresponding
+to the given key. The access permissions specified are then copied
+into the @code{msg_perm} struct and the fields in @code{msqid_ds}
+initialized. The user must use the IPC_CREAT flag or key = IPC_PRIVATE,
+if a new instance is to be allocated. If a resource corresponding to
+@var{key} already exists, the access permissions are verified.@refill
+
+@noindent
+Errors:@*
+@noindent
+EACCES : (procure) Do not have permission for requested access.@*
+@noindent
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.@*
+@noindent
+EIDRM : (procure) The resource was removed.@*
+@noindent
+ENOSPC : All id's are taken (max of MSGMNI id's system-wide).@*
+@noindent
+ENOENT : Resource does not exist and IPC_CREAT not specified.@*
+@noindent
+ENOMEM : A new @code{msqid_ds} was to be created but ... nomem.
+
+
+
+
+@node msgsnd, msgrcv, msgget, Messages
+@subsection msgsnd
+
+@example
+int msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
+@end example
+
+@itemize @bullet
+@item
+@code{msqid} : id obtained by a call to msgget.
+@item
+@code{msgsz} : size of msg text (@code{mtext}) in bytes.
+@item
+@code{msgp} : message to be sent. (msgp->mtype must be positive).
+@item
+@code{msgflg} : IPC_NOWAIT.
+@item
+returns : msgsz on success. -1 on error.
+@end itemize
+
+The message text and type are stored in the internal @code{msg}
+structure. @code{msg_cbytes}, @code{msg_qnum}, @code{msg_lspid},
+and @code{msg_stime} fields are updated. Readers waiting on the
+queue are awakened.@refill
+
+@noindent
+Errors:@*
+@noindent
+EACCES : Do not have write permission on queue.@*
+@noindent
+EAGAIN : IPC_NOWAIT specified and queue is full.@*
+@noindent
+EFAULT : msgp not accessible.@*
+@noindent
+EIDRM : The message queue was removed.@*
+@noindent
+EINTR : Full queue ... would have slept but ... was interrupted.@*
+@noindent
+EINVAL : mtype < 1, msgsz > MSGMAX, msgsz < 0, msqid < 0 or unused.@*
+@noindent
+ENOMEM : Could not allocate space for header and text.@*
+
+
+
+@node msgrcv, msgctl, msgsnd, Messages
+@subsection msgrcv
+
+@example
+int msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
+ int msgflg);
+@end example
+
+@itemize @bullet
+@item
+msqid : id obtained by a call to msgget.
+@item
+msgsz : maximum size of message to receive.
+@item
+msgp : allocated by user to store the message in.
+@item
+msgtyp :
+@itemize @asis
+@item
+0 => get first message on queue.
+@item
+> 0 => get first message of matching type.
+@item
+< 0 => get message with least type which is <= abs(msgtyp).
+@end itemize
+@item
+msgflg :
+@itemize @asis
+@item
+IPC_NOWAIT : Return immediately if message not found.
+@item
+MSG_NOERROR : The message is truncated if it is larger than msgsz.
+@item
+MSG_EXCEPT : Used with msgtyp > 0 to receive any msg except of specified
+type.@refill
+@end itemize
+@item
+returns : size of message if found. -1 on error.
+@end itemize
+
+The first message that meets the @code{msgtyp} specification is
+identified. For msgtyp < 0, the entire queue is searched for the
+message with the smallest type.@refill
+
+If its length is smaller than msgsz or if the user specified the
+MSG_NOERROR flag, its text and type are copied to msgp->mtext and
+msgp->mtype, and it is taken off the queue.@refill
+
+The @code{msg_cbytes}, @code{msg_qnum}, @code{msg_lrpid},
+and @code{msg_rtime} fields are updated. Writers waiting on the
+queue are awakened.@refill
+
+@noindent
+Errors:@*
+@noindent
+E2BIG : msg bigger than msgsz and MSG_NOERROR not specified.@*
+@noindent
+EACCES : Do not have permission for reading the queue.@*
+@noindent
+EFAULT : msgp not accessible.@*
+@noindent
+EIDRM : msg queue was removed.@*
+@noindent
+EINTR : msg not found ... would have slept but ... was interrupted.@*
+@noindent
+EINVAL : msgsz > msgmax or msgsz < 0, msqid < 0 or unused.@*
+@noindent
+ENOMSG : msg of requested type not found and IPC_NOWAIT specified.
+
+
+
+@node msgctl, msglimits, msgrcv, Messages
+@subsection msgctl
+
+@example
+int msgctl (int msqid, int cmd, struct msqid_ds *buf);
+@end example
+
+@itemize @bullet
+@item
+msqid : id obtained by a call to msgget.
+@item
+buf : allocated by user for reading/writing info.
+@item
+cmd : IPC_STAT, IPC_SET, IPC_RMID (@xref{syscalls}).
+@end itemize
+
+IPC_STAT results in the copy of the queue data structure
+into the user supplied buffer.@refill
+
+In the case of IPC_SET, the queue size (@code{msg_qbytes})
+and the @code{uid}, @code{gid}, @code{mode} (low 9 bits) fields
+of the @code{msg_perm} struct are set from the user supplied values.
+@code{msg_ctime} is updated.@refill
+
+Note that only the super user may increase the limit on the size of a
+message queue beyond MSGMNB.@refill
+
+When the queue is destroyed (IPC_RMID), the sequence number is
+incremented and all waiting readers and writers are awakened.
+These processes will then return with @code{errno} set to EIDRM.@refill
+
+@noindent
+Errors:
+@noindent
+EPERM : Insufficient privilege to increase the size of the queue (IPC_SET)
+or remove it (IPC_RMID).@*
+@noindent
+EACCES : Do not have permission for reading the queue (IPC_STAT).@*
+@noindent
+EFAULT : buf not accessible (IPC_STAT, IPC_SET).@*
+@noindent
+EIDRM : msg queue was removed.@*
+@noindent
+EINVAL : invalid cmd, msqid < 0 or unused.
+
+
+@node msglimits, Semaphores, msgctl, Messages
+@subsection Limis on Message Resources
+
+@noindent
+Sizeof various structures:
+@itemize @asis
+@item
+msqid_ds 52 /* 1 per message queue .. dynamic */
+@item
+msg 16 /* 1 for each message in system .. dynamic */
+@item
+msgbuf 8 /* allocated by user */
+@end itemize
+
+@noindent
+Limits
+@itemize @bullet
+@item
+MSGMNI : number of message queue identifiers ... policy.
+@item
+MSGMAX : max size of message.
+Header and message space allocated on one page.
+MSGMAX = (PAGE_SIZE - sizeof(struct msg)).
+Implementation maximum MSGMAX = 4080.@refill
+@item
+MSGMNB : default max size of a message queue ... policy.
+The super-user can increase the size of a
+queue beyond MSGMNB by a @code{msgctl} call.@refill
+@end itemize
+
+@noindent
+Unused or unimplemented:@*
+MSGTQL max number of message headers system-wide.@*
+MSGPOOL total size in bytes of msg pool.
+
+
+
+@node Semaphores, semget, msglimits, top
+@section Semaphores
+
+Each semaphore has a value >= 0. An id provides access to an array
+of @code{nsems} semaphores. Operations such as read, increment or decrement
+semaphores in a set are performed by the @code{semop} call which processes
+@code{nsops} operations at a time. Each operation is specified in a struct
+@code{sembuf} described below. The operations are applied only if all of
+them succeed.@refill
+
+If you do not have a need for such arrays, you are probably better off using
+the @code{test_bit}, @code{set_bit} and @code{clear_bit} bit-operations
+defined in <asm/bitops.h>.@refill
+
+Semaphore operations may also be qualified by a SEM_UNDO flag which
+results in the operation being undone when the process exits.@refill
+
+If a decrement cannot go through, a process will be put to sleep
+on a queue waiting for the @code{semval} to increase unless it specifies
+IPC_NOWAIT. A read operation can similarly result in a sleep on a
+queue waiting for @code{semval} to become 0. (Actually there are
+two queues per semaphore array).@refill
+
+@noindent
+A semaphore array is described by:
+@example
+struct semid_ds
+ struct ipc_perm sem_perm;
+ time_t sem_otime; /* last semop time */
+ time_t sem_ctime; /* last change time */
+ struct wait_queue *eventn; /* wait for a semval to increase */
+ struct wait_queue *eventz; /* wait for a semval to become 0 */
+ struct sem_undo *undo; /* undo entries */
+ ushort sem_nsems; /* no. of semaphores in array */
+@end example
+
+@noindent
+Each semaphore is described internally by :
+@example
+struct sem
+ short sempid; /* pid of last semop() */
+ ushort semval; /* current value */
+ ushort semncnt; /* num procs awaiting increase in semval */
+ ushort semzcnt; /* num procs awaiting semval = 0 */
+@end example
+
+@menu
+* semget::
+* semop::
+* semctl::
+* semlimits:: Limits imposed by this implementation.
+@end menu
+
+@node semget, semop, Semaphores, Semaphores
+@subsection semget
+
+@noindent
+A semaphore array is allocated by a semget system call:
+
+@example
+semid = semget (key_t key, int nsems, int semflg);
+@end example
+
+@itemize @bullet
+@item
+@code{key} : an integer usually got from @code{ftok} or IPC_PRIVATE
+@item
+@code{nsems} :
+@itemize @asis
+@item
+# of semaphores in array (0 <= nsems <= SEMMSL <= SEMMNS)
+@item
+0 => dont care can be used when not creating the resource.
+If successful you always get access to the entire array anyway.@refill
+@end itemize
+@item
+semflg :
+@itemize @asis
+@item
+IPC_CREAT used to create a new resource
+@item
+IPC_EXCL used with IPC_CREAT to ensure failure if the resource exists.
+@item
+rwxrwxrwx access permissions.
+@end itemize
+@item
+returns : semid on success. -1 on failure.
+@end itemize
+
+An array of nsems semaphores is allocated if there is no resource
+corresponding to the given key. The access permissions specified are
+then copied into the @code{sem_perm} struct for the array along with the
+user-id etc. The user must use the IPC_CREAT flag or key = IPC_PRIVATE
+if a new resource is to be created.@refill
+
+@noindent
+Errors:@*
+@noindent
+EINVAL : nsems not in above range (allocate).@*
+ nsems greater than number in array (procure).@*
+@noindent
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.@*
+@noindent
+EIDRM : (procure) The resource was removed.@*
+@noindent
+ENOMEM : could not allocate space for semaphore array.@*
+@noindent
+ENOSPC : No arrays available (SEMMNI), too few semaphores available (SEMMNS).@*
+@noindent
+ENOENT : Resource does not exist and IPC_CREAT not specified.@*
+@noindent
+EACCES : (procure) do not have permission for specified access.
+
+
+@node semop, semctl, semget, Semaphores
+@subsection semop
+
+@noindent
+Operations on semaphore arrays are performed by calling semop :
+
+@example
+int semop (int semid, struct sembuf *sops, unsigned nsops);
+@end example
+@itemize @bullet
+@item
+semid : id obtained by a call to semget.
+@item
+sops : array of semaphore operations.
+@item
+nsops : number of operations in array (0 < nsops < SEMOPM).
+@item
+returns : semval for last operation. -1 on failure.
+@end itemize
+
+@noindent
+Operations are described by a structure sembuf:
+@example
+struct sembuf
+ ushort sem_num; /* semaphore index in array */
+ short sem_op; /* semaphore operation */
+ short sem_flg; /* operation flags */
+@end example
+
+The value @code{sem_op} is to be added (signed) to the current value semval
+of the semaphore with index sem_num (0 .. nsems -1) in the set.
+Flags recognized in sem_flg are IPC_NOWAIT and SEM_UNDO.@refill
+
+@noindent
+Two kinds of operations can result in wait:
+@enumerate
+@item
+If sem_op is 0 (read operation) and semval is non-zero, the process
+sleeps on a queue waiting for semval to become zero or returns with
+error EAGAIN if (IPC_NOWAIT | sem_flg) is true.@refill
+@item
+If (sem_op < 0) and (semval + sem_op < 0), the process either sleeps
+on a queue waiting for semval to increase or returns with error EAGAIN if
+(sem_flg & IPC_NOWAIT) is true.@refill
+@end enumerate
+
+The array sops is first read in and preliminary checks performed on
+the arguments. The operations are parsed to determine if any of
+them needs write permissions or requests an undo operation.@refill
+
+The operations are then tried and the process sleeps if any operation
+that does not specify IPC_NOWAIT cannot go through. If a process sleeps
+it repeats these checks on waking up. If any operation that requests
+IPC_NOWAIT, cannot go through at any stage, the call returns with errno
+set to EAGAIN.@refill
+
+Finally, operations are committed when all go through without an intervening
+sleep. Processes waiting on the zero_queue or increment_queue are awakened
+if any of the semval's becomes zero or is incremented respectively.@refill
+
+@noindent
+Errors:@*
+@noindent
+E2BIG : nsops > SEMOPM.@*
+@noindent
+EACCES : Do not have permission for requested (read/alter) access.@*
+@noindent
+EAGAIN : An operation with IPC_NOWAIT specified could not go through.@*
+@noindent
+EFAULT : The array sops is not accessible.@*
+@noindent
+EFBIG : An operation had semnum >= nsems.@*
+@noindent
+EIDRM : The resource was removed.@*
+@noindent
+EINTR : The process was interrupted on its way to a wait queue.@*
+@noindent
+EINVAL : nsops is 0, semid < 0 or unused.@*
+@noindent
+ENOMEM : SEM_UNDO requested. Could not allocate space for undo structure.@*
+@noindent
+ERANGE : sem_op + semval > SEMVMX for some operation.
+
+
+@node semctl, semlimits, semop, Semaphores
+@subsection semctl
+
+@example
+int semctl (int semid, int semnum, int cmd, union semun arg);
+@end example
+
+@itemize @bullet
+@item
+semid : id obtained by a call to semget.
+@item
+cmd :
+@itemize @asis
+@item
+GETPID return pid for the process that executed the last semop.
+@item
+GETVAL return semval of semaphore with index semnum.
+@item
+GETNCNT return number of processes waiting for semval to increase.
+@item
+GETZCNT return number of processes waiting for semval to become 0
+@item
+SETVAL set semval = arg.val.
+@item
+GETALL read all semval's into arg.array.
+@item
+SETALL set all semval's with values given in arg.array.
+@end itemize
+@item
+returns : 0 on success or as given above. -1 on failure.
+@end itemize
+
+The first 4 operate on the semaphore with index semnum in the set.
+The last two operate on all semaphores in the set.@refill
+
+@code{arg} is a union :
+@example
+union semun
+ int val; value for SETVAL.
+ struct semid_ds *buf; buffer for IPC_STAT and IPC_SET.
+ ushort *array; array for GETALL and SETALL
+@end example
+
+@itemize @bullet
+@item
+IPC_SET, SETVAL, SETALL : sem_ctime is updated.
+@item
+SETVAL, SETALL : Undo entries are cleared for altered semaphores in
+all processes. Processes sleeping on the wait queues are
+awakened if a semval becomes 0 or increases.@refill
+@item
+IPC_SET : sem_perm.uid, sem_perm.gid, sem_perm.mode are updated from
+user supplied values.@refill
+@end itemize
+
+@noindent
+Errors:
+@noindent
+EACCES : do not have permission for specified access.@*
+@noindent
+EFAULT : arg is not accessible.@*
+@noindent
+EIDRM : The resource was removed.@*
+@noindent
+EINVAL : semid < 0 or semnum < 0 or semnum >= nsems.@*
+@noindent
+EPERM : IPC_RMID, IPC_SET ... not creator, owner or super-user.@*
+@noindent
+ERANGE : arg.array[i].semval > SEMVMX or < 0 for some i.
+
+
+
+
+@node semlimits, Shared Memory, semctl, Semaphores
+@subsection Limits on Semaphore Resources
+
+@noindent
+Sizeof various structures:
+@example
+semid_ds 44 /* 1 per semaphore array .. dynamic */
+sem 8 /* 1 for each semaphore in system .. dynamic */
+sembuf 6 /* allocated by user */
+sem_undo 20 /* 1 for each undo request .. dynamic */
+@end example
+
+@noindent
+Limits :@*
+@itemize @bullet
+@item
+SEMVMX 32767 semaphore maximum value (short).
+@item
+SEMMNI number of semaphore identifiers (or arrays) system wide...policy.
+@item
+SEMMSL maximum number of semaphores per id.
+1 semid_ds per array, 1 struct sem per semaphore
+=> SEMMSL = (PAGE_SIZE - sizeof(semid_ds)) / sizeof(sem).
+Implementation maximum SEMMSL = 500.@refill
+@item
+SEMMNS maximum number of semaphores system wide ... policy.
+Setting SEMMNS >= SEMMSL*SEMMNI makes it irrelevent.@refill
+@item
+SEMOPM Maximum number of operations in one semop call...policy.
+@end itemize
+
+@noindent
+Unused or unimplemented:@*
+@noindent
+SEMAEM adjust on exit max value.@*
+@noindent
+SEMMNU number of undo structures system-wide.@*
+@noindent
+SEMUME maximum number of undo entries per process.
+
+
+
+@node Shared Memory, shmget, semlimits, top
+@section Shared Memory
+
+Shared memory is distinct from the sharing of read-only code pages or
+the sharing of unaltered data pages that is available due to the
+copy-on-write mechanism. The essential difference is that the
+shared pages are dirty (in the case of Shared memory) and can be
+made to appear at a convenient location in the process' address space.@refill
+
+@noindent
+A shared segment is described by :
+@example
+struct shmid_ds
+ struct ipc_perm shm_perm;
+ int shm_segsz; /* size of segment (bytes) */
+ time_t shm_atime; /* last attach time */
+ time_t shm_dtime; /* last detach time */
+ time_t shm_ctime; /* last change time */
+ ulong *shm_pages; /* internal page table */
+ ushort shm_cpid; /* pid, creator */
+ ushort shm_lpid; /* pid, last operation */
+ short shm_nattch; /* no. of current attaches */
+@end example
+
+A shmget allocates a shmid_ds and an internal page table. A shmat
+maps the segment into the process' address space with pointers
+into the internal page table and the actual pages are faulted in
+as needed. The memory associated with the segment must be explicitly
+destroyed by calling shmctl with IPC_RMID.@refill
+
+@menu
+* shmget::
+* shmat::
+* shmdt::
+* shmctl::
+* shmlimits:: Limits imposed by this implementation.
+@end menu
+
+
+@node shmget, shmat, Shared Memory, Shared Memory
+@subsection shmget
+
+@noindent
+A shared memory segment is allocated by a shmget system call:
+
+@example
+int shmget(key_t key, int size, int shmflg);
+@end example
+
+@itemize @bullet
+@item
+key : an integer usually got from @code{ftok} or IPC_PRIVATE
+@item
+size : size of the segment in bytes (SHMMIN <= size <= SHMMAX).
+@item
+shmflg :
+@itemize @asis
+@item
+IPC_CREAT used to create a new resource
+@item
+IPC_EXCL used with IPC_CREAT to ensure failure if the resource exists.
+@item
+rwxrwxrwx access permissions.
+@end itemize
+@item
+returns : shmid on success. -1 on failure.
+@end itemize
+
+A descriptor for a shared memory segment is allocated if there isn't one
+corresponding to the given key. The access permissions specified are
+then copied into the @code{shm_perm} struct for the segment along with the
+user-id etc. The user must use the IPC_CREAT flag or key = IPC_PRIVATE
+to allocate a new segment.@refill
+
+If the segment already exists, the access permissions are verified,
+and a check is made to see that it is not marked for destruction.@refill
+
+@code{size} is effectively rounded up to a multiple of PAGE_SIZE as shared
+memory is allocated in pages.@refill
+
+@noindent
+Errors:@*
+@noindent
+EINVAL : (allocate) Size not in range specified above.@*
+ (procure) Size greater than size of segment.@*
+@noindent
+EEXIST : (allocate) IPC_CREAT | IPC_EXCL specified and resource exists.@*
+@noindent
+EIDRM : (procure) The resource is marked destroyed or was removed.@*
+@noindent
+ENOSPC : (allocate) All id's are taken (max of SHMMNI id's system-wide).
+Allocating a segment of the requested size would exceed the
+system wide limit on total shared memory (SHMALL).@refill
+@*
+@noindent
+ENOENT : (procure) Resource does not exist and IPC_CREAT not specified.@*
+@noindent
+EACCES : (procure) Do not have permission for specified access.@*
+@noindent
+ENOMEM : (allocate) Could not allocate memory for shmid_ds or pg_table.
+
+
+
+@node shmat, shmdt, shmget, Shared Memory
+@subsection shmat
+
+@noindent
+Maps a shared segment into the process' address space.
+
+@example
+char *virt_addr;
+virt_addr = shmat (int shmid, char *shmaddr, int shmflg);
+@end example
+
+@itemize @bullet
+@item
+shmid : id got from call to shmget.
+@item
+shmaddr : requested attach address.@*
+ If shmaddr is 0 the system finds an unmapped region.@*
+ If a non-zero value is indicated the value must be page
+ aligned or the user must specify the SHM_RND flag.@refill
+@item
+shmflg :@*
+ SHM_RDONLY : request read-only attach.@*
+ SHM_RND : attach address is rounded DOWN to a multiple of SHMLBA.
+@item
+returns: virtual address of attached segment. -1 on failure.
+@end itemize
+
+When shmaddr is 0, the attach address is determined by finding an
+unmapped region in the address range 1G to 1.5G, starting at 1.5G
+and coming down from there. The algorithm is very simple so you
+are encouraged to avoid non-specific attaches.
+
+@noindent
+Algorithm:
+@display
+Determine attach address as described above.
+Check region (shmaddr, shmaddr + size) is not mapped and allocate
+ page tables (undocumented SHM_REMAP flag!).
+Map the region by setting up pointers into the internal page table.
+Add a descriptor for the attach to the task struct for the process.
+@code{shm_nattch}, @code{shm_lpid}, @code{shm_atime} are updated.
+@end display
+
+@noindent
+Notes:@*
+The @code{brk} value is not altered.
+The segment is automatically detached when the process exits.
+The same segment may be attached as read-only or read-write and
+ more than once in the process' address space.
+A shmat can succeed on a segment marked for destruction.
+The request for a particular type of attach is made using the SHM_RDONLY flag.
+There is no notion of a write-only attach. The requested attach
+ permissions must fall within those allowed by @code{shm_perm.mode}.
+
+@noindent
+Errors:@*
+@noindent
+EACCES : Do not have permission for requested access.@*
+@noindent
+EINVAL : shmid < 0 or unused, shmaddr not aligned, attach at brk failed.@*
+@noindent
+EIDRM : resource was removed.@*
+@noindent
+ENOMEM : Could not allocate memory for descriptor or page tables.
+
+
+@node shmdt, shmctl, shmat, Shared Memory
+@subsection shmdt
+
+@example
+int shmdt (char *shmaddr);
+@end example
+
+@itemize @bullet
+@item
+shmaddr : attach address of segment (returned by shmat).
+@item
+returns : 0 on success. -1 on failure.
+@end itemize
+
+An attached segment is detached and @code{shm_nattch} decremented. The
+occupied region in user space is unmapped. The segment is destroyed
+if it is marked for destruction and @code{shm_nattch} is 0.
+@code{shm_lpid} and @code{shm_dtime} are updated.@refill
+
+@noindent
+Errors:@*
+@noindent
+EINVAL : No shared memory segment attached at shmaddr.
+
+
+@node shmctl, shmlimits, shmdt, Shared Memory
+@subsection shmctl
+
+@noindent
+Destroys allocated segments. Reads/Writes the control structures.
+
+@example
+int shmctl (int shmid, int cmd, struct shmid_ds *buf);
+@end example
+
+@itemize @bullet
+@item
+shmid : id got from call to shmget.
+@item
+cmd : IPC_STAT, IPC_SET, IPC_RMID (@xref{syscalls}).
+@itemize @asis
+@item
+IPC_SET : Used to set the owner uid, gid, and shm_perms.mode field.
+@item
+IPC_RMID : The segment is marked destroyed. It is only destroyed
+on the last detach.@refill
+@item
+IPC_STAT : The shmid_ds structure is copied into the user allocated buffer.
+@end itemize
+@item
+buf : used to read (IPC_STAT) or write (IPC_SET) information.
+@item
+returns : 0 on success, -1 on failure.
+@end itemize
+
+The user must execute an IPC_RMID shmctl call to free the memory
+allocated by the shared segment. Otherwise all the pages faulted in
+will continue to live in memory or swap.@refill
+
+@noindent
+Errors:@*
+@noindent
+EACCES : Do not have permission for requested access.@*
+@noindent
+EFAULT : buf is not accessible.@*
+@noindent
+EINVAL : shmid < 0 or unused.@*
+@noindent
+EIDRM : identifier destroyed.@*
+@noindent
+EPERM : not creator, owner or super-user (IPC_SET, IPC_RMID).
+
+
+@node shmlimits, Notes, shmctl, Shared Memory
+@subsection Limits on Shared Memory Resources
+
+@noindent
+Limits:
+@itemize @bullet
+@item
+SHMMNI max num of shared segments system wide ... 4096.
+@item
+SHMMAX max shared memory segment size (bytes) ... 4M
+@item
+SHMMIN min shared memory segment size (bytes).
+1 byte (though PAGE_SIZE is the effective minimum size).@refill
+@item
+SHMALL max shared mem system wide (in pages) ... policy.
+@item
+SHMLBA segment low boundary address multiple.
+Must be page aligned. SHMLBA = PAGE_SIZE.@refill
+@end itemize
+@noindent
+Unused or unimplemented:@*
+SHMSEG : maximum number of shared segments per process.
+
+
+
+@node Notes, top, shmlimits, top
+@section Miscellaneous Notes
+
+The system calls are mapped into one -- @code{sys_ipc}. This should be
+transparent to the user.@refill
+
+@subsection Semaphore @code{undo} requests
+
+There is one sem_undo structure associated with a process for
+each semaphore which was altered (with an undo request) by the process.
+@code{sem_undo} structures are freed only when the process exits.
+
+One major cause for unhappiness with the undo mechanism is that
+it does not fit in with the notion of having an atomic set of
+operations on an array. The undo requests for an array and each
+semaphore therein may have been accumulated over many @code{semop}
+calls. Thus use the undo mechanism with private semaphores only.@refill
+
+Should the process sleep in @code{exit} or should all undo
+operations be applied with the IPC_NOWAIT flag in effect?
+Currently those undo operations which go through immediately are
+applied and those that require a wait are ignored silently.@refill
+
+@subsection Shared memory, @code{malloc} and the @code{brk}.
+Note that since this section was written the implementation was
+changed so that non-specific attaches are done in the region
+1G - 1.5G. However much of the following is still worth thinking
+about so I left it in.
+
+On many systems, the shared memory is allocated in a special region
+of the address space ... way up somewhere. As mentioned earlier,
+this implementation attaches shared segments at the lowest possible
+address. Thus if you plan to use @code{malloc}, it is wise to malloc a
+large space and then proceed to attach the shared segments. This way
+malloc sets the brk sufficiently above the region it will use.@refill
+
+Alternatively you can use @code{sbrk} to adjust the @code{brk} value
+as you make shared memory attaches. The implementation is not very
+smart about selecting attach addresses. Using the system default
+addresses will result in fragmentation if detaches do not occur
+in the reverse sequence as attaches.@refill
+
+Taking control of the matter is probably best. The rule applied
+is that attaches are allowed in unmapped regions other than
+in the text space (see <a.out.h>). Also remember that attach addresses
+and segment sizes are multiples of PAGE_SIZE.@refill
+
+One more trap (I quote Bruno on this). If you use malloc() to get space
+for your shared memory (ie. to fix the @code{brk}), you must ensure you
+get an unmapped address range. This means you must mallocate more memory
+than you had ever allocated before. Memory returned by malloc(), used,
+then freed by free() and then again returned by malloc is no good.
+Neither is calloced memory.@refill
+
+Note that a shared memory region remains a shared memory region until
+you unmap it. Attaching a segment at the @code{brk} and calling malloc
+after that will result in an overlap of what malloc thinks is its
+space with what is really a shared memory region. For example in the case
+of a read-only attach, you will not be able to write to the overlapped
+portion.@refill
+
+
+@subsection Fork, exec and exit
+
+On a fork, the child inherits attached shared memory segments but
+not the semaphore undo information.@refill
+
+In the case of an exec, the attached shared segments are detached.
+The sem undo information however remains intact.@refill
+
+Upon exit, all attached shared memory segments are detached.
+The adjust values in the undo structures are added to the relevant semvals
+if the operations are permitted. Disallowed operations are ignored.@refill
+
+
+@subsection Other Features
+
+These features of the current implementation are
+likely to be modified in the future.
+
+The SHM_LOCK and SHM_UNLOCK flag are available (super-user) for use with the
+@code{shmctl} call to prevent swapping of a shared segment. The user
+must fault in any pages that are required to be present after locking
+is enabled.
+
+The IPC_INFO, MSG_STAT, MSG_INFO, SHM_STAT, SHM_INFO, SEM_STAT, SEMINFO
+@code{ctl} calls are used by the @code{ipcs} program to provide information
+on allocated resources. These can be modified as needed or moved to a proc
+file system interface.
+
+
+@sp 3
+Thanks to Ove Ewerlid, Bruno Haible, Ulrich Pegelow and Linus Torvalds
+for ideas, tutorials, bug reports and fixes, and merriment. And more
+thanks to Bruno.
+
+
+@contents
+@bye
+
diff --git a/sys-utils/ipcrm.8 b/sys-utils/ipcrm.8
new file mode 100644
index 000000000..ef2facb92
--- /dev/null
+++ b/sys-utils/ipcrm.8
@@ -0,0 +1,15 @@
+.\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH IPCRM 8 "9 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+ipcs \- provide information on ipc facilities
+.SH SYNOPSIS
+.BI "ipcrm [ shm | msg | sem ] " id
+.SH DESCRIPTION
+.B ipcrm
+will remove the resource speccified by
+.IR id .
+.SH SEE ALSO
+.BR ipcs (8)
+.SH AUTHOR
+krishna balasubramanian (balasub@cis.ohio-state.edu)
diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c
new file mode 100644
index 000000000..7273b341a
--- /dev/null
+++ b/sys-utils/ipcrm.c
@@ -0,0 +1,50 @@
+/*
+ * krishna balasubramanian 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/shm.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+
+int main(int argc, char **argv)
+{
+ int id;
+ union semun arg;
+
+ arg.val = 0;
+
+ if (argc != 3 || strlen(argv[1]) < 3) {
+ printf ("usage: %s [shm | msg | sem] id\n", argv[0]);
+ exit (1);
+ }
+ id = atoi (argv[2]);
+ switch (argv[1][1]) {
+ case 'h':
+ if (!shmctl (id, IPC_RMID, NULL))
+ break;
+ perror ("shmctl ");
+ exit (1);
+
+ case 'e':
+ if (!semctl (id, 0, IPC_RMID, arg))
+ break;
+ perror ("semctl ");
+ exit (1);
+
+ case 's':
+ if (!msgctl (id, IPC_RMID, NULL))
+ break;
+ perror ("msgctl ");
+ exit (1);
+
+ default:
+ printf ("usage: %s [-shm | -msg | -sem] id\n", argv[0]);
+ exit (1);
+ }
+ printf ("resource deleted\n");
+ return 0;
+}
+
diff --git a/sys-utils/ipcs.8 b/sys-utils/ipcs.8
new file mode 100644
index 000000000..97fddf51c
--- /dev/null
+++ b/sys-utils/ipcs.8
@@ -0,0 +1,58 @@
+.\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH IPCS 8 "9 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+ipcs \- provide information on ipc facilities
+.SH SYNOPSIS
+.B ipcs [ \-asmq ] [ \-tclup ]
+.br
+.BI "ipcs [ \-smq ] \-i " id
+.br
+.B ipcs \-h
+.SH DESCRIPTION
+.B ipcs
+provides information on the ipc facilities for which the calling process
+has read acccess.
+
+The
+.B \-i
+option allows a specific resource
+.I id
+to be specified. Only information on this
+.I id
+will be printed.
+
+Resources may be specified as follows:
+.TP
+.B \-m
+shared memory segments
+.TP
+.B \-q
+message queues
+.TP
+.B \-s
+semaphore arrays
+.TP
+.B \-a
+all (this is the default)
+.PP
+The output format may be specified as follows:
+.TP
+.B \-t
+time
+.TP
+.B \-p
+pid
+.TP
+.B \-c
+creator
+.TP
+.B \-l
+limits
+.TP
+.B \-u
+summary
+.SH SEE ALSO
+.BR ipcrm (8)
+.SH AUTHOR
+krishna balasubramanian (balasub@cis.ohio-state.edu)
diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c
new file mode 100644
index 000000000..8e7f9c609
--- /dev/null
+++ b/sys-utils/ipcs.c
@@ -0,0 +1,551 @@
+/* Original author unknown, but may be "krishna balasub@cis.ohio-state.edu"
+ Modified Sat Oct 9 10:55:28 1993 for 0.99.13 */
+
+/* Patches from Mike Jagdis (jaggy@purplet.demon.co.uk) applied Wed Feb 8
+12:12:21 1995 by faith@cs.unc.edu to print numeric uids if no passwd file
+entry. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+#define __KERNEL__
+#include <sys/sem.h>
+#include <sys/msg.h>
+#include <sys/shm.h>
+
+
+#define LIMITS 1
+#define STATUS 2
+#define CREATOR 3
+#define TIME 4
+#define PID 5
+
+void do_shm (char format);
+void do_sem (char format);
+void do_msg (char format);
+void print_shm (int id);
+void print_msg (int id);
+void print_sem (int id);
+
+static char *progname;
+
+void usage(void)
+{
+ printf ("usage : %s -asmq -tclup \n", progname);
+ printf ("\t%s [-s -m -q] -i id\n", progname);
+ printf ("\t%s -h for help.\n", progname);
+ return;
+}
+
+void help (void)
+{
+ printf ("%s provides information on ipc facilities for", progname);
+ printf (" which you have read access.\n");
+ printf ("Resource Specification:\n\t-m : shared_mem\n\t-q : messages\n");
+ printf ("\t-s : semaphores\n\t-a : all (default)\n");
+ printf ("Output Format:\n\t-t : time\n\t-p : pid\n\t-c : creator\n");
+ printf ("\t-l : limits\n\t-u : summary\n");
+ printf ("-i id [-s -q -m] : details on resource identified by id\n");
+ usage();
+ return;
+}
+
+int main (int argc, char **argv)
+{
+ int opt, msg = 0, sem = 0, shm = 0, id=0, print=0;
+ char format = 0;
+ char options[] = "atcluphsmqi:";
+
+ progname = argv[0];
+ while ((opt = getopt (argc, argv, options)) != EOF) {
+ switch (opt) {
+ case 'i':
+ id = atoi (optarg);
+ print = 1;
+ break;
+ case 'a':
+ msg = shm = sem = 1;
+ break;
+ case 'q':
+ msg = 1;
+ break;
+ case 's':
+ sem = 1;
+ break;
+ case 'm':
+ shm = 1;
+ break;
+ case 't':
+ format = TIME;
+ break;
+ case 'c':
+ format = CREATOR;
+ break;
+ case 'p':
+ format = PID;
+ break;
+ case 'l':
+ format = LIMITS;
+ break;
+ case 'u':
+ format = STATUS;
+ break;
+ case 'h':
+ help();
+ exit (0);
+ case '?':
+ usage();
+ exit (0);
+ }
+ }
+
+ if (print) {
+ if (shm) {
+ print_shm (id);
+ exit (0);
+ }
+ if (sem) {
+ print_sem (id);
+ exit (0);
+ }
+ if (msg) {
+ print_msg (id);
+ exit (0);
+ }
+ usage();
+ }
+
+ if ( !shm && !msg && !sem)
+ msg = sem = shm = 1;
+ printf ("\n");
+
+ if (shm) {
+ do_shm (format);
+ printf ("\n");
+ }
+ if (sem) {
+ do_sem (format);
+ printf ("\n");
+ }
+ if (msg) {
+ do_msg (format);
+ printf ("\n");
+ }
+ return 0;
+}
+
+
+void print_perms (int id, struct ipc_perm *ipcp)
+{
+ struct passwd *pw;
+ struct group *gr;
+
+ printf ("%-10d%-10o", id, ipcp->mode & 0777);
+
+ if ((pw = getpwuid(ipcp->cuid)))
+ printf("%-10s", pw->pw_name);
+ else
+ printf("%-10d", ipcp->cuid);
+ if ((gr = getgrgid(ipcp->cgid)))
+ printf("%-10s", gr->gr_name);
+ else
+ printf("%-10d", ipcp->cgid);
+
+ if ((pw = getpwuid(ipcp->uid)))
+ printf("%-10s", pw->pw_name);
+ else
+ printf("%-10d", ipcp->uid);
+ if ((gr = getgrgid(ipcp->gid)))
+ printf("%-10s\n", gr->gr_name);
+ else
+ printf("%-10d\n", ipcp->gid);
+}
+
+
+void do_shm (char format)
+{
+ int maxid, shmid, id;
+ struct shmid_ds shmseg;
+ struct shm_info shm_info;
+ struct shminfo shminfo;
+ struct ipc_perm *ipcp = &shmseg.shm_perm;
+ struct passwd *pw;
+
+ maxid = shmctl (0, SHM_INFO, (struct shmid_ds *) &shm_info);
+ if (maxid < 0) {
+ printf ("kernel not configured for shared memory\n");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ printf ("------ Shared Memory Limits --------\n");
+ if ((shmctl (0, IPC_INFO, (struct shmid_ds *) &shminfo)) < 0 )
+ return;
+ printf ("max number of segments = %d\n", shminfo.shmmni);
+ printf ("max seg size (kbytes) = %d\n", shminfo.shmmax >> 10);
+ printf ("max total shared memory (kbytes) = %d\n", shminfo.shmall << 2);
+ printf ("min seg size (bytes) = %d\n", shminfo.shmmin);
+ return;
+
+ case STATUS:
+ printf ("------ Shared Memory Status --------\n");
+ printf ("segments allocated %d\n", shm_info.used_ids);
+ printf ("pages allocated %d\n", shm_info.shm_tot);
+ printf ("pages resident %d\n", shm_info.shm_rss);
+ printf ("pages swapped %d\n", shm_info.shm_swp);
+ printf ("Swap performance: %d attempts\t %d successes\n",
+ shm_info.swap_attempts, shm_info.swap_successes);
+ return;
+
+ case CREATOR:
+ printf ("------ Shared Memory Segment Creators/Owners --------\n");
+ printf ("%-10s%-10s%-10s%-10s%-10s%-10s\n",
+ "shmid","perms","cuid","cgid","uid","gid");
+ break;
+
+ case TIME:
+ printf ("------ Shared Memory Attach/Detach/Change Times --------\n");
+ printf ("%-10s%-10s %-20s%-20s%-20s\n",
+ "shmid","owner","attached","detached","changed");
+ break;
+
+ case PID:
+ printf ("------ Shared Memory Creator/Last-op --------\n");
+ printf ("%-10s%-10s%-10s%-10s\n","shmid","owner","cpid","lpid");
+ break;
+
+ default:
+ printf ("------ Shared Memory Segments --------\n");
+ printf ("%-10s%-10s%-10s%-10s%-10s%-12s\n", "shmid","owner",
+ "perms","bytes","nattch","status");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ shmid = shmctl (id, SHM_STAT, &shmseg);
+ if (shmid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms (shmid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf ("%-10d%-10.10s", shmid, pw->pw_name);
+ else
+ printf ("%-10d%-10d", shmid, ipcp->uid);
+ printf(" %-20.16s%-20.16s%-20.16s\n",
+ shmseg.shm_atime ? ctime(&shmseg.shm_atime) + 4 : "Not set",
+ shmseg.shm_dtime ? ctime(&shmseg.shm_dtime) + 4 : "Not set",
+ shmseg.shm_ctime ? ctime(&shmseg.shm_ctime) + 4 : "Not set");
+ break;
+ case PID:
+ if (pw)
+ printf ("%-10d%-10.10s", shmid, pw->pw_name);
+ else
+ printf ("%-10d%-10d", shmid, ipcp->uid);
+ printf ("%-10d%-10d\n",
+ shmseg.shm_cpid, shmseg.shm_lpid);
+ break;
+
+ default:
+ if (pw)
+ printf ("%-10d%-10.10s", shmid, pw->pw_name);
+ else
+ printf ("%-10d%-10d", shmid, ipcp->uid);
+ printf ("%-10o%-10d%-10d%-6s%-6s\n",
+ ipcp->mode & 0777,
+ shmseg.shm_segsz, shmseg.shm_nattch,
+ ipcp->mode & SHM_DEST ? "dest" : " ",
+ ipcp->mode & SHM_LOCKED ? "locked" : " ");
+ break;
+ }
+ }
+ return;
+}
+
+
+void do_sem (char format)
+{
+ int maxid, semid, id;
+ struct semid_ds semary;
+ struct seminfo seminfo;
+ struct ipc_perm *ipcp = &semary.sem_perm;
+ struct passwd *pw;
+ union semun arg;
+
+ arg.array = (ushort *) &seminfo;
+ maxid = semctl (0, 0, SEM_INFO, arg);
+ if (maxid < 0) {
+ printf ("kernel not configured for semaphores\n");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ printf ("------ Semaphore Limits --------\n");
+ arg.array = (ushort *) &seminfo; /* damn union */
+ if ((semctl (0, 0, IPC_INFO, arg)) < 0 )
+ return;
+ printf ("max number of arrays = %d\n", seminfo.semmni);
+ printf ("max semaphores per array = %d\n", seminfo.semmsl);
+ printf ("max semaphores system wide = %d\n", seminfo.semmns);
+ printf ("max ops per semop call = %d\n", seminfo.semopm);
+ printf ("semaphore max value = %d\n", seminfo.semvmx);
+ return;
+
+ case STATUS:
+ printf ("------ Semaphore Status --------\n");
+ printf ("used arrays = %d\n", seminfo.semusz);
+ printf ("allocated semaphores = %d\n", seminfo.semaem);
+ return;
+
+ case CREATOR:
+ printf ("------ Semaphore Arrays Creators/Owners --------\n");
+ printf ("%-10s%-10s%-10s%-10s%-10s%-10s\n",
+ "semid","perms","cuid","cgid","uid","gid");
+ break;
+
+ case TIME:
+ printf ("------ Shared Memory Operation/Change Times --------\n");
+ printf ("%-8s%-10s %-26.24s %-26.24s\n",
+ "shmid","owner","last-op","last-changed");
+ break;
+
+ case PID:
+ break;
+
+ default:
+ printf ("------ Semaphore Arrays --------\n");
+ printf ("%-10s%-10s%-10s%-10s%-12s\n",
+ "semid","owner","perms","nsems","status");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ arg.buf = (struct semid_ds *) &semary;
+ semid = semctl (id, 0, SEM_STAT, arg);
+ if (semid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms (semid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf ("%-8d%-10.10s", semid, pw->pw_name);
+ else
+ printf ("%-8d%-10d", semid, ipcp->uid);
+ printf (" %-26.24s %-26.24s\n",
+ semary.sem_otime ? ctime(&semary.sem_otime) : "Not set",
+ semary.sem_ctime ? ctime(&semary.sem_ctime) : "Not set");
+ break;
+ case PID:
+ break;
+
+ default:
+ if (pw)
+ printf ("%-10d%-10.9s", semid, pw->pw_name);
+ else
+ printf ("%-10d%-9d", semid, ipcp->uid);
+ printf ("%-10o%-10d\n",
+ ipcp->mode & 0777,
+ semary.sem_nsems);
+ break;
+ }
+ }
+ return;
+}
+
+
+void do_msg (char format)
+{
+ int maxid, msqid, id;
+ struct msqid_ds msgque;
+ struct msginfo msginfo;
+ struct ipc_perm *ipcp = &msgque.msg_perm;
+ struct passwd *pw;
+
+ maxid = msgctl (0, MSG_INFO, (struct msqid_ds *) &msginfo);
+ if (maxid < 0) {
+ printf ("kernel not configured for shared memory\n");
+ return;
+ }
+
+ switch (format) {
+ case LIMITS:
+ if ((msgctl (0, IPC_INFO, (struct msqid_ds *) &msginfo)) < 0 )
+ return;
+ printf ("------ Messages: Limits --------\n");
+ printf ("max queues system wide = %d\n", msginfo.msgmni);
+ printf ("max size of message (bytes) = %d\n", msginfo.msgmax);
+ printf ("default max size of queue (bytes) = %d\n", msginfo.msgmnb);
+ return;
+
+ case STATUS:
+ printf ("------ Messages: Status --------\n");
+ printf ("allocated queues = %d\n", msginfo.msgpool);
+ printf ("used headers = %d\n", msginfo.msgmap);
+ printf ("used space = %d bytes\n", msginfo.msgtql);
+ return;
+
+ case CREATOR:
+ printf ("------ Message Queues: Creators/Owners --------\n");
+ printf ("%-10s%-10s%-10s%-10s%-10s%-10s\n",
+ "msqid","perms","cuid","cgid","uid","gid");
+ break;
+
+ case TIME:
+ printf ("------ Message Queues Send/Recv/Change Times --------\n");
+ printf ("%-8s%-10s %-20s%-20s%-20s\n",
+ "msqid","owner","send","recv","change");
+ break;
+
+ case PID:
+ break;
+
+ default:
+ printf ("------ Message Queues --------\n");
+ printf ("%-10s%-10s%-10s%-12s%-12s\n", "msqid","owner",
+ "perms", "used-bytes", "messages");
+ break;
+ }
+
+ for (id = 0; id <= maxid; id++) {
+ msqid = msgctl (id, MSG_STAT, &msgque);
+ if (msqid < 0)
+ continue;
+ if (format == CREATOR) {
+ print_perms (msqid, ipcp);
+ continue;
+ }
+ pw = getpwuid(ipcp->uid);
+ switch (format) {
+ case TIME:
+ if (pw)
+ printf ("%-8d%-10.10s", msqid, pw->pw_name);
+ else
+ printf ("%-8d%-10d", msqid, ipcp->uid);
+ printf (" %-20.16s%-20.16s%-20.16s\n",
+ msgque.msg_stime ? ctime(&msgque.msg_stime) + 4 : "Not set",
+ msgque.msg_rtime ? ctime(&msgque.msg_rtime) + 4 : "Not set",
+ msgque.msg_ctime ? ctime(&msgque.msg_ctime) + 4 : "Not set");
+ break;
+ case PID:
+ break;
+
+ default:
+ if (pw)
+ printf ("%-10d%-10.10s", msqid, pw->pw_name);
+ else
+ printf ("%-10d%-10d", msqid, ipcp->uid);
+ printf ("%-10o%-12d%-12d\n",
+ ipcp->mode & 0777, msgque.msg_cbytes,
+ msgque.msg_qnum);
+ break;
+ }
+ }
+ return;
+}
+
+
+void print_shm (int shmid)
+{
+ struct shmid_ds shmds;
+ struct ipc_perm *ipcp = &shmds.shm_perm;
+
+ if (shmctl (shmid, IPC_STAT, &shmds) == -1) {
+ perror ("shmctl ");
+ return;
+ }
+
+ printf ("\nShared memory Segment shmid=%d\n", shmid);
+ printf ("uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n",
+ ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid);
+ printf ("mode=%#o\taccess_perms=%#o\n", ipcp->mode, ipcp->mode & 0777);
+ printf ("bytes=%d\tlpid=%d\tcpid=%d\tnattch=%d\n",
+ shmds.shm_segsz, shmds.shm_lpid, shmds.shm_cpid,
+ shmds.shm_nattch);
+ printf ("att_time=%s", shmds.shm_atime ? ctime (&shmds.shm_atime) :
+ "Not set\n");
+ printf ("det_time=%s", shmds.shm_dtime ? ctime (&shmds.shm_dtime) :
+ "Not set\n");
+ printf ("change_time=%s", ctime (&shmds.shm_ctime));
+ printf ("\n");
+ return;
+}
+
+
+
+void print_msg (int msqid)
+{
+ struct msqid_ds buf;
+ struct ipc_perm *ipcp = &buf.msg_perm;
+
+ if (msgctl (msqid, IPC_STAT, &buf) == -1) {
+ perror ("msgctl ");
+ return;
+ }
+ printf ("\nMessage Queue msqid=%d\n", msqid);
+ printf ("uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n",
+ ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid, ipcp->mode);
+ printf ("cbytes=%d\tqbytes=%d\tqnum=%d\tlspid=%d\tlrpid=%d\n",
+ buf.msg_cbytes, buf.msg_qbytes, buf.msg_qnum, buf.msg_lspid,
+ buf.msg_lrpid);
+ printf ("send_time=%srcv_time=%schange_time=%s",
+ buf.msg_rtime? ctime (&buf.msg_rtime) : "Not Set\n",
+ buf.msg_stime? ctime (&buf.msg_stime) : "Not Set\n",
+ buf.msg_ctime? ctime (&buf.msg_ctime) : "Not Set\n");
+ printf ("\n");
+ return;
+}
+
+void print_sem (int semid)
+{
+ struct semid_ds semds;
+ struct ipc_perm *ipcp = &semds.sem_perm;
+ union semun arg;
+ int i;
+
+ arg.buf = &semds;
+ if (semctl (semid, 0, IPC_STAT, arg) < 0) {
+ perror ("semctl ");
+ return;
+ }
+ printf ("\nSemaphore Array semid=%d\n", semid);
+ printf ("uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n",
+ ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid);
+ printf ("mode=%#o, access_perms=%#o\n", ipcp->mode, ipcp->mode & 0777);
+ printf ("nsems = %d\n", semds.sem_nsems);
+ printf ("otime = %s", semds.sem_otime ? ctime (&semds.sem_otime) :
+ "Not set\n");
+ printf ("ctime = %s", ctime (&semds.sem_ctime));
+
+ printf ("%-10s%-10s%-10s%-10s%-10s\n", "semnum","value","ncount",
+ "zcount","pid");
+ arg.val = 0;
+ for (i=0; i< semds.sem_nsems; i++) {
+ int val, ncnt, zcnt, pid;
+ val = semctl (semid, i, GETVAL, arg);
+ ncnt = semctl (semid, i, GETNCNT, arg);
+ zcnt = semctl (semid, i, GETZCNT, arg);
+ pid = semctl (semid, i, GETPID, arg);
+ if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) {
+ perror ("semctl ");
+ exit (1);
+ }
+ printf ("%-10d%-10d%-10d%-10d%-10d\n", i, val, ncnt, zcnt, pid);
+ }
+ printf ("\n");
+ return;
+}
+
diff --git a/sys-utils/kbdrate.8 b/sys-utils/kbdrate.8
new file mode 100644
index 000000000..3fef3395f
--- /dev/null
+++ b/sys-utils/kbdrate.8
@@ -0,0 +1,57 @@
+.\" Copyright 1992, 1994 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.\" Updated Wed Jun 22 21:09:43 1994, faith@cs.unc.edu
+.TH KBDRATE 8 "22 June 1994" "Linux 1.1.19" "Linux Programmer's Manual"
+.SH NAME
+kbdrate \- reset the keyboard repeat rate and delay time
+.SH SYNOPSIS
+.B "kbdrate [ \-s ] [ \-r"
+rate
+.B "] [ \-d"
+delay
+.B ]
+.SH DESCRIPTION
+.B kbdrate
+is used to change the IBM keyboard repeat rate and delay time. The delay
+is the amount of time that a key must be depressed before it will start to
+repeat.
+
+Using
+.B kbdrate
+without any options will reset the rate to 10.9 characters per second (cps)
+and the delay to 250 milliseconds (mS). These are the IBM defaults.
+.SH OPTIONS
+.TP
+.B \-s
+Silent. No messages are printed.
+.TP
+.BI \-r " rate"
+Change the keyboard repeat rate to
+.I rate
+cps. The allowable range is from 2.0 to 30.0 cps. Only certain, specific
+values are possible, and the program will select the nearest possible value
+to the one specified. The possible values are given, in characters per
+second, as follows: 2.0, 2.1, 2.3, 2.5, 2.7, 3.0, 3.3, 3.7, 4.0, 4.3, 4.6,
+5.0, 5.5, 6.0, 6.7, 7.5, 8.0, 8.6, 9.2, 10.0, 10.9, 12.0, 13.3, 15.0, 16.0,
+17.1, 18.5, 20.0, 21.8, 24.0, 26.7, 30.0.
+.TP
+.BI \-d " delay"
+Change the delay to
+.I delay
+milliseconds. The allowable range is from 250 to 1000 mS, but the only
+possible values (based on hardware restrictions) are: 250mS, 500mS, 750mS,
+and 1000mS.
+.SH BUGS
+Not all keyboards support all rates.
+.PP
+Not all keyboards have the rates mapped in the same way.
+.PP
+Setting the repeat rate on the Gateway AnyKey keyboard does not work. If
+someone with a Gateway figures out how to program the keyboard, please send
+mail to faith@cs.unc.edu.
+.SH FILES
+.I /etc/rc.local
+.br
+.I /dev/port
+.SH AUTHOR
+Rik Faith (faith@cs.unc.edu)
diff --git a/sys-utils/kbdrate.c b/sys-utils/kbdrate.c
new file mode 100644
index 000000000..d8632a204
--- /dev/null
+++ b/sys-utils/kbdrate.c
@@ -0,0 +1,130 @@
+/*
+From: faith@cs.unc.edu (Rik Faith)
+Subject: User mode keyboard rate changer
+Date: 27 Apr 92 13:44:26 GMT
+
+I put together this program, called kbdrate.c, which will reset the keyboard
+repeat rate and delay in user mode. The program must have read/write
+access to /dev/port, so if /dev/port is only read/writeable by group port,
+then kbdrate must run setgid to group port (for example).
+
+The "rate" is the rate in characters per second
+
+The "delay" is the amount of time the key must remain depressed before it
+will start to repeat.
+
+Usage examples:
+
+kbdrate set rate to IBM default (10.9 cps, 250mS delay)
+kbdrate -r 30.0 set rate to 30 cps and delay to 250mS
+kbdrate -r 20.0 -s set rate to 20 cps (delay 250mS) -- don't print message
+kbdrate -r 0 -d 0 set rate to 2.0 cps and delay to 250 mS
+
+I find it useful to put kbdrate in my /etc/rc file so that the keyboard
+rate is set to something that I find comfortable at boot time. This sure
+beats rebuilding the kernel!
+*/
+
+/********************** CUT HERE *****************************/
+/* kbdrate.c -- Set keyboard typematic rate (and delay)
+ * Created: Thu Apr 23 12:24:30 1992
+ * Revised: Wed Jun 22 22:40:46 1994 by faith@cs.unc.edu
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992 Rickard E. Faith. Distributed under the GPL.
+ * This program comes with ABSOLUTELY NO WARRANTY.
+ * Usage: kbdrate [-r rate] [-d delay] [-s]
+ * Rate can range from 2.0 to 30.0 (units are characters per second)
+ * Delay can range from 250 to 1000 (units are milliseconds)
+ * -s suppressed message
+ * Compiles under gcc 2.1 for Linux (tested with the pre-0.96 kernel)
+ *
+ * Wed Jun 22 21:35:43 1994, faith@cs.unc.edu:
+ * Changed valid_rates per suggestion by Andries.Brouwer@cwi.nl.
+ * Wed Jun 22 22:18:29 1994, faith@cs.unc.edu:
+ * Added patch for AUSTIN notebooks from John Bowman
+ * (bowman@hagar.ph.utexas.edu)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/file.h>
+
+static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
+ 133, 120, 109, 100, 92, 86, 80, 75, 67,
+ 60, 55, 50, 46, 43, 40, 37, 33, 30, 27,
+ 25, 23, 21, 20 };
+#define RATE_COUNT (sizeof( valid_rates ) / sizeof( int ))
+
+static int valid_delays[] = { 250, 500, 750, 1000 };
+#define DELAY_COUNT (sizeof( valid_delays ) / sizeof( int ))
+
+void main( int argc, char **argv )
+{
+ double rate = 10.9; /* Default rate */
+ int delay = 250; /* Default delay */
+ int value = 0x7f; /* Maximum delay with slowest rate */
+ /* DO NOT CHANGE this value */
+ int silent = 0;
+ int fd;
+ char data;
+ int c;
+ int i;
+ extern char *optarg;
+ extern int optind;
+
+ while ( (c = getopt( argc, argv, "r:d:s" )) != EOF )
+ switch (c) {
+ case 'r':
+ rate = atof( optarg );
+ break;
+ case 'd':
+ delay = atoi( optarg );
+ break;
+ case 's':
+ silent = 1;
+ break;
+ }
+
+ for (i = 0; i < RATE_COUNT; i++)
+ if (rate * 10 >= valid_rates[i]) {
+ value &= 0x60;
+ value |= i;
+ break;
+ }
+
+ for (i = 0; i < DELAY_COUNT; i++)
+ if (delay <= valid_delays[i]) {
+ value &= 0x1f;
+ value |= i << 5;
+ break;
+ }
+
+ if ( (fd = open( "/dev/port", O_RDWR )) < 0) {
+ perror( "Cannot open /dev/port" );
+ exit( 1 );
+ }
+
+ do {
+ lseek( fd, 0x64, 0 );
+ read( fd, &data, 1 );
+ } while ((data & 2) == 2 ); /* wait */
+
+ lseek( fd, 0x60, 0 );
+ data = 0xf3; /* set typematic rate */
+ write( fd, &data, 1 );
+
+ do {
+ lseek( fd, 0x64, 0 );
+ read( fd, &data, 1 );
+ } while ((data & 2) == 2 ); /* wait */
+
+ lseek( fd, 0x60, 0 );
+ sleep( 1 );
+ write( fd, &value, 1 );
+
+ close( fd );
+
+ if (!silent) printf( "Typematic Rate set to %.1f cps (delay = %d mS)\n",
+ valid_rates[value & 0x1f] / 10.0,
+ valid_delays[ (value & 0x60) >> 5 ] );
+}
diff --git a/sys-utils/lpcntl.8 b/sys-utils/lpcntl.8
new file mode 100644
index 000000000..87bcd039e
--- /dev/null
+++ b/sys-utils/lpcntl.8
@@ -0,0 +1,30 @@
+.\" Public Domain 1994 Rik Faith (faith@cs.unc.edu)
+.\" "
+.TH LPCNTL 8 "18 July 1994" "Linux 1.1" "Linux Programmer's Manual"
+.SH NAME
+lpcntl \- interface to line printer ioctl
+.SH SYNOPSIS
+.BI "lpcntl " device " [ " irq " ]"
+.SH DESCRIPTION
+.B lpcntl
+is used to manipulate the line printer driver.
+.PP
+.I device
+specifies a line printer device (e.g.,
+.IR /dev/lp1 ).
+.PP
+If
+.I irq
+is specified, then the line printer driver is set to use that IRQ. If the
+.I irq
+is zero, then the polling driver is selected. Only the super user may
+change the IRQ.
+.PP
+If no
+.I irq
+is specified, then
+.B lpcntl
+will report the interrupt number currently in use, or will report that the
+polling driver is currently being used.
+.SH AUTHOR
+Nigel Gamble (nigel@gate.net)
diff --git a/sys-utils/lpcntl.c b/sys-utils/lpcntl.c
new file mode 100644
index 000000000..bf164a632
--- /dev/null
+++ b/sys-utils/lpcntl.c
@@ -0,0 +1,54 @@
+/*
+ * Simple command interface to ioctl(fd, LPSETIRQ, irq).
+ * Nigel Gamble (nigel@gate.net)
+ * e.g.
+ * lpcntl /dev/lp1 7
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <linux/lp.h>
+
+int
+main(int argc, char **argv)
+{
+ unsigned int irq;
+ int fd;
+ int ret;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <lp device> [<irq>]\n", argv[0]);
+ exit(1);
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ if (argc == 2) {
+ irq = ioctl(fd, LPGETIRQ);
+ if (irq == -1) {
+ perror(argv[1]);
+ exit(1);
+ }
+ if (irq)
+ printf("%s using IRQ %d\n", argv[1], irq);
+ else
+ printf("%s using polling\n", argv[1]);
+ } else {
+ irq = atoi(argv[2]);
+ ret = ioctl(fd, LPSETIRQ, irq);
+ if (ret == -1) {
+ if (errno == EPERM)
+ fprintf(stderr, "%s: only super-user can change the IRQ\n", argv[0]);
+ else
+ perror(argv[1]);
+ exit(1);
+ }
+ }
+
+ return 0;
+}
diff --git a/sys-utils/ramsize.8 b/sys-utils/ramsize.8
new file mode 100644
index 000000000..901bd7591
--- /dev/null
+++ b/sys-utils/ramsize.8
@@ -0,0 +1 @@
+.so man8/rdev.8
diff --git a/sys-utils/rdev.8 b/sys-utils/rdev.8
new file mode 100644
index 000000000..78a62355f
--- /dev/null
+++ b/sys-utils/rdev.8
@@ -0,0 +1,166 @@
+.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.\" Changes from sct@dcs.ed.ac.uk added Sat Oct 9 09:54:00 1993.
+.TH RDEV 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+rdev \- query/set image root device, swap device, RAM disk size, or video mode
+.SH SYNOPSIS
+.nf
+.BR "rdev [ \-rsvh ] [ \-o " offset " ] [ " image " [ " value " [ " offset " ] ] ]"
+.BR "rdev [ \-o " offset " ] [ " image " [ " root_device " [ " offset " ] ] ]"
+.BR "swapdev [ \-o " offset " ] [ " image " [ " swap_device " [ " offset " ] ] ]"
+.BR "ramsize [ \-o " offset " ] [ " image " [ " size " [ " offset " ] ] ]"
+.BR "vidmode [ \-o " offset " ] [ " image " [ " mode " [ " offset " ] ] ]"
+.BR "rootflags [ \-o " offset " ] [ " image " [ " flags " [ " offset " ] ] ]"
+.fi
+.SH DESCRIPTION
+.\" " for emacs hilit19
+With no arguments,
+.B rdev
+outputs an
+.I /etc/mtab
+line for the current root file system.
+With no arguments,
+.BR swapdev ", " ramsize ", " vidmode ", and " rootflags
+print usage information.
+
+In a bootable image for the Linux kernel, there are several pairs of bytes
+which specify the root device, the video mode, the size of the RAM disk,
+and the swap device. These pairs of bytes, by default, begin at offset 504
+(decimal) in the kernel image:
+
+.nf
+.RS
+ 498 Root flags
+(500 and 502 Reserved)
+ 504 RAM Disk Size
+ 506 VGA Mode
+ 508 Root Device
+(510 Boot Signature)
+.RE
+.fi
+
+.B rdev
+will change these values.
+
+Typical values for the
+.I image
+parameter, which is a bootable Linux kernel image, are as follows:
+
+.nf
+.RS
+/vmlinux
+/vmlinux.test
+/vmunix
+/vmunix.test
+/dev/fd0
+/dev/fd1
+.RE
+.fi
+
+When using the
+.BR rdev ", or " swapdev
+commands, the
+.IR root_device " or " swap_device
+parameter are as follows:
+
+.nf
+.RS
+/dev/hda[1-8]
+/dev/hdb[1-8]
+/dev/sda[1-8]
+/dev/sdb[1-8]
+.RE
+.fi
+
+For the
+.B ramsize
+command, the
+.B size
+parameter specifies the size of the RAM disk in kilobytes.
+
+For the
+.B rootflags
+command, the
+.B flags
+parameter contains extra information used when mounting root.
+Currently the only effect of these flags is to force the kernel to
+mount the root filesystem in readonly mode if
+.B flags
+is non-zero.
+
+For the
+.B vidmode
+command, the
+.B mode
+parameter specifies the video mode:
+
+.nf
+.RS
+-3 = Prompt
+-2 = Extended VGA
+-1 = Normal VGA
+ 0 = as if "0" was pressed at the prompt
+ 1 = as if "1" was pressed at the prompt
+ 2 = as if "2" was pressed at the prompt
+ n = as if "n" was pressed at the prompt
+.RE
+.fi
+
+If the
+.I value
+is not specified, the
+.I image
+will be examined to determine the current settings.
+.SH OPTIONS
+.TP
+.B \-s
+Causes
+.B rdev
+to act like
+.BR swapdev .
+.TP
+.B \-r
+Causes
+.B rdev
+to act like
+.BR ramsize .
+.TP
+.B \-R
+Causes
+.B rdev
+to act like
+.BR rootflags .
+.TP
+.B \-v
+Causes
+.B rdev
+to act like
+.BR vidmode .
+.TP
+.B \-h
+Provides help.
+.SH BUGS
+For historical reasons, there are two methods for specifying alternative
+values for the offset.
+.sp
+The user interface is cumbersome, non-intuitive, and should probably be
+re-written from scratch, allowing multiple kernel image parameters to be
+changed or examined with a single command.
+.sp
+If LILO is used,
+.B rdev
+is no longer needed for setting the root device and the VGA mode, since
+these parameters that
+.B rdev
+modifies can be set from the LILO prompt during a boot. However,
+.B rdev
+is still needed at this time for setting the RAM disk size. Users are
+encouraged to find the LILO documentation for more information, and to use
+LILO when booting their systems.
+.SH AUTHORS
+.nf
+Originally by Werner Almesberger (almesber@nessie.cs.id.ethz.ch)
+Modified by Peter MacDonald (pmacdona@sanjuan.UVic.CA)
+rootflags support added by Stephen Tweedie (sct@dcs.ed.ac.uk)
+.fi
diff --git a/sys-utils/rdev.c b/sys-utils/rdev.c
new file mode 100644
index 000000000..cb3a730ee
--- /dev/null
+++ b/sys-utils/rdev.c
@@ -0,0 +1,244 @@
+/*
+
+ rdev.c - query/set root device.
+
+-------------------------------------------------------------------------
+
+Date: Sun, 27 Dec 1992 15:55:31 +0000
+Subject: Re: rdev
+From: almesber@nessie.cs.id.ethz.ch (Werner Almesberger)
+To: Rik Faith <faith@cs.unc.edu>
+
+There are quite a few versions of rdev:
+
+ - the original rootdev that only printed the current root device, by
+ Linus.
+ - rdev that does what rootdev did and that also allows you to change
+ the root (and swap) device, by me.
+ - rdev got renamed to setroot and I think even to rootdev on various
+ distributions.
+ - Peter MacDonald added video mode and RAM disk setting and included
+ this version on SLS, called rdev again. I've attached his rdev.c to
+ this mail.
+
+-------------------------------------------------------------------------
+
+Date: 11 Mar 92 21:37:37 GMT
+Subject: rdev - query/set root device
+From: almesber@nessie.cs.id.ethz.ch (Werner Almesberger)
+Organization: Swiss Federal Institute of Technology (ETH), Zurich, CH
+
+With all that socket, X11, disk driver and FS hacking going on, apparently
+nobody has found time to address one of the minor nuisances of life: set-
+ting the root FS device is still somewhat cumbersome. I've written a little
+utility which can read and set the root device in boot images:
+
+rdev accepts an optional offset argument, just in case the address should
+ever move from 508. If called without arguments, rdev outputs an mtab line
+for the current root FS, just like /etc/rootdev does.
+
+ramsize sets the size of the ramdisk. If size is zero, no ramdisk is used.
+
+vidmode sets the default video mode at bootup time. -1 uses default video
+mode, -2 uses menu.
+
+-------------------------------------------------------------------------
+
+Sun Dec 27 10:42:16 1992: Minor usage changes, faith@cs.unc.edu.
+Tue Mar 30 09:31:52 1993: rdev -Rn to set root readonly flag, sct@dcs.ed.ac.uk
+Wed Jun 22 21:12:29 1994: Applied patches from Dave
+ (gentzel@nova.enet.dec.com) to prevent dereferencing
+ the NULL pointer, faith@cs.unc.edu
+
+-------------------------------------------------------------------------
+
+*/
+
+/* rdev.c - query/set root device. */
+
+usage()
+{
+
+ puts("usage: rdev [ -rsv ] [ -o OFFSET ] [ IMAGE [ VALUE [ OFFSET ] ] ]");
+ puts(" rdev /dev/fd0 (or rdev /linux, etc.) displays the current ROOT device");
+ puts(" rdev /dev/fd0 /dev/hda2 sets ROOT to /dev/hda2");
+ puts(" rdev -R /dev/fd0 1 set the ROOTFLAGS (readonly status)");
+ puts(" rdev -s /dev/fd0 /dev/hda2 set the SWAP device");
+ puts(" rdev -r /dev/fd0 627 set the RAMDISK size");
+ puts(" rdev -v /dev/fd0 1 set the bootup VIDEOMODE");
+ puts(" rdev -o N ... use the byte offset N");
+ puts(" rootflags ... same as rdev -R");
+ puts(" swapdev ... same as rdev -s");
+ puts(" ramsize ... same as rdev -r");
+ puts(" vidmode ... same as rdev -v");
+ puts("Note: video modes are: -3=Ask, -2=Extended, -1=NormalVga, 1=key1, 2=key2,...");
+ puts(" use -R 1 to mount root readonly, -R 0 for read/write.");
+ exit(-1);
+}
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#define DEFAULT_OFFSET 508
+
+
+static void die(char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
+
+static char *find_dev(int number)
+{
+ DIR *dp;
+ struct dirent *dir;
+ static char name[PATH_MAX+1];
+ struct stat s;
+
+ if (!number) return "Boot device";
+ if ((dp = opendir("/dev")) == NULL) die("opendir /dev");
+ strcpy(name,"/dev/");
+ while (dir = readdir(dp)) {
+ strcpy(name+5,dir->d_name);
+ if (stat(name,&s) < 0) die(name);
+ if ((s.st_mode & S_IFMT) == S_IFBLK && s.st_rdev == number) return name;
+ }
+ sprintf(name,"0x%04x",number);
+ return name;
+}
+
+/* enum { RDEV, SDEV, RAMSIZE, VIDMODE }; */
+enum { RDEV, VIDMODE, RAMSIZE, SDEV, __syssize__, ROOTFLAGS };
+char *cmdnames[6] = { "rdev", "vidmode", "ramsize", "swapdev",
+ "", "rootflags"};
+char *desc[6] = { "Root device", "Video mode", "Ramsize", "Swap device",
+ "", "Root flags"};
+#define shift(n) argv+=n,argc-=n
+
+int main(int argc,char **argv)
+{
+ int image,offset,dev_nr, i, newoffset=-1;
+ char *device, cmd = 0, *ptr, tmp[40];
+ struct stat s;
+
+ device = NULL;
+ if (ptr = strrchr(argv[0],'/'))
+ ptr++;
+ else
+ ptr = argv[0];
+ for (i=0; i<=5; i++)
+ if (!strcmp(ptr,cmdnames[i]))
+ break;
+ cmd = i;
+ if (cmd>5)
+ cmd=RDEV;
+ offset = DEFAULT_OFFSET-cmd*2;
+
+ while (argc > 1)
+ {
+ if (argv[1][0] != '-')
+ break;
+ else
+ switch (argv[1][1])
+ {
+ case 'R':
+ cmd=ROOTFLAGS;
+ offset = DEFAULT_OFFSET-cmd*2;
+ shift(1);
+ break;
+ case 'r':
+ cmd=RAMSIZE;
+ offset = DEFAULT_OFFSET-cmd*2;
+ shift(1);
+ break;
+ case 'v':
+ cmd=VIDMODE;
+ offset = DEFAULT_OFFSET-cmd*2;
+ shift(1);
+ break;
+ case 's':
+ cmd=SDEV;
+ offset = DEFAULT_OFFSET-cmd*2;
+ shift(1);
+ break;
+ case 'o':
+ if (argv[1][2])
+ {
+ newoffset=atoi(argv[1]+2);
+ shift(1);
+ break;
+ } else if (argc > 2) {
+ newoffset=atoi(argv[2]);
+ shift(2);
+ break;
+ }
+ /* Fall through. . . */
+ default:
+ usage();
+ }
+ }
+ if (newoffset >= 0)
+ offset = newoffset;
+
+ if ((cmd==RDEV) && (argc == 1 || argc > 4)) {
+ if (stat("/",&s) < 0) die("/");
+ printf("%s /\n",find_dev(s.st_dev));
+ exit(0);
+ } else if ((cmd != RDEV) && (argc == 1 || argc > 4)) usage();
+
+ if ((cmd==RDEV) || (cmd==SDEV))
+ {
+ if (argc == 4) {
+ device = argv[2];
+ offset = atoi(argv[3]);
+ }
+ else {
+ if (argc == 3) {
+ if (isdigit(*argv[2])) offset = atoi(argv[2]);
+ else device = argv[2];
+ }
+ }
+ }
+ else
+ {
+ if (argc>=3)
+ device = argv[2];
+ if (argc==4)
+ offset = atoi(argv[3]);
+ }
+ if (device) {
+ if ((cmd==SDEV) || (cmd==RDEV))
+ { if (stat(device,&s) < 0) die(device);
+ } else
+ s.st_rdev=atoi(device);
+ if ((image = open(argv[1],O_WRONLY)) < 0) die(argv[1]);
+ if (lseek(image,offset,0) < 0) die("lseek");
+ if (write(image,(char *)&s.st_rdev,2) != 2) die(argv[1]);
+ if (close(image) < 0) die("close");
+ }
+ else {
+ if ((image = open(argv[1],O_RDONLY)) < 0) die(argv[1]);
+ if (lseek(image,offset,0) < 0) die("lseek");
+ dev_nr = 0;
+ if (read(image,(char *)&dev_nr,2) != 2) die(argv[1]);
+ if (close(image) < 0) die("close");
+ printf(desc[cmd]);
+ if ((cmd==SDEV) || (cmd==RDEV))
+ printf(" %s\n", find_dev(dev_nr));
+ else
+ printf(" %d\n", dev_nr);
+ }
+ return 0;
+}
+
+
diff --git a/sys-utils/readprofile.1 b/sys-utils/readprofile.1
new file mode 100644
index 000000000..fd5d7196d
--- /dev/null
+++ b/sys-utils/readprofile.1
@@ -0,0 +1,159 @@
+.TH READPROFILE 1 "January 1995"
+.UC 4
+.SH NAME
+readprofile - a tool to read kernel profiling information
+.SH SYNOPSIS
+.B readprofile
+[
+.I options
+]
+
+.SH VERSION
+This manpage documents version 1.1 of the program.
+
+.SH DESCRIPTION
+
+.LP
+The
+.B readprofile
+command uses the
+.B /proc/profile
+information to print ascii data on standard output.
+The output is
+organized in three columns: the first is the number of clock ticks,
+the second is the name of the C function in the kernel where those many
+ticks occurred, and the third is the normalized `load' of the procedure,
+calculated as a ratio between the number of thicks and the lenght of
+the procedure. The output is filled with blanks to ease readability.
+
+.LP
+Available command line options are the following:
+
+.TP
+.RB -m " mapfile"
+Specify a mapfile, which by default is
+.B /usr/src/linux/System.map.
+To ease use of
+.B readprofile
+with kernels in the 1.1.7x series, if the default file can't be opened,
+the alternate file
+.B /usr/src/linux/zSystem.map
+is tried.
+You should specify the map file on cmdline if your current kernel isn't the
+last one you compiled. If the name of the map file ends with `.gz' it
+is decompressed on the fly.
+
+.TP
+.RB -p " pro-file"
+Specify a different profiling buffer, which by default is
+.B /proc/profile.
+Using a different pro-file is useful if you want to `freeze' the
+kernel profiling at some time and read it later. The
+.B /proc/profile
+file can be copied using `cat' or `cp'. If the name of the pro-file
+ends by `.gz' it is decompressed on the fly. The pro-file is such that
+.B gzip
+shrinks it by 50-100 times.
+
+.TP
+.B -i
+Info. This makes
+.B readprofile
+only print the profiling step used by the kernel.
+The profiling step is the resolution of the profiling buffer, and
+is chosen during kernel configuration (through `make config').
+If the
+.B -t
+(terse) switch is used together with
+.B -i
+only the decimal number is printed.
+
+.TP
+.B -a
+Print all symbols in the mapfile. By default the procedures with 0 reported
+ticks are not printed.
+
+.TP
+.B -r
+Reset the profiling buffer. This can only be invoked by root, because
+.B /proc/profile
+is readable by everybody but writable only by the superuser.
+
+.TP
+.B -t
+Terse. This causes the output to be unfilled. It is the format used in the
+first release of
+.B readprofile.
+
+.TP
+.B -v
+Verbose. The output is organized in four columns and filled with blanks.
+The first column is the RAM address of a kernel function, the second is
+the name of the function, the third is the number of clock ticks and the
+last is the normalized load.
+
+.TP
+.B -V
+Version. This makes
+.B readprofile
+print its version number and exit.
+
+.SH EXAMPLES
+Browse the profiling buffer ordering by clock ticks:
+.nf
+ readprofile | sort -nr | less
+
+.fi
+Print the 20 most loaded procedures:
+.nf
+ readprofile | sort -nr +2 | head -20
+
+.fi
+Print only filesystem profile:
+.nf
+ readprofile | grep _ext2
+
+.fi
+Look at all the kernel information, with ram addresses"
+.nf
+ readprofile -av | less
+
+.fi
+Browse a gzipped `freezed' profile buffer for a non current kernel:
+.nf
+ readprofile -p ~/profile.freeze.gz -m /zImage.map
+
+.fi
+
+.SH BUGS
+
+.LP
+.B readprofile
+needs a kernel version 1.1.73 or newer, because
+.B /proc/profile
+is absent
+in older versions.
+
+.LP
+To enable profiling, the kernel must be reconfigured, recompiled, and
+rebooted. No profiling module is available, and it wouldn't be easy to
+build. So this can be construed as a feature.
+
+.LP
+Profiling is disabled when interrupts are inhibited. This means that many
+profiling ticks happen when interrupts are re-enabled. Watch out for
+misleading information.
+
+.SH AUTHOR
+
+Readprofile and /proc/profile are by Alessandro Rubini (rubini@ipvvis.unipv.it)
+
+.SH FILES
+.nf
+/proc/profile A binary snapshot of the profiling buffer.
+/usr/src/linux/System.map The symbol table for the kernel.
+/usr/src/linux/zSystem.map Old name for the symbol table.
+
+/usr/src/linux/* The program being profiled :-)
+.fi
+
diff --git a/sys-utils/readprofile.c b/sys-utils/readprofile.c
new file mode 100644
index 000000000..58234f6af
--- /dev/null
+++ b/sys-utils/readprofile.c
@@ -0,0 +1,223 @@
+/*
+ * readprofile.c - used to read /proc/profile
+ *
+ * Copyright (C) 1994 Alessandro Rubini
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h> /* getopt() */
+#include <string.h>
+
+#define RELEASE "1.1, Jan 1995"
+
+#define S_LEN 128
+
+static char *prgname;
+
+/* These are the defaults and they cna be changed */
+static char defaultmap1[]="/usr/src/linux/System.map";
+static char defaultmap2[]="/usr/src/linux/zSystem.map";
+static char defaultpro[]="/proc/profile";
+static char optstring[]="m:p:itvarV";
+
+void usage()
+{
+ fprintf(stderr,
+ "%s: Usage: \"%s [options]\n"
+ "\t -m <mapfile> (default = \"%s\")\n"
+ "\t -p <pro-file> (default = \"%s\")\n"
+ "\t -i print only info about the sampling step\n"
+ "\t -t print terse data\n"
+ "\t -v print verbose data\n"
+ "\t -a print all symbols, even if count is 0\n"
+ "\t -r reset all the counters (root only)\n"
+ "\t -V print version and exit\n"
+ ,prgname,prgname,defaultmap1,defaultpro);
+ exit(1);
+}
+
+FILE *myopen(char *name, char *mode, int *flag)
+{
+static char cmdline[S_LEN];
+
+ if (!strcmp(name+strlen(name)-3,".gz"))
+ {
+ *flag=1;
+ sprintf(cmdline,"zcat %s", name);
+ return popen(cmdline,mode);
+ }
+ *flag=0;
+ return fopen(name,mode);
+}
+
+int main (int argc, char **argv)
+{
+FILE *pro;
+FILE *map;
+unsigned long l;
+char *proFile;
+char *mapFile;
+int add, step;
+int fn_add[2]; /* current and next address */
+char fn_name[2][S_LEN]; /* current and next name */
+char mode[8];
+int i,c,current=0;
+int optAll=0, optInfo=0, optReset=0, optTerse=0, optVerbose=0;
+char mapline[S_LEN];
+int maplineno=1;
+int popenMap, popenPro; /* flags to tell if popen() is used */
+
+#define next (current^1)
+
+ prgname=argv[0];
+ proFile=defaultpro;
+ mapFile=defaultmap1;
+
+ while ((c=getopt(argc,argv,optstring))!=-1)
+ {
+ switch(c)
+ {
+ case 'm': mapFile=optarg; break;
+ case 'p': proFile=optarg; break;
+ case 'a': optAll++; break;
+ case 'i': optInfo++; break;
+ case 't': optTerse++; break;
+ case 'r': optReset++; break;
+ case 'v': optVerbose++; break;
+ case 'V': printf("%s Version %s\n",prgname,RELEASE); exit(0);
+ default: usage();
+ }
+ }
+
+ if (optReset)
+ {
+ pro=fopen(defaultpro,"w");
+ if (!pro)
+ {perror(proFile); exit(1);}
+ fprintf(pro,"anything\n");
+ fclose(pro);
+ exit(0);
+ }
+
+ if (!(pro=myopen(proFile,"r",&popenPro)))
+ {fprintf(stderr,"%s: ",prgname);perror(proFile);exit(1);}
+
+ /*
+ * In opening the map file, try both the default names, but exit
+ * at first fail if the filename was specified on cmdline
+ */
+ for (map=NULL; map==NULL; )
+ {
+ if (!(map=myopen(mapFile,"r",&popenMap)))
+ {
+ fprintf(stderr,"%s: ",prgname);perror(mapFile);
+ if (mapFile!=defaultmap1) exit(1);
+ mapFile=defaultmap2;
+ }
+ }
+
+#define NEXT_WORD(where) \
+ (fread((void *)where, 1,sizeof(unsigned long),pro), feof(pro) ? 0 : 1)
+
+ /*
+ * Init the 'next' field
+ */
+ if (!fgets(mapline,S_LEN,map))
+ {
+ fprintf(stderr,"%s: %s(%i): premature EOF\n",prgname,mapFile,maplineno);
+ exit(1);
+ }
+ if (sscanf(mapline,"%x %s %s",&(fn_add[next]),mode,fn_name[next])!=3)
+ {
+ fprintf(stderr,"%s: %s(%i): wrong map line\n",prgname,mapFile, maplineno);
+ exit(1);
+ }
+
+ add=0;
+
+ if (!NEXT_WORD(&step))
+ {
+ fprintf(stderr,"%s: %s: premature EOF\n",prgname,proFile);
+ exit(1);
+ }
+
+ if (optInfo)
+ {
+ printf(optTerse ? "%i\n" : "The sampling step in the kernel is %i bytes\n",
+ step);
+ exit(0);
+ }
+
+ /*
+ * The main loop is build around the mapfile
+ */
+
+ while(current^=1, maplineno++, fgets(mapline,S_LEN,map))
+ {
+ int fn_len;
+ int count=0;
+
+
+ if (sscanf(mapline,"%x %s %s",&(fn_add[next]),mode,fn_name[next])!=3)
+ {
+ fprintf(stderr,"%s: %s(%i): wrong map line\n",
+ prgname,mapFile, maplineno);
+ exit(1);
+ }
+
+ if (!(fn_len=fn_add[next]-fn_add[current]))
+ continue;
+
+ if (*mode=='d' || *mode=='D') break; /* only text is profiled */
+
+ while (add<fn_add[next])
+ {
+ if (!NEXT_WORD(&l))
+ {
+ fprintf(stderr,"%s: %s: premature EOF\n",prgname,proFile);
+ exit(1);
+ }
+ count+=l; add+=step;
+ }
+
+ if (count || optAll)
+ {
+ if (optTerse)
+ printf("%i %s %lg\n",
+ count,fn_name[current],count/(double)fn_len);
+ else if (optVerbose)
+ printf("%08x %-40s %6i %8.4lf\n",
+ fn_add[current],fn_name[current],count,count/(double)fn_len);
+ else
+ printf("%6i %-40s %8.4lf\n",
+ count,fn_name[current],count/(double)fn_len);
+ }
+ }
+
+ if (feof(map))
+ {
+ fprintf(stderr,"%s: %s(%i): premature EOF\n",prgname,mapFile,maplineno);
+ exit(1);
+ }
+
+ popenPro ? pclose(pro) : fclose(pro);
+ popenMap ? pclose(map) : fclose(map);
+ exit(0);
+}
+
+
diff --git a/sys-utils/renice.8 b/sys-utils/renice.8
new file mode 100644
index 000000000..5a260a8db
--- /dev/null
+++ b/sys-utils/renice.8
@@ -0,0 +1,131 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" @(#)renice.8 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt RENICE 8
+.Os BSD 4
+.Sh NAME
+.Nm renice
+.Nd alter priority of running processes
+.Sh SYNOPSIS
+.Nm renice
+.Ar priority
+.Oo
+.Op Fl p
+.Ar pid ...
+.Oc
+.Oo
+.Op Fl g
+.Ar pgrp ...
+.Oc
+.Oo
+.Op Fl u
+.Ar user ...
+.Oc
+.Sh DESCRIPTION
+.Nm Renice
+alters the
+scheduling priority of one or more running processes.
+The following
+.Ar who
+parameters are interpreted as process ID's, process group
+ID's, or user names.
+.Nm Renice Ns 'ing
+a process group causes all processes in the process group
+to have their scheduling priority altered.
+.Nm Renice Ns 'ing
+a user causes all processes owned by the user to have
+their scheduling priority altered.
+By default, the processes to be affected are specified by
+their process ID's.
+.Pp
+Options supported by
+.Nm renice :
+.Bl -tag -width Ds
+.It Fl g
+Force
+.Ar who
+parameters to be interpreted as process group ID's.
+.It Fl u
+Force the
+.Ar who
+parameters to be interpreted as user names.
+.It Fl p
+Resets the
+.Ar who
+interpretation to be (the default) process ID's.
+.El
+.Pp
+For example,
+.Bd -literal -offset
+renice +1 987 -u daemon root -p 32
+.Ed
+.Pp
+would change the priority of process ID's 987 and 32, and
+all processes owned by users daemon and root.
+.Pp
+Users other than the super-user may only alter the priority of
+processes they own,
+and can only monotonically increase their ``nice value''
+within the range 0 to
+.Dv PRIO_MAX
+(20).
+(This prevents overriding administrative fiats.)
+The super-user
+may alter the priority of any process
+and set the priority to any value in the range
+.Dv PRIO_MIN
+(\-20)
+to
+.Dv PRIO_MAX .
+Useful priorities are:
+20 (the affected processes will run only when nothing else
+in the system wants to),
+0 (the ``base'' scheduling priority),
+anything negative (to make things go very fast).
+.Sh FILES
+.Bl -tag -width /etc/passwd -compact
+.It Pa /etc/passwd
+to map user names to user ID's
+.El
+.Sh SEE ALSO
+.Xr getpriority 2 ,
+.Xr setpriority 2
+.Sh BUGS
+Non super-users can not increase scheduling priorities of their own processes,
+even if they were the ones that decreased the priorities in the first place.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/sys-utils/renice.c b/sys-utils/renice.c
new file mode 100644
index 000000000..6deba6b00
--- /dev/null
+++ b/sys-utils/renice.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. 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. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <stdio.h>
+#include <pwd.h>
+
+/*
+ * Change the priority (nice) of processes
+ * or groups of processes which are already
+ * running.
+ */
+main(argc, argv)
+ char **argv;
+{
+ int which = PRIO_PROCESS;
+ int who = 0, prio, errs = 0;
+
+ argc--, argv++;
+ if (argc < 2) {
+ fprintf(stderr, "usage: renice priority [ [ -p ] pids ] ");
+ fprintf(stderr, "[ [ -g ] pgrps ] [ [ -u ] users ]\n");
+ exit(1);
+ }
+ prio = atoi(*argv);
+ argc--, argv++;
+ if (prio > PRIO_MAX)
+ prio = PRIO_MAX;
+ if (prio < PRIO_MIN)
+ prio = PRIO_MIN;
+ for (; argc > 0; argc--, argv++) {
+ if (strcmp(*argv, "-g") == 0) {
+ which = PRIO_PGRP;
+ continue;
+ }
+ if (strcmp(*argv, "-u") == 0) {
+ which = PRIO_USER;
+ continue;
+ }
+ if (strcmp(*argv, "-p") == 0) {
+ which = PRIO_PROCESS;
+ continue;
+ }
+ if (which == PRIO_USER) {
+ register struct passwd *pwd = getpwnam(*argv);
+
+ if (pwd == NULL) {
+ fprintf(stderr, "renice: %s: unknown user\n",
+ *argv);
+ continue;
+ }
+ who = pwd->pw_uid;
+ } else {
+ who = atoi(*argv);
+ if (who < 0) {
+ fprintf(stderr, "renice: %s: bad value\n",
+ *argv);
+ continue;
+ }
+ }
+ errs += donice(which, who, prio);
+ }
+ exit(errs != 0);
+}
+
+donice(which, who, prio)
+ int which, who, prio;
+{
+ int oldprio;
+ extern int errno;
+
+ errno = 0, oldprio = getpriority(which, who);
+ if (oldprio == -1 && errno) {
+ fprintf(stderr, "renice: %d: ", who);
+ perror("getpriority");
+ return (1);
+ }
+ if (setpriority(which, who, prio) < 0) {
+ fprintf(stderr, "renice: %d: ", who);
+ perror("setpriority");
+ return (1);
+ }
+ printf("%d: old priority %d, new priority %d\n", who, oldprio, prio);
+ return (0);
+}
diff --git a/sys-utils/rootflags.8 b/sys-utils/rootflags.8
new file mode 100644
index 000000000..901bd7591
--- /dev/null
+++ b/sys-utils/rootflags.8
@@ -0,0 +1 @@
+.so man8/rdev.8
diff --git a/sys-utils/setserial.8 b/sys-utils/setserial.8
new file mode 100644
index 000000000..539db21a2
--- /dev/null
+++ b/sys-utils/setserial.8
@@ -0,0 +1,392 @@
+.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.\" Portions of this text are from the README in setserial-2.01.tar.z,
+.\" but I can't figure out who wrote that document. If anyone knows,
+.\" please tell me
+.\"
+.\" [tytso:19940519.2239EDT] I did... - Ted Ts'o (tytso@mit.edu)
+.\" Sat Aug 27 17:08:38 1994 Changes from Kai Petzke
+.\" (wpp@marie.physik.tu-berlin.de) were applied by Rik Faith
+.\" (faith@cs.unc.edu)
+.\" "
+.TH SETSERIAL 8 "27 August 1994" "Setserial 2.10" "Linux Programmer's Manual"
+.SH NAME
+setserial \- get/set Linux serial port information
+.SH SYNOPSIS
+.B setserial
+.B "[ \-abqvVW ]"
+device
+.BR "[ " parameter1 " [ " arg " ] ] ..."
+
+.B "setserial -g"
+.B "[ \-abv ]"
+device1 ...
+.SH DESCRIPTION
+.B setserial
+is a program designed to set and/or report the configuration information
+associated with a serial port. This information includes what I/O
+port and IRQ a particular serial port is using, and whether or not the
+break key should be interpreted as the Secure Attention Key, and so
+on.
+
+During the normal bootup process, only COM ports 1-4 are initialized,
+using the default I/O ports and IRQ values, as listed below. In order
+to initialize any additional serial ports, or to change the COM 1-4
+ports to a nonstadard configuration, the
+.B setserial
+program should be used. Typically it is called from an
+.I rc.serial
+script, which is usually run out of
+.IR /etc/rc.local .
+
+The
+.I device
+argument or arguments specifies the serial device which should be configured or
+interrogated. It will usually have the following form:
+.BR /dev/cua[0-3] .
+
+If no parameters are specified,
+.B setserial
+will print out the port type (i.e., 8250, 16450, 16550, 16550A), the
+hardware I/O port, the hardware IRQ line, its "baud base," and some of
+its operational flags.
+
+If the
+.B \-g
+option is given, the arguments to setserial are interpreted as a list
+of devices for which the characteristics of those devices should be
+printed.
+
+Without the
+.B \-g
+option, the first argument to setserial is interpreted as the device
+to be modified or characteristics to be printed, and any additional
+arguments are interpreted as parameters which should be assigned
+to that serial device.
+
+For the most part, superuser privilege is required to set the
+configuration parameters of a serial port. A few serial port parameters
+can be set by normal users, however, and these will be noted as
+exceptions in this manual page.
+
+.SH OPTIONS
+.B Setserial
+accepts the following options:
+
+.TP
+.B \-a
+When reporting the configuration of a serial device, print all
+available information.
+.TP
+.B \-b
+When reporting the configuration of a serial device, print a summary
+of the device's configuration, which might be suitable for printing
+during the bootup process, during the /etc/rc script.
+.TP
+.B \-q
+Be quiet.
+.B Setserial
+will print fewer lines of output.
+.TP
+.B \-v
+Be verbose.
+.B Setserial
+will print additional status output.
+.TP
+.B \-V
+Display version and exit.
+.TP
+.B \-W
+Do wild interrupt initialization and exit.
+
+.SH PARAMETERS
+The following parameters can be assigned to a serial port.
+
+All argument values are assumed to be in decimal unless preceeded by "0x".
+
+.TP
+.BR port " port_number"
+The
+.B port
+option sets the I/O port, as described above.
+.TP
+.BR irq " irq_number"
+The
+.B irq
+option sets the hardware IRQ, as described above.
+.TP
+.BR uart " uart_type"
+This option is used to set the UART type. The permitted types are
+.BR none ,
+8250, 16450, 16550, and 16550A. Since the 8250 and 16450 UARTS do not have
+FIFO's, and since the original 16550 have bugs which make the FIFO's unusable,
+the FIFO will only be used on chips identifiied as 16550A UARTs.
+Setting the UART type to 8250, 16450, or 16550 will enable the serial
+port without trying to use the FIFO. Using UART type
+.B none
+will disable the port.
+
+Some internal modems are billed as having a "16550A UART with a 1k
+buffer". This is a lie. They do not have really have a 16550A
+compatible UART; instead what they have is a 16450 compatible UART
+with a 1k receive buffer to prevent receiver overruns. This is
+important, because they do not have a transmit FIFO. Hence, they are
+not compatible with a 16550A UART, and the autoconfiguration process
+will correctly identify them as 16450's. If you attempt to override
+this using the
+.B uart
+parameter, you will see dropped characters during file transmissions.
+These UART's usually have other problems: the
+.B skip_test
+parameter also often must be specified.
+.TP
+.B autoconfig
+When this parameter is given,
+.B setserial
+will ask the kernel to attempt to automatically configure the serial
+port. The I/O port must be correctly set; the kernel will attempt to
+determine the UART type, and if the
+.B auto_irq
+parameter is set, Linux will attempt to automatically determine the
+IRQ. The
+.B autoconfigure
+parameter should be given after the
+.BR port , auto_irq ", and" skip_test
+parameters have been specified.
+.TP
+.B auto_irq
+During autoconfiguration, try to determine the IRQ. This feature is
+not guaranteed to always produce the correct result; some hardware
+configurations will fool the Linux kernel. It is generally safer not
+to use the
+.B auto_irq
+feature, but rather to specify the IRQ to be used explicitly, using
+the
+.B irq
+parameter.
+.TP
+.B ^auto_irq
+During autoconfiguration, do
+.I not
+try to determine the IRQ.
+.TP
+.B skip_test
+During autoconfiguration, skip the UART test. Some internal modems do
+not have National Semiconductor compatible UART's, but have cheap
+imitations instead. Some of these cheasy imitations UART's do not
+fully support the loopback detection mode, which is used by the kernel
+to make sure there really is a UART at a particular address before
+attempting to configure it. So for certain internal modems you will
+need to specify this parameter so Linux can initialize the UART
+correctly.
+.TP
+.B ^skip_test
+During autoconfiguration, do
+.I not
+skip the UART test.
+.TP
+.BR baud_base " baud_base"
+This option sets the base baud rate, which is the clock frequency divided
+by 16. Normally this value is 115200, which is also the fastest baud
+rate which the UART can support.
+.TP
+.B
+spd_hi
+Use 57.6kb when the application requests 38.4kb.
+This parameter may be specified by a non-privileged user.
+.TP
+.B spd_vhi
+Use 115kb when the application requests 38.4kb.
+This parameter may be specified by a non-privileged user.
+.TP
+.B spd_cust
+Use the custom divisor to set the speed when the application requests
+38.4kb. In this case, the baud rate is the
+.B baud_base
+divided by the
+.BR divisor .
+This parameter may be specified by a non-privileged user.
+.TP
+.B spd_normal
+Use 38.4kb when the application requests 38.4kb.
+This parameter may be specified by a non-privileged user.
+.TP
+.BR divisor " divisor"
+This option sets the custom divison. This divisor will be used then the
+.B spd_cust
+option is selected and the serial port is set to 38.4kb by the
+application.
+This parameter may be specified by a non-privileged user.
+.TP
+.B sak
+Set the break key at the Secure Attention Key.
+.TP
+.B ^sak
+disable the Secure Attention Key.
+.TP
+.B fourport
+Configure the port as an AST Fourport card.
+.TP
+.B ^fourport
+Disable AST Fourport configuration.
+.TP
+.BR close_delay " delay"
+Specify the amount of time, in hundredths of a second, that DTR should
+remain low on a serial line after the callout device is closed, before
+the blocked dialin device raises DTR again. The default value of this
+option is 50, or a half-second delay.
+.TP
+.B session_lockout
+Lock out callout port (/dev/cuaXX) accesses across different sessions.
+That is, once a process has opened a port, do not allow a process with
+a different session ID to open that port until the first process has
+closed it.
+.TP
+.B ^session_lockout
+Do not lock out callout port accesses across different sessions.
+.TP
+.B pgrp_lockout
+Lock out callout port (/dev/cuaXX) accesses across different process groups.
+That is, once a process has opened a port, do not allow a process in a
+different process group to open that port until the first process has
+closed it.
+.TP
+.B ^pgrp_lockout
+Do not lock out callout port accesses across different process groups.
+.TP
+.B hup_notify
+Notify a process blocked on opening a dial in line when a process has
+finished using a callout line (either by closing it or by the serial
+line being hung up) by returning EAGAIN to the open.
+
+The application of this parameter is for getty's which are blocked on
+a serial port's dial in line. This allows the getty to reset the
+modem (which may have had its configuration modified by the
+application using the callout device) before blocking on the open again.
+.TP
+.B ^hup_notify
+Do not notify a process blocked on opening a dial in line when the
+callout device is hung up.
+.TP
+.B split_termios
+Treat the termios settings used by the callout device and the termios
+settings used by the dialin devices as separate.
+.TP
+.B ^split_termios
+Use the same termios structure to store both the dialin and callout
+ports. This is the default option.
+.TP
+.B callout_nohup
+If this particular serial port is opened as a callout device, do not
+hangup the tty when carrier detect is dropped.
+.TP
+.B ^callout_nohup
+Do not skip hanging up the tty when a serial port is opened as a
+callout device. Of course, the HUPCL termios flag must be enabled if
+the hangup is to occur.
+.SH CONSIDERATIONS OF CONFIGURING SERIAL PORTS
+It is important to note that setserial merely tells the Linux kernel
+where it should expect to find the I/O port and IRQ lines of a
+particular serial port. It does *not* configure the hardware, the
+actual serial board, to use a particular I/O port. In order to do
+that, you will need to physically program the serial board, usually by
+setting some jumpers or by switching some DIP switches.
+
+This section will provide some pointers in helping you decide how you
+would like to configure your serial ports.
+
+The "standard MS-DOS" port associations are given below:
+
+.nf
+.RS
+/dev/ttyS0 (COM1), port 0x3f8, irq 4
+/dev/ttyS1 (COM2), port 0x2f8, irq 3
+/dev/ttyS2 (COM3), port 0x3e8, irq 4
+/dev/ttyS3 (COM4), port 0x2e8, irq 3
+.RE
+.fi
+
+Due to the limitations in the design of the AT/ISA bus architecture,
+normally an IRQ line may not be shared between two or more serial
+ports. If you attempt to do this, one or both serial ports will
+become unreliable if you try to use both simultaneously. This
+limitation can be overcome by special multi-port serial port boards,
+which are designed to share multiple serial ports over a single IRQ
+line. Multi-port serial cards supported by Linux include the AST
+FourPort, the Accent Async board, the Usenet Serial II board, the
+Bocaboard BB-1004, BB-1008, and BB-2016 boards, and the HUB-6 serial
+board.
+
+The selection of an alternative IRQ line
+is difficult, since most of them are already used. The following table
+lists the "standard MS-DOS" assignments of available IRQ lines:
+
+.nf
+.RS
+IRQ 3: COM2
+IRQ 4: COM1
+IRQ 5: LPT2
+IRQ 7: LPT1
+.RE
+.fi
+
+Most people find that IRQ 5 is a good choice, assuming that there is
+only one parallel port active in the computer. Another good choice is
+IRQ 2 (aka IRQ 9); although this IRQ is sometimes used by network
+cards, and very rarely VGA cards will be configured to use IRQ 2 as a
+vertical retrace interrupt. If your VGA card is configured this way;
+try to disable it so you can reclaim that IRQ line for some other
+card. It's not necessary for Linux and most other Operating systems.
+
+The only other available IRQ lines are 3, 4, and 7, and these are
+probably used by the other serial and parallel ports. (If your serial
+card has a 16bit card edge connector, and supports higher interrupt
+numbers, then IRQ 10, 11, 12, and 15 are also available.)
+
+On AT class machines, IRQ 2 is seen as IRQ 9, and Linux will interpret it
+in this manner.
+
+IRQ's other than 2 (9), 3, 4, 5, 7, 10, 11, 12, and 15, should
+.I not
+be used, since they are assigned to other hardware and cannot, in general,
+be changed. Here are the "standard" assignments:
+
+.nf
+.RS
+IRQ 0 Timer channel 0
+IRQ 1 Keyboard
+IRQ 2 Cascade for controller 2
+IRQ 3 Serial port 2
+IRQ 4 Serial port 1
+IRQ 5 Parallel port 2 (Reserved in PS/2)
+IRQ 6 Floppy diskette
+IRQ 7 Parallel port 1
+IRQ 8 Real-time clock
+IRQ 9 Redirected to IRQ2
+IRQ 10 Reserved
+IRQ 11 Reserved
+IRQ 12 Reserved (Auxillary device in PS/2)
+IRQ 13 Math coprocessor
+IRQ 14 Hard disk controller
+IRQ 15 Reserved
+.RE
+.fi
+
+
+.SH CAUTION
+CAUTION: Using an invalid port can lock up your machine.
+.SH FILES
+.BR /etc/rc.local
+.BR /etc/rc.serial
+.SH "SEE ALSO"
+.BR tty (4),
+.BR ttys (4),
+kernel/chr_drv/serial.c
+.SH AUTHOR
+The original version of setserial was written by Rick Sladkey
+(jrs@world.std.com), and was modified by Michael K. Johnson
+(johnsonm@stolaf.edu).
+
+This version has since been rewritten from scratch by Theodore Ts'o
+(tytso@mit.edu) on 1/1/93. Any bugs or problems are solely his
+responsibility.
diff --git a/sys-utils/setserial.c b/sys-utils/setserial.c
new file mode 100644
index 000000000..71179baa8
--- /dev/null
+++ b/sys-utils/setserial.c
@@ -0,0 +1,436 @@
+/* setserial.c - get/set Linux serial port info - rick sladkey */
+/* modified to do work again and added setting fast serial speeds,
+ Michael K. Johnson, johnsonm@stolaf.edu */
+/*
+ * Very heavily modified --- almost rewritten from scratch --- to have
+ * a more flexible command structure. Now able to set any of the
+ * serial-specific options using the TIOCSSERIAL ioctl().
+ * Theodore Ts'o, tytso@mit.edu, 1/1/93
+ *
+ * Last modified: [tytso:19940520.0036EDT]
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <string.h>
+#include <errno.h>
+
+#include <linux/fs.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+#define VERSION_STR "2.10"
+
+char *progname;
+
+int verbosity = 1; /* 1 = normal, 0=boot-time, 2=everything */
+int verbose_flag = 0; /* print results after setting a port */
+int quiet_flag = 0;
+
+struct serial_type_struct {
+ int id;
+ char *name;
+} serial_type_tbl[] = {
+ PORT_UNKNOWN, "unknown",
+ PORT_8250, "8250",
+ PORT_16450, "16450",
+ PORT_16550, "16550",
+ PORT_16550A, "16550A",
+ PORT_UNKNOWN, "none",
+ -1, NULL
+};
+
+#define CMD_FLAG 1
+#define CMD_PORT 2
+#define CMD_IRQ 3
+#define CMD_DIVISOR 4
+#define CMD_TYPE 5
+#define CMD_BASE 6
+#define CMD_DELAY 7
+#define CMD_CONFIG 8
+
+#define FLAG_CAN_INVERT 0x0001
+#define FLAG_NEED_ARG 0x0002
+
+struct flag_type_table {
+ int cmd;
+ char *name;
+ int bits;
+ int mask;
+ int level;
+ int flags;
+} flag_type_tbl[] = {
+ CMD_FLAG, "spd_normal", 0, ASYNC_SPD_MASK, 2, 0,
+ CMD_FLAG, "spd_hi", ASYNC_SPD_HI, ASYNC_SPD_MASK, 0, 0,
+ CMD_FLAG, "spd_vhi", ASYNC_SPD_VHI, ASYNC_SPD_MASK, 0, 0,
+ CMD_FLAG, "spd_cust", ASYNC_SPD_CUST, ASYNC_SPD_MASK, 0, 0,
+
+ CMD_FLAG, "SAK", ASYNC_SAK, ASYNC_SAK, 0, FLAG_CAN_INVERT,
+ CMD_FLAG, "Fourport", ASYNC_FOURPORT, ASYNC_FOURPORT, 0, FLAG_CAN_INVERT,
+ CMD_FLAG, "hup_notify", ASYNC_HUP_NOTIFY, ASYNC_HUP_NOTIFY, 0, FLAG_CAN_INVERT,
+ CMD_FLAG, "skip_test", ASYNC_SKIP_TEST,ASYNC_SKIP_TEST,2, FLAG_CAN_INVERT,
+ CMD_FLAG, "auto_irq", ASYNC_AUTO_IRQ, ASYNC_AUTO_IRQ, 2, FLAG_CAN_INVERT,
+#ifdef ASYNC_SPLIT_TERMIOS
+ CMD_FLAG, "split_termios", ASYNC_SPLIT_TERMIOS, ASYNC_SPLIT_TERMIOS, 2, FLAG_CAN_INVERT,
+#endif
+ CMD_FLAG, "session_lockout", ASYNC_SESSION_LOCKOUT, ASYNC_SESSION_LOCKOUT, 2, FLAG_CAN_INVERT,
+ CMD_FLAG, "pgrp_lockout", ASYNC_PGRP_LOCKOUT, ASYNC_PGRP_LOCKOUT, 2, FLAG_CAN_INVERT,
+#ifdef ASYNC_CALLOUT_NOHUP
+ CMD_FLAG, "callout_nohup", ASYNC_CALLOUT_NOHUP, ASYNC_CALLOUT_NOHUP, 2, FLAG_CAN_INVERT,
+#endif
+
+ CMD_PORT, "port", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_IRQ, "irq", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_DIVISOR, "divisor", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_TYPE, "uart", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_BASE, "base", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_BASE, "baud_base", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_DELAY, "close_delay", 0, 0, 0, FLAG_NEED_ARG,
+ CMD_CONFIG, "autoconfig", 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+};
+
+char *serial_type(int id)
+{
+ int i;
+
+ for (i = 0; serial_type_tbl[i].id != -1; i++)
+ if (id == serial_type_tbl[i].id)
+ return serial_type_tbl[i].name;
+ return "undefined";
+}
+
+int uart_type(char *name)
+{
+ int i;
+
+ for (i = 0; serial_type_tbl[i].id != -1; i++)
+ if (!strcasecmp(name, serial_type_tbl[i].name))
+ return serial_type_tbl[i].id;
+ return -1;
+}
+
+
+int atonum(char *s)
+{
+ int n;
+
+ while (*s == ' ')
+ s++;
+ if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
+ sscanf(s + 2, "%x", &n);
+ else if (s[0] == '0' && s[1])
+ sscanf(s + 1, "%o", &n);
+ else
+ sscanf(s, "%d", &n);
+ return n;
+}
+
+void print_flags(struct serial_struct *serinfo,
+ char *prefix, char *postfix)
+{
+ struct flag_type_table *p;
+ int flags;
+ int first = 1;
+
+ flags = serinfo->flags;
+
+ for (p = flag_type_tbl; p->name; p++) {
+ if (p->cmd != CMD_FLAG)
+ continue;
+ if (verbosity < p->level)
+ continue;
+ if ((flags & p->mask) == p->bits) {
+ if (first) {
+ printf("%s", prefix);
+ first = 0;
+ } else
+ printf(" ");
+ printf("%s", p->name);
+ }
+ }
+
+ if (!first)
+ printf("%s", postfix);
+}
+
+void get_serial(char *device)
+{
+ struct serial_struct serinfo;
+ int fd;
+
+ if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
+ perror(device);
+ return;
+ }
+ if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) {
+ perror("Cannot get serial info");
+ close(fd);
+ return;
+ }
+ if (serinfo.irq == 9)
+ serinfo.irq = 2; /* People understand 2 better than 9 */
+ if (verbosity==2) {
+ printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n",
+ device, serinfo.line, serial_type(serinfo.type),
+ serinfo.port, serinfo.irq);
+ printf("\tBaud_base: %d, close_delay: %d, divisor: %d\n",
+ serinfo.baud_base, serinfo.close_delay,
+ serinfo.custom_divisor);
+ print_flags(&serinfo, "\tFlags: ", "");
+ printf("\n\n");
+ } else if (verbosity==0) {
+ if (serinfo.type) {
+ printf("%s at 0x%.4x (irq = %d) is a %s",
+ device, serinfo.port, serinfo.irq,
+ serial_type(serinfo.type));
+ print_flags(&serinfo, " (", ")");
+ printf("\n");
+ }
+ } else {
+ printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d",
+ device, serial_type(serinfo.type),
+ serinfo.port, serinfo.irq);
+ print_flags(&serinfo, ", Flags: ", "");
+ printf("\n");
+ }
+ close(fd);
+}
+
+void set_serial(char *device, char ** arg)
+{
+ struct serial_struct old_serinfo, new_serinfo;
+ struct flag_type_table *p;
+ int fd;
+ int do_invert = 0;
+ char *word;
+
+
+ if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
+ if (verbosity==0 && errno==ENOENT)
+ exit(201);
+ perror(device);
+ exit(201);
+ }
+ if (ioctl(fd, TIOCGSERIAL, &old_serinfo) < 0) {
+ perror("Cannot get serial info");
+ exit(1);
+ }
+ new_serinfo = old_serinfo;
+ while (*arg) {
+ do_invert = 0;
+ word = *arg++;
+ if (*word == '^') {
+ do_invert++;
+ word++;
+ }
+ for (p = flag_type_tbl; p->name; p++) {
+ if (!strcasecmp(p->name, word))
+ break;
+ }
+ if (!p->name) {
+ fprintf(stderr, "Invalid flag: %s\n", word);
+ exit(1);
+ }
+ if (do_invert && !(p->flags & FLAG_CAN_INVERT)) {
+ fprintf(stderr, "This flag can not be inverted: %s\n", word);
+ exit(1);
+ }
+ if ((p->flags & FLAG_NEED_ARG) && !*arg) {
+ fprintf(stderr, "Missing argument for %s\n", word);
+ exit(1);
+ }
+ switch (p->cmd) {
+ case CMD_FLAG:
+ new_serinfo.flags &= ~p->mask;
+ if (!do_invert)
+ new_serinfo.flags |= p->bits;
+ break;
+ case CMD_PORT:
+ new_serinfo.port = atonum(*arg++);
+ break;
+ case CMD_IRQ:
+ new_serinfo.irq = atonum(*arg++);
+ break;
+ case CMD_DIVISOR:
+ new_serinfo.custom_divisor = atonum(*arg++);
+ break;
+ case CMD_TYPE:
+ new_serinfo.type = uart_type(*arg++);
+ if (new_serinfo.type < 0) {
+ fprintf(stderr, "Illegal UART type: %s", *--arg);
+ exit(1);
+ }
+ break;
+ case CMD_BASE:
+ new_serinfo.baud_base = atonum(*arg++);
+ break;
+ case CMD_DELAY:
+ new_serinfo.close_delay = atonum(*arg++);
+ break;
+ case CMD_CONFIG:
+ if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
+ perror("Cannot set serial info");
+ exit(1);
+ }
+ if (ioctl(fd, TIOCSERCONFIG) < 0) {
+ perror("Cannot autoconfigure port");
+ exit(1);
+ }
+ if (ioctl(fd, TIOCGSERIAL, &new_serinfo) < 0) {
+ perror("Cannot get serial info");
+ exit(1);
+ }
+ break;
+ default:
+ fprintf(stderr, "Internal error: unhandled cmd #%d\n", p->cmd);
+ exit(1);
+ }
+ }
+ if (ioctl(fd, TIOCSSERIAL, &new_serinfo) < 0) {
+ perror("Cannot set serial info");
+ exit(1);
+ }
+ close(fd);
+ if (verbose_flag)
+ get_serial(device);
+}
+
+void do_wild_intr(char *device)
+{
+ int fd;
+ int i, mask;
+ int wild_mask = -1;
+
+ if ((fd = open(device, O_RDWR|O_NONBLOCK)) < 0) {
+ perror(device);
+ exit(1);
+ }
+ if (ioctl(fd, TIOCSERSWILD, &wild_mask) < 0) {
+ perror("Cannot scan for wild interrupts");
+ exit(1);
+ }
+ if (ioctl(fd, TIOCSERGWILD, &wild_mask) < 0) {
+ perror("Cannot get wild interrupt mask");
+ exit(1);
+ }
+ close(fd);
+ if (quiet_flag)
+ return;
+ if (wild_mask) {
+ printf("Wild interrupts found: ");
+ for (i=0, mask=1; mask <= wild_mask; i++, mask <<= 1)
+ if (mask & wild_mask)
+ printf(" %d", i);
+ printf("\n");
+ } else if (verbose_flag)
+ printf("No wild interrupts found.\n");
+ return;
+}
+
+
+
+
+void usage()
+{
+ fprintf(stderr, "setserial Version %s\n\n", VERSION_STR);
+ fprintf(stderr,
+ "usage: %s serial-device [cmd1 [arg]] ... \n\n", progname);
+ fprintf(stderr, "Available commands: (* = Takes an argument)\n");
+ fprintf(stderr, "\t\t(^ = can be preceded by a '^' to turn off the option)\n");
+fprintf(stderr, "\t* port\t\tset the I/O port\n");
+ fprintf(stderr, "\t* irq\t\tset the interrupt\n");
+ fprintf(stderr, "\t* uart\t\tset UART type (none, 8250, 16450, 16550, 16550A\n");
+ fprintf(stderr, "\t* baud_base\tset base baud rate (CLOCK_FREQ / 16)\n");
+ fprintf(stderr, "\t* divisor\tset the custom divisor (see spd_custom)\n");
+ fprintf(stderr, "\t* close_delay\tset the amount of time (in 1/100 of a\n");
+ fprintf(stderr, "\t\t\t\tsecond) that DTR should be kept low\n");
+ fprintf(stderr, "\t\t\t\twhile being closed\n");
+
+ fprintf(stderr, "\t^ fourport\tconfigure the port as an AST Fourport\n");
+ fprintf(stderr, "\t autoconfigure\tautomatically configure the serial port\n");
+ fprintf(stderr, "\t^ auto_irq\ttry to determine irq during autoconfiguration\n");
+ fprintf(stderr, "\t^ skip_test\tskip UART test during autoconfiguration\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\t^ sak\t\tset the break key as the Secure Attention Key\n");
+ fprintf(stderr, "\t^ session_lockout Lock out callout port across different sessions\n");
+ fprintf(stderr, "\t^ pgrp_lockout\tLock out callout port across different process groups\n");
+#ifdef ASYNC_CALLOUT_NOHUP
+ fprintf(stderr, "\t^ callout_nohup\tDon't hangup the tty when carrier detect drops\n");
+#endif
+ fprintf(stderr, "\t\t\t\t on the callout device\n");
+#ifdef ASYNC_SPLIT_TERMIOS
+ fprintf(stderr, "\t^ split_termios Use separate termios for callout and dailin lines\n");
+#endif
+ fprintf(stderr, "\t^ hup_notify\tNotify a process blocked on opening a dial in line\n");
+ fprintf(stderr, "\t\t\t\twhen a process has finished using a callout\n");
+ fprintf(stderr, "\t\t\t\tline by returning EAGAIN to the open.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "\t spd_hi\tuse 56kb instead of 38.4kb\n");
+ fprintf(stderr, "\t spd_vhi\tuse 115kb instead of 38.4kb\n");
+ fprintf(stderr, "\t spd_cust\tuse the custom divisor to set the speed at 38.4kb\n");
+ fprintf(stderr, "\t\t\t\t(baud rate = baud_base / custom_divisor)\n");
+ fprintf(stderr, "\t spd_normal\tuse 38.4kb when a buad rate of 38.4kb is selected\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Use a leading '0x' for hex numbers.\n");
+ fprintf(stderr, "CAUTION: Using an invalid port can lock up your machine!\n");
+ exit(1);
+}
+
+main(int argc, char **argv)
+{
+ int get_flag = 0, wild_intr_flag = 0;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ progname = argv[0];
+ if (argc == 1)
+ usage();
+ while ((c = getopt(argc, argv, "abgqvVW")) != EOF) {
+ switch (c) {
+ case 'a':
+ verbosity = 2;
+ break;
+ case 'b':
+ verbosity = 0;
+ break;
+ case 'q':
+ quiet_flag++;
+ break;
+ case 'v':
+ verbose_flag++;
+ break;
+ case 'g':
+ get_flag++;
+ break;
+ case 'V':
+ fprintf(stderr, "setserial version %s\n", VERSION_STR);
+ exit(0);
+ case 'W':
+ wild_intr_flag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (get_flag) {
+ argv += optind;
+ while (*argv)
+ get_serial(*argv++);
+ exit(0);
+ }
+ if (argc == optind)
+ usage();
+ if (wild_intr_flag) {
+ do_wild_intr(argv[optind]);
+ exit(0);
+ }
+ if (argc-optind == 1)
+ get_serial(argv[optind]);
+ else
+ set_serial(argv[optind], argv+optind+1);
+ exit(0);
+}
+
diff --git a/sys-utils/setsid.8 b/sys-utils/setsid.8
new file mode 100644
index 000000000..59ee0a20f
--- /dev/null
+++ b/sys-utils/setsid.8
@@ -0,0 +1,15 @@
+.\" Rick Sladkey <jrs@world.std.com>
+.\" In the public domain.
+.\" Path modifications by faith@cs.unc.edu
+.TH SETSID 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+setsid \- run a program in a new session
+.SH SYNOPSIS
+.BI setsid " program" " [ " "arg ..." " ]"
+.SH DESCRIPTION
+.B setsid
+runs a program in a new session.
+.SH "SEE ALSO"
+.BR setsid (2)
+.SH AUTHOR
+Rick Sladkey <jrs@world.std.com>
diff --git a/sys-utils/setsid.c b/sys-utils/setsid.c
new file mode 100644
index 000000000..10f1501d6
--- /dev/null
+++ b/sys-utils/setsid.c
@@ -0,0 +1,25 @@
+/*
+ * setsid.c -- execute a command in a new session
+ * Rick Sladkey <jrs@world.std.com>
+ * In the public domain.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s program [arg ...]\n",
+ argv[0]);
+ exit(1);
+ }
+ if (setsid() < 0) {
+ perror("setsid");
+ exit(1);
+ }
+ execvp(argv[1], argv + 1);
+ perror("execvp");
+ exit(1);
+}
diff --git a/sys-utils/sln.c b/sys-utils/sln.c
new file mode 100644
index 000000000..257b4342e
--- /dev/null
+++ b/sys-utils/sln.c
@@ -0,0 +1,72 @@
+/* `sln' program to create links between files.
+ Copyright (C) 1986, 1989, 1990, 1991, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Mike Parker and David MacKenzie. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if !defined(S_ISDIR) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ struct stat stats;
+
+ if (argc != 3) return 1;
+
+ /* Destination must not be a directory. */
+#if 0
+ if (stat (argv [2], &stats) == 0 && S_ISDIR (stats.st_mode))
+ {
+ return 1;
+ }
+#endif
+
+ if (lstat (argv [2], &stats) == 0)
+ {
+ if (S_ISDIR (stats.st_mode))
+ {
+ return 1;
+ }
+ else if (unlink (argv [2]) && errno != ENOENT)
+ {
+ return 1;
+ }
+ }
+ else if (errno != ENOENT)
+ {
+ return 1;
+ }
+
+#ifdef S_ISLNK
+ if (symlink (argv [1], argv [2]) == 0)
+#else
+ if (link (argv [1], argv [2]) == 0)
+#endif
+ {
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/sys-utils/swapdev.8 b/sys-utils/swapdev.8
new file mode 100644
index 000000000..901bd7591
--- /dev/null
+++ b/sys-utils/swapdev.8
@@ -0,0 +1 @@
+.so man8/rdev.8
diff --git a/sys-utils/sync.8 b/sys-utils/sync.8
new file mode 100644
index 000000000..f8bb704ff
--- /dev/null
+++ b/sys-utils/sync.8
@@ -0,0 +1,38 @@
+.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH SYNC 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+sync \- flush Linux filesystem buffers
+.SH SYNOPSIS
+.B sync
+.SH DESCRIPTION
+.B sync
+executes
+.BR sync (2),
+which flushes the filesystem buffers to disk.
+.B sync
+should be called before the processor is halted in an unusual manner (i.e.,
+before causing a kernel panic when debugging new kernel code). In general,
+the processor should be halted using the
+.BR reboot "(8), or " halt (8)
+commands, which will attempt to put the system in a quiescent state before
+calling
+.BR sync (2).
+
+From Linus: "Note that
+.B sync
+is only guaranteed to schedule the dirty blocks for writing: it can
+actually take a short time before all the blocks are finally written. If
+you are doing the
+.B sync
+with the expectation of killing the machine soon after, please take this
+into account and sleep for a few seconds. [The
+.BR reboot (8)
+command takes these precautions.]
+.SH "SEE ALSO"
+.BR sync (2),
+.BR update (8),
+.BR reboot (8),
+.BR halt (8)
+.SH AUTHOR
+Linus Torvalds (torvalds@cs.helsinki.fi)
diff --git a/sys-utils/sync.S b/sys-utils/sync.S
new file mode 100644
index 000000000..2fa8f5662
--- /dev/null
+++ b/sys-utils/sync.S
@@ -0,0 +1,21 @@
+/* File:
+ * sync.S
+ * Compile:
+ * /lib/cpp sync.S > sync.s
+ * as -o sync.o sync.s
+ * ld -s -N -e _main sync.o -o sync
+ * Author:
+ * Nick Holloway, with thanks to James Bonfield
+ * Last Changed:
+ * September 1993.
+ */
+# include <sys/syscall.h>
+
+ .text
+ .globl _main
+_main:
+ movl $(SYS_sync),%eax /* sync () */
+ int $0x80
+ movl $(SYS_exit),%eax /* exit ( 0 ) */
+ movl $0,%ebx
+ int $0x80
diff --git a/sys-utils/tunelp.8 b/sys-utils/tunelp.8
new file mode 100644
index 000000000..559118450
--- /dev/null
+++ b/sys-utils/tunelp.8
@@ -0,0 +1,84 @@
+.\" This file Copyright 1992 Michael K. Johnson (johnsonm@nigel.vnet.net)
+.\" It may be distributed under the GNU Public License, version 2, or
+.\" any higher version. See section COPYING of the GNU Public license
+.\" for conditions under which this file may be redistributed.
+.\" tunelp.8,v 1.1.1.1 1995/02/22 19:09:12 faith Exp
+.TH tunelp 8 "26 August 1992" "Cohesive Systems" "Linux Programmer's Manual"
+.SH NAME
+tunelp \- set various parameters for the lp device
+.SH SYNOPSIS
+\fBtunelp\fP \fI<device>\fP [-i \fI<IRQ>\fP | -t \fI<TIME>\fP | -c \fI<CHARS>\fP | -w \fI<WAIT>\fP | -a [on|off] | -o [on|off] | -C [on|off] | -r | -s | -q [on|off] ]
+.SH DESCRIPTION
+\fBtunelp\fP sets several parameters for the /dev/lp\fI?\fP devices, for better
+performance (or for any performance at all, if your printer won't work
+without it...) Without parameters, tells whether the device is using
+interrups, and if so, which one. With parameters, sets the device
+characteristics accordingly. The parameters are as follows:
+
+-i \fI<IRQ>\fP is the IRQ to use for the parallel port in question. If this
+is set to something non-zero, -t and -c have no effect. If your port
+does not use interrupts, this option will make printing stop.
+.B tunelp -i 0
+restores non-interrupt driven (polling) action, and your printer should
+work again. If your parallel port does support interrupts,
+interrupt-driven printing should be somewhat faster and efficient, and
+will probably be desireable.
+
+-t \fI<TIME>\fP is the amount of time in jiffies that the driver waits if the
+printer doesn't take a character for the number of tries dictated by
+the -c parameter. 10 is the default value. If you want fastest
+possible printing, and don't care about system load, you may set this
+to 0. If you don't care how fast your printer goes, or are printing
+text on a slow printer with a buffer, then 500 (5 seconds) should be
+fine, and will give you very low system load. This value generally
+should be lower for printing graphics than text, by a factor of
+approximately 10, for best performance.
+
+-c \fI<CHARS>\fP is the number of times to try to output a character to the
+printer before sleeping for -t \fI<TIME>\fP. It is the number of times around
+a loop that tries to send a character to the printer. 120 appears to
+be a good value for most printers. 250 is the default, because there
+are some printers that require a wait this long, but feel free to
+change this. If you have a very fast printer like an HP laserjet 4, a
+value of 10 might make more sense. If you have a \fIreally\fP old
+printer, you can increase this farther.
+
+Setting -t \fI<TIME>\fP to 0 is equivalent to setting -c \fI<CHARS>\fP
+to infinity.
+
+-w \fI<WAIT>\fP is the a busy loop counter for the strobe signal. While most
+printers appear to be able to deal with an extremely short strobe,
+some printers demand a longer one. Increasing this from the default
+0 may make it possible to print with those printers. This may also
+make it possible to use longer cables.
+
+-a [on|off] This is whether to abort on printer error -- the default
+is not to. If you are sitting at your computer, you probably want to
+be able to see an error and fix it, and have the printer go on
+printing. On the other hand, if you aren't, you might rather that
+your printer spooler find out that the printer isn't ready, quit
+trying, and send you mail about it. The choice is yours.
+
+-o [on|off] This option is much like -a. It makes any open() of this
+device check to see that the device is on-line and not reporting any
+out of paper or other errors. This is the correct setting for most
+versions of lpd.
+
+-C [on|off] This option adds extra ("careful") error checking. When
+this option is on, the printer driver will ensure that the printer is
+on-line and not reporting any out of paper or other errors before
+sending data. This is particularly useful for printers that normally
+appear to accept data when turned off.
+
+-s This option returns the current printer status, both as a
+decimal number from 0..255, and as a list of active flags. When
+this option is specified, -q off, turning off the display of the
+current IRQ, is implied.
+
+-o, -C, and -s all require a Linux kernel version of 1.1.76 or later.
+
+-r This option resets the port. It requires a Linux kernel version of
+1.1.80 or later.
+
+-q [on|off] This option sets printing the display of the current IRQ
+setting.
diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c
new file mode 100644
index 000000000..9005b172d
--- /dev/null
+++ b/sys-utils/tunelp.c
@@ -0,0 +1,248 @@
+/****************************************************************************\
+* Copyright (C) 1992 by Michael K. Johnson, johnsonm@nigel.vnet.net *
+* *
+* This file is placed under the conditions of the GNU public *
+* license, version 2, or any later version. See file COPYING *
+* for information on distribution conditions. *
+\****************************************************************************/
+
+/* tunelp.c,v 1.1.1.1 1995/02/22 19:09:12 faith Exp
+ * tunelp.c,v
+ * Revision 1.1.1.1 1995/02/22 19:09:12 faith
+ * Imported sources
+ *
+ * Revision 1.5 1995/01/13 10:33:43 johnsonm
+ * Chris's changes for new ioctl numbers and backwards compatibility
+ * and the reset ioctl.
+ *
+ * Revision 1.4 1995/01/03 17:42:14 johnsonm
+ * -s isn't supposed to take an argument; removed : after s in getopt...
+ *
+ * Revision 1.3 1995/01/03 07:36:49 johnsonm
+ * Fixed typo
+ *
+ * Revision 1.2 1995/01/03 07:33:44 johnsonm
+ * revisions for lp driver updates in Linux 1.1.76
+ *
+ *
+ */
+
+#include<unistd.h>
+#include<stdio.h>
+#include<fcntl.h>
+#include<linux/lp.h>
+#include<linux/fs.h>
+#include<sys/ioctl.h>
+#include<sys/stat.h>
+#include<sys/types.h>
+#include<malloc.h>
+#include<string.h>
+#include<errno.h>
+
+struct command {
+ long op;
+ long val;
+ struct command *next;
+};
+
+
+
+
+void print_usage(char *progname) {
+ printf("Usage: %s <device> [ -i <IRQ> | -t <TIME> | -c <CHARS> | -w <WAIT> | \n"
+ " -a [on|off] | -o [on|off] | -C [on|off] | -q [on|off] | -s ]\n", progname);
+ exit (1);
+}
+
+
+
+
+
+void *mylloc(long size) {
+ void *ptr;
+ if(!(ptr = (void*)malloc(size))) {
+ perror("malloc error");
+ exit(2);
+ }
+ return ptr;
+}
+
+
+
+long get_val(char *val) {
+ long ret;
+ if (!(sscanf(val, "%d", &ret) == 1)) {
+ perror("sscanf error");
+ exit(3);
+ }
+ return ret;
+}
+
+
+long get_onoff(char *val) {
+ if (!strncasecmp("on", val, 2))
+ return 1;
+ return 0;
+}
+
+
+
+int main (int argc, char ** argv) {
+ int c, fd, irq, status, show_irq, offset = 0, retval;
+ char *progname;
+ char *filename;
+ struct stat statbuf;
+ struct command *cmds, *cmdst;
+
+
+ progname = argv[0];
+ if (argc < 2) print_usage(progname);
+
+ filename = strdup(argv[1]);
+ fd = open(filename, O_WRONLY|O_NONBLOCK, 0);
+ /* Need to open O_NONBLOCK in case ABORTOPEN is already set and
+ printer is off or off-line or in an error condition. Otherwise
+ we would abort... */
+ if (fd < 0) {
+ perror(argv[1]);
+ return -1;
+ }
+
+ fstat(fd, &statbuf);
+
+ if((!S_ISCHR(statbuf.st_mode)) || (MAJOR(statbuf.st_rdev) != 6 )
+ || (MINOR(statbuf.st_rdev) > 3)) {
+ printf("%s: %s not an lp device.\n", argv[0], argv[1]);
+ print_usage(progname);
+ }
+
+ cmdst = cmds = mylloc(sizeof(struct command));
+ cmds->next = 0;
+
+ show_irq = 1;
+ while ((c = getopt(argc, argv, "t:c:w:a:i:ho:C:sq:r")) != EOF) {
+ switch (c) {
+ case 'h':
+ print_usage(progname);
+ break;
+ case 'i':
+ cmds->op = LPSETIRQ;
+ cmds->val = get_val(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 't':
+ cmds->op = LPTIME;
+ cmds->val = get_val(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 'c':
+ cmds->op = LPCHAR;
+ cmds->val = get_val(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 'w':
+ cmds->op = LPWAIT;
+ cmds->val = get_val(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 'a':
+ cmds->op = LPABORT;
+ cmds->val = get_onoff(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 'q':
+ if (get_onoff(optarg)) {
+ show_irq=1;
+ } else {
+ show_irq=0;
+ }
+#ifdef LPGETSTATUS
+ case 'o':
+ cmds->op = LPABORTOPEN;
+ cmds->val = get_onoff(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 'C':
+ cmds->op = LPCAREFUL;
+ cmds->val = get_onoff(optarg);
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+ case 's':
+ show_irq = 0;
+ cmds->op = LPGETSTATUS;
+ cmds->val = 0;
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+#endif
+#ifdef LPRESET
+ case 'r':
+ cmds->op = LPRESET;
+ cmds->val = 0;
+ cmds->next = mylloc(sizeof(struct command));
+ cmds = cmds->next; cmds->next = 0;
+ break;
+#endif
+ default: print_usage(progname);
+ }
+ }
+
+ /* Allow for binaries compiled under a new kernel to work on the old ones */
+ if (LPGETIRQ >= 0x0600 && ioctl(fd, LPGETIRQ) < 0 && errno == EINVAL)
+ offset = 0x0600; /* We don't understand the new ioctls */
+
+ cmds = cmdst;
+ while (cmds->next) {
+#ifdef LPGETSTATUS
+ if (cmds->op == LPGETSTATUS) {
+ status = 0xdeadbeef;
+ retval = ioctl(fd, LPGETSTATUS - offset, &status);
+ if (retval < 0)
+ perror("LPGETSTATUS error");
+ else {
+ if (status == 0xdeadbeef) /* a few 1.1.7x kernels will do this */
+ status = retval;
+ printf("%s status is %d", filename, status);
+ if (!(status & LP_PBUSY)) printf(", busy");
+ if (!(status & LP_PACK)) printf(", ready");
+ if ((status & LP_POUTPA)) printf(", out of paper");
+ if ((status & LP_PSELECD)) printf(", on-line");
+ if (!(status & LP_PERRORP)) printf(", error");
+ printf("\n");
+ }
+ } else
+#endif /* LPGETSTATUS */
+ if (ioctl(fd, cmds->op - offset, cmds->val) < 0) {
+ perror("tunelp: ioctl");
+ }
+ cmdst = cmds;
+ cmds = cmds->next;
+ free(cmdst);
+ }
+
+ if (show_irq) {
+ irq = 0xdeadbeef;
+ retval = ioctl(fd, LPGETIRQ - offset, &irq);
+ if (retval == -1) {
+ perror("LPGETIRQ error");
+ exit(4);
+ }
+ if (irq == 0xdeadbeef) /* up to 1.1.77 will do this */
+ irq = retval;
+ if (irq)
+ printf("%s using IRQ %d\n", filename, irq);
+ else
+ printf("%s using polling\n", filename);
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/sys-utils/update_state.8 b/sys-utils/update_state.8
new file mode 100644
index 000000000..1013843e6
--- /dev/null
+++ b/sys-utils/update_state.8
@@ -0,0 +1,35 @@
+.\" Copyright 1994 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.\" "
+.TH update_state 8 "8 July 1994" "Linux 1.0" "Linux Programmer's Manual"
+.SH NAME
+update_state \- update system state
+.SH SYNOPSIS
+.BR update_state
+.SH DESCRIPTION
+.B update_state
+updates a bunch of system state. It takes a long time to execute, and
+would be suitable for execution in a cron job.
+
+Currently,
+.B update_state
+performs the following functions: updates the locate database (in
+.IR /usr/lib/locate ), updates the whatis database (in
+.IR /usr/man ", " /usr/local/man ", " /usr/X386/man ", and "
+.IR /usr/interviews/man ),
+and updates the TeX ls-R cache file (in
+.IR /usr/lib/texmf ).
+.SH BUGS
+The script expects things to be where the FSSTND says they are.
+example, if you have
+.BR makewhatis (8)
+in
+.IR /usr/lib ,
+where it would be traditionally, then you lose, because it should be in
+.IR /usr/bin .
+.SH "SEE ALSO"
+.BR cron(8),
+.BR find(1),
+.BR locate(1),
+.SH AUTHOR
+Rik Faith (faith@cs.unc.edu)
diff --git a/sys-utils/update_state.sh b/sys-utils/update_state.sh
new file mode 100644
index 000000000..f318d08a1
--- /dev/null
+++ b/sys-utils/update_state.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+if test "`whoami`" != "root"; then
+ echo "This script must be executed by root"
+ exit 1
+fi
+
+if test -x /usr/lib/locate/updatedb; then
+ echo "WARNING: The /usr/lib/locate/find.codes file may violate the"
+ echo " privacy of your users. Please consider making it"
+ echo " readable only by root."
+ echo ""
+ echo "Updating locate database"
+
+ /usr/lib/locate/updatedb
+fi
+
+if test -d /usr/lib/texmf; then
+ echo "Building ls-R cache file for TeX"
+ /bin/ls -LR /usr/lib/texmf > /tmp/ls-R.$$
+ if test -f /usr/lib/texmf/ls-R; then
+ cp /usr/lib/texmf/ls-R /usr/lib/texmf/ls-R.old
+ fi
+ mv /tmp/ls-R.$$ /usr/lib/texmf/ls-R
+fi
+
+if test -x /usr/bin/makewhatis; then
+ for i in /usr/man /usr/local/man /usr/X386/man /usr/interviews/man; do
+ if test -d $i; then
+ echo "Building whatis database in $i"
+ /usr/bin/makewhatis $i
+ fi
+ done
+fi
+
+if test -x /usr/bin/mandb; then
+ echo "Updating manpage database"
+ /usr/bin/mandb
+fi
+
+exit 0
diff --git a/sys-utils/vidmode.8 b/sys-utils/vidmode.8
new file mode 100644
index 000000000..901bd7591
--- /dev/null
+++ b/sys-utils/vidmode.8
@@ -0,0 +1 @@
+.so man8/rdev.8