From: Karel Zak Date: Wed, 6 Dec 2006 23:25:34 +0000 (+0100) Subject: Imported from util-linux-2.7.1 tarball. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd6b7a7ffc50400704beb41d5a23af5f9edb1eed;p=util-linux Imported from util-linux-2.7.1 tarball. --- diff --git a/ANNOUNCE b/ANNOUNCE index 8af6f911..ad02f841 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,71 +1,39 @@ +util-linux-2.7.tar.gz (source only distribution) -util-linux-2.5.tar.gz (source distribution only) +READ the README file and the stuff below. - WARNING: THIS COLLECTION DOES *NOT* SUPPORT SHADOW PASSWORDS. +util-linux-2.7.tar.gz (source only distribution) - WARNING: THIS COLLECTION DOES *NOT* SUPPORT SYSTEM V INITTAB. +NOTE: Before installing util-linux. READ the README or risk nuking +your system. Thank you. - WARNING: DO *NOT* INSTALL WITHOUT THINKING. + Util-linux is a suite of essential utilities for any Linux system. +It's primary audience is system integrators (like the people at +RedHat) and DIY Linux hackers. The rest of you will get a digested +version of util-linux installed with no risk to your sanity. - This is a collection of many assorted utilities for Linux. Some are - system utilities that are not easily available anywhere elsewhere - (e.g., mkfs.minix, mkswap, cfdisk, fdisk); others are BSD ports of - common utilities that are not yet contained in any FSF package (e.g., - col); others are non-System-V alternatives to common utilities (e.g., - simpleinit, agetty, login, passwd). + Version 2.7 of util-linux is mostly a bugfix release. But several +utilities that appear in other packages have been removed and +hwclock(8) has replaced clock(8) entirely. - The arrangement, as nearly as I can determine, conforms to the Linux - Filesystem Structure, Interim Release 1.2, March 28, 1995, with *NO* - exceptions. A copy of the standards document can be found at - tsx-11.mit.edu:/pub/linux/docs/linux-standards/fsstnd/*. + Util-linux is attempting to be portable, but the only platform it +has been tested much on is linux/intel. There have however been +integrated several patches for Arm, m68k, and Alpha linux versions. +The present version is known to compile on at least Linux 1.2/libc 4 +and Linux 2.0/Libc 5 and has also been tested with libc 6 on intel, +alpha and sparc. People are encouraged to make _nice_ patches to +util-linux and submitting them to util-linux@math.uio.no. Thank you. - Many people provided patches and suggestions. I deeply appreciate - this. +[To be more precise, earlier versions of util-linux did compile on +Linux 1.2/libc 4. The present version contains at least one obstacle: +the routine snprintf() is not available in libc 4.5.26, but it is in 4.6.27.] - This product includes software developed by the University of - California, Berkeley and its contributors. +Util-Linux 2.7 is imediately available from + ftp.math.uio.no:/pub/linux, and + sunsite.uio.no:/pub/unix/linux/packages/util-linux, +and will appear at + sunsite.unc.edu:/pub/Linux/system/Misc, as well as + tsx-11.mit.edu:/pub/linux/packages/utils +when the people in charge there get time. - IN THE FUTURE, SEND UPDATES AND PATCHES TO: util-linux@math.uio.no - - - -HIGHLIGHTS for version 2.5: - -0) Nicolai Langfeldt is taking over maintenance of util-linux, with the - help of a few others (Michael K. Johnson, Andries Brouwer, and Rik - Faith). - - PLEASE SEND PATCHES AND UPDATES TO: util-linux@math.uio.no - -1) The following packages have been removed. Please use the up-to-date, - canonical versions of these packages from the listed places: - - timezone support (/usr/lib/zoneinfo, libz.a, zic, zdump): - elsie.nci.nih.gov:/pub/tzcode95d.tar.gz - elsie.nci.nih.gov:/pub/tzdata95h.tar.gz - MAKEDEV-C: - sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-C-1.5.tar.gz - MAKEDEV: - sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-2.2.tar.gz - md5sum: - prep.ai.mit.edu:/pub/gnu/textutils-1.3.tar.gz - [The GNU version is now compatible with the Plumb/Lankester - version.] - ksymoops: - Now bundled with the kernel in linux/scripts. - -2) update_state has been removed -3) fdisk now supports NetBSD disklabels courtesy of Bernhard Fastenrath - (and > 8GB disks, courtesy of - Andries Brouwer) -4) mount improved -- many patches from Andries Brouwer for greatly improved - error reporting -5) ddate, chkdupexe, and other programs have been improved and bug fixed -6) util-linux is now a source-only distribution -7) mcookie generates better random numbers and will use /dev/random or - /dev/audio if available -8) chfn, chsh, passwd, and vipw have been updated with security patches - from Zefram . Now, they all use the same - locking, and several security holes have been patched. Further, chsh - and chfn can be configured at compile time to require a password before - updates and chsh can be configured to only use shells from /etc/shells. +Nicolai Langfeldt diff --git a/FAQ b/FAQ new file mode 100644 index 00000000..0eabb0e5 --- /dev/null +++ b/FAQ @@ -0,0 +1,11 @@ +Util linux faqs: + +Q. Where can I get util-linux? +A. Please read the ANNOUNCE file. + +Q. Will util-linux support shadow passwords? +A. No, not ever. + +Q. Will util-linux support NLS things? +A. Maybe. + diff --git a/LSM b/LSM index 0a64cfe3..a8b483dd 100644 --- a/LSM +++ b/LSM @@ -1,23 +1,25 @@ Begin3 Title: util-linux: Miscellaneous utilities for Linux -Version: 2.5 -Entered-date: Thu Oct 12 15:20:00 1995 -Description: agetty arch cal cat cfdisk chfn chkdupexe chroot chsh clear - clock col colcrt colrm column ctrlaltdel cytune ddate dmesg - dnsdomainname domainname dsplit fastboot fasthalt fdformat - fdisk fsck.minix getopt halt hexdump hostid hostname ipcrm - ipcs kbdrate kill last logger login look mcookie mesg mkfs - mkfs.minix mkswap more mount namei passwd ramsize rdev - readprofile reboot renice reset rev rootflags script - setfdprm setserial setsid setterm shutdown simpleinit sln - strings swapdev swapoff swapon sync syslogd tsort tunelp ul - umount vidmode vipw wall whereis write +Version: 2.7.1 +Description: agetty arch cal cfdisk chfn chkdupexe chroot chsh + clear hwclock col colcrt colrm column ctrlaltdel + cytune ddate dmesg dsplit fastboot fasthalt fdformat + fdisk fsck.minix getopt halt hexdump hostid ipcrm ipcs + kbdrate kill last logger login look mcookie mesg mkfs + mkfs.minix mkswap more mount namei passwd ramsize rdev + readprofile reboot renice reset rev rootflags script + setfdprm setsid setterm sfdisk shutdown simpleinit sln + strings swapdev swapoff swapon tsort tunelp ul umount + vidmode vipw wall whereis write + Keywords: essential utilities Author: several Maintained-by: Nicolai Langfeldt -Primary-site: tsx-11.mit.edu /pub/linux/packages/utils - 487k util-linux-2.5.tar.gz +Primary-site: ftp.math.uio.no /pub/linux + ~520k util-linux-2.7.1.tar.gz +Alternate-site: sunsite.uio.no /pub/unix/linux/packages/util-linux Alternate-site: sunsite.unc.edu /pub/Linux/system/Misc -Platforms: Linux 1.2.x/1.3.x +Alternate-site: tsx-11.mit.edu /pub/linux/packages/utils +Platforms: Linux 1.2.x/1.3.x/2.x/Libc 4/5/6 Copying-policy: GPL, BSD, others End diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 00000000..5229601d --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,19 @@ +util-linux is maintained by a group of people, all reachable at +util-linux@math.uio.no. + +Some have specific interests, others just do everything else. + +This is a partial list of interests: + +Rik: Founding father +Andries: *fdisk, mount, ... +Peter: login, passwd, simpleinit, agetty, last, newgrp, shutdown, hostid, + domainname, ctrlaltdel +Michael: Spirit of advice +Erik: General hackery +Nicolai: mail queue processor (batch oriented) + +Bryan: hwclock master, he's not on the list but the mail queue + processor forwards mail to him. + +Unassigned programs (defaulting to Nicolai): chfn, chsh, write, wall diff --git a/MCONFIG b/MCONFIG index 12fef136..500a3229 100644 --- a/MCONFIG +++ b/MCONFIG @@ -1,15 +1,44 @@ # MCONFIG -- Configuration stuff for util-linux # Created: Sat Feb 4 15:50:30 1995 -# Revised: Thu Oct 12 10:11:33 1995 by r.faith@ieee.org +# Revised: Sun Nov 10 20:10:13 1996 by faith@cs.unc.edu # Copyright 1995 Rickard E. Faith (faith@cs.unc.edu) # +# Not all utils work with all architectures, select yours here. + +# NOTE: UTIL-LINUX has not been tested extensively on anything but +# INTEL. If you find problems in compiling on other architectures +# please provide fix to util-linux@math.uio.no. + +CPU=intel +#CPU=alpha +#CPU=sparc +#CPU=arm +#CPU=m68k +#CPU=mips + +# if HAVE_LIBCRYPT is "yes" -lcrypt will be used +HAVE_LIBCRYPT=no +#HAVE_LIBCRYPT=yes + +# If HAVE_PAM is set to "yes", then login, chfn, chsh, and newgrp +# will use PAM for authentication. Additionally, passwd will not be +# installed as it is not PAM aware. +HAVE_PAM=no +#HAVE_PAM=yes + # If HAVE_SHADOW is set to "yes", then login, chfn, chsh, newgrp, passwd, # and vipw will not be built or installed from the login-utils -# subdirectory. +# subdirectory. HAVE_SHADOW=no #HAVE_SHADOW=yes +# If HAVE_PASSWD is set to "yes", then passwd will not be built or +# installed from the login-utils subdirectory (but login, chfn, chsh, +# newgrp, and vipw *will* be installed). +HAVE_PASSWD=no +#HAVE_PASSWD=yes + # If you use chfn and chsh from this package, REQUIRE_PASSWORD will require # non-root users to enter the account password before updating /etc/passwd. REQUIRE_PASSWORD=yes @@ -22,27 +51,21 @@ ONLY_LISTED_SHELLS=yes #ONLY_LISTED_SHELLS=no -# If HAVE_PASSWD is set to "yes", then passwd will not be built or -# installed from the login-utils subdirectory (but login, chfn, chsh, -# newgrp, and vipw *will* be installed). -HAVE_PASSWD=no -#HAVE_PASSWD=yes - # If HAVE_SYSVINIT is set to "yes", then simpleinit and shutdown will not # be built or installed from the login-utils subdirectory. (The shutdown # and halt that come with the SysVinit package should be used with the init # found in that package.) -HAVE_SYSVINIT=no -#HAVE_SYSVINIT=yes +#HAVE_SYSVINIT=no +HAVE_SYSVINIT=yes # If HAVE_SYSVINIT_UTILS is set to "yes", then last, mesg, and wall will # not be built or installed from the login-utils subdirectory. (The # shutdown and init from the SysVinit package do not depend on the last, # mesg, and wall from that package.) -HAVE_SYSVINIT_UTILS=no -#HAVE_SYSVINIT_UTILS=yes +#HAVE_SYSVINIT_UTILS=no +HAVE_SYSVINIT_UTILS=yes -# If HAVE_ANOTHER_GETTY is set to "yes", then agetty will not be built or +# If HAVE_GETTY is set to "yes", then agetty will not be built or # installed from the login-utils subdirectory. Note that agetty can # co-exist with other gettys, so this option should never be used. HAVE_GETTY=no @@ -60,35 +83,56 @@ USE_TTY_GROUP=yes # If HAVE_STRINGS is set to "yes", then strings won't be installed. This # is the quick fix until the strings in GNU binutils is in wide use and has # internationalization support. -HAVE_STRINGS=no -#HAVE_STRINGS=yes - -# If HAVE_CLEAR is set to "yes", then clear won't be installed, since a -# version of clear comes with the ncurses package. -HAVE_CLEAR=no -#HAVE_CLEAR=yes - -# If HAVE_SYSLOGD is set to "yes", then syslogd will not be built or -# installed from the syslogd subdirectory. -HAVE_SYSLOGD=no -#HAVE_SYSLOGD=yes - -# If HAVE_ANOTHER_FDISK is set to "yes", then fdisk will not be built or -# installed from the disk-utils subdirectory. This anticipates the -# replacement of fdisk 2.x by fdisk 3.x, which will be distributed -# separately. -HAVE_FDISK=no -#HAVE_FDISK=yes +#HAVE_STRINGS=no +HAVE_STRINGS=yes + +# If HAVE_RESET is set to "yes", then reset won't be installed. The version +# of reset that comes with the ncurses package is less aggressive. +#HAVE_RESET=no +HAVE_RESET=yes + +# If HAVE_MOUNT is set to "yes", then reset won't be installed, since many +# folks grab mount independenty of util-linux +# When util-linux is released it always contains the very latest mount. +HAVE_MOUNT=no +# HAVE_MOUNT=yes CC= gcc -OPT= -pipe -O2 -m486 -fomit-frame-pointer -LDFLAGS= -s -N -CFLAGS= $(OPT) -I. -I$(BSD) \ + +# Different optimizations for different cpus. +ifeq "$(CPU)" "intel" + OPT= -pipe -O3 -m486 -fomit-frame-pointer +else + ifeq "$(CPU)" "arm" + OPT= -O2 -m3 -fomit-frame-pointer + else + OPT= -O3 -fomit-frame-pointer + endif +endif + +BSD= ../bsd + +LDFLAGS = -s +# WARNFLAGS = -Wall +CFLAGS = $(OPT) -I. -I$(BSD) $(WARNFLAGS) $(CURSESFLAGS) $(EXTRACFLAGS) \ -DSBINDIR=\"$(SBINDIR)\" \ -DUSRSBINDIR=\"$(USRSBINDIR)\" \ -DLOGDIR=\"$(LOGDIR)\" \ -DVARPATH=\"$(VARPATH)\" +# +# ncurses appears to be installed in three major ways. +# +# There is a subdirectory /usr/include/ncurses, with curses.h in +# CURSESFLAGS=-I/usr/include/ncurses -DNCH=0 +# No such subdirectory, but ncurses/curses.h is installed as ncurses.h +# CURSESFLAGS=-DNCH=1 +# No such subdirectory - is the ncurses one. +# CURSESFLAGS=-DNCH=0 +# Pick your choice. +CURSESFLAGS=-DNCH=0 +LIBCURSES=-lncurses + DEVDIR= $(DESTDIR)/dev ETCDIR= $(DESTDIR)/etc SBINDIR= $(DESTDIR)/sbin @@ -122,7 +166,7 @@ BINMODE= 755 MANMODE= 644 DATMODE= 644 INFOMODE= 644 -SUIDMODE= 4755 +SUIDMODE= 4711 CHMOD= chmod INSTALL= install @@ -132,10 +176,9 @@ INSTALLMAN= $(INSTALL) -m $(MANMODE) INSTALLDAT= $(INSTALL) -m $(DATMODE) INSTALLSUID= $(INSTALL) -m $(SUIDMODE) -o root -BSD= ../bsd - %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ %: %.cc $(CXX) $(CFLAGS) $< -o $@ + diff --git a/Makefile b/Makefile index 0cc45be2..a9244ab1 100644 --- a/Makefile +++ b/Makefile @@ -5,23 +5,23 @@ # May be distributed under the terms of the GNU GPL. # -VERSION=2.5 +VERSION=2.7.1 include ./MCONFIG +ifeq "$(HAVE_MOUNT)" "no" + MOUNTDIR=mount +endif + SUBDIRS= bsd \ disk-utils \ games \ login-utils \ misc-utils \ - mount \ + $(MOUNTDIR) \ sys-utils \ text-utils -ifeq "$(HAVE_SYSLOGD)" "no" -SUBDIRS:=$(SUBDIRS) syslogd -endif - .PHONEY: all install clean all: @for subdir in $(SUBDIRS); do \ @@ -36,7 +36,7 @@ install: clean: -rm -f *.o *~ core poe.diffs - @for subdir in $(SUBDIRS) historic/selection; do \ + @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ done @@ -50,8 +50,7 @@ dist: find -type d | xargs chown root:root; \ find -type f | xargs chown root:root; \ cd ..; \ - tar cvvf util-linux-$(VERSION).tar util-linux-$(VERSION); \ - gzip -9 util-linux-$(VERSION).tar; \ + GZIP=-9 tar cvvzf util-linux-$(VERSION).tar.gz util-linux-$(VERSION); \ cp -p util-linux-$(VERSION)/LSM util-linux-$(VERSION).lsm; \ cp -p util-linux-$(VERSION)/ANNOUNCE util-linux-$(VERSION).Announce; \ echo Done.) diff --git a/README b/README index ff2a6e06..75c54d6d 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -util-linux 2.5 +util-linux 2.7 WARNING: THE PROGRAMS IN THIS SUITE DO *NOT* SUPPORT SHADOW PASSWORD FILES! @@ -8,36 +8,117 @@ WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! WARNING: DO *NOT* INSTALL WITHOUT THINKING. -WARNING: The agetty, simpleinit, login, passwd, and other programs in this - package are *NOT* System V compliant. These utilities are meant - to be used by people who build their own systems. If you are not +WARNING: The simpleinit and some other programs in this package are + *NOT* System V compliant. These utilities are meant to be + used by people who build their own systems. If you are not a wizard, do *NOT* blindly install these utilities: they could prevent you from logging into your system. Have a boot floppy - ready, especially if you don't know what you are doing. - - + ready, especially if you don't know what you are doing. It's a + great way to learn though ;-) To install from source: 1) Get source distribution (see the .lsm file for locations) -2) Untar util-linux-2.5.tar.gz in /usr/src -3) cd util-linux-2.5 +2) Untar util-linux-2.7.tar.gz in /usr/src +3) cd util-linux-2.7 4) Edit MCONFIG 5) make - - Note that libc 4.5.26 headers need a small patch to be used with - recent kernels. See the file uio.h-diff for the patch, if necessary. - 6) make install 7) If you want to use simpleinit and agetty, then make softlinks from /sbin/init to simpleinit and from /sbin/getty to agetty, but make sure that your /etc/inittab is set up right (this is *NOT* the System V compatible init!), or you will be hosed. If you are using the SysV init and/or some other getty, they you can keep using those. -8) Remove all the old binaries from previous locations. -9) See the HIGHLIGHTS below for links you need to make for the new FSSTND - compliance. +HIGLIGHTS for version 2.7: + +1) util-linux now _requires_ ncurses. Several programs are completely + converted to use terminfo (instead of termcap). + +2) Removed progams: + - clock: Dropped entierly. Use hwclock (included). + - sync: is in gnu fileutils. + - setserial: Is being maintained by Ted Ts'o, he recommends + setserial-2.12 (2.13 is bad luck) + - clear: Included in ncurses + - hostname, domainname, dnsdomainname: It's in net-utils. + +3) Bugfixes, additions: + - cfdisk: A much improved version. All known bugs have been fixed. + - sfdisk: A command line fdisk type utility, formerly called fdisk-3.04. + - SECURITY: All known holes in login, chfn, chsh and others have been + plugged. UPGRADE NOW if you haven't already fixed them yourself. + - Should work with libc 4, 5 and 6 (gnulibc), on m68k, intel, alpha + and sparc. + +4) Problems.: + - The rpcgen that comes in NetKit-B-0.09 is broken. At least as + packaged with RedHat 4.2 (NetKit-B-0.09-6). There are several + ways to deal with this: + - Don't run rpcgen, the needed pre-generated sources are included + (nfsmount_xdr.c). You must hack mount/Makefile to do this. + - Edit the source emited by rpcgen so it can compile. This is very + simple if you know C. + - Disable the NFS parts of mount. You have to edit mount/Makefile + to do this. + - Use some other rpcgen + +util-linux 2.6.1 + +This release was never made public + +See notes for 2.6 for installation instructions. + +This is a incremental release containing some fixes. A new release +will be made later fixing the outstanding bugs. +- Things compiles and works better with recent releases of kernel, + ncurses, and so forth: fdisk, more +- Some fixes to make things compile out of the box on alphas. +- There has been reported a problem with login and /etc/usertty. It + should be fixed. If you still have problems get a recent MAKEDEV and + use it to make new tty devices. They were renumbered sometime during + the 1.3 phase of the kernel. +- ipcs now displays the key of the structures. +- A (harmless?) overflow bug was fixed in login. + +Outstanding bugs: +- login/getty has a denial of service problem. +- Several places needs a bit more polish. +- There are a _lot_ of nonfatal warnings when compiling mount. This will + not necesarily be fixed. + + +util-linux 2.6 + +HIGHLIGHTS for version 2.6: + +0) The first release with me at the helm. PLEASE SEND PATCHES AND + UPDATES TO: util-linux@math.uio.no. + +1) Removed programs: + - md5sum: available in GNU textutils. + - syslogd: Sysklogd is now prefered. It is available at + tsx-11.mit.edu:/pub/sources/sbin + sunsite.unc.edu:/pub/Linux/system/Daemons + +2) Bugfixes, additions: + - SECURITY: All known holes in mount have been fixed. UPGRADE NOW + if you haven't already! + - Portability enhancments to the minix filesystem utils (m68k and + Arm patches). + - passwd/chsh/chfn will not mess up the passwd file on a NIS machine + - others too numerous to enumerate. + +3) New programs: + - vigr (it's like vipw) + - Introducing hwclock. A complete rewrite of the latest available + clock source. It supports intel/CMOS, /dev/rtc and linux/m68k + system clock interfaces. Clock supports the same things but is now + obsolete and will not be present in the next release. Start using + hwclock now. Please. + + +util-linux 2.5 HIGHLIGHTS for version 2.5: 0) Nicolai Langfeldt is taking over maintenance of util-linux, with the diff --git a/bsd/pathnames.h b/bsd/pathnames.h index b37c6793..f6e46721 100644 --- a/bsd/pathnames.h +++ b/bsd/pathnames.h @@ -21,6 +21,8 @@ * from poe@daimi.aau.dk * Changed: Wed Jun 22 22:50:13 1994 by faith@cs.unc.edu * Changed: Sat Feb 4 16:02:10 1995 by faith@cs.unc.edu + * Changed: Tue Jul 2 09:37:36 1996 by janl@math.uio.no, axp patches + * Changed: Thu Nov 9 21:58:36 1995 by joey@infodrom.north.de */ #ifndef __STDC__ @@ -53,14 +55,18 @@ #define VARPATH "/var" #endif +#ifndef UT_NAMESIZE +#define UT_NAMESIZE 8 +#endif + #define _PATH_BSHELL "/bin/sh" #define _PATH_CSHELL "/bin/csh" -#define UT_NAMESIZE 8 #define _PATH_TTY "/dev/tty" #define TTYTYPES "/etc/ttytype" #define SECURETTY "/etc/securetty" #define _PATH_UTMP "/var/run/utmp" #define _PATH_WTMP LOGDIR "/wtmp" +#define _PATH_WTMPLOCK "/etc/wtmplock" #define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin:." #define _PATH_DEFPATH_ROOT SBINDIR ":/bin:" USRSBINDIR ":/usr/bin" @@ -87,5 +93,9 @@ #define _PATH_PTMP "/etc/ptmp" #define _PATH_PTMPTMP "/etc/ptmptmp" +#define _PATH_GROUP "/etc/group" +#define _PATH_GTMP "/etc/gtmp" +#define _PATH_GTMPTMP "/etc/gtmptmp" + #define _PATH_WORDS "/usr/dict/words" #define _PATH_WORDS_ALT "/usr/dict/web2" diff --git a/disk-utils/Makefile b/disk-utils/Makefile index 739d1283..fac3134b 100644 --- a/disk-utils/Makefile +++ b/disk-utils/Makefile @@ -8,17 +8,20 @@ include ../MCONFIG # Where to put man pages? -MAN8= cfdisk.8 fdformat.8 fsck.minix.8 \ - mkfs.8 mkfs.minix.8 mkswap.8 setfdprm.8 +MAN8= fdformat.8 mkswap.8 setfdprm.8 -MAN8.FDISK= fdisk.8 +ifneq "$(CPU)" "sparc" +MAN8:=$(MAN8) fdisk.8 cfdisk.8 sfdisk.8 fsck.minix.8 mkfs.8 mkfs.minix.8 +endif # Where to put binaries? # See the "install" rule for the links. . . -SBIN= cfdisk fsck.minix mkfs mkfs.minix mkswap +SBIN= mkfs mkswap -SBIN.FDISK= fdisk +ifneq "$(CPU)" "sparc" +SBIN:=$(SBIN) fdisk cfdisk sfdisk fsck.minix mkfs.minix +endif USRBIN= fdformat setfdprm @@ -26,27 +29,30 @@ USRBIN= fdformat setfdprm ETC= fdprm -ifeq "$(HAVE_FDISK)" "no" -SBIN:=$(SBIN) $(SBIN.FDISK) -MAN8:=$(MAN8) $(MAN8.FDISK) -endif - all: $(SBIN) $(USRBIN) cfdisk: cfdisk.o llseek.o - $(CC) $(LDFLAGS) $^ -o $@ -lcurses -ltermcap -lm + $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) -lm + +# not installed by default +activate: sfdisk + rm -f activate + ln -s sfdisk activate # Rules for everything else fdformat: fdformat.o fdisk: fdisk.o fdisklabel.o llseek.o +sfdisk: sfdisk.o fsck.minix: fsck.minix.o +fsck.minix.o: fsck.minix.c bitops.h mkfs: mkfs.o mkfs.minix: mkfs.minix.o +mkfs.minix.o: mkfs.minix.c bitops.h mkswap: mkswap.o setfdprm: setfdprm.o fdisk.o: fdisk.c fdisk.h -fdisklabel.o: fdisklabel.c fdisk.h +fdisklabel.o: fdisklabel.c fdisk.h fdisklabel.h install: all $(INSTALLDIR) $(SBINDIR) $(USRBINDIR) $(ETCDIR) diff --git a/disk-utils/README.fdisk.alpha b/disk-utils/README.fdisk.alpha deleted file mode 100644 index da6e8734..00000000 --- a/disk-utils/README.fdisk.alpha +++ /dev/null @@ -1,16 +0,0 @@ - -There are some things which have to be done for the alpha version: -- LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined in fdisklabel.h - These values are different for different versions of NetBSD and I don't - have the alpha source tree for NetBSD yet (It's not in 1.0 but in current). - I guess Linux/Alpha uses the same values. -- The alpha fdisklabel.c requires a few functions from fdisk.c. - ("make test" shows the undefined symbols when fdisk.c is missing) - All the other functions/variables shouldn't be declared. I didn't do - that because I didn't want to change much in fdisk.c. -- The disklabel in fdisklabel.c is the NetBSD disklabel which might - differ from the Linux/Alpha disklabel in some parts. -- bselect () should be called from main () immediately. Under Linux/Alpha - it's the main menu and not a submenu. - -fasten@informatik.uni-bonn.de diff --git a/disk-utils/README.fdisk.bsd b/disk-utils/README.fdisk.bsd deleted file mode 100644 index 705df90f..00000000 --- a/disk-utils/README.fdisk.bsd +++ /dev/null @@ -1,28 +0,0 @@ - -All changes in fdisk.c are marked with this comment: /* bf */ - -I added some explanatory comments to make it easier to see what -changed and why. You'll probably want to remove them. - -There's a function sync_disks() in fdisklabel.c which could be called -from write_table() in fdisk.c (line 1216) (and be moved to fdisk.c) -to save a few bytes. - -There's a function edit_int() in fdisklabel.c which I added because read_int() -had no default value. In fdisk v2.0d it has so edit_int could be replaces by -read_int(). The function which uses edit_int() (bsd_edit_disklabel ()) is a -bit crufty anyhow: -- The disklabel contains some values which are probably meaningless for IDE or - SCSI drives, I made them editable but I don't know any sensible range of - values (bad for read_int()). (interleave, trackskew, cylskew) -- I made the values secsize/nsectors/ntracks/ncylinders editable for Linux/Alpha - but not for Linux/i386 because under Linux/i386 the disklabel is inside a - DOS partition so the disklabel was written by an OS which got along with the - disk and should have left the correct values there. - -I've put the BSD copyright (which applies to fdisklabel.h and -alpha_bootblock_checksum, bsd_dkcksum, bsd_print_disklabel in fdisklabel.c) -into a separate man page. This way all Linux versions of BSD programs can refer -to ths bsd. man page. - -fasten@informatik.uni-bonn.de diff --git a/disk-utils/bitops.h b/disk-utils/bitops.h new file mode 100644 index 00000000..270dc2d8 --- /dev/null +++ b/disk-utils/bitops.h @@ -0,0 +1,54 @@ +#ifdef __i386__ + +#define bitop(name,op) \ +static inline int name(char * addr,unsigned int nr) \ +{ \ +int __res; \ +__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ +:"=g" (__res) \ +:"r" (nr),"m" (*(addr)),"0" (0)); \ +return __res; \ +} + +bitop(bit,"") +bitop(setbit,"s") +bitop(clrbit,"r") + +#elif defined(__mc68000__) + +#define bitop(name,op) \ +static inline int name (char *addr, unsigned int nr) \ +{ \ + char __res; \ + __asm__ __volatile__("bf" op " %2@{%1:#1}; sne %0" \ + : "=d" (__res) \ + : "d" (nr ^ 15), "a" (addr)); \ + return __res != 0; \ +} + +bitop (bit, "tst") +bitop (setbit, "set") +bitop (clrbit, "clr") + +#else +static inline int bit(char * addr,unsigned int nr) +{ + return (addr[nr >> 3] & (1<<(nr & 7))) != 0; +} + +static inline int setbit(char * addr,unsigned int nr) +{ + int __res = bit(addr, nr); + addr[nr >> 3] |= (1<<(nr & 7)); + return __res != 0; \ +} + +static inline int clrbit(char * addr,unsigned int nr) +{ + int __res = bit(addr, nr); + addr[nr >> 3] &= ~(1<<(nr & 7)); + return __res != 0; +} + +#endif + diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c index beb46e50..1b87aae7 100644 --- a/disk-utils/cfdisk.c +++ b/disk-utils/cfdisk.c @@ -29,6 +29,7 @@ * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto * + * Versions 0.8e-h: aeb@cwi.nl * ****************************************************************************/ @@ -44,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -55,12 +57,10 @@ typedef long long ext2_loff_t; typedef long ext2_loff_t; #endif -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, +extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, unsigned int origin); - -#define VERSION "0.8d BETA (>2GB)" +#define VERSION "0.8i" #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" @@ -79,7 +79,8 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, #define UNUSABLE -1 #define FREE_SPACE 0x00 -#define EXTENDED 0x05 +#define DOS_EXTENDED 0x05 +#define LINUX_EXTENDED 0x85 #define LINUX_MINIX 0x81 #define LINUX_SWAP 0x82 #define LINUX 0x83 @@ -107,6 +108,7 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, #define BAD_CYLINDERS "Illegal cylinders value" #define BAD_HEADS "Illegal heads value" #define BAD_SECTORS "Illegal sectors value" +#define READONLY_WARN "Opened disk read-only - you have no permission to write" #define WRITE_WARN "Warning!! This may destroy data on your disk!" #define YES_NO "Please enter `yes' or `no'" #define WRITING_PART "Writing partition table to disk..." @@ -155,6 +157,11 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, s |= (sector >> 2) & 0xC0;\ } +#define is_extended(x) ((x) == DOS_EXTENDED || (x) == LINUX_EXTENDED) + +/* we might also want to recognise 0xe and 0xf */ +#define is_dos_partition(x) ((x) == 1 || (x) == 4 || (x) == 6) + #define ALIGNMENT 2 typedef union { struct { @@ -176,6 +183,8 @@ typedef struct { int flags; /* active == 0x80 */ int id; /* filesystem type */ int num; /* number of partition -- primary vs. logical */ +#define LABELSZ 11 + char dos_label[LABELSZ+1]; } partition_info; char *disk_device = DEFAULT_DEVICE; @@ -185,6 +194,8 @@ int sectors = 0; int cylinders = 0; int changed = FALSE; int opened = FALSE; +int opentype; +int curses_started = 0; partition_info p_info[MAXIMUM_PARTS]; partition_info ext_info; @@ -227,12 +238,20 @@ char *partition_type[NUM_PART_TYPES] = { [LINUX_SWAP] = "Linux Swap", [LINUX] = "Linux", [FREE_SPACE] = "Free Space", - [EXTENDED] = "Extended", - [0x01] = "DOS 12-bit FAT", - [0x04] = "DOS 16-bit < 32Mb", - [0x06] = "DOS 16-bit >=32Mb", - [0x07] = "OS/2 HPFS", + [DOS_EXTENDED]= "Extended", + [LINUX_EXTENDED] = "Linux extended", + [0x01] = "DOS FAT12", + [0x04] = "DOS FAT16", + [0x06] = "DOS FAT16 (big)", + [0x07] = "OS/2 HPFS or NTFS", [0x0A] = "OS/2 Boot Manager", + [0x0B] = "Win95 FAT32", + [0x0C] = "Win95 FAT32 (LBA)", + [0x0E] = "Win95 FAT16 (LBA)", + [0x0F] = "Win95 Extended (LBA)", + [0x11] = "Hidden DOS FAT12", + [0x14] = "Hidden DOS FAT16", + [0x16] = "Hidden DOS FAT16 (big)", [0xA5] = "BSD/386", /* The rest of these are taken from A. V. Le Blanc's (LeBlanc@mcc.ac.uk) @@ -279,7 +298,6 @@ void fdexit(int ret) "page for additional information.\n" ); } - exit(ret); } @@ -346,7 +364,7 @@ void clear_warning(void) { int i; - if (!warning_last_time) + if (!curses_started || !warning_last_time) return; move(WARNING_START,0); @@ -358,37 +376,56 @@ void clear_warning(void) void print_warning(char *s) { - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ + if (!curses_started) { + fprintf(stderr, "%s\n", s); + } else { + mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); + putchar(BELL); /* CTRL-G */ - warning_last_time = TRUE; + warning_last_time = TRUE; + } } +void die_x(int ret); + void fatal(char *s) { char str[LINE_LENGTH]; - sprintf(str, "FATAL ERROR: %s", s); - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "Press any key to exit fdisk"); - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - - refresh(); + if (curses_started) { + sprintf(str, "FATAL ERROR: %s", s); + mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); + sprintf(str, "Press any key to exit fdisk"); + mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); + putchar(BELL); /* CTRL-G */ + refresh(); + (void)getch(); + die_x(1); + } else { + fprintf(stderr, "FATAL ERROR: %s\n", s); + exit(1); + } +} - (void)getch(); +void die(int dummy) +{ + die_x(0); +} +void die_x(int ret) +{ signal(SIGINT, old_SIGINT); signal(SIGTERM, old_SIGTERM); mvcur(0, COLS-1, LINES-1, 0); nl(); endwin(); - fdexit(1); + printf("\n"); + fdexit(ret); } void read_sector(char *buffer, int sect_num) { - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) fatal(BAD_SEEK); if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) fatal(BAD_READ); @@ -396,12 +433,30 @@ void read_sector(char *buffer, int sect_num) void write_sector(char *buffer, int sect_num) { - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) fatal(BAD_SEEK); if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) fatal(BAD_WRITE); } +void get_dos_label(int i) +{ + char label[LABELSZ+1]; + ext2_loff_t offset; + int j; + + offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset) + * SECTOR_SIZE + 43; + if (ext2_llseek(fd, offset, SEEK_SET) == offset + && read(fd, &label, LABELSZ) == LABELSZ) { + for(j=0; j 0 && IS_LOGICAL(p_info[i].num)) log++; - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (log > 0) pri++; else { @@ -423,10 +478,10 @@ void check_part_info(void) ext_info.num = PRIMARY; } - if (pri >= 4) + if (pri >= 4) { for (i = 0; i < num_parts; i++) if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (p_info[i].first_sector >= ext_info.first_sector && p_info[i].last_sector <= ext_info.last_sector) { p_info[i].id = FREE_SPACE; @@ -447,16 +502,16 @@ void check_part_info(void) p_info[i].num = LOGICAL; } else p_info[i].id = UNUSABLE; - else /* if (ext_info.id != EXTENDED) */ + else /* if (!is_extended(ext_info.id)) */ p_info[i].id = UNUSABLE; else /* if (p_info[i].id > 0) */ while (0); /* Leave these alone */ - else /* if (pri < 4) */ + } else { /* if (pri < 4) */ for (i = 0; i < num_parts; i++) { if (p_info[i].id == UNUSABLE) p_info[i].id = FREE_SPACE; if (p_info[i].id == FREE_SPACE) - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) if (p_info[i].first_sector >= ext_info.first_sector && p_info[i].last_sector <= ext_info.last_sector) p_info[i].num = LOGICAL; @@ -474,11 +529,12 @@ void check_part_info(void) p_info[i].num = PRI_OR_LOG; else p_info[i].num = PRIMARY; - else /* if (ext_info.id != EXTENDED) */ + else /* if (!is_extended(ext_info.id)) */ p_info[i].num = PRI_OR_LOG; else /* if (p_info[i].id > 0) */ while (0); /* Leave these alone */ } + } } void remove_part(int i) @@ -491,8 +547,7 @@ void remove_part(int i) num_parts--; } -void insert_part(int i, int num, int id, int flags, int first, int last, - int offset) +void insert_empty_part(int i, int first, int last) { int p; @@ -501,10 +556,11 @@ void insert_part(int i, int num, int id, int flags, int first, int last, p_info[i].first_sector = first; p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + p_info[i].dos_label[0] = 0; num_parts++; } @@ -548,8 +604,10 @@ void del_part(int i) * last logical drive; and if there are any other logical drives * then renumber the ones after "num". */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) + if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) { ext_info.first_sector = p_info[i].last_sector + 1; + ext_info.offset = 0; + } if (i == num_parts-1 || (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) ext_info.last_sector = p_info[i].first_sector - 1; @@ -562,7 +620,8 @@ void del_part(int i) check_part_info(); } -int add_part(int num, int id, int flags, int first, int last, int offset) +int add_part(int num, int id, int flags, int first, int last, int offset, + int want_label) { int i, pri = 0, log = 0; @@ -570,45 +629,51 @@ int add_part(int num, int id, int flags, int first, int last, int offset) first < 0 || first >= cylinders*heads*sectors || last < 0 || - last >= cylinders*heads*sectors) - return -1; + last >= cylinders*heads*sectors) { + return -1; /* bad start or end */ + } for (i = 0; i < num_parts; i++) if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) pri++; else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) log++; - if (ext_info.id == EXTENDED && log > 0) + if (is_extended(ext_info.id) && log > 0) pri++; if (IS_PRIMARY(num)) - if (pri >= 4) - return -1; - else + if (pri >= 4) { + return -1; /* no room for more */ + } else pri++; - for (i = 0; p_info[i].last_sector < first; i++); + for (i = 0; i < num_parts && p_info[i].last_sector < first; i++); - if (p_info[i].id != FREE_SPACE || last > p_info[i].last_sector) + if (i == num_parts || p_info[i].id != FREE_SPACE + || last > p_info[i].last_sector) { return -1; + } - if (id == EXTENDED) - if (ext_info.id != FREE_SPACE) - return -1; + if (is_extended(id)) { + if (ext_info.id != FREE_SPACE) { + return -1; /* second extended */ + } else if (IS_PRIMARY(num)) { ext_info.first_sector = first; ext_info.last_sector = last; ext_info.offset = offset; ext_info.flags = flags; - ext_info.id = EXTENDED; + ext_info.id = id; ext_info.num = num; - + ext_info.dos_label[0] = 0; return 0; - } else - return -1; + } else { + return -1; /* explicit extended logical */ + } + } if (IS_LOGICAL(num)) { - if (ext_info.id != EXTENDED) { + if (!is_extended(ext_info.id)) { print_warning("!!!! Internal error creating logical " "drive with no extended partition !!!!"); } else { @@ -626,29 +691,29 @@ int add_part(int num, int id, int flags, int first, int last, int offset) if (first == 0) { ext_info.first_sector = 0; ext_info.offset = first = offset; - } else + } else { ext_info.first_sector = first; + } } } else if (last > ext_info.last_sector) { if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { print_warning(TWO_EXTENDEDS); return -1; - } else + } else { ext_info.last_sector = last; + } } } } if (first != p_info[i].first_sector && !(IS_LOGICAL(num) && first == offset)) { - insert_part(i, PRI_OR_LOG, FREE_SPACE, 0, - p_info[i].first_sector, first-1, 0); + insert_empty_part(i, p_info[i].first_sector, first-1); i++; } if (last != p_info[i].last_sector) - insert_part(i+1, PRI_OR_LOG, FREE_SPACE, 0, - last+1, p_info[i].last_sector, 0); + insert_empty_part(i+1, last+1, p_info[i].last_sector); p_info[i].first_sector = first; p_info[i].last_sector = last; @@ -656,6 +721,9 @@ int add_part(int num, int id, int flags, int first, int last, int offset) p_info[i].flags = flags; p_info[i].id = id; p_info[i].num = num; + p_info[i].dos_label[0] = 0; + if (want_label && is_dos_partition(id)) + get_dos_label(i); check_part_info(); @@ -668,7 +736,7 @@ int find_primary(void) while (cur < num_parts && IS_PRIMARY(num)) if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (ext_info.id == EXTENDED && ext_info.num == num)) { + (is_extended(ext_info.id) && ext_info.num == num)) { num++; cur = 0; } else @@ -1046,7 +1114,7 @@ void new_part(int i) return; } - if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { + if (IS_LOGICAL(num) && !is_extended(ext_info.id)) { /* We want to add a logical partition, but need to create an * extended partition first. */ @@ -1054,8 +1122,9 @@ void new_part(int i) print_warning(NEED_EXT); return; } - (void)add_part(ext, EXTENDED, 0, first, last, - (first == 0 ? sectors : 0)); + (void) add_part(ext, DOS_EXTENDED, 0, first, last, + (first == 0 ? sectors : 0), 0); + first = ext_info.first_sector + ext_info.offset; } if (IS_LOGICAL(num)) @@ -1065,7 +1134,7 @@ void new_part(int i) if (first == 0 || IS_LOGICAL(num)) offset = sectors; - (void)add_part(num, id, flags, first, last, offset); + (void) add_part(num, id, flags, first, last, offset, 0); } void clear_p_info(void) @@ -1093,8 +1162,20 @@ void fill_p_info(void) partition_table buffer; partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; - if ((fd = open(disk_device, O_RDWR)) < 0) - fatal(BAD_OPEN); + if ((fd = open(disk_device, O_RDWR)) < 0) { + if ((fd = open(disk_device, O_RDONLY)) < 0) + fatal(BAD_OPEN); + opentype = O_RDONLY; + print_warning(READONLY_WARN); + if (curses_started) { + refresh(); + getch(); + clear_warning(); + } + } else + opentype = O_RDWR; + opened = TRUE; + read_sector(buffer.c.b, 0); if (!ioctl(fd, HDIO_GETGEO, &geometry)) { @@ -1113,52 +1194,53 @@ void fill_p_info(void) if (!zero_table) { for (i = 0; i < 4; i++) { + int bs = buffer.p.part[i].start_sect; + if (buffer.p.part[i].sys_ind > 0 && add_part(i, buffer.p.part[i].sys_ind, buffer.p.part[i].boot_ind, - ((buffer.p.part[i].start_sect <= sectors) ? - 0 : buffer.p.part[i].start_sect), + ((bs <= sectors) ? 0 : bs), buffer.p.part[i].start_sect + buffer.p.part[i].nr_sects - 1, - ((buffer.p.part[i].start_sect <= sectors) ? - buffer.p.part[i].start_sect : 0))) { + ((bs <= sectors) ? bs : 0), + 1)) { fatal(BAD_PRIMARY); } - if (buffer.p.part[i].sys_ind == EXTENDED) + if (is_extended(buffer.p.part[i].sys_ind)) tmp_ext = ext_info; } - if (tmp_ext.id == EXTENDED) { + if (is_extended(tmp_ext.id)) { ext_info = tmp_ext; - logical_sectors[logical] = ext_info.first_sector; + logical_sectors[logical] = + ext_info.first_sector + ext_info.offset; read_sector(buffer.c.b, logical_sectors[logical++]); i = 4; do { for (p = 0; p < 4 && (!buffer.p.part[p].sys_ind || - buffer.p.part[p].sys_ind == 5); + is_extended(buffer.p.part[p].sys_ind)); p++); - if (p > 3) - fatal(BAD_LOGICAL); - if (add_part(i++, + if (p < 4 && add_part(i++, buffer.p.part[p].sys_ind, buffer.p.part[p].boot_ind, logical_sectors[logical-1], logical_sectors[logical-1] + buffer.p.part[p].start_sect + buffer.p.part[p].nr_sects - 1, - buffer.p.part[p].start_sect)) { + buffer.p.part[p].start_sect, + 1)) { fatal(BAD_LOGICAL); } for (p = 0; - p < 4 && buffer.p.part[p].sys_ind != 5; + p < 4 && !is_extended(buffer.p.part[p].sys_ind); p++); if (p < 4) { - logical_sectors[logical] = - ext_info.first_sector + buffer.p.part[p].start_sect; + logical_sectors[logical] = ext_info.first_sector + + ext_info.offset + buffer.p.part[p].start_sect; read_sector(buffer.c.b, logical_sectors[logical++]); } } while (p < 4 && logical < MAXIMUM_PARTS-4); @@ -1197,7 +1279,7 @@ void fill_primary_table(partition_table *buffer) if (IS_PRIMARY(p_info[i].num)) fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); - if (ext_info.id == EXTENDED) + if (is_extended(ext_info.id)) fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); buffer->p.flag = PART_TABLE_FLAG; @@ -1228,8 +1310,8 @@ void fill_logical_table(partition_table *buffer, partition_info *pi) pi = &(p_info[i]); p->boot_ind = 0; - p->sys_ind = 5; - p->start_sect = pi->first_sector - ext_info.first_sector; + p->sys_ind = DOS_EXTENDED; + p->start_sect = pi->first_sector - ext_info.first_sector - ext_info.offset; p->nr_sects = pi->last_sector - pi->first_sector + 1; sects = ((pi->first_sector/(sectors*heads) > 1023) ? heads*sectors*1024 - 1 : pi->first_sector); @@ -1246,62 +1328,78 @@ void write_part_table(void) { int i, done = FALSE, len; partition_table buffer; + struct stat s; + int is_bdev; char response[LINE_LENGTH]; - print_warning(WRITE_WARN); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Are you sure you want write the partition table to disk? (yes or no): "); - - len = get_string(response, LINE_LENGTH, NULL); - - clear_warning(); + if (opentype == O_RDONLY) { + print_warning(READONLY_WARN); + refresh(); + getch(); + clear_warning(); + return; + } - if (len == GS_ESCAPE) - return; - else if (len == 2 && - toupper(response[0]) == 'N' && - toupper(response[1]) == 'O') { - print_warning(NO_WRITE); - return; - } else if (len == 3 && - toupper(response[0]) == 'Y' && - toupper(response[1]) == 'E' && - toupper(response[2]) == 'S') - done = TRUE; - else - print_warning(YES_NO); + is_bdev = 0; + if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode)) + is_bdev = 1; + + if (is_bdev) { + print_warning(WRITE_WARN); + + while (!done) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Are you sure you want write the partition table " + "to disk? (yes or no): "); + len = get_string(response, LINE_LENGTH, NULL); + clear_warning(); + if (len == GS_ESCAPE) + return; + else if (len == 2 && + toupper(response[0]) == 'N' && + toupper(response[1]) == 'O') { + print_warning(NO_WRITE); + return; + } else if (len == 3 && + toupper(response[0]) == 'Y' && + toupper(response[1]) == 'E' && + toupper(response[2]) == 'S') + done = TRUE; + else + print_warning(YES_NO); + } + + clear_warning(); + print_warning(WRITING_PART); + refresh(); } - clear_warning(); - print_warning(WRITING_PART); - refresh(); - read_sector(buffer.c.b, 0); fill_primary_table(&buffer); write_sector(buffer.c.b, 0); for (i = 0; i < num_parts; i++) if (IS_LOGICAL(p_info[i].num)) { - /* Read the extended partition table from disk ??? KEM */ read_sector(buffer.c.b, p_info[i].first_sector); fill_logical_table(&buffer, &(p_info[i])); write_sector(buffer.c.b, p_info[i].first_sector); } - sync(); - sleep(2); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; - sync(); - sleep(4); - - clear_warning(); - if (changed) - print_warning(YES_WRITE); - else - print_warning(RRPART_FAILED); + if (is_bdev) { + sync(); + sleep(2); + if (!ioctl(fd,BLKRRPART)) + changed = TRUE; + sync(); + sleep(4); + + clear_warning(); + if (changed) + print_warning(YES_WRITE); + else + print_warning(RRPART_FAILED); + } else + print_warning(YES_WRITE); } void fp_printf(FILE *fp, char *format, ...) @@ -1380,12 +1478,14 @@ void print_raw_table(void) fp_printf(fp, "Disk Drive: %s\n", disk_device); + fp_printf(fp, "Sector 0:\n"); read_sector(buffer.c.b, 0); fill_primary_table(&buffer); print_file_buffer(fp, buffer.c.b); for (i = 0; i < num_parts; i++) if (IS_LOGICAL(p_info[i].num)) { + fp_printf(fp, "Sector %d:\n", p_info[i].first_sector); read_sector(buffer.c.b, p_info[i].first_sector); fill_logical_table(&buffer, &(p_info[i])); print_file_buffer(fp, buffer.c.b); @@ -1402,7 +1502,7 @@ void print_raw_table(void) void print_p_info_entry(FILE *fp, partition_info *p) { int size; - char part_str[21]; + char part_str[40]; if (p->id == UNUSABLE) fp_printf(fp, " None "); @@ -1418,45 +1518,39 @@ void print_p_info_entry(FILE *fp, partition_info *p) fp_printf(fp, " "); - fp_printf(fp, "%7d%c", p->first_sector, + fp_printf(fp, "%8d%c", p->first_sector, ((p->first_sector/(sectors*heads)) != ((float)p->first_sector/(sectors*heads)) ? '*' : ' ')); - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->last_sector, + fp_printf(fp, "%8d%c", p->last_sector, (((p->last_sector+1)/(sectors*heads)) != ((float)(p->last_sector+1)/(sectors*heads)) ? '*' : ' ')); - fp_printf(fp, " "); - - fp_printf(fp, "%6d%c", p->offset, + fp_printf(fp, "%7d%c", p->offset, ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && (p->offset != sectors)) || (p->first_sector != 0 && IS_PRIMARY(p->num) && p->offset != 0)) ? '#' : ' ')); - fp_printf(fp, " "); - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%7d%c", size, + fp_printf(fp, "%8d%c", size, ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? '*' : ' ')); fp_printf(fp, " "); if (p->id == UNUSABLE) - sprintf(part_str, "%.16s", "Unusable"); + sprintf(part_str, "%.17s", "Unusable"); else if (p->id == FREE_SPACE) - sprintf(part_str, "%.16s", "Free Space"); + sprintf(part_str, "%.17s", "Free Space"); else if (partition_type[p->id]) - sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); + sprintf(part_str, "%.17s (%02X)", partition_type[p->id], p->id); else - sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); - fp_printf(fp, "%-21.21s", part_str); + sprintf(part_str, "%.17s (%02X)", "Unknown", p->id); + fp_printf(fp, "%-22.22s", part_str); fp_printf(fp, " "); @@ -1474,7 +1568,7 @@ void print_p_info(void) { char fname[LINE_LENGTH]; FILE *fp; - int i, to_file, pext = (ext_info.id == EXTENDED); + int i, to_file, pext = is_extended(ext_info.id); if (print_only) { fp = stdout; @@ -1502,9 +1596,9 @@ void print_p_info(void) fp_printf(fp, "Partition Table for %s\n", disk_device); fp_printf(fp, "\n"); - fp_printf(fp, " First Last\n"); - fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); - fp_printf(fp, "-- ------- -------- -------- ------- -------- --------------------- ---------\n"); + fp_printf(fp, " First Last\n"); + fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); + fp_printf(fp, "-- ------- -------- --------- ------ --------- ---------------------- ---------\n"); for (i = 0; i < num_parts; i++) { if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { @@ -1557,7 +1651,7 @@ void print_part_entry(FILE *fp, int num, partition_info *pi) ec = end / heads; } - fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", + fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %9d\n", num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); } @@ -1594,9 +1688,9 @@ void print_part_table(void) fp_printf(fp, "Partition Table for %s\n", disk_device); fp_printf(fp, "\n"); - fp_printf(fp, " ---Starting--- ----Ending---- Start Number\n"); - fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); - fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- -------\n"); + fp_printf(fp, " ---Starting--- ----Ending---- Start Number of\n"); + fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); + fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- ---------\n"); for (i = 0; i < 4; i++) { for (j = 0; @@ -1604,7 +1698,7 @@ void print_part_table(void) j++); if (j < num_parts) { print_part_entry(fp, i, &(p_info[j])); - } else if (ext_info.id == EXTENDED && ext_info.num == i) { + } else if (is_extended(ext_info.id) && ext_info.num == i) { print_part_entry(fp, i, &ext_info); } else { print_part_entry(fp, i, NULL); @@ -1667,7 +1761,7 @@ void display_help() "allows you to create, delete and modify partitions on your hard", "disk drive.", "", - "Copyright (C) 1994 Kevin E. Martin", + "Copyright (C) 1994-1997 Kevin E. Martin & aeb", "", "Command Meaning", "------- -------", @@ -1796,8 +1890,10 @@ int change_geometry(void) } if (ret_val) { - if (p_info[num_parts-1].last_sector > heads*sectors*cylinders-1) { - while (p_info[num_parts-1].first_sector > heads*sectors*cylinders-1) { + int disk_end = heads*sectors*cylinders-1; + + if (p_info[num_parts-1].last_sector > disk_end) { + while (p_info[num_parts-1].first_sector > disk_end) { if (p_info[num_parts-1].id == FREE_SPACE || p_info[num_parts-1].id == UNUSABLE) remove_part(num_parts-1); @@ -1805,18 +1901,18 @@ int change_geometry(void) del_part(num_parts-1); } - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + p_info[num_parts-1].last_sector = disk_end; - if (ext_info.last_sector > heads*sectors*cylinders-1) - ext_info.last_sector = heads*sectors*cylinders - 1; - } else if (p_info[num_parts-1].last_sector < heads*sectors*cylinders-1) { + if (ext_info.last_sector > disk_end) + ext_info.last_sector = disk_end; + } else if (p_info[num_parts-1].last_sector < disk_end) { if (p_info[num_parts-1].id == FREE_SPACE || p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; + p_info[num_parts-1].last_sector = disk_end; } else { - insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, - p_info[num_parts-1].last_sector+1, - heads*sectors*cylinders-1, 0); + insert_empty_part(num_parts, + p_info[num_parts-1].last_sector+1, + disk_end); } } @@ -1878,7 +1974,7 @@ void change_id(int i) if (new_id == 0) print_warning(ID_EMPTY); - else if (new_id == EXTENDED) + else if (is_extended(new_id)) print_warning(ID_EXT); else p_info[i].id = new_id; @@ -1935,6 +2031,11 @@ void draw_partition(int i) else mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + if (p_info[i].dos_label[0]) { + int l = strlen(p_info[i].dos_label); + mvprintw(y, SIZE_START-5-l, " [%s] ", p_info[i].dos_label); + } + size = p_info[i].last_sector - p_info[i].first_sector + 1; if (display_units == SECTORS) mvprintw(y, SIZE_START, "%9d", size); @@ -2055,16 +2156,6 @@ int draw_cursor(int move) return 0; } -void die(int dummy) -{ - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - void do_curses_fdisk(void) { int done = FALSE; @@ -2085,7 +2176,7 @@ void do_curses_fdisk(void) { 'W', "Write", "Write partition table to disk (this might destroy data)" }, { 0, NULL, NULL } }; - + curses_started = 1; initscr(); old_SIGINT = signal(SIGINT, die); old_SIGTERM = signal(SIGTERM, die); @@ -2105,18 +2196,23 @@ void do_curses_fdisk(void) draw_screen(); while (!done) { - (void)draw_cursor(0); + char *s; - if (p_info[cur_part].id == FREE_SPACE) - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hnpquW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - else if (p_info[cur_part].id > 0) - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "bdhmpqtuW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - else - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, "hpquW", - MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + (void)draw_cursor(0); + if (p_info[cur_part].id == FREE_SPACE) { + s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else if (p_info[cur_part].id > 0) { + s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else { + s = ((opentype == O_RDWR) ? "hpquW" : "hpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } switch ( command ) { case 'B': case 'b': @@ -2225,30 +2321,34 @@ void do_curses_fdisk(void) } } - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); + die_x(0); } void copyright(void) { - fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\n"); + fprintf(stderr, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n"); } void usage(char *prog_name) { - fprintf(stderr, - "%s: [-avz] [-c # cylinders] [-h # heads] [-s # sectors/track]\n", - prog_name); - fprintf(stderr, - "[ -P opt ] device\n"); + fprintf(stderr, "\nUsage:\n"); + fprintf(stderr, "Print version:\n"); + fprintf(stderr, "\t%s -v\n", prog_name); + fprintf(stderr, "Print partition table:\n"); + fprintf(stderr, "\t%s -P {r|s|t} [options] device\n", prog_name); + fprintf(stderr, "Interactive use:\n"); + fprintf(stderr, "\t%s [options] device\n", prog_name); + fprintf(stderr, " +Options: +-a: Use arrow instead of highlighting; +-z: Start with a zero partition table, instead of reading the pt from disk; +-c C -h H -s S: Override the kernel's idea of the number of cylinders, + the number of heads and the number of sectors/track.\n\n"); + copyright(); } -void main(int argc, char **argv) +int main(int argc, char **argv) { char c; int i, len; @@ -2315,7 +2415,7 @@ void main(int argc, char **argv) else if (argc-optind != 0) { usage(argv[0]); exit(1); - } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0) disk_device = ALTERNATE_DEVICE; else close(fd); @@ -2329,4 +2429,5 @@ void main(int argc, char **argv) print_part_table(); } else do_curses_fdisk(); + return 0; } diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c index 8b08535a..46b9e232 100644 --- a/disk-utils/fdformat.c +++ b/disk-utils/fdformat.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -28,13 +29,15 @@ static void format_disk(char *name) for (track = 0; track < param.track; track++) { descr.track = track; descr.head = 0; - if (ioctl(ctrl,FDFMTTRK,(int) &descr) < 0) PERROR("\nioctl(FDFMTTRK)"); + if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) + PERROR("\nioctl(FDFMTTRK)"); + printf("%3d\b\b\b",track); fflush(stdout); if (param.head == 2) { descr.head = 1; - if (ioctl(ctrl,FDFMTTRK,(int) &descr) < 0) - PERROR("\nioctl(FDFMTTRK)"); + if (ioctl(ctrl,FDFMTTRK,(long) &descr) < 0) + PERROR("\nioctl(FDFMTTRK)"); } } if (ioctl(ctrl,FDFMTEND,NULL) < 0) PERROR("\nioctl(FDFMTEND)"); @@ -72,7 +75,7 @@ static void usage(char *name) { char *this; - if (this = strrchr(name,'/')) name = this+1; + if ((this = strrchr(name,'/')) != NULL) name = this+1; fprintf(stderr,"usage: %s [ -n ] device\n",name); exit(1); } @@ -100,7 +103,8 @@ int main(int argc,char **argv) } if (access(argv[1],W_OK) < 0) PERROR(argv[1]); if ((ctrl = open(argv[1],3)) < 0) PERROR(argv[1]); - if (ioctl(ctrl,FDGETPRM,(int) ¶m) < 0) PERROR("ioctl(FDGETPRM)"); + if (ioctl(ctrl,FDGETPRM,(long) ¶m) < 0) + PERROR("Could not determine current format type"); printf("%sle-sided, %d tracks, %d sec/track. Total capacity %d kB.\n", param.head ? "Doub" : "Sing",param.track,param.sect,param.size >> 1); format_disk(argv[1]); diff --git a/disk-utils/fdisk.8 b/disk-utils/fdisk.8 index 395e9c71..29d56c40 100644 --- a/disk-utils/fdisk.8 +++ b/disk-utils/fdisk.8 @@ -101,7 +101,7 @@ if you use the .B dd command, since a small typo can make all of the data on your disk useless. -For best resutls, you should always use an OS-specific partition table +For best results, you should always use an OS-specific partition table program. For example, you should make DOS partitions with the DOS FDISK program and Linux partitions with the Linux fdisk or Linux cfdisk program. diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index f3455fa5..95b958d8 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -225,7 +225,7 @@ void menu(void) puts("Command action\n" " a toggle a bootable flag\n" " b edit bsd disklabel\n" /* bf */ - " c toggle the dos compatiblity flag\n" + " c toggle the dos compatibility flag\n" " d delete a partition\n" " l list known partition types\n" " m print this menu\n" @@ -449,7 +449,7 @@ void read_extended(struct partition *p) } } -void get_boot(void) +int get_boot(void) { int i; struct hd_geometry geometry; @@ -464,6 +464,7 @@ void get_boot(void) } if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) fatal(unable_to_read); + #ifdef HDIO_REQ if (!ioctl(fd, HDIO_REQ, &geometry)) { #else @@ -479,6 +480,10 @@ void get_boot(void) else update_units(); warn_geometry(); + if (*(unsigned short *) (0x1fe + buffer) != 0xAA55) { + return 0; /* not a valid partition table */ + } + for (i = 0; i < 4; i++) if(part_table[i]->sys_ind == EXTENDED) if (partitions != 4) @@ -493,6 +498,8 @@ void get_boot(void) *table_check(buffers[i]), i + 1); changed[i] = 1; } + + return 1; } int read_line(void) @@ -587,6 +594,7 @@ uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) case lower: i += low; break; case upper: i += high; break; case deflt: i += dflt; break; + case ignore: } } else @@ -805,12 +813,12 @@ static void check_consistency(struct partition *p, int partition) return; /* do not check extended partitions */ /* physical beginning c, h, s */ - pbc = p->cyl & 0xff | (p->sector << 2) & 0x300; + pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300); pbh = p->head; pbs = p->sector & 0x3f; /* physical ending c, h, s */ - pec = p->end_cyl & 0xff | (p->end_sector << 2) & 0x300; + pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); peh = p->end_head; pes = p->end_sector & 0x3f; @@ -902,7 +910,7 @@ void x_list_table(int extend) disk_device, heads, sectors, cylinders); printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); for (i = 0 ; i < partitions; i++) - if (p = q[i]) { + if ((p = q[i]) != NULL) { printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n", i + 1, p->boot_ind, p->head, sector(p->sector), @@ -987,9 +995,8 @@ void verify(void) last[i]); total += last[i] + 1 - first[i]; for (j = 0; j < i; j++) - if (first[i] >= first[j] && first[i] <= last[j] - || (last[i] <= last[j] && - last[i] >= first[j])) { + if ((first[i] >= first[j] && first[i] <= last[j]) + || ((last[i] <= last[j] && last[i] >= first[j]))) { printf("Warning: partition %d overlaps " "partition %d.\n", j + 1, i + 1); total += first[i] >= first[j] ? @@ -1021,7 +1028,7 @@ void verify(void) if (total > heads * sectors * cylinders) printf("Total allocated sectors %d greater than the maximum " "%d\n", total, heads * sectors * cylinders); - else if (total = heads * sectors * cylinders - total) + else if ((total = heads * sectors * cylinders - total) != 0) printf("%d unallocated sectors\n", total); } @@ -1219,11 +1226,10 @@ void write_table(void) printf("The partition table has been altered!\n\n"); - printf("Calling ioctl() to re-read partition table.\n" - "(Reboot to ensure the partition table has been updated.)\n"); + printf("Calling ioctl() to re-read partition table.\n"); sync(); sleep(2); - if (i = ioctl(fd, BLKRRPART)) { + if ((i = ioctl(fd, BLKRRPART)) != 0) { error = errno; } else { /* some kernel versions (1.2.x) seem to have trouble @@ -1231,7 +1237,7 @@ void write_table(void) twice, the second time works. - biro@yggdrasil.com */ sync(); sleep(2); - if(i = ioctl(fd, BLKRRPART)) + if((i = ioctl(fd, BLKRRPART)) != 0) error = errno; } @@ -1352,22 +1358,27 @@ void xselect(void) void try(char *device) { disk_device = device; - if (!setjmp(listingbuf)) + if (!setjmp(listingbuf)) { if ((fd = open(disk_device, type_open)) >= 0) { - close(fd); - get_boot(); - list_table(); - if (partitions > 4) + if (get_boot()) { + close(fd); + list_table(); + if (partitions > 4) delete_partition(ext_index); - } else { + } else { + btrydev(device); + close(fd); + } + } else { /* Ignore other errors, since we try IDE and SCSI hard disks which may not be installed on the system. */ - if(errno == EACCES) { - fprintf(stderr, "Cannot open %s\n", device); - exit(1); - } - } + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + exit(1); + } + } + } } void main(int argc, char **argv) diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h index 4f23fd8a..89510031 100644 --- a/disk-utils/fdisk.h +++ b/disk-utils/fdisk.h @@ -45,3 +45,4 @@ extern char *const str_units(void); /* prototypes for fdisklabel.c */ extern void bselect(void); +extern void btrydev (char * dev); diff --git a/disk-utils/fdisklabel.c b/disk-utils/fdisklabel.c index 5fbf67a4..a6b5ecc4 100644 --- a/disk-utils/fdisklabel.c +++ b/disk-utils/fdisklabel.c @@ -55,37 +55,45 @@ #define DKTYPENAMES #include "fdisklabel.h" -static void bsd_delete_part (void); -static void bsd_new_part (void); -static void bsd_print_disklabel (int show_all); -static void bsd_write_disklabel (void); -static int bsd_create_disklabel (void); -static void bsd_edit_disklabel (void); -static void bsd_write_bootstrap (void); -static void bsd_change_fstype (void); -static int bsd_get_part_index (int max); -static int bsd_check_new_partition (int *i); -static void bsd_list_types (void); -static u_short bsd_dkcksum (struct disklabel *lp); -static int bsd_initlabel (struct partition *p, struct disklabel *d, int pindex); -static int bsd_readlabel (struct partition *p, struct disklabel *d); -static int bsd_writelabel (struct partition *p, struct disklabel *d); +static void xbsd_delete_part (void); +static void xbsd_new_part (void); +static void xbsd_print_disklabel (int show_all); +static void xbsd_write_disklabel (void); +static int xbsd_create_disklabel (void); +static void xbsd_edit_disklabel (void); +static void xbsd_write_bootstrap (void); +static void xbsd_change_fstype (void); +static int xbsd_get_part_index (int max); +static int xbsd_check_new_partition (int *i); +static void xbsd_list_types (void); +static u_short xbsd_dkcksum (struct xbsd_disklabel *lp); +static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex); +static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d); +static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d); static void sync_disks (void); #if defined (i386) -static int bsd_translate_fstype (int linux_type); -static void bsd_link_part (void); +static int xbsd_translate_fstype (int linux_type); +static void xbsd_link_part (void); #endif #if defined (__alpha__) void alpha_bootblock_checksum (char *boot); #endif -static struct disklabel bsd_dlabel; +static struct xbsd_disklabel xbsd_dlabel; static char buffer[BSD_BBSIZE]; #if defined (i386) -static struct partition *bsd_part; -static int bsd_part_index; +static struct partition *xbsd_part; +static int xbsd_part_index; #endif +void +btrydev (char * dev) { + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + return; + printf("\nBSD label for device: %s\n", dev); + xbsd_print_disklabel (0); +} + void bmenu (void) { @@ -119,18 +127,18 @@ bselect (void) for (t=0; t<4; t++) if (part_table[t] -> sys_ind == NETBSD_PARTITION) { - bsd_part = part_table[t]; - bsd_part_index = t; - if (bsd_part -> start_sect == 0) + xbsd_part = part_table[t]; + xbsd_part_index = t; + if (xbsd_part -> start_sect == 0) { fprintf (stderr, "Partition %s%d has invalid starting sector 0.\n", disk_device, t+1); return; } printf ("Reading disklabel of %s%d at sector %d.\n", - disk_device, t+1, bsd_part -> start_sect + BSD_LABELSECTOR); - if (bsd_readlabel (bsd_part, &bsd_dlabel) == 0) - if (bsd_create_disklabel () == 0) + disk_device, t+1, xbsd_part -> start_sect + BSD_LABELSECTOR); + if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) return; break; } @@ -143,8 +151,8 @@ bselect (void) #elif defined (__alpha__) - if (bsd_readlabel (NULL, &bsd_dlabel) == 0) - if (bsd_create_disklabel () == 0) + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) exit ( EXIT_SUCCESS ); #endif @@ -155,40 +163,40 @@ bselect (void) switch (tolower (read_char ("BSD disklabel command (m for help): "))) { case 'd': - bsd_delete_part (); + xbsd_delete_part (); break; case 'e': - bsd_edit_disklabel (); + xbsd_edit_disklabel (); break; case 'i': - bsd_write_bootstrap (); + xbsd_write_bootstrap (); break; case 'l': - bsd_list_types (); + xbsd_list_types (); break; case 'n': - bsd_new_part (); + xbsd_new_part (); break; case 'p': - bsd_print_disklabel (0); + xbsd_print_disklabel (0); break; case 'q': close (fd); exit ( EXIT_SUCCESS ); case 's': - bsd_print_disklabel (1); + xbsd_print_disklabel (1); break; case 't': - bsd_change_fstype (); + xbsd_change_fstype (); break; case 'w': - bsd_write_disklabel (); + xbsd_write_disklabel (); break; #if defined (i386) case 'r': return; case 'x': - bsd_link_part (); + xbsd_link_part (); break; #endif default: @@ -199,35 +207,35 @@ bselect (void) } static void -bsd_delete_part (void) +xbsd_delete_part (void) { int i; - i = bsd_get_part_index (bsd_dlabel.d_npartitions); - bsd_dlabel.d_partitions[i].p_size = 0; - bsd_dlabel.d_partitions[i].p_offset = 0; - bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; - if (bsd_dlabel.d_npartitions == i + 1) - while (bsd_dlabel.d_partitions[bsd_dlabel.d_npartitions-1].p_size == 0) - bsd_dlabel.d_npartitions--; + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_size = 0; + xbsd_dlabel.d_partitions[i].p_offset = 0; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + if (xbsd_dlabel.d_npartitions == i + 1) + while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0) + xbsd_dlabel.d_npartitions--; } static void -bsd_new_part (void) +xbsd_new_part (void) { uint begin, end; char mesg[48]; int i; - if (!bsd_check_new_partition (&i)) + if (!xbsd_check_new_partition (&i)) return; #if defined (i386) - begin = bsd_part -> start_sect; - end = begin + bsd_part -> nr_sects - 1; + begin = xbsd_part -> start_sect; + end = begin + xbsd_part -> nr_sects - 1; #elif defined (__alpha__) begin = 0; - end = bsd_dlabel.d_secperunit; + end = xbsd_dlabel.d_secperunit; #endif sprintf (mesg, "First %s", str_units()); @@ -241,32 +249,32 @@ bsd_new_part (void) begin = (begin - 1) * display_factor; end = end * display_factor - 1; } - bsd_dlabel.d_partitions[i].p_size = end - begin + 1; - bsd_dlabel.d_partitions[i].p_offset = begin; - bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + xbsd_dlabel.d_partitions[i].p_size = end - begin + 1; + xbsd_dlabel.d_partitions[i].p_offset = begin; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; } static void -bsd_print_disklabel (int show_all) +xbsd_print_disklabel (int show_all) { - struct disklabel *lp = &bsd_dlabel; - struct bsd_partition *pp; + struct xbsd_disklabel *lp = &xbsd_dlabel; + struct xbsd_partition *pp; FILE *f = stdout; int i, j; if (show_all) { #if defined (i386) - fprintf(f, "# %s%d:\n", disk_device, bsd_part_index+1); + fprintf(f, "# %s%d:\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) fprintf(f, "# %s:\n", disk_device); #endif if ((unsigned) lp->d_type < BSD_DKMAXTYPES) - fprintf(f, "type: %s\n", bsd_dktypenames[lp->d_type]); + fprintf(f, "type: %s\n", xbsd_dktypenames[lp->d_type]); else fprintf(f, "type: %d\n", lp->d_type); - fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename); - fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname); + fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename); + fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname); fprintf(f, "flags:"); if (lp->d_flags & BSD_D_REMOVABLE) fprintf(f, " removable"); @@ -275,17 +283,19 @@ bsd_print_disklabel (int show_all) if (lp->d_flags & BSD_D_BADSECT) fprintf(f, " badsect"); fprintf(f, "\n"); - fprintf(f, "bytes/sector: %d\n", lp->d_secsize); - fprintf(f, "sectors/track: %d\n", lp->d_nsectors); - fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks); - fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl); - fprintf(f, "cylinders: %d\n", lp->d_ncylinders); + /* On various machines the fields of *lp are short/int/long */ + /* In order to avoid problems, we cast them all to long. */ + fprintf(f, "bytes/sector: %ld\n", (long) lp->d_secsize); + fprintf(f, "sectors/track: %ld\n", (long) lp->d_nsectors); + fprintf(f, "tracks/cylinder: %ld\n", (long) lp->d_ntracks); + fprintf(f, "sectors/cylinder: %ld\n", (long) lp->d_secpercyl); + fprintf(f, "cylinders: %ld\n", (long) lp->d_ncylinders); fprintf(f, "rpm: %d\n", lp->d_rpm); fprintf(f, "interleave: %d\n", lp->d_interleave); fprintf(f, "trackskew: %d\n", lp->d_trackskew); fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); - fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); - fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); + fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long) lp->d_headswitch); + fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long) lp->d_trkseek); fprintf(f, "drivedata: "); for (i = NDDATA - 1; i >= 0; i--) if (lp->d_drivedata[i]) @@ -293,29 +303,29 @@ bsd_print_disklabel (int show_all) if (i < 0) i = 0; for (j = 0; j <= i; j++) - fprintf(f, "%d ", lp->d_drivedata[j]); + fprintf(f, "%ld ", (long) lp->d_drivedata[j]); } fprintf (f, "\n%d partitions:\n", lp->d_npartitions); fprintf (f, "# size offset fstype [fsize bsize cpg]\n"); pp = lp->d_partitions; for (i = 0; i < lp->d_npartitions; i++, pp++) { if (pp->p_size) { - fprintf(f, " %c: %8d %8d ", 'a' + i, - pp->p_size, pp->p_offset); + fprintf(f, " %c: %8ld %8ld ", 'a' + i, + (long) pp->p_size, (long) pp->p_offset); if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) - fprintf(f, "%8.8s", bsd_fstypes[pp->p_fstype].name); + fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name); else fprintf(f, "%8x", pp->p_fstype); switch (pp->p_fstype) { case BSD_FS_UNUSED: - fprintf(f, " %5d %5d %5.5s ", - pp->p_fsize, pp->p_fsize * pp->p_frag, ""); + fprintf(f, " %5ld %5ld %5.5s ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, ""); break; case BSD_FS_BSDFFS: - fprintf(f, " %5d %5d %5d ", - pp->p_fsize, pp->p_fsize * pp->p_frag, + fprintf(f, " %5ld %5ld %5d ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg); break; @@ -323,7 +333,7 @@ bsd_print_disklabel (int show_all) fprintf(f, "%20.20s", ""); break; } - fprintf(f, "\t# (Cyl. %4d", + fprintf(f, "\t# (Cyl. %4ld", (long) #if 0 pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ #else @@ -333,8 +343,8 @@ bsd_print_disklabel (int show_all) putc('*', f); else putc(' ', f); - fprintf(f, "- %d", - (pp->p_offset + + fprintf(f, "- %ld", + (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / #if 0 lp->d_secpercyl - 1); /* differs from Linux fdisk */ @@ -349,25 +359,25 @@ bsd_print_disklabel (int show_all) } static void -bsd_write_disklabel (void) +xbsd_write_disklabel (void) { #if defined (i386) - printf ("Writing disklabel to %s%d.\n", disk_device, bsd_part_index+1); - bsd_writelabel (bsd_part, &bsd_dlabel); + printf ("Writing disklabel to %s%d.\n", disk_device, xbsd_part_index+1); + xbsd_writelabel (xbsd_part, &xbsd_dlabel); #elif defined (__alpha__) printf ("Writing disklabel to %s.\n", disk_device); - bsd_writelabel (NULL, &bsd_dlabel); + xbsd_writelabel (NULL, &xbsd_dlabel); #endif } static int -bsd_create_disklabel (void) +xbsd_create_disklabel (void) { char c; #if defined (i386) fprintf (stderr, "%s%d contains no disklabel.\n", - disk_device, bsd_part_index+1); + disk_device, xbsd_part_index+1); #elif defined (__alpha__) fprintf (stderr, "%s contains no disklabel.\n", disk_device); #endif @@ -376,12 +386,12 @@ bsd_create_disklabel (void) if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') { #if defined (i386) - if (bsd_initlabel (bsd_part, &bsd_dlabel, bsd_part_index) == 1) + if (xbsd_initlabel (xbsd_part, &xbsd_dlabel, xbsd_part_index) == 1) #elif defined (__alpha__) - if (bsd_initlabel (NULL, &bsd_dlabel, 0) == 1) + if (xbsd_initlabel (NULL, &xbsd_dlabel, 0) == 1) #endif { - bsd_print_disklabel (1); + xbsd_print_disklabel (1); return 1; } else @@ -405,11 +415,11 @@ edit_int (int def, char *mesg) } static void -bsd_edit_disklabel (void) +xbsd_edit_disklabel (void) { - struct disklabel *d; + struct xbsd_disklabel *d; - d = &bsd_dlabel; + d = &xbsd_dlabel; #ifdef __alpha__ d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); @@ -439,7 +449,7 @@ bsd_edit_disklabel (void) } static int -bsd_get_bootstrap (char *path, void *ptr, int size) +xbsd_get_bootstrap (char *path, void *ptr, int size) { int fd; @@ -460,16 +470,16 @@ bsd_get_bootstrap (char *path, void *ptr, int size) } static void -bsd_write_bootstrap (void) +xbsd_write_bootstrap (void) { char *bootdir = BSD_LINUX_BOOTDIR; char path[MAXPATHLEN]; char *dkbasename; - struct disklabel dl; + struct xbsd_disklabel dl; char *d, *p, *e; int sector; - if (bsd_dlabel.d_type == BSD_DTYPE_SCSI) + if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI) dkbasename = "sd"; else dkbasename = "wd"; @@ -481,22 +491,22 @@ bsd_write_bootstrap (void) dkbasename = line_ptr; } sprintf (path, "%s/%sboot", bootdir, dkbasename); - if (!bsd_get_bootstrap (path, buffer, (int) bsd_dlabel.d_secsize)) + if (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize)) return; - /* We need a backup of the disklabel (bsd_dlabel might have changed). */ + /* We need a backup of the disklabel (xbsd_dlabel might have changed). */ d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; - bcopy (d, &dl, sizeof (struct disklabel)); + bcopy (d, &dl, sizeof (struct xbsd_disklabel)); /* The disklabel will be overwritten by 0's from bootxx anyway */ - bzero (d, sizeof (struct disklabel)); + bzero (d, sizeof (struct xbsd_disklabel)); sprintf (path, "%s/boot%s", bootdir, dkbasename); - if (!bsd_get_bootstrap (path, &buffer[bsd_dlabel.d_secsize], - (int) bsd_dlabel.d_bbsize - bsd_dlabel.d_secsize)) + if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize], + (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize)) return; - e = d + sizeof (struct disklabel); + e = d + sizeof (struct xbsd_disklabel); for (p=d; p < e; p++) if (*p) { @@ -504,10 +514,10 @@ bsd_write_bootstrap (void) exit ( EXIT_FAILURE ); } - bcopy (&dl, d, sizeof (struct disklabel)); + bcopy (&dl, d, sizeof (struct xbsd_disklabel)); #if defined (i386) - sector = bsd_part -> start_sect; + sector = xbsd_part -> start_sect; #elif defined (__alpha__) sector = 0; alpha_bootblock_checksum (buffer); @@ -519,7 +529,7 @@ bsd_write_bootstrap (void) fatal (unable_to_write); #if defined (i386) - printf ("Bootstrap installed on %s%d.\n", disk_device, bsd_part_index+1); + printf ("Bootstrap installed on %s%d.\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) printf ("Bootstrap installed on %s.\n", disk_device); #endif @@ -528,16 +538,16 @@ bsd_write_bootstrap (void) } static void -bsd_change_fstype (void) +xbsd_change_fstype (void) { int i; - i = bsd_get_part_index (bsd_dlabel.d_npartitions); - bsd_dlabel.d_partitions[i].p_fstype = read_hex (bsd_fstypes, BSD_FSMAXTYPES); + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes, BSD_FSMAXTYPES); } static int -bsd_get_part_index (int max) +xbsd_get_part_index (int max) { char prompt[40]; char l; @@ -550,14 +560,14 @@ bsd_get_part_index (int max) } static int -bsd_check_new_partition (int *i) +xbsd_check_new_partition (int *i) { int t; - if (bsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) + if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) { for (t=0; t < BSD_MAXPARTITIONS; t++) - if (bsd_dlabel.d_partitions[t].p_size == 0) + if (xbsd_dlabel.d_partitions[t].p_size == 0) break; if (t == BSD_MAXPARTITIONS) @@ -566,12 +576,12 @@ bsd_check_new_partition (int *i) return 0; } } - *i = bsd_get_part_index (BSD_MAXPARTITIONS); + *i = xbsd_get_part_index (BSD_MAXPARTITIONS); - if (*i >= bsd_dlabel.d_npartitions) - bsd_dlabel.d_npartitions = (*i) + 1; + if (*i >= xbsd_dlabel.d_npartitions) + xbsd_dlabel.d_npartitions = (*i) + 1; - if (bsd_dlabel.d_partitions[*i].p_size != 0) + if (xbsd_dlabel.d_partitions[*i].p_size != 0) { fprintf (stderr, "This partition already exists.\n"); return 0; @@ -580,13 +590,13 @@ bsd_check_new_partition (int *i) } static void -bsd_list_types (void) +xbsd_list_types (void) { - list_types (bsd_fstypes, BSD_FSMAXTYPES); + list_types (xbsd_fstypes, BSD_FSMAXTYPES); } static u_short -bsd_dkcksum (struct disklabel *lp) +xbsd_dkcksum (struct xbsd_disklabel *lp) { register u_short *start, *end; register u_short sum = 0; @@ -599,17 +609,17 @@ bsd_dkcksum (struct disklabel *lp) } static int -bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) +xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) { struct hd_geometry geometry; - struct bsd_partition *pp; + struct xbsd_partition *pp; if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) { perror ("ioctl"); return 0; } - bzero (d, sizeof (struct disklabel)); + bzero (d, sizeof (struct xbsd_disklabel)); d -> d_magic = BSD_DISKMAGIC; @@ -667,7 +677,7 @@ bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) } static int -bsd_readlabel (struct partition *p, struct disklabel *d) +xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d) { int t, sector; @@ -683,7 +693,7 @@ bsd_readlabel (struct partition *p, struct disklabel *d) fatal (unable_to_read); bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - d, sizeof (struct disklabel)); + d, sizeof (struct xbsd_disklabel)); for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) { @@ -701,7 +711,7 @@ bsd_readlabel (struct partition *p, struct disklabel *d) } static int -bsd_writelabel (struct partition *p, struct disklabel *d) +xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d) { int sector; @@ -712,13 +722,13 @@ bsd_writelabel (struct partition *p, struct disklabel *d) #endif d -> d_checksum = 0; - d -> d_checksum = bsd_dkcksum (d); + d -> d_checksum = xbsd_dkcksum (d); /* This is necessary if we want to write the bootstrap later, otherwise we'd write the old disklabel with the bootstrap. */ bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - sizeof (struct disklabel)); + sizeof (struct xbsd_disklabel)); #if defined (__alpha__) && BSD_LABELSECTOR == 0 alpha_bootblock_checksum (buffer); @@ -729,7 +739,7 @@ bsd_writelabel (struct partition *p, struct disklabel *d) #else if (ext2_llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1) fatal (unable_to_seek); - if (sizeof (struct disklabel) != write (fd, d, sizeof (struct disklabel))) + if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel))) fatal (unable_to_write); #endif @@ -748,7 +758,7 @@ sync_disks (void) #if defined (i386) static int -bsd_translate_fstype (int linux_type) +xbsd_translate_fstype (int linux_type) { switch (linux_type) { @@ -767,24 +777,23 @@ bsd_translate_fstype (int linux_type) } static void -bsd_link_part (void) +xbsd_link_part (void) { int k, i; k = get_partition (1, partitions); - if (!bsd_check_new_partition (&i)) + if (!xbsd_check_new_partition (&i)) return; - bsd_dlabel.d_partitions[i].p_size = part_table[k] -> nr_sects; - bsd_dlabel.d_partitions[i].p_offset = part_table[k] -> start_sect; - bsd_dlabel.d_partitions[i].p_fstype = - bsd_translate_fstype (part_table[k] -> sys_ind); + xbsd_dlabel.d_partitions[i].p_size = part_table[k] -> nr_sects; + xbsd_dlabel.d_partitions[i].p_offset = part_table[k] -> start_sect; + xbsd_dlabel.d_partitions[i].p_fstype = + xbsd_translate_fstype (part_table[k] -> sys_ind); } #endif #if defined (__alpha__) -typedef unsigned long long u_int64_t; void alpha_bootblock_checksum (char *boot) diff --git a/disk-utils/fdisklabel.h b/disk-utils/fdisklabel.h index 841046bb..d007b34b 100644 --- a/disk-utils/fdisklabel.h +++ b/disk-utils/fdisklabel.h @@ -31,8 +31,14 @@ * SUCH DAMAGE. */ -#define BSD_DISKMAGIC ((u_long) 0x82564557) +#ifndef BSD_DISKMAGIC /* perhaps from */ +#define BSD_DISKMAGIC ((__u32) 0x82564557) +#endif + +#ifndef BSD_MAXPARTITIONS #define BSD_MAXPARTITIONS 8 +#endif + #define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" #if defined (i386) @@ -41,62 +47,40 @@ #define BSD_BBSIZE 8192 /* size of boot area, with label */ #define BSD_SBSIZE 8192 /* max size of fs superblock */ #elif defined (__alpha__) -#error LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __alpha__ #define BSD_LABELSECTOR 0 -#define BSD_LABELOFFSET 0 -#define BSD_BBSIZE 0 -#define BSD_SBSIZE 0 +#define BSD_LABELOFFSET 64 +#define BSD_BBSIZE 8192 +#define BSD_SBSIZE 8192 #else #error unknown architecture #endif -struct disklabel { - u_long d_magic; /* the magic number */ - short d_type; /* drive type */ - short d_subtype; /* controller/d_type specific */ +struct xbsd_disklabel { + __u32 d_magic; /* the magic number */ + __s16 d_type; /* drive type */ + __s16 d_subtype; /* controller/d_type specific */ char d_typename[16]; /* type name, e.g. "eagle" */ - /* - * d_packname contains the pack identifier and is returned when - * the disklabel is read off the disk or in-core copy. - * d_boot0 and d_boot1 are the (optional) names of the - * primary (block 0) and secondary (block 1-15) bootstraps - * as found in /usr/mdec. These are returned when using - * getdiskbyname(3) to retrieve the values from /etc/disktab. - */ -#if defined(KERNEL) || defined(STANDALONE) char d_packname[16]; /* pack identifier */ -#else - union { - char un_d_packname[16]; /* pack identifier */ - struct { - char *un_d_boot0; /* primary bootstrap name */ - char *un_d_boot1; /* secondary bootstrap name */ - } un_b; - } d_un; -#define d_packname d_un.un_d_packname -#define d_boot0 d_un.un_b.un_d_boot0 -#define d_boot1 d_un.un_b.un_d_boot1 -#endif /* ! KERNEL or STANDALONE */ /* disk geometry: */ - u_long d_secsize; /* # of bytes per sector */ - u_long d_nsectors; /* # of data sectors per track */ - u_long d_ntracks; /* # of tracks per cylinder */ - u_long d_ncylinders; /* # of data cylinders per unit */ - u_long d_secpercyl; /* # of data sectors per cylinder */ - u_long d_secperunit; /* # of data sectors per unit */ + __u32 d_secsize; /* # of bytes per sector */ + __u32 d_nsectors; /* # of data sectors per track */ + __u32 d_ntracks; /* # of tracks per cylinder */ + __u32 d_ncylinders; /* # of data cylinders per unit */ + __u32 d_secpercyl; /* # of data sectors per cylinder */ + __u32 d_secperunit; /* # of data sectors per unit */ /* * Spares (bad sector replacements) below * are not counted in d_nsectors or d_secpercyl. * Spare sectors are assumed to be physical sectors * which occupy space at the end of each track and/or cylinder. */ - u_short d_sparespertrack; /* # of spare sectors per track */ - u_short d_sparespercyl; /* # of spare sectors per cylinder */ + __u16 d_sparespertrack; /* # of spare sectors per track */ + __u16 d_sparespercyl; /* # of spare sectors per cylinder */ /* * Alternate cylinders include maintenance, replacement, * configuration description areas, etc. */ - u_long d_acylinders; /* # of alt. cylinders per unit */ + __u32 d_acylinders; /* # of alt. cylinders per unit */ /* hardware characteristics: */ /* @@ -115,30 +99,30 @@ struct disklabel { * Finally, d_cylskew is the offset of sector 0 on cylinder N * relative to sector 0 on cylinder N-1. */ - u_short d_rpm; /* rotational speed */ - u_short d_interleave; /* hardware sector interleave */ - u_short d_trackskew; /* sector 0 skew, per track */ - u_short d_cylskew; /* sector 0 skew, per cylinder */ - u_long d_headswitch; /* head switch time, usec */ - u_long d_trkseek; /* track-to-track seek, usec */ - u_long d_flags; /* generic flags */ + __u16 d_rpm; /* rotational speed */ + __u16 d_interleave; /* hardware sector interleave */ + __u16 d_trackskew; /* sector 0 skew, per track */ + __u16 d_cylskew; /* sector 0 skew, per cylinder */ + __u32 d_headswitch; /* head switch time, usec */ + __u32 d_trkseek; /* track-to-track seek, usec */ + __u32 d_flags; /* generic flags */ #define NDDATA 5 - u_long d_drivedata[NDDATA]; /* drive-type specific information */ + __u32 d_drivedata[NDDATA]; /* drive-type specific information */ #define NSPARE 5 - u_long d_spare[NSPARE]; /* reserved for future use */ - u_long d_magic2; /* the magic number (again) */ - u_short d_checksum; /* xor of data incl. partitions */ + __u32 d_spare[NSPARE]; /* reserved for future use */ + __u32 d_magic2; /* the magic number (again) */ + __u16 d_checksum; /* xor of data incl. partitions */ /* filesystem and partition information: */ - u_short d_npartitions; /* number of partitions in following */ - u_long d_bbsize; /* size of boot area at sn0, bytes */ - u_long d_sbsize; /* max size of fs superblock, bytes */ - struct bsd_partition { /* the partition table */ - u_long p_size; /* number of sectors in partition */ - u_long p_offset; /* starting sector */ - u_long p_fsize; /* filesystem basic fragment size */ - u_char p_fstype; /* filesystem type, see below */ - u_char p_frag; /* filesystem fragments per block */ - u_short p_cpg; /* filesystem cylinders per group */ + __u16 d_npartitions; /* number of partitions in following */ + __u32 d_bbsize; /* size of boot area at sn0, bytes */ + __u32 d_sbsize; /* max size of fs superblock, bytes */ + struct xbsd_partition { /* the partition table */ + __u32 p_size; /* number of sectors in partition */ + __u32 p_offset; /* starting sector */ + __u32 p_fsize; /* filesystem basic fragment size */ + __u8 p_fstype; /* filesystem type, see below */ + __u8 p_frag; /* filesystem fragments per block */ + __u16 p_cpg; /* filesystem cylinders per group */ } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ }; @@ -159,7 +143,7 @@ struct disklabel { #define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ #ifdef DKTYPENAMES -static char *bsd_dktypenames[] = { +static char *xbsd_dktypenames[] = { "unknown", "SMD", "MSCP", @@ -173,7 +157,7 @@ static char *bsd_dktypenames[] = { "floppy", 0 }; -#define BSD_DKMAXTYPES (sizeof(bsd_dktypenames) / sizeof(bsd_dktypenames[0]) - 1) +#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1) #endif /* @@ -189,7 +173,6 @@ static char *bsd_dktypenames[] = { #define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ #define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ #define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ -#define BSD_FS_MSDOS 8 /* MS-DOS file system */ #define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ #define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ #define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ @@ -199,8 +182,15 @@ static char *bsd_dktypenames[] = { #define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ #define BSD_FS_HFS 15 /* Macintosh HFS */ +/* this is annoying, but it's also the way it is :-( */ +#ifdef __alpha__ +#define BSD_FS_EXT2 8 /* MS-DOS file system */ +#else +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#endif + #ifdef DKTYPENAMES -static struct systypes bsd_fstypes[] = { +static struct systypes xbsd_fstypes[] = { {BSD_FS_UNUSED, "unused"}, {BSD_FS_SWAP, "swap"}, {BSD_FS_V6, "Version 6"}, @@ -209,7 +199,11 @@ static struct systypes bsd_fstypes[] = { {BSD_FS_V71K, "4.1BSD"}, {BSD_FS_V8, "Eighth Edition"}, {BSD_FS_BSDFFS, "4.2BSD"}, +#ifdef __alpha__ + {BSD_FS_EXT2, "ext2"}, +#else {BSD_FS_MSDOS, "MS-DOS"}, +#endif {BSD_FS_BSDLFS, "4.4LFS"}, {BSD_FS_OTHER, "unknown"}, {BSD_FS_HPFS, "HPFS"}, @@ -219,7 +213,7 @@ static struct systypes bsd_fstypes[] = { {BSD_FS_HFS, "HFS"} }; -#define BSD_FSMAXTYPES (sizeof(bsd_fstypes) / sizeof(struct systypes)) +#define BSD_FSMAXTYPES (sizeof(xbsd_fstypes) / sizeof(struct systypes)) #endif /* diff --git a/disk-utils/fsck.minix.8 b/disk-utils/fsck.minix.8 index 024e1b7a..f0d85375 100644 --- a/disk-utils/fsck.minix.8 +++ b/disk-utils/fsck.minix.8 @@ -1,7 +1,7 @@ .\" Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu) .\" May be freely distributed. .\" " for hilit19 -.TH FSCK 8 "10 January 1994" "Linux 0.99" "Linux Programmer's Manual" +.TH FSCK 8 "2 July 1996" "Util-Linux 2.6" "Linux Programmer's Manual" .SH NAME fsck.minix \- a file system consistency checker for Linux .SH SYNOPSIS @@ -22,10 +22,10 @@ searches for files). The device will usually have the following form: .nf .RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] +/dev/hda[1-63] (IDE disk 1) +/dev/hdb[1-63] (IDE disk 2) +/dev/sda[1-15] (SCSI disk 1) +/dev/sdb[1-15] (SCSI disk 2) .RE .fi @@ -126,3 +126,9 @@ Added support for file system valid flag: Dr. Wettstein .br Check to prevent fsck of mounted filesystem added by Daniel Quinlan (quinlan@yggdrasil.com) +.br +Minix v2 fs support by Andreas Schwab +(schwab@issan.informatik.uni-dortmund.de), updated by Nicolai +Langfeldt (janl@math.uio.no) +.br +Portability patch by Russell King (rmk@ecs.soton.ac.uk). diff --git a/disk-utils/fsck.minix.c b/disk-utils/fsck.minix.c index 209f9ce7..0e8dc64e 100644 --- a/disk-utils/fsck.minix.c +++ b/disk-utils/fsck.minix.c @@ -37,11 +37,31 @@ * added program_version variable and output of * program name and version number when program * is executed. - * + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) + * * 10.12.94 - added test to prevent checking of mounted fs adapted * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck * program. (Daniel Quinlan, quinlan@yggdrasil.com) * + * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such + * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) + * + * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk + * (Russell King). He made them for ARM. It would seem + * that the ARM is powerfull enough to do this in C whereas + * i386 and m64k must use assembly to get it fast >:-) + * This should make minix fsck systemindependent. + * (janl@math.uio.no, Nicolai Langfeldt) + * + * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler + * warnings. Added mc68k bitops from + * Joerg Dorchain . + * + * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by + * Andreas Schwab. + * * I've had no time to add comments - hopefully the function names * are comments enough. As with all file system checkers, this assumes * the file system is quiescent - don't use it on a mounted device @@ -62,6 +82,7 @@ */ #include +#include #include #include #include @@ -73,9 +94,10 @@ #include #include +#include "../version.h" -#ifndef __GNUC__ -#error "needs gcc for the bitop-__asm__'s" +#ifdef MINIX2_SUPER_MAGIC2 +#define HAVE_MINIX2 1 #endif #ifndef __linux__ @@ -86,13 +108,19 @@ #define UPPER(size,n) ((size+((n)-1))/(n)) #define INODE_SIZE (sizeof(struct minix_inode)) -#define INODE_BLOCKS UPPER(INODES,MINIX_INODES_PER_BLOCK) +#ifdef HAVE_MINIX2 +#define INODE_SIZE2 (sizeof(struct minix2_inode)) +#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ + : MINIX_INODES_PER_BLOCK)) +#else +#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) +#endif #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) #define BITS_PER_BLOCK (BLOCK_SIZE<<3) static char * program_name = "fsck.minix"; -static char * program_version = "1.0 - 12/30/93"; +static char * program_version = "1.2 - 11/11/96"; static char * device_name = NULL; static int IN; static int repair=0, automatic=0, verbose=0, list=0, show=0, warn_mode=0, @@ -104,6 +132,9 @@ static int changed = 0; /* flags if the filesystem has been changed */ static int errors_uncorrected = 0; /* flag if some error was not corrected */ static int dirsize = 16; static int namelen = 14; +static int version2 = 0; +static struct termios termios; +static int termios_set = 0; /* File-name data */ #define MAX_DEPTH 50 @@ -112,10 +143,15 @@ static char name_list[MAX_DEPTH][NAME_MAX+1]; static char * inode_buffer = NULL; #define Inode (((struct minix_inode *) inode_buffer)-1) +#define Inode2 (((struct minix2_inode *) inode_buffer)-1) static char super_block_buffer[BLOCK_SIZE]; #define Super (*(struct minix_super_block *)super_block_buffer) #define INODES ((unsigned long)Super.s_ninodes) -#define ZONES ((unsigned long)Super.s_nzones) +#ifdef HAVE_MINIX2 +#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) +#else +#define ZONES ((unsigned long)(Super.s_nzones)) +#endif #define IMAPS ((unsigned long)Super.s_imap_blocks) #define ZMAPS ((unsigned long)Super.s_zmap_blocks) #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) @@ -131,20 +167,9 @@ static unsigned char * inode_count = NULL; static unsigned char * zone_count = NULL; void recursive_check(unsigned int ino); +void recursive_check2(unsigned int ino); -#define bitop(name,op) \ -static inline int name(char * addr,unsigned int nr) \ -{ \ -int __res; \ -__asm__ __volatile__("bt" op "l %1,%2; adcl $0,%0" \ -:"=g" (__res) \ -:"r" (nr),"m" (*(addr)),"0" (0)); \ -return __res; \ -} - -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") +#include "bitops.h" #define inode_in_use(x) (bit(inode_map,(x))) #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) @@ -155,14 +180,12 @@ bitop(clrbit,"r") #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) -/* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. - */ -volatile void fatal_error(const char * fmt_string, int status) +void fatal_error(const char *, int) __attribute__ ((noreturn)); +void fatal_error(const char * fmt_string, int status) { fprintf(stderr,fmt_string,program_name,device_name); + if (termios_set) + tcsetattr(0, TCSANOW, &termios); exit(status); } @@ -179,6 +202,8 @@ void print_current_name(void) while (i= ZONES) + printf ("Zone nr >= ZONES in file `"); + else + return *nr; + print_current_name (); + printf ("'."); + if (ask ("Remove block", 1)) { + *nr = 0; + *corrected = 1; + } + return 0; +} + /* * read-block reads block nr into the buffer at addr. */ @@ -378,6 +423,65 @@ int map_block(struct minix_inode * inode, unsigned int blknr) return result; } +#ifdef HAVE_MINIX2 +int map_block2 (struct minix2_inode *inode, unsigned int blknr) +{ + unsigned int ind[BLOCK_SIZE >> 2]; + unsigned int dind[BLOCK_SIZE >> 2]; + unsigned int tind[BLOCK_SIZE >> 2]; + int blk_chg, block, result; + + if (blknr < 7) + return check_zone_nr2 (inode->i_zone + blknr, &changed); + blknr -= 7; + if (blknr < 256) { + block = check_zone_nr2 (inode->i_zone + 7, &changed); + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (blknr + ind, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; + } + blknr -= 256; + if (blknr >= 256 * 256) { + block = check_zone_nr2 (inode->i_zone + 8, &changed); + read_block (block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2 (dind + blknr / 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) dind); + block = result; + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; + } + blknr -= 256 * 256; + block = check_zone_nr2 (inode->i_zone + 9, &changed); + read_block (block, (char *) tind); + blk_chg = 0; + result = check_zone_nr2 (tind + blknr / (256 * 256), &blk_chg); + if (blk_chg) + write_block (block, (char *) tind); + block = result; + read_block (block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2 (dind + (blknr / 256) % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) dind); + block = result; + read_block (block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2 (ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block (block, (char *) ind); + return result; +} +#endif + void write_super_block(void) { /* @@ -411,10 +515,31 @@ void write_tables(void) die("Unable to write inodes"); } -void read_tables(void) +void get_dirsize (void) +{ + int block; + char blk[BLOCK_SIZE]; + int size; + +#if HAVE_MINIX2 + if (version2) + block = Inode2[ROOT_INO].i_zone[0]; + else +#endif + block = Inode[ROOT_INO].i_zone[0]; + read_block (block, blk); + for (size = 16; size < BLOCK_SIZE; size <<= 1) { + if (strcmp (blk + size + 2, "..") == 0) { + dirsize = size; + namelen = size - 2; + return; + } + } + /* use defaults */ +} + +void read_superblock(void) { - memset(inode_map,0,sizeof(inode_map)); - memset(zone_map,0,sizeof(zone_map)); if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) die("seek failed"); if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) @@ -422,9 +547,21 @@ void read_tables(void) if (MAGIC == MINIX_SUPER_MAGIC) { namelen = 14; dirsize = 16; + version2 = 0; } else if (MAGIC == MINIX_SUPER_MAGIC2) { namelen = 30; dirsize = 32; + version2 = 0; +#ifdef HAVE_MINIX2 + } else if (MAGIC == MINIX2_SUPER_MAGIC) { + namelen = 14; + dirsize = 16; + version2 = 1; + } else if (MAGIC == MINIX2_SUPER_MAGIC2) { + namelen = 30; + dirsize = 32; + version2 = 1; +#endif } else die("bad magic number in super-block"); if (ZONESIZE != 0 || BLOCK_SIZE != 1024) @@ -433,6 +570,12 @@ void read_tables(void) die("bad s_imap_blocks field in super-block"); if (!ZMAPS || ZMAPS > MINIX_Z_MAP_SLOTS) die("bad s_zmap_blocks field in super-block"); +} + +void read_tables(void) +{ + memset(inode_map,0,sizeof(inode_map)); + memset(zone_map,0,sizeof(zone_map)); inode_buffer = malloc(INODE_BUFFER_SIZE); if (!inode_buffer) die("Unable to allocate buffer for inodes"); @@ -452,12 +595,13 @@ void read_tables(void) printf("Warning: Firstzone != Norm_firstzone\n"); errors_uncorrected = 1; } + get_dirsize (); if (show) { - printf("%d inodes\n",INODES); - printf("%d blocks\n",ZONES); - printf("Firstdatazone=%d (%d)\n",FIRSTZONE,NORM_FIRSTZONE); + printf("%ld inodes\n",INODES); + printf("%ld blocks\n",ZONES); + printf("Firstdatazone=%ld (%ld)\n",FIRSTZONE,NORM_FIRSTZONE); printf("Zonesize=%d\n",BLOCK_SIZE<= INODES) + return NULL; + total++; + inode = Inode2 + nr; + if (!inode_count[nr]) { + if (!inode_in_use (nr)) { + printf ("Inode %d marked not used, but used for file '", nr); + print_current_name (); + printf ("'\n"); + if (repair) { + if (ask ("Mark in use", 1)) + mark_inode (nr); + else + errors_uncorrected = 1; + } + } + if (S_ISDIR (inode->i_mode)) + directory++; + else if (S_ISREG (inode->i_mode)) + regular++; + else if (S_ISCHR (inode->i_mode)) + chardev++; + else if (S_ISBLK (inode->i_mode)) + blockdev++; + else if (S_ISLNK (inode->i_mode)) + symlinks++; + else if (S_ISSOCK (inode->i_mode)); + else if (S_ISFIFO (inode->i_mode)); + else { + print_current_name (); + printf (" has mode %05o\n", inode->i_mode); + } + } else + links++; + if (!++inode_count[nr]) { + printf ("Warning: inode count too big.\n"); + inode_count[nr]--; + errors_uncorrected = 1; + } + return inode; +} +#endif + void check_root(void) { struct minix_inode * inode = Inode + ROOT_INO; @@ -520,6 +713,16 @@ void check_root(void) die("root inode isn't a directory"); } +#ifdef HAVE_MINIX2 +void check_root2 (void) +{ + struct minix2_inode *inode = Inode2 + ROOT_INO; + + if (!inode || !S_ISDIR (inode->i_mode)) + die ("root inode isn't a directory"); +} +#endif + static int add_zone(unsigned short * znr, int * corrected) { int result; @@ -553,6 +756,40 @@ static int add_zone(unsigned short * znr, int * corrected) return block; } + +static int add_zone2 (unsigned int *znr, int *corrected) +{ + int result; + int block; + + result = 0; + block = check_zone_nr2 (znr, corrected); + if (!block) + return 0; + if (zone_count[block]) { + printf ("Block has been used before. Now in file `"); + print_current_name (); + printf ("'."); + if (ask ("Clear", 1)) { + *znr = 0; + block = 0; + *corrected = 1; + } + } + if (!block) + return 0; + if (!zone_in_use (block)) { + printf ("Block %d in file `", block); + print_current_name (); + printf ("' is marked not in use."); + if (ask ("Correct", 1)) + mark_zone (block); + } + if (!++zone_count[block]) + zone_count[block]--; + return block; +} + static void add_zone_ind(unsigned short * znr, int * corrected) { static char blk[BLOCK_SIZE]; @@ -569,6 +806,22 @@ static void add_zone_ind(unsigned short * znr, int * corrected) write_block(block, blk); } +static void add_zone_ind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, chg_blk = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone2 (i + (unsigned int *) blk, &chg_blk); + if (chg_blk) + write_block (block, blk); +} + static void add_zone_dind(unsigned short * znr, int * corrected) { static char blk[BLOCK_SIZE]; @@ -585,6 +838,40 @@ static void add_zone_dind(unsigned short * znr, int * corrected) write_block(block, blk); } +static void +add_zone_dind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_ind2 (i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block (block, blk); +} + +static void +add_zone_tind2 (unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2 (znr, corrected); + if (!block) + return; + read_block (block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_dind2 (i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block (block, blk); +} + void check_zones(unsigned int i) { struct minix_inode * inode; @@ -603,6 +890,28 @@ void check_zones(unsigned int i) add_zone_dind(8 + inode->i_zone, &changed); } +#ifdef HAVE_MINIX2 +void +check_zones2 (unsigned int i) +{ + struct minix2_inode *inode; + + if (!i || i >= INODES) + return; + if (inode_count[i] > 1) /* have we counted this file already? */ + return; + inode = Inode2 + i; + if (!S_ISDIR (inode->i_mode) && !S_ISREG (inode->i_mode) + && !S_ISLNK (inode->i_mode)) + return; + for (i = 0; i < 7; i++) + add_zone2 (i + inode->i_zone, &changed); + add_zone_ind2 (7 + inode->i_zone, &changed); + add_zone_dind2 (8 + inode->i_zone, &changed); + add_zone_tind2 (9 + inode->i_zone, &changed); +} +#endif + void check_file(struct minix_inode * dir, unsigned int offset) { static char blk[BLOCK_SIZE]; @@ -625,7 +934,11 @@ void check_file(struct minix_inode * dir, unsigned int offset) } ino = 0; } + if (name_depth < MAX_DEPTH) + strncpy (name_list[name_depth], name, namelen); + name_depth++; inode = get_inode(ino); + name_depth--; if (!offset) if (!inode || strcmp(".",name)) { print_current_name(); @@ -659,6 +972,71 @@ void check_file(struct minix_inode * dir, unsigned int offset) return; } +#ifdef HAVE_MINIX2 +void +check_file2 (struct minix2_inode *dir, unsigned int offset) +{ + static char blk[BLOCK_SIZE]; + struct minix2_inode *inode; + int ino; + char *name; + int block; + + block = map_block2 (dir, offset / BLOCK_SIZE); + read_block (block, blk); + name = blk + (offset % BLOCK_SIZE) + 2; + ino = *(unsigned short *) (name - 2); + if (ino >= INODES) { + print_current_name (); + printf (" contains a bad inode number for file '"); + printf ("%.*s'.", namelen, name); + if (ask (" Remove", 1)) { + *(unsigned short *) (name - 2) = 0; + write_block (block, blk); + } + ino = 0; + } + if (name_depth < MAX_DEPTH) + strncpy (name_list[name_depth], name, namelen); + name_depth++; + inode = get_inode2 (ino); + name_depth--; + if (!offset) { + if (!inode || strcmp (".", name)) { + print_current_name (); + printf (": bad directory: '.' isn't first\n"); + errors_uncorrected = 1; + } else + return; + } + if (offset == dirsize) { + if (!inode || strcmp ("..", name)) { + print_current_name (); + printf (": bad directory: '..' isn't second\n"); + errors_uncorrected = 1; + } else + return; + } + if (!inode) + return; + name_depth++; + if (list) { + if (verbose) + printf ("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); + print_current_name (); + if (S_ISDIR (inode->i_mode)) + printf (":\n"); + else + printf ("\n"); + } + check_zones2 (ino); + if (inode && S_ISDIR (inode->i_mode)) + recursive_check2 (ino); + name_depth--; + return; +} +#endif + void recursive_check(unsigned int ino) { struct minix_inode * dir; @@ -667,7 +1045,7 @@ void recursive_check(unsigned int ino) dir = Inode + ino; if (!S_ISDIR(dir->i_mode)) die("internal error"); - if (dir->i_size < 32) { + if (dir->i_size < 2 * dirsize) { print_current_name(); printf(": bad directory: size<32"); errors_uncorrected = 1; @@ -676,6 +1054,26 @@ void recursive_check(unsigned int ino) check_file(dir,offset); } +#ifdef HAVE_MINIX2 +void +recursive_check2 (unsigned int ino) +{ + struct minix2_inode *dir; + unsigned int offset; + + dir = Inode2 + ino; + if (!S_ISDIR (dir->i_mode)) + die ("internal error"); + if (dir->i_size < 2 * dirsize) { + print_current_name (); + printf (": bad directory: size < 32"); + errors_uncorrected = 1; + } + for (offset = 0; offset < dir->i_size; offset += dirsize) + check_file2 (dir, offset); +} +#endif + int bad_zone(int i) { char buffer[1024]; @@ -736,6 +1134,59 @@ void check_counts(void) } } +#ifdef HAVE_MINIX2 +void +check_counts2 (void) +{ + int i; + + for (i = 1; i < INODES; i++) { + if (!inode_in_use (i) && Inode2[i].i_mode && warn_mode) { + printf ("Inode %d mode not cleared.", i); + if (ask ("Clear", 1)) { + Inode2[i].i_mode = 0; + changed = 1; + } + } + if (!inode_count[i]) { + if (!inode_in_use (i)) + continue; + printf ("Inode %d not used, marked used in the bitmap.", i); + if (ask ("Clear", 1)) + unmark_inode (i); + continue; + } + if (!inode_in_use (i)) { + printf ("Inode %d used, marked unused in the bitmap.", i); + if (ask ("Set", 1)) + mark_inode (i); + } + if (Inode2[i].i_nlinks != inode_count[i]) { + printf ("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", + i, Inode2[i].i_mode, Inode2[i].i_nlinks, inode_count[i]); + if (ask ("Set i_nlinks to count", 1)) { + Inode2[i].i_nlinks = inode_count[i]; + changed = 1; + } + } + } + for (i = FIRSTZONE; i < ZONES; i++) { + if (zone_in_use (i) == zone_count[i]) + continue; + if (!zone_count[i]) { + if (bad_zone (i)) + continue; + printf ("Zone %d: marked in use, no file uses it.", i); + if (ask ("Unmark", 1)) + unmark_zone (i); + continue; + } + printf ("Zone %d: %sin use, counted=%d\n", + i, zone_in_use (i) ? "" : "not ", zone_count[i]); + } +} +#endif + void check(void) { memset(inode_count,0,INODES*sizeof(*inode_count)); @@ -745,9 +1196,21 @@ void check(void) check_counts(); } +#ifdef HAVE_MINIX2 +void +check2 (void) +{ + memset (inode_count, 0, INODES * sizeof (*inode_count)); + memset (zone_count, 0, ZONES * sizeof (*zone_count)); + check_zones2 (ROOT_INO); + recursive_check2 (ROOT_INO); + check_counts2 (); +} +#endif + int main(int argc, char ** argv) { - struct termios termios,tmp; + struct termios tmp; int count; int retcode = 0; @@ -755,6 +1218,10 @@ int main(int argc, char ** argv) program_name = *argv; if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) die("bad inode size"); +#ifdef HAVE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad v2 inode size"); +#endif while (argc-- > 1) { argv++; if (argv[0][0] != '-') @@ -780,17 +1247,13 @@ int main(int argc, char ** argv) if (repair && !automatic) { if (!isatty(0) || !isatty(1)) die("need terminal for interactive repairs"); - tcgetattr(0,&termios); - tmp = termios; - tmp.c_lflag &= ~(ICANON|ECHO); - tcsetattr(0,TCSANOW,&tmp); } IN = open(device_name,repair?O_RDWR:O_RDONLY); if (IN < 0) die("unable to open '%s'"); for (count=0 ; count<3 ; count++) sync(); - read_tables(); + read_superblock(); /* * Determine whether or not we should continue with the checking. @@ -798,14 +1261,13 @@ int main(int argc, char ** argv) * flags and whether or not the -f switch was specified on the * command line. */ - printf("%s, %s\n", program_name, program_version); + printf("%s, %s / %s\n", program_name, program_version, + util_linux_version); if ( !(Super.s_state & MINIX_ERROR_FS) && (Super.s_state & MINIX_VALID_FS) && !force ) { if (repair) printf("%s is clean, no check.\n", device_name); - if (repair && !automatic) - tcsetattr(0,TCSANOW,&termios); return retcode; } else if (force) @@ -814,20 +1276,38 @@ int main(int argc, char ** argv) printf("Filesystem on %s is dirty, needs checking.\n",\ device_name); - check_root(); - check(); + read_tables(); + + if (repair && !automatic) { + tcgetattr(0,&termios); + tmp = termios; + tmp.c_lflag &= ~(ICANON|ECHO); + tcsetattr(0,TCSANOW,&tmp); + termios_set = 1; + } + +#if HAVE_MINIX2 + if (version2) { + check_root2 (); + check2 (); + } else +#endif + { + check_root(); + check(); + } if (verbose) { int i, free; for (i=1,free=0 ; i < INODES ; i++) if (!inode_in_use(i)) free++; - printf("\n%6d inodes used (%d%%)\n",(INODES-free-1), + printf("\n%6ld inodes used (%ld%%)\n",(INODES-free-1), 100*(INODES-free-1)/(INODES-1)); for (i=FIRSTZONE,free=0 ; i < ZONES ; i++) if (!zone_in_use(i)) free++; - printf("%6d zones used (%d%%)\n",(ZONES-free), + printf("%6ld zones used (%ld%%)\n",(ZONES-free), 100*(ZONES-free)/ZONES); printf("\n%6d regular files\n" "%6d directories\n" diff --git a/disk-utils/llseek.c b/disk-utils/llseek.c index 3e59ec95..dcbfb2a4 100644 --- a/disk-utils/llseek.c +++ b/disk-utils/llseek.c @@ -11,26 +11,39 @@ #include #include -#include + #ifndef FOR_UTIL_LINUX + #include "et/com_err.h" #include "ext2fs/io.h" -#endif -#ifdef FOR_UTIL_LINUX +#else /* FOR_UTIL_LINUX */ + #if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long ext2_loff_t; +typedef long long ext2_loff_t; #else -typedef long ext2_loff_t; +typedef long ext2_loff_t; #endif -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); -#endif +ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); + +#endif /* FOR_UTIL_LINUX */ #ifdef __linux__ +#ifdef HAVE_LLSEEK +#include + +#else /* HAVE_LLSEEK */ + +#ifdef __alpha__ + +#define my_llseek lseek + +#elif __i386__ + +#include + #ifndef __NR__llseek #define __NR__llseek 140 #endif @@ -42,54 +55,66 @@ static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, unsigned long, offset_low,ext2_loff_t *,result, unsigned int, origin) +static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset, + unsigned int origin) +{ + ext2_loff_t result; + int retval; + + retval = _llseek (fd, ((unsigned long long) offset) >> 32, + ((unsigned long long) offset) & 0xffffffff, + &result, origin); + return (retval == -1 ? (ext2_loff_t) retval : result); +} + +#else + +#error "llseek() is not available" + +#endif /* __alpha__ */ + +#endif /* HAVE_LLSEEK */ + ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, unsigned int origin) { - unsigned long offset_high; - unsigned long offset_low; ext2_loff_t result; - int retval; static int do_compat = 0; + if ((sizeof(off_t) >= sizeof(ext2_loff_t)) || + (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) + return lseek(fd, (off_t) offset, origin); + if (do_compat) { - compat_lseek: - if ((sizeof(off_t) < sizeof(ext2_loff_t)) && - (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { - errno = -EINVAL; - return -1; - } - return lseek (fd, (off_t) offset, origin); + errno = EINVAL; + return -1; } - offset_high = ((unsigned long long) offset) >> 32; - offset_low = ((unsigned long long) offset) & 0xffffffff; - retval = _llseek (fd, offset_high, offset_low, &result, origin); - if (retval == -1 && errno == ENOSYS) { + result = my_llseek (fd, offset, origin); + if (result == -1 && errno == ENOSYS) { /* * Just in case this code runs on top of an old kernel * which does not support the llseek system call */ do_compat++; - goto compat_lseek; + errno = EINVAL; } - if (retval == -1) - result = -1; return result; } -#else +#else /* !linux */ ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, unsigned int origin) { if ((sizeof(off_t) < sizeof(ext2_loff_t)) && (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { - errno = -EINVAL; + errno = EINVAL; return -1; } return lseek (fd, (off_t) offset, origin); } -#endif +#endif /* linux */ diff --git a/disk-utils/mkfs.c b/disk-utils/mkfs.c index 78a3a0c2..8d467191 100644 --- a/disk-utils/mkfs.c +++ b/disk-utils/mkfs.c @@ -7,6 +7,9 @@ * Authors: David Engel, * Fred N. van Kempen, * Ron Sommeling, + * + * Mon Jul 1 18:52:58 1996: janl@math.uio.no (Nicolai Langfeldt): + * Incorporated fix by Jonathan Kamens */ @@ -17,10 +20,10 @@ #include -#define VERSION "1.9" +#define VERSION "1.10" #ifndef DEFAULT_FSTYPE -# define DEFAULT_FSTYPE "minix" +# define DEFAULT_FSTYPE "ext2" #endif #define SEARCH_PATH "PATH=/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc" @@ -44,6 +47,7 @@ int main(int argc, char *argv[]) fstype = optarg; break; default: + optind--; more = 1; break; /* start of specific arguments */ } diff --git a/disk-utils/mkfs.minix.8 b/disk-utils/mkfs.minix.8 index 3c59bb07..8f9e7024 100644 --- a/disk-utils/mkfs.minix.8 +++ b/disk-utils/mkfs.minix.8 @@ -1,21 +1,19 @@ .\" Copyright 1992, 1993, 1994 Rickard E. Faith (faith@cs.unc.edu) .\" May be freely distributed. .\" " for emacs hilit19 mode -.TH MKFS 8 "10 January 1994" "Linux 0.99" "Linux Programmer's Manual" +.TH MKFS 8 "2 July 1996" "Util-linux 2.6" "Linux System Administrator's Manual" .SH NAME mkfs \- make a Linux MINIX filesystem .SH SYNOPSIS -.BR "mkfs [ \-c ] [ \-n" +.BR "mkfs [ \-c | \-l filename ] [ \-n" namelength .B ] [ \-i inodecount +.B ] [ \-v ] +device +.B [ +size-in-blocks .B ] -device size-in-blocks -.br -.B "mkfs [ \-l" -filename -.B ] -device size-in-blocks .SH DESCRIPTION .B mkfs creates a Linux MINIX file-system on a device (usually a disk partition). @@ -26,10 +24,10 @@ is usually of the following form: .nf .RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] +/dev/hda[1-8] (IDE disk 1) +/dev/hdb[1-8] (IDE disk 2) +/dev/sda[1-8] (SCSI disk 1) +/dev/sdb[1-8] (SCSI disk 2) .RE .fi @@ -38,8 +36,11 @@ The parameter is the desired size of the file system, in blocks. This information can be determined from the .BR fdisk (8) -program. Only block counts strictly greater than 10 and strictly less than -65536 are allowed. +or +.BR cfdisk (8) +program. If omitted it will be determined automaticaly. Only block +counts strictly greater than 10 and strictly less than 65536 are +allowed. .SH OPTIONS .TP .B \-c @@ -62,6 +63,9 @@ Read the bad blocks list from .IR filename . The file has one bad block number per line. The count of bad blocks read is printed. +.TP +.B \-v +Make a Minix version 2 filesystem. .SH "EXIT CODES" The exit code returned by .B mkfs.minix @@ -77,8 +81,8 @@ Usage or syntax error .BR mkefs (8), .BR efsck (8), .BR reboot (8) -.SH AUTHOR -Linus Torvalds (torvalds@cs.helsinki.fi) +.SH AUTHORS +Stared by Linus Torvalds (torvalds@cs.helsinki.fi). .br Error code values by Rik Faith (faith@cs.unc.edu) .br @@ -89,3 +93,9 @@ Support for the file system valid flag by Dr. Wettstein .br Check to prevent mkfs of mounted filesystem and boot sector clearing by Daniel Quinlan (quinlan@yggdrasil.com) +.br +Minix v2 support by Andreas Schwab +(schwab@issan.informatik.uni-dortmund.de), updated by Nicolai +Langfeldt (janl@math.uio.no) +.br +Portability patch by Russell King. \ No newline at end of file diff --git a/disk-utils/mkfs.minix.c b/disk-utils/mkfs.minix.c index 87c7c127..403a278c 100644 --- a/disk-utils/mkfs.minix.c +++ b/disk-utils/mkfs.minix.c @@ -31,6 +31,9 @@ * * 03.01.94 - Added support for file system valid flag. * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) * * 09.11.94 - Added test to prevent overwrite of mounted fs adapted * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs @@ -40,13 +43,16 @@ * the filesystem is not misidentified as a MS-DOS FAT filesystem. * (Daniel Quinlan, quinlan@yggdrasil.com) * - * Usage: mkfs [-c] [-nXX] [-iXX] device size-in-blocks - * mkfs [-l filename ] device size-in-blocks + * 02.07.96 - Added small patch from Russell King to make the program a + * good deal more portable (janl@math.uio.no) + * + * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] * * -c for readablility checking (SLOW!) * -l for getting a list of bad blocks from a file. * -n for namelength (currently the kernel only uses 14 or 30) * -i for number of inodes + * -v for v2 filesystem * * The device may be a block device or a image of one, but this isn't * enforced (but it's not much fun on a character device :-). @@ -62,11 +68,16 @@ #include #include #include +#include #include #include #include +#ifdef MINIX2_SUPER_MAGIC2 +#define HAVE_MINIX2 1 +#endif + #ifndef __GNUC__ #error "needs gcc for the bitop-__asm__'s" #endif @@ -83,7 +94,13 @@ #define UPPER(size,n) ((size+((n)-1))/(n)) #define INODE_SIZE (sizeof(struct minix_inode)) -#define INODE_BLOCKS UPPER(INODES,MINIX_INODES_PER_BLOCK) +#ifdef HAVE_MINIX2 +#define INODE_SIZE2 (sizeof(struct minix2_inode)) +#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \ + : MINIX_INODES_PER_BLOCK)) +#else +#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK)) +#endif #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) #define BITS_PER_BLOCK (BLOCK_SIZE<<3) @@ -96,18 +113,26 @@ static int check = 0; static int badblocks = 0; static int namelen = 30; /* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */ -static int dirsize = 16; -static int magic = MINIX_SUPER_MAGIC; +static int dirsize = 32; +static int magic = MINIX_SUPER_MAGIC2; +static int version2 = 0; static char root_block[BLOCK_SIZE] = "\0"; static char * inode_buffer = NULL; #define Inode (((struct minix_inode *) inode_buffer)-1) +#ifdef HAVE_MINIX2 +#define Inode2 (((struct minix2_inode *) inode_buffer)-1) +#endif static char super_block_buffer[BLOCK_SIZE]; static char boot_block_buffer[512]; #define Super (*(struct minix_super_block *)super_block_buffer) #define INODES ((unsigned long)Super.s_ninodes) -#define ZONES ((unsigned long)Super.s_nzones) +#ifdef HAVE_MINIX2 +#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones)) +#else +#define ZONES ((unsigned long)(Super.s_nzones)) +#endif #define IMAPS ((unsigned long)Super.s_imap_blocks) #define ZMAPS ((unsigned long)Super.s_zmap_blocks) #define FIRSTZONE ((unsigned long)Super.s_firstdatazone) @@ -123,19 +148,7 @@ static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; static int used_good_blocks = 0; static unsigned long req_nr_inodes = 0; -#define bitop(name,op) \ -static inline int name(char * addr,unsigned int nr) \ -{ \ -int __res; \ -__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ -:"=g" (__res) \ -:"r" (nr),"m" (*(addr)),"0" (0)); \ -return __res; \ -} - -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") +#include "bitops.h" #define inode_in_use(x) (bit(inode_map,(x))) #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) @@ -157,7 +170,7 @@ volatile void fatal_error(const char * fmt_string,int status) exit(status); } -#define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name blocks\n",16) +#define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]\n",16) #define die(str) fatal_error("%s: " str "\n",8) /* @@ -182,6 +195,57 @@ static void check_mount(void) die("%s is mounted; will not make a filesystem here!"); } +static long valid_offset (int fd, int offset) +{ + char ch; + + if (lseek (fd, offset, 0) < 0) + return 0; + if (read (fd, &ch, 1) < 1) + return 0; + return 1; +} + +static int count_blocks (int fd) +{ + int high, low; + + low = 0; + for (high = 1; valid_offset (fd, high); high *= 2) + low = high; + while (low < high - 1) + { + const int mid = (low + high) / 2; + + if (valid_offset (fd, mid)) + low = mid; + else + high = mid; + } + valid_offset (fd, 0); + return (low + 1); +} + +static int get_size(const char *file) +{ + int fd; + int size; + + fd = open(file, O_RDWR); + if (fd < 0) { + perror(file); + exit(1); + } + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + close(fd); + return (size * 512); + } + + size = count_blocks(fd); + close(fd); + return size; +} + void write_tables(void) { /* Mark the super block valid. */ @@ -300,6 +364,58 @@ end_bad: write_block(dind, (char *) dind_block); } +#ifdef HAVE_MINIX2 +void +make_bad_inode2 (void) +{ + struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; + int i, j, zone; + int ind = 0, dind = 0; + unsigned long ind_block[BLOCK_SIZE >> 2]; + unsigned long dind_block[BLOCK_SIZE >> 2]; + + if (!badblocks) + return; + mark_inode (MINIX_BAD_INO); + inode->i_nlinks = 1; + inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); + inode->i_mode = S_IFREG + 0000; + inode->i_size = badblocks * BLOCK_SIZE; + zone = next (0); + for (i = 0; i < 7; i++) { + inode->i_zone[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[7] = ind = get_free_block (); + memset (ind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + ind_block[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[8] = dind = get_free_block (); + memset (dind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + write_block (ind, (char *) ind_block); + dind_block[i] = ind = get_free_block (); + memset (ind_block, 0, BLOCK_SIZE); + for (j = 0; j < 256; j++) { + ind_block[j] = zone; + if (!NEXT_BAD) + goto end_bad; + } + } + /* Could make triple indirect block here */ + die ("too many bad blocks"); + end_bad: + if (ind) + write_block (ind, (char *) ind_block); + if (dind) + write_block (dind, (char *) dind_block); +} +#endif + void make_root_inode(void) { struct minix_inode * inode = &Inode[MINIX_ROOT_INO]; @@ -319,9 +435,32 @@ void make_root_inode(void) write_block(inode->i_zone[0],root_block); } +#ifdef HAVE_MINIX2 +void +make_root_inode2 (void) +{ + struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; + + mark_inode (MINIX_ROOT_INO); + inode->i_zone[0] = get_free_block (); + inode->i_nlinks = 2; + inode->i_atime = inode->i_mtime = inode->i_ctime = time (NULL); + if (badblocks) + inode->i_size = 3 * dirsize; + else { + root_block[2 * dirsize] = '\0'; + root_block[2 * dirsize + 1] = '\0'; + inode->i_size = 2 * dirsize; + } + inode->i_mode = S_IFDIR + 0755; + write_block (inode->i_zone[0], root_block); +} +#endif + void setup_tables(void) { int i; + unsigned long inodes; memset(inode_map,0xff,sizeof(inode_map)); memset(zone_map,0xff,sizeof(zone_map)); @@ -329,13 +468,16 @@ void setup_tables(void) memset(boot_block_buffer,0,512); MAGIC = magic; ZONESIZE = 0; - MAXSIZE = (7+512+512*512)*1024; + MAXSIZE = version2 ? 0x7fffffff : (7+512+512*512)*1024; ZONES = BLOCKS; /* some magic nrs: 1 inode / 3 blocks */ if ( req_nr_inodes == 0 ) - INODES = BLOCKS/3; + inodes = BLOCKS/3; else - INODES = req_nr_inodes; + inodes = req_nr_inodes; + if (inodes > 65535) + inodes = 65535; + INODES = inodes; /* I don't want some off-by-one errors, so this hack... */ if ((INODES & 8191) > 8188) INODES -= 5; @@ -345,6 +487,8 @@ void setup_tables(void) ZMAPS = 0; while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK)) ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK); + if (ZMAPS > 64) + die ("Filesystem too big for Linux to handle"); FIRSTZONE = NORM_FIRSTZONE; for (i = FIRSTZONE ; i1)?"s":""); - } +{ + FILE *listfile; + unsigned long blockno; + + listfile=fopen(filename,"r"); + if(listfile == (FILE *)NULL) { + die("can't open file of bad blocks"); + } + while(!feof(listfile)) { + fscanf(listfile,"%ld\n", &blockno); + mark_zone(blockno); + badblocks++; + } + if(badblocks) { + printf("%d bad block%s\n", badblocks, (badblocks>1)?"s":""); + } } int main(int argc, char ** argv) + { - int i; - char * tmp; - struct stat statbuf; - char * listfile = NULL; - - if (argc && *argv) - program_name = *argv; - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad inode size"); - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') - if (device_name) { - BLOCKS = strtol(argv[0],&tmp,0); - if (*tmp) { - printf("strtol error: number of" - " blocks not specified"); - usage(); - } - } else - device_name = argv[0]; - else { - if(argv[0][1] == 'l') { - listfile = argv[1]; - argv++; - if (!(argc--)) - usage(); - } else { - if(argv[0][1] == 'i') { - req_nr_inodes - = (unsigned long)atol(argv[1]); - argv++; - if (!(argc--)) - usage(); - } else while (*(++argv[0])) { - switch (argv[0][0]) { - case 'c': check=1; break; - case 'n': - i = strtoul(argv[0]+1,&tmp,0); - if (*tmp) - usage(); - argv[0][1] = '\0'; - if (i == 14) - magic = MINIX_SUPER_MAGIC; - else if (i == 30) - magic = MINIX_SUPER_MAGIC2; - else - usage(); - namelen = i; - dirsize = i+2; - break; - default: usage(); - } - } - } - } + int i; + char * tmp; + struct stat statbuf; + char * listfile = NULL; + + if (argc && *argv) + program_name = *argv; + if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad inode size"); +#ifdef HAVE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad inode size"); +#endif + while (argc-- > 1) { + argv++; + if (argv[0][0] != '-') + if (device_name) { + BLOCKS = strtol(argv[0],&tmp,0); + if (*tmp) { + printf("strtol error: number of" + " blocks not specified"); + usage(); } - if (!device_name || BLOCKS<10 || BLOCKS > 65536) { - usage(); + } else + device_name = argv[0]; + else { + if(argv[0][1] == 'l') { + listfile = argv[1]; + argv++; + if (!(argc--)) + usage(); + } else { + if(argv[0][1] == 'i') { + req_nr_inodes + = (unsigned long)atol(argv[1]); + argv++; + if (!(argc--)) + usage(); + } else while (*(++argv[0])) { + switch (argv[0][0]) { + case 'c': check=1; break; + case 'n': + i = strtoul(argv[0]+1,&tmp,0); + if (*tmp) + usage(); + argv[0][1] = '\0'; + if (i == 14) + magic = MINIX_SUPER_MAGIC; + else if (i == 30) + magic = MINIX_SUPER_MAGIC2; + else + usage(); + namelen = i; + dirsize = i+2; + break; + case 'v': +#ifdef HAVE_MINIX2 + version2 = 1; +#else + fatal_error("%s: not compiled with minix v2 support\n",-1); +#endif + break; + default: usage(); + } } - check_mount(); /* is it already mounted? */ - tmp = root_block; - tmp[0] = 1; - tmp[1] = 0; - strcpy(tmp+2,"."); - tmp += dirsize; - tmp[0] = 1; - tmp[1] = 0; - strcpy(tmp+2,".."); - tmp += dirsize; - tmp[0] = 2; - tmp[1] = 0; - strcpy(tmp+2,".badblocks"); - DEV = open(device_name,O_RDWR ); - if (DEV<0) - die("unable to open %s"); - if (fstat(DEV,&statbuf)<0) - die("unable to stat %s"); - if (!S_ISBLK(statbuf.st_mode)) - check=0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - die("will not try to make filesystem on '%s'"); - setup_tables(); - if (check) - check_blocks(); - else if (listfile) - get_list_blocks(listfile); - make_root_inode(); - make_bad_inode(); - mark_good_blocks(); - write_tables(); - return 0; + } + } + } + if (device_name && !BLOCKS) + BLOCKS = get_size (device_name) / 1024; + if (!device_name || BLOCKS<10) { + usage(); + } +#ifdef HAVE_MINIX2 + if (version2) { + if (namelen == 14) + magic = MINIX2_SUPER_MAGIC; + else + magic = MINIX2_SUPER_MAGIC2; + } else +#endif + if (BLOCKS > 65535) + BLOCKS = 65535; + check_mount(); /* is it already mounted? */ + tmp = root_block; + *(short *)tmp = 1; + strcpy(tmp+2,"."); + tmp += dirsize; + *(short *)tmp = 1; + strcpy(tmp+2,".."); + tmp += dirsize; + *(short *)tmp = 2; + strcpy(tmp+2,".badblocks"); + DEV = open(device_name,O_RDWR ); + if (DEV<0) + die("unable to open %s"); + if (fstat(DEV,&statbuf)<0) + die("unable to stat %s"); + if (!S_ISBLK(statbuf.st_mode)) + check=0; + else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) + die("will not try to make filesystem on '%s'"); + setup_tables(); + if (check) + check_blocks(); + else if (listfile) + get_list_blocks(listfile); +#ifdef HAVE_MINIX2 + if (version2) { + make_root_inode2 (); + make_bad_inode2 (); + } else +#endif + { + make_root_inode(); + make_bad_inode(); + } + mark_good_blocks(); + write_tables(); + return 0; } diff --git a/disk-utils/mkswap.8 b/disk-utils/mkswap.8 index 643d7ba0..1e14167b 100644 --- a/disk-utils/mkswap.8 +++ b/disk-utils/mkswap.8 @@ -5,7 +5,7 @@ .\" Patches from jaggy@purplet.demon.co.uk (Mike Jagdis), Wed Feb 8 1995 .\" Added comments from Nick Holloway, Sat Feb 11 1995, faith@cs.unc.edu .\" " -.TH MKSWAP 8 "8 February 1995" "Linux 1.0" "Linux Programmer's Manual" +.TH MKSWAP 8 "February 1995" "Linux 1.0" "Linux Programmer's Manual" .SH NAME mkswap \- set up a Linux swap area .SH SYNOPSIS diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c index fe3f04c1..2a402740 100644 --- a/disk-utils/mkswap.c +++ b/disk-utils/mkswap.c @@ -24,9 +24,11 @@ #include #include #include +#include #include +#include -#include +#define BLKGETSIZE 0x1260 #ifndef __linux__ # define volatile @@ -43,7 +45,7 @@ static int badpages = 0; static int signature_page[PAGE_SIZE/sizeof(int)]; -static long bit_test_and_set (unsigned int *addr, unsigned int nr) +static void bit_set (unsigned int *addr, unsigned int nr) { unsigned int r, m; @@ -51,10 +53,9 @@ static long bit_test_and_set (unsigned int *addr, unsigned int nr) r = *addr; m = 1 << (nr & (8 * sizeof(int) - 1)); *addr = r | m; - return (r & m) != 0; } -static bit_test_and_clear (unsigned int *addr, unsigned int nr) +static int bit_test_and_clear (unsigned int *addr, unsigned int nr) { unsigned int r, m; @@ -88,18 +89,18 @@ void check_blocks(void) current_page = 0; while (current_page < PAGES) { if (!check) { - bit_test_and_set(signature_page,current_page++); + bit_set(signature_page,current_page++); continue; } if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != current_page*PAGE_SIZE) die("seek failed in check_blocks"); - if (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) { + if ((do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE)))) { bit_test_and_clear(signature_page,current_page++); badpages++; continue; } - bit_test_and_set(signature_page,current_page++); + bit_set(signature_page,current_page++); } if (badpages) printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); @@ -183,7 +184,13 @@ int main(int argc, char ** argv) if (device_name && !PAGES) { PAGES = get_size(device_name) / PAGE_SIZE; } - if (!device_name || PAGES<10) { + if (!device_name) { + fprintf(stderr, + "%s: error: Nowhere to set up swap on?\n", + program_name); + usage(); + } + if (PAGES < 10) { fprintf(stderr, "%s: error: swap area needs to be at least %ldkB\n", program_name, 10 * PAGE_SIZE / 1024); @@ -209,8 +216,9 @@ int main(int argc, char ** argv) goodpages = PAGES - badpages - 1; if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace, size = %d bytes\n",goodpages*PAGE_SIZE); - strncpy((char*)signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); + printf("Setting up swapspace, size = %ld bytes\n", + goodpages*PAGE_SIZE); + strncpy((char*)signature_page+PAGE_SIZE-10, "SWAP-SPACE", 10); if (lseek(DEV, 0, SEEK_SET)) die("unable to rewind swap-device"); if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) diff --git a/disk-utils/setfdprm.c b/disk-utils/setfdprm.c index bd98f5a2..fee55300 100644 --- a/disk-utils/setfdprm.c +++ b/disk-utils/setfdprm.c @@ -2,11 +2,13 @@ autodetection and switches diagnostic messages. */ #include +#include #include #include #include #include #include +#include #include #define FDPRMFILE "/etc/fdprm" @@ -89,7 +91,7 @@ static void usage(char *name) { char *this; - if (this = strrchr(name,'/')) name = this+1; + if ((this = strrchr(name,'/')) != NULL) name = this+1; fprintf(stderr,"usage: %s [ -p ] dev name\n",name); fprintf(stderr," %s [ -p ] dev size sect heads tracks stretch \ gap rate spec1 fmt_gap\n",name); @@ -101,10 +103,11 @@ gap rate spec1 fmt_gap\n",name); exit(1); } - +void main(int argc,char **argv) { - int cmd,fd; + int fd; + unsigned int cmd; char *name; name = argv[0]; @@ -143,7 +146,11 @@ main(int argc,char **argv) if (argc != 2) usage(name); cmd_without_param(cmd,fd); } - if (argc != 11 && argc != 3) usage(name); - if (argc == 11) set_params(cmd,fd,&argv[2]); - else find_params(cmd,fd,argv[2]); + if (argc != 11 && argc != 3) + usage(name); + else if (argc == 11) + set_params(cmd,fd,&argv[2]); + else + find_params(cmd,fd,argv[2]); + /* not reached */ } diff --git a/disk-utils/sfdisk.8 b/disk-utils/sfdisk.8 new file mode 100644 index 00000000..fc930801 --- /dev/null +++ b/disk-utils/sfdisk.8 @@ -0,0 +1,497 @@ +.\" Copyright 1995 Andries E. Brouwer (aeb@cwi.nl) +.\" May be distributed under the GNU General Public License +.\" The `DOS 6.x Warning' was taken from the old fdisk.8, which says +.\" -- Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) +.\" -- May be distributed under the GNU General Public License +.\" The `DRDOS Warning' was taken from a net post by Stephen Tweedie. +.\" +.TH SFDISK 8 "1 September 1995" "Linux 1.3.23" "Linux Programmer's Manual" +.SH NAME +sfdisk \- Partition table manipulator for Linux +.SH SYNOPSIS +.BR sfdisk " [options] device" +.br +.BR "sfdisk \-s " [partition] +.SH DESCRIPTION +.B sfdisk +has four (main) uses: list the size of a partition, list the partitions +on a device, check the partitions on a device, and - very dangerous - +repartition a device. + +.SS "List Sizes" +.BI "sfdisk \-s " partition +gives the size of +.I partition +in blocks. This may be useful in connection with programs like +.B mkswap +or so. Here +.I partition +is usually something like +.I /dev/hda1 +or +.IR /dev/sdb12 , +but may also be an entire disk, like +.IR /dev/xda . +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s /dev/hda9 +81599 +% +.if t .ft R +.fi +.RE +If the partition argument is omitted, +.B sfdisk +will list the sizes of all disks, and the total: +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s +/dev/hda: 208896 +/dev/hdb: 1025136 +/dev/hdc: 1031063 +/dev/sda: 8877895 +/dev/sdb: 1758927 +total: 12901917 blocks +% +.if t .ft R +.fi +.RE + +.SS "List Partitions" +The second type of invocation: +.BI "sfdisk \-l " "[options] device" +will list the partitions on this device. +If the device argument is omitted, the partitions on all hard disks +are listed. +.br +.nf +.if t .ft CW +% sfdisk \-l /dev/hdc + +Disk /dev/hdc: 16 heads, 63 sectors, 2045 cylinders +Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hdc1 0+ 406 407\- 205096+ 83 Linux native +/dev/hdc2 407 813 407 205128 83 Linux native +/dev/hdc3 814 2044 1231 620424 83 Linux native +/dev/hdc4 0 \- 0 0 0 Empty +% +.if t .ft R +.fi +The trailing \- and + signs indicate that rounding has taken place, +and that the actual value is slightly less (more). +To see the exact values, ask for a listing with sectors as unit. + +.SS "Check partitions" +The third type of invocation: +.BI "sfdisk \-V " device +will apply various consistency checks to the partition tables on +.IR device . +It prints `OK' or complains. The \-V option can be used together +with \-l. In a shell script one might use +.BI "sfdisk \-V \-q " device +which only returns a status. + +.SS "Create partitions" +The fourth type of invocation: +.BI "sfdisk " device +will cause +.B sfdisk +to read the specification for the desired partitioning of +.I device +from its standard input, and then to change the partition tables +on that disk. Thus, it is possible to use +.B sfdisk +from a shell script. When +.B sfdisk +determines that its standard input is a terminal, it will be +conversational; otherwise it will abort on any error. +.LP +BE EXTREMELY CAREFUL - ONE TYPING MISTAKE AND ALL YOUR DATA IS LOST +.LP +As a precaution, one can save the sectors changed by +.BR sfdisk : +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-O hdd-partition-sectors.save +% +.if t .ft R +.fi +.RE +.LP +Then, if you discover that you did something stupid before anything +else has been written to disk, it may be possible to recover +the old situation with +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-I hdd-partition-sectors.save +% +.if t .ft R +.fi +.RE + +There are many options. + +.SH OPTIONS +.TP +.BR \-v " or " \-\-version +Print version number of +.B sfdisk +and exit immediately. +.TP +.BR \-? " or " \-\-help +Print a usage message and exit immediately. +.TP +.BR \-T " or " \-\-list-types +Print the recognized types (system Id's). +.TP +.BR \-s " or " \-\-show\-size +List the size of a partition. +.TP +.BR \-g " or " \-\-show\-geometry +List the kernel's idea of the geometry of the indicated disk(s). +.TP +.BR \-l " or " \-\-list +List the partitions of a device. +.TP +.BR \-d +Dump the partitions of a device in a format useful as input +to sfdisk. For example, +.br +.nf +.if t .ft CW + % sfdisk -d /dev/hda > hda.out + % sfdisk /dev/hda < hda.out +.if t .ft R +.fi +will correct the bad last extended partition that the OS/2 +sfdisk creates. +.TP +.BR \-V " or " \-\-verify +Test whether partitions seem correct. (See above.) +.TP +.BR \-i " or " \-\-increment +Number cylinders etc. starting from 1 instead of 0. +.TP +.BI \-N " number" +Change only the single partition indicated. For example: +.br +.nf +.if t .ft CW + % sfdisk /dev/hdb \-N5 + ,,,* + % +.if t .ft R +.fi +will make the fifth partition on /dev/hdb bootable (`active') +and change nothing else. (Probably this fifth partition +is called /dev/hdb5, but you are free to call it something else, +like `/my_equipment/disks/2/5' or so). +.TP +.BI \-A " number" +Make the indicated partition(s) active, and all others inactive. +.TP +.BI \-c " or " \-\-id " number [Id]" +If no Id argument given: print the partition Id of the indicated +partition. If an Id argument is present: change the type (Id) of +the indicated partition to the given value. +This option has the two very long forms \-\-print\-id and \-\-change\-id. +For example: +.br +.nf +.if t .ft CW + % sfdisk --print-id /dev/hdb 5 + 6 + % sfdisk --change-id /dev/hdb 5 83 + OK +.if t .ft R +.fi +first reports that /dev/hdb5 has Id 6, and then changes that into 83. +.TP +.BR \-uS " or " \-uB " or " \-uC " or " \-uM +Accept or report in units of sectors (blocks, cylinders, megabytes, +respectively). The default is cylinders, at least when the geometry +is known. +.TP +.BR \-x " or " \-\-show\-extended +Also list non-primary extended partitions on output, +and expect descriptors for them on input. +.TP +.BI \-C " cylinders" +Specify the number of cylinders, possibly overriding what the kernel thinks. +.TP +.BI \-H " heads" +Specify the number of heads, possibly overriding what the kernel thinks. +.TP +.BI \-S " sectors" +Specify the number of sectors, possibly overriding what the kernel thinks. +.TP +.BR \-f " or " \-\-force +Do what I say, even if it is stupid. +.TP +.BR \-q " or " \-\-quiet +Suppress warning messages. +.TP +.BR \-L " or " \-\-Linux +Do not complain about things irrelevant for Linux. +.TP +.BR \-D " or " \-\-DOS +For DOS-compatibility: waste a little space. +(More precisely: if a partition cannot contain sector 0, +e.g. because that is the MBR of the device, or contains +the partition table of an extended partition, then +.B sfdisk +would make it start the next sector. However, when this +option is given it skips to the start of the next track, +wasting for example 33 sectors (in case of 34 sectors/track), +just like certain versions of DOS do.) +Certain Disk Managers and boot loaders (such as OSBS, but not +LILO or the OS/2 Boot Manager) also live in this empty space, +so maybe you want this option if you use one. +.TP +.BR \-\-IBM " or " \-\-leave\-last +Certain IBM diagnostic programs assume that they can use the +last cylinder on a disk for disk-testing purposes. If you think +you might ever run such programs, use this option to tell +.B sfdisk +that it should not allocate the last cylinder. +Sometimes the last cylinder contains a bad sector table. +.TP +.B \-n +Go through all the motions, but do not actually write to disk. +.TP +.B \-R +Only execute the BLKRRPART ioctl (to make the kernel re-read +the partition table). This can be useful for checking in advance +that the final BLKRRPART will be successful, and also when you +changed the partition table `by hand' (e.g., using dd from a backup). +If the kernel complains (`device busy for revalidation (usage = 2)') +then something still uses the device, and you still have to unmount +some file system, or say swapoff to some swap partition. +.TP +.B \-\-no\-reread +When starting a repartitioning of a disk, sfdisk checks that this disk +is not mounted, or in use as a swap device, and refuses to continue +if it is. This option suppresses the test. (On the other hand, the \-f +option would force sfdisk to continue even when this test fails.) +.TP +.BI \-O " file" +Just before writing the new partition, output the sectors +that are going to be overwritten to +.I file +(where hopefully +.I file +resides on another disk, or on a floppy). +.TP +.BI \-I " file" +After destroying your filesystems with an unfortunate +.B sfdisk +command, you would have been able to restore the old situation +if only you had preserved it using the \-O flag. + +.SH THEORY +Block 0 of a disk (the Master Boot Record) contains among +other things four partition descriptors. The partitions +described here are called +.I primary +partitions. +.LP +A partition descriptor has 6 fields: +.br +.nf +.RS +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + hsc begin_hsc; + unsigned char id; + hsc end_hsc; + unsigned int starting_sector; + unsigned int nr_of_sectors; +} +.RE +.fi +.LP +The two hsc fields indicate head, sector and cylinder of the +begin and the end of the partition. Since each hsc field only +takes 3 bytes, only 24 bits are available, which does not +suffice for big disks (say > 8GB). In fact, due to the wasteful +representation (that uses a byte for the number of heads, which +is typically 16), problems already start with 0.5GB. +However Linux does not use these fields, and problems can arise +only at boot time, before Linux has been started. For more +details, see the +.B lilo +documentation. +.LP +Each partition has a type, its `Id', and if this type is 5 +.IR "" "(`" "extended partition" "')" +the starting sector of the partition +again contains 4 partition descriptors. MSDOS only uses the +first two of these: the first one an actual data partition, +and the second one again an extended partition (or empty). +In this way one gets a chain of extended partitions. +Other operating systems have slightly different conventions. +Linux also accepts type 85 as equivalent to 5 - this can be +useful if one wants to have extended partitions under Linux past +the 1024 cylinder boundary, without DOS FDISK hanging. +(If there is no good reason, you should just use 5, which is +understood by other systems.) +.LP +Partitions that are not primary or extended are called +.IR logical . +Often, one cannot boot from logical partitions (because the +process of finding them is more involved than just looking +at the MBR). +Note that of an extended partition only the Id and the start +are used. There are various conventions about what to write +in the other fields. One should not try to use extended partitions +for data storage or swap. + +.SH "INPUT FORMAT" +.B sfdisk +reads lines of the form +.br +.RS + +.RE +where each line fills one partition descriptor. +.LP +Fields are separated by whitespace, or comma or semicolon possibly +followed by whitespace; initial and trailing whitespace is ignored. +Numbers can be octal, decimal or hexadecimal, decimal is default. +When a field is absent or empty, a default value is used. +.LP +The parts can (and probably should) be omitted - +.B sfdisk +computes them from and and the disk geometry +as given by the kernel or specified using the \-H, \-S, \-C flags. +.LP +Bootable is specified as [*|\-], with as default not-bootable. +(The value of this field is irrelevant for Linux - when Linux +runs it has been booted already - but might play a role for +certain boot loaders and for other operating systems. +For example, when there are several primary DOS partitions, +DOS assigns C: to the first among these that is bootable.) +.LP +Id is given in hex, without the 0x prefix, or is [E|S|L|X], where +L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), E +is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED (85). +.LP +The default value of start is the first nonassigned sector/cylinder/... +.LP +The default value of size is as much as possible (until next +partition or end-of-disk). +.LP +However, for the four partitions inside an extended partition, +the defaults are: Linux partition, Extended partition, Empty, Empty. +.LP +But when the \-N option (change a single partition only) is given, +the default for each field is its previous value. + +.SH EXAMPLE +The command +.RS +.nf +.if t .ft CW +sfdisk /dev/hdc << EOF +0,407 +,407 +; +; +EOF +.if t .ft R +.fi +.RE +will partition /dev/hdc just as indicated above. + +With the \-x option, the number of input lines must be a multiple of 4: +you have to list the two empty partitions that you never want +using two blank lines. Without the \-x option, you give one line +for the partitions inside a extended partition, instead of four, +and terminate with end-of-file (^D). +(And +.B sfdisk +will assume that your input line represents the first of four, +that the second one is extended, and the 3rd and 4th are empty.) + +.SH "DOS 6.x WARNING" + +The DOS 6.x FORMAT command looks for some information in the first +sector of the data area of the partition, and treats this information +as more reliable than the information in the partition table. DOS +FORMAT expects DOS FDISK to clear the first 512 bytes of the data area +of a partition whenever a size change occurs. DOS FORMAT will look at +this extra information even if the /U flag is given -- we consider +this a bug in DOS FORMAT and DOS FDISK. +.LP +The bottom line is that if you use sfdisk to change the size of a +DOS partition table entry, then you must also use +.B dd +to zero the first 512 bytes of that partition before using DOS FORMAT to +format the partition. For example, if you were using sfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting sfdisk and +rebooting Linux so that the partition table information is valid) you +would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero +the first 512 bytes of the partition. +.B BE EXTREMELY CAREFUL +if you use the +.B dd +command, since a small typo can make all of the data on your disk useless. + +For best results, you should always use an OS-specific partition table +program. For example, you should make DOS partitions with the DOS FDISK +program and Linux partitions with the Linux sfdisk program. + +.SH "DRDOS WARNINGS" + +Stephen Tweedie reported (930515): `Most reports of superblock +corruption turn out to be due to bad partitioning, with one filesystem +overrunning the start of the next and corrupting its superblock. +I have even had this problem with the supposedly-reliable DRDOS. This +was quite possibly due to DRDOS-6.0's FDISK command. Unless I created +a blank track or cylinder between the DRDOS partition and the +immediately following one, DRDOS would happily stamp all over the +start of the next partition. Mind you, as long as I keep a little +free disk space after any DRDOS partition, I don't have any other +problems with the two coexisting on the one drive.' + +A. V. Le Blanc writes in README.esfdisk: `Dr. DOS 5.0 and 6.0 has been +reported to have problems cooperating with Linux, and with this version +of efdisk in particular. This efdisk sets the system type +to hexadecimal 81. Dr. DOS seems to confuse +this with hexadecimal 1, a DOS code. If you use Dr. DOS, use the +efdisk command 't' to change the system code of any Linux partitions +to some number less than hexadecimal 80; I suggest 41 and 42 for +the moment.' + +A. V. Le Blanc writes in his README.fdisk: `DR-DOS 5.0 and 6.0 +are reported to have difficulties with partition ID codes of 80 or more. +The Linux `fdisk' used to set the system type +of new partitions to hexadecimal 81. DR-DOS seems to confuse this with +hexadecimal 1, a DOS code. The values 82 for swap and 83 for file +systems should not cause problems with DR-DOS. If they do, you may use +the `fdisk' command `t' to change the system code of any Linux +partitions to some number less than hexadecimal 80; I suggest 42 and 43 +for the moment.' + +In fact, it seems that only 4 bits are significant for the DRDOS FDISK, +so that for example 11 and 21 are listed as DOS 2.0. However, DRDOS +itself seems to use the full byte. I have not been able to reproduce +any corruption with DRDOS or its fdisk. + +.SH BUGS +A corresponding interactive +.B cfdisk +(with curses interface) is still lacking. +.LP +There are too many options. + +.SH AUTHOR +A. E. Brouwer (aeb@cwi.nl) diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c new file mode 100644 index 00000000..fcc76c41 --- /dev/null +++ b/disk-utils/sfdisk.c @@ -0,0 +1,2712 @@ +/* + * sfdisk version 3.0 - aeb - 950813 + * + * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) + * + * This program is free software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either Version 1 + * or (at your option) any later version. + * + * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, + * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, + * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) + * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. + * This program had (head,sector,cylinder) as basic unit, and was + * (therefore) broken in several ways for the use on larger disks - + * for example, my last patch (from 2.0d to 2.0e) was required + * to allow a partition to cross cylinder 8064, and to write an + * extended partition past the 4GB mark. + * + * The current program is a rewrite from scratch, and I started a + * version numbering at 3.0. + * Andries Brouwer, aeb@cwi.nl, 950813 + * + * Well, a good user interface is still lacking. On the other hand, + * many configurations cannot be handled by any other fdisk. + * I changed the name to sfdisk to prevent confusion. - aeb, 970501 + */ + +#define PROGNAME "sfdisk" +#define VERSION "3.06" +#define DATE "970626" + +#include +#include /* atoi, free */ +#include /* varargs */ +#include /* read, write */ +#include /* O_RDWR */ +#include /* ERANGE */ +#include /* index() */ +#include +#include +#include +#include +#include /* _syscall */ +#include /* HDIO_GETGEO */ +#include /* BLKGETSIZE */ + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* + * Table of contents: + * A. About seeking + * B. About sectors + * C. About heads, sectors and cylinders + * D. About system Ids + * E. About partitions + * F. The standard input + * G. The command line + * H. Listing the current situation + * I. Writing the new situation + */ +int exit_status = 0; + +int force = 0; /* 1: do what I say, even if it is stupid ... */ +int quiet = 0; /* 1: suppress all warnings */ +int Linux = 0; /* 1: suppress warnings irrelevant for Linux */ +int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */ +int dump = 0; /* 1: list in a format suitable for later input */ +int verify = 0; /* 1: check that listed partition is reasonable */ +int no_write = 0; /* 1: do not actually write to disk */ +int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */ +int leave_last = 0; /* 1: don't allocate the last cylinder */ +int opt_list = 0; +char *save_sector_file = NULL; +char *restore_sector_file = NULL; + +void +warn(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + if (!quiet) + vfprintf (stderr, s, p); + va_end(p); +} + +void +error(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); +} + +void +fatal(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); + exit(1); +} + +/* + * A. About seeking + */ + +/* + * sseek: seek to specified sector - return 0 on failure + * + * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. + * On the other hand, a 32 bit sector number is OK until 2TB. + * The routines _llseek and sseek below are the only ones that + * know about the loff_t type. + */ +#ifndef __alpha__ +static +_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); +#endif + +int +sseek(char *dev, unsigned int fd, unsigned long s) { + loff_t in, out; + in = ((loff_t) s << 9); + out = 1; + +#ifndef __alpha__ + if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) { +#else + if ((out = lseek(fd, in, SEEK_SET)) != in) { +#endif + perror("llseek"); + error("seek error on %s - cannot seek to %lu\n", dev, s); + return 0; + } + + if (in != out) { + error("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n", + (uint)(in>>32), (uint)(in & 0xffffffff), + (uint)(out>>32), (uint)(out & 0xffffffff)); + return 0; + } + return 1; +} + +/* + * B. About sectors + */ + +/* + * We preserve all sectors read in a chain - some of these will + * have to be modified and written back. + */ +struct sector { + struct sector *next; + unsigned long sectornumber; + int to_be_written; + char data[512]; +} *sectorhead; + +void +free_sectors(void) { + struct sector *s; + + while (sectorhead) { + s = sectorhead; + sectorhead = s->next; + free(s); + } +} + +struct sector * +get_sector(char *dev, int fd, unsigned long sno) { + struct sector *s; + + for(s = sectorhead; s; s = s->next) + if(s->sectornumber == sno) + return s; + + if (!sseek(dev, fd, sno)) + return 0; + + if (!(s = (struct sector *) malloc(sizeof(struct sector)))) + fatal("out of memory - giving up\n"); + + if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", dev, sno); + free(s); + return 0; + } + + s->next = sectorhead; + sectorhead = s; + s->sectornumber = sno; + s->to_be_written = 0; + + return s; +} + +int +msdos_signature (struct sector *s) { + if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) { + error("ERROR: sector %lu does not have an msdos signature\n", + s->sectornumber); + return 0; + } + return 1; +} + +int +write_sectors(char *dev, int fd) { + struct sector *s; + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + if (!sseek(dev, fd, s->sectornumber)) + return 0; + if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("write"); + error("write error on %s - cannot write sector %lu\n", + dev, s->sectornumber); + return 0; + } + s->to_be_written = 0; + } + return 1; +} + +void +ulong_to_chars(unsigned long u, char *uu) { + int i; + + for(i=0; i<4; i++) { + uu[i] = (u & 0xff); + u >>= 8; + } +} + +unsigned long +chars_to_ulong(unsigned char *uu) { + int i; + unsigned long u = 0; + + for(i=3; i>=0; i--) + u = (u << 8) | uu[i]; + return u; +} + +int +save_sectors(char *dev, int fdin) { + struct sector *s; + char ss[516]; + int fdout; + + fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); + if (fdout < 0) { + perror(save_sector_file); + error("cannot open partition sector save file (%s)\n", + save_sector_file); + return 0; + } + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + ulong_to_chars(s->sectornumber, ss); + if (!sseek(dev, fdin, s->sectornumber)) + return 0; + if (read(fdin, ss+4, 512) != 512) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", + dev, s->sectornumber); + return 0; + } + if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { + perror("write"); + error("write error on %s\n", save_sector_file); + return 0; + } + } + return 1; +} + +void reread_disk_partition(char *dev, int fd); + +int +restore_sectors(char *dev) { + int fdin, fdout, ct; + struct stat statbuf; + char *ss0, *ss; + unsigned long sno; + + if (stat(restore_sector_file, &statbuf) < 0) { + perror(restore_sector_file); + error("cannot stat partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (statbuf.st_size % 516) { + error("partition restore file has wrong size - not restoring\n"); + return 0; + } + if (!(ss = (char *) malloc(statbuf.st_size))) { + error("out of memory?\n"); + return 0; + } + fdin = open(restore_sector_file, O_RDONLY); + if (fdin < 0) { + perror(restore_sector_file); + error("cannot open partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { + perror("read"); + error("error reading %s\n", restore_sector_file); + return 0; + } + + fdout = open(dev, O_WRONLY); + if (fdout < 0) { + perror(dev); + error("cannot open device %s for writing\n", dev); + return 0; + } + + ss0 = ss; + ct = statbuf.st_size/516; + while(ct--) { + sno = chars_to_ulong(ss); + if (!sseek(dev, fdout, sno)) + return 0; + if (write(fdout, ss+4, 512) != 512) { + perror(dev); + error("error writing sector %lu on %s\n", sno, dev); + return 0; + } + ss += 516; + } + free(ss0); + + reread_disk_partition(dev, fdout); + + return 1; +} + +/* + * C. About heads, sectors and cylinders + */ + +/* + * defines HDIO_GETGEO and + * struct hd_geometry { + * unsigned char heads; + * unsigned char sectors; + * unsigned short cylinders; + * unsigned long start; + * }; + */ + +unsigned long cylindersize; +unsigned long heads, sectors, cylinders; +unsigned long specified_heads, specified_sectors, specified_cylinders; + +void +get_cylindersize(char *dev, int fd, int silent) { + struct hd_geometry g; + int ioctl_ok = 0; + + heads = sectors = cylinders = 0; + + if (!ioctl(fd, HDIO_GETGEO, &g)) { + ioctl_ok = 1; + + heads = g.heads; + sectors = g.sectors; + cylinders = g.cylinders; + } + + if (specified_heads) + heads = specified_heads; + if (specified_sectors) + sectors = specified_sectors; + if (specified_cylinders) + cylinders = specified_cylinders; + + cylindersize = heads * sectors; + + if (ioctl_ok) { + if (g.start && !force) { + warn( + "Warning: start=%d - this looks like a partition rather than\n" + "the entire disk. Using fdisk on it is probably meaningless.\n" + "[Use the --force option if you really want this]\n", g.start); + exit(1); + } + if (heads != g.heads) + warn("Warning: HDIO_GETGEO says that there are %d heads\n", + g.heads); + if (sectors != g.sectors) + warn("Warning: HDIO_GETGEO says that there are %d sectors\n", + g.sectors); + if (cylinders != g.cylinders) + warn("Warning: HDIO_GETGEO says that there are %d cylinders\n", + g.cylinders); + } else if (!silent) + if (!heads || !sectors || !cylinders) + printf("Disk %s: cannot get geometry\n", dev); + if (sectors > 63) + warn("Warning: unlikely number of sectors (%d) - usually at most 63\n" + "This will give problems with all software that uses C/H/S addressing.\n", + sectors); + if (!silent) + printf("\nDisk %s: %lu heads, %lu sectors, %lu cylinders\n", + dev, heads, sectors, cylinders); +} + +typedef struct { unsigned char h,s,c; } chs; /* has some c bits in s */ +chs zero_chs = { 0,0,0 }; + +typedef struct { unsigned long h,s,c; } longchs; +longchs zero_longchs; + +chs +longchs_to_chs (longchs aa) { + chs a; + + if (aa.h < 256 && aa.s < 64 && aa.c < 1024) { + a.h = aa.h; + a.s = aa.s | ((aa.c >> 2) & 0xc0); + a.c = (aa.c & 0xff); + } else if (heads && sectors) { + a.h = heads - 1; + a.s = sectors | 0xc0; + a.c = 0xff; + } else + a = zero_chs; + return a; +} + +longchs +chs_to_longchs (chs a) { + longchs aa; + + aa.h = a.h; + aa.s = (a.s & 0x3f); + aa.c = (a.s & 0xc0); + aa.c = (aa.c << 2) + a.c; + return aa; +} + +longchs +ulong_to_longchs (unsigned long sno) { + longchs aa; + + if (heads && sectors && cylindersize) { + aa.s = 1 + sno % sectors; + aa.h = (sno / sectors) % heads; + aa.c = sno / cylindersize; + return aa; + } else { + return zero_longchs; + } +} + +unsigned long +longchs_to_ulong (longchs aa) { + return (aa.c*cylindersize + aa.h*sectors + aa.s - 1); +} + +chs +ulong_to_chs (unsigned long sno) { + return longchs_to_chs(ulong_to_longchs(sno)); +} + +unsigned long +chs_to_ulong (chs a) { + return longchs_to_ulong(chs_to_longchs(a)); +} + +int +is_equal_chs (chs a, chs b) { + return (a.h == b.h && a.s == b.s && a.c == b.c); +} + +int +chs_ok (chs a, char *v, char *w) { + longchs aa = chs_to_longchs(a); + int ret = 1; + + if (is_equal_chs(a, zero_chs)) + return 1; + if (heads && aa.h >= heads) { + warn("%s of partition %s has impossible value for head: " + "%d (should be in 0-%d)\n", w, v, aa.h, heads-1); + ret = 0; + } + if (sectors && (aa.s == 0 || aa.s > sectors)) { + warn("%s of partition %s has impossible value for sector: " + "%d (should be in 1-%d)\n", w, v, aa.s, sectors); + ret = 0; + } + if (cylinders && aa.c >= cylinders) { + warn("%s of partition %s has impossible value for cylinders: " + "%d (should be in 0-%d)\n", w, v, aa.c, cylinders-1); + ret = 0; + } + return ret; +} + +/* + * D. About system Ids + */ + +#define EMPTY_PARTITION 0 +#define EXTENDED_PARTITION 5 +#define DM6_PARTITION 0x54 +#define EZD_PARTITION 0x55 +#define DM6_AUX1PARTITION 0x51 +#define DM6_AUX3PARTITION 0x53 +#define LINUX_SWAP 0x82 +#define LINUX_NATIVE 0x83 +#define LINUX_EXTENDED 0x85 + +/* + * List of system Id's, adapted from fdisk 2.0d and + * and SFS and several other sources. + */ +struct systypes { + unsigned char type; + char *name; +} sys_types[] = { + {0, "Empty"}, + {1, "DOS 12-bit FAT"}, /* Primary DOS with 12-bit FAT */ + {2, "XENIX /"}, /* XENIX / filesystem */ + {3, "XENIX /usr"}, /* XENIX /usr filesystem */ + {4, "DOS 16-bit FAT <32M"}, /* Primary DOS with 16-bit FAT */ + {5, "DOS Extended"}, /* DOS 3.3+ extended partition */ + {6, "DOS 16-bit FAT >=32M"}, + {7, "HPFS / NTFS"}, + {8, "AIX boot or SplitDrive"}, + {9, "AIX data or Coherent"}, + {0x0a, "OS/2 Boot Manager"}, + {0x0b, "Win95 FAT32"}, + {0x0c, "Win95 FAT32 (LBA)"}, + {0x0e, "Win95 FAT16 (LBA)"}, + {0x0f, "Win95 Extended (LBA)"}, + {0x10, "OPUS"}, + {0x11, "Hidden DOS FAT12"}, + {0x12, "Compaq diagnostics"}, + {0x14, "Hidden DOS FAT16"}, + {0x16, "Hidden DOS FAT16 (big)"}, + {0x17, "Hidden HPFS/NTFS"}, + {0x18, "AST Windows swapfile"}, + {0x24, "NEC DOS"}, + {0x3c, "PartitionMagic recovery"}, + {0x40, "Venix 80286"}, + {0x41, "Linux/MINIX (sharing disk with DRDOS)"}, + {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, + {0x43, "Linux native (sharing disk with DRDOS)"}, + {0x50, "DM (disk manager)"}, + {0x51, "DM6 Aux1 (or Novell)"}, + {0x52, "CP/M or Microport SysV/AT"}, + {0x53, "DM6 Aux3"}, + {0x54, "DM6"}, + {0x55, "EZ-Drive (disk manager)"}, + {0x56, "Golden Bow (disk manager)"}, + {0x5c, "Priam Edisk (disk manager)"}, + {0x61, "SpeedStor"}, + {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"}, + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x70, "DiskSecure Multi-Boot"}, + {0x75, "PC/IX"}, + {0x77, "QNX4.x"}, + {0x78, "QNX4.x 2nd part"}, + {0x79, "QNX4.x 3rd part"}, + {0x80, "MINIX until 1.4a"}, + {0x81, "MINIX / old Linux"}, + {0x82, "Linux swap"}, + {0x83, "Linux native"}, + {0x84, "OS/2 hidden C: drive"}, + {0x85, "Linux extended"}, + {0x86, "NTFS volume set"}, + {0x87, "NTFS volume set"}, + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */ + {0xa5, "BSD/386"}, /* 386BSD */ + {0xa7, "NeXTSTEP 486"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc1, "DRDOS/sec (FAT-12)"}, + {0xc4, "DRDOS/sec (FAT-16, < 32M)"}, + {0xc6, "DRDOS/sec (FAT-16, >= 32M)"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, + {0xe1, "DOS access or SpeedStor 12-bit FAT extended partition"}, + {0xe3, "DOS R/O or SpeedStor"}, + {0xe4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, + {0xf1, "SpeedStor"}, + {0xf2, "DOS 3.3+ secondary"}, + {0xf4, "SpeedStor large partition"}, + {0xfe, "SpeedStor >1024 cyl. or LANstep"}, + {0xff, "Xenix Bad Block Table"} +}; + + +const char * +sysname(unsigned char type) { + struct systypes *s; + + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + if (s->type == type) + return s->name; + return "Unknown"; +} + +void +list_types(void) { + struct systypes *s; + + printf("Id Name\n\n"); + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + printf("%2x %s\n", s->type, s->name); +} + +int +is_extended(unsigned char type) { + return (type == EXTENDED_PARTITION || type == LINUX_EXTENDED); +} + +/* + * E. About partitions + */ + +/* MS/DOS partition */ + +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + chs begin_chs; + unsigned char sys_type; + chs end_chs; + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +/* Unfortunately, partitions are not aligned, and non-Intel machines + are unhappy with non-aligned integers. So, we need a copy by hand. */ +int +copy_to_int(unsigned char *cp) { + unsigned int m; + + m = *cp++; + m += (*cp++ << 8); + m += (*cp++ << 16); + m += (*cp++ << 24); + return m; +} + +void +copy_from_int(int m, char *cp) { + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); +} + +void +copy_to_part(char *cp, struct partition *p) { + p->bootable = *cp++; + p->begin_chs.h = *cp++; + p->begin_chs.s = *cp++; + p->begin_chs.c = *cp++; + p->sys_type = *cp++; + p->end_chs.h = *cp++; + p->end_chs.s = *cp++; + p->end_chs.c = *cp++; + p->start_sect = copy_to_int(cp); + p->nr_sects = copy_to_int(cp+4); +} + +void +copy_from_part(struct partition *p, char *cp) { + *cp++ = p->bootable; + *cp++ = p->begin_chs.h; + *cp++ = p->begin_chs.s; + *cp++ = p->begin_chs.c; + *cp++ = p->sys_type; + *cp++ = p->end_chs.h; + *cp++ = p->end_chs.s; + *cp++ = p->end_chs.c; + copy_from_int(p->start_sect, cp); + copy_from_int(p->nr_sects, cp+4); +} + +/* Roughly speaking, Linux doesn't use any of the above fields except + for partition type, start sector and number of sectors. (However, + see also linux/drivers/scsi/fdomain.c.) + The only way partition type is used (in the kernel) is the comparison + for equality with EXTENDED_PARTITION (and these Disk Manager types). */ + +struct part_desc { + unsigned long start; + unsigned long size; + unsigned long sector, offset; /* disk location of this info */ + struct partition p; + struct part_desc *ep; /* extended partition containing this one */ +} zero_part_desc; + +struct part_desc * +outer_extended_partition(struct part_desc *p) { + while (p->ep) + p = p->ep; + return p; +} + +int +is_parent(struct part_desc *pp, struct part_desc *p) { + while (p) { + if (pp == p) + return 1; + p = p->ep; + } + return 0; +} + +struct disk_desc { + struct part_desc partitions[128]; + int partno; +} oldp, newp; + +/* determine where on the disk this information goes */ +void +add_sector_and_offset(struct disk_desc *z) { + int pno; + struct part_desc *p; + + for (pno = 0; pno < z->partno; pno++) { + p = &(z->partitions[pno]); + p->offset = 0x1be + (pno%4)*sizeof(struct partition); + p->sector = (p->ep ? p->ep->start : 0); + } +} + +/* tell the kernel to reread the partition tables */ +int reread_ioctl(int fd) { + if(ioctl(fd, BLKRRPART)) { + perror("BLKRRPART"); + return -1; + } + return 0; +} + +/* reread after writing */ +void +reread_disk_partition(char *dev, int fd) { + printf("Re-reading the partition table ...\n"); + fflush(stdout); + sync(); + sleep(3); /* superfluous since 1.3.20 */ + + if(reread_ioctl(fd)) + printf("The command to re-read the partition table failed\n" + "Reboot your system now, before using mkfs\n"); + + if (close(fd)) { + perror(dev); + printf("Error closing %s\n", dev); + } + printf("\n"); +} + +/* find Linux name of this partition, assuming that it will have a name */ +int +index_to_linux(int pno, struct disk_desc *z) { + int i, ct = 1; + struct part_desc *p = &(z->partitions[0]); + for (i=0; isize > 0 && !is_extended(p->p.sys_type))) + ct++; + return ct; +} + +int +linux_to_index(int lpno, struct disk_desc *z) { + int i, ct = 0; + struct part_desc *p = &(z->partitions[0]); + for (i=0; ipartno && ct < lpno; i++,p++) + if((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) + && ++ct == lpno) + return i; + return -1; +} + +int +asc_to_index(char *pnam, struct disk_desc *z) { + int pnum, pno; + + if (*pnam == '#') { + pno = atoi(pnam+1); + } else { + pnum = atoi(pnam); + pno = linux_to_index(pnum, z); + } + if (!(pno >= 0 && pno < z->partno)) + fatal("%s: no such partition\n", pnam); + return pno; +} + +/* + * List partitions - in terms of sectors, blocks or cylinders + */ +#define F_SECTOR 1 +#define F_BLOCK 2 +#define F_CYLINDER 3 +#define F_MEGABYTE 4 + +int default_format = F_MEGABYTE; +int specified_format = 0; +int show_extended = 0; +int one_only = 0; +int one_only_pno; +int increment = 0; + +void +set_format(char c) { + switch(c) { + default: + printf("unrecognized format - using sectors\n"); + case 'S': specified_format = F_SECTOR; break; + case 'B': specified_format = F_BLOCK; break; + case 'C': specified_format = F_CYLINDER; break; + case 'M': specified_format = F_MEGABYTE; break; + } +} + +unsigned long +unitsize(int format) { + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + case F_CYLINDER: + if(cylindersize) return cylindersize; + case F_SECTOR: + return 1; + case F_BLOCK: + return 2; + case F_MEGABYTE: + return 2048; + } +} + +unsigned long +get_disksize(int format) { + unsigned long cs = cylinders; + if (cs && leave_last) + cs--; + return (cs * cylindersize) / unitsize(format); +} + +void +out_partition_header(char *dev, int format) { + if (dump) { + printf("# partition table of %s\n", dev); + printf("unit: sectors\n\n"); + return; + } + + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + printf("unimplemented format - using %s\n", + cylindersize ? "cylinders" : "sectors"); + case F_CYLINDER: + if (cylindersize) { + printf("Units = cylinders of %lu bytes, blocks of 1024 bytes" + ", counting from %d\n\n", + cylindersize<<9, increment); + printf(" Device Boot Start End #cyls #blocks Id System\n"); + break; + } + /* fall through */ + case F_SECTOR: + printf("Units = sectors of 512 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #sectors Id System\n"); + break; + case F_BLOCK: + printf("Units = blocks of 1024 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #blocks Id System\n"); + break; + case F_MEGABYTE: + printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes" + ", counting from %d\n\n", increment); + printf(" Device Boot Start End MB #blocks Id System\n"); + break; + } +} + +static void +out_rounddown(int width, unsigned long n, unsigned long unit, int inc) { + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar((n % unit) ? '+' : ' '); + putchar(' '); +} + +static void +out_roundup(int width, unsigned long n, unsigned long unit, int inc) { + if (n == (unsigned long)(-1)) + printf("%*s", width, "-"); + else + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar(((n+1) % unit) ? '-' : ' '); + putchar(' '); +} + +static void +out_roundup_size(int width, unsigned long n, unsigned long unit) { + printf("%*lu", width, (n+unit-1)/unit); + if (unit != 1) + putchar((n % unit) ? '-' : ' '); + putchar(' '); +} + +void +out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { + unsigned long start, end, size; + int pno, lpno; + + if (!format && !(format = specified_format)) + format = default_format; + + pno = p - &(z->partitions[0]); /* our index */ + lpno = index_to_linux(pno, z); /* name of next one that has a name */ + if(pno == linux_to_index(lpno, z)) /* was that us? */ + printf("%8s%-2u", dev, lpno); /* yes */ + else if(show_extended) + printf(" - "); + else + return; + putchar(dump ? ':' : ' '); + + start = p->start; + end = p->start + p->size - 1; + size = p->size; + + if (dump) { + printf(" start=%9lu", start); + printf(", size=%8lu", size); + printf(", Id=%2x", p->p.sys_type); + if (p->p.bootable == 0x80) + printf(", bootable"); + printf("\n"); + return; + } + + if(p->p.bootable == 0x80) + printf(" * "); + else if(p->p.bootable == 0) + printf(" "); + else + printf(" ? "); /* garbage */ + + switch(format) { + case F_CYLINDER: + if (cylindersize) { + out_rounddown(6, start, cylindersize, increment); + out_roundup(6, end, cylindersize, increment); + out_roundup_size(6, size, cylindersize); + out_rounddown(8, size, 2, 0); + break; + } + /* fall through */ + default: + case F_SECTOR: + out_rounddown(9, start, 1, increment); + out_roundup(9, end, 1, increment); + out_rounddown(9, size, 1, 0); + break; + case F_BLOCK: +#if 0 + printf("%8lu,%3lu ", + p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset); +#endif + out_rounddown(8, start, 2, increment); + out_roundup(8, end, 2, increment); + out_rounddown(8, size, 2, 0); + break; + case F_MEGABYTE: + out_rounddown(5, start, 2048, increment); + out_roundup(5, end, 2048, increment); + out_roundup_size(5, size, 2048); + out_rounddown(8, size, 2, 0); + break; + } + printf(" %2x %s\n", + p->p.sys_type, sysname(p->p.sys_type)); + + /* Is chs as we expect? */ + if (!quiet) { + chs a, b; + longchs aa, bb; + a = (size ? ulong_to_chs(start) : zero_chs); + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = (size ? ulong_to_chs(end) : zero_chs); + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + printf("partition ends on cylinder %ld, beyond the end of the disk\n", + bb.c); + } +} + +void +out_partitions(char *dev, struct disk_desc *z) { + int pno, format = 0; + + if (z->partno == 0) + printf("No partitions found\n"); + else { + out_partition_header(dev, format); + for(pno=0; pno < z->partno; pno++) { + out_partition(dev, format, &(z->partitions[pno]), z); + if(show_extended && pno%4==3) + printf("\n"); + } + } +} + +static int +disj(struct part_desc *p, struct part_desc *q) { + return + ((p->start + p->size <= q->start) + || (is_extended(p->p.sys_type) + && q->start + q->size <= p->start + p->size)); +} + +char * +pnumber(struct part_desc *p, struct disk_desc *z) { + static char buf[20]; + int this, next; + struct part_desc *p0 = &(z->partitions[0]); + + this = index_to_linux(p-p0, z); + next = index_to_linux(p-p0+1, z); + + if (next > this) + sprintf(buf, "%d", this); + else + sprintf(buf, "[%d]", this); + return buf; +} + +int +partitions_ok(struct disk_desc *z) { + struct part_desc *partitions = &(z->partitions[0]), *p, *q; + int partno = z->partno; + +#define PNO(p) pnumber(p, z) + + /* Have at least 4 partitions been defined? */ + if (partno < 4) { + if (!partno) + fatal("no partition table present.\n"); + else + fatal("strange, only %d partitions defined.\n", partno); + return 0; + } + + /* Are the partitions of size 0 marked empty? + And do they have start = 0? And bootable = 0? */ + for (p = partitions; p - partitions < partno; p++) + if (p->size == 0) { + if(p->p.sys_type != EMPTY_PARTITION) + warn("Warning: partition %s has size 0 but is not marked Empty\n", + PNO(p)); + else if(p->p.bootable != 0) + warn("Warning: partition %s has size 0 and is bootable\n", + PNO(p)); + else if(p->p.start_sect != 0) + warn("Warning: partition %s has size 0 and nonzero start\n", + PNO(p)); + /* all this is probably harmless, no error return */ + } + + /* Are the logical partitions contained in their extended partitions? */ + for (p = partitions+4; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) { + q = p->ep; + if (p->start < q->start || p->start + p->size > q->start + q->size) { + warn("Warning: partition %s ", PNO(p)); + warn("is not contained in partition %s\n", PNO(q)); + return 0; + } + } + + /* Are the data partitions mutually disjoint? */ + for (p = partitions; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) + for (q = p+1; q < partitions+partno; q++) + if (q->size && !is_extended(q->p.sys_type)) + if(!((p->start > q-> start) ? disj(q,p) : disj(p,q))) { + warn("Warning: partitions %s ", PNO(p)); + warn("and %s overlap\n", PNO(q)); + return 0; + } + + /* Do they start past zero and end before end-of-disk? */ + { unsigned long ds = get_disksize(F_SECTOR); + for (p = partitions; p < partitions+partno; p++) + if (p->size) { + if(p->start == 0) { + warn("Warning: partition %s starts at sector 0\n", PNO(p)); + return 0; + } + if (p->size && p->start + p->size > ds) { + warn("Warning: partition %s extends past end of disk\n", PNO(p)); + return 0; + } + } + } + + /* At most one chain of DOS extended partitions ? */ + /* It seems that the OS/2 fdisk has the additional requirement + that the extended partition must be the fourth one */ + { int ect = 0; + for (p = partitions; p < partitions+4; p++) + if (p->p.sys_type == EXTENDED_PARTITION) + ect++; + if (ect > 1 && !Linux) { + warn("Among the primary partitions, at most one can be extended\n"); + warn(" (although this is not a problem under Linux)\n"); + return 0; + } + } + + /* + * Do all partitions start at a cylinder boundary ? + * (this is not required for Linux) + * The first partition starts after MBR. + * Logical partitions start slightly after the containing extended partn. + */ + if (cylindersize) { + for(p = partitions; p < partitions+partno; p++) + if (p->size) { + if(p->start % cylindersize != 0 + && (!p->ep || p->start / cylindersize != p->ep->start / cylindersize) + && (p->p.start_sect >= cylindersize)) { + warn("Warning: partition %s does not start " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + if((p->start + p->size) % cylindersize) { + warn("Warning: partition %s does not end " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + } + } + + /* Usually, one can boot only from primary partitions. */ + /* In fact, from a unique one only. */ + /* do not warn about bootable extended partitions - + often LILO is there */ + { int pno = -1; + for(p = partitions; p < partitions+partno; p++) + if (p->p.bootable) { + if (pno == -1) + pno = p - partitions; + else if (p - partitions < 4) { + warn("Warning: more than one primary partition is marked " + "bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + break; + } + if (p - partitions >= 4) { + warn("Warning: usually one can boot from primary partitions " + "only\n" "LILO disregards the `bootable' flag.\n"); + break; + } + } + if (pno == -1 || pno >= 4) + warn("Warning: no primary partition is marked bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + } + + /* Is chs as we expect? */ + for(p = partitions; p < partitions+partno; p++) { + chs a, b; + longchs aa, bb; + a = p->size ? ulong_to_chs(p->start) : zero_chs; + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "start")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = p->size ? ulong_to_chs(p->start + p->size - 1) : zero_chs; + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "end")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + warn("partition %s ends on cylinder %ld, beyond the end of the disk\n", + PNO(p), bb.c); + } + + return 1; + +#undef PNO +} + +static void +extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { + char *cp; + struct sector *s; + unsigned long start, here, next; + int i, moretodo = 1; + struct partition p; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + here = start = ep->start; + + while (moretodo) { + moretodo = 0; + + if (!(s = get_sector(dev, fd, here))) + break; + + if (!msdos_signature(s)) + break; + + cp = s->data + 0x1be; + + if (pno+4 >= SIZE(z->partitions)) { + printf("too many partitions - ignoring those past nr (%d)\n", + pno-1); + break; + } + + next = 0; + + for (i=0; i<4; i++,cp += sizeof(struct partition)) { + partitions[pno].sector = here; + partitions[pno].offset = cp - s->data; + partitions[pno].ep = ep; + copy_to_part(cp,&p); + if (is_extended(p.sys_type)) { + if (next) + printf("tree of partitions?\n"); + partitions[pno].start = next = start + p.start_sect; + moretodo = 1; + } else { + partitions[pno].start = here + p.start_sect; + } + partitions[pno].size = p.nr_sects; + partitions[pno++].p = p; + } + here = next; + } + + z->partno = pno; +} + +static int +msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + int i; + char *cp; + struct partition pt; + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + if (!(s = get_sector(dev, fd, start))) + return 0; + + if (!msdos_signature(s)) + return 0; + + cp = s->data + 0x1be; + copy_to_part(cp,&pt); + + /* If I am not mistaken, recent kernels will hide this from us, + so we will never actually see traces of a Disk Manager */ + if (pt.sys_type == DM6_PARTITION + || pt.sys_type == EZD_PARTITION + || pt.sys_type == DM6_AUX1PARTITION + || pt.sys_type == DM6_AUX3PARTITION) { + printf("detected Disk Manager - unable to handle that\n"); + return 0; + } + { unsigned int sig = *(unsigned short *)(s->data + 2); + if (sig <= 0x1ae + && *(unsigned short *)(s->data + sig) == 0x55aa + && (1 & *(unsigned char *)(s->data + sig + 2))) { + printf("DM6 signature found - giving up\n"); + return 0; + } + } + + for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) { + partitions[pno].sector = start; + partitions[pno].offset = cp - s->data; + copy_to_part(cp,&pt); + partitions[pno].start = start + pt.start_sect; + partitions[pno].size = pt.nr_sects; + partitions[pno].ep = 0; + partitions[pno].p = pt; + } + + z->partno = pno; + + for (i=0; i<4; i++) + if (is_extended(partitions[i].p.sys_type)) { + if (!partitions[i].size) { + printf("strange..., an extended partition of size 0?\n"); + continue; + } + extended_partition(dev, fd, &partitions[i], z); + } + + return 1; +} + +static int +osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +void +get_partitions(char *dev, int fd, struct disk_desc *z) { + z->partno = 0; + + if (!msdos_partition(dev, fd, 0, z) && !osf_partition(dev, fd, 0, z)) { + printf(" %s: unrecognized partition\n", dev); + return; + } +} + +int +write_partitions(char *dev, int fd, struct disk_desc *z) { + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]), *p; + int pno = z->partno; + + if (no_write) { + printf("-n flag was given: Nothing changed\n"); + exit(0); + } + + for (p = partitions; p < partitions+pno; p++) { + s = get_sector(dev, fd, p->sector); + if (!s) return 0; + s->to_be_written = 1; + copy_from_part(&(p->p), s->data + p->offset); + *(unsigned short *)(&(s->data[0x1fe])) = 0xaa55; + } + if (save_sector_file) { + if (!save_sectors(dev, fd)) { + fatal("Failed saving the old sectors - aborting\n"); + return 0; + } + } + if (!write_sectors(dev, fd)) { + error("Failed writing the partition on %s\n", dev); + return 0; + } + return 1; +} + +/* + * F. The standard input + */ + +/* + * Input format: + * + * Fields are separated by whitespace or comma or semicolon possibly + * followed by whitespace; initial and trailing whitespace is ignored. + * Numbers can be octal, decimal or hexadecimal, decimal is default + * The parts can (and probably should) be omitted. + * Bootable is specified as [*|-], with as default not-bootable. + * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where + * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E + * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85). + * The default value of start is the first nonassigned sector/cylinder/... + * The default value of size is as much as possible (until next + * partition or end-of-disk). + * .: end of chain of extended partitions. + * + * On interactive input an empty line means: all defaults. + * Otherwise empty lines are ignored. + */ + +int eof, eob; + +struct dumpfld { + int fldno; + char *fldname; + int is_bool; +} dumpflds[] = { + { 0, "start", 0 }, + { 1, "size", 0 }, + { 2, "Id", 0 }, + { 3, "bootable", 1 }, + { 4, "bh", 0 }, + { 5, "bs", 0 }, + { 6, "bc", 0 }, + { 7, "eh", 0 }, + { 8, "es", 0 }, + { 9, "ec", 0 } +}; + +/* + * Read a line, split it into fields + * + * (some primitive handwork, but a more elaborate parser seems + * unnecessary) + */ +#define RD_EOF (-1) +#define RD_CMD (-2) + +int +read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) { + unsigned char *lp, *ip; + int c, fno; + + /* boolean true and empty string at start */ + line[0] = '*'; + line[1] = 0; + for (fno=0; fno < fieldssize; fno++) + fields[fno] = line + 1; + fno = 0; + + /* read a line from stdin */ + lp = fgets(line+2, linesize, stdin); + if (lp == NULL) { + eof = 1; + return RD_EOF; + } + if (!(lp = index(lp, '\n'))) + fatal("long or incomplete input line - quitting\n"); + *lp = 0; + + /* remove comments, if any */ + if ((lp = index(line+2, '#')) != 0) + *lp = 0; + + /* recognize a few commands - to be expanded */ + if (!strcmp(line+2, "unit: sectors")) { + specified_format = F_SECTOR; + return RD_CMD; + } + + /* dump style? - then bad input is fatal */ + if ((ip = index(line+2, ':')) != 0) { + struct dumpfld *d; + + nxtfld: + ip++; + while(isspace(*ip)) + ip++; + if (*ip == 0) + return fno; + for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) { + if(!strncmp(ip, d->fldname, strlen(d->fldname))) { + ip += strlen(d->fldname); + while(isspace(*ip)) + ip++; + if (d->is_bool) + fields[d->fldno] = line; + else if (*ip == '=') { + while(isspace(*++ip)) ; + fields[d->fldno] = ip; + while(isalnum(*ip)) /* 0x07FF */ + ip++; + } else + fatal("input error: `=' expected after %s field\n", + d->fldname); + if (fno <= d->fldno) + fno = d->fldno + 1; + if(*ip == 0) + return fno; + if(*ip != ',' && *ip != ';') + fatal("input error: unexpected character %c after %s field\n", + *ip, d->fldname); + *ip = 0; + goto nxtfld; + } + } + fatal("unrecognized input: %s\n", ip); + } + + /* split line into fields */ + lp = ip = line+2; + fields[fno++] = lp; + while((c = *ip++) != 0) { + if (!lp[-1] && (c == '\t' || c == ' ')) + ; + else if (c == '\t' || c == ' ' || c == ',' || c == ';') { + *lp++ = 0; + if (fno < fieldssize) + fields[fno++] = lp; + continue; + } else + *lp++ = c; + } + + if (lp == fields[fno-1]) + fno--; + return fno; +} + +/* read a number, use default if absent */ +int +get_ul(char *u, unsigned long *up, unsigned long def, int base) { + char *nu; + + if (*u) { + errno = 0; + *up = strtoul(u, &nu, base); + if (errno == ERANGE) { + printf("number too big\n"); + return -1; + } + if (*nu) { + printf("trailing junk after number\n"); + return -1; + } + } else + *up = def; + return 0; +} + +/* There are two common ways to structure extended partitions: + as nested boxes, and as a chain. Sometimes the partitions + must be given in order. Sometimes all logical partitions + must lie inside the outermost extended partition. +NESTED: every partition is contained in the surrounding partitions + and is disjoint from all others. +CHAINED: every data partition is contained in the surrounding partitions + and disjoint from all others, but extended partitions may lie outside + (insofar as allowed by all_logicals_inside_outermost_extended). +ONESECTOR: all data partitions are mutually disjoint; extended partitions + each use one sector only (except perhaps for the outermost one). +*/ +int partitions_in_order = 0; +int all_logicals_inside_outermost_extended = 1; +enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED; + +/* find the default value for - assuming entire units */ +unsigned long +first_free(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long mid, struct disk_desc *z) { + unsigned long ff, fff; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } +#if 0 + ff = pp ? (pp->start + unit - 1) / unit : 0; +#else + /* rounding up wastes almost an entire cylinder - round down + and leave it to compute_start_sect() to fix the difference */ + ff = pp ? pp->start / unit : 0; +#endif + /* MBR and 1st sector of an extended partition are never free */ + if (unit == 1) + ff++; + + again: + for(pp = partitions; pp < partitions+pno; pp++) { + if (!is_parent(pp, ep) && pp->size > 0) { + if ((partitions_in_order || pp->start / unit <= ff + || (mid && pp->start / unit <= mid)) + && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) { + ff = fff; + goto again; + } + } + } + + return ff; +} + +/* find the default value for - assuming entire units */ +unsigned long +max_length(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long start, struct disk_desc *z) { + unsigned long fu; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } + fu = pp ? (pp->start + pp->size) / unit : get_disksize(format); + + for(pp = partitions; pp < partitions+pno; pp++) + if (!is_parent(pp, ep) && pp->size > 0 + && pp->start / unit >= start && pp->start / unit < fu) + fu = pp->start / unit; + + return (fu > start) ? fu - start : 0; +} + +/* compute starting sector of a partition inside an extended one */ +/* ep is 0 or points to surrounding extended partition */ +int +compute_start_sect(struct part_desc *p, struct part_desc *ep) { + unsigned long base; + int inc = (DOS && sectors) ? sectors : 1; + int delta; + + if (ep && p->start + p->size >= ep->start + 1) + delta = p->start - ep->start - inc; + else if (p->start == 0 && p->size > 0) + delta = -inc; + else + delta = 0; + if (delta < 0) { + p->start -= delta; + p->size += delta; + if (is_extended(p->p.sys_type) && boxes == ONESECTOR) + p->size = inc; + else if ((int)(p->size) <= 0) { + warn("no room for partition descriptor\n"); + return 0; + } + } + base = (!ep ? 0 + : (is_extended(p->p.sys_type) ? + outer_extended_partition(ep) : ep)->start); + p->ep = ep; + if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) { + p->p.start_sect = 0; + p->p.begin_chs = zero_chs; + p->p.end_chs = zero_chs; + } else { + p->p.start_sect = p->start - base; + p->p.begin_chs = ulong_to_chs(p->start); + p->p.end_chs = ulong_to_chs(p->start + p->size - 1); + } + p->p.nr_sects = p->size; + return 1; +} + +/* build the extended partition surrounding a given logical partition */ +int +build_surrounding_extended(struct part_desc *p, struct part_desc *ep, + struct disk_desc *z) { + int inc = (DOS && sectors) ? sectors : 1; + int format = F_SECTOR; + struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep; + + if (boxes == NESTED) { + ep->start = first_free(ep-p0, 1, eep, format, p->start, z); + ep->size = max_length(ep-p0, 1, eep, format, ep->start, z); + if (ep->start > p->start || ep->start + ep->size < p->start + p->size) { + warn("cannot build surrounding extended partition\n"); + return 0; + } + } else { + ep->start = p->start; + if(boxes == CHAINED) + ep->size = p->size; + else + ep->size = inc; + } + + ep->p.nr_sects = ep->size; + ep->p.bootable = 0; + ep->p.sys_type = EXTENDED_PARTITION; + if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) { + ep->p.sys_type = EMPTY_PARTITION; + ep->size = 0; + return 0; + } + + return 1; +} + +int +read_line(int pno, struct part_desc *ep, char *dev, int interactive, + struct disk_desc *z) { + unsigned char line[1000]; + unsigned char *fields[11]; + int fno, pct = pno%4; + struct part_desc p, *orig; + unsigned long ff, ff1, ul, ml, ml1, def; + int format, lpno, is_extd; + + if (eof || eob) + return -1; + + lpno = index_to_linux(pno, z); + + if (interactive) { + if (pct == 0 && (show_extended || pno == 0)) + warn("\n"); + warn("%8s%d: ", dev, lpno); + } + + /* read input line - skip blank lines when reading from a file */ + do { + fno = read_stdin(fields, line, SIZE(fields), SIZE(line)); + } while(fno == RD_CMD || (fno == 0 && !interactive)); + if (fno == RD_EOF) { + return -1; + } else if (fno > 10 && *(fields[10]) != 0) { + printf("too many input fields\n"); + return 0; + } + + if (fno == 1 && !strcmp(fields[0], ".")) { + eob = 1; + return -1; + } + + /* use specified format, but round to cylinders if F_MEGABYTE specified */ + format = 0; + if (cylindersize && specified_format == F_MEGABYTE) + format = F_CYLINDER; + + orig = (one_only ? &(oldp.partitions[pno]) : 0); + + p = zero_part_desc; + p.ep = ep; + + /* first read the type - we need to know whether it is extended */ + /* stop reading when input blank (defaults) and all is full */ + is_extd = 0; + if (fno == 0) { /* empty line */ + if (orig && is_extended(orig->p.sys_type)) + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + if (ml == 0 && is_extd == 0) { + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + } + if (ml == 0 && pno >= 4) { + /* no free blocks left - don't read any further */ + warn("No room for more\n"); + return -1; + } + } + if (fno < 3 || !*(fields[2])) + ul = orig ? orig->p.sys_type : + (is_extd || (pno > 3 && pct == 1 && show_extended)) + ? EXTENDED_PARTITION : LINUX_NATIVE; + else if(!strcmp(fields[2], "L")) + ul = LINUX_NATIVE; + else if(!strcmp(fields[2], "S")) + ul = LINUX_SWAP; + else if(!strcmp(fields[2], "E")) + ul = EXTENDED_PARTITION; + else if(!strcmp(fields[2], "X")) + ul = LINUX_EXTENDED; + else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16)) + return 0; + if (ul > 255) { + warn("Illegal type\n"); + return 0; + } + p.p.sys_type = ul; + is_extd = is_extended(ul); + + /* find start */ + ff = first_free(pno, is_extd, ep, format, 0, z); + ff1 = ff * unitsize(format); + def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1; + if (fno < 1 || !*(fields[0])) + p.start = def; + else { + if (get_ul(fields[0], &ul, def / unitsize(0), 0)) + return 0; + p.start = ul * unitsize(0); + p.start -= (p.start % unitsize(format)); + } + + /* find length */ + ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z); + ml1 = ml * unitsize(format); + def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1; + if (fno < 2 || !*(fields[1])) + p.size = def; + else { + if (get_ul(fields[1], &ul, def / unitsize(0), 0)) + return 0; + p.size = ul * unitsize(0) + unitsize(format) - 1; + p.size -= (p.size % unitsize(format)); + } + if (p.size > ml1) { + warn("Warning: exceeds max allowable size (%lu)\n", ml1 / unitsize(0)); + if (!force) + return 0; + } + if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) { + warn("Warning: empty partition\n"); + if (!force) + return 0; + } + p.p.nr_sects = p.size; + + if (p.size == 0 && !orig) { + if(fno < 1 || !*(fields[0])) + p.start = 0; + if(fno < 3 || !*(fields[2])) + p.p.sys_type = EMPTY_PARTITION; + } + + if (p.start < ff1 && p.size > 0) { + warn("Warning: bad partition start (earliest %lu)\n", + (ff1 + unitsize(0) - 1) / unitsize(0)); + if (!force) + return 0; + } + + if (fno < 4 || !*(fields[3])) + ul = (orig ? orig->p.bootable : 0); + else if (!strcmp(fields[3], "-")) + ul = 0; + else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+")) + ul = 0x80; + else { + warn("unrecognized bootable flag - choose - or *\n"); + return 0; + } + p.p.bootable = ul; + + if (ep && ep->p.sys_type == EMPTY_PARTITION) { + if(!build_surrounding_extended(&p, ep, z)) + return 0; + } else + if(!compute_start_sect(&p, ep)) + return 0; + + { longchs aa = chs_to_longchs(p.p.begin_chs), bb; + + if (fno < 5) { + bb = aa; + } else if (fno < 7) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[4], &bb.c, aa.c, 0) || + get_ul(fields[5], &bb.h, aa.h, 0) || + get_ul(fields[6], &bb.s, aa.s, 0)) + return 0; + p.p.begin_chs = longchs_to_chs(bb); + } + { longchs aa = chs_to_longchs(p.p.end_chs), bb; + + if (fno < 8) { + bb = aa; + } else if (fno < 10) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[7], &bb.c, aa.c, 0) || + get_ul(fields[8], &bb.h, aa.h, 0) || + get_ul(fields[9], &bb.s, aa.s, 0)) + return 0; + p.p.end_chs = longchs_to_chs(bb); + } + + if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION + && (is_extended(p.p.sys_type) != (pct == 1))) { + warn("Extended partition not where expected\n"); + if (!force) + return 0; + } + + z->partitions[pno] = p; + if (pno >= z->partno) + z->partno += 4; /* reqd for out_partition() */ + + if (interactive) + out_partition(dev, 0, &(z->partitions[pno]), z); + + return 1; +} + +/* ep either points to the extended partition to contain this one, + or to the empty partition that may become extended or is 0 */ +int +read_partition(char *dev, int interactive, int pno, struct part_desc *ep, + struct disk_desc *z) { + struct part_desc *p = &(z->partitions[pno]); + int i; + + if (one_only) { + *p = oldp.partitions[pno]; + if (one_only_pno != pno) + goto ret; + } else if (!show_extended && pno > 4 && pno%4) + goto ret; + + while (!(i = read_line(pno, ep, dev, interactive, z))) + if (!interactive) + fatal("bad input\n"); + if (i < 0) { + p->ep = ep; + return 0; + } + + ret: + p->ep = ep; + if (pno >= z->partno) + z->partno += 4; + return 1; +} + +void +read_partition_chain(char *dev, int interactive, struct part_desc *ep, + struct disk_desc *z) { + int i, base; + + eob = 0; + while (1) { + base = z->partno; + if (base+4 > SIZE(z->partitions)) { + printf("too many partitions\n"); + break; + } + for (i=0; i<4; i++) + if (!read_partition(dev, interactive, base+i, ep, z)) + return; + for (i=0; i<4; i++) { + ep = &(z->partitions[base+i]); + if (is_extended(ep->p.sys_type) && ep->size) + break; + } + if (i == 4) { + /* nothing found - maybe an empty partition is going + to be extended */ + if (one_only || show_extended) + break; + ep = &(z->partitions[base+1]); + if (ep->size || ep->p.sys_type != EMPTY_PARTITION) + break; + } + } +} + +void +read_input(char *dev, int interactive, struct disk_desc *z) { + int i; + struct part_desc *partitions = &(z->partitions[0]), *ep; + + for (i=0; i < SIZE(z->partitions); i++) + partitions[i] = zero_part_desc; + z->partno = 0; + + if (interactive) + warn(" +Input in the following format; absent fields get a default value. + +Usually you only need to specify and (and perhaps ). +"); + eof = 0; + + for (i=0; i<4; i++) + read_partition(dev, interactive, i, 0, z); + for (i=0; i<4; i++) { + ep = partitions+i; + if (is_extended(ep->p.sys_type) && ep->size) + read_partition_chain(dev, interactive, ep, z); + } + add_sector_and_offset(z); +} + +/* + * G. The command line + */ + +static void version(void) { + printf(PROGNAME " version " VERSION " (aeb@cwi.nl, " DATE ")\n"); +} + +static void +usage(void) { + version(); + printf("Usage: + " PROGNAME " [options] device ... +device: something like /dev/hda or /dev/sda +useful options: + -s [or --show-size]: list size of a partition + -c [or --id]: print or change partition Id + -l [or --list]: list partitions of each device + -d [or --dump]: idem, but in a format suitable for later input + -i [or --increment]: number cylinders etc. from 1 instead of from 0 + -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB + -T [or --list-types]:list the known partition types + -D [or --DOS]: for DOS-compatibility: waste a little space + -R [or --re-read]: make kernel reread partition table + -N# : change only the partition with number # + -n : do not actually write to disk + -O file : save the sectors that will be overwritten to file + -I file : restore these sectors again + -v [or --version]: print version + -? [or --help]: print this message +dangerous options: + -g [or --show-geometry]: print the kernel's idea of the geometry + -x [or --show-extended]: also list extended partitions on output + or expect descriptors for them on input + -L [or --Linux]: do not complain about things irrelevant for Linux + -q [or --quiet]: suppress warning messages + You can override the detected geometry using: + -C# [or --cylinders #]:set the number of cylinders to use + -H# [or --heads #]: set the number of heads to use + -S# [or --sectors #]: set the number of sectors to use + You can disable all consistency checking with: + -f [or --force]: do what I say, even if it is stupid +"); + exit(1); +} + +static void +activate_usage(char *progn) { + printf("Usage: + %s device list active partitions on device + %s device n1 n2 ... activate partitions n1 ..., inactivate the rest + %s device activate partition n, inactivate the other ones +", progn, progn, PROGNAME " -An"); + exit(1); +} + +static void +unhide_usage(char *progn) { + exit(1); +} + +static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V"; + +#define PRINT_ID 0400 +#define CHANGE_ID 01000 + +static const struct option long_opts[] = { + { "change-id", no_argument, NULL, 'c' + CHANGE_ID }, + { "print-id", no_argument, NULL, 'c' + PRINT_ID }, + { "id", no_argument, NULL, 'c' }, + { "dump", no_argument, NULL, 'd' }, + { "force", no_argument, NULL, 'f' }, + { "show-geometry", no_argument, NULL, 'g' }, + { "increment", no_argument, NULL, 'i' }, + { "list", no_argument, NULL, 'l' }, + { "quiet", no_argument, NULL, 'q' }, + { "show-size", no_argument, NULL, 's' }, + { "unit", required_argument, NULL, 'u' }, + { "version", no_argument, NULL, 'v' }, + { "show-extended", no_argument, NULL, 'x' }, + { "help", no_argument, NULL, '?' }, + { "one-only", no_argument, NULL, '1' }, + { "cylinders", required_argument, NULL, 'C' }, + { "heads", required_argument, NULL, 'H' }, + { "sectors", required_argument, NULL, 'S' }, + { "activate", optional_argument, NULL, 'A' }, + { "DOS", no_argument, NULL, 'D' }, + { "Linux", no_argument, NULL, 'L' }, + { "re-read", no_argument, NULL, 'R' }, + { "list-types", no_argument, NULL, 'T' }, + { "unhide", optional_argument, NULL, 'U' }, + { "no-reread", no_argument, NULL, 160 }, + { "IBM", no_argument, NULL, 161 }, + { "leave-last", no_argument, NULL, 161 }, +/* undocumented flags - not all completely implemented */ + { "in-order", no_argument, NULL, 128 }, + { "not-in-order", no_argument, NULL, 129 }, + { "inside-outer", no_argument, NULL, 130 }, + { "not-inside-outer", no_argument, NULL, 131 }, + { "nested", no_argument, NULL, 132 }, + { "chained", no_argument, NULL, 133 }, + { "onesector", no_argument, NULL, 134 }, + { NULL, 0, NULL, 0 } +}; + +/* default devices to list */ +static struct devd { + char *pref, *letters; +} defdevs[] = { + { "hd", "abcdefgh" }, + { "sd", "abcde" }, + { "xd", "ab" } +}; + +void do_list(char *dev, int silent); +void do_size(char *dev, int silent); +void do_geom(char *dev, int silent); +void do_fdisk(char *dev); +void do_reread(char *dev); +void do_change_id(char *dev, char *part, char *id); +void do_unhide(char **av, int ac, char *arg); +void do_activate(char **av, int ac, char *arg); + +int total_size; + +int +main(int argc, char **argv) { + char *progn; + int c; + char *dev; + int opt_size = 0; + int opt_out_geom = 0; + int opt_reread = 0; + int activate = 0; + int do_id = 0; + int unhide = 0; + int fdisk = 0; + char *activatearg = 0; + char *unhidearg = 0; + + if (argc < 1) + fatal("no command?\n"); + if ((progn = rindex(argv[0], '/')) == NULL) + progn = argv[0]; + else + progn++; + if (!strcmp(progn, "activate")) + activate = 1; /* equivalent to `fdisk -A' */ +#if 0 /* not important enough to deserve a name */ + else if (!strcmp(progn, "unhide")) + unhide = 1; /* equivalent to `fdisk -U' */ +#endif + else + fdisk = 1; + + while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (c) { + case 'f': + force = 1; break; /* does not imply quiet */ + case 'g': + opt_out_geom = 1; break; + case 'i': + increment = 1; break; + case 'c': + case 'c' + PRINT_ID: + case 'c' + CHANGE_ID: + do_id = c; break; + case 'd': + dump = 1; /* fall through */ + case 'l': + opt_list = 1; break; + case 'n': + no_write = 1; break; + case 'q': + quiet = 1; break; + case 's': + opt_size = 1; break; + case 'u': + set_format(*optarg); break; + case 'v': + version(); + exit(0); + case 'x': + show_extended = 1; break; + case 'A': + activatearg = optarg; + activate = 1; break; + case 'C': + specified_cylinders = atoi(optarg); break; + case 'D': + DOS = 1; break; + case 'H': + specified_heads = atoi(optarg); break; + case 'L': + Linux = 1; break; + case 'N': + one_only = atoi(optarg); break; + case 'I': + restore_sector_file = optarg; break; + case 'O': + save_sector_file = optarg; break; + case 'R': + opt_reread = 1; break; + case 'S': + specified_sectors = atoi(optarg); break; + case 'T': + list_types(); + exit(0); + case 'U': + unhidearg = optarg; + unhide = 1; break; + case 'V': + verify = 1; break; + case '?': + default: + usage(); break; + + /* undocumented flags */ + case 128: + partitions_in_order = 1; break; + case 129: + partitions_in_order = 0; break; + case 130: + all_logicals_inside_outermost_extended = 1; break; + case 131: + all_logicals_inside_outermost_extended = 0; break; + case 132: + boxes = NESTED; break; + case 133: + boxes = CHAINED; break; + case 134: + boxes = ONESECTOR; break; + + /* more flags */ + case 160: + no_reread = 1; break; + case 161: + leave_last = 1; break; + } + } + + if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) { + struct devd *dp; + char *lp; + char device[10]; + + total_size = 0; + + for(dp = defdevs; dp-defdevs < SIZE(defdevs); dp++) { + lp = dp->letters; + while(*lp) { + sprintf(device, "/dev/%s%c", dp->pref, *lp++); + if (opt_out_geom) + do_geom(device, 1); + if (opt_size) + do_size(device, 1); + if (opt_list || verify) + do_list(device, 1); + } + } + + if (opt_size) + printf("total: %d blocks\n", total_size); + + exit(exit_status); + } + + if (optind == argc) { + if (activate) + activate_usage(fdisk ? "fdisk -A" : progn); + else if (unhide) + unhide_usage(fdisk ? "fdisk -U" : progn); + else + usage(); + } + + if (opt_list || opt_out_geom || opt_size || verify) { + while (optind < argc) { + if (opt_out_geom) + do_geom(argv[optind], 0); + if (opt_size) + do_size(argv[optind], 0); + if (opt_list || verify) + do_list(argv[optind], 0); + optind++; + } + exit(exit_status); + } + + if (activate) { + do_activate(argv+optind, argc-optind, activatearg); + exit(exit_status); + } + if (unhide) { + do_unhide(argv+optind, argc-optind, unhidearg); + exit(exit_status); + } + if (do_id) { + if ((do_id & PRINT_ID) != 0 && optind != argc-2) + fatal("usage: fdisk --print-id device partition-number\n"); + else if ((do_id & CHANGE_ID) != 0 && optind != argc-3) + fatal("usage: fdisk --change-id device partition-number Id\n"); + else if (optind != argc-3 && optind != argc-2) + fatal("usage: fdisk --id device partition-number [Id]\n"); + do_change_id(argv[optind], argv[optind+1], + (optind == argc-2) ? 0 : argv[optind+2]); + exit(exit_status); + } + + if (optind != argc-1) + fatal("can specify only one device (except with -l or -s)\n"); + dev = argv[optind]; + + if (opt_reread) + do_reread(dev); + else if (restore_sector_file) + restore_sectors(dev); + else + do_fdisk(dev); + + return 0; +} + +/* + * H. Listing the current situation + */ + +int +my_open (char *dev, int rw, int silent) { + int fd, mode; + + mode = (rw ? O_RDWR : O_RDONLY); + fd = open(dev, mode); + if (fd < 0 && !silent) { + perror(dev); + fatal("cannot open %s %s\n", dev, rw ? "read-write" : "for reading"); + } + return fd; +} + +void +do_list (char *dev, int silent) { + int fd; + struct disk_desc *z; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1); + get_partitions(dev, fd, z); + + if (opt_list) + out_partitions(dev, z); + + if (verify) { + if (partitions_ok(z)) + warn("%s: OK\n", dev); + else + exit_status = 1; + } +} + +void +do_geom (char *dev, int silent) { + int fd; + struct hd_geometry g; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + /* get_cylindersize(dev, fd, silent); */ + if (!ioctl(fd, HDIO_GETGEO, &g)) + printf("%s: %d cylinders, %d heads, %d sectors/track\n", + dev, g.cylinders, g.heads, g.sectors); + else + printf("%s: unknown geometry\n", dev); +} + +/* for compatibility with earlier fdisk: provide option -s */ +void +do_size (char *dev, int silent) { + int fd, size; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + if(ioctl(fd, BLKGETSIZE, &size)) { + if(!silent) { + perror(dev); + fatal("BLKGETSIZE ioctl failed for %s\n", dev); + } + return; + } + + size /= 2; /* convert sectors to blocks */ + if (silent) + printf("%s: %d\n", dev, size); + else + printf("%d\n", size); + + total_size += size; +} + +/* + * Activate: usually one wants to have a single primary partition + * to be active. OS/2 fdisk makes non-bootable logical partitions + * active - I don't know what that means to OS/2 Boot Manager. + * + * Call: activate /dev/hda 2 5 7 make these partitions active + * and the remaining ones inactive + * Or: fdisk -A /dev/hda 2 5 7 + * + * If only a single partition must be active, one may also use the form + * fdisk -A2 /dev/hda + * + * With "activate /dev/hda" or "fdisk -A /dev/hda" the active partitions + * are listed but not changed. To get zero active partitions, use + * "activate /dev/hda none" or "fdisk -A /dev/hda none". + * Use something like `echo ",,,*" | fdisk -N2 /dev/hda' to only make + * /dev/hda2 active, without changing other partitions. + * + * A warning will be given if after the change not precisely one primary + * partition is active. + * + * The present syntax was chosen to be (somewhat) compatible with the + * activate from the LILO package. + */ +void +set_active (struct disk_desc *z, char *pnam) { + int pno; + + pno = asc_to_index(pnam, z); + z->partitions[pno].p.bootable = 0x80; +} + +void +do_activate (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd; + int rw, i, pno, lpno; + struct disk_desc *z; + + z = &oldp; + + rw = (!no_write && (arg || ac > 1)); + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + if (!arg && ac == 1) { + /* list active partitions */ + for (pno=0; pno < z->partno; pno++) { + if (z->partitions[pno].p.bootable) { + lpno = index_to_linux(pno, z); + if (pno == linux_to_index(lpno, z)) + printf("%s%d\n", dev, lpno); + else + printf("%s#%d\n", dev, pno); + if (z->partitions[pno].p.bootable != 0x80) + warn("bad active byte: 0x%x instead of 0x80\n", + z->partitions[pno].p.bootable); + } + } + } else { + /* clear `active byte' everywhere */ + for (pno=0; pno < z->partno; pno++) + z->partitions[pno].p.bootable = 0; + + /* then set where desired */ + if (ac == 1) + set_active(z, arg); + else for(i=1; ipartno && pno < 4; pno++) + if (z->partitions[pno].p.bootable) + i++; + if (i != 1) + warn("You have %d active primary partitions. This does not matter for LILO,\n" + "but the DOS MBR will only boot a disk with 1 active partition.\n", i); +} + +void +set_unhidden (struct disk_desc *z, char *pnam) { + int pno; + unsigned char id; + + pno = asc_to_index(pnam, z); + id = z->partitions[pno].p.sys_type; + if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17) + id -= 0x10; + else + fatal("partition %s has id %x and is not hidden\n", pnam, id); + z->partitions[pno].p.sys_type = id; +} + +/* + * maybe remove and make part of --change-id + */ +void +do_unhide (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd, rw, i; + struct disk_desc *z; + + z = &oldp; + + rw = !no_write; + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + /* unhide where desired */ + if (ac == 1) + set_unhidden(z, arg); + else for(i=1; ipartitions[pno].p.sys_type); + return; + } + i = strtoul(id, NULL, 16); + if (i > 255) + fatal("Bad Id %x\n", i); + z->partitions[pno].p.sys_type = i; + + if(write_partitions(dev, fd, z)) + warn("Done\n\n"); + else + exit_status = 1; +} + +void +do_reread(char *dev) { + int fd; + + fd = my_open(dev, 0, 0); + if(reread_ioctl(fd)) + printf("This disk is currently in use.\n"); +} + +/* + * I. Writing the new situation + */ + +void +do_fdisk(char *dev){ + int fd; + int c, answer; + struct stat statbuf; + int interactive = isatty(0); + struct disk_desc *z; + + if (stat(dev, &statbuf) < 0) { + perror(dev); + fatal("Fatal error: cannot find %s\n", dev); + } + if (!S_ISBLK(statbuf.st_mode)) { + warn("Warning: %s is not a block device\n", dev); + } + fd = my_open(dev, !no_write, 0); + + if(!no_write && !no_reread) { + warn("Checking that no-one is using this disk right now ...\n"); + if(reread_ioctl(fd)) { + printf(" +This disk is currently in use - repartitioning is probably a bad idea. +Umount all file systems, and swapoff all swap partitions on this disk. +Use the --no-reread flag to suppress this check.\n"); + if (!force) { + printf("Use the --force flag to overrule all checks.\n"); + exit(1); + } + } else + warn("OK"); + } + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, 0); + get_partitions(dev, fd, z); + + printf("Old situation:\n"); + out_partitions(dev, z); + + if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0) + fatal("Partition %d does not exist, cannot change it\n", one_only); + + z = &newp; + + while(1) { + + read_input(dev, interactive, z); + + printf("New situation:\n"); + out_partitions(dev, z); + + if (!partitions_ok(z) && !force) { + if(!interactive) + fatal("I don't like these partitions - nothing changed.\n" + "(If you really want this, use the --force option.)\n"); + else + printf("I don't like this - probably you should answer No\n"); + } + ask: + if (interactive) { + if (no_write) + printf("Are you satisfied with this? [ynq] "); + else + printf("Do you want to write this to disk? [ynq] "); + answer = c = getchar(); + while (c != '\n' && c != EOF) + c = getchar(); + if (c == EOF) + printf("\nfdisk: premature end of input\n"); + if (c == EOF || answer == 'q' || answer == 'Q') { + fatal("Quitting - nothing changed\n"); + } else if (answer == 'n' || answer == 'N') { + continue; + } else if (answer == 'y' || answer == 'Y') { + break; + } else { + printf("Please answer one of y,n,q\n"); + goto ask; + } + } else + break; + } + + if(write_partitions(dev, fd, z)) + printf("Successfully wrote the new partition table\n\n"); + else + exit_status = 1; + + reread_disk_partition(dev, fd); + + warn("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n" + "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n" + "(See fdisk(8).)\n"); + + sync(); /* superstition */ + sleep(3); + exit(exit_status); +} diff --git a/disk-utils/sfdisk.examples b/disk-utils/sfdisk.examples new file mode 100644 index 00000000..13e671d4 --- /dev/null +++ b/disk-utils/sfdisk.examples @@ -0,0 +1,264 @@ +Examples of the use of sfdisk 3.0 (to partition a disk) +Input lines have fields ,,... - see sfdisk.8. +Usually no is given, and input lines start with a comma. + +Before doing anything with a disk, make sure it is not in use; +unmount all its file systems, and say swapoff to its swap partitions. +(The final BLKRRPART ioctl will fail if anything else still uses +the disk, and you will have to reboot. It is easier to first make +sure that nothing uses the disk, e.g., by testing: + % umount /dev/sdb1 + % sfdisk -R /dev/sdb + BLKRRPART: Device or resource busy + * Device busy for revalidation (usage=2) + % swapoff /dev/sdb3 + % sfdisk -R /dev/sdb + * sdb: sdb1 < sdb5 sdb6 > sdb3 + % +Note that the starred messages are kernel messages, that may be +logged somewhere, or written to some other console. +In sfdisk 3.01 sfdisk automatically does this check, unless told not to.) + +1. One big partition: + sfdisk /dev/hda << EOF + ; + EOF + +(If there was garbage on the disk before, you may get error messages +like: `ERROR: sector 0 does not have an msdos signature' +and `/dev/hda: unrecognized partition'. This does not matter +if you write an entirely fresh partition table anyway.) + +The output will be: +----------------------------------------------------------------------- +Old situation: +... +New situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 1023 1024- 208895+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 +----------------------------------------------------------------------- +Writing and rereading the partition table takes a few seconds - +don't be alarmed if nothing happens for six seconds or so. + + +2. Three primary partitions: two of size 50MB and the rest: + sfdisk /dev/hda -uM << EOF + ,50 + ,50 + ; + EOF +----------------------------------------------------------------------- +New situation: +Units = megabytes of 1048576 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 50- 51- 51203+ 83 Linux native +/dev/hda2 50+ 100- 51- 51204 83 Linux native +/dev/hda3 100+ 203 104- 106488 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 +----------------------------------------------------------------------- +/dev/hda1 is one block (in fact only half a block) shorter than +/dev/hda2 because its start had to be shifted away from zero in +order to leave room for the Master Boot Record (MBR). + + +3. A 1MB OS2 Boot Manager partition, a 50MB DOS partition, + and three extended partitions (DOS D:, Linux swap, Linux): + sfdisk /dev/hda -uM << EOF + ,1,a + ,50,6 + ,,E + ; + ,20,4 + ,16,S + ; + EOF +----------------------------------------------------------------------- + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 1- 2- 1223+ a OS/2 Boot Manager +/dev/hda2 1+ 51- 51- 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 51+ 203 153- 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 51+ 71- 21- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 71+ 87- 17- 16523+ 82 Linux swap +/dev/hda7 87+ 203 117- 119339+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 < hda5 hda6 hda7 > +----------------------------------------------------------------------- +All these rounded numbers look better in cylinder units: + % sfdisk -l /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native +----------------------------------------------------------------------- +But still - why does /dev/hda5 not start on a cylinder boundary? +Because it is contained in an extended partition that does. +Of the chain of extended partitions, usually only the first is +shown. (The others have no name under Linux anyway.) But +these additional extended partitions can be made visible: + % sfdisk -l -x /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty + +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M + - 358 1023 666 135864 5 Extended + - 257 256 0 0 0 Empty + - 257 256 0 0 0 Empty + +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap + - 439 1023 585 119340 5 Extended + - 358 357 0 0 0 Empty + - 358 357 0 0 0 Empty + +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty +----------------------------------------------------------------------- + +Why the empty 4th input line? The description of the extended partitions +starts after that of the four primary partitions. +You force an empty partition with a ",0" input line, but here all +space was divided already, so the fourth partition became empty +automatically. + +How did I know about 4,6,a,E,S? Well, E,S,L stand for Extended, +Swap and Linux. The other values are hexadecimal and come from +the table: + % sfdisk -T + Id Name + + 0 Empty + 1 DOS 12-bit FAT + 2 XENIX root + 3 XENIX usr + 4 DOS 16-bit FAT <32M + 5 Extended + 6 DOS 16-bit FAT >=32M + 7 OS/2 HPFS or QNX or Advanced UNIX + 8 AIX data + 9 AIX boot or Coherent + a OS/2 Boot Manager + ... + + +4. Preserving the sectors changed by sfdisk. + % sfdisk -O save-hdd-partition-sectors /dev/hda + ... + will write the sectors overwritten by sfdisk to file. + If you notice that you trashed some partition, you may + be able to restore things by + % sfdisk -I save-hdd-partition-sectors /dev/hda + % + +5. Preserving some old partitions. + % sfdisk -N2 /dev/hda + ... + will only change the partition /dev/hda2, and leave the rest + unchanged. The most obvious application is to change an Id: + % sfdisk -N7 /dev/hda + ,,63 + % +----------------------------------------------------------------------- +Old situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + +New situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 63 GNU HURD +----------------------------------------------------------------------- + Note that changing a logical partition into an empty partition + will decrease the number of all subsequent logical partitions. + +6. Deleting a partition. +At first I thought of having an option -X# for deleting partitions, +but there are several ways in which a partition can be deleted, and +it is probably better to handle this just as a general change. + % sfdisk -d /dev/hda > ohda +will write the current tables on the file `ohda'. +----------------------------------------------------------------------- +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 81600, size= 336192, Id=83 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +----------------------------------------------------------------------- +In order to delete the partition on /dev/hda3, edit this file +and feed the result to sfdisk again. +----------------------------------------------------------------------- +% emacs ohda +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 0, size= 0, Id= 0 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +% sfdisk /dev/hda < ohda +Old situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 200 1023 824 168096 83 Linux native +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +New situation: +Units = sectors of 512 bytes, counting from 0 + + Device Boot Start End #sectors Id System +/dev/hda1 1 40799 40799 5 Extended +/dev/hda2 40800 81599 40800 83 Linux native +/dev/hda3 0 - 0 0 Empty +/dev/hda4 0 - 0 0 Empty +/dev/hda5 2 40799 40798 83 Linux native +Successfully wrote the new partition table +% sfdisk -l -V /dev/hda + +Disk /dev/hda: 12 heads, 34 sectors, 1024 cylinders +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 0 - 0 0 0 Empty +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +/dev/hda: OK +----------------------------------------------------------------------- +This is a good way of making changes: dump the current status +to file, edit the file, and feed it to sfdisk. +Preserving the file on some other disk could be useful: +if ever the MBR gets thrashed it can be used to restore +the old situation. diff --git a/example.files/inittab b/example.files/inittab index d4a2177d..2095190f 100644 --- a/example.files/inittab +++ b/example.files/inittab @@ -2,9 +2,9 @@ # Format: # ttyline:termcap-entry:getty-command tty1:linux:/sbin/getty 9600 tty1 -tty2:console:/sbin/getty 9600 tty2 -tty3:console:/sbin/getty 9600 tty3 -tty4:console:/sbin/getty 9600 tty4 -tty5:console:/sbin/getty 9600 tty5 -tty6:console:/sbin/getty 9600 tty6 +tty2:linux:/sbin/getty 9600 tty2 +tty3:linux:/sbin/getty 9600 tty3 +tty4:linux:/sbin/getty 9600 tty4 +tty5:linux:/sbin/getty 9600 tty5 +tty6:linux:/sbin/getty 9600 tty6 ttyS1:vt100:/sbin/getty -Lh 19200 ttyS1 diff --git a/games/banner.c b/games/banner.c index 65d04e5d..6dcd0467 100644 --- a/games/banner.c +++ b/games/banner.c @@ -46,7 +46,7 @@ static char sccsid[] = "@(#)banner.c 8.3 (Berkeley) 4/2/94"; * banner [-w#] [-d] [-t] message ... */ -#include +#include "err.h" #include #include #include diff --git a/historic/frag.8 b/historic/frag.8 deleted file mode 100644 index c2f67b58..00000000 --- a/historic/frag.8 +++ /dev/null @@ -1,47 +0,0 @@ -.\" Copyright 1992,1993,1994 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH FRAG 8 "8 January 1994" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -frag \- simple fragmentation checker -.SH SYNOPSIS -.B /usr/sbin/frag -.B "[ \-s [ \-s ]]" -filename ... -.SH DESCRIPTION -.B frag -will report the file system fragmentation on a specified -.IR filename . -If the -.I filename -is a directory, -.B frag -will recursively descend the directory. -.SH OPTIONS -.TP -.B \-s -Silent (may be set to 1 or 2). The first -.B \-s -eliminates the file by file statistics, and just prints the -examined directories and a summary. The second -.B \-s -eliminates the printing of the directories, and just prints a -summary. This option is useful when -.B frag -is used on a directory. -.SH "SEE ALSO" -.BR mkfs (8), -.BR fsck (8), -.BR mkefs (8), -.BR efsck (8) -.SH BUGS -.B frag -will get caught in an infinite loop in the /proc filesystem. -.SH AUTHORS -V1.0 by Werner Almesberger -.br -V1.1 by Steffen Zahn, adding directory recursion -.br -V1.2 by Rob Hooft, adding hole counts -.br -V1.3 by Steffen Zahn, ignore symlinks, -don't cross filesys borders, get filesystem block size at runtime diff --git a/historic/frag.c b/historic/frag.c deleted file mode 100644 index 0098e02f..00000000 --- a/historic/frag.c +++ /dev/null @@ -1,311 +0,0 @@ -/* frag.c - simple fragmentation checker - V1.0 by Werner Almesberger - V1.1 by Steffen Zahn, adding directory recursion - V1.2 by Rob Hooft, adding hole counts - V1.3 by Steffen Zahn, email: szahn%masterix@emndev.siemens.co.at - 14 Nov 93 - - ignore symlinks, - - don't cross filesys borders - - get filesystem block size at runtime - V1.4 by Michael Bischoff to handle - indirect blocks better, but only for ext2fs - (applied by faith@cs.unc.edu, Sat Feb 4 22:06:27 1995) - - TODO: - handle hard links - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for FIBMAP */ - -typedef struct StackElem { - struct StackElem *backref, *next; - char name[NAME_MAX]; - char dir_seen; - char from_cmd_line; -} StackElem; - -StackElem *top = NULL; - - -void discard( void ) -{ - StackElem *se = top; - if( se == NULL ) - return ; - top = se->next; - free(se); -} - -void push( StackElem * se ) -{ - se -> next = top; - top = se; -} - -char *p2s( StackElem *se, char *path ) -{ - char *s; - if( se->backref!=NULL ) { - path = p2s( se->backref, path ); - if( path[-1]!='/' ) - *path++ = '/'; - } - s = se->name; - while( *s ) - *path++ = *s++; - return path; -} - -char *path2str( StackElem *se, char *path ) -{ - *(p2s( se, path ))=0; - return path; -} - -void *xmalloc( size_t size ) -{ - void *p; - if( (p=malloc(size))==NULL ) { - fprintf(stderr,"\nvirtual memory exhausted.\n"); - exit(1); - } - return p; -} - -int main(int argc,char **argv) -{ - int fd,last_phys_block, - fragments_in_file, blocks_in_file, - blocks,current_phys_block, - this_fragment, largest_fragment, i; - long sum_blocks=0, sum_frag_blocks=0, sum_files=0, sum_frag_files=0; - long num_hole=0, sum_hole=0, hole; - struct stat st; - struct statfs stfs; - StackElem *se, *se1; - char path[PATH_MAX], pathlink[PATH_MAX], *p; - DIR *dir; - struct dirent *de; - char silent_flag=0; - dev_t local_fs; - int block_size; - - if (argc < 2) - { - fprintf(stderr,"usage: %s [-s [-s]] filename ...\n",argv[0]); - exit(1); - } - argc--; argv++; - while (argc>0) - { - p = *argv; - if( *p=='-' ) - while( *++p ) - switch( *p ) - { - case 's': - silent_flag++; /* may be 1 or 2 */ - break; - default: - fprintf(stderr,"\nunknown flag %c\n", *p ); - exit(1); - } - else - { - se = xmalloc( sizeof(StackElem) ); - se->backref=NULL; se->dir_seen=0; se->from_cmd_line=1; - strcpy( se->name, p ); - push(se); - } - argc--; argv++; - } - while ( top != NULL) - { - se = top; - if( se->dir_seen ) - discard(); - else - { - path2str( se, path ); - if( readlink( path, pathlink, sizeof(pathlink) )>=0 ) - { /* ignore symlinks */ - if(silent_flag<1) - { - printf("symlink %s\n", path ); - } - discard(); - } - else if( stat( path,&st) < 0) - { - perror( path ); - discard(); - } - else if( !se->from_cmd_line && (local_fs!=st.st_dev) ) - { /* do not cross filesystem borders */ - if(silent_flag<2) - { - printf("different filesystem %s\n", path ); - } - discard(); - } - else - { - if( se->from_cmd_line ) - { - local_fs = st.st_dev; - if ( statfs( path, &stfs )<0 ) - { - perror( path ); - block_size = 1024; - } - else - block_size = stfs.f_bsize; - } - if( S_ISREG(st.st_mode)) /* regular file */ - { - if ( (fd = open( path ,O_RDONLY)) < 0 ) - { - perror( path ); - discard(); - } - else - { - last_phys_block = -1; - fragments_in_file = 0; - hole = 0; this_fragment=0; - largest_fragment=0; - blocks_in_file = (st.st_size+block_size-1)/block_size; - for (blocks = 0; blocks < blocks_in_file; blocks++) - { - current_phys_block = blocks; - if (ioctl(fd,FIBMAP,¤t_phys_block) < 0) - { - perror(path); - break; - } - if (current_phys_block) { /* no hole here */ - int indirect; - /* indirect is the number of indirection */ - /* blocks which must be skipped */ - indirect = 0; - /* every 256 blocks there is an indirect block, - the first of these is before block 12 */ - if (blocks >= 12 && (blocks-12) % 256 == 0) - ++indirect; - /* there is a block pointing to the indirect - blocks every 64K blocks */ - if (blocks >= 256+12 && (blocks-256-12) % 65536 == 0) - ++indirect; /* 2nd indirect block */ - /* there is a single triple indirect block */ - if (blocks == 65536 + 256 + 12) - ++indirect; - if (last_phys_block == current_phys_block-1-indirect) - this_fragment++; - else { /* start of first or new fragment */ - if( largest_fragment1 ) - { - sum_frag_blocks+=blocks_in_file-largest_fragment; - sum_frag_files++; - } - discard(); - close(fd); - } - } - else if( S_ISDIR( st.st_mode ) ) /* push dir contents */ - { - if( (dir=opendir( path ))==NULL ) - { - perror(path); - discard(); - } - else - { - if( silent_flag<2 ) - printf("reading %s\n", path); - while( (de=readdir(dir))!=NULL ) - { - if( (strcmp(de->d_name,".")!=0) - && (strcmp(de->d_name,"..")!=0) ) - { - se1 = xmalloc( sizeof(StackElem) ); - se1->backref=se; se1->dir_seen=0; - se1->from_cmd_line=0; - strcpy( se1->name, de->d_name ); - push(se1); - } - } - closedir( dir ); - se->dir_seen=1; - } - } - else /* if( S_ISREG(st.st_mode)) */ - discard(); - } - } /* if( se->dir_seen ) */ - } /* while ( top != NULL) */ - if (sum_files>1) - { - printf("\nsummary:\n"); - printf(" %3ld%% file fragmentation (%ld of %ld files contain fragments)\n", - sum_files<1 ? 0L : sum_frag_files*100/sum_files, - sum_frag_files, sum_files); - printf(" %3ld%% block fragmentation (%ld of %ld blocks are in fragments)\n", - sum_blocks<1 ? 0L : sum_frag_blocks*100/sum_blocks, - sum_frag_blocks, sum_blocks); - if (num_hole>1) - printf(" %ld files contain %ld blocks in holes\n", - num_hole,sum_hole); - } - exit(0); -} diff --git a/historic/lpcntl.8 b/historic/lpcntl.8 deleted file mode 100644 index 87bcd039..00000000 --- a/historic/lpcntl.8 +++ /dev/null @@ -1,30 +0,0 @@ -.\" Public Domain 1994 Rik Faith (faith@cs.unc.edu) -.\" " -.TH LPCNTL 8 "18 July 1994" "Linux 1.1" "Linux Programmer's Manual" -.SH NAME -lpcntl \- interface to line printer ioctl -.SH SYNOPSIS -.BI "lpcntl " device " [ " irq " ]" -.SH DESCRIPTION -.B lpcntl -is used to manipulate the line printer driver. -.PP -.I device -specifies a line printer device (e.g., -.IR /dev/lp1 ). -.PP -If -.I irq -is specified, then the line printer driver is set to use that IRQ. If the -.I irq -is zero, then the polling driver is selected. Only the super user may -change the IRQ. -.PP -If no -.I irq -is specified, then -.B lpcntl -will report the interrupt number currently in use, or will report that the -polling driver is currently being used. -.SH AUTHOR -Nigel Gamble (nigel@gate.net) diff --git a/historic/lpcntl.c b/historic/lpcntl.c deleted file mode 100644 index bf164a63..00000000 --- a/historic/lpcntl.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Simple command interface to ioctl(fd, LPSETIRQ, irq). - * Nigel Gamble (nigel@gate.net) - * e.g. - * lpcntl /dev/lp1 7 - */ - -#include -#include -#include -#include - -int -main(int argc, char **argv) -{ - unsigned int irq; - int fd; - int ret; - - if (argc < 2) { - fprintf(stderr, "usage: %s []\n", argv[0]); - exit(1); - } - - fd = open(argv[1], O_RDONLY); - if (fd == -1) { - perror(argv[1]); - exit(1); - } - - if (argc == 2) { - irq = ioctl(fd, LPGETIRQ); - if (irq == -1) { - perror(argv[1]); - exit(1); - } - if (irq) - printf("%s using IRQ %d\n", argv[1], irq); - else - printf("%s using polling\n", argv[1]); - } else { - irq = atoi(argv[2]); - ret = ioctl(fd, LPSETIRQ, irq); - if (ret == -1) { - if (errno == EPERM) - fprintf(stderr, "%s: only super-user can change the IRQ\n", argv[0]); - else - perror(argv[1]); - exit(1); - } - } - - return 0; -} diff --git a/historic/makehole.8 b/historic/makehole.8 deleted file mode 100644 index 5b5c63be..00000000 --- a/historic/makehole.8 +++ /dev/null @@ -1,44 +0,0 @@ -.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH MAKEHOLE 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -makehole \- a program to make filesystem "holes" in pure executables -.SH SYNOPSIS -.B makehole -Imagefile -.SH DESCRIPTION -.B makehole -copies the -.IR Imagefile , -using -.BR lseek (2) -to skip over sections of the file which contain all zeros. If the file -system is smart enough to recognize this use of -.BR lseek (2), -then it will store the file in a more efficient fashion. - -The logical length of the file will -.I not -be changed, only the way it is stored in the filesystem. This can save a -lot of space if the file contains large blocks of zeros. -.BR cp (3) -will not similar "hole creation," but it does not seem to be as extensive -(see the GNU source code for details). -.BR dd (3) -will -.I not -create holes, and should be used when holes are not desired (i.e., for the -.BR shoelace (8) -boot image). -.SH "SEE ALSO" -.BR lseek (2), -.BR cp (3), -.BR dd (3) -.SH BUGS -Must be root to run. -.br -The -.I Imagefile -must be a pure exectuable. -.SH AUTHOR -HJ Lu diff --git a/historic/makehole.c b/historic/makehole.c deleted file mode 100644 index 6c337db0..00000000 --- a/historic/makehole.c +++ /dev/null @@ -1,140 +0,0 @@ -/* makehole.c - original by HJ Lu */ - -/* Patched by faith@cs.unc.edu, Wed Oct 6 18:01:39 1993 based on - information from Michael Bischoff (Fri, 18 - Jun 93 10:10:19 +0200). */ - -#include -#include -#include -#include -#include -#include - -#define BUFSIZE 1024 -#undef DEBUG - -void usage(char *name, char *message) -{ - if (message) - fprintf(stderr, "%s: %s\n", name, message); - - if (errno) - perror(name); - - fprintf(stderr, "Usage:%s Imagefile\n", name); - exit(1); -} - -int ishole(char *buf, int size) -{ - int i; - - for (i = 0; i < size; i++) - if (buf[i]) - return 0; - - return 1; -} - -void main(int argc, char *argv[]) -{ - char buf[BUFSIZE]; - char tmp_file[64]; - int fdin, fdout; - int ret; - int abs_offset; - int hole; - struct exec *header = (struct exec *) buf; - -#ifndef DEBUG - if (geteuid()) { - fprintf(stderr, "%s: must be root to run!\n", *argv); - exit(1); - } -#endif - - switch (argc) { - case 2: - break; - default: - usage(*argv, NULL); - } - - errno = 0; - - sprintf( tmp_file, "hole%d", getpid() ); - if (tmp_file == NULL) { - usage(*argv, "Unable to get a temporary image filename!"); - } -#ifdef DEBUG - else { - fprintf(stderr, "Temparory image file: %s\n", tmp_file); - } -#endif - - errno = 0; - fdin = open(argv[1], O_RDONLY); - if (fdin == -1) { - usage(*argv, "unable to open file."); - } - fprintf(stderr, "Making holes in %s...\n", argv[1]); - - errno = 0; - - if ((ret = read(fdin, header, BUFSIZE)) != BUFSIZE - || N_MAGIC(*header) != ZMAGIC) { - usage(*argv, "file must be pure executable."); - } - - fdout = creat(tmp_file, 0555); - if (fdout == -1) { - perror("Unable to create the temparory image file!"); - exit(1); - } - if (write(fdout, header, ret) != ret) { - perror("Fail to write header to the temparory image file!"); - unlink(tmp_file); - exit(1); - } - abs_offset = ret; - hole = 0; - while ((ret = read(fdin, buf, BUFSIZE)) > 0) { - abs_offset += ret; - if (ishole(buf, ret)) { -#ifdef DEBUG - fprintf(stderr, "There is a %d byte hole from 0x%x to 0x%x.\n", ret, abs_offset - ret, abs_offset); -#endif - hole += ret; - if (lseek(fdout, abs_offset, SEEK_SET) != abs_offset) { - perror("Fail to make a hole in the temparory image file!"); - unlink(tmp_file); - exit(1); - } - } else { -#ifdef DEBUG - fprintf(stderr, "Writing %d bytes from 0x%x to 0x%x.\n", ret, abs_offset - ret, abs_offset); -#endif - if (write(fdout, buf, ret) != ret) { - perror("Fail to write the temparory image file!"); - unlink(tmp_file); - exit(1); - } - } - } - - if (ftruncate(fdout, abs_offset)) { - perror("Fail to truncate the temparory image file!"); - unlink(tmp_file); - exit(1); - } - close(fdout); - close(fdin); - - if (rename(tmp_file, argv[1])) { - perror("Fail to rename the temparory image file to the old image file!"); - unlink(tmp_file); - exit(1); - } - fprintf(stderr, "There are %d byte holes out of %d bytes in `%s'.\n", hole, abs_offset, argv[1]); -} diff --git a/historic/makeinfo.sh b/historic/makeinfo.sh deleted file mode 100644 index 9061c833..00000000 --- a/historic/makeinfo.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -emacs -batch $* -f texinfo-format-buffer -f save-buffer diff --git a/historic/mesg.1 b/historic/mesg.1 deleted file mode 100644 index 81932dfd..00000000 --- a/historic/mesg.1 +++ /dev/null @@ -1,24 +0,0 @@ -.\" Original author: Miquel van Smoorenburg, miquels@drinkel.nl.mugnet.org -.\" Updated by faith@cs.unc.edu, Fri Oct 29 23:22:16 1993 -.TH MESG 1 "29 October 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -mesg \- control write access to your terminal -.SH SYNOPSIS -.B mesg -.RB [y|n] -.br -.SH DESCRIPTION -.B Mesg -controls the access to your terminal by others. It's typically used -to allow/disallow others users to \fBwrite(1)\fP to your terminal. -.SH FLAGS -.IP y -Allow write access to your terminal. -.IP n -Disallow write access to your terminal. -.IP [none] -Prints out the current access state of your terminal. -.SH SEE ALSO -.BR write (1), wall (1) -.SH AUTHOR -Miquel van Smoorenburg, miquels@drinkel.nl.mugnet.org diff --git a/historic/mesg.c b/historic/mesg.c deleted file mode 100644 index 07c5fad1..00000000 --- a/historic/mesg.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * mesg.c The "mesg" utility. Gives / restrict access to - * your terminal by others. - * - * Usage: mesg [y|n]. - * Without arguments prints out the current settings. - */ -#include -#include -#include -#include -#include - -char *Version = "@(#) mesg 1.0 08-12-92 MvS"; - -int main(int argc, char **argv) -{ - struct stat st; - - if (!isatty(0)) { - /* Or should we look in /etc/utmp? */ - fprintf(stderr, "stdin: is not a tty"); - return(1); - } - - if (fstat(0, &st) < 0) { - perror("fstat"); - return(1); - } - if (argc < 2) { - printf("Is %s\n", ((st.st_mode & 022) == 022) ? "y" : "n"); - return(0); - } - if (argc > 2 || (argv[1][0] != 'y' && argv[1][0] != 'n')) { - fprintf(stderr, "Usage: mesg [y|n]\n"); - return(1); - } - if (argv[1][0] == 'y') - st.st_mode |= 022; - else - st.st_mode &= ~022; - fchmod(0, st.st_mode); - return(0); -} diff --git a/historic/mkfs.c b/historic/mkfs.c deleted file mode 100644 index 018a5384..00000000 --- a/historic/mkfs.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * fs-util A simple generic frontend for the for the fsck and mkfs - * programs under Linux. See the manual pages for details. - * - * Usage: fsck [-AV] [-t fstype] [fs-options] device - * mkfs [-V] [-t fstype] [fs-options] device< [size] - * - * Authors: David Engel, - * Fred N. van Kempen, - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifndef DEFAULT_FSTYPE -# define DEFAULT_FSTYPE "minix" -#endif - -#define _PATH_PROG "%s.%s" -#define _PROG_FSCK "fsck" - -#define EXIT_OK 0 -#define EXIT_NONDESTRUCT 1 -#define EXIT_DESTRUCT 2 -#define EXIT_UNCORRECTED 4 -#define EXIT_ERROR 8 -#define EXIT_USAGE 16 -#define EXIT_LIBRARY 128 - -static char *Version = "1.8"; -static char *ignored_types[] = { - "ignore", - "iso9660", - "msdos", - "nfs", - "proc", - "sw", - "swap", - NULL -}; - - -/* Execute a program. */ -int do_exec(char *prog, char **argv, int verbose) -{ - char *args[33]; - register int i; - int pid, status; - - /* Build the vector. */ - i = 0; - args[i++] = prog; - while(*argv != NULL && i < 32) - args[i++] = *argv++; - args[i] = NULL; - - if (verbose) { - i = 0; - while(args[i] != NULL) { - printf("%s ", args[i]); - i++; - } - printf("\n"); - if (verbose > 1) - return EXIT_OK; - } - - /* Fork and execute the correct program. */ - if ((pid = fork()) < 0) { - perror("fork"); - status = EXIT_ERROR; - } else if (pid == 0) { - (void) execvp(args[0], args); - perror(args[0]); - exit(EXIT_ERROR); - } else { - while(wait(&status) != pid) - ; - status = WEXITSTATUS(status); - } - - return status; -} - - -/* Check if we have to ignore a file system type. */ -int ignore(char *type, char *opts) -{ - char *cp; - char **ip; - - ip = ignored_types; - while (*ip != NULL) { - if (!strcmp(type, *ip)) - return 1; - ip++; - } - - for (cp = strtok(opts, ","); cp != NULL; cp = strtok(NULL, ",")) { - if (!strcmp(cp, "noauto")) - return 1; - } - - return 0; -} - - -/* Check all file systems, using the /etc/fstab table. */ -int check_all(int verbose, char **argv) -{ - char path[PATH_MAX]; - char *args[33]; - FILE *mntfile; - struct mntent *mp; - register int i; - int status = EXIT_OK; - - if (verbose) - printf("Checking all file systems.\n"); - - /* Create an array of arguments. */ - i = 0; - while (*argv != NULL && i < 32) - args[i++] = *argv++; - args[i] = NULL; - args[i + 1] = NULL; - - /* Open the mount table. */ - if ((mntfile = setmntent(MNTTAB, "r")) == NULL) { - perror(MNTTAB); - exit(EXIT_ERROR); - } - - /* Walk through the /etc/fstab file. */ - while ((mp = getmntent(mntfile)) != NULL) { - if (verbose) - printf("%-7s %-15s %-15s ", mp->mnt_type, - mp->mnt_fsname, mp->mnt_dir); - if (ignore(mp->mnt_type, mp->mnt_opts)) { - if (verbose) - printf("(ignored)\n"); - continue; - } - - /* Build program name. */ - sprintf(path, _PATH_PROG, _PROG_FSCK, mp->mnt_type); - args[i] = mp->mnt_fsname; - status |= do_exec(path, args, verbose); - } - - (void) endmntent(mntfile); - - return status; -} - - -/* Lookup filesys in /etc/fstab and return the corresponding entry. */ -struct mntent *lookup(char *filesys) -{ - FILE *mntfile; - struct mntent *mp; - - /* No filesys name given. */ - if (filesys == NULL) - return NULL; - - /* Open the mount table. */ - if ((mntfile = setmntent(MNTTAB, "r")) == NULL) { - perror(MNTTAB); - exit(EXIT_ERROR); - } - - while ((mp = getmntent(mntfile)) != NULL) { - if (!strcmp(filesys, mp->mnt_fsname) || - !strcmp(filesys, mp->mnt_dir)) - break; - } - - (void) endmntent(mntfile); - - return mp; -} - - -void usage(int fsck, char *prog) -{ - if (fsck) { - fprintf(stderr, "Usage: fsck [-AV] [-t fstype] [fs-options] filesys\n"); - } else { - fprintf(stderr, "Usage: mkfs [-V] [-t fstype] [fs-options] filesys [size]\n"); - } - - exit(EXIT_USAGE); -} - - -void main(int argc, char *argv[]) -{ - char path[PATH_MAX]; - char *oldpath, newpath[PATH_MAX]; - register char *sp; - struct mntent *fsent; - char *fstype = NULL; - int verbose = 0; - int doall = 0; - int i, fsck, more; - - /* Must be 1 for "fsck" and 0 for "mkfs". */ - if ((sp = strrchr(argv[0], '/')) != NULL) - sp++; - else - sp = argv[0]; - if (!strcmp(sp, _PROG_FSCK)) - fsck = 1; - else - fsck = 0; - - /* Check commandline options. */ - opterr = 0; - more = 0; - while ((more == 0) && ((i = getopt(argc, argv, "AVt:")) != EOF)) - switch(i) { - case 'A': - doall++; - break; - case 'V': - verbose++; - break; - case 't': - if (optarg == NULL) - usage(fsck, sp); - fstype = optarg; - break; - default: - more = 1; - break; /* start of specific arguments */ - } - - /* Did we get any specific arguments? */ - if (more) - optind--; - - /* Print our version number if requested. */ - if (verbose) - printf("%s (fsutil) version %s (%s)\n", argv[0], - Version, __DATE__); - - /* Update our PATH to include /etc/fs and /etc. */ - strcpy(newpath, "PATH=/etc/fs:/etc:"); - if ((oldpath = getenv("PATH")) != NULL) - strcat(newpath, oldpath); - putenv(newpath); - - /* If -A was specified ("check all"), double-check. */ - if (doall) { - if (!fsck || (fstype != NULL)) - usage(fsck, sp); - exit(check_all(verbose, &argv[optind])); - } else { - /* If -t wasn't specified, we must deduce fstype. */ - if (fstype == NULL) { - /* make sure that "filesys" was specified */ - if (optind >= argc) - usage(fsck, sp); - /* then try looking for it in /etc/fstab */ - if ((fsent = lookup(argv[argc - 1])) != NULL) { - argv[argc - 1] = fsent->mnt_fsname; - fstype = fsent->mnt_type; - } else { - if (!fsck && optind < argc-1) { - if ((fsent = lookup(argv[argc - 2])) != NULL) { - argv[argc - 2] = fsent->mnt_fsname; - fstype = fsent->mnt_type; - } - } - } - /* if we still don't know, use the default */ - if (fstype == NULL) fstype = DEFAULT_FSTYPE; - } - - /* Build program name. */ - sprintf(path, _PATH_PROG, sp, fstype); - exit(do_exec(path, &argv[optind], verbose)); - } - /*NOTREACHED*/ -} diff --git a/historic/mkswap.8 b/historic/mkswap.8 deleted file mode 100644 index 2c02fbbe..00000000 --- a/historic/mkswap.8 +++ /dev/null @@ -1,86 +0,0 @@ -.\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.\" Modified with suggestions from Linus, Mon Feb 1 21:40:49 1993 -.\" Modified with patches from Kai, Wed Jun 22 21:54:56 1994 -.\" Patches from jaggy@purplet.demon.co.uk (Mike Jagdis), Wed Feb 8 1995 -.\" Added comments from Nick Holloway, Sat Feb 11 1995, faith@cs.unc.edu -.\" " -.TH MKSWAP 8 "8 February 1995" "Linux 1.0" "Linux Programmer's Manual" -.SH NAME -mkswap \- set up a Linux swap device -.SH SYNOPSIS -.B "mkswap [ \-c ]" -.IB device " [" size-in-blocks "]" -.SH DESCRIPTION -.B mkswap -sets up a Linux swap area on a device (usually a disk partition). - -The -.I device -is usually of the following form: - -.nf -.RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] -.RE -.fi - -The -.I size-in-blocks -parameter is the desired size of the file system, in blocks. This -information is determined automatically by mkswap if it is omitted. Block -counts are rounded down to pages of 4 kB each. Only block counts equal to -or greater than 40 and equal to or less than 131072 are allowed. Block -counts greater than 130752 are (silently) rounded down to 130752. - -As Nick Holloway explains, the actual maximum for each swap file/partition -is: -.RS -(4096 - 10) * 8 * 4096 = 133890048 bytes = 130752 blocks = 127.6875 Mb -.RE -This is because a single page is used to hold the swap bitmap at the -start of the partition, where each bit is a single 4K page. The reason -for the -10, is that the signature is "SWAP-SPACE" -- 10 characters. - -.B mkswap -can also set up swap files, although the file has to be created first. A -sequence of commands similar to the following is reasonable for this -purpose: - -.nf -.RS -# dd if=/dev/zero of=swapfile bs=1024 count=8192 -# mkswap swapfile 8192 -# sync -# swapon swapfile -.RE -.fi - -Note that the regular file has to be created before running -.B mkswap -on the file, and that the file must not contain any holes (so, using -.BR cp (1) -to create the file is not acceptable). - -.SH OPTIONS -.TP -.B \-c -Check the device for bad blocks before creating the file system. If any -are found, the count is printed. This option is meant to be used for swap -partitions -.BR only , -and should -.B not -be used for regular files! To make sure that regular files do not contain -bad blocks, the partition that contains the regular file should have been -created with -.BR "mkfs -c" . -.SH "SEE ALSO" -.BR fsck (8), -.BR mkfs (8), -.BR fdisk (8) -.SH AUTHOR -Linus Torvalds (torvalds@cs.helsinki.fi) diff --git a/historic/mkswap.c b/historic/mkswap.c deleted file mode 100644 index bb4e2249..00000000 --- a/historic/mkswap.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * mkswap.c - set up a linux swap device - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * 20.12.91 - time began. Got VM working yesterday by doing this by hand. - * - * Usuage: mkswap [-c] device [size-in-blocks] - * - * -c for readablility checking (use it unless you are SURE!) - * - * The device may be a block device or a image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - * - * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the - * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#ifndef __GNUC__ -#error "needs gcc for the bitop-__asm__'s" -#endif - -#ifndef __linux__ -#define volatile -#endif - -#define TEST_BUFFER_PAGES 8 - -static char * program_name = "mkswap"; -static char * device_name = NULL; -static int DEV = -1; -static long PAGES = 0; -static int check = 0; -static int badpages = 0; - -static char signature_page[PAGE_SIZE]; - -#define bitop(name,op) \ -static inline int name(char * addr,unsigned int nr) \ -{ \ -int __res; \ -__asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ -:"=g" (__res) \ -:"r" (nr),"m" (*(addr)),"0" (0)); \ -return __res; \ -} - -bitop(bit,"") -bitop(setbit,"s") -bitop(clrbit,"r") - -/* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. - */ -volatile void fatal_error(const char * fmt_string) -{ - fprintf(stderr,fmt_string,program_name,device_name); - exit(1); -} - -#define usage() fatal_error("Usage: %s [-c] /dev/name [blocks]\n") -#define die(str) fatal_error("%s: " str "\n") - -void check_blocks(void) -{ - unsigned int current_page; - int do_seek = 1; - static char buffer[PAGE_SIZE]; - - current_page = 0; - while (current_page < PAGES) { - if (!check) { - setbit(signature_page,current_page++); - continue; - } - if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != - current_page*PAGE_SIZE) - die("seek failed in check_blocks"); - if (do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE))) { - clrbit(signature_page,current_page++); - badpages++; - continue; - } - setbit(signature_page,current_page++); - } - if (badpages) - printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); -} - -static long valid_offset (int fd, int offset) -{ - char ch; - - if (lseek (fd, offset, 0) < 0) - return 0; - if (read (fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int count_blocks (int fd) -{ - int high, low; - - low = 0; - for (high = 1; valid_offset (fd, high); high *= 2) - low = high; - while (low < high - 1) - { - const int mid = (low + high) / 2; - - if (valid_offset (fd, mid)) - low = mid; - else - high = mid; - } - valid_offset (fd, 0); - return (low + 1); -} - -static int get_size(const char *file) -{ - int fd; - int size; - - fd = open(file, O_RDWR); - if (fd < 0) { - perror(file); - exit(1); - } - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); - } - - size = count_blocks(fd); - close(fd); - return size; -} - -int main(int argc, char ** argv) -{ - char * tmp; - struct stat statbuf; - int goodpages; - - memset(signature_page,0,PAGE_SIZE); - if (argc && *argv) - program_name = *argv; - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') - if (device_name) { - PAGES = strtol(argv[0],&tmp,0)>>2; - if (*tmp) - usage(); - } else - device_name = argv[0]; - else while (*++argv[0]) - switch (argv[0][0]) { - case 'c': check=1; break; - default: usage(); - } - } - if (device_name && !PAGES) { - PAGES = get_size(device_name) / PAGE_SIZE; - } - if (!device_name || PAGES<10) - usage(); - if (PAGES > 32688) /* 130752 blocks */ - PAGES=32688; -#if 0 - if (PAGES > 32768) - PAGES=32768; -#endif - DEV = open(device_name,O_RDWR); - if (DEV < 0 || fstat(DEV, &statbuf) < 0) { - perror(device_name); - exit(1); - } - if (!S_ISBLK(statbuf.st_mode)) - check=0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - die("Will not try to make swapdevice on '%s'"); - check_blocks(); - if (!clrbit(signature_page,0)) - die("fatal: first page unreadable"); - goodpages = PAGES - badpages - 1; - if (!goodpages) - die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace, size = %d bytes\n",goodpages*PAGE_SIZE); - strncpy(signature_page+PAGE_SIZE-10,"SWAP-SPACE",10); - if (lseek(DEV, 0, SEEK_SET)) - die("unable to rewind swap-device"); - if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) - die("unable to write signature page"); - return 0; -} diff --git a/historic/selection/Makefile b/historic/selection/Makefile deleted file mode 100644 index 4195d79d..00000000 --- a/historic/selection/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -# Makefile for selection utility -# Andrew Haylett, 17th June 1993 -# Minor modifications by Rik Faith (faith@cs.unc.edu), Sat Nov 20 09:47:59 1993 - -# bump .., since we live in historic now -include ../../MCONFIG -BINDIR = $(USRBINDIR) -MANEXT = 1 - -all: selection test-mouse - -selection: selection.o mouse.o - $(CC) $(LDFLAGS) -o selection selection.o mouse.o - -test-mouse: test-mouse.o mouse.o - $(CC) $(LDFLAGS) -o test-mouse test-mouse.o mouse.o - -mouse.o: mouse.c mouse.h - -selection.o: selection.c mouse.h Makefile - -test-mouse.o: test-mouse.c mouse.h - -selection.man: selection.1 - nroff -man selection.1 > selection.man - -install: selection # selection.man - $(INSTALLDIR) $(USRBINDIR) $(MAN1DIR) - $(INSTALLBIN) selection $(USRBINDIR) - $(INSTALLMAN) selection.1 $(MAN1DIR) - -DIST = selection-1.5 -DATE = 17th June 1993 -PATCH = patch-0.99.10 -SRC = README Makefile selection.1 mouse.c mouse.h selection.c test-mouse.c -DFILES = $(SRC) selection.man $(PATCH) -DIFF = diff -DFLAGS = -u - -patch: - (cd /usr/src/linux; \ - $(DIFF) -c0 $(DFLAGS) config.in~ config.in; \ - $(DIFF) $(DFLAGS) kernel/chr_drv/tty_ioctl.c~ kernel/chr_drv/tty_ioctl.c; \ - $(DIFF) $(DFLAGS) kernel/chr_drv/console.c~ kernel/chr_drv/console.c) \ - > $(PATCH); true - -update: - perl -pi -e 's/\d+\S+ \S+ 199[3]/$(DATE)/' $(SRC) - -dist: update patch $(DFILES) - rm -fr $(DIST) - mkdir $(DIST) - cp $(DFILES) $(DIST) - tar cf - $(DIST) | gzip -c > $(DIST).tar.z - rm -fr $(DIST) - -clean: - rm -f selection.o mouse.o test-mouse.o selection test-mouse \ - selection.man *~ diff --git a/historic/selection/README.selection b/historic/selection/README.selection deleted file mode 100644 index 7435161d..00000000 --- a/historic/selection/README.selection +++ /dev/null @@ -1,151 +0,0 @@ - selection 1.5: Copy and paste for Linux Virtual Consoles using mouse - -------------------------------------------------------------------- - -This package implements mouse-driven selection of text from a VC and pasting -of the text into the same or a different VC, the user interface being based -loosely on the equivalent xterm facility. - -Version 1.5 ------------ - - fixed support for bus mice. - - added support for PS/2 and Mouse Systems 3-byte mice. - - command line options added. - - updated for kernel version 0.99.pl10. - - cooperates with XFree86 1.2, for serial mice at least. - - enabled as part of normal kernel configuration process. - -Version 1.4 ------------ - - added manual page. - - updated for kernel version 0.99.pl0. - -Version 1.3 ------------ - - improved support for Logitech mice (speed set correctly). - - optional flag for left-handed users. - - corrected bug in Mouse Systems handling code. - -Version 1.2 ------------ - - disabled when console in graphics mode, eg. under X11 or MGR. - - uses default screen size if ioctl TIOCGWINSZ fails. - -Version 1.1 ------------ - - support for some common mouse types. - - selection by word or line as well as by character. - - changes in the interface to make it behave more like xterm. - -Manifest --------- - README - Makefile - selection.1 manual page - selection.man formatted manual page - patch-0.99.10 patches to kernel - mouse.c source for mouse driver - mouse.h mouse driver interface - selection.c source for selection manager - test-mouse.c test code for mouse compatibility - -Mouse support -------------- - -The following types of mouse are supported. - - - Microsoft - - MouseSystems 3-byte and 5-byte - - MM Series - - Logitech - - BusMouse - - PS/2 - -The code has been tested with various types of mice, including -Microsoft-compatible and Logitech, a three-button Mouse Systems, and with bus -and PS/2 mice; please tell me if it doesn't work with yours and you think it -ought to. - -Installation ------------- - -1. Check it out ---------------- - - - Make the mouse device. If you have a serial mouse, either use `mknod' to - make /dev/mouse reference the appropriate serial driver or create a - symbolic link from /dev/ttys? to /dev/mouse. If you have a bus mouse, - use `mknod' to create the bus mouse device if it doesn't already exist. - Make sure that your kernel is configured to support the appropriate - bus mouse device (specified during `make config'). - -e.g. mknod /dev/mouse c 4 64 -or ln -s /dev/ttys1 /dev/mouse (for serial mouse) - - mknod /dev/busmouse c 10 0 (for Logitech bus mouse) - - - Test your mouse for compatibility by using the test-mouse facility - supplied. Build it by typing `make test-mouse', then run `test-mouse'. - You may need to supply it with certain options; try `test-mouse -?'. - If your mouse device is not /dev/mouse, use the -m option. You should - be able to move the cursor over the entire screen, and draw - asterisks in different colours by moving the mouse while pressing - different buttons. Press both the left and right buttons while the mouse - is not moving to quit the program. The options that you find work with - `test-mouse' should also work with `selection'. - -2. Patch the kernel -------------------- - - [ NOTE: Precompiled versions of the kernel supplied with the SLS - package should already have the patch applied, in which case this - section may be skipped. ] - - - Apply the kernel patches, by going into the directory in which the - kernel source is located (eg. /usr/src/linux) and typing: - - patch < patch-0.99.10 - - The patches were generated against the standard 0.99.pl10 kernel. - -The following files are patched: - - config.in to add the selection mechanism as a - configuration option. - - kernel/chr_drv/tty_ioctl.c to provide the interface to the selection - mechanism via ioctl(..., TCIOLINUX, ...). - - kernel/chr_drv/console.c to implement the selection mechanism itself. - - - Reconfigure the kernel by typing 'make config', remembering to include - the selection mechanism by answering 'y' to the appropriate question. - - - To be safe, rebuild the kernel dependencies using 'make dep'. - - - Rebuild the kernel and reboot. - - - Make sure you have the /dev/tty0 (current VC) device. If not, make it using - - mknod /dev/tty0 c 4 0 - -3. Build the program --------------------- - - - Type `make' in the directory in which you unpacked the selection code; - this will build the `selection' executable. It has been tested with - gcc 2.3.3 and libc.so.4.3.3. - - - Run `selection &' to test it out. Use `selection -?' to see what - options are supported. Then type `make install', which installs the - executable in /etc and the manual page in /usr/man, and start it up - from /etc/rc.local. Consult the manual page for usage. It should - work with text screens of various sizes, e.g. 80x28, 80x50, etc. - -The default size of the paste buffer is 2048 bytes. This may be changed by -altering the value of SEL_BUFFER_SIZE in kernel/chr_drv/console.c. - -And that's all there is to it, hopefully. See the manual page for a more -detailed description of operation. Please let me know of any problems, -suggestions for enhancements, etc, etc. - -Andrew Haylett , 17th June 1993 diff --git a/historic/selection/mouse.c b/historic/selection/mouse.c deleted file mode 100644 index 87e9d06e..00000000 --- a/historic/selection/mouse.c +++ /dev/null @@ -1,367 +0,0 @@ -/* simple driver for serial mouse */ -/* Andrew Haylett, 17th June 1993 */ - -#include -#include -#include -#include -#include -#include - -#include "mouse.h" - -#define DEF_MDEV "/dev/mouse" -#define DEF_MTYPE P_MS -#define DEF_MBAUD 1200 -#define DEF_MSAMPLE 100 -#define DEF_MDELTA 25 -#define DEF_MACCEL 2 -#define DEF_SLACK -1 - -/* thse settings may be altered by the user */ -static char *mdev = DEF_MDEV; /* mouse device */ -static mouse_type mtype = DEF_MTYPE; /* mouse type */ -static int mbaud = DEF_MBAUD; /* mouse device baud rate */ -static int msample = DEF_MSAMPLE; /* sample rate for Logitech mice */ -static int mdelta = DEF_MDELTA; /* x+y movements more than mdelta pixels..*/ -static int maccel = DEF_MACCEL; /* ..are multiplied by maccel. */ -static int slack = DEF_SLACK; /* < 0 ? no wraparound : amount of slack */ -int ms_copy_button = MS_BUTLEFT, - ms_paste_button = MS_BUTRIGHT; - -static char *progname; - -static void -ms_usage() -{ - printf( - "Selection version 1.5, 17th June 1993\n" - "Usage: %s [-a accel] [-b baud-rate] [-c l|m|r] [-d delta]\n" - " [-m mouse-device] [-p l|m|r] [-s sample-rate] [-t mouse-type]\n" - " [-w slack]\n\n", progname); - printf( - " -a accel sets the acceleration (default %d)\n" - " -b baud-rate sets the baud rate (default %d)\n" - " -c l|m|r sets the copy button (default `l')\n" - " -d delta sets the delta value (default %d)\n" - " -m mouse-device sets mouse device (default `%s')\n" - " -p l|m|r sets the paste button (default `r')\n" - " -s sample-rate sets the sample rate (default %d)\n" - " -t mouse-type sets mouse type (default `ms')\n" - " Microsoft = `ms', Mouse Systems Corp = `msc',\n" - " MM Series = `mm', Logitech = `logi', BusMouse = `bm',\n" - " MSC 3-bytes = `sun', PS/2 = `ps2')\n" - " -w slack turns on wrap-around and specifies slack (default off)\n", - DEF_MACCEL, DEF_MBAUD, DEF_MDELTA, DEF_MDEV, DEF_MSAMPLE); - exit(1); -} - -extern int optind; -extern char *optarg; - -void -ms_params(int argc, char *argv[]) -{ - int opt; - - progname = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0]; - while ((opt = getopt(argc, argv, "a:b:c:d:m:p:s:t:w:")) != -1) - { - switch (opt) - { - case 'a': - maccel = atoi(optarg); - if (maccel < 2) - ms_usage(); - break; - case 'b': - mbaud = atoi(optarg); - break; - case 'c': - switch (*optarg) - { - case 'l': ms_copy_button = MS_BUTLEFT; break; - case 'm': ms_copy_button = MS_BUTMIDDLE; break; - case 'r': ms_copy_button = MS_BUTRIGHT; break; - default: ms_usage(); break; - } - break; - case 'd': - mdelta = atoi(optarg); - if (mdelta < 2) - ms_usage(); - break; - case 'm': - mdev = optarg; - break; - case 'p': - switch (*optarg) - { - case 'l': ms_paste_button = MS_BUTLEFT; break; - case 'm': ms_paste_button = MS_BUTMIDDLE; break; - case 'r': ms_paste_button = MS_BUTRIGHT; break; - default: ms_usage(); break; - } - break; - case 's': - msample = atoi(optarg); - break; - case 't': - if (!strcmp(optarg, "ms")) - mtype = P_MS; - else if (!strcmp(optarg, "sun")) - mtype = P_SUN; - else if (!strcmp(optarg, "msc")) - mtype = P_MSC; - else if (!strcmp(optarg, "mm")) - mtype = P_MM; - else if (!strcmp(optarg, "logi")) - mtype = P_LOGI; - else if (!strcmp(optarg, "bm")) - mtype = P_BM; - else if (!strcmp(optarg, "ps2")) - mtype = P_PS2; - else - ms_usage(); - break; - case 'w': - slack = atoi (optarg); - break; - default: - ms_usage(); - break; - } - } -} - -#define limit(n,l,u,s) n = ((s) < 0 ? \ - (((n) < (l) ? (l) : ((n) > (u) ? (u) : (n)))) : \ - (((n) < (l-s) ? (u) : ((n) > (u+s) ? (l) : (n))))) - -static int mx = 32767; -static int my = 32767; -static int x, y; -static int mfd = -1; - -static const unsigned short cflag[NR_TYPES] = -{ - (CS7 | CREAD | CLOCAL | HUPCL ), /* MicroSoft */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems 3 */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems 5 */ - (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* MMSeries */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Logitech */ - 0, /* BusMouse */ - 0 /* PS/2 */ -}; - -static const unsigned char proto[NR_TYPES][5] = -{ - /* hd_mask hd_id dp_mask dp_id nobytes */ - { 0x40, 0x40, 0x40, 0x00, 3 }, /* MicroSoft */ - { 0xf8, 0x80, 0x00, 0x00, 3 }, /* MouseSystems 3 (Sun) */ - { 0xf8, 0x80, 0x00, 0x00, 5 }, /* MouseSystems 5 */ - { 0xe0, 0x80, 0x80, 0x00, 3 }, /* MMSeries */ - { 0xe0, 0x80, 0x80, 0x00, 3 }, /* Logitech */ - { 0xf8, 0x80, 0x00, 0x00, 5 }, /* BusMouse */ - { 0xcc, 0x00, 0x00, 0x00, 3 } /* PS/2 */ -}; - -static void -ms_setspeed(const int old, const int new, - const unsigned short c_cflag) -{ - struct termios tty; - char *c; - - tcgetattr(mfd, &tty); - - tty.c_iflag = IGNBRK | IGNPAR; - tty.c_oflag = 0; - tty.c_lflag = 0; - tty.c_line = 0; - tty.c_cc[VTIME] = 0; - tty.c_cc[VMIN] = 1; - - switch (old) - { - case 9600: tty.c_cflag = c_cflag | B9600; break; - case 4800: tty.c_cflag = c_cflag | B4800; break; - case 2400: tty.c_cflag = c_cflag | B2400; break; - case 1200: - default: tty.c_cflag = c_cflag | B1200; break; - } - - tcsetattr(mfd, TCSAFLUSH, &tty); - - switch (new) - { - case 9600: c = "*q"; tty.c_cflag = c_cflag | B9600; break; - case 4800: c = "*p"; tty.c_cflag = c_cflag | B4800; break; - case 2400: c = "*o"; tty.c_cflag = c_cflag | B2400; break; - case 1200: - default: c = "*n"; tty.c_cflag = c_cflag | B1200; break; - } - - write(mfd, c, 2); - usleep(100000); - tcsetattr(mfd, TCSAFLUSH, &tty); -} - -int -ms_init(const int maxx, const int maxy) -{ - if ((mfd = open(mdev, O_RDWR)) < 0) - { - char buf[32]; - sprintf(buf, "ms_init: %s", mdev); - perror(buf); - return -1; - } - - if (mtype != P_BM && mtype != P_PS2) - { - ms_setspeed(9600, mbaud, cflag[mtype]); - ms_setspeed(4800, mbaud, cflag[mtype]); - ms_setspeed(2400, mbaud, cflag[mtype]); - ms_setspeed(1200, mbaud, cflag[mtype]); - - if (mtype == P_LOGI) - { - write(mfd, "S", 1); - ms_setspeed(mbaud, mbaud, cflag[P_MM]); - } - - if (msample <= 0) write(mfd, "O", 1); - else if (msample <= 15) write(mfd, "J", 1); - else if (msample <= 27) write(mfd, "K", 1); - else if (msample <= 42) write(mfd, "L", 1); - else if (msample <= 60) write(mfd, "R", 1); - else if (msample <= 85) write(mfd, "M", 1); - else if (msample <= 125) write(mfd, "Q", 1); - else write(mfd, "N", 1); - } - - mx = maxx; - my = maxy; - x = mx / 2; - y = my / 2; - return 0; -} - -int -get_ms_event(struct ms_event *ev) -{ - unsigned char buf[5]; - char dx, dy; - int i, acc; - - if (mfd == -1) - return -1; - if (mtype != P_BM) - { - if (read(mfd, &buf[0], 1) != 1) - return -1; -restart: - /* find a header packet */ - while ((buf[0] & proto[mtype][0]) != proto[mtype][1]) - { - if (read(mfd, &buf[0], 1) != 1) - { - perror("get_ms_event: read"); - return -1; - } - } - - /* read in the rest of the packet */ - for (i = 1; i < proto[mtype][4]; ++i) - { - if (read(mfd, &buf[i], 1) != 1) - { - perror("get_ms_event: read"); - return -1; - } - /* check whether it's a data packet */ - if (mtype != P_PS2 && ((buf[i] & proto[mtype][2]) != proto[mtype][3] - || buf[i] == 0x80)) - goto restart; - } - } - else /* bus mouse */ - { - while ((i = read(mfd, buf, 3)) != 3 && errno == EAGAIN) - usleep(40000); - if (i != 3) - { - perror("get_ms_event: read"); - return -1; - } - } - -/* construct the event */ - switch (mtype) - { - case P_MS: /* Microsoft */ - default: - ev->ev_butstate = ((buf[0] & 0x20) >> 3) | ((buf[0] & 0x10) >> 4); - dx = (char)(((buf[0] & 0x03) << 6) | (buf[1] & 0x3F)); - dy = (char)(((buf[0] & 0x0C) << 4) | (buf[2] & 0x3F)); - break; - case P_SUN: /* Mouse Systems 3 byte as used in Sun workstations */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)(buf[1]); - dy = -(char)(buf[2]); - break; - case P_MSC: /* Mouse Systems Corp (5 bytes, PC) */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)(buf[1]) + (char)(buf[3]); - dy = - ((char)(buf[2]) + (char)(buf[4])); - break; - case P_MM: /* MM Series */ - case P_LOGI: /* Logitech */ - ev->ev_butstate = buf[0] & 0x07; - dx = (buf[0] & 0x10) ? buf[1] : - buf[1]; - dy = (buf[0] & 0x08) ? - buf[2] : buf[2]; - break; - case P_BM: /* BusMouse */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)buf[1]; - dy = - (char)buf[2]; - break; - case P_PS2: /* PS/2 Mouse */ - ev->ev_butstate = 0; - if (buf[0] & 0x01) - ev->ev_butstate |= MS_BUTLEFT; - if (buf[0] & 0x02) - ev->ev_butstate |= MS_BUTRIGHT; - dx = (buf[0] & 0x10) ? buf[1]-256 : buf[1]; - dy = - ((buf[0] & 0x20) ? buf[2]-256 : buf[2]); - break; - } - - acc = (abs(ev->ev_dx) + abs(ev->ev_dy) > mdelta) ? maccel : 1; - ev->ev_dx = dx * acc; - ev->ev_dy = dy * acc; - x += ev->ev_dx; - y += ev->ev_dy; - limit(x, 0, mx, (int) (slack * mx / my)); - limit(y, 0, my, slack); - ev->ev_x = x; - ev->ev_y = y; - limit(ev->ev_x, 0, mx, -1); - limit(ev->ev_y, 0, my, -1); - if (dx || dy) - { - if (ev->ev_butstate) - ev->ev_code = MS_DRAG; - else - ev->ev_code = MS_MOVE; - } - else - { - if (ev->ev_butstate) - ev->ev_code = MS_BUTDOWN; - else - ev->ev_code = MS_BUTUP; - } - return 0; -} diff --git a/historic/selection/mouse.c.old b/historic/selection/mouse.c.old deleted file mode 100644 index e5e474ea..00000000 --- a/historic/selection/mouse.c.old +++ /dev/null @@ -1,356 +0,0 @@ -/* simple driver for serial mouse */ -/* Andrew Haylett, 17th June 1993 */ - -#include -#include -#include -#include -#include -#include - -#include "mouse.h" - -#define DEF_MDEV "/dev/mouse" -#define DEF_MTYPE P_MS -#define DEF_MBAUD 1200 -#define DEF_MSAMPLE 100 -#define DEF_MDELTA 25 -#define DEF_MACCEL 2 - -/* thse settings may be altered by the user */ -static char *mdev = DEF_MDEV; /* mouse device */ -static mouse_type mtype = DEF_MTYPE; /* mouse type */ -static int mbaud = DEF_MBAUD; /* mouse device baud rate */ -static int msample = DEF_MSAMPLE; /* sample rate for Logitech mice */ -static int mdelta = DEF_MDELTA; /* x+y movements more than mdelta pixels..*/ -static int maccel = DEF_MACCEL; /* ..are multiplied by maccel. */ -int ms_copy_button = MS_BUTLEFT, - ms_paste_button = MS_BUTRIGHT; - -static char *progname; - -static void -ms_usage() -{ - printf( - "Selection version 1.5, 17th June 1993\n" - "Usage: %s [-a accel] [-b baud-rate] [-c l|m|r] [-d delta]\n" - " [-m mouse-device] [-p l|m|r] [-s sample-rate] [-t mouse-type]\n\n", progname); - printf( - " -a accel sets the acceleration (default %d)\n" - " -b baud-rate sets the baud rate (default %d)\n" - " -c l|m|r sets the copy button (default `l')\n" - " -d delta sets the delta value (default %d)\n" - " -m mouse-device sets mouse device (default `%s')\n" - " -p l|m|r sets the paste button (default `r')\n" - " -s sample-rate sets the sample rate (default %d)\n" - " -t mouse-type sets mouse type (default `ms')\n" - " Microsoft = `ms', Mouse Systems Corp = `msc',\n" - " MM Series = `mm', Logitech = `logi', BusMouse = `bm',\n" - " MSC 3-bytes = `sun', PS/2 = `ps2')\n", - DEF_MACCEL, DEF_MBAUD, DEF_MDELTA, DEF_MDEV, DEF_MSAMPLE); - exit(1); -} - -extern int optind; -extern char *optarg; - -void -ms_params(int argc, char *argv[]) -{ - int opt; - - progname = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0]; - while ((opt = getopt(argc, argv, "a:b:c:d:m:p:s:t:")) != -1) - { - switch (opt) - { - case 'a': - maccel = atoi(optarg); - if (maccel < 2) - ms_usage(); - break; - case 'b': - mbaud = atoi(optarg); - break; - case 'c': - switch (*optarg) - { - case 'l': ms_copy_button = MS_BUTLEFT; break; - case 'm': ms_copy_button = MS_BUTMIDDLE; break; - case 'r': ms_copy_button = MS_BUTRIGHT; break; - default: ms_usage(); break; - } - break; - case 'd': - mdelta = atoi(optarg); - if (mdelta < 2) - ms_usage(); - break; - case 'm': - mdev = optarg; - break; - case 'p': - switch (*optarg) - { - case 'l': ms_paste_button = MS_BUTLEFT; break; - case 'm': ms_paste_button = MS_BUTMIDDLE; break; - case 'r': ms_paste_button = MS_BUTRIGHT; break; - default: ms_usage(); break; - } - break; - case 's': - msample = atoi(optarg); - break; - case 't': - if (!strcmp(optarg, "ms")) - mtype = P_MS; - else if (!strcmp(optarg, "sun")) - mtype = P_SUN; - else if (!strcmp(optarg, "msc")) - mtype = P_MSC; - else if (!strcmp(optarg, "mm")) - mtype = P_MM; - else if (!strcmp(optarg, "logi")) - mtype = P_LOGI; - else if (!strcmp(optarg, "bm")) - mtype = P_BM; - else if (!strcmp(optarg, "ps2")) - mtype = P_PS2; - else - ms_usage(); - break; - default: - ms_usage(); - break; - } - } -} - -#define limit(n,l,u) n = ((n) < (l) ? (l) : ((n) > (u) ? (u) : (n))) - -static int mx = 32767; -static int my = 32767; -static int x, y; -static int mfd = -1; - -static const unsigned short cflag[NR_TYPES] = -{ - (CS7 | CREAD | CLOCAL | HUPCL ), /* MicroSoft */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems 3 */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* MouseSystems 5 */ - (CS8 | PARENB | PARODD | CREAD | CLOCAL | HUPCL ), /* MMSeries */ - (CS8 | CSTOPB | CREAD | CLOCAL | HUPCL ), /* Logitech */ - 0, /* BusMouse */ - 0 /* PS/2 */ -}; - -static const unsigned char proto[NR_TYPES][5] = -{ - /* hd_mask hd_id dp_mask dp_id nobytes */ - { 0x40, 0x40, 0x40, 0x00, 3 }, /* MicroSoft */ - { 0xf8, 0x80, 0x00, 0x00, 3 }, /* MouseSystems 3 (Sun) */ - { 0xf8, 0x80, 0x00, 0x00, 5 }, /* MouseSystems 5 */ - { 0xe0, 0x80, 0x80, 0x00, 3 }, /* MMSeries */ - { 0xe0, 0x80, 0x80, 0x00, 3 }, /* Logitech */ - { 0xf8, 0x80, 0x00, 0x00, 5 }, /* BusMouse */ - { 0xcc, 0x00, 0x00, 0x00, 3 } /* PS/2 */ -}; - -static void -ms_setspeed(const int old, const int new, - const unsigned short c_cflag) -{ - struct termios tty; - char *c; - - tcgetattr(mfd, &tty); - - tty.c_iflag = IGNBRK | IGNPAR; - tty.c_oflag = 0; - tty.c_lflag = 0; - tty.c_line = 0; - tty.c_cc[VTIME] = 0; - tty.c_cc[VMIN] = 1; - - switch (old) - { - case 9600: tty.c_cflag = c_cflag | B9600; break; - case 4800: tty.c_cflag = c_cflag | B4800; break; - case 2400: tty.c_cflag = c_cflag | B2400; break; - case 1200: - default: tty.c_cflag = c_cflag | B1200; break; - } - - tcsetattr(mfd, TCSAFLUSH, &tty); - - switch (new) - { - case 9600: c = "*q"; tty.c_cflag = c_cflag | B9600; break; - case 4800: c = "*p"; tty.c_cflag = c_cflag | B4800; break; - case 2400: c = "*o"; tty.c_cflag = c_cflag | B2400; break; - case 1200: - default: c = "*n"; tty.c_cflag = c_cflag | B1200; break; - } - - write(mfd, c, 2); - usleep(100000); - tcsetattr(mfd, TCSAFLUSH, &tty); -} - -int -ms_init(const int maxx, const int maxy) -{ - if ((mfd = open(mdev, O_RDWR)) < 0) - { - char buf[32]; - sprintf(buf, "ms_init: %s", mdev); - perror(buf); - return -1; - } - - if (mtype != P_BM && mtype != P_PS2) - { - ms_setspeed(9600, mbaud, cflag[mtype]); - ms_setspeed(4800, mbaud, cflag[mtype]); - ms_setspeed(2400, mbaud, cflag[mtype]); - ms_setspeed(1200, mbaud, cflag[mtype]); - - if (mtype == P_LOGI) - { - write(mfd, "S", 1); - ms_setspeed(mbaud, mbaud, cflag[P_MM]); - } - - if (msample <= 0) write(mfd, "O", 1); - else if (msample <= 15) write(mfd, "J", 1); - else if (msample <= 27) write(mfd, "K", 1); - else if (msample <= 42) write(mfd, "L", 1); - else if (msample <= 60) write(mfd, "R", 1); - else if (msample <= 85) write(mfd, "M", 1); - else if (msample <= 125) write(mfd, "Q", 1); - else write(mfd, "N", 1); - } - - mx = maxx; - my = maxy; - x = mx / 2; - y = my / 2; - return 0; -} - -int -get_ms_event(struct ms_event *ev) -{ - unsigned char buf[5]; - char dx, dy; - int i, acc; - - if (mfd == -1) - return -1; - if (mtype != P_BM) - { - if (read(mfd, &buf[0], 1) != 1) - return -1; -restart: - /* find a header packet */ - while ((buf[0] & proto[mtype][0]) != proto[mtype][1]) - { - if (read(mfd, &buf[0], 1) != 1) - { - perror("get_ms_event: read"); - return -1; - } - } - - /* read in the rest of the packet */ - for (i = 1; i < proto[mtype][4]; ++i) - { - if (read(mfd, &buf[i], 1) != 1) - { - perror("get_ms_event: read"); - return -1; - } - /* check whether it's a data packet */ - if (mtype != P_PS2 && ((buf[i] & proto[mtype][2]) != proto[mtype][3] - || buf[i] == 0x80)) - goto restart; - } - } - else /* bus mouse */ - { - while ((i = read(mfd, buf, 3)) != 3 && errno == EAGAIN) - usleep(40000); - if (i != 3) - { - perror("get_ms_event: read"); - return -1; - } - } - -/* construct the event */ - switch (mtype) - { - case P_MS: /* Microsoft */ - default: - ev->ev_butstate = ((buf[0] & 0x20) >> 3) | ((buf[0] & 0x10) >> 4); - dx = (char)(((buf[0] & 0x03) << 6) | (buf[1] & 0x3F)); - dy = (char)(((buf[0] & 0x0C) << 4) | (buf[2] & 0x3F)); - break; - case P_SUN: /* Mouse Systems 3 byte as used in Sun workstations */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)(buf[1]); - dy = -(char)(buf[2]); - break; - case P_MSC: /* Mouse Systems Corp (5 bytes, PC) */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)(buf[1]) + (char)(buf[3]); - dy = - ((char)(buf[2]) + (char)(buf[4])); - break; - case P_MM: /* MM Series */ - case P_LOGI: /* Logitech */ - ev->ev_butstate = buf[0] & 0x07; - dx = (buf[0] & 0x10) ? buf[1] : - buf[1]; - dy = (buf[0] & 0x08) ? - buf[2] : buf[2]; - break; - case P_BM: /* BusMouse */ - ev->ev_butstate = (~buf[0]) & 0x07; - dx = (char)buf[1]; - dy = - (char)buf[2]; - break; - case P_PS2: /* PS/2 Mouse */ - ev->ev_butstate = 0; - if (buf[0] & 0x01) - ev->ev_butstate |= MS_BUTLEFT; - if (buf[0] & 0x02) - ev->ev_butstate |= MS_BUTRIGHT; - dx = (buf[0] & 0x10) ? buf[1]-256 : buf[1]; - dy = - ((buf[0] & 0x20) ? buf[2]-256 : buf[2]); - break; - } - - acc = (abs(ev->ev_dx) + abs(ev->ev_dy) > mdelta) ? maccel : 1; - ev->ev_dx = dx * acc; - ev->ev_dy = dy * acc; - x += ev->ev_dx; - y += ev->ev_dy; - limit(x, 0, mx); - limit(y, 0, my); - ev->ev_x = x; - ev->ev_y = y; - if (dx || dy) - { - if (ev->ev_butstate) - ev->ev_code = MS_DRAG; - else - ev->ev_code = MS_MOVE; - } - else - { - if (ev->ev_butstate) - ev->ev_code = MS_BUTDOWN; - else - ev->ev_code = MS_BUTUP; - } - return 0; -} diff --git a/historic/selection/mouse.h b/historic/selection/mouse.h deleted file mode 100644 index b8014dbd..00000000 --- a/historic/selection/mouse.h +++ /dev/null @@ -1,34 +0,0 @@ -/* interface file for mouse driver */ -/* Andrew Haylett, 17th June 1993 */ - -#ifndef MOUSE_H -#define MOUSE_H - -#define MS_BUTLEFT 4 -#define MS_BUTMIDDLE 2 -#define MS_BUTRIGHT 1 - -typedef enum { - P_MS = 0, - P_SUN = 1, - P_MSC = 2, - P_MM = 3, - P_LOGI = 4, - P_BM = 5, - P_PS2 = 6 -} mouse_type; - -#define NR_TYPES 7 /* keep in step with mouse_type! */ - -struct ms_event { - enum { MS_NONE, MS_BUTUP, MS_BUTDOWN, MS_MOVE, MS_DRAG } ev_code; - char ev_butstate; - int ev_x, ev_y; - int ev_dx, ev_dy; -}; - -void ms_params(int argc, char *argv[]); -int ms_init(const int maxx, const int maxy); -int get_ms_event(struct ms_event *ev); - -#endif /* MOUSE_H */ diff --git a/historic/selection/selection.1 b/historic/selection/selection.1 deleted file mode 100644 index 450c9fab..00000000 --- a/historic/selection/selection.1 +++ /dev/null @@ -1,142 +0,0 @@ -.\" -.\" selection.1 - the cut and paste utility for Linux virtual consoles -.\" -.\" Modified by faith@cs.unc.edu -.\" -.TH SELECTION 1 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -selection - the cut and paste utility for Linux virtual consoles -.SH SYNTAX -\fBselection [-a accel] [-b baud-rate] [-c l|m|r] [-d delta] [-m mouse-device] [-p l|m|r] [-s sample-rate] [-t mouse-type] [-r slack]\fR -.SH DESCRIPTION -\fBselection\fR is a utility that allows characters to be selected from the -current Linux virtual console using the mouse and pasted into the current -console. \fBselection\fR is normally invoked at boot time from /etc/rc.local, -and runs as a background process. -.SH OPTIONS -.IP \fB\-a\fP\fIaccel\fP -movements of more than \fIdelta\fP pixels are multiplied by \fIaccel\fP (default 2) -.IP \fB\-b\fP\fIbaud-rate\fP -set the baud rate of the mouse (default 1200 baud) -.IP \fB\-c\fP\fIl|m|r\fP -set the copy button to be the left, middle or right button (default left) -.IP \fB\-d\fP\fIdelta\fP -movements of more than \fIdelta\fP pixels are multiplied by \fIaccel\fP -(default 25) -.IP \fB\-m\fP\fImouse-device\fP -specify the mouse device (default /dev/mouse) -.IP \fB\-p\fP\fIl|m|r\fP -set the paste button to be the left, middle or right button (default right) -.IP \fB\-s\fP\fIsample-rate\fP -set the sample rate of the mouse (default 100) -.IP \fB\-t\fP\fImouse-type\fP -specify the mouse type (Microsoft = `ms', Mouse Systems Corp = `msc', -MM Series = `mm', Logitech = `logi', BusMouse = `bm', -MSC 3-bytes = `sun', PS/2 = `ps2'; default = ms) -.IP \fB\-w\fP\fIslack\fP -turn on wrap-around, specifying the amount of slack before the pointer -reappears at the other side of the screen (default off) -.SH OPERATION -To invoke the selection mechanism, press and release the copy button -(the meaning of the buttons may be set at startup as above). A highlighted -block will start moving around the screen, correlated with the movement of the -mouse. -.PP -Move the block to the first character of the selection, then press and hold -down the copy button. -.PP -Drag out the selection; the selected text will be highlighted. Then release -the copy button. You can take the end of the selection to before the start of -the selection if necessary. -.PP -Double-clicking the copy button while the highlighted block is on the -screen selects text by word boundaries; treble-clicking selects by entire -lines. If the button is held down after double- or treble-clicking, multiple -words or lines may be selected. A word consists of a set of alphanumeric -characters and underscores. -.PP -If a trailing space after the contents of a line is highlighted, and if there -is no other text on the remainder of the line, the rest of the line will be -selected automatically. If a number of lines are selected, highlighted -trailing spaces on each line will be removed from the selection buffer. -.PP -Pressing the paste button in any virtual console pastes the -selected text into the read queue of the associated tty. -.PP -Any output on the virtual console holding the selection will clear the -highlighted selection from the screen, to maintain integrity of the display, -although the contents of the paste buffer will be unaffected. -.PP -The selection mechanism is disabled if the controlling virtual console is -placed in graphics mode, for example when running X11, and is re-enabled when -text mode is resumed. (But see BUGS section below.) -.SH FILES -/dev/mouse - default mouse device -.br -/dev/console - current VC device -.SH DIAGNOSTICS -\fBselection\fR complains if any of the devices it requires cannot be located. -.SH BUGS -The size of the paste buffer is set at 2048 bytes by default. This may be -changed at compile time; consult the installation notes. -.PP -The selection mechanism doesn't work very well with graphics characters, or -indeed with any characters where a mapping between the typed character and -the displayed character is performed by the console driver. The selection -mechanism pastes into the input buffer the character codes as they are -displayed on the screen, not those originally typed in by the user. -.PP -Because of the way that the kernel bus mouse drivers work, allowing only one -process to have the mouse device open at once, \fBselection\fR cannot -co-exist with X11 using ATI XL, Logitech and Microsoft bus mice or with a -PS/2 mouse. The X server will not start while \fBselection\fR is running. -This problem is not present with serial mice. -.SH AUTHOR -.nf -Andrew Haylett -.SH ACKNOWLEDGEMENTS -.nf -Lefty patches originally suggested by: -.ti +4 -Sotiris C. Vassilopoulos -.br -Logitech patches from: -.ti +4 -Jim Winstead Jr -.br -Command line options based on those from: -.ti +4 -Peter Macdonald -.br -Patches for bus mouse from: -.br -.ti +4 -Erik Troan -.br -.ti +4 -Christoph Niemann -.br -.ti +4 -Koen Gadeyne -.br -Patches for PS/2 mouse from: -.br -.ti +4 -Hans D. Fink -.br -Patches for Sun mouse from: -.br -.ti +4 -Michael Haardt -.br -Run-time configurable mouse buttons suggested by: -.br -.ti +4 -Charlie Brady -.br -Setsid patches by: -.bt -.ti +4 -Rick Sladkey -.sp -Apologies to any contributors whose names I have omitted. diff --git a/historic/selection/selection.1.old b/historic/selection/selection.1.old deleted file mode 100644 index fdc76af5..00000000 --- a/historic/selection/selection.1.old +++ /dev/null @@ -1,139 +0,0 @@ -.\" -.\" selection.1 - the cut and paste utility for Linux virtual consoles -.\" -.\" Modified by faith@cs.unc.edu -.\" -.TH SELECTION 1 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -selection - the cut and paste utility for Linux virtual consoles -.SH SYNTAX -\fBselection [-a accel] [-b baud-rate] [-c l|m|r] [-d delta] [-m mouse-device] [-p l|m|r] [-s sample-rate] [-t mouse-type]\fR -.SH DESCRIPTION -\fBselection\fR is a utility that allows characters to be selected from the -current Linux virtual console using the mouse and pasted into the current -console. \fBselection\fR is normally invoked at boot time from /etc/rc.local, -and runs as a background process. -.SH OPTIONS -.IP \fB\-a\fP\fIaccel\fP -movements of more than \fIdelta\fP pixels are multiplied by \fIaccel\fP (default 2) -.IP \fB\-b\fP\fIbaud-rate\fP -set the baud rate of the mouse (default 1200 baud) -.IP \fB\-c\fP\fIl|m|r\fP -set the copy button to be the left, middle or right button (default left) -.IP \fB\-d\fP\fIdelta\fP -movements of more than \fIdelta\fP pixels are multiplied by \fIaccel\fP -(default 25) -.IP \fB\-m\fP\fImouse-device\fP -specify the mouse device (default /dev/mouse) -.IP \fB\-p\fP\fIl|m|r\fP -set the paste button to be the left, middle or right button (default right) -.IP \fB\-s\fP\fIsample-rate\fP -set the sample rate of the mouse (default 100) -.IP \fB\-t\fP\fImouse-type\fP -specify the mouse type (Microsoft = `ms', Mouse Systems Corp = `msc', -MM Series = `mm', Logitech = `logi', BusMouse = `bm', -MSC 3-bytes = `sun', PS/2 = `ps2'; default = ms) -.SH OPERATION -To invoke the selection mechanism, press and release the copy button -(the meaning of the buttons may be set at startup as above). A highlighted -block will start moving around the screen, correlated with the movement of the -mouse. -.PP -Move the block to the first character of the selection, then press and hold -down the copy button. -.PP -Drag out the selection; the selected text will be highlighted. Then release -the copy button. You can take the end of the selection to before the start of -the selection if necessary. -.PP -Double-clicking the copy button while the highlighted block is on the -screen selects text by word boundaries; treble-clicking selects by entire -lines. If the button is held down after double- or treble-clicking, multiple -words or lines may be selected. A word consists of a set of alphanumeric -characters and underscores. -.PP -If a trailing space after the contents of a line is highlighted, and if there -is no other text on the remainder of the line, the rest of the line will be -selected automatically. If a number of lines are selected, highlighted -trailing spaces on each line will be removed from the selection buffer. -.PP -Pressing the paste button in any virtual console pastes the -selected text into the read queue of the associated tty. -.PP -Any output on the virtual console holding the selection will clear the -highlighted selection from the screen, to maintain integrity of the display, -although the contents of the paste buffer will be unaffected. -.PP -The selection mechanism is disabled if the controlling virtual console is -placed in graphics mode, for example when running X11, and is re-enabled when -text mode is resumed. (But see BUGS section below.) -.SH FILES -/dev/mouse - default mouse device -.br -/dev/tty0 - current VC device -.SH DIAGNOSTICS -\fBselection\fR complains if any of the devices it requires cannot be located. -.SH BUGS -The size of the paste buffer is set at 2048 bytes by default. This may be -changed at compile time; consult the installation notes. -.PP -The selection mechanism doesn't work very well with graphics characters, or -indeed with any characters where a mapping between the typed character and -the displayed character is performed by the console driver. The selection -mechanism pastes into the input buffer the character codes as they are -displayed on the screen, not those originally typed in by the user. -.PP -Because of the way that the kernel bus mouse drivers work, allowing only one -process to have the mouse device open at once, \fBselection\fR cannot -co-exist with X11 using ATI XL, Logitech and Microsoft bus mice or with a -PS/2 mouse. The X server will not start while \fBselection\fR is running. -This problem is not present with serial mice. -.SH AUTHOR -.nf -Andrew Haylett -.SH ACKNOWLEDGEMENTS -.nf -Lefty patches originally suggested by: -.ti +4 -Sotiris C. Vassilopoulos -.br -Logitech patches from: -.ti +4 -Jim Winstead Jr -.br -Command line options based on those from: -.ti +4 -Peter Macdonald -.br -Patches for bus mouse from: -.br -.ti +4 -Erik Troan -.br -.ti +4 -Christoph Niemann -.br -.ti +4 -Koen Gadeyne -.br -Patches for PS/2 mouse from: -.br -.ti +4 -Hans D. Fink -.br -Patches for Sun mouse from: -.br -.ti +4 -Michael Haardt -.br -Run-time configurable mouse buttons suggested by: -.br -.ti +4 -Charlie Brady -.br -Setsid patches by: -.bt -.ti +4 -Rick Sladkey -.sp -Apologies to any contributors whose names I have omitted. diff --git a/historic/selection/selection.c b/historic/selection/selection.c deleted file mode 100644 index 058936fc..00000000 --- a/historic/selection/selection.c +++ /dev/null @@ -1,237 +0,0 @@ -/* implement copying and pasting in Linux virtual consoles */ -/* Andrew Haylett, 17th June 1993 */ -/* Wed Feb 15 09:33:16 1995, faith@cs.unc.edu changed tty0 to console, since - most systems don't have a tty0 any more. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mouse.h" - -extern int ms_copy_button, ms_paste_button; - -static const int SCALE = 10; -static const long CLICK_INTERVAL = 250; /* msec */ -static const char *console = "/dev/console"; - -typedef enum { character = 0, word = 1, line = 2 } sel_mode; - -static int open_console(const int mode); -static void set_sel(const int xs, const int ys, const int xe, - const int ye, const sel_mode mode); -static void paste(void); -static long interval(const struct timeval *t1, const struct timeval *t2); -static int check_mode(void); - -int -main(int argc, char *argv[]) -{ - struct ms_event ev; - struct winsize win; - struct timeval tv1, tv2; - int xs, ys, xe, ye, x1, y1, fd, clicks = 0; - sel_mode mode; - - fd = open_console(O_RDONLY); - ioctl(fd, TIOCGWINSZ, &win); - close(fd); - if (! win.ws_col || ! win.ws_row) - { - fprintf(stderr, "selection: zero screen dimension, assuming 80x25.\n"); - win.ws_col = 80; - win.ws_row = 25; - } - - ms_params(argc, argv); - - if (ms_init(win.ws_col * SCALE - 1, win.ws_row * SCALE - 1)) - exit(1); - - if (fork() > 0) - exit(0); - setsid(); - - gettimeofday(&tv1, (struct timezone *)NULL); - -restart: - while (1) - { - if (check_mode()) - goto restart; - if (get_ms_event(&ev)) - exit(1); - if (ev.ev_butstate == ms_copy_button) - { - ++clicks; - gettimeofday(&tv2, (struct timezone *)NULL); - xs = ev.ev_x / SCALE + 1; - ys = ev.ev_y / SCALE + 1; - if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 1) - { - mode = word; - set_sel(xs, ys, xs, ys, mode); - } - else if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 2) - { - mode = line; - set_sel(xs, ys, xs, ys, mode); - } - else - { - mode = character; - clicks = 0; - do /* wait for left button up */ - { - if (check_mode()) - goto restart; - if (get_ms_event(&ev)) - exit(1); - } while (ev.ev_butstate); - x1 = y1 = 0; - do /* track start selection until left button down */ - { - xs = ev.ev_x / SCALE + 1; - ys = ev.ev_y / SCALE + 1; - if (xs != x1 || ys != y1) - { - set_sel(xs, ys, xs, ys, mode); - x1 = xs; y1 = ys; - } - if (check_mode()) - goto restart; - if (get_ms_event(&ev)) - exit(1); - } while (ev.ev_butstate != ms_copy_button); - } - x1 = y1 = 0; - gettimeofday(&tv1, (struct timezone *)NULL); - do /* track end selection until left button up */ - { - xe = ev.ev_x / SCALE + 1; - ye = ev.ev_y / SCALE + 1; - if (xe != x1 || ye != y1) - { - set_sel(xs, ys, xe, ye, mode); - x1 = xe; y1 = ye; - } - if (check_mode()) - goto restart; - if (get_ms_event(&ev)) - exit(1); - } while (ev.ev_butstate == ms_copy_button); - } else if (ev.ev_butstate == ms_paste_button) - { /* paste selection */ - paste(); - do /* wait for right button up */ - { - if (check_mode()) - goto restart; - if (get_ms_event(&ev)) - exit(1); - } while (ev.ev_butstate); - gettimeofday(&tv1, (struct timezone *)NULL); - clicks = 0; - } - } -} - -/* We have to keep opening and closing the console because (a) /dev/tty0 - changed its behaviour at some point such that the current VC is fixed - after the open(), rather than being re-evaluated at each write(), and (b) - because we seem to lose our grip on /dev/tty? after someone logs in if - this is run from /etc/rc. */ - -static int -open_console(const int mode) -{ - int fd; - - if ((fd = open(console, mode)) < 0) - { - perror("selection: open_console()"); - exit(1); - } - return fd; -} - -/* mark selected text on screen. */ -static void -set_sel(const int xs, const int ys, - const int xe, const int ye, const sel_mode mode) -{ - unsigned char buf[sizeof(char) + 5 * sizeof(short)]; - unsigned short *arg = (unsigned short *)(buf + 1); - int fd; - - buf[0] = 2; - - arg[0] = xs; - arg[1] = ys; - arg[2] = xe; - arg[3] = ye; - arg[4] = mode; - - fd = open_console(O_WRONLY); - if (ioctl(fd, TIOCLINUX, buf) < 0) - { - perror("selection: ioctl(..., TIOCLINUX, ...)"); - exit(1); - } - close(fd); -} - -/* paste contents of selection buffer into console. */ -static void -paste(void) -{ - char c = 3; - int fd; - - fd = open_console(O_WRONLY); - if (ioctl(fd, TIOCLINUX, &c) < 0) - { - perror("selection: ioctl(..., TIOCLINUX, ...)"); - exit(1); - } - close(fd); -} - -/* evaluate interval between times. */ -static long -interval(const struct timeval *t1, const struct timeval *t2) -{ - return (t2->tv_sec - t1->tv_sec) * 1000 - + (t2->tv_usec - t1->tv_usec) / 1000; -} - -/* Check whether console is in graphics mode; if so, wait until it isn't. */ -static int -check_mode(void) -{ - int fd, ch = 0; - long kd_mode; - - do - { - fd = open_console(O_RDONLY); - if (ioctl(fd, KDGETMODE, &kd_mode) < 0) - { - perror("selection: ioctl(..., KDGETMODE, ...)"); - exit(1); - } - close(fd); - if (kd_mode != KD_TEXT) - { - ++ch; - sleep(2); - } - } while (kd_mode != KD_TEXT); - return (ch > 0); -} diff --git a/historic/selection/test-mouse.c b/historic/selection/test-mouse.c deleted file mode 100644 index fd80989b..00000000 --- a/historic/selection/test-mouse.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * test-mouse: exercise rodent to test compatibility. - * Any button to draw asterisks of different - * colour. Left and right buttons (while mouse is stationary) to quit. - * Andrew Haylett, 17th June 1993 - */ - -#include -#include -#include -#include -#include - -#include "mouse.h" - -#define SCALE 10 - -int -main(int argc, char *argv[]) -{ - struct ms_event ev; - struct winsize win; - - ms_params(argc, argv); - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (! win.ws_col || ! win.ws_row) - { - fprintf(stderr, "selection: zero screen dimension: assuming 80x25.\n"); - win.ws_col = 80; - win.ws_row = 25; - } - - printf("\033[2J\033[%d;%dH", win.ws_row / 2, win.ws_col / 2); - fflush(stdout); - if (ms_init((win.ws_col + 1) * SCALE - 1, (win.ws_row + 1) * SCALE - 1)) - { - perror("ms_init"); - exit(1); - } - while (1) - { - if (get_ms_event(&ev)) - { - perror("get_ms_event"); - exit(1); - } - if (ev.ev_code == MS_BUTDOWN && ev.ev_butstate == (MS_BUTLEFT | MS_BUTRIGHT)) - { - printf("\033[;H\033[2J\033[m"); - exit(0); - } - else if (ev.ev_code == MS_MOVE || ev.ev_code == MS_DRAG) - { - printf("\033[%d;%dH", ev.ev_y / SCALE, ev.ev_x / SCALE); - if (ev.ev_code == MS_DRAG) - { - if (ev.ev_butstate == MS_BUTLEFT) - printf("\033[31m*\033[D"); /* red */ - else if (ev.ev_butstate == MS_BUTRIGHT) - printf("\033[35m*\033[D"); /* purple */ - else - printf("\033[34m*\033[D"); /* blue */ - } - } - fflush(stdout); - } -} diff --git a/historic/sync.c b/historic/sync.c deleted file mode 100644 index 76e0b622..00000000 --- a/historic/sync.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * sync.c - flush Linux filesystem buffers - * - * Copyright 1992 Linus Torvalds. - * This file may be redistributed as per the GNU copyright. - */ - -#include -#include - -int main(int argc, char **argv) { - sync(); - return 0; -} diff --git a/historic/update.8 b/historic/update.8 deleted file mode 100644 index e6887a73..00000000 --- a/historic/update.8 +++ /dev/null @@ -1,25 +0,0 @@ -.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH UPDATE 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -update \- periodically flush Linux filesystem buffers -.SH SYNOPSIS -.B update [ interval ] -.SH DESCRIPTION -.B update -executes -.BR sync (2) -every -.I interval -seconds. By default, the -.I interval -is 30 seconds. It is generally started at boot time in -.IR /etc/rc . -.SH "SEE ALSO" -.BR sync (2), -.BR sync (8), -.BR init (8) -.SH AUTHOR -Linus Torvalds (torvalds@cs.helsinki.fi) -.br -With modifications by Rick Sladkey (jrs@world.std.com) diff --git a/historic/update.c b/historic/update.c deleted file mode 100644 index 0506df87..00000000 --- a/historic/update.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * update.c -- periodically sync the filesystems to disk - */ - -#include -#include -#include -#include - -void alarm_handler(int sig) -{ -} - -int main(int argc, char *argv[]) -{ - int i; - int interval; - struct sigaction sa; - sigset_t empty_set; - sigset_t alarm_set; - - interval = (argc > 1) ? atoi(argv[1]) : 30; - if (fork() > 0) - exit(0); - chdir("/"); - for (i = 0; i < OPEN_MAX; i++) - close(i); - setsid(); - sa.sa_handler = SIG_IGN; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sa.sa_handler = alarm_handler; - sigaction(SIGALRM, &sa, NULL); - sigemptyset(&empty_set); - sigemptyset(&alarm_set); - sigaddset(&alarm_set, SIGALRM); - sigprocmask(SIG_BLOCK, &alarm_set, NULL); - for (;;) { - alarm(interval); - sigsuspend(&empty_set); - sync(); - } -} diff --git a/login-utils/Makefile b/login-utils/Makefile index 35c8125a..9f41fcd1 100644 --- a/login-utils/Makefile +++ b/login-utils/Makefile @@ -1,6 +1,6 @@ # Makefile -- Makefile for util-linux Linux utilities # Created: Sat Dec 26 20:09:40 1992 -# Revised: Thu Oct 12 10:10:32 1995 by r.faith@ieee.org +# Revised: Sun Nov 10 20:28:43 1996 by faith@cs.unc.edu # Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) # # Suggested changed from Bauke Jan Douma have been @@ -19,7 +19,7 @@ MAN8.GETTY= agetty.8 MAN8.INIT= fastboot.8 fasthalt.8 halt.8 reboot.8 simpleinit.8 shutdown.8 -MAN8.PUTILS= vipw.8 +MAN8.PUTILS= vipw.8 vigr.8 # Where to put binaries? # See the "install" rule for the links. . . @@ -37,10 +37,21 @@ USRBIN.PASSWD= passwd USRSBIN.PUTILS= vipw +ifeq "$(HAVE_LIBCRYPT)" "yes" +CRYPT=-lcrypt +endif + +ifeq "$(HAVE_PAM)" "yes" +PAM=-lpam -ldl -lpam_misc +PAMFL=-DUSE_PAM=1 +endif + ifeq "$(HAVE_SHADOW)" "no" +ifeq "$(HAVE_PAM)" "no" ifeq "$(HAVE_PASSWD)" "no" WHAT_TO_BUILD:=$(WHAT_TO_BUILD) all-passwd all-putils WHAT_TO_INSTALL:=$(WHAT_TO_INSTALL) install-passwd install-putils +endif else WHAT_TO_BUILD:=$(WHAT_TO_BUILD) all-putils WHAT_TO_INSTALL:=$(WHAT_TO_INSTALL) install-putils @@ -73,36 +84,52 @@ all-misc: $(USRBIN.MISC) agetty.o: $(BSD)/pathnames.h agetty: agetty.o -chfn: chfn.o setpwnam.o -chsh: chsh.o setpwnam.o +chfn: chfn.o islocal.o setpwnam.o + $(CC) -o $@ $^ $(CRYPT) $(PAM) +chsh: chsh.o islocal.o setpwnam.o + $(CC) -o $@ $^ $(CRYPT) $(PAM) +islocal.o: $(BSD)/pathnames.h last.o: $(BSD)/pathnames.h last: last.o $(BSD)/getopt.o -login: login.o checktty.o + +ifeq "$(HAVE_PAM)" "yes" +login: login.o + $(CC) -o $@ $^ $(CRYPT) $(PAM) +else +login: login.o checktty.o + $(CC) -o $@ $^ $(CRYPT) +endif + mesg: mesg.o $(BSD)/getopt.o $(BSD)/err.o -newgrp.o: $(BSD)/pathnames.h -newgrp: newgrp.o +newgrp: newgrp.o + $(CC) -o $@ $^ $(CRYPT) $(PAM) setpwnam.o: $(BSD)/pathnames.h shutdown.o: $(BSD)/pathnames.h shutdown: shutdown.o simpleinit.o: $(BSD)/pathnames.h -simpleinit: simpleinit.o +simpleinit: simpleinit.o $(CRYPT) vipw.o: $(BSD)/pathnames.h vipw: vipw.o + +newgrp.o: $(BSD)/pathnames.h + $(CC) -c $(CFLAGS) $(PAMFL) newgrp.c + wall: wall.o ttymsg.o ifeq "$(USE_TTY_GROUP)" "yes" login.o: login.c $(BSD)/pathnames.h - $(CC) -c $(CFLAGS) -DUSE_TTY_GROUP login.c + $(CC) -c $(CFLAGS) $(PAMFL) -DUSE_TTY_GROUP login.c mesg.o: mesg.c $(BSD)/err.h $(CC) -c $(CFLAGS) -DUSE_TTY_GROUP mesg.c else login.o: $(BSD)/pathnames.h + $(CC) -c $(CFLAGS) $(PAMFL) login.c mesg.o: $(BSD)/err.h endif -passwd: passwd.o islocal.o setpwnam.o +passwd: passwd.o islocal.o setpwnam.o $(CRYPT) passwd.o: passwd.c - $(CC) -c $(CFLAGS) -DUSE_SETPWNAM passwd.c + $(CC) -c $(CFLAGS) passwd.c ifeq "$(REQUIRE_PASSWORD)" "yes" CHSH_FLAGS:=$(CHSH_FLAGS) -DREQUIRE_PASSWORD @@ -113,10 +140,10 @@ CHSH_FLAGS:=$(CHSH_FLAGS) -DONLY_LISTED_SHELLS endif chsh.o: chsh.c - $(CC) -c $(CFLAGS) $(CHSH_FLAGS) chsh.c + $(CC) -c $(CFLAGS) $(PAMFL) $(CHSH_FLAGS) chsh.c chfn.o: chfn.c - $(CC) -c $(CFLAGS) $(CHSH_FLAGS) chfn.c + $(CC) -c $(CFLAGS) $(PAMFL) $(CHSH_FLAGS) chfn.c install: all $(WHAT_TO_INSTALL) @@ -125,6 +152,7 @@ install-putils: $(BIN.PUTILS) $(USRBIN.PUTILS) $(USRSBIN.PUTILS) $(INSTALLSUID) $(BIN.PUTILS) $(BINDIR) $(INSTALLSUID) $(USRBIN.PUTILS) $(USRBINDIR) $(INSTALLBIN) $(USRSBIN.PUTILS) $(USRSBINDIR) + (cd $(USRSBINDIR); ln -sf vipw vigr) $(INSTALLDIR) $(MAN1DIR) $(MAN8DIR) $(INSTALLMAN) $(MAN1.PUTILS) $(MAN1DIR) $(INSTALLMAN) $(MAN8.PUTILS) $(MAN8DIR) diff --git a/login-utils/README.admutil b/login-utils/README.admutil index 3e25e84e..448f99f0 100644 --- a/login-utils/README.admutil +++ b/login-utils/README.admutil @@ -1,12 +1,51 @@ -README file for the admutils V1.16 for Linux. +README file for the admutils V1.23 for Linux. See installation instructions at the bottom. Currently the latest versions -of this software is maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ +of this software are maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ LICENSE: This software is distributed as is without any warranty what so ever. With respect to copyrights it is covered by the GNU Public License. +Version 1.24 (20-Jun-97) + Small patches for glibc compat. + +Version 1.23 (6-Jun-97): + Patch by Christophe Thaelemans to last.c, + no longer considers all users logged out in case of a run-level + change. + +Version 1.22 (28-Jan-97): + Clean-up release. + +Version 1.21c (27-Jan-97): + Updated setpwnam.[hc] to be in sync with util-linux 2.6, this + also prevents passwd from copying the entire passwd YP/NIS map + into the local /etc/passwd. Edited setpwnam.c somewhat to + improve error checking, beautify the code, and remove output + to stderr. + Fixed a couple of buffer overrun nits in passwd.c, patches from + David Holland. + +Version 1.21b (23-Jan-97): + Shutdown now supports a message on the command line, a'la + "shutdown -f +5 'for some reason'" + +Version 1.20 (2-Nov-96): + Fix by Steffen Zahn for shutdown.c so it + prints its final message. + +Version 1.19 (8-Jul-96): + Fix by faith@cs.unc.edu to allow C-A-D after halting in shutdown.c + +Version 1.18 (19-Nov-95): + passwd almost completely rewritten by Martin Schulze + to use setpwnam() and support + more long options. There's a new man-page as well. + Hacked some more on Martins passwd.c to support -s and -f options. + The old passwd.c is in the Attic/ sub-directory. + Bugfix in shutdown.c to fix file modes. + Version 1.17 (7-Oct-95): Added setrlimit() calls to passwd.c and chsh.c to fix security hole caused by resource limitations. Inspired by Zefram diff --git a/login-utils/README.modems-with-agetty b/login-utils/README.modems-with-agetty new file mode 100644 index 00000000..44a611e2 --- /dev/null +++ b/login-utils/README.modems-with-agetty @@ -0,0 +1,76 @@ +25/10/95 Peter Orbaek + +Some notes for using agetty with modems + +Using a comms program to initialize the modem +--------------------------------------------- + +* Use kermit or minicom to initialize the modem to + + - be entirely quiet. + - don't do local echo in command mode. + - turn on DCD (carrier detect) only when there is a connection going. + - enable auto-answer. + - keep a constant computer/modem bitrate at all times. + - optionally save this setup as the modem startup configuration. + +* Run agetty on the appropriate ttySn port with the arguments: + * -w to wait for a CR or LF before writing the /etc/issue message + * computer/modem bitrate + * the tty name. + +Example from my modem setup, an old 2400 bps SupraModem using Hayes standard +AT commands. + +Initialize modem using kermit with the commands + + AT E0 Q1 &D2 &C1 S0=1 &W0 + +to + - turn off local echo from modem when in command mode (E0). + - disable all result codes from modem (Q1). + - make an on/off transition on the DTR line make the modem + disconnect and go into command mode (&D2). + - make the computer/modem DCD line track the modem/modem + carrier detect signal, i.e. no connection means no + carrier detect signal to the computer (&C1). + - enable auto-answer after the first ring (S0=1). + - store the configuration as the start configuration (&W0). + +The commands on your modem to achieve the same setup may vary, especially +the &D2 and &C1 commands may not be entirely standard. + +Exit kermit/minicom. + +Put the command + + /sbin/agetty -w 2400 ttyS1 + +in the command field of the appropriate line in /etc/inittab to start +agetty on /dev/ttyS1 with a 2400 bps speed between modem and computer. + +Initializing the modem with agetty +---------------------------------- + +Use the agetty -I command line option to specify a modem init string, like +for the same setup as above, use the following agetty command in your +/etc/inittab. + + /sbin/agetty -w -I 'ATE0Q1&D2&C1S0=1\015' 2400 ttyS1 + +The final \015 is an octal coding of the carriage return character +ending the command string. + +If you're using simpleinit (part of this package) instead of the SYSV +compatible init (you're most likely using the SYSV one!) then you must +remove the single quotes from the command line above. + +Note that the &W0 command was not used here since the modem will be +initialized each time agetty starts. + +With a V.34 (28.8 kbps) modem try starting with a command like: + + /sbin/agetty -w -I 'ATE0Q1&D2&C1S0=1\015' 115200 ttyS1 + +Note that agetty supports the higher (>9600 bps) serial speeds +directly, there's no need to use setserial to use the higher speeds. diff --git a/login-utils/README.poeigl b/login-utils/README.poeigl index 5b6fac3f..5d30ec58 100644 --- a/login-utils/README.poeigl +++ b/login-utils/README.poeigl @@ -15,7 +15,81 @@ is different. If you are uncertain whether you got the latest version, check out - ftp://ftp.daimi.aau.dk:/pub/linux/poe/ + ftp://ftp.daimi.aau.dk/pub/linux/poe/ + +Version 1.49 (20-Jun-97) + Small patches for new util-linux distribution and glibc compat. + PAM support in login.c by Erik Troan. + +Version 1.48 (6-Jun-97) + Now changes mode and owner of /dev/vcs devices for console logins. + After idea by Andries Brouwer. + +Version 1.47 (2-Apr-97) + Got new version of hostid.c and hostid.1 from + Sander van Malssen . + Removed premature endutent() call in login.c, simpleinit.c and + agetty.c to be compatible with the changed semantics of gnu libc2. + Fix by Jesse Thilo . + +Version 1.46 (28-Jan-97) + Several security fixes for login by David Holland (buffer overruns) + + Fixed write.c, to handle a terminating period correctly. + Re-indented login.c, it was getting too messy. + +Version 1.45a (16-Dec-96) + Better support in login for shadow passwords. Compile with + -DSHADOW_PWD if you have . This is on by default. + By Marek Michalkiewicz . + Changed the wtmp locking scheme in login.c,agetty.c,simpleinit.c + to flock() /etc/wtmplock instead of the wtmp file directly. + This avoids a denial of service attack. + Some support for the RB-1 Cryptocard token for challenge/response + authentication. This needs a DES library, either Eric Young's + libdes, or the Koontz implementation, see cryptocard.c. + Initial support patch by Randolph Bentson, + + Changed getpass() to use fputs() instead of fprintf(). + +Version 1.44 (13-Nov-96): + Made isapty() in checktty.c more resilient to 2.0 systems + that haven't re-MAKEDEV'ed their pty devices. + +Version 1.43 (8-Nov-96): + Fix to checktty.c: PTY's are numbered differently after 1.3, + blush! Fix by Gerhard Schneider + +Version 1.42c (6-Nov-96): + Small fix by Gabriel M. Schuyler , to get + better syslog messages (1 LOGIN FAILURE instead of 2 LOGIN FAILURES). + Patch butchered by me. + +Version 1.42b (30-Sep-96): + Got patch for checktty.c from Christoph Lameter + so it doesn't traverse the groupfile + "manually" but uses the getgroups() call, this is more efficient + with large groupfiles and NIS/YP. + +Version 1.42a (24-Sep-96): + Added extra syslog() call to login.c to log all good logins. + Patch from Steve Philp. + +Version 1.41 (20-Jul-96): + Added security fix to checktty.c by JDS to clear certain lists. + Patches butchered and ANSI'fied by me. + Added -n option to agetty to avoid the login prompt. + +Version 1.40a (29-Dec-95): + Added -f option to agetty. Patches from Eric Rasmussen + , but somewhat butchered by me. + +Version 1.39 (25-Oct-95): + Lots of testing and bugfixes in agetty. Now the modem init stuff + should finally work (for me). Also wrote modem.agetty as an example + on how to use agetty with a modem. + Agetty now also supports baud rates of 38400, 57600, 115200 and + 230400 bps. Version 1.37 (15-Sep-95): Added -I and -w options to agetty.c for those that diff --git a/login-utils/agetty.8 b/login-utils/agetty.8 index f6a59909..ebbc2758 100644 --- a/login-utils/agetty.8 +++ b/login-utils/agetty.8 @@ -1,20 +1,33 @@ .TH AGETTY 8 -.ad -.fi .SH NAME agetty \- alternative Linux getty + .SH SYNOPSIS -.na -.nf -agetty [-ihLmw] [-l login_program] [-I init] [-t timeout] port baud_rate,... [term] -agetty [-ihLmw] [-l login_program] [-I init] [-t timeout] baud_rate,... port [term] +.BR "agetty " [\-ihLmnw] +.RI "[-f " issue_file ] +.RI "[-l " login_program ] +.RI "[-I " init ] +.RI "[-t " timeout ] +.I port +.I baud_rate,... +.RI [ term ] +.br +.BR "agetty " [\-ihLmnw] +.RI "[-f " issue_file ] +.RI "[-l " login_program ] +.RI "[-I " init ] +.RI "[-t " timeout ] +.I baud_rate,... +.I port +.RI [ term ] + .SH DESCRIPTION .ad .fi -\fIagetty\fP opens a tty port, prompts for a login name and invokes +\fBagetty\fP opens a tty port, prompts for a login name and invokes the /bin/login command. It is normally invoked by \fIinit(8)\fP. -\fIagetty\fP has several \fInon-standard\fP features that are useful +\fBagetty\fP has several \fInon-standard\fP features that are useful for hard-wired and for dial-in lines: .IP o Adapts the tty settings to parity bits and to erase, kill, @@ -30,8 +43,11 @@ Hayes(tm)-compatible modems. Optionally does not hang up when it is given an already opened line (useful for call-back applications). .IP o -Optionally does not display the contents of the \fI/etc/issue\fP file -(System V only). +Optionally does not display the contents of the \fI/etc/issue\fP file. +.IP o +Optionally displays an alternative issue file instead of \fI/etc/issue\fP. +.IP o +Optionally does not ask for a login name. .IP o Optionally invokes a non-standard login program instead of \fI/bin/login\fP. @@ -50,7 +66,7 @@ This program does not use the \fI/etc/gettydefs\fP (System V) or .TP port A path name relative to the \fI/dev\fP directory. If a "-" is -specified, \fIagetty\fP assumes that its standard input is +specified, \fBagetty\fP assumes that its standard input is already connected to a tty port and that a connection to a remote user has already been established. .sp @@ -59,7 +75,7 @@ by a "--". .TP baud_rate,... A comma-separated list of one or more baud rates. Each time -\fIagetty\fP receives a BREAK character it advances through +\fBagetty\fP receives a BREAK character it advances through the list, which is treated as if it were circular. .sp Baud rates should be specified in descending order, so that the @@ -74,18 +90,23 @@ whatever init(8) may have set, and is inherited by login and the shell. .fi .ad .TP --h +\-h Enable hardware (RTS/CTS) flow control. It is left up to the application to disable software (XON/XOFF) flow protocol where appropriate. .TP --i -Do not display the contents of \fI/etc/issue\fP before writing the +\-i +Do not display the contents of \fI/etc/issue\fP (or other) before writing the login prompt. Terminals or communications hardware may become confused when receiving lots of text at the wrong baud rate; dial-up scripts may fail if the login prompt is preceded by too much text. .TP --I initstring +\-f \fIissue_file\fP +Display the contents of \fIissue_file\fP instead of \fI/etc/issue\fP. +This allows custom messages to be displayed on different terminals. +The \-i option will override this option. +.TP +\-I \fIinitstring\fP Set an initial string to be sent to the tty or modem before sending anything else. This may be used to initialize a modem. Non printable characters may be sent by writing their octal code preceded by a @@ -93,59 +114,80 @@ backslash (\\). For example to send a linefeed character (ASCII 10, octal 012) write \\012. .PP .TP --l login_program +\-l \fIlogin_program\fP Invoke the specified \fIlogin_program\fP instead of /bin/login. This allows the use of a non-standard login program (for example, one that asks for a dial-up password or that uses a different password file). .TP --m -Try to extract the baud rate the \fIconnect\fP status message -produced by some Hayes(tm)-compatible modems. These status +\-m +Try to extract the baud rate the CONNECT status message +produced by Hayes(tm)\-compatible modems. These status messages are of the form: "". -\fIagetty\fP assumes that the modem emits its status message at +\fBagetty\fP assumes that the modem emits its status message at the same speed as specified with (the first) \fIbaud_rate\fP value on the command line. .sp -Since the \fI-m\fP feature may fail on heavily-loaded systems, +Since the \fI\-m\fP feature may fail on heavily-loaded systems, you still should enable BREAK processing by enumerating all expected baud rates on the command line. +.TP +\-n +Do not prompt the user for a login name. This can be used in +connection with \-l option to invoke a non-standard login process such +as a BBS system. Note that with the \-n option, \fBagetty\fR gets no input from +user who logs in and therefore won't be able to figure out parity, +character size, and newline processing of the connection. It defaults to +space parity, 7 bit characters, and ASCII CR (13) end-of-line character. +Beware that the program that \fBagetty\fR starts (usually /bin/login) +is run as root. .TP --t timeout +\-t \fItimeout\fP Terminate if no user name could be read within \fItimeout\fP seconds. This option should probably not be used with hard-wired lines. .TP --L -Force the line to be local line with no need for carrier detect. This can -be useful when you have locally attached terminal where the serial line +\-L +Force the line to be a local line with no need for carrier detect. This can +be useful when you have a locally attached terminal where the serial line does not set the carrier detect signal. .TP --w -Wait for the user or the modem to send a carriage-return or a linefeed -character before sending the /etc/issue file and the login prompt. +\-w +Wait for the user or the modem to send a carriage-return or a +linefeed character before sending the \fI/etc/issue\fP (or other) file +and the login prompt. Very useful in connection with the \-I option. .PP .SH EXAMPLES .na .nf -This section shows sample entries for the \fI/etc/inittab\fP file. +This section shows sample command entries for the \fI/etc/inittab\fP file. + +For a hard-wired line or a console tty: +.ti +5 +/sbin/agetty 9600 ttyS1 -For a hard-wired line: +For a directly connected terminal without proper carriage detect wiring: +(try this if your terminal just sleeps instead of giving you a password: +prompt.) .ti +5 -tty1:con80x60:/sbin/agetty 9600 tty1 +/sbin/agetty \-L 9600 ttyS1 vt100 -For a dial-in line with a 9600/2400/1200 baud modem: +For a old style dial-in line with a 9600/2400/1200 baud modem: .ti +5 -ttyS1:dumb:/sbin/agetty -mt60 ttyS1 9600,2400,1200 +/sbin/agetty \-mt60 ttyS1 9600,2400,1200 -These examples assume you use the simpleinit(8) init program for Linux. -If you use a SysV like init (does /etc/inittab mention "respawn"?), refer -to the appropriate manual page. +For a Hayes modem with a fixed 115200 bps interface to the machine: +(the example init string turns off modem echo and result codes, makes +modem/computer DCD track modem/modem DCD, makes a DTR drop cause a +dis-connection and turn on auto-answer after 1 ring.) +.ti +5 +/sbin/agetty \-w \-I 'ATE0Q1&D2&C1S0=1\\015' 115200 ttyS1 .SH ISSUE ESCAPES -The \fI/etc/issue\fP file may contain certain escape codes to display the -system name, date and time etc. All escape codes consist of a backslash -(\\) immediately followed by one of the letters explained below. +The issue-file (\fI/etc/issue\fP or the file set with the \-f option) +may contain certain escape codes to display the system name, date and +time etc. All escape codes consist of a backslash (\\) immediately +followed by one of the letters explained below. .TP b @@ -203,19 +245,19 @@ This is thingol.orcan.dk (Linux i386 1.1.9) 18:29:30 .na .nf /var/run/utmp, the system status file. -/etc/issue, printed before the login prompt (System V only). +/etc/issue, printed before the login prompt. /dev/console, problem reports (if syslog(3) is not used). -/etc/inittab (Linux simpleinit(8) configuration file). +/etc/inittab, \fIinit\fP(8) configuration file. .SH BUGS .ad .fi The baud-rate detection feature (the \fI-m\fP option) requires that -\fIagetty\fP be scheduled soon enough after completion of a dial-in +\fBagetty\fP be scheduled soon enough after completion of a dial-in call (within 30 ms with modems that talk at 2400 baud). For robustness, -always use the \fI-m\fP option in combination with a multiple baud +always use the \fI\-m\fP option in combination with a multiple baud rate command-line argument, so that BREAK processing is enabled. -The text in the /etc/issue file and the login prompt +The text in the \fI/etc/issue\fP file (or other) and the login prompt are always output with 7-bit characters and space parity. The baud-rate detection feature (the \fI-m\fP option) requires that @@ -237,7 +279,10 @@ Department of Mathematics and Computer Science Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands Peter Orbaek -Linux port. +Linux port and more options. Still maintains the code. + +Eric Rasmussen +Added \-f option to display custom login messages on different terminals. .SH CREATION DATE .na @@ -246,8 +291,4 @@ Sat Nov 25 22:51:05 MET 1989 .SH LAST MODIFICATION .na .nf -91/09/01 23:22:00 -.SH VERSION/RELEASE -.na -.nf -1.29 +96/07/20 diff --git a/login-utils/agetty.c b/login-utils/agetty.c index c7595bf3..ba28336b 100644 --- a/login-utils/agetty.c +++ b/login-utils/agetty.c @@ -2,6 +2,8 @@ Ported to Linux by Peter Orbaek This program is freely distributable. The entire man-page used to be here. Now read the real man-page agetty.8 instead. + + -f option added by Eric Rasmussen - 12/28/95 */ #ifndef lint @@ -25,7 +27,7 @@ char sccsid[] = "@(#) agetty.c 1.29 9/1/91 23:22:00"; #include #include -#ifdef linux +#ifdef __linux__ #include "pathnames.h" #include #define USE_SYSLOG @@ -111,8 +113,9 @@ extern void closelog(); * executable small on systems that do not have shared libraries (System V * Release <3). */ - +#ifndef BUFSIZ #define BUFSIZ 1024 +#endif /* * When multiple baud rates are specified on the command line, the first one @@ -129,10 +132,11 @@ struct options { int flags; /* toggle switches, see below */ int timeout; /* time-out period */ char *login; /* login program */ - int numspeed; /* number of baud rates to try */ - int speeds[MAX_SPEED]; /* baud rates to be tried */ char *tty; /* name of tty */ char *initstring; /* modem init string */ + char *issue; /* alternative issue file */ + int numspeed; /* number of baud rates to try */ + int speeds[MAX_SPEED]; /* baud rates to be tried */ }; #define F_PARSE (1<<0) /* process modem status messages */ @@ -141,6 +145,8 @@ struct options { #define F_LOCAL (1<<3) /* force local */ #define F_INITSTRING (1<<4) /* initstring is set */ #define F_WAITCRLF (1<<5) /* wait for CR or LF */ +#define F_CUSTISSUE (1<<6) /* give alternative issue file */ +#define F_NOPROMPT (1<<7) /* don't ask for login name! */ /* Storage for things detected while the login name was read. */ @@ -157,9 +163,52 @@ struct chardata { struct chardata init_chardata = { DEF_ERASE, /* default erase character */ DEF_KILL, /* default kill character */ - 0, /* always filled in at runtime */ + 13, /* default eol char */ 0, /* space parity */ - 0, /* always filled in at runtime */ + 0, /* no capslock */ +}; + +struct Speedtab { + long speed; + int code; +}; + +static struct Speedtab speedtab[] = { + { 50, B50 }, + { 75, B75 }, + { 110, B110 }, + { 134, B134 }, + { 150, B150 }, + { 200, B200 }, + { 300, B300 }, + { 600, B600 }, + { 1200, B1200 }, + { 1800, B1800 }, + { 2400, B2400 }, + { 4800, B4800 }, + { 9600, B9600 }, +#ifdef B19200 + { 19200, B19200 }, +#endif +#ifdef B38400 + { 38400, B38400 }, +#endif +#ifdef EXTA + { 19200, EXTA }, +#endif +#ifdef EXTB + { 38400, EXTB }, +#endif +#ifdef B57600 + { 57600, B57600 }, +#endif +#ifdef B115200 + { 115200, B115200 }, +#endif +#ifdef B230400 + { 230400, B230400 }, +#endif + { 0, 0 }, }; #define P_(s) () @@ -196,13 +245,16 @@ main(argc, argv) int argc; char **argv; { - char *logname; /* login name, given to /bin/login */ + char *logname = NULL; /* login name, given to /bin/login */ struct chardata chardata; /* set by get_logname() */ struct termio termio; /* terminal mode bits */ static struct options options = { F_ISSUE, /* show /etc/issue (SYSV_STYLE) */ 0, /* no timeout */ _PATH_LOGIN, /* default login program */ + "tty1", /* default tty line */ + "", /* modem init string */ + ISSUE, /* default issue file */ 0, /* no baud rates known yet */ }; @@ -215,7 +267,7 @@ main(argc, argv) #endif #ifdef DEBUGGING - dbf = fopen("/dev/tty1", "w"); + dbf = fopen("/dev/ttyp0", "w"); { int i; @@ -229,7 +281,7 @@ main(argc, argv) parse_args(argc, argv, &options); -#ifdef linux +#ifdef __linux__ setsid(); #endif @@ -239,10 +291,11 @@ main(argc, argv) update_utmp(options.tty); #endif + debug("calling open_tty\n"); /* Open the tty as standard { input, output, error }. */ open_tty(options.tty, &termio, options.flags & F_LOCAL); -#ifdef linux +#ifdef __linux__ { int iv; @@ -251,39 +304,50 @@ main(argc, argv) } #endif /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */ - + debug("calling termio_init\n"); termio_init(&termio, options.speeds[FIRST_SPEED], options.flags & F_LOCAL); - /* write the modem init string and flush the buffers */ + /* write the modem init string and DON'T flush the buffers */ if (options.flags & F_INITSTRING) { + debug("writing init string\n"); write(1, options.initstring, strlen(options.initstring)); - ioctl(1, TCFLSH, 2); } - /* Optionally detect the baud rate from the modem status message. */ + if (!(options.flags & F_LOCAL)) { + /* go to blocking write mode unless -L is specified */ + fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK); + } + /* Optionally detect the baud rate from the modem status message. */ + debug("before autobaud\n"); if (options.flags & F_PARSE) auto_baud(&termio); /* Set the optional timer. */ - if (options.timeout) (void) alarm((unsigned) options.timeout); - + /* optionally wait for CR or LF before writing /etc/issue */ if (options.flags & F_WAITCRLF) { char ch; + debug("waiting for cr-lf\n"); while(read(0, &ch, 1) == 1) { ch &= 0x7f; /* strip "parity bit" */ +#ifdef DEBUGGING + fprintf(dbf, "read %c\n", ch); +#endif if (ch == '\n' || ch == '\r') break; } } - /* Read the login name. */ - - while ((logname = get_logname(&options, &chardata, &termio)) == 0) - next_speed(&termio, &options); + chardata = init_chardata; + if (!(options.flags & F_NOPROMPT)) { + /* Read the login name. */ + debug("reading login name\n"); + while ((logname = get_logname(&options, &chardata, &termio)) == 0) + next_speed(&termio, &options); + } /* Disable timer. */ @@ -317,7 +381,7 @@ parse_args(argc, argv, op) extern int optind; /* getopt */ int c; - while (isascii(c = getopt(argc, argv, "I:Lhil:mt:w"))) { + while (isascii(c = getopt(argc, argv, "I:Lf:hil:mt:wn"))) { switch (c) { case 'I': if (!(op->initstring = malloc(strlen(optarg)))) { @@ -362,6 +426,10 @@ parse_args(argc, argv, op) case 'L': /* force local */ op->flags |= F_LOCAL; break; + case 'f': /* custom issue file */ + op->flags |= F_CUSTISSUE; + op->issue = optarg; + break; case 'h': /* enable h/w flow control */ op->flags |= F_RTSCTS; break; @@ -374,6 +442,9 @@ parse_args(argc, argv, op) case 'm': /* parse modem status message */ op->flags |= F_PARSE; break; + case 'n': + op->flags |= F_NOPROMPT; + break; case 't': /* time out */ if ((op->timeout = atoi(optarg)) <= 0) error("bad timeout value: %s", optarg); @@ -433,8 +504,8 @@ void update_utmp(line) char *line; { - struct utmp ut; - long ut_size = sizeof(ut); /* avoid nonsense */ + struct utmp ut; + time_t t; int ut_fd; int mypid = getpid(); long time(); @@ -451,7 +522,7 @@ update_utmp(line) * entry in the utmp file. */ -#ifdef linux +#ifdef __linux__ utmpname(_PATH_UTMP); setutent(); while ((utp = getutent()) @@ -465,27 +536,37 @@ update_utmp(line) memset(&ut, 0, sizeof(ut)); strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); } - endutent(); + /*endutent();*/ strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user)); strncpy(ut.ut_line, line, sizeof(ut.ut_line)); - time(&ut.ut_time); + time(&t); + ut.ut_time = t; ut.ut_type = LOGIN_PROCESS; ut.ut_pid = mypid; pututline(&ut); endutent(); - if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { - flock(ut_fd, LOCK_EX); - write(ut_fd, &ut, sizeof(ut)); - flock(ut_fd, LOCK_UN); - close(ut_fd); + { + int lf; + + if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { + flock(lf, LOCK_EX); + if ((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { + write(ut_fd, &ut, sizeof(ut)); + close(ut_fd); + } + flock(lf, LOCK_UN); + close(lf); + } } #else if ((ut_fd = open(UTMP_FILE, 2)) < 0) { error("%s: open for update: %m", UTMP_FILE); } else { + long ut_size = sizeof(ut); /* avoid nonsense */ + while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) { if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) { ut.ut_type = LOGIN_PROCESS; @@ -500,7 +581,7 @@ update_utmp(line) } error("%s: no utmp entry", line); } -#endif /* linux */ +#endif /* __linux__ */ } #endif @@ -537,7 +618,8 @@ open_tty(tty, tp, local) (void) close(0); errno = 0; /* ignore close(2) errors */ - if (open(tty, (local ? O_RDWR|O_NONBLOCK : O_RDWR), 0) != 0) + debug("open(2)\n"); + if (open(tty, O_RDWR|O_NONBLOCK, 0) != 0) error("/dev/%s: cannot open as standard input: %m", tty); } else { @@ -552,7 +634,7 @@ open_tty(tty, tp, local) } /* Set up standard output and standard error file descriptors. */ - + debug("duping\n"); if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */ error("%s: dup problem: %m", tty); /* we have a problem */ @@ -598,9 +680,9 @@ termio_init(tp, speed, local) * reads will be done in raw mode anyway. Errors will be dealt with * lateron. */ -#ifdef linux - /* flush input and output queues, important for modems! */ - (void) ioctl(0, TCFLSH, 2); +#ifdef __linux__ + /* flush input and output queues, important for modems! */ + (void) ioctl(0, TCFLSH, TCIOFLUSH); #endif tp->c_cflag = CS8 | HUPCL | CREAD | speed; @@ -612,9 +694,10 @@ termio_init(tp, speed, local) tp->c_cc[VMIN] = 1; tp->c_cc[VTIME] = 0; (void) ioctl(0, TCSETA, tp); - if (local) { - (void) fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NDELAY); - } + + /* go to blocking input even in local mode */ + fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); + debug("term_io 2\n"); } @@ -698,7 +781,7 @@ do_prompt(op, tp) (void) write(1, "\r\n", 2); /* start a new line */ #ifdef ISSUE /* optional: show /etc/issue */ - if ((op->flags & F_ISSUE) && (fd = fopen(ISSUE, "r"))) { + if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) { oflag = tp->c_oflag; /* save current setting */ tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */ (void) ioctl(0, TCSETAW, tp); @@ -733,8 +816,14 @@ do_prompt(op, tp) break; case 'o': - (void) printf ("%s", uts.domainname); - break; + { + char domainname[256]; + + getdomainname(domainname, sizeof(domainname)); + domainname[sizeof(domainname)-1] = '\0'; + printf ("%s", domainname); + } + break; case 'd': case 't': @@ -769,13 +858,15 @@ do_prompt(op, tp) case 'b': { - char *zpeedz[] = { "0", "50", "75", "110", "134.5", - "150", "200", "300", "600", "1200", - "1800", "2400", "4800", "9600", - "19200", "38400" }; + int i; - (void) printf ("%s", zpeedz[tp->c_cflag & CBAUD]); - break; + for (i = 0; speedtab[i].speed; i++) { + if (speedtab[i].code == (tp->c_cflag & CBAUD)) { + printf("%ld", speedtab[i].speed); + break; + } + } + break; } case 'u': case 'U': @@ -806,7 +897,7 @@ do_prompt(op, tp) (void) fclose(fd); } #endif -#ifdef linux +#ifdef __linux__ { char hn[MAXHOSTNAMELEN+1]; @@ -858,7 +949,7 @@ char *get_logname(op, cp, tp) /* Flush pending input (esp. after parsing or switching the baud rate). */ (void) sleep(1); - (void) ioctl(0, TCFLSH, (struct termio *) 0); + (void) ioctl(0, TCFLSH, TCIFLUSH); /* Prompt for and read a login name. */ @@ -960,7 +1051,7 @@ termio_final(op, tp, cp) tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ tp->c_cc[VEOL] = DEF_EOL; -#ifdef linux +#ifdef __linux__ tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ #else tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */ @@ -1033,38 +1124,6 @@ int bcode(s) char *s; { - struct Speedtab { - long speed; - int code; - }; - static struct Speedtab speedtab[] = { - 50, B50, - 75, B75, - 110, B110, - 134, B134, - 150, B150, - 200, B200, - 300, B300, - 600, B600, - 1200, B1200, - 1800, B1800, - 2400, B2400, - 4800, B4800, - 9600, B9600, -#ifdef B19200 - 19200, B19200, -#endif -#ifdef B38400 - 38400, B38400, -#endif -#ifdef EXTA - 19200, EXTA, -#endif -#ifdef EXTB - 38400, EXTB, -#endif - 0, 0, - }; struct Speedtab *sp; long speed = atol(s); @@ -1079,15 +1138,11 @@ bcode(s) void usage() { -#if defined(SYSV_STYLE) && !defined(linux) static char msg[] = - "[-i] [-l login_program] [-m] [-t timeout] line baud_rate,..."; -#else - static char msg[] = - "[-h] [-l login_program] [-m] [-t timeout] baud_rate,... line"; -#endif + "[-hiLmw] [-l login_program] [-t timeout] [-I initstring] baud_rate,... line [termtype]\nor\t[-hiLmw] [-l login_program] [-t timeout] [-I initstring] line baud_rate,... [termtype]"; - error("usage: %s %s", progname, msg); + fprintf(stderr, "Usage: %s %s\n", progname, msg); + exit(1); } /* error - report errors to console or syslog; only understands %s and %m */ @@ -1157,7 +1212,7 @@ error(va_alist) */ #ifdef USE_SYSLOG - (void) openlog(progname, LOG_PID, LOG_AUTH); + (void) openlog(progname, LOG_PID, LOG_AUTHPRIV); (void) syslog(LOG_ERR, "%s", buf); closelog(); #else diff --git a/login-utils/checktty.c b/login-utils/checktty.c index 8daa1720..e5d03815 100644 --- a/login-utils/checktty.c +++ b/login-utils/checktty.c @@ -1,7 +1,13 @@ /* checktty.c - linked into login, checks user against /etc/usertty Created 25-Aug-95 by Peter Orbaek + Fixed by JDS June 1996 to clear lists and close files */ +#define _GNU_SOURCE /* for snprintf */ + +#include +#include + #include #include #include @@ -14,7 +20,7 @@ #include #include -#ifdef linux +#ifdef __linux__ # include # include #endif @@ -22,7 +28,7 @@ #include "pathnames.h" /* functions in login.c */ -void badlogin(char *s); +void badlogin(const char *s); void sleepexit(int); extern struct hostent hostaddress; extern char *hostname; @@ -32,7 +38,7 @@ struct hostent hostaddress; char *hostname; void -badlogin(char *s) +badlogin(const char *s) { printf("badlogin: %s\n", s); } @@ -45,6 +51,9 @@ sleepexit(int x) } #endif +static gid_t mygroups[NGROUPS]; +static int num_groups; + #define NAMELEN 128 /* linked list of names */ @@ -52,9 +61,7 @@ struct grplist { struct grplist *next; char name[NAMELEN]; }; - -struct grplist *mygroups = NULL; - + enum State { StateUsers, StateGroups, StateClasses }; #define CLASSNAMELEN 32 @@ -67,57 +74,25 @@ struct ttyclass { struct ttyclass *ttyclasses = NULL; -static void -add_group(char *group) -{ - struct grplist *ge; - - ge = (struct grplist *)malloc(sizeof(struct grplist)); - - /* we can't just bail out at this stage! */ - if (!ge) { - printf("login: memory low, login may fail\n"); - syslog(LOG_WARNING, "can't malloc grplist"); - return; - } - - ge->next = mygroups; - strncpy(ge->name, group, NAMELEN); - mygroups = ge; -} - static int am_in_group(char *group) { - struct grplist *ge; - - for (ge = mygroups; ge; ge = ge->next) { - if (strcmp(ge->name, group) == 0) return 1; - } - return 0; + struct group *g; + gid_t *ge; + + g = getgrnam(group); + if (g) { + for (ge = mygroups; ge < mygroups + num_groups; ge++) { + if (g->gr_gid== *ge) return 1; + } + } + return 0; } static void -find_groups(gid_t defgrp, char *user) +find_groups(gid_t defgrp, const char *user) { - struct group *gp; - char **p; - - setgrent(); - while ((gp = getgrent())) { - if (gp->gr_gid == defgrp) { - add_group(gp->gr_name); - } else { - for(p = gp->gr_mem; *p; p++) { - if (strcmp(user, *p) == 0) { - add_group(gp->gr_name); - break; - } - } - } - - } - endgrent(); + num_groups = getgroups(NGROUPS, mygroups); } static struct ttyclass * @@ -135,6 +110,7 @@ new_class(char *class) tc->next = ttyclasses; tc->first = NULL; strncpy(tc->classname, class, CLASSNAMELEN); + tc->classname[CLASSNAMELEN-1] = 0; ttyclasses = tc; return tc; } @@ -155,21 +131,30 @@ add_to_class(struct ttyclass *tc, char *tty) ge->next = tc->first; strncpy(ge->name, tty, NAMELEN); + ge->name[NAMELEN-1] = 0; tc->first = ge; } /* return true if tty is a pty. Very linux dependent */ static int -isapty(tty) - char *tty; +isapty(const char *tty) { char devname[100]; struct stat stb; -#ifdef linux - strcpy(devname, "/dev/"); - strncat(devname, tty, 80); + snprintf(devname, sizeof(devname), "/dev/%s", tty); + +#if defined(__linux__) && defined(PTY_SLAVE_MAJOR) + /* this is for linux 1.3 and newer */ + if((stat(devname, &stb) >= 0) + && major(stb.st_rdev) == PTY_SLAVE_MAJOR) { + return 1; + } +#endif + +#if defined(__linux__) + /* this is for linux versions before 1.3, backward compat. */ if((stat(devname, &stb) >= 0) && major(stb.st_rdev) == TTY_MAJOR && minor(stb.st_rdev) >= 192) { @@ -181,9 +166,7 @@ isapty(tty) /* match the hostname hn against the pattern pat */ static int -hnmatch(hn, pat) - char *hn; - char *pat; +hnmatch(const char *hn, const char *pat) { int x1, x2, x3, x4, y1, y2, y3, y4; unsigned long p, mask, a; @@ -260,7 +243,7 @@ timeok(struct tm *t, char *spec) Also return true if hostname matches the hostname pattern, class or a pattern in the class named by class. */ static int -in_class(char *tty, char *class) +in_class(const char *tty, char *class) { struct ttyclass *tc; struct grplist *ge; @@ -276,7 +259,8 @@ in_class(char *tty, char *class) if (class[0] == '[') { if ((p = strchr(class, ']'))) { *p = 0; - strcpy(timespec, class+1); + strncpy(timespec, class+1, sizeof(timespec)); + timespec[sizeof(timespec)-1] = 0; *p = ']'; if(!timeok(tm, timespec)) return 0; class = p+1; @@ -297,7 +281,8 @@ in_class(char *tty, char *class) if (n[0] == '[') { if ((p = strchr(n, ']'))) { *p = 0; - strcpy(timespec, n+1); + strncpy(timespec, n+1, sizeof(timespec)); + timespec[sizeof(timespec)-1] = 0; *p = ']'; if(!timeok(tm, timespec)) continue; n = p+1; @@ -316,11 +301,41 @@ in_class(char *tty, char *class) return 0; } +/* start JDS - SBA */ +void +free_group(struct grplist *ge) +{ + if (ge) { + memset(ge->name, 0, NAMELEN); + free_group(ge->next); + free(ge->next); + ge->next = NULL; + } +} + +void +free_class(struct ttyclass *tc) +{ + if (tc) { + memset(tc->classname, 0, CLASSNAMELEN); + free_group(tc->first); + tc->first = NULL; + free_class(tc->next); + free(tc->next); + tc->next = NULL; + } +} + +void +free_all(void) +{ + free_class(ttyclasses); + ttyclasses = NULL; +} +/* end JDS - SBA */ + void -checktty(user, tty, pwd) - char *user; - char *tty; - struct passwd *pwd; +checktty(const char *user, const char *tty, struct passwd *pwd) { FILE *f; char buf[256], defaultbuf[256]; @@ -335,7 +350,10 @@ checktty(user, tty, pwd) if (!(f = fopen(_PATH_USERTTY, "r"))) return; #endif - if (pwd == NULL) return; /* misspelled username handled elsewhere */ + if (pwd == NULL) { + fclose(f); + return; /* misspelled username handled elsewhere */ + } find_groups(pwd->pw_gid, user); @@ -348,6 +366,7 @@ checktty(user, tty, pwd) if (buf[0] == '*') { strncpy(defaultbuf, buf, 256); + defaultbuf[255] = 0; continue; } @@ -369,6 +388,7 @@ checktty(user, tty, pwd) while((ptr = strtok(NULL, "\t\n "))) { if (in_class(tty, ptr)) { fclose(f); + free_all(); /* JDS */ return; } } @@ -388,7 +408,10 @@ checktty(user, tty, pwd) if (defaultbuf[0]) { strtok(defaultbuf, " \t"); while((ptr = strtok(NULL, "\t\n "))) { - if (in_class(tty, ptr)) return; + if (in_class(tty, ptr)) { + free_all(); /* JDS */ + return; + } } /* there was a default rule, but user didn't match, reject! */ @@ -410,6 +433,7 @@ checktty(user, tty, pwd) /* users not matched in /etc/usertty are by default allowed access on all tty's */ + free_all(); /* JDS */ } #ifdef TESTING diff --git a/login-utils/chfn.c b/login-utils/chfn.c index 207bcb25..e81c5c18 100644 --- a/login-utils/chfn.c +++ b/login-utils/chfn.c @@ -6,16 +6,25 @@ * modify it under the terms of the gnu general public license. * there is no warranty. * - * $Author: faith $ - * $Revision: 1.8 $ - * $Date: 1995/10/12 14:46:35 $ + * $Author: aebr $ + * $Revision: 1.15 $ + * $Date: 1997/07/06 23:10:41 $ * * Updated Thu Oct 12 09:19:26 1995 by faith@cs.unc.edu with security * patches from Zefram * + * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, + * to allow peaceful coexistence with yp: using the changes by + * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from + * passwd.c (now moved to setpwnam.c); + * to remove trailing empty fields. Oct 5, 96. + * */ -static char rcsId[] = "$Version: $Id: chfn.c,v 1.8 1995/10/12 14:46:35 faith Exp $ $"; +static char rcsId[] = "$Version: $Id: chfn.c,v 1.15 1997/07/06 23:10:41 aebr Exp $ $"; + +#define _XOPEN_SOURCE /* for crypt() */ +#define _BSD_SOURCE /* for strcasecmp() */ #include #include @@ -26,6 +35,14 @@ static char rcsId[] = "$Version: $Id: chfn.c,v 1.8 1995/10/12 14:46:35 faith Exp #include #include #include +#include "../version.h" + +#if REQUIRE_PASSWORD && USE_PAM +#include +#include +#endif + +extern int is_local(char *); #undef P #if __STDC__ @@ -38,7 +55,6 @@ typedef unsigned char boolean; #define false 0 #define true 1 -static char *version_string = "chfn 0.9a beta"; static char *whoami; static char buf[1024]; @@ -62,10 +78,9 @@ static int check_gecos_string P((char *msg, char *gecos)); static boolean set_changed_data P((struct finfo *oldfp, struct finfo *newfp)); static int save_new_data P((struct finfo *pinfo)); static void *xmalloc P((int bytes)); -#if 0 -extern int strcasecmp P((char *, char *)); + extern int setpwnam P((struct passwd *pwd)); -#endif + #define memzero(ptr, size) memset((char *) ptr, 0, size) int main (argc, argv) @@ -78,6 +93,11 @@ int main (argc, argv) boolean interactive; int status; extern int errno; +#if REQUIRE_PASSWORD && USE_PAM + pam_handle_t *pamh = NULL; + int retcode; + struct pam_conv conv = { misc_conv, NULL }; +#endif /* whoami is the program name for error messages */ whoami = argv[0]; @@ -114,7 +134,13 @@ int main (argc, argv) return (-1); } } - /* reality check */ + if (!(is_local(oldf.username))) { + fprintf (stderr, "%s: can only change local entries; use yp%s instead.\n", + whoami, whoami); + exit(1); + } + + /* Reality check */ if (uid != 0 && uid != oldf.pw->pw_uid) { errno = EACCES; perror (whoami); @@ -124,6 +150,31 @@ int main (argc, argv) printf ("Changing finger information for %s.\n", oldf.username); #if REQUIRE_PASSWORD +# if USE_PAM + if(uid != 0) { + if (pam_start("chfn", oldf.username, &conv, &pamh)) { + puts("Password error."); + exit(1); + } + if (pam_authenticate(pamh, 0)) { + puts("Password error."); + exit(1); + } + retcode = pam_acct_mgmt(pamh, 0); + if (retcode == PAM_AUTHTOKEN_REQD) { + retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } else if (retcode) { + puts("Password error."); + exit(1); + } + if (pam_setcred(pamh, 0)) { + puts("Password error."); + exit(1); + } + /* no need to establish a session; this isn't a session-oriented + * activity... */ + } +# else /* USE_PAM */ /* require password, unless root */ if(uid != 0 && oldf.pw->pw_passwd && oldf.pw->pw_passwd[0]) { pwdstr = getpass("Password: "); @@ -133,7 +184,8 @@ int main (argc, argv) exit(1); } } -#endif +# endif /* USE_PAM */ +#endif /* REQUIRE_PASSWORD */ if (interactive) ask_info (&oldf, &newf); @@ -176,7 +228,7 @@ static boolean parse_argv (argc, argv, pinfo) if (c == EOF) break; /* version? output version and exit. */ if (c == 'v') { - printf ("%s\n", version_string); + printf ("%s\n", util_linux_version); exit (0); } if (c == 'u') { @@ -191,7 +243,10 @@ static boolean parse_argv (argc, argv, pinfo) /* ok, we were given an argument */ info_given = true; status = 0; - strcpy (buf, whoami); strcat (buf, ": "); + + strncpy (buf, whoami, sizeof(buf)-128); + buf[sizeof(buf)-128-1] = 0; + strcat (buf, ": "); /* now store the argument */ switch (c) { @@ -404,6 +459,12 @@ static int save_new_data (pinfo) sprintf (gecos, "%s,%s,%s,%s,%s", pinfo->full_name, pinfo->office, pinfo->office_phone, pinfo->home_phone, pinfo->other); + /* remove trailing empty fields (but not subfields of pinfo->other) */ + if (! pinfo->other[0] ) { + while (len > 0 && gecos[len-1] == ',') len--; + gecos[len] = 0; + } + /* write the new struct passwd to the passwd file. */ pinfo->pw->pw_gecos = gecos; if (setpwnam (pinfo->pw) < 0) { diff --git a/login-utils/chsh.c b/login-utils/chsh.c index 9ffd81b2..3cafc966 100644 --- a/login-utils/chsh.c +++ b/login-utils/chsh.c @@ -6,17 +6,27 @@ * modify it under the terms of the gnu general public license. * there is no warranty. * - * $Author: faith $ - * $Revision: 1.8 $ - * $Date: 1995/10/12 14:46:35 $ + * $Author: aebr $ + * $Revision: 1.16 $ + * $Date: 1997/07/06 00:12:08 $ * * Updated Thu Oct 12 09:33:15 1995 by faith@cs.unc.edu with security - * patches from Zefram + * patches from Zefram + * + * Updated Mon Jul 1 18:46:22 1996 by janl@math.uio.no with security + * suggestion from Zefram. Disallowing users with shells not in /etc/shells + * from changing their shell. + * + * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, + * to allow peaceful coexistence with yp: using the changes by + * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from + * passwd.c (now moved to setpwnam.c). Oct 5, 96. * */ -static char rcsId[] = "$Version: $Id: chsh.c,v 1.8 1995/10/12 14:46:35 faith Exp $ $"; +static char rcsId[] = "$Version: $Id: chsh.c,v 1.16 1997/07/06 00:12:08 aebr Exp $ $"; +#define _XOPEN_SOURCE /* to get definition of crypt() */ #if 0 #define _POSIX_SOURCE 1 #endif @@ -30,6 +40,14 @@ static char rcsId[] = "$Version: $Id: chsh.c,v 1.8 1995/10/12 14:46:35 faith Exp #include #include #include +#include "../version.h" + +#if REQUIRE_PASSWORD && USE_PAM +#include +#include +#endif + +extern int is_local(char *); #undef P #if __STDC__ @@ -42,7 +60,10 @@ typedef unsigned char boolean; #define false 0 #define true 1 -static char *version_string = "chsh 0.9a beta"; +/* Only root is allowed to assign a luser a non-listed shell, by default */ +#define ONLY_LISTED_SHELLS 1 + + static char *whoami; static char buf[FILENAME_MAX]; @@ -70,6 +91,11 @@ int main (argc, argv) struct sinfo info; struct passwd *pw; extern int errno; +#if REQUIRE_PASSWORD && USE_PAM + pam_handle_t *pamh = NULL; + int retcode; + struct pam_conv conv = { misc_conv, NULL }; +#endif /* whoami is the program name for error messages */ whoami = argv[0]; @@ -96,21 +122,21 @@ int main (argc, argv) return (-1); } } + if (!(is_local(pw->pw_name))) { + fprintf (stderr, "%s: can only change local entries; use yp%s instead.\n +", + whoami, whoami); + exit(1); + } + oldshell = pw->pw_shell; if (!oldshell[0]) oldshell = "/bin/sh"; /* reality check */ -#if 0 - /* Require current shell to be in list. - This is not a reasonable expectation on - most Linux systems, and the error is - confusing. */ if (uid != 0 && (uid != pw->pw_uid || !get_shell_list(oldshell))) { -#else - if (uid != 0 && uid != pw->pw_uid) { -#endif errno = EACCES; - perror (whoami); + fprintf(stderr,"%s: Your shell is not in /etc/shells, shell change" + " denied\n",whoami); return (-1); } @@ -118,16 +144,43 @@ int main (argc, argv) printf( "Changing shell for %s.\n", pw->pw_name ); -#ifdef REQUIRE_PASSWORD +#if REQUIRE_PASSWORD +# if USE_PAM + if(uid != 0) { + if (pam_start("chsh", pw->pw_name, &conv, &pamh)) { + puts("Password error."); + exit(1); + } + if (pam_authenticate(pamh, 0)) { + puts("Password error."); + exit(1); + } + retcode = pam_acct_mgmt(pamh, 0); + if (retcode == PAM_AUTHTOKEN_REQD) { + retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } else if (retcode) { + puts("Password error."); + exit(1); + } + if (pam_setcred(pamh, 0)) { + puts("Password error."); + exit(1); + } + /* no need to establish a session; this isn't a session-oriented + * activity... */ + } +# else /* USE_PAM */ /* require password, unless root */ if(uid != 0 && pw->pw_passwd && pw->pw_passwd[0]) { pwdstr = getpass("Password: "); - if(strncmp(pw->pw_passwd, crypt(pwdstr, pw->pw_passwd), 13)) { + if(strncmp(pw->pw_passwd, + crypt(pwdstr, pw->pw_passwd), 13)) { puts("Incorrect password."); exit(1); } } -#endif +# endif /* USE_PAM */ +#endif /* REQUIRE_PASSWORD */ if (! shell) { shell = prompt ("New shell", oldshell); @@ -178,7 +231,7 @@ static void parse_argv (argc, argv, pinfo) case EOF: break; case 'v': - printf ("%s\n", version_string); + printf ("%s\n", util_linux_version); exit (0); case 'u': usage (stdout); @@ -246,7 +299,7 @@ static char *prompt (question, def_val) if (len <= 0) return NULL; ans[len] = 0; cp = (char *) xmalloc (len + 1); - strcpy (cp, buf); + strcpy (cp, ans); return cp; } @@ -287,17 +340,17 @@ static int check_shell (shell) #if ONLY_LISTED_SHELLS if (! get_shell_list (shell)) { if (!getuid()) - printf ("Warning: \"%s\" is not listed as a valid shell.\n", shell); + printf ("Warning: \"%s\" is not listed in /etc/shells\n", shell); else { - printf ("%s: \"%s\" is not listed as a valid shell.\n", + printf ("%s: \"%s\" is not listed in /etc/shells.\n", whoami, shell); - printf( "%s: use -l option to see list\n" ); + printf( "%s: use -l option to see list\n", whoami ); exit(1); } } #else if (! get_shell_list (shell)) { - printf ("Warning: \"%s\" is not listed as a valid shell.\n", shell); + printf ("Warning: \"%s\" is not listed in /etc/shells.\n", shell); printf( "Use %s -l to see list.\n", whoami ); } #endif diff --git a/login-utils/cryptocard.c b/login-utils/cryptocard.c new file mode 100644 index 00000000..e735c727 --- /dev/null +++ b/login-utils/cryptocard.c @@ -0,0 +1,222 @@ +/* cryptocard.c - support for the CRYPTOCard + RB-1 Challenge-Response Token, initial code by + bentson@grieg.seaslug.org (Randolph Bentson) on 3-Dec-96, + Hacked severely by poe@daimi.aau.dk. + This relies on an implementation of DES in a library, currently + it interfaces with the koontz-des.tar.gz implementation which + can be found in: + + ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/des/ + + (Link with the fdes.o file from that distribution) + + and with Eric A. Young's libdes implementation used in SSLeay. Also + available from the above ftp site. Link with the libdes.a library. + + The sources for this code are maintained in + + ftp://ftp.daimi.aau.dk/pub/linux/poe/poeigl-X.XX.tar.gz +*/ +#ifdef CRYPTOCARD + +/******************** CONFIGURATION section *****************************/ +/*--------------- select ONE DES implementation ------------------------*/ +/*#define KOONTZ_DES */ +#define EAY_LIBDES +/*--------------- define if on little endian machine (Intel x86) -------*/ +#define LITTLE_ENDIAN +/******************** end of CONFIGURATION section **********************/ + +#define _BSD_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KOONTZ_DES +#include "../koontz-des/des.h" +#endif /* KOONTZ_DES */ + +#ifdef EAY_LIBDES +#include "../libdes/des.h" +#endif /* EAY_LIBDES */ + +extern char *getpass(const char *prompt); +extern struct passwd *pwd; +extern int timeout; + +static char * +generate_challenge(void) +{ + static char challenge_str[30]; + int rfd; + unsigned long clong; + + /* create and present a challenge string */ + if ((rfd = open("/dev/urandom", O_RDONLY)) < 0) { + syslog(LOG_NOTICE, "couldn't open /dev/urandom"); + return NULL; + } + if (read(rfd, &clong, 4) < 4) { + close(rfd); + syslog(LOG_NOTICE, "couldn't read random data from /dev/urandom"); + return NULL; + } + close(rfd); + + sprintf(challenge_str,"%08lu", clong); + return challenge_str; +} + +static char * +get_key() +{ + int success = 0; + char keyfile[MAXPATHLEN]; + static char key[10]; + int rfd; + struct stat statbuf; + + snprintf(keyfile, sizeof(keyfile), "%s/.cryptocard", pwd->pw_dir); + + if ((rfd = open(keyfile, O_RDONLY)) < 0) { + syslog(LOG_NOTICE, "can't open %s for reading", keyfile); + goto bail_out; + } + if (fstat(rfd, &statbuf) < 0) { + syslog(LOG_NOTICE, "can't stat(%s)", keyfile); + goto close_and_bail_out; + } + if ((statbuf.st_uid != pwd->pw_uid) + || ((statbuf.st_mode & S_IFMT) != S_IFREG) + || (statbuf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) { + syslog(LOG_NOTICE, "%s doesn't have the correct filemodes", keyfile); + goto close_and_bail_out; + } + + if (read(rfd, key, 8) < 8) { + syslog(LOG_NOTICE, "can't read data from %s", keyfile); + goto close_and_bail_out; + } + + key[8] = 0; + success = 1; + +close_and_bail_out: + close(rfd); + +bail_out: + if (success) + return key; + else + return NULL; +} + +static int +check_response(char *challenge, char *response, char *key) +{ + char buf[20]; + +#ifdef KOONTZ_DES + extern void des (union LR_block *); + extern void loadkey(char *,int); + extern void set_des_mode(int); + + union LR_block data; + + strncpy((char *)data.string, (char *)challenge, 8); + set_des_mode(ENCRYPT); + loadkey(key, NOSHIFT); + des(&data); + + memset(key, 0, 8); /* no need for the secret key anymore, scratch it */ + + sprintf(buf, "%2.2X%2.2X%2.2X%2.2X", + (int)(data.LR[0]) & 0xff, + (int)(data.LR[0]>>8) & 0xff, + (int)(data.LR[0]>>16) & 0xff, + (int)(data.LR[0]>>24) & 0xff); +#endif /* KOONTZ_DES */ +#ifdef EAY_LIBDES + des_cblock res; + des_key_schedule ks; + + des_set_key((des_cblock *)key, ks); + memset(key, 0, 8); + des_ecb_encrypt((des_cblock *)challenge, &res, ks, DES_ENCRYPT); + +#ifdef LITTLE_ENDIAN + /* use this on Intel x86 boxes */ + sprintf(buf, "%2.2X%2.2X%2.2X%2.2X", + res[0], res[1], res[2], res[3]); +#else /* ie. BIG_ENDIAN */ + /* use this on big endian RISC boxes */ + sprintf(buf, "%2.2X%2.2X%2.2X%2.2X", + res[3], res[2], res[1], res[0]); +#endif /* LITTLE_ENDIAN */ +#endif /* EAY_LIBDES */ + + /* return success only if ALL requirements have been met */ + if (strncmp(buf, response, 8) == 0) + return 1; + + return 0; +} + +int +cryptocard(void) +{ + char prompt[80]; + char *challenge; + char *key; + char *response; + + challenge = generate_challenge(); + if (challenge == NULL) return 0; + + snprintf(prompt, sizeof(prompt), "%s Password: ", challenge); + + alarm((unsigned int)timeout); /* give user time to fiddle with card */ + response = getpass(prompt); /* presents challenge and gets response */ + + if (response == NULL) return 0; + + /* This requires some explanation: As root we may not be able to + read the directory of the user if it is on an NFS mounted + filesystem. We temporarily set our effective uid to the user-uid + making sure that we keep root privs. in the real uid. + + A portable solution would require a fork(), but we rely on Linux + having the BSD setreuid() */ + + { + uid_t ruid = getuid(); + gid_t egid = getegid(); + + setregid(-1, pwd->pw_gid); + setreuid(0, pwd->pw_uid); + + /* now we can access the file */ + /* get the (properly qualified) key */ + key = get_key(); + + /* reset to root privs */ + setuid(0); /* setreuid doesn't do it alone! */ + setreuid(ruid, 0); + setregid(-1, egid); + + if (key == NULL) return 0; + } + + return check_response(challenge, response, key); +} + +#endif /* CRYPTOCARD */ diff --git a/login-utils/islocal.c b/login-utils/islocal.c index a4cfb16a..5480c574 100644 --- a/login-utils/islocal.c +++ b/login-utils/islocal.c @@ -1,13 +1,22 @@ -/* islocal.c - returns true if user is registered in the local +/* + islocal.c - returns true if user is registered in the local /etc/passwd file. Written by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, to allow peaceful coexistence with yp. Nov 94. + Hacked a bit by poe@daimi.aau.dk See also ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil* + + Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, + to distinguish user names where one is a prefix of the other, + and to use "pathnames.h". Oct 5, 96. + */ #include #include +#include "pathnames.h" + #define MAX_LENGTH 1024 int @@ -16,14 +25,16 @@ is_local(char *user) FILE *fd; char line[MAX_LENGTH]; int local = 0; + int len; - if(!(fd = fopen("/etc/passwd", "r"))) { - puts("Can't read /etc/passwd, exiting."); + if(!(fd = fopen(_PATH_PASSWD, "r"))) { + fprintf(stderr,"Can't read %s, exiting.",_PATH_PASSWD); exit(1); } + len = strlen(user); while(fgets(line, MAX_LENGTH, fd) > 0) { - if(!strncmp(line, user, strlen(user))) { + if(!strncmp(line, user, len) && line[len] == ':') { local = 1; break; } diff --git a/login-utils/last.c b/login-utils/last.c index bc829497..fa9f8f83 100644 --- a/login-utils/last.c +++ b/login-utils/last.c @@ -201,72 +201,82 @@ wtmp() (void)signal(SIGQUIT, onintr); while (--bl >= 0) { - if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 || - (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) { - fprintf(stderr, "last: %s: ", file); - perror((char *)NULL); - exit(1); - } - for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) { - /* - * if the terminal line is '~', the machine stopped. - * see utmp(5) for more info. - */ - if (!strncmp(bp->ut_line, "~", LMAX)) { - /* everybody just logged out */ - for (T = ttylist; T; T = T->next) - T->logout = -bp->ut_time; - currentout = -bp->ut_time; - crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down "; - if (!bp->ut_name[0]) - (void)strcpy(bp->ut_name, "reboot"); - if (want(bp, NO)) { - ct = ctime(&bp->ut_time); - if(bp->ut_type != LOGIN_PROCESS) { - print_partial_line(bp); - putchar('\n'); - } - if (maxrec && !--maxrec) - return; - } - continue; - } - /* find associated tty */ - for (T = ttylist;; T = T->next) { - if (!T) { - /* add new one */ - T = addtty(bp->ut_line); - break; - } - if (!strncmp(T->tty, bp->ut_line, LMAX)) - break; + if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 || + (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) { + fprintf(stderr, "last: %s: ", file); + perror((char *)NULL); + exit(1); + } + for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) { + /* + * if the terminal line is '~', the machine stopped. + * see utmp(5) for more info. + */ + if (!strncmp(bp->ut_line, "~", LMAX)) { + /* + * utmp(5) also mentions that the user + * name should be 'shutdown' or 'reboot'. + * Not checking the name causes i.e. runlevel + * changes to be displayed as 'crash'. -thaele + */ + if (!strncmp(bp->ut_user, "reboot", NMAX) || + !strncmp(bp->ut_user, "shutdown", NMAX)) { + /* everybody just logged out */ + for (T = ttylist; T; T = T->next) + T->logout = -bp->ut_time; + } + + currentout = -bp->ut_time; + crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down "; + if (!bp->ut_name[0]) + (void)strcpy(bp->ut_name, "reboot"); + if (want(bp, NO)) { + ct = ctime(&bp->ut_time); + if(bp->ut_type != LOGIN_PROCESS) { + print_partial_line(bp); + putchar('\n'); } - if (bp->ut_name[0] && bp->ut_type != LOGIN_PROCESS - && bp->ut_type != DEAD_PROCESS - && want(bp, YES)) { - - print_partial_line(bp); - - if (!T->logout) - puts(" still logged in"); - else { - if (T->logout < 0) { - T->logout = -T->logout; - printf("- %s", crmsg); - } - else - printf("- %5.5s", ctime(&T->logout)+11); - delta = T->logout - bp->ut_time; - if (delta < SECDAY) - printf(" (%5.5s)\n", asctime(gmtime(&delta))+11); - else - printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11); - } - if (maxrec != -1 && !--maxrec) - return; + if (maxrec && !--maxrec) + return; + } + continue; + } + /* find associated tty */ + for (T = ttylist;; T = T->next) { + if (!T) { + /* add new one */ + T = addtty(bp->ut_line); + break; + } + if (!strncmp(T->tty, bp->ut_line, LMAX)) + break; + } + if (bp->ut_name[0] && bp->ut_type != LOGIN_PROCESS + && bp->ut_type != DEAD_PROCESS + && want(bp, YES)) { + + print_partial_line(bp); + + if (!T->logout) + puts(" still logged in"); + else { + if (T->logout < 0) { + T->logout = -T->logout; + printf("- %s", crmsg); } - T->logout = bp->ut_time; + else + printf("- %5.5s", ctime(&T->logout)+11); + delta = T->logout - bp->ut_time; + if (delta < SECDAY) + printf(" (%5.5s)\n", asctime(gmtime(&delta))+11); + else + printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11); + } + if (maxrec != -1 && !--maxrec) + return; } + T->logout = bp->ut_time; + } } ct = ctime(&buf[0].ut_time); printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); diff --git a/login-utils/login.1 b/login-utils/login.1 index 0e1f5eff..92a082c6 100644 --- a/login-utils/login.1 +++ b/login-utils/login.1 @@ -1,6 +1,6 @@ .\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH LOGIN 1 "1 February 1993" "Linux 0.99" "Linux Programmer's Manual" +.TH LOGIN 1 "4 November 1996" "Util-linux 1.6" "Linux Programmer's Manual" .SH NAME login \- sign on .SH SYNOPSIS @@ -42,8 +42,8 @@ Failures will be logged with the facility. After these conditions are checked, the password will be requested and -checks (if a password is required for this username). Ten attempts are -allowed before +checks (if a password is required for this username). Ten attempts +are allowed before .B login dies, but after the first three, the response starts to get very slow. Login failures are reported via the @@ -52,27 +52,29 @@ facility. This facility is also used to report any successful root logins. If the file .I .hushlogin -exists, then a "quiet" login is performed (this disables the checking of -the checking of mail and the printing of the last login time and message of -the day). Otherwise, if +exists, then a "quiet" login is performed (this disables the checking +of the checking of mail and the printing of the last login time and +message of the day). Otherwise, if .I /var/log/lastlog -exists, the last login time is printed (and the current login is recorded). +exists, the last login time is printed (and the current login is +recorded). -Random administrative things, such as setting the UID and GID of the tty -are performed. The TERM environment variable is preserved, if it exists -(other environment variables are preserved if the +Random administrative things, such as setting the UID and GID of the +tty are performed. The TERM environment variable is preserved, if it +exists (other environment variables are preserved if the .B \-p option is used). Then the HOME, PATH, SHELL, TERM, MAIL, and LOGNAME environment variables are set. PATH defaults to .I /usr/local/bin:/bin:/usr/bin:. for normal users, and to .I /sbin:/bin:/usr/sbin:/usr/bin -for root. Last, if this is not a "quiet" login, the message of the day is -printed and the file with the user's name in +for root. Last, if this is not a "quiet" login, the message of the +day is printed and the file with the user's name in .I /usr/spool/mail will be checked, and a message printed if it has non-zero length. -The user's shell is then started. If no shell is specified for the user in +The user's shell is then started. If no shell is specified for the +user in .BR /etc/passwd , then .B /bin/sh @@ -102,41 +104,43 @@ Used by other servers (i.e., .BR telnetd (8)) to pass the name of the remote host to .B login -so that it may be placed in utmp and wtmp. Only the superuser may use this -option. +so that it may be placed in utmp and wtmp. Only the superuser may use +this option. .SH "SPECIAL ACCESS RESTRICTIONS" The file .I /etc/securetty -lists the names of the ttys where root is allowed to log in. One name of -a tty device without the /dev/ prefix must be specified on each line. -If the file does not exist, root is allowed to log in on any tty. +lists the names of the ttys where root is allowed to log in. One name +of a tty device without the /dev/ prefix must be specified on each +line. If the file does not exist, root is allowed to log in on any +tty. .PP The file .I /etc/usertty -specifies additional access restrictions for specific users. If this file -does not exist, no additional access restrictions are imposed. The file -consists of a sequence of sections. There are three possible section -types: CLASSES, GROUPS and USERS. A CLASSES section defines classes of -ttys and hostname patterns, A GROUPS section defines allowed ttys and -hosts on a per group basis, and a USERS section defines allowed ttys -and hosts on a per user basis. +specifies additional access restrictions for specific users. If this +file does not exist, no additional access restrictions are +imposed. The file consists of a sequence of sections. There are three +possible section types: CLASSES, GROUPS and USERS. A CLASSES section +defines classes of ttys and hostname patterns, A GROUPS section +defines allowed ttys and hosts on a per group basis, and a USERS +section defines allowed ttys and hosts on a per user basis. .PP -Each line in this file in may be no longer than 255 characters. Comments -start with # character and extend to the end of the line. +Each line in this file in may be no longer than 255 +characters. Comments start with # character and extend to the end of +the line. .PP .SS "The CLASSES Section" -A CLASSES section begins with the word CLASSES at the start of a line in all -upper case. Each following line until the start of a new section or the -end of the file consists of a sequence of words separated by tabs or -spaces. Each line defines a class of ttys and host patterns. +A CLASSES section begins with the word CLASSES at the start of a line +in all upper case. Each following line until the start of a new +section or the end of the file consists of a sequence of words +separated by tabs or spaces. Each line defines a class of ttys and +host patterns. .PP -The word at -the beginning of a line becomes defined as a collective name for the -ttys and host patterns specified at the rest of the line. This collective -name can be used in any subsequent GROUPS or USERS section. No such class -name must occur as part of the definition of a class in order to avoid -problems with recursive classes. +The word at the beginning of a line becomes defined as a collective +name for the ttys and host patterns specified at the rest of the +line. This collective name can be used in any subsequent GROUPS or +USERS section. No such class name must occur as part of the definition +of a class in order to avoid problems with recursive classes. .PP An example CLASSES section: .PP @@ -155,7 +159,7 @@ and as the corresponding right hand sides. .PP -.SS "The GROUPS Section +.SS "The GROUPS Section" A GROUPS section defines allowed ttys and hosts on a per Unix group basis. If a user is a member of a Unix group according to .I /etc/passwd @@ -184,9 +188,11 @@ stud myclass1 tty4 .PP This example specifies that members of group .I sys -may log in on tty1 and from hosts in the bar.edu domain. Users in group +may log in on tty1 and from hosts in the bar.edu domain. Users in +group .I stud -may log in from hosts/ttys specified in the class myclass1 or from tty4. +may log in from hosts/ttys specified in the class myclass1 or from +tty4. .PP .SS "The USERS Section" @@ -209,44 +215,48 @@ blue tty3 myclass2 .in -0.5 .fi .PP -This lets the user zacho login only on tty1 and from hosts with IP addreses -in the range 130.225.16.0 \- 130.225.16.255, and user blue is allowed to -log in from tty3 and whatever is specified in the class myclass2. +This lets the user zacho login only on tty1 and from hosts with IP +addreses in the range 130.225.16.0 \- 130.225.16.255, and user blue is +allowed to log in from tty3 and whatever is specified in the class +myclass2. .PP -There may be a line in a USERS section starting with a username of *. This -is a default rule and it will be applied to any user not matching any other -line. +There may be a line in a USERS section starting with a username of +*. This is a default rule and it will be applied to any user not +matching any other line. .PP -If both a USERS line and GROUPS line match a user then the user is allowed -access from the union of all the ttys/hosts mentioned in these specifications. +If both a USERS line and GROUPS line match a user then the user is +allowed access from the union of all the ttys/hosts mentioned in these +specifications. .SS Origins -The tty and host pattern specifications used in the specification of classes, -group and user access are called origins. An origin string may have -one of these formats: +The tty and host pattern specifications used in the specification of +classes, group and user access are called origins. An origin string +may have one of these formats: .IP o The name of a tty device without the /dev/ prefix, for example tty1 or ttyS0. .PP .IP o -The string @localhost, meaning that the user is allowed to telnet/rlogin -from the local host to the same host. This also allows the user to for -example run the command: xterm -e /bin/login. +The string @localhost, meaning that the user is allowed to +telnet/rlogin from the local host to the same host. This also allows +the user to for example run the command: xterm -e /bin/login. .PP .IP o A domain name suffix such as @.some.dom, meaning that the user may -rlogin/telnet from any host whose domain name has the suffix .some.dom. +rlogin/telnet from any host whose domain name has the suffix +.some.dom. .PP .IP o -A range of IPv4 addresses, written @x.x.x.x/y.y.y.y where x.x.x.x -is the IP address in the usual dotted quad decimal notation, and -y.y.y.y is a bitmask in the same notation specifying which bits in the -address to compare with the IP address of the remote host. For example +A range of IPv4 addresses, written @x.x.x.x/y.y.y.y where x.x.x.x is +the IP address in the usual dotted quad decimal notation, and y.y.y.y +is a bitmask in the same notation specifying which bits in the address +to compare with the IP address of the remote host. For example @130.225.16.0/255.255.254.0 means that the user may rlogin/telnet from -any host whose IP address is in the range 130.225.16.0 \- 130.225.17.255. +any host whose IP address is in the range 130.225.16.0 \- +130.225.17.255. .PP -Any of the above origins may be prefixed by a time specification according -to the syntax: +Any of the above origins may be prefixed by a time specification +according to the syntax: .PP .nf timespec ::= '[' [':' ]* ']' @@ -256,16 +266,16 @@ hourspec ::= | '\-' day-or-hour ::= | .fi .PP -For example, the origin [mon:tue:wed:thu:fri:8\-17]tty3 means that log in is -allowed on mondays through fridays between 8:00 and 17:59 (5:59 pm) on tty3. -This also shows that an hour range a\-b includes all moments between a:00 and -b:59. A single hour specification (such as 10) means the time span between -10:00 and 10:59. +For example, the origin [mon:tue:wed:thu:fri:8\-17]tty3 means that log +in is allowed on mondays through fridays between 8:00 and 17:59 (5:59 +pm) on tty3. This also shows that an hour range a\-b includes all +moments between a:00 and b:59. A single hour specification (such as +10) means the time span between 10:00 and 10:59. .PP -Not specifying any time prefix for a tty or host means log in from that origin -is allowed any time. If you give a time prefix be sure to specify both a set -of days and one or more hours or hour ranges. A time specification may -not include any white space. +Not specifying any time prefix for a tty or host means log in from +that origin is allowed any time. If you give a time prefix be sure to +specify both a set of days and one or more hours or hour ranges. A +time specification may not include any white space. .PP If no default rule is given then users not matching any line .I /etc/usertty @@ -292,7 +302,9 @@ are allowed to log in from anywhere as is standard behavior. .BR environ (7), .BR shutdown (8) .SH BUGS -Linux, unlike other draconian operating systems, does not check quotas. + +Linux, unlike other draconian operating systems, does not check +quotas. The undocumented BSD .B \-r @@ -300,7 +312,7 @@ option is not supported. This may be required by some .BR rlogind (8) programs. .SH AUTHOR -Derived from BSD login 5.40 (5/9/89) by Michael Glad (glad@daimi.dk) for HP-UX +Derived from BSD login 5.40 (5/9/89) by Michael Glad (glad@daimi.dk) +for HP-UX .br Ported to Linux 0.12: Peter Orbaek (poe@daimi.aau.dk) - diff --git a/login-utils/login.c b/login-utils/login.c index 33a0b03e..c1626183 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -1,57 +1,58 @@ /* This program is derived from 4.3 BSD software and is subject to the copyright notice below. - + The port to HP-UX has been motivated by the incapability of 'rlogin'/'rlogind' as per HP-UX 6.5 (and 7.0) to transfer window sizes. - + Changes: - + - General HP-UX portation. Use of facilities not available in HP-UX (e.g. setpriority) has been eliminated. Utmp/wtmp handling has been ported. - + - The program uses BSD command line options to be used in connection with e.g. 'rlogind' i.e. 'new login'. - + - HP features left out: logging of bad login attempts in /etc/btmp, - they are sent to syslog - + they are sent to syslog + password expiry - + '*' as login shell, add it if you need it - BSD features left out: quota checks - password expiry + password expiry analysis of terminal type (tset feature) - + - BSD features thrown in: Security logging to syslogd. This requires you to have a (ported) syslog system -- 7.0 comes with syslog - + 'Lastlog' feature. - + - A lot of nitty gritty details has been adjusted in favour of HP-UX, e.g. /etc/securetty, default paths and the environment variables assigned by 'login'. - + - We do *nothing* to setup/alter tty state, under HP-UX this is to be done by getty/rlogind/telnetd/some one else. - + Michael Glad (glad@daimi.dk) Computer Science Department Aarhus University Denmark - + 1990-07-04 - + 1991-09-24 glad@daimi.aau.dk: HP-UX 8.0 port: - - now explictly sets non-blocking mode on descriptors - - strcasecmp is now part of HP-UX + - now explictly sets non-blocking mode on descriptors + - strcasecmp is now part of HP-UX + 1992-02-05 poe@daimi.aau.dk: Ported the stuff to Linux 0.12 - From 1992 till now (1995) this code for Linux has been maintained at + From 1992 till now (1997) this code for Linux has been maintained at ftp.daimi.aau.dk:/pub/linux/poe/ -*/ - + */ + /* * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. * All rights reserved. @@ -71,7 +72,7 @@ #ifndef lint char copyright[] = -"@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ + "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ All rights reserved.\n"; #endif /* not lint */ @@ -85,6 +86,8 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ +#define _GNU_SOURCE /* to get definition of snprintf */ + /* #define TESTING */ #ifdef TESTING @@ -93,10 +96,12 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #include #endif +#include #include #include #include #include +#include #include #include #include @@ -106,18 +111,24 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #define index strchr #define rindex strrchr #include +#include #include #include #include #include +#include #include #include -#include #include #include #include #include +#ifdef __linux__ +# include +# include +#endif + #ifdef TESTING # include "utmp.h" #else @@ -125,21 +136,39 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #endif #ifdef SHADOW_PWD -#include +# include #endif -#ifndef linux -#include +#ifdef USE_PAM +# include +# include +# define PAM_MAX_LOGIN_TRIES 3 +# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ + fprintf(stderr,"\n%s\n",pam_strerror(retcode)); \ + syslog(LOG_ERR,"%s",pam_strerror(retcode)); \ + pam_end(pamh, retcode); exit(1); \ + } +# define PAM_END { retcode = pam_close_session(pamh,0); \ + pam_end(pamh,retcode); } +# define PAM_END { \ + retcode = pam_close_session(pamh,0); pam_end(pamh,retcode); \ +} +#endif + +#ifndef __linux__ +# include #endif #include +#define SLEEP_EXIT_TIMEOUT 5 + #if 0 /* from before we had a lastlog.h file in linux */ struct lastlog - { long ll_time; - char ll_line[12]; - char ll_host[16]; - }; +{ long ll_time; + char ll_line[12]; + char ll_host[16]; +}; #endif #include "pathnames.h" @@ -153,11 +182,13 @@ void motd P_((void)); void sigint P_((void)); void checknologin P_((void)); void dolastlog P_((int quiet)); -void badlogin P_((char *name)); +void badlogin P_((const char *name)); char *stypeof P_((char *ttyid)); void checktty P_((char *user, char *tty, struct passwd *pwd)); -void getstr P_((char *buf, int cnt, char *err)); void sleepexit P_((int eval)); +#ifdef CRYPTOCARD +int cryptocard P_((void)); +#endif #undef P_ #ifdef KERBEROS @@ -167,6 +198,12 @@ char realm[REALM_SZ]; int kerror = KSUCCESS, notickets = 1; #endif +#ifdef USE_TTY_GROUP +# define TTY_MODE 0620 +#else +# define TTY_MODE 0600 +#endif + #define TTYGRPNAME "tty" /* name of group to own ttys */ /**# define TTYGRPNAME "other" **/ @@ -178,7 +215,7 @@ int kerror = KSUCCESS, notickets = 1; * This bounds the time given to login. Not a define so it can * be patched on machines where it's too small. */ -#ifndef linux +#ifndef __linux__ int timeout = 300; #else int timeout = 60; @@ -190,19 +227,19 @@ char term[64], *hostname, *username, *tty; struct hostent hostaddress; char thishost[100]; -#ifndef linux +#ifndef __linux__ struct sgttyb sgttyb; struct tchars tc = { - CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK -}; + CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK + }; struct ltchars ltc = { - CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT -}; + CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT + }; #endif -char *months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", - "Sep", "Oct", "Nov", "Dec" }; +const char *months[] = +{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; /* provided by Linus Torvalds 16-Feb-93 */ void @@ -210,7 +247,7 @@ opentty(const char * tty) { int i; int fd = open(tty, O_RDWR); - + for (i = 0 ; i < fd ; i++) close(i); for (i = 0 ; i < 3 ; i++) @@ -219,657 +256,916 @@ opentty(const char * tty) close(fd); } +/* true if the filedescriptor fd is a console tty, very Linux specific */ +static int +consoletty(int fd) +{ +#ifdef __linux__ + struct stat stb; + + if ((fstat(fd, &stb) >= 0) + && (major(stb.st_rdev) == TTY_MAJOR) + && (minor(stb.st_rdev) < 64)) { + return 1; + } +#endif + return 0; +} + + int main(argc, argv) - int argc; - char **argv; + int argc; + char **argv; { - extern int errno, optind; - extern char *optarg, **environ; - struct timeval tp; - struct tm *ttp; - struct group *gr; - register int ch; - register char *p; - int ask, fflag, hflag, pflag, cnt; - int quietlog, passwd_req, ioctlval; - char *domain, *salt, *ttyn, *pp; - char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; - char *ctime(), *ttyname(), *stypeof(); - time_t time(); - void timedout(); - char *termenv; - -#ifdef linux - char tmp[100]; - /* Just as arbitrary as mountain time: */ - /* (void)setenv("TZ", "MET-1DST",0); */ + extern int errno, optind; + extern char *optarg, **environ; + struct group *gr; + register int ch; + register char *p; + int ask, fflag, hflag, pflag, cnt; + int quietlog, passwd_req, ioctlval; + char *domain, *salt, *ttyn, *pp; + char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; + char *ctime(), *ttyname(), *stypeof(); + time_t time(); + void timedout(); + char *termenv; + char vcsn[20], vcsan[20]; + char * childArgv[10]; + char * buff; + int childArgc = 0; + int error = 0; +#ifdef USE_PAM + int retcode; + pam_handle_t *pamh = NULL; + struct pam_conv conv = { misc_conv, NULL }; + pid_t childPid; + int childStatus; + void * oldSigHandler; #endif - (void)signal(SIGALRM, timedout); - (void)alarm((unsigned int)timeout); - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)setpriority(PRIO_PROCESS, 0, 0); +#ifdef __linux__ + char tmp[100]; + /* Just as arbitrary as mountain time: */ + /* (void)setenv("TZ", "MET-1DST",0); */ +#endif + + signal(SIGALRM, timedout); + alarm((unsigned int)timeout); + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_IGN); + + setpriority(PRIO_PROCESS, 0, 0); #ifdef HAVE_QUOTA - (void)quota(Q_SETUID, 0, 0, 0); + quota(Q_SETUID, 0, 0, 0); #endif - - /* - * -p is used by getty to tell login not to destroy the environment - * -f is used to skip a second login authentication - * -h is used by other servers to pass the name of the remote - * host to login so that it may be placed in utmp and wtmp - */ - (void)gethostname(tbuf, sizeof(tbuf)); - (void)strncpy(thishost, tbuf, sizeof(thishost)-1); - domain = index(tbuf, '.'); - - hostname = NULL; - fflag = hflag = pflag = 0; - passwd_req = 1; - while ((ch = getopt(argc, argv, "fh:p")) != EOF) - switch (ch) { - case 'f': - fflag = 1; - break; - - case 'h': - if (getuid()) { - (void)fprintf(stderr, - "login: -h for super-user only.\n"); - exit(1); - } - hflag = 1; - if (domain && (p = index(optarg, '.')) && - strcasecmp(p, domain) == 0) - *p = 0; - hostname = optarg; - { - struct hostent *he = gethostbyname(hostname); - if (he) { - memcpy(&hostaddress, he, sizeof(hostaddress)); - } else { - memset(&hostaddress, 0, sizeof(hostaddress)); - } - } - break; - - case 'p': - pflag = 1; - break; - case '?': - default: - (void)fprintf(stderr, - "usage: login [-fp] [username]\n"); - exit(1); - } - argc -= optind; - argv += optind; - if (*argv) { - username = *argv; - ask = 0; - } else - ask = 1; - -#ifndef linux - ioctlval = 0; - (void)ioctl(0, TIOCLSET, &ioctlval); - (void)ioctl(0, TIOCNXCL, 0); - (void)fcntl(0, F_SETFL, ioctlval); - (void)ioctl(0, TIOCGETP, &sgttyb); - sgttyb.sg_erase = CERASE; - sgttyb.sg_kill = CKILL; - (void)ioctl(0, TIOCSLTC, <c); - (void)ioctl(0, TIOCSETC, &tc); - (void)ioctl(0, TIOCSETP, &sgttyb); - - /* - * Be sure that we're in - * blocking mode!!! - * This is really for HPUX - */ - ioctlval = 0; - (void)ioctl(0, FIOSNBIO, &ioctlval); + + /* + * -p is used by getty to tell login not to destroy the environment + * -f is used to skip a second login authentication + * -h is used by other servers to pass the name of the remote + * host to login so that it may be placed in utmp and wtmp + */ + gethostname(tbuf, sizeof(tbuf)); + strncpy(thishost, tbuf, sizeof(thishost)-1); + thishost[sizeof(thishost)-1] = 0; + domain = index(tbuf, '.'); + + username = tty = hostname = NULL; + fflag = hflag = pflag = 0; + passwd_req = 1; + while ((ch = getopt(argc, argv, "fh:p")) != EOF) + switch (ch) { + case 'f': + fflag = 1; + break; + + case 'h': + if (getuid()) { + fprintf(stderr, + "login: -h for super-user only.\n"); + exit(1); + } + hflag = 1; + if (domain && (p = index(optarg, '.')) && + strcasecmp(p, domain) == 0) + *p = 0; + hostname = optarg; + { + struct hostent *he = gethostbyname(hostname); + if (he) { + memcpy(&hostaddress, he, sizeof(hostaddress)); + } else { + memset(&hostaddress, 0, sizeof(hostaddress)); + } + } + break; + + case 'p': + pflag = 1; + break; + + case '?': + default: + fprintf(stderr, + "usage: login [-fp] [username]\n"); + exit(1); + } + argc -= optind; + argv += optind; + if (*argv) { + username = *argv; + ask = 0; + } else + ask = 1; + +#ifndef __linux__ + ioctlval = 0; + ioctl(0, TIOCLSET, &ioctlval); + ioctl(0, TIOCNXCL, 0); + fcntl(0, F_SETFL, ioctlval); + ioctl(0, TIOCGETP, &sgttyb); + sgttyb.sg_erase = CERASE; + sgttyb.sg_kill = CKILL; + ioctl(0, TIOCSLTC, <c); + ioctl(0, TIOCSETC, &tc); + ioctl(0, TIOCSETP, &sgttyb); + + /* + * Be sure that we're in + * blocking mode!!! + * This is really for HPUX + */ + ioctlval = 0; + ioctl(0, FIOSNBIO, &ioctlval); #endif - - for (cnt = getdtablesize(); cnt > 2; cnt--) - close(cnt); - - ttyn = ttyname(0); - if (ttyn == NULL || *ttyn == '\0') { - (void)sprintf(tname, "%s??", _PATH_TTY); - ttyn = tname; + + for (cnt = getdtablesize(); cnt > 2; cnt--) + close(cnt); + + ttyn = ttyname(0); + if (ttyn == NULL || *ttyn == '\0') { + snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); + ttyn = tname; + } + + /* find names of Virtual Console devices, for later mode change */ + { + char *p = ttyn; + /* find number of tty */ + while (*p && !isdigit(*p)) p++; + + strcpy(vcsn, "/dev/vcs"); strcat(vcsn, p); + strcpy(vcsan, "/dev/vcsa"); strcat(vcsan, p); + } + + setpgrp(); + + { + struct termios tt, ttt; + + tcgetattr(0, &tt); + ttt = tt; + ttt.c_cflag &= ~HUPCL; + + if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) { + tcsetattr(0,TCSAFLUSH,&ttt); + signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */ + vhangup(); + signal(SIGHUP, SIG_DFL); } + + setsid(); + + /* re-open stdin,stdout,stderr after vhangup() closed them */ + /* if it did, after 0.99.5 it doesn't! */ + opentty(ttyn); + tcsetattr(0,TCSAFLUSH,&tt); + } + + if ((tty = rindex(ttyn, '/'))) + ++tty; + else + tty = ttyn; + + openlog("login", LOG_ODELAY, LOG_AUTHPRIV); + +#ifdef USE_PAM + /* username is initialized to NULL + and if specified on the command line it is set. + Therefore, we are safe not setting it to anything + */ + + retcode = pam_start("login",username, &conv, &pamh); + if(retcode != PAM_SUCCESS) { + fprintf(stderr,"login: PAM Failure, aborting: %s\n", + pam_strerror(retcode)); + syslog(LOG_ERR,"Couldn't initialize PAM: %s", pam_strerror(retcode)); + exit(99); + } + /* hostname & tty are either set to NULL or their correct values, + depending on how much we know */ + retcode = pam_set_item(pamh, PAM_RHOST, hostname); + PAM_FAIL_CHECK; + retcode = pam_set_item(pamh, PAM_TTY, tty); + PAM_FAIL_CHECK; + /* if fflag == 1, then the user has already been authenticated */ + if (fflag && (getuid() == 0)) + passwd_req = 0; + else + passwd_req = 1; - setpgrp(); - - { - struct termios tt, ttt; - - tcgetattr(0, &tt); - ttt = tt; - ttt.c_cflag &= ~HUPCL; - - if((chown(ttyn, 0, 0) == 0) && (chmod(ttyn, 0622) == 0)) { - tcsetattr(0,TCSAFLUSH,&ttt); - signal(SIGHUP, SIG_IGN); /* so vhangup() wont kill us */ - vhangup(); - signal(SIGHUP, SIG_DFL); - } - - setsid(); - - /* re-open stdin,stdout,stderr after vhangup() closed them */ - /* if it did, after 0.99.5 it doesn't! */ - opentty(ttyn); - tcsetattr(0,TCSAFLUSH,&tt); + if(passwd_req == 1) { + int failcount=0; + + /* there may be better ways to deal with some of these + conditions, but at least this way I don't think we'll + be giving away information... */ + /* Perhaps someday we can trust that all PAM modules will + pay attention to failure count and get rid of MAX_LOGIN_TRIES? */ + + retcode = pam_authenticate(pamh, 0); + while((failcount++ < PAM_MAX_LOGIN_TRIES) && + ((retcode == PAM_AUTH_ERR) || + (retcode == PAM_USER_UNKNOWN) || + (retcode == PAM_CRED_INSUFFICIENT) || + (retcode == PAM_AUTHINFO_UNAVAIL))) { + pam_get_item(pamh, PAM_USER, (const void **) &username); + syslog(LOG_NOTICE,"FAILED LOGIN %d FROM %s FOR %s, %s", + failcount, hostname,username,pam_strerror(retcode)); + fprintf(stderr,"Login incorrect\n\n"); + pam_set_item(pamh,PAM_USER,NULL); + retcode = pam_authenticate(pamh, 0); } - if ((tty = rindex(ttyn, '/'))) - ++tty; - else - tty = ttyn; - - openlog("login", LOG_ODELAY, LOG_AUTH); - - for (cnt = 0;; ask = 1) { - ioctlval = 0; -#ifndef linux - (void)ioctl(0, TIOCSETD, &ioctlval); -#endif + if (retcode != PAM_SUCCESS) { + pam_get_item(pamh, PAM_USER, (const void **) &username); - if (ask) { - fflag = 0; - getloginname(); - } - - /* Dirty patch to fix a gigantic security hole when using - yellow pages. This problem should be solved by the - libraries, and not by programs, but this must be fixed - urgently! If the first char of the username is '+', we - avoid login success. - Feb 95 */ - - if (username[0] == '+') { - puts("Illegal username"); - badlogin(username); - sleepexit(1); - } + if (retcode == PAM_MAXTRIES) + syslog(LOG_NOTICE,"TOO MANY LOGIN TRIES (%d) FROM %s FOR " + "%s, %s", failcount, hostname, username, + pam_strerror(retcode)); + else + syslog(LOG_NOTICE,"FAILED LOGIN SESSION FROM %s FOR %s, %s", + hostname, username, pam_strerror(retcode)); - (void)strcpy(tbuf, username); - if ((pwd = getpwnam(username))) - salt = pwd->pw_passwd; - else - salt = "xx"; - - checktty(username, tty, pwd); /* in checktty.c */ + fprintf(stderr,"\nLogin incorrect\n"); + pam_end(pamh, retcode); + exit(0); + } - /* if user not super-user, check for disabled logins */ - if (pwd == NULL || pwd->pw_uid) - checknologin(); + retcode = pam_acct_mgmt(pamh, 0); - /* - * Disallow automatic login to root; if not invoked by - * root, disallow if the uid's differ. - */ - if (fflag && pwd) { - int uid = getuid(); + if(retcode == PAM_AUTHTOKEN_REQD) { + retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + } - passwd_req = pwd->pw_uid == 0 || - (uid && uid != pwd->pw_uid); - } + PAM_FAIL_CHECK; + } - /* - * If trying to log in as root, but with insecure terminal, - * refuse the login attempt. - */ - if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { - (void)fprintf(stderr, - "%s login refused on this terminal.\n", - pwd->pw_name); - - if (hostname) - syslog(LOG_NOTICE, - "LOGIN %s REFUSED FROM %s ON TTY %s", - pwd->pw_name, hostname, tty); - else - syslog(LOG_NOTICE, - "LOGIN %s REFUSED ON TTY %s", - pwd->pw_name, tty); - continue; - } + /* Grab the user information out of the password file for future usage + First get the username that we are actually using, though. + */ + retcode = pam_get_item(pamh, PAM_USER, (const void **) &username); + setpwent(); + pwd = getpwnam(username); + if (pwd) initgroups(username, pwd->pw_gid); - /* - * If no pre-authentication and a password exists - * for this user, prompt for one and verify it. - */ - if (!passwd_req || (pwd && !*pwd->pw_passwd)) - break; + retcode = pam_setcred(pamh, PAM_CRED_ESTABLISH); + PAM_FAIL_CHECK; - setpriority(PRIO_PROCESS, 0, -4); - pp = getpass("Password: "); - p = crypt(pp, salt); - setpriority(PRIO_PROCESS, 0, 0); + retcode = pam_open_session(pamh, 0); + PAM_FAIL_CHECK; -#ifdef KERBEROS +#else /* ! USE_PAM */ - /* - * If not present in pw file, act as we normally would. - * If we aren't Kerberos-authenticated, try the normal - * pw file for a password. If that's ok, log the user - * in without issueing any tickets. - */ - - if (pwd && !krb_get_lrealm(realm,1)) { - /* - * get TGT for local realm; be careful about uid's - * here for ticket file ownership - */ - (void)setreuid(geteuid(),pwd->pw_uid); - kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, - "krbtgt", realm, DEFAULT_TKT_LIFE, pp); - (void)setuid(0); - if (kerror == INTK_OK) { - memset(pp, 0, strlen(pp)); - notickets = 0; /* user got ticket */ - break; - } - } -#endif - (void) memset(pp, 0, strlen(pp)); - if (pwd && !strcmp(p, pwd->pw_passwd)) - break; - - (void)printf("Login incorrect\n"); - failures++; - badlogin(username); /* log ALL bad logins */ - - /* we allow 10 tries, but after 3 we start backing off */ - if (++cnt > 3) { - if (cnt >= 10) { - sleepexit(1); - } - sleep((unsigned int)((cnt - 3) * 5)); - } + for (cnt = 0;; ask = 1) { + ioctlval = 0; +# ifndef __linux__ + ioctl(0, TIOCSETD, &ioctlval); +# endif + + if (ask) { + fflag = 0; + getloginname(); } + + /* Dirty patch to fix a gigantic security hole when using + yellow pages. This problem should be solved by the + libraries, and not by programs, but this must be fixed + urgently! If the first char of the username is '+', we + avoid login success. + Feb 95 */ + + if (username[0] == '+') { + puts("Illegal username"); + badlogin(username); + sleepexit(1); + } + + /* (void)strcpy(tbuf, username); why was this here? */ + if ((pwd = getpwnam(username))) { +# ifdef SHADOW_PWD + struct spwd *sp; + + if ((sp = getspnam(username))) + pwd->pw_passwd = sp->sp_pwdp; +# endif + salt = pwd->pw_passwd; + } else + salt = "xx"; + + if (pwd) { + initgroups(username, pwd->pw_gid); + checktty(username, tty, pwd); /* in checktty.c */ + } + + /* if user not super-user, check for disabled logins */ + if (pwd == NULL || pwd->pw_uid) + checknologin(); + + /* + * Disallow automatic login to root; if not invoked by + * root, disallow if the uid's differ. + */ + if (fflag && pwd) { + int uid = getuid(); + + passwd_req = pwd->pw_uid == 0 || + (uid && uid != pwd->pw_uid); + } + + /* + * If trying to log in as root, but with insecure terminal, + * refuse the login attempt. + */ + if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { + fprintf(stderr, + "%s login refused on this terminal.\n", + pwd->pw_name); + + if (hostname) + syslog(LOG_NOTICE, + "LOGIN %s REFUSED FROM %s ON TTY %s", + pwd->pw_name, hostname, tty); + else + syslog(LOG_NOTICE, + "LOGIN %s REFUSED ON TTY %s", + pwd->pw_name, tty); + continue; + } + + /* + * If no pre-authentication and a password exists + * for this user, prompt for one and verify it. + */ + if (!passwd_req || (pwd && !*pwd->pw_passwd)) + break; + + setpriority(PRIO_PROCESS, 0, -4); + pp = getpass("Password: "); + +# ifdef CRYPTOCARD + if (strncmp(pp, "CRYPTO", 6) == 0) { + if (pwd && cryptocard()) break; + } +# endif /* CRYPTOCARD */ + + p = crypt(pp, salt); + setpriority(PRIO_PROCESS, 0, 0); - /* committed to login -- turn off timeout */ - (void)alarm((unsigned int)0); - +# ifdef KERBEROS + /* + * If not present in pw file, act as we normally would. + * If we aren't Kerberos-authenticated, try the normal + * pw file for a password. If that's ok, log the user + * in without issueing any tickets. + */ + + if (pwd && !krb_get_lrealm(realm,1)) { + /* + * get TGT for local realm; be careful about uid's + * here for ticket file ownership + */ + setreuid(geteuid(),pwd->pw_uid); + kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, + "krbtgt", realm, DEFAULT_TKT_LIFE, pp); + setuid(0); + if (kerror == INTK_OK) { + memset(pp, 0, strlen(pp)); + notickets = 0; /* user got ticket */ + break; + } + } +# endif /* KERBEROS */ + memset(pp, 0, strlen(pp)); + if (pwd && !strcmp(p, pwd->pw_passwd)) + break; + + printf("Login incorrect\n"); + badlogin(username); /* log ALL bad logins */ + failures++; + + /* we allow 10 tries, but after 3 we start backing off */ + if (++cnt > 3) { + if (cnt >= 10) { + sleepexit(1); + } + sleep((unsigned int)((cnt - 3) * 5)); + } + } +#endif /* !USE_PAM */ + + /* committed to login -- turn off timeout */ + alarm((unsigned int)0); + #ifdef HAVE_QUOTA - if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { - switch(errno) { - case EUSERS: - (void)fprintf(stderr, - "Too many users logged on already.\nTry again later.\n"); - break; - case EPROCLIM: - (void)fprintf(stderr, - "You have too many processes running.\n"); - break; - default: - perror("quota (Q_SETUID)"); - } - sleepexit(0); + if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { + switch(errno) { + case EUSERS: + fprintf(stderr, + "Too many users logged on already.\nTry again later.\n"); + break; + case EPROCLIM: + fprintf(stderr, + "You have too many processes running.\n"); + break; + default: + perror("quota (Q_SETUID)"); } + sleepexit(0); + } #endif + + /* paranoia... */ +#ifdef SHADOW_PWD + endspent(); +#endif + endpwent(); + + /* This requires some explanation: As root we may not be able to + read the directory of the user if it is on an NFS mounted + filesystem. We temporarily set our effective uid to the user-uid + making sure that we keep root privs. in the real uid. + + A portable solution would require a fork(), but we rely on Linux + having the BSD setreuid() */ + + { + char tmpstr[MAXPATHLEN]; + uid_t ruid = getuid(); + gid_t egid = getegid(); + + snprintf(tmpstr, sizeof(tmpstr), + "%s/%s", pwd->pw_dir, _PATH_HUSHLOGIN); + + setregid(-1, pwd->pw_gid); + setreuid(0, pwd->pw_uid); + quietlog = (access(tmpstr, R_OK) == 0); + setuid(0); /* setreuid doesn't do it alone! */ + setreuid(ruid, 0); + setregid(-1, egid); + } + +#ifndef __linux__ +# ifdef KERBEROS + if (notickets && !quietlog) + printf("Warning: no Kerberos tickets issued\n"); +# endif + +# ifndef USE_PAM /* PAM does all of this for us */ +# define TWOWEEKS (14*24*60*60) + if (pwd->pw_change || pwd->pw_expire) { + struct timeval tp; - /* paranoia... */ - endpwent(); - - /* This requires some explanation: As root we may not be able to - read the directory of the user if it is on an NFS mounted - filesystem. We temporarily set our effective uid to the user-uid - making sure that we keep root privs. in the real uid. - - A portable solution would require a fork(), but we rely on Linux - having the BSD setreuid() */ - - { - char tmpstr[MAXPATHLEN]; - uid_t ruid = getuid(); - gid_t egid = getegid(); - - strncpy(tmpstr, pwd->pw_dir, MAXPATHLEN-12); - strncat(tmpstr, ("/" _PATH_HUSHLOGIN), MAXPATHLEN); + gettimeofday(&tp, (struct timezone *)NULL); - setregid(-1, pwd->pw_gid); - setreuid(0, pwd->pw_uid); - quietlog = (access(tmpstr, R_OK) == 0); - setuid(0); /* setreuid doesn't do it alone! */ - setreuid(ruid, 0); - setregid(-1, egid); + if (pwd->pw_change) { + if (tp.tv_sec >= pwd->pw_change) { + printf("Sorry -- your password has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { + struct tm *ttp; + ttp = localtime(&pwd->pw_change); + printf("Warning: your password expires on %s %d, %d\n", + months[ttp->tm_mon], ttp->tm_mday, + TM_YEAR_BASE + ttp->tm_year); + } } -#ifndef linux -#ifdef KERBEROS - if (notickets && !quietlog) - (void)printf("Warning: no Kerberos tickets issued\n"); -#endif - -#define TWOWEEKS (14*24*60*60) - if (pwd->pw_change || pwd->pw_expire) - (void)gettimeofday(&tp, (struct timezone *)NULL); - if (pwd->pw_change) - if (tp.tv_sec >= pwd->pw_change) { - (void)printf("Sorry -- your password has expired.\n"); - sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_change < TWOWEEKS && !quietlog) { - ttp = localtime(&pwd->pw_change); - (void)printf("Warning: your password expires on %s %d, %d\n", - months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); - } - if (pwd->pw_expire) - if (tp.tv_sec >= pwd->pw_expire) { - (void)printf("Sorry -- your account has expired.\n"); - sleepexit(1); - } - else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { - ttp = localtime(&pwd->pw_expire); - (void)printf("Warning: your account expires on %s %d, %d\n", - months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); - } - - /* nothing else left to fail -- really log in */ - { - struct utmp utmp; - - memset((char *)&utmp, 0, sizeof(utmp)); - (void)time(&utmp.ut_time); - strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); - if (hostname) - strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); - strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); - login(&utmp); + if (pwd->pw_expire) { + if (tp.tv_sec >= pwd->pw_expire) { + printf("Sorry -- your account has expired.\n"); + sleepexit(1); + } + else if (tp.tv_sec - pwd->pw_expire < TWOWEEKS && !quietlog) { + struct tm *ttp; + ttp = localtime(&pwd->pw_expire); + printf("Warning: your account expires on %s %d, %d\n", + months[ttp->tm_mon], ttp->tm_mday, + TM_YEAR_BASE + ttp->tm_year); + } + } + } +# endif /* !USE_PAM */ + + /* nothing else left to fail -- really log in */ + { + struct utmp utmp; + + memset((char *)&utmp, 0, sizeof(utmp)); + time(&utmp.ut_time); + strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); + /* ut_name may legally be non-null-terminated */ + if (hostname) { + strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); + utmp.ut_host[sizeof(utmp.ut_host)-1] = 0; } + strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); + utmp.ut_line[sizeof(utmp.ut_line)-1] = 0; + login(&utmp); + } #else - /* for linux, write entries in utmp and wtmp */ - { - struct utmp ut; - int wtmp; - struct utmp *utp; - pid_t mypid = getpid(); - - utmpname(_PATH_UTMP); - setutent(); - while ((utp = getutent()) - && !(utp->ut_pid == mypid)) /* nothing */; - - if (utp) { - memcpy(&ut, utp, sizeof(ut)); - } else { - /* some gettys/telnetds don't initialize utmp... */ - memset(&ut, 0, sizeof(ut)); - } - endutent(); - - if (ut.ut_id[0] == 0) - strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id)); - - strncpy(ut.ut_user, username, sizeof(ut.ut_user)); - strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line)); - time(&ut.ut_time); - ut.ut_type = USER_PROCESS; - ut.ut_pid = mypid; - if (hostname) { - strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); - if (hostaddress.h_addr_list) - memcpy(&ut.ut_addr, hostaddress.h_addr_list[0], - sizeof(ut.ut_addr)); - } - - pututline(&ut); - endutent(); - - if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { - flock(wtmp, LOCK_EX); - write(wtmp, (char *)&ut, sizeof(ut)); - flock(wtmp, LOCK_UN); - close(wtmp); - } + /* for linux, write entries in utmp and wtmp */ + { + struct utmp ut; + int wtmp; + struct utmp *utp; + time_t t; + pid_t mypid = getpid(); + + utmpname(_PATH_UTMP); + setutent(); + while ((utp = getutent()) + && !(utp->ut_pid == mypid)) /* nothing */; + + if (utp) { + memcpy(&ut, utp, sizeof(ut)); + } else { + /* some gettys/telnetds don't initialize utmp... */ + memset(&ut, 0, sizeof(ut)); } -#endif - - dolastlog(quietlog); + /* endutent(); superfluous, error for glibc */ -#ifndef linux - if (!hflag) { /* XXX */ - static struct winsize win = { 0, 0, 0, 0 }; - - (void)ioctl(0, TIOCSWINSZ, &win); + if (ut.ut_id[0] == 0) + strncpy(ut.ut_id, ttyn + 8, sizeof(ut.ut_id)); + + strncpy(ut.ut_user, username, sizeof(ut.ut_user)); + strncpy(ut.ut_line, ttyn + 5, sizeof(ut.ut_line)); + ut.ut_line[sizeof(ut.ut_line)-1] = 0; + time(&t); + ut.ut_time = t; /* ut_time is not always a time_t */ + /* (we might test #ifdef _HAVE_UT_TV ) */ + ut.ut_type = USER_PROCESS; + ut.ut_pid = mypid; + if (hostname) { + strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); + ut.ut_host[sizeof(ut.ut_host)-1] = 0; + if (hostaddress.h_addr_list) + memcpy(&ut.ut_addr, hostaddress.h_addr_list[0], + sizeof(ut.ut_addr)); } + + pututline(&ut); + endutent(); + + { + int lf; + if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { + flock(lf, LOCK_EX); + if ((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { + write(wtmp, (char *)&ut, sizeof(ut)); + close(wtmp); + } + flock(lf, LOCK_UN); + close(lf); + } + } + } #endif - (void)chown(ttyn, pwd->pw_uid, - (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); - -#ifdef USE_TTY_GROUP - chmod(ttyn, 0620); -#else - chmod(ttyn, 0600); + + dolastlog(quietlog); + +#ifndef __linux__ + if (!hflag) { /* XXX */ + static struct winsize win = { 0, 0, 0, 0 }; + + ioctl(0, TIOCSWINSZ, &win); + } #endif - - setgid(pwd->pw_gid); - initgroups(username, pwd->pw_gid); - + chown(ttyn, pwd->pw_uid, + (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); + chmod(ttyn, TTY_MODE); + + /* if tty is one of the VC's then change owner and mode of the + special /dev/vcs devices as well */ + if (consoletty(0)) { + chown(vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); + chown(vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid)); + chmod(vcsn, TTY_MODE); + chmod(vcsan, TTY_MODE); + } + + setgid(pwd->pw_gid); + #ifdef HAVE_QUOTA - quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); + quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); #endif - - if (*pwd->pw_shell == '\0') - pwd->pw_shell = _PATH_BSHELL; -#ifndef linux - /* turn on new line discipline for the csh */ - else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { - ioctlval = NTTYDISC; - (void)ioctl(0, TIOCSETD, &ioctlval); - } + + if (*pwd->pw_shell == '\0') + pwd->pw_shell = _PATH_BSHELL; +#ifndef __linux__ + /* turn on new line discipline for the csh */ + else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { + ioctlval = NTTYDISC; + ioctl(0, TIOCSETD, &ioctlval); + } #endif - - /* preserve TERM even without -p flag */ - { - char *ep; - - if(!((ep = getenv("TERM")) && (termenv = strdup(ep)))) - termenv = "dumb"; - } - - /* destroy environment unless user has requested preservation */ - if (!pflag) - { + + /* preserve TERM even without -p flag */ + { + char *ep; + + if(!((ep = getenv("TERM")) && (termenv = strdup(ep)))) + termenv = "dumb"; + } + + /* destroy environment unless user has requested preservation */ + if (!pflag) + { environ = (char**)malloc(sizeof(char*)); memset(environ, 0, sizeof(char*)); - } - -#ifndef linux - (void)setenv("HOME", pwd->pw_dir, 1); - (void)setenv("SHELL", pwd->pw_shell, 1); - if (term[0] == '\0') - strncpy(term, stypeof(tty), sizeof(term)); - (void)setenv("TERM", term, 0); - (void)setenv("USER", pwd->pw_name, 1); - (void)setenv("PATH", _PATH_DEFPATH, 0); + } + +#ifndef __linux__ + setenv("HOME", pwd->pw_dir, 1); + setenv("SHELL", pwd->pw_shell, 1); + if (term[0] == '\0') { + strncpy(term, stypeof(tty), sizeof(term)); + term[sizeof(term)-1] = 0; + } + setenv("TERM", term, 0); + setenv("USER", pwd->pw_name, 1); + setenv("PATH", _PATH_DEFPATH, 0); #else - (void)setenv("HOME", pwd->pw_dir, 0); /* legal to override */ - if(pwd->pw_uid) - (void)setenv("PATH", _PATH_DEFPATH, 1); - else - (void)setenv("PATH", _PATH_DEFPATH_ROOT, 1); - (void)setenv("SHELL", pwd->pw_shell, 1); - (void)setenv("TERM", termenv, 1); - - /* mailx will give a funny error msg if you forget this one */ - (void)sprintf(tmp,"%s/%s",_PATH_MAILDIR,pwd->pw_name); - (void)setenv("MAIL",tmp,0); - - /* LOGNAME is not documented in login(1) but - HP-UX 6.5 does it. We'll not allow modifying it. - */ - (void)setenv("LOGNAME", pwd->pw_name, 1); + setenv("HOME", pwd->pw_dir, 0); /* legal to override */ + if(pwd->pw_uid) + setenv("PATH", _PATH_DEFPATH, 1); + else + setenv("PATH", _PATH_DEFPATH_ROOT, 1); + + setenv("SHELL", pwd->pw_shell, 1); + setenv("TERM", termenv, 1); + + /* mailx will give a funny error msg if you forget this one */ + snprintf(tmp, sizeof(tmp), "%s/%s", _PATH_MAILDIR, pwd->pw_name); + setenv("MAIL",tmp,0); + + /* LOGNAME is not documented in login(1) but + HP-UX 6.5 does it. We'll not allow modifying it. + */ + setenv("LOGNAME", pwd->pw_name, 1); #endif - if (tty[sizeof("tty")-1] == 'S') - syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); - - if (pwd->pw_uid == 0) - if (hostname) - syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", - tty, hostname); - else - syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); - - if (!quietlog) { - struct stat st; - - motd(); - (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); - if (stat(tbuf, &st) == 0 && st.st_size != 0) - (void)printf("You have %smail.\n", - (st.st_mtime > st.st_atime) ? "new " : ""); - } +#ifdef USE_PAM + { + int i; + const char * const * env; - (void)signal(SIGALRM, SIG_DFL); - (void)signal(SIGQUIT, SIG_DFL); - (void)signal(SIGINT, SIG_DFL); - (void)signal(SIGTSTP, SIG_IGN); - (void)signal(SIGHUP, SIG_DFL); + env = (const char * const *)pam_getenvlist(pamh); - /* discard permissions last so can't get killed and drop core */ - if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { - syslog(LOG_ALERT, "setuid() failed"); - exit(1); + if (env != NULL) { + for (i=0; env[i++]; ) { + putenv(env[i-1]); + /* D(("env[%d] = %s", i-1,env[i-1])); */ + } } - - /* wait until here to change directory! */ - if (chdir(pwd->pw_dir) < 0) { - (void)printf("No directory %s!\n", pwd->pw_dir); - if (chdir("/")) - exit(0); - pwd->pw_dir = "/"; - (void)printf("Logging in with home = \"/\".\n"); + } +#endif + + if (tty[sizeof("tty")-1] == 'S') + syslog(LOG_INFO, "DIALUP AT %s BY %s", tty, pwd->pw_name); + + /* allow tracking of good logins. + -steve philp (sphilp@mail.alliance.net) */ + + if (pwd->pw_uid == 0) { + if (hostname) + syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", + tty, hostname); + else + syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); + } else { + if (hostname) + syslog(LOG_INFO, "LOGIN ON %s BY %s FROM %s", tty, + pwd->pw_name, hostname); + else + syslog(LOG_INFO, "LOGIN ON %s BY %s", tty, + pwd->pw_name); + } + + if (!quietlog) { + struct stat st; + + motd(); + snprintf(tbuf, sizeof(tbuf), + "%s/%s", _PATH_MAILDIR, pwd->pw_name); + if (stat(tbuf, &st) == 0 && st.st_size != 0) + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); + } + + signal(SIGALRM, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTSTP, SIG_IGN); + signal(SIGHUP, SIG_DFL); + + /* discard permissions last so can't get killed and drop core */ + if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { + syslog(LOG_ALERT, "setuid() failed"); +#ifdef USE_PAM + PAM_END; +#endif + exit(1); + } + + /* wait until here to change directory! */ + if (chdir(pwd->pw_dir) < 0) { + printf("No directory %s!\n", pwd->pw_dir); + if (chdir("/")) { +#ifdef USE_PAM + PAM_END; +#endif + exit(0); } - - /* if the shell field has a space: treat it like a shell script */ - if (strchr(pwd->pw_shell, ' ')) { - char *buff = malloc(strlen(pwd->pw_shell) + 6); - if (buff) { - strcpy(buff, "exec "); - strcat(buff, pwd->pw_shell); - execlp("/bin/sh", "-sh", "-c", buff, (char *)0); - fprintf(stderr, "login: couldn't exec shell script: %s.\n", - strerror(errno)); - exit(0); - } + pwd->pw_dir = "/"; + printf("Logging in with home = \"/\".\n"); + } + + /* if the shell field has a space: treat it like a shell script */ + if (strchr(pwd->pw_shell, ' ')) { + buff = malloc(strlen(pwd->pw_shell) + 6); + + if (!buff) { fprintf(stderr, "login: no memory for shell script.\n"); exit(0); } + strcpy(buff, "exec "); + strcat(buff, pwd->pw_shell); + childArgv[childArgc++] = "/bin/sh"; + childArgv[childArgc++] = "-sh"; + childArgv[childArgc++] = "-c"; + childArgv[childArgc++] = buff; + } else { tbuf[0] = '-'; - strcpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ? - p + 1 : pwd->pw_shell)); - - execlp(pwd->pw_shell, tbuf, (char *)0); - (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); + strncpy(tbuf + 1, ((p = rindex(pwd->pw_shell, '/')) ? + p + 1 : pwd->pw_shell), + sizeof(tbuf)-1); + tbuf[sizeof(tbuf)-1] = 0; + + childArgv[childArgc++] = pwd->pw_shell; + childArgv[childArgc++] = tbuf; + } + + childArgv[childArgc++] = NULL; + +#ifndef USE_PAM + execvp(childArgv[0], childArgv + 1); + error = 1; +#else /* USE_PAM */ + oldSigHandler = signal(SIGINT, SIG_IGN); + childPid = fork(); + if (childPid < 0) { + /* error in fork() */ + fprintf(stderr,"login: failure forking: %s", strerror(errno)); + PAM_END; exit(0); + } else if (childPid) { + /* parent */ + wait(&childStatus); + signal(SIGINT, oldSigHandler); + PAM_END; + + if (!WIFEXITED(&childStatus)) error = 1; + } else { + /* child */ + execvp(childArgv[0], childArgv + 1); + exit(1); + } +#endif /* USE_PAM */ + + if (error) { + if (!strcmp(childArgv[0], "/bin/sh")) + fprintf(stderr, "login: couldn't exec shell script: %s.\n", + strerror(errno)); + else + fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); + } + + exit(0); } void getloginname() { - register int ch; - register char *p; - static char nbuf[UT_NAMESIZE + 1]; - int cnt, cnt2; - - cnt2 = 0; - for (;;) { - cnt = 0; - (void)printf("\n%s login: ", thishost); fflush(stdout); - for (p = nbuf; (ch = getchar()) != '\n'; ) { - if (ch == EOF) { - badlogin("EOF"); - exit(0); - } - if (p < nbuf + UT_NAMESIZE) - *p++ = ch; - - cnt++; - if (cnt > UT_NAMESIZE + 20) { - fprintf(stderr, "login name much too long.\n"); - badlogin("NAME too long"); - exit(0); - } - } - if (p > nbuf) - if (nbuf[0] == '-') - (void)fprintf(stderr, - "login names may not start with '-'.\n"); - else { - *p = '\0'; - username = nbuf; - break; - } - - cnt2++; - if (cnt2 > 50) { - fprintf(stderr, "too many bare linefeeds.\n"); - badlogin("EXCESSIVE linefeeds"); - exit(0); - } + register int ch; + register char *p; + static char nbuf[UT_NAMESIZE + 1]; + int cnt, cnt2; + + cnt2 = 0; + for (;;) { + cnt = 0; + printf("\n%s login: ", thishost); fflush(stdout); + for (p = nbuf; (ch = getchar()) != '\n'; ) { + if (ch == EOF) { + badlogin("EOF"); + exit(0); + } + if (p < nbuf + UT_NAMESIZE) + *p++ = ch; + + cnt++; + if (cnt > UT_NAMESIZE + 20) { + fprintf(stderr, "login name much too long.\n"); + badlogin("NAME too long"); + exit(0); + } + } + if (p > nbuf) + if (nbuf[0] == '-') + fprintf(stderr, + "login names may not start with '-'.\n"); + else { + *p = '\0'; + username = nbuf; + break; + } + + cnt2++; + if (cnt2 > 50) { + fprintf(stderr, "too many bare linefeeds.\n"); + badlogin("EXCESSIVE linefeeds"); + exit(0); } + } } -void timedout() +void +timedout() { - struct termio ti; - - (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); - - /* reset echo */ - (void) ioctl(0, TCGETA, &ti); - ti.c_lflag |= ECHO; - (void) ioctl(0, TCSETA, &ti); - exit(0); + struct termio ti; + + fprintf(stderr, "Login timed out after %d seconds\n", timeout); + + /* reset echo */ + ioctl(0, TCGETA, &ti); + ti.c_lflag |= ECHO; + ioctl(0, TCSETA, &ti); + exit(0); } int rootterm(ttyn) - char *ttyn; -#ifndef linux + char *ttyn; +#ifndef __linux__ { - struct ttyent *t; - - return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); + struct ttyent *t; + + return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); } #else { - int fd; - char buf[100],*p; - int cnt, more; - - fd = open(SECURETTY, O_RDONLY); - if(fd < 0) return 1; - - /* read each line in /etc/securetty, if a line matches our ttyline - then root is allowed to login on this tty, and we should return - true. */ - for(;;) { + int fd; + char buf[100],*p; + int cnt, more; + + fd = open(SECURETTY, O_RDONLY); + if(fd < 0) return 1; + + /* read each line in /etc/securetty, if a line matches our ttyline + then root is allowed to login on this tty, and we should return + true. */ + for(;;) { p = buf; cnt = 100; while(--cnt >= 0 && (more = read(fd, p, 1)) == 1 && *p != '\n') p++; if(more && *p == '\n') { - *p = '\0'; - if(!strcmp(buf, ttyn)) { - close(fd); - return 1; - } else - continue; + *p = '\0'; + if(!strcmp(buf, ttyn)) { + close(fd); + return 1; + } else + continue; } else { - close(fd); - return 0; + close(fd); + return 0; } - } + } } #endif @@ -878,121 +1174,108 @@ jmp_buf motdinterrupt; void motd() { - register int fd, nchars; - void (*oldint)(), sigint(); - char tbuf[8192]; - - if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) - return; - oldint = signal(SIGINT, sigint); - if (setjmp(motdinterrupt) == 0) - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - (void)signal(SIGINT, oldint); - (void)close(fd); + register int fd, nchars; + void (*oldint)(), sigint(); + char tbuf[8192]; + + if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) + return; + oldint = signal(SIGINT, sigint); + if (setjmp(motdinterrupt) == 0) + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + write(fileno(stdout), tbuf, nchars); + signal(SIGINT, oldint); + close(fd); } -void sigint() +void +sigint() { - longjmp(motdinterrupt, 1); + longjmp(motdinterrupt, 1); } +#ifndef USE_PAM /* PAM takes care of this */ void checknologin() { - register int fd, nchars; - char tbuf[8192]; - - if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { - while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) - (void)write(fileno(stdout), tbuf, nchars); - sleepexit(0); - } + register int fd, nchars; + char tbuf[8192]; + + if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { + while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) + write(fileno(stdout), tbuf, nchars); + sleepexit(0); + } } +#endif void dolastlog(quiet) - int quiet; + int quiet; { - struct lastlog ll; - int fd; - - if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { - (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); - if (!quiet) { - if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && - ll.ll_time != 0) { - (void)printf("Last login: %.*s ", - 24-5, (char *)ctime(&ll.ll_time)); - - if (*ll.ll_host != '\0') - printf("from %.*s\n", - (int)sizeof(ll.ll_host), ll.ll_host); - else - printf("on %.*s\n", - (int)sizeof(ll.ll_line), ll.ll_line); - } - (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); - } - memset((char *)&ll, 0, sizeof(ll)); - (void)time(&ll.ll_time); - strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); - if (hostname) - strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); - (void)write(fd, (char *)&ll, sizeof(ll)); - (void)close(fd); + struct lastlog ll; + int fd; + + if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + if (!quiet) { + if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && + ll.ll_time != 0) { + printf("Last login: %.*s ", + 24-5, (char *)ctime(&ll.ll_time)); + + if (*ll.ll_host != '\0') + printf("from %.*s\n", + (int)sizeof(ll.ll_host), ll.ll_host); + else + printf("on %.*s\n", + (int)sizeof(ll.ll_line), ll.ll_line); + } + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); } + memset((char *)&ll, 0, sizeof(ll)); + time(&ll.ll_time); + strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); + ll.ll_line[sizeof(ll.ll_line)-1] = 0; + if (hostname) { + strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); + ll.ll_host[sizeof(ll.ll_host)-1] = 0; + } + write(fd, (char *)&ll, sizeof(ll)); + close(fd); + } } void -badlogin(name) - char *name; +badlogin(const char *name) { - if (hostname) - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", - failures, failures > 1 ? "S" : "", hostname, name); - else - syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", - failures, failures > 1 ? "S" : "", tty, name); + if (hostname) + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", + failures, failures > 1 ? "S" : "", hostname, name); + else + syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", + failures, failures > 1 ? "S" : "", tty, name); } #undef UNKNOWN #define UNKNOWN "su" -#ifndef linux +#ifndef __linux__ char * stypeof(ttyid) - char *ttyid; + char *ttyid; { - struct ttyent *t; + struct ttyent *t; - return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); + return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); } #endif -void -getstr(buf, cnt, err) - char *buf, *err; - int cnt; -{ - char ch; - - do { - if (read(0, &ch, sizeof(ch)) != sizeof(ch)) - exit(1); - if (--cnt < 0) { - (void)fprintf(stderr, "%s too long\r\n", err); - sleepexit(1); - } - *buf++ = ch; - } while (ch); -} - +/* should not be called from PAM code... Why? */ void sleepexit(eval) - int eval; + int eval; { - sleep((unsigned int)5); - exit(eval); + sleep(SLEEP_EXIT_TIMEOUT); + exit(eval); } - diff --git a/login-utils/mesg.c b/login-utils/mesg.c index 79d3ef21..4e491635 100644 --- a/login-utils/mesg.c +++ b/login-utils/mesg.c @@ -36,6 +36,8 @@ * SUCH DAMAGE. * * Modified Fri Mar 10 20:27:19 1995, faith@cs.unc.edu, for Linux + * Modified Mon Jul 1 18:14:10 1996, janl@ifi.uio.no, writing to stdout + * as suggested by Michael Meskes * */ @@ -84,10 +86,10 @@ main(argc, argv) if (*argv == NULL) { if (sb.st_mode & (S_IWGRP | S_IWOTH)) { - (void)fprintf(stderr, "is y\n"); + (void)fprintf(stdout, "is y\n"); exit(0); } - (void)fprintf(stderr, "is n\n"); + (void)fprintf(stdout, "is n\n"); exit(1); } diff --git a/login-utils/newgrp.c b/login-utils/newgrp.c index ba13fdeb..65dd00d9 100644 --- a/login-utils/newgrp.c +++ b/login-utils/newgrp.c @@ -3,6 +3,7 @@ /* Vesa Roukonen added code for asking password */ /* Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ */ +#define _XOPEN_SOURCE /* for crypt() */ #include #include #include diff --git a/login-utils/passwd.1 b/login-utils/passwd.1 index f2bf9de9..c696c53d 100644 --- a/login-utils/passwd.1 +++ b/login-utils/passwd.1 @@ -1,49 +1,112 @@ .\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH PASSWD 1 "22 June 1994" "Linux 1.2" "Linux Programmer's Manual" +.TH PASSWD 1 "11 November 1996" "Util-linux 2.6" "Linux Programmer's Manual" .SH NAME passwd \- change password .SH SYNOPSIS -.BR "passwd [ " name " [ " password " ] ]" +.BR "passwd" +.RB [ " \-o " ] +.RB [ " \-q " ] +.RB [ " \-v " ] +.RI [ " name " [ " password " ]] +.br +.BR "passwd \-f " +.RI [ " arguments to chfn " ] +.br +.BR "passwd \-s " +.RI [ " arguments to chsh " ] + .SH DESCRIPTION Without arguments .B passwd will change the password for the current user. First the user is asked for the old password, then prompted twice for the new password in order to -catch typing errors. The new password must be at least six characters long, -and have both upper and lower case letters or non-letters. The new password -must not be equal to the old password, and it must not match the username. +catch typing errors. The one and two argument forms may only be used by the superuser. Using the -one argument form, the superuser may change the password for that user. -The superuser is not asked for the users old password, and the rules -for proper passwords are not applied since the superuser may have legitimate +one argument form, the superuser may change the password for that +.IR user . +The superuser is not asked for the users old password, but the rules +for proper passwords are also applied unless the +.B "\-o" +option is used. The superuser may have legitimate reasons to choose a non-conformant password. The two argument form gives the -.I user -the password stated as the second argument. This may be useful when -giving many users an initial generated password. +.IR user " the " password +stated as the second argument. This may be useful when giving many +users an initial generated password. But it can also be extremely +dangerous. A simple script bug might change to root password to +something unknown. Giving an empty string as the second argument erases the password for the -user. +user, but only in combination with the +.B "\-o" +option. + +Password changes may get logged using the +.BR syslog (3) +facility, depending on compile-time defines (on by default). +If so, every change will +be logged at a low level as auth.notice, except for changing the root +password with will be logged with auth.warning. + +.SH OPTIONS +.TP +.B "\-f, \-\-fullname" +Change the user's full name (the GECOS field of the passwd entry). +Invokes /usr/bin/chfn with the non-option command line arguments. +.TP +.B "\-o, \-\-force" +Turn off simplicity checks on the new password. This option may only +be used by the super user. This is intend to allow simple initial +passwords given by the superuser. +.TP +.B "\-s, \-\-shell" +Change the user's shell by invoking /usr/bin/chsh with the non-option +command line arguments. +.TP +.B "\-q, \-\-quiet, \-\-silent" +In this mode passwd won't tell that the passwd get's changed. +.TP +.B "\-v, \-V, \-\-version" +Prints version information and exits. + +.SH PASSWORD RULES +The new password must fulfill these rules: +.TP +o +be at least six characters long; +.TP +o +must not be equal to the old password; + +.TP +o +must contain characters out of at least two of the following classes: +upper and lower case letters, digits and non alphanumeric characters; + +.TP +o +must not match neither the username nor any word of the realname, +neither in normal nor in reverse order, neither at the beginning nor +at the end. .SH FILES +.TP .I /etc/passwd -.br -.I /etc/shells +The password file. .SH "SEE ALSO" .BR chsh (1), -.BR chfn (1) -.SH BUGS -A password consisting of all digits is allowed. +.BR chfn (1), +.BR syslog (3), +.BR syslog.conf (5), +.BR passwd (8). +.SH AUTHOR +Peter Orbaek (poe@daimi.aau.dk). .br -No warnings are printed if the superuser chooses a poor password. +Martin Schulze (joey@infodrom.north.de) with extensive rewriting and +improving done. .br -The -.B \-f -and -.B \-s -options are not supported. -.SH AUTHOR -Peter Orbaek (poe@daimi.aau.dk) +.SH MAINTAINER +Nicolai Langfeldt (janl@math.uio.no) diff --git a/login-utils/passwd.c b/login-utils/passwd.c index 1c786e94..f707c052 100644 --- a/login-utils/passwd.c +++ b/login-utils/passwd.c @@ -1,12 +1,43 @@ -/* passwd.c - change password on an account +/* + * passwd.c - change password on an account + * * Initially written for Linux by Peter Orbaek * Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ + + Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, + to allow peaceful coexistence with yp. Nov 94. + + Hacked to allow root to set passwd from command line. + by Arpad Magossanyi (mag@tas.vein.hu) + + Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, + moved Alvaro's changes to setpwnam.c (so they get used + by chsh and chfn as well). Oct 5, 96. + */ -/* Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, - to allow peaceful coexistence with yp. Nov 94. */ -/* Hacked to allow root to set passwd from command line. - by Arpad Magossanyi (mag@tas.vein.hu) */ +/* + * Sun Oct 15 13:18:34 1995 Martin Schulze + * + * I have completely rewritten the whole argument handlig (what?) + * to support two things. First I wanted "passwd $user $pw" to + * work and second I wanted simplicity checks to be done for + * root, too. Only root can turn this of using the -f + * switch. Okay, I started with this to support -V version + * information, but one thing comes to the next. *sigh* + * In a later step perhaps we'll be able to support shadow + * passwords. (?) + * + * I have also included a DEBUG mode (-DDEBUG) to test the + * argument handling _without_ any write attempt to + * /etc/passwd. + * + * If you're paranoid about security on your system, you may want + * to add -DLOGALL to CFLAGS. This will turn on additional syslog + * logging of every password change. (user changes are logged as + * auth.notice, but changing root's password is logged as + * auth.warning. (Of course, the password itself is not logged.) + */ /* * Usage: passwd [username [password]] @@ -17,7 +48,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -26,21 +60,170 @@ #include #include -extern int is_local(char *); +#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#include +#endif + +#if 0 +# include "../version.h" +#else +char version[] = "admutil 1.18, 15-Oct-95"; +#endif + +#ifndef _PATH_CHFN +# define _PATH_CHFN "/usr/bin/chfn" +# define _PATH_CHSH "/usr/bin/chsh" +#endif + +#define LOGALL + +#ifdef LOGALL +#include +#endif /* LOGALL */ + +extern int is_local(char *); /* islocal.c */ +extern int setpwnam(struct passwd *); /* setpwnam.c */ #define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') -#define MAX_LENGTH 1024 - static void -pexit(str) - char *str; +pexit(char *str, ...) { - perror(str); + va_list vlst; + + va_start(vlst, str); + vfprintf(stderr, str, vlst); + fprintf(stderr, ": "); + perror(""); + va_end(vlst); exit(1); } +/* + * Do various checks for stupid passwords here... + * + * This would probably be the best place for checking against + * dictionaries. :-) + */ + +int check_passwd_string(char *passwd, char *string) +{ + int r; + char *p, *q; + + r = 0; + /* test for string at the beginning of passwd */ + for (p = passwd, q = string; *q && *p; q++, p++) { + if(tolower(*p) != tolower(*q)) { + r++; + break; + } + } + + /* test for reverse string at the beginning of passwd */ + for (p = passwd, q = string + strlen(string)-1; + *p && q >= string; p++, q--) { + if(tolower(*p) != tolower(*q)) { + r++; + break; + } + } + + /* test for string at the end of passwd */ + for (p = passwd + strlen(passwd)-1, q = string + strlen(string)-1; + q >= string && p >= passwd; q--, p--) { + if(tolower(*p) != tolower(*q)) { + r++; + break; + } + } + + /* test for reverse string at the beginning of passwd */ + for (p = passwd + strlen(passwd)-1, q = string; + p >= passwd && *q; p--, q++) { + if(tolower(*p) != tolower(*q)) { + r++; + break; + } + } + + if (r != 4) { + return 0; + } + return 1; +} + +int check_passwd(char *passwd, char *oldpasswd, char *user, char *gecos) +{ + int ucase, lcase, digit, other; + char *c, *g, *p; + + if ( (strlen(passwd) < 6) ) { + printf("The password must have at least 6 characters, try again.\n"); + return 0; + } + + other = digit = ucase = lcase = 0; + for (p = passwd; *p; p++) { + ucase = ucase || isupper(*p); + lcase = lcase || islower(*p); + digit = digit || isdigit(*p); + other = other || !isalnum(*p); + } + + if ( (other + digit + ucase + lcase) < 2) { + printf("The password must contain characters out of two of the following\n"); + printf("classes: upper and lower case letters, digits and non alphanumeric\n"); + printf("characters. See passwd(1) for more information.\n"); + return 0; + } + + if ( oldpasswd[0] && !strncmp(oldpasswd, crypt(passwd, oldpasswd), 13) ) { + printf("You cannot reuse the old password.\n"); + return 0; + } + + if ( !check_passwd_string(passwd, user) ) { + printf("Please don't use something like your username as password!\n"); + return 0; + } + + /* check against realname */ + if ( (c = index(gecos, ',')) ) { + if ( c-gecos && (g = (char *)malloc (c-gecos+1)) ) { + strncpy (g, gecos, c-gecos); + g[c-gecos] = 0; + while ( (c=rindex(g, ' ')) ) { + if ( !check_passwd_string(passwd, c+1) ) { + printf("Please don't use something like your realname as password!\n"); + free (g); + return 0; + } + *c = '\0'; + } /* while */ + if ( !check_passwd_string(passwd, g) ) { + printf("Please don't use something like your realname as password!\n"); + free (g); + return 0; + } + free (g); + } /* if malloc */ + } + + /* + * if ( !check_password_dict(passwd) ) ... + */ + + return 1; /* fine */ +} + +void usage() +{ + printf ("Usage: passwd [username [password]]\n"); + printf("Only root may use the one and two argument forms.\n"); +} + int main(argc, argv) int argc; @@ -50,56 +233,101 @@ main(argc, argv) uid_t gotuid = getuid(); char *pwdstr = NULL, *cryptstr, *oldstr; char pwdstr1[10]; - int ucase, lcase, other; - char *p, *q, *user; + char *user; time_t tm; char salt[2]; - FILE *fd_in, *fd_out; - char line[MAX_LENGTH]; - char colonuser[16]; - int error=0; - int r; - int ptmp; -#ifndef USE_SETPWNAM - struct rlimit rlim; -#endif + int force_passwd = 0; + int silent = 0; + char c; + int opt_index; + int fullname = 0, shell = 0; + static const struct option long_options[] = + { + {"fullname", no_argument, 0, 'f'}, + {"shell", no_argument, 0, 's'}, + {"force", no_argument, 0, 'o'}, + {"quiet", no_argument, 0, 'q'}, + {"silent", no_argument, 0, 'q'}, + {"version", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; - if(argc > 3) { - puts("Too many arguments"); - exit(1); - } else if(argc >= 2) { - if(gotuid) { - puts("Only root can change the password for others"); + optind = 0; + while ( (c = getopt_long(argc, argv, "foqsvV", long_options, &opt_index)) != -1 ) { + switch (c) { + case 'f': + fullname = 1; + break; + case 's': + shell = 1; + break; + case 'o': + force_passwd = 1; + break; + case 'q': + silent = 1; + break; + case 'V': + case 'v': + printf("%s\n", version); + exit(0); + default: + fprintf(stderr, "Usage: passwd [-foqsvV] [user [password]]\n"); exit(1); - } - user = argv[1]; - - if (argc == 3) pwdstr = argv[2]; - - } else { - if (!(user = getlogin())) { - if (!(pe = getpwuid( getuid() ))) { + } /* switch (c) */ + } /* while */ + + if (fullname || shell) { + char *args[100]; + int i, j; + + setuid(getuid()); /* drop special privs. */ + if (fullname) + args[0] = _PATH_CHFN; + else + args[0] = _PATH_CHSH; + + for (i = optind, j = 1; (i < argc) && (j < 99); i++, j++) + args[j] = argv[i]; + + args[j] = NULL; + execv(args[0], args); + fprintf(stderr, "Can't exec %s: %s\n", args[0], strerror(errno)); + exit(1); + } + + switch (argc - optind) { + case 0: + if ( !(user = getlogin()) ) { + if ( !(pe = getpwuid( getuid() )) ) { pexit("Cannot find login name"); } else - user = pe->pw_name; + user = pe->pw_name; } - } + break; + case 1: + if(gotuid) { + printf("Only root can change the password for others.\n"); + exit (1); + } else + user = argv[optind]; + break; + case 2: + if(gotuid) { + printf("Only root can change the password for others.\n"); + exit(1); + } else { + user = argv[optind]; + pwdstr = argv[optind+1]; + } + break; + default: + printf("Too many arguments.\n"); + exit (1); + } /* switch */ -#ifndef USE_SETPWNAM - umask(022); - - rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CPU, &rlim); - setrlimit(RLIMIT_FSIZE, &rlim); - setrlimit(RLIMIT_STACK, &rlim); - setrlimit(RLIMIT_DATA, &rlim); - setrlimit(RLIMIT_RSS, &rlim); - rlim.rlim_cur = rlim.rlim_max = 0; - setrlimit(RLIMIT_CORE, &rlim); -#endif - if(!(pe = getpwnam(user))) { - pexit("Can't find username anywhere. Are you really a user?"); + pexit("Can't find username anywhere. Is `%s' really a user?", user); } if (!(is_local(user))) { @@ -113,9 +341,11 @@ main(argc, argv) exit(1); } - printf( "Changing password for %s\n", user ); + if ( !silent ) + printf( "Changing password for %s\n", user ); - if(gotuid && pe->pw_passwd && pe->pw_passwd[0]) { + if ( (gotuid && pe->pw_passwd && pe->pw_passwd[0]) + || (!gotuid && !strcmp(user,"root")) ) { oldstr = getpass("Enter old password: "); if(strncmp(pe->pw_passwd, crypt(oldstr, pe->pw_passwd), 13)) { puts("Illegal password, imposter."); @@ -123,7 +353,10 @@ main(argc, argv) } } - if (!pwdstr) { + if ( pwdstr ) { /* already set on command line */ + if ( !force_passwd && !check_passwd(pwdstr, pe->pw_passwd, user, pe->pw_gecos) ) + exit (1); + } else { /* password not set on command line by root, ask for it ... */ redo_it: @@ -132,126 +365,53 @@ main(argc, argv) puts("Password not changed."); exit(1); } - - if((strlen(pwdstr) < 6) && gotuid) { - puts("The password must have at least 6 characters, try again."); - goto redo_it; - } - - other = ucase = lcase = 0; - for(p = pwdstr; *p; p++) { - ucase = ucase || isupper(*p); - lcase = lcase || islower(*p); - other = other || !isalpha(*p); - } - - if((!ucase || !lcase) && !other && gotuid) { - puts("The password must have both upper- and lowercase"); - puts("letters, or non-letters; try again."); - goto redo_it; - } - - if (pe->pw_passwd[0] - && !strncmp(pe->pw_passwd, crypt(pwdstr, pe->pw_passwd), 13) - && gotuid) { - puts("You cannot reuse the old password."); - goto redo_it; - } - - r = 0; - for(p = pwdstr, q = pe->pw_name; *q && *p; q++, p++) { - if(tolower(*p) != tolower(*q)) { - r = 1; - break; - } - } - - for(p = pwdstr + strlen(pwdstr)-1, q = pe->pw_name; - *q && p >= pwdstr; q++, p--) { - if(tolower(*p) != tolower(*q)) { - r += 2; - break; - } - } - - if(gotuid && r != 3) { - puts("Please don't use something like your username as password!"); + + if ( (gotuid || (!gotuid && !force_passwd)) + && !check_passwd(pwdstr, pe->pw_passwd, user, pe->pw_gecos) ) goto redo_it; - } - - /* do various other checks for stupid passwords here... */ strncpy(pwdstr1, pwdstr, 9); + pwdstr1[9] = 0; pwdstr = getpass("Re-type new password: "); if(strncmp(pwdstr, pwdstr1, 8)) { puts("You misspelled it. Password not changed."); exit(1); } - } /* pwdstr != argv[2] i.e. password set on command line */ + } /* pwdstr i.e. password set on command line */ - time(&tm); + time(&tm); tm ^= getpid(); salt[0] = bin_to_ascii(tm & 0x3f); salt[1] = bin_to_ascii((tm >> 6) & 0x3f); cryptstr = crypt(pwdstr, salt); if (pwdstr[0] == 0) cryptstr = ""; -#ifdef USE_SETPWNAM +#ifdef LOGALL + openlog("passwd", 0, LOG_AUTH); + if (gotuid) + syslog(LOG_NOTICE,"password changed, user %s",user); + else { + if ( !strcmp(user, "root") ) + syslog(LOG_WARNING,"ROOT PASSWORD CHANGED"); + else + syslog(LOG_NOTICE,"password changed by root, user %s",user); + } + closelog(); +#endif /* LOGALL */ + pe->pw_passwd = cryptstr; +#ifdef DEBUG + printf ("calling setpwnam to set password.\n"); +#else if (setpwnam( pe ) < 0) { perror( "setpwnam" ); printf( "Password *NOT* changed. Try again later.\n" ); exit( 1 ); } -#else - if ((ptmp = open("/etc/ptmp", O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0) { - pexit("Can't exclusively open /etc/ptmp, can't update password"); - } - fd_out = fdopen(ptmp, "w"); - - if(!(fd_in = fopen("/etc/passwd", "r"))) { - pexit("Can't read /etc/passwd, can't update password"); - } - - strcpy(colonuser, user); - strcat(colonuser, ":"); - while(fgets(line, sizeof(line), fd_in)) { - if(!strncmp(line,colonuser,strlen(colonuser))) { - pe->pw_passwd = cryptstr; - if(putpwent(pe, fd_out) < 0) { - error = 1; - } - } else { - if(fputs(line,fd_out) < 0) { - error = 1; - } - } - if(error) { - puts("Error while writing new password file, password not changed."); - fclose(fd_out); - endpwent(); - unlink("/etc/ptmp"); - exit(1); - } - } - fclose(fd_in); - fclose(fd_out); - - unlink("/etc/passwd.OLD"); /* passwd.OLD not required */ - if (link("/etc/passwd", "/etc/passwd.OLD")) - pexit("link(/etc/passwd, /etc/passwd.OLD) failed: no change"); - if (unlink("/etc/passwd") < 0) - pexit("unlink(/etc/passwd) failed: no change"); - if (link("/etc/ptmp", "/etc/passwd") < 0) - pexit("link(/etc/ptmp, /etc/passwd) failed: PASSWD file DROPPED!!"); - if (unlink("/etc/ptmp") < 0) - pexit("unlink(/etc/ptmp) failed: /etc/ptmp still exists"); - - chmod("/etc/passwd", 0644); - chown("/etc/passwd", 0, 0); #endif - - puts("Password changed."); + + if ( !silent ) + printf("Password changed.\n"); exit(0); } diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c index 8a01c6ec..1f1067cf 100644 --- a/login-utils/setpwnam.c +++ b/login-utils/setpwnam.c @@ -8,6 +8,11 @@ * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * + * Edited 11/10/96 (DD/MM/YY ;-) by Nicolai Langfeldt (janl@math.uio.no) + * to read /etc/passwd directly so that passwd, chsh and chfn can work + * on machines that run NIS (né YP). Changes will not be made to + * usernames starting with +. + * * This file is distributed with no warranty. * * Usage: @@ -17,15 +22,25 @@ * 2) edit the fields you want to edit. * 3) call setpwnam() with the edited struct passwd. * - * You should never directly read from or write to /etc/passwd. - * All user database queries should be directed through - * getpwnam() and setpwnam(). + * A _normal user_ program should never directly manipulate + * /etc/passwd but use getpwnam() and (family, as well as) + * setpwnam(). + * + * But, setpwnam was made to _edit_ the password file. For use by + * chfn, chsh and passwd. _I_ _HAVE_ to read and write /etc/passwd + * directly. Let those who say nay be forever silent and think about + * how getpwnam (and family) works on a machine running YP. + * + * Added checks for failure of malloc() and removed error reporting + * to stderr, this is a library function and should not print on the + * screen, but return appropriate error codes. + * 27-Jan-97 - poe@daimi.aau.dk * * Thanks to "two guys named Ian". - */ -/* $Author: faith $ - * $Revision: 1.5 $ - * $Date: 1995/10/12 14:46:36 $ + * + * $Author: poer $ + * $Revision: 1.13 $ + * $Date: 1997/06/23 08:26:29 $ */ #undef DEBUG @@ -43,207 +58,164 @@ #include #include #include -#ifdef BSD43 -#include -#endif +#include #include -#include "pathnames.h" - -extern int errno; +#include "setpwnam.h" -typedef int boolean; -#define false 0 -#define true 1 - -#ifndef DEBUG -#define PASSWD_FILE _PATH_PASSWD -#define PTMP_FILE _PATH_PTMP -#define PTMPTMP_FILE _PATH_PTMPTMP -#else -#define PASSWD_FILE "/tmp/passwd" -#define PTMP_FILE "/tmp/ptmp" -#define PTMPTMP_FILE "/tmp/ptmptmp" -#endif - -static int copy_pwd (struct passwd *src, struct passwd *dest); -static char *xstrdup (char *str); static void pw_init(void); /* * setpwnam () -- * takes a struct passwd in which every field is filled in and valid. - * If the given username exists in the passwd file, his entry is + * If the given username exists in the passwd file, the entry is * replaced with the given entry. */ -int setpwnam (struct passwd *pwd) +int +setpwnam (struct passwd *pwd) { - FILE *fp; + FILE *fp = NULL, *pwf = NULL; int x, save_errno, fd, ret; - struct passwd *entry; boolean found; - struct passwd spwd; int oldumask; + int namelen; + int buflen = 256; + int contlen; + char *linebuf = malloc(buflen); - /* getpwent() returns a pointer to a static buffer. - * "pwd" might have some from getpwent(), so we have to copy it to - * some other buffer before calling getpwent(). - */ - if (copy_pwd (pwd, &spwd) < 0) - return (-1); + if (!linebuf) return -1; oldumask = umask(0); /* Create with exact permissions */ + pw_init(); /* sanity check */ for (x = 0; x < 3; x++) { - if (x > 0) sleep (1); - fd = open (PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644); - if(fd == -1) { - perror(PTMPTMP_FILE); + if (x > 0) sleep(1); + fd = open(PTMPTMP_FILE, O_WRONLY|O_CREAT, 0644); + if (fd == -1) { umask(oldumask); - return (-1); + return -1; } ret = link(PTMPTMP_FILE, PTMP_FILE); unlink(PTMPTMP_FILE); - if(ret == -1) + if (ret == -1) close(fd); else break; } - umask(oldumask); - if (ret == -1) return (-1); + if (ret == -1) return -1; /* ptmp should be owned by root.root or root.wheel */ - if (chown (PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0) - perror ("chown"); + if (chown(PTMP_FILE, (uid_t) 0, (gid_t) 0) < 0) return -1; /* open ptmp for writing and passwd for reading */ - fp = fdopen (fd, "w"); - if (! fp) goto fail; + fp = fdopen(fd, "w"); + if (!fp) goto fail; - setpwent (); + pwf = fopen(PASSWD_FILE, "r"); + if (!pwf) goto fail; + + namelen = strlen(pwd->pw_name); /* parse the passwd file */ found = false; - while ((entry = getpwent ()) != NULL) { - if (! strcmp (spwd.pw_name, entry->pw_name)) { - entry = &spwd; - found = true; - } - if (putpwent (entry, fp) < 0) goto fail; + /* Do you wonder why I don't use getpwent? Read comments at top of file */ + while (fgets(linebuf, buflen, pwf) != NULL) { + contlen = strlen(linebuf); + while (linebuf[contlen-1] != '\n' && !feof(pwf)) { + /* Extend input buffer if it failed getting the whole line */ + + /* So now we double the buffer size */ + buflen *= 2; + + linebuf = realloc(linebuf, buflen); + if (linebuf == NULL) goto fail; + + /* And fill the rest of the buffer */ + if (fgets(&linebuf[contlen], buflen/2, pwf) == NULL) break; + contlen = strlen(linebuf); + + /* That was a lot of work for nothing. Gimme perl! */ + } + + /* Is this the username we were sent to change? */ + if (!found && linebuf[namelen] == ':' && + !strncmp(linebuf, pwd->pw_name, namelen)) { + /* Yes! So go forth in the name of the Lord and change it! */ + if (putpwent(pwd, fp) < 0) goto fail; + found = true; + continue; + } + /* Nothing in particular happened, copy input to output */ + fputs(linebuf, fp); } - if (fclose (fp) < 0) goto fail; + + if (fclose(fp) < 0) goto fail; + fp = NULL; close (fd); - endpwent (); + fd = -1; + fclose (pwf); /* I don't think I want to know if this failed */ + pwf = NULL; - if (! found) { + if (!found) { errno = ENOENT; /* give me something better */ goto fail; } /* we don't care if we can't remove the backup file */ - unlink (PASSWD_FILE".OLD"); + unlink(PASSWD_FILE".OLD"); /* we don't care if we can't create the backup file */ - link (PASSWD_FILE, PASSWD_FILE".OLD"); + link(PASSWD_FILE, PASSWD_FILE".OLD"); /* we DO care if we can't rename to the passwd file */ - if (rename (PTMP_FILE, PASSWD_FILE) < 0) + if(rename(PTMP_FILE, PASSWD_FILE) < 0) goto fail; /* finally: success */ return 0; - fail: +fail: save_errno = errno; - if (fp) fclose (fp); + if (fp != NULL) fclose (fp); + if (pwf != NULL) fclose(pwf); if (fd >= 0) close (fd); - endpwent (); - unlink (PTMP_FILE); + if (linebuf != NULL) free(linebuf); + unlink(PTMP_FILE); errno = save_errno; - return (-1); + return -1; } -#define memzero(ptr, size) memset((char *) ptr, 0, size) -static int failed; - -static int copy_pwd (struct passwd *src, struct passwd *dest) -{ - /* this routine destroys abstraction barriers. it's not portable - * across systems, or even across different versions of the C library - * on a given system. it's dangerous and evil and wrong and I dispise - * getpwent() for forcing me to write this. - */ - failed = 0; - memzero (dest, sizeof (struct passwd)); - dest->pw_name = xstrdup (src->pw_name); - dest->pw_passwd = xstrdup (src->pw_passwd); - dest->pw_uid = src->pw_uid; - dest->pw_gid = src->pw_gid; - dest->pw_gecos = xstrdup (src->pw_gecos); - dest->pw_dir = xstrdup (src->pw_dir); - dest->pw_shell = xstrdup (src->pw_shell); - return (failed); -} +/* Set up the limits so that we're not foiled */ -static char *xstrdup (char *str) +static void +pw_init() { - char *dup; - - if (! str) - return NULL; - dup = (char *) malloc (strlen (str) + 1); - if (! dup) { - failed = -1; - return NULL; - } - strcpy (dup, str); - return dup; -} + struct rlimit rlim; -#ifdef NO_PUTPWENT - -int putpwent (const struct passwd *p, FILE *stream) -{ - if (p == NULL || stream == NULL) { - errno = EINVAL; - return (-1); - } - if (fprintf (stream, "%s:%s:%u:%u:%s:%s:%s\n", - p->pw_name, p->pw_passwd, p->pw_uid, p->pw_gid, - p->pw_gecos, p->pw_dir, p->pw_shell) < 0) - return (-1); - return(0); -} + /* Unlimited resource limits. */ + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + setrlimit(RLIMIT_CPU, &rlim); + setrlimit(RLIMIT_FSIZE, &rlim); + setrlimit(RLIMIT_STACK, &rlim); + setrlimit(RLIMIT_DATA, &rlim); + setrlimit(RLIMIT_RSS, &rlim); +#ifndef DEBUG + /* Don't drop core (not really necessary, but GP's). */ + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); #endif -static void -pw_init() -{ - struct rlimit rlim; - - /* Unlimited resource limits. */ - rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; - (void)setrlimit(RLIMIT_CPU, &rlim); - (void)setrlimit(RLIMIT_FSIZE, &rlim); - (void)setrlimit(RLIMIT_STACK, &rlim); - (void)setrlimit(RLIMIT_DATA, &rlim); - (void)setrlimit(RLIMIT_RSS, &rlim); - - /* Don't drop core (not really necessary, but GP's). */ - rlim.rlim_cur = rlim.rlim_max = 0; - (void)setrlimit(RLIMIT_CORE, &rlim); - - /* Turn off signals. */ - (void)signal(SIGALRM, SIG_IGN); - (void)signal(SIGHUP, SIG_IGN); - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGPIPE, SIG_IGN); - (void)signal(SIGQUIT, SIG_IGN); - (void)signal(SIGTERM, SIG_IGN); - (void)signal(SIGTSTP, SIG_IGN); - (void)signal(SIGTTOU, SIG_IGN); - - /* Create with exact permissions. */ - (void)umask(0); + /* Turn off signals. */ + signal(SIGALRM, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + + /* Create with exact permissions. */ + umask(0); } diff --git a/login-utils/setpwnam.h b/login-utils/setpwnam.h new file mode 100644 index 00000000..b4790f7a --- /dev/null +++ b/login-utils/setpwnam.h @@ -0,0 +1,38 @@ +/* + * setpwnam.h -- + * define several paths + * + * (c) 1994 Martin Schulze + * This file is based on setpwnam.c which is + * (c) 1994 Salvatore Valente + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + */ + +#include "pathnames.h" + +#define false 0 +#define true 1 + +typedef int boolean; + +#ifndef DEBUG +#define PASSWD_FILE _PATH_PASSWD +#define PTMP_FILE _PATH_PTMP +#define PTMPTMP_FILE _PATH_PTMPTMP + +#define GROUP_FILE _PATH_GROUP +#define GTMP_FILE _PATH_GTMP +#define GTMPTMP_FILE _PATH_GTMPTMP +#else +#define PASSWD_FILE "/tmp/passwd" +#define PTMP_FILE "/tmp/ptmp" +#define PTMPTMP_FILE "/tmp/ptmptmp" + +#define GROUP_FILE "/tmp/group" +#define GTMP_FILE "/tmp/gtmp" +#define GTMPTMP_FILE "/tmp/gtmptmp" +#endif diff --git a/login-utils/shutdown.8 b/login-utils/shutdown.8 index 21b38412..443acc2a 100644 --- a/login-utils/shutdown.8 +++ b/login-utils/shutdown.8 @@ -5,11 +5,11 @@ shutdown \- close down the system .SH SYNOPSIS .nf -.BR "shutdown [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]" -.BR "reboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]" -.BR "fastboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]" -.BR "halt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]" -.BR "fasthalt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ]" +.BR "shutdown [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]" +.BR "reboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]" +.BR "fastboot [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]" +.BR "halt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]" +.BR "fasthalt [ \-h | \-r ] [ \-fqs ] [ now | " hh:ss " | " +mins " ] [ " message " ]" .fi .SH DESCRIPTION .\" " for emacs hilit19 @@ -17,7 +17,11 @@ In general, .B shutdown prepares the system for a power down or reboot. A absolute or delta time can be given, and periodic messages will be sent to all users warning of -the shutdown. +the shutdown. If no message is specified on the command line, +.B shutdown +will ask for a message to be sent, unless the +.B \-q +option is set. .B halt is the same as diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c index 155154c2..a63cbd6e 100644 --- a/login-utils/shutdown.c +++ b/login-utils/shutdown.c @@ -56,6 +56,7 @@ int opt_fast; /* true if fast boot */ char message[90]; /* reason for shutdown if any... */ int opt_single = 0; /* true is we want to boot singleuser */ char *whom; /* who is shutting the system down */ +int opt_msgset = 0; /* message set on command line */ /* #define DEBUGGING */ @@ -156,7 +157,7 @@ main(argc, argv) timeout = 0; } else if(argv[c][0] == '+') { timeout = 60 * atoi(&argv[c][1]); - } else { + } else if (isdigit(argv[c][0])) { char *colon; int hour = 0; int minute = 0; @@ -180,11 +181,15 @@ main(argc, argv) fprintf(stderr, "That must be tomorrow, can't you wait till then?\n"); exit(1); } + } else { + strncpy(message, argv[c], sizeof(message)); + message[sizeof(message)-1] = '\0'; + opt_msgset = 1; } } } - if(!opt_quiet) { + if(!opt_quiet && !opt_msgset) { /* now ask for message, gets() is insecure */ int cnt = sizeof(message)-1; char *ptr; @@ -196,8 +201,9 @@ main(argc, argv) ptr++; } *ptr = '\0'; - } else + } else if (!opt_msgset) { strcpy(message, "for maintenance; bounce, bounce"); + } #ifdef DEBUGGING printf("timeout = %d, quiet = %d, reboot = %d\n", @@ -221,7 +227,7 @@ main(argc, argv) } - if((fd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT)) >= 0) { + if((fd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT, 0644)) >= 0) { WR("\r\nThe system is being shut down within 5 minutes\r\n"); write(fd, message, strlen(message)); WR("\r\nLogin is therefore prohibited.\r\n"); @@ -249,13 +255,13 @@ main(argc, argv) closelog(); if(opt_fast) - if((fd = open("/fastboot", O_WRONLY|O_CREAT)) >= 0) + if((fd = open("/fastboot", O_WRONLY|O_CREAT, 0644)) >= 0) close(fd); kill(1, SIGTSTP); /* tell init not to spawn more getty's */ write_wtmp(); if(opt_single) - close(open(_PATH_SINGLE, O_CREAT|O_WRONLY)); + close(open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644)); sync(); @@ -288,9 +294,12 @@ main(argc, argv) if(opt_reboot) { reboot(0xfee1dead, 672274793, 0x1234567); } else { + freopen(_PATH_CONSOLE, "w", stdout); printf("\nNow you can turn off the power...\n"); - /* allow C-A-D now, faith@cs.unc.edu */ + fflush(stdout); + /* allow C-A-D now, faith@cs.unc.edu, re-fixed 8-Jul-96 */ reboot(0xfee1dead, 672274793, 0x89abcdef); + reboot(0xfee1dead, 672274793, 0xcdef0123); } /* NOTREACHED */ exit(0); /* to quiet gcc */ @@ -364,7 +373,7 @@ write_wtmp() time(&ut.ut_time); ut.ut_type = BOOT_TIME; - if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) { + if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0644)) >= 0) { write(fd, (char *)&ut, sizeof(ut)); close(fd); } diff --git a/login-utils/simpleinit.8 b/login-utils/simpleinit.8 index a506e1ae..ad942d3b 100644 --- a/login-utils/simpleinit.8 +++ b/login-utils/simpleinit.8 @@ -90,11 +90,11 @@ An example is as follows: .nf .RS -tty1:console:/sbin/getty 9600 tty1 -tty2:console:/sbin/getty 9600 tty2 -tty3:console:/sbin/getty 9600 tty3 -tty4:console:/sbin/getty 9600 tty4 -# tty5:console:/sbin/getty 9600 tty5 +tty1:linux:/sbin/getty 9600 tty1 +tty2:linux:/sbin/getty 9600 tty2 +tty3:linux:/sbin/getty 9600 tty3 +tty4:linux:/sbin/getty 9600 tty4 +# tty5:linux:/sbin/getty 9600 tty5 # ttyS1:dumb:/sbin/getty 9600 ttyS1 # ttyS2:dumb:/sbin/getty -m -t60 2400 ttyS2 .RE diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c index 3a39dcd4..14d8cfad 100644 --- a/login-utils/simpleinit.c +++ b/login-utils/simpleinit.c @@ -140,7 +140,7 @@ int main(int argc, char *argv[]) /* clear utmp entry, and append to wtmp if possible */ { struct utmp *ut; - int ut_fd; + int ut_fd, lf; utmpname(_PATH_UTMP); setutent(); @@ -152,13 +152,17 @@ int main(int argc, char *argv[]) ut->ut_type = DEAD_PROCESS; ut->ut_pid = 0; ut->ut_addr = 0; - endutent(); + /*endutent();*/ pututline(ut); - if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { - flock(ut_fd, LOCK_EX|LOCK_NB); - write(ut_fd, ut, sizeof(struct utmp)); - flock(ut_fd, LOCK_UN|LOCK_NB); - close(ut_fd); + + if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { + flock(lf, LOCK_EX|LOCK_NB); + if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { + write(ut_fd, ut, sizeof(struct utmp)); + close(ut_fd); + } + flock(lf, LOCK_UN|LOCK_NB); + close(lf); } break; } @@ -431,7 +435,7 @@ void set_tz() void write_wtmp() { - int fd; + int fd, lf; struct utmp ut; memset((char *)&ut, 0, sizeof(ut)); @@ -439,11 +443,14 @@ void write_wtmp() memset(ut.ut_name, 0, sizeof(ut.ut_name)); time(&ut.ut_time); ut.ut_type = BOOT_TIME; - - if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) { - flock(fd, LOCK_EX|LOCK_NB); /* make sure init won't hang */ - write(fd, (char *)&ut, sizeof(ut)); - flock(fd, LOCK_UN|LOCK_NB); - close(fd); + + if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { + flock(lf, LOCK_EX|LOCK_NB); /* make sure init won't hang */ + if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) { + write(fd, (char *)&ut, sizeof(ut)); + close(fd); + } + flock(lf, LOCK_UN|LOCK_NB); + close(lf); } } diff --git a/login-utils/ttymsg.c b/login-utils/ttymsg.c index e6aa3961..1f5fd1f5 100644 --- a/login-utils/ttymsg.c +++ b/login-utils/ttymsg.c @@ -68,7 +68,7 @@ ttymsg(iov, iovcnt, line, tmout) char *line; int tmout; { - static char device[MAXNAMLEN] = _PATH_DEV; + static char device[MAXNAMLEN]; static char errbuf[1024]; register int cnt, fd, left, wret; struct iovec localiov[6]; @@ -77,17 +77,13 @@ ttymsg(iov, iovcnt, line, tmout) if (iovcnt > sizeof(localiov) / sizeof(localiov[0])) return ("too many iov's (change code in wall/ttymsg.c)"); - (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); - if (strchr(device + sizeof(_PATH_DEV) - 1, '/')) { + if (strchr(line, '/')) { /* A slash is an attempt to break security... */ -#ifdef __linux__ - (void) sprintf(errbuf, "'/' in \"%s\"", device); -#else (void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"", device); -#endif return (errbuf); } + (void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line); /* * open will fail on slip lines or exclusive-use lines @@ -96,13 +92,8 @@ ttymsg(iov, iovcnt, line, tmout) if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { if (errno == EBUSY || errno == EACCES) return (NULL); -#ifdef __linux__ - (void) sprintf(errbuf, - "%s: %s", device, strerror(errno)); -#else (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device, strerror(errno)); -#endif return (errbuf); } @@ -140,13 +131,8 @@ ttymsg(iov, iovcnt, line, tmout) } cpid = fork(); if (cpid < 0) { -#ifdef __linux__ - (void) sprintf(errbuf, - "fork: %s", strerror(errno)); -#else (void) snprintf(errbuf, sizeof(errbuf), "fork: %s", strerror(errno)); -#endif (void) close(fd); return (errbuf); } @@ -172,13 +158,8 @@ ttymsg(iov, iovcnt, line, tmout) (void) close(fd); if (forked) _exit(1); -#ifdef __linux__ - (void) sprintf(errbuf, - "%s: %s", device, strerror(errno)); -#else (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device, strerror(errno)); -#endif return (errbuf); } diff --git a/login-utils/vigr.8 b/login-utils/vigr.8 new file mode 100644 index 00000000..ff72d7ae --- /dev/null +++ b/login-utils/vigr.8 @@ -0,0 +1 @@ +.so man8/vipw.8 diff --git a/login-utils/vipw.8 b/login-utils/vipw.8 index b2786d0e..7f15d951 100644 --- a/login-utils/vipw.8 +++ b/login-utils/vipw.8 @@ -30,16 +30,21 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)vipw.8 6.7 (Berkeley) 3/16/91 -.\" $Id: vipw.8,v 1.2 1995/03/12 01:33:13 faith Exp $ +.\" $Id: vipw.8,v 1.3 1996/07/02 16:57:55 janl Exp $ .\" -.Dd March 16, 1991 +.Dd 7 July 1996 .Dt VIPW 8 -.Os BSD 4 +.Os Util-Linux 2.6 .Sh NAME -.Nm vipw -.Nd edit the password file +.Nm vipw, vigr +.Nd edit the password or group files .Sh SYNOPSIS .Nm vipw +.Op -V +.Op --version +.Nm vigr +.Op -V +.Op --version .Sh DESCRIPTION .Nm Vipw edits the password file after setting the appropriate locks, @@ -51,6 +56,9 @@ to try again later. The default editor for .Nm vipw is .Xr vi 1 . +.br +.Nm Vigr +edits the group file in the same manner as vipw. .Sh ENVIRONMENT If the following environment variable exists it will be utilized by .Nm vipw : @@ -67,6 +75,10 @@ will be invoked instead of the default editor .Xr passwd 5 .Sh HISTORY The -.Nm +.Nm vipw command appeared in .Bx 4.0 . +.br +The +.Nm vigr +command appeared in Util-Linux 2.6. diff --git a/login-utils/vipw.c b/login-utils/vipw.c index 681d9a65..6eff4f3b 100644 --- a/login-utils/vipw.c +++ b/login-utils/vipw.c @@ -33,6 +33,10 @@ * Updated Thu Oct 12 09:56:55 1995 by faith@cs.unc.edu with security * patches from Zefram * + * Updated Thu Nov 9 21:58:53 1995 by Martin Schulze + * . Support for vigr. + * + * Martin Schulze's patches adapted to Util-Linux by Nicolai Langfeldt. */ #ifndef lint @@ -43,9 +47,11 @@ char copyright[] = #ifndef lint /*static char sccsid[] = "from: @(#)vipw.c 5.16 (Berkeley) 3/3/91";*/ -static char rcsid[] = "$Id: vipw.c,v 1.4 1995/10/12 14:46:36 faith Exp $"; +static char rcsid[] = "$Id: vipw.c,v 1.6 1997/07/06 00:12:23 aebr Exp $"; #endif /* not lint */ +static char version_string[] = "vipw 1.4"; + #include #include #include @@ -63,13 +69,20 @@ static char rcsid[] = "$Id: vipw.c,v 1.4 1995/10/12 14:46:36 faith Exp $"; #include #include -#include "pathnames.h" +#include "setpwnam.h" +#define FILENAMELEN 67 -char *progname = "vipw"; -void pw_error __P((char *, int, int)); +char *progname; +enum { VIPW, VIGR }; +int program; +char orig_file[FILENAMELEN]; /* original file /etc/passwd or /etc/group */ +char tmp_file[FILENAMELEN]; /* tmp file */ +char tmptmp_file[FILENAMELEN]; /* very tmp file */ +void pw_error __P((char *, int, int)); +void copyfile(from, to) register int from, to; { @@ -79,9 +92,10 @@ copyfile(from, to) while ((nr = read(from, buf, sizeof(buf))) > 0) for (off = 0; off < nr; nr -= nw, off += nw) if ((nw = write(to, buf + off, nr)) < 0) - pw_error(_PATH_PTMP, 1, 1); + pw_error(tmp_file, 1, 1); + if (nr < 0) - pw_error(_PATH_PASSWD, 1, 1); + pw_error(orig_file, 1, 1); } @@ -120,7 +134,6 @@ int pw_lock() { int lockfd, fd, ret; - char *p; /* * If the password file doesn't exist, the system is hosed. @@ -128,34 +141,37 @@ pw_lock() * that users can't get at the encrypted passwords while editing. * Open should allow flock'ing the file; see 4.4BSD. XXX */ - lockfd = open(_PATH_PASSWD, O_RDONLY, 0); + lockfd = open(orig_file, O_RDONLY, 0); + if (lockfd < 0) { (void)fprintf(stderr, "%s: %s: %s\n", - progname, _PATH_PASSWD, strerror(errno)); + progname, orig_file, strerror(errno)); exit(1); } #if 0 /* flock()ing is superfluous here, with the ptmp/ptmptmp system. */ if (flock(lockfd, LOCK_EX|LOCK_NB)) { (void)fprintf(stderr, - "%s: the password file is busy.\n", progname); + "%s: the %s file is busy.\n", progname, + program == VIPW ? "password" : "group" ); exit(1); } #endif - if ((fd = open(_PATH_PTMPTMP, O_WRONLY|O_CREAT, 0644)) == -1) { - (void)fprintf(stderr, - "%s: %s: %s\n", progname, _PATH_PTMPTMP, strerror(errno)); - exit(1); + if ((fd = open(tmptmp_file, O_WRONLY|O_CREAT, 0644)) == -1) { + (void)fprintf(stderr, + "%s: %s: %s\n", progname, tmptmp_file, strerror(errno)); + exit(1); } - ret = link(_PATH_PTMPTMP, _PATH_PTMP); - (void)unlink(_PATH_PTMPTMP); + ret = link(tmptmp_file, tmp_file); + (void)unlink(tmptmp_file); if (ret == -1) { if (errno == EEXIST) (void)fprintf(stderr, - "%s: the password file is busy\n", progname); + "%s: the %s file is busy\n", progname, + program == VIPW ? "password" : "group" ); else (void)fprintf(stderr, "%s: can't link %s: %s\n", progname, - _PATH_PTMP, strerror(errno)); + tmp_file, strerror(errno)); exit(1); } copyfile(lockfd, fd); @@ -167,15 +183,18 @@ pw_lock() void pw_unlock() { - unlink(_PATH_PASSWD ".OLD"); - link(_PATH_PASSWD, _PATH_PASSWD ".OLD" ); - if (rename(_PATH_PTMP, _PATH_PASSWD) == -1) { - (void)fprintf(stderr, - "%s: can't unlock %s: %s (your changes are still in %s)\n", - progname, _PATH_PASSWD, strerror(errno), _PATH_PTMP); - exit(1); - } - (void)unlink(_PATH_PTMP); + char tmp[FILENAMELEN]; + + sprintf(tmp, "%s%s", orig_file, ".OLD"); + unlink(tmp); + link(orig_file, tmp); + if (rename(tmp_file, orig_file) == -1) { + (void)fprintf(stderr, + "%s: can't unlock %s: %s (your changes are still in %s)\n", + progname, orig_file, strerror(errno), tmp_file); + exit(1); + } + (void)unlink(tmp_file); } @@ -199,7 +218,7 @@ pw_edit(notsetuid) (void)setgid(getgid()); (void)setuid(getuid()); } - execlp(editor, p, _PATH_PTMP, NULL); + execlp(editor, p, tmp_file, NULL); _exit(1); } for (;;) { @@ -231,28 +250,48 @@ pw_error(name, err, eval) (void)fprintf(stderr, "%s\n", strerror(sverrno)); } (void)fprintf(stderr, - "%s: %s unchanged\n", progname, _PATH_PASSWD); - (void)unlink(_PATH_PTMP); + "%s: %s unchanged\n", progname, orig_file); + (void)unlink(tmp_file); exit(eval); } -main() +int main(int argc, char *argv[]) { - register int pfd, tfd; - struct stat begin, end; - - pw_init(); - pw_lock(); - - if (stat(_PATH_PTMP, &begin)) - pw_error(_PATH_PTMP, 1, 1); - pw_edit(0); - if (stat(_PATH_PTMP, &end)) - pw_error(_PATH_PTMP, 1, 1); - if (begin.st_mtime == end.st_mtime) { - (void)fprintf(stderr, "vipw: no changes made\n"); - pw_error((char *)NULL, 0, 0); - } - pw_unlock(); - exit(0); + struct stat begin, end; + + bzero(tmp_file, FILENAMELEN); + progname = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0]; + if (!strcmp(progname, "vigr")) { + program = VIGR; + strncpy(orig_file, GROUP_FILE, FILENAMELEN-1); + strncpy(tmp_file, GTMP_FILE, FILENAMELEN-1); + strncpy(tmptmp_file, GTMPTMP_FILE, FILENAMELEN-1); + } + else { + program = VIPW; + strncpy(orig_file, PASSWD_FILE, FILENAMELEN-1); + strncpy(tmp_file, PTMP_FILE, FILENAMELEN-1); + strncpy(tmptmp_file, PTMPTMP_FILE, FILENAMELEN-1); + } + + if ((argc > 1) && + (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))) { + printf("%s\n", version_string); + exit(0); + } + + pw_init(); + pw_lock(); + + if (stat(tmp_file, &begin)) + pw_error(tmp_file, 1, 1); + pw_edit(0); + if (stat(tmp_file, &end)) + pw_error(tmp_file, 1, 1); + if (begin.st_mtime == end.st_mtime) { + (void)fprintf(stderr, "%s: no changes made\n", progname); + pw_error((char *)NULL, 0, 0); + } + pw_unlock(); + exit(0); } diff --git a/login-utils/wall.c b/login-utils/wall.c index 7f3e6123..7957ae29 100644 --- a/login-utils/wall.c +++ b/login-utils/wall.c @@ -127,7 +127,7 @@ usage: continue; #endif strncpy(line, utmp.ut_line, sizeof(utmp.ut_line)); - line[sizeof(utmp.ut_line)] = '\0'; + line[sizeof(utmp.ut_line)-1] = '\0'; if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) (void)fprintf(stderr, "wall: %s\n", p); } @@ -145,11 +145,11 @@ makemsg(fname) time_t now, time(); FILE *fp; int fd; - char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[15]; + char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[64]; char *getlogin(), *strcpy(), *ttyname(); - (void)strcpy(tmpname, _PATH_TMP); - (void)strcat(tmpname, "/wall.XXXXXX"); + (void)snprintf(tmpname, sizeof(tmpname), + "%s/wall.XXXXXX", _PATH_TMP); if (!(fd = mkstemp(tmpname)) || !(fp = fdopen(fd, "r+"))) { (void)fprintf(stderr, "wall: can't open temporary file.\n"); exit(1); @@ -171,11 +171,13 @@ makemsg(fname) * in column 80, but that can't be helped. */ (void)fprintf(fp, "\r%79s\r\n", " "); - (void)sprintf(lbuf, "Broadcast Message from %s@%s", - whom, hostname); + (void)snprintf(lbuf, sizeof(lbuf), + "Broadcast Message from %s@%s", + whom, hostname); (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); - (void)sprintf(lbuf, " (%s) at %d:%02d ...", ttyname(2), - lt->tm_hour, lt->tm_min); + (void)snprintf(lbuf, sizeof(lbuf), + " (%s) at %d:%02d ...", ttyname(2), + lt->tm_hour, lt->tm_min); (void)fprintf(fp, "%-79.79s\r\n", lbuf); } (void)fprintf(fp, "%79s\r\n", " "); diff --git a/misc-utils/Makefile b/misc-utils/Makefile index f69f0c1e..1ae67df3 100644 --- a/misc-utils/Makefile +++ b/misc-utils/Makefile @@ -1,6 +1,6 @@ # Makefile -- Makefile for util-linux Linux utilities # Created: Sat Dec 26 20:09:40 1992 -# Revised: Fri Oct 6 20:27:07 1995 by r.faith@ieee.org +# Revised: Mon Nov 11 10:12:16 1996 by faith@cs.unc.edu # Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) # May be distirbuted under the GPL # @@ -9,35 +9,40 @@ include ../MCONFIG # Where to put man pages? -MAN1= cal.1 chkdupexe.1 ddate.1 dnsdomainname.1 domainname.1 \ - dsplit.1 hostid.1 hostname.1 kill.1 logger.1 look.1 mcookie.1 \ - namei.1 reset.1 script.1 setterm.1 tsort.1 \ - whereis.1 write.1 - -ifeq "$(HAVE_CLEAR)" "no" -MAN1:=$(MAN1) clear.1 -endif +MAN1= cal.1 chkdupexe.1 ddate.1 hostid.1 kill.1 \ + logger.1 look.1 mcookie.1 namei.1 script.1 \ + setterm.1 tsort.1 whereis.1 write.1 # Where to put binaries? # See the "install" rule for the links. . . -BIN= domainname hostname kill +BIN= kill -USRBIN= cal chkdupexe ddate dsplit hostid logger look mcookie \ - namei reset script setterm tsort whereis write +USRBIN= cal chkdupexe ddate hostid logger look mcookie \ + namei script setterm tsort whereis write ifeq "$(HAVE_CLEAR)" "no" USRBIN:=$(USRBIN) clear +MAN1:=$(MAN1) clear.1 +endif + +ifeq "$(HAVE_RESET)" "no" +USRBIN:=$(USRBIN) reset +MAN1:=$(MAN1) reset.1 endif +# ifeq "$(HAVE_SYSVINIT)" "no" +# USRBIN:=$(USRBIN) pidof +# endif + # Programs requiring special compilation -NEEDS_TERMCAP= setterm +NEEDS_CURSES= setterm all: $(BIN) $(USRBIN) $(USRBIN.NONSHADOW) $(USRGAMES) getoptprog -$(NEEDS_TERMCAP): - $(CC) $(LDFLAGS) $^ -o $@ -ltermcap +$(NEEDS_CURSES): + $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) %: %.sh cp $@.sh $@ @@ -52,28 +57,25 @@ $(NEEDS_TERMCAP): cal: cal.o $(BSD)/getopt.o $(BSD)/err.o chkdupexe: chkdupexe.pl clear: clear.sh -domainname: domainname.o -dsplit: dsplit.o getoptprog: getoptprog.o $(BSD)/getopt.o hostid: hostid.o -hostname: hostname.o kill: kill.o procs.o logger: logger.o $(BSD)/getopt.o mcookie: mcookie.o md5.o -md5sum: md5sum.o md5.o -md5.o: md5.h +mcookie.o: mcookie.c md5.h +md5.o: md5.c md5.h namei: namei.o reset: reset.sh script: script.o setterm: setterm.o tsort: tsort.o +# pidof: pidof.o procs.o install: all $(INSTALLDIR) $(BINDIR) $(USRBINDIR) $(INSTALLBIN) $(BIN) $(BINDIR) $(INSTALLBIN) $(USRBIN) $(USRBINDIR) $(INSTALLBIN) getoptprog $(USRBINDIR)/getopt - (cd $(BINDIR); ln -sf hostname dnsdomainname) $(INSTALLDIR) $(MAN1DIR) $(MAN8DIR) $(INSTALLMAN) $(MAN1) $(MAN1DIR) $(INSTALLMAN) getoptprog.1 $(MAN1DIR)/getopt.1 diff --git a/misc-utils/README.hostname b/misc-utils/README.hostname deleted file mode 100644 index 1e82b8cf..00000000 --- a/misc-utils/README.hostname +++ /dev/null @@ -1,29 +0,0 @@ - -You may ask "Why another version of the hostname command?". The answer is -simple. A lot of people misuse the domainname command to get the DNS domain -name. Since the domainname command should ONLY be used to set/show the NIS -domain name (formerly known as Yellow Pages) there was no easy way to get -the FQDN (Fully Qualified Domain Name) or the DNS domainname from within a -shell script. - -This hostname command offers you some additional features: - -- show the FQDN (long host name) -- show the short host name -- show the DNS domain name -- read the host name from file - -For further informations simply type "hostname --help" or read the manual -page. - -If the program is called as dnsdomainname it will simply show the DNS domain -name. - -If you ONLY use the loopback mode you can only use the normal features -(set/show the host name) since you probably don't have a FQDN (Fully Qualified -Domain Name) in the /etc/hosts file. You can change this by either using -the dummy device or by changing the localhost line in /etc/hosts to -something like this (it will use localhost as an alias name): - -127.0.0.1 erdos.maths.groucho.edu localhost erdos - diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 87ab71df..ecdc7998 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -34,15 +34,18 @@ * SUCH DAMAGE. */ -#ifndef lint static char copyright[] = "@(#) Copyright (c) 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94"; -#endif /* not lint */ + + +/* This defines _LINUX_C_LIB_VERSION_MAJOR, dunno about gnulibc. We + don't want it to read /usr/i586-unknown-linux/include/_G_config.h + so we specify fill path. Were we got /usr/i586-unknown-linux from? + Dunno. */ + +#include "/usr/include/_G_config.h" #include @@ -55,7 +58,15 @@ static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94"; #include #include -#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4 +/* Test changes to deal with gnulibc, Linux libc 5. */ +/* #if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4 */ +#if _LINUX_C_LIB_VERSION_MAJOR - 0 > 4 || __GNU_LIBRARY__ - 0 >= 5 +# define LANGINFO 1 +#else +# define LANGINFO 0 +#endif + +#if LANGINFO # include #else # include @@ -165,7 +176,7 @@ main(argc, argv) argc -= optind; argv += optind; - month = 0; + month = year = 0; switch(argc) { case 2: if ((month = atoi(*argv++)) < 1 || month > 12) @@ -210,7 +221,7 @@ void headers_init(void) strcpy(j_day_headings,""); for(i = 0 ; i < 7 ; i++ ) { -#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4 +#if defined(__linux__) && (_LINUX_C_LIB_VERSION_MAJOR > 4 || __GNU_LIBRARY__ > 1) strncat(day_headings,nl_langinfo(ABDAY_1+i),2); strcat(j_day_headings,nl_langinfo(ABDAY_1+i)); #else @@ -222,7 +233,7 @@ void headers_init(void) } for (i = 0; i < 12; i++) { -#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4 +#if defined(__linux__) && (_LINUX_C_LIB_VERSION_MAJOR > 4 || __GNU_LIBRARY__ > 1) full_month[i] = nl_langinfo(MON_1+i); #else full_month[i] = _time_info->full_month[i]; diff --git a/misc-utils/chkdupexe.pl b/misc-utils/chkdupexe.pl index 117d20fa..f6111def 100644 --- a/misc-utils/chkdupexe.pl +++ b/misc-utils/chkdupexe.pl @@ -1,44 +1,85 @@ -#!/usr/bin/perl +#!/usr/bin/perl5 -w # -# chkdupexe version 2.0 +# chkdupexe version 2.1.1 # # Simple script to look for and list duplicate executables and dangling # symlinks in the system executable directories. # -# Copyright 1993 Nicolai Langfeldt. Distribute under gnu copyleft -# (included in perl package) +# Copyright 1993 Nicolai Langfeldt. janl@math.uio.no +# Distribute under gnu copyleft (included in perl package) # # Modified 1995-07-04 Michael Shields # Don't depend on GNU ls. # Cleanups. # Merge together $ENV{'PATH'} and $execdirs. # Don't break if there are duplicates in $PATH. -# +# +# Modified 1996-02-16 Nicolai Langfeldt (janl@math.uio.no). +# I was thinking admins would edit the $execdirs list to suit their +# machine(s) when I wrote this. This is ofcourse not the case, thus +# Michaels fixes. And my fixes to his :-) +# - Working duplicate dirs detection. +# - Added more checks +# - Took out $PATH from the list of checked directories and added a +# check for $execdirs and $PATH consistency instead +# - Made it possible to run with perl -w + +$execdirs='/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin '. + '/usr/X11/bin /usr/bin/X11 /usr/local/X11/bin '. + '/usr/TeX/bin /usr/tex/bin /usr/games '. + '/usr/local/games /usr/intervies/bin/LINUX'; + +# Values from /usr/include/linux/errno.h. Existence of linux/errno.ph is not +# something to count on... :-( +$ENOENT=2; + +%didthis=(); -$execdirs='/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/local/bin:/local/sbin:/usr/X11/bin:/usr/bin/X11:/usr/local/X11/bin:/local/X11/bin:/usr/TeX/bin:/usr/tex/bin:/usr/local/graph/bin:/usr/games:/usr/local/games:/usr/intervies/bin/LINUX'; +foreach $dir (split(/\s+/, "$execdirs")) { -DIRECTORY: -foreach $dir (split(/:/, "$execdirs:$ENV{'PATH'}")) { + # It's like this: One directory corresponds to one $device,$inode tuple + # If a symlink points to a directory we already checked that directory + # will have the same $device,$inode tuple. - # Follow symlinks and make sure we haven't scanned this directory already. - while (-l $dir) { - $newdir = readlink($dir); - print "Dangling symlink: $dir\n" unless $newdir; - $dir = $newdir; - next DIRECTORY if $seendir{$dir}++; + # Does this directory have any real exstence outside the ravings of + # symlinks pointing hither and dither? + ($device,$inode)=stat($dir); + if (!defined($device)) { + # Nonexistant directory, or dangling symlink? + ($dum)=lstat($dir); + next if $! == $ENOENT; + if (!$dum) { + print "Dangling symlink: $dir\n"; + next; + } + # warn "Nonexistent directory: $dir\n"; + next; } - opendir(DIR,$dir) || (warn "Couldn't opendir($dir): $!\n", next); + if (!-d _) { + print "Not a directory: $dir\n"; + next; + } + + next if defined($didthis{$device,$inode}); + + $didthis{$device,$inode}=1; + + chdir($dir) || die "Could not chdir $dir: $!\n"; +# This would give us the true directory name, do we want that? +# chop($dir=`pwd`); + opendir(DIR,".") || + die "NUTS! Personaly I think your perl or filesystem is broken.\n". + "I've done all sorts of checks on $dir, and now I can't open it!\n"; foreach $_ (readdir(DIR)) { - lstat("$dir/$_"); + lstat($_); if (-l _) { - ($dum)=stat("$dir/$_"); - # Might as well report these since we discover them anyway - print "Dangling symlink: $dir/$_\n" unless $dum; + ($dum)=stat($_); + print "Dangling symlink: $dir/$_\n" unless defined($dum); next; } next unless -f _ && -x _; # Only handle regular executable files - if ($count{$_}) { + if (defined($count{$_})) { $progs{$_}.=" $dir/$_"; $count{$_}++; } else { @@ -54,3 +95,19 @@ while (($prog,$paths)=each %progs) { print LS "$paths\n" if ($count{$prog}>1); } close(LS); + +@unchecked=(); +# Check if the users PATH contains something I've not checked. The site admin +# might want to know about inconsistencies in user PATHs and chkdupexec +# configuration +foreach $dir (split(/:/,$ENV{'PATH'})) { + ($device,$inode)=stat($dir); + next unless defined($device); + next if defined($didthis{$device,$inode}); + push(@unchecked,$dir); + $didthis{$device,$inode}=1; +} + +print "Warning: Your path contanis these directories which chkdupexe have not checked:\n",join(',',@unchecked), + ".\nPlease review the execdirs list in chkdupexe.\n" + if ($#unchecked>=$[); diff --git a/misc-utils/clear.1 b/misc-utils/clear.1 deleted file mode 100644 index 9d208230..00000000 --- a/misc-utils/clear.1 +++ /dev/null @@ -1,31 +0,0 @@ -.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH CLEAR 1 "10 October 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -clear \- clear terminal screen -.SH SYNOPSIS -.BR clear -.SH DESCRIPTION -.B clear -calls -.BR tput (1) -with the -.I clear -argument. This causes -.B tput -to attempt to clear the screen checking the data in -.I /etc/termcap -(for the GNU or BSD -.BR tput ) -or in the terminfo database -(for the -.B ncurses -.BR tput ) -and sending the appropriate sequence to the terminal. This command can be -redirected to clear the screen of some other terminal. -.SH "SEE ALSO" -.BR reset (1), -.BR stty (1), -.BR tput (1) -.SH AUTHOR -Rik Faith (faith@cs.unc.edu) diff --git a/misc-utils/clear.sh b/misc-utils/clear.sh deleted file mode 100644 index 73d1ebe1..00000000 --- a/misc-utils/clear.sh +++ /dev/null @@ -1,2 +0,0 @@ -#! /bin/sh -tput clear diff --git a/misc-utils/ddate.c b/misc-utils/ddate.c index 96421d02..f838d1c6 100644 --- a/misc-utils/ddate.c +++ b/misc-utils/ddate.c @@ -53,14 +53,20 @@ /*#define PRAISE_BOB 13013*/ -#include +#include #include +#include #include #ifndef __GNUC__ #define inline /* foo */ #endif +#ifdef KILL_BOB +int xday_countdown(int yday, int year); +#endif + + /* string constants */ char *day_long[5] = { @@ -76,11 +82,11 @@ char *season_long[5] = { char *season_short[5] = {"Chs", "Dsc", "Cfn", "Bcy", "Afm"}; char *holyday[5][2] = { - "Mungday", "Chaoflux", - "Mojoday", "Discoflux", - "Syaday", "Confuflux", - "Zaraday", "Bureflux", - "Maladay", "Afflux" + { "Mungday", "Chaoflux" }, + { "Mojoday", "Discoflux" }, + { "Syaday", "Confuflux" }, + { "Zaraday", "Bureflux" }, + { "Maladay", "Afflux" } }; struct disc_time { @@ -131,6 +137,7 @@ int load_fortunes(char *fn, char *delim, char** result); struct disc_time convert(int,int); struct disc_time makeday(int,int,int); +int main (int argc, char *argv[]) { long t; @@ -298,7 +305,6 @@ struct disc_time convert(int nday, int nyear) } - #ifdef KILL_BOB /* Code for counting down to X-Day, X-Day being Cfn 40, 3164 */ diff --git a/misc-utils/dnsdomainname.1 b/misc-utils/dnsdomainname.1 deleted file mode 100644 index 1f45128b..00000000 --- a/misc-utils/dnsdomainname.1 +++ /dev/null @@ -1 +0,0 @@ -.so man1/hostname.1 diff --git a/misc-utils/domainname.1 b/misc-utils/domainname.1 deleted file mode 100644 index 0a305ad1..00000000 --- a/misc-utils/domainname.1 +++ /dev/null @@ -1,28 +0,0 @@ -.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH DOMAINNAME 1 "26 December 1992" "Linux 0.98" "Linux Programmer's Manual" -.SH NAME -domainname \- set or print domain of current host -.SH SYNOPSIS -.BR "domainname [ " name " ]" -.SH DESCRIPTION -.B domainname -prints the domainname of the current host, from the -.BR getdomainname (3) -library call. If an argument is present and the effective UID is 0, -.B domainname -changes the name of the host, with the -.BR setdomainname (2) -system call. This is usually done at boot time in the -.I /etc/rc.local -script. -.SH FILES -.I /etc/rc.local -.SH "SEE ALSO" -.BR getdomainname (3), -.BR setdomainname (2), -.BR uname (1), -.BR uname (2) -.SH AUTHOR -Lars Wirzenius by substituting in hostname.c - diff --git a/misc-utils/domainname.c b/misc-utils/domainname.c deleted file mode 100644 index 107091e8..00000000 --- a/misc-utils/domainname.c +++ /dev/null @@ -1,29 +0,0 @@ -/* domainname.c - poe@daimi.aau.dk */ - -#include -#include -#include -#include - -#define MAXDNAME 64 - -int main(int argc, char *argv[]) -{ - char hn[MAXDNAME + 1]; - - if(argc >= 2) { - if(geteuid() || getuid()) { - puts("You must be root to change the domainname"); - exit(1); - } - if(strlen(argv[1]) > MAXDNAME) { - puts("That name is too long."); - exit(1); - } - setdomainname(argv[1], strlen(argv[1])); - } else { - getdomainname(hn, MAXDNAME); - puts(hn); - } - exit(0); -} diff --git a/misc-utils/dsplit.1 b/misc-utils/dsplit.1 deleted file mode 100644 index f78f058f..00000000 --- a/misc-utils/dsplit.1 +++ /dev/null @@ -1,46 +0,0 @@ -.\" Public Domain 1994 Rik Faith (faith@cs.unc.edu) -.TH DSPLIT 1 "5 July 1994" "Linux 1.1" "Linux Programmer's Manual" -.SH NAME -dsplit \- split a large file into pieces -.SH SYNOPSIS -.BI "dsplit [ \-size " nnn " ] [ " input_file " [ " output_base " ] ]" -.SH DESCRIPTION -.B dsplit -splits binary files into smaller chunks so that they may be placed on -floppy disks. -.SH OPTIONS -.TP -.BI \-size " nnn" -Specifies the size of each output file, in bytes. The default is 1457000, -which is enough to will a 1.44 MB floppy disk. -.TP -.I input_file -Specifies the name of the file to split up. A \- indicates standard input. -The default is standard input. -.TP -.I output_base -Specifies the name of the output files to be written. -.B dsplit -will append 000, 001, ..., to the -.IR output_base . -The default is "dsplit". -.SH "AUTHOR'S NOTES" -Submitted-by: arnstein@netcom.com (David Arnstein) -.br -Posting-number: Volume 40, Issue 51 -.br -Archive-name: dsplit/part01 -.br -Environment: MS-DOS, UNIX -.PP -Here is a portable binary file splitting program. It reads a binary file -and splits it into pieces. I use this program to put large binary files on -floppy disks. For this reason, the default size of the output files is -1,457,000 bytes, which just about fills up a 1.44 MB floppy disk. -.PP -Unlike other binary split programs I have seen, dsplit does not malloc a -huge block of memory. Dsplit is suitable for use under MSDOS and other -primitive operating systems. -.PP -(The program came from -gatekeeper.dec.com:/pub/usenet/comp.sources.misc/volume40/dsplit). diff --git a/misc-utils/dsplit.c b/misc-utils/dsplit.c deleted file mode 100644 index c3c22a30..00000000 --- a/misc-utils/dsplit.c +++ /dev/null @@ -1,271 +0,0 @@ -#ifdef lint - static char RCSid[] = "$RCSfile: dsplit.c,v $ $Revision: 1.9 $ $Date: 1995/03/12 01:31:03 $"; -#endif -/* - Program dsplit: Splits a large file into pieces. - - Usage: - dsplit [-size nnn] [input_file [output_base]] - Size is size of each output file, in bytes. The default is 1457000, - enough to fill a "1.44MB" diskette, save 152 bytes. - input_file is the name of the file to split up. A dash (-) indicates - standard input. Defaults to standard input. - output_base is the name of the output files to be written, minus the - extension. Dsplit adds suffixes 000, 001, ... - The default base name is dsplit. -*/ -#include -#include -#include -#include -#if (defined (__MSDOS__) || defined (WIN32)) -#include -#include -#endif /* __MSDOS__ or WIN32 */ -#ifndef FILENAME_MAX -#define FILENAME_MAX 1024 -#endif - -#define DEFAULT_NAME "dsplit" -#define DEFAULT_SIZE 1457000L -#if (defined (__MSDOS__) || defined (WIN32)) -# define READ_OPTIONS "rb" -# define WRITE_OPTIONS "wb" -#else -# define READ_OPTIONS "r" -# define WRITE_OPTIONS "w" -#endif /* __MSDOS__ or WIN32 */ - -#ifndef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) -#endif - -static unsigned long output_size = DEFAULT_SIZE; -static char* base_name = DEFAULT_NAME; -static FILE* input_handle; -static char* input_name = "-"; - -#ifdef __STDC__ -static void init (int argc, char* argv[]); -static int write_one (int count); -static void ToLower (char* string); -static void usage_error (void); -#else /* not __STDC__ */ -static void init (/* int argc, char* argv[] */); -static int write_one (/* int count */); -static void ToLower (/* char* string */); -static void usage_error (/* void */); -#endif /* __STDC__ */ - - - -#ifdef __STDC__ -int main (int argc, char* argv[]) -#else -int main (argc, argv) -int argc; -char* argv[]; -#endif -{ - int count; - - /* Process command line arguments, open input file. */ - init (argc, argv); - - /* Write the output files */ - for (count = 0 ; write_one (count) ; ++count) - ; - - /* Close input file (a matter of style) */ - if (fclose (input_handle) != 0) - { - (void)fprintf (stderr, "Could not close file \"%s\" for input\n", - input_name); - return 1; - } - - /* Normal successful conclusion */ - return 0; -} - - - -#ifdef __STDC__ -static void init (int argc, char* argv[]) -#else -static void init (argc, argv) -int argc; -char* argv[]; -#endif -{ - int iarg; - int name_count; - - /* Initialize the input file handle to standard input. IBM's Toolset++ - won't let me do this statically, unfortunately. */ - input_handle = stdin; - - /* Initialize for following loop */ - name_count = 0; - - /* Loop over command line arguments */ - for (iarg = 1 ; iarg < argc ; ++iarg) - { - /* Point to argument,for convenience */ - char* arg = argv[iarg]; - - /* If this argument is an option */ - if (arg[0] == '-' && arg[1] != '\0') - { - /* Process option if recognized */ - ToLower (arg+1); - if (strcmp (arg+1, "size") != 0) - usage_error (); - ++iarg; - if (iarg >= argc) - usage_error (); - arg = argv[iarg]; - if (sscanf (arg, "%ld", &output_size) != 1) - { - (void)fprintf (stderr, "Illegal numeric expression \"%s\"\n", arg); - exit (1); - } - } - else /* argument is not an option */ - { - /* Argument is a name string. Determine which one. */ - switch (name_count) - { - case 0: - input_name = argv[iarg]; - break; - case 1: - base_name = argv[iarg]; - break; - default: - usage_error (); - break; - } - ++name_count; - - } /* End if this argument is an option */ - - } /* End loop over command line arguments */ - - /* Open the input file */ - if (strcmp (input_name, "-") == 0) - { -# if (defined (__MSDOS__) || defined (WIN32)) - if (setmode (0, O_BINARY) == -1) - { - perror ("dsplit: setmode"); - exit (1); - } -# endif - } - else - { - if ((input_handle = fopen (input_name, READ_OPTIONS)) == NULL) - { - (void)fprintf (stderr, "Could not open file \"%s\" for input\n", - input_name); - exit (1); - } - } -} - - - -#ifdef __STDC__ -static int write_one (int count) -#else -static int write_one (count) -int count; -#endif -{ - char output_name[FILENAME_MAX]; - int bytes_written; - unsigned long total_written; - FILE* output_handle; - - /* Read the first buffer full now, just to see if any data is left */ - static char buff[1024]; - int to_read = MIN (sizeof(buff), output_size); - int bytes_read = fread (buff, 1, to_read, input_handle); - if (bytes_read <= 0) - return 0; - - /* Open file for output */ - sprintf (output_name, "%s.%03d", base_name, count); - output_handle = fopen (output_name, WRITE_OPTIONS); - if (output_handle == NULL) - { - (void)fprintf (stderr, - "Could not open file \"%s\" for output\n", output_name); - exit (1); - } - - /* Write the first output buffer */ - bytes_written = fwrite (buff, 1, bytes_read, output_handle); - if (bytes_written != bytes_read) - { - (void)fprintf (stderr, "Error writing to file \"%s\"\n", output_name); - exit (1); - } - total_written = bytes_written; - - /* Write output file */ - while (total_written < output_size) - { - to_read = MIN (sizeof(buff), output_size-total_written); - bytes_read = fread (buff, 1, to_read, input_handle); - if (bytes_read <= 0) - break; - bytes_written = fwrite (buff, 1, bytes_read, output_handle); - if (bytes_written != bytes_read) - { - (void)fprintf (stderr, "Error writing to file \"%s\"\n", output_name); - exit (1); - } - total_written += bytes_written; - } - - /* Close the output file, it is complete */ - if (fclose (output_handle) != 0) - { - (void)fprintf (stderr, - "Could not close file \"%s\" for output\n", output_name); - exit (1); - } - - /* Indicate whether more data remains to be transferred */ - return (bytes_read == to_read); -} - - - -#ifdef __STDC__ -static void ToLower (char* string) -#else -static void ToLower (string) -char* string; -#endif -{ - - while (*string != '\0') - tolower (*string++); -} - - - -#ifdef __STDC__ -static void usage_error (void) -#else -static void usage_error () -#endif -{ - (void)fprintf (stderr, - "Usage: dsplit [-size nnn] [input_file [output_base]]\n"); - exit (1); -} - diff --git a/misc-utils/getoptprog.c b/misc-utils/getoptprog.c index 03b0987e..94eac145 100644 --- a/misc-utils/getoptprog.c +++ b/misc-utils/getoptprog.c @@ -1,5 +1,7 @@ #include +#include +int main(argc, argv) int argc; char *argv[]; @@ -26,5 +28,5 @@ char *argv[]; for (; optind < argc; optind++) printf(" %s", argv[optind]); printf("\n"); - exit(status); + return status; } diff --git a/misc-utils/hostid.c b/misc-utils/hostid.c index 829c5b67..211e4ce5 100644 --- a/misc-utils/hostid.c +++ b/misc-utils/hostid.c @@ -6,7 +6,7 @@ #include #include -void main (int argc, char **argv) +int main (int argc, char **argv) { int verbose = 0; @@ -32,5 +32,5 @@ void main (int argc, char **argv) printf("Usage: %s hostid_number\n",*argv); } } - exit(0); + return 0; } diff --git a/misc-utils/hostname.1 b/misc-utils/hostname.1 deleted file mode 100644 index 9efc0758..00000000 --- a/misc-utils/hostname.1 +++ /dev/null @@ -1,77 +0,0 @@ -.TH HOSTNAME 1 "28 July 1994" "Linux" "Linux Programmer's Manual" -.SH NAME -hostname \- show or set the system's host name -.br -dnsdomainname \- show the system's domain name -.SH SYNOPSIS -.B hostname -.RB [ \-d ] -.RB [ \-\-domain ] -.RB [ \-F\ filename ] -.RB [ \-\-file\ filename ] -.RB [ \-f ] -.RB [ \-\-fqdn ] -.RB [ \-h ] -.RB [ \-\-help ] -.RB [ \-\-long ] -.RB [ \-s ] -.RB [ \-\-short ] -.RB [ \-v ] -.RB [ \-\-version ] -.RB [ name ] -.br -.B dnsdomainname -.SH DESCRIPTION -.B Hostname -is the program that is used to either set the host name or display -the current host or domain name of the system. This name is used -by many of the networking programs to identify the machine. -.LP -When called without any arguments, the program displays the current -name as set by the -.B hostname -command. You can change the output format to display always the short -or the long host name (FQDN). When called with arguments, the program will -set the value of the host name to the value specified. This usually is -done only once, at system startup time, by the -.I /etc/rc.d/rc.inet1 -configuration script. -.LP -Note, that only the super-user can change the host name. -.LP -If the program was called as -.B dnsdomainname -it will show the DNS domain name. You can't change the DNS domain name with -.B dnsdomainname -(see below). -.SH OPTIONS -.TP -.I "\-d, \-\-domain" -Display the name of the DNS domain. Don't use the command -.B domainname -to get the DNS domain name because it will show the NIS domain name and -not the DNS domain name. -.TP -.I "\-F, \-\-file filename" -Read the host name from the specified file. Comments (lines starting with -a `#') are ignored. -.TP -.I "\-f, \-\-fqdn, \-\-long" -Display the FQDN (Fully Qualified Domain Name). A FQDN consists of a -short host name and the DNS domain name. Unless you are using bind or NIS -for host lookups you can change the FQDN and the DNS domain name (which is -part of the FQDN) in the \fI/etc/hosts\fR file. -.TP -.I "\-h, \-\-help" -Print a usage message on standard output and exit successfully. -.TP -.I "\-s, \-\-short" -Display the short host name. -.TP -.I "\-v, \-\-version" -Print version information on standard output and exit successfully. -.SH FILES -.B /etc/hosts -.SH AUTHOR -Peter Tobias, - diff --git a/misc-utils/hostname.c b/misc-utils/hostname.c deleted file mode 100644 index 2ff915af..00000000 --- a/misc-utils/hostname.c +++ /dev/null @@ -1,184 +0,0 @@ -/* hostname -- set the host name or show the host/domain name - - Copyright (C) 1994 Peter Tobias - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#define NO_OPT -1 - -static char *program_name; -static const char *version_string = "hostname 1.6"; - -static void sethname(char *); -static void showhname(char *, int); -static void usage(void); - -static void sethname(char *hname) -{ - if(sethostname(hname, strlen(hname))) { - switch(errno) { - case EPERM: - fprintf(stderr,"%s: you must be root to change the host name\n", program_name); - break; - case EINVAL: - fprintf(stderr,"%s: name too long\n", program_name); - break; - default: - } - exit(1); - }; -} - -static void showhname(char *hname, int c) -{ - struct hostent *hp; - register char *p; - - if (!(hp = gethostbyname(hname))) { - herror(program_name); - exit(1); - } - - if (!(p = strchr(hp->h_name, '.')) && (c == 'd')) return; - - switch(c) { - case 'd': - printf("%s\n", ++p); - break; - case 'f': - printf("%s\n", hp->h_name); - break; - case 's': - if (p != NULL) *p = '\0'; - printf("%s\n", hp->h_name); - break; - default: - } -} - -static void usage(void) -{ - printf("Usage: %s [OPTION]... [hostname]\n\n\ - -d, --domain display the DNS domain name\n\ - -F, --file filename read the host name from file\n\ - -f, --fqdn, --long display the long host name (FQDN)\n\ - -s, --short display the short host name\n\ - -h, --help display this help and exit\n\ - -v, --version output version information and exit\n\ -\n\ - When the program is called without any arguments, it displays the\n\ - current host name as set by the hostname command. If an argument\n\ - is given, the program will set the value of the host name to the\n\ - value specified.\n\ - Unless you are using bind or NIS for host lookups you can change the\n\ - FQDN (Fully Qualified Domain Name) and the DNS domain name (which is\n\ - part of the FQDN) in the /etc/hosts file.\n", program_name); -} - -int main(int argc, char **argv) -{ - int c; - int option_index = 0; - - char myname[MAXHOSTNAMELEN+1]; - - static const struct option long_options[] = - { - {"domain", no_argument, 0, 'd'}, - {"file", required_argument, 0, 'F'}, - {"fqdn", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"long", no_argument, 0, 'f'}, - {"short", no_argument, 0, 's'}, - {"version", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - - program_name = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0]; - - if (strcmp(program_name, "dnsdomainname") == 0) { - if (argc > 1) { - fprintf(stderr,"%s: You can't change the DNS domainname with this command\n", program_name); - fprintf(stderr,"\nUnless you are using bind or NIS for host lookups you can change the DNS\n"); - fprintf(stderr,"domain name (which is part of the FQDN) in the /etc/hosts file.\n"); - exit(1); - } - c = 'd'; - } else - c = getopt_long(argc, argv, "dfF:hsv", long_options, &option_index); - - gethostname(myname, sizeof(myname)); - - switch(c) - { - case 'd': - case 'f': - case 's': - showhname(myname, c); - break; - case 'F': - { - register FILE *fd; - register char *p; - char fline[MAXHOSTNAMELEN]; - - if ((fd = fopen(optarg, "r")) != NULL) { - while (fgets(fline, sizeof(fline), fd) != NULL) - if ((p = index(fline, '\n')) != NULL) { - *p = '\0'; - if (fline[0] == '#') - continue; - sethname(fline); - } - (void) fclose(fd); - } else { - fprintf(stderr,"%s: can't open `%s'\n", - program_name, optarg); - exit(1); - } - } - break; - case 'h': - usage(); - break; - case 'v': - printf("%s\n", version_string); - break; - case '?': - fprintf(stderr,"Try `%s --help' for more information.\n", program_name); - exit(1); - break; - case NO_OPT: - if (optind < argc) { - sethname(argv[optind]); - exit(0); - } - default: - printf("%s\n", myname); - - }; - exit(0); -} diff --git a/misc-utils/kill.1 b/misc-utils/kill.1 index aad5c23b..f4fd6436 100644 --- a/misc-utils/kill.1 +++ b/misc-utils/kill.1 @@ -23,7 +23,26 @@ Specify the list of processes that .B kill should signal. Each .I pid -can be a process id, or a process name. +can be one of four things. A +.I "process name" +in which case processes called that will be signaled. +.I n +where +.I n +is larger than 0. The process with pid +.I n +will be signaled. +.I -1 +in which case all processes from MAX_INT to 2 will be signaled, +as allowed by the issuing user. +.I -n +where +.I n +is larger than 1, in which case processes in process group +.I n +are signaled. IFF a negative argument is given the signal +.I must +be specified first, otherwise it will be taken as the signal to send. .TP .BR \-s Specify the signal to send. diff --git a/misc-utils/kill.c b/misc-utils/kill.c index f89ff67c..85911211 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -59,7 +59,7 @@ char *sys_signame[NSIG] = { #endif int main (int argc, char *argv[]); -char *mybasename(char *pathname); +extern char *mybasename(char *); int signame_to_signum (char *sig); int arg_to_signum (char *arg); void nosig (char *name); @@ -144,8 +144,12 @@ int main (int argc, char *argv[]) continue; } /* `arg' begins with a dash but is not a known option. - so it's probably something like -HUP. - try to deal with it. */ + so it's probably something like -HUP, or -1/-n + try to deal with it. + -n could be signal n, or pid -n (i.e. process group n). + If a signal has been parsed, assume it's a pid, break */ + if (do_kill) + break; arg++; if ((numsig = arg_to_signum (arg)) < 0) { return usage (1); @@ -186,13 +190,6 @@ int main (int argc, char *argv[]) return (errors); } -char *mybasename (char *path) -{ - char *cp; - - cp = strrchr (path, '/'); - return (cp ? cp + 1 : path); -} int signame_to_signum (char *sig) { diff --git a/misc-utils/look.c b/misc-utils/look.c index 5a47970e..13cb6787 100644 --- a/misc-utils/look.c +++ b/misc-utils/look.c @@ -92,6 +92,7 @@ void print_from __P((char *, char *, char *)); static void usage __P((void)); +void main(argc, argv) int argc; char *argv[]; @@ -102,6 +103,8 @@ main(argc, argv) file = _PATH_WORDS; termchar = '\0'; + string = NULL; /* just for gcc */ + while ((ch = getopt(argc, argv, "adft:")) != EOF) switch(ch) { case 'a': @@ -152,6 +155,7 @@ main(argc, argv) exit(look(string, front, back)); } +int look(string, front, back) char *string, *front, *back; { @@ -159,7 +163,7 @@ look(string, front, back) register char *readp, *writep; /* Reformat string string to avoid doing it multiple times later. */ - for (readp = writep = string; ch = *readp++;) { + for (readp = writep = string; (ch = *readp++) != 0;) { if (fflag) ch = FOLD(ch); if (dflag) diff --git a/misc-utils/mcookie.c b/misc-utils/mcookie.c index a4c89607..05136190 100644 --- a/misc-utils/mcookie.c +++ b/misc-utils/mcookie.c @@ -4,7 +4,7 @@ * Public Domain 1995 Rickard E. Faith (faith@cs.unc.edu) * This program comes with ABSOLUTELY NO WARRANTY. * - * $Id: mcookie.c,v 1.2 1995/10/07 01:32:00 faith Exp $ + * $Id: mcookie.c,v 1.5 1997/07/06 00:13:06 aebr Exp $ * * This program gathers some random bits of data and used the MD5 * message-digest algorithm to generate a 128-bit hexadecimal number for @@ -87,7 +87,7 @@ int main( int argc, char **argv ) if (file[0] == '-' && !file[1]) fd = fileno(stdin); else if ((fd = open( file, O_RDONLY )) <0) { - fprintf( stderr, "Could not open %s\n" ); + fprintf( stderr, "Could not open %s\n", file ); } while ((r = read( fd, buf, sizeof( buf ) )) > 0) { diff --git a/misc-utils/md5sum.1 b/misc-utils/md5sum.1 deleted file mode 100644 index 86094b27..00000000 --- a/misc-utils/md5sum.1 +++ /dev/null @@ -1,64 +0,0 @@ -.\" md5sum.1 -- -.\" Public Domain 1995 Rik Faith (faith@cs.unc.edu) -.\" Revised: Sat Feb 11 12:16:48 1995 by faith@cs.unc.edu -.\" " -.TH MD5SUM 1 "11 February 1995" "Linux 1.0" "Linux Programmer's Manual" -.SH NAME -md5sum \- generate/check MD5 message digests -.SH SYNOPSIS -.BR "md5sum [" \-bv "] [" \-c -.BR "[ " file " ] ]" -.br -.BR "md5sum " file " ..." -.SH DESCRIPTION -.B md5sum -generates and checks MD5 message digests, as described in RFC-1321. The -"message digest" produced can be thought of as a 128-bit "signature" of the -input file. Typically, -.B md5sum -is used to verify the integrity of files made available for distribution -via anonymous ftp (for example, announcements for new versions of -.BR irc(1) -usually contain MD5 signatures). -.P -Message digests for a tree of files can be generated with a command similar -to the following: -.RS -.sp -find . -type f -print | xargs md5sum -.sp -.RE -The output of this command is suitable as input for the -.B \-c -option. -.SH OPTIONS -.TP -.BI "\-c [" file "]" -Check message digests. Input is taken from -.B stdin -or from the spcified -.IR file . -The input should be in the same format as the output generated by -.BR md5sum . -.TP -.B \-v -Verbose. Print file names when checking. -.TP -.B \-b -Read files in binary mode (otherwise, end-of-file conventions will be -ignored). -.SH HISTOY -The -.B md5sum -program was written by Branko Lankester and may be freely distributed. The -original source code is in the MIT PGP 2.6.2 distribution. Those concerned -about the integrity of this version should obtain the original sources and -compile their own version. -.PP -The underlying implementation of Ron Rivest's MD5 algorithm was written by -Colin Plumb and is in the Public Domain. (Equivalent code is also -available from RSA Data Security, Inc.) -.SH "SEE ALSO" -.BR sum (1), -.BR cksum (1), -.BR pgp (1) diff --git a/misc-utils/md5sum.c b/misc-utils/md5sum.c deleted file mode 100644 index e0b1dc9c..00000000 --- a/misc-utils/md5sum.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * md5sum.c - Generate/check MD5 Message Digests - * - * Compile and link with md5.c. If you don't have getopt() in your library - * also include getopt.c. For MSDOS you can also link with the wildcard - * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC) - * so that you can use wildcards on the commandline. - * - * Written March 1993 by Branko Lankester - * Modified June 1993 by Colin Plumb for altered md5.c. - */ -#include -#include -#include "md5.h" - -#ifdef UNIX -#define FOPRTXT "r" -#define FOPRBIN "r" -#else -#ifdef VMS -#define FOPRTXT "r","ctx=stm" -#define FOPRBIN "rb","ctx=stm" -#else -#define FOPRTXT "r" -#define FOPRBIN "rb" -#endif -#endif - -extern char *optarg; -extern int optind; - -void usage(); -void print_digest(); -int mdfile(FILE *fp, unsigned char *digest); -int do_check(FILE *chkf); - -char *progname; -int verbose = 0; -int bin_mode = 0; - -void -main(int argc, char **argv) -{ - int opt, rc = 0; - int check = 0; - FILE *fp; - unsigned char digest[16]; - - progname = *argv; - while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) { - switch (opt) { - case 'c': check = 1; break; - case 'v': verbose = 1; break; - case 'b': bin_mode = 1; break; - default: usage(); - } - } - argc -= optind; - argv += optind; - if (check) { - switch (argc) { - case 0: fp = stdin; break; - case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) { - perror(*argv); - exit(2); - } - break; - default: usage(); - } - exit(do_check(fp)); - } - if (argc == 0) { - if (mdfile(stdin, digest)) { - fprintf(stderr, "%s: read error on stdin\n", progname); - exit(2); - } - print_digest(digest); - printf("\n"); - exit(0); - } - for ( ; argc > 0; --argc, ++argv) { - if (bin_mode) - fp = fopen(*argv, FOPRBIN); - else - fp = fopen(*argv, FOPRTXT); - if (fp == NULL) { - perror(*argv); - rc = 2; - continue; - } - if (mdfile(fp, digest)) { - fprintf(stderr, "%s: error reading %s\n", progname, *argv); - rc = 2; - } else { - print_digest(digest); - printf(" %c%s\n", bin_mode ? '*' : ' ', *argv); - } - fclose(fp); - } - exit(rc); -} - -void -usage() -{ - fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n"); - fprintf(stderr, "Generates or checks MD5 Message Digests\n"); - fprintf(stderr, " -c check message digests (default is generate)\n"); - fprintf(stderr, " -v verbose, print file names when checking\n"); - fprintf(stderr, " -b read files in binary mode\n"); - fprintf(stderr, "The input for -c should be the list of message digests and file names\n"); - fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n"); - exit(2); -} - -int -mdfile(FILE *fp, unsigned char *digest) -{ - unsigned char buf[1024]; - MD5_CTX ctx; - int n; - - MD5Init(&ctx); - while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) - MD5Update(&ctx, buf, n); - MD5Final(digest, &ctx); - if (ferror(fp)) - return -1; - return 0; -} - -void -print_digest(unsigned char *p) -{ - int i; - - for (i = 0; i < 16; ++i) - printf("%02x", *p++); -} - -int -hex_digit(int c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return -1; -} - -int -get_md5_line(FILE *fp, unsigned char *digest, char *file) -{ - char buf[1024]; - int i, d1, d2, rc; - char *p = buf; - - if (fgets(buf, sizeof(buf), fp) == NULL) - return -1; - - for (i = 0; i < 16; ++i) { - if ((d1 = hex_digit(*p++)) == -1) - return 0; - if ((d2 = hex_digit(*p++)) == -1) - return 0; - *digest++ = d1*16 + d2; - } - if (*p++ != ' ') - return 0; - /* - * next char is an attribute char, space means text file - * if it's a '*' the file should be checked in binary mode. - */ - if (*p == ' ') - rc = 1; - else if (*p == '*') - rc = 2; - else { - fprintf(stderr, "%s: unrecognized line: %s", progname, buf); - return 0; - } - ++p; - i = strlen(p); - if (i < 2 || i > 255) - return 0; - p[i-1] = '\0'; - strcpy(file, p); - return rc; -} - -int -do_check(FILE *chkf) -{ - int rc, ex = 0, failed = 0, checked = 0; - unsigned char chk_digest[16], file_digest[16]; - char filename[256]; - FILE *fp; - int flen = 14; - - while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) { - if (rc == 0) /* not an md5 line */ - continue; - if (verbose) { - if (strlen(filename) > flen) - flen = strlen(filename); - fprintf(stderr, "%-*s ", flen, filename); - } - if (bin_mode || rc == 2) - fp = fopen(filename, FOPRBIN); - else - fp = fopen(filename, FOPRTXT); - if (fp == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, filename); - ex = 2; - continue; - } - if (mdfile(fp, file_digest)) { - fprintf(stderr, "%s: error reading %s\n", progname, filename); - ex = 2; - fclose(fp); - continue; - } - fclose(fp); - if (memcmp(chk_digest, file_digest, 16) != 0) { - if (verbose) - fprintf(stderr, "FAILED\n"); - else - fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename); - ++failed; - } else if (verbose) - fprintf(stderr, "OK\n"); - ++checked; - } - if (verbose && failed) - fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked); - if (!checked) { - fprintf(stderr, "%s: no files checked\n", progname); - return 3; - } - if (!ex && failed) - ex = 1; - return ex; -} diff --git a/misc-utils/namei.c b/misc-utils/namei.c index 75057618..2c985002 100644 --- a/misc-utils/namei.c +++ b/misc-utils/namei.c @@ -42,15 +42,20 @@ chdir to /, or if it encounters an unknown file type. -------------------------------------------------------------*/ #ifndef lint -static char *RCSid = "$Id: namei.c,v 1.4 1995/03/12 01:35:45 faith Exp $"; +static char *RCSid = "$Id: namei.c,v 1.6 1997/07/06 00:13:09 aebr Exp $"; #endif #include +#include +#include #include #include #include +#ifndef __GNU_LIBRARY__ extern char *sys_errlist[]; +#endif + extern int errno; #define ERR sys_errlist[errno],errno @@ -64,6 +69,7 @@ int xflag = 0; static char *pperm(); +int main(argc, argv) int argc; char *argv[]; @@ -110,7 +116,7 @@ char *argv[]; exit(1); } } - exit(0); + return 0; } void diff --git a/misc-utils/procs.c b/misc-utils/procs.c index 4d0ea7ac..2ea3e098 100644 --- a/misc-utils/procs.c +++ b/misc-utils/procs.c @@ -6,9 +6,9 @@ * modify it under the terms of the gnu general public license. * there is no warranty. * - * $Author: faith $ - * $Revision: 1.2 $ - * $Date: 1995/03/12 02:55:24 $ + * $Author: janl $ + * $Revision: 1.5 $ + * $Date: 1996/11/11 22:40:03 $ * */ @@ -111,3 +111,12 @@ static char *parse_parens (char *buf) } return cp; } + + +char *mybasename (char *path) +{ + char *cp; + + cp = strrchr (path, '/'); + return (cp ? cp + 1 : path); +} diff --git a/misc-utils/reset.1 b/misc-utils/reset.1 index 46aea01e..c4a4de45 100644 --- a/misc-utils/reset.1 +++ b/misc-utils/reset.1 @@ -4,7 +4,7 @@ .SH NAME reset \- reset the terminal .SH SYNOPSIS -.BR clear +.BR reset .SH DESCRIPTION .B reset calls @@ -28,7 +28,7 @@ is called with the .I sane argument in an attempt to get cooked mode back. .SH "SEE ALSO" -.BR reset (1), +.BR clear (1), .BR stty (1), .BR tput (1) .SH AUTHOR diff --git a/misc-utils/script.c b/misc-utils/script.c index d1e8b1e9..ba322fe5 100644 --- a/misc-utils/script.c +++ b/misc-utils/script.c @@ -54,11 +54,20 @@ static char sccsid[] = "@(#)script.c 5.13 (Berkeley) 3/5/91"; #include #include -#ifdef linux +#ifdef __linux__ #include #include #endif +void done(void); +void fail(void); +void fixtty(void); +void getmaster(void); +void getslave(void); +void doinput(void); +void dooutput(void); +void doshell(void); + char *shell; FILE *fscript; int master; @@ -74,6 +83,7 @@ int l; char line[] = "/dev/ptyXX"; int aflg; +void main(argc, argv) int argc; char *argv[]; @@ -134,6 +144,7 @@ main(argc, argv) doinput(); } +void doinput() { register int cc; @@ -162,6 +173,7 @@ finish() done(); } +void dooutput() { register int cc; @@ -181,11 +193,12 @@ dooutput() done(); } +void doshell() { + /*** int t; - /*** t = open(_PATH_TTY, O_RDWR); if (t >= 0) { (void) ioctl(t, TIOCNOTTY, (char *)0); @@ -199,7 +212,7 @@ doshell() (void) dup2(slave, 1); (void) dup2(slave, 2); (void) close(slave); -#ifdef linux +#ifdef __linux__ execl(shell, strrchr(shell, '/') + 1, "-i", 0); #else execl(shell, "sh", "-i", 0); @@ -208,6 +221,7 @@ doshell() fail(); } +void fixtty() { struct termios rtt; @@ -218,6 +232,7 @@ fixtty() (void) tcsetattr(0, TCSAFLUSH, &rtt); } +void fail() { @@ -225,6 +240,7 @@ fail() done(); } +void done() { time_t tvec, time(); @@ -242,6 +258,7 @@ done() exit(0); } +void getmaster() { char *pty, *bank, *cp; @@ -278,6 +295,7 @@ getmaster() fail(); } +void getslave() { diff --git a/misc-utils/setterm.1 b/misc-utils/setterm.1 index 794fea7d..3853a713 100644 --- a/misc-utils/setterm.1 +++ b/misc-utils/setterm.1 @@ -2,7 +2,7 @@ .\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) .\" Most of this was copied from the source code. Do not restrict distribution. .\" May be distributed under the GNU General Public License -.TH SETTERM 1 "25 December 1992" "Linux 0.98" "Linux Programmer's Manual" +.TH SETTERM 1 "2 July 1996" "Util-Linux 2.6" "Linux Programmer's Manual" .SH NAME setterm \- set terminal attributes .SH SYNOPSIS @@ -36,21 +36,25 @@ setterm \- set terminal attributes .BR "setterm [ \-clrtabs [ tab1 tab2 tab3 ... ]" " where (tabn = 1-160)" .BR "setterm [ \-regtabs [" " 1-160 " "] ]" .BR "setterm [ \-blank [" " 0-60 " "] ]" +.BR "setterm [ \-powersave [ on|vsync|hsync|powerdown|off ] ]" +.BR "setterm [ \-powerdown [" " 0-60 " "] ]" .BR "setterm [ \-dump [" " 1-NR_CONS " "] ]" .BR "setterm [ \-append [" " 1-NR_CONS " "] ]" .BR "setterm [ \-file" " dumpfilename " ] .BR "setterm [ \-standout [" " attr " "] ]" +.BR "setterm [ \-blength [" " 0-2000 " "] ]" +.B "setterm [ \-bfreq freqnumber ]" .fi .SH DESCRIPTION .B setterm writes to standard output a character string that will invoke the specified terminal capabilities. Where possibile -.I /etc/termcap +.I terminfo is consulted to find the string to use. Some options however do not correspond to a -.BR termcap (5) -capability. In this case, if the terminal type is "minix-vc", or -"minix-vcam" the string that invokes the specified capabilities on the PC +.BR terminfo (5) +capability. In this case, if the terminal type is "con", or +"linux" the string that invokes the specified capabilities on the PC Minix virtual console driver is output. Options that are not implemented by the terminal are ignored. .SH OPTIONS @@ -76,13 +80,15 @@ stores the terminal's current rendering options as the default values. .SH "SEE ALSO" .BR tput (1), .BR stty (1), -.BR termcap (5), +.BR terminfo (5), .BR tty (4) .SH BUGS -Differences between the Minux and Linux versions are not documented. +Differences between the Minix and Linux versions are not documented. .SH AUTHORS Gordon Irlam (gordoni@cs.ua.oz.au) .br Adaption to Linux by Peter MacDonald .br Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI) +.br +Beep patch by Christophe Jolif (cjolif@storm.gatelink.fr.net) diff --git a/misc-utils/setterm.c b/misc-utils/setterm.c index e81fccc3..60145d9f 100644 --- a/misc-utils/setterm.c +++ b/misc-utils/setterm.c @@ -8,6 +8,13 @@ * * Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI) * + * Beep modifications by Christophe Jolif (cjolif@storm.gatelink.fr.net) + * + * Sanity increases by Cafeine Addict [sic]. + * + * Powersave features by, todd j. derr + * + * Converted to terminfo by Kars de Jong (jongk@cs.utwente.nl) * * Syntax: * @@ -47,18 +54,22 @@ * [ -standout [attr] ] * [ -msg [on|off] ] * [ -msglevel [0-8] ] - * [ -powersave [on|off] ] + * [ -powersave [on|vsync|hsync|powerdown|off] ] + * [ -powerdown [0-60] ] + * [ -blength [0-2000] ] + * [ -bfreq freq ] * * * Semantics: * - * Setterm writes to standard output a character string that will invoke the - * specified terminal capabilities. Where possibile termcap is consulted to - * find the string to use. Some options however do not correspond to a - * termcap capability. In this case if the terminal type is "con*", or - * "linux*" the string that invokes the specified capabilities on the PC - * Linux virtual console driver is output. Options that are not implemented - * by the terminal are ignored. + * Setterm writes to standard output a character string that will + * invoke the specified terminal capabilities. Where possibile + * terminfo is consulted to find the string to use. Some options + * however do not correspond to a terminfo capability. In this case if + * the terminal type is "con*", or "linux*" the string that invokes + * the specified capabilities on the PC Linux virtual console driver + * is output. Options that are not implemented by the terminal are + * ignored. * * The following options are non-obvious. * @@ -74,33 +85,47 @@ * -default sets the terminal's rendering options to the default values. * * -store stores the terminal's current rendering options as the default - * values. - */ + * values. */ #include #include +#include #include -#include -#include -#include #include #include #include +#include +#include +#if NCH +#include +#else +#include +#endif +#include +#include -/* for syslog system call */ -#include -#include -_syscall3(int, syslog, int, type, char*, buf, int, len); +#ifndef TCGETS +/* TCGETS is either defined in termios.h, or here: */ +#include +#endif -/* Constants. */ +#if __GNU_LIBRARY__ < 5 +#ifndef __alpha__ +# include +#define __NR_klogctl __NR_syslog +_syscall3(int, klogctl, int, type, char*, buf, int, len); +#else /* __alpha__ */ +#define klogctl syslog +#endif +#endif -/* Termcap constants. */ -#define TC_BUF_SIZE 1024 /* Size of termcap(3) buffer. */ -#define TC_ENT_SIZE 50 /* Size of termcap(3) entry buffer. */ +/* Constants. */ /* General constants. */ +#ifndef TRUE #define TRUE 1 #define FALSE 0 +#endif /* Keyboard types. */ #define PC 0 @@ -127,8 +152,6 @@ _syscall3(int, syslog, int, type, char*, buf, int, len); /* Static variables. */ -char tc_buf[TC_BUF_SIZE]; /* Termcap buffer. */ - /* Option flags. Set if the option is to be invoked. */ int opt_term, opt_reset, opt_initialize, opt_cursor, opt_keyboard; int opt_linewrap, opt_snow, opt_softscroll, opt_default, opt_foreground; @@ -136,7 +159,8 @@ int opt_background, opt_bold, opt_blink, opt_reverse, opt_underline; int opt_store, opt_clear, opt_blank, opt_snap, opt_snapfile, opt_standout; int opt_append, opt_ulcolor, opt_hbcolor, opt_halfbright, opt_repeat; int opt_tabs, opt_clrtabs, opt_regtabs, opt_appcursorkeys, opt_inversescreen; -int opt_msg, opt_msglevel, opt_powersave; +int opt_msg, opt_msglevel, opt_powersave, opt_powerdown; +int opt_blength, opt_bfreq; /* Option controls. The variable names have been contracted to ensure * uniqueness. @@ -144,20 +168,25 @@ int opt_msg, opt_msglevel, opt_powersave; char *opt_te_terminal_name; /* Terminal name. */ int opt_cu_on, opt_li_on, opt_sn_on, opt_so_on, opt_bo_on, opt_hb_on, opt_bl_on; int opt_re_on, opt_un_on, opt_rep_on, opt_appck_on, opt_invsc_on; -int opt_msg_on, opt_ps_on; /* Boolean switches. */ +int opt_msg_on; /* Boolean switches. */ int opt_ke_type; /* Keyboard type. */ int opt_fo_color, opt_ba_color; /* Colors. */ int opt_ul_color, opt_hb_color; int opt_cl_all; /* Clear all or rest. */ int opt_bl_min; /* Blank screen. */ +int opt_blength_l; +int opt_bfreq_f; int opt_sn_num = 0; /* Snap screen. */ int opt_st_attr; int opt_rt_len; /* regular tab length */ int opt_tb_array[161]; /* Array for tab list */ int opt_msglevel_num; +int opt_ps_mode, opt_pd_min; /* powersave mode/powerdown time */ char opt_sn_name[200] = "screen.dump"; +void screendump(int vcnum, FILE *F); + /* Command line parsing routines. * * Note that it is an error for a given option to be invoked more than once. @@ -253,30 +282,31 @@ int *bad_arg; /* Set to true if an error is detected. */ if (argc != 1 || *option) *bad_arg = TRUE; *option = TRUE; if (argc == 1) { - if (strcmp(argv[0], "black") == 0) - *opt_color = BLACK; - else if (strcmp(argv[0], "red") == 0) - *opt_color = RED; - else if (strcmp(argv[0], "green") == 0) - *opt_color = GREEN; - else if (strcmp(argv[0], "yellow") == 0) - *opt_color = YELLOW; - else if (strcmp(argv[0], "blue") == 0) - *opt_color = BLUE; - else if (strcmp(argv[0], "magenta") == 0) - *opt_color = MAGENTA; - else if (strcmp(argv[0], "cyan") == 0) - *opt_color = CYAN; - else if (strcmp(argv[0], "white") == 0) - *opt_color = WHITE; - else if (strcmp(argv[0], "default") == 0) - *opt_color = DEFAULT; - else if (isdigit(argv[0][0])) - *opt_color = atoi(argv[0]); - else - *bad_arg = TRUE; - if(*opt_color < 0 || *opt_color > 15) - *bad_arg = TRUE; + if (strcmp(argv[0], "black") == 0) + *opt_color = BLACK; + else if (strcmp(argv[0], "red") == 0) + *opt_color = RED; + else if (strcmp(argv[0], "green") == 0) + *opt_color = GREEN; + else if (strcmp(argv[0], "yellow") == 0) + *opt_color = YELLOW; + else if (strcmp(argv[0], "blue") == 0) + *opt_color = BLUE; + else if (strcmp(argv[0], "magenta") == 0) + *opt_color = MAGENTA; + else if (strcmp(argv[0], "cyan") == 0) + *opt_color = CYAN; + else if (strcmp(argv[0], "white") == 0) + *opt_color = WHITE; + else if (strcmp(argv[0], "default") == 0) + *opt_color = DEFAULT; + else if (isdigit(argv[0][0])) + *opt_color = atoi(argv[0]); + else + *bad_arg = TRUE; + + if(*opt_color < 0 || *opt_color > 7) + *bad_arg = TRUE; } } @@ -364,7 +394,7 @@ int *option; /* Clear flag to set. */ int *opt_all; /* Clear all switch to set or reset. */ int *bad_arg; /* Set to true if an error is detected. */ { -/* Parse a -clear specification. */ +/* Parse a -blank specification. */ if (argc > 1 || *option) *bad_arg = TRUE; *option = TRUE; @@ -377,6 +407,35 @@ int *bad_arg; /* Set to true if an error is detected. */ } } +void parse_powersave(argc, argv, option, opt_mode, bad_arg) +int argc; /* Number of arguments for this option. */ +char *argv[]; /* Arguments for this option. */ +int *option; /* powersave flag to set. */ +int *opt_mode; /* Powersaving mode, defined in vesa_blank.c */ +int *bad_arg; /* Set to true if an error is detected. */ +{ +/* Parse a -powersave mode specification. */ + + if (argc > 1 || *option) *bad_arg = TRUE; + *option = TRUE; + if (argc == 1) { + if (strcmp(argv[0], "on") == 0) + *opt_mode = 1; + else if (strcmp(argv[0], "vsync") == 0) + *opt_mode = 1; + else if (strcmp(argv[0], "hsync") == 0) + *opt_mode = 2; + else if (strcmp(argv[0], "powerdown") == 0) + *opt_mode = 3; + else if (strcmp(argv[0], "off") == 0) + *opt_mode = 0; + else + *bad_arg = TRUE; + } else { + *opt_mode = 0; + } +} + #if 0 void parse_standout(argc, argv, option, opt_all, bad_arg) int argc; /* Number of arguments for this option. */ @@ -385,7 +444,7 @@ int *option; /* Clear flag to set. */ int *opt_all; /* Clear all switch to set or reset. */ int *bad_arg; /* Set to true if an error is detected. */ { -/* Parse a -clear specification. */ +/* Parse a -standout specification. */ if (argc > 1 || *option) *bad_arg = TRUE; *option = TRUE; @@ -423,7 +482,7 @@ int *option; /* Clear flag to set. */ int *opt_all; /* Clear all switch to set or reset. */ int *bad_arg; /* Set to true if an error is detected. */ { -/* Parse a -clear specification. */ +/* Parse a -dump or -append specification. */ if (argc > 1 || *option) *bad_arg = TRUE; *option = TRUE; @@ -443,7 +502,7 @@ int *option; /* Clear flag to set. */ int *opt_all; /* Clear all switch to set or reset. */ int *bad_arg; /* Set to true if an error is detected. */ { -/* Parse a -clear specification. */ +/* Parse a -file specification. */ if (argc != 1 || *option) *bad_arg = TRUE; *option = TRUE; @@ -514,9 +573,49 @@ int *bad_arg; /* Set to true if an error is detected. */ } } + +void parse_blength(argc, argv, option, opt_all, bad_arg) +int argc; /* Number of arguments for this option. */ +char *argv[]; /* Arguments for this option. */ +int *option; /* Clear flag to set. */ +int *opt_all; +int *bad_arg; /* Set to true if an error is detected. */ +{ +/* Parse -blength specification. */ + + if (argc > 1 || *option) *bad_arg = TRUE; + *option = TRUE; + if (argc == 1) { + *opt_all = atoi(argv[0]); + if (*opt_all > 2000) + *bad_arg = TRUE; + } else { + *opt_all = 0; + } +} + +void parse_bfreq(argc, argv, option, opt_all, bad_arg) +int argc; /* Number of arguments for this option. */ +char *argv[]; /* Arguments for this option. */ +int *option; /* Clear flag to set. */ +int *opt_all; +int *bad_arg; /* Set to true if an error is detected. */ +{ +/* Parse -bfreq specification. */ + + if (argc > 1 || *option) *bad_arg = TRUE; + *option = TRUE; + if (argc == 1) { + *opt_all = atoi(argv[0]); + } else { + *opt_all = 0; + } +} + + void show_tabs() { - int i, co = tgetnum("co"); + int i, co = tigetnum("cols"); if(co > 0) { printf("\r "); @@ -612,7 +711,13 @@ int *bad_arg; /* Set to true if an error is detected. */ else if (STRCMP(option, "msglevel") == 0) parse_msglevel(argc, argv, &opt_msglevel, &opt_msglevel_num, bad_arg); else if (STRCMP(option, "powersave") == 0) - parse_switch(argc, argv, &opt_powersave, &opt_ps_on, bad_arg); + parse_powersave(argc, argv, &opt_powersave, &opt_ps_mode, bad_arg); + else if (STRCMP(option, "powerdown") == 0) + parse_blank(argc, argv, &opt_powerdown, &opt_pd_min, bad_arg); + else if (STRCMP(option, "blength") == 0) + parse_blength(argc, argv, &opt_blength, &opt_blength_l, bad_arg); + else if (STRCMP(option, "bfreq") == 0) + parse_bfreq(argc, argv, &opt_bfreq, &opt_bfreq_f, bad_arg); #if 0 else if (STRCMP(option, "standout") == 0) parse_standout(argc, argv, &opt_standout, &opt_st_attr, bad_arg); @@ -676,23 +781,23 @@ char *prog_name; /* Name of this program. */ fprintf(stderr, " [ -file dumpfilename ]\n"); fprintf(stderr, " [ -msg [on|off] ]\n"); fprintf(stderr, " [ -msglevel [0-8] ]\n"); - fprintf(stderr, " [ -powersave [on|off] ]\n"); + fprintf(stderr, " [ -powersave [on|vsync|hsync|powerdown|off] ]\n"); + fprintf(stderr, " [ -powerdown [0-60] ]\n"); + fprintf(stderr, " [ -blength [0-2000] ]\n"); + fprintf(stderr, " [ -bfreq freqnumber ]\n"); } -char tc_ent_buf[TC_ENT_SIZE]; /* Buffer for storing a termcap entry. */ - -char *tc_entry(name) -char *name; /* Termcap capability string to lookup. */ +char *ti_entry(name) +const char *name; /* Terminfo capability string to lookup. */ { -/* Return the specified termcap string, or an empty string if no such termcap +/* Return the specified terminfo string, or an empty string if no such terminfo * capability exists. */ char *buf_ptr; - buf_ptr = tc_ent_buf; - if (tgetstr(name, &buf_ptr) == NULL) tc_ent_buf[0] = '\0'; - return tc_ent_buf; + if ((buf_ptr = tigetstr(name)) == (char *)-1) buf_ptr = NULL; + return buf_ptr; } void perform_sequence(vcterm) @@ -703,20 +808,20 @@ int vcterm; /* Set if terminal is a virtual console. */ /* -reset. */ if (opt_reset) { - printf("%s", tc_entry("rs")); + putp(ti_entry("rs1")); } /* -initialize. */ if (opt_initialize) { - printf("%s", tc_entry("is")); + putp(ti_entry("is2")); } /* -cursor [on|off]. */ if (opt_cursor) { if (opt_cu_on) - printf("%s", tc_entry("ve")); + putp(ti_entry("cnorm")); else - printf("%s", tc_entry("vi")); + putp(ti_entry("civis")); } #if 0 @@ -788,7 +893,7 @@ int vcterm; /* Set if terminal is a virtual console. */ if (vcterm) printf("\033[0m"); else - printf("%s", tc_entry("me")); + putp(ti_entry("sgr0")); } /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. @@ -834,12 +939,12 @@ int vcterm; /* Set if terminal is a virtual console. */ */ if (opt_bold) { if (opt_bo_on) - printf("%s", tc_entry("md")); + putp(ti_entry("bold")); else { if (vcterm) printf("%s%s", ESC, "[22m"); else - printf("%s", tc_entry("me")); + putp(ti_entry("sgr0")); } } @@ -848,12 +953,12 @@ int vcterm; /* Set if terminal is a virtual console. */ */ if (opt_halfbright) { if (opt_hb_on) - printf("%s", tc_entry("mh")); + putp(ti_entry("dim")); else { if (vcterm) printf("%s%s", ESC, "[22m"); else - printf("%s", tc_entry("me")); + putp(ti_entry("sgr0")); } } @@ -862,12 +967,12 @@ int vcterm; /* Set if terminal is a virtual console. */ */ if (opt_blink) { if (opt_bl_on) - printf("%s", tc_entry("mb")); + putp(ti_entry("blink")); else { if (vcterm) printf("%s%s", ESC, "[25m"); else - printf("%s", tc_entry("me")); + putp(ti_entry("sgr0")); } } @@ -876,21 +981,21 @@ int vcterm; /* Set if terminal is a virtual console. */ */ if (opt_reverse) { if (opt_re_on) - printf("%s", tc_entry("mr")); + putp(ti_entry("rev")); else { if (vcterm) printf("%s%s", ESC, "[27m"); else - printf("%s", tc_entry("me")); + putp(ti_entry("sgr0")); } } /* -underline [on|off]. */ if (opt_underline) { if (opt_un_on) - printf("%s", tc_entry("us")); + putp(ti_entry("smul")); else - printf("%s", tc_entry("ue")); + putp(ti_entry("rmul")); } /* -store. Vc only. */ @@ -901,9 +1006,9 @@ int vcterm; /* Set if terminal is a virtual console. */ /* -clear [all|rest]. */ if (opt_clear) { if (opt_cl_all) - printf("%s", tc_entry("cl")); + putp(ti_entry("clear")); else - printf("%s", tc_entry("cd")); + putp(ti_entry("ed")); } /* -tabs Vc only. */ @@ -926,7 +1031,7 @@ int vcterm; /* Set if terminal is a virtual console. */ if (opt_tb_array[0] == -1) printf("\033[3g"); else - for(i=0; opt_tb_array[i]; i++) + for(i=0; opt_tb_array[i] > 0; i++) printf("\033[%dG\033[g", opt_tb_array[i]); putchar('\r'); } @@ -942,18 +1047,23 @@ int vcterm; /* Set if terminal is a virtual console. */ } /* -blank [0-60]. */ - if (opt_blank) + if (opt_blank && vcterm) printf("\033[9;%d]", opt_bl_min); - /* -powersave [on|off] (console) */ + /* -powersave [on|vsync|hsync|powerdown|off] (console) */ if (opt_powersave) { char ioctlarg[2]; ioctlarg[0] = 10; /* powersave */ - ioctlarg[1] = opt_ps_on; + ioctlarg[1] = opt_ps_mode; if (ioctl(0,TIOCLINUX,ioctlarg)) fprintf(stderr,"cannot (un)set powersave mode\n"); } + /* -powerdown [0-60]. */ + if (opt_powerdown) { + printf("\033[14;%d]", opt_pd_min); + } + #if 0 /* -standout [num]. */ if (opt_standout) @@ -979,26 +1089,38 @@ int vcterm; /* Set if terminal is a virtual console. */ if (opt_msg && vcterm) { if (opt_msg_on) /* 7 -- Enable printk's to console */ - result = syslog(7, NULL, 0); + result = klogctl(7, NULL, 0); else /* 6 -- Disable printk's to console */ - result = syslog(6, NULL, 0); + result = klogctl(6, NULL, 0); if (result != 0) - printf("syslog error: %s\n", strerror(result)); + printf("klogctl error: %s\n", strerror(result)); } /* -msglevel [0-8] */ if (opt_msglevel && vcterm) { /* 8 -- Set level of messages printed to console */ - result = syslog(8, NULL, opt_msglevel_num); + result = klogctl(8, NULL, opt_msglevel_num); if (result != 0) - printf("syslog error: %s\n", strerror(result)); + printf("klogctl error: %s\n", strerror(result)); } + + /* -blength [0-2000] */ + if (opt_blength && vcterm) { + printf("\033[11;%d]", opt_blength_l); + } + + /* -bfreq freqnumber */ + if (opt_bfreq && vcterm) { + printf("\033[10;%d]", opt_bfreq_f); + } + } extern char *malloc(); +void screendump(int vcnum, FILE *F){ #include char infile[MAXPATHLEN]; @@ -1069,7 +1191,7 @@ try_ioctl: } } -void main(int argc, char **argv) +int main(int argc, char **argv) { int bad_arg = FALSE; /* Set if error in arguments. */ int arg, modifier; @@ -1117,13 +1239,9 @@ void main(int argc, char **argv) } } - /* Find termcap entry. */ + /* Find terminfo entry. */ - if (tgetent(tc_buf, term) != 1) { - fprintf(stderr, "%s: Could not find termcap entry for %s.\n", - argv[0], term); - exit(1); - } + setupterm(term, 1, (int *)0); /* See if the terminal is a virtual console terminal. */ @@ -1133,5 +1251,5 @@ void main(int argc, char **argv) perform_sequence(vcterm); - exit(0); + return 0; } diff --git a/misc-utils/tsort.c b/misc-utils/tsort.c index 4ccfcd53..a5a44dae 100644 --- a/misc-utils/tsort.c +++ b/misc-utils/tsort.c @@ -93,6 +93,7 @@ typedef struct _buf { NODE *add_node(), *find_node(); void add_arc(), no_memory(), remove_node(), tsort(); char *grow_buf(), *malloc(); +int find_cycle(NODE *, NODE *, int, int); extern int errno; NODE *graph; @@ -100,6 +101,7 @@ NODE *hashtable[HASHSIZE]; NODE **cycle_buf; NODE **longest_cycle; +int main(argc, argv) int argc; char **argv; @@ -158,7 +160,7 @@ main(argc, argv) /* do the sort */ tsort(); - exit(0); + return 0; } /* double the size of oldbuf and return a pointer to the new buffer. */ @@ -213,6 +215,7 @@ add_arc(s1, s2) ++n2->n_refcnt; } +int hash_string(s) char *s; { @@ -257,7 +260,7 @@ add_node(name) n->n_flags = 0; /* add to linked list */ - if (n->n_next = graph) + if ((n->n_next = graph) != NULL) graph->n_prevp = &n->n_next; n->n_prevp = &graph; graph = n; @@ -312,7 +315,7 @@ tsort() } for (n = graph; n; n = n->n_next) if (!(n->n_flags & NF_ACYCLIC)) { - if (cnt = find_cycle(n, n, 0, 0)) { + if ((cnt = find_cycle(n, n, 0, 0)) != 0) { register int i; (void)fprintf(stderr, @@ -353,6 +356,7 @@ remove_node(n) } /* look for the longest cycle from node from to node to. */ +int find_cycle(from, to, longest_len, depth) NODE *from, *to; int depth, longest_len; diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c index f869040a..84136011 100644 --- a/misc-utils/whereis.c +++ b/misc-utils/whereis.c @@ -44,8 +44,20 @@ static char sccsid[] = "@(#)whereis.c 5.5 (Berkeley) 4/18/91"; #include #include #include +#include #include +void zerof(void); +void getlist(int *, char ***, char ***, int *); +void lookup(char *); +void looksrc(char *); +void lookbin(char *); +void lookman(char *); +void findv(char **, int, char *); +void find(char **, char *); +void findin(char *, char *); +int itsit(char *, char *); + static char *bindirs[] = { #ifdef __linux__ "/bin", @@ -66,6 +78,8 @@ static char *bindirs[] = { "/usr/lib/emacs/19.28/etc", "/usr/lib/emacs/19.29/etc", "/usr/lib/emacs/19.30/etc", + "/usr/lib/emacs/19.31/etc", + "/usr/lib/emacs/19.32/etc", "/usr/TeX/bin", "/usr/tex/bin", "/usr/interviews/bin/LINUX", @@ -231,6 +245,7 @@ char uflag; * whereis name * look for source, documentation and binaries */ +int main(argc, argv) int argc; char *argv[]; @@ -288,9 +303,10 @@ usage: } else lookup(*argv++); while (--argc > 0); - exit(0); + return 0; } +void getlist(argcp, argvp, flagp, cntp) char ***argvp; int *argcp; @@ -308,16 +324,17 @@ getlist(argcp, argvp, flagp, cntp) } +void zerof() { - if (sflag && bflag && mflag) sflag = bflag = mflag = 0; } + int count; int print; - +void lookup(cp) register char *cp; { @@ -369,6 +386,7 @@ again: printf("\n"); } +void looksrc(cp) char *cp; { @@ -378,6 +396,7 @@ looksrc(cp) findv(Sflag, Scnt, cp); } +void lookbin(cp) char *cp; { @@ -387,6 +406,7 @@ lookbin(cp) findv(Bflag, Bcnt, cp); } +void lookman(cp) char *cp; { @@ -396,6 +416,7 @@ lookman(cp) findv(Mflag, Mcnt, cp); } +void findv(dirv, dirc, cp) char **dirv; int dirc; @@ -406,6 +427,7 @@ findv(dirv, dirc, cp) findin(*dirv++, cp), dirc--; } +void find(dirs, cp) char **dirs; char *cp; @@ -415,6 +437,7 @@ find(dirs, cp) findin(*dirs++, cp); } +void findin(dir, cp) char *dir, *cp; { @@ -434,6 +457,7 @@ findin(dir, cp) closedir(dirp); } +int itsit(cp, dp) register char *cp, *dp; { diff --git a/misc-utils/write.c b/misc-utils/write.c index a1865bd7..545404b4 100644 --- a/misc-utils/write.c +++ b/misc-utils/write.c @@ -36,7 +36,10 @@ * Modified for Linux, Mon Mar 8 18:16:24 1993, faith@cs.unc.edu * Wed Jun 22 21:41:56 1994, faith@cs.unc.edu: * Added fix from Mike Grupenhoff (kashmir@umiacs.umd.edu) - * + * Mon Jul 1 17:01:39 MET DST 1996, janl@math.uio.no: + * - Added fix from David.Chapell@mail.trincoll.edu enabeling daemons + * to use write. + * - ANSIed it since I was working on it anyway. */ #ifndef lint @@ -49,27 +52,35 @@ static char copyright[] = static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ -#include -#include -#include -#include -#include +#define _GNU_SOURCE /* for snprintf */ + +#include #include #include #include #include #include +#include +#include +#include +#include +#include #ifdef __linux__ #include #include "pathnames.h" #include #endif +void search_utmp(char *, char *, char *, uid_t); +void do_write(char *, char *, uid_t); +void wr_fputs(char *); +int term_chk(char *, int *, time_t *, int); +int utmp_chk(char *, char *); + extern int errno; -main(argc, argv) - int argc; - char **argv; +void +main(int argc, char **argv) { register char *cp; time_t atime; @@ -90,21 +101,25 @@ main(argc, argv) else if (isatty(fileno(stderr))) myttyfd = fileno(stderr); else { - (void)fprintf(stderr, "write: can't find your tty\n"); - exit(1); + myttyfd = -1; } - if (!(mytty = ttyname(myttyfd))) { + if (myttyfd != -1) { + if (!(mytty = ttyname(myttyfd))) { (void)fprintf(stderr, "write: can't find your tty's name\n"); exit(1); - } - if (cp = rindex(mytty, '/')) + } + if ((cp = rindex(mytty, '/')) != NULL) mytty = cp + 1; - if (term_chk(mytty, &msgsok, &atime, 1)) + if (term_chk(mytty, &msgsok, &atime, 1)) exit(1); - if (!msgsok) { + if (!msgsok) { (void)fprintf(stderr, "write: you have write permission turned off.\n"); exit(1); + } + + } else { + mytty = ""; } myuid = getuid(); @@ -142,28 +157,32 @@ main(argc, argv) /* NOTREACHED */ } + /* * utmp_chk - checks that the given user is actually logged in on * the given tty */ -utmp_chk(user, tty) - char *user, *tty; +int utmp_chk(char *user, char *tty) + { struct utmp u; - int ufd; + struct utmp *uptr; + int res = 1; - if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) - return(0); /* ignore error, shouldn't happen anyway */ + utmpname(_PATH_UTMP); + setutent(); - while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u)) + while ((uptr = getutent())) { + memcpy(&u, uptr, sizeof(u)); if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 && strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) { - (void)close(ufd); - return(0); + res = 0; + break; } + } - (void)close(ufd); - return(1); + endutent(); + return(res); } /* @@ -177,28 +196,27 @@ utmp_chk(user, tty) * Special case for writing to yourself - ignore the terminal you're * writing from, unless that's the only terminal with messages enabled. */ -search_utmp(user, tty, mytty, myuid) - char *user, *tty, *mytty; - uid_t myuid; +void search_utmp(char *user, char *tty, char *mytty, uid_t myuid) + { struct utmp u; + struct utmp *uptr; time_t bestatime, atime; - int ufd, nloggedttys, nttys, msgsok, user_is_me; + int nloggedttys, nttys, msgsok, user_is_me; #ifdef __linux__ char atty[sizeof(u.ut_line) + 1]; #else char atty[UT_LINESIZE + 1]; #endif - if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) { - perror("utmp"); - exit(1); - } + utmpname(_PATH_UTMP); + setutent(); nloggedttys = nttys = 0; bestatime = 0; user_is_me = 0; - while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u)) + while ((uptr = getutent())) { + memcpy(&u, uptr, sizeof(u)); if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) { ++nloggedttys; #ifdef __linux__ @@ -226,8 +244,9 @@ search_utmp(user, tty, mytty, myuid) (void)strcpy(tty, atty); } } + } - (void)close(ufd); + endutent(); if (nloggedttys == 0) { (void)fprintf(stderr, "write: %s is not logged in\n", user); exit(1); @@ -251,15 +270,13 @@ search_utmp(user, tty, mytty, myuid) * term_chk - check that a terminal exists, and get the message bit * and the access time */ -term_chk(tty, msgsokP, atimeP, showerror) - char *tty; - int *msgsokP, showerror; - time_t *atimeP; +int term_chk(char *tty, int *msgsokP, time_t *atimeP, int showerror) + { struct stat s; char path[MAXPATHLEN]; - (void)sprintf(path, "/dev/%s", tty); + (void)snprintf(path, sizeof(path), "/dev/%s", tty); if (stat(path, &s) < 0) { if (showerror) (void)fprintf(stderr, @@ -274,9 +291,8 @@ term_chk(tty, msgsokP, atimeP, showerror) /* * do_write - actually make the connection */ -do_write(tty, mytty, myuid) - char *tty, *mytty; - uid_t myuid; +void do_write(char *tty, char *mytty, uid_t myuid) + { register char *login, *nows; register struct passwd *pwd; @@ -286,12 +302,12 @@ do_write(tty, mytty, myuid) /* Determine our login name before the we reopen() stdout */ if ((login = getlogin()) == NULL) - if (pwd = getpwuid(myuid)) + if ((pwd = getpwuid(myuid)) != NULL) login = pwd->pw_name; else login = "???"; - (void)sprintf(path, "/dev/%s", tty); + (void)snprintf(path, sizeof(path), "/dev/%s", tty); if ((freopen(path, "w", stdout)) == NULL) { (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno)); exit(1); @@ -316,8 +332,7 @@ do_write(tty, mytty, myuid) /* * done - cleanup and exit */ -void -done() +void done(void) { (void)printf("EOF\r\n"); exit(0); @@ -327,10 +342,10 @@ done() * wr_fputs - like fputs(), but makes control characters visible and * turns \n into \r\n */ -wr_fputs(s) - register char *s; +void wr_fputs(char *s) + { - register char c; + char c; #define PUTC(c) if (putchar(c) == EOF) goto err; diff --git a/mount/Makefile b/mount/Makefile index 22c146ce..cfbedd59 100644 --- a/mount/Makefile +++ b/mount/Makefile @@ -1,19 +1,13 @@ -# To make "ext" the default file system type for mount -# (used when no other type is specified), replace \"minix\" by \"ext2\". -# Use iso9660 instead, since CDROMs are popular. -DEFAULT_FSTYPE=\"iso9660\" - -# you need rpcgen and libc-4.2 or rpclib to compile in the NFS support -DEFINES = -DHAVE_NFS -DFSTYPE_DEFAULT=$(DEFAULT_FSTYPE) - +ifeq (../MCONFIG,$(wildcard ../MCONFIG)) include ../MCONFIG -#CC = gcc -#OPTFLAGS= -O2 -m486 -fomit-frame-pointer -##OPTFLAGS= -O2 -fomit-frame-pointer # or change on make's command line -#CFLAGS = -pipe $(OPTFLAGS) +endif + +CC = gcc +CFLAGS = -O2 WARNFLAGS = -Wall -Wstrict-prototypes -Wmissing-prototypes -#LDFLAGS = -s -N -LDLIBS = +DEFINES = -DHAVE_NFS +LDFLAGS = + RPCSVCDIR = rpcsvc RPC_CFLAGS = -Wno-unused RPCGEN = rpcgen @@ -21,12 +15,11 @@ RPCGEN = rpcgen #INSTALL_SUID = $(INSTALL) -m 4755 -o root #INSTALL_PROG = $(INSTALL) -m 755 #INSTALL_DATA = $(INSTALL) -m 644 -#prefix = /usr ## for suid progs (mount, umount) #BINDIR = /bin ## for nosuid progs (swapon) -#SBINDIR = /etc +#SBINDIR = /sbin # End of configuration section. @@ -34,15 +27,15 @@ COMPILE = $(CC) -c $(WARNFLAGS) $(CFLAGS) $(DEFINES) LINK = $(CC) $(LDFLAGS) SUID_PROGS = mount umount -NOSUID_PROGS = swapon +NOSUID_PROGS = swapon losetup PROGS = $(SUID_PROGS) $(NOSUID_PROGS) MAN5 = fstab.5 nfs.5 -MAN8 = mount.8 swapoff.8 swapon.8 umount.8 +MAN8 = mount.8 swapoff.8 swapon.8 umount.8 losetup.8 # comment these out if you are not compiling in NFS support -NFS_OBJS = nfsmount.o mount_xdr.o mount_clnt.o +NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o # uncomment this if you don't have libc-4.2 but do have the rpclib -GEN_FILES = mount.x mount.h mount_xdr.c mount_clnt.c +GEN_FILES = nfsmount.x nfsmount.h nfsmount_xdr.c nfsmount_clnt.c # comment these out if you are not compiling in loop support LO_OBJS=lomount.o @@ -61,34 +54,75 @@ install: $(PROGS) %.o: %.c $(COMPILE) $< -mount: mount.o fstab.o sundries.o version.o $(NFS_OBJS) $(LO_OBJS) +mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS) $(LINK) $^ $(LDLIBS) -o $@ -umount: umount.o fstab.o sundries.o version.o $(LO_OBJS) +umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS) $(LINK) $^ $(LDLIBS) -o $@ -swapon: swapon.o fstab.o version.o +swapon: swapon.o version.o $(LINK) $^ $(LDLIBS) -o $@ -nfsmount.o mount_xdr.o mount_clnt.o: mount.h +losetup: losetup.o + $(LINK) $^ $(LDLIBS) -o $@ + +mount.o umount.o nfsmount.o losetup.o fstab.o sundries.o: sundries.h + +mount.o umount.o fstab.o sundries.o: fstab.h + +mount.o umount.o losetup.o: lomount.h loop.h + +swapon.o: swap.h swapargs.h -mount_clnt.o: mount_clnt.c - $(COMPILE) $(RPC_CFLAGS) mount_clnt.c +sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h -mount_xdr.o: mount_xdr.c - $(COMPILE) $(RPC_CFLAGS) mount_xdr.c +nfsmount_clnt.o: nfsmount_clnt.c + $(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c -mount.h mount_xdr.c mount_clnt.c: mount.x - rm -f mount.h mount_xdr.c mount_clnt.c - $(RPCGEN) -h -o mount.h mount.x - $(RPCGEN) -c -o mount_xdr.c mount.x - $(RPCGEN) -l -o mount_clnt.c mount.x +nfsmount_xdr.o: nfsmount_xdr.c + $(COMPILE) $(RPC_CFLAGS) nfsmount_xdr.c -mount.x: - cp $(RPCSVCDIR)/mount.x . +# rpcgen generates files that do not compile - use the pregenerated ones +# nfsmount.h nfsmount_xdr.c nfsmount_clnt.c: nfsmount.x +# rm -f nfsmount.h nfsmount_xdr.c nfsmount_clnt.c +# $(RPCGEN) -h -o nfsmount.h nfsmount.x +# $(RPCGEN) -c -o nfsmount_xdr.c nfsmount.x +# $(RPCGEN) -l -o nfsmount_clnt.c nfsmount.x + +nfsmount.x: + cp $(RPCSVCDIR)/nfsmount.x . + +nfsmount.o: nfs_mountversion.h nfs_mount3.h + +NFSMOUNTH=/usr/include/linux/nfs_mount.h +SWAPH=/usr/include/linux/swap.h +LOOPH=/usr/include/linux/loop.h + +nfs_mountversion.h: + rm -f nfs_mountversion.h + if [ -f $(NFSMOUNTH) ]; then \ + grep NFS_MOUNT_VERSION $(NFSMOUNTH) \ + | sed -e 's/NFS/KERNEL_NFS/'; \ + else \ + echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \ + fi > nfs_mountversion.h + +swap.h: + rm -f swap.h + if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi + +swapargs.h: + sh swap.configure + +loop.h: + rm -f loop.h + if [ -f $(LOOPH) ]; then cp $(LOOPH) .; else touch loop.h; fi clean: - rm -f a.out core *~ *.o $(PROGS) + rm -f a.out core *~ *.o swapargs.h $(PROGS) + +cleaner: clean + rm -f swap.h loop.h nfs_mountversion.h -clobber: clean - rm -f $(PROGS) $(GEN_FILES) +clobber distclean realclean: cleaner +# rm -f $(GEN_FILES) diff --git a/mount/Makefile.standalone b/mount/Makefile.standalone new file mode 100644 index 00000000..9576cdb1 --- /dev/null +++ b/mount/Makefile.standalone @@ -0,0 +1,143 @@ +# ifeq (../MCONFIG,$(wildcard ../MCONFIG)) +# include ../MCONFIG +# endif + +# For now: a standalone version + +CC = gcc +CFLAGS = -O2 + +#WARNFLAGS = -Wall -Wstrict-prototypes +# We really want +WARNFLAGS = -Wall -Wstrict-prototypes -Wmissing-prototypes +# but at the moment that yields +#:72: warning: no previous prototype for `cmsg_nxthdr' + +# you need rpcgen and libc-4.2 or rpclib to compile in the NFS support +# pregenerated files are included. +# Make sure nfsmount_clnt.c is newer than nfsmount.x to avoid gcc complaints. +DEFINES = -DHAVE_NFS + +RPCSVCDIR = rpcsvc +RPC_CFLAGS = -Wno-unused +RPCGEN = rpcgen + +INSTALL = install +INSTALL_SUID = $(INSTALL) -m 4755 -o root +INSTALL_PROG = $(INSTALL) -m 755 +INSTALL_DATA = $(INSTALL) -m 644 +INSTALL_DIR = mkdir -p +INSTALL_MAN = $(INSTALL_DATA) + +MANDIR = /usr/man +## for suid progs (mount, umount) +BINDIR = /bin +## for nosuid progs (swapon) +SBINDIR = /sbin + +# End of configuration section. + +COMPILE = $(CC) -c $(WARNFLAGS) $(CFLAGS) $(DEFINES) +LINK = $(CC) $(LDFLAGS) + +SUID_PROGS = mount umount +NOSUID_PROGS = swapon losetup +PROGS = $(SUID_PROGS) $(NOSUID_PROGS) +MAN5 = fstab.5 nfs.5 +MAN8 = mount.8 swapoff.8 swapon.8 umount.8 losetup.8 + +# comment these out if you are not compiling in NFS support +NFS_OBJS = nfsmount.o nfsmount_xdr.o nfsmount_clnt.o +# uncomment this if you don't have libc-4.2 but do have the rpclib +GEN_FILES = nfsmount.x nfsmount.h nfsmount_xdr.c nfsmount_clnt.c + +# comment these out if you are not compiling in loop support +LO_OBJS=lomount.o + +all: $(PROGS) + +install: $(PROGS) + $(INSTALL_DIR) $(BINDIR) $(SBINDIR) + $(INSTALL_SUID) -s $(SUID_PROGS) $(BINDIR) + $(INSTALL_PROG) -s $(NOSUID_PROGS) $(SBINDIR) + (cd $(SBINDIR); ln -sf swapon swapoff) + $(INSTALL_DIR) $(MANDIR)/man5 $(MANDIR)/man8 + $(INSTALL_MAN) $(MAN5) $(MANDIR)/man5 + $(INSTALL_MAN) $(MAN8) $(MANDIR)/man8 + +%.o: %.c + $(COMPILE) $< + +mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS) + $(LINK) $^ -o $@ + +umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS) + $(LINK) $^ -o $@ + +swapon: swapon.o version.o + $(LINK) $^ -o $@ + +losetup: losetup.o + $(LINK) $^ -o $@ + +mount.o umount.o nfsmount.o losetup.o fstab.o sundries.o: sundries.h + +mount.o umount.o fstab.o sundries.o: fstab.h + +mount.o umount.o losetup.o: lomount.h loop.h + +swapon.o: swap.h swapargs.h + +sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h + +umount.o: mount_constants.h + +nfsmount_clnt.o: nfsmount_clnt.c + $(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c + +nfsmount_xdr.o: nfsmount_xdr.c + $(COMPILE) $(RPC_CFLAGS) nfsmount_xdr.c + +nfsmount.h nfsmount_xdr.c nfsmount_clnt.c: nfsmount.x + rm -f nfsmount.h nfsmount_xdr.c nfsmount_clnt.c + $(RPCGEN) -h -o nfsmount.h nfsmount.x + $(RPCGEN) -c -o nfsmount_xdr.c nfsmount.x + $(RPCGEN) -l -o nfsmount_clnt.c nfsmount.x + +nfsmount.x: + cp $(RPCSVCDIR)/nfsmount.x . + +nfsmount.o: nfs_mountversion.h nfs_mount3.h + +NFSMOUNTH=/usr/include/linux/nfs_mount.h +SWAPH=/usr/include/linux/swap.h +LOOPH=/usr/include/linux/loop.h + +nfs_mountversion.h: + rm -f nfs_mountversion.h + if [ -f $(NFSMOUNTH) ]; then \ + grep NFS_MOUNT_VERSION $(NFSMOUNTH) \ + | sed -e 's/NFS/KERNEL_NFS/'; \ + else \ + echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \ + fi > nfs_mountversion.h + +swap.h: + rm -f swap.h + if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi + +swapargs.h: + sh swap.configure + +loop.h: + rm -f loop.h + if [ -f $(LOOPH) ]; then cp $(LOOPH) .; else touch loop.h; fi + +clean: + rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff + +cleaner: clean + rm -f swap.h loop.h nfs_mountversion.h + +clobber distclean realclean: cleaner + rm -f $(GEN_FILES) diff --git a/mount/README.mount b/mount/README.mount index 9bea2dc2..2a8fae1c 100644 --- a/mount/README.mount +++ b/mount/README.mount @@ -1,147 +1,10 @@ -mount/umount for Linux 0.99.14 -============================== +mount/umount for Linux 0.97.3 and later. +Authors: +Doug Quale , +H.J. Lu , +Rick Sladkey , +Stephen Tweedie . -Enhance nfsmount.c to allow the program number or port number -to be specified for both the mount daemon and the nfs daemon. -Also anticipate tcp and namelen support. +Presently maintained by Andries Brouwer . +Ftp site: ftp.win.tue.nl:/pub/linux/util . -Rewrite canonicalize in terms of realpath. Don't be obsessive about -the path pre-existing for nfs, ifs, none, etc. - -Fix memory overwriting bug in the new remount code. - -Fix mtab handling in the new remount code so entries appear -exactly once and in their proper mounting order. - -Fix defaults, remount and noauto so these options don't appear in the mtab. - -Repair extra options handling that got damaged with the remount code. - -Handle combining -o from the command line with options specified -in /etc/mtab or /etc/fstab. - -Fix completely broken file-locking. - -Beautify the options field so it contains no duplicates or redundancies. - -Added long-style options to all programs. - -Added version and help options to all programs. - -Brought the Makefile up to GNU standards regarding CFLAGS and LDLFLAGS. - -Added support for the `user' option where mount and umount run suid to root. - -Rick Sladkey - -mount/umount for Linux 0.99.10 -============================== - -[Stephen Tweedie ] - -A number of changes introduced to cater for new kernel facilities. -mount can now remount an already-mounted filesystem, and umount -attempts to unmount even root filesystems. Supercedes the [u]mount -previously available in the bootutils-0.1 collection. - -Fixed a minor bug in canonicalise(). - -mount/umount/swapon/swapoff(8) for Linux 0.99.6 -=============================================== - -Here is a minor update to the previous version that fixes -a longstanding "off by one" bug in parsing fs-specific -options. No other real changes. - -mount/umount/swapon/swapoff(8) for Linux 0.99.2 -=============================================== - -Here is a new version of Doug Quale's mount/umount package that -includes support for mounting and unmount NFS filesystems. It is -still possible to compile it without NFS support by modifying the -Makefile. Even if you don't have rpcgen, but do have libc-4.2 -you can "cp -p" the pre-generated files in the rpcsvc directory -into the mount source directory. - -The primary difference besides the actual NFS mounting code is that -mount understands hostname:/path syntax for the "device" as well as -the new keyword "none" which is useful for the proc filesystem. Also, -umount had to be trained to specify the mount-point instead of the -device when unmounting such filesystems. For compatibility, -filesystems with true devices are unmounted using their device name -which will still work with older kernels. However, all umounts could -just as well be done by specifying the mount point instead of the -device. - -Other changes since the beta NFS mount are: - -* incorportated H.J. Lu's changes for mtab permissions and errno handling -* corrected the error message for unhandled errors from mount and umount -* improved (a little :-) the reporting of handled mount and umount errors -* added the ability to NFS mount from a IP address as well as a hostname -* added a string error message instead of numeric for failed NFS mounts -* changed 32 to _NSIG when setting all signals (should be using sigismember) -* eliminated the obsolete HAVE_MOUNT5 and HAVE_SWAPOFF ifdefs -* added support for the sync and async mount options -* added the noauto option for fstab entries that shouldn't get mounted with -a -* changed mount -a to check the mtab for already mounted filesystems -* eliminated a few new warning messages from gcc 2.3.3 -* wrote an nfs man page - -Features still missing: - -* ability to background NFS mounts that have timed out -* notify the NFS server of umounts (but addr=ip-addr support is in there) -* add the possibility of interrupting an in-progress mount -* man pages for the other Linux filesystem types - -Rick Sladkey -jrs@world.std.com -=============================================== -mount/umount/swapon/swapoff(8) for Linux 0.98.5 -=============================================== - -This version fixed the umask of root. fchmod () is called -before close /etc/mtab. This version should work with -0.97.3 or above, although I only tested it under 0.98.5. -I also fixed the error report. - -H.J. Lu -hlu@eecs.wsu.edu -11/25/92 -=============================================== -mount/umount/swapon/swapoff(8) for Linux 0.97.3 -=============================================== - -The most significant improvement over the first release is the repair of -at least a half dozen really dumb bugs, mostly involving null pointers. -These bugs caused frequent core dumps and really made the code unusable. - -Some race conditions in the lock handling code have been removed. - -Swapoff is available for 0.97.3 and later kernels. - -Swapon supports multiple swap files. In particular, swapon -a will try -to enable swapping on all the swap entries in /etc/fstab. - -File system specific mount options are now supported. This is of particular -utility with Werner Almesberger's msdos fs. - -Umount -a now reads /etc/mtab instead of /etc/fstab (thanks to David -Engel for a valuable discussion on this and other points). In addition, -it umounts the entries in reverse order, ensuring that it tries to umount -/usr/spool before /usr, for instance. - -Mount will now print mtab for ordinary users as well as for the superuser. -Several people pointed out this deficiency, and it was a real no-brainer -that broke it in the first release. - -Thanks to Linus, for another great release. 0.97.3 compiled the first time -out and is working flawlessly. Thanks also to Ross Biro, for his work on -Linux TCP/IP which has made it much easier to get this little thing off my -machine. Special thanks to everyone who put up with my bugs. - -Brickbats etc. to - -Doug Quale -quale@saavik.cs.wisc.edu diff --git a/mount/fstab.5 b/mount/fstab.5 index 82bf0f4c..e276350c 100644 --- a/mount/fstab.5 +++ b/mount/fstab.5 @@ -70,8 +70,9 @@ field should be specified as ``none''. The third field, .RI ( fs_vfstype ), -describes the type of the filesystem. The system currently supports three -types of filesystems: +describes the type of the filesystem. The system currently supports these +types of filesystems (and possibly others - consult +.IR /proc/filesystems ): .TP .I minix a local filesystem, supporting filenames of length 14 or 30 characters. diff --git a/mount/fstab.c b/mount/fstab.c index d13280f8..524779a6 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -1,92 +1,385 @@ -/* $Header: /home/faith/cvs/util-linux/mount/fstab.c,v 1.2 1995/10/07 01:32:03 faith Exp $ */ - -#include "fstab.h" +#include +#include +#include #include +#include +#include +#include "fstab.h" +#include "sundries.h" /* for xmalloc() etc */ + #define streq(s, t) (strcmp ((s), (t)) == 0) -/* These routines are superseded by mntent(3), but I use them for - convenience. Mntent(3) is used in the implementation, so be - very careful about the static buffers that are returned. */ +#define PROC_MOUNTS "/proc/mounts" + +/* Information about mtab. ------------------------------------*/ +static int have_mtab_info = 0; +static int var_mtab_does_not_exist = 0; +static int var_mtab_is_a_symlink = 0; -static FILE *F_fstab = NULL; +static void +get_mtab_info(void) { + struct stat mtab_stat; + + if (!have_mtab_info) { + if (lstat(MOUNTED, &mtab_stat)) + var_mtab_does_not_exist = 1; + else if (S_ISLNK(mtab_stat.st_mode)) + var_mtab_is_a_symlink = 1; + have_mtab_info = 1; + } +} -/* Open fstab or rewind if already open. */ int -setfsent (void) -{ - if (F_fstab) - return (fseek (F_fstab, 0L, SEEK_SET) == 0); +mtab_does_not_exist(void) { + get_mtab_info(); + return var_mtab_does_not_exist; +} - F_fstab = setmntent (_PATH_FSTAB, "r"); - return (F_fstab != NULL); +int +mtab_is_a_symlink(void) { + get_mtab_info(); + return var_mtab_is_a_symlink; } -/* Close fstab. */ -void -endfsent (void) -{ - endmntent (F_fstab); +int +mtab_is_writable() { + static int ret = -1; + + /* Should we write to /etc/mtab upon an update? + Probably not if it is a symlink to /proc/mounts, since that + would create a file /proc/mounts in case the proc filesystem + is not mounted. */ + if (mtab_is_a_symlink()) + return 0; + + if (ret == -1) { + int fd = open(MOUNTED, O_RDWR | O_CREAT, 0644); + if (fd >= 0) { + close(fd); + ret = 1; + } else + ret = 0; + } + return ret; } -/* Return next entry in fstab, skipping ignore entries. I also put - in some ugly hacks here to skip comments and blank lines. */ -struct mntent * -getfsent (void) -{ - struct mntent *fstab; - - if (!F_fstab && !setfsent()) - return 0; - - for (;;) - { - fstab = getmntent (F_fstab); - if (fstab == NULL) - { - if (!feof (F_fstab) && !ferror (F_fstab)) - continue; - else +/* Contents of mtab and fstab ---------------------------------*/ + +struct mntentchn mounttable, fstab; +static int got_mtab = 0; +static int got_fstab = 0; + +static void read_mounttable(void), read_fstab(void); + +struct mntentchn * +mtab_head() { + if (!got_mtab) + read_mounttable(); + return &mounttable; +} + +struct mntentchn * +fstab_head() { + if (!got_fstab) + read_fstab(); + return &fstab; +} + +static void +read_mntentchn(FILE *fp, const char *fnam, struct mntentchn *mc0) { + struct mntentchn *mc = mc0; + struct mntent *mnt; + + while (!feof(fp) && !ferror(fp)) { + if ((mnt = getmntent (fp)) != NULL /* ignore blank lines */ + && *mnt->mnt_fsname != '#' /* and comment lines */ + && !streq (mnt->mnt_type, MNTTYPE_IGNORE)) { + mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc)); + mc->nxt->prev = mc; + mc = mc->nxt; + mc->mnt_fsname = xstrdup(mnt->mnt_fsname); + mc->mnt_dir = xstrdup(mnt->mnt_dir); + mc->mnt_type = xstrdup(mnt->mnt_type); + mc->mnt_opts = xstrdup(mnt->mnt_opts); + mc->nxt = NULL; + } + } + mc0->prev = mc; + if (ferror (fp)) { + error("warning: error reading %s: %s", fnam, strerror (errno)); + mc0->nxt = mc0->prev = NULL; + } + endmntent(fp); +} + +/* + * Read /etc/mtab. If that fails, try /proc/mounts. + * This produces a linked list. The list head mounttable is a dummy. + * Return 0 on success. + */ +static void +read_mounttable() { + FILE *fp = NULL; + const char *fnam; + struct mntentchn *mc = &mounttable; + + got_mtab = 1; + mc->nxt = mc->prev = NULL; + + fnam = MOUNTED; + if ((fp = setmntent (fnam, "r")) == NULL) { + int errsv = errno; + fnam = PROC_MOUNTS; + if ((fp = setmntent (fnam, "r")) == NULL) { + error("warning: can't open %s: %s", MOUNTED, strerror (errsv)); + return; + } + if (verbose) + printf ("mount: could not open %s - using %s instead\n", + MOUNTED, PROC_MOUNTS); + } + read_mntentchn(fp, fnam, mc); +} + +static void +read_fstab() { + FILE *fp = NULL; + const char *fnam; + struct mntentchn *mc = &fstab; + + got_fstab = 1; + mc->nxt = mc->prev = NULL; + + fnam = _PATH_FSTAB; + if ((fp = setmntent (fnam, "r")) == NULL) { + error("warning: can't open %s: %s", _PATH_FSTAB, strerror (errno)); + return; + } + read_mntentchn(fp, fnam, mc); +} + + +/* Given the name NAME, try to find it in mtab. */ +struct mntentchn * +getmntfile (const char *name) { + struct mntentchn *mc; + + for (mc = mtab_head()->nxt; mc; mc = mc->nxt) + if (streq (mc->mnt_dir, name) || (streq (mc->mnt_fsname, name))) break; - } - else if ((*fstab->mnt_fsname != '#') - && !streq (fstab->mnt_type, MNTTYPE_IGNORE)) - break; - } - return fstab; + + return mc; } -/* Find the dir FILE in fstab. */ -struct mntent * -getfsfile (const char *file) +/* Given the name FILE, try to find the option "loop=FILE" in mtab. */ +struct mntentchn * +getmntoptfile (const char *file) { - struct mntent *fstab; + struct mntentchn *mc; + char *opts, *s; + int l; - /* Open or rewind fstab. */ - if (!setfsent ()) - return 0; + if (!file) + return NULL; - while ((fstab = getfsent ())) - if (streq (fstab->mnt_dir, file)) - break; + l = strlen(file); - return fstab; + for (mc = mtab_head()->nxt; mc; mc = mc->nxt) + if ((opts = mc->mnt_opts) != NULL + && (s = strstr(opts, "loop=")) + && !strncmp(s+5, file, l) + && (s == opts || s[-1] == ',') + && (s[l+5] == 0 || s[l+5] == ',')) + return mc; + + return NULL; +} + +/* Find the dir FILE in fstab. */ +struct mntentchn * +getfsfile (const char *file) { + struct mntentchn *mc; + + for (mc = fstab_head()->nxt; mc; mc = mc->nxt) + if (streq (mc->mnt_dir, file)) + break; + + return mc; } /* Find the device SPEC in fstab. */ -struct mntent * +struct mntentchn * getfsspec (const char *spec) { - struct mntent *fstab; + struct mntentchn *mc; + + for (mc = fstab_head()->nxt; mc; mc = mc->nxt) + if (streq (mc->mnt_fsname, spec)) + break; + + return mc; +} + +/* Updating mtab ----------------------------------------------*/ + +/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */ +static int lock = -1; + +/* Flag for already existing lock file. */ +static int old_lockfile = 1; + +/* Ensure that the lock is released if we are interrupted. */ +static void +handler (int sig) { + die (EX_USER, "%s", sys_siglist[sig]); +} + +static void +setlkw_timeout (int sig) { + /* nothing, fcntl will fail anyway */ +} + +/* Create the lock file. The lock file will be removed if we catch a signal + or when we exit. The value of lock is tested to remove the race. */ +void +lock_mtab (void) { + int sig = 0; + struct sigaction sa; + struct flock flock; + + /* If this is the first time, ensure that the lock will be removed. */ + if (lock < 0) { + struct stat st; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigfillset (&sa.sa_mask); + + while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { + if (sig == SIGALRM) + sa.sa_handler = setlkw_timeout; + else + sa.sa_handler = handler; + sigaction (sig, &sa, (struct sigaction *) 0); + } + + /* This stat is performed so we know when not to be overly eager + when cleaning up after signals. The window between stat and + open is not significant. */ + if (lstat (MOUNTED_LOCK, &st) < 0 && errno == ENOENT) + old_lockfile = 0; + + lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT, 0); + if (lock < 0) { + die (EX_FILEIO, "can't create lock file %s: %s " + "(use -n flag to override)", + MOUNTED_LOCK, strerror (errno)); + } + + flock.l_type = F_WRLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + alarm(LOCK_BUSY); + if (fcntl (lock, F_SETLKW, &flock) < 0) { + close (lock); + /* The file should not be removed */ + lock = -1; + die (EX_FILEIO, "can't lock lock file %s: %s", + MOUNTED_LOCK, + errno == EINTR ? "timed out" : strerror (errno)); + } + /* We have now access to the lock, and it can always be removed */ + old_lockfile = 0; + } +} + +/* Remove lock file. */ +void +unlock_mtab (void) { + if (lock != -1) { + close (lock); + if (!old_lockfile) + unlink (MOUNTED_LOCK); + } +} + +/* + * Update the mtab. + * Used by umount with null INSTEAD: remove any DIR entries. + * Used by mount upon a remount: update option part, + * and complain if a wrong device or type was given. + * [Note that often a remount will be a rw remount of / + * where there was no entry before, and we'll have to believe + * the values given in INSTEAD.] + */ + +void +update_mtab (const char *dir, struct mntent *instead) { + struct mntent *mnt; + struct mntent *next; + struct mntent remnt; + int added = 0; + FILE *fp, *ftmp; + + if (mtab_does_not_exist() || mtab_is_a_symlink()) + return; + + lock_mtab(); + + if ((fp = setmntent(MOUNTED, "r")) == NULL) { + error ("cannot open %s (%s) - mtab not updated", + MOUNTED, strerror (errno)); + goto leave; + } + + if ((ftmp = setmntent (MOUNTED_TEMP, "w")) == NULL) { + error ("can't open %s (%s) - mtab not updated", + MOUNTED_TEMP, strerror (errno)); + goto leave; + } + + while ((mnt = getmntent (fp))) { + if (streq (mnt->mnt_dir, dir)) { + added++; + if (instead) { /* a remount */ + remnt = *instead; + next = &remnt; + remnt.mnt_fsname = mnt->mnt_fsname; + remnt.mnt_type = mnt->mnt_type; + if (instead->mnt_fsname + && !streq(mnt->mnt_fsname, instead->mnt_fsname)) + printf("mount: warning: cannot change " + "mounted device with a remount\n"); + else if (instead->mnt_type + && !streq(instead->mnt_type, "unknown") + && !streq(mnt->mnt_type, instead->mnt_type)) + printf("mount: warning: cannot change " + "filesystem type with a remount\n"); + } else + next = NULL; + } else + next = mnt; + if (next && addmntent(ftmp, next) == 1) + die (EX_FILEIO, "error writing %s: %s", + MOUNTED_TEMP, strerror (errno)); + } + if (instead && !added && addmntent(ftmp, instead) == 1) + die (EX_FILEIO, "error writing %s: %s", + MOUNTED_TEMP, strerror (errno)); - /* Open or rewind fstab. */ - if (!setfsent()) - return 0; + endmntent (fp); + if (fchmod (fileno (ftmp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + fprintf(stderr, "error changing mode of %s: %s", MOUNTED_TEMP, + strerror (errno)); + endmntent (ftmp); - while ((fstab = getfsent ())) - if (streq (fstab->mnt_fsname, spec)) - break; + if (rename (MOUNTED_TEMP, MOUNTED) < 0) + fprintf(stderr, "can't rename %s to %s: %s", MOUNTED_TEMP, MOUNTED, + strerror(errno)); - return fstab; +leave: + unlock_mtab(); } diff --git a/mount/fstab.h b/mount/fstab.h index 82582259..f22f2e7c 100644 --- a/mount/fstab.h +++ b/mount/fstab.h @@ -1,26 +1,29 @@ -/* The fsent(3) routines are obsoleted by mntent(3). I use them for - convenience. Since the implementation uses mntent(3), be very - careful with the static buffers returned. - $Header: /home/faith/cvs/util-linux/mount/fstab.h,v 1.2 1995/09/25 20:57:42 faith Exp $ */ +#define _PATH_FSTAB "/etc/fstab" +#define MOUNTED_LOCK "/etc/mtab~" +#define MOUNTED_TEMP "/etc/mtab.tmp" +#define LOCK_BUSY 10 -#ifndef _FSTAB_H -#include -#include +int mtab_is_writable(void); +int mtab_does_not_exist(void); +int mtab_is_a_symlink(void); -#define _PATH_FSTAB "/etc/fstab" +struct mntentchn { + struct mntentchn *nxt, *prev; + char *mnt_fsname; + char *mnt_dir; + char *mnt_type; + char *mnt_opts; +}; -/* Translate fsent(3) stuff into mntent(3) stuff. - In general this won't work, but it's good enough here. */ -#define fstab mntent -#define fs_type mnt_type -#define fs_spec mnt_fsname -#define fs_mntopts mnt_opts -#define FSTAB_SW MNTTYPE_SWAP +struct mntentchn *mtab_head (void); +struct mntentchn *getmntfile (const char *name); +struct mntentchn *getmntoptfile (const char *file); -struct fstab *getfsent (void); -struct fstab *getfsspec (const char *spec); -struct fstab *getfsfile (const char *file); -int setfsent (void); -void endfsent (void); +struct mntentchn *fstab_head (void); +struct mntentchn *getfsfile (const char *file); +struct mntentchn *getfsspec (const char *spec); -#endif /* _FSTAB_H */ +#include +void lock_mtab (void); +void unlock_mtab (void); +void update_mtab (const char *special, struct mntent *with); diff --git a/mount/loop.h b/mount/h/loop.h similarity index 58% rename from mount/loop.h rename to mount/h/loop.h index 81ee7611..a78dff72 100644 --- a/mount/loop.h +++ b/mount/h/loop.h @@ -1,6 +1,3 @@ -#ifndef _LINUX_LOOP_H -#define _LINUX_LOOP_H - /* * include/linux/loop.h * @@ -13,33 +10,6 @@ #define LO_NAME_SIZE 64 #define LO_KEY_SIZE 32 -struct loop_device { - int lo_number; - struct inode *lo_inode; - int lo_refcnt; - dev_t lo_device; - int lo_offset; - int lo_encrypt_type; - int lo_encrypt_key_size; - int lo_flags; - int (*transfer)(struct loop_device *, int cmd, - char *raw_buf, char *loop_buf, int size); - char lo_name[LO_NAME_SIZE]; - char lo_encrypt_key[LO_KEY_SIZE]; -#ifdef DES_AVAILABLE - des_key_schedule lo_des_key; - unsigned long lo_des_init[2]; -#endif -}; - -typedef int (* transfer_proc_t)(struct loop_device *, int cmd, - char *raw_buf, char *loop_buf, int size); - -/* - * Loop flags - */ -#define LO_FLAGS_DO_BMAP 0x00000001 - struct loop_info { int lo_number; /* ioctl r/o */ dev_t lo_device; /* ioctl r/o */ @@ -62,8 +32,8 @@ struct loop_info { #define LO_CRYPT_NONE 0 #define LO_CRYPT_XOR 1 #define LO_CRYPT_DES 2 -#define LO_CRYPT_IDEA 4 -#define MAX_LO_CRYPT 3 +#define LO_CRYPT_IDEA 3 +#define MAX_LO_CRYPT 4 /* * IOCTL commands --- we will commandeer 0x4C ('L') @@ -73,5 +43,3 @@ struct loop_info { #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS 0x4C02 #define LOOP_GET_STATUS 0x4C03 - -#endif diff --git a/mount/h/swap.h b/mount/h/swap.h new file mode 100644 index 00000000..db3fc404 --- /dev/null +++ b/mount/h/swap.h @@ -0,0 +1,5 @@ +#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ +#define SWAP_FLAG_PRIO_MASK 0x7fff +#define SWAP_FLAG_PRIO_SHIFT 0 + +#define MAX_SWAPFILES 8 diff --git a/mount/lomount.c b/mount/lomount.c index 5dd02d8b..a6ad187a 100644 --- a/mount/lomount.c +++ b/mount/lomount.c @@ -1,4 +1,8 @@ /* Taken from Ted's losetup.c - Mitch */ +/* Added vfs mount options - aeb - 960223 */ +/* Removed lomount - aeb - 960224 */ + +#define PROC_DEVICES "/proc/devices" /* * losetup.c - setup and control loop devices @@ -8,71 +12,62 @@ #include #include #include +#include #include #include #include -#include -#include "loop.h" +#include -char *crypt_name (int); -int crypt_type (char *); -void show_loop (char *); -int del_loop (const char *); -int set_loop (const char *, const char *, int offset, char *); -int lomount (const char *, const char *, const char *, char **, - int *, char **, char **); +#if defined(__GLIBC__) +#define _SOCKETBITS_H +#endif /* __GLIBC */ +#include "sundries.h" /* for xstrdup */ +#include "loop.h" +#include "lomount.h" +#ifdef LOOP_SET_FD struct crypt_type_struct { int id; char *name; } crypt_type_tbl[] = { - - { - LO_CRYPT_NONE, "no" - }, - { - LO_CRYPT_NONE, "none" - }, - { - LO_CRYPT_XOR, "xor" - }, - { - LO_CRYPT_DES, "DES" - }, - { - -1, NULL - } + { LO_CRYPT_NONE, "no" }, + { LO_CRYPT_NONE, "none" }, + { LO_CRYPT_XOR, "xor" }, + { LO_CRYPT_DES, "DES" }, + { -1, NULL } }; -char * -crypt_name (int id) +static int +crypt_type (const char *name) { int i; - for (i = 0; crypt_type_tbl[i].id != -1; i++) - if (id == crypt_type_tbl[i].id) - return crypt_type_tbl[i].name; - return "undefined"; + if (name) + for (i = 0; crypt_type_tbl[i].id != -1; i++) + if (!strcasecmp (name, crypt_type_tbl[i].name)) + return crypt_type_tbl[i].id; + return -1; } -int -crypt_type (char *name) +#if 0 +static char * +crypt_name (int id) { int i; for (i = 0; crypt_type_tbl[i].id != -1; i++) - if (!strcasecmp (name, crypt_type_tbl[i].name)) - return crypt_type_tbl[i].id; - return -1; + if (id == crypt_type_tbl[i].id) + return crypt_type_tbl[i].name; + return "undefined"; } -void +static void show_loop (char *device) { struct loop_info loopinfo; int fd; - if ((fd = open (device, O_RDWR)) < 0) { + if ((fd = open (device, O_RDONLY)) < 0) { fprintf(stderr, "loop: can't open device %s: %s\n", device, strerror (errno)); return; @@ -89,24 +84,97 @@ show_loop (char *device) crypt_name (loopinfo.lo_encrypt_type)); close (fd); } +#endif + +char * +find_unused_loop_device (void) +{ + /* Just creating a device, say in /tmp, is probably a bad idea - + people might have problems with backup or so. + So, we just try /dev/loop[0-7]. */ + char dev[20]; + int i, fd, somedev = 0, someloop = 0, loop_known = 0; + struct stat statbuf; + struct loop_info loopinfo; + FILE *procdev; + + for(i = 0; i < 256; i++) { + sprintf(dev, "/dev/loop%d", i); + if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { + somedev++; + fd = open (dev, O_RDONLY); + if (fd >= 0) { + if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == 0) + someloop++; /* in use */ + else if (errno == ENXIO) { + close (fd); + return xstrdup(dev); /* probably free */ + } + close (fd); + } + continue; /* continue trying as long as devices exist */ + } + if (i >= 7) + break; + } + + /* Nothing found. Why not? */ + if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) { + char line[100]; + while (fgets (line, sizeof(line), procdev)) + if (strstr (line, " loop\n")) { + loop_known = 1; + break; + } + fclose(procdev); + if (!loop_known) + loop_known = -1; + } + + if (!somedev) + error("mount: could not find any device /dev/loop#"); + else if(!someloop) { + if (loop_known == 1) + error( +"mount: Could not find any loop device.\n" +" Maybe /dev/loop# has a wrong major number?\n"); + else if (loop_known == -1) + error( +"mount: Could not find any loop device, and, according to %s,\n" +" this kernel does not know about the loop device.\n" +" (If so, then recompile or `insmod loop.o'.)\n", PROC_DEVICES); + else + error( +"mount: Could not find any loop device. Maybe this kernel does not know\n" +" about the loop device (then recompile or `insmod loop.o'), or\n" +" maybe /dev/loop# has the wrong major number?\n"); + } else + error("mount: could not find any free loop device"); + return 0; +} int -set_loop (const char *device, const char *file, int offset, char *encryption) +set_loop (const char *device, const char *file, int offset, + const char *encryption, int *loopro) { struct loop_info loopinfo; - int fd, - ffd, - i; + int fd, ffd, mode, i; char *pass; - if ((fd = open (device, O_RDWR)) < 0) { - perror (device); - return 1; + mode = (*loopro ? O_RDONLY : O_RDWR); + if ((ffd = open (file, mode)) < 0) { + if (!*loopro && errno == EROFS) + ffd = open (file, mode = O_RDONLY); + if (ffd < 0) { + perror (file); + return 1; + } } - if ((ffd = open (file, O_RDWR)) < 0) { - perror (file); + if ((fd = open (device, mode)) < 0) { + perror (device); return 1; } + *loopro = (mode == O_RDONLY); memset (&loopinfo, 0, sizeof (loopinfo)); strncpy (loopinfo.lo_name, file, LO_NAME_SIZE); loopinfo.lo_name[LO_NAME_SIZE - 1] = 0; @@ -159,6 +227,8 @@ set_loop (const char *device, const char *file, int offset, char *encryption) } close (fd); close (ffd); + if (verbose > 1) + printf("set_loop(%s,%s,%d): success\n", device, file, offset); return 0; } @@ -173,51 +243,39 @@ del_loop (const char *device) return 1; } if (ioctl (fd, LOOP_CLR_FD, 0) < 0) { -#if 0 perror ("ioctl: LOOP_CLR_FD"); -#endif return 1; } + close (fd); + if (verbose > 1) + printf("del_loop(%s): success\n", device); return 0; } +#else /* no LOOP_SET_FD defined */ +static void +mutter(void) { + fprintf(stderr, + "This mount was compiled without loop support. Please recompile.\n"); +} -int -lomount (const char *spec, const char *node, const char *device, char **type, - int *flags, char **extra_opts, char **mount_opts) -{ - char *opt, - *opteq; - int val; - char *encryption = NULL, *vfs = NULL; - int offset = 0, err; - char new_opts[1024]; - - for (opt = strtok (*extra_opts, ","); opt; opt = strtok (NULL, ",")) { - if ((opteq = strchr (opt, '='))) { - val = atoi (opteq + 1); - *opteq = '\0'; - if (!strcmp (opt, "encryption")) - encryption = strdup(opteq + 1); - else if (!strcmp (opt, "vfs")) - vfs = strdup(opteq + 1); - else if (!strcmp (opt, "offset")) - offset = val; - else { - printf ("unknown loop mount parameter: " - "%s=%d (%s)\n", opt, val, opteq+1); - return 1; - } - } else { - printf ("unknown loop mount parameter: " - "%s\n", opt); - return 1; - } - } - err = set_loop (device, spec, offset, encryption); - sprintf(new_opts, "vfs=%s,offset=%d,encryption=%s", - *type = vfs ? vfs : FSTYPE_DEFAULT, offset, - encryption=crypt_type(encryption)<0?"none":encryption); - *extra_opts=strdup(new_opts); - return err; +int +set_loop (const char *device, const char *file, int offset, + const char *encryption, int *loopro) { + mutter(); + return 1; +} + +int +del_loop (const char *device) { + mutter(); + return 1; } + +char * +find_unused_loop_device (void) { + mutter(); + return 0; +} + +#endif diff --git a/mount/lomount.h b/mount/lomount.h new file mode 100644 index 00000000..00a49f55 --- /dev/null +++ b/mount/lomount.h @@ -0,0 +1,4 @@ +extern int verbose; +extern int set_loop (const char *, const char *, int, const char *, int *); +extern int del_loop (const char *); +extern char * find_unused_loop_device (void); diff --git a/mount/losetup.8 b/mount/losetup.8 new file mode 100644 index 00000000..c2e41307 --- /dev/null +++ b/mount/losetup.8 @@ -0,0 +1,87 @@ +.TH LOSETUP 8 "Nov 24 1993" "Linux" "MAINTENANCE COMMANDS" +.SH NAME +losetup \- set up and control loop devices +.SH SYNOPSIS +.ad l +.B losetup +[ +.B \-e +.I encryption +] [ +.B \-o +.I offset +] +.I loop_device file +.br +.B losetup +[ +.B \-d +] +.I loop_device +.ad b +.SH DESCRIPTION +.B losetup +is used to associate loop devices with regular files or block devices, +to detach loop devices and to query the status of a loop device. If only the +\fIloop_device\fP argument is given, the status of the corresponding loop +device is shown. +.SH OPTIONS +.IP \fB\-d\fP +detach the file or device associated with the specified loop device. +.IP "\fB\-e \fIencryption\fP" +.RS +enable data encryption. The following keywords are recognized: +.IP \fBNONE\fP +use no encryption (default). +.PD 0 +.IP \fBXOR\fP +use a simple XOR encryption. +.IP \fBDES\fP +use DES encryption. DES encryption is only available if the optional +DES package has been added to the kernel. DES encryption uses an additional +start value that is used to protect passwords against dictionary +attacks. +.PD +.RE +.IP "\fB\-o \fIoffset\fP" +the data start is moved \fIoffset\fP bytes into the specified file or +device. +.SH FILES +.nf +/dev/loop0,/dev/loop1,... loop devices (major=7) +.fi +.SH EXAMPLE +If you are using the loadable module you must have the module loaded +first with the command +.IP +# insmod loop.o +.LP +The following commands can be used as an example of using the loop device. +.nf +.IP +dd if=/dev/zero of=/file bs=1k count=100 +losetup -e des /dev/loop0 /file +Password: +Init (up to 16 hex digits): +mkfs -t ext2 /dev/loop0 100 +mount -t ext2 /dev/loop0 /mnt + ... +umount /dev/loop0 +losetup -d /dev/loop0 +.fi +.LP +If you are using the loadable module you may remove the module with +the command +.IP +# rmmod loop +.LP +.fi +.SH RESTRICTION +DES encryption is painfully slow. On the other hand, XOR is terribly weak. +.SH AUTHORS +.nf +Original version: Theodore Ts'o +Maintained by: Werner Almesberger +Original DES by: Eric Young +Modularized and updated 28-5-94: Mitch DSouza +.fi diff --git a/mount/losetup.c b/mount/losetup.c new file mode 100644 index 00000000..ae5886ac --- /dev/null +++ b/mount/losetup.c @@ -0,0 +1,225 @@ +/* + * losetup.c - setup and control loop devices + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "loop.h" +#include "lomount.h" + +#ifdef LOOP_SET_FD + +static char *progname; + +struct crypt_type_struct { + int id; + char *name; +} crypt_type_tbl[] = { + { LO_CRYPT_NONE,"no" }, + { LO_CRYPT_NONE,"none" }, + { LO_CRYPT_XOR, "xor" }, + { LO_CRYPT_DES, "DES" }, + { -1, NULL } +}; + + +static char *crypt_name(int id) +{ + int i; + + for (i = 0; crypt_type_tbl[i].id != -1; i++) + if (id == crypt_type_tbl[i].id) + return crypt_type_tbl[i].name; + return "undefined"; +} + + +static int crypt_type(const char *name) +{ + int i; + + for (i = 0; crypt_type_tbl[i].id != -1; i++) + if (!strcasecmp(name, crypt_type_tbl[i].name)) + return crypt_type_tbl[i].id; + return -1; +} + + +static void show_loop(const char *device) +{ + struct loop_info loopinfo; + int fd; + + if ((fd = open(device, O_RDWR)) < 0) { + perror(device); + return; + } + if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) { + perror("Cannot get loop info"); + close(fd); + return; + } + printf("%s: [%04x]:%ld (%s) offset %d, %s encryption\n", + device, loopinfo.lo_device, loopinfo.lo_inode, + loopinfo.lo_name, loopinfo.lo_offset, + crypt_name(loopinfo.lo_encrypt_type)); + close(fd); +} + + +int set_loop(const char *device, const char *file, int offset, + const char *encryption, int *loopro) +{ + struct loop_info loopinfo; + int fd, ffd, mode, i; + char *pass; + + mode = *loopro ? O_RDONLY : O_RDWR; + if ((ffd = open (file, mode)) < 0 && !*loopro + && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { + perror (file); + return 1; + } + if ((fd = open (device, mode)) < 0) { + perror (device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE-1] = 0; + if (encryption && (loopinfo.lo_encrypt_type = crypt_type(encryption)) + < 0) { + fprintf(stderr,"Unsupported encryption type %s",encryption); + exit(1); + } + loopinfo.lo_offset = offset; + switch (loopinfo.lo_encrypt_type) { + case LO_CRYPT_NONE: + loopinfo.lo_encrypt_key_size = 0; + break; + case LO_CRYPT_XOR: + pass = getpass("Password: "); + strncpy(loopinfo.lo_encrypt_key, pass, LO_KEY_SIZE); + loopinfo.lo_encrypt_key[LO_KEY_SIZE-1] = 0; + loopinfo.lo_encrypt_key_size = strlen(loopinfo.lo_encrypt_key); + break; + case LO_CRYPT_DES: + pass = getpass("Password: "); + strncpy(loopinfo.lo_encrypt_key, pass, 8); + loopinfo.lo_encrypt_key[8] = 0; + loopinfo.lo_encrypt_key_size = 8; + pass = getpass("Init (up to 16 hex digits): "); + for (i = 0; i < 16 && pass[i]; i++) + if (isxdigit(pass[i])) + loopinfo.lo_init[i >> 3] |= (pass[i] > '9' ? + (islower(pass[i]) ? toupper(pass[i]) : + pass[i])-'A'+10 : pass[i]-'0') << (i & 7)*4; + else { + fprintf(stderr,"Non-hex digit '%c'.\n",pass[i]); + exit(1); + } + break; + default: + fprintf(stderr, + "Don't know how to get key for encryption system %d\n", + loopinfo.lo_encrypt_type); + exit(1); + } + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + exit(1); + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror("ioctl: LOOP_SET_STATUS"); + exit(1); + } + close(fd); + close(ffd); + return 0; +} + +int del_loop(const char *device) +{ + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) { + perror(device); + exit(1); + } + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + perror("ioctl: LOOP_CLR_FD"); + exit(1); + } + return(0); +} + + +static int usage(void) +{ + fprintf(stderr, "usage:\n\ + %s loop_device # give info\n\ + %s -d loop_device # delete\n\ + %s [ -e encryption ] [ -o offset ] loop_device file # setup\n", + progname, progname, progname); + exit(1); +} + +int main(int argc, char **argv) +{ + char *offset,*encryption; + int delete,off,c; + int ro = 0; + + delete = off = 0; + offset = encryption = NULL; + progname = argv[0]; + while ((c = getopt(argc,argv,"de:o:")) != EOF) { + switch (c) { + case 'd': + delete = 1; + break; + case 'e': + encryption = optarg; + break; + case 'o': + offset = optarg; + break; + default: + usage(); + } + } + if (argc == 1) usage(); + if ((delete && (argc != optind+1 || encryption || offset)) || + (!delete && (argc < optind+1 || argc > optind+2))) + usage(); + if (argc == optind+1) + if (delete) + del_loop(argv[optind]); + else + show_loop(argv[optind]); + else { + if (offset && sscanf(offset,"%d",&off) != 1) + usage(); + set_loop(argv[optind],argv[optind+1],off,encryption,&ro); + } + return 0; +} + +#else /* LOOP_SET_FD not defined */ + +int main(int argc, char **argv) { + fprintf(stderr, + "No loop support was available at compile time. Please recompile.\n"); + return -1; +} +#endif diff --git a/mount/mount.8 b/mount/mount.8 index 4c197f46..e1ed6f4a 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -1,111 +1,237 @@ -.\" Copyright (c) 1980, 1989, 1991 The Regents of the University of California. -.\" All rights reserved. +.\" Copyright (c) 1996 Andries Brouwer .\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. +.\" This page is somewhat derived from a page that was +.\" (c) 1980, 1989, 1991 The Regents of the University of California +.\" and had been heavily modified by Rik Faith and myself. +.\" (Probably no BSD text remains.) +.\" Fragments of text were written by Werner Almesberger, Remy Card, +.\" Stephen Tweedie and Eric Youngdale. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. .\" -.\" @(#)mount.8 6.17 (Berkeley) 8/5/91 +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. .\" -.\" When you change this file, please add an update notice to the ones below: +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. .\" -.\" Sun Dec 27 12:10:38 1992: Updated by faith@cs.unc.edu -.\" Thu Jan 14 21:15:06 1993: Updated by faith@cs.unc.edu -.\" Mon Feb 1 21:18:21 1993: Updated by faith@cs.unc.edu -.\" Sat Mar 6 20:46:29 1993: Updated by faith@cs.unc.edu -.\" Sat Oct 9 08:56:26 1993: Updated by faith@cs.unc.edu -.\" based on changes by Stephen Tweedie (sct@dcs.ed.ac.uk) -.\" Sat Oct 9 08:59:46 1993: Converted to man format by faith@cs.unc.edu -.\" Sat Nov 27 20:04:28 1993: File-system specific options documented by Rik -.\" Faith (faith@cs.unc.edu), using extensive additions taken from -.\" documentation written by Werner Almesberger -.\" (almesber@nessie.cs.id.ethz.ch), and email written by Eric -.\" Youngdale (eric@tantalus.nrl.navy.mil) and Remy Card -.\" (Remy.Card@masi.ibp.fr). -.\" Sun Apr 24 19:25:59 1994: Updated per information supplied by Remy Card. -.\" Thu Jul 14 07:44:36 1994: Updated absence of -t option. -.\" (faith@cs.unc.edu) -.\" Thu Jul 14 07:49:14 1994: Updated list of valid filesystems. -.\" Wed Feb 8 09:25:48 1995: Updated man pages for Mike Grupenhoff's changes. -.\" Sat Jul 22 01:45:58 1995: Updated list of binary extensions for -.\" msdos conversion. (sl14@cornell.edu) -.\" Wed Jul 26 00:00:00 1995: Updated by Martin Schulze. -.\" (joey@infodrom.north.de) -.\" Tue Sep 26 12:02:03 1995: Updated umount, nfs, proc parts of page. -.\" (aeb@cwi.nl) +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. .\" -.TH MOUNT 8 "26 September 1995" "Linux 1.3" "Linux Programmer's Manual" +.\" 960705, aeb: version for mount-2.5k +.\" 970114, aeb: xiafs and ext are dead; romfs is new +.\" 970623, aeb: -F option +.\" +.TH MOUNT 8 "5 July 1996" "Linux 2.0" "Linux Programmer's Manual" .SH NAME -mount, umount \- mount and dismount file systems +mount \- mount a file system .SH SYNOPSIS -.BI "mount [\-afrwuvn] [\-t " vfstype ] +.BI "mount [\-hV]" +.LP +.BI "mount \-a [\-fFnrvw] [\-t " vfstype ] .br -.BI "mount [\-frwuvn] [\-o " remount " [,...]] " "special " | " node" +.BI "mount [\-fnrvw] [\-o " options " [,...]] " "device " | " dir" .br -.BI "mount [\-frwun] [\-t " vfstype "] [\-o " options "] " "special node" +.BI "mount [\-fnrvw] [\-t " vfstype "] [\-o " options "] " "device dir" +.SH DESCRIPTION +All files accessible in a Unix system are arranged in one big +tree, the file hierarchy, rooted at +.BR / . +These files can be spread out over several devices. The +.B mount +command serves to attach the file system found on some device +to the big file tree. Conversely, the +.BR umount (8) +command will detach it again. + +The standard form of the +.B mount +command, is +.RS +.br +.BI "mount \-t" " type device dir" +.RE +This tells the kernel to attach the file system found on +.I device +(which is of type +.IR type ) +at the directory +.IR dir . +The previous contents (if any) and owner and mode of +.I dir +become invisible, and as long as this file system remains mounted, +the pathname +.I dir +refers to the root of the file system on +.IR device . + +Three forms of invocation do not actually mount anything: +.RS .br -.BI "umount [\-ahvV] [\-t " vfstype ] +.B "mount \-h" +.RE +prints a help message; +.RS .br -.BI "umount [\-v] " "special " | " node " [...] -.\" " for hilit19 -.SH DESCRIPTION +.B "mount \-V" +.RE +prints a version string; and just +.RS +.BI "mount [-t" " type" ] +.RE +lists all mounted file systems (of type +.IR type ) +- see below. + The -.B mount -command calls the -.BR mount (2) -system call to prepare and graft a -.I special -device on to the file system tree at the point -.IR node . -If either -.IR special " or " node -are not provided, the appropriate information is taken from the -.BR fstab (5) -file. The .I proc file system is not associated with a special device, and when mounting it, an arbitrary keyword, such as .I proc -can be used instead of a path or -.I node -specification. (The customary choice +can be used instead of a device specification. +(The customary choice .I none -is less fortunate: the error message `none busy' from umount +is less fortunate: the error message `none busy' from +.B umount can be confusing.) -The system maintains a list of currently mounted file systems. If no -arguments are given to +Most devices are indicated by a file name (of a block special device), like +.IR /dev/sda1 , +but there are other possibilities. For example, in the case of an NFS mount, +.I device +may look like +.IR knuth.cwi.nl:/dir . + +The file +.I /etc/fstab +(see +.BR fstab (5)), +may contain lines describing what devices are usually +mounted where, using which options. This file is used in three ways: +.LP +(i) The command +.RS +.br +.BI "mount \-a [-t" " type" ] +.RE +(usually given in a bootscript) causes all file systems mentioned in +.I fstab +(of the proper type) to be mounted as indicated, except for those +whose line contains the +.B noauto +keyword. Adding the +.B \-F +option will make mount fork, so that the +filesystems are mounted simultaneously. +.LP +(ii) When mounting a file system mentioned in +.IR fstab , +it suffices to give only the device, or only the mount point. +.LP +(iii) Normally, only the superuser can mount file systems. +However, when +.I fstab +contains the +.B user +option on a line, then anybody can mount the corresponding system. +.LP +Thus, given a line +.RS +.br +.B "/dev/cdrom /cd iso9660 ro,user,noauto,unhide" +.RE +any user can mount the iso9660 file system found on his CDROM +using the command +.RS +.br +.B "mount /dev/cdrom" +.RE +or +.RS +.br +.B "mount /cd" +.RE +For more details, see +.BR fstab (5). + +The programs +.B mount +and +.B umount +maintain a list of currently mounted file systems in the file +.IR /etc/mtab . +If no arguments are given to .BR mount , this list is printed. +When the +.I proc +filesystem is mounted (say at +.IR /proc ), +the files +.I /etc/mtab +and +.I /proc/mounts +have very similar contents. The former has somewhat +more information, such as the mount options used, +but is not necessarily up-to-date (cf. the +.B \-n +option below). It is possible to replace +.I /etc/mtab +by a symbolic link to +.IR /proc/mounts , +but some information is lost that way, and in particular +working with the loop device will be less convenient. + +.SH OPTIONS +The full set of options used by an invocation of +.B mount +is determined by first extracting the +options for the file system from the +.I fstab +table, then applying any options specified by the +.B \-o +argument, and finally applying a +.BR \-r " or " \-w +option, when present. Options available for the .B mount command: .TP +.B \-V +Output version. +.TP +.B \-h +Print a help message. +.TP +.B \-v +Verbose mode. +.TP +.B \-a +Mount all filesystems (of the given types) mentioned in +.IR fstab . +.TP +.B \-F +(Used in conjunction with +.BR \-a .) +Fork off a new incarnation of mount for each device. +This will do the mounts on different devices in parallel. +This has the advantage that it is faster; also NFS timeouts go in +parallel. A disadvantage is that the mounts are done in undefined order. +Thus, you cannot use this option if you want to mount both +.I /usr +and +.IR /usr/spool . +.TP .B \-f Causes everything to be done except for the actual system call; if it's not obvious, this ``fakes'' mounting the file system. This option is useful in @@ -113,14 +239,94 @@ conjunction with the .B \-v flag to determine what the .B mount -command is trying to do. +command is trying to do. It can also be used to add entries for devices +that were mounted earlier with the -n option. +.TP +.B \-n +Mount without writing in +.IR /etc/mtab . +This is necessary for example when +.I /etc +is on a read-only file system. +.TP +.B \-r +Mount the file system read-only. A synonym is +.BR "\-o ro" . +.TP +.B \-w +Mount the file system read/write. This is the default. A synonym is +.BR "\-o rw" . +.TP +.BI \-t " vfstype" +The argument following the +.B \-t +is used to indicate the file system type. The file system types which are +currently supported are listed in +.IR linux/fs/filesystems.c : +.IR minix ", " ext ", " ext2 ", " xiafs ", " hpfs , +.IR msdos ", " umsdos ", " vfat , +.IR proc ", " nfs ", " iso9660 ", " smbfs ", " ncpfs , +.IR affs ", " ufs ", " romfs , +.IR sysv ", " xenix ", " coherent . +Note that the last three are equivalent and that +.I xenix +and +.I coherent +will be removed at some point in the future \(em use +.I sysv +instead. Since kernel version 2.1.21 the types +.I ext +and +.I xiafs +do not exist anymore. + +The type +.I iso9660 +is the default. If no +.B \-t +option is given, or if the +.B auto +type is specified, the superblock is probed for the filesystem type +.RI ( minix ", " ext ", " ext2 ", " xiafs ", " iso9660 ", " romfs +are supported). +If this probe fails and +.I /proc/filesystems +exists, then all of the filesystems listed there will be tried, +except for those that are labeled "nodev" (e.g., +.I proc +and +.IR nfs ). + +Note that the +.B auto +type may be useful for user-mounted floppies. +Warning: the probing uses a heuristic (the presence of appropriate `magic'), +and could recognize the wrong filesystem type. + +More than one type may be specified in a comma separated +list. The list of file system types can be prefixed with +.B no +to specify the file system types on which no action should be taken. +(This can be meaningful with the +.B \-a +option.) + +For example, the command: +.RS +.RS +.B "mount \-a \-t nomsdos,ext" +.RE +mounts all file systems except those of type +.I msdos +and +.IR ext . +.RE .TP .B \-o Options are specified with a .B \-o flag followed by a comma separated string of options. -.B N.B., -many of these options are only useful when they appear in the +Some of these options are only useful when they appear in the .I /etc/fstab file. The following options apply to any file system that is being mounted: @@ -129,6 +335,9 @@ mounted: .B async All I/O to the file system should be done asynchronously. .TP +.B atime +Update inode access time for each access. This is the default. +.TP .B auto Can be mounted with the .B \-a @@ -144,6 +353,10 @@ Interpret character or block special devices on the file system. .B exec Permit execution of binaries. .TP +.B noatime +Do not update inode access times on this file system (e.g, for faster +access on the news spool to speed up news servers). +.TP .B noauto Can only be mounted explicitly (i.e., the .B \-a @@ -151,12 +364,11 @@ option will not cause the file system to be mounted). .TP .B nodev Do not interpret character or block special devices on the file -system. This options is useful for a server that has file systems -containing special devices for architectures other than its own. +system. .TP .B noexec Do not allow execution of any binaries on the mounted file system. -This options is useful for a server that has file systems containing +This option might be useful for a server that has file systems containing binaries for architectures other than its own. .TP .B nosuid @@ -165,6 +377,7 @@ effect. .TP .B nouser Forbid an ordinary (i.e., non-root) user to mount the file system. +This is the default. .TP .B remount Attempt to remount an already-mounted file system. This is commonly @@ -185,210 +398,294 @@ effect. All I/O to the file system should be done synchronously. .TP .B user -Allow an ordinary user to mount the file system. Ordinary users always -have the following options activated: +Allow an ordinary user to mount the file system. This option implies +the options .BR noexec ", " nosuid ", and " nodev -(unless overridden by the superuser by using, for example, the following -option line: -.BR user,exec,dev,suid . -.PP -The following options apply only to certain file systems: +(unless overridden by subsequent options, as in the option line +.BR user,exec,dev,suid ). +.RE + +.SH "FILESYSTEM SPECIFIC MOUNT OPTIONS" +The following options apply only to certain file systems. +We sort them by file system. They all follow the +.B \-o +flag. + +.SH "Mount options for affs" .TP -.BI case= value -For the -.I hpfs -file system, specify case as -.I lower +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +Set the owner and group of the root of the file system (default: uid=gid=0, +but with option +.B uid or -.IR asis . -.TP -.BI check= value -Tells the -.I ext2 -file sysem kernel code to do some more checks while the file system is -mounted. Currently (1.3.11), the following values can be specified with -this option: -.RS +.B gid +without specified value, the uid and gid of the current process are taken). .TP -.I none -no extra check is performed by the kernel code +\fBsetuid=\fP\fIvalue\fP and \fBsetgid=\fP\fIvalue\fP +Set the owner and group of all files. +.TP +.BI mode= value +Set the mode of all files to +.IR value " & 0777" +disregarding the original permissions. +Add search permission to directories that have read permission. +The value is given in octal. +.TP +.B protect +Do not allow any changes to the protection bits on the file system. +.TP +.B usemp +Set uid and gid of the root of the file system to the uid and gid +of the mount point upon the first sync or umount, and then +clear this option. Strange... +.TP +.B verbose +Print an informational message for each successful mount. +.TP +.BI prefix= string +Prefix used before volume name, when following a link. +.TP +.BI volume= string +Prefix (of length at most 30) used before '/' when following a symbolic link. +.TP +.BI reserved= value +(Default: 2.) Number of unused blocks at the start of the device. +.TP +.BI root= value +Give explicitly the location of the root block. .TP -.I normal -The inodes and blocks bitmaps are checked when the file system is mounted -(this is the default) +.BI bs= value +Give blocksize. Allowed values are 512, 1024, 2048, 4096. .TP -.I strict -In addition to the -.I normal -checks, block deallocation checks that the block to free is in the data -zone. +.BR grpquota " / " noquota " / " quota " / " usrquota +These options are accepted but ignored. + +.SH "Mount options for coherent" +None. + +.SH "Mount options for ext" +None. +Note that the `ext' file system is obsolete. Don't use it. +Since Linux version 2.1.21 extfs is no longer part of the kernel source. + +.SH "Mount options for ext2" +The `ext2' file system is the standard Linux file system. +Due to a kernel bug, it may be mounted with random mount options +(fixed in Linux 2.0.4). +.TP +.BR bsddf " / " minixdf +Set the behaviour for the +.I statfs +system call. The +.B minixdf +behaviour is to return in the +.I f_blocks +field the total number of blocks of the file system, while the +.B bsddf +behaviour (which is the default) is to subtract the overhead blocks +used by the ext2 file system and not available for file storage. Thus .RE +.nf + +% mount /k -o minixdf; df /k; umount /k +Filesystem 1024-blocks Used Available Capacity Mounted on +/dev/sda6 2630655 86954 2412169 3% /k +% mount /k -o bsddf; df /k; umount /k +Filesystem 1024-blocks Used Available Capacity Mounted on +/dev/sda6 2543714 13 2412169 0% /k + +.fi +(Note that this example shows that one can add command line options +to the options given in +.IR /etc/fstab .) + .TP -.BI check= value -For the -.I msdos -file system, three different levels of pickyness can be chosen: +.BR check " / " check=normal " / " check=strict +Set checking level. When at least one of these options is set (and +.B check=normal +is set by default) the inodes and blocks bitmaps are checked upon mount +(which can take half a minute or so on a big disk). +With strict checking, block deallocation checks that the block to free +is in the data zone. +.TP +.BR check=none " / " nocheck +No checking is done. +.TP +.B debug +Print debugging info upon each (re)mount. +.TP +.BR errors=continue " / " errors=remount-ro " / " errors=panic +Define the behaviour when an error is encountered. +(Either ignore errors and just mark the file system erroneous and continue, +or remount the file system read-only, or panic and halt the system.) +The default is set in the filesystem superblock, and can be +changed using +.BR tune2fs (8). +.TP +.BR grpid " or " bsdgroups " / " nogrpid " or " sysvgroups +These options define what group id a newly created file gets. +When +.BR grpid +is set, it takes the group id of the directory in which it is created; +otherwise (the default) it takes the fsgid of the current process, unless +the directory has the setgid bit set, in which case it takes the gid +from the parent directory, and also gets the setgid bit set +if it is a directory itself. +.TP +\fBresgid=\fP\fIn\fP and \fBresuid=\fP\fIn\fP +The ext2 file system reserves a certain percentage of the available +space (by default 5%, see +.BR mke2fs (8) +and +.BR tune2fs (8)). +These options determine who can use the reserved blocks. +(Roughly: whoever has the specified uid, or belongs to the specified group.) +.TP +.BI sb= n +Instead of block 1, use block +.I n +as superblock. This could be useful when the filesystem has been damaged. +Usually, copies of the superblock are found every 8192 blocks: in +block 1, 8193, 16385, ... +(Thus, one gets hundreds or even thousands of copies of the superblock +on a big filesystem. I do not know of options to mke2fs that would +cause fewer copies to be written.) +.TP +.BR grpquota " / " noquota " / " quota " / " usrquota +These options are accepted but ignored. + +.SH "Mount options for fat" +(Note: +.I fat +is not a separate filesystem, but a common part of the +.IR msdos , +.I umsdos +and +.I vfat +filesystems.) +.TP +.BR blocksize=512 " / " blocksize=1024 +Set blocksize (default 512). +.TP +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +Set the owner and group of all files. (Default: the uid and gid +of the current process.) +.TP +.BI umask= value +Set the umask (the bitmask of the permissions that are +.B not +present). The default is the umask of the current process. +The value is given in octal. +.TP +.BI check= value +Three different levels of pickyness can be chosen: .RS .TP -.I relaxed +.B r[elaxed] Upper and lower case are accepted and equivalent, long name parts are -truncated (e.g. verlongname.foobar becomes verylong.foo), leading and -embedded spaces are accepted in each name part (name and extension). +truncated (e.g. +.I verylongname.foobar +becomes +.IR verylong.foo ), +leading and embedded spaces are accepted in each name part (name and extension). .TP -.I normal +.B n[ormal] Like "relaxed", but many special characters (*, ?, <, spaces, etc.) are rejected. This is the default. .TP -.I strict +.B s[trict] Like "normal", but names may not contain long parts and special characters that are sometimes used on Linux, but are not accepted by MS-DOS are rejected. (+, =, spaces, etc.) .RE .TP -.BI conv= value -For the -.IR msdos , -.IR hpfs , -and -.I iso9660 -file systems, specify file conversion as -.IR binary ", " text ", or " auto . +.BR conv=b[inary] " / " conv=t[ext] " / " conv=a[uto] The -.I iso9660 -file system also allows -.I value -to be -.IR mtext . - -The -.I msdos +.I fat file system can perform CRLF<-->NL (MS-DOS text format to UNIX text format) conversion in the kernel. The following conversion modes are available: .RS .TP -.I binary +.B binary no translation is performed. This is the default. .TP -.I text +.B text CRLF<-->NL translation is performed on all files. .TP -.I auto +.B auto CRLF<-->NL translation is performed on all files that don't have a "well-known binary" extension. The list of known extensions can be found at the beginning of -.I fs/msdos/misc.c -(as of 1.3.11, the list is: exe, com, bin, app, sys, drv, ovl, ovr, obj, +.I fs/fat/misc.c +(as of 2.0, the list is: exe, com, bin, app, sys, drv, ovl, ovr, obj, lib, dll, pif, arc, zip, lha, lzh, zoo, tar, z, arj, tz, taz, tzp, tpz, gz, tgz, deb, gif, bmp, tif, gl, jpg, pcx, tfm, vf, gf, pk, pxl, dvi). .PP Programs that do computed lseeks won't like in-kernel text conversion. Several people have had their data ruined by this translation. Beware! -For file systems mounted in -.B binary -mode, a conversion tool (fromdos/todos) is available. +For file systems mounted in binary mode, a conversion tool +(fromdos/todos) is available. .RE .TP -.BI block= value -For the -.I iso9660 -file system, set the blocksize. -.TP -.B bsdgroups -See -.B grpid -.TP -.B cruft -For the -.I iso9660 -file system, set the -.I cruft -flag to 'y'. This option is available because there are buggy premastering -programs out there that leave junk in the top byte of the file size. This -option clears the top byte, but restricts files to 16Mb maximum in the -process. -.TP .B debug -For the -.I msdos -file system, turn on the +Turn on the .I debug flag. A version string and a list of file system parameters will be printed (these data are also printed if the parameters appear to be inconsistent). .TP -.B debug -For the -.I ext2fs -file system, causes the kernel code to display the file system parameters -when the file system is mounted. -.TP -.BI errors= value -For the -.I ext2fs -file system, specifies the error behavior: -.RS -.TP -.B continue -No special action is taken on errors (except marking the file system as -erroneous). This is the default. -.TP -.B remount +.BR fat=12 " / " fat=16 +Specify either a 12 bit fat or a 16 bit fat. This overrides +the automatic FAT type detection routine. Use with caution! .TP -.B ro -The file system is remounted read only, and subsequent writes are refused. +.B quiet +Turn on the +.I quiet +flag. Attempts to chown or chmod files do not return errors, +although they fail. Use with caution! .TP -.B panic -When an error is detected, the system panics. -.RE +.B "sys_immutable, showexec, dots, nodots, dotsOK=[yes|no]" +Various misguided attempts to force Unix or DOS conventions +onto a FAT file system. + +.SH "Mount options for hpfs" .TP -.BI fat= value -For the -.I msdos -file system, specify either a 12 bit fat or a 16 bit fat. This overrides -the automatic FAT type detection routine. Use with caution! +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +Set the owner and group of all files. (Default: the uid and gid +of the current process.) .TP -.BI gid= value -For the -.I msdos -and -.I hpfs -file systems, give every file a gid equal to -.IR value . -.TP -.B grpid -Causes the -.I ext2fs -to use the BSD behavior when creating files: file are created with the -group id of their parent directory. -.TP -.BI map= value -For the -.I iso9660 -file system, specify mapping as -.IR off " or " normal . -In general, non-Rock Ridge discs have all of the filenames in upper case, -and all of the filenames have a ";1" appended. The map option strips the -";1" and makes the name lower case. C.f. -.BR norock . +.BI umask= value +Set the umask (the bitmask of the permissions that are +.B not +present). The default is the umask of the current process. +The value is given in octal. +.TP +.BR case=lower " / " case=asis +Convert all files names to lower case, or leave them. +(Default: +.BR case=lower .) +.TP +.BR conv=binary " / " conv=text " / " conv=auto +For +.BR conv=text , +delete some random CRs (in particular, all followed by NL) +when reading a file. +For +.BR conv=auto , +choose more or less at random between +.BR conv=binary " and " conv=text . +For +.BR conv=binary , +just read what is in the file. This is the default. .TP .B nocheck -For the -.IR ext2fs , -turns of checking (see -.BR check=none ). -.TP -.B nogrpid -Causes the -.I ext2fs -to use the System V behaviour when creating files: files are created with -the group id of the creating process, unless the setgid bit is set on the -parent directory. This is the default for all Linux file systems. -.TP -.B norock +Do not abort mounting when certain consistency checks fail. + +.SH "Mount options for iso9660" Normal -.I iso9600 +.I iso9660 filenames appear in a 8.3 format (i.e., DOS-like restrictions on filename length), and in addition all characters are in upper case. Also there is no field for file ownership, protection, number of links, provision for @@ -399,186 +696,281 @@ features. Basically there are extensions to each directory record that supply all of the additional information, and when Rock Ridge is in use, the filesystem is indistinguishable from a normal UNIX file system (except that it is read-only, of course). - -The +.TP .B norock -switch disables the use of Rock Ridge extensions, even if available. C.f. +Disable the use of Rock Ridge extensions, even if available. Cf.\& .BR map . .TP -.B quiet -For the -.I msdos -file system, turn on the -.I quiet -flag. Attempts to chown or chmod files do not yield errors, although they -fail. Use with caution! -.TP -.B soft -For the -.IR nfs -file system this allows the kernel to time out if the nfs server is not -responding for some time, otherwise it will try forever. The time can be -specified with -.BR timeo=time . -For more information look at -.IR nfs (5). - -This option is useful if your nfs server sometimes doesn't respond or will -be rebooted while some process tries to get a file from the server. -.TP -.BI sb= value -For the -.I ext2 -file system, use an alternate superblock located at block -.IR value . -.I value -is numbered in 1024 bytes blocks. An -.I ext2 -file system usually has backups of the super block at blocks 1, 8193, 16385 -and so on. -.TP -.BI sysvgroups -See -.B nogrpid -.TP -.BI uid= value -For the -.I msdos +.BR check=r[elaxed] " / " check=s[trict] +With +.BR check=relaxed , +a filename is first converted to lower case before doing the lookup. +This is probably only meaningful together with +.B norock and -.I hpfs -file systems, give every file a uid equal to -.IR value . +.BR map=normal . +(Default: +.BR check=strict .) +.TP +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +Give all files in the file system the indicated user or group id, +possibly overriding the information found in the Rock Ridge extensions. +(Default: +.BR uid=0,gid=0 .) +.TP +.BR map=n[ormal] " / " map=o[ff] +For non-Rock Ridge volumes, normal name translation maps upper +to lower case ASCII, drops a trailing `;1', and converts `;' to `.'. +With +.B map=off +no name translation is done. See +.BR norock . +(Default: +.BR map=normal .) +.TP +.BI mode= value +For non-Rock Ridge volumes, give all files the indicated mode. +(Default: read permission for everybody.) +Since Linux 2.1.37 one no longer needs to specify the mode in +decimal. (Octal is indicated by a leading 0.) +.TP +.B unhide +Also show hidden and associated files. +.TP +.B block=[512|1024|2048] +Set the block size to the indicated value. +(Default: +.BR block=1024 .) +.TP +.BR conv=a[uto] " / " conv=b[inary] " / " conv=m[text] " / " conv=t[ext] +(Default: +.BR conv=binary .) +Since Linux 1.3.54 this option has no effect anymore. +(And non-binary settings used to be very dangerous, +often leading to silent data corruption.) .TP -.BI umask= value -For the -.I msdos -and -.I hpfs -file systems, give every file a umask of -.IR value . -The radix defaults to octal. -.PP -The full set of options applied is determined by first extracting the -options for the file system from the -.B fstab -table, then applying any options specified by the -.B \-o -argument, and finally applying the -.BR \-r " or " \-w -option. +.B cruft +If the high byte of the file length contains other garbage, +set this mount option to ignore the high order bits of the file length. +This implies that a file cannot be larger than 16MB. +The `cruft' option is set automatically if the entire CDROM +has a weird size (negative, or more than 800MB). It is also +set when volume sequence numbers other than 0 or 1 are seen. + +.SH "Mount options for minix" +None. +.SH "Mount options for msdos" +See mount options for fat. If the .I msdos file system detects an inconsistency, it reports an error and sets the file system read-only. The file system can be made writeable again by remounting it. -.RE -.TP -.B \-r -The file system object is to be mounted read-only. -.TP -.BI \-t " vfstype" -The argument following the -.B \-t -is used to indicate the file system type. The file system types which are -currently supported are listed in -.IR linux/fs/filesystems.c : -.IR minix ", " ext ", " ext2 ", " xiafs ", " msdos ", " umsdos , -.IR hpfs ", " proc ", " nfs ", " iso9660 ", " smbfs , -.IR sysv ", " xenix ", " coherent . -Note that that last three are equivalent and that "xenix" and "coherent" -will be removed at some point in the future \(em use "sysv" instead. -The type -.I minix -is the default. If no -.B \-t -option is given, or if the "auto" type is specified, the superblock is -probed for the filesystem type (minix, ext, ext2, xia are supported). If -this probe fails and -.I /proc/filesystems -exists, then all of the filesystems listed will be tried, -.I except -for those that are labeled "nodev" (e.g., "proc" and "nfs"). - -Note that the "auto" type may be useful for user-mounted floppies. - -For example, the +.SH "Mount options for ncp" +Just like +.IR nfs ", the " ncp +implementation expects a binary argument (a +.IR "struct ncp_mount_data" ) +to the mount system call. This argument is constructed by +.BR ncpmount (8) +and the current version of .B mount -command: -.RS +(2.6h) does not know anything about ncp. -.RS -mount -a -t nomsdos,ext -.RE +.SH "Mount options for nfs" +Instead of a textual option string, parsed by the kernel, the +.I nfs +file system expects a binary argument of type +.IR "struct nfs_mount_data" . +The program +.B mount +itself parses the following options of the form `tag=value', +and puts them in the structure mentioned: +.BI rsize= n, +.BI wsize= n, +.BI timeo= n, +.BI retrans= n, +.BI acregmin= n, +.BI acregmax= n, +.BI acdirmin= n, +.BI acdirmax= n, +.BI actimeo= n, +.BI retry= n, +.BI port= n, +.BI mountport= n, +.BI mounthost= name, +.BI mountprog= n, +.BI mountvers= n, +.BI nfsprog= n, +.BI nfsvers= n, +.BI namlen= n. +The option +.BI addr= n +is accepted but ignored. +Also the following Boolean options, possibly preceded by +.B no +are recognized: +.BR bg , +.BR fg , +.BR soft , +.BR hard , +.BR intr , +.BR posix , +.BR cto , +.BR ac , +.BR tcp , +.BR udp , +.BR lock . +For details, see +.BR nfs (5). -mounts all file systems except those of type -.I msdos -and -.IR ext . -.RE +Especially useful options include .TP -.B \-v -Verbose mode. +.B rsize=8192,wsize=8192 +This will make your nfs connection much faster than with the default +buffer size of 1024. .TP -.B \-w -The file system object is to be read and write. +.B hard +The program accessing a file on a NFS mounted file system will hang +when the server crashes. The process cannot be interrupted or +killed unless you also specify +.BR intr . +When the NFS server is back online the program will continue undisturbed +from where it was. This is probably what you want. .TP -.B \-n -Mount without writing in -.IR /etc/mtab . -.PP -.B Umount -removes the -.I special -device, or the device grafted at point -.IR node , -from the file system tree. - -Options for the -.B umount -command: +.B soft +This option allows the kernel to time out if the nfs server is not +responding for some time. The time can be +specified with +.BR timeo=time . +This option might be useful if your nfs server sometimes doesn't respond +or will be rebooted while some process tries to get a file from the server. +Usually it just causes lots of trouble. .TP -.B \-a -All of the file systems described in -.I /etc/mtab -are unmounted. +.B nolock +Do not use locking. Do not start lockd. + +.SH "Mount options for proc" .TP -.BI \-t " vfstype" -Is used to indicate the actions should only be taken on file systems of the -specified type. More than one type may be specified in a comma separated -list. The list of file system types can be prefixed with ``no'' to specify -the file system types on which no action should be taken. (See example -above for the +\fBuid=\fP\fIvalue\fP and \fBgid=\fP\fIvalue\fP +These options are recognized, but have no effect as far as I can see. + +.SH "Mount options for romfs" +None. + +.SH "Mount options for smbfs" +Just like +.IR nfs ", the " smb +implementation expects a binary argument (a +.IR "struct smb_mount_data" ) +to the mount system call. This argument is constructed by +.BR smbmount (8) +and the current version of .B mount -command.) -.TP -.B \-V -Print version and exit. -.TP -.B \-h -Print help message and exit. -.TP -.B \-v -Verbose mode. +(2.6c) does not know anything about smb. + +.SH "Mount options for sysv" +None. + +.SH "Mount options for ufs" +None. + +.SH "Mount options for umsdos" +See mount options for msdos. +The +.B dotsOK +option is explicitly killed by +.IR umsdos . + +.SH "Mount options for vfat" +First of all, the mount options for +.I fat +are recognized. +The +.B dotsOK +option is explicitly killed by +.IR vfat . +Furthermore, there are +.TP +.B uni_xlate +Translate unhandled Unicode characters to special escaped sequences. +This lets you backup and restore filenames that are created with any +Unicode characters. Without this option, a '?' is used when no +translation is possible. The escape character is ':' because it is +otherwise illegal on the vfat filesystem. The escape sequence +that gets used, where u is the unicode character, +is: ':', (u & 0x3f), ((u>>6) & 0x3f), (u>>12). +.TP +.B posix +Allow two files with names that only differ in case. +.TP +.B nonumtail +First try to make a short name without sequence number, +before trying +.IR name~num.ext . + +.SH "Mount options for xenix" +None. + +.SH "Mount options for xiafs" +None. Although nothing is wrong with xiafs, it is not used much, +and is not maintained. Probably one shouldn't use it. +Since Linux version 2.1.21 xiafs is no longer part of the kernel source. + +.SH "THE LOOP DEVICE" +One further possible type is a mount via the loop device. For example, +the command + +.nf +.B " mount /tmp/fdimage /mnt -t msdos -o loop=/dev/loop3,blocksize=1024" +.fi + +will set up the loop device +.I /dev/loop3 +to correspond to the file +.IR /tmp/fdimage , +and then mount this device on +.IR /mnt . +This type of mount knows about three options, namely +.BR loop ", " offset " and " encryption , +that are really options to +.BR losetup (8). +If no explicit loop device is mentioned +(but just an option `\fB\-o loop\fP' is given), then +.B mount +will try to find some unused loop device and use that. .SH FILES .I /etc/fstab file system table .br +.I /etc/mtab +table of mounted file systems +.br .I /etc/mtab~ lock file .br .I /etc/mtab.tmp temporary file .SH "SEE ALSO" -.BR mount "(2), " umount "(2), " fstab "(5), " swapon "(8), " nfs (5), -.BR mountd "(8), " nfsd (8) +.BR mount (2), +.BR umount (2), +.BR fstab (5), +.BR umount (8), +.BR swapon (8), +.BR nfs (5), +.BR mountd (8), +.BR nfsd (8), +.BR mke2fs (8), +.BR tune2fs (8), +.BR losetup (8) .SH BUGS It is possible for a corrupted file system to cause a crash. .PP Some Linux file systems don't support -.BI \-o " synchronous" +.B "\-o sync" (the ext2fs .I does support synchronous updates (a la BSD) when mounted with the @@ -586,9 +978,9 @@ support synchronous updates (a la BSD) when mounted with the option). .PP The -.BI \-o " remount" +.B "\-o remount" may not be able to change mount parameters (all -.I ext2fs +.IR ext2fs -specific parameters, except .BR sb , are changeable with a remount, for example, but you can't change @@ -596,32 +988,8 @@ are changeable with a remount, for example, but you can't change or .B umask for the -.IR dosfs ). +.IR fatfs ). .SH HISTORY A .B mount command appeared in Version 6 AT&T UNIX. -.SH "AUTHORS AND CONTRIBUTORS" -.na -The Linux -.B mount -command has a long and continuing history. Major releases are noted below, -with the name of the primary modifier noted: -.sp -0.97.3: Doug Quale (quale@saavik.cs.wisc.edu). -.br -0.98.5: H. J. Lu (hlu@eecs.wsu.edu). -.br -0.99.2: Rick Sladkey (jrs@world.std.com). -.br -0.99.6: Rick Sladkey (jrs@world.std.com). -.br -0.99.10: Stephen Tweedie (sct@dcs.ed.ac.uk). -.br -0.99.14: Rick Sladkey (jrs@world.std.com). -.sp -(File-system specific information added to man page on 27 November 1993 by -Rik Faith with lots of information -.I and text -from the following file system authors: Werner Almesberger, Eric Youngdale, -and Remy Card.) diff --git a/mount/mount.c b/mount/mount.c index 028848ac..98093956 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -22,42 +22,67 @@ * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages. * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied. * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes + * Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes * + * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect + * + * Since then, many changes - aeb. */ -#include "sundries.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(__GLIBC__) +#define _LINUX_TYPES_H /* kludge to prevent inclusion */ +#endif /* __GLIBC */ +#define _LINUX_WAIT_H /* idem */ +#define _I386_BITOPS_H /* idem */ #include #include -#include #include -#include -#include -#include +#include + +#if defined(__GLIBC__) +#define _SOCKETBITS_H +#endif /* __GLIBC */ +#include "sundries.h" +#include "fstab.h" +#include "lomount.h" +#include "loop.h" #define PROC_FILESYSTEMS "/proc/filesystems" #define SIZE(a) (sizeof(a)/sizeof(a[0])) -int del_loop (const char *); - /* True for fake mount (-f). */ int fake = 0; /* Don't write a entry in /etc/mtab (-n). */ int nomtab = 0; -/* True for readonly (-r). */ +/* True for explicit readonly (-r). */ int readonly = 0; /* Nonzero for chatty (-v). */ int verbose = 0; -/* True for read/write (-w). */ +/* True for explicit read/write (-w). */ int readwrite = 0; /* True for all mount (-a). */ int all = 0; +/* True for fork() during all mount (-F). */ +int optfork = 0; + /* True if ruid != euid. */ int suid = 0; @@ -65,16 +90,20 @@ int suid = 0; struct opt_map { const char *opt; /* option name */ + int skip; /* skip in mtab option string */ int inv; /* true if flag value should be inverted */ int mask; /* flag mask value */ }; /* Custom mount options for our own purposes. */ +/* We can use the high-order 16 bits, since the mount call + has MS_MGC_VAL there. */ #define MS_NOAUTO 0x80000000 #define MS_USER 0x40000000 +#define MS_LOOP 0x00010000 /* Options that we keep the mount system call from seeing. */ -#define MS_NOSYS (MS_NOAUTO|MS_USER) +#define MS_NOSYS (MS_NOAUTO|MS_USER|MS_LOOP) /* Options that we keep from appearing in the options field in the mtab. */ #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USER) @@ -82,72 +111,112 @@ struct opt_map /* OPTIONS that we make ordinary users have by default. */ #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV) -const struct opt_map opt_map[] = -{ - { "defaults", 0, 0 }, /* default options */ - { "ro", 0, MS_RDONLY }, /* read-only */ - { "rw", 1, MS_RDONLY }, /* read-write */ - { "exec", 1, MS_NOEXEC }, /* permit execution of binaries */ - { "noexec", 0, MS_NOEXEC }, /* don't execute binaries */ - { "suid", 1, MS_NOSUID }, /* honor suid executables */ - { "nosuid", 0, MS_NOSUID }, /* don't honor suid executables */ - { "dev", 1, MS_NODEV }, /* interpret device files */ - { "nodev", 0, MS_NODEV }, /* don't interpret devices */ - { "sync", 0, MS_SYNCHRONOUS}, /* synchronous I/O */ - { "async", 1, MS_SYNCHRONOUS}, /* asynchronous I/O */ - { "remount", 0, MS_REMOUNT }, /* Alter flags of mounted FS */ - { "auto", 1, MS_NOAUTO }, /* Can be mounted using -a */ - { "noauto", 0, MS_NOAUTO }, /* Can only be mounted explicitly */ - { "user", 0, MS_USER }, /* Allow ordinary user to mount */ - { "nouser", 1, MS_USER }, /* Forbid ordinary user to mount */ +const struct opt_map opt_map[] = { + { "defaults", 0, 0, 0 }, /* default options */ + { "ro", 1, 0, MS_RDONLY }, /* read-only */ + { "rw", 1, 1, MS_RDONLY }, /* read-write */ + { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */ + { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */ + { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */ + { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */ + { "dev", 0, 1, MS_NODEV }, /* interpret device files */ + { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */ + { "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */ + { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */ + { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */ + { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */ + { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */ + { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */ + { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */ /* add new options here */ #ifdef MS_NOSUB - { "sub", 1, MS_NOSUB }, /* allow submounts */ - { "nosub", 0, MS_NOSUB }, /* don't allow submounts */ + { "sub", 0, 1, MS_NOSUB }, /* allow submounts */ + { "nosub", 0, 0, MS_NOSUB }, /* don't allow submounts */ +#endif +#ifdef MS_SILENT + { "quiet", 0, 0, MS_SILENT }, /* be quiet */ + { "loud", 0, 1, MS_SILENT }, /* print out messages. */ #endif -#ifdef MS_SILENT - { "quiet", 0, MS_SILENT }, /* be quiet */ - { "loud", 1, MS_SILENT }, /* print out messages. */ +#ifdef MS_MANDLOCK + { "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */ + { "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */ #endif - { NULL, 0, 0 } + { "loop", 1, 0, MS_LOOP }, /* use a loop device */ +#ifdef MS_NOATIME + { "atime", 0, 1, MS_NOATIME }, /* Update access time */ + { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */ +#endif + { NULL, 0, 0, 0 } +}; + +char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption; + +struct string_opt_map { + char *tag; + int skip; + char **valptr; +} string_opt_map[] = { + { "loop=", 0, &opt_loopdev }, + { "vfs=", 1, &opt_vfstype }, + { "offset=", 0, &opt_offset }, + { "encryption=", 0, &opt_encryption }, + { NULL, 0, NULL } }; +static void +clear_string_opts(void) { + struct string_opt_map *m; + + for (m = &string_opt_map[0]; m->tag; m++) + *(m->valptr) = NULL; +} + +static int +parse_string_opt(char *s) { + struct string_opt_map *m; + int lth; + + for (m = &string_opt_map[0]; m->tag; m++) { + lth = strlen(m->tag); + if (!strncmp(s, m->tag, lth)) { + *(m->valptr) = xstrdup(s + lth); + return 1; + } + } + return 0; +} + int mount_quiet=0; /* Report on a single mount. */ static void -print_one (const struct mntent *mnt) -{ - if (mount_quiet) return; - printf ("%s on %s", mnt->mnt_fsname, mnt->mnt_dir); - if ((mnt->mnt_type != NULL) && *mnt->mnt_type != '\0') - printf (" type %s", mnt->mnt_type); - if (mnt->mnt_opts != NULL) - printf (" (%s)", mnt->mnt_opts); - printf ("\n"); +print_one (const struct mntentchn *mc) { + if (mount_quiet) + return; + printf ("%s on %s", mc->mnt_fsname, mc->mnt_dir); + if (mc->mnt_type != NULL && *(mc->mnt_type) != '\0') + printf (" type %s", mc->mnt_type); + if (mc->mnt_opts != NULL) + printf (" (%s)", mc->mnt_opts); + printf ("\n"); } /* Report on everything in mtab (of the specified types if any). */ static int print_all (string_list types) { - struct mntent *mnt; - - open_mtab ("r"); - - while ((mnt = getmntent (F_mtab)) != NULL) - if (matching_type (mnt->mnt_type, types)) - print_one (mnt); + struct mntentchn *mc; - if (ferror (F_mtab)) - die (1, "mount: error reading %s: %s", MOUNTED, strerror (errno)); - - exit (0); + for (mc = mtab_head()->nxt; mc; mc = mc->nxt) { + if (matching_type (mc->mnt_type, types)) + print_one (mc); + } + exit (0); } /* Look for OPT in opt_map table and return mask value. If OPT isn't found, - tack it onto extra_opts. */ + tack it onto extra_opts (which is non-NULL). */ static inline void parse_opt (const char *opt, int *mask, char *extra_opts) { @@ -185,15 +254,16 @@ parse_opts (char *opts, int *flags, char **extra_opts) *flags = 0; *extra_opts = NULL; + clear_string_opts(); + if (opts != NULL) { *extra_opts = xmalloc (strlen (opts) + 1); **extra_opts = '\0'; - for (opt = strtok (opts, ","); - opt != NULL; - opt = strtok (NULL, ",")) - parse_opt (opt, flags, *extra_opts); + for (opt = strtok (opts, ","); opt; opt = strtok (NULL, ",")) + if (!parse_string_opt (opt)) + parse_opt (opt, flags, *extra_opts); } if (readonly) @@ -207,30 +277,64 @@ static char * fix_opts_string (int flags, char *extra_opts) { const struct opt_map *om; + const struct string_opt_map *m; char *new_opts; - char *tmp; new_opts = (flags & MS_RDONLY) ? "ro" : "rw"; - for (om = opt_map; om->opt != NULL; om++) - { - if (om->mask & MS_RDONLY) + for (om = opt_map; om->opt != NULL; om++) { + if (om->skip) continue; if (om->inv || !om->mask || (flags & om->mask) != om->mask) continue; - tmp = xmalloc(strlen(new_opts) + strlen(om->opt) + 2); - sprintf(tmp, "%s,%s", new_opts, om->opt); - new_opts = tmp; + new_opts = xstrconcat3(new_opts, ",", om->opt); flags &= ~om->mask; - } - if (extra_opts && *extra_opts) - { - tmp = xmalloc(strlen(new_opts) + strlen(extra_opts) + 2); - sprintf(tmp, "%s,%s", new_opts, extra_opts); - new_opts = tmp; - } + } + for (m = &string_opt_map[0]; m->tag; m++) { + if (!m->skip && *(m->valptr)) + new_opts = xstrconcat4(new_opts, ",", m->tag, *(m->valptr)); + } + if (extra_opts && *extra_opts) { + new_opts = xstrconcat3(new_opts, ",", extra_opts); + } return new_opts; } +/* Most file system types can be recognized by a `magic' number + in the superblock. Note that the order of the tests is + significant: by coincidence a filesystem can have the + magic numbers for several file system types simultaneously. + For example, the romfs magic lives in the 1st sector; + xiafs does not touch the 1st sector and has its magic in + the 2nd sector; ext2 does not touch the first two sectors. */ + +/* ext definitions - required since 2.1.21 */ +#ifndef EXT_SUPER_MAGIC +#define EXT_SUPER_MAGIC 0x137D +struct ext_super_block { + unsigned long s_dummy[14]; + unsigned short s_magic; +}; +#endif + +/* xiafs definitions - required since they were removed from + the kernel since 2.1.21 */ +#ifndef _XIAFS_SUPER_MAGIC +#define _XIAFS_SUPER_MAGIC 0x012FD16D +struct xiafs_super_block { + u_char s_boot_segment[512]; /* 1st sector reserved for boot */ + u_long s_dummy[15]; + u_long s_magic; /* 15: magic number for xiafs */ +}; +#endif + +#ifndef EXT2_PRE_02B_MAGIC +#define EXT2_PRE_02B_MAGIC 0xEF51 +#endif + +static inline unsigned short +swapped(unsigned short a) { + return (a>>8) | (a<<8); +} /* char *fstype(const char *device); @@ -242,10 +346,13 @@ fix_opts_string (int flags, char *extra_opts) for mount(8) by Mike Grupenhoff . Read the superblock only once - aeb Added a test for iso9660 - aeb + Added a test for high sierra (iso9660) - quinlan@bucknell.edu + Corrected the test for xiafs - aeb + added romfs - aeb - Currently supports: minix, ext, ext2, xiafs, iso9660 + Currently supports: minix, ext, ext2, xiafs, iso9660, romfs */ -char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660" }; +char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs" }; static int tested(const char *device) { @@ -261,65 +368,76 @@ static char * fstype(const char *device) { int fd; - char ifs_magic[8]; + char *type = NULL; union { struct minix_super_block ms; struct ext_super_block es; struct ext2_super_block e2s; - struct xiafs_super_block xfs; } sb; + union { + struct xiafs_super_block xiasb; + char romfs_magic[8]; + } xsb; + union { + struct iso_volume_descriptor iso; + struct hs_volume_descriptor hs; + } isosb; struct stat statbuf; /* opening and reading an arbitrary unknown path can have undesired side effects - first check that `device' refers to a block device */ - if (stat (device, &statbuf)) - error("mount: %s does not exist", device); - if (!S_ISBLK(statbuf.st_mode)) - error("mount: %s is not a block device", device); + if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode)) + return 0; fd = open(device, O_RDONLY); - if (fd < 0 - || lseek(fd, BLOCK_SIZE, SEEK_SET) < 0 - || read(fd, (char *) &sb, sizeof(sb)) < 0) { - perror(device); - return 0; - } + if (fd < 0) + return 0; - if (sb.ms.s_magic == MINIX_SUPER_MAGIC - || sb.ms.s_magic == MINIX_SUPER_MAGIC2) { - close (fd); - return("minix"); - } + if (lseek(fd, BLOCK_SIZE, SEEK_SET) != BLOCK_SIZE + || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) + goto io_error; - if (sb.es.s_magic == EXT_SUPER_MAGIC) { - close (fd); - return("ext"); - } - -#ifndef EXT2_PRE_02B_MAGIC -#define EXT2_PRE_02B_MAGIC 0xEF51 -#endif if (sb.e2s.s_magic == EXT2_SUPER_MAGIC - || sb.e2s.s_magic == EXT2_PRE_02B_MAGIC) { - close (fd); - return("ext2"); + || sb.e2s.s_magic == EXT2_PRE_02B_MAGIC + || sb.e2s.s_magic == swapped(EXT2_SUPER_MAGIC)) + type = "ext2"; + + else if (sb.ms.s_magic == MINIX_SUPER_MAGIC + || sb.ms.s_magic == MINIX_SUPER_MAGIC2) + type = "minix"; + + else if (sb.es.s_magic == EXT_SUPER_MAGIC) + type = "ext"; + + if (!type) { + if (lseek(fd, 0, SEEK_SET) != 0 + || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) + goto io_error; + + if (xsb.xiasb.s_magic == _XIAFS_SUPER_MAGIC) + type = "xiafs"; + else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) + type = "romfs"; } - if (sb.xfs.s_magic == _XIAFS_SUPER_MAGIC) { - close (fd); - return("xiafs"); - } + if (!type) { + if (lseek(fd, 0x8000, SEEK_SET) != 0x8000 + || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb)) + goto io_error; - if (lseek (fd, 0100000, SEEK_SET) != -1 - && read (fd, ifs_magic, 8) == 8 - && !strncmp(ifs_magic, "\001CD001\001", 8)) { /* ECMA 119 */ - close (fd); - return("iso9660"); + if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0 + || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0) + type = "iso9660"; } close (fd); - return(0); + return(type); + +io_error: + perror(device); + close(fd); + return 0; } FILE *procfs; @@ -363,20 +481,68 @@ is_in_proc(char *type) { static int already (char *spec, char *node) { - struct mntent *me; + struct mntentchn *mc; int ret = 1; - if ((me = getmntfile(node)) != NULL) + if ((mc = getmntfile(node)) != NULL) error ("mount: according to mtab, %s is already mounted on %s", - me->mnt_fsname, node); - else if ((me = getmntfile(spec)) != NULL) + mc->mnt_fsname, node); + else if ((mc = getmntfile(spec)) != NULL) error ("mount: according to mtab, %s is mounted on %s", - spec, me->mnt_dir); + spec, mc->mnt_dir); else ret = 0; return ret; } +/* Create mtab with a root entry. */ +static void +create_mtab (void) { + struct mntentchn *fstab; + struct mntent mnt; + int flags; + char *extra_opts; + FILE *fp; + + lock_mtab(); + + if ((fp = setmntent (MOUNTED, "a+")) == NULL) + die (EX_FILEIO, "mount: can't open %s for writing: %s", + MOUNTED, strerror (errno)); + + /* Find the root entry by looking it up in fstab */ + if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) { + parse_opts (xstrdup (fstab->mnt_opts), &flags, &extra_opts); + mnt.mnt_dir = "/"; + mnt.mnt_fsname = canonicalize (fstab->mnt_fsname); + mnt.mnt_type = fstab->mnt_type; + mnt.mnt_opts = fix_opts_string (flags, extra_opts); + mnt.mnt_freq = mnt.mnt_passno = 0; + + if (addmntent (fp, &mnt) == 1) + die (EX_FILEIO, "mount: error writing %s: %s", + MOUNTED, strerror (errno)); + } + if (fchmod (fileno (fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + if (errno != EROFS) + die (EX_FILEIO, "mount: error changing mode of %s: %s", + MOUNTED, strerror (errno)); + endmntent (fp); + + unlock_mtab(); +} + +/* count successful mount system calls */ +static int mountcount = 0; + +static int +mount5 (char *special, char *dir, char *type, int flags, void *data) { + int ret = mount (special, dir, type, 0xC0ED0000 | (flags), data); + if (ret == 0) + mountcount++; + return ret; +} + /* Mount a single file system. Return status, so don't exit on non-fatal errors. */ @@ -384,13 +550,11 @@ static int try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { char *fsname; - if (strcasecmp (*type, "auto") == 0) + if (*type && strcasecmp (*type, "auto") == 0) *type = NULL; - if (!*type) { + if (!*type && !(flags & MS_REMOUNT)) { *type = fstype(spec); - if (!*type && !procopen()) - *type = FSTYPE_DEFAULT; if (verbose) { printf ("mount: you didn't specify a filesystem type for %s\n", spec); @@ -402,9 +566,11 @@ try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { } } - if (*type) + if (*type || (flags & MS_REMOUNT)) return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts); + if (!procopen()) + return -1; while ((fsname = procnext()) != NULL) { if (tested (fsname)) continue; @@ -424,32 +590,52 @@ try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { return -1; } - static int -mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) +mount_one (char *spec0, char *node0, char *type0, char *opts0, + int freq, int pass) { + struct mntentchn mcn; struct mntent mnt; int mnt_err; int flags; - char *extra_opts; - char *mount_opts; + char *extra_opts; /* written in mtab */ + char *mount_opts; /* actually used on system call */ static int added_ro = 0; - int loop=0; + int loop, looptype, offset; + char *spec, *node, *type, *opts, *loopdev, *loopfile; - if (type == NULL) - { - if (strchr (spec, ':') != NULL) + spec = xstrdup(spec0); + node = xstrdup(node0); + type = xstrdup(type0); + opts = xstrdup(opts0); + +/* + * There are two special cases: nfs mounts and loop mounts. + * In the case of nfs mounts spec is probably of the form machine:path. + * In the case of a loop mount, either type is of the form lo@/dev/loop5 + * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or + * mount just has to figure things out for itself from the fact that + * spec is not a block device. We do not test for a block device + * immediately: maybe later other types of mountable objects will occur. + */ + + if (type == NULL) { + if (strchr (spec, ':') != NULL) { type = "nfs"; - } + if (verbose) + printf("mount: no type was given - " + "I'll assume nfs because of the colon\n"); + } + } parse_opts (xstrdup (opts), &flags, &extra_opts); /* root may allow certain types of mounts by ordinary users */ if (suid && !(flags & MS_USER)) { if (already (spec, node)) - die (3, "mount failed"); + die (EX_USAGE, "mount failed"); else - die (3, "mount: only root can mount %s on %s", spec, node); + die (EX_USAGE, "mount: only root can mount %s on %s", spec, node); } /* quietly succeed for fstab entries that don't get mounted automatically */ @@ -458,69 +644,156 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) mount_opts = extra_opts; - if (!fake && type && strncmp("lo@", type, 3)==0) { - extern int lomount (char *, char *, char *, char **, - int *, char **, char **); - char *dev=type+3; + /* + * A loop mount? + * Only test for explicitly specified loop here, + * and try implicit loop if the mount fails. + */ + loopdev = opt_loopdev; + + looptype = (type && strncmp("lo@", type, 3) == 0); + if (looptype) { + if (loopdev) + error("mount: loop device specified twice"); + loopdev = type+3; + type = opt_vfstype; + } + else if (opt_vfstype) { + if (type) + error("mount: type specified twice"); + else + type = opt_vfstype; + } - loop=1; - if (lomount (spec, node, dev, &type, - &flags, &opts, &mount_opts) != 0) - return 1; - spec=dev; - mount_opts=NULL; + loop = ((flags & MS_LOOP) || loopdev || opt_offset || opt_encryption); + loopfile = spec; + + if (loop) { + flags |= MS_LOOP; + if (fake) { + if (verbose) + printf("mount: skipping the setup of a loop device\n"); + } else { + int loopro = (flags & MS_RDONLY); + + if (!loopdev || !*loopdev) + loopdev = find_unused_loop_device(); + if (!loopdev) + return EX_SYSERR; /* no more loop devices */ + if (verbose) + printf("mount: going to use the loop device %s\n", loopdev); + offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0; + if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro)) + return EX_FAIL; + spec = loopdev; + if (loopro) + flags |= MS_RDONLY; + } } if (!fake && type && streq (type, "nfs")) #ifdef HAVE_NFS if (nfsmount (spec, node, &flags, &extra_opts, &mount_opts) != 0) - return 1; + return EX_FAIL; #else - die (1, "mount: this version was compiled without support for the type `nfs'"); + die (EX_SOFTWARE, "mount: this version was compiled " + "without support for the type `nfs'"); #endif + /* + * Call mount.TYPE for types that require a separate + * mount program. For the moment these types are ncp and smb. + */ + if (type) +#ifndef ALWAYS_STAT + if (streq (type, "smb") || streq (type, "ncp")) +#else + if (strlen (type) < 100) +#endif + { + struct stat statbuf; + char mountprog[120]; + + sprintf(mountprog, "/sbin/mount.%s", type); + if (stat(mountprog, &statbuf) == 0) { + if (fork() == 0) { + char *oo, *mountargs[10]; + int i = 0; + + setuid(getuid()); + setgid(getgid()); + oo = fix_opts_string (flags, extra_opts); + mountargs[i++] = mountprog; + mountargs[i++] = spec; + mountargs[i++] = node; + if (nomtab) + mountargs[i++] = "-n"; + if (verbose) + mountargs[i++] = "-v"; + if (oo && *oo) { + mountargs[i++] = "-o"; + mountargs[i++] = oo; + } + mountargs[i] = NULL; + execv(mountprog, mountargs); + exit(1); /* exec failed */ + } else if (fork() != -1) { + int status; + wait(&status); + return status; + } else + error("cannot fork: %s", strerror(errno)); + } + } + block_signals (SIG_BLOCK); if (fake || (try_mount5 (spec, node, &type, flags & ~MS_NOSYS, mount_opts)) == 0) - /* Mount succeeded, write mtab entry. */ + /* Mount succeeded, report this (if verbose) and write mtab entry. */ { - if (!nomtab) - { - mnt.mnt_fsname = canonicalize (spec); - mnt.mnt_dir = canonicalize (node); - mnt.mnt_type = loop ? "loop" : type; - mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, - loop?opts:extra_opts); - mnt.mnt_freq = freq; - mnt.mnt_passno = pass; + if (loop) + opt_loopdev = loopdev; + + mcn.mnt_fsname = mnt.mnt_fsname = canonicalize (loop ? loopfile : spec); + mcn.mnt_dir = mnt.mnt_dir = canonicalize (node); + mcn.mnt_type = mnt.mnt_type = type ? type : "unknown"; + mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, extra_opts); + mcn.nxt = 0; + mnt.mnt_freq = freq; + mnt.mnt_passno = pass; - /* We get chatty now rather than after the update to mtab since the - mount succeeded, even if the write to /etc/mtab should fail. */ - if (verbose) - print_one (&mnt); + /* We get chatty now rather than after the update to mtab since the + mount succeeded, even if the write to /etc/mtab should fail. */ + if (verbose) + print_one (&mcn); + if (!nomtab && mtab_is_writable()) { if (flags & MS_REMOUNT) - { - close_mtab (); - update_mtab (mnt.mnt_dir, &mnt); - open_mtab ("a+"); - } - else - if ((addmntent (F_mtab, &mnt)) == 1) - die (1, "mount: error writing %s: %s", - MOUNTED, strerror (errno)); - } + update_mtab (mnt.mnt_dir, &mnt); + else { + FILE *fp = setmntent(MOUNTED, "a+"); + if (fp == NULL) + error("mount: can't open %s: %s", MOUNTED, + strerror (errno)); + else { + if ((addmntent (fp, &mnt)) == 1) + error("mount: error writing %s: %s", MOUNTED, + strerror (errno)); + endmntent(fp); + } + } + } block_signals (SIG_UNBLOCK); return 0; } + mnt_err = errno; + if (loop) del_loop(spec); - mnt_err = errno; /* work around for errno bug in sigprocmask */ - block_signals (SIG_UNBLOCK); /* Mount failed, complain, but don't die. */ @@ -531,14 +804,22 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) switch (mnt_err) { case EPERM: - if (geteuid() == 0) - error ("mount: mount point %s is not a directory", node); - else + if (geteuid() == 0) { + struct stat statbuf; + if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode)) + error ("mount: mount point %s is not a directory", node); + else + error ("mount: permission denied"); + } else error ("mount: must be superuser to use mount"); break; case EBUSY: - error ("mount: %s already mounted or %s busy", spec, node); - already (spec, node); + if (flags & MS_REMOUNT) { + error ("mount: %s is busy", node); + } else { + error ("mount: %s already mounted or %s busy", spec, node); + already (spec, node); + } break; case ENOENT: { struct stat statbuf; @@ -556,27 +837,78 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) break; } case ENOTDIR: - error ("mount: mount point %s is not a directory", node); break; + error ("mount: mount point %s is not a directory", node); + break; case EINVAL: - error ("mount: wrong fs type or bad superblock on %s", spec); break; + { int fd, size; + struct stat statbuf; + + if (flags & MS_REMOUNT) { + error ("mount: %s not mounted already, or bad option\n", node); + } else { + error ("mount: wrong fs type, bad option, bad superblock on %s,\n" + " or too many mounted file systems", + spec); + + if (stat (spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode) + && (fd = open(spec, O_RDONLY)) >= 0) { + if(ioctl(fd, BLKGETSIZE, &size) == 0 && size <= 2) + error (" (aren't you trying to mount an extended partition,\n" + " instead of some logical partition inside?)\n"); + close(fd); + } + } + break; + } case EMFILE: error ("mount table full"); break; case EIO: error ("mount: %s: can't read superblock", spec); break; case ENODEV: - if (is_in_proc(type)) + if (is_in_proc(type) || !strcmp(type, "guess")) error("mount: %s has wrong major or minor number", spec); - else if (procfs) + else if (procfs) { + char *lowtype, *p; + int u; + error ("mount: fs type %s not supported by kernel", type); - else + + /* maybe this loser asked for FAT or ISO9660 or isofs */ + lowtype = xstrdup(type); + u = 0; + for(p=lowtype; *p; p++) { + if(tolower(*p) != *p) { + *p = tolower(*p); + u++; + } + } + if (u && is_in_proc(lowtype)) + error ("mount: probably you meant %s", lowtype); + else if (!strncmp(lowtype, "iso", 3) && is_in_proc("iso9660")) + error ("mount: maybe you meant iso9660 ?"); + free(lowtype); + } else error ("mount: %s has wrong device number or fs type %s not supported", spec, type); break; case ENOTBLK: - error ("mount: %s is not a block device", spec); break; + { struct stat statbuf; + + if (stat (spec, &statbuf)) /* strange ... */ + error ("mount: %s is not a block device, and stat fails?", spec); + else if (S_ISBLK(statbuf.st_mode)) + error ("mount: the kernel does not recognize %s as a block device\n" + " (maybe `insmod driver'?)", spec); + else if (S_ISREG(statbuf.st_mode)) + error ("mount: %s is not a block device (maybe try `-o loop'?)", + spec); + else + error ("mount: %s is not a block device", spec); + } + break; case ENXIO: error ("mount: %s is not a valid block device", spec); break; - case EACCES: /* pre-linux 1.1.38 */ + case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */ case EROFS: /* linux 1.1.38 and later */ if (added_ro) { error ("mount: block device %s is not permitted on its filesystem", @@ -584,6 +916,10 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) break; } else { added_ro = 1; + if (loop) { + opts = opts0; + type = type0; + } if (opts) { opts = realloc(xstrdup(opts), strlen(opts)+4); strcat(opts, ",ro"); @@ -591,104 +927,132 @@ mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass) opts = "ro"; if (type && !strcmp(type, "guess")) type = 0; - error ("mount: block device %s is write-protected, " - "mounting read-only", spec); - return mount_one (spec, node, type, opts, freq, pass); + error ("mount: %s%s is write-protected, mounting read-only", + loop ? "" : "block device ", spec0); + return mount_one (spec0, node0, type, opts, freq, pass); } break; default: error ("mount: %s", strerror (mnt_err)); break; } - return 1; + return EX_FAIL; } /* Check if an fsname/dir pair was already in the old mtab. */ static int -mounted (char *spec, char *node, string_list spec_list, string_list node_list) -{ - spec = canonicalize (spec); - node = canonicalize (node); - - while (spec_list != NULL) - { - if (streq (spec, car (spec_list)) && streq (node, car (node_list))) - return 1; - spec_list = cdr (spec_list); - node_list = cdr (node_list); - } - return 0; -} - -/* Mount all filesystems of the specified types except swap and root. */ -static int -mount_all (string_list types) -{ - struct mntent *fstab; - struct mntent *mnt; - string_list spec_list = NULL; - string_list node_list = NULL; - int status; - - rewind (F_mtab); - - while ((mnt = getmntent (F_mtab))) - if (matching_type (mnt->mnt_type, types) - && !streq (mnt->mnt_dir, "/") - && !streq (mnt->mnt_dir, "root")) - { - spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list); - node_list = cons (xstrdup (mnt->mnt_dir), node_list); - } +mounted (char *spec, char *node) { + struct mntentchn *mc; - status = 0; - if (!setfsent()) return 1; - while ((fstab = getfsent ()) != NULL) - if (matching_type (fstab->mnt_type, types) - && !streq (fstab->mnt_dir, "/") - && !streq (fstab->mnt_dir, "root")) - if (mounted (fstab->mnt_fsname, fstab->mnt_dir, spec_list, node_list)) - { - if (verbose) - printf("mount: %s already mounted on %s\n", - fstab->mnt_fsname, fstab->mnt_dir); - } - else - status |= mount_one (fstab->mnt_fsname, fstab->mnt_dir, - fstab->mnt_type, fstab->mnt_opts, - fstab->mnt_freq, fstab->mnt_passno); + spec = canonicalize (spec); + node = canonicalize (node); - return status; + for (mc = mtab_head()->nxt; mc; mc = mc->nxt) + if (streq (spec, mc->mnt_fsname) && streq (node, mc->mnt_dir)) + return 1; + return 0; } -/* Create mtab with a root entry. */ -static void -create_mtab (void) -{ - struct mntent *fstab; - struct mntent mnt; - int flags; - char *extra_opts; - - if ((F_mtab = setmntent (MOUNTED, "a+")) == NULL) - die (1, "mount: can't open %s for writing: %s", MOUNTED, strerror (errno)); - - /* Find the root entry by looking it up in fstab, which might be wrong. - We could statfs "/" followed by a slew of stats on /dev/ but then - we'd have to unparse the mount options as well.... */ - if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) - { - parse_opts (xstrdup (fstab->mnt_opts), &flags, &extra_opts); - mnt = *fstab; - mnt.mnt_fsname = canonicalize (fstab->mnt_fsname); - mnt.mnt_dir = "/"; - mnt.mnt_opts = fix_opts_string (flags, extra_opts); +/* Mount all filesystems of the specified types except swap and root. */ +/* With the --fork option: fork and let different incarnations of + mount handle different filesystems. However, try to avoid several + simultaneous mounts on the same physical disk, since that is very slow. */ +#define DISKMAJOR(m) ((m) & ~0xf) - if (addmntent (F_mtab, &mnt) == 1) - die (1, "mount: error writing %s: %s", MOUNTED, strerror (errno)); - } - if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) - die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno)); - endmntent (F_mtab); +static int +mount_all (string_list types) { + struct mntentchn *mc, *mtmp; + int status = 0, m; + struct stat statbuf; + struct child { + pid_t pid; + dev_t major; + struct mntentchn *mec; + struct mntentchn *meclast; + struct child *nxt; + } childhead, *childtail, *cp; + + /* build a chain of what we have to do, or maybe + several chains, one for each major */ + childhead.nxt = 0; + childtail = &childhead; + for (mc = fstab_head()->nxt; mc; mc = mc->nxt) { + if (matching_type (mc->mnt_type, types) + && !streq (mc->mnt_dir, "/") + && !streq (mc->mnt_dir, "root")) { + if (mounted (mc->mnt_fsname, mc->mnt_dir)) { + if (verbose) + printf("mount: %s already mounted on %s\n", + mc->mnt_fsname, mc->mnt_dir); + } else { + mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp)); + *mtmp = *mc; + mtmp->nxt = 0; + m = 0; + if (optfork && stat(mc->mnt_fsname, &statbuf) == 0 + && S_ISBLK(statbuf.st_mode)) + m = DISKMAJOR(statbuf.st_rdev); + if (m) { + for (cp = childhead.nxt; cp; cp = cp->nxt) + if (cp->major == m) { + cp->meclast->nxt = mtmp; + cp->meclast = mtmp; + goto fnd; + } + } + cp = (struct child *) xmalloc(sizeof *cp); + cp->nxt = 0; + cp->mec = cp->meclast = mtmp; + cp->major = m; + cp->pid = 0; + childtail->nxt = cp; + childtail = cp; + fnd:; + } + } + } + + /* now do everything */ + for (cp = childhead.nxt; cp; cp = cp->nxt) { + pid_t p = -1; + if (optfork) { + p = fork(); + if (p == -1) + error("mount: cannot fork: %s", strerror (errno)); + else if (p != 0) + cp->pid = p; + } + + /* if child, or not forked, do the mounting */ + if (p == 0 || p == -1) { + for (mc = cp->mec; mc; mc = mc->nxt) + status |= mount_one (mc->mnt_fsname, mc->mnt_dir, + mc->mnt_type, mc->mnt_opts, 0, 0); + if (mountcount) + status |= EX_SOMEOK; + if (p == 0) + exit(status); + } + } + + /* wait for children, if any */ + while ((cp = childhead.nxt) != NULL) { + childhead.nxt = cp->nxt; + if (cp->pid) { + int ret; + keep_waiting: + if(waitpid(cp->pid, &ret, 0) == -1) { + if (errno == EINTR) + goto keep_waiting; + perror("waitpid"); + } else if (WIFEXITED(ret)) + status |= WEXITSTATUS(ret); + else + status |= EX_SYSERR; + } + } + if (mountcount) + status |= EX_SOMEOK; + return status; } extern char version[]; @@ -696,6 +1060,7 @@ static struct option longopts[] = { { "all", 0, 0, 'a' }, { "fake", 0, 0, 'f' }, + { "fork", 0, 0, 'F' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "read-only", 0, 0, 'r' }, @@ -711,7 +1076,7 @@ static struct option longopts[] = const char *usage_string = "\ usage: mount [-hV]\n\ - mount -a [-nfrvw] [-t vfstypes]\n\ + mount -a [-nfFrvw] [-t vfstypes]\n\ mount [-nfrvw] [-o options] special | node\n\ mount [-nfrvw] [-t vfstype] [-o options] special node\n\ "; @@ -725,118 +1090,110 @@ usage (FILE *fp, int n) } int -main (int argc, char *argv[]) -{ - int c; - char *options = NULL; +main (int argc, char *argv[]) { + int c, result = 0; + char *options = NULL, *spec; string_list types = NULL; - struct mntent *fs; - char *spec; - int result = 0; - struct stat statbuf; + struct mntentchn *mc; - while ((c = getopt_long (argc, argv, "afhnrvVwt:o:", longopts, NULL)) != EOF) - switch (c) - { + while ((c = getopt_long (argc, argv, "afFhno:rvVwt:", longopts, NULL)) + != EOF) + switch (c) { case 'a': /* mount everything in fstab */ ++all; break; case 'f': /* fake (don't actually do mount(2) call) */ ++fake; break; + case 'F': + ++optfork; + break; case 'h': /* help */ usage (stdout, 0); break; case 'n': /* mount without writing in /etc/mtab */ ++nomtab; break; + case 'o': /* specify mount options */ + if (options) + options = xstrconcat3(options, ",", optarg); + else + options = xstrdup(optarg); + break; case 'r': /* mount readonly */ - ++readonly; + readonly = 1; readwrite = 0; break; - case 'v': /* be chatty */ + case 't': /* specify file system types */ + types = parse_list (optarg); + break; + case 'v': /* be chatty - very chatty if repeated */ ++verbose; break; case 'V': /* version */ printf ("mount: %s\n", version); exit (0); case 'w': /* mount read/write */ - ++readwrite; + readwrite = 1; readonly = 0; break; - case 't': /* specify file system types */ - types = parse_list (optarg); - break; - case 'o': /* specify mount options */ - options = optarg; - break; case 0: break; case '?': default: - usage (stderr, 1); - break; - } + usage (stderr, EX_USAGE); + } argc -= optind; argv += optind; - if (argc == 0) - { + if (argc == 0) { if (options) - usage (stderr, 1); + usage (stderr, EX_USAGE); if (!all) return print_all (types); - } + } - if (getuid () != geteuid ()) - { + if (getuid () != geteuid ()) { suid = 1; if (types || options || readwrite || nomtab || all || fake || argc != 1) - die (2, "mount: only root can do that"); - } - - if (!nomtab) - { - lock_mtab (); - if (stat(MOUNTED, &statbuf) < 0) - create_mtab (); - open_mtab ("a+"); - } - else if (stat(MOUNTED, &statbuf) >= 0) - open_mtab ("r"); + die (EX_USAGE, "mount: only root can do that"); + } + if (!nomtab && mtab_does_not_exist()) { + if (verbose > 1) + printf("mount: no %s found - creating it..\n", MOUNTED); + create_mtab (); + } - switch (argc) - { + switch (argc) { case 0: /* mount -a */ result = mount_all (types); + if (result == 0 && verbose) + error("not mounted anything"); break; case 1: /* mount [-nfrvw] [-o options] special | node */ if (types != NULL) - usage (stderr, 1); + usage (stderr, EX_USAGE); + /* Try to find the other pathname in fstab. */ spec = canonicalize (*argv); - if (!(fs = getmntfile (spec)) - && !(fs = getfsspec (spec)) && !(fs = getfsfile (spec))) - die (2, "mount: can't find %s in %s or %s", - spec, MOUNTED, _PATH_FSTAB); + if ((mc = getmntfile (spec)) == NULL && + (mc = getfsspec (spec)) == NULL && (mc = getfsfile (spec)) == NULL) + die (EX_USAGE, "mount: can't find %s in %s or %s", + spec, MOUNTED, _PATH_FSTAB); + /* Merge the fstab and command line options. */ if (options == NULL) - options = fs->mnt_opts; + options = mc->mnt_opts; else - { - char *tmp = xmalloc(strlen(fs->mnt_opts) + strlen(options) + 2); + options = xstrconcat3(mc->mnt_opts, ",", options); - sprintf (tmp, "%s,%s", fs->mnt_opts, options); - options = tmp; - } - result = mount_one (xstrdup (fs->mnt_fsname), xstrdup (fs->mnt_dir), - xstrdup (fs->mnt_type), options, - fs->mnt_freq, fs->mnt_passno); + result = mount_one (xstrdup (mc->mnt_fsname), xstrdup (mc->mnt_dir), + xstrdup (mc->mnt_type), options, 0, 0); break; case 2: @@ -846,18 +1203,14 @@ main (int argc, char *argv[]) else if (cdr (types) == NULL) result = mount_one (argv[0], argv[1], car (types), options, 0, 0); else - usage (stderr, 2); + usage (stderr, EX_USAGE); break; default: - usage (stderr, 2); - } - - if (!nomtab) - { - endmntent (F_mtab); - unlock_mtab (); - } + usage (stderr, EX_USAGE); + } + if (result == EX_SOMEOK) + result = 0; exit (result); } diff --git a/mount/mount.x b/mount/mount.x deleted file mode 100644 index 7e0d7f3a..00000000 --- a/mount/mount.x +++ /dev/null @@ -1,161 +0,0 @@ -/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */ -/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/* - * Protocol description for the mount program - */ - - -const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ -const MNTNAMLEN = 255; /* maximum bytes in a name argument */ -const FHSIZE = 32; /* size in bytes of a file handle */ - -/* - * The fhandle is the file handle that the server passes to the client. - * All file operations are done using the file handles to refer to a file - * or a directory. The file handle can contain whatever information the - * server needs to distinguish an individual file. - */ -typedef opaque fhandle[FHSIZE]; - -/* - * If a status of zero is returned, the call completed successfully, and - * a file handle for the directory follows. A non-zero status indicates - * some sort of error. The status corresponds with UNIX error numbers. - */ -union fhstatus switch (unsigned fhs_status) { -case 0: - fhandle fhs_fhandle; -default: - void; -}; - -/* - * The type dirpath is the pathname of a directory - */ -typedef string dirpath; - -/* - * The type name is used for arbitrary names (hostnames, groupnames) - */ -typedef string name; - -/* - * A list of who has what mounted - */ -typedef struct mountbody *mountlist; -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; - -/* - * A list of netgroups - */ -typedef struct groupnode *groups; -struct groupnode { - name gr_name; - groups gr_next; -}; - -/* - * A list of what is exported and to whom - */ -typedef struct exportnode *exports; -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; - -program MOUNTPROG { - /* - * Version one of the mount protocol communicates with version two - * of the NFS protocol. The only connecting point is the fhandle - * structure, which is the same for both protocols. - */ - version MOUNTVERS { - /* - * Does no work. It is made available in all RPC services - * to allow server reponse testing and timing - */ - void - MOUNTPROC_NULL(void) = 0; - - /* - * If fhs_status is 0, then fhs_fhandle contains the - * file handle for the directory. This file handle may - * be used in the NFS protocol. This procedure also adds - * a new entry to the mount list for this client mounting - * the directory. - * Unix authentication required. - */ - fhstatus - MOUNTPROC_MNT(dirpath) = 1; - - /* - * Returns the list of remotely mounted filesystems. The - * mountlist contains one entry for each hostname and - * directory pair. - */ - mountlist - MOUNTPROC_DUMP(void) = 2; - - /* - * Removes the mount list entry for the directory - * Unix authentication required. - */ - void - MOUNTPROC_UMNT(dirpath) = 3; - - /* - * Removes all of the mount list entries for this client - * Unix authentication required. - */ - void - MOUNTPROC_UMNTALL(void) = 4; - - /* - * Returns a list of all the exported filesystems, and which - * machines are allowed to import it. - */ - exports - MOUNTPROC_EXPORT(void) = 5; - - /* - * Identical to MOUNTPROC_EXPORT above - */ - exports - MOUNTPROC_EXPORTALL(void) = 6; - } = 1; -} = 100005; diff --git a/mount/mount_clnt.c b/mount/mount_clnt.c deleted file mode 100644 index bc6e5122..00000000 --- a/mount/mount_clnt.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#include /* for memset */ -#include "mount.h" - -/* Default timeout can be changed using clnt_control() */ -static struct timeval TIMEOUT = { 25, 0 }; - -void * -mountproc_null_1(void *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_NULL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -fhstatus * -mountproc_mnt_1(dirpath *argp, CLIENT *clnt) -{ - static fhstatus clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_MNT, xdr_dirpath, argp, xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -mountlist * -mountproc_dump_1(void *argp, CLIENT *clnt) -{ - static mountlist clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_DUMP, xdr_void, argp, xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -void * -mountproc_umnt_1(dirpath *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_UMNT, xdr_dirpath, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -void * -mountproc_umntall_1(void *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_UMNTALL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -exports * -mountproc_export_1(void *argp, CLIENT *clnt) -{ - static exports clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_EXPORT, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -exports * -mountproc_exportall_1(void *argp, CLIENT *clnt) -{ - static exports clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_EXPORTALL, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} diff --git a/mount/mount_constants.h b/mount/mount_constants.h new file mode 100644 index 00000000..c0ae4984 --- /dev/null +++ b/mount/mount_constants.h @@ -0,0 +1,17 @@ +#define MS_RDONLY 1 /* Mount read-only */ +#define MS_NOSUID 2 /* Ignore suid and sgid bits */ +#define MS_NODEV 4 /* Disallow access to device special files */ +#define MS_NOEXEC 8 /* Disallow program execution */ +#define MS_SYNCHRONOUS 16 /* Writes are synced at once */ +#define MS_REMOUNT 32 /* Alter flags of a mounted FS */ +#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ +#define S_WRITE 128 /* Write on file/directory/symlink */ +#define S_APPEND 256 /* Append-only file */ +#define S_IMMUTABLE 512 /* Immutable file */ +#define MS_NOATIME 1024 /* Do not update access times. */ + +/* + * Magic mount flag number. Has to be or-ed to the flag values. + */ +#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */ +#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ diff --git a/mount/mount_xdr.c b/mount/mount_xdr.c deleted file mode 100644 index be5eb41f..00000000 --- a/mount/mount_xdr.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#include "mount.h" - -bool_t -xdr_fhandle(XDR *xdrs, fhandle objp) -{ - - register long *buf; - - if (!xdr_opaque(xdrs, objp, FHSIZE)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_fhstatus(XDR *xdrs, fhstatus *objp) -{ - - register long *buf; - - if (!xdr_u_int(xdrs, &objp->fhs_status)) { - return (FALSE); - } - switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) { - return (FALSE); - } - break; - default: - break; - } - return (TRUE); -} - -bool_t -xdr_dirpath(XDR *xdrs, dirpath *objp) -{ - - register long *buf; - - if (!xdr_string(xdrs, objp, MNTPATHLEN)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_name(XDR *xdrs, name *objp) -{ - - register long *buf; - - if (!xdr_string(xdrs, objp, MNTNAMLEN)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_mountlist(XDR *xdrs, mountlist *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_mountbody(XDR *xdrs, mountbody *objp) -{ - - register long *buf; - - if (!xdr_name(xdrs, &objp->ml_hostname)) { - return (FALSE); - } - if (!xdr_dirpath(xdrs, &objp->ml_directory)) { - return (FALSE); - } - if (!xdr_mountlist(xdrs, &objp->ml_next)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_groups(XDR *xdrs, groups *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_groupnode(XDR *xdrs, groupnode *objp) -{ - - register long *buf; - - if (!xdr_name(xdrs, &objp->gr_name)) { - return (FALSE); - } - if (!xdr_groups(xdrs, &objp->gr_next)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_exports(XDR *xdrs, exports *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_exportnode(XDR *xdrs, exportnode *objp) -{ - - register long *buf; - - if (!xdr_dirpath(xdrs, &objp->ex_dir)) { - return (FALSE); - } - if (!xdr_groups(xdrs, &objp->ex_groups)) { - return (FALSE); - } - if (!xdr_exports(xdrs, &objp->ex_next)) { - return (FALSE); - } - return (TRUE); -} diff --git a/mount/nfs_mount3.h b/mount/nfs_mount3.h new file mode 100644 index 00000000..e5c2b2fe --- /dev/null +++ b/mount/nfs_mount3.h @@ -0,0 +1,57 @@ +/* + * We want to be able to compile mount on old kernels in such a way + * that the binary will work well on more recent kernels. + * Thus, if necessary we teach nfsmount.c the structure of new fields + * that will come later. + */ +#include "nfs_mountversion.h" + +#if KERNEL_NFS_MOUNT_VERSION >= 3 + +/* + * The kernel includes are at least as good as this file. + * Use them. + */ +#include + +#else /* KERNEL_NFS_MOUNT_VERSION < 3 */ + +/* + * We know more than the kernel. Override the kernel defines. + * Check at runtime whether the running kernel can handle the new stuff. + */ +#define NFS_MOUNT_VERSION 3 + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs_fh root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT 0x0001 /* 1 */ +#define NFS_MOUNT_INTR 0x0002 /* 1 */ +#define NFS_MOUNT_SECURE 0x0004 /* 1 */ +#define NFS_MOUNT_POSIX 0x0008 /* 1 */ +#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ +#define NFS_MOUNT_NOAC 0x0020 /* 1 */ +#define NFS_MOUNT_TCP 0x0040 /* 2 */ +#define NFS_MOUNT_VER3 0x0080 /* 3 */ +#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ +#define NFS_MOUNT_NONLM 0x0200 /* 3 */ + +#endif diff --git a/mount/nfsmount.c b/mount/nfsmount.c index 9be51be0..ee869dc4 100644 --- a/mount/nfsmount.c +++ b/mount/nfsmount.c @@ -14,44 +14,87 @@ * * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port * numbers to be specified on the command line. + * + * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : + * Omit the call to connect() for Linux version 1.3.11 or later. */ /* * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp */ +#include #include +#include +#include +#include #include #include #include #include #include -#include -#include +#include #include -#include #include "sundries.h" +#include "nfsmount.h" -#include "mount.h" - +#if defined(__GLIBC__) +#define _LINUX_SOCKET_H +#endif /* __GLIBC__ */ +#define _I386_BITOPS_H #include #include -#include - -static char *strndup (char *str, int n) { - char *ret; - ret = malloc (n+1); - if (ret == NULL) { - perror ("malloc"); - return (NULL); - } - strncpy (ret, str, n); - return (ret); -} +#include "nfs_mount3.h" static char *nfs_strerror(int stat); +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) + +static int +linux_version_code(void) { + struct utsname my_utsname; + int p, q, r; + + if (uname(&my_utsname) == 0) { + p = atoi(strtok(my_utsname.release, ".")); + q = atoi(strtok(NULL, ".")); + r = atoi(strtok(NULL, ".")); + return MAKE_VERSION(p,q,r); + } + return 0; +} + +/* + * nfs_mount_version according to the kernel sources seen at compile time. + */ +static int nfs_mount_version = KERNEL_NFS_MOUNT_VERSION; + +/* + * Unfortunately, the kernel prints annoying console messages + * in case of an unexpected nfs mount version (instead of + * just returning some error). Therefore we'll have to try + * and figure out what version the kernel expects. + * + * Variables: + * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time + * NFS_MOUNT_VERSION: these nfsmount sources at compile time + * nfs_mount_version: version this source and running kernel can handle + */ +static void +find_kernel_nfs_mount_version(void) { + int kernel_version = linux_version_code(); + + if (kernel_version) { + if (kernel_version < MAKE_VERSION(2,1,32)) + nfs_mount_version = 1; + else + nfs_mount_version = 3; + } + if (nfs_mount_version > NFS_MOUNT_VERSION) + nfs_mount_version = NFS_MOUNT_VERSION; +} + int nfsmount(const char *spec, const char *node, int *flags, char **extra_opts, char **mount_opts) { @@ -83,6 +126,7 @@ int nfsmount(const char *spec, const char *node, int *flags, int posix; int nocto; int noac; + int nolock; int retry; int tcp; int mountprog; @@ -90,8 +134,15 @@ int nfsmount(const char *spec, const char *node, int *flags, int nfsprog; int nfsvers; + find_kernel_nfs_mount_version(); + msock = fsock = -1; mclient = NULL; + if (strlen(spec) >= sizeof(hostdir)) { + fprintf(stderr, "mount: " + "excessively long host:dir argument\n"); + goto fail; + } strcpy(hostdir, spec); if ((s = (strchr(hostdir, ':')))) { hostname = hostdir; @@ -104,36 +155,38 @@ int nfsmount(const char *spec, const char *node, int *flags, goto fail; } - if (hostname[0] >= '0' && hostname[0] <= '9') { - server_addr.sin_family = AF_INET; - server_addr.sin_addr.s_addr = inet_addr(hostname); - } - else if ((hp = gethostbyname(hostname)) == NULL) { - fprintf(stderr, "mount: can't get address for %s\n", hostname); - goto fail; - } - else { - server_addr.sin_family = AF_INET; - memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); + server_addr.sin_family = AF_INET; + if (!inet_aton(hostname, &server_addr.sin_addr)) { + if ((hp = gethostbyname(hostname)) == NULL) { + fprintf(stderr, "mount: can't get address for %s\n", + hostname); + goto fail; + } else + memcpy(&server_addr.sin_addr, hp->h_addr, hp->h_length); } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); /* add IP address to mtab options for use when unmounting */ + s = inet_ntoa(server_addr.sin_addr); old_opts = *extra_opts; if (!old_opts) old_opts = ""; + if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { + fprintf(stderr, "mount: " + "excessively long option argument\n"); + goto fail; + } sprintf(new_opts, "%s%saddr=%s", - old_opts, *old_opts ? "," : "", - inet_ntoa(server_addr.sin_addr)); - *extra_opts = strdup(new_opts); - - /* set default options */ - - data.rsize = 0; /* let kernel decide */ - data.wsize = 0; /* let kernel decide */ - data.timeo = 7; + old_opts, *old_opts ? "," : "", s); + *extra_opts = xstrdup(new_opts); + + /* Set default options. + * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to + * let the kernel decide. + * timeo is filled in after we know whether it'll be TCP or UDP. */ + memset(&data, 0, sizeof(data)); data.retrans = 3; data.acregmin = 3; data.acregmax = 60; @@ -148,6 +201,7 @@ int nfsmount(const char *spec, const char *node, int *flags, intr = 0; posix = 0; nocto = 0; + nolock = 0; noac = 0; retry = 10000; tcp = 0; @@ -194,7 +248,7 @@ int nfsmount(const char *spec, const char *node, int *flags, else if (!strcmp(opt, "mountport")) mountport = val; else if (!strcmp(opt, "mounthost")) - mounthost=strndup(opteq+1, + mounthost=xstrndup(opteq+1, strcspn(opteq+1," \t\n\r,")); else if (!strcmp(opt, "mountprog")) mountprog = val; @@ -206,10 +260,11 @@ int nfsmount(const char *spec, const char *node, int *flags, nfsvers = val; else if (!strcmp(opt, "namlen")) { #if NFS_MOUNT_VERSION >= 2 - data.namlen = val; -#else - printf("Warning: Option namlen is not supported.\n"); + if (nfs_mount_version >= 2) + data.namlen = val; + else #endif + printf("Warning: Option namlen is not supported.\n"); } else if (!strcmp(opt, "addr")) /* ignore */; @@ -245,7 +300,12 @@ int nfsmount(const char *spec, const char *node, int *flags, tcp = val; else if (!strcmp(opt, "udp")) tcp = !val; - else { + else if (!strcmp(opt, "lock")) { + if (nfs_mount_version >= 3) + nolock = !val; + else + printf("Warning: option nolock is not supported.\n"); + } else { printf("unknown nfs mount option: " "%s%s\n", val ? "" : "no", opt); goto fail; @@ -258,9 +318,18 @@ int nfsmount(const char *spec, const char *node, int *flags, | (nocto ? NFS_MOUNT_NOCTO : 0) | (noac ? NFS_MOUNT_NOAC : 0); #if NFS_MOUNT_VERSION >= 2 - data.flags |= (tcp ? NFS_MOUNT_TCP : 0); + if (nfs_mount_version >= 2) + data.flags |= (tcp ? NFS_MOUNT_TCP : 0); +#endif +#if NFS_MOUNT_VERSION >= 3 + if (nfs_mount_version >= 3) + data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); #endif + /* Adjust options if none specified */ + if (!data.timeo) + data.timeo = tcp ? 70 : 7; + #ifdef NFS_MOUNT_DEBUG printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", data.rsize, data.wsize, data.timeo, data.retrans); @@ -285,7 +354,7 @@ int nfsmount(const char *spec, const char *node, int *flags, #endif #endif - data.version = NFS_MOUNT_VERSION; + data.version = nfs_mount_version; *mount_opts = (char *) &data; if (*flags & MS_REMOUNT) @@ -336,8 +405,8 @@ int nfsmount(const char *spec, const char *node, int *flags, /* try to mount hostname:dirname */ clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, - xdr_dirpath, &dirname, - xdr_fhstatus, &status, + (xdrproc_t) xdr_dirpath, &dirname, + (xdrproc_t) xdr_fhstatus, &status, total_timeout); if (clnt_stat != RPC_SUCCESS) { clnt_perror(mclient, "rpc mount"); @@ -355,14 +424,12 @@ int nfsmount(const char *spec, const char *node, int *flags, /* create nfs socket for kernel */ if (tcp) { -#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version < 3) { + printf("NFS over TCP is not supported.\n"); + goto fail; + } fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); -#else - printf("NFS over TCP is not supported.\n"); - goto fail; -#endif - } - else + } else fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fsock < 0) { perror("nfs socket"); @@ -387,8 +454,14 @@ int nfsmount(const char *spec, const char *node, int *flags, printf("using port %d for nfs deamon\n", port); #endif server_addr.sin_port = htons(port); - if (connect(fsock, (struct sockaddr *) &server_addr, - sizeof (server_addr)) < 0) { + /* + * connect() the socket for kernels 1.3.10 and below only, + * to avoid problems with multihomed hosts. + * --Swen + */ + if (linux_version_code() <= 66314 + && connect(fsock, (struct sockaddr *) &server_addr, + sizeof (server_addr)) < 0) { perror("nfs connect"); goto fail; } @@ -418,12 +491,17 @@ fail: } if (fsock != -1) close(fsock); - return 1;} + return 1; +} /* * We need to translate between nfs status return values and * the local errno values which may not be the same. + * + * Andreas Schwab : change errno: + * "after #include the symbol errno is reserved for any use, + * it cannot even be used as a struct tag or field name". */ #ifndef EDQUOT @@ -432,7 +510,7 @@ fail: static struct { enum nfs_stat stat; - int errno; + int errnum; } nfs_errtbl[] = { { NFS_OK, 0 }, { NFSERR_PERM, EPERM }, @@ -457,6 +535,9 @@ static struct { #ifdef EWFLUSH { NFSERR_WFLUSH, EWFLUSH }, #endif + /* Throw in some NFSv3 values for even more fun (HP returns these) */ + { 71, EREMOTE }, + { -1, EIO } }; @@ -467,7 +548,7 @@ static char *nfs_strerror(int stat) for (i = 0; nfs_errtbl[i].stat != -1; i++) { if (nfs_errtbl[i].stat == stat) - return strerror(nfs_errtbl[i].errno); + return strerror(nfs_errtbl[i].errnum); } sprintf(buf, "unknown nfs status return value: %d", stat); return buf; diff --git a/mount/mount.h b/mount/nfsmount.h similarity index 55% rename from mount/mount.h rename to mount/nfsmount.h index d70ccaf9..73c71fc6 100644 --- a/mount/mount.h +++ b/mount/nfsmount.h @@ -3,11 +3,47 @@ * It was generated using rpcgen. */ -#ifndef _MOUNT_H_RPCGEN -#define _MOUNT_H_RPCGEN +#ifndef _NFSMOUNT_H_RPCGEN +#define _NFSMOUNT_H_RPCGEN #include +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ +#ifndef _rpcsvc_mount_h +#define _rpcsvc_mount_h #define MNTPATHLEN 1024 #define MNTNAMLEN 255 #define FHSIZE 32 @@ -132,6 +168,28 @@ bool_t xdr_exportnode(); #endif /* Old Style C */ +struct ppathcnf { + int pc_link_max; + short pc_max_canon; + short pc_max_input; + short pc_name_max; + short pc_path_max; + short pc_pipe_buf; + u_char pc_vdisable; + char pc_xxx; + short pc_mask[2]; +}; +typedef struct ppathcnf ppathcnf; +#ifdef __cplusplus +extern "C" bool_t xdr_ppathcnf(XDR *, ppathcnf*); +#elif __STDC__ +extern bool_t xdr_ppathcnf(XDR *, ppathcnf*); +#else /* Old Style C */ +bool_t xdr_ppathcnf(); +#endif /* Old Style C */ + +#endif /*!_rpcsvc_mount_h*/ + #define MOUNTPROG ((u_long)100005) #define MOUNTVERS ((u_long)1) @@ -204,5 +262,64 @@ extern exports * mountproc_export_1_svc(); extern exports * mountproc_exportall_1(); extern exports * mountproc_exportall_1_svc(); #endif /* Old Style C */ +#define MOUNTVERS_POSIX ((u_long)2) + +#ifdef __cplusplus +extern "C" void * mountproc_null_2(void *, CLIENT *); +extern "C" void * mountproc_null_2_svc(void *, struct svc_req *); +extern "C" fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern "C" fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern "C" mountlist * mountproc_dump_2(void *, CLIENT *); +extern "C" mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern "C" void * mountproc_umnt_2(dirpath *, CLIENT *); +extern "C" void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern "C" void * mountproc_umntall_2(void *, CLIENT *); +extern "C" void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern "C" exports * mountproc_export_2(void *, CLIENT *); +extern "C" exports * mountproc_export_2_svc(void *, struct svc_req *); +extern "C" exports * mountproc_exportall_2(void *, CLIENT *); +extern "C" exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern "C" ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern "C" ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); + +#elif __STDC__ +extern void * mountproc_null_2(void *, CLIENT *); +extern void * mountproc_null_2_svc(void *, struct svc_req *); +extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern mountlist * mountproc_dump_2(void *, CLIENT *); +extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern void * mountproc_umnt_2(dirpath *, CLIENT *); +extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern void * mountproc_umntall_2(void *, CLIENT *); +extern void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern exports * mountproc_export_2(void *, CLIENT *); +extern exports * mountproc_export_2_svc(void *, struct svc_req *); +extern exports * mountproc_exportall_2(void *, CLIENT *); +extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); + +#else /* Old Style C */ +extern void * mountproc_null_2(); +extern void * mountproc_null_2_svc(); +extern fhstatus * mountproc_mnt_2(); +extern fhstatus * mountproc_mnt_2_svc(); +extern mountlist * mountproc_dump_2(); +extern mountlist * mountproc_dump_2_svc(); +extern void * mountproc_umnt_2(); +extern void * mountproc_umnt_2_svc(); +extern void * mountproc_umntall_2(); +extern void * mountproc_umntall_2_svc(); +extern exports * mountproc_export_2(); +extern exports * mountproc_export_2_svc(); +extern exports * mountproc_exportall_2(); +extern exports * mountproc_exportall_2_svc(); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern ppathcnf * mountproc_pathconf_2(); +extern ppathcnf * mountproc_pathconf_2_svc(); +#endif /* Old Style C */ -#endif /* !_MOUNT_H_RPCGEN */ +#endif /* !_NFSMOUNT_H_RPCGEN */ diff --git a/mount/nfsmount.x b/mount/nfsmount.x new file mode 100644 index 00000000..90590eb2 --- /dev/null +++ b/mount/nfsmount.x @@ -0,0 +1,259 @@ +%/* +% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for +% * unrestricted use provided that this legend is included on all tape +% * media and as a part of the software program in whole or part. Users +% * may copy or modify Sun RPC without charge, but are not authorized +% * to license or distribute it to anyone else except as part of a product or +% * program developed by the user or with the express written consent of +% * Sun Microsystems, Inc. +% * +% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE +% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR +% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. +% * +% * Sun RPC is provided with no support and without any obligation on the +% * part of Sun Microsystems, Inc. to assist in its use, correction, +% * modification or enhancement. +% * +% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE +% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC +% * OR ANY PART THEREOF. +% * +% * In no event will Sun Microsystems, Inc. be liable for any lost revenue +% * or profits or other special, indirect and consequential damages, even if +% * Sun has been advised of the possibility of such damages. +% * +% * Sun Microsystems, Inc. +% * 2550 Garcia Avenue +% * Mountain View, California 94043 +% */ + +%/* +% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. +% */ +% +%/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +/* + * Protocol description for the mount program + */ + +#ifdef RPC_HDR +%#ifndef _rpcsvc_mount_h +%#define _rpcsvc_mount_h +#endif + +#ifdef RPC_CLNT +%#include /* for memset() */ +#endif + +const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ +const MNTNAMLEN = 255; /* maximum bytes in a name argument */ +const FHSIZE = 32; /* size in bytes of a file handle */ + +/* + * The fhandle is the file handle that the server passes to the client. + * All file operations are done using the file handles to refer to a file + * or a directory. The file handle can contain whatever information the + * server needs to distinguish an individual file. + */ +typedef opaque fhandle[FHSIZE]; + +/* + * If a status of zero is returned, the call completed successfully, and + * a file handle for the directory follows. A non-zero status indicates + * some sort of error. The status corresponds with UNIX error numbers. + */ +union fhstatus switch (unsigned fhs_status) { +case 0: + fhandle fhs_fhandle; +default: + void; +}; + +/* + * The type dirpath is the pathname of a directory + */ +typedef string dirpath; + +/* + * The type name is used for arbitrary names (hostnames, groupnames) + */ +typedef string name; + +/* + * A list of who has what mounted + */ +typedef struct mountbody *mountlist; +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; + +/* + * A list of netgroups + */ +typedef struct groupnode *groups; +struct groupnode { + name gr_name; + groups gr_next; +}; + +/* + * A list of what is exported and to whom + */ +typedef struct exportnode *exports; +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; + +/* + * POSIX pathconf information + */ +struct ppathcnf { + int pc_link_max; /* max links allowed */ + short pc_max_canon; /* max line len for a tty */ + short pc_max_input; /* input a tty can eat all at once */ + short pc_name_max; /* max file name length (dir entry) */ + short pc_path_max; /* max path name length (/x/y/x/.. ) */ + short pc_pipe_buf; /* size of a pipe (bytes) */ + u_char pc_vdisable; /* safe char to turn off c_cc[i] */ + char pc_xxx; /* alignment padding; cc_t == char */ + short pc_mask[2]; /* validity and boolean bits */ +}; + +program MOUNTPROG { + /* + * Version one of the mount protocol communicates with version two + * of the NFS protocol. The only connecting point is the fhandle + * structure, which is the same for both protocols. + */ + version MOUNTVERS { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + } = 1; + + /* + * Version two of the mount protocol communicates with version two + * of the NFS protocol. + * The only difference from version one is the addition of a POSIX + * pathconf call. + */ + version MOUNTVERS_POSIX { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + + /* + * POSIX pathconf info (Sun hack) + */ + ppathcnf + MOUNTPROC_PATHCONF(dirpath) = 7; + } = 2; +} = 100005; + +#ifdef RPC_HDR +%#endif /*!_rpcsvc_mount_h*/ +#endif diff --git a/mount/nfsmount_clnt.c b/mount/nfsmount_clnt.c new file mode 100644 index 00000000..a77f4c5e --- /dev/null +++ b/mount/nfsmount_clnt.c @@ -0,0 +1,255 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfsmount.h" +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +#include /* for memset() */ + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +void * +mountproc_null_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +fhstatus * +mountproc_mnt_1(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static fhstatus clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +mountlist * +mountproc_dump_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static mountlist clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_umnt_1(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +void * +mountproc_umntall_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +exports * +mountproc_export_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +exports * +mountproc_exportall_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_null_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +fhstatus * +mountproc_mnt_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static fhstatus clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +mountlist * +mountproc_dump_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static mountlist clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_umnt_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +void * +mountproc_umntall_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +exports * +mountproc_export_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +exports * +mountproc_exportall_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +ppathcnf * +mountproc_pathconf_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static ppathcnf clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_PATHCONF, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_ppathcnf, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} diff --git a/mount/nfsmount_xdr.c b/mount/nfsmount_xdr.c new file mode 100644 index 00000000..6f539c24 --- /dev/null +++ b/mount/nfsmount_xdr.c @@ -0,0 +1,351 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfsmount.h" +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +bool_t +xdr_fhandle(xdrs, objp) + XDR *xdrs; + fhandle objp; +{ + + register long *buf; + + if (!xdr_opaque(xdrs, objp, FHSIZE)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_fhstatus(xdrs, objp) + XDR *xdrs; + fhstatus *objp; +{ + + register long *buf; + + if (!xdr_u_int(xdrs, &objp->fhs_status)) { + return (FALSE); + } + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) { + return (FALSE); + } + break; + } + return (TRUE); +} + +bool_t +xdr_dirpath(xdrs, objp) + XDR *xdrs; + dirpath *objp; +{ + + register long *buf; + + if (!xdr_string(xdrs, objp, MNTPATHLEN)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_name(xdrs, objp) + XDR *xdrs; + name *objp; +{ + + register long *buf; + + if (!xdr_string(xdrs, objp, MNTNAMLEN)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mountlist(xdrs, objp) + XDR *xdrs; + mountlist *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mountbody(xdrs, objp) + XDR *xdrs; + mountbody *objp; +{ + + register long *buf; + + if (!xdr_name(xdrs, &objp->ml_hostname)) { + return (FALSE); + } + if (!xdr_dirpath(xdrs, &objp->ml_directory)) { + return (FALSE); + } + if (!xdr_mountlist(xdrs, &objp->ml_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_groups(xdrs, objp) + XDR *xdrs; + groups *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_groupnode(xdrs, objp) + XDR *xdrs; + groupnode *objp; +{ + + register long *buf; + + if (!xdr_name(xdrs, &objp->gr_name)) { + return (FALSE); + } + if (!xdr_groups(xdrs, &objp->gr_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_exports(xdrs, objp) + XDR *xdrs; + exports *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_exportnode(xdrs, objp) + XDR *xdrs; + exportnode *objp; +{ + + register long *buf; + + if (!xdr_dirpath(xdrs, &objp->ex_dir)) { + return (FALSE); + } + if (!xdr_groups(xdrs, &objp->ex_groups)) { + return (FALSE); + } + if (!xdr_exports(xdrs, &objp->ex_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_ppathcnf(xdrs, objp) + XDR *xdrs; + ppathcnf *objp; +{ + + register long *buf; + + int i; + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs,6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + + } + else { + IXDR_PUT_LONG(buf,objp->pc_link_max); + IXDR_PUT_SHORT(buf,objp->pc_max_canon); + IXDR_PUT_SHORT(buf,objp->pc_max_input); + IXDR_PUT_SHORT(buf,objp->pc_name_max); + IXDR_PUT_SHORT(buf,objp->pc_path_max); + IXDR_PUT_SHORT(buf,objp->pc_pipe_buf); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + + } + else { + { register short *genp; + for ( i = 0,genp=objp->pc_mask; + i < 2; i++){ + IXDR_PUT_SHORT(buf,*genp++); + } + }; + } + + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs,6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + + } + else { + objp->pc_link_max = IXDR_GET_LONG(buf); + objp->pc_max_canon = IXDR_GET_SHORT(buf); + objp->pc_max_input = IXDR_GET_SHORT(buf); + objp->pc_name_max = IXDR_GET_SHORT(buf); + objp->pc_path_max = IXDR_GET_SHORT(buf); + objp->pc_pipe_buf = IXDR_GET_SHORT(buf); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + + } + else { + { register short *genp; + for ( i = 0,genp=objp->pc_mask; + i < 2; i++){ + *genp++ = IXDR_GET_SHORT(buf); + } + }; + } + return(TRUE); + } + + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + return (TRUE); +} diff --git a/mount/realpath.c b/mount/realpath.c index 4ea46a31..4214cad7 100644 --- a/mount/realpath.c +++ b/mount/realpath.c @@ -13,8 +13,11 @@ * GNU Library Public License for more details. */ +#define HAVE_GETCWD + /* - * realpath.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp + * This routine is part of libc. We include it nevertheless, + * since the libc version has some security flaws. */ #ifdef __linux__ @@ -79,9 +82,14 @@ char *resolved_path; int n; /* Make a copy of the source path since we may need to modify it. */ + if (strlen(path) >= PATH_MAX) { + errno = ENAMETOOLONG; + return NULL; + } strcpy(copy_path, path); path = copy_path; max_path = copy_path + PATH_MAX - 2; + /* If it's a relative pathname use getwd for starters. */ if (*path != '/') { #ifdef HAVE_GETCWD diff --git a/mount/rpcsvc/mount.x b/mount/rpcsvc/mount.x deleted file mode 100644 index 7e0d7f3a..00000000 --- a/mount/rpcsvc/mount.x +++ /dev/null @@ -1,161 +0,0 @@ -/* @(#)mount.x 2.1 88/08/01 4.0 RPCSRC */ -/* @(#)mount.x 1.2 87/09/18 Copyr 1987 Sun Micro */ - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ - -/* - * Protocol description for the mount program - */ - - -const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ -const MNTNAMLEN = 255; /* maximum bytes in a name argument */ -const FHSIZE = 32; /* size in bytes of a file handle */ - -/* - * The fhandle is the file handle that the server passes to the client. - * All file operations are done using the file handles to refer to a file - * or a directory. The file handle can contain whatever information the - * server needs to distinguish an individual file. - */ -typedef opaque fhandle[FHSIZE]; - -/* - * If a status of zero is returned, the call completed successfully, and - * a file handle for the directory follows. A non-zero status indicates - * some sort of error. The status corresponds with UNIX error numbers. - */ -union fhstatus switch (unsigned fhs_status) { -case 0: - fhandle fhs_fhandle; -default: - void; -}; - -/* - * The type dirpath is the pathname of a directory - */ -typedef string dirpath; - -/* - * The type name is used for arbitrary names (hostnames, groupnames) - */ -typedef string name; - -/* - * A list of who has what mounted - */ -typedef struct mountbody *mountlist; -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; - -/* - * A list of netgroups - */ -typedef struct groupnode *groups; -struct groupnode { - name gr_name; - groups gr_next; -}; - -/* - * A list of what is exported and to whom - */ -typedef struct exportnode *exports; -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; - -program MOUNTPROG { - /* - * Version one of the mount protocol communicates with version two - * of the NFS protocol. The only connecting point is the fhandle - * structure, which is the same for both protocols. - */ - version MOUNTVERS { - /* - * Does no work. It is made available in all RPC services - * to allow server reponse testing and timing - */ - void - MOUNTPROC_NULL(void) = 0; - - /* - * If fhs_status is 0, then fhs_fhandle contains the - * file handle for the directory. This file handle may - * be used in the NFS protocol. This procedure also adds - * a new entry to the mount list for this client mounting - * the directory. - * Unix authentication required. - */ - fhstatus - MOUNTPROC_MNT(dirpath) = 1; - - /* - * Returns the list of remotely mounted filesystems. The - * mountlist contains one entry for each hostname and - * directory pair. - */ - mountlist - MOUNTPROC_DUMP(void) = 2; - - /* - * Removes the mount list entry for the directory - * Unix authentication required. - */ - void - MOUNTPROC_UMNT(dirpath) = 3; - - /* - * Removes all of the mount list entries for this client - * Unix authentication required. - */ - void - MOUNTPROC_UMNTALL(void) = 4; - - /* - * Returns a list of all the exported filesystems, and which - * machines are allowed to import it. - */ - exports - MOUNTPROC_EXPORT(void) = 5; - - /* - * Identical to MOUNTPROC_EXPORT above - */ - exports - MOUNTPROC_EXPORTALL(void) = 6; - } = 1; -} = 100005; diff --git a/mount/rpcsvc/mount_clnt.c b/mount/rpcsvc/mount_clnt.c deleted file mode 100644 index bc6e5122..00000000 --- a/mount/rpcsvc/mount_clnt.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#include /* for memset */ -#include "mount.h" - -/* Default timeout can be changed using clnt_control() */ -static struct timeval TIMEOUT = { 25, 0 }; - -void * -mountproc_null_1(void *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_NULL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -fhstatus * -mountproc_mnt_1(dirpath *argp, CLIENT *clnt) -{ - static fhstatus clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_MNT, xdr_dirpath, argp, xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -mountlist * -mountproc_dump_1(void *argp, CLIENT *clnt) -{ - static mountlist clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_DUMP, xdr_void, argp, xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -void * -mountproc_umnt_1(dirpath *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_UMNT, xdr_dirpath, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -void * -mountproc_umntall_1(void *argp, CLIENT *clnt) -{ - static char clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_UMNTALL, xdr_void, argp, xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return ((void *)&clnt_res); -} - -exports * -mountproc_export_1(void *argp, CLIENT *clnt) -{ - static exports clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_EXPORT, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} - -exports * -mountproc_exportall_1(void *argp, CLIENT *clnt) -{ - static exports clnt_res; - - memset((char *)&clnt_res, 0, sizeof(clnt_res)); - if (clnt_call(clnt, MOUNTPROC_EXPORTALL, xdr_void, argp, xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { - return (NULL); - } - return (&clnt_res); -} diff --git a/mount/rpcsvc/mount_xdr.c b/mount/rpcsvc/mount_xdr.c deleted file mode 100644 index be5eb41f..00000000 --- a/mount/rpcsvc/mount_xdr.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Please do not edit this file. - * It was generated using rpcgen. - */ - -#include "mount.h" - -bool_t -xdr_fhandle(XDR *xdrs, fhandle objp) -{ - - register long *buf; - - if (!xdr_opaque(xdrs, objp, FHSIZE)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_fhstatus(XDR *xdrs, fhstatus *objp) -{ - - register long *buf; - - if (!xdr_u_int(xdrs, &objp->fhs_status)) { - return (FALSE); - } - switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) { - return (FALSE); - } - break; - default: - break; - } - return (TRUE); -} - -bool_t -xdr_dirpath(XDR *xdrs, dirpath *objp) -{ - - register long *buf; - - if (!xdr_string(xdrs, objp, MNTPATHLEN)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_name(XDR *xdrs, name *objp) -{ - - register long *buf; - - if (!xdr_string(xdrs, objp, MNTNAMLEN)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_mountlist(XDR *xdrs, mountlist *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_mountbody(XDR *xdrs, mountbody *objp) -{ - - register long *buf; - - if (!xdr_name(xdrs, &objp->ml_hostname)) { - return (FALSE); - } - if (!xdr_dirpath(xdrs, &objp->ml_directory)) { - return (FALSE); - } - if (!xdr_mountlist(xdrs, &objp->ml_next)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_groups(XDR *xdrs, groups *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_groupnode(XDR *xdrs, groupnode *objp) -{ - - register long *buf; - - if (!xdr_name(xdrs, &objp->gr_name)) { - return (FALSE); - } - if (!xdr_groups(xdrs, &objp->gr_next)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_exports(XDR *xdrs, exports *objp) -{ - - register long *buf; - - if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) { - return (FALSE); - } - return (TRUE); -} - -bool_t -xdr_exportnode(XDR *xdrs, exportnode *objp) -{ - - register long *buf; - - if (!xdr_dirpath(xdrs, &objp->ex_dir)) { - return (FALSE); - } - if (!xdr_groups(xdrs, &objp->ex_groups)) { - return (FALSE); - } - if (!xdr_exports(xdrs, &objp->ex_next)) { - return (FALSE); - } - return (TRUE); -} diff --git a/mount/rpcsvc/mount.h b/mount/rpcsvc/nfsmount.h similarity index 55% rename from mount/rpcsvc/mount.h rename to mount/rpcsvc/nfsmount.h index d70ccaf9..73c71fc6 100644 --- a/mount/rpcsvc/mount.h +++ b/mount/rpcsvc/nfsmount.h @@ -3,11 +3,47 @@ * It was generated using rpcgen. */ -#ifndef _MOUNT_H_RPCGEN -#define _MOUNT_H_RPCGEN +#ifndef _NFSMOUNT_H_RPCGEN +#define _NFSMOUNT_H_RPCGEN #include +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ +#ifndef _rpcsvc_mount_h +#define _rpcsvc_mount_h #define MNTPATHLEN 1024 #define MNTNAMLEN 255 #define FHSIZE 32 @@ -132,6 +168,28 @@ bool_t xdr_exportnode(); #endif /* Old Style C */ +struct ppathcnf { + int pc_link_max; + short pc_max_canon; + short pc_max_input; + short pc_name_max; + short pc_path_max; + short pc_pipe_buf; + u_char pc_vdisable; + char pc_xxx; + short pc_mask[2]; +}; +typedef struct ppathcnf ppathcnf; +#ifdef __cplusplus +extern "C" bool_t xdr_ppathcnf(XDR *, ppathcnf*); +#elif __STDC__ +extern bool_t xdr_ppathcnf(XDR *, ppathcnf*); +#else /* Old Style C */ +bool_t xdr_ppathcnf(); +#endif /* Old Style C */ + +#endif /*!_rpcsvc_mount_h*/ + #define MOUNTPROG ((u_long)100005) #define MOUNTVERS ((u_long)1) @@ -204,5 +262,64 @@ extern exports * mountproc_export_1_svc(); extern exports * mountproc_exportall_1(); extern exports * mountproc_exportall_1_svc(); #endif /* Old Style C */ +#define MOUNTVERS_POSIX ((u_long)2) + +#ifdef __cplusplus +extern "C" void * mountproc_null_2(void *, CLIENT *); +extern "C" void * mountproc_null_2_svc(void *, struct svc_req *); +extern "C" fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern "C" fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern "C" mountlist * mountproc_dump_2(void *, CLIENT *); +extern "C" mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern "C" void * mountproc_umnt_2(dirpath *, CLIENT *); +extern "C" void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern "C" void * mountproc_umntall_2(void *, CLIENT *); +extern "C" void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern "C" exports * mountproc_export_2(void *, CLIENT *); +extern "C" exports * mountproc_export_2_svc(void *, struct svc_req *); +extern "C" exports * mountproc_exportall_2(void *, CLIENT *); +extern "C" exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern "C" ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern "C" ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); + +#elif __STDC__ +extern void * mountproc_null_2(void *, CLIENT *); +extern void * mountproc_null_2_svc(void *, struct svc_req *); +extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern mountlist * mountproc_dump_2(void *, CLIENT *); +extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern void * mountproc_umnt_2(dirpath *, CLIENT *); +extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern void * mountproc_umntall_2(void *, CLIENT *); +extern void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern exports * mountproc_export_2(void *, CLIENT *); +extern exports * mountproc_export_2_svc(void *, struct svc_req *); +extern exports * mountproc_exportall_2(void *, CLIENT *); +extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); + +#else /* Old Style C */ +extern void * mountproc_null_2(); +extern void * mountproc_null_2_svc(); +extern fhstatus * mountproc_mnt_2(); +extern fhstatus * mountproc_mnt_2_svc(); +extern mountlist * mountproc_dump_2(); +extern mountlist * mountproc_dump_2_svc(); +extern void * mountproc_umnt_2(); +extern void * mountproc_umnt_2_svc(); +extern void * mountproc_umntall_2(); +extern void * mountproc_umntall_2_svc(); +extern exports * mountproc_export_2(); +extern exports * mountproc_export_2_svc(); +extern exports * mountproc_exportall_2(); +extern exports * mountproc_exportall_2_svc(); +#define MOUNTPROC_PATHCONF ((u_long)7) +extern ppathcnf * mountproc_pathconf_2(); +extern ppathcnf * mountproc_pathconf_2_svc(); +#endif /* Old Style C */ -#endif /* !_MOUNT_H_RPCGEN */ +#endif /* !_NFSMOUNT_H_RPCGEN */ diff --git a/mount/rpcsvc/nfsmount.x b/mount/rpcsvc/nfsmount.x new file mode 100644 index 00000000..90590eb2 --- /dev/null +++ b/mount/rpcsvc/nfsmount.x @@ -0,0 +1,259 @@ +%/* +% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for +% * unrestricted use provided that this legend is included on all tape +% * media and as a part of the software program in whole or part. Users +% * may copy or modify Sun RPC without charge, but are not authorized +% * to license or distribute it to anyone else except as part of a product or +% * program developed by the user or with the express written consent of +% * Sun Microsystems, Inc. +% * +% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE +% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR +% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. +% * +% * Sun RPC is provided with no support and without any obligation on the +% * part of Sun Microsystems, Inc. to assist in its use, correction, +% * modification or enhancement. +% * +% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE +% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC +% * OR ANY PART THEREOF. +% * +% * In no event will Sun Microsystems, Inc. be liable for any lost revenue +% * or profits or other special, indirect and consequential damages, even if +% * Sun has been advised of the possibility of such damages. +% * +% * Sun Microsystems, Inc. +% * 2550 Garcia Avenue +% * Mountain View, California 94043 +% */ + +%/* +% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. +% */ +% +%/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +/* + * Protocol description for the mount program + */ + +#ifdef RPC_HDR +%#ifndef _rpcsvc_mount_h +%#define _rpcsvc_mount_h +#endif + +#ifdef RPC_CLNT +%#include /* for memset() */ +#endif + +const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ +const MNTNAMLEN = 255; /* maximum bytes in a name argument */ +const FHSIZE = 32; /* size in bytes of a file handle */ + +/* + * The fhandle is the file handle that the server passes to the client. + * All file operations are done using the file handles to refer to a file + * or a directory. The file handle can contain whatever information the + * server needs to distinguish an individual file. + */ +typedef opaque fhandle[FHSIZE]; + +/* + * If a status of zero is returned, the call completed successfully, and + * a file handle for the directory follows. A non-zero status indicates + * some sort of error. The status corresponds with UNIX error numbers. + */ +union fhstatus switch (unsigned fhs_status) { +case 0: + fhandle fhs_fhandle; +default: + void; +}; + +/* + * The type dirpath is the pathname of a directory + */ +typedef string dirpath; + +/* + * The type name is used for arbitrary names (hostnames, groupnames) + */ +typedef string name; + +/* + * A list of who has what mounted + */ +typedef struct mountbody *mountlist; +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; + +/* + * A list of netgroups + */ +typedef struct groupnode *groups; +struct groupnode { + name gr_name; + groups gr_next; +}; + +/* + * A list of what is exported and to whom + */ +typedef struct exportnode *exports; +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; + +/* + * POSIX pathconf information + */ +struct ppathcnf { + int pc_link_max; /* max links allowed */ + short pc_max_canon; /* max line len for a tty */ + short pc_max_input; /* input a tty can eat all at once */ + short pc_name_max; /* max file name length (dir entry) */ + short pc_path_max; /* max path name length (/x/y/x/.. ) */ + short pc_pipe_buf; /* size of a pipe (bytes) */ + u_char pc_vdisable; /* safe char to turn off c_cc[i] */ + char pc_xxx; /* alignment padding; cc_t == char */ + short pc_mask[2]; /* validity and boolean bits */ +}; + +program MOUNTPROG { + /* + * Version one of the mount protocol communicates with version two + * of the NFS protocol. The only connecting point is the fhandle + * structure, which is the same for both protocols. + */ + version MOUNTVERS { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + } = 1; + + /* + * Version two of the mount protocol communicates with version two + * of the NFS protocol. + * The only difference from version one is the addition of a POSIX + * pathconf call. + */ + version MOUNTVERS_POSIX { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + + /* + * POSIX pathconf info (Sun hack) + */ + ppathcnf + MOUNTPROC_PATHCONF(dirpath) = 7; + } = 2; +} = 100005; + +#ifdef RPC_HDR +%#endif /*!_rpcsvc_mount_h*/ +#endif diff --git a/mount/rpcsvc/nfsmount_clnt.c b/mount/rpcsvc/nfsmount_clnt.c new file mode 100644 index 00000000..a77f4c5e --- /dev/null +++ b/mount/rpcsvc/nfsmount_clnt.c @@ -0,0 +1,255 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfsmount.h" +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +#include /* for memset() */ + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +void * +mountproc_null_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +fhstatus * +mountproc_mnt_1(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static fhstatus clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +mountlist * +mountproc_dump_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static mountlist clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_umnt_1(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +void * +mountproc_umntall_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +exports * +mountproc_export_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +exports * +mountproc_exportall_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_null_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_NULL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +fhstatus * +mountproc_mnt_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static fhstatus clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_fhstatus, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +mountlist * +mountproc_dump_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static mountlist clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_mountlist, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +void * +mountproc_umnt_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +void * +mountproc_umntall_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static char clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_void, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((void *)&clnt_res); +} + +exports * +mountproc_export_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +exports * +mountproc_exportall_2(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static exports clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp, (xdrproc_t) xdr_exports, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +ppathcnf * +mountproc_pathconf_2(argp, clnt) + dirpath *argp; + CLIENT *clnt; +{ + static ppathcnf clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, MOUNTPROC_PATHCONF, (xdrproc_t) xdr_dirpath, argp, (xdrproc_t) xdr_ppathcnf, &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} diff --git a/mount/rpcsvc/nfsmount_xdr.c b/mount/rpcsvc/nfsmount_xdr.c new file mode 100644 index 00000000..6f539c24 --- /dev/null +++ b/mount/rpcsvc/nfsmount_xdr.c @@ -0,0 +1,351 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "nfsmount.h" +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +bool_t +xdr_fhandle(xdrs, objp) + XDR *xdrs; + fhandle objp; +{ + + register long *buf; + + if (!xdr_opaque(xdrs, objp, FHSIZE)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_fhstatus(xdrs, objp) + XDR *xdrs; + fhstatus *objp; +{ + + register long *buf; + + if (!xdr_u_int(xdrs, &objp->fhs_status)) { + return (FALSE); + } + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) { + return (FALSE); + } + break; + } + return (TRUE); +} + +bool_t +xdr_dirpath(xdrs, objp) + XDR *xdrs; + dirpath *objp; +{ + + register long *buf; + + if (!xdr_string(xdrs, objp, MNTPATHLEN)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_name(xdrs, objp) + XDR *xdrs; + name *objp; +{ + + register long *buf; + + if (!xdr_string(xdrs, objp, MNTNAMLEN)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mountlist(xdrs, objp) + XDR *xdrs; + mountlist *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct mountbody), (xdrproc_t)xdr_mountbody)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mountbody(xdrs, objp) + XDR *xdrs; + mountbody *objp; +{ + + register long *buf; + + if (!xdr_name(xdrs, &objp->ml_hostname)) { + return (FALSE); + } + if (!xdr_dirpath(xdrs, &objp->ml_directory)) { + return (FALSE); + } + if (!xdr_mountlist(xdrs, &objp->ml_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_groups(xdrs, objp) + XDR *xdrs; + groups *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct groupnode), (xdrproc_t)xdr_groupnode)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_groupnode(xdrs, objp) + XDR *xdrs; + groupnode *objp; +{ + + register long *buf; + + if (!xdr_name(xdrs, &objp->gr_name)) { + return (FALSE); + } + if (!xdr_groups(xdrs, &objp->gr_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_exports(xdrs, objp) + XDR *xdrs; + exports *objp; +{ + + register long *buf; + + if (!xdr_pointer(xdrs, (char **)objp, sizeof(struct exportnode), (xdrproc_t)xdr_exportnode)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_exportnode(xdrs, objp) + XDR *xdrs; + exportnode *objp; +{ + + register long *buf; + + if (!xdr_dirpath(xdrs, &objp->ex_dir)) { + return (FALSE); + } + if (!xdr_groups(xdrs, &objp->ex_groups)) { + return (FALSE); + } + if (!xdr_exports(xdrs, &objp->ex_next)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_ppathcnf(xdrs, objp) + XDR *xdrs; + ppathcnf *objp; +{ + + register long *buf; + + int i; + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs,6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + + } + else { + IXDR_PUT_LONG(buf,objp->pc_link_max); + IXDR_PUT_SHORT(buf,objp->pc_max_canon); + IXDR_PUT_SHORT(buf,objp->pc_max_input); + IXDR_PUT_SHORT(buf,objp->pc_name_max); + IXDR_PUT_SHORT(buf,objp->pc_path_max); + IXDR_PUT_SHORT(buf,objp->pc_pipe_buf); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + + } + else { + { register short *genp; + for ( i = 0,genp=objp->pc_mask; + i < 2; i++){ + IXDR_PUT_SHORT(buf,*genp++); + } + }; + } + + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs,6 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + + } + else { + objp->pc_link_max = IXDR_GET_LONG(buf); + objp->pc_max_canon = IXDR_GET_SHORT(buf); + objp->pc_max_input = IXDR_GET_SHORT(buf); + objp->pc_name_max = IXDR_GET_SHORT(buf); + objp->pc_path_max = IXDR_GET_SHORT(buf); + objp->pc_pipe_buf = IXDR_GET_SHORT(buf); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + + } + else { + { register short *genp; + for ( i = 0,genp=objp->pc_mask; + i < 2; i++){ + *genp++ = IXDR_GET_SHORT(buf); + } + }; + } + return(TRUE); + } + + if (!xdr_int(xdrs, &objp->pc_link_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_canon)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_max_input)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_name_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_path_max)) { + return (FALSE); + } + if (!xdr_short(xdrs, &objp->pc_pipe_buf)) { + return (FALSE); + } + if (!xdr_u_char(xdrs, &objp->pc_vdisable)) { + return (FALSE); + } + if (!xdr_char(xdrs, &objp->pc_xxx)) { + return (FALSE); + } + if (!xdr_vector(xdrs, (char *)objp->pc_mask, 2, sizeof(short), (xdrproc_t)xdr_short)) { + return (FALSE); + } + return (TRUE); +} diff --git a/mount/sundries.c b/mount/sundries.c index 5ebf0195..4506924a 100644 --- a/mount/sundries.c +++ b/mount/sundries.c @@ -4,328 +4,224 @@ * * added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927 */ - +#include +#include +#include +#include /* for MNTTYPE_SWAP */ +#include "fstab.h" #include "sundries.h" -#include "mount.h" - -/* File pointer for /etc/mtab. */ -FILE *F_mtab = NULL; - -/* File pointer for temp mtab. */ -FILE *F_temp = NULL; +#include "nfsmount.h" -/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */ -static int lock = -1; - -/* Flag for already existing lock file. */ -static int old_lockfile = 1; /* String list constructor. (car() and cdr() are defined in "sundries.h"). */ string_list -cons (char *a, const string_list b) -{ - string_list p; - - p = xmalloc (sizeof *p); +cons (char *a, const string_list b) { + string_list p; - car (p) = a; - cdr (p) = b; - return p; + p = xmalloc (sizeof *p); + car (p) = a; + cdr (p) = b; + return p; } void * -xmalloc (size_t size) -{ - void *t; +xmalloc (size_t size) { + void *t; - if (size == 0) - return NULL; + if (size == 0) + return NULL; - t = malloc (size); - if (t == NULL) - die (2, "not enough memory"); + t = malloc (size); + if (t == NULL) + die (EX_SYSERR, "not enough memory"); - return t; + return t; } char * -xstrdup (const char *s) -{ - char *t; +xstrdup (const char *s) { + char *t; - if (s == NULL) - return NULL; + if (s == NULL) + return NULL; - t = strdup (s); + t = strdup (s); - if (t == NULL) - die (2, "not enough memory"); + if (t == NULL) + die (EX_SYSERR, "not enough memory"); - return t; + return t; } -/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */ -void -block_signals (int how) -{ - sigset_t sigs; +char * +xstrndup (const char *s, int n) { + char *t; - sigfillset (&sigs); - sigprocmask (how, &sigs, (sigset_t *) 0); -} + if (s == NULL) + die (EX_SOFTWARE, "bug in xstrndup call"); + t = xmalloc(n+1); + strncpy(t,s,n); + t[n] = 0; -/* Non-fatal error. Print message and return. */ -void -error (const char *fmt, ...) -{ - va_list args; - - if (mount_quiet) return; - va_start (args, fmt); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); + return t; } -/* Fatal error. Print message and exit. */ -void -die (int err, const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); +char * +xstrconcat2 (const char *s, const char *t) { + char *res; - unlock_mtab (); - exit (err); + if (!s) s = ""; + if (!t) t = ""; + res = xmalloc(strlen(s) + strlen(t) + 1); + strcpy(res, s); + strcat(res, t); + return res; } -/* Ensure that the lock is released if we are interrupted. */ -static void -handler (int sig) -{ - die (2, "%s", sys_siglist[sig]); -} +char * +xstrconcat3 (const char *s, const char *t, const char *u) { + char *res; -static void -setlkw_timeout (int sig) -{ - /* nothing, fcntl will fail anyway */ + if (!s) s = ""; + if (!t) t = ""; + if (!u) u = ""; + res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1); + strcpy(res, s); + strcat(res, t); + strcat(res, u); + return res; } -/* Create the lock file. The lock file will be removed if we catch a signal - or when we exit. The value of lock is tested to remove the race. */ -void -lock_mtab (void) -{ - int sig = 0; - struct sigaction sa; - struct flock flock; - - /* If this is the first time, ensure that the lock will be removed. */ - if (lock < 0) - { - struct stat st; - sa.sa_handler = handler; - sa.sa_flags = 0; - sigfillset (&sa.sa_mask); - - while (sigismember (&sa.sa_mask, ++sig) != -1) - { - if (sig == SIGALRM) - sa.sa_handler = setlkw_timeout; - else - sa.sa_handler = handler; - sigaction (sig, &sa, (struct sigaction *) 0); - } - - /* This stat is performed so we know when not to be overly eager - when cleaning up after signals. The window between stat and - open is not significant. */ - if (lstat (MOUNTED_LOCK, &st) < 0 && errno == ENOENT) - old_lockfile = 0; - - lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT, 0); - if (lock < 0) - { - die (2, "can't create lock file %s: %s", - MOUNTED_LOCK, strerror (errno)); - } - - flock.l_type = F_WRLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - alarm(LOCK_BUSY); - if (fcntl (lock, F_SETLKW, &flock) < 0) - { - close (lock); - /* The file should not be removed */ - lock = -1; - die (2, "can't lock lock file %s: %s", - MOUNTED_LOCK, errno == EINTR ? "timed out" : strerror (errno)); - } - /* We have now access to the lock, and it can always be removed */ - old_lockfile = 0; - } -} +char * +xstrconcat4 (const char *s, const char *t, const char *u, const char *v) { + char *res; -/* Remove lock file. */ -void -unlock_mtab (void) -{ - if (lock != -1) - { - close (lock); - if (!old_lockfile) - unlink (MOUNTED_LOCK); - } + if (!s) s = ""; + if (!t) t = ""; + if (!u) u = ""; + if (!v) v = ""; + res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1); + strcpy(res, s); + strcat(res, t); + strcat(res, u); + strcat(res, v); + return res; } -/* Open mtab. */ +/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock. */ void -open_mtab (const char *mode) -{ - if ((F_mtab = setmntent (MOUNTED, mode)) == NULL) - die (2, "can't open %s: %s", MOUNTED, strerror (errno)); -} +block_signals (int how) { + sigset_t sigs; -/* Close mtab. */ -void -close_mtab (void) -{ - if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) - die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno)); - endmntent (F_mtab); + sigfillset (&sigs); + sigdelset(&sigs, SIGTRAP); + sigdelset(&sigs, SIGSEGV); + sigprocmask (how, &sigs, (sigset_t *) 0); } -/* Update the mtab by removing any DIR entries and replace it with INSTEAD. */ -void -update_mtab (const char *dir, struct mntent *instead) -{ - struct mntent *mnt; - struct mntent *next; - int added = 0; - open_mtab ("r"); +/* Non-fatal error. Print message and return. */ +/* (print the message in a single printf, in an attempt + to avoid mixing output of several threads) */ +void +error (const char *fmt, ...) { + va_list args; + char *fmt2; - if ((F_temp = setmntent (MOUNTED_TEMP, "w")) == NULL) - die (2, "can't open %s: %s", MOUNTED_TEMP, strerror (errno)); - - while ((mnt = getmntent (F_mtab))) - { - next = streq (mnt->mnt_dir, dir) ? (added++, instead) : mnt; - if (next && addmntent(F_temp, next) == 1) - die (1, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); - } - if (instead && !added) - addmntent(F_temp, instead); - - endmntent (F_mtab); - if (fchmod (fileno (F_temp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) - die (1, "error changing mode of %s: %s", MOUNTED_TEMP, strerror (errno)); - endmntent (F_temp); - - if (rename (MOUNTED_TEMP, MOUNTED) < 0) - die (1, "can't rename %s to %s: %s", - MOUNTED_TEMP, MOUNTED, strerror(errno)); + if (mount_quiet) + return; + fmt2 = xstrconcat2 (fmt, "\n"); + va_start (args, fmt); + vfprintf (stderr, fmt2, args); + va_end (args); + free (fmt2); } -/* Given the name FILE, try to find it in mtab. */ -struct mntent * -getmntfile (const char *file) -{ - struct mntent *mnt; - - if (!F_mtab) - return NULL; - - rewind(F_mtab); +/* Fatal error. Print message and exit. */ +void +die (int err, const char *fmt, ...) { + va_list args; - while ((mnt = getmntent (F_mtab)) != NULL) - { - if (streq (mnt->mnt_dir, file)) - break; - if (streq (mnt->mnt_fsname, file)) - break; - } + va_start (args, fmt); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); - return mnt; + unlock_mtab (); + exit (err); } /* Parse a list of strings like str[,str]... into a string list. */ string_list -parse_list (char *strings) -{ - string_list list; - char *t; +parse_list (char *strings) { + string_list list; + char *t; - if (strings == NULL) - return NULL; + if (strings == NULL) + return NULL; - list = cons (strtok (strings, ","), NULL); + list = cons (strtok (strings, ","), NULL); - while ((t = strtok (NULL, ",")) != NULL) - list = cons (t, list); + while ((t = strtok (NULL, ",")) != NULL) + list = cons (t, list); - return list; + return list; } /* True if fstypes match. Null *TYPES means match anything, - except that swap types always return false. This routine - has some ugliness to deal with ``no'' types. */ + except that swap types always return false. + This routine has some ugliness to deal with ``no'' types. + Fixed bug: the `no' part comes at the end - aeb, 970216 */ int -matching_type (const char *type, string_list types) -{ - char *notype; - int no; /* true if a "no" type match, ie -t nominix */ - - if (streq (type, MNTTYPE_SWAP)) - return 0; - if (types == NULL) - return 1; - - if ((notype = alloca (strlen (type) + 3)) == NULL) - die (2, "mount: out of memory"); - sprintf (notype, "no%s", type); - no = (car (types)[0] == 'n') && (car (types)[1] == 'o'); - - /* If we get a match and the user specified a positive match type (e.g. - "minix") we return true. If we match and a negative match type (e.g. - "nominix") was specified we return false. */ - while (types != NULL) - if (streq (type, car (types))) - return !no; - else if (streq (notype, car (types))) - return 0; /* match with "nofoo" always returns false */ - else - types = cdr (types); - - /* No matches, so if the user specified a positive match type return false, - if a negative match type was specified, return true. */ - return no; +matching_type (const char *type, string_list types) { + char *notype; + int foundyes, foundno; + int no; /* true if a "no" type match, eg -t nominix */ + + if (streq (type, MNTTYPE_SWAP)) + return 0; + if (types == NULL) + return 1; + + if ((notype = alloca (strlen (type) + 3)) == NULL) + die (EX_SYSERR, "mount: out of memory"); + sprintf (notype, "no%s", type); + + foundyes = foundno = no = 0; + while (types != NULL) { + if (cdr (types) == NULL) + no = (car (types)[0] == 'n') && (car (types)[1] == 'o'); + if (streq (type, car (types))) + foundyes = 1; + else if (streq (notype, car (types))) + foundno = 1; + types = cdr (types); + } + + return (foundno ? 0 : (no ^ foundyes)); } /* Make a canonical pathname from PATH. Returns a freshly malloced string. It is up the *caller* to ensure that the PATH is sensible. i.e. canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.'' - is not a legal pathname for ``/dev/fd0.'' Anything we cannot parse + is not a legal pathname for ``/dev/fd0''. Anything we cannot parse we return unmodified. */ char * -canonicalize (const char *path) -{ - char *canonical = xmalloc (PATH_MAX + 1); +canonicalize (const char *path) { + char *canonical; - if (path == NULL) - return NULL; + if (path == NULL) + return NULL; + + if (streq(path, "none") || streq(path, "proc")) + return xstrdup(path); + + canonical = xmalloc (PATH_MAX + 1); - if (realpath (path, canonical)) - return canonical; + if (realpath (path, canonical)) + return canonical; - strcpy (canonical, path); - return canonical; + free(canonical); + return xstrdup(path); } diff --git a/mount/sundries.h b/mount/sundries.h index 77d8d32f..0c96f865 100644 --- a/mount/sundries.h +++ b/mount/sundries.h @@ -4,49 +4,21 @@ */ #include -#include -#include -#include -#include #include -#include #include -#include #include #include #include -#include -#include - -#if 0 -#include -#if LINUX_VERSION_CODE >= 0x010302 -#define SUPPORT_PRIORITIES -#endif +#ifndef bool_t +#include #endif -#ifdef SUPPORT_PRIORITIES -#include -#endif - -#include "fstab.h" - extern int mount_quiet; +extern int verbose; #define streq(s, t) (strcmp ((s), (t)) == 0) -#define MOUNTED_LOCK "/etc/mtab~" -#define MOUNTED_TEMP "/etc/mtab.tmp" -#define _PATH_FSTAB "/etc/fstab" -#define LOCK_BUSY 10 - -/* File pointer for /etc/mtab. */ -extern FILE *F_mtab; - -/* File pointer for temp mtab. */ -extern FILE *F_temp; - /* String list data structure. */ typedef struct string_list { @@ -62,24 +34,19 @@ string_list cons (char *a, const string_list); /* Quiet compilation with -Wmissing-prototypes. */ int main (int argc, char *argv[]); -/* From mount_call.c. */ -int mount5 (const char *, const char *, const char *, int, void *); - /* Functions in sundries.c that are used in mount.c and umount.c */ void block_signals (int how); char *canonicalize (const char *path); char *realpath (const char *path, char *resolved_path); -void close_mtab (void); void error (const char *fmt, ...); -void lock_mtab (void); int matching_type (const char *type, string_list types); -void open_mtab (const char *mode); string_list parse_list (char *strings); -void unlock_mtab (void); -void update_mtab (const char *special, struct mntent *with); -struct mntent *getmntfile (const char *file); void *xmalloc (size_t size); char *xstrdup (const char *s); +char *xstrndup (const char *s, int n); +char *xstrconcat2 (const char *, const char *); +char *xstrconcat3 (const char *, const char *, const char *); +char *xstrconcat4 (const char *, const char *, const char *, const char *); /* Here is some serious cruft. */ #ifdef __GNUC__ @@ -97,6 +64,11 @@ int nfsmount (const char *spec, const char *node, int *flags, char **orig_opts, char **opt_args); #endif -#define mount5(special, dir, type, flags, data) \ - mount (special, dir, type, 0xC0ED0000 | (flags), data) - +/* exit status - bits below are ORed */ +#define EX_USAGE 1 /* incorrect invocation or permission */ +#define EX_SYSERR 2 /* out of memory, cannot fork, ... */ +#define EX_SOFTWARE 4 /* internal mount bug or wrong version */ +#define EX_USER 8 /* user interrupt */ +#define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ +#define EX_FAIL 32 /* mount failure */ +#define EX_SOMEOK 64 /* some mount succeeded */ diff --git a/mount/swap.configure b/mount/swap.configure new file mode 100644 index 00000000..70bce506 --- /dev/null +++ b/mount/swap.configure @@ -0,0 +1,22 @@ +# find out whether we can include +# and whether libc thinks that swapon() has two arguments. +CC=${CC-cc} +compile="$CC -o conftest conftest.c >/dev/null 2>&1" +rm -f conftest conftest.c swapargs.h +SWAPH= +if [ -f /usr/include/sys/swap.h ]; then SWAPH="#include "; fi +echo $SWAPH > conftest.c +echo '#include +main(){ exit(0); swapon("/dev/null", 0); }' >> conftest.c +eval $compile +if test -s conftest && ./conftest 2>/dev/null; then + echo "#define SWAPON_HAS_TWO_ARGS" > swapargs.h + echo $SWAPH >> swapargs.h +else + echo > swapargs.h + echo " +Your libc thinks that swapon has 1 arg only. +Define SWAPON_NEEDS_TWO_ARGS in swapon.c if you want to use priorities. +" 1>&2 +fi +rm -f conftest conftest.c diff --git a/mount/swapon.8 b/mount/swapon.8 index 911855dc..0ebb450a 100644 --- a/mount/swapon.8 +++ b/mount/swapon.8 @@ -36,6 +36,7 @@ .\" Sat Oct 9 09:35:30 1993: Converted to man format by faith@cs.unc.edu .\" Sat Nov 27 20:22:42 1993: Updated authorship information, faith@cs.unc.edu .\" Mon Sep 25 14:12:38 1995: Added -v and -p information +.\" Tue Apr 30 03:32:07 1996: Added some text from A. Koppenhoefer .\" .TH SWAPON 8 "25 September 1995" "Linux 1.x" "Linux Programmer's Manual" .SH NAME @@ -47,6 +48,8 @@ swapon, swapoff \- enable/disable devices and files for paging and swapping .br .BI "/sbin/swapon [\-v] [\-p " "priority" "] " " specialfile " ... .br +.B /sbin/swapon [\-s] +.br .B /sbin/swapoff [\-h \-V] .br .B /sbin/swapoff \-a @@ -70,6 +73,9 @@ Provide help .B \-V Display version .TP +.B \-s +Display swap usage summary by device +.TP .B \-a All devices marked as ``sw'' swap devices in .I /etc/fstab @@ -81,6 +87,15 @@ Specify priority for This option is only available if .B swapon was compiled under and is used under a 1.3.2 or later kernel. +.I priority +is a value between 0 and 32767. See +.BR swapon (2) +for a full description of swap priorities. Add +.BI pri= value +to the option field of +.I /etc/fstab +for use with +.BR "swapon -a" . .PP .B Swapoff disables swapping on the specified devices and files, or on all swap diff --git a/mount/swapon.c b/mount/swapon.c index 331238f0..5fdd15c5 100644 --- a/mount/swapon.c +++ b/mount/swapon.c @@ -1,15 +1,28 @@ /* * A swapon(8)/swapoff(8) for Linux 0.99. * swapon.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp + * Added '-s' (Summary option) 02/1997. */ -#include "sundries.h" +#include +#include +#include +#include +#include +#include +#include "swap.h" +#include "swapargs.h" + +#define streq(s, t) (strcmp ((s), (t)) == 0) + +#define _PATH_FSTAB "/etc/fstab" +#define PROC_SWAPS "/proc/swaps" + +/* #define SWAPON_NEEDS_TWO_ARGS */ /* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */ int verbose = 0; -#ifdef SUPPORT_PRIORITIES int priority = -1; /* non-prioritized swap by default */ -#endif extern char version[]; static char *program_name; @@ -17,57 +30,69 @@ static struct option longopts[] = { { "all", 0, 0, 'a' }, { "help", 0, 0, 'h' }, -#ifdef SUPPORT_PRIORITIES { "priority", required_argument, 0, 'p' }, -#endif + { "summary", 0, 0, 's' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { NULL, 0, 0, 0 } }; -#ifdef SUPPORT_PRIORITIES -const char *usage_string = "\ -usage: %s [-hV]\n\ - %s -a [-v]\n\ - %s [-v] [-p priority] special ...\n\ -"; -#else const char *usage_string = "\ usage: %s [-hV]\n\ %s -a [-v]\n\ %s [-v] [-p priority] special ...\n\ + %s [-s]\n\ "; -#endif static void usage (FILE *fp, int n) { - fprintf (fp, usage_string, program_name, program_name, program_name); + fprintf (fp, usage_string, program_name, program_name, program_name, program_name); exit (n); } -static int -#ifdef SUPPORT_PRIORITIES -swap (const char *special, int prio) +#ifdef SWAPON_HAS_TWO_ARGS +#define SWAPON_NEEDS_TWO_ARGS +#endif + +#ifdef SWAPON_NEEDS_TWO_ARGS +#ifdef SWAPON_HAS_TWO_ARGS +/* libc is OK */ +#include +#else +/* We want a swapon with two args, but have an old libc. + Build the kernel call by hand. */ +#include +static +_syscall2(int, swapon, const char *, path, int, flags); +static +_syscall1(int, swapoff, const char *, path); +#endif #else -swap (const char *special) +/* just do as libc says */ +#include #endif + +static int +swap (const char *special, int prio) { int status; -#ifdef SUPPORT_PRIORITIES - int flags; -#endif if (verbose) printf("%s on device %s\n", program_name, special); if (streq (program_name, "swapon")) { -#ifdef SUPPORT_PRIORITIES - flags = 0; +#ifdef SWAPON_NEEDS_TWO_ARGS + int flags = 0; + +#ifdef SWAP_FLAG_PREFER if (prio >= 0) { + if (prio > SWAP_FLAG_PRIO_MASK) + prio = SWAP_FLAG_PRIO_MASK; flags = SWAP_FLAG_PREFER | ((prio & SWAP_FLAG_PRIO_MASK) << SWAP_FLAG_PRIO_SHIFT); } +#endif status = swapon (special, flags); #else status = swapon (special); @@ -81,10 +106,27 @@ swap (const char *special) return status; } +static int +display_summary(void) +{ + FILE *swaps; + char line[200] ; + + if ((swaps = fopen(PROC_SWAPS, "r")) == NULL) { + fprintf (stderr, "%s: %s: %s\n", program_name, PROC_SWAPS, + strerror (errno)); + return -1 ; + } + while ( fgets(line, sizeof(line), swaps)) + printf ("%s", line); + + return 0 ; +} + int main (int argc, char *argv[]) { - struct fstab *fstab; + struct mntent *fstab; int status; int all = 0; int c; @@ -94,11 +136,7 @@ main (int argc, char *argv[]) else program_name = argv[0]; -#ifdef SUPPORT_PRIORITIES - while ((c = getopt_long (argc, argv, "ahp:vV", longopts, NULL)) != EOF) -#else - while ((c = getopt_long (argc, argv, "ahvV", longopts, NULL)) != EOF) -#endif + while ((c = getopt_long (argc, argv, "ahp:svV", longopts, NULL)) != EOF) switch (c) { case 'a': /* all */ @@ -107,16 +145,17 @@ main (int argc, char *argv[]) case 'h': /* help */ usage (stdout, 0); break; -#ifdef SUPPORT_PRIORITIES case 'p': /* priority */ priority = atoi(optarg); break; -#endif + case 's': /* tell about current use of swap areas */ + status = display_summary(); + exit(status); case 'v': /* be chatty */ ++verbose; break; case 'V': /* version */ - printf ("swapon: %s\n", version); + printf ("%s: %s\n", program_name, version); exit (0); case 0: break; @@ -129,43 +168,30 @@ main (int argc, char *argv[]) status = 0; - if (all) - { - while ((fstab = getfsent()) != NULL) - if (streq (fstab->fs_type, FSTAB_SW)) - { -#ifdef SUPPORT_PRIORITIES - /* parse mount options; */ - char *opt, *opts = strdup(fstab->fs_mntopts); + if (all) { + FILE *fp = setmntent(_PATH_FSTAB, "r"); + if (fp == NULL) { + fprintf(stderr, "%s: cannot open %s: %s\n", program_name, + _PATH_FSTAB, strerror(errno)); + exit(2); + } + while ((fstab = getmntent(fp)) != NULL) { + if (streq (fstab->mnt_type, MNTTYPE_SWAP)) { + /* parse mount options; */ + char *opt, *opts = strdup(fstab->mnt_opts); - for (opt = strtok (opts, ","); - opt != NULL; - opt = strtok (NULL, ",")) - { - if (strncmp(opt, "pri=", 4) == 0) - { - priority = atoi(opt+4); - } - } - status |= swap (fstab->fs_spec, priority); -#else - status |= swap (fstab->fs_spec); -#endif - } - } - else if (*argv == NULL) - { - usage (stderr, 2); - } - else - { - while (*argv != NULL) { -#ifdef SUPPORT_PRIORITIES - status |= swap (*argv++,priority); -#else - status |= swap (*argv++); -#endif + for (opt = strtok (opts, ","); opt != NULL; + opt = strtok (NULL, ",")) + if (strncmp(opt, "pri=", 4) == 0) + priority = atoi(opt+4); + status |= swap (fstab->mnt_fsname, priority); + } } - } + } else if (*argv == NULL) { + usage (stderr, 2); + } else { + while (*argv != NULL) + status |= swap (*argv++,priority); + } return status; } diff --git a/mount/umount.8 b/mount/umount.8 index 85425b48..196bd7f8 100644 --- a/mount/umount.8 +++ b/mount/umount.8 @@ -1 +1,108 @@ -.so man8/mount.8 +.\" Copyright (c) 1996 Andries Brouwer +.\" This page is somewhat derived from a page that was +.\" (c) 1980, 1989, 1991 The Regents of the University of California +.\" and had been heavily modified by Rik Faith and myself. +.\" +.\" This is free documentation; you can redistribute it and/or +.\" modify it under the terms of the GNU General Public License as +.\" published by the Free Software Foundation; either version 2 of +.\" the License, or (at your option) any later version. +.\" +.\" The GNU General Public License's references to "object code" +.\" and "executables" are to be interpreted as the output of any +.\" document formatting or typesetting system, including +.\" intermediate and printed output. +.\" +.\" This manual is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public +.\" License along with this manual; if not, write to the Free +.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, +.\" USA. +.\" +.TH UMOUNT 8 "26 July 1997" "Linux 2.0" "Linux Programmer's Manual" +.SH NAME +umount \- unmount file systems +.SH SYNOPSIS +.BI "umount [\-hV]" +.LP +.BI "umount -a [\-nrv] [\-t " vfstype ] +.br +.BI "umount [\-nrv] " "device " | " dir " [...] +.SH DESCRIPTION +The +.B umount +command detaches the file system(s) mentioned from the file hierarchy. +A file system is specified either by giving the directory where it +has been mounted, or by giving the special device on which it lives. + +Note that a file system cannot be unmounted when it is `busy' - +for example, when there are open files on it, or when some process +has its working directory there, or when a swap file on it is in use. +The offending process could even be +.B umount +itself - it opens libc, and libc in its turn may open for example +locale files. + +Options for the +.B umount +command: +.TP +.B \-V +Print version and exit. +.TP +.B \-h +Print help message and exit. +.TP +.B \-v +Verbose mode. +.TP +.B \-n +Unmount without writing in +.IR /etc/mtab . +.TP +.B \-r +In case unmounting fails, try to remount read-only. +.TP +.B \-a +All of the file systems described in +.I /etc/mtab +are unmounted. (With +.B umount +version 2.7 and later: the +.I proc +filesystem is not unmounted.) +.TP +.BI \-t " vfstype" +Indicate that the actions should only be taken on file systems of the +specified type. More than one type may be specified in a comma separated +list. The list of file system types can be prefixed with +.B no +to specify the file system types on which no action should be taken. + +.SH "THE LOOP DEVICE" +The +.B umount +command will free the loop device (if any) associated +with the mount, in case it finds the option `loop=...' in +.IR /etc/mtab . +Any pending loop devices can be freed using `losetup -d', see +.BR losetup (8). + + +.SH FILES +.I /etc/mtab +table of mounted file systems + +.SH "SEE ALSO" +.BR umount (2), +.BR mount (8), +.BR losetup (8). + +.SH HISTORY +A +.B umount +command appeared in Version 6 AT&T UNIX. diff --git a/mount/umount.c b/mount/umount.c index 236f0524..de80fd1b 100644 --- a/mount/umount.c +++ b/mount/umount.c @@ -8,9 +8,29 @@ * * Tue Sep 26 16:33:09 1995: Added patches from Greg Page (greg@caldera.com) * so that NetWare filesystems can be unmounted. + * + * 951213: Marek Michalkiewicz : + * Ignore any RPC errors, so that you can umount an nfs mounted filesystem + * if the server is down. + * + * 960223: aeb - several minor changes + * 960324: aeb - added some changes from Rob Leslie + * 960823: aeb - also try umount(spec) when umount(node) fails + * 970307: aeb - canonise names from fstab + * 970726: aeb - remount read-only in cases where umount fails */ +#include +#include +#include +#include +#include +#include +#include "mount_constants.h" #include "sundries.h" +#include "lomount.h" +#include "loop.h" +#include "fstab.h" #ifdef HAVE_NFS #include @@ -19,7 +39,7 @@ #include #include #include -#include "mount.h" +#include "nfsmount.h" #include #endif @@ -29,6 +49,12 @@ int force = 0; #endif +/* When umount fails, attempt a read-only remount (-r). */ +int remount = 0; + +/* Don't write a entry in /etc/mtab (-n). */ +int nomtab = 0; + /* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */ int verbose = 0; @@ -40,32 +66,109 @@ static int xdr_dir(XDR *xdrsp, char *dirp) { return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); } -#endif - - -/* Umount a single device. Return a status code, so don't exit - on a non-fatal error. We lock/unlock around each umount. */ static int -umount_one (const char *spec, const char *node, const char *type) +nfs_umount_rpc_call(const char *spec, const char *opts) { - int umnt_err; - int isroot; - struct mntent *mnt; - -#ifdef HAVE_NFS - char buffer[256]; register CLIENT *clp; struct sockaddr_in saddr; struct timeval pertry, try; enum clnt_stat clnt_stat; int so = RPC_ANYSOCK; - char *p; struct hostent *hostp; - char hostname[MAXHOSTNAMELEN]; - char dirname[1024]; + char *hostname; + char *dirname; + char *p; + + if (spec == NULL || (p = strchr(spec,':')) == NULL) + return 0; + hostname = xstrndup(spec, p-spec); + dirname = xstrdup(p+1); +#ifdef DEBUG + printf("host: %s, directory: %s\n", hostname, dirname); +#endif + + if (opts && (p = strstr(opts, "addr="))) { + char *q; + + free(hostname); + p += 5; + q = p; + while (*q && *q != ',') q++; + hostname = xstrndup(p,q-p); + } + + if (hostname[0] >= '0' && hostname[0] <= '9') + saddr.sin_addr.s_addr = inet_addr(hostname); + else + if ((hostp = gethostbyname(hostname)) == NULL) { + fprintf(stderr, "mount: can't get address for %s\n", + hostname); + return 1; + } else + memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); + + saddr.sin_family = AF_INET; + saddr.sin_port = 0; + pertry.tv_sec = 3; + pertry.tv_usec = 0; + if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS, + pertry, &so)) == NULL) { + clnt_pcreateerror("Cannot MOUNTPROG RPC"); + return (1); + } + clp->cl_auth = authunix_create_default(); + try.tv_sec = 20; + try.tv_usec = 0; + clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, + (xdrproc_t) xdr_dir, dirname, + (xdrproc_t) xdr_void, (caddr_t) 0, + try); + + if (clnt_stat != RPC_SUCCESS) { + clnt_perror(clp, "Bad UMNT RPC"); + return (1); + } + auth_destroy(clp->cl_auth); + clnt_destroy(clp); + + return (0); +} #endif /* HAVE_NFS */ - + +/* complain about a failed umount */ +static void complain(int err, const char *dev) { + switch (err) { + case ENXIO: + error ("umount: %s: invalid block device", dev); break; + case EINVAL: + error ("umount: %s: not mounted", dev); break; + case EIO: + error ("umount: %s: can't write superblock", dev); break; + case EBUSY: + /* Let us hope fstab has a line "proc /proc ..." + and not "none /proc ..."*/ + error ("umount: %s: device is busy", dev); break; + case ENOENT: + error ("umount: %s: not found", dev); break; + case EPERM: + error ("umount: %s: must be superuser to umount", dev); break; + case EACCES: + error ("umount: %s: block devices not permitted on fs", dev); break; + default: + error ("umount: %s: %s", dev, strerror (err)); break; + } +} + +/* Umount a single device. Return a status code, so don't exit + on a non-fatal error. We lock/unlock around each umount. */ +static int +umount_one (const char *spec, const char *node, const char *type, + const char *opts) +{ + int umnt_err, umnt_err2; + int isroot; + int res; /* Special case for root. As of 0.99pl10 we can (almost) unmount root; the kernel will remount it readonly so that we can carry on running @@ -73,122 +176,108 @@ umount_one (const char *spec, const char *node, const char *type) for writing at the time, so we can't update mtab for an unmount of root. As it is only really a remount, this doesn't matter too much. [sct May 29, 1993] */ - isroot = (streq (node, "/") || streq (node, "root")); + isroot = (streq (node, "/") || streq (node, "root") + || streq (node, "rootfs")); + if (isroot) + nomtab++; #ifdef HAVE_NFS - strcpy(buffer,spec); - /* spec is constant so must use own buffer */ - if(!strcasecmp(type, "nfs") && (p=strchr(buffer,':'))) - { - *p='\0'; - strcpy(hostname,buffer); - strcpy(dirname,p+1); -#ifdef DEBUG - printf("host: %s, directory: %s\n", hostname,dirname); + /* Ignore any RPC errors, so that you can umount the filesystem + if the server is down. */ + if (strcasecmp(type, "nfs") == 0) + nfs_umount_rpc_call(spec, opts); #endif - - - if (hostname[0] >= '0' && hostname[0] <= '9') - { - saddr.sin_addr.s_addr = inet_addr(hostname); - } - else - if ((hostp = gethostbyname(hostname)) == NULL) - { - fprintf(stderr, "mount: can't get address for %s\n", hostname); - return(1); - } - else - { - memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); - } - - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - pertry.tv_sec = 3; - pertry.tv_usec = 0; - if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS, - pertry, &so)) == NULL) - { - clnt_pcreateerror("Cannot MOUNTPROG PRC"); - return (1); - } - clp->cl_auth = authunix_create_default(); - try.tv_sec = 20; - try.tv_usec = 0; - clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, - xdr_dir, dirname, - xdr_void, (caddr_t)0, - try); - - if (clnt_stat != RPC_SUCCESS) - { - clnt_perror(clp, "Bad UMNT RPC"); - return (1); - } - auth_destroy(clp->cl_auth); - clnt_destroy(clp); - } -#endif /* HAVE_NFS */ - if (!isroot) - lock_mtab (); - if (umount (node) >= 0) - /* Umount succeeded, update mtab. */ - { + umnt_err = umnt_err2 = 0; + res = umount (node); + if (res < 0) { + umnt_err = errno; + /* A device might have been mounted on a node that has since + been deleted or renamed, so if node fails, also try spec. */ + /* if (umnt_err == ENOENT || umnt_err == EINVAL) */ + if (umnt_err != EBUSY && strcmp(node, spec)) { + if (verbose) + printf ("could not umount %s - trying %s instead\n", + node, spec); + res = umount (spec); + if (res < 0) + umnt_err2 = errno; + /* Do not complain about remote NFS mount points */ + if (errno == ENOENT && index(spec, ':')) + umnt_err2 = 0; + } + } + + if (res < 0 && remount && (umnt_err == EBUSY || umnt_err2 == EBUSY)) { + /* Umount failed - let us try a remount */ + res=mount(spec, node, NULL, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); + if (res == 0) { + struct mntent remnt; + fprintf(stderr, "umount: %s busy - remounted read-only\n", spec); + remnt.mnt_type = remnt.mnt_fsname = NULL; + remnt.mnt_dir = xstrdup(node); + remnt.mnt_opts = "ro"; + update_mtab(node, &remnt); + return 0; + } else if (errno != EBUSY) { /* hmm ... */ + perror("remount"); + fprintf(stderr, "umount: could not remount %s read-only\n", + spec); + } + } + + if (res >= 0) { + /* Umount succeeded, update mtab. */ if (verbose) printf ("%s umounted\n", spec); - if (!isroot) - { + if (!nomtab && mtab_is_writable()) { + struct mntentchn *mc; /* Special stuff for loop devices */ - open_mtab("r"); - if ((mnt = getmntfile (spec)) || - (mnt = getmntfile (node))) { - if (mnt && streq(mnt->mnt_type, "loop")) { - extern int del_loop(const char *); - + + if ((mc = getmntfile (spec)) || (mc = getmntfile (node))) { + char *opts; + + /* old style mtab line? */ + if (streq(mc->mnt_type, "loop")) if (del_loop(spec)) goto fail; + + /* new style mtab line? */ + opts = mc->mnt_opts ? xstrdup(mc->mnt_opts) : ""; + for (opts = strtok (opts, ","); opts; opts = strtok (NULL, ",")) { + if (!strncmp(opts, "loop=", 5)) { + if (del_loop(opts+5)) + goto fail; + break; + } } + } else { + /* maybe spec is a loop device? */ + /* no del_loop() - just delete it from mtab */ + if ((mc = getmntoptfile (spec)) != NULL) + node = mc->mnt_dir; } - close_mtab(); /* Non-loop stuff */ update_mtab (node, NULL); - unlock_mtab (); - } + } return 0; - } + } fail: - /* Umount failed, complain, but don't die. */ - umnt_err = errno; - if (!isroot) - unlock_mtab (); + /* Umount or del_loop failed, complain, but don't die. */ + if (!nomtab) { + /* remove obsolete entry */ + if (umnt_err == EINVAL || umnt_err == ENOENT) + update_mtab (node, NULL); + } - switch (umnt_err) - { - case ENXIO: - error ("umount: %s: invalid block device", spec); break; - case EINVAL: - error ("umount: %s: not mounted", spec); break; - case EIO: - error ("umount: %s: can't write superblock", spec); break; - case EBUSY: - /* Let us hope fstab has a line "proc /proc ..." - and not "none /proc ..."*/ - error ("umount: %s: device is busy", spec); break; - case ENOENT: - error ("umount: %s: not mounted", spec); break; - case EPERM: - error ("umount: %s: must be superuser to umount", spec); break; - case EACCES: - error ("umount: %s: block devices not permitted on fs", spec); break; - default: - error ("umount: %s: %s", spec, strerror (umnt_err)); break; - } + if (umnt_err2) + complain(umnt_err2, spec); + if (umnt_err && umnt_err != umnt_err2) + complain(umnt_err, node); return 1; } @@ -196,39 +285,24 @@ fail: concurrently updating mtab after every succesful umount, we have to slurp in the entire file before we start. This isn't too bad, because in any case it's important to umount mtab entries in reverse order - to umount, e.g. /usr/spool before /usr. */ + to mount, e.g. /usr/spool before /usr. */ static int -umount_all (string_list types) -{ - string_list spec_list = NULL; - string_list node_list = NULL; - string_list type_list = NULL; - struct mntent *mnt; - int errors; - - open_mtab ("r"); - - while ((mnt = getmntent (F_mtab))) - if (matching_type (mnt->mnt_type, types)) - { - spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list); - node_list = cons (xstrdup (mnt->mnt_dir), node_list); - type_list = cons (xstrdup (mnt->mnt_type), type_list); - } - - close_mtab (); - - errors = 0; - while (spec_list != NULL) - { - errors |= umount_one (car (spec_list), car (node_list), car (type_list)); - spec_list = cdr (spec_list); - node_list = cdr (node_list); - type_list = cdr (type_list); - } +umount_all (string_list types) { + struct mntentchn *mc, *hd; + int errors = 0; + + hd = mtab_head(); + if (!hd->prev) + die (2, "umount: cannot find list of filesystems to unmount"); + for (mc = hd->prev; mc != hd; mc = mc->prev) { + if (matching_type (mc->mnt_type, types)) { + errors |= umount_one (mc->mnt_fsname, mc->mnt_dir, + mc->mnt_type, mc->mnt_opts); + } + } - sync (); - return errors; + sync (); + return errors; } extern char version[]; @@ -237,16 +311,18 @@ static struct option longopts[] = { "all", 0, 0, 'a' }, { "force", 0, 0, 'f' }, { "help", 0, 0, 'h' }, + { "no-mtab", 0, 0, 'n' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, + { "read-only", 0, 0, 'r' }, { "types", 1, 0, 't' }, { NULL, 0, 0, 0 } }; char *usage_string = "\ usage: umount [-hV]\n\ - umount -a [-v] [-t vfstypes]\n\ - umount [-v] special | node...\n\ + umount -a [-r] [-n] [-v] [-t vfstypes]\n\ + umount [-r] [-n] [-v] special | node...\n\ "; static void @@ -265,15 +341,12 @@ main (int argc, char *argv[]) int all = 0; string_list types = NULL; string_list options; - struct mntent *mnt; - struct mntent mntbuf; - struct mntent *fs; + struct mntentchn *mc, *fs; char *file; int result = 0; - while ((c = getopt_long (argc, argv, "afhvVt:", longopts, NULL)) != EOF) - switch (c) - { + while ((c = getopt_long (argc, argv, "afhnrvVt:", longopts, NULL)) != EOF) + switch (c) { case 'a': /* umount everything */ ++all; break; @@ -287,6 +360,12 @@ main (int argc, char *argv[]) case 'h': /* help */ usage (stdout, 0); break; + case 'n': + ++nomtab; + break; + case 'r': /* remount read-only if umount fails */ + ++remount; + break; case 'v': /* make noise */ ++verbose; break; @@ -301,65 +380,65 @@ main (int argc, char *argv[]) case '?': default: usage (stderr, 1); - } + } if (getuid () != geteuid ()) { suid = 1; - if (all || types) + if (all || types || nomtab) die (2, "umount: only root can do that"); } argc -= optind; argv += optind; - if (all) - result = umount_all (types); - else if (argc < 1) - usage (stderr, 2); - else while (argc--) - { - file = canonicalize (*argv); /* mtab paths are canonicalized */ - - open_mtab ("r"); - mnt = getmntfile (file); - if (mnt) - { - /* Copy the structure and strings becuase they're in static areas. */ - mntbuf = *mnt; - mnt = &mntbuf; - mnt->mnt_fsname = xstrdup (mnt->mnt_fsname); - mnt->mnt_dir = xstrdup (mnt->mnt_dir); - } - close_mtab (); - - if (suid) - { - if (!mnt) + if (all) { + if (types == NULL) + types = parse_list(xstrdup("noproc")); + result = umount_all (types); + } else if (argc < 1) { + usage (stderr, 2); + } else while (argc--) { + file = canonicalize (*argv); /* mtab paths are canonicalized */ + if (verbose > 1) + printf("Trying to umount %s\n", file); + + mc = getmntfile (file); + if (!mc && verbose) + printf("Could not find %s in mtab\n", file); + + if (suid) { + if (!mc) die (2, "umount: %s is not mounted (according to mtab)", file); if (!(fs = getfsspec (file)) && !(fs = getfsfile (file))) - die (2, "umount: %s is not in the fstab", file); - if (!streq (mnt->mnt_fsname, fs->mnt_fsname) - || !streq (mnt->mnt_dir, fs->mnt_dir)) + die (2, "umount: %s is not in the fstab (and you are not root)", + file); + if ((!streq (mc->mnt_fsname, fs->mnt_fsname) && + !streq (mc->mnt_fsname, canonicalize (fs->mnt_fsname))) + || (!streq (mc->mnt_dir, fs->mnt_dir) && + !streq (mc->mnt_dir, canonicalize (fs->mnt_dir)))) { die (2, "umount: %s mount disagrees with the fstab", file); + } options = parse_list (fs->mnt_opts); - while (options) - { + while (options) { if (streq (car (options), "user")) break; options = cdr (options); - } + } if (!options) die (2, "umount: only root can unmount %s from %s", fs->mnt_fsname, fs->mnt_dir); - } + } - if (mnt) - result = umount_one (xstrdup (mnt->mnt_fsname), xstrdup(mnt->mnt_dir), - xstrdup(mnt->mnt_type)); - else - result = umount_one (*argv, *argv, *argv); + if (mc) + result = umount_one (xstrdup(mc->mnt_fsname), xstrdup(mc->mnt_dir), + xstrdup(mc->mnt_type), xstrdup(mc->mnt_opts)); + else + result = umount_one (*argv, *argv, *argv, *argv); - } + argv++; + + } exit (result); } + diff --git a/mount/version.c b/mount/version.c index 47aed1dc..c17613e0 100644 --- a/mount/version.c +++ b/mount/version.c @@ -1 +1 @@ -char version[] = "version from util-linux-2.5"; +char version[] = "mount-2.7e"; diff --git a/sys-utils/Makefile b/sys-utils/Makefile index fc5afd4e..9513717e 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 02652b2b..00000000 --- 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 diff --git a/sys-utils/README.hwclock b/sys-utils/README.hwclock new file mode 100644 index 00000000..7d2f460d --- /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 00000000..ae636713 --- /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 bf3a5847..00000000 --- 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 00000000..766d6cbd --- /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 c465c55f..a2830ed3 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 1f6139ae..00000000 --- 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 15020c26..00000000 --- a/sys-utils/clock.c +++ /dev/null @@ -1,490 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define USE_INLINE_ASM_IO - -#ifdef USE_INLINE_ASM_IO -#include -#endif - -/* V1.0 - * CMOS clock manipulation - Charles Hedrick, hedrick@cs.rutgers.edu, Apr 1992 - * - * clock [-u] -r - read cmos clock - * clock [-u] -w - write cmos clock from system time - * clock [-u] -s - set system time from cmos clock - * clock [-u] -a - set system time from cmos clock, adjust the time to - * correct for systematic error, and put it back to the cmos. - * -u indicates cmos clock is kept in universal time - * - * The program is designed to run setuid, since we need to be able to - * write the CMOS port. - * - * I don't know what the CMOS clock will do in 2000, so this program - * probably won't work past the century boundary. - * - ********************* - * V1.1 - * Modified for clock adjustments - Rob Hooft, hooft@chem.ruu.nl, Nov 1992 - * Also moved error messages to stderr. The program now uses getopt. - * Changed some exit codes. Made 'gcc 2.3 -Wall' happy. - * - * I think a small explanation of the adjustment routine should be given - * here. The problem with my machine is that its CMOS clock is 10 seconds - * per day slow. With this version of clock.c, and my '/etc/rc.local' - * reading '/etc/clock -au' instead of '/etc/clock -u -s', this error - * is automatically corrected at every boot. - * - * To do this job, the program reads and writes the file '/etc/adjtime' - * to determine the correction, and to save its data. In this file are - * three numbers: - * - * 1) the correction in seconds per day (So if your clock runs 5 - * seconds per day fast, the first number should read -5.0) - * 2) the number of seconds since 1/1/1970 the last time the program was - * used. - * 3) the remaining part of a second which was leftover after the last - * adjustment - * - * Installation and use of this program: - * - * a) create a file '/etc/adjtime' containing as the first and only line: - * '0.0 0 0.0' - * b) run 'clock -au' or 'clock -a', depending on whether your cmos is in - * universal or local time. This updates the second number. - * c) set your system time using the 'date' command. - * d) update your cmos time using 'clock -wu' or 'clock -w' - * e) replace the first number in /etc/adjtime by your correction. - * f) put the command 'clock -au' or 'clock -a' in your '/etc/rc.local' - * - * If the adjustment doesn't work for you, try contacting me by E-mail. - * - ****** - * V1.2 - * - * Applied patches by Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de) - * Patched and indented by Rob Hooft (hooft@EMBL-Heidelberg.DE) - * - * A free quote from a MAIL-message (with spelling corrections): - * - * "I found the explanation and solution for the CMOS reading 0xff problem - * in the 0.99pl13c (ALPHA) kernel: the RTC goes offline for a small amount - * of time for updating. Solution is included in the kernel source - * (linux/kernel/time.c)." - * - * "I modified clock.c to fix this problem and added an option (now default, - * look for USE_INLINE_ASM_IO) that I/O instructions are used as inline - * code and not via /dev/port (still possible via #undef ...)." - * - * With the new code, which is partially taken from the kernel sources, - * the CMOS clock handling looks much more "official". - * Thanks Harald (and Torsten for the kernel code)! - * - ****** - * V1.3 - * Canges from alan@spri.levels.unisa.edu.au (Alan Modra): - * a) Fix a few typos in comments and remove reference to making - * clock -u a cron job. The kernel adjusts cmos time every 11 - * minutes - see kernel/sched.c and kernel/time.c set_rtc_mmss(). - * This means we should really have a cron job updating - * /etc/adjtime every 11 mins (set last_time to the current time - * and not_adjusted to ???). - * b) Swapped arguments of outb() to agree with asm/io.h macro of the - * same name. Use outb() from asm/io.h as it's slightly better. - * c) Changed CMOS_READ and CMOS_WRITE to inline functions. Inserted - * cli()..sti() pairs in appropriate places to prevent possible - * errors, and changed ioperm() call to iopl() to allow cli. - * d) Moved some variables around to localise them a bit. - * e) Fixed bug with clock -ua or clock -us that cleared environment - * variable TZ. This fix also cured the annoying display of bogus - * day of week on a number of machines. (Use mktime(), ctime() - * rather than asctime() ) - * f) Use settimeofday() rather than stime(). This one is important - * as it sets the kernel's timezone offset, which is returned by - * gettimeofday(), and used for display of MSDOS and OS2 file - * times. - * g) faith@cs.unc.edu added -D flag for debugging - * - * V1.4: alan@SPRI.Levels.UniSA.Edu.Au (Alan Modra) - * Wed Feb 8 12:29:08 1995, fix for years > 2000. - * faith@cs.unc.edu added -v option to print version. - * - */ - -#define VERSION "1.4" - -/* Here the information for time adjustments is kept. */ -#define ADJPATH "/etc/adjtime" - - -/* used for debugging the code. */ -/*#define KEEP_OFF */ - -/* Globals */ -int readit = 0; -int adjustit = 0; -int writeit = 0; -int setit = 0; -int universal = 0; -int debug = 0; - -volatile void -usage () -{ - fprintf (stderr, - "clock [-u] -r|w|s|a|v\n" - " r: read and print CMOS clock\n" - " w: write CMOS clock from system time\n" - " s: set system time from CMOS clock\n" - " a: get system time and adjust CMOS clock\n" - " u: CMOS clock is in universal time\n" - " v: print version (" VERSION ") and exit\n" - ); - exit (1); -} - -#ifndef USE_INLINE_ASM_IO -int cmos_fd; -#endif - -static inline unsigned char cmos_read(unsigned char reg) -{ - register unsigned char ret; - __asm__ volatile ("cli"); - outb (reg | 0x80, 0x70); - ret = inb (0x71); - __asm__ volatile ("sti"); - return ret; -} - -static inline void cmos_write(unsigned char reg, unsigned char val) -{ - outb (reg | 0x80, 0x70); - outb (val, 0x71); -} - -#ifndef outb -static inline void -outb (char val, unsigned short port) -{ -#ifdef USE_INLINE_ASM_IO - __asm__ volatile ("out%B0 %0,%1"::"a" (val), "d" (port)); -#else - lseek (cmos_fd, port, 0); - write (cmos_fd, &val, 1); -#endif -} -#endif - -#ifndef inb -static inline unsigned char -inb (unsigned short port) -{ - unsigned char ret; -#ifdef USE_INLINE_ASM_IO - __asm__ volatile ("in%B0 %1,%0":"=a" (ret):"d" (port)); -#else - lseek (cmos_fd, port, 0); - read (cmos_fd, &ret, 1); -#endif - return ret; -} -#endif - -void -cmos_init () -{ -#ifdef USE_INLINE_ASM_IO - if (iopl (3)) - { - fprintf(stderr,"clock: unable to get I/O port access\n"); - exit (1); - } -#else - cmos_fd = open ("/dev/port", 2); - if (cmos_fd < 0) - { - perror ("unable to open /dev/port read/write : "); - exit (1); - } - if (lseek (cmos_fd, 0x70, 0) < 0 || lseek (cmos_fd, 0x71, 0) < 0) - { - perror ("unable to seek port 0x70 in /dev/port : "); - exit (1); - } -#endif -} - -static inline int -cmos_read_bcd (int addr) -{ - int b; - b = cmos_read (addr); - return (b & 15) + (b >> 4) * 10; -} - -static inline void -cmos_write_bcd (int addr, int value) -{ - cmos_write (addr, ((value / 10) << 4) + value % 10); -} - -int -main (int argc, char **argv, char **envp) -{ - struct tm tm; - time_t systime; - time_t last_time; - char arg; - double factor; - double not_adjusted; - int adjustment = 0; - unsigned char save_control, save_freq_select; - - while ((arg = getopt (argc, argv, "rwsuaDv")) != -1) - { - switch (arg) - { - case 'r': - readit = 1; - break; - case 'w': - writeit = 1; - break; - case 's': - setit = 1; - break; - case 'u': - universal = 1; - break; - case 'a': - adjustit = 1; - break; - case 'D': - debug = 1; - break; - case 'v': - fprintf( stderr, "clock " VERSION "\n" ); - exit(0); - default: - usage (); - } - } - - if (readit + writeit + setit + adjustit > 1) - usage (); /* only allow one of these */ - - if (!(readit | writeit | setit | adjustit)) /* default to read */ - readit = 1; - - cmos_init (); - - if (adjustit) - { /* Read adjustment parameters first */ - FILE *adj; - if ((adj = fopen (ADJPATH, "r")) == NULL) - { - perror (ADJPATH); - exit (2); - } - if (fscanf (adj, "%lf %d %lf", &factor, &last_time, ¬_adjusted) < 0) - { - perror (ADJPATH); - exit (2); - } - fclose (adj); - if (debug) printf ("Last adjustment done at %d seconds after 1/1/1970\n", last_time); - } - - if (readit || setit || adjustit) - { - int i; - -/* read RTC exactly on falling edge of update flag */ -/* Wait for rise.... (may take upto 1 second) */ - - for (i = 0; i < 10000000; i++) - if (cmos_read (10) & 0x80) - break; - -/* Wait for fall.... (must try at least 2.228 ms) */ - - for (i = 0; i < 1000000; i++) - if (!(cmos_read (10) & 0x80)) - break; - -/* The purpose of the "do" loop is called "low-risk programming" */ -/* In theory it should never run more than once */ - do - { - tm.tm_sec = cmos_read_bcd (0); - tm.tm_min = cmos_read_bcd (2); - tm.tm_hour = cmos_read_bcd (4); - tm.tm_wday = cmos_read_bcd (6); - tm.tm_mday = cmos_read_bcd (7); - tm.tm_mon = cmos_read_bcd (8); - tm.tm_year = cmos_read_bcd (9); - } - while (tm.tm_sec != cmos_read_bcd (0)); - if (tm.tm_year < 70) - tm.tm_year += 100; /* 70..99 => 1970..1999, 0..69 => 2000..2069 */ - tm.tm_mon--; /* DOS uses 1 base */ - tm.tm_wday -= 3; /* DOS uses 3 - 9 for week days */ - tm.tm_isdst = -1; /* don't know whether it's daylight */ - if (debug) printf ("Cmos time : %d:%d:%d\n", tm.tm_hour, tm.tm_min, tm.tm_sec); - } - - if (readit || setit || adjustit) - { -/* - * mktime() assumes we're giving it local time. If the CMOS clock - * is in GMT, we have to set up TZ so mktime knows it. tzset() gets - * called implicitly by the time code, but only the first time. When - * changing the environment variable, better call tzset() explicitly. - */ - if (universal) - { - char *zone; - zone = (char *) getenv ("TZ"); /* save original time zone */ - (void) putenv ("TZ="); - tzset (); - systime = mktime (&tm); - /* now put back the original zone */ - if (zone) - { - - char *zonebuf; - zonebuf = malloc (strlen (zone) + 4); - strcpy (zonebuf, "TZ="); - strcpy (zonebuf+3, zone); - putenv (zonebuf); - free (zonebuf); - } - else - { /* wasn't one, so clear it */ - putenv ("TZ"); - } - tzset (); - } - else - { - systime = mktime (&tm); - } - if (debug) printf ("Number of seconds since 1/1/1970 is %d\n", systime); - } - - if (readit) - { - printf ("%s", ctime (&systime )); - } - - if (setit || adjustit) - { - struct timeval tv; - struct timezone tz; - -/* program is designed to run setuid, be secure! */ - - if (getuid () != 0) - { - fprintf (stderr, "Sorry, must be root to set or adjust time\n"); - exit (2); - } - - if (adjustit) - { /* the actual adjustment */ - double exact_adjustment; - - exact_adjustment = ((double) (systime - last_time)) - * factor / (24 * 60 * 60) - + not_adjusted; - if (exact_adjustment > 0) - adjustment = (int) (exact_adjustment + 0.5); - else - adjustment = (int) (exact_adjustment - 0.5); - not_adjusted = exact_adjustment - (double) adjustment; - systime += adjustment; - if (debug) { - printf ("Time since last adjustment is %d seconds\n", - (int) (systime - last_time)); - printf ("Adjusting time by %d seconds\n", - adjustment); - printf ("remaining adjustment is %.3f seconds\n", - not_adjusted); - } - } -#ifndef KEEP_OFF - tv.tv_sec = systime; - tv.tv_usec = 0; - tz.tz_minuteswest = timezone / 60; - tz.tz_dsttime = daylight; - - if (settimeofday (&tv, &tz) != 0) - { - fprintf (stderr, - "Unable to set time -- probably you are not root\n"); - exit (1); - } - - if (debug) { - printf( "Called settimeofday:\n" ); - printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n", - tv.tv_sec, tv.tv_usec ); - printf( "\ttz.tz_minuteswest = %d, tz.tz_dsttime = %d\n", - tz.tz_minuteswest, tz.tz_dsttime ); - } -#endif - } - - if (writeit || (adjustit && adjustment != 0)) - { - struct tm *tmp; - systime = time (NULL); - if (universal) - tmp = gmtime (&systime); - else - tmp = localtime (&systime); - -#ifndef KEEP_OFF - __asm__ volatile ("cli"); - save_control = cmos_read (11); /* tell the clock it's being set */ - cmos_write (11, (save_control | 0x80)); - save_freq_select = cmos_read (10); /* stop and reset prescaler */ - cmos_write (10, (save_freq_select | 0x70)); - - cmos_write_bcd (0, tmp->tm_sec); - cmos_write_bcd (2, tmp->tm_min); - cmos_write_bcd (4, tmp->tm_hour); - cmos_write_bcd (6, tmp->tm_wday + 3); - cmos_write_bcd (7, tmp->tm_mday); - cmos_write_bcd (8, tmp->tm_mon + 1); - cmos_write_bcd (9, tmp->tm_year); - - cmos_write (10, save_freq_select); - cmos_write (11, save_control); - __asm__ volatile ("sti"); -#endif - if (debug) printf ("Set to : %d:%d:%d\n", tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - } - else - if (debug) printf ("CMOS clock unchanged.\n"); - /* Save data for next 'adjustit' call */ - if (adjustit) - { - FILE *adj; - if ((adj = fopen (ADJPATH, "w")) == NULL) - { - perror (ADJPATH); - exit (2); - } - fprintf (adj, "%f %d %f\n", factor, systime, not_adjusted); - fclose (adj); - } - exit (0); -} diff --git a/sys-utils/cytune.c b/sys-utils/cytune.c index 32a27006..f7fe1ee3 100644 --- a/sys-utils/cytune.c +++ b/sys-utils/cytune.c @@ -35,11 +35,11 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -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 88052853..56beb3fe 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -9,13 +9,24 @@ #include #include #include +#include -#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 +#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 00000000..a7308a60 --- /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 00000000..9f4d7714 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 , 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 +/* 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 +#include +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 seconds after + the time . Of course, 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 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 of the Hardware Clock value to . +----------------------------------------------------------------------------*/ +#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 . 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 + 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 + 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 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 argument. + + Use the method indicated by 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 . 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 . + 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 , in local time zone or UTC, + according to . + + Use the method indicated by the 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 and before that was set + to . + + We assume that the user has been doing regular drift adjustments + using the drift factor in the adjtime file, so if and + 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 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 and are current values from the adjtime + file. + + is the current time set in the Hardware Clock. + + is the current system time (to be precise, it is the system + time at the time was read, which due to computational delay + could be a short time ago). + + : the Hardware Clock is kept in UTC. + + : 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 + 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. + + 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 , 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 . + + 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 7273b341..eceb0b71 100644 --- a/sys-utils/ipcrm.c +++ b/sys-utils/ipcrm.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c index 12df2261..9505aff5 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 #include @@ -18,6 +28,11 @@ entry. */ #include #include +#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 d8632a20..e61fb890 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 +#include #include #include +#include +#include +#if LINUX_VERSION_CODE >= 131072 +/* Kd.h is not available with all linux versions. 131072 is equivalent + to linux 2.0.0 */ +#include +#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 cb3a730e..77e1a58f 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 + /* 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 fd5d7196..a72113c8 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 58234f6a..4c52cf1f 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 #include #include -#include /* getopt() */ +#include #include +#include +#include +#include -#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 (default = \"%s\")\n" "\t -p (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 #include +#include + +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 539db21a..00000000 --- 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 71179baa..00000000 --- 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 -#include -#include -#include -#include - -#include -#include -#include - -#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 00000000..a61a2696 --- /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 00000000..6d31225c --- /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 + * + **************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#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 00000000..ca8501ef --- /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 00000000..a8927193 --- /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 f8bb704f..00000000 --- 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 5b7fd82b..00000000 --- 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 -#ifndef __ASSEMBLY__ -#define __ASSEMBLY__ -#endif -#include - - .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 bff56762..8b148f20 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 +.\" 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 a854b46b..6bdebda7 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 */ diff --git a/syslogd/Makefile b/syslogd/Makefile deleted file mode 100644 index 9892e3bd..00000000 --- a/syslogd/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Makefile -- Makefile for syslogd utility for Linux -# Created: Sat Oct 9 10:25:19 1993 -# Revised: Fri Mar 10 21:21:51 1995 by faith@cs.unc.edu -# Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) -# - -include ../MCONFIG - -LDLIBS= -lbsd - -MAN5= syslog.conf.5 - -MAN8= syslogd.8 - -ETC= syslogd - -all: $(ETC) - -$(ETC): - $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) - -syslogd: syslogd.o ttymsg.o - -install: all - $(INSTALLDIR) $(USRSBINDIR) - $(INSTALLBIN) $(ETC) $(USRSBINDIR) - $(INSTALLDIR) $(MAN5DIR) $(MAN8DIR) - $(INSTALLMAN) $(MAN5) $(MAN5DIR) - $(INSTALLMAN) $(MAN8) $(MAN8DIR) - -clean: - -rm -f $(ETC) *.o *~ diff --git a/syslogd/syslog.conf.5 b/syslogd/syslog.conf.5 deleted file mode 100644 index edb970ce..00000000 --- a/syslogd/syslog.conf.5 +++ /dev/null @@ -1,240 +0,0 @@ -.\" Copyright (c) 1990, 1991 The Regents of the University of California. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)syslog.conf.5 5.3 (Berkeley) 5/10/91 -.\" -.Dd May 10, 1991 -.Dt SYSLOG.CONF 5 -.Os -.Sh NAME -.Nm syslog.conf -.Nd -.Xr syslogd 8 -configuration file -.Sh DESCRIPTION -The -.Nm syslog.conf -file is the configuration file for the -.Xr syslogd 8 -program. -It consists of lines with two fields: the -.Em selector -field which specifies the types of messages and priorities to which the -line applies, and an -.Em action -field which specifies the action to be taken if a message -.Xr syslogd -received matches the selection criteria. There may not be -.Em any -spaces in the action field. -The -.Em selector -field is separated from the -.Em action -field by one or more tab or space characters (this is a departure from the -standard BSD way of doing things: both tabs -.Em and -spaces may be used to separate the selector from the action). -.Pp -The -.Em Selector -functions -are encoded as a -.Em facility , -a period (``.''), and a -.Em level , -with no intervening white-space. -Both the -.Em facility -and the -.Em level -are case insensitive. -.Pp -The -.Em facility -describes the part of the system generating the message, and is one of -the following keywords: auth, authpriv, cron, daemon, kern, lpr, mail, -mark, news, syslog, user, uucp and local0 through local7. -These keywords (with the exception of mark) correspond to the -similar -.Dq Dv LOG_ -values specified to the -.Xr openlog 3 -and -.Xr syslog 3 -library routines. -.Pp -The -.Em level -describes the severity of the message, and is a keyword, optionally -preceded by an equals (``=''), from the following ordered list -(higher to lower): emerg, alert, crit, err, warning, notice, info, -and debug. -These keywords correspond to the -similar -.Pq Dv LOG_ -values specified to the -.Xr syslog -library routine. -.Pp -See -.Xr syslog 3 -for a further descriptions of both the -.Em facility -and -.Em level -keywords and their significance. -.Pp -If a received message matches the specified -.Em facility -and is of the specified -.Em level -.Em (or a higher level if -.Em level -was specified without ``='') , -the action specified in the -.Em action -field will be taken. -.Pp -Multiple -.Em selectors -may be specified for a single -.Em action -by separating them with semicolon (``;'') characters. -It is important to note, however, that each -.Em selector -can modify the ones preceding it. -.Pp -Multiple -.Em facilities -may be specified for a single -.Em level -by separating them with comma (``,'') characters. -.Pp -An asterisk (``*'') can be used to specify all -.Em facilities -or all -.Em levels . -.Pp -The special -.Em facility -``mark'' receives a message at priority ``info'' every 20 minutes -(see -.Xr syslogd 8 ) . -This is not enabled by a -.Em facility -field containing an asterisk. -.Pp -The special -.Em level -``none'' disables a particular -.Em facility . -.Pp -The -.Em action -field of each line specifies the action to be taken when the -.Em selector -field selects a message. -There are four forms: -.Bl -bullet -.It -A pathname (beginning with a leading slash). -Selected messages are appended to the file. -.It -A hostname (preceded by an at (``@'') sign). -Selected messages are forwarded to the -.Xr syslogd -program on the named host. -.It -A comma separated list of users. -Selected messages are written to those users -if they are logged in. -.It -An asterisk. -Selected messages are written to all logged-in users. -.El -.Pp -Blank lines and lines whose first non-blank character is a hash (``#'') -character are ignored. -.Sh EXAMPLES -.Pp -A configuration file might appear as follows: -.Bd -literal -# Log all kernel messages, authentication messages of -# level notice or higher and anything of level err or -# higher to the console. -# Don't log private authentication messages! -*.err;kern.*;auth.notice;authpriv.none /dev/console - -# Log anything (except mail) of level info or higher. -# Don't log private authentication messages! -*.info;mail.none;authpriv.none /var/log/messages - -# Log debug messages only -*.=debug /var/log/debug - -# The authpriv file has restricted access. -authpriv.* /var/log/secure - -# Log all the mail messages in one place. -mail.* /var/log/maillog - -# Everybody gets emergency messages, plus log them on another -# machine. -*.emerg * -*.emerg @arpa.berkeley.edu - -# Root and Eric get alert and higher messages. -*.alert root,eric - -# Save mail and news errors of level err and higher in a -# special file. -uucp,news.crit /var/log/spoolerr -.Ed -.Sh FILES -.Bl -tag -width /etc/syslog.conf -compact -.It Pa /etc/syslog.conf -The -.Xr syslogd 8 -configuration file. -.El -.Sh BUGS -The effects of multiple selectors are sometimes not intuitive. -For example ``mail.crit,*.err'' will select ``mail'' facility messages at -the level of ``err'' or higher, not at the level of ``crit'' or higher. -.Sh SEE ALSO -.Xr syslog 3 , -.Xr syslogd 8 -.Sh HISTORY -The -.Nm syslog.conf -file format is -.Ud . diff --git a/syslogd/syslogd.8 b/syslogd/syslogd.8 deleted file mode 100644 index 3ec0959c..00000000 --- a/syslogd/syslogd.8 +++ /dev/null @@ -1,122 +0,0 @@ -.\" Copyright (c) 1983, 1986, 1991 The Regents of the University of California. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)syslogd.8 6.10 (Berkeley) 3/16/91 -.\" -.Dd March 16, 1991 -.Dt SYSLOGD 8 -.Os BSD 4.2 -.Sh NAME -.Nm syslogd -.Nd log systems messages -.Sh SYNOPSIS -.Nm syslogd -.Op Fl f Ar config_file -.Op Fl m Ar mark_interval -.Op Fl p Ar log_socket -.Sh DESCRIPTION -.Nm Syslogd -reads and logs messages to the system console, log files, other -machines and/or users as specified by its configuration file. -The options are as follows: -.Bl -tag -width Ds -.It Fl f -Specify the pathname of an alternate configuration file; -the default is -.Pa /etc/syslog.conf . -.It Fl m -Select the number of minutes between ``mark'' messages; -the default is 20 minutes. -.It Fl p -Specify the pathname of an alternate log socket; -the default is -.Pa /dev/log . -.El -.Pp -.Nm Syslogd -reads its configuration file when it starts up and whenever it -receives a hangup signal. -For information on the format of the configuration file, -see -.Xr syslog.conf 5 . -.Pp -.Nm Syslogd -reads messages from the -.Tn UNIX -domain socket -.Pa /dev/log , -from an Internet domain socket specified in -.Pa /etc/services , -and from the special device -.Pa /dev/klog -(to read kernel messages). -.Pp -.Nm Syslogd -creates the file -.Pa /var/run/syslog.pid , -and stores its process -id there. -This can be used to kill or reconfigure -.Nm syslogd . -.Pp -The message sent to -.Nm syslogd -should consist of a single line. -The message can contain a priority code, which should be a preceding -decimal number in angle braces, for example, -.Sq Aq 5. -This priority code should map into the priorities defined in the -include file -.Aq Pa sys/syslog.h . -.Sh FILES -.Bl -tag -width /var/run/syslog.pid -compact -.It Pa /etc/syslog.conf -The configuration file. -.It Pa /var/run/syslog.pid -The process id of current -.Nm syslogd . -.It Pa /dev/log -Name of the -.Tn UNIX -domain datagram log socket. -.It Pa /dev/klog -The kernel log device. -.El -.Sh SEE ALSO -.Xr logger 1 , -.Xr syslog 3 , -.Xr services 5 , -.Xr syslog.conf 5 -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.3 . diff --git a/syslogd/syslogd.c b/syslogd/syslogd.c deleted file mode 100644 index 733e3a69..00000000 --- a/syslogd/syslogd.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * Copyright (c) 1983, 1988 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Wed Sep 14 21:56:59 1994: Applied patches from Alan Modra - * (alan@spri.levels.unisa.edu.au): - * 1) Add O_CREAT to open flags so that syslogd doesn't complain about - * non-existent files - * 2) Modified f_pmask initialisation and testing to allow logging of - * messages at a particular priority level, rather that all messages - * at or above a given priority level. - * - * Sat Jun 3 12:48:16 1995: Applied patches from - * Jochen.Hein@informatik.tu-clausthal.de to allow spaces *AND* tabs to - * separate the selector from the action. This means that no whitespace is - * allowed inside the selector. - * */ - -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)syslogd.c 5.45 (Berkeley) 3/2/91"; -#endif /* not lint */ - -/* - * syslogd -- log system messages - * - * This program implements a system log. It takes a series of lines. - * Each line may have a priority, signified as "" as - * the first characters of the line. If this is - * not present, a default priority is used. - * - * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will - * cause it to reread its configuration file. - * - * Defined Constants: - * - * MAXLINE -- the maximimum line length that can be handled. - * DEFUPRI -- the default priority for user messages - * DEFSPRI -- the default priority for kernel messages - * - * Author: Eric Allman - * extensive changes by Ralph Campbell - * more extensive changes by Eric Allman (again) - * - * Modified, Sun Mar 7 15:21:13 1993, faith@cs.unc.edu for Linux: - * - * SUN_LEN_MISSING: struct sockaddr does not have sun_len - * SYSLOG_STREAM: syslog is implemented using stream sockets - * SYSLOG_INET: support inet logging - * KLOG_STREAM: kernel logging uses a stream device - * STATUS_BROKEN: use "int status" instead of "union wait status" - * RE_INSTALL_SIGNAL: signal() does *not* remain installed - * SYS_MSGBUF_H_MISSING: sys/msgbuf.h is missing - * FSYNC_MISSING: fsync() is missing - * KERNEL_NAME: what the kernel is usually called - * - * Original Linux version by Rik Faith - * with changes by Rick Sladkey and - * Rick . Anyone else - * named Rick who wants to chip in? :-) - * More corrections by Neal Becker Sun Jan 16, 1994 - * Patches from Jochen Hein (Jochen.Hein@informatik.tu-clausthal.de) to treat - * spaces and tabs the same, applied Sat Mar 11 10:09:24 1995 - */ - -#ifdef __linux__ -#define SUN_LEN_MISSING -#define SYSLOG_STREAM -#define SYSLOG_INET -#define KLOG_STREAM -#undef STATUS_BROKEN -#define RE_INSTALL_SIGNAL -#define SYS_MSGBUF_H_MISSING -#undef FSYNC_MISSING -#define KERNEL_NAME "linux" -#endif - -#define MAXLINE 1024 /* maximum line length */ -#define MAXSVLINE 120 /* maximum saved line length */ -#define DEFUPRI (LOG_USER|LOG_NOTICE) -#define DEFSPRI (LOG_KERN|LOG_CRIT) -#define TIMERINTVL 30 /* interval for checking flush, mark */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef SYS_MSGBUF_H_MISSING -#define MSG_BSIZE (MAXLINE*2) -#else -#include -#endif -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define SYSLOG_NAMES -#include - -char *LogName = _PATH_LOG; -char *ConfFile = _PATH_LOGCONF; - -#ifdef __linux__ -#define CONFORM_TO_FSSTND -#include "pathnames.h" -#endif - -#ifdef CONFORM_TO_FSSTND -char *PidFile = "/var/run/syslog.pid"; -#else -char *PidFile = _PATH_LOGPID; -#endif - -char ctty[] = _PATH_CONSOLE; - -#define FDMASK(fd) (1 << (fd)) - -#define dprintf if (Debug) printf - -#define MAXUNAMES 20 /* maximum number of user names */ - -/* - * Flags to logmsg(). - */ - -#define IGN_CONS 0x001 /* don't print on console */ -#define SYNC_FILE 0x002 /* do fsync on file after printing */ -#define ADDDATE 0x004 /* add a date to the message */ -#define MARK 0x008 /* this message is a mark */ - -/* - * This structure represents the files that will have log - * copies printed. - */ - -struct filed { - struct filed *f_next; /* next in linked list */ - short f_type; /* entry type, see below */ - short f_file; /* file descriptor */ - time_t f_time; /* time this was last written */ - u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ - union { - char f_uname[MAXUNAMES][UT_NAMESIZE+1]; - struct { - char f_hname[MAXHOSTNAMELEN+1]; - struct sockaddr_in f_addr; - } f_forw; /* forwarding address */ - char f_fname[MAXPATHLEN]; - } f_un; - char f_prevline[MAXSVLINE]; /* last message logged */ - char f_lasttime[16]; /* time of last occurrence */ - char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ - int f_prevpri; /* pri of f_prevline */ - int f_prevlen; /* length of f_prevline */ - int f_prevcount; /* repetition cnt of prevline */ - int f_repeatcount; /* number of "repeated" msgs */ -}; - -/* - * Intervals at which we flush out "message repeated" messages, - * in seconds after previous message is logged. After each flush, - * we move to the next interval until we reach the largest. - */ -int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ -#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) -#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) -#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ - (f)->f_repeatcount = MAXREPEAT; \ - } - -/* values for f_type */ -#define F_UNUSED 0 /* unused entry */ -#define F_FILE 1 /* regular file */ -#define F_TTY 2 /* terminal */ -#define F_CONSOLE 3 /* console terminal */ -#define F_FORW 4 /* remote machine */ -#define F_USERS 5 /* list of users */ -#define F_WALL 6 /* everyone logged on */ - -char *TypeNames[7] = { - "UNUSED", "FILE", "TTY", "CONSOLE", - "FORW", "USERS", "WALL" -}; - -struct filed *Files; -struct filed consfile; - -int Debug; /* debug flag */ -char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ -char *LocalDomain; /* our local domain name */ -int InetInuse = 0; /* non-zero if INET sockets are being used */ -#ifdef SYSLOG_INET -int finet; /* Internet datagram socket */ -#endif /* SYSLOG_INET */ -int LogPort; /* port number for INET connections */ -int Initialized = 0; /* set when we have initialized ourselves */ -int MarkInterval = 20 * 60; /* interval between marks in seconds */ -int MarkSeq = 0; /* mark sequence number */ - -extern int errno; -extern char *ctime(), *index(), *calloc(); - -main(argc, argv) - int argc; - char **argv; -{ - register int i; - register char *p; - int funix, fklog, len; - struct sockaddr_un sunx, fromunix; - struct sockaddr_in sin, frominet; - FILE *fp; - int ch; - char line[MSG_BSIZE + 1]; - extern int optind; - extern char *optarg; - void die(), domark(), init(), reapchild(); -#ifdef SYSLOG_STREAM - fd_set unixm; - int fd; -#endif /* SYSLOG_STREAM */ - - while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) - switch((char)ch) { - case 'd': /* debug */ - Debug++; - break; - case 'f': /* configuration file */ - ConfFile = optarg; - break; - case 'm': /* mark interval */ - MarkInterval = atoi(optarg) * 60; - break; - case 'p': /* path */ - LogName = optarg; - break; - case '?': - default: - usage(); - } - if (argc -= optind) - usage(); - - if (!Debug) - daemon(0, 0); - else - setlinebuf(stdout); - - consfile.f_type = F_CONSOLE; - (void) strcpy(consfile.f_un.f_fname, ctty); - (void) gethostname(LocalHostName, sizeof LocalHostName); - if (p = index(LocalHostName, '.')) { - *p++ = '\0'; - LocalDomain = p; - } - else - LocalDomain = ""; - (void) signal(SIGTERM, die); - (void) signal(SIGINT, Debug ? die : SIG_IGN); - (void) signal(SIGQUIT, Debug ? die : SIG_IGN); - (void) signal(SIGCHLD, reapchild); - (void) signal(SIGALRM, domark); - (void) alarm(TIMERINTVL); - (void) unlink(LogName); - - bzero((char *)&sunx, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path); -#ifdef SYSLOG_STREAM - funix = socket(AF_UNIX, SOCK_STREAM, 0); - if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, - sizeof(sunx)) < 0 || listen(funix, 5) < 0 || -#else /* !SYSLOG_STREAM */ - funix = socket(AF_UNIX, SOCK_DGRAM, 0); - if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, - sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+ - strlen(sunx.sun_path)) < 0 || -#endif /* !SYSLOG_STREAM */ - chmod(LogName, 0666) < 0) { - (void) sprintf(line, "cannot create %s", LogName); - logerror(line); - dprintf("cannot create %s (%d)\n", LogName, errno); - die(0); - } -#ifdef SYSLOG_INET - finet = socket(AF_INET, SOCK_DGRAM, 0); - if (finet >= 0) { - struct servent *sp; - - sp = getservbyname("syslog", "udp"); - if (sp == NULL) { - errno = 0; - logerror("syslog/udp: unknown service"); - } - else { - bzero((char *) &sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = LogPort = sp->s_port; - if (bind(finet, (struct sockaddr *) &sin, - sizeof(sin)) < 0) - logerror("bind"); - else - InetInuse = 1; - } - if (!InetInuse) - finet = -1; - } -#endif /* SYSLOG_INET */ - if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) - dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); - - /* tuck my process id away */ - fp = fopen(PidFile, "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); - (void) fclose(fp); - } - - dprintf("off & running....\n"); - - init(); -#ifndef RE_INSTALL_SIGNAL /* init installs itself as the handler */ - (void) signal(SIGHUP, init); -#endif /* !RE_INSTALL_SIGNAL */ -#ifdef SYSLOG_STREAM - FD_ZERO(&unixm); -#endif /* SYSLOG_STREAM */ - - for (;;) { - int nfds; - fd_set readfds; - -#ifdef SYSLOG_STREAM - readfds = unixm; -#else /* !SYSLOG_STREAM */ - FD_ZERO(&readfds); -#endif /* !SYSLOG_STREAM */ - if (funix >= 0) - FD_SET(funix, &readfds); - if (fklog >= 0) - FD_SET(fklog, &readfds); -#ifdef SYSLOG_INET - if (finet >= 0) - FD_SET(finet, &readfds); -#endif /* SYSLOG_INET */ - - errno = 0; - dprintf("readfds = %#x\n", *((long *)&readfds)); - nfds = select(FD_SETSIZE, &readfds, (fd_set *) NULL, - (fd_set *) NULL, (struct timeval *) NULL); - if (nfds == 0) - continue; - if (nfds < 0) { - if (errno != EINTR) - logerror("select"); - continue; - } - dprintf("got a message (%d, %#x)\n", nfds, *((long *)&readfds)); - -#ifdef KLOG_STREAM - if (FD_ISSET(fklog, &readfds)) { - nfds--; - for (;;) { - i = klogread(fklog, line, sizeof(line) - 1); - if (i > 0) { - line[i] = '\0'; - printsys(line); - } - else { - if (i < 0 && errno != EINTR) { - logerror("klog"); - fklog = -1; - } - break; - } - } - } -#else /* !KLOG_STREAM */ - if (FD_ISSET(fklog, &readfds)) { - nfds--; - i = read(fklog, line, sizeof(line) - 1); - if (i > 0) { - line[i] = '\0'; - printsys(line); - } else if (i < 0 && errno != EINTR) { - logerror("klog"); - fklog = -1; - } - } -#endif /* !KLOG_STREAM */ - -#ifdef SYSLOG_STREAM - /* Accept a new unix connection. */ - if (FD_ISSET(funix, &readfds)) { - nfds--; - len = sizeof fromunix; - if ((fd = accept(funix, (struct sockaddr *) &fromunix, - &len)) >= 0) { - FD_SET(fd, &unixm); - dprintf("new stream connect (%d)\n", fd); - } - else - logerror("accept"); - } - /* Recv from existing connections. */ - for (fd = 0; nfds > 0 && fd < FD_SETSIZE; fd++) { - if (FD_ISSET(fd, &unixm) && FD_ISSET(fd, &readfds)) { - nfds--; - dprintf("message from stream (%d)\n", fd); - i = read(fd, line, MAXLINE); - if (i > 0) { - line[i] = '\0'; - printmulti(LocalHostName, line, i); - } - else if (i == 0) { - dprintf("stream closed (%d)\n", fd); - close(fd); - FD_CLR(fd, &unixm); - } - else if (i < 0 && errno != EINTR) { - logerror("recv stream"); - close(fd); - FD_CLR(fd, &unixm); - } - } - } -#else /* !SYSLOG_STREAM */ - if (FD_ISSET(funix, &readfds)) { - nfds--; - len = sizeof fromunix; - i = recvfrom(funix, line, MAXLINE, 0, - (struct sockaddr *) &fromunix, &len); - if (i > 0) { - line[i] = '\0'; - printmulti(LocalHostName, line,i); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom unix"); - } -#endif /* !SYSLOG_STREAM */ - -#ifdef SYSLOG_INET - if (FD_ISSET(finet, &readfds)) { - nfds--; - len = sizeof frominet; - i = recvfrom(finet, line, MAXLINE, 0, - (struct sockaddr *) &frominet, &len); - if (i > 0) { - extern char *cvthname(); - - line[i] = '\0'; - printmulti(cvthname(&frominet), line,i); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom inet"); - } -#endif /* SYSLOG_INET */ - if (nfds != 0) - logerror("loose cannon"); - } -} - -usage() -{ - (void) fprintf(stderr, - "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n"); - exit(1); -} - -/* - * Break up null terminated lines for printline. - */ - -printmulti(hname, msg, len) - char *hname; - char *msg; - int len; -{ - int i; - char *pt; - - dprintf("strlen = %d, len = %d\n", strlen(msg), len ); - for (pt = msg, i = 0; i < len; i++) { - if (msg[i] == '\0') { - printline(hname,pt); - pt = &msg[i+1]; - } - } -} - -/* - * Take a raw input line, decode the message, and print the message - * on the appropriate log files. - */ - -printline(hname, msg) - char *hname; - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri; - - /* test for special codes */ - pri = DEFUPRI; - p = msg; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFUPRI; - - /* don't allow users to log kernel messages */ - if (LOG_FAC(pri) == LOG_KERN) - pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); - - q = line; - - while ((c = *p++ & 0177) != '\0' && - q < &line[sizeof(line) - 1]) - if (iscntrl(c)) { - if (c == '\n') - *q++ = ' '; - else if (c == '\r') - *q++ = ' '; - else if (c == '\t') - *q++ = '\t'; - else { - *q++ = '^'; - *q++ = c ^ 0100; - } - } - else - *q++ = c; - *q = '\0'; - - logmsg(pri, line, hname, 0); -} - -/* - * Take a raw input line from /dev/klog, split and format similar to syslog(). - */ - -printsys(msg) - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri, flags; - char *lp; - -#ifdef KERNEL_NAME - (void) sprintf(line, "%s: ", KERNEL_NAME); -#else /* !KERNEL_NAME */ - (void) strcpy(line, "vmunix: "); -#endif /* !KERNEL_NAME */ - - lp = line + strlen(line); - for (p = msg; *p != '\0'; ) { - flags = SYNC_FILE | ADDDATE; /* fsync file after write */ - pri = DEFSPRI; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } else { - /* kernel printf's come out on console */ - flags |= IGN_CONS; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFSPRI; - q = lp; - while (*p != '\0' && (c = *p++) != '\n' && - q < &line[MAXLINE]) - if (iscntrl(c)) { - if (c == '\n') - *q++ = ' '; - else if (c == '\r') - *q++ = ' '; - else if (c == '\t') - *q++ = '\t'; - else { - *q++ = '^'; - *q++ = c ^ 0100; - } - } - else - *q++ = c; - *q = '\0'; - logmsg(pri, line, LocalHostName, flags); - } -} - -time_t now; - -/* - * Log a message to the appropriate log files, users, etc. based on - * the priority. - */ - -logmsg(pri, msg, from, flags) - int pri; - char *msg, *from; - int flags; -{ - register struct filed *f; - int fac, prilev; - int omask, msglen; - char *timestamp; - time_t time(); - - dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", - pri, flags, from, msg); - - omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); - - /* - * Check to see if msg looks non-standard. - */ - msglen = strlen(msg); - if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') - flags |= ADDDATE; - - (void) time(&now); - if (flags & ADDDATE) - timestamp = ctime(&now) + 4; - else { - timestamp = msg; - msg += 16; - msglen -= 16; - } - - /* extract facility and priority level */ - if (flags & MARK) - fac = LOG_NFACILITIES; - else - fac = LOG_FAC(pri); - prilev = 1 << (LOG_PRIMASK - LOG_PRI(pri)); - - /* log the message to the particular outputs */ - if (!Initialized) { - f = &consfile; -#ifdef O_NOCTTY - f->f_file = open(ctty, O_WRONLY|O_NOCTTY, 0); -#else /* !O_NOCTTY */ - f->f_file = open(ctty, O_WRONLY, 0); -#endif /* !O_NOCTTY */ - - if (f->f_file >= 0) { - fprintlog(f, flags, msg); - (void) close(f->f_file); - } - (void) sigsetmask(omask); - return; - } - for (f = Files; f; f = f->f_next) { - /* skip messages that are incorrect priority */ - if (!(f->f_pmask[fac] & prilev)) - continue; - - if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) - continue; - - /* don't output marks to recently written files */ - if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) - continue; - - /* - * suppress duplicate lines to this file - */ - if ((flags & MARK) == 0 && msglen == f->f_prevlen && - !strcmp(msg, f->f_prevline) && - !strcmp(from, f->f_prevhost)) { - (void) strncpy(f->f_lasttime, timestamp, 15); - f->f_prevcount++; - dprintf("msg repeated %d times, %ld sec of %d\n", - f->f_prevcount, now - f->f_time, - repeatinterval[f->f_repeatcount]); - /* - * If domark would have logged this by now, - * flush it now (so we don't hold isolated messages), - * but back off so we'll flush less often - * in the future. - */ - if (now > REPEATTIME(f)) { - fprintlog(f, flags, (char *)NULL); - BACKOFF(f); - } - } else { - /* new line, save it */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - f->f_repeatcount = 0; - (void) strncpy(f->f_lasttime, timestamp, 15); - (void) strncpy(f->f_prevhost, from, - sizeof(f->f_prevhost)); - if (msglen < MAXSVLINE) { - f->f_prevlen = msglen; - f->f_prevpri = pri; - (void) strcpy(f->f_prevline, msg); - fprintlog(f, flags, (char *)NULL); - } else { - f->f_prevline[0] = 0; - f->f_prevlen = 0; - fprintlog(f, flags, msg); - } - } - } - (void) sigsetmask(omask); -} - -fprintlog(f, flags, msg) - register struct filed *f; - int flags; - char *msg; -{ - struct iovec iov[6]; - register struct iovec *v; - register int l; - char line[MAXLINE + 1], repbuf[80], greetings[200]; - - v = iov; - if (f->f_type == F_WALL) { - v->iov_base = greetings; - v->iov_len = sprintf(greetings, - "\r\n\7Message from syslogd@%s at %.24s ...\r\n", - f->f_prevhost, ctime(&now)); - v++; - v->iov_base = ""; - v->iov_len = 0; - v++; - } else { - v->iov_base = f->f_lasttime; - v->iov_len = 15; - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - } - v->iov_base = f->f_prevhost; - v->iov_len = strlen(v->iov_base); - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - - if (msg) { - v->iov_base = msg; - v->iov_len = strlen(msg); - } else if (f->f_prevcount > 1) { - v->iov_base = repbuf; - v->iov_len = sprintf(repbuf, "last message repeated %d times", - f->f_prevcount); - } else { - v->iov_base = f->f_prevline; - v->iov_len = f->f_prevlen; - } - v++; - - dprintf("Logging to %s", TypeNames[f->f_type]); - f->f_time = now; - - switch (f->f_type) { - case F_UNUSED: - dprintf("\n"); - break; - - case F_FORW: - dprintf(" %s\n", f->f_un.f_forw.f_hname); - l = sprintf(line, "<%d>%.15s %s", f->f_prevpri, - iov[0].iov_base, iov[4].iov_base); - if (l > MAXLINE) - l = MAXLINE; - if (sendto(finet, line, l, 0, - (struct sockaddr *)&f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr) != l) { - int e = errno; - (void) close(f->f_file); - f->f_type = F_UNUSED; - errno = e; - logerror("sendto"); - } - break; - - case F_CONSOLE: - if (flags & IGN_CONS) { - dprintf(" (ignored)\n"); - break; - } - /* FALLTHROUGH */ - - case F_TTY: - case F_FILE: - dprintf(" %s\n", f->f_un.f_fname); - if (f->f_type != F_FILE) { - v->iov_base = "\r\n"; - v->iov_len = 2; - } else { - v->iov_base = "\n"; - v->iov_len = 1; - } - again: - if (writev(f->f_file, iov, 6) < 0) { - int e = errno; - (void) close(f->f_file); - /* - * Check for errors on TTY's due to loss of tty - */ - if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { - f->f_file = open(f->f_un.f_fname, - O_WRONLY|O_APPEND, 0); - if (f->f_file < 0) { - f->f_type = F_UNUSED; - logerror(f->f_un.f_fname); - } else - goto again; - } else { - f->f_type = F_UNUSED; - errno = e; - logerror(f->f_un.f_fname); - } - } -#ifdef FSYNC_MISSING - else if (flags & SYNC_FILE) - (void) sync(); -#else - else if (flags & SYNC_FILE) - (void) fsync(f->f_file); -#endif - break; - - case F_USERS: - case F_WALL: - dprintf("\n"); - v->iov_base = "\r\n"; - v->iov_len = 2; - wallmsg(f, iov); - break; - } - f->f_prevcount = 0; -} - -/* - * WALLMSG -- Write a message to the world at large - * - * Write the specified message to either the entire - * world, or a list of approved users. - */ - -wallmsg(f, iov) - register struct filed *f; - struct iovec *iov; -{ - static int reenter; /* avoid calling ourselves */ - register FILE *uf; - register int i; - struct utmp ut; - char *p, *ttymsg(); - - if (reenter++) - return; - if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { - logerror(_PATH_UTMP); - reenter = 0; - return; - } - /* NOSTRICT */ - while (fread((char *) &ut, sizeof ut, 1, uf) == 1) { - if (ut.ut_name[0] == '\0') - continue; -#ifdef USER_PROCESS - if (ut.ut_type != USER_PROCESS) - continue; -#endif - if (f->f_type == F_WALL) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - continue; - } - /* should we send the message to this user? */ - for (i = 0; i < MAXUNAMES; i++) { - if (!f->f_un.f_uname[i][0]) - break; - if (!strncmp(f->f_un.f_uname[i], ut.ut_name, - UT_NAMESIZE)) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - break; - } - } - } - (void) fclose(uf); - reenter = 0; -} - -void -reapchild() -{ -#ifdef STATUS_BROKEN - int status; -#else - union wait status; -#endif - - while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) - ; -} - -/* - * Return a printable representation of a host address. - */ -char * -cvthname(f) - struct sockaddr_in *f; -{ - struct hostent *hp; - register char *p; - extern char *inet_ntoa(); - - dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); - - if (f->sin_family != AF_INET) { - dprintf("Malformed from address\n"); - return ("???"); - } - hp = gethostbyaddr((char *)&f->sin_addr, - sizeof(struct in_addr), f->sin_family); - if (hp == 0) { - dprintf("Host name for your address (%s) unknown\n", - inet_ntoa(f->sin_addr)); - return (inet_ntoa(f->sin_addr)); - } - if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) - *p = '\0'; - return ((char *) hp->h_name); -} - -void -domark() -{ - register struct filed *f; - time_t time(); - - now = time((time_t *)NULL); - MarkSeq += TIMERINTVL; - if (MarkSeq >= MarkInterval) { - logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); - MarkSeq = 0; - } - - for (f = Files; f; f = f->f_next) { - if (f->f_prevcount && now >= REPEATTIME(f)) { - dprintf("flush %s: repeated %d times, %d sec.\n", - TypeNames[f->f_type], f->f_prevcount, - repeatinterval[f->f_repeatcount]); - fprintlog(f, 0, (char *)NULL); - BACKOFF(f); - } - } -#ifdef RE_INSTALL_SIGNAL - (void) signal(SIGALRM, domark); -#endif - (void) alarm(TIMERINTVL); -} - -/* - * Print syslogd errors some place. - */ -logerror(type) - char *type; -{ - char buf[100], *strerror(); - - if (errno) - (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno)); - else - (void) sprintf(buf, "syslogd: %s", type); - errno = 0; - dprintf("%s\n", buf); - logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); -} - -void -die(sig) -{ - register struct filed *f; - char buf[100]; - - for (f = Files; f != NULL; f = f->f_next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - } - if (sig) { - dprintf("syslogd: exiting on signal %d\n", sig); - (void) sprintf(buf, "exiting on signal %d", sig); - errno = 0; - logerror(buf); - } - (void) unlink(LogName); - exit(0); -} - -/* - * INIT -- Initialize syslogd from configuration table - */ - -void -init() -{ - register int i; - register FILE *cf; - register struct filed *f, *next, **nextp; - register char *p; - char cline[BUFSIZ]; - - dprintf("init\n"); - - /* - * Close all open log files. - */ - Initialized = 0; - for (f = Files; f != NULL; f = next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - case F_FORW: - (void) close(f->f_file); - break; - } - next = f->f_next; - free((char *) f); - } - Files = NULL; - nextp = &Files; - - /* open the configuration file */ - if ((cf = fopen(ConfFile, "r")) == NULL) { - dprintf("cannot open %s\n", ConfFile); - *nextp = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.ERR\t/dev/console", *nextp); - (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.PANIC\t*", (*nextp)->f_next); - Initialized = 1; - return; - } - - /* - * Foreach line in the conf table, open that file. - */ - f = NULL; - while (fgets(cline, sizeof cline, cf) != NULL) { - /* - * check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - for (p = cline; isspace(*p); ++p); - if (*p == '\0' || *p == '#') - continue; - for (p = index(cline, '\0'); isspace(*--p);); - *++p = '\0'; - f = (struct filed *)calloc(1, sizeof(*f)); - *nextp = f; - nextp = &f->f_next; - cfline(cline, f); - } - - /* close the configuration file */ - (void) fclose(cf); - - Initialized = 1; - - if (Debug) { - for (f = Files; f; f = f->f_next) { - for (i = 0; i <= LOG_NFACILITIES; i++) - if (f->f_pmask[i] == 0) - printf("X "); - else - printf("0x%02x ", f->f_pmask[i]); - printf("%s: ", TypeNames[f->f_type]); - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - printf("%s", f->f_un.f_fname); - break; - - case F_FORW: - printf("%s", f->f_un.f_forw.f_hname); - break; - - case F_USERS: - for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) - printf("%s, ", f->f_un.f_uname[i]); - break; - } - printf("\n"); - } - } - - logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); - dprintf("syslogd: restarted\n"); -#ifdef RE_INSTALL_SIGNAL - (void) signal(SIGHUP, init); -#endif /* RE_INSTALL_SIGNAL */ -} - -/* - * Crack a configuration file line - */ - -cfline(line, f) - char *line; - register struct filed *f; -{ - register char *p; - register char *q; - register int i; - char *bp; - int pri; - struct hostent *hp; - char buf[MAXLINE], ebuf[100]; - - dprintf("cfline(%s)\n", line); - - errno = 0; /* keep strerror() stuff out of logerror messages */ - - /* clear out file entry */ - bzero((char *) f, sizeof *f); - for (i = 0; i <= LOG_NFACILITIES; i++) - f->f_pmask[i] = 0; - - /* scan through the list of selectors */ - for (p = line; *p && *p != '\t' && *p != ' ';) { - - /* find the end of this facility name list */ - for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; ) - continue; - - /* collect priority name */ - for (bp = buf; *q && !index("\t,; ", *q); ) - *bp++ = *q++; - *bp = '\0'; - - /* skip cruft */ - while (index(",;", *q)) /* spaces no longer allowed! */ - q++; - - /* decode priority name */ - if (*buf == '*') - pri = -1; - else { - pri = decode(*buf == '=' ? buf+1 : buf, prioritynames); - if (pri == INTERNAL_NOPRI) - pri = 0; - else if (pri < 0 || pri > LOG_PRIMASK) { - (void) sprintf(ebuf, - "unknown priority name \"%s\"", buf); - logerror(ebuf); - return; - } - else - pri = (*buf == '=' ? 1 : -1) << (LOG_PRIMASK - pri); - - } - - /* scan facilities */ - while (*p && !index("\t.; ", *p)) { - for (bp = buf; *p && !index("\t,;. ", *p); ) - *bp++ = *p++; - *bp = '\0'; - if (*buf == '*') - for (i = 0; i < LOG_NFACILITIES; i++) - if (pri == 0) - f->f_pmask[i] = pri; - else - f->f_pmask[i] |= pri; - else { - i = decode(buf, facilitynames); - if (i < 0) { - (void) sprintf(ebuf, - "unknown facility name \"%s\"", - buf); - logerror(ebuf); - return; - } - if (pri == 0) - f->f_pmask[i >> 3] = pri; - else - f->f_pmask[i >> 3] |= pri; - } - while (*p == ',' || *p == ' ') - p++; - } - - p = q; - } - - /* skip to action part */ - while (*p == '\t' || *p == ' ') - p++; - - switch (*p) - { - case '@': - if (!InetInuse) - break; - (void) strcpy(f->f_un.f_forw.f_hname, ++p); - hp = gethostbyname(p); - if (hp == NULL) { - extern int h_errno, h_nerr; - extern char **h_errlist; - - logerror((u_int)h_errno < h_nerr ? - h_errlist[h_errno] : "Unknown error"); - break; - } - bzero((char *) &f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr); - f->f_un.f_forw.f_addr.sin_family = AF_INET; - f->f_un.f_forw.f_addr.sin_port = LogPort; - bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length); - f->f_type = F_FORW; - break; - - case '/': - (void) strcpy(f->f_un.f_fname, p); -#ifdef O_NOCTTY - if ((f->f_file = open(p, - O_CREAT|O_WRONLY|O_APPEND|O_NOCTTY, - 0644)) < 0) { -#else /* !O_NOCTTY */ - if ((f->f_file = open(p, - O_CREAT|O_WRONLY|O_APPEND, 0644)) < 0) { -#endif /* !O_NOCTTY */ - f->f_file = F_UNUSED; - logerror(p); - break; - } - if (isatty(f->f_file)) - f->f_type = F_TTY; - else - f->f_type = F_FILE; - if (strcmp(p, ctty) == 0) - f->f_type = F_CONSOLE; - break; - - case '*': - f->f_type = F_WALL; - break; - - default: - for (i = 0; i < MAXUNAMES && *p; i++) { - for (q = p; *q && *q != ','; ) - q++; - (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); - if ((q - p) > UT_NAMESIZE) - f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; - else - f->f_un.f_uname[i][q - p] = '\0'; - while (*q == ',' || *q == ' ') - q++; - p = q; - } - f->f_type = F_USERS; - break; - } -} - - -/* - * Decode a symbolic name to a numeric value - */ - -decode(name, codetab) - char *name; - CODE *codetab; -{ - register CODE *c; - register char *p; - char buf[40]; - - if (isdigit(*name)) - return (atoi(name)); - - (void) strcpy(buf, name); - for (p = buf; *p; p++) - if (isupper(*p)) - *p = tolower(*p); - for (c = codetab; c->c_name; c++) - if (!strcmp(buf, c->c_name)) - return (c->c_val); - - return (-1); -} - -#ifdef KLOG_STREAM - -int klogread(fd, buf, size) - int fd; - char *buf; - int size; -{ - static char line[MAXLINE]; - static char *pos = line; - - int i; - char *obuf = buf; - char *s; - char *end; - *pos = '\0'; - if (!(end = strchr(line, '\n'))) { - struct timeval tv; - fd_set readfds; - - tv.tv_sec = tv.tv_usec = 0; - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - i = select(fd + 1, (fd_set *) &readfds, (fd_set *) NULL, - (fd_set *) NULL, &tv); - if (i <= 0) - return i; - i = read(fd, pos, sizeof(line) - 1 - (pos - line)); - if (i <= 0) - return i; - pos += i; - *pos = '\0'; - if (!(end = strchr(line, '\n'))) - return 0; - } - for (s = line; s < end; s++) - if (*s != '\r') - *buf++ = *s; - end++; - for (s = line; end < pos; s++) - *s = *end++; - pos = s; - return (buf - obuf); -} - -#endif /* KLOG_STREAM */ diff --git a/syslogd/syslogd.c.bsd b/syslogd/syslogd.c.bsd deleted file mode 100644 index 63af6246..00000000 --- a/syslogd/syslogd.c.bsd +++ /dev/null @@ -1,1120 +0,0 @@ -/* - * Copyright (c) 1983, 1988 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)syslogd.c 5.45 (Berkeley) 3/2/91"; -#endif /* not lint */ - -/* - * syslogd -- log system messages - * - * This program implements a system log. It takes a series of lines. - * Each line may have a priority, signified as "" as - * the first characters of the line. If this is - * not present, a default priority is used. - * - * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will - * cause it to reread its configuration file. - * - * Defined Constants: - * - * MAXLINE -- the maximimum line length that can be handled. - * DEFUPRI -- the default priority for user messages - * DEFSPRI -- the default priority for kernel messages - * - * Author: Eric Allman - * extensive changes by Ralph Campbell - * more extensive changes by Eric Allman (again) - */ - -#define MAXLINE 1024 /* maximum line length */ -#define MAXSVLINE 120 /* maximum saved line length */ -#define DEFUPRI (LOG_USER|LOG_NOTICE) -#define DEFSPRI (LOG_KERN|LOG_CRIT) -#define TIMERINTVL 30 /* interval for checking flush, mark */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include "pathnames.h" - -#define SYSLOG_NAMES -#include - -char *LogName = _PATH_LOG; -char *ConfFile = _PATH_LOGCONF; -char *PidFile = _PATH_LOGPID; -char ctty[] = _PATH_CONSOLE; - -#define FDMASK(fd) (1 << (fd)) - -#define dprintf if (Debug) printf - -#define MAXUNAMES 20 /* maximum number of user names */ - -/* - * Flags to logmsg(). - */ - -#define IGN_CONS 0x001 /* don't print on console */ -#define SYNC_FILE 0x002 /* do fsync on file after printing */ -#define ADDDATE 0x004 /* add a date to the message */ -#define MARK 0x008 /* this message is a mark */ - -/* - * This structure represents the files that will have log - * copies printed. - */ - -struct filed { - struct filed *f_next; /* next in linked list */ - short f_type; /* entry type, see below */ - short f_file; /* file descriptor */ - time_t f_time; /* time this was last written */ - u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ - union { - char f_uname[MAXUNAMES][UT_NAMESIZE+1]; - struct { - char f_hname[MAXHOSTNAMELEN+1]; - struct sockaddr_in f_addr; - } f_forw; /* forwarding address */ - char f_fname[MAXPATHLEN]; - } f_un; - char f_prevline[MAXSVLINE]; /* last message logged */ - char f_lasttime[16]; /* time of last occurrence */ - char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ - int f_prevpri; /* pri of f_prevline */ - int f_prevlen; /* length of f_prevline */ - int f_prevcount; /* repetition cnt of prevline */ - int f_repeatcount; /* number of "repeated" msgs */ -}; - -/* - * Intervals at which we flush out "message repeated" messages, - * in seconds after previous message is logged. After each flush, - * we move to the next interval until we reach the largest. - */ -int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ -#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) -#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) -#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ - (f)->f_repeatcount = MAXREPEAT; \ - } - -/* values for f_type */ -#define F_UNUSED 0 /* unused entry */ -#define F_FILE 1 /* regular file */ -#define F_TTY 2 /* terminal */ -#define F_CONSOLE 3 /* console terminal */ -#define F_FORW 4 /* remote machine */ -#define F_USERS 5 /* list of users */ -#define F_WALL 6 /* everyone logged on */ - -char *TypeNames[7] = { - "UNUSED", "FILE", "TTY", "CONSOLE", - "FORW", "USERS", "WALL" -}; - -struct filed *Files; -struct filed consfile; - -int Debug; /* debug flag */ -char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ -char *LocalDomain; /* our local domain name */ -int InetInuse = 0; /* non-zero if INET sockets are being used */ -int finet; /* Internet datagram socket */ -int LogPort; /* port number for INET connections */ -int Initialized = 0; /* set when we have initialized ourselves */ -int MarkInterval = 20 * 60; /* interval between marks in seconds */ -int MarkSeq = 0; /* mark sequence number */ - -extern int errno; -extern char *ctime(), *index(), *calloc(); - -main(argc, argv) - int argc; - char **argv; -{ - register int i; - register char *p; - int funix, inetm, fklog, klogm, len; - struct sockaddr_un sunx, fromunix; - struct sockaddr_in sin, frominet; - FILE *fp; - int ch; - char line[MSG_BSIZE + 1]; - extern int optind; - extern char *optarg; - void die(), domark(), init(), reapchild(); - - while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) - switch((char)ch) { - case 'd': /* debug */ - Debug++; - break; - case 'f': /* configuration file */ - ConfFile = optarg; - break; - case 'm': /* mark interval */ - MarkInterval = atoi(optarg) * 60; - break; - case 'p': /* path */ - LogName = optarg; - break; - case '?': - default: - usage(); - } - if (argc -= optind) - usage(); - - if (!Debug) - daemon(0, 0); - else - setlinebuf(stdout); - - consfile.f_type = F_CONSOLE; - (void) strcpy(consfile.f_un.f_fname, ctty); - (void) gethostname(LocalHostName, sizeof LocalHostName); - if (p = index(LocalHostName, '.')) { - *p++ = '\0'; - LocalDomain = p; - } - else - LocalDomain = ""; - (void) signal(SIGTERM, die); - (void) signal(SIGINT, Debug ? die : SIG_IGN); - (void) signal(SIGQUIT, Debug ? die : SIG_IGN); - (void) signal(SIGCHLD, reapchild); - (void) signal(SIGALRM, domark); - (void) alarm(TIMERINTVL); - (void) unlink(LogName); - - bzero((char *)&sunx, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path); - funix = socket(AF_UNIX, SOCK_DGRAM, 0); - if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, - sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+ - strlen(sunx.sun_path)) < 0 || - chmod(LogName, 0666) < 0) { - (void) sprintf(line, "cannot create %s", LogName); - logerror(line); - dprintf("cannot create %s (%d)\n", LogName, errno); - die(0); - } - finet = socket(AF_INET, SOCK_DGRAM, 0); - if (finet >= 0) { - struct servent *sp; - - sp = getservbyname("syslog", "udp"); - if (sp == NULL) { - errno = 0; - logerror("syslog/udp: unknown service"); - die(0); - } - sin.sin_family = AF_INET; - sin.sin_port = LogPort = sp->s_port; - if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - logerror("bind"); - if (!Debug) - die(0); - } else { - inetm = FDMASK(finet); - InetInuse = 1; - } - } - if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) - klogm = FDMASK(fklog); - else { - dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); - klogm = 0; - } - - /* tuck my process id away */ - fp = fopen(PidFile, "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); - (void) fclose(fp); - } - - dprintf("off & running....\n"); - - init(); - (void) signal(SIGHUP, init); - - for (;;) { - int nfds, readfds = FDMASK(funix) | inetm | klogm; - - errno = 0; - dprintf("readfds = %#x\n", readfds); - nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL, - (fd_set *) NULL, (struct timeval *) NULL); - if (nfds == 0) - continue; - if (nfds < 0) { - if (errno != EINTR) - logerror("select"); - continue; - } - dprintf("got a message (%d, %#x)\n", nfds, readfds); - if (readfds & klogm) { - i = read(fklog, line, sizeof(line) - 1); - if (i > 0) { - line[i] = '\0'; - printsys(line); - } else if (i < 0 && errno != EINTR) { - logerror("klog"); - fklog = -1; - klogm = 0; - } - } - if (readfds & FDMASK(funix)) { - len = sizeof fromunix; - i = recvfrom(funix, line, MAXLINE, 0, - (struct sockaddr *) &fromunix, &len); - if (i > 0) { - line[i] = '\0'; - printline(LocalHostName, line); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom unix"); - } - if (readfds & inetm) { - len = sizeof frominet; - i = recvfrom(finet, line, MAXLINE, 0, - (struct sockaddr *) &frominet, &len); - if (i > 0) { - extern char *cvthname(); - - line[i] = '\0'; - printline(cvthname(&frominet), line); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom inet"); - } - } -} - -usage() -{ - (void) fprintf(stderr, - "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n"); - exit(1); -} - -/* - * Take a raw input line, decode the message, and print the message - * on the appropriate log files. - */ - -printline(hname, msg) - char *hname; - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri; - - /* test for special codes */ - pri = DEFUPRI; - p = msg; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFUPRI; - - /* don't allow users to log kernel messages */ - if (LOG_FAC(pri) == LOG_KERN) - pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); - - q = line; - - while ((c = *p++ & 0177) != '\0' && - q < &line[sizeof(line) - 1]) - if (iscntrl(c)) - if (c == '\n') - *q++ = ' '; - else if (c == '\t') - *q++ = '\t'; - else { - *q++ = '^'; - *q++ = c ^ 0100; - } - else - *q++ = c; - *q = '\0'; - - logmsg(pri, line, hname, 0); -} - -/* - * Take a raw input line from /dev/klog, split and format similar to syslog(). - */ - -printsys(msg) - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri, flags; - char *lp; - - (void) strcpy(line, "vmunix: "); - lp = line + strlen(line); - for (p = msg; *p != '\0'; ) { - flags = SYNC_FILE | ADDDATE; /* fsync file after write */ - pri = DEFSPRI; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } else { - /* kernel printf's come out on console */ - flags |= IGN_CONS; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFSPRI; - q = lp; - while (*p != '\0' && (c = *p++) != '\n' && - q < &line[MAXLINE]) - *q++ = c; - *q = '\0'; - logmsg(pri, line, LocalHostName, flags); - } -} - -time_t now; - -/* - * Log a message to the appropriate log files, users, etc. based on - * the priority. - */ - -logmsg(pri, msg, from, flags) - int pri; - char *msg, *from; - int flags; -{ - register struct filed *f; - int fac, prilev; - int omask, msglen; - char *timestamp; - time_t time(); - - dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", - pri, flags, from, msg); - - omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); - - /* - * Check to see if msg looks non-standard. - */ - msglen = strlen(msg); - if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') - flags |= ADDDATE; - - (void) time(&now); - if (flags & ADDDATE) - timestamp = ctime(&now) + 4; - else { - timestamp = msg; - msg += 16; - msglen -= 16; - } - - /* extract facility and priority level */ - if (flags & MARK) - fac = LOG_NFACILITIES; - else - fac = LOG_FAC(pri); - prilev = LOG_PRI(pri); - - /* log the message to the particular outputs */ - if (!Initialized) { - f = &consfile; - f->f_file = open(ctty, O_WRONLY, 0); - - if (f->f_file >= 0) { - fprintlog(f, flags, msg); - (void) close(f->f_file); - } - (void) sigsetmask(omask); - return; - } - for (f = Files; f; f = f->f_next) { - /* skip messages that are incorrect priority */ - if (f->f_pmask[fac] < prilev || - f->f_pmask[fac] == INTERNAL_NOPRI) - continue; - - if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) - continue; - - /* don't output marks to recently written files */ - if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) - continue; - - /* - * suppress duplicate lines to this file - */ - if ((flags & MARK) == 0 && msglen == f->f_prevlen && - !strcmp(msg, f->f_prevline) && - !strcmp(from, f->f_prevhost)) { - (void) strncpy(f->f_lasttime, timestamp, 15); - f->f_prevcount++; - dprintf("msg repeated %d times, %ld sec of %d\n", - f->f_prevcount, now - f->f_time, - repeatinterval[f->f_repeatcount]); - /* - * If domark would have logged this by now, - * flush it now (so we don't hold isolated messages), - * but back off so we'll flush less often - * in the future. - */ - if (now > REPEATTIME(f)) { - fprintlog(f, flags, (char *)NULL); - BACKOFF(f); - } - } else { - /* new line, save it */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - f->f_repeatcount = 0; - (void) strncpy(f->f_lasttime, timestamp, 15); - (void) strncpy(f->f_prevhost, from, - sizeof(f->f_prevhost)); - if (msglen < MAXSVLINE) { - f->f_prevlen = msglen; - f->f_prevpri = pri; - (void) strcpy(f->f_prevline, msg); - fprintlog(f, flags, (char *)NULL); - } else { - f->f_prevline[0] = 0; - f->f_prevlen = 0; - fprintlog(f, flags, msg); - } - } - } - (void) sigsetmask(omask); -} - -fprintlog(f, flags, msg) - register struct filed *f; - int flags; - char *msg; -{ - struct iovec iov[6]; - register struct iovec *v; - register int l; - char line[MAXLINE + 1], repbuf[80], greetings[200]; - - v = iov; - if (f->f_type == F_WALL) { - v->iov_base = greetings; - v->iov_len = sprintf(greetings, - "\r\n\7Message from syslogd@%s at %.24s ...\r\n", - f->f_prevhost, ctime(&now)); - v++; - v->iov_base = ""; - v->iov_len = 0; - v++; - } else { - v->iov_base = f->f_lasttime; - v->iov_len = 15; - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - } - v->iov_base = f->f_prevhost; - v->iov_len = strlen(v->iov_base); - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - - if (msg) { - v->iov_base = msg; - v->iov_len = strlen(msg); - } else if (f->f_prevcount > 1) { - v->iov_base = repbuf; - v->iov_len = sprintf(repbuf, "last message repeated %d times", - f->f_prevcount); - } else { - v->iov_base = f->f_prevline; - v->iov_len = f->f_prevlen; - } - v++; - - dprintf("Logging to %s", TypeNames[f->f_type]); - f->f_time = now; - - switch (f->f_type) { - case F_UNUSED: - dprintf("\n"); - break; - - case F_FORW: - dprintf(" %s\n", f->f_un.f_forw.f_hname); - l = sprintf(line, "<%d>%.15s %s", f->f_prevpri, - iov[0].iov_base, iov[4].iov_base); - if (l > MAXLINE) - l = MAXLINE; - if (sendto(finet, line, l, 0, - (struct sockaddr *)&f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr) != l) { - int e = errno; - (void) close(f->f_file); - f->f_type = F_UNUSED; - errno = e; - logerror("sendto"); - } - break; - - case F_CONSOLE: - if (flags & IGN_CONS) { - dprintf(" (ignored)\n"); - break; - } - /* FALLTHROUGH */ - - case F_TTY: - case F_FILE: - dprintf(" %s\n", f->f_un.f_fname); - if (f->f_type != F_FILE) { - v->iov_base = "\r\n"; - v->iov_len = 2; - } else { - v->iov_base = "\n"; - v->iov_len = 1; - } - again: - if (writev(f->f_file, iov, 6) < 0) { - int e = errno; - (void) close(f->f_file); - /* - * Check for errors on TTY's due to loss of tty - */ - if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { - f->f_file = open(f->f_un.f_fname, - O_WRONLY|O_APPEND, 0); - if (f->f_file < 0) { - f->f_type = F_UNUSED; - logerror(f->f_un.f_fname); - } else - goto again; - } else { - f->f_type = F_UNUSED; - errno = e; - logerror(f->f_un.f_fname); - } - } else if (flags & SYNC_FILE) - (void) fsync(f->f_file); - break; - - case F_USERS: - case F_WALL: - dprintf("\n"); - v->iov_base = "\r\n"; - v->iov_len = 2; - wallmsg(f, iov); - break; - } - f->f_prevcount = 0; -} - -/* - * WALLMSG -- Write a message to the world at large - * - * Write the specified message to either the entire - * world, or a list of approved users. - */ - -wallmsg(f, iov) - register struct filed *f; - struct iovec *iov; -{ - static int reenter; /* avoid calling ourselves */ - register FILE *uf; - register int i; - struct utmp ut; - char *p, *ttymsg(); - - if (reenter++) - return; - if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { - logerror(_PATH_UTMP); - reenter = 0; - return; - } - /* NOSTRICT */ - while (fread((char *) &ut, sizeof ut, 1, uf) == 1) { - if (ut.ut_name[0] == '\0') - continue; - if (f->f_type == F_WALL) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - continue; - } - /* should we send the message to this user? */ - for (i = 0; i < MAXUNAMES; i++) { - if (!f->f_un.f_uname[i][0]) - break; - if (!strncmp(f->f_un.f_uname[i], ut.ut_name, - UT_NAMESIZE)) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - break; - } - } - } - (void) fclose(uf); - reenter = 0; -} - -void -reapchild() -{ - union wait status; - - while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) - ; -} - -/* - * Return a printable representation of a host address. - */ -char * -cvthname(f) - struct sockaddr_in *f; -{ - struct hostent *hp; - register char *p; - extern char *inet_ntoa(); - - dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); - - if (f->sin_family != AF_INET) { - dprintf("Malformed from address\n"); - return ("???"); - } - hp = gethostbyaddr((char *)&f->sin_addr, - sizeof(struct in_addr), f->sin_family); - if (hp == 0) { - dprintf("Host name for your address (%s) unknown\n", - inet_ntoa(f->sin_addr)); - return (inet_ntoa(f->sin_addr)); - } - if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) - *p = '\0'; - return (hp->h_name); -} - -void -domark() -{ - register struct filed *f; - time_t time(); - - now = time((time_t *)NULL); - MarkSeq += TIMERINTVL; - if (MarkSeq >= MarkInterval) { - logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); - MarkSeq = 0; - } - - for (f = Files; f; f = f->f_next) { - if (f->f_prevcount && now >= REPEATTIME(f)) { - dprintf("flush %s: repeated %d times, %d sec.\n", - TypeNames[f->f_type], f->f_prevcount, - repeatinterval[f->f_repeatcount]); - fprintlog(f, 0, (char *)NULL); - BACKOFF(f); - } - } - (void) alarm(TIMERINTVL); -} - -/* - * Print syslogd errors some place. - */ -logerror(type) - char *type; -{ - char buf[100], *strerror(); - - if (errno) - (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno)); - else - (void) sprintf(buf, "syslogd: %s", type); - errno = 0; - dprintf("%s\n", buf); - logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); -} - -void -die(sig) -{ - register struct filed *f; - char buf[100]; - - for (f = Files; f != NULL; f = f->f_next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - } - if (sig) { - dprintf("syslogd: exiting on signal %d\n", sig); - (void) sprintf(buf, "exiting on signal %d", sig); - errno = 0; - logerror(buf); - } - (void) unlink(LogName); - exit(0); -} - -/* - * INIT -- Initialize syslogd from configuration table - */ - -void -init() -{ - register int i; - register FILE *cf; - register struct filed *f, *next, **nextp; - register char *p; - char cline[BUFSIZ]; - - dprintf("init\n"); - - /* - * Close all open log files. - */ - Initialized = 0; - for (f = Files; f != NULL; f = next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - case F_FORW: - (void) close(f->f_file); - break; - } - next = f->f_next; - free((char *) f); - } - Files = NULL; - nextp = &Files; - - /* open the configuration file */ - if ((cf = fopen(ConfFile, "r")) == NULL) { - dprintf("cannot open %s\n", ConfFile); - *nextp = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.ERR\t/dev/console", *nextp); - (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.PANIC\t*", (*nextp)->f_next); - Initialized = 1; - return; - } - - /* - * Foreach line in the conf table, open that file. - */ - f = NULL; - while (fgets(cline, sizeof cline, cf) != NULL) { - /* - * check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - for (p = cline; isspace(*p); ++p); - if (*p == NULL || *p == '#') - continue; - for (p = index(cline, '\0'); isspace(*--p);); - *++p = '\0'; - f = (struct filed *)calloc(1, sizeof(*f)); - *nextp = f; - nextp = &f->f_next; - cfline(cline, f); - } - - /* close the configuration file */ - (void) fclose(cf); - - Initialized = 1; - - if (Debug) { - for (f = Files; f; f = f->f_next) { - for (i = 0; i <= LOG_NFACILITIES; i++) - if (f->f_pmask[i] == INTERNAL_NOPRI) - printf("X "); - else - printf("%d ", f->f_pmask[i]); - printf("%s: ", TypeNames[f->f_type]); - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - printf("%s", f->f_un.f_fname); - break; - - case F_FORW: - printf("%s", f->f_un.f_forw.f_hname); - break; - - case F_USERS: - for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) - printf("%s, ", f->f_un.f_uname[i]); - break; - } - printf("\n"); - } - } - - logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); - dprintf("syslogd: restarted\n"); -} - -/* - * Crack a configuration file line - */ - -cfline(line, f) - char *line; - register struct filed *f; -{ - register char *p; - register char *q; - register int i; - char *bp; - int pri; - struct hostent *hp; - char buf[MAXLINE], ebuf[100]; - - dprintf("cfline(%s)\n", line); - - errno = 0; /* keep strerror() stuff out of logerror messages */ - - /* clear out file entry */ - bzero((char *) f, sizeof *f); - for (i = 0; i <= LOG_NFACILITIES; i++) - f->f_pmask[i] = INTERNAL_NOPRI; - - /* scan through the list of selectors */ - for (p = line; *p && *p != '\t';) { - - /* find the end of this facility name list */ - for (q = p; *q && *q != '\t' && *q++ != '.'; ) - continue; - - /* collect priority name */ - for (bp = buf; *q && !index("\t,;", *q); ) - *bp++ = *q++; - *bp = '\0'; - - /* skip cruft */ - while (index(", ;", *q)) - q++; - - /* decode priority name */ - if (*buf == '*') - pri = LOG_PRIMASK + 1; - else { - pri = decode(buf, prioritynames); - if (pri < 0) { - (void) sprintf(ebuf, - "unknown priority name \"%s\"", buf); - logerror(ebuf); - return; - } - } - - /* scan facilities */ - while (*p && !index("\t.;", *p)) { - for (bp = buf; *p && !index("\t,;.", *p); ) - *bp++ = *p++; - *bp = '\0'; - if (*buf == '*') - for (i = 0; i < LOG_NFACILITIES; i++) - f->f_pmask[i] = pri; - else { - i = decode(buf, facilitynames); - if (i < 0) { - (void) sprintf(ebuf, - "unknown facility name \"%s\"", - buf); - logerror(ebuf); - return; - } - f->f_pmask[i >> 3] = pri; - } - while (*p == ',' || *p == ' ') - p++; - } - - p = q; - } - - /* skip to action part */ - while (*p == '\t') - p++; - - switch (*p) - { - case '@': - if (!InetInuse) - break; - (void) strcpy(f->f_un.f_forw.f_hname, ++p); - hp = gethostbyname(p); - if (hp == NULL) { - extern int h_errno, h_nerr; - extern char **h_errlist; - - logerror((u_int)h_errno < h_nerr ? - h_errlist[h_errno] : "Unknown error"); - break; - } - bzero((char *) &f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr); - f->f_un.f_forw.f_addr.sin_family = AF_INET; - f->f_un.f_forw.f_addr.sin_port = LogPort; - bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length); - f->f_type = F_FORW; - break; - - case '/': - (void) strcpy(f->f_un.f_fname, p); - if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { - f->f_file = F_UNUSED; - logerror(p); - break; - } - if (isatty(f->f_file)) - f->f_type = F_TTY; - else - f->f_type = F_FILE; - if (strcmp(p, ctty) == 0) - f->f_type = F_CONSOLE; - break; - - case '*': - f->f_type = F_WALL; - break; - - default: - for (i = 0; i < MAXUNAMES && *p; i++) { - for (q = p; *q && *q != ','; ) - q++; - (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); - if ((q - p) > UT_NAMESIZE) - f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; - else - f->f_un.f_uname[i][q - p] = '\0'; - while (*q == ',' || *q == ' ') - q++; - p = q; - } - f->f_type = F_USERS; - break; - } -} - - -/* - * Decode a symbolic name to a numeric value - */ - -decode(name, codetab) - char *name; - CODE *codetab; -{ - register CODE *c; - register char *p; - char buf[40]; - - if (isdigit(*name)) - return (atoi(name)); - - (void) strcpy(buf, name); - for (p = buf; *p; p++) - if (isupper(*p)) - *p = tolower(*p); - for (c = codetab; c->c_name; c++) - if (!strcmp(buf, c->c_name)) - return (c->c_val); - - return (-1); -} diff --git a/syslogd/syslogd.c.orig b/syslogd/syslogd.c.orig deleted file mode 100644 index 0124f6e9..00000000 --- a/syslogd/syslogd.c.orig +++ /dev/null @@ -1,1340 +0,0 @@ -/* - * Copyright (c) 1983, 1988 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)syslogd.c 5.45 (Berkeley) 3/2/91"; -#endif /* not lint */ - -/* - * syslogd -- log system messages - * - * This program implements a system log. It takes a series of lines. - * Each line may have a priority, signified as "" as - * the first characters of the line. If this is - * not present, a default priority is used. - * - * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will - * cause it to reread its configuration file. - * - * Defined Constants: - * - * MAXLINE -- the maximimum line length that can be handled. - * DEFUPRI -- the default priority for user messages - * DEFSPRI -- the default priority for kernel messages - * - * Author: Eric Allman - * extensive changes by Ralph Campbell - * more extensive changes by Eric Allman (again) - * - * Modified, Sun Mar 7 15:21:13 1993, faith@cs.unc.edu for Linux: - * - * SUN_LEN_MISSING: struct sockaddr does not have sun_len - * SYSLOG_STREAM: syslog is implemented using stream sockets - * SYSLOG_INET: support inet logging - * KLOG_STREAM: kernel logging uses a stream device - * STATUS_BROKEN: use "int status" instead of "union wait status" - * RE_INSTALL_SIGNAL: signal() does *not* remain installed - * SYS_MSGBUF_H_MISSING: sys/msgbuf.h is missing - * FSYNC_MISSING: fsync() is missing - * KERNEL_NAME: what the kernel is usually called - * - * Original Linux version by Rik Faith - * with changes by Rick Sladkey and - * Rick . Anyone else - * named Rick who wants to chip in? :-) - */ - -#ifdef __linux__ -#define SUN_LEN_MISSING -#define SYSLOG_STREAM -#define SYSLOG_INET -#define KLOG_STREAM -#undef STATUS_BROKEN -#define RE_INSTALL_SIGNAL -#define SYS_MSGBUF_H_MISSING -#undef FSYNC_MISSING -#define KERNEL_NAME "linux" -#endif - -#define MAXLINE 1024 /* maximum line length */ -#define MAXSVLINE 120 /* maximum saved line length */ -#define DEFUPRI (LOG_USER|LOG_NOTICE) -#define DEFSPRI (LOG_KERN|LOG_CRIT) -#define TIMERINTVL 30 /* interval for checking flush, mark */ - -#include -#include -#include -#include -#include -#include -#include -#ifdef SYS_MSGBUF_H_MISSING -#define MSG_BSIZE (MAXLINE*2) -#else -#include -#endif -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define SYSLOG_NAMES -#include - -char *LogName = _PATH_LOG; -char *ConfFile = _PATH_LOGCONF; -char *PidFile = _PATH_LOGPID; -char ctty[] = _PATH_CONSOLE; - -#define FDMASK(fd) (1 << (fd)) - -#define dprintf if (Debug) printf - -#define MAXUNAMES 20 /* maximum number of user names */ - -/* - * Flags to logmsg(). - */ - -#define IGN_CONS 0x001 /* don't print on console */ -#define SYNC_FILE 0x002 /* do fsync on file after printing */ -#define ADDDATE 0x004 /* add a date to the message */ -#define MARK 0x008 /* this message is a mark */ - -/* - * This structure represents the files that will have log - * copies printed. - */ - -struct filed { - struct filed *f_next; /* next in linked list */ - short f_type; /* entry type, see below */ - short f_file; /* file descriptor */ - time_t f_time; /* time this was last written */ - u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ - union { - char f_uname[MAXUNAMES][UT_NAMESIZE+1]; - struct { - char f_hname[MAXHOSTNAMELEN+1]; - struct sockaddr_in f_addr; - } f_forw; /* forwarding address */ - char f_fname[MAXPATHLEN]; - } f_un; - char f_prevline[MAXSVLINE]; /* last message logged */ - char f_lasttime[16]; /* time of last occurrence */ - char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ - int f_prevpri; /* pri of f_prevline */ - int f_prevlen; /* length of f_prevline */ - int f_prevcount; /* repetition cnt of prevline */ - int f_repeatcount; /* number of "repeated" msgs */ -}; - -/* - * Intervals at which we flush out "message repeated" messages, - * in seconds after previous message is logged. After each flush, - * we move to the next interval until we reach the largest. - */ -int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ -#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) -#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) -#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ - (f)->f_repeatcount = MAXREPEAT; \ - } - -/* values for f_type */ -#define F_UNUSED 0 /* unused entry */ -#define F_FILE 1 /* regular file */ -#define F_TTY 2 /* terminal */ -#define F_CONSOLE 3 /* console terminal */ -#define F_FORW 4 /* remote machine */ -#define F_USERS 5 /* list of users */ -#define F_WALL 6 /* everyone logged on */ - -char *TypeNames[7] = { - "UNUSED", "FILE", "TTY", "CONSOLE", - "FORW", "USERS", "WALL" -}; - -struct filed *Files; -struct filed consfile; - -int Debug; /* debug flag */ -char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ -char *LocalDomain; /* our local domain name */ -int InetInuse = 0; /* non-zero if INET sockets are being used */ -#ifdef SYSLOG_INET -int finet; /* Internet datagram socket */ -#endif /* SYSLOG_INET */ -int LogPort; /* port number for INET connections */ -int Initialized = 0; /* set when we have initialized ourselves */ -int MarkInterval = 20 * 60; /* interval between marks in seconds */ -int MarkSeq = 0; /* mark sequence number */ - -extern int errno; -extern char *ctime(), *index(), *calloc(); - -main(argc, argv) - int argc; - char **argv; -{ - register int i; - register char *p; - int funix, fklog, len; - struct sockaddr_un sunx, fromunix; - struct sockaddr_in sin, frominet; - FILE *fp; - int ch; - char line[MSG_BSIZE + 1]; - extern int optind; - extern char *optarg; - void die(), domark(), init(), reapchild(); -#ifdef SYSLOG_STREAM - fd_set unixm; - int fd; -#endif /* SYSLOG_STREAM */ - - while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) - switch((char)ch) { - case 'd': /* debug */ - Debug++; - break; - case 'f': /* configuration file */ - ConfFile = optarg; - break; - case 'm': /* mark interval */ - MarkInterval = atoi(optarg) * 60; - break; - case 'p': /* path */ - LogName = optarg; - break; - case '?': - default: - usage(); - } - if (argc -= optind) - usage(); - - if (!Debug) - daemon(0, 0); - else - setlinebuf(stdout); - - consfile.f_type = F_CONSOLE; - (void) strcpy(consfile.f_un.f_fname, ctty); - (void) gethostname(LocalHostName, sizeof LocalHostName); - if (p = index(LocalHostName, '.')) { - *p++ = '\0'; - LocalDomain = p; - } - else - LocalDomain = ""; - (void) signal(SIGTERM, die); - (void) signal(SIGINT, Debug ? die : SIG_IGN); - (void) signal(SIGQUIT, Debug ? die : SIG_IGN); - (void) signal(SIGCHLD, reapchild); - (void) signal(SIGALRM, domark); - (void) alarm(TIMERINTVL); - (void) unlink(LogName); - - bzero((char *)&sunx, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path); -#ifdef SYSLOG_STREAM - funix = socket(AF_UNIX, SOCK_STREAM, 0); - if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, - sizeof(sunx)) < 0 || listen(funix, 5) < 0 || -#else /* !SYSLOG_STREAM */ - funix = socket(AF_UNIX, SOCK_DGRAM, 0); - if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, - sizeof(sunx.sun_family)+sizeof(sunx.sun_len)+ - strlen(sunx.sun_path)) < 0 || -#endif /* !SYSLOG_STREAM */ - chmod(LogName, 0666) < 0) { - (void) sprintf(line, "cannot create %s", LogName); - logerror(line); - dprintf("cannot create %s (%d)\n", LogName, errno); - die(0); - } -#ifdef SYSLOG_INET - finet = socket(AF_INET, SOCK_DGRAM, 0); - if (finet >= 0) { - struct servent *sp; - - sp = getservbyname("syslog", "udp"); - if (sp == NULL) { - errno = 0; - logerror("syslog/udp: unknown service"); - } - else { - bzero((char *) &sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = LogPort = sp->s_port; - if (bind(finet, (struct sockaddr *) &sin, - sizeof(sin)) < 0) - logerror("bind"); - else { - finet = -1; - InetInuse = 1; - } - } - } -#endif /* SYSLOG_INET */ - if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) - dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); - - /* tuck my process id away */ - fp = fopen(PidFile, "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); - (void) fclose(fp); - } - - dprintf("off & running....\n"); - - init(); - (void) signal(SIGHUP, init); -#ifdef SYSLOG_STREAM - FD_ZERO(&unixm); -#endif /* SYSLOG_STREAM */ - - for (;;) { - int nfds; - fd_set readfds; - -#ifdef SYSLOG_STREAM - readfds = unixm; -#else /* !SYSLOG_STREAM */ - FD_ZERO(&readfds); -#endif /* !SYSLOG_STREAM */ - if (funix >= 0) - FD_SET(funix, &readfds); - if (fklog >= 0) - FD_SET(fklog, &readfds); -#ifdef SYSLOG_INET - if (finet >= 0) - FD_SET(finet, &readfds); -#endif /* SYSLOG_INET */ - - errno = 0; - dprintf("readfds = %#x\n", *((long *)&readfds)); - nfds = select(FD_SETSIZE, &readfds, (fd_set *) NULL, - (fd_set *) NULL, (struct timeval *) NULL); - if (nfds == 0) - continue; - if (nfds < 0) { - if (errno != EINTR) - logerror("select"); - continue; - } - dprintf("got a message (%d, %#x)\n", nfds, *((long *)&readfds)); - -#ifdef KLOG_STREAM - if (FD_ISSET(fklog, &readfds)) { - nfds--; - for (;;) { - i = klogread(fklog, line, sizeof(line) - 1); - if (i > 0) { - line[i] = '\0'; - printsys(line); - } - else { - if (i < 0 && errno != EINTR) { - logerror("klog"); - fklog = -1; - } - break; - } - } - } -#else /* !KLOG_STREAM */ - if (FD_ISSET(fklog, &readfds)) { - nfds--; - i = read(fklog, line, sizeof(line) - 1); - if (i > 0) { - line[i] = '\0'; - printsys(line); - } else if (i < 0 && errno != EINTR) { - logerror("klog"); - fklog = -1; - } - } -#endif /* !KLOG_STREAM */ - -#ifdef SYSLOG_STREAM - /* Accept a new unix connection. */ - if (FD_ISSET(funix, &readfds)) { - nfds--; - len = sizeof fromunix; - if ((fd = accept(funix, (struct sockaddr *) &fromunix, - &len)) >= 0) { - FD_SET(fd, &unixm); - dprintf("new stream connect (%d)\n", fd); - FD_SET(fd, &readfds); - nfds++; - } - } - /* Recv from existing connections. */ - for (fd = 0; nfds > 0 && fd < FD_SETSIZE; fd++) { - if (FD_ISSET(fd, &unixm) && FD_ISSET(fd, &readfds)) { - nfds--; - dprintf("message from stream (%d)\n", fd); - i = read(fd, line, MAXLINE); - if (i > 0) { - line[i] = '\0'; - printline(LocalHostName, line); - } - else if (i == 0) { - dprintf("stream closed (%d)\n", fd); - close(fd); - FD_CLR(fd, &unixm); - } - else if (i < 0 && errno != EINTR) { - logerror("recv stream"); - close(fd); - FD_CLR(fd, &unixm); - } - } - } -#else /* !SYSLOG_STREAM */ - if (FD_ISSET(funix, &readfds)) { - nfds--; - len = sizeof fromunix; - i = recvfrom(funix, line, MAXLINE, 0, - (struct sockaddr *) &fromunix, &len); - if (i > 0) { - line[i] = '\0'; - printline(LocalHostName, line); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom unix"); - } -#endif /* !SYSLOG_STREAM */ - -#ifdef SYSLOG_INET - if (FD_ISSET(finet, &readfds)) { - nfds--; - len = sizeof frominet; - i = recvfrom(finet, line, MAXLINE, 0, - (struct sockaddr *) &frominet, &len); - if (i > 0) { - extern char *cvthname(); - - line[i] = '\0'; - printline(cvthname(&frominet), line); - } else if (i < 0 && errno != EINTR) - logerror("recvfrom inet"); - } -#endif /* SYSLOG_INET */ - if (nfds != 0) - logerror("loose cannon"); - } -} - -usage() -{ - (void) fprintf(stderr, - "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n"); - exit(1); -} - -/* - * Take a raw input line, decode the message, and print the message - * on the appropriate log files. - */ - -printline(hname, msg) - char *hname; - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri; - - /* test for special codes */ - pri = DEFUPRI; - p = msg; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFUPRI; - - /* don't allow users to log kernel messages */ - if (LOG_FAC(pri) == LOG_KERN) - pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); - - q = line; - - while ((c = *p++ & 0177) != '\0' && - q < &line[sizeof(line) - 1]) - if (iscntrl(c)) { - if (c == '\n') - *q++ = ' '; - else if (c == '\r') - *q++ = ' '; - else if (c == '\t') - *q++ = '\t'; - else { - *q++ = '^'; - *q++ = c ^ 0100; - } - } - else - *q++ = c; - *q = '\0'; - - logmsg(pri, line, hname, 0); -} - -/* - * Take a raw input line from /dev/klog, split and format similar to syslog(). - */ - -printsys(msg) - char *msg; -{ - register char *p, *q; - register int c; - char line[MAXLINE + 1]; - int pri, flags; - char *lp; - -#ifdef KERNEL_NAME - (void) sprintf(line, "%s: ", KERNEL_NAME); -#else /* !KERNEL_NAME */ - (void) strcpy(line, "vmunix: "); -#endif /* !KERNEL_NAME */ - - lp = line + strlen(line); - for (p = msg; *p != '\0'; ) { - flags = SYNC_FILE | ADDDATE; /* fsync file after write */ - pri = DEFSPRI; - if (*p == '<') { - pri = 0; - while (isdigit(*++p)) - pri = 10 * pri + (*p - '0'); - if (*p == '>') - ++p; - } else { - /* kernel printf's come out on console */ - flags |= IGN_CONS; - } - if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) - pri = DEFSPRI; - q = lp; - while (*p != '\0' && (c = *p++) != '\n' && - q < &line[MAXLINE]) - if (iscntrl(c)) { - if (c == '\n') - *q++ = ' '; - else if (c == '\r') - *q++ = ' '; - else if (c == '\t') - *q++ = '\t'; - else { - *q++ = '^'; - *q++ = c ^ 0100; - } - } - else - *q++ = c; - *q = '\0'; - logmsg(pri, line, LocalHostName, flags); - } -} - -time_t now; - -/* - * Log a message to the appropriate log files, users, etc. based on - * the priority. - */ - -logmsg(pri, msg, from, flags) - int pri; - char *msg, *from; - int flags; -{ - register struct filed *f; - int fac, prilev; - int omask, msglen; - char *timestamp; - time_t time(); - - dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", - pri, flags, from, msg); - - omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); - - /* - * Check to see if msg looks non-standard. - */ - msglen = strlen(msg); - if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') - flags |= ADDDATE; - - (void) time(&now); - if (flags & ADDDATE) - timestamp = ctime(&now) + 4; - else { - timestamp = msg; - msg += 16; - msglen -= 16; - } - - /* extract facility and priority level */ - if (flags & MARK) - fac = LOG_NFACILITIES; - else - fac = LOG_FAC(pri); - prilev = LOG_PRI(pri); - - /* log the message to the particular outputs */ - if (!Initialized) { - f = &consfile; -#ifdef O_NOCTTY - f->f_file = open(ctty, O_WRONLY|O_NOCTTY, 0); -#else /* !O_NOCTTY */ - f->f_file = open(ctty, O_WRONLY, 0); -#endif /* !O_NOCTTY */ - - if (f->f_file >= 0) { - fprintlog(f, flags, msg); - (void) close(f->f_file); - } - (void) sigsetmask(omask); - return; - } - for (f = Files; f; f = f->f_next) { - /* skip messages that are incorrect priority */ - if (f->f_pmask[fac] < prilev || - f->f_pmask[fac] == INTERNAL_NOPRI) - continue; - - if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) - continue; - - /* don't output marks to recently written files */ - if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) - continue; - - /* - * suppress duplicate lines to this file - */ - if ((flags & MARK) == 0 && msglen == f->f_prevlen && - !strcmp(msg, f->f_prevline) && - !strcmp(from, f->f_prevhost)) { - (void) strncpy(f->f_lasttime, timestamp, 15); - f->f_prevcount++; - dprintf("msg repeated %d times, %ld sec of %d\n", - f->f_prevcount, now - f->f_time, - repeatinterval[f->f_repeatcount]); - /* - * If domark would have logged this by now, - * flush it now (so we don't hold isolated messages), - * but back off so we'll flush less often - * in the future. - */ - if (now > REPEATTIME(f)) { - fprintlog(f, flags, (char *)NULL); - BACKOFF(f); - } - } else { - /* new line, save it */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - f->f_repeatcount = 0; - (void) strncpy(f->f_lasttime, timestamp, 15); - (void) strncpy(f->f_prevhost, from, - sizeof(f->f_prevhost)); - if (msglen < MAXSVLINE) { - f->f_prevlen = msglen; - f->f_prevpri = pri; - (void) strcpy(f->f_prevline, msg); - fprintlog(f, flags, (char *)NULL); - } else { - f->f_prevline[0] = 0; - f->f_prevlen = 0; - fprintlog(f, flags, msg); - } - } - } - (void) sigsetmask(omask); -} - -fprintlog(f, flags, msg) - register struct filed *f; - int flags; - char *msg; -{ - struct iovec iov[6]; - register struct iovec *v; - register int l; - char line[MAXLINE + 1], repbuf[80], greetings[200]; - - v = iov; - if (f->f_type == F_WALL) { - v->iov_base = greetings; - v->iov_len = sprintf(greetings, - "\r\n\7Message from syslogd@%s at %.24s ...\r\n", - f->f_prevhost, ctime(&now)); - v++; - v->iov_base = ""; - v->iov_len = 0; - v++; - } else { - v->iov_base = f->f_lasttime; - v->iov_len = 15; - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - } - v->iov_base = f->f_prevhost; - v->iov_len = strlen(v->iov_base); - v++; - v->iov_base = " "; - v->iov_len = 1; - v++; - - if (msg) { - v->iov_base = msg; - v->iov_len = strlen(msg); - } else if (f->f_prevcount > 1) { - v->iov_base = repbuf; - v->iov_len = sprintf(repbuf, "last message repeated %d times", - f->f_prevcount); - } else { - v->iov_base = f->f_prevline; - v->iov_len = f->f_prevlen; - } - v++; - - dprintf("Logging to %s", TypeNames[f->f_type]); - f->f_time = now; - - switch (f->f_type) { - case F_UNUSED: - dprintf("\n"); - break; - - case F_FORW: - dprintf(" %s\n", f->f_un.f_forw.f_hname); - l = sprintf(line, "<%d>%.15s %s", f->f_prevpri, - iov[0].iov_base, iov[4].iov_base); - if (l > MAXLINE) - l = MAXLINE; - if (sendto(finet, line, l, 0, - (struct sockaddr *)&f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr) != l) { - int e = errno; - (void) close(f->f_file); - f->f_type = F_UNUSED; - errno = e; - logerror("sendto"); - } - break; - - case F_CONSOLE: - if (flags & IGN_CONS) { - dprintf(" (ignored)\n"); - break; - } - /* FALLTHROUGH */ - - case F_TTY: - case F_FILE: - dprintf(" %s\n", f->f_un.f_fname); - if (f->f_type != F_FILE) { - v->iov_base = "\r\n"; - v->iov_len = 2; - } else { - v->iov_base = "\n"; - v->iov_len = 1; - } - again: - if (writev(f->f_file, iov, 6) < 0) { - int e = errno; - (void) close(f->f_file); - /* - * Check for errors on TTY's due to loss of tty - */ - if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { - f->f_file = open(f->f_un.f_fname, - O_WRONLY|O_APPEND, 0); - if (f->f_file < 0) { - f->f_type = F_UNUSED; - logerror(f->f_un.f_fname); - } else - goto again; - } else { - f->f_type = F_UNUSED; - errno = e; - logerror(f->f_un.f_fname); - } - } -#ifdef FSYNC_MISSING - else if (flags & SYNC_FILE) - (void) sync(); -#else - else if (flags & SYNC_FILE) - (void) fsync(f->f_file); -#endif - break; - - case F_USERS: - case F_WALL: - dprintf("\n"); - v->iov_base = "\r\n"; - v->iov_len = 2; - wallmsg(f, iov); - break; - } - f->f_prevcount = 0; -} - -/* - * WALLMSG -- Write a message to the world at large - * - * Write the specified message to either the entire - * world, or a list of approved users. - */ - -wallmsg(f, iov) - register struct filed *f; - struct iovec *iov; -{ - static int reenter; /* avoid calling ourselves */ - register FILE *uf; - register int i; - struct utmp ut; - char *p, *ttymsg(); - - if (reenter++) - return; - if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { - logerror(_PATH_UTMP); - reenter = 0; - return; - } - /* NOSTRICT */ - while (fread((char *) &ut, sizeof ut, 1, uf) == 1) { - if (ut.ut_name[0] == '\0') - continue; -#ifdef USER_PROCESS - if (ut.ut_type != USER_PROCESS) - continue; -#endif - if (f->f_type == F_WALL) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - continue; - } - /* should we send the message to this user? */ - for (i = 0; i < MAXUNAMES; i++) { - if (!f->f_un.f_uname[i][0]) - break; - if (!strncmp(f->f_un.f_uname[i], ut.ut_name, - UT_NAMESIZE)) { - if (p = ttymsg(iov, 6, ut.ut_line, 1)) { - errno = 0; /* already in msg */ - logerror(p); - } - break; - } - } - } - (void) fclose(uf); - reenter = 0; -} - -void -reapchild() -{ -#ifdef STATUS_BROKEN - int status; -#else - union wait status; -#endif - - while (wait3((int *)&status, WNOHANG, (struct rusage *) NULL) > 0) - ; -} - -/* - * Return a printable representation of a host address. - */ -char * -cvthname(f) - struct sockaddr_in *f; -{ - struct hostent *hp; - register char *p; - extern char *inet_ntoa(); - - dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); - - if (f->sin_family != AF_INET) { - dprintf("Malformed from address\n"); - return ("???"); - } - hp = gethostbyaddr((char *)&f->sin_addr, - sizeof(struct in_addr), f->sin_family); - if (hp == 0) { - dprintf("Host name for your address (%s) unknown\n", - inet_ntoa(f->sin_addr)); - return (inet_ntoa(f->sin_addr)); - } - if ((p = index(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) - *p = '\0'; - return ((char *) hp->h_name); -} - -void -domark() -{ - register struct filed *f; - time_t time(); - - now = time((time_t *)NULL); - MarkSeq += TIMERINTVL; - if (MarkSeq >= MarkInterval) { - logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); - MarkSeq = 0; - } - - for (f = Files; f; f = f->f_next) { - if (f->f_prevcount && now >= REPEATTIME(f)) { - dprintf("flush %s: repeated %d times, %d sec.\n", - TypeNames[f->f_type], f->f_prevcount, - repeatinterval[f->f_repeatcount]); - fprintlog(f, 0, (char *)NULL); - BACKOFF(f); - } - } -#ifdef RE_INSTALL_SIGNAL - (void) signal(SIGALRM, domark); -#endif - (void) alarm(TIMERINTVL); -} - -/* - * Print syslogd errors some place. - */ -logerror(type) - char *type; -{ - char buf[100], *strerror(); - - if (errno) - (void) sprintf(buf, "syslogd: %s: %s", type, strerror(errno)); - else - (void) sprintf(buf, "syslogd: %s", type); - errno = 0; - dprintf("%s\n", buf); - logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); -} - -void -die(sig) -{ - register struct filed *f; - char buf[100]; - - for (f = Files; f != NULL; f = f->f_next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - } - if (sig) { - dprintf("syslogd: exiting on signal %d\n", sig); - (void) sprintf(buf, "exiting on signal %d", sig); - errno = 0; - logerror(buf); - } - (void) unlink(LogName); - exit(0); -} - -/* - * INIT -- Initialize syslogd from configuration table - */ - -void -init() -{ - register int i; - register FILE *cf; - register struct filed *f, *next, **nextp; - register char *p; - char cline[BUFSIZ]; - - dprintf("init\n"); - - /* - * Close all open log files. - */ - Initialized = 0; - for (f = Files; f != NULL; f = next) { - /* flush any pending output */ - if (f->f_prevcount) - fprintlog(f, 0, (char *)NULL); - - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - case F_FORW: - (void) close(f->f_file); - break; - } - next = f->f_next; - free((char *) f); - } - Files = NULL; - nextp = &Files; - - /* open the configuration file */ - if ((cf = fopen(ConfFile, "r")) == NULL) { - dprintf("cannot open %s\n", ConfFile); - *nextp = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.ERR\t/dev/console", *nextp); - (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); - cfline("*.PANIC\t*", (*nextp)->f_next); - Initialized = 1; - return; - } - - /* - * Foreach line in the conf table, open that file. - */ - f = NULL; - while (fgets(cline, sizeof cline, cf) != NULL) { - /* - * check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - for (p = cline; isspace(*p); ++p); - if (*p == '\0' || *p == '#') - continue; - for (p = index(cline, '\0'); isspace(*--p);); - *++p = '\0'; - f = (struct filed *)calloc(1, sizeof(*f)); - *nextp = f; - nextp = &f->f_next; - cfline(cline, f); - } - - /* close the configuration file */ - (void) fclose(cf); - - Initialized = 1; - - if (Debug) { - for (f = Files; f; f = f->f_next) { - for (i = 0; i <= LOG_NFACILITIES; i++) - if (f->f_pmask[i] == INTERNAL_NOPRI) - printf("X "); - else - printf("%d ", f->f_pmask[i]); - printf("%s: ", TypeNames[f->f_type]); - switch (f->f_type) { - case F_FILE: - case F_TTY: - case F_CONSOLE: - printf("%s", f->f_un.f_fname); - break; - - case F_FORW: - printf("%s", f->f_un.f_forw.f_hname); - break; - - case F_USERS: - for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) - printf("%s, ", f->f_un.f_uname[i]); - break; - } - printf("\n"); - } - } - - logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); - dprintf("syslogd: restarted\n"); -} - -/* - * Crack a configuration file line - */ - -cfline(line, f) - char *line; - register struct filed *f; -{ - register char *p; - register char *q; - register int i; - char *bp; - int pri; - struct hostent *hp; - char buf[MAXLINE], ebuf[100]; - - dprintf("cfline(%s)\n", line); - - errno = 0; /* keep strerror() stuff out of logerror messages */ - - /* clear out file entry */ - bzero((char *) f, sizeof *f); - for (i = 0; i <= LOG_NFACILITIES; i++) - f->f_pmask[i] = INTERNAL_NOPRI; - - /* scan through the list of selectors */ - for (p = line; *p && *p != '\t';) { - - /* find the end of this facility name list */ - for (q = p; *q && *q != '\t' && *q++ != '.'; ) - continue; - - /* collect priority name */ - for (bp = buf; *q && !index("\t,;", *q); ) - *bp++ = *q++; - *bp = '\0'; - - /* skip cruft */ - while (index(", ;", *q)) - q++; - - /* decode priority name */ - if (*buf == '*') - pri = LOG_PRIMASK + 1; - else { - pri = decode(buf, prioritynames); - if (pri < 0) { - (void) sprintf(ebuf, - "unknown priority name \"%s\"", buf); - logerror(ebuf); - return; - } - } - - /* scan facilities */ - while (*p && !index("\t.;", *p)) { - for (bp = buf; *p && !index("\t,;.", *p); ) - *bp++ = *p++; - *bp = '\0'; - if (*buf == '*') - for (i = 0; i < LOG_NFACILITIES; i++) - f->f_pmask[i] = pri; - else { - i = decode(buf, facilitynames); - if (i < 0) { - (void) sprintf(ebuf, - "unknown facility name \"%s\"", - buf); - logerror(ebuf); - return; - } - f->f_pmask[i >> 3] = pri; - } - while (*p == ',' || *p == ' ') - p++; - } - - p = q; - } - - /* skip to action part */ - while (*p == '\t') - p++; - - switch (*p) - { - case '@': - if (!InetInuse) - break; - (void) strcpy(f->f_un.f_forw.f_hname, ++p); - hp = gethostbyname(p); - if (hp == NULL) { - extern int h_errno, h_nerr; - extern char **h_errlist; - - logerror((u_int)h_errno < h_nerr ? - h_errlist[h_errno] : "Unknown error"); - break; - } - bzero((char *) &f->f_un.f_forw.f_addr, - sizeof f->f_un.f_forw.f_addr); - f->f_un.f_forw.f_addr.sin_family = AF_INET; - f->f_un.f_forw.f_addr.sin_port = LogPort; - bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length); - f->f_type = F_FORW; - break; - - case '/': - (void) strcpy(f->f_un.f_fname, p); -#ifdef O_NOCTTY - if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NOCTTY, 0)) < 0) { -#else /* !O_NOCTTY */ - if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { -#endif /* !O_NOCTTY */ - f->f_file = F_UNUSED; - logerror(p); - break; - } - if (isatty(f->f_file)) - f->f_type = F_TTY; - else - f->f_type = F_FILE; - if (strcmp(p, ctty) == 0) - f->f_type = F_CONSOLE; - break; - - case '*': - f->f_type = F_WALL; - break; - - default: - for (i = 0; i < MAXUNAMES && *p; i++) { - for (q = p; *q && *q != ','; ) - q++; - (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); - if ((q - p) > UT_NAMESIZE) - f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; - else - f->f_un.f_uname[i][q - p] = '\0'; - while (*q == ',' || *q == ' ') - q++; - p = q; - } - f->f_type = F_USERS; - break; - } -} - - -/* - * Decode a symbolic name to a numeric value - */ - -decode(name, codetab) - char *name; - CODE *codetab; -{ - register CODE *c; - register char *p; - char buf[40]; - - if (isdigit(*name)) - return (atoi(name)); - - (void) strcpy(buf, name); - for (p = buf; *p; p++) - if (isupper(*p)) - *p = tolower(*p); - for (c = codetab; c->c_name; c++) - if (!strcmp(buf, c->c_name)) - return (c->c_val); - - return (-1); -} - -#ifdef KLOG_STREAM - -int klogread(fd, buf, size) - int fd; - char *buf; - int size; -{ - static char line[MAXLINE]; - static char *pos = line; - - int i; - char *obuf = buf; - char *s; - char *end; - *pos = '\0'; - if (!(end = strchr(line, '\n'))) { - struct timeval tv; - fd_set readfds; - - tv.tv_sec = tv.tv_usec = 0; - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - i = select(fd + 1, (fd_set *) &readfds, (fd_set *) NULL, - (fd_set *) NULL, &tv); - if (i <= 0) - return i; - i = read(fd, pos, sizeof(line) - 1 - (pos - line)); - if (i <= 0) - return i; - pos += i; - *pos = '\0'; - if (!(end = strchr(line, '\n'))) - return 0; - } - for (s = line; s < end; s++) - if (*s != '\r') - *buf++ = *s; - end++; - for (s = line; end < pos; s++) - *s = *end++; - pos = s; - return (buf - obuf); -} - -#endif /* KLOG_STREAM */ diff --git a/syslogd/ttymsg.c b/syslogd/ttymsg.c deleted file mode 100644 index 71a3ca15..00000000 --- a/syslogd/ttymsg.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static char sccsid[] = "@(#)ttymsg.c 5.8 (Berkeley) 7/1/91"; -#endif /* not lint */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Display the contents of a uio structure on a terminal. Used by wall(1) - * and syslogd(8). Forks and finishes in child if write would block, waiting - * at most five minutes. Returns pointer to error string on unexpected error; - * string is not newline-terminated. Various "normal" errors are ignored - * (exclusive-use, lack of permission, etc.). - */ -char * -ttymsg(iov, iovcnt, line) - struct iovec *iov; - int iovcnt; - char *line; -{ - static char device[MAXNAMLEN] = _PATH_DEV; - static char errbuf[1024]; - register int cnt, fd, left, wret; - struct iovec localiov[6]; - int forked = 0; - - if (iovcnt > 6) - return ("too many iov's (change code in wall/ttymsg.c)"); - /* - * open will fail on slip lines or exclusive-use lines - * if not running as root; not an error. - */ - (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); - if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { - if (errno == EBUSY || errno == EACCES) - return (NULL); - (void) snprintf(errbuf, sizeof(errbuf), - "%s: %s", device, strerror(errno)); - return (errbuf); - } - - for (cnt = left = 0; cnt < iovcnt; ++cnt) - left += iov[cnt].iov_len; - - for (;;) { - wret = writev(fd, iov, iovcnt); - if (wret >= left) - break; - if (wret >= 0) { - left -= wret; - if (iov != localiov) { - bcopy(iov, localiov, - iovcnt * sizeof(struct iovec)); - iov = localiov; - } - for (cnt = 0; wret >= iov->iov_len; ++cnt) { - wret -= iov->iov_len; - ++iov; - --iovcnt; - } - if (wret) { - iov->iov_base += wret; - iov->iov_len -= wret; - } - continue; - } - if (errno == EWOULDBLOCK) { - int cpid, off = 0; - - if (forked) { - (void) close(fd); - _exit(1); - } - cpid = fork(); - if (cpid < 0) { - (void) snprintf(errbuf, sizeof(errbuf), - "fork: %s", strerror(errno)); - (void) close(fd); - return (errbuf); - } - if (cpid) { /* parent */ - (void) close(fd); - return (NULL); - } - forked++; - /* wait at most 5 minutes */ - (void) signal(SIGALRM, SIG_DFL); - (void) signal(SIGTERM, SIG_DFL); /* XXX */ - (void) sigsetmask(0); - (void) alarm((u_int)(60 * 5)); - (void) fcntl(fd, O_NONBLOCK, &off); - continue; - } - /* - * We get ENODEV on a slip line if we're running as root, - * and EIO if the line just went away. - */ - if (errno == ENODEV || errno == EIO) - break; - (void) close(fd); - if (forked) - _exit(1); - (void) snprintf(errbuf, sizeof(errbuf), - "%s: %s", device, strerror(errno)); - return (errbuf); - } - - (void) close(fd); - if (forked) - _exit(0); - return (NULL); -} diff --git a/text-utils/Makefile b/text-utils/Makefile index 834531d2..d5c80b29 100644 --- a/text-utils/Makefile +++ b/text-utils/Makefile @@ -1,6 +1,6 @@ # Makefile -- Makefile for util-linux Linux utilities # Created: Sat Dec 26 20:09:40 1992 -# Revised: Sat Jun 3 14:11:08 1995 by r.faith@ieee.org +# Revised: Mon Aug 19 20:11:15 1996 by faith@cs.unc.edu # Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) # @@ -32,12 +32,12 @@ USRLIB= more.help # Programs requiring special compilation -NEEDS_TERMCAP= more ul +NEEDS_NCURSES= more ul all: $(BIN) $(USRBIN) -$(NEEDS_TERMCAP): - $(CC) $(LDFLAGS) $^ -o $@ -ltermcap +$(NEEDS_NCURSES): + $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) # Rules for hexdump diff --git a/text-utils/col.c b/text-utils/col.c index 8be274e0..700e5919 100644 --- a/text-utils/col.c +++ b/text-utils/col.c @@ -49,10 +49,13 @@ char copyright[] = static char sccsid[] = "@(#)col.c 5.3 (Berkeley) 2/2/91"; #endif /* not lint */ +#include +#include #include #include #include #include +#include #include #define BS '\b' /* backspace */ @@ -92,8 +95,15 @@ struct line_str { int l_max_col; /* max column in the line */ }; -LINE *alloc_line(); -void *xmalloc(); +void usage(void); +void wrerr(void); +void warn(int); +void free_line(LINE *l); +void flush_line(LINE *l); +void flush_lines(int); +void flush_blanks(void); +void *xmalloc(void *p, size_t size); +LINE *alloc_line(void); CSET last_set; /* char_set of last char printed */ LINE *lines; @@ -107,9 +117,7 @@ int no_backspaces; /* if not to output any backspaces */ if (putchar(ch) == EOF) \ wrerr(); -main(argc, argv) - int argc; - char **argv; +int main(int argc, char **argv) { extern int optind; extern char *optarg; @@ -313,11 +321,10 @@ main(argc, argv) /* missing a \n on the last line? */ nblank_lines = 2; flush_blanks(); - exit(0); + return 0; } -flush_lines(nflush) - int nflush; +void flush_lines(int nflush) { LINE *l; @@ -342,7 +349,7 @@ flush_lines(nflush) * is the number of half line feeds, otherwise it is the number of whole line * feeds. */ -flush_blanks() +void flush_blanks() { int half, i, nb; @@ -370,8 +377,7 @@ flush_blanks() * Write a line to stdout taking care of space to tab conversion (-h flag) * and character set shifts. */ -flush_line(l) - LINE *l; +void flush_line(LINE *l) { CHAR *c, *endc; int nchars, last_col, this_col; @@ -489,17 +495,14 @@ alloc_line() return(l); } -free_line(l) - LINE *l; +void free_line(LINE *l) { l->l_next = line_freelist; line_freelist = l; } void * -xmalloc(p, size) - void *p; - size_t size; +xmalloc(void *p, size_t size) { if (!(p = (void *)realloc(p, size))) { (void)fprintf(stderr, "col: %s.\n", strerror(ENOMEM)); @@ -508,20 +511,19 @@ xmalloc(p, size) return(p); } -usage() +void usage() { (void)fprintf(stderr, "usage: col [-bfx] [-l nline]\n"); exit(1); } -wrerr() +void wrerr() { (void)fprintf(stderr, "col: write error.\n"); exit(1); } -warn(line) - int line; +void warn(int line) { (void)fprintf(stderr, "col: warning: can't back up %s.\n", line < 0 ? diff --git a/text-utils/colcrt.c b/text-utils/colcrt.c index 9e6136b5..544c20de 100644 --- a/text-utils/colcrt.c +++ b/text-utils/colcrt.c @@ -42,6 +42,13 @@ static char sccsid[] = "@(#)colcrt.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #include +#include /* for close() */ +#include + +int plus(char c, char d); +void move(int l, int m); +void pflush(int ol); + /* * colcrt - replaces col for crts with new nroff esp. when using tbl. * Bill Joy UCB July 14, 1977 @@ -67,9 +74,7 @@ char printall; char *progname; FILE *f; -main(argc, argv) - int argc; - char *argv[]; +int main(int argc, char **argv) { register c; register char *cp, *dp; @@ -177,22 +182,20 @@ main(argc, argv) } } while (argc > 0); fflush(stdout); - exit(0); + return 0; } -plus(c, d) - char c, d; +int plus(char c, char d) { - return (c == '|' && d == '-' || d == '_'); + return (c == '|' && (d == '-' || d == '_')); } int first; -pflush(ol) - int ol; +void pflush(int ol) { - register int i, j; + register int i; register char *cp; char lastomit; int l; @@ -223,8 +226,7 @@ pflush(ol) first = 1; } -move(l, m) - int l, m; +void move(int l, int m) { register char *cp, *dp; diff --git a/text-utils/colrm.c b/text-utils/colrm.c index 0fcf725b..1ec5db58 100644 --- a/text-utils/colrm.c +++ b/text-utils/colrm.c @@ -47,9 +47,9 @@ COLRM removes unwanted columns from a file Jeff Schriebman UC Berkeley 11-74 */ +int getn(char *ap); -main(argc,argv) -char **argv; +int main(int argc, char **argv) { register c, ct, first, last; @@ -109,11 +109,10 @@ loop1: } fin: fflush(stdout); - exit(0); + return 0; } -getn(ap) -char *ap; +int getn(char *ap) { register int n,c; register char *p; diff --git a/text-utils/column.c b/text-utils/column.c index 7536c06d..463adf5c 100644 --- a/text-utils/column.c +++ b/text-utils/column.c @@ -48,6 +48,7 @@ static char sccsid[] = "@(#)column.c 8.3 (Berkeley) 4/2/94"; #include #include #include +#include #include #include @@ -85,7 +86,7 @@ main(argc, argv) #endif if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) { - if (p = getenv("COLUMNS")) + if ((p = getenv("COLUMNS")) != NULL) termwidth = atoi(p); } else termwidth = win.ws_col; @@ -115,7 +116,7 @@ main(argc, argv) if (!*argv) input(stdin); else for (; *argv; ++argv) - if (fp = fopen(*argv, "r")) { + if ((fp = fopen(*argv, "r")) != NULL) { input(fp); (void)fclose(fp); } else { @@ -156,7 +157,7 @@ c_columnate() endcol = maxlength; putchar('\n'); } else { - while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { + while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { (void)putchar('\t'); chcnt = cnt; } @@ -173,7 +174,10 @@ r_columnate() int base, chcnt, cnt, col, endcol, numcols, numrows, row; maxlength = (maxlength + TAB) & ~(TAB - 1); + /* This could be 0 */ numcols = termwidth / maxlength; + if (!numcols) + numcols = 1; numrows = entries / numcols; if (entries % numcols) ++numrows; @@ -184,7 +188,7 @@ r_columnate() chcnt += printf("%s", list[base]); if ((base += numrows) >= entries) break; - while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) { + while ((cnt = ((chcnt + TAB) & ~(TAB - 1))) <= endcol) { (void)putchar('\t'); chcnt = cnt; } @@ -224,8 +228,9 @@ maketbl() cols = emalloc((maxcols = DEFCOLS) * sizeof(char *)); lens = emalloc(maxcols * sizeof(int)); for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) { - for (coloff = 0, p = *lp; cols[coloff] = strtok(p, separator); - p = NULL) + for (coloff = 0, p = *lp; + (cols[coloff] = strtok(p, separator)) != NULL; + p = NULL) if (++coloff == maxcols) { if (!(cols = realloc(cols, (u_int)maxcols + DEFCOLS * sizeof(char *))) || diff --git a/text-utils/conv.c b/text-utils/conv.c index c7a37a2b..e2e9690a 100644 --- a/text-utils/conv.c +++ b/text-utils/conv.c @@ -35,13 +35,12 @@ static char sccsid[] = "@(#)conv.c 5.4 (Berkeley) 6/1/90"; #endif /* not lint */ -#include +#include #include +#include #include "hexdump.h" -conv_c(pr, p) - PR *pr; - u_char *p; +void conv_c(PR *pr, u_char *p) { extern int deprecated; char buf[10], *str; @@ -89,9 +88,7 @@ strpr: *pr->cchar = 's'; } } -conv_u(pr, p) - PR *pr; - u_char *p; +void conv_u(PR *pr, u_char *p) { extern int deprecated; static char *list[] = { diff --git a/text-utils/display.c b/text-utils/display.c index 12732ee7..d906cfc9 100644 --- a/text-utils/display.c +++ b/text-utils/display.c @@ -45,7 +45,9 @@ static char sccsid[] = "@(#)display.c 5.11 (Berkeley) 3/9/91"; #include #include "hexdump.h" -#ifdef linux +static void doskip(char *, int); + +#ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif @@ -135,7 +137,23 @@ static off_t savaddress; /* saved address/offset in stream */ } \ } -display() +void bpad(PR *pr) +{ + static char *spec = " -0+#"; + register char *p1, *p2; + + /* + * remove all conversion flags; '-' is the only one valid + * with %s, and it's not useful here. + */ + pr->flags = F_BPAD; + *pr->cchar = 's'; + for (p1 = pr->fmt; *p1 != '%'; ++p1); + for (p2 = ++p1; *p1 && index(spec, *p1); ++p1); + while ((*p2++ = *p1++) != 0) ; +} + +void display() { extern FU *endfu; register FS *fs; @@ -144,9 +162,9 @@ display() register int cnt; register u_char *bp; off_t saveaddress; - u_char savech, *savebp, *get(); + u_char savech = 0, *savebp, *get(); - while (bp = get()) + while ((bp = get()) != NULL) for (fs = fshead, savebp = bp, saveaddress = address; fs; fs = fs->nextfs, bp = savebp, address = saveaddress) for (fu = fs->nextfu; fu; fu = fu->nextfu) { @@ -189,23 +207,6 @@ display() } } -bpad(pr) - PR *pr; -{ - static char *spec = " -0+#"; - register char *p1, *p2; - - /* - * remove all conversion flags; '-' is the only one valid - * with %s, and it's not useful here. - */ - pr->flags = F_BPAD; - *pr->cchar = 's'; - for (p1 = pr->fmt; *p1 != '%'; ++p1); - for (p2 = ++p1; *p1 && index(spec, *p1); ++p1); - while (*p2++ = *p1++); -} - static char **_argv; u_char * @@ -234,7 +235,7 @@ get() * and no other files are available, zero-pad the rest of the * block and set the end flag. */ - if (!length || ateof && !next((char **)NULL)) { + if (!length || (ateof && !next((char **)NULL))) { if (need == blocksize) return((u_char *)NULL); if (vflag != ALL && !bcmp(curp, savp, nread)) { @@ -277,10 +278,7 @@ get() } } -extern off_t skip; /* bytes to skip */ - -next(argv) - char **argv; +int next(char **argv) { extern int errno, exitval; static int done; @@ -315,9 +313,8 @@ next(argv) /* NOTREACHED */ } -doskip(fname, statok) - char *fname; - int statok; +static void +doskip(char *fname, int statok) { extern int errno; struct stat sbuf; @@ -328,7 +325,11 @@ doskip(fname, statok) fname, strerror(errno)); exit(1); } - if (skip >= sbuf.st_size) { + if ( ( ! (S_ISCHR(sbuf.st_mode) || + S_ISBLK(sbuf.st_mode) || + S_ISFIFO(sbuf.st_mode)) ) && + skip >= sbuf.st_size) { + /* If size valid and skip >= size */ skip -= sbuf.st_size; address += sbuf.st_size; return; @@ -344,8 +345,7 @@ doskip(fname, statok) } char * -emalloc(size) - int size; +emalloc(int size) { char *p; @@ -355,7 +355,7 @@ emalloc(size) return(p); } -nomem() +void nomem() { extern int errno; diff --git a/text-utils/hexdump.c b/text-utils/hexdump.c index 4b282427..7329d119 100644 --- a/text-utils/hexdump.c +++ b/text-utils/hexdump.c @@ -50,11 +50,10 @@ int blocksize; /* data block size */ int exitval; /* final exit value */ int length = -1; /* max bytes to read */ -main(argc, argv) +int main(argc, argv) int argc; char **argv; { - extern int errno; register FS *tfs; char *p, *rindex(); @@ -75,5 +74,5 @@ main(argc, argv) (void)next(argv); display(); - exit(exitval); + return exitval; } diff --git a/text-utils/hexdump.h b/text-utils/hexdump.h index 9def7633..3ca46b91 100644 --- a/text-utils/hexdump.h +++ b/text-utils/hexdump.h @@ -70,7 +70,23 @@ typedef struct _fs { /* format strings */ int bcnt; } FS; +extern FU *endfu; extern FS *fshead; /* head of format strings list */ extern int blocksize; /* data block size */ +extern int deprecated; +extern off_t skip; /* bytes to skip */ enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ + char *emalloc(); +int size(FS *); +void add(char *); +void rewrite(FS *); +void addfile(char *); +void display(void); +void nomem(void); +void usage(void); +void conv_c(PR *, u_char *); +void conv_u(PR *, u_char *); +int next(char **); +void oldsyntax(int, char ***); +void newsyntax(int, char ***); diff --git a/text-utils/hexsyntax.c b/text-utils/hexsyntax.c index 3812e979..4a6638a0 100644 --- a/text-utils/hexsyntax.c +++ b/text-utils/hexsyntax.c @@ -36,14 +36,14 @@ static char sccsid[] = "@(#)hexsyntax.c 5.2 (Berkeley) 5/8/90"; #endif /* not lint */ #include +#include +#include #include #include "hexdump.h" off_t skip; /* bytes to skip */ -newsyntax(argc, argvp) - int argc; - char ***argvp; +void newsyntax(int argc, char ***argvp) { extern enum _vflag vflag; extern FS *fshead; @@ -122,7 +122,7 @@ newsyntax(argc, argvp) *argvp += optind; } -usage() +void usage() { (void)fprintf(stderr, "hexdump: [-bcdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n"); diff --git a/text-utils/more.c b/text-utils/more.c index 51ddc643..123ef06e 100644 --- a/text-utils/more.c +++ b/text-utils/more.c @@ -32,21 +32,33 @@ static char sccsid[] = "@(#)more.c 5.19 (Berkeley) 6/29/88"; ** ** modified by Geoff Peck, UCB to add underlining, single spacing ** modified by John Foderaro, UCB to add -c and MORE environment variable +** modified by Erik Troan to be more posix and so compile +** on linux/axp. +** modified by Kars de Jong to use terminfo instead +** of termcap. */ #include +#include #include +#include /* for alloca() */ #include #include #include #include #include #include +#include #include #include +#include #include -#include -#include +#if NCH +#include +#else +#include +#endif +#include #define HELPFILE "/usr/lib/more.help" #define VI "/usr/bin/vi" @@ -57,25 +69,40 @@ static char sccsid[] = "@(#)more.c 5.19 (Berkeley) 6/29/88"; #define Getc(f) (++file_pos, getc(f)) #define Ungetc(c,f) (--file_pos, ungetc(c,f)) -#define stty(fd,argp) ioctl(fd,TCSETAF,argp) +#define stty(fd,argp) ioctl(fd,TCSETSF,argp) /* some function declarations */ -void initterm(); +void initterm(void); +void kill_line(void); +void doclear(void); +void cleareol(void); +void clreos(void); +void home(void); +void error (char *mess); +void do_shell (char *filename); +int colon (char *filename, int cmd, int nlines); +int expand (char *outbuf, char *inbuf); void argscan(char *s); +void rdline (register FILE *f); void copy_file(register FILE *f); -void doclear(); -void home(); void search(char buf[], FILE *file, register int n); +void skipf (register int nskip); void skiplns(register int n, register FILE *f); void screen (register FILE *f, register int num_lines); int command (char *filename, register FILE *f); -void erase (register int col); -void cleareol(); -void clreos(); +void erasep (register int col); +void show (register char ch); int pr(char *s1); -void reset_tty(); -int getline(register FILE *f, int *length); +int printd (int n); +void set_tty(void); +void reset_tty(void); +void ttyin (char buf[], register int nmax, char pchar); +int number(char *cmd); +int readch (void); +int get_line(register FILE *f, int *length); void prbuf (register char *s, register int n); +int xprintf (char *fmt, ...); +void execute (char *filename, char *cmd, ...); #define TBUFSIZ 1024 #define LINSIZ 256 @@ -84,7 +111,7 @@ void prbuf (register char *s, register int n); #define ESC '\033' #define QUIT '\034' -struct termio otty, savetty; +struct termios otty, savetty0; long file_pos, file_size; int fnum, no_intty, no_tty, slow_tty; int dum_opt, dlines; @@ -149,7 +176,7 @@ int main(int argc, char **argv) { int initopt = 0; int srchopt = 0; int clearit = 0; - int initline; + int initline = 0; char initbuf[80]; FILE *checkf(); @@ -159,7 +186,7 @@ int main(int argc, char **argv) { nscroll = Lpp/2 - 1; if (nscroll <= 0) nscroll = 1; - if(s = getenv("MORE")) argscan(s); + if((s = getenv("MORE")) != NULL) argscan(s); while (--nfiles > 0) { if ((ch = (*++fnames)[0]) == '-') { argscan(*fnames+1); @@ -279,12 +306,12 @@ int main(int argc, char **argv) { doclear (); if (prnames) { if (bad_so) - erase (0); + erasep (0); if (clreol) cleareol (); pr("::::::::::::::"); if (promptlen > 14) - erase (14); + erasep (14); xprintf ("\n"); if(clreol) cleareol(); xprintf("%s\n", fnames[fnum]); @@ -424,23 +451,6 @@ magic(f, fs) return(0); } -/* -** A real function, for the tputs routine in termlib -*/ -#ifdef __linux__ -int putch( int ch ) -#else -void -putch (ch) -char ch; -#endif -{ - putchar (ch); -#ifdef __linux__ - return 0; -#endif -} - /* ** Print out the contents of the file f, one screenful at a time. */ @@ -456,7 +466,7 @@ void screen (register FILE *f, register int num_lines) for (;;) { while (num_lines > 0 && !Pause) { - if ((nchars = getline (f, &length)) == EOF) + if ((nchars = get_line (f, &length)) == EOF) { if (clreol) clreos(); @@ -466,7 +476,7 @@ void screen (register FILE *f, register int num_lines) continue; prev_len = length; if (bad_so || ((Senter && *Senter == ' ') && (promptlen > 0))) - erase (0); + erasep (0); /* must clear before drawing line since tabs on some terminals * do not erase what they tab over. */ @@ -474,7 +484,7 @@ void screen (register FILE *f, register int num_lines) cleareol (); prbuf (Line, length); if (nchars < promptlen) - erase (nchars); /* erase () sets promptlen to 0 */ + erasep (nchars); /* erasep () sets promptlen to 0 */ else promptlen = 0; /* is this needed? * if (clreol) @@ -487,7 +497,7 @@ void screen (register FILE *f, register int num_lines) num_lines--; } if (pstate) { - tputs(ULexit, 1, putch); + putp (ULexit); pstate = 0; } fflush(stdout); @@ -506,7 +516,7 @@ void screen (register FILE *f, register int num_lines) if ((num_lines = command (NULL, f)) == 0) return; if (hard && promptlen > 0) - erase (0); + erasep (0); if (noscroll && num_lines >= dlines) { if (clreol) @@ -599,16 +609,14 @@ void copy_file(register FILE *f) { /* Simplified printf function */ -int xprintf (fmt, va_alist) -register char *fmt; -va_dcl +int xprintf (char *fmt, ...) { va_list ap; register char ch; register int ccount; ccount = 0; - va_start(ap); + va_start(ap, fmt); while (*fmt) { while ((ch = *fmt++) != '%') { if (ch == '\0') @@ -643,12 +651,11 @@ va_dcl ** returning the length of the print representation. */ -printd (n) -int n; +int printd (int n) { int a, nchars; - if (a = n/10) + if ((a = n/10) != 0) nchars = 1 + printd(a); else nchars = 1; @@ -659,25 +666,22 @@ int n; /* Put the print representation of an integer into a string */ static char *sptr; -scanstr (n, str) -int n; -char *str; -{ - sptr = str; - Sprintf (n); - *sptr = '\0'; -} - -Sprintf (n) -{ +void Sprintf (int n) { int a; - if (a = n/10) + if ((a = n/10) != 0) Sprintf (a); *sptr++ = n % 10 + '0'; } -static char bell = ctrl('G'); +void scanstr (int n, char *str) +{ + sptr = str; + Sprintf (n); + *sptr = '\0'; +} + +static char my_bell = ctrl('G'); #ifdef undef strlen (s) @@ -696,7 +700,7 @@ char *s; ** string "string" */ -tailequ (path, string) +int tailequ (path, string) char *path; register char *string; { @@ -713,7 +717,7 @@ register char *string; return(0); } -prompt (filename) +void prompt (filename) char *filename; { if (clreol) @@ -723,7 +727,7 @@ char *filename; if (!hard) { promptlen = 8; if (Senter && Sexit) { - tputs (Senter, 1, putch); + putp (Senter); promptlen += (2 * soglitch); } if (clreol) @@ -739,13 +743,13 @@ char *filename; promptlen += pr("[Press space to continue, 'q' to quit.]"); } if (Senter && Sexit) - tputs (Sexit, 1, putch); + putp (Sexit); if (clreol) clreos (); fflush(stdout); } else - write (2, &bell, 1); + write (2, &my_bell, 1); inwait++; } @@ -753,7 +757,7 @@ char *filename; ** Get a logical line */ -int getline(register FILE *f, int *length) +int get_line(register FILE *f, int *length) { register int c; register char *p; @@ -783,10 +787,10 @@ int getline(register FILE *f, int *length) } *p++ = c; if (c == '\t') - if (!hardtabs || column < promptlen && !hard) { + if (!hardtabs || (column < promptlen && !hard)) { if (hardtabs && eraseln && !dumb) { column = 1 + (column | 7); - tputs (eraseln, 1, putch); + putp (eraseln); promptlen = 0; } else { @@ -837,7 +841,7 @@ int getline(register FILE *f, int *length) ** Erase the rest of the prompt, assuming we are starting at column col. */ -void erase (register int col) +void erasep (register int col) { if (promptlen == 0) @@ -849,7 +853,7 @@ void erase (register int col) if (col == 0) putchar ('\r'); if (!dumb && eraseln) - tputs (eraseln, 1, putch); + putp (eraseln); else for (col = promptlen - col; col > 0; col--) putchar (' '); @@ -861,10 +865,11 @@ void erase (register int col) ** Erase the current line entirely */ -kill_line () +void kill_line () { - erase (0); - if (!eraseln || dumb) putchar ('\r'); + erasep (0); + if (!eraseln || dumb) + putchar ('\r'); } /* @@ -872,12 +877,12 @@ kill_line () */ void cleareol() { - tputs(eraseln, 1, putch); + putp(eraseln); } void clreos() { - tputs(EodClr, 1, putch); + putp(EodClr); } /* @@ -889,7 +894,7 @@ int pr(char *s1) register char *s; register char c; - for (s = s1; c = *s++; ) + for (s = s1; (c = *s++) != 0; ) putchar(c); return (int) (s - s1 - 1); } @@ -911,7 +916,7 @@ void prbuf (register char *s, register int n) s++; continue; } - if (state = wouldul(s, n)) { + if ((state = wouldul(s, n)) != 0) { c = (*s == '_')? s[2] : *s ; n -= 2; s += 3; @@ -921,13 +926,13 @@ void prbuf (register char *s, register int n) if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) state = 1; else - tputs(state ? ULenter : ULexit, 1, putch); + putp(state ? ULenter : ULexit); } if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) putchar(c); if (state && *chUL) { pr(chBS); - tputs(chUL, 1, putch); + putp(chUL); } pstate = state; } @@ -940,7 +945,7 @@ void doclear() { if (Clear && !hard) { - tputs(Clear, 1, putch); + putp(Clear); /* Put out carriage return so that system doesn't ** get confused by escape sequences when expanding tabs @@ -956,7 +961,7 @@ doclear() void home() { - tputs(Home,1,putch); + putp(Home); } static int lastcmd, lastarg, lastp; @@ -973,12 +978,12 @@ char shell_line[132]; int command (char *filename, register FILE *f) { register int nlines; - register int retval; + register int retval = 0; register char c; char colonch; FILE *helpf; int done; - char comchar, cmdbuf[80], *p; + char comchar, cmdbuf[80]; #define ret(val) retval=val;done++;break @@ -1016,14 +1021,14 @@ int command (char *filename, register FILE *f) register int initline; if (no_intty) { - write(2, &bell, 1); + write(2, &my_bell, 1); return (-1); } if (nlines == 0) nlines++; putchar ('\r'); - erase (0); + erasep (0); xprintf ("\n"); if (clreol) cleareol (); @@ -1069,7 +1074,7 @@ int command (char *filename, register FILE *f) if (comchar == 'f') nlines *= dlines; putchar ('\r'); - erase (0); + erasep (0); xprintf ("\n"); if (clreol) cleareol (); @@ -1108,7 +1113,7 @@ int command (char *filename, register FILE *f) ret (dlines); } else { - write (2, &bell, 1); + write (2, &my_bell, 1); break; } case '\'': @@ -1120,7 +1125,7 @@ int command (char *filename, register FILE *f) ret (dlines); } else { - write (2, &bell, 1); + write (2, &my_bell, 1); break; } case '=': @@ -1141,7 +1146,7 @@ int command (char *filename, register FILE *f) search (NULL, f, nlines); /* Use previous r.e. */ } else { - ttyin (cmdbuf, 78, '/'); + ttyin (cmdbuf, sizeof(cmdbuf)-2, '/'); write (2, "\r", 1); search (cmdbuf, f, nlines); } @@ -1172,16 +1177,16 @@ int command (char *filename, register FILE *f) if (dum_opt) { kill_line (); if (Senter && Sexit) { - tputs (Senter, 1, putch); + putp (Senter); promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); - tputs (Sexit, 1, putch); + putp (Sexit); } else promptlen = pr ("[Press 'h' for instructions.]"); fflush (stdout); } else - write (2, &bell, 1); + write (2, &my_bell, 1); break; } if (done) break; @@ -1201,10 +1206,7 @@ char ch; * more of the file to be printed. */ -colon (filename, cmd, nlines) -char *filename; -int cmd; -int nlines; +int colon (char *filename, int cmd, int nlines) { if (cmd == 0) ch = readch (); @@ -1227,16 +1229,16 @@ int nlines; nlines++; } putchar ('\r'); - erase (0); + erasep (0); skipf (nlines); return (0); case 'p': if (no_intty) { - write (2, &bell, 1); + write (2, &my_bell, 1); return (-1); } putchar ('\r'); - erase (0); + erasep (0); if (nlines == 0) nlines++; skipf (-nlines); @@ -1248,7 +1250,7 @@ int nlines; case 'Q': end_it (); default: - write (2, &bell, 1); + write (2, &my_bell, 1); return (-1); } } @@ -1258,8 +1260,7 @@ int nlines; ** terminates the number. */ -number(cmd) -char *cmd; +int number(char *cmd) { register int i; @@ -1278,8 +1279,7 @@ char *cmd; return (i); } -do_shell (filename) -char *filename; +void do_shell (char *filename) { char cmdbuf[80]; @@ -1290,7 +1290,7 @@ char *filename; if (lastp) pr (shell_line); else { - ttyin (cmdbuf, 78, '!'); + ttyin (cmdbuf, sizeof(cmdbuf)-2, '!'); if (expand (shell_line, cmdbuf)) { kill_line (); promptlen = xprintf ("!%s", shell_line); @@ -1383,14 +1383,14 @@ void search(char buf[], FILE *file, register int n) } /*VARARGS2*/ -execute (filename, cmd, va_alist) -char *filename; -char *cmd; -va_dcl +void execute (char * filename, char * cmd, ...) { int id; int n; va_list argp; + char * arg; + char ** args; + int argcount; fflush (stdout); reset_tty (); @@ -1401,11 +1401,33 @@ va_dcl close(0); open("/dev/tty", 0); } - va_start(argp); - execv (cmd, argp); + + va_start(argp, cmd); + + arg = va_arg(argp, char *); + argcount = 0; + while (arg) { + argcount++; + arg = va_arg(argp, char *); + } + va_end(argp); /* balance {}'s for some UNIX's */ + + args = alloca(sizeof(char *) * (argcount + 1)); + args[argcount] = NULL; + + va_start(argp, cmd); + arg = va_arg(argp, char *); + argcount = 0; + while (arg) { + args[argcount] = arg; + argcount++; + arg = va_arg(argp, char *); + } + va_end(argp); /* balance {}'s for some UNIX's */ + + execv (cmd, args); write (2, "exec failed\n", 12); exit (1); - va_end(argp); /* balance {}'s for some UNIX's */ } if (id > 0) { signal (SIGINT, SIG_IGN); @@ -1445,8 +1467,7 @@ void skiplns (register int n, register FILE *f) ** negative. */ -skipf (nskip) -register int nskip; +void skipf (register int nskip) { if (nskip == 0) return; if (nskip > 0) { @@ -1476,70 +1497,74 @@ register int nskip; void initterm() { - char buf[TBUFSIZ]; - static char clearbuf[TBUFSIZ]; - char *clearptr, *padstr; - int ldisc; - int lmode; + int ret; + char *padstr; char *term; - int tgrp; struct winsize win; +#ifdef do_SIGTTOU retry: - no_tty = ioctl(fileno(stdout), TCGETA, &otty); +#endif + no_tty = ioctl(fileno(stdout), TCGETS, &otty); if (!no_tty) { docrterase = (otty.c_cc[VERASE] != 255); docrtkill = (otty.c_cc[VKILL] != 255); -#ifdef undef - /* - * Wait until we're in the foreground before we save the - * the terminal modes. - */ - if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { - perror("TIOCGPGRP"); - exit(1); - } - if (tgrp != getpgrp(0)) { - kill(0, SIGTTOU); - goto retry; +#ifdef do_SIGTTOU + { + int tgrp; + /* + * Wait until we're in the foreground before we save the + * the terminal modes. + */ + if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { + perror("TIOCGPGRP"); + exit(1); + } + if (tgrp != getpgrp(0)) { + kill(0, SIGTTOU); + goto retry; + } } #endif - if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { + if ((term = getenv("TERM")) == 0) { + dumb++; ul_opt = 0; + } + setupterm(term, 1, &ret); + if (ret <= 0) { dumb++; ul_opt = 0; } else { #ifdef TIOCGWINSZ if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { #endif - Lpp = tgetnum("li"); - Mcol = tgetnum("co"); + Lpp = tigetnum("lines"); + Mcol = tigetnum("cols"); #ifdef TIOCGWINSZ } else { if ((Lpp = win.ws_row) == 0) - Lpp = tgetnum("li"); + Lpp = tigetnum("lines"); if ((Mcol = win.ws_col) == 0) - Mcol = tgetnum("co"); + Mcol = tigetnum("cols"); } #endif - if ((Lpp <= 0) || tgetflag("hc")) { + if ((Lpp <= 0) || tigetflag("hc")) { hard++; /* Hard copy terminal */ Lpp = 24; } - if (tgetflag("xn")) + if (tigetflag("xenl")) eatnl++; /* Eat newline at last column + 1; dec, concept */ if (Mcol <= 0) Mcol = 80; - if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) + if (tailequ (fnames[0], "page")) noscroll++; - Wrap = tgetflag("am"); - bad_so = tgetflag ("xs"); - clearptr = clearbuf; - eraseln = tgetstr("ce",&clearptr); - Clear = tgetstr("cl", &clearptr); - Senter = tgetstr("so", &clearptr); - Sexit = tgetstr("se", &clearptr); - if ((soglitch = tgetnum("sg")) < 0) + Wrap = tigetflag("am"); + bad_so = tigetflag ("xhp"); + eraseln = tigetstr("el"); + Clear = tigetstr("clear"); + Senter = tigetstr("smso"); + Sexit = tigetstr("rmso"); + if ((soglitch = tigetnum("xmc")) < 0) soglitch = 0; /* @@ -1550,50 +1575,49 @@ retry: * isn't available, settle for standout sequence. */ - if (tgetflag("ul") || tgetflag("os")) + if (tigetflag("ul") || tigetflag("os")) ul_opt = 0; - if ((chUL = tgetstr("uc", &clearptr)) == NULL ) + if ((chUL = tigetstr("uc")) == NULL ) chUL = ""; - if (((ULenter = tgetstr("us", &clearptr)) == NULL || - (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { + if (((ULenter = tigetstr("smul")) == NULL || + (ULexit = tigetstr("rmul")) == NULL) && !*chUL) { if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { ULenter = ""; ULexit = ""; } else ulglitch = soglitch; } else { - if ((ulglitch = tgetnum("ug")) < 0) - ulglitch = 0; + ulglitch = 0; } - if (padstr = tgetstr("pc", &clearptr)) + if ((padstr = tigetstr("pad")) != NULL) PC = *padstr; - Home = tgetstr("ho",&clearptr); + Home = tigetstr("home"); if (Home == 0 || *Home == '\0') { - if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { - strcpy(cursorhome, tgoto(cursorm, 0, 0)); + if ((cursorm = tigetstr("cup")) != NULL) { + strcpy(cursorhome, (const char *)tparm(cursorm, 0, 0)); Home = cursorhome; } } - EodClr = tgetstr("cd", &clearptr); - if ((chBS = tgetstr("bc", &clearptr)) == NULL) + EodClr = tigetstr("ed"); + if ((chBS = tigetstr("cub1")) == NULL) chBS = "\b"; } if ((shell = getenv("SHELL")) == NULL) shell = "/bin/sh"; } - no_intty = ioctl(fileno(stdin), TCGETA, &otty); - ioctl(fileno(stderr), TCGETA, &otty); - savetty = otty; + no_intty = ioctl(fileno(stdin), TCGETS, &otty); + ioctl(fileno(stderr), TCGETS, &otty); + savetty0 = otty; slow_tty = (otty.c_cflag & CBAUD) < B1200; hardtabs = (otty.c_oflag & TABDLY) != XTABS; if (!no_tty) otty.c_lflag &= ~(ICANON|ECHO); } -readch () +int readch () { char ch; extern int errno; @@ -1616,10 +1640,7 @@ static char CARAT = '^'; else \ write (2, &BS, sizeof(BS)); -ttyin (buf, nmax, pchar) -char buf[]; -register int nmax; -char pchar; +void ttyin (char buf[], register int nmax, char pchar) { register char *sptr; register char ch; @@ -1661,7 +1682,7 @@ char pchar; putchar ('\r'); putchar (pchar); if (eraseln) - erase (1); + erasep (1); else if (docrtkill) while (promptlen-- > 1) write (2, BSB, sizeof(BSB)); @@ -1697,9 +1718,7 @@ char pchar; error ("Line too long"); } -expand (outbuf, inbuf) -char *outbuf; -char *inbuf; +int expand (char *outbuf, char *inbuf) { register char *instr; register char *outstr; @@ -1740,8 +1759,7 @@ char *inbuf; return (changed); } -show (ch) -register char ch; +void show (register char ch) { char cbuf; @@ -1755,8 +1773,7 @@ register char ch; promptlen++; } -error (mess) -char *mess; +void error (char *mess) { if (clreol) cleareol (); @@ -1764,9 +1781,9 @@ char *mess; kill_line (); promptlen += strlen (mess); if (Senter && Sexit) { - tputs (Senter, 1, putch); + putp (Senter); pr(mess); - tputs (Sexit, 1, putch); + putp (Sexit); } else pr (mess); @@ -1776,27 +1793,30 @@ char *mess; } -set_tty () +void set_tty () { otty.c_lflag &= ~(ICANON|ECHO); stty(fileno(stderr), &otty); } +int ourputch(int ch) { + return putc(ch, stdout); +} + void reset_tty () { if (no_tty) return; if (pstate) { - tputs(ULexit, 1, putch); + tputs(ULexit, 1, ourputch); fflush(stdout); pstate = 0; } otty.c_lflag |= ICANON|ECHO; - stty(fileno(stderr), &savetty); + stty(fileno(stderr), &savetty0); } -rdline (f) -register FILE *f; +void rdline (register FILE *f) { register char c; register char *p; diff --git a/text-utils/odsyntax.c b/text-utils/odsyntax.c index 2dd5a2a2..120928bf 100644 --- a/text-utils/odsyntax.c +++ b/text-utils/odsyntax.c @@ -38,18 +38,20 @@ static char sccsid[] = "@(#)odsyntax.c 5.4 (Berkeley) 3/8/91"; #include #include #include +#include /* for isdigit() */ +#include /* for getopt() */ #include "hexdump.h" +static void odoffset(int, char ***); + int deprecated; -oldsyntax(argc, argvp) - int argc; - char ***argvp; +void +oldsyntax(int argc, char ***argvp) { extern enum _vflag vflag; extern FS *fshead; - extern char *optarg; - extern int length, optind; + extern int optind; int ch; char **argv; static void odprecede(); @@ -147,11 +149,10 @@ oldsyntax(argc, argvp) } #define ishexdigit(c) \ - (c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') + ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) -odoffset(argc, argvp) - int argc; - char ***argvp; +static void +odoffset(int argc, char ***argvp) { extern off_t skip; register char *num, *p; diff --git a/text-utils/parse.c b/text-utils/parse.c index e0d982e1..27280982 100644 --- a/text-utils/parse.c +++ b/text-utils/parse.c @@ -43,10 +43,15 @@ static char sccsid[] = "@(#)parse.c 5.6 (Berkeley) 3/9/91"; #include #include "hexdump.h" +static void escape(register char *p1); +static void badcnt(char *s); +static void badsfmt(void); +static void badfmt(char *fmt); +static void badconv(char *ch); + FU *endfu; /* format at end-of-data */ -addfile(name) - char *name; +void addfile(char *name) { register char *p; FILE *fp; @@ -72,8 +77,7 @@ addfile(name) (void)fclose(fp); } -add(fmt) - char *fmt; +void add(char *fmt) { register char *p; static FS **nextfs; @@ -147,8 +151,8 @@ add(fmt) } static char *spec = ".#-+ 0123456789"; -size(fs) - FS *fs; + +int size(FS *fs) { register FU *fu; register int bcnt, cursize; @@ -200,15 +204,14 @@ size(fs) return(cursize); } -rewrite(fs) - FS *fs; +void rewrite(FS *fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; - register PR *pr, **nextpr; + register PR *pr, **nextpr = NULL; register FU *fu; register char *p1, *p2; char savech, *fmtp; - int nconv, prec; + int nconv, prec = 0; for (fu = fs->nextfu; fu; fu = fu->nextfu) { /* @@ -439,8 +442,7 @@ sw2: switch(fu->bcnt) { } -escape(p1) - register char *p1; +static void escape(register char *p1) { register char *p2; @@ -481,30 +483,27 @@ escape(p1) } } -badcnt(s) - char *s; +static void badcnt(char *s) { (void)fprintf(stderr, "hexdump: bad byte count for conversion character %s.\n", s); exit(1); } -badsfmt() +static void badsfmt() { (void)fprintf(stderr, "hexdump: %%s requires a precision or a byte count.\n"); exit(1); } -badfmt(fmt) - char *fmt; +static void badfmt(char *fmt) { (void)fprintf(stderr, "hexdump: bad format {%s}\n", fmt); exit(1); } -badconv(ch) - char *ch; +static void badconv(char *ch) { (void)fprintf(stderr, "hexdump: bad conversion character %%%s.\n", ch); exit(1); diff --git a/text-utils/rev.c b/text-utils/rev.c index 1cede0bc..3b4e4210 100644 --- a/text-utils/rev.c +++ b/text-utils/rev.c @@ -45,7 +45,7 @@ char copyright[] = #ifndef lint /*static char sccsid[] = "from: @(#)rev.c 5.2 (Berkeley) 3/21/92";*/ -static char rcsid[] = "$Id: rev.c,v 1.3 1995/10/07 01:32:14 faith Exp $"; +static char rcsid[] = "$Id: rev.c,v 1.4 1996/07/02 20:08:07 janl Exp $"; #endif /* not lint */ #include @@ -53,7 +53,7 @@ static char rcsid[] = "$Id: rev.c,v 1.3 1995/10/07 01:32:14 faith Exp $"; #include #include #include -#ifdef linux +#ifdef __linux__ #include #endif /* linux */ @@ -66,7 +66,7 @@ main(argc, argv) char *argv[]; { register char *filename, *t; -#ifdef linux +#ifdef __linux__ char p[512]; #else /* linux */ char *p; @@ -98,7 +98,7 @@ main(argc, argv) } filename = *argv++; } -#ifndef linux +#ifndef __linux__ while (p = fgetline(fp, &len)) { t = p + len - 1; for (t = p + len - 1; t >= p; --t) diff --git a/text-utils/ul.1 b/text-utils/ul.1 index 701797ae..9bd4e8ee 100644 --- a/text-utils/ul.1 +++ b/text-utils/ul.1 @@ -49,9 +49,9 @@ and translates occurrences of underscores to the sequence which indicates underlining for the terminal in use, as specified by the environment variable .Ev TERM . -The file -.Pa /etc/termcap -is read to determine the appropriate sequences for underlining. +The +.Pa terminfo +database is read to determine the appropriate sequences for underlining. If the terminal is incapable of underlining, but is capable of a standout mode then that is used instead. If the terminal can overstrike, @@ -81,7 +81,7 @@ The .Ev TERM variable is used to relate a tty device with its device capability description (see -.Xr termcap 5 ) . +.Xr terminfo 5 ) . .Ev TERM is set at login time, either by the default terminal type specified in diff --git a/text-utils/ul.c b/text-utils/ul.c index 75e6f95c..4d3cf262 100644 --- a/text-utils/ul.c +++ b/text-utils/ul.c @@ -41,7 +41,26 @@ static char copyright[] = static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ +/* +** modified by Kars de Jong to use terminfo instead +** of termcap. +*/ + #include +#include /* for getopt(), isatty() */ +#include /* for bzero() */ +#include /* for setupterm() */ + +void filter(FILE *f); +void flushln(void); +void overstrike(void); +void iattr(void); +void initbuf(void); +void fwd(void); +void reverse(void); +void initinfo(void); +void outc(int c); +void setmode(int newmode); #define IESC '\033' #define SO '\016' @@ -75,19 +94,15 @@ int halfpos; int upln; int iflag; -int outchar(); -#define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar) +#define PRINT(s) if (s == NULL) /* void */; else putp(s) -main(argc, argv) - int argc; - char **argv; +int main(int argc, char **argv) { extern int optind; extern char *optarg; - int c; + int c, ret; char *termtype; FILE *f; - char termcap[1024]; char *getenv(), *strcpy(); termtype = getenv("TERM"); @@ -110,24 +125,24 @@ main(argc, argv) argv[0]); exit(1); } - - switch(tgetent(termcap, termtype)) { + setupterm(termtype, 1, &ret); + switch(ret) { case 1: break; default: - fprintf(stderr,"trouble reading termcap"); + fprintf(stderr,"trouble reading terminfo"); /* fall through to ... */ case 0: /* No such terminal type - assume dumb */ - (void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:"); + setupterm("dumb", 1, (int *)0); break; } - initcap(); - if ( (tgetflag("os") && ENTER_BOLD==NULL ) || - (tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) + initinfo(); + if ( (tigetflag("os") && ENTER_BOLD==NULL ) || + (tigetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) must_overstrike = 1; initbuf(); if (optind == argc) @@ -140,11 +155,10 @@ main(argc, argv) } else filter(f); } - exit(0); + return 0; } -filter(f) - FILE *f; +void filter(FILE *f) { register c; @@ -256,7 +270,7 @@ filter(f) flushln(); } -flushln() +void flushln() { register lastmode; register i; @@ -295,7 +309,7 @@ flushln() * For terminals that can overstrike, overstrike underlines and bolds. * We don't do anything with halfline ups and downs, or Greek. */ -overstrike() +void overstrike() { register int i; char lbuf[256]; @@ -332,7 +346,7 @@ overstrike() } } -iattr() +void iattr() { register int i; char lbuf[256]; @@ -355,7 +369,7 @@ iattr() putchar('\n'); } -initbuf() +void initbuf() { bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ @@ -364,7 +378,7 @@ initbuf() mode &= ALTSET; } -fwd() +void fwd() { register oldcol, oldmax; @@ -375,7 +389,7 @@ fwd() maxcol = oldmax; } -reverse() +void reverse() { upln++; fwd(); @@ -384,31 +398,24 @@ reverse() upln++; } -initcap() +void initinfo() { - static char tcapbuf[512]; - char *bp = tcapbuf; - char *getenv(), *tgetstr(); - - /* This nonsense attempts to work with both old and new termcap */ - CURS_UP = tgetstr("up", &bp); - CURS_RIGHT = tgetstr("ri", &bp); - if (CURS_RIGHT == NULL) - CURS_RIGHT = tgetstr("nd", &bp); - CURS_LEFT = tgetstr("le", &bp); + char *getenv(), *tigetstr(); + + CURS_UP = tigetstr("cuu1"); + CURS_RIGHT = tigetstr("cuf1"); + CURS_LEFT = tigetstr("cub1"); if (CURS_LEFT == NULL) - CURS_LEFT = tgetstr("bc", &bp); - if (CURS_LEFT == NULL && tgetflag("bs")) CURS_LEFT = "\b"; - ENTER_STANDOUT = tgetstr("so", &bp); - EXIT_STANDOUT = tgetstr("se", &bp); - ENTER_UNDERLINE = tgetstr("us", &bp); - EXIT_UNDERLINE = tgetstr("ue", &bp); - ENTER_DIM = tgetstr("mh", &bp); - ENTER_BOLD = tgetstr("md", &bp); - ENTER_REVERSE = tgetstr("mr", &bp); - EXIT_ATTRIBUTES = tgetstr("me", &bp); + ENTER_STANDOUT = tigetstr("smso"); + EXIT_STANDOUT = tigetstr("rmso"); + ENTER_UNDERLINE = tigetstr("smul"); + EXIT_UNDERLINE = tigetstr("rmul"); + ENTER_DIM = tigetstr("dim"); + ENTER_BOLD = tigetstr("bold"); + ENTER_REVERSE = tigetstr("rev"); + EXIT_ATTRIBUTES = tigetstr("sgr0"); if (!ENTER_BOLD && ENTER_REVERSE) ENTER_BOLD = ENTER_REVERSE; @@ -433,20 +440,13 @@ initcap() * letters the 37 has. */ - UNDER_CHAR = tgetstr("uc", &bp); + UNDER_CHAR = tigetstr("uc"); must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE); } -outchar(c) - int c; -{ - putchar(c & 0177); -} - static int curmode = 0; -outc(c) - int c; +void outc(int c) { putchar(c); if (must_use_uc && (curmode&UNDERL)) { @@ -455,8 +455,7 @@ outc(c) } } -setmode(newmode) - int newmode; +void setmode(int newmode) { if (!iflag) { if (curmode != NORMAL && newmode != NORMAL) diff --git a/version.h b/version.h new file mode 100644 index 00000000..64fb6d81 --- /dev/null +++ b/version.h @@ -0,0 +1,2 @@ +#define UTIL_LINUX 1 +char *util_linux_version="util-linux 2.6";