diff options
author | Karel Zak | 2006-12-07 00:25:32 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:32 +0100 |
commit | 6dbe3af945a63f025561abb83275cee9ff06c57b (patch) | |
tree | 19e59eac8ac465b5bc409b5adf815b582c92f633 /sys-utils | |
download | kernel-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')
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, ¬_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 |