summaryrefslogtreecommitdiffstats
path: root/sys-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:34 +0100
committerKarel Zak2006-12-07 00:25:34 +0100
commitfd6b7a7ffc50400704beb41d5a23af5f9edb1eed (patch)
tree997c0ca2abc018369babd7da59bcd0afe492068e /sys-utils
parentImported from util-linux-2.5 tarball. (diff)
downloadkernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.gz
kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.tar.xz
kernel-qcow2-util-linux-fd6b7a7ffc50400704beb41d5a23af5f9edb1eed.zip
Imported from util-linux-2.7.1 tarball.
Diffstat (limited to 'sys-utils')
-rw-r--r--sys-utils/Makefile40
-rw-r--r--sys-utils/README.MAKEDEV24
-rw-r--r--sys-utils/README.hwclock46
-rw-r--r--sys-utils/README.linux68k11
-rw-r--r--sys-utils/README.setserial73
-rw-r--r--sys-utils/README.shhopt-1.1155
-rw-r--r--sys-utils/arch.14
-rw-r--r--sys-utils/clock.8108
-rw-r--r--sys-utils/clock.c490
-rw-r--r--sys-utils/cytune.c4
-rw-r--r--sys-utils/dmesg.c25
-rw-r--r--sys-utils/hwclock.8246
-rw-r--r--sys-utils/hwclock.c1623
-rw-r--r--sys-utils/ipcrm.c1
-rw-r--r--sys-utils/ipcs.c56
-rw-r--r--sys-utils/kbdrate.c194
-rw-r--r--sys-utils/rdev.c10
-rw-r--r--sys-utils/readprofile.159
-rw-r--r--sys-utils/readprofile.c227
-rw-r--r--sys-utils/renice.85
-rw-r--r--sys-utils/renice.c5
-rw-r--r--sys-utils/setserial.8392
-rw-r--r--sys-utils/setserial.c436
-rw-r--r--sys-utils/shhopt-1.1.lsm17
-rw-r--r--sys-utils/shhopt.c467
-rw-r--r--sys-utils/shhopt.h33
-rw-r--r--sys-utils/sln.122
-rw-r--r--sys-utils/sync.838
-rw-r--r--sys-utils/sync.S24
-rw-r--r--sys-utils/tunelp.810
-rw-r--r--sys-utils/tunelp.c32
31 files changed, 3024 insertions, 1853 deletions
diff --git a/sys-utils/Makefile b/sys-utils/Makefile
index fc5afd4eb..9513717ee 100644
--- a/sys-utils/Makefile
+++ b/sys-utils/Makefile
@@ -1,7 +1,8 @@
# Makefile -- Makefile for util-linux Linux utilities
# Created: Sat Dec 26 20:09:40 1992
-# Revised: Sat Oct 7 19:24:39 1995 by r.faith@ieee.org
+# Revised: Mon Aug 19 20:12:33 1996 by faith@cs.unc.edu
# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu)
+# Copyright 1996 Nicolai Langfeldt (janl@math.uio.no)??
#
include ../MCONFIG
@@ -10,21 +11,37 @@ include ../MCONFIG
MAN1= arch.1 readprofile.1
-MAN8= chroot.8 clock.8 ctrlaltdel.8 cytune.8 dmesg.8 \
- ipcrm.8 ipcs.8 kbdrate.8 ramsize.8 rdev.8 renice.8 \
- rootflags.8 setserial.8 setsid.8 swapdev.8 sync.8 tunelp.8 \
- vidmode.8
+MAN8= chroot.8 ctrlaltdel.8 cytune.8 dmesg.8 \
+ ipcrm.8 ipcs.8 kbdrate.8 ramsize.8 renice.8 \
+ rootflags.8 setsid.8 swapdev.8 tunelp.8 \
+ vidmode.8
+
+ifneq "$(CPU)" "sparc"
+MAN8:= $(MAN8) hwclock.8
+endif
+
+ifeq "$(CPU)" "intel"
+MAN8:= $(MAN8) rdev.8
+endif
# Where to put binaries?
# See the "install" rule for the links. . .
-SBIN= clock ctrlaltdel kbdrate sln
+SBIN= sln ctrlaltdel kbdrate
+
+ifneq "$(CPU)" "sparc"
+SBIN:=$(SBIN) hwclock
+endif
-BIN= arch dmesg setserial sync
+BIN= arch dmesg
USRSBIN= chroot
-USRBIN= cytune ipcrm ipcs rdev renice readprofile setsid tunelp
+USRBIN= cytune ipcrm ipcs renice readprofile setsid tunelp
+
+ifeq "$(CPU)" "intel"
+USRBIN:=$(USRBIN) rdev
+endif
# Where to put datebase files?
@@ -35,14 +52,12 @@ all: $(SBIN) $(BIN) $(USRSBIN) $(USRBIN)
sln: sln.c
$(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@
-sync: sync.S
- $(CC) -nostdlib $(LDFLAGS) $< -o $@
-
# Rules for everything else
arch: arch.o
chroot: chroot.o
-clock: clock.o
+hwclock.o: hwclock.c shhopt.h
+hwclock: hwclock.o shhopt.o
ctrlaltdel: ctrlaltdel.o
ipcrm: ipcrm.o
ipcs: ipcs.o
@@ -50,7 +65,6 @@ kbdrate: kbdrate.o
rdev: rdev.o
renice: renice.o
readprofile: readprofile.o
-setserial: setserial.o
setsid: setsid.o
install: all
diff --git a/sys-utils/README.MAKEDEV b/sys-utils/README.MAKEDEV
deleted file mode 100644
index 02652b2b6..000000000
--- a/sys-utils/README.MAKEDEV
+++ /dev/null
@@ -1,24 +0,0 @@
-$Id: README.MAKEDEV,v 2.2 1995/06/04 16:32:02 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 go to many people. Ian Jackson for the original help and
-encouragement, to Matthias Urlichs for plugging "MAKEDEV update", and
-to the many others that have bought errors and omissions to my attention.
-
- Nick Holloway <Nick.Holloway@alfie.demon.co.uk>
diff --git a/sys-utils/README.hwclock b/sys-utils/README.hwclock
new file mode 100644
index 000000000..7d2f460dd
--- /dev/null
+++ b/sys-utils/README.hwclock
@@ -0,0 +1,46 @@
+Hwclock is a program that runs under Linux and sets and queries the
+Hardware Clock, which is often called the Real Time Clock, RTC, or
+CMOS clock.
+
+Hwclock is shipped with an ELF executable built for ISA (Intel)
+machines. So there is nothing to build for those machines. Just
+install the executable file "hwclock" and the man page file
+"hwclock.8" in suitable directories (like /sbin/hwclock and
+/usr/man/man8/hwclock.8) and you're ready to go.
+
+hwclock accesses platform-dependent hardware, so if you have something
+other than an ISA machine, the shipped executable probably doesn't work,
+and you have to compile hwclock yourself.
+
+Sometimes, you need to install hwclock setuid root. If you want users
+other than the superuser to be able to display the clock value using the
+direct ISA I/O method, install it setuid root. If you have the /dev/rtc
+interface on your system or are on a non-ISA system, there's no need for
+users to use the direct ISA I/O method, so don't bother.
+
+To install setuid root, do something like this:
+
+ chmod a=rx,u=s /sbin/hwclock
+
+In any case, hwclock will not allow you to set anything unless you have
+the superuser _real_ uid. (This is restriction is not necessary if you
+haven't installed setuid root, but it's there for now).
+
+You may want to preformat and/or compress the man page before installing.
+
+If you want to build hwclock, just cd to the source directory and invoke
+make with no parameters.
+
+hwclock calls option processing routines in the libsshopt library,
+which is part of Sverre H. Huseby's "shhopt" package. An ELF
+executable of this library is included in the package, but you can use
+a copy that is already on your system by altering the make file. You
+can find a more authoritative copy of this library, and its source
+code, on sunsite (ftp://sunsite.unc.edu/pub/Linux/libs/shhopt-X.Y).
+
+As shipped, the routines are linked in statically, so you only need the
+libsshopt.a file to build hwclock, not to run it.
+
+
+
+
diff --git a/sys-utils/README.linux68k b/sys-utils/README.linux68k
new file mode 100644
index 000000000..ae6367130
--- /dev/null
+++ b/sys-utils/README.linux68k
@@ -0,0 +1,11 @@
+
+Here are the ports of the clock and kbdrate utilities that needed
+/dev/port in their original implementation. /dev/port does not exist
+under Linux/68k, so the needed functionalities are implemented as new
+ioctls in the kernel. The modified sources (in src/) first test if the
+kernel knows that ioctls. If it does, they are used. Else, /dev/port
+is tried the old way. The kernel patch necessary for clock and kbdrate
+is in kernel-patch/. (It is #14a of my patch list to 0.9pl4).
+
+Roman (Roman.Hodek@informatik.uni-erlangen.de)
+
diff --git a/sys-utils/README.setserial b/sys-utils/README.setserial
deleted file mode 100644
index bf3a5847d..000000000
--- a/sys-utils/README.setserial
+++ /dev/null
@@ -1,73 +0,0 @@
-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/README.shhopt-1.1 b/sys-utils/README.shhopt-1.1
new file mode 100644
index 000000000..766d6cbdc
--- /dev/null
+++ b/sys-utils/README.shhopt-1.1
@@ -0,0 +1,155 @@
+shhopt - library for parsing command line options.
+==================================================
+
+This is a set of functions for parsing command line options. Both
+traditional one-character options, and GNU-style --long-options are
+supported.
+
+
+What separates this from traditional getopt?
+--------------------------------------------
+
+This library does more of the parsing for you. You set up a special
+structure describing the names and types of the options you want your
+program to support. In the structure you also give addresses of
+variables to update or functions to call for the various
+options. By calling optParseOptions, all options in argv are parsed
+and removed from argv. What is left, are the non-optional arguments to
+your program.
+
+The down-side of this, is that you won't be able to make a program
+where the position of the options between the non-options are
+significant.
+
+
+Usage
+-----
+
+To see how to use this library, take a look at the sample program
+example.c.
+
+A brief explanation:
+
+To parse your command line, you need to create and initialize an array
+of optStruct's. Each element in the array describes a long and short
+version of an option and specifies what type of option it is and how
+to handle it.
+
+The structure fields (see also shhopt.h):
+
+ `shortName' is the short option name without the leading '-'.
+
+ `longName' is the long option name without the leading "--".
+
+ `type' specifies what type of option this is. (Does it expect an
+ argument? Is it a flag? If it takes an argument,what type should
+ it be?)
+
+ `arg' is either a function to be called with the argument from
+ the commandline, or a pointer to a location in which to store
+ the value.
+
+ `flags' indicates whether `arg' points to a function or a storage
+ location.
+
+The different argument types:
+
+ `OPT_END' flags this as the last element in the options array.
+
+ `OPT_FLAG' indicates an option that takes no arguments. If `arg' is
+ not a function pointer, the value of `arg' will be set to 1 if
+ this flag is found on the command line.
+
+ `OPT_STRING' expects a string argument.
+
+ `OPT_INT' expects an int argument.
+
+ `OPT_UINT' expects an unsigned int argument.
+
+ `OPT_LONG' expects a long argument.
+
+ `OPT_ULONG' expects an unsigned long argument.
+
+The different flag types:
+
+ `OPT_CALLFUNC' indicates that `arg' is a function pointer. If this
+ is not given, `arg' is taken as a pointer to a variable.
+
+
+Notes
+-----
+
+* A dash (`-') by itself is not taken as any kind of an option, as
+ several programs use this to indicate the special files stdin and
+ stdout. It is thus left as a normal argument to the program.
+
+* Two dashes (`--') as an argument, is taken to mean that the rest of
+ the arguments should not be scanned for options. This simplifies
+ giving names of files that start with a dash.
+
+* Short (one-character) options accept parameters in two ways, either
+ directly following the option in the same argv-entry, or in the next
+ argv-entry:
+
+ -sPARAMETER
+ -s PARAMETER
+
+* Long options accept parameters in two ways:
+
+ --long-option=PARAMETER
+ --long-option PARAMETER
+
+ To follow the GNU-tradition, your program documentation should use
+ the first form.
+
+* Several one-character options may be combined after a single
+ dash. If any of the options requires a parameter, the rest of the
+ string is taken as this parameter. If there is no "rest of the
+ string", the next argument is taken as the parameter.
+
+* There is no support for floating point (double) arguments to
+ options. This is to avoid unnecessary linking with the math
+ library. See example.c for how to get around this by writing a
+ function converting a string argument to a double.
+
+
+Portability
+-----------
+
+If your libc lacks strtoul, you will need to link with GNU's -liberty,
+that may be found by anonymous ftp to prep.ai.mit.edu:/pub/gnu
+
+The library has (more or less recently) been compiled and `tested' on
+the following systems:
+
+ IRIX Release 5.3 IP22
+ Linux 1.2.9
+ SunOS Release 4.1.3_U1 (-liberty needed)
+ ULTRIX V4.4 (Rev. 69)
+
+All compilations were done using GNU's gcc, and GNU's make.
+
+
+Author
+------
+
+The program is written by
+
+ Sverre H. Huseby
+ Maridalsvn. 122, leil. 101
+ N-0461 Oslo
+ Norway
+
+ sverrehu@ifi.uio.no
+ http://www.ifi.uio.no/~sverrehu/
+
+You can use and copy this for free. If you decide to use it, please do
+me three small favours:
+
+ 1. Tell me! (E-mail, postcard, letter, whatever. If you wish
+ to give me something, please send a bottle of your
+ favourite beer (making this BeerWare))
+ 2. Let your friends and favourite download site have a copy!
+ (with all files intact, please..)
+ 3. Report any bugs you find!
+
diff --git a/sys-utils/arch.1 b/sys-utils/arch.1
index c465c55fe..a2830ed3c 100644
--- a/sys-utils/arch.1
+++ b/sys-utils/arch.1
@@ -1,7 +1,7 @@
.\" 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"
+.TH ARCH 1 "4 July 1997" "Linux 2.0" "Linux Programmer's Manual"
.SH NAME
arch \- print machine architecture
.SH SYNOPSIS
@@ -13,6 +13,6 @@ is equivalent to
On current Linux systems,
.B arch
-prints "i386" or "i486".
+prints things such as "i386" or "i486".
.SH SEE ALSO
.BR uname (1) ", " uname (2)
diff --git a/sys-utils/clock.8 b/sys-utils/clock.8
deleted file mode 100644
index 1f6139ae4..000000000
--- a/sys-utils/clock.8
+++ /dev/null
@@ -1,108 +0,0 @@
-.\" 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 "/sbin/clock [ -u ] -r"
-.br
-.B "/sbin/clock [ -u ] -w"
-.br
-.B "/sbin/clock [ -u ] -s"
-.br
-.B "/sbin/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
deleted file mode 100644
index 15020c260..000000000
--- a/sys-utils/clock.c
+++ /dev/null
@@ -1,490 +0,0 @@
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <time.h>
-#include <sys/time.h>
-#include <string.h>
-
-#define USE_INLINE_ASM_IO
-
-#ifdef USE_INLINE_ASM_IO
-#include <asm/io.h>
-#endif
-
-/* V1.0
- * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992
- *
- * clock [-u] -r - read cmos clock
- * clock [-u] -w - write cmos clock from system time
- * clock [-u] -s - set system time from cmos clock
- * clock [-u] -a - set system time from cmos clock, adjust the time to
- * correct for systematic error, and put it back to the cmos.
- * -u indicates cmos clock is kept in universal time
- *
- * The program is designed to run setuid, since we need to be able to
- * write the CMOS port.
- *
- * I don't know what the CMOS clock will do in 2000, so this program
- * probably won't work past the century boundary.
- *
- *********************
- * V1.1
- * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992
- * Also moved error messages to stderr. The program now uses getopt.
- * Changed some exit codes. Made 'gcc 2.3 -Wall' happy.
- *
- * I think a small explanation of the adjustment routine should be given
- * here. The problem with my machine is that its CMOS clock is 10 seconds
- * per day slow. With this version of clock.c, and my '/etc/rc.local'
- * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error
- * is automatically corrected at every boot.
- *
- * To do this job, the program reads and writes the file '/etc/adjtime'
- * to determine the correction, and to save its data. In this file are
- * three numbers:
- *
- * 1) the correction in seconds per day (So if your clock runs 5
- * seconds per day fast, the first number should read -5.0)
- * 2) the number of seconds since 1/1/1970 the last time the program was
- * used.
- * 3) the remaining part of a second which was leftover after the last
- * adjustment
- *
- * Installation and use of this program:
- *
- * a) create a file '/etc/adjtime' containing as the first and only line:
- * '0.0 0 0.0'
- * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in
- * universal or local time. This updates the second number.
- * c) set your system time using the 'date' command.
- * d) update your cmos time using 'clock -wu' or 'clock -w'
- * e) replace the first number in /etc/adjtime by your correction.
- * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local'
- *
- * If the adjustment doesn't work for you, try contacting me by E-mail.
- *
- ******
- * V1.2
- *
- * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de)
- * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE)
- *
- * A free quote from a MAIL-message (with spelling corrections):
- *
- * "I found the explanation and solution for the CMOS reading 0xff problem
- * in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount
- * of time for updating. Solution is included in the kernel source
- * (linux/kernel/time.c)."
- *
- * "I modified clock.c to fix this problem and added an option (now default,
- * look for USE_INLINE_ASM_IO) that I/O instructions are used as inline
- * code and not via /dev/port (still possible via #undef ...)."
- *
- * With the new code, which is partially taken from the kernel sources,
- * the CMOS clock handling looks much more "official".
- * Thanks Harald (and Torsten for the kernel code)!
- *
- ******
- * V1.3
- * Canges from alan@spri.levels.unisa.edu.au (Alan Modra):
- * a) Fix a few typos in comments and remove reference to making
- * clock -u a cron job. The kernel adjusts cmos time every 11
- * minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss().
- * This means we should really have a cron job updating
- * /etc/adjtime every 11 mins (set last_time to the current time
- * and not_adjusted to ???).
- * b) Swapped arguments of outb() to agree with asm/io.h macro of the
- * same name. Use outb() from asm/io.h as it's slightly better.
- * c) Changed CMOS_READ and CMOS_WRITE to inline functions. Inserted
- * cli()..sti() pairs in appropriate places to prevent possible
- * errors, and changed ioperm() call to iopl() to allow cli.
- * d) Moved some variables around to localise them a bit.
- * e) Fixed bug with clock -ua or clock -us that cleared environment
- * variable TZ. This fix also cured the annoying display of bogus
- * day of week on a number of machines. (Use mktime(), ctime()
- * rather than asctime() )
- * f) Use settimeofday() rather than stime(). This one is important
- * as it sets the kernel's timezone offset, which is returned by
- * gettimeofday(), and used for display of MSDOS and OS2 file
- * times.
- * g) faith@cs.unc.edu added -D flag for debugging
- *
- * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra)
- * Wed Feb 8 12:29:08 1995, fix for years > 2000.
- * faith@cs.unc.edu added -v option to print version.
- *
- */
-
-#define VERSION "1.4"
-
-/* Here the information for time adjustments is kept. */
-#define ADJPATH "/etc/adjtime"
-
-
-/* used for debugging the code. */
-/*#define KEEP_OFF */
-
-/* Globals */
-int readit = 0;
-int adjustit = 0;
-int writeit = 0;
-int setit = 0;
-int universal = 0;
-int debug = 0;
-
-volatile void
-usage ()
-{
- fprintf (stderr,
- "clock [-u] -r|w|s|a|v\n"
- " r: read and print CMOS clock\n"
- " w: write CMOS clock from system time\n"
- " s: set system time from CMOS clock\n"
- " a: get system time and adjust CMOS clock\n"
- " u: CMOS clock is in universal time\n"
- " v: print version (" VERSION ") and exit\n"
- );
- exit (1);
-}
-
-#ifndef USE_INLINE_ASM_IO
-int cmos_fd;
-#endif
-
-static inline unsigned char cmos_read(unsigned char reg)
-{
- register unsigned char ret;
- __asm__ volatile ("cli");
- outb (reg | 0x80, 0x70);
- ret = inb (0x71);
- __asm__ volatile ("sti");
- return ret;
-}
-
-static inline void cmos_write(unsigned char reg, unsigned char val)
-{
- outb (reg | 0x80, 0x70);
- outb (val, 0x71);
-}
-
-#ifndef outb
-static inline void
-outb (char val, unsigned short port)
-{
-#ifdef USE_INLINE_ASM_IO
- __asm__ volatile ("out%B0 %0,%1"::"a" (val), "d" (port));
-#else
- lseek (cmos_fd, port, 0);
- write (cmos_fd, &val, 1);
-#endif
-}
-#endif
-
-#ifndef inb
-static inline unsigned char
-inb (unsigned short port)
-{
- unsigned char ret;
-#ifdef USE_INLINE_ASM_IO
- __asm__ volatile ("in%B0 %1,%0":"=a" (ret):"d" (port));
-#else
- lseek (cmos_fd, port, 0);
- read (cmos_fd, &ret, 1);
-#endif
- return ret;
-}
-#endif
-
-void
-cmos_init ()
-{
-#ifdef USE_INLINE_ASM_IO
- if (iopl (3))
- {
- fprintf(stderr,"clock: unable to get I/O port access\n");
- exit (1);
- }
-#else
- cmos_fd = open ("/dev/port", 2);
- if (cmos_fd < 0)
- {
- perror ("unable to open /dev/port read/write : ");
- exit (1);
- }
- if (lseek (cmos_fd, 0x70, 0) < 0 || lseek (cmos_fd, 0x71, 0) < 0)
- {
- perror ("unable to seek port 0x70 in /dev/port : ");
- exit (1);
- }
-#endif
-}
-
-static inline int
-cmos_read_bcd (int addr)
-{
- int b;
- b = cmos_read (addr);
- return (b & 15) + (b >> 4) * 10;
-}
-
-static inline void
-cmos_write_bcd (int addr, int value)
-{
- cmos_write (addr, ((value / 10) << 4) + value % 10);
-}
-
-int
-main (int argc, char **argv, char **envp)
-{
- struct tm tm;
- time_t systime;
- time_t last_time;
- char arg;
- double factor;
- double not_adjusted;
- int adjustment = 0;
- unsigned char save_control, save_freq_select;
-
- while ((arg = getopt (argc, argv, "rwsuaDv")) != -1)
- {
- switch (arg)
- {
- case 'r':
- readit = 1;
- break;
- case 'w':
- writeit = 1;
- break;
- case 's':
- setit = 1;
- break;
- case 'u':
- universal = 1;
- break;
- case 'a':
- adjustit = 1;
- break;
- case 'D':
- debug = 1;
- break;
- case 'v':
- fprintf( stderr, "clock " VERSION "\n" );
- exit(0);
- default:
- usage ();
- }
- }
-
- if (readit + writeit + setit + adjustit > 1)
- usage (); /* only allow one of these */
-
- if (!(readit | writeit | setit | adjustit)) /* default to read */
- readit = 1;
-
- cmos_init ();
-
- if (adjustit)
- { /* Read adjustment parameters first */
- FILE *adj;
- if ((adj = fopen (ADJPATH, "r")) == NULL)
- {
- perror (ADJPATH);
- exit (2);
- }
- if (fscanf (adj, "%lf %d %lf", &factor, &last_time, &not_adjusted) < 0)
- {
- perror (ADJPATH);
- exit (2);
- }
- fclose (adj);
- if (debug) printf ("Last adjustment done at %d seconds after 1/1/1970\n", last_time);
- }
-
- if (readit || setit || adjustit)
- {
- int i;
-
-/* read RTC exactly on falling edge of update flag */
-/* Wait for rise.... (may take upto 1 second) */
-
- for (i = 0; i < 10000000; i++)
- if (cmos_read (10) & 0x80)
- break;
-
-/* Wait for fall.... (must try at least 2.228 ms) */
-
- for (i = 0; i < 1000000; i++)
- if (!(cmos_read (10) & 0x80))
- break;
-
-/* The purpose of the "do" loop is called "low-risk programming" */
-/* In theory it should never run more than once */
- do
- {
- tm.tm_sec = cmos_read_bcd (0);
- tm.tm_min = cmos_read_bcd (2);
- tm.tm_hour = cmos_read_bcd (4);
- tm.tm_wday = cmos_read_bcd (6);
- tm.tm_mday = cmos_read_bcd (7);
- tm.tm_mon = cmos_read_bcd (8);
- tm.tm_year = cmos_read_bcd (9);
- }
- while (tm.tm_sec != cmos_read_bcd (0));
- if (tm.tm_year < 70)
- tm.tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */
- tm.tm_mon--; /* DOS uses 1 base */
- tm.tm_wday -= 3; /* DOS uses 3 - 9 for week days */
- tm.tm_isdst = -1; /* don't know whether it's daylight */
- if (debug) printf ("Cmos time : %d:%d:%d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);
- }
-
- if (readit || setit || adjustit)
- {
-/*
- * mktime() assumes we're giving it local time. If the CMOS clock
- * is in GMT, we have to set up TZ so mktime knows it. tzset() gets
- * called implicitly by the time code, but only the first time. When
- * changing the environment variable, better call tzset() explicitly.
- */
- if (universal)
- {
- char *zone;
- zone = (char *) getenv ("TZ"); /* save original time zone */
- (void) putenv ("TZ=");
- tzset ();
- systime = mktime (&tm);
- /* now put back the original zone */
- if (zone)
- {
-
- char *zonebuf;
- zonebuf = malloc (strlen (zone) + 4);
- strcpy (zonebuf, "TZ=");
- strcpy (zonebuf+3, zone);
- putenv (zonebuf);
- free (zonebuf);
- }
- else
- { /* wasn't one, so clear it */
- putenv ("TZ");
- }
- tzset ();
- }
- else
- {
- systime = mktime (&tm);
- }
- if (debug) printf ("Number of seconds since 1/1/1970 is %d\n", systime);
- }
-
- if (readit)
- {
- printf ("%s", ctime (&systime ));
- }
-
- if (setit || adjustit)
- {
- struct timeval tv;
- struct timezone tz;
-
-/* program is designed to run setuid, be secure! */
-
- if (getuid () != 0)
- {
- fprintf (stderr, "Sorry, must be root to set or adjust time\n");
- exit (2);
- }
-
- if (adjustit)
- { /* the actual adjustment */
- double exact_adjustment;
-
- exact_adjustment = ((double) (systime - last_time))
- * factor / (24 * 60 * 60)
- + not_adjusted;
- if (exact_adjustment > 0)
- adjustment = (int) (exact_adjustment + 0.5);
- else
- adjustment = (int) (exact_adjustment - 0.5);
- not_adjusted = exact_adjustment - (double) adjustment;
- systime += adjustment;
- if (debug) {
- printf ("Time since last adjustment is %d seconds\n",
- (int) (systime - last_time));
- printf ("Adjusting time by %d seconds\n",
- adjustment);
- printf ("remaining adjustment is %.3f seconds\n",
- not_adjusted);
- }
- }
-#ifndef KEEP_OFF
- tv.tv_sec = systime;
- tv.tv_usec = 0;
- tz.tz_minuteswest = timezone / 60;
- tz.tz_dsttime = daylight;
-
- if (settimeofday (&tv, &tz) != 0)
- {
- fprintf (stderr,
- "Unable to set time -- probably you are not root\n");
- exit (1);
- }
-
- if (debug) {
- printf( "Called settimeofday:\n" );
- printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n",
- tv.tv_sec, tv.tv_usec );
- printf( "\ttz.tz_minuteswest = %d, tz.tz_dsttime = %d\n",
- tz.tz_minuteswest, tz.tz_dsttime );
- }
-#endif
- }
-
- if (writeit || (adjustit && adjustment != 0))
- {
- struct tm *tmp;
- systime = time (NULL);
- if (universal)
- tmp = gmtime (&systime);
- else
- tmp = localtime (&systime);
-
-#ifndef KEEP_OFF
- __asm__ volatile ("cli");
- save_control = cmos_read (11); /* tell the clock it's being set */
- cmos_write (11, (save_control | 0x80));
- save_freq_select = cmos_read (10); /* stop and reset prescaler */
- cmos_write (10, (save_freq_select | 0x70));
-
- cmos_write_bcd (0, tmp->tm_sec);
- cmos_write_bcd (2, tmp->tm_min);
- cmos_write_bcd (4, tmp->tm_hour);
- cmos_write_bcd (6, tmp->tm_wday + 3);
- cmos_write_bcd (7, tmp->tm_mday);
- cmos_write_bcd (8, tmp->tm_mon + 1);
- cmos_write_bcd (9, tmp->tm_year);
-
- cmos_write (10, save_freq_select);
- cmos_write (11, save_control);
- __asm__ volatile ("sti");
-#endif
- if (debug) printf ("Set to : %d:%d:%d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- }
- else
- if (debug) printf ("CMOS clock unchanged.\n");
- /* Save data for next 'adjustit' call */
- if (adjustit)
- {
- FILE *adj;
- if ((adj = fopen (ADJPATH, "w")) == NULL)
- {
- perror (ADJPATH);
- exit (2);
- }
- fprintf (adj, "%f %d %f\n", factor, systime, not_adjusted);
- fclose (adj);
- }
- exit (0);
-}
diff --git a/sys-utils/cytune.c b/sys-utils/cytune.c
index 32a27006b..f7fe1ee38 100644
--- a/sys-utils/cytune.c
+++ b/sys-utils/cytune.c
@@ -35,11 +35,11 @@
#include <stdio.h>
#include <stdlib.h>
-#include <sys/serial.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
+#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/tty.h>
@@ -151,7 +151,7 @@ static int set_def_time_val = -1;
int main(int argc, char *argv[]) {
struct timeval lasttime, thistime;
- struct timezone tz = {0,DST_NONE};
+ struct timezone tz = {0,0};
double diff;
int errflg = 0;
int file;
diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c
index 880528531..56beb3fea 100644
--- a/sys-utils/dmesg.c
+++ b/sys-utils/dmesg.c
@@ -9,13 +9,24 @@
#include <linux/unistd.h>
#include <stdio.h>
#include <getopt.h>
+#include <stdlib.h>
-#define __NR_klog __NR_syslog
+#if __GNU_LIBRARY__ < 5
-static inline _syscall3(int,klog,int,type,char *,b,int,len)
+#ifndef __alpha__
+# define __NR_klogctl __NR_syslog
+ static inline _syscall3(int, klogctl, int, type, char *, b, int, len);
+#else /* __alpha__ */
+#define klogctl syslog
+#endif
+
+#else
+# include <sys/klog.h>
+#endif
static char *progname;
+void
usage()
{
fprintf( stderr, "Usage: %s [-c] [-n level]\n", progname );
@@ -27,7 +38,7 @@ int main( int argc, char *argv[] )
int i;
int n;
int c;
- int level;
+ int level = 0;
int lastc;
int cmd = 3;
@@ -56,17 +67,17 @@ int main( int argc, char *argv[] )
}
if (cmd == 8) {
- n = klog( cmd, NULL, level );
+ n = klogctl( cmd, NULL, level );
if (n < 0) {
- perror( "klog" );
+ perror( "klogctl" );
exit( 1 );
}
exit( 0 );
}
- n = klog( cmd, buf, sizeof( buf ) );
+ n = klogctl( cmd, buf, sizeof( buf ) );
if (n < 0) {
- perror( "klog" );
+ perror( "klogctl" );
exit( 1 );
}
diff --git a/sys-utils/hwclock.8 b/sys-utils/hwclock.8
new file mode 100644
index 000000000..a7308a600
--- /dev/null
+++ b/sys-utils/hwclock.8
@@ -0,0 +1,246 @@
+.TH CLOCK 8 "23 September 1996"
+.SH NAME
+clock \- query and set the ISA hardware clock (RTC)
+.SH SYNOPSIS
+.B "hwclock --show [ --utc ] [ --test ] [ --debug ]"
+.br
+.B "hwclock --set --date=newdate [ --utc ] [ --test ] [ --debug ]"
+.br
+.B "hwclock --systohc [ --utc ] [ --test ] [ --debug ]"
+.br
+.B "hwclock --hctosys [ --utc ] [ --test ] [ --debug ]"
+.br
+.B "hwclock --adjust [ --utc ] [ --test ] [ --debug ]"
+.br
+.B "hwclock --version [ --debug ]
+.PP
+Minimum unique abbreviations of all options are acceptable.
+.PP
+Also, equivalent options -r, -w, -s, -a, -v, -u, and -D are accepted for
+compatibility with the program "clock".
+
+.SH DESCRIPTION
+.I hwclock
+is a tool for accessing the Hardware Clock. You can display the
+current time, set the Hardware Clock to a specified time, set the
+Hardware Clock to the System Time, and set the System Time from the
+Hardware Clock.
+.PP
+You can also run
+.I hwclock
+periodically to insert or remove time from the Hardware Clock to
+compensate for systematic drift (where the clock consistently gains or
+loses time at a certain rate if left to run).
+
+.SH OPTIONS
+You need exactly one of the following options to tell
+.I hwclock
+what function to perform:
+.PP
+.TP
+.B \-\-show
+Read the Hardware Clock and print the time on Standard Output.
+.TP
+.B \-\-set
+Set the Hardware Clock to the time given by the
+.B \-\-date
+option.
+.TP
+.B \-\-hctosys
+Set the System Time from the Hardware Clock. This is a good option to use
+in one of the system startup scripts.
+.TP
+.B \-\-systohc
+Set the Hardware Clock to the current System Time.
+.TP
+.B \-\-adjust
+Add or subtract time from the Hardware Clock to account for systematic
+drift since the last time the clock was set or adjusted. See discussion
+below.
+.TP
+.B \-\-version
+Print the version of
+.I hwclock
+on Standard Output.
+.br
+You need the following option if you specify
+.B \-\-set
+option. Otherwise, it is ignored.
+.TP
+.B \-\-date=date_string
+Specifies the time to which to set the Hardware Clock. The value of this
+option is an argument to the
+.I date(1)
+program. For example,
+.sp
+.I hwclock --set --date="9/22/96 16:45:05"
+.PP
+The following options apply to most functions.
+.TP
+.B \-\-utc
+Indicates that the Hardware Clock is kept in Universal Coordinated
+Time. It is your choice whether to keep your clock in UTC or local
+time, but nothing in the clock tells which you've chosen. So this
+option is how you give that information to
+.I hwclock.
+.PP
+If you don't specify
+.B --utc
+when you should, or vice versa, both setting and querying of the
+Hardware Clock will be messed up.
+.TP
+.B \-\-test
+Do everything except actually updating the Hardware Clock. This is
+useful, especially in conjunction with
+.B \-\-debug,
+in learning about
+.I hwclock.
+.TP
+.B \-\-debug
+Display a lot of information about what
+.I hwclock
+is doing internally. Some of its function is complex and this output
+can help you understand how the program works.
+
+
+.SH NOTES
+
+
+.SH Clocks in a Linux System
+.PP
+There are two main clocks in a Linux system:
+.PP
+.B The Hardware Clock:
+This is a clock that runs independently of any control program running
+in the CPU and even when the machine is powered off. It is specified
+as part of the ISA standard. The control program can read or set this
+clock to a whole second, but the control program can also detect the
+edges of the 1 second clock ticks, so the clock actually has virtually
+infinite precision.
+.PP
+This clock is commonly called the hardware clock, the real time clock,
+the RTC, the BIOS clock, and the CMOS clock. Hardware Clock, in its
+capitalized form, was coined for use by
+.I hwclock
+because all of the other names are inappropriate to the point of being
+misleading.
+.PP
+.B The System Time:
+This is the time kept by a clock inside the Linux kernel and driven by
+the ISA timer interrupt. It has meaning only while Linux is running
+on the machine. The System Time is the number of seconds since
+00:00:00 January 1, 1970 UTC (or more succinctly, the number of
+seconds since 1969). The System Time is not an integer, though. It
+has virtually infinite precision.
+.PP
+The System Time is the time that matters. The Hardware Clock's basic
+purpose in a Linux system is to keep time when Linux is not running. You
+initialize the System Time to the time from the Hardware Clock when Linux
+starts up, and then never use the Hardware Clock again. Note that in DOS,
+for which ISA was designed, the Hardware Clock is the only real time clock.
+.PP
+It is important that the System Time not have any discontinuities such as
+would happen if you used the
+.I date(1L)
+program to set it while the system is running. You can, however, do whatever
+you want to the Hardware Clock while the system is running, and the next
+time Linux starts up, it will do so with the adjusted time from the Hardware
+Clock. You can also use the program
+.I adjtimex(8)
+to smoothly adjust the System Time while the system runs.
+
+
+.SH The Adjust Function
+.PP
+The Hardware Clock is usually not very accurate. However, much of its
+inaccuracy is completely predictable -- it gains or loses the same amount
+of time every day. This is called systematic drift.
+.I Hwclock's
+"adjust" function lets you make systematic corrections to correct the
+systematic drift.
+.PP
+It works like this:
+.I Hwclock
+keeps a file,
+.I /etc/adjtime,
+that keeps some historical information. This is called the adjtime file.
+.PP
+Suppose you start with no adjtime file. You issue a
+.I hwclock --set
+command to set the Hardware Clock to the true current time.
+.I Hwclock
+creates the adjtime file and records in it the current time as the
+last time the clock was calibrated.
+5 days
+later, the clock has gained 10 seconds, so you issue another
+.I hwclock --set
+command to set it back 10 seconds.
+.I Hwclock
+updates the adjtime file to show the current time as the last time the
+clock was calibrated, and records 2 seconds per day as the systematic
+drift rate. 24 hours go by, and then you issue a
+.I hwclock --adjust
+command.
+.I Hwclock
+consults the adjtime file and sees that the clock gains 2 seconds per
+day when left alone and that it has been left alone for exactly one
+day. So it subtracts 2 seconds from the Hardware Clock. It then
+records the current time as the last time the clock was adjusted.
+Another 24 hours goes by and you issue another
+.I hwclock --adjust.
+.I Hwclock
+does the same thing: subtracts 2 seconds and updates the adjtime file
+with the current time as the last time the clock was adjusted.
+.PP
+Every time you calibrate (set) the clock,
+.I hwclock
+recalculates the systematic drift rate based on how long it has been
+since the last calibration, how long it has been since the last
+adjustment, what drift rate was assumed in any intervening
+adjustments, and the amount by which the clock is presently off.
+.PP
+A small amount of error creeps in any time
+.I hwclock
+sets the clock, so it refrains from making an adjustment that would be
+less than 1 second. Later on, when you request an adjustment again,
+the accumulated drift will be more than a second and
+.I hwclock
+will do the adjustment then.
+.PP
+It is good to do a
+.I hwclock --adjust
+just before the
+.I hwclock --set
+at system startup time, and maybe periodically while the system is
+running via cron.
+.PP
+The format of the adjtime file is:
+.PP
+Line 1: 3 numbers: 1) systematic drift rate in seconds per day,
+floating point decimal; 2) Resulting number of seconds since 1969 UTC
+of most recent adjustment or calibration, decimal integer; 3) zero
+(for compatibility with
+.I clock
+).
+.PP
+Line 2: 1 number: Resulting number of seconds since 1969 UTC of most
+recent calibration.
+.PP
+You can use an adjtime file that was previously used with the
+.I clock
+program with
+.I hwclock.
+
+.SH FILES
+.I /etc/adjtime
+
+.SH SEE ALSO
+adjtimex(8), date(1), gettimeofday(2), settimeofday(2), crontab(1)
+
+.SH AUTHORS
+Written By Bryan Henderson, September 1996, based on work done on the
+.I clock
+program by Charles Hedrick, Rob Hooft, and Harald Koenig. See the source
+code for complete history and credits.
+
+
diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c
new file mode 100644
index 000000000..9f4d77149
--- /dev/null
+++ b/sys-utils/hwclock.c
@@ -0,0 +1,1623 @@
+/**************************************************************************
+ hwclock
+***************************************************************************
+
+ This is a program for reading and setting the Hardware Clock on an ISA
+ family computer. This is the clock that is also known as the RTC,
+ real time clock, or, unfortunately, the CMOS clock.
+
+ See man page for details.
+
+ By Bryan Henderson, 96.09.19
+
+ Based on work by others; see history at end of source code.
+
+**************************************************************************/
+/**************************************************************************
+ Maintenance notes
+
+ To compile this, you must use GNU compiler optimization (-O option)
+ in order to make the "extern inline" functions from asm/io.h (inb(),
+ etc.) compile. If you don't optimize, which means the compiler
+ will generate no inline functions, the references to these functions
+ in this program will be compiled as external references. Since you
+ probably won't be linking with any functions by these names, you will
+ have unresolved external references when you link.
+
+ The program is designed to run setuid superuser, since we need to be
+ able to do direct I/O. (More to the point: we need permission to
+ execute the iopl() system call.) (However, if you use one of the
+ methods other than direct ISA I/O to access the clock, no setuid is
+ required).
+
+ Here's some info on how we must deal with the time that elapses while
+ this program runs: There are two major delays as we run:
+
+ 1) Waiting up to 1 second for a transition of the Hardware Clock so
+ we are synchronized to the Hardware Clock.
+
+ 2) Running the "date" program to interpret the value of our --date
+ option.
+
+ Reading the /etc/adjtime file is the next biggest source of delay and
+ uncertainty.
+
+ The user wants to know what time it was at the moment he invoked us,
+ not some arbitrary time later. And in setting the clock, he is
+ giving us the time at the moment we are invoked, so if we set the
+ clock some time later, we have to add some time to that.
+
+ So we check the system time as soon as we start up, then run "date"
+ and do file I/O if necessary, then wait to synchronize with a
+ Hardware Clock edge, then check the system time again to see how
+ much time we spent. We immediately read the clock then and (if
+ appropriate) report that time, and additionally, the delay we measured.
+
+ If we're setting the clock to a time given by the user, we wait some
+ more so that the total delay is an integral number of seconds, then
+ set the Hardware Clock to the time the user requested plus that
+ integral number of seconds. N.B. The Hardware Clock can only be set
+ in integral seconds.
+
+ If we're setting the clock to the system clock value, we wait for it
+ to reach the top of a second, and then set the Hardware Clock to the
+ system clock's value.
+
+ Here's an interesting point about setting the Hardware Clock: On my
+ machine, when you set it, it sets to that precise time. But one can
+ imagine another clock whose update oscillator marches on a steady one
+ second period, so updating the clock between any two oscillator ticks
+ is the same as updating it right at the earlier tick. To avoid any
+ complications that might cause, we set the clock as soon as possible
+ after an oscillator tick.
+
+ Enhancements needed:
+
+ - When waiting for whole second boundary in set_hardware_clock_exact,
+ fail if we miss the goal by more than .1 second, as could happen if
+ we get pre-empted (by the kernel dispatcher).
+
+****************************************************************************/
+
+#define _GNU_SOURCE /* for snprintf */
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <asm/io.h>
+#include <shhopt.h>
+#include "../version.h"
+
+#define MYNAME "hwclock"
+#define VERSION "2.1"
+
+#define FLOOR(arg) ((arg >= 0 ? (int) arg : ((int) arg) - 1));
+
+/* Here the information for time adjustments is kept. */
+#define ADJPATH "/etc/adjtime"
+
+/* Note that we must define the boolean type as int because we use the
+ shhopt option processing library which, unfortunately, returns flag
+ options as integers. It is customary to define bool as char, but
+ then we would have to do a lot of conversion in order to interface
+ with shhopt.
+*/
+typedef int bool;
+#define TRUE 1
+#define FALSE 0
+
+struct adjtime {
+ /* This is information we keep in the adjtime file that tells us how
+ to do drift corrections. Elements are all straight from the
+ adjtime file, so see documentation of that file for details.
+ Exception is <dirty>, which is an indication that what's in this
+ structure is not what's in the disk file (because it has been
+ updated since read from the disk file).
+ */
+ bool dirty;
+ float drift_factor;
+ time_t last_adj_time;
+ float not_adjusted;
+ time_t last_calib_time;
+};
+
+
+enum clock_access_method {ISA, RTC_IOCTL, KD};
+ /* A method for accessing (reading, writing) the hardware clock:
+
+ ISA:
+ via direct CPU I/O instructions that work on an ISA family
+ machine (IBM PC compatible).
+
+ RTC_IOCTL:
+ via the rtc device driver, using device special file /dev/rtc.
+
+ KD:
+ via the console driver, using device special file /dev/console.
+ This is the m64k ioctl interface.
+
+ NO_CLOCK:
+ Unable to determine a accessmethod for the system clock.
+ */
+
+
+/* The following are just constants. Oddly, this program will not
+ compile if the inb() and outb() functions use something even
+ slightly different from these variables. This is probably at least
+ partially related to the fact that __builtin_constant_p() doesn't
+ work (is never true) in an inline function. See comment to this
+ effect in asm/io.h.
+*/
+static unsigned short clock_ctl_addr = 0x70;
+static unsigned short clock_data_addr = 0x71;
+
+bool debug;
+ /* We are running in debug mode, wherein we put a lot of information about
+ what we're doing to standard error. Because of the pervasive and yet
+ background nature of this value, this is a global variable. */
+
+
+#include <linux/version.h>
+/* Check if the /dev/rtc interface is available in this version of
+ the system headers. 131072 is linux 2.0.0. Might need to make
+ it conditional on i386 or something too -janl */
+#if LINUX_VERSION_CODE >= 131072
+#include <linux/mc146818rtc.h>
+#include <linux/kd.h>
+static const bool got_rtc = TRUE;
+#else
+/* Dummy to make it compile */
+#define RTC_SET_TIME 0
+static const bool got_rtc = FALSE;
+#endif
+
+
+
+#if defined(KDGHWCLK)
+static const bool got_kdghwclk = TRUE;
+static const int kdghwclk_ioctl = KDGHWCLK;
+static const int kdshwclk_ioctl = KDSHWCLK;
+#else
+static const bool got_kdghwclk = FALSE;
+static const int kdghwclk_ioctl; /* Never used; just to make compile work */
+struct hwclk_time {char dummy;};
+ /* Never used; just to make compile work */
+#endif
+
+
+
+float
+time_diff(struct timeval subtrahend, struct timeval subtractor) {
+/*---------------------------------------------------------------------------
+ The difference in seconds between two times in "timeval" format.
+----------------------------------------------------------------------------*/
+ return( (subtrahend.tv_sec - subtractor.tv_sec)
+ + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6 );
+}
+
+
+struct timeval
+time_inc(struct timeval addend, float increment) {
+/*----------------------------------------------------------------------------
+ The time, in "timeval" format, which is <increment> seconds after
+ the time <addend>. Of course, <increment> may be negative.
+-----------------------------------------------------------------------------*/
+ struct timeval newtime;
+
+ newtime.tv_sec = addend.tv_sec + (int) increment;
+ newtime.tv_usec = addend.tv_usec + (increment - (int) increment) * 1E6;
+
+ /* Now adjust it so that the microsecond value is between 0 and 1 million */
+ if (newtime.tv_usec < 0) {
+ newtime.tv_usec += 1E6;
+ newtime.tv_sec -= 1;
+ } else if (newtime.tv_usec >= 1E6) {
+ newtime.tv_usec -= 1E6;
+ newtime.tv_sec += 1;
+ }
+ return(newtime);
+}
+
+
+
+static inline unsigned char
+hclock_read(unsigned char reg) {
+/*---------------------------------------------------------------------------
+ Relative byte <reg> of the Hardware Clock value.
+---------------------------------------------------------------------------*/
+#ifdef __i386__
+ register unsigned char ret;
+ __asm__ volatile ("cli");
+ /* & 0x7f ensures that we are not disabling NMI while we read.
+ Setting on Bit 7 here would disable NMI
+ */
+ outb(reg & 0x7f, clock_ctl_addr);
+ ret = inb(clock_data_addr);
+ __asm__ volatile ("sti");
+ return ret;
+#endif
+}
+
+
+
+static inline void
+hclock_write(unsigned char reg, unsigned char val) {
+/*----------------------------------------------------------------------------
+ Set relative byte <reg> of the Hardware Clock value to <val>.
+----------------------------------------------------------------------------*/
+#ifdef __i386__
+ /* & 0x7f ensures that we are not disabling NMI while we read.
+ Setting on Bit 7 here would disable NMI
+ */
+ outb(reg & 0x7f, clock_ctl_addr);
+ outb(val, clock_data_addr);
+#endif
+}
+
+
+
+static inline int
+hclock_read_bcd (int addr) {
+ int b;
+ b = hclock_read(addr);
+ return (b & 15) + (b >> 4) * 10;
+}
+
+static inline void
+hclock_write_bcd(int addr, int value) {
+ hclock_write(addr, ((value / 10) << 4) + value % 10);
+}
+
+
+void
+read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
+/*----------------------------------------------------------------------------
+ Read the adjustment parameters out of the /etc/adjtime file.
+
+ Return them as the adjtime structure <*adjtime_p>.
+
+ If there is no /etc/adjtime file, return defaults.
+ If values are missing from the file, return defaults for them.
+
+ return *rc_p = 0 if all OK, !=0 otherwise.
+
+-----------------------------------------------------------------------------*/
+ FILE *adjfile;
+ int rc; /* local return code */
+ struct stat statbuf; /* We don't even use the contents of this. */
+
+ rc = stat(ADJPATH, &statbuf);
+ if (rc < 0 && errno == ENOENT) {
+ /* He doesn't have a adjtime file, so we'll use defaults. */
+ adjtime_p->drift_factor = 0;
+ adjtime_p->last_adj_time = 0;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->last_calib_time = 0;
+
+ *rc_p = 0;
+ } else {
+ adjfile = fopen(ADJPATH, "r"); /* open file for reading */
+ if (adjfile == NULL) {
+ const int fopen_errno = errno;
+ fprintf(stderr, MYNAME " is unable to open file " ADJPATH ". "
+ "fopen() errno=%d:%s", fopen_errno, strerror(fopen_errno));
+ *rc_p = 2;
+ } else {
+ char line1[81]; /* String: first line of adjtime file */
+ char line2[81]; /* String: second line of adjtime file */
+
+ line1[0] = '\0'; /* In case fgets fails */
+ fgets(line1, sizeof(line1), adjfile);
+ line2[0] = '\0'; /* In case fgets fails */
+ fgets(line2, sizeof(line2), adjfile);
+
+ fclose(adjfile);
+
+ /* Set defaults in case values are missing from file */
+ adjtime_p->drift_factor = 0;
+ adjtime_p->last_adj_time = 0;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->last_calib_time = 0;
+
+ sscanf(line1, "%f %d %f",
+ &adjtime_p->drift_factor,
+ (int *) &adjtime_p->last_adj_time,
+ &adjtime_p->not_adjusted);
+
+ sscanf(line2, "%d", (int *) &adjtime_p->last_calib_time);
+
+ *rc_p = 0;
+ }
+ adjtime_p->dirty = FALSE;
+
+ if (debug) {
+ printf("Last drift adjustment done at %d seconds after 1969\n",
+ (int) adjtime_p->last_adj_time);
+ printf("Last calibration done at %d seconds after 1969\n",
+ (int) adjtime_p->last_calib_time);
+ }
+ }
+}
+
+
+
+void
+synchronize_to_clock_tick_ISA(int *retcode_p) {
+/*----------------------------------------------------------------------------
+ Same as synchronize_to_clock_tick(), but just for ISA.
+-----------------------------------------------------------------------------*/
+ int i; /* local loop index */
+
+ /* Wait for rise. Should be within a second, but in case something
+ weird happens, we have a limit on this loop to reduce the impact
+ of this failure.
+ */
+ for (i = 0; !(hclock_read(10) & 0x80) && (i < 10000000); i++);
+ if (i >= 10000000) *retcode_p = 1;
+ else {
+ /* Wait for fall. Should be within 2.228 ms. */
+ for (i = 0; (hclock_read(10) & 0x80) && (i < 1000000); i++);
+ if (i >= 10000000) *retcode_p = 1;
+ else *retcode_p = 0;
+ }
+}
+
+
+
+void
+synchronize_to_clock_tick_RTC(int *retcode_p) {
+/*----------------------------------------------------------------------------
+ Same as synchronize_to_clock_tick(), but just for /dev/rtc.
+-----------------------------------------------------------------------------*/
+#if defined(_MC146818RTC_H)
+ int rc; /* local return code */
+ int rtc_fd; /* File descriptor of /dev/rtc */
+
+ rtc_fd = open("/dev/rtc",O_RDONLY);
+ if (rtc_fd == -1) {
+ fprintf(stderr, "open() of /dev/rtc failed, errno = %s (%d).\n",
+ strerror(errno), errno);
+ *retcode_p = 1;
+ } else {
+ /* Turn on update interrupts (one per second) */
+ rc = ioctl(rtc_fd, RTC_UIE_ON, 0);
+ if (rc == -1) {
+ fprintf(stderr, "ioctl() to /dev/rtc to turn on update interrupts "
+ "failed, errno = %s (%d).\n", strerror(errno), errno);
+ *retcode_p = 1;
+ } else {
+ unsigned long dummy;
+
+ /* this blocks */
+ rc = read(rtc_fd, &dummy, sizeof(unsigned long));
+ if (rc == -1) {
+ fprintf(stderr, "read() to /dev/rtc to wait for clock tick failed, "
+ "errno = %s (%d).\n", strerror(errno), errno);
+ *retcode_p = 1;
+ } else {
+ *retcode_p = 0;
+
+ /* Turn off update interrupts */
+ rc = ioctl(rtc_fd, RTC_UIE_OFF, 0);
+ if (rc == -1) {
+ fprintf(stderr, "ioctl() to /dev/rtc to turn off update interrupts "
+ "failed, errno = %s (%d).\n", strerror(errno), errno);
+ }
+ }
+ }
+ close(rtc_fd);
+ }
+#else
+/* This function should never be called. It is here just to make the
+ program compile.
+*/
+#endif
+}
+
+
+
+int
+synchronize_to_clock_tick(enum clock_access_method clock_access) {
+/*-----------------------------------------------------------------------------
+ Wait until the falling edge of the Hardware Clock's update flag so
+ that any time that is read from the clock immediately after we
+ return will be exact.
+
+ The clock only has 1 second precision, so it gives the exact time only
+ once per second, right on the falling edge of the update flag.
+
+ We wait (up to one second) either blocked waiting for an rtc device
+ or in a CPU spin loop. The former is probably not very accurate.
+
+ For the KD clock access method, we have no way to synchronize, so we
+ just return immediately. This will mess some things up, but it's the
+ best we can do.
+
+ Return 1 if something weird goes wrong (nothing can normally go wrong),
+ 0 if everything OK.
+
+-----------------------------------------------------------------------------*/
+ int retcode; /* our eventual return code */
+
+ if (debug) printf("Waiting for clock tick...\n");
+
+ switch (clock_access) {
+ case ISA: synchronize_to_clock_tick_ISA(&retcode); break;
+ case RTC_IOCTL: synchronize_to_clock_tick_RTC(&retcode); break;
+ case KD:
+ if (debug)
+ printf("Can't wait for clock tick because we're using the Alpha "
+ "/dev/console clock! Assuming a clock tick.\n");
+ retcode = 1;
+ break;
+ default:
+ fprintf(stderr, "Internal error in synchronize_to_clock_tick. Invalid "
+ "value for clock_access argument.\n");
+ retcode = 1;
+ }
+ if (debug) printf("...got clock tick\n");
+ return(retcode);
+}
+
+
+
+time_t
+mktime_tz(struct tm tm, const bool universal) {
+/*-----------------------------------------------------------------------------
+ Convert a time in broken down format (hours, minutes, etc.) into standard
+ unix time (seconds into epoch).
+
+ The broken down time is argument <tm>. This broken down time is either in
+ local time zone or UTC, depending on value of logical argument "universal".
+ True means it is in UTC.
+-----------------------------------------------------------------------------*/
+ time_t systime; /* our eventual return value */
+ char *zone; /* Local time zone name */
+
+ /* We use the C library function mktime(), but since it only works on
+ local time zone input, we may have to fake it out by temporarily
+ changing the local time zone to UTC.
+ */
+ zone = (char *) getenv("TZ"); /* remember original time zone */
+
+ if (universal) {
+ /* Set timezone to UTC */
+ (void) putenv("TZ=");
+ /* Note: tzset() gets called implicitly by the time code, but only the
+ first time. When changing the environment variable, better call
+ tzset() explicitly.
+ */
+ tzset();
+ }
+ systime = mktime(&tm);
+ if (systime == -1) {
+ /* We don't expect this to happen. Consider this a crash */
+ fprintf(stderr, "mktime() failed unexpectedly (rc -1). Aborting.\n");
+ exit(2);
+ }
+
+ /* now put back the original zone. */
+ if (zone)
+ setenv ("TZ", zone, 1);
+ else
+ putenv ("TZ");
+ tzset();
+
+ if (debug)
+ printf("Hw clock time : %.2d:%.2d:%.2d = %d seconds since 1969\n",
+ tm.tm_hour, tm.tm_min, tm.tm_sec, (int) systime);
+
+ return(systime);
+}
+
+
+
+void
+read_hardware_clock_kd(struct tm *tm) {
+/*----------------------------------------------------------------------------
+ Read the hardware clock and return the current time via <tm>
+ argument. Use ioctls to /dev/console on what we assume is an Alpha
+ machine.
+-----------------------------------------------------------------------------*/
+#ifdef KDGHWCLK
+ int con_fd;
+ struct hwclk_time t;
+
+ con_fd = open("/dev/console", O_RDONLY);
+ if (con_fd < 0) {
+ fprintf(stderr, "open() failed to open /dev/console, errno = %s (%d).\n",
+ strerror(errno), errno);
+ exit(5);
+ } else {
+ int rc; /* return code from ioctl() */
+
+ rc = ioctl(con_fd, kdghwclk_ioctl, &t);
+ if (rc == -1) {
+ fprintf(stderr, "ioctl() failed to read time from /dev/console, "
+ "errno = %s (%d).\n",
+ strerror(errno), errno);
+ exit(5);
+ }
+ close(con_fd);
+ }
+
+ tm->tm_sec = t.sec;
+ tm->tm_min = t.min;
+ tm->tm_hour = t.hour;
+ tm->tm_mday = t.day;
+ tm->tm_mon = t.mon;
+ tm->tm_year = t.year;
+ tm->tm_wday = t.wday;
+ tm->tm_isdst = -1; /* Don't know if it's Daylight Savings Time */
+#else
+ /* This routine should never be invoked. It is here just to make the
+ program compile.
+ */
+#endif
+}
+
+
+
+void
+read_hardware_clock_rtc_ioctl(struct tm *tm) {
+/*----------------------------------------------------------------------------
+ Read the hardware clock and return the current time via <tm>
+ argument. Use ioctls to "rtc" device /dev/rtc.
+-----------------------------------------------------------------------------*/
+#if defined(_MC146818RTC_H)
+ int rc; /* Local return code */
+ int rtc_fd; /* File descriptor of /dev/rtc */
+
+ rtc_fd = open("/dev/rtc",O_RDONLY);
+ if (rtc_fd == -1) {
+ fprintf(stderr, "open() of /dev/rtc failed, errno = %s (%d).\n",
+ strerror(errno), errno);
+ exit(5);
+ } else {
+ /* Read the RTC time/date */
+ rc = ioctl(rtc_fd, RTC_RD_TIME, tm);
+ if (rc == -1) {
+ fprintf(stderr, "ioctl() to /dev/rtc to read the time failed, "
+ "errno = %s (%d).\n", strerror(errno), errno);
+ exit(5);
+ }
+ close(rtc_fd);
+ }
+ tm->tm_isdst = -1; /* don't know whether it's daylight */
+#else
+ /* This function should never be called. It exists just to make the
+ program compile.
+ */
+#endif
+}
+
+
+
+void
+read_hardware_clock_isa(struct tm *tm) {
+/*----------------------------------------------------------------------------
+ Read the hardware clock and return the current time via <tm> argument.
+ Assume we have an ISA machine and read the clock directly with CPU I/O
+ instructions.
+-----------------------------------------------------------------------------*/
+ /* The loop here is just for integrity. In theory it should never run
+ more than once
+ */
+ do {
+ tm->tm_sec = hclock_read_bcd(0);
+ tm->tm_min = hclock_read_bcd(2);
+ tm->tm_hour = hclock_read_bcd(4);
+ tm->tm_wday = hclock_read_bcd(6);
+ tm->tm_mday = hclock_read_bcd(7);
+ tm->tm_mon = hclock_read_bcd(8);
+ tm->tm_year = hclock_read_bcd(9);
+ if (hclock_read_bcd(50) == 0) {
+ /* I suppose Linux could run on an old machine that doesn't implement
+ the Byte 50 century value, and that if it does, that machine puts
+ zero in Byte 50. If so, this could could be useful, in that it
+ makes values 70-99 -> 1970-1999 and 00-69 -> 2000-2069.
+ */
+ if (hclock_read_bcd(9) >= 70) tm->tm_year = hclock_read_bcd(9);
+ else tm->tm_year = hclock_read_bcd(9) + 100;
+ } else {
+ tm->tm_year = hclock_read_bcd(50) * 100 + hclock_read_bcd(9) - 1900;
+ /* Note: Byte 50 contains centuries since A.D. Byte 9 contains
+ years since beginning of century. tm_year contains years
+ since 1900. At least we _assume_ that's what tm_year
+ contains. It is documented only as "year", and it could
+ conceivably be years since the beginning of the current
+ century. If so, this code won't work after 1999.
+ */
+ }
+ } while (tm->tm_sec != hclock_read_bcd (0));
+
+ 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 */
+}
+
+
+
+void
+read_hardware_clock(const enum clock_access_method method, struct tm *tm){
+/*----------------------------------------------------------------------------
+ Read the hardware clock and return the current time via <tm> argument.
+
+ Use the method indicated by <method> argument to access the hardware clock.
+-----------------------------------------------------------------------------*/
+ switch (method) {
+ case ISA:
+ read_hardware_clock_isa(tm);
+ break;
+ case RTC_IOCTL:
+ read_hardware_clock_rtc_ioctl(tm);
+ break;
+ case KD:
+ read_hardware_clock_kd(tm);
+ break;
+ default:
+ fprintf(stderr,
+ "Internal error: invalid value for clock access method.\n");
+ exit(5);
+ }
+ if (debug)
+ printf ("Time read from Hardware Clock: %02d:%02d:%02d\n",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+
+
+void
+set_hardware_clock_kd(const struct tm new_broken_time,
+ const bool testing) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the time <new_broken_time>. Use ioctls to
+ /dev/console on what we assume is an Alpha machine.
+----------------------------------------------------------------------------*/
+#ifdef KDGHWCLK
+ int con_fd; /* File descriptor of /dev/console */
+ struct hwclk_time t;
+
+ con_fd = open("/dev/console", O_RDONLY);
+ if (con_fd < 0) {
+ fprintf(stderr, "Error opening /dev/console. Errno: %s (%d)\n",
+ strerror(errno), errno);
+ exit(1);
+ } else {
+ int rc; /* locally used return code */
+
+ t.sec = new_broken_time->tm_sec;
+ t.min = new_broken_time->tm_min;
+ t.hour = new_broken_time->tm_hour;
+ t.day = new_broken_time->tm_mday;
+ t.mon = new_broken_time->tm_mon;
+ t.year = new_broken_time->tm_year;
+ t.wday = new_broken_time->tm_wday;
+
+ if (testing)
+ printf("Not setting Hardware Clock because running in test mode.\n");
+ else {
+ rc = ioctl(con_fd, kdshwclk_ioctl, &t );
+ if (rc < 0) {
+ fprintf(stderr, "ioctl() to open /dev/console failed. "
+ "Errno: %s (%d)\n",
+ strerror(errno), errno);
+ exit(1);
+ }
+ }
+ close(con_fd);
+ }
+#else
+ /* This function should never be invoked. It is here just to make the
+ program compile.
+ */
+#endif
+}
+
+
+
+void
+set_hardware_clock_rtc_ioctl(const struct tm new_broken_time,
+ const bool testing) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the broken down time <new_broken_time>.
+ Use ioctls to "rtc" device /dev/rtc.
+----------------------------------------------------------------------------*/
+ int rc;
+ int rtc_fd;
+
+ rtc_fd = open("/dev/rtc", O_RDONLY);
+ if (rtc_fd < 0) {
+ fprintf(stderr, "Unable to open /dev/rtc, open() errno = %s (%d)\n",
+ strerror(errno), errno);
+ exit(5);
+ } else {
+ rc = ioctl(rtc_fd, RTC_SET_TIME, &new_broken_time);
+ if (rc == -1) {
+ fprintf(stderr, "ioctl() (RTC_SET_TIME) to /dev/rtc to set time failed, "
+ "errno = %s (%d).\n", strerror(errno), errno);
+ exit(5);
+ } else {
+ if (debug)
+ fprintf(stderr, "ioctl(RTC_SET_TIME) was successful.\n");
+ }
+ close(rtc_fd);
+ }
+}
+
+
+
+void
+set_hardware_clock_isa(const struct tm new_broken_time,
+ const bool testing) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the time (in broken down format)
+ new_broken_time. Use direct I/O instructions to what we assume is
+ an ISA Hardware Clock.
+----------------------------------------------------------------------------*/
+ unsigned char save_control, save_freq_select;
+
+ if (testing)
+ printf("Not setting Hardware Clock because running in test mode.\n");
+ else {
+#ifdef __i386__
+ __asm__ volatile ("cli");
+#endif
+ save_control = hclock_read(11); /* tell the clock it's being set */
+ hclock_write(11, (save_control | 0x80));
+ save_freq_select = hclock_read(10); /* stop and reset prescaler */
+ hclock_write (10, (save_freq_select | 0x70));
+
+ hclock_write_bcd(0, new_broken_time.tm_sec);
+ hclock_write_bcd(2, new_broken_time.tm_min);
+ hclock_write_bcd(4, new_broken_time.tm_hour);
+ hclock_write_bcd(6, new_broken_time.tm_wday + 3);
+ hclock_write_bcd(7, new_broken_time.tm_mday);
+ hclock_write_bcd(8, new_broken_time.tm_mon + 1);
+ hclock_write_bcd(9, new_broken_time.tm_year%100);
+ hclock_write_bcd(50, (1900+new_broken_time.tm_year)/100);
+
+ /* The kernel sources, linux/arch/i386/kernel/time.c, have the
+ following comment:
+
+ The following flags have to be released exactly in this order,
+ otherwise the DS12887 (popular MC146818A clone with integrated
+ battery and quartz) will not reset the oscillator and will not
+ update precisely 500 ms later. You won't find this mentioned
+ in the Dallas Semiconductor data sheets, but who believes data
+ sheets anyway ... -- Markus Kuhn
+
+ Hence, they will also be done in this order here.
+ faith@cs.unc.edu, Thu Nov 9 08:26:37 1995
+ */
+
+ hclock_write (11, save_control);
+ hclock_write (10, save_freq_select);
+#ifdef __i386__
+ __asm__ volatile ("sti");
+#endif
+ }
+}
+
+
+void
+set_hardware_clock(const enum clock_access_method method,
+ const time_t newtime,
+ const bool universal,
+ const bool testing) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the time <newtime>, in local time zone or UTC,
+ according to <universal>.
+
+ Use the method indicated by the <method> argument.
+----------------------------------------------------------------------------*/
+
+ struct tm new_broken_time;
+ /* Time to which we will set Hardware Clock, in broken down format, in
+ the time zone of caller's choice
+ */
+
+ if (universal) new_broken_time = *gmtime(&newtime);
+ else new_broken_time = *localtime(&newtime);
+
+ if (debug)
+ printf("Setting Hardware Clock to %.2d:%.2d:%.2d "
+ "= %d seconds since 1969\n",
+ new_broken_time.tm_hour, new_broken_time.tm_min,
+ new_broken_time.tm_sec, (int) newtime);
+
+ switch (method) {
+ case ISA:
+ set_hardware_clock_isa(new_broken_time, testing);
+ break;
+ case RTC_IOCTL:
+ set_hardware_clock_rtc_ioctl(new_broken_time, testing);
+ break;
+ case KD:
+ set_hardware_clock_kd(new_broken_time, testing);
+ break;
+ default:
+ fprintf(stderr,
+ "Internal error: invalid value for clock access method.\n");
+ exit(5);
+ }
+}
+
+
+
+void
+set_hardware_clock_exact(const time_t settime,
+ const struct timeval ref_time,
+ const enum clock_access_method clock_access,
+ const bool universal,
+ const bool testing) {
+/*----------------------------------------------------------------------------
+ Set the Hardware Clock to the time "settime", in local time zone or UTC,
+ according to "universal".
+
+ But correct "settime" and wait for a fraction of a second so that
+ "settime" is the value of the Hardware Clock as of system time
+ "ref_time", which is in the past. For example, if "settime" is
+ 14:03:05 and "ref_time" is 12:10:04.5 and the current system
+ time is 12:10:06.0: Wait .5 seconds (to make exactly 2 seconds since
+ "ref_time") and then set the Hardware Clock to 14:03:07, thus
+ getting a precise and retroactive setting of the clock.
+
+ (Don't be confused by the fact that the system clock and the Hardware
+ Clock differ by two hours in the above example. That's just to remind
+ you that there are two independent time scales here).
+
+ This function ought to be able to accept set times as fractional times.
+ Idea for future enhancement.
+
+-----------------------------------------------------------------------------*/
+ time_t newtime; /* Time to which we will set Hardware Clock */
+ struct timeval now_time; /* locally used time */
+
+ gettimeofday(&now_time, NULL);
+ newtime = settime + (int) time_diff(now_time, ref_time) + 1;
+ if (debug)
+ printf("Time elapsed since reference time has been %.6f seconds.\n"
+ "Delaying further to reach the next full second.\n",
+ time_diff(now_time, ref_time));
+
+ /* Now delay some more until Hardware Clock time newtime arrives */
+ do gettimeofday(&now_time, NULL);
+ while (time_diff(now_time, ref_time) < newtime - settime);
+
+ set_hardware_clock(clock_access, newtime, universal, testing);
+}
+
+
+
+void
+display_time(const time_t systime, const float sync_duration) {
+/*----------------------------------------------------------------------------
+ Put the time "systime" on standard output in display format.
+
+ Include in the output the adjustment "sync_duration".
+-----------------------------------------------------------------------------*/
+ char *ctime_now; /* Address of static storage containing time string */
+
+ /* For some strange reason, ctime() is designed to include a newline
+ character at the end. We have to remove that.
+ */
+ ctime_now = ctime(&systime); /* Compute display value for time */
+ *(ctime_now+strlen(ctime_now)-1) = '\0'; /* Cut off trailing newline */
+
+ printf("%s %.6f seconds\n", ctime_now, -(sync_duration));
+}
+
+
+
+int
+interpret_date_string(const char *date_opt, const time_t *time_p) {
+/*----------------------------------------------------------------------------
+ Interpret the value of the --date option, which is something like
+ "13:05:01". In fact, it can be any of the myriad ASCII strings that specify
+ a time which the "date" program can understand. The date option value in
+ question is our "dateopt" argument.
+
+ The specified time is in the local time zone.
+
+ Our output, "*newtime", is a seconds-into-epoch time.
+
+ We use the "date" program to interpret the date string. "date" must be
+ runnable by issuing the command "date" to the /bin/sh shell. That means
+ in must be in the current PATH.
+
+ If anything goes wrong (and many things can), we return return code 10.
+ Otherwise, return code is 0 and *newtime is valid.
+----------------------------------------------------------------------------*/
+
+ FILE *date_child_fp;
+ char date_resp[100];
+ const char magic[]="seconds-into-epoch=";
+ char date_command[100];
+ int retcode; /* our eventual return code */
+ int rc; /* local return code */
+
+ if (date_opt == NULL) {
+ fprintf(stderr, "No --date option specified.\n");
+ retcode = 14;
+ } else if (strchr(date_opt, '"') != NULL) {
+ /* Quotation marks in date_opt would ruin the date command we construct.
+ */
+ fprintf(stderr, "The value of the --date option is not a valid date.\n"
+ "In particular, it contains quotation marks.\n");
+ retcode = 12;
+ } else {
+ sprintf(date_command, "date --date=\"%s\" +seconds-into-epoch=%%s",
+ date_opt);
+ if (debug) printf("Issuing date command: %s\n", date_command);
+
+ date_child_fp = popen(date_command, "r");
+ if (date_child_fp == NULL) {
+ fprintf(stderr, "Unable to run 'date' program in /bin/sh shell. "
+ "popen() failed with errno=%d:%s\n", errno, strerror(errno));
+ retcode = 10;
+ } else {
+ date_resp[0] = '\0'; /* in case fgets fails */
+ fgets(date_resp, sizeof(date_resp), date_child_fp);
+ if (debug) printf("response from date command = %s\n", date_resp);
+ if (strncmp(date_resp, magic, sizeof(magic)-1) != 0) {
+ fprintf(stderr, "The date command issued by " MYNAME " returned "
+ "unexpected results.\n"
+ "The command was:\n %s\nThe response was:\n %s\n",
+ date_command, date_resp);
+ retcode = 8;
+ } else {
+ rc = sscanf(date_resp + sizeof(magic)-1, "%d", (int *) time_p);
+ if (rc < 1) {
+ fprintf(stderr, "The date command issued by " MYNAME " returned"
+ "something other than an integer where the converted"
+ "time value was expected.\n"
+ "The command was:\n %s\nThe response was:\n %s\n",
+ date_command, date_resp);
+ retcode = 6;
+ } else {
+ retcode = 0;
+ if (debug)
+ printf("date string %s equates to %d seconds since 1969.\n",
+ date_opt, (int) *time_p);
+ }
+ }
+ fclose(date_child_fp);
+ }
+ }
+ return(retcode);
+}
+
+
+
+int
+set_system_clock(const time_t newtime, const int testing) {
+
+ struct timeval tv;
+ int retcode; /* our eventual return code */
+ int rc; /* local return code */
+
+ tv.tv_sec = newtime;
+ tv.tv_usec = 0;
+
+ if (debug) {
+ printf( "Calling settimeofday:\n" );
+ /* Note: In Linux 1.2, tv_sec and tv_usec were long int */
+ printf( "\ttv.tv_sec = %d, tv.tv_usec = %d\n",
+ tv.tv_sec, tv.tv_usec );
+ }
+ if (testing) {
+ printf("Not setting system clock because running in test mode.\n");
+ retcode = 0;
+ } else {
+ rc = settimeofday(&tv, NULL);
+ if (rc != 0) {
+ if (errno == EPERM)
+ fprintf(stderr, "Must be superuser to set system clock.\n");
+ else
+ fprintf(stderr,
+ "settimeofday() failed, errno=%d:%s\n",
+ errno, strerror(errno));
+ retcode = 1;
+ } else retcode = 0;
+ }
+ return(retcode);
+}
+
+
+void
+adjust_drift_factor(struct adjtime *adjtime_p,
+ const time_t nowtime,
+ const time_t hclocktime ) {
+/*---------------------------------------------------------------------------
+ Update the drift factor in <*adjtime_p> to reflect the fact that the
+ Hardware Clock was calibrated to <nowtime> and before that was set
+ to <hclocktime>.
+
+ We assume that the user has been doing regular drift adjustments
+ using the drift factor in the adjtime file, so if <nowtime> and
+ <clocktime> are different, that means the adjustment factor isn't
+ quite right.
+
+ We record in the adjtime file the time at which we last calibrated
+ the clock so we can compute the drift rate each time we calibrate.
+
+----------------------------------------------------------------------------*/
+ if ((hclocktime - adjtime_p->last_calib_time) >= 24 * 60 * 60) {
+ const float factor_adjust =
+ ((float) (nowtime - hclocktime)
+ / (hclocktime - adjtime_p->last_calib_time))
+ * 24 * 60 * 60;
+
+ if (debug)
+ printf("Clock drifted %d seconds in the past %d seconds "
+ "in spite of a drift factor of %f seconds/day.\n"
+ "Adjusting drift factor by %f seconds/day\n",
+ (int) (nowtime - hclocktime),
+ (int) (hclocktime - adjtime_p->last_calib_time),
+ adjtime_p->drift_factor,
+ factor_adjust );
+
+ adjtime_p->drift_factor += factor_adjust;
+ } else if (debug)
+ printf("Not adjusting drift factor because it has been less than a "
+ "day since the last calibration.\n");
+
+ adjtime_p->last_calib_time = nowtime;
+
+ adjtime_p->last_adj_time = nowtime;
+
+ adjtime_p->not_adjusted = 0;
+
+ adjtime_p->dirty = TRUE;
+}
+
+
+
+void
+calculate_adjustment(
+ const float factor,
+ const time_t last_time,
+ const float not_adjusted,
+ const time_t systime,
+ int *adjustment_p,
+ float *retro_p,
+ const int debug ) {
+/*----------------------------------------------------------------------------
+ Do the drift adjustment calculation.
+
+ The way we have to set the clock, we need the adjustment in two parts:
+
+ 1) an integer number of seconds (return as *adjustment_p)
+
+ 2) a positive fraction of a second (less than 1) (return as *retro_p)
+
+ The sum of these two values is the adjustment needed. Positive means to
+ advance the clock or insert seconds. Negative means to retard the clock
+ or remove seconds.
+----------------------------------------------------------------------------*/
+ float exact_adjustment;
+
+ exact_adjustment = ((float) (systime - last_time)) * factor / (24 * 60 * 60)
+ + not_adjusted;
+ *adjustment_p = FLOOR(exact_adjustment);
+
+ *retro_p = exact_adjustment - (float) *adjustment_p;
+ if (debug) {
+ printf ("Time since last adjustment is %d seconds\n",
+ (int) (systime - last_time));
+ printf ("Need to insert %d seconds and refer time back "
+ "%.6f seconds ago\n",
+ *adjustment_p, *retro_p);
+ }
+}
+
+
+
+void
+save_adjtime(const struct adjtime adjtime, const bool testing) {
+/*-----------------------------------------------------------------------------
+ Write the contents of the <adjtime> structure to its disk file.
+
+ But if the contents are clean (unchanged since read from disk), don't
+ bother.
+-----------------------------------------------------------------------------*/
+ FILE *adjfile;
+ char newfile[162]; /* Stuff to write to disk file */
+
+ int rc; /* locally used: return code from a function */
+
+ if (adjtime.dirty) {
+ snprintf(newfile, sizeof(newfile), "%f %d %f\n%d\n",
+ adjtime.drift_factor,
+ adjtime.last_adj_time,
+ adjtime.not_adjusted,
+ adjtime.last_calib_time );
+
+ if (testing) {
+ printf("Not updating adjtime file because of testing mode.\n");
+ printf("Would have written the following to %s:\n%s",
+ ADJPATH, newfile);
+ } else {
+ adjfile = fopen(ADJPATH, "w");
+ if (adjfile == NULL) {
+ const int fopen_errno = errno;
+ printf("Could not open file with the clock adjustment parameters "
+ "in it (%s) for output.\n"
+ "fopen() returned errno %d: %s.\n"
+ "Drift adjustment parameters not updated.\n",
+ ADJPATH, fopen_errno, strerror(errno));
+ } else {
+ rc = fprintf(adjfile, newfile);
+ if (rc < 0) {
+ const int fprintf_errno = errno;
+ printf("Could not update file with the clock adjustment parameters "
+ "(%s) in it.\n"
+ "fprintf() returned errno %d: %s.\n"
+ "Drift adjustment parameters not updated.\n",
+ ADJPATH, fprintf_errno, strerror(errno));
+ }
+ rc = fclose(adjfile);
+ if (rc < 0) {
+ const int fclose_errno = errno;
+ printf("Could not update file with the clock adjustment parameters "
+ "(%s) in it.\n"
+ "fclose() returned errno %d: %s.\n"
+ "Drift adjustment parameters not updated.\n",
+ ADJPATH, fclose_errno, strerror(errno));
+ }
+ }
+ }
+ }
+}
+
+
+
+void
+do_adjustment(struct adjtime *adjtime_p,
+ const time_t hclocktime, const struct timeval read_time,
+ const enum clock_access_method clock_access,
+ const bool universal, const bool testing) {
+/*---------------------------------------------------------------------------
+ Do the adjustment requested, by 1) setting the Hardware Clock (if
+ necessary), and 2) updating the last-adjusted time in the adjtime
+ structure.
+
+ arguments <factor> and <last_time> are current values from the adjtime
+ file.
+
+ <hclocktime> is the current time set in the Hardware Clock.
+
+ <read_time> is the current system time (to be precise, it is the system
+ time at the time <hclocktime> was read, which due to computational delay
+ could be a short time ago).
+
+ <universal>: the Hardware Clock is kept in UTC.
+
+ <testing>: We are running in test mode (no updating of clock).
+
+ We do not bother to update the clock if the adjustment would be less than
+ one second. This is to avoid cumulative error and needless CPU hogging
+ (remember we use an infinite loop for some timing) if the user runs us
+ frequently.
+
+----------------------------------------------------------------------------*/
+ int adjustment;
+ /* Number of seconds we must insert in the Hardware Clock */
+ float retro;
+ /* Fraction of second we have to remove from clock after inserting
+ <adjustment> whole seconds.
+ */
+ calculate_adjustment(adjtime_p->drift_factor,
+ adjtime_p->last_adj_time,
+ adjtime_p->not_adjusted,
+ hclocktime,
+ &adjustment, &retro,
+ debug );
+ if (adjustment > 0 || adjustment < -1) {
+ set_hardware_clock_exact(hclocktime + adjustment,
+ time_inc(read_time, -retro),
+ clock_access, universal, testing);
+ adjtime_p->last_adj_time = hclocktime + adjustment;
+ adjtime_p->not_adjusted = 0;
+ adjtime_p->dirty = TRUE;
+ } else
+ if (debug)
+ printf("Needed adjustment is less than one second, "
+ "so not setting clock.\n");
+}
+
+
+
+void
+determine_clock_access_method(const bool user_requests_ISA,
+ enum clock_access_method *clock_access_p) {
+/*----------------------------------------------------------------------------
+ Figure out how we're going to access the hardware clock, by seeing
+ what facilities are available, looking at invocation options, and
+ using compile-time constants.
+
+ <user_requests_ISA> means the user explicitly asked for the ISA method.
+-----------------------------------------------------------------------------*/
+ bool rtc_works;
+ /* The /dev/rtc method is available and seems to work on this machine */
+
+ if (got_rtc) {
+ int rtc_fd = open("/dev/rtc", O_RDONLY);
+ if (rtc_fd > 0) {
+ rtc_works = TRUE;
+ close(rtc_fd);
+ } else {
+ rtc_works = FALSE;
+ if (debug)
+ printf("Open of /dev/rtc failed, errno = %s (%d). "
+ "falling back to more primitive clock access method.\n",
+ strerror(errno), errno);
+ }
+ } else rtc_works = TRUE;
+
+ if (user_requests_ISA) *clock_access_p = ISA;
+ else if (rtc_works) *clock_access_p = RTC_IOCTL;
+ else if (got_kdghwclk) {
+ int con_fd;
+ struct hwclk_time t;
+
+ con_fd = open("/dev/console", O_RDONLY);
+ if (con_fd >= 0) {
+ if (ioctl( con_fd, kdghwclk_ioctl, &t ) >= 0)
+ *clock_access_p = KD;
+ else {
+ if (errno == EINVAL) {
+ /* KDGHWCLK not implemented in this kernel... */
+ *clock_access_p = ISA;
+ } else {
+ *clock_access_p = KD;
+ fprintf(stderr,
+ "KDGHWCLK ioctl failed, errno = %s (%d).\n",
+ strerror(errno), errno);
+ }
+ }
+ } else {
+ *clock_access_p = KD;
+ fprintf(stderr,
+ "Can't open /dev/console. open() errno = %s (%d).\n",
+ strerror(errno), errno);
+ }
+ close(con_fd);
+ } else {
+ *clock_access_p = ISA;
+ }
+ if (debug) {
+ switch (*clock_access_p) {
+ case ISA: printf("Using direct I/O instructions to ISA clock.\n"); break;
+ case KD: printf("Using /dev/console interface to Alpha clock.\n"); break;
+ case RTC_IOCTL: printf("Using /dev/rtc interface to clock.\n"); break;
+ default:
+ printf("determine_clock_access_method() returned invalid value: %d.\n",
+ *clock_access_p);
+ }
+ }
+}
+
+
+
+void
+manipulate_clock(const bool show, const bool adjust,
+ const bool set, const time_t set_time,
+ const bool hctosys, const bool systohc,
+ const struct timeval startup_time,
+ const enum clock_access_method clock_access,
+ const bool universal, const bool testing,
+ int *retcode
+ ) {
+/*---------------------------------------------------------------------------
+ Do all the normal work of hwclock - read, set clock, etc.
+
+ Issue output to stdout and error message to stderr where appropriate.
+
+ Return rc == 0 if everything went OK, rc != 0 if not.
+----------------------------------------------------------------------------*/
+ struct adjtime adjtime;
+ /* Contents of the adjtime file, or what they should be. */
+ struct tm tm;
+ time_t hclocktime;
+ /* The time the hardware clock had just after we synchronized to its
+ next clock tick when we started up.
+ */
+ struct timeval read_time;
+ /* The time at which we read the Hardware Clock */
+
+ int rc; /* local return code */
+ bool no_auth; /* User lacks necessary authorization to access the clock */
+
+ if (clock_access == ISA) {
+ rc = iopl(3);
+ if (rc != 0) {
+ fprintf(stderr, MYNAME " is unable to get I/O port access. "
+ "I.e. iopl(3) returned nonzero return code %d.\n"
+ "This is often because the program isn't running "
+ "with superuser privilege, which it needs.\n",
+ rc);
+ no_auth = TRUE;
+ } else no_auth = FALSE;
+ } else no_auth = FALSE;
+
+ if (no_auth) *retcode = 1;
+ else {
+ if (adjust || set)
+ read_adjtime(&adjtime, &rc);
+ else {
+ /* A little trick to avoid reading the file if we don't have to */
+ adjtime.dirty = FALSE;
+ rc = 0;
+ }
+ if (rc != 0) *retcode = 2;
+ else {
+ synchronize_to_clock_tick(clock_access); /* this takes up to 1 second */
+
+ /* Get current time from Hardware Clock, in case we need it */
+ gettimeofday(&read_time, NULL);
+ read_hardware_clock(clock_access, &tm);
+ hclocktime = mktime_tz(tm, universal);
+
+ if (show) {
+ display_time(hclocktime, time_diff(read_time, startup_time));
+ *retcode = 0;
+ } else if (set) {
+ set_hardware_clock_exact(set_time, startup_time,
+ clock_access, universal, testing);
+ adjust_drift_factor(&adjtime, set_time, hclocktime);
+ *retcode = 0;
+ } else if (adjust) {
+ do_adjustment(&adjtime, hclocktime, read_time, clock_access,
+ universal, testing);
+ *retcode = 0;
+ } else if (systohc) {
+ struct timeval nowtime, reftime;
+ /* We can only set_hardware_clock_exact to a whole seconds time, so we
+ set it with reference to the most recent whole seconds time.
+ */
+ gettimeofday(&nowtime, NULL);
+ reftime.tv_sec = nowtime.tv_sec;
+ reftime.tv_usec = 0;
+
+ set_hardware_clock_exact((time_t) reftime.tv_sec, reftime,
+ clock_access, universal, testing);
+ *retcode = 0;
+ } else if (hctosys) {
+ rc = set_system_clock(hclocktime, testing);
+ if (rc != 0) {
+ printf("Unable to set system clock.\n");
+ *retcode = 1;
+ } else *retcode = 0;
+ }
+ save_adjtime(adjtime, testing);
+ }
+ }
+}
+
+
+
+int
+main(int argc, char **argv, char **envp) {
+/*----------------------------------------------------------------------------
+ MAIN
+-----------------------------------------------------------------------------*/
+ struct timeval startup_time;
+ /* The time we started up, in seconds into the epoch, including fractions.
+ */
+ time_t set_time; /* Time to which user said to set Hardware Clock */
+
+ enum clock_access_method clock_access;
+ /* The method that we determine is best for accessing Hardware Clock
+ on this system.
+ */
+
+ bool permitted; /* User is permitted to do the function */
+ int retcode; /* Our eventual return code */
+
+ int rc; /* local return code */
+
+ /* option_def is the control table for the option parser. These other
+ variables are the results of parsing the options and their meanings
+ are given by the option_def. The only exception is <show>, which
+ may be modified after parsing is complete to effect an implied option.
+ */
+ bool show, set, systohc, hctosys, adjust, version;
+ bool universal, testing, directisa;
+ char *date_opt;
+
+ const optStruct option_def[] = {
+ { 'r', (char *) "show", OPT_FLAG, &show, 0 },
+ { 0, (char *) "set", OPT_FLAG, &set, 0 },
+ { 'w', (char *) "systohc", OPT_FLAG, &systohc, 0 },
+ { 's', (char *) "hctosys", OPT_FLAG, &hctosys, 0 },
+ { 'a', (char *) "adjust", OPT_FLAG, &adjust, 0 },
+ { 'v', (char *) "version", OPT_FLAG, &version, 0 },
+ { 0, (char *) "date", OPT_STRING, &date_opt, 0 },
+ { 'u', (char *) "utc", OPT_FLAG, &universal, 0 },
+ { 0, (char *) "directisa", OPT_FLAG, &directisa, 0 },
+ { 0, (char *) "test", OPT_FLAG, &testing, 0 },
+ { 'D', (char *) "debug", OPT_FLAG, &debug, 0 }
+ };
+ int argc_parse; /* argc, except we modify it as we parse */
+ char **argv_parse; /* argv, except we modify it as we parse */
+
+ gettimeofday(&startup_time, NULL); /* Remember what time we were invoked */
+
+ /* set option defaults */
+ show = set = systohc = hctosys = adjust = version = universal =
+ directisa = testing = debug = FALSE;
+ date_opt = NULL;
+
+ argc_parse = argc; argv_parse = argv;
+ optParseOptions(&argc_parse, argv_parse, option_def, 0);
+ /* Uses and sets argc_parse, argv_parse.
+ Sets show, systohc, hctosys, adjust, universal, version, testing,
+ debug, set, date_opt
+ */
+
+ if (argc_parse - 1 > 0) {
+ fprintf(stderr, MYNAME " takes no non-option arguments. "
+ "You supplied %d.\n",
+ argc_parse - 1);
+ exit(100);
+ }
+
+ if (show + set + systohc + hctosys + adjust + version > 1) {
+ fprintf(stderr, "You have specified multiple function options.\n"
+ "You can only perform one function at a time.\n");
+ exit(100);
+ }
+
+ if (set) {
+ rc = interpret_date_string(date_opt, &set_time); /* (time-consuming) */
+ if (rc != 0) {
+ fprintf(stderr, "No usable set-to time. Cannot set clock.\n");
+ exit(100);
+ }
+ }
+
+ if (!(show | set | systohc | hctosys | adjust | version))
+ show = 1; /* default to show */
+
+ if (set || hctosys || systohc || adjust) {
+ /* program is designed to run setuid, be secure! */
+
+ if (getuid() != 0) {
+ fprintf(stderr,
+ "Sorry, only superuser can change the Hardware Clock.\n");
+ permitted = FALSE;
+ } else permitted = TRUE;
+ } else permitted = TRUE;
+
+ if (!permitted) retcode = 2;
+ else {
+ retcode = 0;
+ if (version) {
+ printf(MYNAME " " VERSION "/%s\n",util_linux_version);
+ } else {
+ determine_clock_access_method(directisa, &clock_access);
+
+ manipulate_clock(show, adjust, set, set_time, hctosys, systohc,
+ startup_time, clock_access, universal, testing, &rc);
+ }
+ }
+ exit(retcode);
+}
+
+
+/****************************************************************************
+
+ History of this program:
+
+ 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte
+ 50) of the ISA Hardware Clock when using direct ISA I/O. Problem
+ discovered by job (jei@iclnl.icl.nl).
+
+ Use the rtc clock access method in preference to the KDGHWCLK method.
+ Problem discovered by Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>.
+
+ November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt
+ (janl@math.uio.no) to make it compile on linux 1.2 machines as well
+ as more recent versions of the kernel. Introduced the NO_CLOCK
+ access method and wrote feature test code to detect absense of rtc
+ headers.
+
+
+ Bryan Henderson based hwclock on the program "clock", in September
+ 1996. While remaining mostly backward compatible with clock,
+ hwclock added the following:
+
+ - You can set the hardware clock without also modifying the Linux
+ system clock.
+
+ - You can read and set the clock with finer than 1 second precision.
+
+ - When you set the clock, hwclock automatically refigures the drift
+ rate, based on how far off the clock was before you set it. (This
+ is the drift rate that is used with the --adjust function to
+ automatically adjust the clock periodically to compensate for drift).
+
+ - More mnemonic GNU-style command line options.
+
+ - Comments describing how the clock and program work to improve
+ maintainability.
+
+ - Removed the old dead I/O code that worked without the inb/outb
+ instructions and without the asm/io.h definitions.
+
+ The first version of hwclock was Version 2.
+
+ Here is the history section from the "clock" program at the time it was
+ used as a basis for hwclock:
+
+ V1.0
+
+
+ V1.0 by Charles Hedrick, hedrick@cs.rutgers.edu, April 1992.
+
+ ********************
+ 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.
+
+ *****
+ 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. */
+
+
diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c
index 7273b341a..eceb0b71c 100644
--- a/sys-utils/ipcrm.c
+++ b/sys-utils/ipcrm.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/msg.h>
diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c
index 12df2261a..9505aff55 100644
--- a/sys-utils/ipcs.c
+++ b/sys-utils/ipcs.c
@@ -1,9 +1,19 @@
/* 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. */
+/*
+
+ 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.
+
+ Patch from arnolds@ifns.de (Heinz-Ado Arnolds) applied Mon Jul 1
+ 19:30:41 1996 by janl@math.uio.no to add code missing in case PID:
+ clauses.
+
+ Patched to display the key field -- hy@picksys.com 12/18/96
+
+*/
#include <stdio.h>
#include <stdlib.h>
@@ -18,6 +28,11 @@ entry. */
#include <sys/msg.h>
#include <sys/shm.h>
+#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
+#define KEY __key
+#else
+#define KEY key
+#endif
#define LIMITS 1
#define STATUS 2
@@ -196,10 +211,10 @@ void do_shm (char format)
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",
+ printf ("pages allocated %ld\n", shm_info.shm_tot);
+ printf ("pages resident %ld\n", shm_info.shm_rss);
+ printf ("pages swapped %ld\n", shm_info.shm_swp);
+ printf ("Swap performance: %ld attempts\t %ld successes\n",
shm_info.swap_attempts, shm_info.swap_successes);
return;
@@ -222,8 +237,8 @@ void do_shm (char format)
default:
printf ("------ Shared Memory Segments --------\n");
- printf ("%-10s%-10s%-10s%-10s%-10s%-12s\n", "shmid","owner",
- "perms","bytes","nattch","status");
+ printf ("%-11s%-10s%-10s%-10s%-10s%-10s%-12s\n", "key","shmid",
+ "owner","perms","bytes","nattch","status");
break;
}
@@ -257,6 +272,7 @@ void do_shm (char format)
break;
default:
+ printf( "0x%08x ",ipcp->KEY );
if (pw)
printf ("%-10d%-10.10s", shmid, pw->pw_name);
else
@@ -325,8 +341,8 @@ void do_sem (char format)
default:
printf ("------ Semaphore Arrays --------\n");
- printf ("%-10s%-10s%-10s%-10s%-12s\n",
- "semid","owner","perms","nsems","status");
+ printf ("%-10s%-10s%-10s%-10s%-10s%-12s\n",
+ "key","semid","owner","perms","nsems","status");
break;
}
@@ -354,6 +370,7 @@ void do_sem (char format)
break;
default:
+ printf( "0x%08x ",ipcp->KEY );
if (pw)
printf ("%-10d%-10.9s", semid, pw->pw_name);
else
@@ -412,12 +429,14 @@ void do_msg (char format)
break;
case PID:
+ printf ("------ Message Queues PIDs --------\n");
+ printf ("%-10s%-10s%-10s%-10s\n","msqid","owner","lspid","lrpid");
break;
default:
printf ("------ Message Queues --------\n");
- printf ("%-10s%-10s%-10s%-12s%-12s\n", "msqid","owner",
- "perms", "used-bytes", "messages");
+ printf ("%-10s%-10s%-10s%-10s%-12s%-12s\n", "key","msqid",
+ "owner", "perms", "used-bytes", "messages");
break;
}
@@ -442,9 +461,16 @@ void do_msg (char format)
msgque.msg_ctime ? ctime(&msgque.msg_ctime) + 4 : "Not set");
break;
case PID:
- break;
-
+ if (pw)
+ printf ("%-8d%-10.10s", msqid, pw->pw_name);
+ else
+ printf ("%-8d%-10d", msqid, ipcp->uid);
+ printf (" %5d %5d\n",
+ msgque.msg_lspid, msgque.msg_lrpid);
+ break;
+
default:
+ printf( "0x%08x ",ipcp->KEY );
if (pw)
printf ("%-10d%-10.10s", msqid, pw->pw_name);
else
diff --git a/sys-utils/kbdrate.c b/sys-utils/kbdrate.c
index d8632a204..e61fb8906 100644
--- a/sys-utils/kbdrate.c
+++ b/sys-utils/kbdrate.c
@@ -23,31 +23,55 @@ 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)
- */
+
+ kbdrate.c -- Set keyboard typematic rate (and delay)
+ Created: Thu Apr 23 12:24:30 1992
+ 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)
+
+ Linux/68k modifications by Roman Hodek
+ (Roman.Hodek@informatik.uni-erlangen.de):
+
+ Reading/writing the Intel I/O ports via /dev/port is not the
+ English way... Such hardware dependant stuff can never work on
+ other architectures.
+
+ Linux/68k has an new ioctl for setting the keyboard repeat rate
+ and delay. Both values are counted in msecs, the kernel will do
+ any rounding to values possible with the underlying hardware.
+
+ kbdrate now first tries if the KDKBDREP ioctl is available. If it
+ is, it is used, else the old method is applied.
+
+*/
#include <stdio.h>
+#include <unistd.h>
#include <stdlib.h>
#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= 131072
+/* Kd.h is not available with all linux versions. 131072 is equivalent
+ to linux 2.0.0 */
+#include <linux/kd.h>
+#endif
+
+#define VERSION "1.3"
static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
133, 120, 109, 100, 92, 86, 80, 75, 67,
@@ -58,7 +82,12 @@ static int valid_rates[] = { 300, 267, 240, 218, 200, 185, 171, 160, 150,
static int valid_delays[] = { 250, 500, 750, 1000 };
#define DELAY_COUNT (sizeof( valid_delays ) / sizeof( int ))
-void main( int argc, char **argv )
+#ifdef KDKBDREP
+static int ioctl_possible = 0;
+struct kbd_repeat kbdrep_s;
+#endif
+
+int main( int argc, char **argv )
{
double rate = 10.9; /* Default rate */
int delay = 250; /* Default delay */
@@ -72,7 +101,7 @@ void main( int argc, char **argv )
extern char *optarg;
extern int optind;
- while ( (c = getopt( argc, argv, "r:d:s" )) != EOF )
+ while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF )
switch (c) {
case 'r':
rate = atof( optarg );
@@ -83,48 +112,89 @@ void main( int argc, char **argv )
case 's':
silent = 1;
break;
+ case 'v':
+ fprintf( stderr, "util-linux kbdrate " VERSION "\n");
+ exit(0);
}
- 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 );
+#ifdef KDKBDREP
+ kbdrep_s.rate = -1; /* don't change, just test */
+ kbdrep_s.delay = -1;
+ if (ioctl( 0, KDKBDREP, &kbdrep_s )) {
+ if (errno == EINVAL)
+ ioctl_possible = 0;
+ else {
+ perror( "ioctl(KDKBDREP)" );
+ exit( 1 );
+ }
+ } else ioctl_possible = 1;
+
+ if (ioctl_possible) {
+ kbdrep_s.rate = 1000.0 / rate; /* convert cps to msec */
+ if (kbdrep_s.rate < 1) kbdrep_s.rate = 1;
+ kbdrep_s.delay = delay;
+ if (kbdrep_s.delay < 1) kbdrep_s.delay = 1;
+
+ if (ioctl( 0, KDKBDREP, &kbdrep_s )) {
+ perror( "ioctl(KDKBDREP)" );
+ exit( 1 );
+ }
+
+ if (!silent)
+ printf( "Typematic Rate set to %.1f cps (delay = %d mS)\n",
+ 1000.0 / (double)kbdrep_s.rate, kbdrep_s.delay );
+ } else {
+#endif
+
+ /* The ioport way */
+
+ 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 ] );
+
+#ifdef KDKBREP
}
+#endif
- 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 ] );
+ return 0;
}
diff --git a/sys-utils/rdev.c b/sys-utils/rdev.c
index cb3a730ee..77e1a58f5 100644
--- a/sys-utils/rdev.c
+++ b/sys-utils/rdev.c
@@ -54,8 +54,11 @@ Wed Jun 22 21:12:29 1994: Applied patches from Dave
*/
+#include <stdio.h>
+
/* rdev.c - query/set root device. */
+void
usage()
{
@@ -108,7 +111,7 @@ static char *find_dev(int number)
if (!number) return "Boot device";
if ((dp = opendir("/dev")) == NULL) die("opendir /dev");
strcpy(name,"/dev/");
- while (dir = readdir(dp)) {
+ while ((dir = readdir(dp)) != NULL) {
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;
@@ -128,11 +131,12 @@ char *desc[6] = { "Root device", "Video mode", "Ramsize", "Swap device",
int main(int argc,char **argv)
{
int image,offset,dev_nr, i, newoffset=-1;
- char *device, cmd = 0, *ptr, tmp[40];
+ char *device, *ptr;
struct stat s;
+ int cmd = 0;
device = NULL;
- if (ptr = strrchr(argv[0],'/'))
+ if ((ptr = strrchr(argv[0],'/')) != NULL)
ptr++;
else
ptr = argv[0];
diff --git a/sys-utils/readprofile.1 b/sys-utils/readprofile.1
index fd5d7196d..a72113c85 100644
--- a/sys-utils/readprofile.1
+++ b/sys-utils/readprofile.1
@@ -1,4 +1,4 @@
-.TH READPROFILE 1 "January 1995"
+.TH READPROFILE 1 "May 1996"
.UC 4
.SH NAME
readprofile - a tool to read kernel profiling information
@@ -9,7 +9,7 @@ readprofile - a tool to read kernel profiling information
]
.SH VERSION
-This manpage documents version 1.1 of the program.
+This manpage documents version 2.0 of the program.
.SH DESCRIPTION
@@ -33,12 +33,6 @@ Available command line options are the following:
.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.
@@ -50,10 +44,10 @@ Specify a different profiling buffer, which by default is
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.
+file can be copied using `cat' or `cp'. There is no more support for
+compressed profile buffers, like in
+.B readprofile-1.1,
+because the program needs to know the size of the buffer in advance.
.TP
.B -i
@@ -61,7 +55,8 @@ 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').
+is chosen during kernel configuration (through `make config'),
+or in the kernel's command line.
If the
.B -t
(terse) switch is used together with
@@ -77,13 +72,10 @@ ticks are not printed.
.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.
+is readable by everybody but writable only by the superuser. However,
+you can make
+.B readprofile
+setuid 0, in order to reset the buffer without gaining privileges.
.TP
.B -v
@@ -119,9 +111,9 @@ Look at all the kernel information, with ram addresses"
readprofile -av | less
.fi
-Browse a gzipped `freezed' profile buffer for a non current kernel:
+Browse a `freezed' profile buffer for a non current kernel:
.nf
- readprofile -p ~/profile.freeze.gz -m /zImage.map
+ readprofile -p ~/profile.freeze -m /zImage.map.gz
.fi
@@ -129,31 +121,30 @@ Browse a gzipped `freezed' profile buffer for a non current kernel:
.LP
.B readprofile
-needs a kernel version 1.1.73 or newer, because
+only works with an 1.3.x or newer kernel,
+because
.B /proc/profile
-is absent
-in older versions.
+changed in the step from 1.2 to 1.3
.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.
+This program only works with ELF kernels. The change for a.out kernels
+is trivial, and left as an exercise to the a.out user.
+
+.LP
+To enable profiling, the kernel must be rebooted, because no profiling module
+is available, and it wouldn't be easy to build. To enable profiling,
+you can specify "profile=2" (or another number) on the kernel commandline.
+The number you specify is the two-exponent used as profiling step.
.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
index 58234f6af..4c52cf1fa 100644
--- a/sys-utils/readprofile.c
+++ b/sys-utils/readprofile.c
@@ -1,7 +1,7 @@
/*
* readprofile.c - used to read /proc/profile
*
- * Copyright (C) 1994 Alessandro Rubini
+ * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
*
* 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
@@ -18,20 +18,23 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h> /* getopt() */
+#include <unistd.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
-#define RELEASE "1.1, Jan 1995"
+#define RELEASE "2.0, May 1996"
#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";
+/* These are the defaults */
+static char defaultmap[]="/usr/src/linux/System.map";
static char defaultpro[]="/proc/profile";
static char optstring[]="m:p:itvarV";
@@ -42,12 +45,11 @@ void usage()
"\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);
+ ,prgname,prgname,defaultmap,defaultpro);
exit(1);
}
@@ -56,11 +58,11 @@ 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=1;
+ sprintf(cmdline,"zcat %s", name);
+ return popen(cmdline,mode);
+ }
*flag=0;
return fopen(name,mode);
}
@@ -69,24 +71,24 @@ 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 */
+int proFd;
+char *mapFile, *proFile;
+unsigned int len, add0=0, step, index=0;
+unsigned int *buf, total, fn_len;
+unsigned int fn_add, next_add; /* current and next address */
+char fn_name[S_LEN], next_name[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;
+int c;
+int optAll=0, optInfo=0, optReset=0, optVerbose=0;
char mapline[S_LEN];
int maplineno=1;
-int popenMap, popenPro; /* flags to tell if popen() is used */
+int popenMap; /* flag to tell if popen() has been used */
#define next (current^1)
prgname=argv[0];
proFile=defaultpro;
- mapFile=defaultmap1;
+ mapFile=defaultmap;
while ((c=getopt(argc,argv,optstring))!=-1)
{
@@ -96,128 +98,121 @@ int popenMap, popenPro; /* flags to tell if popen() is used */
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);
+ 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);
+ {
+ /* try to become root, just in case */
+ setuid(0);
+ 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
+ * Use an fd for the profiling buffer, to skip stdio overhead
*/
- 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)
+ if ( ((proFd=open(proFile,O_RDONLY)) < 0)
+ || ((len=lseek(proFd,0,SEEK_END)) < 0)
+ || (lseek(proFd,0,SEEK_SET)<0) )
+ {
+ fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
+ exit(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);
+ if ( !(buf=malloc(len)) )
+ { fprintf(stderr,"%s: malloc(): %s\n",prgname, strerror(errno)); exit(1); }
+
+ if (read(proFd,buf,len) != len)
+ {
+ fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno));
exit(1);
}
+ close(proFd);
+ step=buf[0];
if (optInfo)
{
- printf(optTerse ? "%i\n" : "The sampling step in the kernel is %i bytes\n",
- step);
+ printf("Sampling_step: %i\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;
+ total=0;
+ if (!(map=myopen(mapFile,"r",&popenMap)))
+ {fprintf(stderr,"%s: ",prgname);perror(mapFile);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);
- }
+ while(fgets(mapline,S_LEN,map))
+ {
+ if (sscanf(mapline,"%x %s %s",&fn_add,mode,fn_name)!=3)
+ {
+ fprintf(stderr,"%s: %s(%i): wrong map line\n",
+ prgname,mapFile, maplineno);
+ exit(1);
+ }
+ if (strcmp(fn_name,"_stext")) /* only elf works like this */
+ {
+ add0=fn_add;
+ break;
+ }
+ }
- if (!(fn_len=fn_add[next]-fn_add[current]))
- continue;
+ if (!add0)
+ {
+ fprintf(stderr,"%s: can't find \"_stext\" in %s\n",prgname, mapFile);
+ exit(1);
+ }
- if (*mode=='d' || *mode=='D') break; /* only text is profiled */
+ /*
+ * Main loop.
+ */
+ while(fgets(mapline,S_LEN,map))
+ {
+ unsigned int this=0;
- while (add<fn_add[next])
+ if (sscanf(mapline,"%x %s %s",&next_add,mode,next_name)!=3)
{
- if (!NEXT_WORD(&l))
- {
- fprintf(stderr,"%s: %s: premature EOF\n",prgname,proFile);
- exit(1);
- }
- count+=l; add+=step;
+ fprintf(stderr,"%s: %s(%i): wrong map line\n",
+ prgname,mapFile, maplineno);
+ exit(1);
}
+ if (*mode!='T' && *mode!='t') break; /* only text is profiled */
+
+ while (index < (next_add-add0)/step)
+ this += buf[index++];
+ total += this;
- 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);
- }
+ fn_len = next_add-fn_add;
+ if (fn_len && (this || optAll))
+ {
+ if (optVerbose)
+ printf("%08x %-40s %6i %8.4f\n",
+ fn_add,fn_name,this,this/(double)fn_len);
+ else
+ printf("%6i %-40s %8.4f\n",
+ this,fn_name,this/(double)fn_len);
+ }
+ fn_add=next_add; strcpy(fn_name,next_name);
+ }
+ /* trailer */
+ if (optVerbose)
+ printf("%08x %-40s %6i %8.4f\n",
+ 0,"total",total,total/(double)(fn_add-add0));
+ else
+ printf("%6i %-40s %8.4f\n",
+ total,"total",total/(double)(fn_add-add0));
- popenPro ? pclose(pro) : fclose(pro);
popenMap ? pclose(map) : fclose(map);
exit(0);
}
+
diff --git a/sys-utils/renice.8 b/sys-utils/renice.8
index 5a260a8db..7c1222cd2 100644
--- a/sys-utils/renice.8
+++ b/sys-utils/renice.8
@@ -124,6 +124,11 @@ to map user names to user ID's
.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.
+.br
+The Linux kernel (at least version 2.0.0) and linux libc (at least
+version 5.2.18) does not agree entierly on what the specifics of the
+systemcall interface to set nice values is. Thus causes renice to
+report bogus previous nice values.
.Sh HISTORY
The
.Nm
diff --git a/sys-utils/renice.c b/sys-utils/renice.c
index 6deba6b00..63af8cd4e 100644
--- a/sys-utils/renice.c
+++ b/sys-utils/renice.c
@@ -47,12 +47,16 @@ static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93";
#include <stdio.h>
#include <pwd.h>
+#include <stdlib.h>
+
+int donice(int,int,int);
/*
* Change the priority (nice) of processes
* or groups of processes which are already
* running.
*/
+void
main(argc, argv)
char **argv;
{
@@ -106,6 +110,7 @@ main(argc, argv)
exit(errs != 0);
}
+int
donice(which, who, prio)
int which, who, prio;
{
diff --git a/sys-utils/setserial.8 b/sys-utils/setserial.8
deleted file mode 100644
index 539db21a2..000000000
--- a/sys-utils/setserial.8
+++ /dev/null
@@ -1,392 +0,0 @@
-.\" 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
deleted file mode 100644
index 71179baa8..000000000
--- a/sys-utils/setserial.c
+++ /dev/null
@@ -1,436 +0,0 @@
-/* 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/shhopt-1.1.lsm b/sys-utils/shhopt-1.1.lsm
new file mode 100644
index 000000000..a61a26969
--- /dev/null
+++ b/sys-utils/shhopt-1.1.lsm
@@ -0,0 +1,17 @@
+Begin3
+Title: shhopt - library for parsing command line options.
+Version: 1.1
+Entered-date: 06JUN96
+Description: C-functions for parsing command line options, both
+ traditional one-character options, and GNU'ish
+ --long-options.
+Keywords: programming, library, lib, commandline
+Author: sverrehu@ifi.uio.no (Sverre H. Huseby)
+Primary-site: sunsite.unc.edu /pub/Linux/libs
+ shhopt-1.1.tar.gz
+Platforms: Requires ANSI C-compiler.
+Copying-policy: BeerWare: If you have the time and money, send me a bottle
+ of your favourite beer. If not, just send me a mail or
+ something. Copy and use as you wish; just leave the
+ author's name where you find it.
+End
diff --git a/sys-utils/shhopt.c b/sys-utils/shhopt.c
new file mode 100644
index 000000000..6d31225c8
--- /dev/null
+++ b/sys-utils/shhopt.c
@@ -0,0 +1,467 @@
+/* $Id: shhopt.c,v 2.2 1997/07/06 23:11:55 aebr Exp $ */
+/**************************************************************************
+ *
+ * FILE shhopt.c
+ *
+ * DESCRIPTION Functions for parsing command line arguments. Values
+ * of miscellaneous types may be stored in variables,
+ * or passed to functions as specified.
+ *
+ * REQUIREMENTS Some systems lack the ANSI C -function strtoul. If your
+ * system is one of those, you'll ned to write one yourself,
+ * or get the GNU liberty-library (from prep.ai.mit.edu).
+ *
+ * WRITTEN BY Sverre H. Huseby <sverrehu@ifi.uio.no>
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+
+#include "shhopt.h"
+
+/**************************************************************************
+ * *
+ * P R I V A T E D A T A *
+ * *
+ **************************************************************************/
+
+static void optFatalFunc(const char *, ...);
+static void (*optFatal)(const char *format, ...) = optFatalFunc;
+
+
+
+/**************************************************************************
+ * *
+ * P R I V A T E F U N C T I O N S *
+ * *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optFatalFunc
+ *
+ * FUNCTION Show given message and abort the program.
+ *
+ * INPUT format, ...
+ * Arguments used as with printf().
+ *
+ * RETURNS Never returns. The program is aborted.
+ *
+ */
+void optFatalFunc(const char *format, ...)
+{
+ va_list ap;
+
+ fflush(stdout);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(99);
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optStructCount
+ *
+ * FUNCTION Get number of options in a optStruct.
+ *
+ * INPUT opt array of possible options.
+ *
+ * RETURNS Number of options in the given array.
+ *
+ * DESCRIPTION Count elements in an optStruct-array. The strcture must
+ * be ended using an element of type OPT_END.
+ *
+ */
+static int optStructCount(const optStruct opt[])
+{
+ int ret = 0;
+
+ while (opt[ret].type != OPT_END)
+ ++ret;
+ return ret;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optMatch
+ *
+ * FUNCTION Find a matching option.
+ *
+ * INPUT opt array of possible options.
+ * s string to match, without `-' or `--'.
+ * lng match long option, otherwise short.
+ *
+ * RETURNS Index to the option if found, -1 if not found.
+ *
+ * DESCRIPTION Short options are matched from the first character in
+ * the given string.
+ *
+ */
+static int optMatch(const optStruct opt[], const char *s, int lng)
+{
+ int nopt, q, matchlen = 0;
+ char *p;
+
+ nopt = optStructCount(opt);
+ if (lng) {
+ if ((p = strchr(s, '=')) != NULL)
+ matchlen = p - s;
+ else
+ matchlen = strlen(s);
+ }
+ for (q = 0; q < nopt; q++) {
+ if (lng) {
+ if (!opt[q].longName)
+ continue;
+ if (strncmp(s, opt[q].longName, matchlen) == 0)
+ return q;
+ } else {
+ if (!opt[q].shortName)
+ continue;
+ if (*s == opt[q].shortName)
+ return q;
+ }
+ }
+ return -1;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optString
+ *
+ * FUNCTION Return a (static) string with the option name.
+ *
+ * INPUT opt the option to stringify.
+ * lng is it a long option?
+ *
+ * RETURNS Pointer to static string.
+ *
+ */
+static char *optString(const optStruct *opt, int lng)
+{
+ static char ret[31];
+
+ if (lng) {
+ strcpy(ret, "--");
+ strncpy(ret + 2, opt->longName, 28);
+ } else {
+ ret[0] = '-';
+ ret[1] = opt->shortName;
+ ret[2] = '\0';
+ }
+ return ret;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optNeedsArgument
+ *
+ * FUNCTION Check if an option requires an argument.
+ *
+ * INPUT opt the option to check.
+ *
+ * RETURNS Boolean value.
+ *
+ */
+static int optNeedsArgument(const optStruct *opt)
+{
+ return opt->type == OPT_STRING
+ || opt->type == OPT_INT
+ || opt->type == OPT_UINT
+ || opt->type == OPT_LONG
+ || opt->type == OPT_ULONG;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME argvRemove
+ *
+ * FUNCTION Remove an entry from an argv-array.
+ *
+ * INPUT argc pointer to number of options.
+ * argv array of option-/argument-strings.
+ * i index of option to remove.
+ *
+ * OUTPUT argc new argument count.
+ * argv array with given argument removed.
+ *
+ */
+static void argvRemove(int *argc, char *argv[], int i)
+{
+ if (i >= *argc)
+ return;
+ while (i++ < *argc)
+ argv[i - 1] = argv[i];
+ --*argc;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optExecute
+ *
+ * FUNCTION Perform the action of an option.
+ *
+ * INPUT opt array of possible options.
+ * arg argument to option, if it applies.
+ * lng was the option given as a long option?
+ *
+ * RETURNS Nothing. Aborts in case of error.
+ *
+ */
+void optExecute(const optStruct *opt, char *arg, int lng)
+{
+ switch (opt->type) {
+ case OPT_FLAG:
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(void)) opt->arg)();
+ else
+ *((int *) opt->arg) = 1;
+ break;
+
+ case OPT_STRING:
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(char *)) opt->arg)(arg);
+ else
+ *((char **) opt->arg) = arg;
+ break;
+
+ case OPT_INT:
+ case OPT_LONG: {
+ long tmp;
+ char *e;
+
+ tmp = strtol(arg, &e, 10);
+ if (*e)
+ optFatal("invalid number `%s'\n", arg);
+ if (errno == ERANGE
+ || (opt->type == OPT_INT && (tmp > INT_MAX || tmp < INT_MIN)))
+ optFatal("number `%s' to `%s' out of range\n",
+ arg, optString(opt, lng));
+ if (opt->type == OPT_INT) {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(int)) opt->arg)((int) tmp);
+ else
+ *((int *) opt->arg) = (int) tmp;
+ } else /* OPT_LONG */ {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(long)) opt->arg)(tmp);
+ else
+ *((long *) opt->arg) = tmp;
+ }
+ break;
+ }
+
+ case OPT_UINT:
+ case OPT_ULONG: {
+ unsigned long tmp;
+ char *e;
+
+ tmp = strtoul(arg, &e, 10);
+ if (*e)
+ optFatal("invalid number `%s'\n", arg);
+ if (errno == ERANGE
+ || (opt->type == OPT_UINT && tmp > UINT_MAX))
+ optFatal("number `%s' to `%s' out of range\n",
+ arg, optString(opt, lng));
+ if (opt->type == OPT_UINT) {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(unsigned)) opt->arg)((unsigned) tmp);
+ else
+ *((unsigned *) opt->arg) = (unsigned) tmp;
+ } else /* OPT_ULONG */ {
+ if (opt->flags & OPT_CALLFUNC)
+ ((void (*)(unsigned long)) opt->arg)(tmp);
+ else
+ *((unsigned long *) opt->arg) = tmp;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+
+
+/**************************************************************************
+ * *
+ * P U B L I C F U N C T I O N S *
+ * *
+ **************************************************************************/
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optSetFatalFunc
+ *
+ * FUNCTION Set function used to display error message and exit.
+ *
+ * SYNOPSIS #include "shhmsg.h"
+ * void optSetFatalFunc(void (*f)(const char *, ...));
+ *
+ * INPUT f function accepting printf()'like parameters,
+ * that _must_ abort the program.
+ *
+ */
+void optSetFatalFunc(void (*f)(const char *, ...))
+{
+ optFatal = f;
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * NAME optParseOptions
+ *
+ * FUNCTION Parse commandline options.
+ *
+ * SYNOPSIS #include "shhopt.h"
+ * void optParseOptions(int *argc, char *argv[],
+ * const optStruct opt[], int allowNegNum);
+ *
+ * INPUT argc Pointer to number of options.
+ * argv Array of option-/argument-strings.
+ * opt Array of possible options.
+ * allowNegNum
+ * a negative number is not to be taken as
+ * an option.
+ *
+ * OUTPUT argc new argument count.
+ * argv array with arguments removed.
+ *
+ * RETURNS Nothing. Aborts in case of error.
+ *
+ * DESCRIPTION This function checks each option in the argv-array
+ * against strings in the opt-array, and `executes' any
+ * matching action. Any arguments to the options are
+ * extracted and stored in the variables or passed to
+ * functions pointed to by entries in opt.
+ *
+ * Options and arguments used are removed from the argv-
+ * array, and argc is decreased accordingly.
+ *
+ * Any error leads to program abortion.
+ *
+ */
+void optParseOptions(int *argc, char *argv[],
+ const optStruct opt[], int allowNegNum)
+{
+ int ai, /* argv index. */
+ optarg, /* argv index of option argument, or -1 if none. */
+ mi, /* Match index in opt. */
+ done;
+ char *arg, /* Pointer to argument to an option. */
+ *o, /* pointer to an option character */
+ *p;
+
+ /*
+ * Loop through all arguments.
+ */
+ for (ai = 0; ai < *argc; ) {
+ /*
+ * "--" indicates that the rest of the argv-array does not
+ * contain options.
+ */
+ if (strcmp(argv[ai], "--") == 0) {
+ argvRemove(argc, argv, ai);
+ break;
+ }
+
+ if (allowNegNum && argv[ai][0] == '-' && isdigit(argv[ai][1])) {
+ ++ai;
+ continue;
+ } else if (strncmp(argv[ai], "--", 2) == 0) {
+ /* long option */
+ /* find matching option */
+ if ((mi = optMatch(opt, argv[ai] + 2, 1)) < 0)
+ optFatal("unrecognized option `%s'\n", argv[ai]);
+
+ /* possibly locate the argument to this option. */
+ arg = NULL;
+ if ((p = strchr(argv[ai], '=')) != NULL)
+ arg = p + 1;
+
+ /* does this option take an argument? */
+ optarg = -1;
+ if (optNeedsArgument(&opt[mi])) {
+ /* option needs an argument. find it. */
+ if (!arg) {
+ if ((optarg = ai + 1) == *argc)
+ optFatal("option `%s' requires an argument\n",
+ optString(&opt[mi], 1));
+ arg = argv[optarg];
+ }
+ } else {
+ if (arg)
+ optFatal("option `%s' doesn't allow an argument\n",
+ optString(&opt[mi], 1));
+ }
+ /* perform the action of this option. */
+ optExecute(&opt[mi], arg, 1);
+ /* remove option and any argument from the argv-array. */
+ if (optarg >= 0)
+ argvRemove(argc, argv, ai);
+ argvRemove(argc, argv, ai);
+ } else if (*argv[ai] == '-') {
+ /* A dash by itself is not considered an option. */
+ if (argv[ai][1] == '\0') {
+ ++ai;
+ continue;
+ }
+ /* Short option(s) following */
+ o = argv[ai] + 1;
+ done = 0;
+ optarg = -1;
+ while (*o && !done) {
+ /* find matching option */
+ if ((mi = optMatch(opt, o, 0)) < 0)
+ optFatal("unrecognized option `-%c'\n", *o);
+
+ /* does this option take an argument? */
+ optarg = -1;
+ arg = NULL;
+ if (optNeedsArgument(&opt[mi])) {
+ /* option needs an argument. find it. */
+ arg = o + 1;
+ if (!*arg) {
+ if ((optarg = ai + 1) == *argc)
+ optFatal("option `%s' requires an argument\n",
+ optString(&opt[mi], 0));
+ arg = argv[optarg];
+ }
+ done = 1;
+ }
+ /* perform the action of this option. */
+ optExecute(&opt[mi], arg, 0);
+ ++o;
+ }
+ /* remove option and any argument from the argv-array. */
+ if (optarg >= 0)
+ argvRemove(argc, argv, ai);
+ argvRemove(argc, argv, ai);
+ } else {
+ /* a non-option argument */
+ ++ai;
+ }
+ }
+}
diff --git a/sys-utils/shhopt.h b/sys-utils/shhopt.h
new file mode 100644
index 000000000..ca8501ef5
--- /dev/null
+++ b/sys-utils/shhopt.h
@@ -0,0 +1,33 @@
+/* $Id: shhopt.h,v 2.2 1997/07/06 23:11:58 aebr Exp $ */
+#ifndef SHHOPT_H
+#define SHHOPT_H
+
+/* constants for recognized option types. */
+typedef enum {
+ OPT_END, /* nothing. used as ending element. */
+ OPT_FLAG, /* no argument following. sets variable to 1. */
+ OPT_STRING, /* string argument. */
+ OPT_INT, /* signed integer argument. */
+ OPT_UINT, /* unsigned integer argument. */
+ OPT_LONG, /* signed long integer argument. */
+ OPT_ULONG, /* unsigned long integer argument. */
+} optArgType;
+
+/* flags modifying the default way options are handeled. */
+#define OPT_CALLFUNC 1 /* pass argument to a function. */
+
+typedef struct {
+ char shortName; /* Short option name. */
+ char *longName; /* Long option name, no including '--'. */
+ optArgType type; /* Option type. */
+ void *arg; /* Pointer to variable to fill with argument,
+ * or pointer to function if Type == OPT_FUNC. */
+ int flags; /* Modifier flags. */
+} optStruct;
+
+
+void optSetFatalFunc(void (*f)(const char *, ...));
+void optParseOptions(int *argc, char *argv[],
+ const optStruct opt[], int allowNegNum);
+
+#endif
diff --git a/sys-utils/sln.1 b/sys-utils/sln.1
new file mode 100644
index 000000000..a89271936
--- /dev/null
+++ b/sys-utils/sln.1
@@ -0,0 +1,22 @@
+.\" Nicolai Langfeldt (janl@math.uio.no)
+.\" In the public domain.
+.TH SLN 8 "20 June 1997" "Linux 2.0" "Linux Programmer's Manual"
+.SH NAME
+sln \- static ln
+.SH SYNOPSIS
+.BI sln " source dest"
+.SH DESCRIPTION
+.B sln
+symbolically links
+.I dest
+to
+.I source
+It is statically linked, needing no dynamic linking at all. This that
+sln is usefull to make symbolic links to dynamic libraries if the
+dynamic linking system for some reason is nonfunctional.
+.SH "SEE ALSO"
+.BR ln(1)
+.BR ldconfig(8)
+.BR ld.so(8)
+.SH AUTHOR
+Mike Parker and David MacKenzie.
diff --git a/sys-utils/sync.8 b/sys-utils/sync.8
deleted file mode 100644
index f8bb704ff..000000000
--- a/sys-utils/sync.8
+++ /dev/null
@@ -1,38 +0,0 @@
-.\" 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
deleted file mode 100644
index 5b7fd82b2..000000000
--- a/sys-utils/sync.S
+++ /dev/null
@@ -1,24 +0,0 @@
-/* File:
- * sync.S
- * Compile:
- * gcc -nostdlib sync.S -o sync
- * Author:
- * Nick Holloway, with thanks to James Bonfield
- * Modified for ELF by Michael Shields
- * Rik Faith added __ASSEMBLY__ for gcc 2.5.8
- * Last Changed:
- * 1995-07-04
- */
-#include <sys/syscall.h>
-#ifndef __ASSEMBLY__
-#define __ASSEMBLY__
-#endif
-#include <linux/linkage.h>
-
- .text
-ENTRY(_start)
- 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
index bff567626..8b148f20a 100644
--- a/sys-utils/tunelp.8
+++ b/sys-utils/tunelp.8
@@ -1,8 +1,8 @@
-.\" 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.
-.\" $Id: tunelp.8,v 1.5 1995/03/12 01:34:24 faith Exp $
+.\" This file Copyright (C) 1992-1997 Michael K. Johnson <johnsonm@redhat.com>
+.\" It may be distributed under the terms of the GNU General Public License,
+.\" version 2, or any higher version. See section COPYING of the GNU General
+.\" Public license for conditions under which this file may be redistributed.
+.\" $Id: tunelp.8,v 1.6 1997/06/20 16:10:35 janl Exp $
.TH tunelp 8 "26 August 1992" "Cohesive Systems" "Linux Programmer's Manual"
.SH NAME
tunelp \- set various parameters for the lp device
diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c
index a854b46b1..6bdebda72 100644
--- a/sys-utils/tunelp.c
+++ b/sys-utils/tunelp.c
@@ -1,18 +1,30 @@
/****************************************************************************\
-* Copyright (C) 1992 by Michael K. Johnson, johnsonm@nigel.vnet.net *
+* Copyright (C) 1992-1997 Michael K. Johnson, johnsonm@redhat.com *
* *
-* This file is placed under the conditions of the GNU public *
-* license, version 2, or any later version. See file COPYING *
+* This file is licensed under the terms of the GNU General *
+* Public License, version 2, or any later version. See file COPYING *
* for information on distribution conditions. *
\****************************************************************************/
-/* $Id: tunelp.c,v 1.6 1995/06/04 01:47:11 faith Exp $
+/* $Id: tunelp.c,v 1.8 1997/07/06 00:14:06 aebr Exp $
* $Log: tunelp.c,v $
- * Revision 1.6 1995/06/04 01:47:11 faith
- * Changes for util-linux-2.4
+ * Revision 1.8 1997/07/06 00:14:06 aebr
+ * Fixes to silence -Wall.
*
- * Revision 1.5 1995/03/12 01:29:50 faith
- * util-linux-2.1
+ * Revision 1.7 1997/06/20 16:10:38 janl
+ * tunelp refreshed from authors archive.
+ *
+ * Revision 1.9 1997/06/20 12:56:43 johnsonm
+ * Finished fixing license terms.
+ *
+ * Revision 1.8 1997/06/20 12:34:59 johnsonm
+ * Fixed copyright and license.
+ *
+ * Revision 1.7 1995/03/29 11:16:23 johnsonm
+ * TYPO fixed...
+ *
+ * Revision 1.6 1995/03/29 11:12:15 johnsonm
+ * Added third argument to ioctl needed with new kernels
*
* Revision 1.5 1995/01/13 10:33:43 johnsonm
* Chris's changes for new ioctl numbers and backwards compatibility
@@ -74,7 +86,7 @@ void *mylloc(long size) {
long get_val(char *val) {
long ret;
- if (!(sscanf(val, "%d", &ret) == 1)) {
+ if (!(sscanf(val, "%ld", &ret) == 1)) {
perror("sscanf error");
exit(3);
}
@@ -198,6 +210,8 @@ int main (int argc, char ** argv) {
}
/* Allow for binaries compiled under a new kernel to work on the old ones */
+ /* The irq argument to ioctl isn't touched by the old kernels, but we don't */
+ /* want to cause the kernel to complain if we are using a new kernel */
if (LPGETIRQ >= 0x0600 && ioctl(fd, LPGETIRQ, &irq) < 0 && errno == EINVAL)
offset = 0x0600; /* We don't understand the new ioctls */