From: Karel Zak Date: Wed, 6 Dec 2006 23:25:35 +0000 (+0100) Subject: Imported from util-linux-2.8 tarball. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2b6fc908bc368b540845a313c3b8a867c5ad9a42;p=util-linux Imported from util-linux-2.8 tarball. --- diff --git a/ANNOUNCE b/ANNOUNCE index ad02f841..0d762863 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,21 +1,17 @@ -util-linux-2.7.tar.gz (source only distribution) +util-linux-2.8.tar.gz (source only distribution) READ the README file and the stuff below. -util-linux-2.7.tar.gz (source only distribution) +util-linux-2.8.tar.gz (source only distribution) NOTE: Before installing util-linux. READ the README or risk nuking your system. Thank you. 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 +It's primary audience is system integrators (like the people at Debian +and RedHat) and DIY Linux hackers. The rest of you will get a digested version of util-linux installed with no risk to your sanity. - 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. - 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. @@ -24,11 +20,7 @@ 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. -[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.] - -Util-Linux 2.7 is imediately available from +Util-Linux 2.8 is imediately available from ftp.math.uio.no:/pub/linux, and sunsite.uio.no:/pub/unix/linux/packages/util-linux, and will appear at diff --git a/FAQ b/FAQ deleted file mode 100644 index 0eabb0e5..00000000 --- a/FAQ +++ /dev/null @@ -1,11 +0,0 @@ -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 a8b483dd..0906306c 100644 --- a/LSM +++ b/LSM @@ -1,10 +1,10 @@ Begin3 Title: util-linux: Miscellaneous utilities for Linux -Version: 2.7.1 -Description: agetty arch cal cfdisk chfn chkdupexe chroot chsh +Version: 2.8 +Description: agetty arch cal cfdisk chfn chkdupexe chsh clear hwclock col colcrt colrm column ctrlaltdel cytune ddate dmesg dsplit fastboot fasthalt fdformat - fdisk fsck.minix getopt halt hexdump hostid ipcrm ipcs + fdisk fsck.minix getopt halt hexdump 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 @@ -14,12 +14,12 @@ Description: agetty arch cal cfdisk chfn chkdupexe chroot chsh Keywords: essential utilities Author: several -Maintained-by: Nicolai Langfeldt +Maintained-by: Nicolai Langfeldt and others Primary-site: ftp.math.uio.no /pub/linux - ~520k util-linux-2.7.1.tar.gz + ~567k util-linux-2.8.tar.gz Alternate-site: sunsite.uio.no /pub/unix/linux/packages/util-linux -Alternate-site: sunsite.unc.edu /pub/Linux/system/Misc +Alternate-site: sunsite.unc.edu /pub/Linux/system/misc Alternate-site: tsx-11.mit.edu /pub/linux/packages/utils -Platforms: Linux 1.2.x/1.3.x/2.x/Libc 4/5/6 +Platforms: Linux 1.2.x/1.3.x/2.x/Libc 4/5/6, all CPUs Copying-policy: GPL, BSD, others End diff --git a/MAINTAINERS b/MAINTAINERS index 5229601d..623bd520 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7,13 +7,13 @@ This is a partial list of interests: Rik: Founding father Andries: *fdisk, mount, ... -Peter: login, passwd, simpleinit, agetty, last, newgrp, shutdown, hostid, +Peter: login, passwd, simpleinit, agetty, last, newgrp, shutdown, domainname, ctrlaltdel Michael: Spirit of advice Erik: General hackery -Nicolai: mail queue processor (batch oriented) +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 +Unassigned programs (defaulting to Nicolai): chfn, chsh, write, wall, ... diff --git a/MCONFIG b/MCONFIG index 500a3229..2823988e 100644 --- a/MCONFIG +++ b/MCONFIG @@ -2,24 +2,13 @@ # Created: Sat Feb 4 15:50:30 1995 # 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 +# Select for CPU one of intel, alpha, sparc, arm, m68k, mips +CPU=$(shell uname -m | sed s/i.86/intel/) # if HAVE_LIBCRYPT is "yes" -lcrypt will be used HAVE_LIBCRYPT=no -#HAVE_LIBCRYPT=yes +# 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 @@ -91,7 +80,7 @@ HAVE_STRINGS=yes #HAVE_RESET=no HAVE_RESET=yes -# If HAVE_MOUNT is set to "yes", then reset won't be installed, since many +# If HAVE_MOUNT is set to "yes", then mount 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 @@ -113,14 +102,18 @@ endif BSD= ../bsd LDFLAGS = -s -# WARNFLAGS = -Wall -CFLAGS = $(OPT) -I. -I$(BSD) $(WARNFLAGS) $(CURSESFLAGS) $(EXTRACFLAGS) \ +WARNFLAGS = -Wall +CFLAGS = $(OPT) -I. -I$(BSD) $(WARNFLAGS) $(CURSESFLAGS) $(SLANGFLAGS) \ + $(EXTRACFLAGS) \ -DSBINDIR=\"$(SBINDIR)\" \ -DUSRSBINDIR=\"$(USRSBINDIR)\" \ -DLOGDIR=\"$(LOGDIR)\" \ -DVARPATH=\"$(VARPATH)\" -# +# Set HAVE_NCURSES to "yes" if you have ncurses +# (without it, more, ul and setterm are not made) +HAVE_NCURSES=yes + # ncurses appears to be installed in three major ways. # # There is a subdirectory /usr/include/ncurses, with curses.h in @@ -133,6 +126,16 @@ CFLAGS = $(OPT) -I. -I$(BSD) $(WARNFLAGS) $(CURSESFLAGS) $(EXTRACFLAGS) \ CURSESFLAGS=-DNCH=0 LIBCURSES=-lncurses +# Set HAVE_SLANG to yes if you have slang (and prefer to use that for cfdisk) +# (If neither HAVE_NCURSES nor HAVE_SLANG is defined, cfdisk is not made.) +# HAVE_SLANG=yes + +# There is a subdirectory /usr/include/slang containing slcurses.h +# SLANGFLAGS=-I/usr/include/slang +# No such subdirectory - slcurses.h lives in /usr/include +# (no extra definition required). +LIBSLANG=-lslang + DEVDIR= $(DESTDIR)/dev ETCDIR= $(DESTDIR)/etc SBINDIR= $(DESTDIR)/sbin diff --git a/Makefile b/Makefile index a9244ab1..5bbbdc25 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ # May be distributed under the terms of the GNU GPL. # -VERSION=2.7.1 +VERSION=2.8 include ./MCONFIG @@ -14,6 +14,7 @@ ifeq "$(HAVE_MOUNT)" "no" endif SUBDIRS= bsd \ + getopt \ disk-utils \ games \ login-utils \ diff --git a/Notes.pre1995 b/Notes.pre1995 deleted file mode 100644 index cb9ed444..00000000 --- a/Notes.pre1995 +++ /dev/null @@ -1,386 +0,0 @@ -HIGHLIGHTS for version 1.10: -1) domainname is no longer installed. The source for domainname is still - included in the source distribution, as is the hostname-1.5 package, by - Peter Tobias (tobias@server.et-inf.fho-emden.de), which contains a new - hostname and a dnsdomainname program. If you have any questions read - the documentation in hostname-1.5 and NetKit-A. -2) Alan Modra (alan@spri.levels.unisa.edu.au) updated syslogd and clock. -3) Joe Ragland (jrr@interpath.net) updated whereis.1 -4) Kai Petzke (wpp@marie.physik.tu-berlin.de) updated setserial.8 -5) Michael K. Johnson (johnsonm@nigel.vnet.net) updated tunelp -6) Carl Christofferson (cchris@connected.com) updated col -7) bjdouma@xs4all.nl updated rev -8) Lots of updates to mount: without -t, (null) is no longer entered in - mtab; readonly file systems are now remounted readonly if they weren't - the first time; you can mount loop devices; umount will send RPC calls - to the NFS server. -9) agetty, login, hostid updated. - - -HIGHLIGHTS for version 1.9: - -1) Miscellaneous bug fixes by Dave Gentzel (gentzel@nova.enet.dec.com) and - Sander van Malssen (svm@kozmix.hacktic.nl) -2) tunelp has been added -3) selection now allows the mouse pointer to wrap (this is off by default) - (Thanks to Sander van Malssen (svm@kozmix.hacktic.nl).) -4) Many old versions have been removed, making the source distribution - smaller. - - -HIGHLIGHTS for version 1.8: - -1) bdflush is now installed as update (WARNING!). -2) MAKEDEV was updated. This version uses /proc/devices. -3) Minor corrections (thanks to Dave Gentzel). -4) Nigel Gamble's lpcntl is included. - - -HIGHLIGHTS for version 1.7: - -0) A small, static sln (ln substitute) and a small, static sync(1) are - now included. -1) The mkswap(8) man page was fixed (wpp@marie.physik.tu-berlin.de (Kai - Petzke)) -2) hostname and pwd are no longer installed -- they are in FSF's - sh-util-1.10 -3) uuencode and uudecode are no longer installed -- they are in FSF's - uuencode-1.0 -4) ed is no longer installed -- it is in FSF's ed-0.1 -5) The C version of sync was replaced by an assembly version (by Nick - Holloway) -6) setterm was updated to work with dosemu -7) Various security holes were fixed (login, passwd, agetty, etc.) -8) A few other random things were updated. -9) Many 4.3BSD-reno (NET-2) utilities were replaced with the 4.4BSD-Lite - versions. -10) update has been removed. /sbin/update is now a link to /sbin/bdflush. -11) syslogd moved form /sbin to /usr/sbin, to conform to the FSSTND. -12) mount will use /proc/filesystems if no -t option is given (from - Adam J. Richter (adam@adam.yggdrasil.com)). - - -HIGHLIGHTS for version 1.6: - -Additions: - -1) Kevin Martin's cfdisk: a curses based fdisk! -2) Eric Youngdale's bdflush -3) sln: a statically linked (and very stupid) ln -4) getopt(1) - -Deletions: -1) doshell hasn't been needed for years (since before 0.98 when getty - didn't exist). I have deleted it. -2) To avoid horrible confusion, ldd and ldconfig have been removed. Find - them in David Engel's ldso package. - -Updates: -1) Softlinks are now relative. -2) The backspace problem with agetty is fixed. -3) "maintenance" is now spelled correctly. -4) The example files have been updated. -5) Per Kang-Jin Lee's (lee@tengu.in-berlin.de) suggestion, there is now an - "install.shadow" target that will *NOT* overwrite chsh, login, newgrp, - and passwd. There is no other shadow password support. -6) Timezone support totally updated (zic and zdump moved to /usr/sbin) -7) mount man page updated per Remy Card (Remy.Card@masi.ibp.fr) -8) MAKEDEV has been updated -9) sync is now statically linked -10) fdisk 1.5 was patched to support DOS and OS/2 partitions. - - - - -Notes: - -0) This package is the union of my util-etc, util-bin, and util-usrbin - packages. Trying to comply with the draft file system standard was too - much of a headache when these utilities were all in different pacakges. - -1) The clock program from the timesrc-1.2.tar.Z package is included. The - rest of this distribution has been replaced by the ado@elsie.nci.nih.gov - version. See below for details. - - Patches from Hamish Coleman (hamish@zot.apana.org.au) have been applied - to the clock program, making it version 1.2a. See clock.c for details. - These patches "stuff things up" if your cmos clock is not in universal - time, so they have been removed. - - Version 1.3 is updates from Alan Modra (alan@spri.levels.unisa.edu.au). - These were also reverted because they break if your cmos clock is not in - universal time. Version 1.3 source is in the broken subdirectory in - case anyone wants to fix this. - -2) The time directory contains tzcode94e.tar.gz and tzdata94d.tar.gz from - elsie.nci.nih.gov. - -3) Peter Orbaek (poe@daimi.aau.dk) put together the admutil-1.11.tar.gz - package. The following are from that collection: - - ctrlaltdel (by Peter Orbaek) - - shutdown (by Peter Orbaek, - with new modifications by Stephen Tweedie and Rik Faith) - - passwd (by Peter Orbaek) - - newgrp (by Michael Haardt with modifications by Peter Orbaek) - - chsh (by Peter Orbaek) - - last (BSD 5.11 6/29/88) Port by Michael Haardt with changes by - Peter Orbaek. - - I applied a patch to passwd from Markus Armbruster - which allows non-lettters to be used in the - password instead of digits. - -4) Peter Orbaek (poe@daimi.aau.dk) put together the poeigl-1.29.tar.gz - package. The following are from that collection: - - agetty (by W.Z. Venema ) - - simpleinit (by Peter Orbaek) - - domainname (by Peter Orbaek) - - login (BSD 5.40 5/9/89) Ported to HP-UX by Michael Glad, - ported to Linux by Peter Orbaek) - - hostid (by Mitchum DSouza) - - Thanks to Christian von Roques (roques@juliet.ka.sub.org), Bill - Reynolds (bill@goshawk.lanl.gov), Sander van Malssen - (svm@kozmix.hacktic.nl), David A. Holland (dholland@husc.harvard.edu) - and others who sent in several patches. These were forwarded to Peter. - -5) Jim Winstead Jr. (jwinstea@fenris.claremont.edu) put together the - system-0.98.tar.Z package. The following are from that collection: - - doshell (by Jim Wiegand, - with modifications by Marcel Mol (marcel@dutecad.et.tudelft.nl)) - - fdformat (by Werner Almesberger (almesber@nessie.cs.id.ethz.ch), - with modifications by Marcel Mol (marcel@dutecad.et.tudelft.nl)) - -- Actually, updated with a September 1992 version by Werner. - - frag (by Werner Almesberger (V1.0), with modifications - by Steffen Zahn (V1.1), - by Rob Hooft (V1.2), - and by Steffen Zahn (szahn%masterix@emndev.siemens.co.at)) - - setfdprm (by Werner Almesberger (almesber@nessie.cs.id.ethz.ch)) - - sync (by Nick Holloway, with thanks to James Bonfield) -- a small, - assembly language version replaces the old C language version by - Linus Torvalds (torvalds@cs.helsinki.fi) - - ed.old (by Brian Beattie, Kees Bot, and others; with changes by - W. Metzenthen) -- For utilb, this was edited to provide larger - constants (4096 characters per line, etc.) which are needed by - X11R5 for make depend. - - more (BSD 5.19 6/28/88) by Eric Shienbrood, with - modifications by Geoff Peck and John Foderaro) - - kill (by Peter MacDonald) - -6) Rick Sladkey put together the mount-0.99.6.tar.Z package, and Stephen - Tweedie provided updates. The following are from that package (all - appear to be by Doug Quale (quale@saavik.cs.wisc.edu), with - modifications by H. J. Lu (hlu@eecs.wsu.edu) on 11/25/92; Rick Sladkey - (jrs@world.std.com) in January 1993; and Stephen Tweedie - on 8 October 1993: - - mount - umount - swapon - - This distribution mount now supports NFS stuff. I have modified the man - pages. I have also added a small patch from Hamish Glen Coleman - (t933093@minyos.xx.rmit.OZ.AU) which restores the -o semantics. - - Updated with Rick Sladkey's mount-0.99.14.tar.gz package, and with - extra patches from Rick. - - Adam J. Richter allowed -t option to be optional. - - Patrick J. Volkerding (volkerdi@mhd1.moorhead.msus.edu) and Mitchum - DSouza both provided patches that fixed the (null) problem when not - using -t. - - Mitchum DSouza (mitch@mrc-applied-psychology.cambridge.ac.uk) added - support for loop device mounts. - - Sebastian Lederer (lederer@next-pc.informatik.uni-bonn.de) added - support for sending an unmount RPC call to the server when an - NFS-filesystem is unmounted. - - Sander van Malssen (svm@kozmix.hacktic.nl) added support for remounting - readonly file systems readonly. - -7) The rdev program is original work by Werner Almesberger - (almesber@nessie.cs.id.ethz.ch), modified by Peter MacDonald and Stephen - Tweedie. - -8) I (Rik Faith) wrote: - - kbdrate - clear - reset (updated to call 'stty sane' first) - look - - most of the man pages - -9) Linus Torvalds (torvalds@cs.helsinki.fi) released new versions of - fsck.c, mkfs.c, and mkswap.c in February 1993. This fsck and mkfs - support 14 *and* 30 character minux filesystems! - - fsck HAS BEEN RENAMED TO fsck.minix! TAKE NOTE! This change is for - compatibility with the fsutil package. The return codes have also been - fixed for compatibility with the fsutil package. - - fsck.minix and mkfs.minix have been updated by Rik Faith - (faith@cs.unc.edu), Scott Heavner (sdh@po.cwru.edu), and Dr. Wettstein - (greg%wind.uucp@plains.nodak.edu). - -10) David Engel (david@ods.com) put together the fsutil-1.8.tar.gz package, - which contains a generic front-end for fsck and mkfs. This package has - been included in this release. He also did lfconfig, which is from his - ldso-1.3.tar.z package. - -11) Michael K. Johnson (johnsonm@stolaf.edu) re-released Rick Sladkey's - setserial in January 1993, with changes by Theodore Ts'o - (tytso@mit.edu). I think that Theodore also did extensive changes for - version 2.01, I can't find any notes about this in the documentation. - However, Theodore Ts'o (tytso@ATHENA.MIT.EDU) released version 2.10, - and that is now included. - -12) I applied enhancments and bug fixes to the fdisk (by A. V. Le Blanc - (LeBlanc@mcc.ac.uk)) in Jim Winstead Jr.'s - (jwinstea@fenris.claremont.edu) system-0.98.tar.Z package. Owen - (LeBlanc) then re-enhanced the version and added bug fixes. He also - gave me a copy of the excellent documentation: see README.fdisk. I - have replaced this old version with Owen's fdisk 1.5 release, with - Kevin Martin's patches for DOS and OS/2 compatibility. I've called - this version 1.5a. Then I changed a few partition names, and called it - 1.5b. Since Kevin's changes were significant, it should probably have - been called 1.6. . . - -13) Added ipcs and ipcrm from the ipcdelta.tar.z distribution by krishna - balasub@cis.ohio-state.edu on 3/15/93. I also took the ipc.info and - ipc.texi files from that distribution. I wrote short man pages for the - binaries. - -14) The new dmesg program from Theodore Ts'o is also included, with a man - page that I wrote, and changes from Rick Sladkey. - -15) The complete selection-1.5 package, by Andrew Haylett - , 17th June 1993, is included. Kernel patches are - no longer necessary for modern kernels, but these were tiny so I left - them in for historical reasons. The Makefile was modified for this - distribution. With changes from Rick Sladkey. - -16) A posix-compliant ed is now in ed.posix, and is used by default. See - the README and source for authorship information and other credits, - including The Regents of the University of California; Rodney Ruddock - of the University of Guelph, Guelph, Ontario; Matt Bishop of Dartmouth - College, Hanover, NH; and Addison-Wesley Publishing Company. The code - is based on B. W. Kernighan and P. J. Plauger, SOFTWARE TOOLS IN - PASCAL, Addison-Wesley, 1981. - -17) Gordon Irlam (gordoni@cs.ua.oz.au) did setterm, which was adapted to - Linux by Peter MacDonald and enhanced by Mika Liljeberg - (liljeber@cs.Helsinki.FI). A bunch of patches from John Walder - (j-walder@uiuc.edu) were applied so that setterm will work with dosemu. - -18) Several utilities are from the BSD NET-2 (4.3bsd-reno) distribution: - - col (5.3 (Berkeley) 2/2/91) - [See README.col for comments, and differences other cols] - hexdump (5.5 (Berkeley) 6/1/90) - rev (5.2 (Berkeley) 3/21/92, with modifications for Linux by - Charles Hannum (mycroft@gnu.ai.mit.edu) and Brian - Koehmstedt (bpk@gnu.ai.mit.edu)) - strings (5.10 (Berkeley) 5/23/91) - syslogd (5.45 (Berkeley) 3/2/91) [with ttymsg; see below for changes] - tsort (5.3 (Berkeley) 6/1/90) - wall (5.14 (Berkeley) 3/2/91) - whereis (5.5 (Berkeley) 4/18/91) - write (4.22 (Berkeley) 6/1/90) - - Most of the changes for syslogd come from Rick Sladkey - (jrs@world.std.com), but I'd like to thank other people who sent in - changes (which usually got forwarded to Rick): Carsten Paeth - (calle@calle.in-berlin.de) and Kaz Sasayama (kaz@lilia.iijnet.or.jp). - - Original NET-2 source is currently available at - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin}. The only changes - that where made to these sources were that more reasonable paths were - placed in the whereis program and that internationalization support was - added to some programs. These changes can be found by grep'ing for - "linux" in the source file, or by comparing the source file with the - original source. Other patches have been applied as they became - available. The best way to find out how the programs were patched is - to get the original source and do a diff. It is far too much overhead - for me to track these diffs individually. - - The getopt(3) from the NET-2 distribution is included, and is linked - with BSD NET-2 programs that use getopt(3). The BSD getopt behaves - differently from the standard GNU getopt. Please do *NOT* try to use - the GNU getopt for programs which require BSD getopt, since this may - change the program's behavior when a single '-' is given as an option. - The man page for getopt(3) is included for reference in the source - distribution, but is *NOT* installed in /usr/man/man3. - - Other changes that seemed significant: - - string.c needed a ':' after the 'n' in the getopt call. - -19) Several utilities are from the 4.4BSD-Lite distribution: - - banner (8.3 (Berkeley) 4/2/94) - column (8.3 (Berkeley) 4/2/94) - colcrt (8.1 (Berkeley) 6/6/93) - cal (8.4 (Berkeley) 4/2/94) [See README.cal for algorithm details] - logger (8.1 (Berkeley) 6/6/93) - look (8.1 (Berkeley) 6/14/93) - renice (8.1 (Berkeley) 6/9/93) - ul (8.1 (Berkeley) 6/6/93) - - To find the modifications, look for __linux__. The original sources - are available for ftp from: - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - -20) Rick Sladkey (jrs@world.std.com) ported: - - script (BSD 5.13 3/5/91) - - with a small patch from Harald Koenig - (koenig@nova.tat.physik.uni-tuebingen.de) to fixes the problem of - script terminating unexpectedly. - -21) Miquel van Smoorenburg (miquels@htsa.aha.nl, - miquels@drinkel.nl.mugnet.org) put together a sysvinit.tar.Z package. - One utility was taken from that collection: - - mesg - -22) MAKEDEV is Nick Holloway 's latest, version - 2.0, with patches from Dave Gentzel (gentzel@nova.enet.dec.com). - -23) sln by Mike Parker and David MacKenzie (from Linux's libc) - -24) bdflush 1.4, by Eric Youngdale. - -25) getopt is from the NetBSD distribution on - jhunix.hcf.jhu.edu - (/pub/public_domain_software/NetBSD/usr/src/usr.bin/getopt) - -26) cfdisk is from Kevin Martin's cfdisk-0.8.tar.gz *BETA* distribution. - -27) lpcntl from Nigel Gamble (nigel@gate.net), Mon, 18 Jul 94 20:17:35 EDT. - -28) tunelp (by Michael K. Johnson (johnsonm@sunsite.unc.edu)) added from - tunelp-1.1 diff --git a/README b/README index 75c54d6d..cf30bf0a 100644 --- a/README +++ b/README @@ -1,8 +1,10 @@ -util-linux 2.7 +util-linux 2.8: WARNING: THE PROGRAMS IN THIS SUITE DO *NOT* SUPPORT SHADOW PASSWORD FILES! + UNLESS YOU USE PAM. -WARNING: THIS COLLECTION DOES *NOT* SUPPORT SYSTEM V INITTAB. +WARNING: THIS COLLECTION CONFLICTS WITH SYSTEM V INITTAB. + UNLESS YOU CONFIGURE IT NOT TO. WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! @@ -16,11 +18,12 @@ WARNING: The simpleinit and some other programs in this package are 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.7.tar.gz in /usr/src -3) cd util-linux-2.7 +2) Untar util-linux-2.8.tar.gz in /usr/src +3) cd util-linux-2.8 4) Edit MCONFIG 5) make 6) make install @@ -30,6 +33,32 @@ To install from source: 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. +HIGHLIGHTS for version 2.8: + +0a) It's been way to long since the last release. My fault. +0b) NO PAM patches. +1) New programs: + - getopt(1) by Frodo Looijaard replaces the older bsd based version. + Keywords: Backward compatible, supports --long options. +1) Removed programs: + - chroot: is no longer in util-linux. Get it free with GNU sh-utils + - frag: + - lpcntl: This was removed in an earlier release (2.7) but I forgot to + mention it. + - hostid: No-one could figure out the right way for this program to + work. Another hostid program is included in poeigl + (see the LSM, Primary-site: ftp.daimi.aau.dk /pub/linux/poe) +2) Various portability enhancements. Among other things hwclock now works + a lot better on non Intel architectures. Should compile with libc 4, 5 + and 6 as well as old and recent kernels. People using non-intel hardware + are encouraged to send patches. +3) rev now only limits linelength to memory capacity +4) dmesg now uses a buffer that matches the kernel buffer in size (8KB) +0xF) Send questions and/or patches to util-linux@math.uio.no + + +util-linux 2.7: + HIGLIGHTS for version 2.7: 1) util-linux now _requires_ ncurses. Several programs are completely @@ -51,7 +80,7 @@ HIGLIGHTS for version 2.7: - Should work with libc 4, 5 and 6 (gnulibc), on m68k, intel, alpha and sparc. -4) Problems.: +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: diff --git a/bsd/err.c b/bsd/err.c index d171530e..2731a714 100644 --- a/bsd/err.c +++ b/bsd/err.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ - #include #include #include diff --git a/bsd/getopt.c b/bsd/getopt.c index 7126cc1d..be621bd9 100644 --- a/bsd/getopt.c +++ b/bsd/getopt.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)getopt.c 4.13 (Berkeley) 2/23/91"; -#endif /* LIBC_SCCS and not lint */ - #include #include #include diff --git a/disk-utils/Makefile b/disk-utils/Makefile index fac3134b..d21cedb9 100644 --- a/disk-utils/Makefile +++ b/disk-utils/Makefile @@ -10,29 +10,53 @@ include ../MCONFIG MAN8= fdformat.8 mkswap.8 setfdprm.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= mkfs mkswap +USRBIN= fdformat setfdprm + +ETC= fdprm + ifneq "$(CPU)" "sparc" -SBIN:=$(SBIN) fdisk cfdisk sfdisk fsck.minix mkfs.minix +# fsck and mkfs will compile, but there is no kernel support on sparc +MAN8:=$(MAN8) fsck.minix.8 mkfs.8 mkfs.minix.8 +SBIN:=$(SBIN) fsck.minix mkfs.minix +ifneq "$(CPU)" "m68k" +MAN8:=$(MAN8) fdisk.8 cfdisk.8 sfdisk.8 +SBIN:=$(SBIN) fdisk cfdisk sfdisk +endif +else +MAN8:=$(MAN8) fdisk.8 +SBIN:=$(SBIN) fdisk endif - -USRBIN= fdformat setfdprm # Where to put datebase files? -ETC= fdprm +all: $(SBIN) $(USRBIN) -all: $(SBIN) $(USRBIN) +cfdisk.o: cfdisk.c +ifeq "$(HAVE_SLANG)" "yes" + $(CC) -c $(CFLAGS) -DSLCURSES=1 $< -o $@ +else +ifeq "$(HAVE_NCURSES)" "yes" + $(CC) -c $(CFLAGS) $< -o $@ +else + : +endif +endif cfdisk: cfdisk.o llseek.o +ifeq "$(HAVE_SLANG)" "yes" + $(CC) $(LDFLAGS) $^ -o $@ $(LIBSLANG) +else +ifeq "$(HAVE_NCURSES)" "yes" $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) -lm +else + @echo $@ not made since it requires ncurses or slang +endif +endif # not installed by default activate: sfdisk @@ -42,8 +66,6 @@ activate: sfdisk # 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 @@ -51,6 +73,15 @@ mkfs.minix: mkfs.minix.o mkfs.minix.o: mkfs.minix.c bitops.h mkswap: mkswap.o setfdprm: setfdprm.o +sfdisk: sfdisk.o + +ifeq "$(CPU)" "sparc" +fdisk: fdisk.o fdisklabel.o fdisksunlabel.o llseek.o +fdisksunlabel.o: fdisksunlabel.c fdisksunlabel.h fdisk.h +else +fdisk: fdisk.o fdisklabel.o llseek.o +endif + fdisk.o: fdisk.c fdisk.h fdisklabel.o: fdisklabel.c fdisk.h fdisklabel.h diff --git a/disk-utils/cfdisk.8 b/disk-utils/cfdisk.8 index 010c370d..c7ac9417 100644 --- a/disk-utils/cfdisk.8 +++ b/disk-utils/cfdisk.8 @@ -120,18 +120,14 @@ format the partition. For example, if you were using cfdisk to make a DOS partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk 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. +the first 512 bytes of the partition. Note: .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 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/cfdisk.c b/disk-utils/cfdisk.c index 1b87aae7..f0b5482f 100644 --- a/disk-utils/cfdisk.c +++ b/disk-utils/cfdisk.c @@ -29,7 +29,9 @@ * >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 + * Versions 0.8e-l: aeb@cwi.nl + * Recognition of NTFS / HPFS difference inspired by patches + * from Marty Leisner * ****************************************************************************/ @@ -41,12 +43,22 @@ #include #include #include -#include +#ifdef SLCURSES + #include +#else +#if NCH + #include +#else + #include +#endif +#endif #include #include +#include #include #include #include +#include #include #include #include /* for BLKRRPART */ @@ -60,7 +72,7 @@ typedef long ext2_loff_t; extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, unsigned int origin); -#define VERSION "0.8i" +#define VERSION "0.8l" #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" @@ -78,12 +90,14 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, #define PART_TABLE_FLAG 0xAA55 #define UNUSABLE -1 -#define FREE_SPACE 0x00 -#define DOS_EXTENDED 0x05 +#define FREE_SPACE 0x00 +#define DOS_EXTENDED 0x05 +#define OS2_OR_NTFS 0x07 +#define WIN98_EXTENDED 0x0f #define LINUX_EXTENDED 0x85 -#define LINUX_MINIX 0x81 -#define LINUX_SWAP 0x82 -#define LINUX 0x83 +#define LINUX_MINIX 0x81 +#define LINUX_SWAP 0x82 +#define LINUX 0x83 #define ADD_EXISTS "This partition is already in use" #define ADD_UNUSABLE "This partition is unusable" @@ -157,10 +171,13 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, s |= (sector >> 2) & 0xC0;\ } -#define is_extended(x) ((x) == DOS_EXTENDED || (x) == LINUX_EXTENDED) +#define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_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 may_have_dos_label(x) (is_dos_partition(x) \ + || (x) == 7 || (x) == 0xb || (x) == 0xc || (x) == 0xe \ + || (x) == 0x11 || (x) == 0x14 || (x) == 0x16 || (x) == 0x17) #define ALIGNMENT 2 typedef union { @@ -183,8 +200,12 @@ 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]; +#define LABELSZ 16 + char volume_label[LABELSZ+1]; +#define OSTYPESZ 8 + char ostype[OSTYPESZ+1]; +#define FSTYPESZ 8 + char fstype[FSTYPESZ+1]; } partition_info; char *disk_device = DEFAULT_DEVICE; @@ -227,8 +248,9 @@ int COMMAND_LINE_Y = 21; /* X coordinates */ int NAME_START = 4; int FLAGS_START = 16; -int PTYPE_START = 30; -int FSTYPE_START = 45; +int PTYPE_START = 28; +int FSTYPE_START = 38; +int LABEL_START = 54; int SIZE_START = 70; int COMMAND_LINE_X = 5; @@ -241,9 +263,13 @@ char *partition_type[NUM_PART_TYPES] = { [DOS_EXTENDED]= "Extended", [LINUX_EXTENDED] = "Linux extended", [0x01] = "DOS FAT12", + [0x02] = "XENIX root", + [0x03] = "XENIX usr", [0x04] = "DOS FAT16", [0x06] = "DOS FAT16 (big)", - [0x07] = "OS/2 HPFS or NTFS", + [OS2_OR_NTFS] = "OS/2 HPFS or NTFS", + [0x08] = "AIX", + [0x09] = "AIX bootable", [0x0A] = "OS/2 Boot Manager", [0x0B] = "Win95 FAT32", [0x0C] = "Win95 FAT32 (LBA)", @@ -252,17 +278,7 @@ char *partition_type[NUM_PART_TYPES] = { [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) - * fdisk program. I do not know where they came from, but I include - * them for completeness. (With additions.) - */ - - [0x02] = "XENIX root", - [0x03] = "XENIX usr", - [0x08] = "AIX", - [0x09] = "AIX bootable", + [0x17] = "Hidden OS/2 HPFS or NTFS", [0x40] = "Venix 80286", [0x51] = "Novell?", [0x52] = "Microport", @@ -273,6 +289,9 @@ char *partition_type[NUM_PART_TYPES] = { [0x80] = "Old MINIX", [0x93] = "Amoeba", [0x94] = "Amoeba BBT", + [0xA5] = "BSD/386", + [0xA6] = "OpenBSD", + [0xA7] = "NEXTSTEP", [0xB7] = "BSDI fs", [0xB8] = "BSDI swap", [0xC7] = "Syrinx", @@ -283,6 +302,37 @@ char *partition_type[NUM_PART_TYPES] = { [0xFF] = "BBT" }; +/* Some libc's have their own basename() */ +char *my_basename(char *devname) +{ + char *s = rindex(devname, '/'); + return s ? s+1 : devname; +} + +char *partition_type_text(int i) +{ + if (p_info[i].id == UNUSABLE) + return "Unusable"; + else if (p_info[i].id == FREE_SPACE) + return "Free Space"; + else if (p_info[i].id == LINUX) { + if (!strcmp(p_info[i].fstype, "ext2")) + return "Linux ext2"; + else + return "Linux"; + } else if (p_info[i].id == OS2_OR_NTFS) { + if (!strncmp(p_info[i].fstype, "HPFS", 4)) + return "OS/2 HPFS"; + else if (!strncmp(p_info[i].ostype, "OS2", 3)) + return "OS/2 IFS"; + else if (!p_info[i].ostype) + return p_info[i].ostype; + else + return "NTFS"; + } else + return partition_type[p_info[i].id]; +} + void fdexit(int ret) { if (opened) @@ -416,7 +466,12 @@ void die_x(int ret) { signal(SIGINT, old_SIGINT); signal(SIGTERM, old_SIGTERM); +#ifdef SLCURSES + SLsmg_gotorc(LINES-1, 0); + SLsmg_refresh(); +#else mvcur(0, COLS-1, LINES-1, 0); +#endif nl(); endwin(); printf("\n"); @@ -439,21 +494,65 @@ void write_sector(char *buffer, int sect_num) fatal(BAD_WRITE); } +void dos_copy_to_info(char *to, int tosz, char *from, int fromsz) { + int i; + + for(i=0; i 0) { mvprintw(y, NAME_START, - "%s%d", disk_device, p_info[i].num+1); + "%s%d", my_basename(disk_device), p_info[i].num+1); if (p_info[i].flags) { if (p_info[i].flags == ACTIVE_FLAG) mvaddstr(y, FLAGS_START, "Boot"); @@ -2022,18 +2144,18 @@ void draw_partition(int i) (p_info[i].num >= 0 ? "Primary" : (p_info[i].num == PRI_OR_LOG ? "Pri/Log" : (p_info[i].num == PRIMARY ? "Primary" : "Logical")))))); - if (p_info[i].id == UNUSABLE) - mvaddstr(y, FSTYPE_START, "Unusable"); - else if (p_info[i].id == FREE_SPACE) - mvaddstr(y, FSTYPE_START, "Free Space"); - else if (partition_type[p_info[i].id]) - mvaddstr(y, FSTYPE_START, partition_type[p_info[i].id]); + + t = partition_type_text(i); + if (t) + mvaddstr(y, FSTYPE_START, t); else - mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + 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); + if (p_info[i].volume_label[0]) { + int l = strlen(p_info[i].volume_label); + int s = SIZE_START-5-l; + mvprintw(y, (s > LABEL_START) ? LABEL_START : s, + " [%s] ", p_info[i].volume_label); } size = p_info[i].last_sector - p_info[i].first_sector + 1; @@ -2056,6 +2178,7 @@ void init_const(void) FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; + LABEL_START = (((float)LABEL_START)/COLUMNS)*COLS; SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; @@ -2101,8 +2224,9 @@ void draw_screen(void) mvaddstr(DISK_TABLE_START, NAME_START, "Name"); mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags"); - mvaddstr(DISK_TABLE_START, PTYPE_START, "Part Type"); + mvaddstr(DISK_TABLE_START, PTYPE_START-1, "Part Type"); mvaddstr(DISK_TABLE_START, FSTYPE_START, "FS Type"); + mvaddstr(DISK_TABLE_START, LABEL_START+1, "[Label]"); if (display_units == SECTORS) mvaddstr(DISK_TABLE_START, SIZE_START, " Sectors"); else if (display_units == CYLINDERS) @@ -2178,6 +2302,8 @@ void do_curses_fdisk(void) }; curses_started = 1; initscr(); + init_const(); + old_SIGINT = signal(SIGINT, die); old_SIGTERM = signal(SIGTERM, die); #ifdef DEBUG @@ -2189,8 +2315,6 @@ void do_curses_fdisk(void) noecho(); nonl(); - init_const(); - fill_p_info(); draw_screen(); @@ -2353,6 +2477,8 @@ int main(int argc, char **argv) char c; int i, len; + setlocale(LC_CTYPE, ""); + while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) switch (c) { case 'a': @@ -2429,5 +2555,6 @@ int main(int argc, char **argv) print_part_table(); } else do_curses_fdisk(); + return 0; } diff --git a/disk-utils/fdisk.8 b/disk-utils/fdisk.8 index 29d56c40..576bce2e 100644 --- a/disk-utils/fdisk.8 +++ b/disk-utils/fdisk.8 @@ -1,20 +1,50 @@ .\" Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) +.\" Copyright 1998 Andries E. Brouwer (aeb@cwi.nl) .\" May be distributed under the GNU General Public License -.TH FDISK 8 "3 June 1995" "Linux 1.0" "Linux Programmer's Manual" +.TH FDISK 8 "11 June 1998" "Linux 2.0" "Linux Programmer's Manual" .SH NAME fdisk \- Partition table manipulator for Linux .SH SYNOPSIS -.B fdisk -.B "[ \-l ] [ \-v ] [ \-s partition] [" -device -.B ] +.BI "fdisk [\-b] [\-u] [" device ] +.sp +.BI "fdisk \-l [\-b] [\-u] [" "device ..." ] +.sp +.BI "fdisk \-s " "partition ..." +.sp +.BI "fdisk \-v .SH DESCRIPTION +Hard disks can be divided into one or more logical disks called +.IR partitions . +This division is described in the +.I "partition table" +found in sector 0 of the disk. + +In the BSD world one talks about `disk slices' and a `disklabel'. + +Linux needs at least one partition, namely for its root file system. +It can use swap files and/or swap partitions, but the latter are more +efficient. So, usually one will want a second Linux partition +dedicated as swap partition. +On Intel compatible hardware, the BIOS that boots the system +can often only access the first 1024 cylinders of the disk. +For this reason people with large disks often create a third partition, +just a few MB large, typically mounted on +.IR /boot , +to store the kernel image and a few auxiliary files needed at boot time, +so as to make sure that this stuff is accessible to the BIOS. +There may be reasons of security, ease of administration and backup, +or testing, to use more than the minimum number of partitions. + .B fdisk -is a menu driven program for manipulation of the hard disk partition table. +(in the first form of invocation) +is a menu driven program for creation and manipulation of +partition tables. +It understands DOS type partition tables and BSD or SUN type disklabels. + The .I device is usually one of the following: -.sp +.br .nf .RS /dev/hda @@ -23,54 +53,79 @@ is usually one of the following: /dev/sdb .RE .fi +(/dev/hd[a-h] for IDE disks, /dev/sd[a-p] for SCSI disks, +/dev/ed[a-d] for ESDI disks, /dev/xd[ab] for XT disks). +A device name refers to the entire disk. + The .I partition is a .I device name followed by a partition number. For example, .B /dev/hda1 -is the first partition on the first hard disk in the system. +is the first partition on the first IDE hard disk in the system. +IDE disks can have up to 63 partitions, SCSI disks up to 15. +See also +.IR /usr/src/linux/Documentation/devices.txt . + +A BSD/SUN type disklabel can describe 8 partitions, +the third of which should be a `whole disk' partition. +Do not start a partition that actually uses its first sector +(like a swap partition) at cylinder 0, since that will +destroy the disklabel. + +A DOS type partition table can describe an unlimited number +of partitions. In sector 0 there is room for the description +of 4 partitions (called `primary'). One of these may be an +extended partition; this is a box holding logical partitions, +with descriptors found in a linked list of sectors, each +preceding the corresponding logical partitions. +The four primary partitions, present or not, get numbers 1-4. +Logical partitions start numbering from 5. + +In a DOS type partition table the starting offset and the size +of each partition is stored in two ways: as an absolute number +of sectors (given in 32 bits) and as a Cylinders/Heads/Sectors +triple (given in 10+8+6 bits). The former is OK - with 512-byte +sectors this will work up to 2 TB. The latter has two different +problems. First of all, these C/H/S fields can be filled only +when the number of heads and the number of sectors per track +are known. Secondly, even if we know what these numbers should be, +the 24 bits that are available do not suffice. +DOS uses C/H/S only, Windows uses both, Linux never uses C/H/S. If possible, .B fdisk -will obtain the disk geometry automatically. This is -.I not -necessarily the -.I physical -disk geometry, but is the disk geometry that MS-DOS uses for the partition -table. If -.B fdisk -warns you that you need to set the disk geometry, please believe this -statement, and set the geometry. This should only be necessary with -certain SCSI host adapters (the drivers for which are rapidly being -modified to provide geometry information automatically). +will obtain the disk geometry automatically. This is not +necessarily the physical disk geometry (indeed, modern disks do not +really have anything like a physical geometry, certainly not something +that can be described in simplistic Cylinders/Heads/Sectors form), +but is the disk geometry that MS-DOS uses for the partition table. + +Usually all goes well by default, and there are no problems if +Linux is the only system on the disk. However, if the disk has +to be shared with other operating systems, it is often a good idea +to let an fdisk from another operating system make at least one +partition. When Linux boots it looks at the partition table, and +tries to deduce what (fake) geometry is required for good +cooperation with other systems. Whenever a partition table is printed out, a consistency check is performed on the partition table entries. This check verifies that the physical and logical start and end points are identical, and that the partition starts and ends on a cylinder boundary (except for the first partition). -Old versions of fdisk (all versions prior to 1.1r [including 0.93]) -incorrectly mapped the cylinder/head/sector specification onto absolute -sectors. This may result in the first partition on a drive failing the -consistency check. If you use LILO to boot, this situation can be ignored. -However, there are reports that the OS/2 boot manager will not boot a -partition with inconsistent data. - Some versions of MS-DOS create a first partition which does not begin on a cylinder boundary, but on sector 2 of the first cylinder. Partitions beginning in cylinder 1 cannot begin on a cylinder boundary, but this is unlikely to cause difficulty unless you have OS/2 on your machine. -In version 1.1r, a BLKRRPART ioctl() is performed before exiting when the -partition table is updated. This is primarily to ensure that removable -SCSI disks have their partition table information updated. If the kernel -does not update its partition table information, fdisk warns you to -reboot. If you do not reboot your system after receiving such a warning, -you may lose or corrupt the data on the disk. Sometimes BLKRRPART fails -silently, when installing Linux, you should -.I always -reboot after editing the partition table. +A sync() and a BLKRRPART ioctl() (reread partition table from disk) +are performed before exiting when the partition table has been updated. +Long ago it used to be necessary to reboot after the use of fdisk. +I do not think this is the case anymore - indeed, rebooting too quickly +might cause loss of not-yet-written data. Note that both the kernel +and the disk hardware may buffer data. .SH "DOS 6.x WARNING" @@ -91,10 +146,6 @@ partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk 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. .B BE EXTREMELY CAREFUL if you use the @@ -108,59 +159,55 @@ program and Linux partitions with the Linux fdisk or Linux cfdisk program. .SH OPTIONS .TP .B \-v -Prints version number of +Print version number of .B fdisk -program. +program and exit. .TP .B \-l -Lists the partition tables for -.BR /dev/hda , -.BR /dev/hdb , -.BR /dev/sda , -.BR /dev/sdb , -.BR /dev/sdc , -.BR /dev/sdd , -.BR /dev/sde , -.BR /dev/sdf , -.BR /dev/sdg , -.BR /dev/sdh , -and then exits. +List the partition tables for +.BR /dev/hd[a-d] , +.BR /dev/sd[a-h] , +.BR /dev/ed[a-d] , +and then exit. .TP -.BI \-s partition -If the -.I partition -is not a DOS partition (i.e., the partition id is greater than 10), then -the +.B \-b +When listing partition tables, also output a `Begin' column, +as earlier versions of fdisk did by default. +(Note: the values in this column, when given in cylinder units, +cannot be larger than 1023. There is nothing wrong if Begin and Start +differ, at least not as far as Linux is concerned.) +.TP +.B \-u +When listing partition tables, give sizes in sectors instead +of cylinders. +.TP +.BI "\-s " partition +The .I size -of that partition is printed on the standard output. This value is -normally used as an argument to the +of the partition (in blocks) is printed on the standard output. +This value is normally used as an argument to the .BR mkfs (8) program to specify the size of the partition which will be formatted. -.SH BUGS -Although this man page (written by faith@cs.unc.edu) is poor, there is -.I excellent -documentation in the README.fdisk file (written by LeBlanc@mcc.ac.uk) that -should always be with the fdisk distribution. If you cannot find this file -in the -.I util-linux-* -directory or with the -.I fdisk.c -source file, then you should write to the distributor of your version of +(Older versions of fdisk would do this only if the partition id is +greater than 10, in an attempt to refuse DOS partitions; +this test has been deleted.) +Note that +.B "sfdisk -s" +gives different (namely, correct) answers. +Reasons for the difference are that the kernel and .B fdisk -and complain that you do not have all of the available documentation. -.SH AUTHOR -A. V. Le Blanc (LeBlanc@mcc.ac.uk) -.br -v1.0r: SCSI and extfs support added by Rik Faith (faith@cs.unc.edu) -.br -v1.1r: Bug fixes and enhancements by Rik Faith (faith@cs.unc.edu), with -special thanks to Michael Bischoff (i1041905@ws.rz.tu-bs.de or -mbi@mo.math.nat.tu-bs.de). -.br -v1.3: Latest enhancements and bug fixes by A. V. Le Blanc, including the -addition of the -.B \-s -option. -.bt -v2.0: Disks larger than 2GB are now fully supported, thanks to Remy Card's -llseek support. +need not have the same idea about partition numbering +(e.g., in case you have BSD slices), and have different +ideas about the size of an extended partition. +.SH BUGS +There are several *fdisk programs around. +Each has its problems and strengths. +Try them in the order +.BR cfdisk , +.BR fdisk , +.BR sfdisk . +.\" .SH AUTHORS +.\" A. V. Le Blanc (LeBlanc@mcc.ac.uk) +.\" Bernhard Fastenrath (fasten@informatik.uni-bonn.de) +.\" Jakub Jelinek (jj@sunsite.mff.cuni.cz) +.\" and many others. diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c index 95b958d8..d99a8b45 100644 --- a/disk-utils/fdisk.c +++ b/disk-utils/fdisk.c @@ -49,7 +49,18 @@ * Tue Sep 26 17:07:54 1995: More patches from aeb. Fix segfaults, all >4GB. * Don't destroy random data if extd partition starts past 4GB, aeb, 950818. * Don't segfault on bad partition created by previous fdisk. - * + * Modified, Fri Jul 14 11:13:35 MET DST 1996, jj@sunsite.mff.cuni.cz: + * editor for Sun disklabels. + * Modified, Wed Jul 3 10:14:17 MET DST 1996, jj@sunsite.mff.cuni.cz: + * support for Sun floppies + * Modified, Thu Jul 24 16:42:33 MET DST 1997, fasten@shw.com: + * LINUX_EXTENDED support + * Added Windows 95 partition types, aeb. + * Fixed a bug described by johnf@whitsunday.net.au, aeb, 980408. + * [There are lots of other bugs - nobody should use this program] + * [cfdisk on the other hand is nice and correct] + * Try to avoid reading a CD-ROM. + * Do not print Begin column -- it confuses too many people -- aeb, 980610. */ @@ -61,14 +72,18 @@ #include #include #include +#include +#include #include -#include -#include -#include +#include /* for HDIO_GETGEO */ +#include /* for BLKRRPART, BLKGETSIZE */ #include "fdisk.h" +#if defined(sparc) +#include "fdisksunlabel.h" +#endif #define hex_val(c) ({ \ char _c = (c); \ @@ -77,14 +92,11 @@ }) -#define VERSION "2.1 (>4GB)" +#define VERSION "2.8" /* util-linux version */ #define DEFAULT_DEVICE "/dev/hda" #define ALTERNATE_DEVICE "/dev/sda" #define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 -#define PART_TABLE_FLAG 0xaa55 -#define table_check(b) ((unsigned short *)((b) + 0x1fe)) #define offset(b, n) ((struct partition *)((b) + 0x1be + \ (n) * sizeof(struct partition))) #define sector(s) ((s) & 0x3f) @@ -101,12 +113,70 @@ s |= (sector >> 2) & 0xc0; \ } +/* A valid partition table sector ends in 0x55 0xaa */ +unsigned int +part_table_flag(char *b) { + return ((uint) b[510]) + (((uint) b[511]) << 8); +} + +int +valid_part_table_flag(unsigned char *b) { + return (b[510] == 0x55 && b[511] == 0xaa); +} + +void +write_part_table_flag(char *b) { + b[510] = 0x55; + b[511] = 0xaa; +} + +/* start_sect and nr_sects are stored little endian on all machines */ +/* moreover, they are not aligned correctly */ +void +store4_little_endian(unsigned char *cp, unsigned int val) { + cp[0] = (val & 0xff); + cp[1] = ((val >> 8) & 0xff); + cp[2] = ((val >> 16) & 0xff); + cp[3] = ((val >> 24) & 0xff); +} + +unsigned int +read4_little_endian(unsigned char *cp) { + return (uint)(cp[0]) + ((uint)(cp[1]) << 8) + + ((uint)(cp[2]) << 16) + ((uint)(cp[3]) << 24); +} + +void +set_start_sect(struct partition *p, unsigned int start_sect) { + store4_little_endian(p->start4, start_sect); +} + +unsigned int +get_start_sect(struct partition *p) { + return read4_little_endian(p->start4); +} + +void +set_nr_sects(struct partition *p, unsigned int nr_sects) { + store4_little_endian(p->size4, nr_sects); +} + +unsigned int +get_nr_sects(struct partition *p) { + return read4_little_endian(p->size4); +} + #define ACTIVE_FLAG 0x80 -#define EXTENDED 5 +#define EXTENDED 0x05 +#define WIN98_EXTENDED 0x0f #define LINUX_PARTITION 0x81 #define LINUX_SWAP 0x82 #define LINUX_NATIVE 0x83 +#define LINUX_EXTENDED 0x85 + +#define IS_EXTENDED(i) \ + ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED) /* normally O_RDWR, -l option gives O_RDONLY */ static int type_open = O_RDWR; @@ -122,6 +192,8 @@ char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ int fd, /* the disk */ ext_index, /* the prime extended partition */ listing = 0, /* no aborts for fdisk -l */ + nowarn = 0, /* no warnings for fdisk -l/-s */ + show_begin = 0, dos_compatible_flag = ~0, partitions = 4; /* maximum partition + 1 */ @@ -135,51 +207,59 @@ uint heads, extended_offset = 0, /* offset of link pointers */ offsets[MAXIMUM_PARTS] = {0, 0, 0, 0}; +int sun_label = 0; /* looking at sun disklabel */ + struct partition *part_table[MAXIMUM_PARTS] /* partitions */ = {offset(buffer, 0), offset(buffer, 1), offset(buffer, 2), offset(buffer, 3)}, *ext_pointers[MAXIMUM_PARTS] /* link pointers */ = {NULL, NULL, NULL, NULL}; -struct systypes sys_types[] = { /* struct systypes in fdisk.h *//* bf */ - {0, "Empty"}, - {1, "DOS 12-bit FAT"}, - {2, "XENIX root"}, - {3, "XENIX usr"}, - {4, "DOS 16-bit <32M"}, - {EXTENDED, "Extended"}, - {6, "DOS 16-bit >=32M"}, - {7, "OS/2 HPFS"}, /* or QNX? */ - {8, "AIX"}, - {9, "AIX bootable"}, - {10, "OS/2 Boot Manager"}, - {0x40, "Venix 80286"}, - {0x51, "Novell?"}, - {0x52, "Microport"}, /* or CPM? */ - {0x63, "GNU HURD"}, /* or System V/386? */ - {0x64, "Novell Netware 286"}, - {0x65, "Novell Netware 386"}, - {0x75, "PC/IX"}, - {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ - - {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */ - {LINUX_SWAP, "Linux swap"}, - {LINUX_NATIVE, "Linux native"}, - - {0x93, "Amoeba"}, - {0x94, "Amoeba BBT"}, /* (bad block table) */ - {0xa5, "BSD/386"}, - {0xb7, "BSDI fs"}, - {0xb8, "BSDI swap"}, - {0xc7, "Syrinx"}, - {0xdb, "CP/M"}, /* or Concurrent DOS? */ - {0xe1, "DOS access"}, - {0xe3, "DOS R/O"}, - {0xf2, "DOS secondary"}, - {0xff, "BBT"} /* (bad track table) */ - }; - -int nsys_types = sizeof (sys_types) / sizeof (struct systypes); /* bf */ +struct systypes sys_types[] = { + {0x00, "Empty"}, + {0x01, "DOS 12-bit FAT"}, + {0x02, "XENIX root"}, + {0x03, "XENIX usr"}, + {0x04, "DOS 16-bit <32M"}, + {0x05, "Extended"}, + {0x06, "DOS 16-bit >=32M"}, + {0x07, "OS/2 HPFS"}, /* or QNX? */ + {0x08, "AIX"}, + {0x09, "AIX bootable"}, + {0x0a, "OS/2 Boot Manager"}, + {0x0b, "Win95 FAT32"}, + {0x0c, "Win95 FAT32 (LBA)"}, + {0x0e, "Win95 FAT16 (LBA)"}, + {0x0f, "Win95 Extended (LBA)"}, + {0x40, "Venix 80286"}, + {0x51, "Novell?"}, + {0x52, "Microport"}, /* or CPM? */ + {0x63, "GNU HURD"}, /* or System V/386? */ + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x75, "PC/IX"}, + {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ + + {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */ + {LINUX_SWAP, "Linux swap"}, + {LINUX_NATIVE, "Linux native"}, + {LINUX_EXTENDED, "Linux extended"}, + + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa5, "BSD/386"}, + {0xa6, "OpenBSD"}, + {0xa7, "NEXTSTEP"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M"}, /* or Concurrent DOS? */ + {0xe1, "DOS access"}, + {0xe3, "DOS R/O"}, + {0xf2, "DOS secondary"}, + {0xff, "BBT"}, /* (bad track table) */ + { 0, NULL } +}; jmp_buf listingbuf; @@ -195,7 +275,10 @@ void fatal(enum failure why) switch (why) { case usage: message = - "Usage: fdisk [-l] [-v] [-s /dev/hdxn] [/dev/hdx]\n"; +"Usage: fdisk [-b] [-u] [/dev/hdx] Change partition table\n" +" fdisk -l [-b] [-u] [/dev/hdx] List partition table(s)\n" +" fdisk -s /dev/hdxn Give partition size(s)\n" +" fdisk -v Give fdisk version\n"; break; case unable_to_open: sprintf(error, "Unable to open %s\n", disk_device); @@ -222,14 +305,35 @@ void fatal(enum failure why) void menu(void) { - puts("Command action\n" + if (sun_label) + puts("Command action\n" + " a toggle a read only flag\n" /* sun */ + " b edit bsd disklabel\n" + " c toggle the mountable flag\n" /* sun */ + " d delete a partition\n" + " l list known partition types\n" + " m print this menu\n" + " n add a new partition\n" + " o create a new empty DOS partition table\n" + " p print the partition table\n" + " q quit without saving changes\n" + " s create a new empty Sun disklabel\n" /* sun */ + " t change a partition's system id\n" + " u change display/entry units\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + " x extra functionality (experts only)" + ); + else + puts("Command action\n" " a toggle a bootable flag\n" - " b edit bsd disklabel\n" /* bf */ + " b edit bsd disklabel\n" " c toggle the dos compatibility flag\n" " d delete a partition\n" " l list known partition types\n" " m print this menu\n" " n add a new partition\n" + " o create a new empty DOS partition table\n" " p print the partition table\n" " q quit without saving changes\n" " t change a partition's system id\n" @@ -237,16 +341,35 @@ void menu(void) " v verify the partition table\n" " w write table to disk and exit\n" " x extra functionality (experts only)" - ); + ); } void xmenu(void) { - puts("Command action\n" - " b move beginning of data in a partition\n" + if (sun_label) + puts("Command action\n" + " a change number of alternate cylinders\n" /* sun */ + " c change number of cylinders\n" + " d print the raw data in the partition table\n" + " e change number of extra sectors per cylinder\n" /*sun*/ + " h change number of heads\n" + " i change interleave factor\n" /* sun */ + " o change rotation speed (rpm)\n" /* sun */ + " m print this menu\n" + " p print the partition table\n" + " q quit without saving changes\n" + " r return to main menu\n" + " s change number of sectors\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + " y change number of physical cylinders" /* sun */ + ); + else + puts("Command action\n" + " b move beginning of data in a partition\n" /* !sun */ " c change number of cylinders\n" " d print the raw data in the partition table\n" - " e list extended partitions\n" + " e list extended partitions\n" /* sun */ " h change number of heads\n" " m print this menu\n" " p print the partition table\n" @@ -255,34 +378,36 @@ void xmenu(void) " s change number of sectors\n" " v verify the partition table\n" " w write table to disk and exit" - ); + ); } char *partition_type(unsigned char type) { - int high = sizeof(sys_types) / sizeof(struct systypes), - low = 0, mid; - uint tmp; - - while (high >= low) { - mid = (high + low) >> 1; - if ((tmp = sys_types[mid].index) == type) - return sys_types[mid].name; - else if (tmp < type) - low = mid + 1; - else high = mid - 1; - } + int i; + struct systypes *types; + +#if defined(sparc) + if (sun_label) + types = sun_sys_types; + else +#endif + types = sys_types; + + for (i=0; types[i].name; i++) + if (types[i].index == type) + return types[i].name; + return NULL; } -/* added parameters to list_types() so fdisklabel - can pass another list of types. -*//* bf */ -void list_types(struct systypes *sys, int size) +void list_types(struct systypes *sys) { - uint last[4], done = 0, next = 0; + uint last[4], done = 0, next = 0, size; int i; + for (i = 0; sys[i].name; i++); + size = i; + for (i = 3; i >= 0; i--) last[3 - i] = done += (size + i - done) / (i + 1); i = done = 0; @@ -309,17 +434,17 @@ void clear_partition(struct partition *p) p->end_head = 0; p->end_sector = 0; p->end_cyl = 0; - p->start_sect = 0; - p->nr_sects = 0; + set_start_sect(p,0); + set_nr_sects(p,0); } void set_partition(int i, struct partition *p, uint start, uint stop, - int sys, uint offset) + int sysid, uint offset) { p->boot_ind = 0; - p->sys_ind = sys; - p->start_sect = start - offset; - p->nr_sects = stop - start + 1; + p->sys_ind = sysid; + set_start_sect(p, start - offset); + set_nr_sects(p, stop - start + 1); if (dos_compatible_flag && (start/(sectors*heads) > 1023)) start = heads*sectors*1024 - 1; set_hsc(p->head, p->sector, p->cyl, start); @@ -380,13 +505,13 @@ void update_units(void) void warn_cylinders(void) { - update_units(); - if (cylinders > 1024) - fprintf(stderr, "The number of cylinders for this disk is " - "set to %d.\nThis is larger than 1024, and may cause " + if (!sun_label && cylinders > 1024 && !nowarn) + fprintf(stderr, + "The number of cylinders for this disk is set to %d.\n" + "This is larger than 1024, and may cause " "problems with:\n" "1) software that runs at boot time (e.g., LILO)\n" - "2) booting and partitioning software form other OSs\n" + "2) booting and partitioning software from other OSs\n" " (e.g., DOS FDISK, OS/2 FDISK)\n", cylinders); } @@ -397,9 +522,9 @@ void read_extended(struct partition *p) struct partition *q; ext_pointers[ext_index] = part_table[ext_index]; - if (!p->start_sect) + if (!get_start_sect(p)) fprintf(stderr, "Bad offset in primary extended partition\n"); - else while (p->sys_ind == EXTENDED) { + else while (IS_EXTENDED (p->sys_ind)) { if (partitions >= MAXIMUM_PARTS) { fprintf(stderr, "Warning: deleting partitions after %d\n", @@ -408,9 +533,9 @@ void read_extended(struct partition *p) changed[partitions - 1] = 1; return; } - offsets[partitions] = extended_offset + p->start_sect; + offsets[partitions] = extended_offset + get_start_sect(p); if (!extended_offset) - extended_offset = p->start_sect; + extended_offset = get_start_sect(p); if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); @@ -421,7 +546,7 @@ void read_extended(struct partition *p) part_table[partitions] = ext_pointers[partitions] = NULL; q = p = offset(buffers[partitions], 0); for (i = 0; i < 4; i++, p++) { - if (p->sys_ind == EXTENDED) + if (IS_EXTENDED (p->sys_ind)) if (ext_pointers[partitions]) fprintf(stderr, "Warning: extra link " "pointer in partition table " @@ -449,19 +574,50 @@ void read_extended(struct partition *p) } } -int get_boot(void) +void create_doslabel(void) +{ + int i; + + fprintf(stderr, + "Building a new DOS disklabel. Changes will remain in memory only,\n" + "until you decide to write them. After that, of course, the previous\n" + "content won't be recoverable.\n\n"); + + write_part_table_flag(buffer); + for (i = 0; i < 4; i++) + clear_partition(part_table[i]); + for (i = 1; i < MAXIMUM_PARTS; i++) + changed[i] = 0; + changed[0] = 1; + get_boot(create_empty); +} + +/* + * Read MBR. Returns: + * -1: no 0xaa55 flag present (possibly entire disk BSD) + * 0: found or created label + */ +int get_boot(enum action what) { int i; struct hd_geometry geometry; partitions = 4; - if ((fd = open(disk_device, type_open)) < 0) - { + + if (what == create_empty) + goto got_table; /* skip reading disk */ + + if ((fd = open(disk_device, type_open)) < 0) { if ((fd = open(disk_device, O_RDONLY)) < 0) fatal(unable_to_open); else printf("You will not be able to write the partition table.\n"); } + +#if defined(sparc) + guess_device_type(fd); +#endif + if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) fatal(unable_to_read); @@ -475,31 +631,67 @@ int get_boot(void) cylinders = geometry.cylinders; if (dos_compatible_flag) sector_offset = sectors; - warn_cylinders(); + } else { + if (!ioctl(fd, BLKGETSIZE, §ors)) { + heads = 1; + cylinders = 1; + } else { + heads = cylinders = sectors = 0; + } } - else update_units(); - warn_geometry(); + update_units(); + +got_table: - if (*(unsigned short *) (0x1fe + buffer) != 0xAA55) { - return 0; /* not a valid partition table */ +#if defined(sparc) + if (check_sun_label()) + return 0; +#endif + + if (!valid_part_table_flag(buffer)) { + switch(what) { + case fdisk: + fprintf(stderr, + "Device contains neither a valid DOS partition" + " table, nor Sun disklabel\n"); +#ifdef __sparc__ + create_sunlabel(); +#else + create_doslabel(); +#endif + return 0; + case require: + return -1; + case try_only: + return -1; + case create_empty: + break; + } + + fprintf(stderr, "Internal error\n"); + exit(1); } + warn_cylinders(); + warn_geometry(); + for (i = 0; i < 4; i++) - if(part_table[i]->sys_ind == EXTENDED) + if(IS_EXTENDED (part_table[i]->sys_ind)) if (partitions != 4) fprintf(stderr, "Ignoring extra extended " "partition %d\n", i + 1); else read_extended(part_table[ext_index = i]); for (i = 3; i < partitions; i++) - if (*table_check(buffers[i]) != PART_TABLE_FLAG) { - fprintf(stderr, "Warning: invalid flag %04x of parti" - "tion table %d will be corrected by w(rite)\n", - *table_check(buffers[i]), i + 1); + if (!valid_part_table_flag(buffers[i])) { + fprintf(stderr, + "Warning: invalid flag 0x%04x of partition " + "table %d will be corrected by w(rite)\n", + part_table_flag(buffers[i]), i + 1); changed[i] = 1; } - return 1; + return 0; } int read_line(void) @@ -514,14 +706,23 @@ int read_line(void) char read_char(char *mesg) { - do + do { fputs(mesg, stdout); - while (!read_line()); + } while (!read_line()); return *line_ptr; } -/* new function *//* bf */ -int read_hex(struct systypes *sys, int size) +char read_chars(char *mesg) +{ + fputs(mesg, stdout); + if (!read_line()) { + *line_ptr = '\n'; + return '\n'; + } else + return *line_ptr; +} + +int read_hex(struct systypes *sys) { int hex; @@ -529,7 +730,7 @@ int read_hex(struct systypes *sys, int size) { read_char("Hex code (type L to list codes): "); if (tolower(*line_ptr) == 'l') - list_types(sys, size); + list_types(sys); else if (isxdigit (*line_ptr)) { hex = 0; @@ -563,9 +764,17 @@ uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) } while (1) { - while (!isdigit(read_char(ms)) - && (*line_ptr != '-' && *line_ptr != '+')) - continue; + if (base == deflt) { + while (read_chars(ms) != '\n' && !isdigit(*line_ptr) + && *line_ptr != '-' && *line_ptr != '+') + continue; + if (*line_ptr == '\n') + return dflt; + } else { + while (!isdigit(read_char(ms)) + && *line_ptr != '-' && *line_ptr != '+') + continue; + } if (*line_ptr == '+' || *line_ptr == '-') { if (*line_ptr == '+') ++line_ptr; @@ -624,9 +833,14 @@ int get_partition(int warn, int max) */ int i = read_int(1, max, max, ignore, "Partition number") - 1; - if (warn && !part_table[i]->sys_ind) - fprintf(stderr, "Warning: partition %d has empty type\n", - i + 1); + if (warn && ( + (!sun_label && !part_table[i]->sys_ind) +#if defined(sparc) + || (sun_label && + (!sunlabel->partitions[i].num_sectors || + !sunlabel->infos[i].id)) +#endif + )) fprintf(stderr, "Warning: partition %d has empty type\n", i+1); return i; } @@ -649,7 +863,7 @@ void toggle_active(int i) { struct partition *p = part_table[i]; - if (p->sys_ind == EXTENDED && !p->boot_ind) + if (IS_EXTENDED (p->sys_ind) && !p->boot_ind) fprintf(stderr, "WARNING: Partition %d is an extended partition\n", i + 1); @@ -683,8 +897,14 @@ void delete_partition(int i) if (warn_geometry()) return; changed[i] = 1; +#if defined(sparc) + if (sun_label) { + sun_delete_partition(i); + return; + } +#endif if (i < 4) { - if (p->sys_ind == EXTENDED && i == ext_index) { + if (IS_EXTENDED (p->sys_ind) && i == ext_index) { while (partitions > 4) free(buffers[--partitions]); ext_pointers[ext_index] = NULL; @@ -707,14 +927,14 @@ void delete_partition(int i) p->end_head = q->end_head; p->end_sector = q->end_sector; p->end_cyl = q->end_cyl; - p->start_sect = q->start_sect; - p->nr_sects = q->nr_sects; + set_start_sect(p, get_start_sect(q)); + set_nr_sects(p, get_nr_sects(q)); changed[i - 1] = 1; - } - else { - if(part_table[5]) /* prevent SEGFAULT */ - part_table[5]->start_sect += - offsets[5] - extended_offset; + } else { + if(part_table[5]) /* prevent SEGFAULT */ + set_start_sect(part_table[5], + get_start_sect(part_table[5]) + + offsets[5] - extended_offset); offsets[5] = extended_offset; changed[5] = 1; } @@ -738,53 +958,65 @@ void delete_partition(int i) void change_sysid(void) { char *temp; - int i = get_partition(0, partitions), sys; + int i = get_partition(0, partitions), sys, origsys; struct partition *p = part_table[i]; - if ((sys = p->sys_ind) == EXTENDED) - printf("Partition %d is extended. Delete it\n", i + 1); - else if (!sys) - printf("Partition %d does not exist yet!\n", i + 1); - else while (1) { -#if 0 - read_char("Hex code (type L to list codes): "); - if (tolower(*line_ptr) == 'l') - list_types(); - else if (isxdigit(*line_ptr)) { - sys = 0; - do - sys = sys << 4 | hex_val(*line_ptr++); - while (isxdigit(*line_ptr)); +#if defined(sparc) + if (sun_label) + sys = sunlabel->infos[i].id; + else +#endif + sys = p->sys_ind; + origsys = sys; + + if (!sys) + printf("Partition %d does not exist yet!\n", i + 1); + else while (1) { + if (!sun_label) + sys = read_hex (sys_types); +#if defined(sparc) + else + sys = read_hex (sun_sys_types); #endif - /* The above code has been moved to read_hex () - to avoid having the same code in fdisklabel. - *//* bf */ - sys = read_hex (sys_types, nsys_types); /* bf */ - if (!sys) { - delete_partition(i); - break; - } - else if (sys == EXTENDED) { - printf("You may not change a partition " - "to be an extended partition\n"); - break; - } - else if (sys < 256) { - if (sys == p->sys_ind) - break; - part_table[i]->sys_ind = sys; - printf ("Changed system type of partition %d " - "to %x (%s)\n", i + 1, sys, - (temp = partition_type(sys)) ? temp : - "Unknown"); - changed[i] = 1; + if (!sys) { + delete_partition(i); + break; + } + + if (!sun_label) { + if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) { + printf("You cannot change a partition into" + " an extended one or vice versa\n" + "Delete it first.\n"); break; } -#if 0 /* see above *//* bf */ } + + if (sys < 256) { +#if defined(sparc) + if (sun_label && i == 2 && sys != WHOLE_DISK) + printf("Consider leaving partition 3 " + "as Whole disk (5),\n" + "as SunOS/Solaris expects it and " + "even Linux likes it.\n"); #endif - } + if (sys == origsys) + break; +#if defined(sparc) + if (sunlabel) { + sun_change_sysid(i, sys); + } else +#endif + part_table[i]->sys_ind = sys; + printf ("Changed system type of partition %d " + "to %x (%s)\n", i + 1, sys, + (temp = partition_type(sys)) ? temp : + "Unknown"); + changed[i] = 1; + break; + } + } } /* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993, @@ -823,10 +1055,10 @@ static void check_consistency(struct partition *p, int partition) pes = p->end_sector & 0x3f; /* compute logical beginning (c, h, s) */ - long2chs(p->start_sect, &lbc, &lbh, &lbs); + long2chs(get_start_sect(p), &lbc, &lbh, &lbs); /* compute logical ending (c, h, s) */ - long2chs(p->start_sect + p->nr_sects - 1, &lec, &leh, &les); + long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les); /* Same physical / logical beginning? */ if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) { @@ -864,37 +1096,52 @@ static void check_consistency(struct partition *p, int partition) } } -void list_table(void) +void list_table(int xtra) { struct partition *p; char *type; - int i, w = strlen(disk_device); + int i, w; + +#if defined(sparc) + if (sun_label) + sun_list_table(xtra); + return; +#endif + + w = strlen(disk_device); printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = " "%ss of %d * 512 bytes\n\n", disk_device, heads, sectors, cylinders, str_units(), display_factor); if (w < 5) w = 5; - printf("%*s Boot Begin Start End Blocks Id System\n", - w + 1, "Device"); - for (i = 0 ; i < partitions; i++) + printf("%*s Boot %s Start End Blocks Id System\n", + w + 1, "Device", show_begin ? " Begin " : " "); + + for (i = 0 ; i < partitions; i++) { if ((p = part_table[i])->sys_ind) { - printf("%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n", w, -/* device */ disk_device, i + 1, + unsigned int psects = get_nr_sects(p); + printf( + show_begin + ? "%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n" + : "%*s%-2d %c%c%9d%9d%9d%c %2x %s\n", +/* device */ w, disk_device, i+1, /* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG ? '*' : '?', + show_begin ? /* begin */ cround(rounded( calculate(p->head, p->sector, p->cyl), - p->start_sect + offsets[i])), -/* start */ cround(p->start_sect + offsets[i]), -/* end */ cround(p->start_sect + offsets[i] + p->nr_sects - - (p->nr_sects ? 1: 0)), -/* odd flag on end */ p->nr_sects / 2, p->nr_sects & 1 ? '+' : ' ', + get_start_sect(p) + offsets[i])) + : ' ', +/* start */ cround(get_start_sect(p) + offsets[i]), +/* end */ cround(get_start_sect(p) + offsets[i] + psects + - (psects ? 1 : 0)), +/* odd flag on end */ psects / 2, (psects & 1) ? '+' : ' ', /* type id */ p->sys_ind, /* type name */ (type = partition_type(p->sys_ind)) ? type : "Unknown"); check_consistency(p, i); } - + } } void x_list_table(int extend) @@ -917,7 +1164,7 @@ void x_list_table(int extend) cylinder(p->sector, p->cyl), p->end_head, sector(p->end_sector), cylinder(p->end_sector, p->end_cyl), - p->start_sect, p->nr_sects, p->sys_ind); + get_start_sect(p), get_nr_sects(p), p->sys_ind); if (p->sys_ind) check_consistency(p, i); } @@ -931,16 +1178,17 @@ void check_bounds(uint *first, uint *last) partition crossing cylinder 8064 */ struct partition *p = part_table[0]; - for (i = 0; i < partitions; p = part_table[++i]) - if (!p->sys_ind || p->sys_ind == EXTENDED) { + for (i = 0; i < partitions; p = part_table[++i]) { + if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) { first[i] = max; last[i] = 0; - } - else { + } else { first[i] = rounded(calculate(p->head, p->sector, - p->cyl), p->start_sect + offsets[i]); - last[i] = p->start_sect + offsets[i] + p->nr_sects - 1; + p->cyl), get_start_sect(p) + offsets[i]); + last[i] = get_start_sect(p) + offsets[i] + + get_nr_sects(p) - 1; } + } } void check(int n, uint h, uint s, uint c, uint start) @@ -984,11 +1232,17 @@ void verify(void) if (warn_geometry()) return; +#if defined(sparc) + if (sun_label) + verify_sun(); + return; +#endif + check_bounds(first, last); for (i = 0; i < partitions; p = part_table[++i]) - if (p->sys_ind && (p->sys_ind != EXTENDED)) { + if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { check_consistency(p, i); - if (p->start_sect + offsets[i] < first[i]) + if (get_start_sect(p) + offsets[i] < first[i]) printf("Warning: bad start-of-data in " "partition %d\n", i + 1); check(i + 1, p->end_head, p->end_sector, p->end_cyl, @@ -1007,8 +1261,8 @@ void verify(void) } if (extended_offset) { - uint e_last = part_table[ext_index]->start_sect + - part_table[ext_index]->nr_sects - 1; + uint e_last = get_start_sect(part_table[ext_index]) + + get_nr_sects(part_table[ext_index]) - 1; for (p = part_table[i = 4]; i < partitions; p = part_table[++i]) { @@ -1051,12 +1305,12 @@ void add_partition(int n, int sys) limit = heads * sectors * cylinders - 1; if (extended_offset) { first[ext_index] = extended_offset; - last[ext_index] = q->start_sect + q->nr_sects - 1; + last[ext_index] = get_start_sect(q) + + get_nr_sects(q) - 1; } - } - else { + } else { start = extended_offset + sector_offset; - limit = q->start_sect + q->nr_sects - 1; + limit = get_start_sect(q) + get_nr_sects(q) - 1; } if (unit_flag) for (i = 0; i < partitions; i++) @@ -1066,30 +1320,30 @@ void add_partition(int n, int sys) do { temp = start; for (i = 0; i < partitions; i++) { + int lastplusoff; + if (start == offsets[i]) start += sector_offset; - if (start >= first[i] && start <= last[i]) - if (n < 4) - start = last[i] + 1; - else - start = last[i] + sector_offset; + lastplusoff = last[i] + ((n<4) ? 0 : sector_offset); + if (start >= first[i] && start <= lastplusoff) + start = lastplusoff + 1; } if (start > limit) break; - if (start != temp && read) { + if (start >= temp+display_factor && read) { printf("Sector %d is already allocated\n", temp); - temp = start = stop; + temp = start; read = 0; } if (!read && start == temp) { uint i; - i = (stop = start) + (n > 4); + i = start; start = read_int(cround(i), cround(i), cround(limit), ignore, mesg); if (unit_flag) { start = (start - 1) * display_factor; if (start < i) start = i; - } + } read = 1; } } while (start != temp || !read); @@ -1126,7 +1380,7 @@ void add_partition(int n, int sys) set_partition(n, p, start, stop, sys, offsets[n]); - if (sys == EXTENDED) { + if (IS_EXTENDED (sys)) { ext_index = n; offsets[4] = extended_offset = start; ext_pointers[n] = p; @@ -1143,7 +1397,7 @@ void add_partition(int n, int sys) start - sector_offset, stop, EXTENDED, extended_offset); #if 0 - if ((limit = p->nr_sects) & 1) + if ((limit = get_nr_sects(p)) & 1) printf("Warning: partition %d has an odd " "number of sectors.\n", n + 1); #endif @@ -1169,6 +1423,13 @@ void new_partition(void) if (warn_geometry()) return; + +#if defined(sparc) + if (sun_label) + add_sun_partition(get_partition(0, partitions), LINUX_NATIVE); + return; +#endif + if (partitions >= MAXIMUM_PARTS) { printf("The maximum number of partitions has been created\n"); return; @@ -1214,14 +1475,24 @@ void write_table(void) int i, error = 0; changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; - for (i = 3; i < partitions; i++) + if (!sun_label) { + for (i = 3; i < partitions; i++) { if (changed[i]) { - *table_check(buffers[i]) = PART_TABLE_FLAG; + write_part_table_flag(buffers[i]); if (ext2_llseek(fd, (ext2_loff_t)offsets[i] * SECTOR_SIZE, SEEK_SET) < 0) fatal(unable_to_seek); if (write(fd, buffers[i], SECTOR_SIZE) != SECTOR_SIZE) fatal(unable_to_write); + } + } + } else { +#if defined(sparc) + if (changed[3] || changed[4] || changed[5] || + changed[6] || changed[7]) { + sun_write_table(); + } +#endif } printf("The partition table has been altered!\n\n"); @@ -1252,9 +1523,11 @@ void write_table(void) "system to ensure the partition table is updated.\n", error, strerror(error)); - printf( "\nWARNING: If you have created or modified any DOS 6.x\n" + if (!sun_label) + printf( + "\nWARNING: If you have created or modified any DOS 6.x\n" "partitions, please see the fdisk manual page for additional\n" - "information.\n" ); + "information.\n"); exit(0); } @@ -1284,7 +1557,9 @@ void print_raw(void) int i; printf("Device: %s\n", disk_device); - for (i = 3; i < partitions; i++) + if (sun_label) + print_buffer(buffer); + else for (i = 3; i < partitions; i++) print_buffer(buffers[i]); } @@ -1295,20 +1570,20 @@ void move_begin(int i) if (warn_geometry()) return; - if (!p->sys_ind || !p->nr_sects || p->sys_ind == EXTENDED) { + if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) { printf("Partition %d has no data area\n", i + 1); return; } - first = rounded(calculate(p->head, p->sector, p->cyl), p->start_sect + - offsets[i]); + first = rounded(calculate(p->head, p->sector, p->cyl), + get_start_sect(p) + offsets[i]); new = read_int(first, first, - p->start_sect + p->nr_sects + offsets[i] - 1, + get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1, lower, "New beginning of data") - offsets[i]; - if (new != p->nr_sects) { - first = p->nr_sects + p->start_sect - new; - p->nr_sects = first; - p->start_sect = new; + if (new != get_nr_sects(p)) { + first = get_nr_sects(p) + get_start_sect(p) - new; + set_nr_sects(p, first); + set_start_sect(p, new); changed[i] = 1; } } @@ -1318,56 +1593,138 @@ void xselect(void) while(1) { putchar('\n'); switch (tolower(read_char("Expert command (m for help): "))) { - case 'b': move_begin(get_partition(0, partitions)); - break; - case 'c': cylinders = read_int(1, cylinders, 65535, - deflt, "Number of cylinders"); - warn_cylinders(); - break; - case 'd': print_raw(); - break; - case 'e': x_list_table(1); - break; - case 'h': heads = read_int(1, heads, 256, deflt, - "Number of heads"); - update_units(); - break; - case 'p': x_list_table(0); - break; - case 'q': close(fd); - exit(0); - case 'r': return; - case 's': sectors = read_int(1, sectors, 63, deflt, - "Number of sectors"); - if (dos_compatible_flag) { - sector_offset = sectors; - fprintf(stderr, "Warning: setting " - "sector offset for DOS " - "compatiblity\n"); - } - update_units(); - break; - case 'v': verify(); - break; - case 'w': write_table(); - default: xmenu(); +#if defined(sparc) + case 'a': + if (sun_label) + sun_set_alt_cyl(); + break; +#endif + case 'b': + if (!sun_label) + move_begin(get_partition(0, partitions)); + break; + case 'c': + cylinders = read_int(1, cylinders, 65535, + deflt, "Number of cylinders"); +#if defined(sparc) + if (sun_label) + sun_set_ncyl(cylinders); +#endif + warn_cylinders(); + break; + case 'd': + print_raw(); + break; + case 'e': + if (!sun_label) + x_list_table(1); +#if defined(sparc) + else + sun_set_xcyl(); +#endif + break; + case 'h': + heads = read_int(1, heads, 256, deflt, + "Number of heads"); + update_units(); + break; +#if defined(sparc) + case 'i': + if (sun_label) + sun_set_ilfact(); + break; + case 'o': + if (sun_label) + sun_set_rspeed(); + break; +#endif + case 'p': +#if defined(sparc) + if (sun_label) + list_table(1); + else +#endif + x_list_table(0); + break; + case 'q': + close(fd); + exit(0); + case 'r': + return; + case 's': + sectors = read_int(1, sectors, 63, deflt, + "Number of sectors"); + if (dos_compatible_flag) { + sector_offset = sectors; + fprintf(stderr, "Warning: setting " + "sector offset for DOS " + "compatiblity\n"); + } + update_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; +#if defined(sparc) + case 'y': + if (sun_label) + sun_set_pcylcount(); + break; +#endif + default: + xmenu(); } } } -void try(char *device) +int +is_ide_cdrom(char *device) { + /* No device was given explicitly, and we are trying some + likely things. But opening /dev/hdc may produce errors like + "hdc: tray open or drive not ready" + if it happens to be a CD-ROM drive. It even happens that + the process hangs on the attempt to read a music CD. + So try to be careful. This only works since 2.1.73. */ + + FILE *procf; + char buf[100]; + struct stat statbuf; + + sprintf(buf, "/proc/ide/%s/media", device+5); + procf = fopen(buf, "r"); + if (procf != NULL && fgets(buf, sizeof(buf), procf)) + return !strncmp(buf, "cdrom", 5); + + /* Now when this proc file does not exist, skip the + device when it is read-only. */ + if (stat(device, &statbuf) == 0) + return (statbuf.st_mode & 0222) == 0; + + return 0; +} + +void try(char *device, int user_specified) { disk_device = device; if (!setjmp(listingbuf)) { + if (!user_specified) + if (is_ide_cdrom(device)) + return; if ((fd = open(disk_device, type_open)) >= 0) { - if (get_boot()) { - close(fd); - list_table(); - if (partitions > 4) - delete_partition(ext_index); + if (get_boot(try_only) < 0) { + if (btrydev(device) < 0) + fprintf(stderr, + "Disk doesn't contain a valid " + "partition table\n"); + close(fd); } else { - btrydev(device); - close(fd); + close(fd); + list_table(0); + if (!sun_label && partitions > 4) + delete_partition(ext_index); } } else { /* Ignore other errors, since we try IDE @@ -1375,106 +1732,209 @@ void try(char *device) installed on the system. */ if(errno == EACCES) { fprintf(stderr, "Cannot open %s\n", device); - exit(1); + return; } } } } +void +dummy(int *kk) {} + void main(int argc, char **argv) { - if (argc > 3) - fatal(usage); - if (argc > 1 && *argv[1] == '-') { - switch (*(argv[1] + 1)) { - case 'v': - printf("fdisk v" VERSION "\n"); - exit(0); - case 'l': - listing = 1; - type_open = O_RDONLY; - try("/dev/hda"); - try("/dev/hdb"); - try("/dev/hdc"); - try("/dev/hdd"); - try("/dev/sda"); - try("/dev/sdb"); - try("/dev/sdc"); - try("/dev/sdd"); - try("/dev/sde"); - try("/dev/sdf"); - try("/dev/sdg"); - try("/dev/sdh"); - exit(0); - case 's': { - int i; - if (argc < 3) - fatal(usage); - if (!(i = atoi(argv[2] + 8))) - fatal(usage); - disk_device = (char *) malloc(9); - strncpy(disk_device, argv[2], 8); - if ((fd = open(disk_device, O_RDWR)) >= 0) { - close(fd); - get_boot(); - if (i > partitions) exit(1); - if (part_table[--i]->sys_ind > 10) - printf("%d\n", - part_table[i]->nr_sects / 2); - else exit(1); - exit(0); - } + int i, j, s, c; + int optl = 0, opts = 0; + char *part; + + + /* + * Calls: + * fdisk -v + * fdisk -l [-b] [-u] [device] ... + * fdisk -s [partition] ... + * fdisk [-b] [-u] [device] + */ + while ((c = getopt(argc, argv, "blsuv")) != EOF) { + switch (c) { + case 'b': + show_begin = 1; + break; + case 'l': + optl = 1; + break; + case 's': + opts = 1; + break; + case 'u': + unit_flag = 0; + break; + case 'v': + printf("fdisk v" VERSION "\n"); + exit(0); + default: + fatal(usage); + } } - default: + + if (optl) { + listing = 1; + nowarn = 1; + type_open = O_RDONLY; + if (argc > optind) { + int k; + /* avoid gcc warning: + variable `k' might be clobbered by `longjmp' */ + dummy(&k); + for(k=optind; k= partitions) + exit(1); +#if defined(sparc) + if (!sun_label) { + int id = sunlabel->infos[i].id; + + if (!(id > 1 && id != WHOLE_DISK)) + exit(1); + s = get_num_sectors(sunlabel->partitions[i]); + } else +#endif + s = get_nr_sects(part_table[i]); + if (opts == 1) + printf("%d\n", s/2); + else + printf("%s: %d\n", argv[j], s/2); } + exit(0); } - if (argc > 1) - disk_device = argv[argc - 1]; - else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - if (argc == 1) + if (argc-optind == 1) + disk_device = argv[optind]; + else if (argc-optind != 0) + fatal(usage); + else { + if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); printf("Using %s as default device!\n", disk_device); - get_boot(); + } + get_boot(fdisk); while (1) { putchar('\n'); switch (tolower(read_char("Command (m for help): "))) { - case 'a': toggle_active(get_partition(1, partitions)); - break; -/* There should be a define which allows to turn off disklabel support so as - not to make fdisk larger than necessary on installation boot disks. -*/ -#if 1 /* #ifndef NO_DISKLABEL_SUPPORT */ - case 'b': bselect(); /* bf */ - break; + case 'a': +#if defined(sparc) + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x01); + else +#endif + toggle_active(get_partition(1, partitions)); + break; + case 'b': + bselect(); + break; + case 'c': +#if defined(sparc) + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x10); + else #endif - case 'c': toggle_dos(); - break; - case 'd': delete_partition( - get_partition(1, partitions)); - break; - case 'l': list_types(sys_types, nsys_types); /* bf */ - break; - case 'n': new_partition(); - break; - case 'p': list_table(); - break; - case 'q': close(fd); - exit(0); - case 't': change_sysid(); - break; - case 'u': change_units(); - break; - case 'v': verify(); - break; - case 'w': write_table(); - case 'x': xselect(); - break; - default: menu(); + break; + case 'd': + delete_partition( + get_partition(1, partitions)); + break; + case 'l': +#if defined(sparc) + if (sun_label) + list_types(sun_sys_types); + else +#endif + list_types(sys_types); + break; + case 'n': + new_partition(); + break; + case 'o': + create_doslabel(); + break; + case 'p': + list_table(0); + break; + case 'q': + close(fd); + exit(0); +#if defined(sparc) + case 's': + create_sunlabel(); + break; +#endif + case 't': + change_sysid(); + break; + case 'u': + change_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; + case 'x': + xselect(); + break; + default: menu(); } } } + diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h index 89510031..11f529d4 100644 --- a/disk-utils/fdisk.h +++ b/disk-utils/fdisk.h @@ -3,7 +3,10 @@ */ #define SECTOR_SIZE 512 -#define NETBSD_PARTITION 0xa5 +#define MAXIMUM_PARTS 60 + +#define SIZE(a) (sizeof(a)/sizeof((a)[0])) + #define cround(n) (((n) + display_factor * unit_flag) / display_factor) #if defined(__GNUC__) || defined(HAS_LONG_LONG) @@ -16,11 +19,26 @@ extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, unsigned int origin); +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned char start4[4]; /* starting sector counting from 0 */ + unsigned char size4[4]; /* nr of sectors in partition */ +}; + enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, unable_to_write, out_of_memory}; enum offset {ignore, lower, deflt, upper}; +enum action {fdisk, require, try_only, create_empty}; + struct systypes { unsigned char index; char *name; @@ -35,14 +53,20 @@ extern uint unit_flag, display_factor; extern struct partition *part_table[]; extern void fatal(enum failure why); +extern int get_boot(enum action what); extern int get_partition(int warn, int max); -extern void list_types(struct systypes *sys, int size); +extern void list_types(struct systypes *sys); extern int read_line (void); extern char read_char(char *mesg); -extern int read_hex(struct systypes *sys, int size); +extern int read_hex(struct systypes *sys); uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg); extern char *const str_units(void); +extern unsigned int get_start_sect(struct partition *p); +extern unsigned int get_nr_sects(struct partition *p); + /* prototypes for fdisklabel.c */ extern void bselect(void); -extern void btrydev (char * dev); +extern int btrydev (char * dev); + +/* prototypes for fdisksunlabel.c */ diff --git a/disk-utils/fdisklabel.c b/disk-utils/fdisklabel.c index a6b5ecc4..d98d49d0 100644 --- a/disk-utils/fdisklabel.c +++ b/disk-utils/fdisklabel.c @@ -47,11 +47,10 @@ #include #include -#include -#include -#include +#include /* for HDIO_GETGEO */ #include "fdisk.h" +#define NETBSD_PARTITION 0xa5 #define DKTYPENAMES #include "fdisklabel.h" @@ -71,7 +70,7 @@ static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int p 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) +#if defined (i386) || defined (sparc) static int xbsd_translate_fstype (int linux_type); static void xbsd_link_part (void); #endif @@ -81,17 +80,18 @@ void alpha_bootblock_checksum (char *boot); static struct xbsd_disklabel xbsd_dlabel; static char buffer[BSD_BBSIZE]; -#if defined (i386) +#if defined (i386) || defined (sparc) static struct partition *xbsd_part; static int xbsd_part_index; #endif -void +int btrydev (char * dev) { if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) - return; + return -1; printf("\nBSD label for device: %s\n", dev); xbsd_print_disklabel (0); + return 0; } void @@ -106,13 +106,13 @@ bmenu (void) " n add a new BSD partition\n" " p print BSD partition table\n" " q quit without saving changes\n" -#if defined (i386) +#if defined (i386) || defined (sparc) " r return to main menu\n" #endif " s show complete disklabel\n" " t change a partition's filesystem id\n" " w write disklabel to disk\n" -#if defined (i386) +#if defined (i386) || defined (sparc) " x link BSD partition to non-BSD partition" #endif ); @@ -121,22 +121,23 @@ bmenu (void) void bselect (void) { -#if defined (i386) - int t; +#if defined (i386) || defined (sparc) + int t, ss; for (t=0; t<4; t++) if (part_table[t] -> sys_ind == NETBSD_PARTITION) { xbsd_part = part_table[t]; xbsd_part_index = t; - if (xbsd_part -> start_sect == 0) + ss = get_start_sect(xbsd_part); + if (ss == 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, xbsd_part -> start_sect + BSD_LABELSECTOR); + disk_device, t+1, ss + BSD_LABELSECTOR); if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0) if (xbsd_create_disklabel () == 0) return; @@ -192,7 +193,7 @@ bselect (void) case 'w': xbsd_write_disklabel (); break; -#if defined (i386) +#if defined (i386) || defined (sparc) case 'r': return; case 'x': @@ -230,9 +231,9 @@ xbsd_new_part (void) if (!xbsd_check_new_partition (&i)) return; -#if defined (i386) - begin = xbsd_part -> start_sect; - end = begin + xbsd_part -> nr_sects - 1; +#if defined (i386) || defined (sparc) + begin = get_start_sect(xbsd_part); + end = begin + get_nr_sects(xbsd_part) - 1; #elif defined (__alpha__) begin = 0; end = xbsd_dlabel.d_secperunit; @@ -264,7 +265,7 @@ xbsd_print_disklabel (int show_all) if (show_all) { -#if defined (i386) +#if defined (i386) || defined (sparc) fprintf(f, "# %s%d:\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) fprintf(f, "# %s:\n", disk_device); @@ -361,7 +362,7 @@ xbsd_print_disklabel (int show_all) static void xbsd_write_disklabel (void) { -#if defined (i386) +#if defined (i386) || defined (sparc) printf ("Writing disklabel to %s%d.\n", disk_device, xbsd_part_index+1); xbsd_writelabel (xbsd_part, &xbsd_dlabel); #elif defined (__alpha__) @@ -375,7 +376,7 @@ xbsd_create_disklabel (void) { char c; -#if defined (i386) +#if defined (i386) || defined (sparc) fprintf (stderr, "%s%d contains no disklabel.\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) @@ -385,7 +386,7 @@ xbsd_create_disklabel (void) while (1) if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') { -#if defined (i386) +#if defined (i386) || defined (sparc) if (xbsd_initlabel (xbsd_part, &xbsd_dlabel, xbsd_part_index) == 1) #elif defined (__alpha__) if (xbsd_initlabel (NULL, &xbsd_dlabel, 0) == 1) @@ -516,8 +517,8 @@ xbsd_write_bootstrap (void) bcopy (&dl, d, sizeof (struct xbsd_disklabel)); -#if defined (i386) - sector = xbsd_part -> start_sect; +#if defined (i386) || defined (sparc) + sector = get_start_sect(xbsd_part); #elif defined (__alpha__) sector = 0; alpha_bootblock_checksum (buffer); @@ -528,7 +529,7 @@ xbsd_write_bootstrap (void) if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) fatal (unable_to_write); -#if defined (i386) +#if defined (i386) || defined (sparc) printf ("Bootstrap installed on %s%d.\n", disk_device, xbsd_part_index+1); #elif defined (__alpha__) printf ("Bootstrap installed on %s.\n", disk_device); @@ -543,7 +544,7 @@ xbsd_change_fstype (void) int i; i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); - xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes, BSD_FSMAXTYPES); + xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes); } static int @@ -592,7 +593,7 @@ xbsd_check_new_partition (int *i) static void xbsd_list_types (void) { - list_types (xbsd_fstypes, BSD_FSMAXTYPES); + list_types (xbsd_fstypes); } static u_short @@ -632,7 +633,7 @@ xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; #endif -#if defined (i386) +#if defined (i386) || defined (sparc) d -> d_flags = BSD_D_DOSPART; #else d -> d_flags = 0; @@ -655,11 +656,11 @@ xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) d -> d_bbsize = BSD_BBSIZE; d -> d_sbsize = BSD_SBSIZE; -#if defined (i386) +#if defined (i386) || defined (sparc) d -> d_npartitions = 4; pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */ - pp -> p_offset = p -> start_sect; - pp -> p_size = p -> nr_sects; + pp -> p_offset = get_start_sect(p); + pp -> p_size = get_nr_sects(p); pp -> p_fstype = BSD_FS_UNUSED; pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */ pp -> p_offset = 0; @@ -681,8 +682,8 @@ xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d) { int t, sector; -#if defined (i386) - sector = p -> start_sect; +#if defined (i386) || defined (sparc) + sector = (p ? get_start_sect(p) : 0); #elif defined (__alpha__) sector = 0; #endif @@ -715,8 +716,8 @@ xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d) { int sector; -#if defined (i386) - sector = p -> start_sect + BSD_LABELSECTOR; +#if defined (i386) || defined (sparc) + sector = get_start_sect(p) + BSD_LABELSECTOR; #elif defined (__alpha__) sector = BSD_LABELSECTOR; #endif @@ -756,7 +757,7 @@ sync_disks (void) sleep (4); } -#if defined (i386) +#if defined (i386) || defined (sparc) static int xbsd_translate_fstype (int linux_type) { @@ -786,8 +787,8 @@ xbsd_link_part (void) if (!xbsd_check_new_partition (&i)) return; - 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_size = get_nr_sects(part_table[k]); + xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(part_table[k]); xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype (part_table[k] -> sys_ind); } @@ -795,6 +796,10 @@ xbsd_link_part (void) #if defined (__alpha__) +#if 0 +typedef unsigned long long u_int64_t; +#endif + void alpha_bootblock_checksum (char *boot) { diff --git a/disk-utils/fdisklabel.h b/disk-utils/fdisklabel.h index d007b34b..06435f4d 100644 --- a/disk-utils/fdisklabel.h +++ b/disk-utils/fdisklabel.h @@ -31,6 +31,8 @@ * SUCH DAMAGE. */ +#include /* for __u32 etc */ + #ifndef BSD_DISKMAGIC /* perhaps from */ #define BSD_DISKMAGIC ((__u32) 0x82564557) #endif @@ -41,20 +43,19 @@ #define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" -#if defined (i386) +#if defined (i386) || defined (sparc) #define BSD_LABELSECTOR 1 #define BSD_LABELOFFSET 0 -#define BSD_BBSIZE 8192 /* size of boot area, with label */ -#define BSD_SBSIZE 8192 /* max size of fs superblock */ #elif defined (__alpha__) #define BSD_LABELSECTOR 0 #define BSD_LABELOFFSET 64 -#define BSD_BBSIZE 8192 -#define BSD_SBSIZE 8192 #else #error unknown architecture #endif +#define BSD_BBSIZE 8192 /* size of boot area, with label */ +#define BSD_SBSIZE 8192 /* max size of fs superblock */ + struct xbsd_disklabel { __u32 d_magic; /* the magic number */ __s16 d_type; /* drive type */ @@ -210,10 +211,11 @@ static struct systypes xbsd_fstypes[] = { {BSD_FS_ISO9660,"ISO-9660"}, {BSD_FS_BOOT, "boot"}, {BSD_FS_ADOS, "ADOS"}, - {BSD_FS_HFS, "HFS"} + {BSD_FS_HFS, "HFS"}, + { 0, NULL } }; +#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1) -#define BSD_FSMAXTYPES (sizeof(xbsd_fstypes) / sizeof(struct systypes)) #endif /* diff --git a/disk-utils/fdisksunlabel.c b/disk-utils/fdisksunlabel.c new file mode 100644 index 00000000..a5a87b8d --- /dev/null +++ b/disk-utils/fdisksunlabel.c @@ -0,0 +1,661 @@ +/* + * fdisksunlabel.c + * + * I think this is mostly, or entirely, due to + * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996 + * + * Merged with fdisk for other architectures, aeb, June 1998. + */ +#if defined (sparc) + +#include /* stderr */ +#include /* uint */ +#include /* strstr */ +#include /* write */ +#include /* ioctl */ +#include /* stat */ + +#include +#include +#include /* FLOPPY_MAJOR */ +#include /* HDIO_GETGEO */ + +#include "fdisk.h" +#include "fdisksunlabel.h" + +int other_endian = 0; +int scsi_disk = 0; +int floppy = 0; + +#define LINUX_SWAP 0x82 +#define LINUX_NATIVE 0x83 + +struct systypes sun_sys_types[] = { + {0, "Empty"}, + {1, "Boot"}, + {2, "SunOS root"}, + {SUNOS_SWAP, "SunOS swap"}, + {4, "SunOS usr"}, + {WHOLE_DISK, "Whole disk"}, + {6, "SunOS stand"}, + {7, "SunOS var"}, + {8, "SunOS home"}, + {LINUX_SWAP, "Linux swap"}, + {LINUX_NATIVE, "Linux native"}, + { 0, NULL } +}; + +inline unsigned short __swap16(unsigned short x) { + return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); +} +inline __u32 __swap32(__u32 x) { + return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24); +} + +int +get_num_sectors(struct sun_partition p) { + return SSWAP32(p.num_sectors); +} + +void guess_device_type(int fd) { + struct stat bootstat; + + if (fstat (fd, &bootstat) < 0) { + scsi_disk = 0; + floppy = 0; + } else if (S_ISBLK(bootstat.st_mode) + && ((bootstat.st_rdev >> 8) == IDE0_MAJOR || + (bootstat.st_rdev >> 8) == IDE1_MAJOR)) { + scsi_disk = 0; + floppy = 0; + } else if (S_ISBLK(bootstat.st_mode) + && (bootstat.st_rdev >> 8) == FLOPPY_MAJOR) { + scsi_disk = 0; + floppy = 1; + } else { + scsi_disk = 1; + floppy = 0; + } +} + +void set_sun_partition(int i, uint start, uint stop, int sysid) +{ + sunlabel->infos[i].id = sysid; + sunlabel->partitions[i].start_cylinder = + SSWAP32(start / (heads * sectors)); + sunlabel->partitions[i].num_sectors = + SSWAP32(stop - start); + changed[i] = 1; +} + +int check_sun_label(void) +{ + unsigned short *ush; + int csum; + + if (sunlabel->magic != SUN_LABEL_MAGIC && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) { + sun_label = 0; + other_endian = 0; + return 0; + } + other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED); + ush = ((unsigned short *) (sunlabel + 1)) - 1; + for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--; + if (csum) { + fprintf(stderr, "Detected sun disklabel with wrong checksum.\n" + "Probably you'll have to set all the values,\n" + "e.g. heads, sectors, cylinders and partitions\n" + "or force a fresh label (s command in main menu)\n"); + } else { + heads = SSWAP16(sunlabel->ntrks); + cylinders = SSWAP16(sunlabel->ncyl); + sectors = SSWAP16(sunlabel->nsect); + } + update_units(); + sun_label = 1; + partitions = 8; + return 1; +} + +struct sun_predefined_drives { + char *vendor; + char *model; + unsigned short sparecyl; + unsigned short ncyl; + unsigned short nacyl; + unsigned short pcylcount; + unsigned short ntrks; + unsigned short nsect; + unsigned short rspeed; +} sun_drives[] = { +{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662}, +{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662}, +{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600}, +{"","SUN0104",1,974,2,1019,6,35,3662}, +{"","SUN0207",4,1254,2,1272,9,36,3600}, +{"","SUN0327",3,1545,2,1549,9,46,3600}, +{"","SUN0340",0,1538,2,1544,6,72,4200}, +{"","SUN0424",2,1151,2,2500,9,80,4400}, +{"","SUN0535",0,1866,2,2500,7,80,5400}, +{"","SUN0669",5,1614,2,1632,15,54,3600}, +{"","SUN1.0G",5,1703,2,1931,15,80,3597}, +{"","SUN1.05",0,2036,2,2038,14,72,5400}, +{"","SUN1.3G",6,1965,2,3500,17,80,5400}, +{"","SUN2.1G",0,2733,2,3500,19,80,5400}, +{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394}, +}; + +void create_sunlabel(void) +{ + struct hd_geometry geometry; + unsigned int ndiv; + int i; + unsigned char c; + struct sun_predefined_drives *p = NULL; + + fprintf(stderr, "Building a new sun disklabel. Changes will remain in memory only,\n" + "until you decide to write them. After that, of course, the previous\n" + "content won't be recoverable.\n\n"); +#if BYTE_ORDER == LITTLE_ENDIAN + other_endian = 1; +#else + other_endian = 0; +#endif + memset(buffer, 0, SECTOR_SIZE); + sunlabel->magic = SSWAP16(SUN_LABEL_MAGIC); + if (!floppy) { + puts("Drive type\n" + " ? auto configure\n" + " 0 custom (with hardware detected defaults)"); + for (i = 0; i < SIZE(sun_drives); i++) { + printf(" %c %s%s%s\n", + i + 'a', sun_drives[i].vendor, + (*sun_drives[i].vendor) ? " " : "", + sun_drives[i].model); + } + for (;;) { + c = read_char("Select type (? for auto, 0 for custom): "); + if (c >= 'a' && c < 'a' + SIZE(sun_drives)) { + p = sun_drives + c - 'a'; + break; + } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) { + p = sun_drives + c - 'A'; + break; + } else if (c == '0') + break; + else if (c == '?' && scsi_disk) { + unsigned int id[2]; + char buffer[2048]; + char buffer2[2048]; + FILE *pfd; + char *vendor; + char *model; + char *q; + + if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) { + sprintf(buffer, "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n", +#if 0 + ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33, +#else + /* This is very wrong (works only if you have one HBA), but I haven't find a way how to get hostno from the current kernel */ + 0, +#endif + (id[0]>>16)&0xff, + id[0]&0xff, + (id[0]>>8)&0xff); + pfd = fopen("/proc/scsi/scsi","r"); + if (pfd) { + while (fgets(buffer2,2048,pfd)) { + if (!strcmp(buffer, buffer2)) { + if (fgets(buffer2,2048,pfd)) { + q = strstr(buffer2,"Vendor: "); + if (q) { + q += 8; + vendor = q; + q = strstr(q," Model: "); + if (q) { + *q = 0; + q += 8; + model = q; + q = strstr(q," Rev: "); + if (q) { + *q = 0; + for (i = 0; i < SIZE(sun_drives); i++) { + if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor)) + continue; + if (!strstr(model, sun_drives[i].model)) + continue; + printf("Autoconfigure found a %s%s%s\n",sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model); + p = sun_drives + i; + break; + } + } + } + } + } + break; + } + } + fclose(pfd); + } + } + if (!p) + printf("Autoconfigure failed.\n"); + else + break; + } + } + } + if (!p || floppy) { +#ifdef HDIO_REQ + if (!ioctl(fd, HDIO_REQ, &geometry)) { +#else + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { +#endif + heads = geometry.heads; + sectors = geometry.sectors; + cylinders = geometry.cylinders; + } else { + heads = 0; + sectors = 0; + cylinders = 0; + } + if (floppy) { + sunlabel->nacyl = 0; + sunlabel->pcylcount = SSWAP16(cylinders); + sunlabel->rspeed = SSWAP16(300); + sunlabel->ilfact = SSWAP16(1); + sunlabel->sparecyl = 0; + } else { + if (heads) + heads = read_int(1,heads,1024,deflt,"Heads"); + else + heads = read_int(1,1,1024,ignore,"Heads"); + if (sectors) + sectors = read_int(1,sectors,1024,deflt,"Sectors/track"); + else + sectors = read_int(1,1,1024,ignore,"Sectors/track"); + if (cylinders) + cylinders = read_int(1,cylinders-2,65535,deflt,"Cylinders"); + else + cylinders = read_int(1,1,65535,ignore,"Cylinders"); + sunlabel->nacyl = SSWAP16(read_int(0,2,65535,deflt,"Alternate cylinders")); + sunlabel->pcylcount = SSWAP16(read_int(0,cylinders + SSWAP16(sunlabel->nacyl),65535,deflt,"Physical cylinders")); + sunlabel->rspeed = SSWAP16(read_int(1,5400,100000,deflt,"Rotation speed (rpm)")); + sunlabel->ilfact = SSWAP16(read_int(1,1,32,deflt,"Interleave factor")); + sunlabel->sparecyl = SSWAP16(read_int(0,0,sectors,deflt,"Extra sectors per cylinder")); + } + } else { + sunlabel->sparecyl = SSWAP16(p->sparecyl); + sunlabel->ncyl = SSWAP16(p->ncyl); + sunlabel->nacyl = SSWAP16(p->nacyl); + sunlabel->pcylcount = SSWAP16(p->pcylcount); + sunlabel->ntrks = SSWAP16(p->ntrks); + sunlabel->nsect = SSWAP16(p->nsect); + sunlabel->rspeed = SSWAP16(p->rspeed); + cylinders = p->ncyl; + heads = p->ntrks; + sectors = p->nsect; + puts("You may change all the disk params from the x menu"); + } + sprintf(buffer, "%s%s%s cyl %d alt %d hd %d sec %d", + p ? p->vendor : "", (p && *p->vendor) ? " " : "", p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"), + cylinders, SSWAP16(sunlabel->nacyl), heads, sectors); + sunlabel->ntrks = SSWAP16(heads); + sunlabel->nsect = SSWAP16(sectors); + sunlabel->ncyl = SSWAP16(cylinders); + if (floppy) + set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE); + else { + if (cylinders * heads * sectors >= 150 * 2048) { + ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */ + } else + ndiv = cylinders * 2 / 3; + set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE); + set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP); + sunlabel->infos[1].flags |= 0x01; /* Not mountable */ + } + set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK); + { + unsigned short *ush = (unsigned short *)sunlabel; + unsigned short csum = 0; + while(ush < (unsigned short *)(&sunlabel->csum)) + csum ^= *ush++; + sunlabel->csum = csum; + } + for (i = 1; i < MAXIMUM_PARTS; i++) + changed[i] = 0; + changed[0] = 1; + get_boot(create_empty); +} + +void toggle_sunflags(int i, unsigned char mask) +{ + if (sunlabel->infos[i].flags & mask) + sunlabel->infos[i].flags &= ~mask; + else sunlabel->infos[i].flags |= mask; + changed[i] = 1; +} + +void fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) +{ + int i, continuous = 1; + *start = 0; *stop = cylinders * heads * sectors; + for (i = 0; i < partitions; i++) { + if (sunlabel->partitions[i].num_sectors && sunlabel->infos[i].id && sunlabel->infos[i].id != WHOLE_DISK) { + starts[i] = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; + lens[i] = SSWAP32(sunlabel->partitions[i].num_sectors); + if (continuous) { + if (starts[i] == *start) + *start += lens[i]; + else if (starts[i] + lens[i] >= *stop) + *stop = starts[i]; + else + continuous = 0; /* There will be probably more gaps than one, so lets check afterwards */ + } + } else { + starts[i] = 0; + lens[i] = 0; + } + } +} + +static uint *verify_sun_starts; +int verify_sun_cmp(int *a, int *b) +{ + if (*a == -1) return 1; + if (*b == -1) return -1; + if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1; + return -1; +} + +void verify_sun(void) +{ + uint starts[8], lens[8], start, stop; + int i,j,k,starto,endo; + int array[8]; + + verify_sun_starts = starts; + fetch_sun(starts,lens,&start,&stop); + for (k = 0; k < 7; k++) { + for (i = 0; i < 8; i++) { + if (k && (lens[i] % (heads * sectors))) { + printf("Partition %d doesn't end on cylinder boundary\n", i+1); + } + if (lens[i]) { + for (j = 0; j < i; j++) + if (lens[j]) { + if (starts[j] == starts[i]+lens[i]) { + starts[j] = starts[i]; lens[j] += lens[i]; + lens[i] = 0; + } else if (starts[i] == starts[j]+lens[j]){ + lens[j] += lens[i]; + lens[i] = 0; + } else if (!k) { + if (starts[i] < starts[j]+lens[j] && + starts[j] < starts[i]+lens[i]) { + starto = starts[i]; + if (starts[j] > starto) + starto = starts[j]; + endo = starts[i]+lens[i]; + if (starts[j]+lens[j] < endo) + endo = starts[j]+lens[j]; + printf("Partition %d overlaps with others in " + "sectors %d-%d\n", i+1, starto, endo); + } + } + } + } + } + } + for (i = 0; i < 8; i++) { + if (lens[i]) + array[i] = i; + else + array[i] = -1; + } + qsort(array,SIZE(array),sizeof(array[0]), + (int (*)(const void *,const void *)) verify_sun_cmp); + if (array[0] == -1) { + printf("No partitions defined\n"); + return; + } + stop = cylinders * heads * sectors; + if (starts[array[0]]) + printf("Unused gap - sectors 0-%d\n",starts[array[0]]); + for (i = 0; i < 7 && array[i+1] != -1; i++) { + printf("Unused gap - sectors %d-%d\n",starts[array[i]]+lens[array[i]],starts[array[i+1]]); + } + start = starts[array[i]]+lens[array[i]]; + if (start < stop) + printf("Unused gap - sectors %d-%d\n",start,stop); +} + +void add_sun_partition(int n, int sys) +{ + uint start, stop, stop2; + uint starts[8], lens[8]; + int whole_disk = 0; + + char mesg[48]; + int i, first, last; + + if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) { + printf("Partition %d is already defined. Delete " + "it before re-adding it.\n", n + 1); + return; + } + + fetch_sun(starts,lens,&start,&stop); + if (stop <= start) { + if (n == 2) + whole_disk = 1; + else { + printf("Other partitions already cover the whole disk.\nDelete " + "some/shrink them before retry.\n"); + return; + } + } + sprintf(mesg, "First %s", str_units()); + for (;;) { + if (whole_disk) + first = read_int(0, 0, 0, deflt, mesg); + else + first = read_int(scround(start), scround(start), scround(stop), + ignore, mesg); + if (unit_flag) + first *= display_factor; + else + first = (first + heads * sectors - 1) / (heads * sectors); /* Starting sector has to be properly aligned */ + if (n == 2 && first != 0) printf ("It is highly recommended that third partition covers the whole disk\n" + "and is of type `Whole disk'\n"); + for (i = 0; i < partitions; i++) + if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first) + break; + if (i < partitions && !whole_disk) { + if (n == 2 && !first) { + whole_disk = 1; + break; + } + printf("Sector %d is already allocated\n", first); + } else + break; + } + stop = cylinders * heads * sectors; + stop2 = stop; + for (i = 0; i < partitions; i++) { + if (starts[i] > first && starts[i] < stop) + stop = starts[i]; + } + sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); + if (whole_disk) + last = read_int(scround(stop2), scround(stop2), scround(stop2), + deflt, mesg); + else if (n == 2 && !first) + last = read_int(scround(first), scround(stop2), scround(stop2), + upper, mesg); + else + last = read_int(scround(first), scround(stop), scround(stop), + lower, mesg); + if (unit_flag) + last *= display_factor; + if (n == 2 && !first) { + if (last >= stop2) { + whole_disk = 1; + last = stop2; + } else if (last > stop) { + printf ("You haven't covered whole disk with 3rd partition, but your value\n" + "%d %s coveres some other partition. Your entry have been changed\n" + "to %d %s\n", scround(last), str_units(), scround(stop), str_units()); + last = stop; + } + } else if (!whole_disk && last > stop) + last = stop; + + if (whole_disk) sys = WHOLE_DISK; + set_sun_partition(n, first, last, sys); +} + +void +sun_delete_partition(int i) { + if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK && + !sunlabel->partitions[i].start_cylinder && + SSWAP32(sunlabel->partitions[i].num_sectors) == heads * sectors * cylinders) + printf("If you want to maintain SunOS/Solaris compatibility, consider leaving this\n" + "partition as Whole disk (5), starting at 0, with %d sectors\n", + SSWAP32(sunlabel->partitions[i].num_sectors)); + sunlabel->infos[i].id = 0; + sunlabel->partitions[i].num_sectors = 0; +} + +void +sun_change_sysid(int i, int sys) { + if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) { + read_chars( + "It is highly recommended that the partition at offset 0\n" + "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n" + "there may destroy your partition table and bootblock.\n" + "Type YES if you're very sure you would like that partition\n" + "tagged with 82 (Linux swap): "); + if (strcmp (line_ptr, "YES\n")) + return; + } + switch (sys) { + case SUNOS_SWAP: + case LINUX_SWAP: + /* swaps are not mountable by default */ + sunlabel->infos[i].flags |= 0x01; + break; + default: + /* assume other types are mountable; + user can change it anyway */ + sunlabel->infos[i].flags &= ~0x01; + break; + } + sunlabel->infos[i].id = sys; +} + +void +sun_list_table(int xtra) { + int i, w; + char *type; + + w = strlen(disk_device); + if (xtra) + printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n" + "%d cylinders, %d alternate cylinders, %d physical cylinders\n" + "%d extra sects/cyl, interleave %d:1\n" + "%s\n" + "Units = %ss of %d * 512 bytes\n\n", + disk_device, heads, sectors, SSWAP16(sunlabel->rspeed), + cylinders, SSWAP16(sunlabel->nacyl), + SSWAP16(sunlabel->pcylcount), + SSWAP16(sunlabel->sparecyl), + SSWAP16(sunlabel->ilfact), + (char *)sunlabel, + str_units(), display_factor); + else + printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n" + "Units = %ss of %d * 512 bytes\n\n", + disk_device, heads, sectors, cylinders, + str_units(), display_factor); + + printf("%*s Flag %s Start End Blocks Id System\n", + w + 1, "Device", show_begin ? " Begin " : " "); + for (i = 0 ; i < partitions; i++) { + if (sunlabel->partitions[i].num_sectors) { + __u32 start = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; + __u32 len = SSWAP32(sunlabel->partitions[i].num_sectors); + printf( + show_begin + ? "%*s%-2d %c%c%9d%9d%9d%9d%c %2x %s\n" + : "%*s%-2d %c%c%c%9d%9d%9d%c %2x %s\n", +/* device */ w, disk_device, i + 1, +/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', + (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ', +/* begin */ show_begin ? scround(start) : ' ', +/* start */ scround(start), +/* end */ scround(start+len), +/* odd flag on end */ len / 2, len & 1 ? '+' : ' ', +/* type id */ sunlabel->infos[i].id, +/* type name */ (type = partition_type(sunlabel->infos[i].id)) + ? type : "Unknown"); + } + } +} + +void +sun_set_alt_cyl(void) { + sunlabel->nacyl = SSWAP16(read_int(0,SSWAP16(sunlabel->nacyl), + 65535, deflt, + "Number of alternate cylinders")); +} + +void +sun_set_ncyl(int cyl) { + sunlabel->ncyl = SSWAP16(cyl); +} + +void +sun_set_xcyl(void) { + sunlabel->sparecyl = SSWAP16(read_int(0, SSWAP16(sunlabel->sparecyl), + sectors, deflt, + "Extra sectors per cylinder")); +} + +void +sun_set_ilfact(void) { + sunlabel->ilfact = SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), + 32, deflt, + "Interleave factor")); +} + +void +sun_set_rspeed(void) { + sunlabel->rspeed = SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), + 100000, deflt, + "Rotation speed (rpm)")); +} + +void +sun_set_pcylcount(void) { + sunlabel->pcylcount=SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), + 65535, deflt, + "Number of physical cylinders")); +} + +void +sun_write_table(void) { + unsigned short *ush = (unsigned short *)sunlabel; + unsigned short csum = 0; + + while(ush < (unsigned short *)(&sunlabel->csum)) + csum ^= *ush++; + sunlabel->csum = csum; + if (lseek(fd, 0, SEEK_SET) < 0) + fatal(unable_to_seek); + if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE) + fatal(unable_to_write); +} + +#endif /* sparc */ diff --git a/disk-utils/fdisksunlabel.h b/disk-utils/fdisksunlabel.h new file mode 100644 index 00000000..037e437c --- /dev/null +++ b/disk-utils/fdisksunlabel.h @@ -0,0 +1,73 @@ +#include /* for __u32 etc */ + +typedef struct { + unsigned char info[128]; /* Informative text string */ + unsigned char spare0[14]; + struct sun_info { + unsigned char spare1; + unsigned char id; + unsigned char spare2; + unsigned char flags; + } infos[8]; + unsigned char spare1[246]; /* Boot information etc. */ + unsigned short rspeed; /* Disk rotational speed */ + unsigned short pcylcount; /* Physical cylinder count */ + unsigned short sparecyl; /* extra sects per cylinder */ + unsigned char spare2[4]; /* More magic... */ + unsigned short ilfact; /* Interleave factor */ + unsigned short ncyl; /* Data cylinder count */ + unsigned short nacyl; /* Alt. cylinder count */ + unsigned short ntrks; /* Tracks per cylinder */ + unsigned short nsect; /* Sectors per track */ + unsigned char spare3[4]; /* Even more magic... */ + struct sun_partition { + __u32 start_cylinder; + __u32 num_sectors; + } partitions[8]; + unsigned short magic; /* Magic number */ + unsigned short csum; /* Label xor'd checksum */ +} sun_partition; + +#define SUN_LABEL_MAGIC 0xDABE +#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA +#define sunlabel ((sun_partition *)buffer) +#define SSWAP16(x) (other_endian ? __swap16(x) \ + : (__u16)(x)) +#define SSWAP32(x) (other_endian ? __swap32(x) \ + : (__u32)(x)) + +#define scround(x) ((x+(display_factor-1)*unit_flag)/display_factor) + +/* fdisk.c */ +extern char changed[MAXIMUM_PARTS]; +extern char buffer[SECTOR_SIZE]; +extern uint heads, sectors, cylinders; +extern int show_begin; +extern int sun_label; +extern char *partition_type(unsigned char type); +extern void update_units(void); +extern char read_chars(char *mesg); + +/* fdisksunlabel.c */ +#define SUNOS_SWAP 3 +#define WHOLE_DISK 5 + +extern struct systypes sun_sys_types[]; +extern int get_num_sectors(struct sun_partition p); +extern void guess_device_type(int fd); +extern int check_sun_label(void); +extern void create_sunlabel(void); +extern void sun_delete_partition(int i); +extern void sun_change_sysid(int i, int sys); +extern void sun_list_table(int xtra); +extern void verify_sun(void); +extern void add_sun_partition(int n, int sys); +extern void sun_write_table(void); +extern void sun_set_alt_cyl(void); +extern void sun_set_ncyl(int cyl); +extern void sun_set_xcyl(void); +extern void sun_set_ilfact(void); +extern void sun_set_rspeed(void); +extern void sun_set_pcylcount(void); +extern void toggle_sunflags(int i, unsigned char mask); + diff --git a/disk-utils/fsck.minix.c b/disk-utils/fsck.minix.c index 0e8dc64e..ae1d7b1a 100644 --- a/disk-utils/fsck.minix.c +++ b/disk-utils/fsck.minix.c @@ -50,7 +50,7 @@ * * 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 + * that the ARM is powerful 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) @@ -160,8 +160,8 @@ static char super_block_buffer[BLOCK_SIZE]; #define MAGIC (Super.s_magic) #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) -static char inode_map[BLOCK_SIZE * MINIX_I_MAP_SLOTS]; -static char zone_map[BLOCK_SIZE * MINIX_Z_MAP_SLOTS]; +static char *inode_map; +static char *zone_map; static unsigned char * inode_count = NULL; static unsigned char * zone_count = NULL; @@ -566,20 +566,26 @@ void read_superblock(void) die("bad magic number in super-block"); if (ZONESIZE != 0 || BLOCK_SIZE != 1024) die("Only 1k blocks/zones supported"); - if (!IMAPS || IMAPS > MINIX_I_MAP_SLOTS) + if (IMAPS * BLOCK_SIZE * 8 < INODES + 1) die("bad s_imap_blocks field in super-block"); - if (!ZMAPS || ZMAPS > MINIX_Z_MAP_SLOTS) + if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1) die("bad s_zmap_blocks field in super-block"); } void read_tables(void) { + inode_map = malloc(IMAPS * BLOCK_SIZE); + if (!inode_map) + die("Unable to allocate buffer for inode map"); + zone_map = malloc(ZMAPS * BLOCK_SIZE); + if (!inode_map) + die("Unable to allocate buffer for zone map"); 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"); - inode_count = malloc(INODES); + inode_count = malloc(INODES + 1); if (!inode_count) die("Unable to allocate buffer for inode count"); zone_count = malloc(ZONES); @@ -611,7 +617,7 @@ struct minix_inode * get_inode(unsigned int nr) { struct minix_inode * inode; - if (!nr || nr >= INODES) + if (!nr || nr > INODES) return NULL; total++; inode = Inode + nr; @@ -662,7 +668,7 @@ get_inode2 (unsigned int nr) { struct minix2_inode *inode; - if (!nr || nr >= INODES) + if (!nr || nr > INODES) return NULL; total++; inode = Inode2 + nr; @@ -876,7 +882,7 @@ void check_zones(unsigned int i) { struct minix_inode * inode; - if (!i || i >= INODES) + if (!i || i > INODES) return; if (inode_count[i] > 1) /* have we counted this file already? */ return; @@ -896,7 +902,7 @@ check_zones2 (unsigned int i) { struct minix2_inode *inode; - if (!i || i >= INODES) + if (!i || i > INODES) return; if (inode_count[i] > 1) /* have we counted this file already? */ return; @@ -924,7 +930,7 @@ void check_file(struct minix_inode * dir, unsigned int offset) read_block(block, blk); name = blk + (offset % BLOCK_SIZE) + 2; ino = * (unsigned short *) (name-2); - if (ino >= INODES) { + if (ino > INODES) { print_current_name(); printf(" contains a bad inode number for file '"); printf("%.*s'.",namelen,name); @@ -986,7 +992,7 @@ check_file2 (struct minix2_inode *dir, unsigned int offset) read_block (block, blk); name = blk + (offset % BLOCK_SIZE) + 2; ino = *(unsigned short *) (name - 2); - if (ino >= INODES) { + if (ino > INODES) { print_current_name (); printf (" contains a bad inode number for file '"); printf ("%.*s'.", namelen, name); @@ -1087,7 +1093,7 @@ void check_counts(void) { int i; - for (i=1 ; i < INODES ; i++) { + for (i=1 ; i <= INODES ; i++) { if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { printf("Inode %d mode not cleared.",i); if (ask("Clear",1)) { @@ -1140,7 +1146,7 @@ check_counts2 (void) { int i; - for (i = 1; i < INODES; 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)) { @@ -1189,7 +1195,7 @@ check_counts2 (void) void check(void) { - memset(inode_count,0,INODES*sizeof(*inode_count)); + memset(inode_count,0,(INODES + 1) * sizeof(*inode_count)); memset(zone_count,0,ZONES*sizeof(*zone_count)); check_zones(ROOT_INO); recursive_check(ROOT_INO); @@ -1200,7 +1206,7 @@ void check(void) void check2 (void) { - memset (inode_count, 0, INODES * sizeof (*inode_count)); + memset (inode_count, 0, (INODES + 1) * sizeof (*inode_count)); memset (zone_count, 0, ZONES * sizeof (*zone_count)); check_zones2 (ROOT_INO); recursive_check2 (ROOT_INO); @@ -1299,11 +1305,11 @@ int main(int argc, char ** argv) if (verbose) { int i, free; - for (i=1,free=0 ; i < INODES ; i++) + for (i=1,free=0 ; i <= INODES ; i++) if (!inode_in_use(i)) free++; - printf("\n%6ld inodes used (%ld%%)\n",(INODES-free-1), - 100*(INODES-free-1)/(INODES-1)); + printf("\n%6ld inodes used (%ld%%)\n",(INODES-free), + 100*(INODES-free)/INODES); for (i=FIRSTZONE,free=0 ; i < ZONES ; i++) if (!zone_in_use(i)) free++; diff --git a/disk-utils/llseek.c b/disk-utils/llseek.c index dcbfb2a4..a9cd5a3a 100644 --- a/disk-utils/llseek.c +++ b/disk-utils/llseek.c @@ -5,29 +5,18 @@ * under the terms of the GNU Public License. */ -#define FOR_UTIL_LINUX - #include #include #include -#ifndef FOR_UTIL_LINUX - -#include "et/com_err.h" -#include "ext2fs/io.h" - -#else /* FOR_UTIL_LINUX */ - #if defined(__GNUC__) || defined(HAS_LONG_LONG) typedef long long ext2_loff_t; #else typedef long ext2_loff_t; #endif -ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); - -#endif /* FOR_UTIL_LINUX */ +extern ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); #ifdef __linux__ @@ -40,13 +29,8 @@ ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); #define my_llseek lseek -#elif __i386__ - -#include - -#ifndef __NR__llseek -#define __NR__llseek 140 -#endif +#else +#include /* for __NR__llseek */ static int _llseek (unsigned int, unsigned long, unsigned long, ext2_loff_t *, unsigned int); @@ -67,10 +51,6 @@ static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset, return (retval == -1 ? (ext2_loff_t) retval : result); } -#else - -#error "llseek() is not available" - #endif /* __alpha__ */ #endif /* HAVE_LLSEEK */ @@ -81,25 +61,27 @@ ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, ext2_loff_t result; 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) { + result = my_llseek (fd, offset, origin); + if (!(result == -1 && errno == ENOSYS)) + return result; - if (do_compat) { - errno = EINVAL; - return -1; - } - - 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++; - errno = EINVAL; + do_compat = 1; + /* + * Now try ordinary lseek. + */ } - return result; + + 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); + + errno = EINVAL; + return -1; } #else /* !linux */ diff --git a/disk-utils/mkfs.8 b/disk-utils/mkfs.8 index e391f714..57132a48 100644 --- a/disk-utils/mkfs.8 +++ b/disk-utils/mkfs.8 @@ -37,9 +37,11 @@ In actuality, is simply a front-end for the various file system builders (\fBmkfs\fR.\fIfstype\fR) available under Linux. -The file system-specific builder is searched for in /etc/fs first, -then in /etc and finally in the directories listed in the PATH -enviroment variable. +The file system-specific builder is searched for in a number +of directories like /sbin, /sbin/fs, /sbin/fs.d, /etc/fs, /etc +(the precise list is defined at compile time but at least +contains /sbin and /sbin/fs), and finally in the directories +listed in the PATH enviroment variable. Please see the file system-specific builder manual pages for further details. .SH OPTIONS diff --git a/disk-utils/mkfs.c b/disk-utils/mkfs.c index 8d467191..ba293e93 100644 --- a/disk-utils/mkfs.c +++ b/disk-utils/mkfs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ # define DEFAULT_FSTYPE "ext2" #endif -#define SEARCH_PATH "PATH=/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc" +#define SEARCH_PATH "PATH=/sbin:/sbin/fs:/sbin/fs.d:/etc/fs:/etc" #define PROGNAME "mkfs.%s" @@ -35,6 +36,7 @@ int main(int argc, char *argv[]) char progname[NAME_MAX]; char *fstype = NULL; int i, more = 0, verbose = 0; + char *oldpath, *newpath; /* Check commandline options. */ opterr = 0; @@ -62,7 +64,16 @@ int main(int argc, char *argv[]) fstype = DEFAULT_FSTYPE; /* Set PATH and program name */ - putenv(SEARCH_PATH); + oldpath = getenv("PATH"); + if (!oldpath) + oldpath = "/bin"; + newpath = (char *) malloc(strlen(oldpath) + sizeof(SEARCH_PATH) + 2); + if (!newpath) { + fputs("mkfs: out of memory\n", stderr); + exit(1); + } + sprintf(newpath, "%s:%s\n", SEARCH_PATH, oldpath); + putenv(newpath); sprintf(progname, PROGNAME, fstype); argv[--optind] = progname; diff --git a/disk-utils/mkfs.minix.8 b/disk-utils/mkfs.minix.8 index 8f9e7024..9ff75321 100644 --- a/disk-utils/mkfs.minix.8 +++ b/disk-utils/mkfs.minix.8 @@ -81,21 +81,21 @@ Usage or syntax error .BR mkefs (8), .BR efsck (8), .BR reboot (8) -.SH AUTHORS -Stared by Linus Torvalds (torvalds@cs.helsinki.fi). -.br -Error code values by Rik Faith (faith@cs.unc.edu) -.br -Inode request feature by Scott Heavner (sdh@po.cwru.edu) -.br -Support for the file system valid flag by Dr. Wettstein -(greg%wind.uucp@plains.nodak.edu) -.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 +.\" .SH AUTHORS +.\" Linus Torvalds (torvalds@cs.helsinki.fi). +.\" .br +.\" Error code values by Rik Faith (faith@cs.unc.edu) +.\" .br +.\" Inode request feature by Scott Heavner (sdh@po.cwru.edu) +.\" .br +.\" Support for the file system valid flag by Dr. Wettstein +.\" (greg%wind.uucp@plains.nodak.edu) +.\" .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. diff --git a/disk-utils/mkfs.minix.c b/disk-utils/mkfs.minix.c index 403a278c..db7aefae 100644 --- a/disk-utils/mkfs.minix.c +++ b/disk-utils/mkfs.minix.c @@ -141,8 +141,8 @@ static char boot_block_buffer[512]; #define MAGIC (Super.s_magic) #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) -static char inode_map[BLOCK_SIZE * MINIX_I_MAP_SLOTS]; -static char zone_map[BLOCK_SIZE * MINIX_Z_MAP_SLOTS]; +static char *inode_map; +static char *zone_map; static unsigned short good_blocks_table[MAX_GOOD_BLOCKS]; static int used_good_blocks = 0; @@ -432,6 +432,9 @@ void make_root_inode(void) inode->i_size = 2*dirsize; } inode->i_mode = S_IFDIR + 0755; + inode->i_uid = getuid(); + if (inode->i_uid) + inode->i_gid = getgid(); write_block(inode->i_zone[0],root_block); } @@ -453,6 +456,9 @@ make_root_inode2 (void) inode->i_size = 2 * dirsize; } inode->i_mode = S_IFDIR + 0755; + inode->i_uid = getuid(); + if (inode->i_uid) + inode->i_gid = getgid(); write_block (inode->i_zone[0], root_block); } #endif @@ -462,8 +468,6 @@ void setup_tables(void) int i; unsigned long inodes; - memset(inode_map,0xff,sizeof(inode_map)); - memset(zone_map,0xff,sizeof(zone_map)); memset(super_block_buffer,0,BLOCK_SIZE); memset(boot_block_buffer,0,512); MAGIC = magic; @@ -475,24 +479,32 @@ void setup_tables(void) inodes = BLOCKS/3; else inodes = req_nr_inodes; + /* Round up inode count to fill block size */ +#ifdef HAVE_MINIX2 + if (version2) + inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & + ~(MINIX2_INODES_PER_BLOCK - 1)); + else +#endif + inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & + ~(MINIX_INODES_PER_BLOCK - 1)); 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; - if ((INODES & 8191) < 10) - INODES -= 20; - IMAPS = UPPER(INODES,BITS_PER_BLOCK); + IMAPS = UPPER(INODES + 1,BITS_PER_BLOCK); 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"); + while (ZMAPS != UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK)) + ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE + 1,BITS_PER_BLOCK); FIRSTZONE = NORM_FIRSTZONE; + inode_map = malloc(IMAPS * BLOCK_SIZE); + zone_map = malloc(ZMAPS * BLOCK_SIZE); + if (!inode_map || !zone_map) + die("unable to allocate buffers for maps"); + memset(inode_map,0xff,IMAPS * BLOCK_SIZE); + memset(zone_map,0xff,ZMAPS * BLOCK_SIZE); for (i = FIRSTZONE ; i 8 * (PAGE_SIZE - 10)) { - PAGES = 8 * (PAGE_SIZE - 10); + PAGES = 8 * (PAGE_SIZE - 10); fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", program_name, PAGES * PAGE_SIZE / 1024); } @@ -217,11 +217,17 @@ int main(int argc, char ** argv) if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); printf("Setting up swapspace, size = %ld bytes\n", - goodpages*PAGE_SIZE); + (long)(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)) die("unable to write signature page"); + /* + * A subsequent swapon() will fail if the signature + * is not actually on disk. (This is a kernel bug.) + */ + if (fsync(DEV)) + die("fsync failed"); return 0; } diff --git a/disk-utils/sfdisk.8 b/disk-utils/sfdisk.8 index fc930801..33f10dab 100644 --- a/disk-utils/sfdisk.8 +++ b/disk-utils/sfdisk.8 @@ -172,7 +172,7 @@ to sfdisk. For example, .if t .ft R .fi will correct the bad last extended partition that the OS/2 -sfdisk creates. +fdisk creates. .TP .BR \-V " or " \-\-verify Test whether partitions seem correct. (See above.) diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c index fcc76c41..8fbe778f 100644 --- a/disk-utils/sfdisk.c +++ b/disk-utils/sfdisk.c @@ -28,8 +28,8 @@ */ #define PROGNAME "sfdisk" -#define VERSION "3.06" -#define DATE "970626" +#define VERSION "3.07" +#define DATE "980518" #include #include /* atoi, free */ @@ -523,13 +523,15 @@ chs_ok (chs a, char *v, char *w) { #define EMPTY_PARTITION 0 #define EXTENDED_PARTITION 5 -#define DM6_PARTITION 0x54 -#define EZD_PARTITION 0x55 +#define WIN98_EXTENDED 0x0f #define DM6_AUX1PARTITION 0x51 #define DM6_AUX3PARTITION 0x53 +#define DM6_PARTITION 0x54 +#define EZD_PARTITION 0x55 #define LINUX_SWAP 0x82 #define LINUX_NATIVE 0x83 #define LINUX_EXTENDED 0x85 +#define BSD_PARTITION 0xa5 /* * List of system Id's, adapted from fdisk 2.0d and @@ -596,6 +598,7 @@ struct systypes { {0x94, "Amoeba BBT"}, /* (bad block table) */ {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */ {0xa5, "BSD/386"}, /* 386BSD */ + {0xa6, "OpenBSD"}, {0xa7, "NeXTSTEP 486"}, {0xb7, "BSDI fs"}, {0xb8, "BSDI swap"}, @@ -636,7 +639,14 @@ list_types(void) { int is_extended(unsigned char type) { - return (type == EXTENDED_PARTITION || type == LINUX_EXTENDED); + return (type == EXTENDED_PARTITION + || type == LINUX_EXTENDED + || type == WIN98_EXTENDED); +} + +int +is_bsd(unsigned char type) { + return (type == BSD_PARTITION); } /* @@ -715,6 +725,9 @@ struct part_desc { unsigned long sector, offset; /* disk location of this info */ struct partition p; struct part_desc *ep; /* extended partition containing this one */ + int ptype; +#define DOS_TYPE 0 +#define BSD_TYPE 1 } zero_part_desc; struct part_desc * @@ -966,17 +979,19 @@ out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { if (dump) { printf(" start=%9lu", start); printf(", size=%8lu", size); - printf(", Id=%2x", p->p.sys_type); - if (p->p.bootable == 0x80) - printf(", bootable"); + if (p->ptype == DOS_TYPE) { + 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) + if(p->ptype != DOS_TYPE || p->p.bootable == 0) printf(" "); + else if(p->p.bootable == 0x80) + printf(" * "); else printf(" ? "); /* garbage */ @@ -1012,11 +1027,15 @@ out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { out_rounddown(8, size, 2, 0); break; } - printf(" %2x %s\n", + if (p->ptype == DOS_TYPE) { + printf(" %2x %s\n", p->p.sys_type, sysname(p->p.sys_type)); + } else { + printf("\n"); + } /* Is chs as we expect? */ - if (!quiet) { + if (!quiet && p->ptype == DOS_TYPE) { chs a, b; longchs aa, bb; a = (size ? ulong_to_chs(start) : zero_chs); @@ -1113,6 +1132,7 @@ partitions_ok(struct disk_desc *z) { /* Are the logical partitions contained in their extended partitions? */ for (p = partitions+4; p < partitions+partno; p++) + if (p->ptype == DOS_TYPE) 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) { @@ -1133,6 +1153,19 @@ partitions_ok(struct disk_desc *z) { return 0; } + /* Are the data partitions and the extended partition + table sectors disjoint? */ + for (p = partitions; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) + for (q = partitions; q < partitions+partno; q++) + if (is_extended(q->p.sys_type)) + if (p->start <= q->start && p->start + p->size > q->start) { + warn("Warning: partition %s contains part of ", PNO(p)); + warn("the partition table (sector %lu),\n", q->start); + warn("and will destroy it when filled\n"); + 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++) @@ -1217,7 +1250,8 @@ partitions_ok(struct disk_desc *z) { } /* Is chs as we expect? */ - for(p = partitions; p < partitions+partno; p++) { + for(p = partitions; p < partitions+partno; p++) + if(p->ptype == DOS_TYPE) { chs a, b; longchs aa, bb; a = p->size ? ulong_to_chs(p->start) : zero_chs; @@ -1293,7 +1327,9 @@ extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) partitions[pno].start = here + p.start_sect; } partitions[pno].size = p.nr_sects; - partitions[pno++].p = p; + partitions[pno].ptype = DOS_TYPE; + partitions[pno].p = p; + pno++; } here = next; } @@ -1301,6 +1337,68 @@ extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) z->partno = pno; } +#define BSD_DISKMAGIC (0x82564557UL) +#define BSD_MAXPARTITIONS 8 +#define BSD_FS_UNUSED 0 +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +struct bsd_disklabel { + u32 d_magic; + char d_junk1[4]; + char d_typename[16]; + char d_packname[16]; + char d_junk2[92]; + u32 d_magic2; + char d_junk3[2]; + u16 d_npartitions; /* number of partitions in following */ + char d_junk4[8]; + struct bsd_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 */ +}; + +static void +bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { + struct bsd_disklabel *l; + struct bsd_partition *bp, *bp0; + unsigned long start = ep->start; + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + if (!(s = get_sector(dev,fd,start+1))) + return; + l = (struct bsd_disklabel *) (s->data); + if (l->d_magic != BSD_DISKMAGIC) + return; + + bp = bp0 = &l->d_partitions[0]; + while (bp - bp0 <= BSD_MAXPARTITIONS) { + if (pno+1 >= SIZE(z->partitions)) { + printf("too many partitions - ignoring those " + "past nr (%d)\n", pno-1); + break; + } + if (bp->p_fstype != BSD_FS_UNUSED) { + partitions[pno].start = bp->p_offset; + partitions[pno].size = bp->p_size; + partitions[pno].sector = start+1; + partitions[pno].offset = (char *)bp - (char *)bp0; + partitions[pno].ep = 0; + partitions[pno].ptype = BSD_TYPE; + pno++; + } + bp++; + } + z->partno = pno; +} + static int msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { int i; @@ -1349,7 +1447,7 @@ msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { z->partno = pno; - for (i=0; i<4; i++) + 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"); @@ -1357,7 +1455,14 @@ msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { } extended_partition(dev, fd, &partitions[i], z); } - + if (is_bsd(partitions[i].p.sys_type)) { + if (!partitions[i].size) { + printf("strange..., a BSD partition of size 0?\n"); + continue; + } + bsd_partition(dev, fd, &partitions[i], z); + } + } return 1; } @@ -1366,11 +1471,24 @@ osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { return 0; } +static int +sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +static int +amiga_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)) { + if (!msdos_partition(dev, fd, 0, z) + && !osf_partition(dev, fd, 0, z) + && !sun_partition(dev, fd, 0, z) + && !amiga_partition(dev, fd, 0, z)) { printf(" %s: unrecognized partition\n", dev); return; } @@ -2139,6 +2257,31 @@ static struct devd { { "xd", "ab" } }; +int +is_ide_cdrom(char *device) { + /* No device was given explicitly, and we are trying some + likely things. But opening /dev/hdc may produce errors like + "hdc: tray open or drive not ready" + if it happens to be a CD-ROM drive. So try to be careful. + This only works since 2.1.73. */ + + FILE *procf; + char buf[100]; + struct stat statbuf; + + sprintf(buf, "/proc/ide/%s/media", device+5); + procf = fopen(buf, "r"); + if (procf != NULL && fgets(buf, sizeof(buf), procf)) + return !strncmp(buf, "cdrom", 5); + + /* Now when this proc file does not exist, skip the + device when it is read-only. */ + if (stat(device, &statbuf) == 0) + return (statbuf.st_mode & 0222) == 0; + + return 0; +} + void do_list(char *dev, int silent); void do_size(char *dev, int silent); void do_geom(char *dev, int silent); @@ -2277,6 +2420,8 @@ main(int argc, char **argv) { lp = dp->letters; while(*lp) { sprintf(device, "/dev/%s%c", dp->pref, *lp++); + if (!strcmp(dp->pref, "hd") && is_ide_cdrom(device)) + continue; if (opt_out_geom) do_geom(device, 1); if (opt_size) @@ -2427,7 +2572,7 @@ do_size (char *dev, int silent) { size /= 2; /* convert sectors to blocks */ if (silent) - printf("%s: %d\n", dev, size); + printf("%s: %9d\n", dev, size); else printf("%d\n", size); diff --git a/games/banner.c b/games/banner.c index 6dcd0467..400076e6 100644 --- a/games/banner.c +++ b/games/banner.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1980, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)banner.c 8.3 (Berkeley) 4/2/94"; -#endif /* not lint */ - /* * banner - prints large signs * banner [-w#] [-d] [-t] message ... diff --git a/getopt/COPYING b/getopt/COPYING new file mode 100644 index 00000000..a43ea212 --- /dev/null +++ b/getopt/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/getopt/Changelog b/getopt/Changelog new file mode 100644 index 00000000..0480a1de --- /dev/null +++ b/getopt/Changelog @@ -0,0 +1,8 @@ +980611: Bumped up version number to 1.0.2 +980611: Fixed --version bug (was not available, though documented!) +980611: Removed compiler warnings. +980603: Bumped up version number to 1.0.1 +980603: Fixed sizeof() bug (should be strlen) in getopt.c, thanks to Bob Proulx + (rwp@hprwp.fc.hp.com). +980505: Changed date field in LSM to proper syntax +980505: Released version 1.0 diff --git a/getopt/Makefile b/getopt/Makefile new file mode 100644 index 00000000..368291f0 --- /dev/null +++ b/getopt/Makefile @@ -0,0 +1,56 @@ +.SUFFIXES: + +include ../MCONFIG + +prefix=$(DESTDIR)/usr +bindir=$(USRBINDIR) +mandir=$(MANDIR) +man1dir=$(MAN1DIR)/man1 +getoptdir=$(USRLIBDIR)/getopt + +# Define this to 0 to use the getopt(3) routines in this package. +LIBCGETOPT=1 + +SHELL=/bin/sh + +LD=ld +RM=rm -f +INSTALL=install + +CPPFLAGS=-DLIBCGETOPT=$(LIBCGETOPT) +ifeq ($(LIBCGETOPT),0) +CPPFLAGS+=-I./gnu +endif +WARNINGS=-Wall \ + -W -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual \ + -Wcast-align -Wmissing-declarations \ + -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \ + -Wnested-externs -Winline +CFLAGS=$(WARNINGS) $(OPT) + +sources=getopt.c +ifeq ($(LIBCGETOPT),0) +sources+=gnu/getopt.c gnu/getopt1.c +endif + +objects=$(sources:.c=.o) + +binaries=getopt + +.PHONY: all clean realclean +all: $(binaries) + +clean: + -$(RM) $(objects) $(binaries) + +%.o: %.c + $(CC) -c $(CPPFLAGS) $(CFLAGS) $*.c -o $*.o + +getopt: $(objects) + $(CC) $(LDFLAGS) -o $@ $(objects) + +install: getopt + $(INSTALL) -m 755 getopt $(bindir) + $(INSTALL) -m 644 getopt.1 $(man1dir) + $(INSTALL) -m 755 -d $(getoptdir) + $(INSTALL) -m 754 parse.bash parse.tcsh test.bash test.tcsh $(getoptdir) diff --git a/getopt/README b/getopt/README new file mode 100644 index 00000000..04addba9 --- /dev/null +++ b/getopt/README @@ -0,0 +1,80 @@ +This package contains a reimplementation of getopt(1). + +PREFACE + +Getopt(1) is a program to help shell scripts parse command-line parameters. +It is for example included in the util-linux distribution. But, there are +some problems with that getopt(1) implementation, as listed in the +'BUGS' section of its man-page: + +>BUGS +> Whatever getopt(3) has. +> +> Arguments containing white space or imbedded shell metacharacters gener- +> ally will not survive intact; this looks easy to fix but isn't. +> +> The error message for an invalid option is identified as coming from +> getopt rather than from the shell procedure containing the invocation of +> getopt; this again is hard to fix. +> +> The precise best way to use the set command to set the arguments without +> disrupting the value(s) of shell options varies from one shell version to +> another. + +This implementation of getopt(1) is written to solve some of these problems, +while still staying (for all practical purposes) completely compatible with +other getopt(1) implementations. + + +INSTALLATION + +Installation should be very easy. Just type 'make' to compile the sources. +It should compile cleanly, without any warnings, but even if it does not +you probably don't have to worry. You must use GNU Make and gcc, or you +will have to edit the Makefile. + +Type 'make install' to install the binary and the manual page. It installs +by default in /usr/local/bin and /usr/local/man/man1, to install in /usr/bin +and /usr/man/man1 try 'make install prefix=/usr'. + +The example files can be installed in /usr/local/lib/getopt by calling +'make install_doc'. + +If you do not trust the getopt(3) in your libc, or if you do not use a libc +with the GNU getopt(3) routines, you can use the gnu sources as provided +in the gnu directory. Try 'make LIBCGETOPT=0'. Ignore any compile warnings. + +You can check whether the new implementation of getopt is found first +in your path by calling 'bash test.bash'. + + +HIGHLIGHTS + +It can do anything that the GNU getopt(3) routines can do. + +It can cope with spaces and shell metacharacters within arguments. + +It can parse long parameters. + +It can shuffle parameters, so you can mix options and other parameters on +the command-line. + +It can be easily identified as an enhanced getopt(1) from within shell scripts. + +It can report parse errors as coming from the shell script. + +It is fully compatible with other getopt(1) implementations. + +COPYING + +This program comes under the GNU general public licence version 2. See the +file COPYING included in this package. Note that though you may freely +copy it, it is copyright (c) 1997 by Frodo Looijaard . +Files in the gnu directory are from glibc-2.0.4: copyright (C) 1987, 88, +89, 90, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. + + +DOWNLOADING + +You can find the latest version of this program at +. diff --git a/getopt/TODO b/getopt/TODO new file mode 100644 index 00000000..e701f666 --- /dev/null +++ b/getopt/TODO @@ -0,0 +1,4 @@ +Other shells, like zsh and ash, should be supported (perhaps they will work +already, depending on quoting conventions). (zsh seems OK). + +Perhaps a nice configure script? diff --git a/getopt/getopt.1 b/getopt/getopt.1 new file mode 100644 index 00000000..c3aaa019 --- /dev/null +++ b/getopt/getopt.1 @@ -0,0 +1,436 @@ +.TH GETOPT 1 "May 31, 1997" Linux "" +.SH NAME +getopt \- parse command options (enhanced) +.SH SYNOPSIS +.BR getopt " optstring parameters" + +.BR getopt " [options] [" -- "] optstring parameters" + +.BR getopt " [options] " -o | --options " optstring [options] [" -- "] parameters" +.SH DESCRIPTION +.B getopt +is used to break up +.RI ( parse ) +options in command lines for easy parsing by +shell procedures, and to check for legal options. +It uses the +.SM GNU +.BR getopt (3) +routines to do this. + +The parameters +.B getopt +is called with can be divided into two parts: options +which modify the way getopt will parse +.RI ( options +and +.I -o|--options optstring +in the +.BR SYNOPSIS), +and the parameters which are to be +parsed +.RI ( parameters +in the +.BR SYNOPSIS). +The second part will start at the first non-option parameter +that is not an option argument, or after the first occurence of +.RB ` -- '. +If no +.RB ` -o ' +or +.RB ` --options ' +option is found in the first part, the first +parameter of the second part is used as the short options string. + +If the environment variable +.B GETOPT_COMPATIBLE +is set, or if its first parameter +is not an option (does not start with a +.RB ` - ', +this is the first format in the +.BR SYNOPSIS), +.B getopt +will generate output that is compatible with that of other versions of +.BR getopt (1). +It will still do parameter shuffling and recognize optional +arguments (see section +.B COMPATIBILITY +for more information). + +Traditional implementations of +.BR getopt (1) +are unable to cope with whitespace and other (shell-specific) special characters +in arguments and non-option parameters. To solve this problem, this +implementation can generate +quoted output which must once again be interpreted by the shell (usually +by using the +.B eval +command). This has the effect of preserving those characters, but +you must call +.B getopt +in a way that is no longer compatible with other versions (the second +or third format in the +.BR SYNOPSIS). +To determine whether this enhanced version of +.BR getopt (1) +is installed, a special test option +.RB ( -T ) +can be used. +.SH OPTIONS +.IP "-a, --alternative" +Allow long options to start with a single +.RB ` - '. +.IP "-h, --help" +Output a small usage guide and exit succesfully. No other output is generated. +.IP "-l, --longoptions longopts" +The long (multi-character) options to be recognized. +More than one option name +may be specified at once, by separating the names with commas. This option +may be given more than once, the +.I longopts +are cummulative. +Each long option name +in +.I longopts +may be followed by one colon to indicate it has a required argument,and by two colons to indicate it has an optional argument. +.IP "-n, --name progname" +The name that will be used by the +.BR getopt (3) +routines when it reports errors. Note that errors of +.BR getopt (1) +are still reported as coming from getopt. +.IP "-o, --options shortopts" +The short (one-character) options to be recognized. If this options is not +found, the first parameter of +.B getopt +that does not start with +a +.RB ` - ' +(and is not an option argument) is used as the short options string. +Each short option character +in +.I shortopts +may be followed by one colon to indicate it has a required argument, +and by two colons to indicate it has an optional argument. +The first character of shortopts may be +.RB ` + ' +or +.RB ` - ' +to influence the way +options are parsed and output is generated (see section +.B SCANNING MODES +for details). +.IP "-q, --quiet" +Disable error reporting by getopt(3). +.IP "-Q, --quiet-output" +Do not generate normal output. Errors are still reported by +.BR getopt (3), +unless you also use +.IR -q . +.IP "-s, --shell shell" +Set quoting conventions to those of shell. If no -s argument is found, +the +.SM BASH +conventions are used. Valid arguments are currently +.RB ` sh ' +.RB ` bash ', +.RB ` csh ', +and +.RB ` tcsh '. +.IP "-u, --unquoted" +Do not quote the output. Note that whitespace and special (shell-dependent) +characters can cause havoc in this mode (like they do with other +.BR getopt (1) +implementations). +.IP "-T --test" +Test if your +.BR getopt (1) +is this enhanced version or an old version. This generates no output, +and sets the error status to 4. Other implementations of +.BR getopt (1), +and this version if the environment variable +.B GETOPT_COMPATIBLE +is set, +will return +.RB ` -- ' +and error status 0. +.IP "-V, --version" +Output version information and exit succesfully. No other output is generated. +.SH PARSING +This section specifies the format of the second part of the parameters of +.B getopt +(the +.I parameters +in the +.BR SYNOPSIS ). +The next section +.RB ( OUTPUT ) +describes the output that is +generated. These parameters were typically the parameters a shell function +was called with. +Care must be taken that each parameter the shell function was +called with corresponds to exactly one parameter in the parameter list of +.B getopt +(see the +.BR EXAMPLES ). +All parsing is done by the GNU +.BR getopt (3) +routines. + +The parameters are parsed from left to right. Each parameter is classified as a +short option, a long option, an argument to an option, +or a non-option parameter. + +A simple short option is a +.RB ` - ' +followed by a short option character. If +the option has a required argument, it may be written directly after the option +character or as the next parameter (ie. separated by whitespace on the +command line). If the +option has an optional argument, it must be written directly after the +option character if present. + +It is possible to specify several short options after one +.RB ` - ', +as long as all (except possibly the last) do not have required or optional +arguments. + +A long option normally begins with +.RB ` -- ' +followed by the long option name. +If the option has a required argument, it may be written directly after +the long option name, separated by +.RB ` = ', +or as the next argument (ie. separated by whitespace on the command line). +If the option has an optional argument, it must +be written directly after the long option name, separated by +.RB ` = ', +if present (if you add the +.RB ` = ' +but nothing behind it, it is interpreted +as if no argument was present; this is a slight bug, see the +.BR BUGS ). +Long options may be abbreviated, as long as the abbreviation is not +ambiguous. + +Each parameter not starting with a +.RB ` - ', +and not a required argument of +a previous option, is a non-option parameter. Each parameter after +a +.RB ` -- ' +parameter is always interpreted as a non-option parameter. +If the environment variable +.B POSIXLY_CORRECT +is set, or if the short +option string started with a +.RB ` + ', +all remaining parameters are interpreted +as non-option parameters as soon as the first non-option parameter is +found. +.SH OUTPUT +Output is generated for each element described in the previous section. +Output is done +in the same order as the elements are specified in the input, except +for non-option parameters. Output can be done in +.I compatible +.RI ( unquoted ) +mode, or in such way that whitespace and other special characters within +arguments and non-option parameters are preserved (see +.BR QUOTING ). +When the output is processed in the shell script, it will seem to be +composed of distinct elements that can be processed one by one (by using the +shift command in most shell languages). This is imperfect in unquoted mode, +as elements can be split at unexpected places if they contain whitespace +or special characters. + +If there are problems parsing the parameters, for example because a +required argument is not found or an option is not recognized, an error +will be reported on stderr, there will be no output for the offending +element, and a non-zero error status is returned. + +For a short option, a single +.RB ` - ' +and the option character are generated +as one parameter. If the option has an argument, the next +parameter will be the argument. If the option takes an optional argument, +but none was found, the next parameter will be generated but be empty in +quoting mode, +but no second parameter will be generated in unquoted (compatible) mode. +Note that many other +.BR getopt (1) +implemetations do not support optional arguments. + +If several short options were specified after a single +.RB ` - ', +each will be present in the output as a separate parameter. + +For a long option, +.RB ` -- ' +and the full option name are generated as one +parameter. This is done regardless whether the option was abbreviated or +specified with a single +.RB ` - ' +in the input. Arguments are handled as with short options. + +Normally, no non-option parameters output is generated until all options +and their arguments have been generated. Then +.RB ` -- ' +is generated as a +single parameter, and after it the non-option parameters in the order +they were found, each as a separate parameter. +Only if the first character of the short options string was a +.RB ` - ', +non-option parameter output is generated at the place they are found in the +input (this is not supported if the first format of the +.B SYNOPSIS +is used; in that case all preceding occurences of +.RB ` - ' +and +.RB ` + ' +are ignored). +.SH QUOTING +In compatible mode, whitespace or 'special' characters in arguments or +non-option parameters are not handled correctly. As the output is +fed to the shell script, the script does not know how it is supposed to break +the output into separate parameters. To circumvent this +problem, this implementation offers quoting. The idea is that output +is generated with quotes around each parameter. When this output is once +again fed to the shell (usually by a shell +.B eval +command), it is split correctly into separate parameters. + +Quoting is not enabled if the environment variable +.B GETOPT_COMPATIBLE +is set, if the first form of the +.B SYNOPSIS +is used, or if the option +.RB ` -u ' +is found. + +Different shells use different quoting conventions. You can use the +.RB ` -s ' +option to select the shell you are using. The following shells are +currently supported: +.RB ` sh ', +.RB ` bash ', +.RB ` csh ' +and +.RB ` tcsh '. +Actually, only two `flavors' are distinguished: sh-like quoting conventions +and csh-like quoting conventions. Chances are that if you use another shell +script language, one of these flavors can still be used. + +.SH "SCANNING MODES" +The first character of the short options string may be a +.RB ` - ' +or a +.RB ` + ' +to indicate a special scanning mode. If the first calling form +in the +.B SYNOPSIS +is used they are ignored; the environment variable +.B POSIXLY_CORRECT +is still examined, though. + +If the first character is +.RB ` + ', +or if the environment variable +.B POSIXLY_CORRECT +is set, parsing stops as soon as the first non-option parameter +(ie. a parameter that does not start with a +.RB ` - ') +is found that +is not an option argument. The remaining parameters are all interpreted as +non-option parameters. + +If the first character is a +.RB ` - ', +non-option parameters are outputed at the place where they are found; in normal +operation, they are all collected at the end of output after a +.RB ` -- ' +parameter has been generated. Note that this +.RB ` -- ' +parameter is still generated, but it will always be the last parameter in +this mode. +.SH COMPATIBILITY +This version of +.BR getopt (1) +is written to be as compatible as possible to +other versions. Usually you can just replace them with this version +without any modifications, and with some advantages. + +If the first character of the first parameter of getopt is not a +.RB ` - ', +getopt goes into compatibility mode. It will interpret its first parameter as +the string of short options, and all other arguments will be parsed. It +will still do parameter shuffling (ie. all non-option parameters are outputed +at the end), unless the environment variable +.B POSIXLY_CORRECT +is set. + +The environment variable +.B GETOPT_COMPATIBLE +forces +.B getopt +into compatibility mode. Setting both this environment variable and +.B POSIXLY_CORRECT +offers 100% compatibility for `difficult' programs. Usually, though, +neither is needed. + +In compatibility mode, leading +.RB ` - ' +and +.RB ` + ' +characters in the short options string are ignored. +.SH RETURN CODES +.B getopt +returns error code +.B 0 +for succesful parsing, +.B 1 +if +.BR getopt (3) +returns errors, +.B 2 +if it does not understand its own parameters, +.B 3 +if an internal error occurs like out-of-memory, and +.B 4 +if it is called with +.BR -T . +.SH EXAMPLES +Example scripts for (ba)sh and (t)csh are provided with the +.BR getopt (1) +distribution, and are optionally installed in +.B /usr/local/lib/getopt +or +.BR /usr/lib/getopt . +.SH ENVIRONMENT +.IP POSIXLY_CORRECT +This environment variable is examined by the +.BR getopt (3) +routines. +If it is set, parsing stops as soon as a parameter +is found that is not an option or an option argument. All remaining +parameters are also interpreted as non-option parameters, regardless +whether they start with a +.RB ` - '. +.IP GETOPT_COMPATIBLE +Forces +.B getopt +to use the first calling format as specified in the +.BR SYNOPSIS . +.SH BUGS +.BR getopt (3) +can parse long options with optional arguments that are given an empty optional +argument (but can not do this for short options). This +.BR getopt (1) +treats optional arguments that are empty as if they were not present. +.SH AUTHOR +Frodo Looijaard +.SH "SEE ALSO" +.BR getopt (3), +.BR bash (1), +.BR tcsh (1). + diff --git a/getopt/getopt.c b/getopt/getopt.c new file mode 100644 index 00000000..00be49f3 --- /dev/null +++ b/getopt/getopt.c @@ -0,0 +1,448 @@ +/* + getopt.c - Enhanced implementation of BSD getopt(1) + Copyright (c) 1997, 1998 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Version 1.0-b4: Tue Sep 23 1997. First public release. + * Version 1.0: Wed Nov 19 1997. + * Bumped up the version number to 1.0 + * Fixed minor typo (CSH instead of TCSH) + * Version 1.0.1: Tue Jun 3 1998 + * Fixed sizeof instead of strlen bug + * Bumped up the version number to 1.0.1 + * Version 1.0.2: Thu Jun 11 1998 (not present) + * Fixed gcc-2.8.1 warnings + * Fixed --version/-V option (not present) + */ + +#include +#include +#include +#include +#include + +#if LIBCGETOPT +#include +#else +#include "getopt.h" +#endif + +/* NON_OPT is the code that is returned when a non-option is found in '+' + mode */ +#define NON_OPT 1 +/* LONG_OPT is the code that is returned when a long option is found. */ +#define LONG_OPT 2 + +/* The shells recognized. */ +typedef enum {BASH,TCSH} shell_t; + + +/* Some global variables that tells us how to parse. */ +shell_t shell=BASH; /* The shell we generate output for. */ +int quiet_errors=0; /* 0 is not quiet. */ +int quiet_output=0; /* 0 is not quiet. */ +int quote=1; /* 1 is do quote. */ +int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ + +/* Function prototypes */ +void *our_malloc(size_t size); +void *our_realloc(void *ptr, size_t size); +const char *normalize(const char *arg); +int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts); +int main(int argc, char *argv[]); +void parse_error(const char *message); +void add_long_options(char *options); +void add_longopt(const char *name,int has_arg); +void print_help(void); +void set_shell(const char *new_shell); +void set_initial_shell(void); + +void *our_malloc(size_t size) +{ + void *ret=malloc(size); + if (! ret) { + fputs("getopt: Out of memory!",stderr); + exit(3); + } + return(ret); +} + +void *our_realloc(void *ptr, size_t size) +{ + void *ret=realloc(ptr,size); + if (! ret && size) { + fputs("getopt: Out of memory!",stderr); + exit(3); + } + return(ret); +} + +/* + * This function 'normalizes' a single argument: it puts single quotes around + * it and escapes other special characters. If quote is false, it just + * returns its argument. + * Bash only needs special treatment for single quotes; tcsh also recognizes + * exclamation marks within single quotes, and nukes whitespace. + * This function returns a pointer to a buffer that is overwritten by + * each call. + */ +const char *normalize(const char *arg) +{ + static char *BUFFER=NULL; + const char *argptr=arg; + char *bufptr; + + if (BUFFER != NULL) + free(BUFFER); + + if (!quote) { /* Just copy arg */ + BUFFER=our_malloc(strlen(arg)+1); + + strcpy(BUFFER,arg); + return BUFFER; + } + + /* Each character in arg may take upto four characters in the result: + For a quote we need a closing quote, a backslash, a quote and an + opening quote! We need also the global opening and closing quote, + and one extra character for '\0'. */ + BUFFER=our_malloc(strlen(arg)*4+3); + + bufptr=BUFFER; + *bufptr++='\''; + + while (*argptr) { + if (*argptr == '\'') { + /* Quote: replace it with: '\'' */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='\''; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='!') { + /* Exclamation mark: replace it with: \! */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='!'; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='\n') { + /* Newline: replace it with: \n */ + *bufptr++='\\'; + *bufptr++='n'; + } else if (shell==TCSH && isspace(*argptr)) { + /* Non-newline whitespace: replace it with \ */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++=*argptr; + *bufptr++='\''; + } else + /* Just copy */ + *bufptr++=*argptr; + argptr++; + } + *bufptr++='\''; + *bufptr++='\0'; + return BUFFER; +} + +/* + * Generate the output. argv[0] is the program name (used for reporting errors). + * argv[1..] contains the options to be parsed. argc must be the number of + * elements in argv (ie. 1 if there are no options, only the program name), + * optstr must contain the short options, and longopts the long options. + * Other settings are found in global variables. + */ +int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts) +{ + int exit_code = 0; /* We assume everything will be OK */ + int opt; + int longindex; + const char *charptr; + + if (quiet_errors) /* No error reporting from getopt(3) */ + opterr=0; + optind=0; /* Reset getopt(3) */ + + while ((opt = (alternative? + getopt_long_only(argc,argv,optstr,longopts,&longindex): + getopt_long(argc,argv,optstr,longopts,&longindex))) + != EOF) + if (opt == '?' || opt == ':' ) + exit_code = 1; + else if (!quiet_output) + { + if (opt == LONG_OPT) { + printf(" --%s",longopts[longindex].name); + if (longopts[longindex].has_arg) + printf(" %s", + normalize(optarg?optarg:"")); + } else if (opt == NON_OPT) + printf(" %s",normalize(optarg)); + else { + printf(" -%c",opt); + charptr = strchr(optstr,opt); + if (charptr != NULL && *++charptr == ':') + printf(" %s", + normalize(optarg?optarg:"")); + } + } + + if (! quiet_output) { + printf(" --"); + while (optind < argc) + printf(" %s",normalize(argv[optind++])); + printf("\n"); + } + return exit_code; +} + +/* + * Report an error when parsing getopt's own arguments. + * If message is NULL, we already sent a message, we just exit with a helpful + * hint. + */ +void parse_error(const char *message) +{ + if (message) + fprintf(stderr,"getopt: %s\n",message); + fputs("Try `getopt --help' for more information.\n",stderr); + exit(2); +} + +static struct option *long_options=NULL; +static int long_options_length=0; /* Length of array */ +static int long_options_nr=0; /* Nr of used elements in array */ +#define LONG_OPTIONS_INCR 10 +#define init_longopt() add_longopt(NULL,0) + +/* Register a long option. The contents of name is copied. */ +void add_longopt(const char *name,int has_arg) +{ + char *tmp; + if (!name) { /* init */ + free(long_options); + long_options=NULL; + long_options_length=0; + long_options_nr=0; + } + + if (long_options_nr == long_options_length) { + long_options_length += LONG_OPTIONS_INCR; + long_options=our_realloc(long_options, + sizeof(struct option) * + long_options_length); + } + + long_options[long_options_nr].name=NULL; + long_options[long_options_nr].has_arg=0; + long_options[long_options_nr].flag=NULL; + long_options[long_options_nr].val=0; + + if (long_options_nr) { /* Not for init! */ + long_options[long_options_nr-1].has_arg=has_arg; + long_options[long_options_nr-1].flag=NULL; + long_options[long_options_nr-1].val=LONG_OPT; + tmp = our_malloc(strlen(name)+1); + strcpy(tmp,name); + long_options[long_options_nr-1].name=tmp; + } + long_options_nr++; +} + + +/* + * Register several long options. options is a string of long options, + * separated by commas or whitespace. + * This nukes options! + */ +void add_long_options(char *options) +{ + int arg_opt; + char *tokptr=strtok(options,", \t\n"); + while (tokptr) { + arg_opt=no_argument; + if (strlen(tokptr) > 0) { + if (tokptr[strlen(tokptr)-1] == ':') { + if (tokptr[strlen(tokptr)-2] == ':') { + tokptr[strlen(tokptr)-2]='\0'; + arg_opt=optional_argument; + } else { + tokptr[strlen(tokptr)-1]='\0'; + arg_opt=required_argument; + } + if (strlen(tokptr) == 0) + parse_error("empty long option after " + "-l or --long argument"); + } + add_longopt(tokptr,arg_opt); + } + tokptr=strtok(NULL,", \t\n"); + } +} + +void set_shell(const char *new_shell) +{ + if (!strcmp(new_shell,"bash")) + shell=BASH; + else if (!strcmp(new_shell,"tcsh")) + shell=TCSH; + else if (!strcmp(new_shell,"sh")) + shell=BASH; + else if (!strcmp(new_shell,"csh")) + shell=TCSH; + else + parse_error("unknown shell after -s or --shell argument"); +} + +void print_help(void) +{ + fputs("Usage: getopt optstring parameters\n",stderr); + fputs(" getopt [options] [--] optstring parameters\n",stderr); + fputs(" getopt [options] -o|--options optstring [options] [--]\n",stderr); + fputs(" parameters\n",stderr); + fputs(" -a, --alternative Allow long options starting with single -\n",stderr); + fputs(" -h, --help This small usage guide\n",stderr); + fputs(" -l, --longoptions=longopts Long options to be recognized\n",stderr); + fputs(" -n, --name=progname The name under which errors are reported\n",stderr); + fputs(" -o, --options=optstring Short options to be recognized\n",stderr); + fputs(" -q, --quiet Disable error reporting by getopt(3)\n",stderr); + fputs(" -Q, --quiet-output No normal output\n",stderr); + fputs(" -s, --shell=shell Set shell quoting conventions\n",stderr); + fputs(" -T, --test Test for getopt(1) version\n",stderr); + fputs(" -V, --version Output version information\n",stderr); + exit(2); +} + +/* Exit codes: + * 0) No errors, succesful operation. + * 1) getopt(3) returned an error. + * 2) A problem with parameter parsing for getopt(1). + * 3) Internal error, out of memory + * 4) Returned for -T + */ + +static struct option longopts[]={ {"options",required_argument,NULL,'o'}, + {"longoptions",required_argument,NULL,'l'}, + {"quiet",no_argument,NULL,'q'}, + {"quiet-output",no_argument,NULL,'Q'}, + {"shell",required_argument,NULL,'s'}, + {"test",no_argument,NULL,'T'}, + {"unquoted",no_argument,NULL,'u'}, + {"help",no_argument,NULL,'h'}, + {"alternative",no_argument,NULL,'a'}, + {"name",required_argument,NULL,'n'}, + {"version",no_argument,NULL,'V'}, + {NULL,0,NULL,0} + }; + +/* Stop scanning as soon as a non-option argument is found! */ +static const char *shortopts="+ao:l:n:qQs:TuhV"; + +int main(int argc, char *argv[]) +{ + char *optstr=NULL; + char *name=NULL; + char opt; + int compatible=0; + + init_longopt(); + + if (getenv("GETOPT_COMPATIBLE")) + compatible=1; + + if (argc == 1) + { + if (compatible) { + /* For some reason, the original getopt gave no error + when there were no arguments. */ + printf(" --\n"); + exit(0); + } + else + parse_error("missing optstring argument"); + } + + if (argv[1][0] != '-' || compatible) { + quote=0; + optstr=our_malloc(strlen(argv[1])+1); + strcpy(optstr,argv[1]+strspn(argv[1],"-+")); + argv[1]=argv[0]; + exit(generate_output(argv+1,argc-1,optstr,long_options)); + } + + while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) + switch (opt) { + case 'a': + alternative=1; + break; + case 'h': + print_help(); + exit(0); + case 'o': + if (optstr) + free(optstr); + optstr=our_malloc(strlen(optarg)+1); + strcpy(optstr,optarg); + break; + case 'l': + add_long_options(optarg); + break; + case 'n': + if (name) + free(name); + name=our_malloc(strlen(optarg)+1); + strcpy(name,optarg); + break; + case 'q': + quiet_errors=1; + break; + case 'Q': + quiet_output=1; + break; + case 's': + set_shell(optarg); + break; + case 'T': + exit(4); + case 'V': + printf("getopt (enhanced) 1.0.2\n"); + exit(0); + case '?': + case ':': + parse_error(NULL); + default: + parse_error("internal error, contact the author."); + } + + if (!optstr) + { + if (optind >= argc) + parse_error("missing optstring argument"); + else { + optstr=our_malloc(strlen(argv[optind])+1); + strcpy(optstr,argv[optind]); + optind++; + } + } + if (name) + argv[optind-1]=name; + else + argv[optind-1]=argv[0]; + exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); +} diff --git a/getopt/gnu/getopt.c b/getopt/gnu/getopt.c new file mode 100644 index 00000000..59b51cd6 --- /dev/null +++ b/getopt/gnu/getopt.c @@ -0,0 +1,1050 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 + Free Software Foundation, Inc. + + The GNU C Library 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. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#include +#endif /* GNU C library. */ + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +extern pid_t __libc_pid; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +text_set_element (__libc_subinit, store_args_and_env); + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len); + memset (&new_str[nonoption_flags_max_len], '\0', + top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + { + memcpy (__getopt_nonoption_flags, orig_str, len); + memset (&__getopt_nonoption_flags[len], '\0', + nonoption_flags_max_len - len); + } + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/getopt/gnu/getopt.h b/getopt/gnu/getopt.h new file mode 100644 index 00000000..d6ceb0ee --- /dev/null +++ b/getopt/gnu/getopt.h @@ -0,0 +1,131 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/getopt/gnu/getopt1.c b/getopt/gnu/getopt1.c new file mode 100644 index 00000000..4aa8de6f --- /dev/null +++ b/getopt/gnu/getopt1.c @@ -0,0 +1,187 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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. + + The GNU C Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/getopt/parse.bash b/getopt/parse.bash new file mode 100644 index 00000000..864fc0ad --- /dev/null +++ b/getopt/parse.bash @@ -0,0 +1,47 @@ +#!/bin/bash + +# A small example program for using the new getopt(1) program. +# This program will only work with bash(1) +# An similar program using the tcsh(1) script language can be found +# as parse.tcsh + +# Example input and output (from the bash prompt): +# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " +# Option a +# Option c, no argument +# Option c, argument `more' +# Option b, argument ` very long ' +# Remaining arguments: +# --> `par1' +# --> `another arg' +# --> `wow!*\?' + +# Note that we use `"$@"' to let each command-line parameter expand to a +# separate word. The quotes around `$@' are essential! +# We need TEMP as the `eval set --' would nuke the return value of getopt. +TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ + -n 'example.bash' -- "$@"` + +if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi + +# Note the quotes around `$TEMP': they are essential! +eval set -- "$TEMP" + +while true ; do + case "$1" in + -a|--a-long) echo "Option a" ; shift ;; + -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; + -c|--c-long) + # c has an optional argument. As we are in quoted mode, + # an empty parameter will be generated if its optional + # argument is not found. + case "$2" in + "") echo "Option c, no argument"; shift 2 ;; + *) echo "Option c, argument \`$2'" ; shift 2 ;; + esac ;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac +done +echo "Remaining arguments:" +for arg do echo '--> '"\`$arg'" ; done diff --git a/getopt/parse.tcsh b/getopt/parse.tcsh new file mode 100644 index 00000000..7d4f4271 --- /dev/null +++ b/getopt/parse.tcsh @@ -0,0 +1,76 @@ +#!/bin/tcsh + +# A small example program for using the new getopt(1) program. +# This program will only work with bash(1) +# An similar program using the tcsh(1) script language can be found +# as parse.tcsh + +# Example input and output (from the tcsh prompt): +# ./parse.tcsh -a par1 'another arg' --c-long 'wow\!*\?' -cmore -b " very long " +# Option a +# Option c, no argument +# Option c, argument `more' +# Option b, argument ` very long ' +# Remaining arguments: +# --> `par1' +# --> `another arg' +# --> `wow!*\?' + +# Note that we had to escape the exclamation mark in the wow-argument. This +# is _not_ a problem with getopt, but with the tcsh command parsing. If you +# would give the same line from the bash prompt (ie. call ./parse.tcsh), +# you could remove the exclamation mark. + +# This is a bit tricky. We use a temp variable, to be able to check the +# return value of getopt (eval nukes it). argv contains the command arguments +# as a list. The ':q` copies that list without doing any substitutions: +# each element of argv becomes a separate argument for getopt. The braces +# are needed because the result is also a list. +set temp=(`getopt -s tcsh -o ab:c:: --long a-long,b-long:,c-long:: -- $argv:q`) +if ($? != 0) then + echo "Terminating..." >/dev/stderr + exit 1 +endif + +# Now we do the eval part. As the result is a list, we need braces. But they +# must be quoted, because they must be evaluated when the eval is called. +# The 'q` stops doing any silly substitutions. +eval set argv=\($temp:q\) + +set + +while (1) + switch($1:q) + case -a: + case --a-long: + echo "Option a" ; shift + breaksw; + case -b: + case --b-long: + echo "Option b, argument "\`$2\' ; shift ; shift + breaksw + case -c: + case --c-long: + # c has an optional argument. As we are in quoted mode, + # an empty parameter will be generated if its optional + # argument is not found. + + if ($2:q == "") then + echo "Option c, no argument" + else + echo "Option c, argument "\`$2\' + endif + shift; shift + breaksw + case --: + shift + break + default: + echo "Internal error!" ; exit 1 + endsw +end + +echo "Remaining arguments:" +foreach el ($argv:q) + echo '--> '\`$el:q\' +end diff --git a/getopt/test.bash b/getopt/test.bash new file mode 100644 index 00000000..149e1f9b --- /dev/null +++ b/getopt/test.bash @@ -0,0 +1,6 @@ +#!/bin/bash +if `getopt -T >/dev/null 2>&1` ; [ $? = 4 ] ; then + echo "Enhanced getopt(1)" +else + echo "Old getopt(1)" +fi diff --git a/getopt/test.tcsh b/getopt/test.tcsh new file mode 100644 index 00000000..d661e767 --- /dev/null +++ b/getopt/test.tcsh @@ -0,0 +1,7 @@ +#!/bin/tcsh +getopt -T >&/dev/null +if ( $status == 4) then + echo "Enhanced getopt(1)" +else + echo "Old getopt(1)" +endif diff --git a/login-utils/agetty.8 b/login-utils/agetty.8 index ebbc2758..57c9b6b4 100644 --- a/login-utils/agetty.8 +++ b/login-utils/agetty.8 @@ -158,9 +158,9 @@ 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 command entries for the \fI/etc/inittab\fP file. +This section shows examples for the process field of an entry in the +\fI/etc/inittab\fP file. You'll have to prepend appropriate values +for the other fields. See \fIinittab(5)\fP for more details. For a hard-wired line or a console tty: .ti +5 diff --git a/login-utils/agetty.c b/login-utils/agetty.c index ba28336b..03958959 100644 --- a/login-utils/agetty.c +++ b/login-utils/agetty.c @@ -6,13 +6,10 @@ -f option added by Eric Rasmussen - 12/28/95 */ -#ifndef lint -char sccsid[] = "@(#) agetty.c 1.29 9/1/91 23:22:00"; -#endif - #include #include #include +#include #include #include #include @@ -510,7 +507,6 @@ update_utmp(line) int mypid = getpid(); long time(); long lseek(); - char *strncpy(); struct utmp *utp; /* @@ -1162,9 +1158,6 @@ error(va_alist) char buf[BUFSIZ]; char *bp; - char *strcpy(); - char *strcat(); - /* * If the diagnostic is reported via syslog(3), the process name is * automatically prepended to the message. If we write directly to diff --git a/login-utils/checktty.c b/login-utils/checktty.c index e5d03815..f01d0ee8 100644 --- a/login-utils/checktty.c +++ b/login-utils/checktty.c @@ -3,8 +3,6 @@ Fixed by JDS June 1996 to clear lists and close files */ -#define _GNU_SOURCE /* for snprintf */ - #include #include @@ -143,7 +141,10 @@ isapty(const char *tty) char devname[100]; struct stat stb; - snprintf(devname, sizeof(devname), "/dev/%s", tty); + /* avoid snprintf - old systems do not have it */ + if (strlen(tty) + 6 > sizeof(devname)) + return 0; + sprintf(devname, "/dev/%s", tty); #if defined(__linux__) && defined(PTY_SLAVE_MAJOR) /* this is for linux 1.3 and newer */ diff --git a/login-utils/chfn.c b/login-utils/chfn.c index e81c5c18..8e962db0 100644 --- a/login-utils/chfn.c +++ b/login-utils/chfn.c @@ -7,8 +7,8 @@ * there is no warranty. * * $Author: aebr $ - * $Revision: 1.15 $ - * $Date: 1997/07/06 23:10:41 $ + * $Revision: 1.18 $ + * $Date: 1998/06/11 22:30:11 $ * * Updated Thu Oct 12 09:19:26 1995 by faith@cs.unc.edu with security * patches from Zefram @@ -21,9 +21,6 @@ * */ -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 @@ -35,6 +32,7 @@ static char rcsId[] = "$Version: $Id: chfn.c,v 1.15 1997/07/06 23:10:41 aebr Exp #include #include #include +#include "my_crypt.h" #include "../version.h" #if REQUIRE_PASSWORD && USE_PAM @@ -161,7 +159,7 @@ int main (argc, argv) exit(1); } retcode = pam_acct_mgmt(pamh, 0); - if (retcode == PAM_AUTHTOKEN_REQD) { + if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } else if (retcode) { puts("Password error."); diff --git a/login-utils/chsh.c b/login-utils/chsh.c index 3cafc966..f64cd0b7 100644 --- a/login-utils/chsh.c +++ b/login-utils/chsh.c @@ -7,8 +7,8 @@ * there is no warranty. * * $Author: aebr $ - * $Revision: 1.16 $ - * $Date: 1997/07/06 00:12:08 $ + * $Revision: 1.19 $ + * $Date: 1998/06/11 22:30:14 $ * * Updated Thu Oct 12 09:33:15 1995 by faith@cs.unc.edu with security * patches from Zefram @@ -24,9 +24,6 @@ * */ -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 @@ -40,6 +37,7 @@ static char rcsId[] = "$Version: $Id: chsh.c,v 1.16 1997/07/06 00:12:08 aebr Exp #include #include #include +#include "my_crypt.h" #include "../version.h" #if REQUIRE_PASSWORD && USE_PAM @@ -156,7 +154,7 @@ int main (argc, argv) exit(1); } retcode = pam_acct_mgmt(pamh, 0); - if (retcode == PAM_AUTHTOKEN_REQD) { + if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } else if (retcode) { puts("Password error."); diff --git a/login-utils/cryptocard.c b/login-utils/cryptocard.c index e735c727..b3edc6fd 100644 --- a/login-utils/cryptocard.c +++ b/login-utils/cryptocard.c @@ -85,7 +85,9 @@ get_key() int rfd; struct stat statbuf; - snprintf(keyfile, sizeof(keyfile), "%s/.cryptocard", pwd->pw_dir); + if (strlen(pwd->pw_dir) + 13 > sizeof(keyfile)) + goto bail_out; + sprintf(keyfile, "%s/.cryptocard", pwd->pw_dir); if ((rfd = open(keyfile, O_RDONLY)) < 0) { syslog(LOG_NOTICE, "can't open %s for reading", keyfile); @@ -182,7 +184,8 @@ cryptocard(void) challenge = generate_challenge(); if (challenge == NULL) return 0; - snprintf(prompt, sizeof(prompt), "%s Password: ", challenge); + if (strlen(challenge) + 13 > sizeof(prompt)) return 0; + sprintf(prompt, "%s Password: ", challenge); alarm((unsigned int)timeout); /* give user time to fiddle with card */ response = getpass(prompt); /* presents challenge and gets response */ diff --git a/login-utils/last.c b/login-utils/last.c index fa9f8f83..98ffef38 100644 --- a/login-utils/last.c +++ b/login-utils/last.c @@ -18,16 +18,6 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1987 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)last.c 5.11 (Berkeley) 6/29/88"; -#endif /* not lint */ - /* * last */ diff --git a/login-utils/login.c b/login-utils/login.c index c1626183..ebb0a22d 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -70,24 +70,12 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -char copyright[] = - "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; -#endif /* not lint */ - /* * login [ name ] * login -h hostname (for telnetd, etc.) * login -f name (for pre-authenticated login: datakit, xterm, etc.) */ -#define _GNU_SOURCE /* to get definition of snprintf */ - /* #define TESTING */ #ifdef TESTING @@ -123,6 +111,7 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; #include #include #include +#include "my_crypt.h" #ifdef __linux__ # include @@ -144,15 +133,12 @@ static char sccsid[] = "@(#)login.c 5.40 (Berkeley) 5/9/89"; # 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)); \ + fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \ + syslog(LOG_ERR,"%s",pam_strerror(pamh, 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__ @@ -295,23 +281,14 @@ main(argc, argv) 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 - -#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); @@ -407,7 +384,8 @@ main(argc, argv) ttyn = ttyname(0); if (ttyn == NULL || *ttyn == '\0') { - snprintf(tname, sizeof(tname), "%s??", _PATH_TTY); + /* no snprintf required - see definition of tname */ + sprintf(tname, "%s??", _PATH_TTY); ttyn = tname; } @@ -461,8 +439,8 @@ main(argc, argv) 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)); + pam_strerror(pamh, retcode)); + syslog(LOG_ERR,"Couldn't initialize PAM: %s", pam_strerror(pamh, retcode)); exit(99); } /* hostname & tty are either set to NULL or their correct values, @@ -494,7 +472,7 @@ main(argc, argv) (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)); + failcount, hostname,username,pam_strerror(pamh, retcode)); fprintf(stderr,"Login incorrect\n\n"); pam_set_item(pamh,PAM_USER,NULL); retcode = pam_authenticate(pamh, 0); @@ -506,10 +484,10 @@ main(argc, argv) if (retcode == PAM_MAXTRIES) syslog(LOG_NOTICE,"TOO MANY LOGIN TRIES (%d) FROM %s FOR " "%s, %s", failcount, hostname, username, - pam_strerror(retcode)); + pam_strerror(pamh, retcode)); else syslog(LOG_NOTICE,"FAILED LOGIN SESSION FROM %s FOR %s, %s", - hostname, username, pam_strerror(retcode)); + hostname, username, pam_strerror(pamh, retcode)); fprintf(stderr,"\nLogin incorrect\n"); pam_end(pamh, retcode); @@ -518,7 +496,7 @@ main(argc, argv) retcode = pam_acct_mgmt(pamh, 0); - if(retcode == PAM_AUTHTOKEN_REQD) { + if(retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } @@ -533,7 +511,7 @@ main(argc, argv) pwd = getpwnam(username); if (pwd) initgroups(username, pwd->pw_gid); - retcode = pam_setcred(pamh, PAM_CRED_ESTABLISH); + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; retcode = pam_open_session(pamh, 0); @@ -717,16 +695,20 @@ main(argc, argv) 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); + + /* avoid snprintf - old systems do not have it, or worse, + have a libc in which snprintf is the same as sprintf */ + if (strlen(pwd->pw_dir) + sizeof(_PATH_HUSHLOGIN) + 2 > MAXPATHLEN) + quietlog = 0; + else { + sprintf(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__ @@ -921,8 +903,13 @@ main(argc, argv) 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); + { char tmp[MAXPATHLEN]; + /* avoid snprintf */ + if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < MAXPATHLEN) { + sprintf(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. @@ -971,11 +958,13 @@ main(argc, argv) 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 " : ""); + /* avoid snprintf */ + if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < sizeof(tbuf)) { + sprintf(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); @@ -1034,38 +1023,22 @@ main(argc, argv) 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); - } +#ifdef USE_PAM + /* There was some junk with fork()/exec()/signal()/wait() here + that was incorrect, and util-linux-2.7-11.src.rpm contains + a patch that makes the fork entirely useless. + If you introduce one again, please document in the source + what its purpose is. - aeb */ + PAM_END; #endif /* USE_PAM */ - if (error) { - if (!strcmp(childArgv[0], "/bin/sh")) + execvp(childArgv[0], childArgv + 1); + + if (!strcmp(childArgv[0], "/bin/sh")) fprintf(stderr, "login: couldn't exec shell script: %s.\n", strerror(errno)); - else + else fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); - } exit(0); } diff --git a/login-utils/mesg.c b/login-utils/mesg.c index 4e491635..d05d333c 100644 --- a/login-utils/mesg.c +++ b/login-utils/mesg.c @@ -41,16 +41,6 @@ * */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1987, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)mesg.c 8.2 (Berkeley) 1/21/94"; -#endif /* not lint */ - #include #include diff --git a/login-utils/my_crypt.h b/login-utils/my_crypt.h new file mode 100644 index 00000000..efb1a66f --- /dev/null +++ b/login-utils/my_crypt.h @@ -0,0 +1,3 @@ +#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 +#include +#endif diff --git a/login-utils/newgrp.c b/login-utils/newgrp.c index 65dd00d9..5c26a4a0 100644 --- a/login-utils/newgrp.c +++ b/login-utils/newgrp.c @@ -3,7 +3,6 @@ /* 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 @@ -11,6 +10,7 @@ #include #include #include "pathnames.h" +#include "my_crypt.h" #ifndef TRUE # define TRUE 1 diff --git a/login-utils/passwd.1 b/login-utils/passwd.1 index c696c53d..db44aa8e 100644 --- a/login-utils/passwd.1 +++ b/login-utils/passwd.1 @@ -92,6 +92,10 @@ 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 BUGS +If you change your mind there is no escaping from this program. +It will insist on a new password until killed from another terminal. +(This is caused by a bug in getpass(3): it ignores signals.) .SH FILES .TP .I /etc/passwd diff --git a/login-utils/passwd.c b/login-utils/passwd.c index f707c052..4ed1b74d 100644 --- a/login-utils/passwd.c +++ b/login-utils/passwd.c @@ -19,8 +19,12 @@ /* * Sun Oct 15 13:18:34 1995 Martin Schulze * - * I have completely rewritten the whole argument handlig (what?) + * I have completely rewritten the whole argument handling (what?) * to support two things. First I wanted "passwd $user $pw" to + + (a very bad idea; command lines are visible to people doing ps + or running a background job that just collects all command lines) + * 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 @@ -59,10 +63,7 @@ #include #include #include - -#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 -#include -#endif +#include "my_crypt.h" #if 0 # include "../version.h" diff --git a/login-utils/ttymsg.c b/login-utils/ttymsg.c index 1f5fd1f5..7caf35be 100644 --- a/login-utils/ttymsg.c +++ b/login-utils/ttymsg.c @@ -34,10 +34,6 @@ * */ -#ifndef lint -static char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93"; -#endif /* not lint */ - #include #include #include @@ -69,7 +65,7 @@ ttymsg(iov, iovcnt, line, tmout) int tmout; { static char device[MAXNAMLEN]; - static char errbuf[1024]; + static char errbuf[MAXNAMLEN+1024]; register int cnt, fd, left, wret; struct iovec localiov[6]; int forked = 0; @@ -79,11 +75,15 @@ ttymsg(iov, iovcnt, line, tmout) if (strchr(line, '/')) { /* A slash is an attempt to break security... */ - (void) snprintf(errbuf, sizeof(errbuf), "'/' in \"%s\"", - device); + (void) sprintf(errbuf, "'/' in \"%s\"", device); + errbuf[1024] = 0; /* protect caller */ + return (errbuf); + } + if (strlen(line) + sizeof(_PATH_DEV) + 1 > sizeof(device)) { + (void) sprintf(errbuf, "excessively long line arg"); return (errbuf); } - (void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line); + (void) sprintf(device, "%s%s", _PATH_DEV, line); /* * open will fail on slip lines or exclusive-use lines @@ -92,8 +92,10 @@ ttymsg(iov, iovcnt, line, tmout) 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)); + if (strlen(strerror(errno)) > 1000) + return (NULL); + (void) sprintf(errbuf, "%s: %s", device, strerror(errno)); + errbuf[1024] = 0; return (errbuf); } @@ -131,8 +133,11 @@ ttymsg(iov, iovcnt, line, tmout) } cpid = fork(); if (cpid < 0) { - (void) snprintf(errbuf, sizeof(errbuf), - "fork: %s", strerror(errno)); + if (strlen(strerror(errno)) > 1000) + (void) sprintf(errbuf, "cannot fork"); + else + (void) sprintf(errbuf, + "fork: %s", strerror(errno)); (void) close(fd); return (errbuf); } @@ -158,8 +163,12 @@ ttymsg(iov, iovcnt, line, tmout) (void) close(fd); if (forked) _exit(1); - (void) snprintf(errbuf, sizeof(errbuf), - "%s: %s", device, strerror(errno)); + if (strlen(strerror(errno)) > 1000) + (void) sprintf(errbuf, "%s: BAD ERROR", device); + else + (void) sprintf(errbuf, "%s: %s", device, + strerror(errno)); + errbuf[1024] = 0; return (errbuf); } diff --git a/login-utils/vipw.c b/login-utils/vipw.c index 6eff4f3b..a5763b10 100644 --- a/login-utils/vipw.c +++ b/login-utils/vipw.c @@ -39,17 +39,6 @@ * Martin Schulze's patches adapted to Util-Linux by Nicolai Langfeldt. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1987 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -/*static char sccsid[] = "from: @(#)vipw.c 5.16 (Berkeley) 3/3/91";*/ -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 @@ -167,8 +156,10 @@ pw_lock() if (ret == -1) { if (errno == EEXIST) (void)fprintf(stderr, - "%s: the %s file is busy\n", progname, - program == VIPW ? "password" : "group" ); + "%s: the %s file is busy (%s present)\n", + progname, + program == VIPW ? "password" : "group", + tmp_file); else (void)fprintf(stderr, "%s: can't link %s: %s\n", progname, tmp_file, strerror(errno)); @@ -213,7 +204,12 @@ pw_edit(notsetuid) else p = editor; - if (!(pid = vfork())) { + pid = fork(); + if (pid < 0) { + (void)fprintf(stderr, "%s: Cannot fork\n", progname); + exit(1); + } + if (!pid) { if (notsetuid) { (void)setgid(getgid()); (void)setuid(getuid()); diff --git a/login-utils/wall.c b/login-utils/wall.c index 7957ae29..eda7e611 100644 --- a/login-utils/wall.c +++ b/login-utils/wall.c @@ -33,16 +33,6 @@ * Modified Sun Mar 12 10:34:34 1995, faith@cs.unc.edu, for Linux */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1988, 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; -#endif /* not lint */ - /* * This program is not related to David Wall, whose Stanford Ph.D. thesis * is entitled "Mechanisms for Broadcast and Selective Broadcast". @@ -145,11 +135,12 @@ makemsg(fname) time_t now, time(); FILE *fp; int fd; - char *p, *whom, hostname[MAXHOSTNAMELEN], lbuf[100], tmpname[64]; + char *p, *whom, *where, hostname[MAXHOSTNAMELEN], + lbuf[MAXHOSTNAMELEN + 320], + tmpname[sizeof(_PATH_TMP) + 20]; char *getlogin(), *strcpy(), *ttyname(); - (void)snprintf(tmpname, sizeof(tmpname), - "%s/wall.XXXXXX", _PATH_TMP); + (void)sprintf(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); @@ -159,6 +150,11 @@ makemsg(fname) if (!nobanner) { if (!(whom = getlogin())) whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; + if (!whom || strlen(whom) > 100) + whom = "someone"; + where = ttyname(2); + if (!where || strlen(where) > 100) + where = "somewhere"; (void)gethostname(hostname, sizeof(hostname)); (void)time(&now); lt = localtime(&now); @@ -170,14 +166,14 @@ makemsg(fname) * Which means that we may leave a non-blank character * in column 80, but that can't be helped. */ + /* snprintf is not always available, but the sprintf's here + will not overflow as long as %d takes at most 100 chars */ (void)fprintf(fp, "\r%79s\r\n", " "); - (void)snprintf(lbuf, sizeof(lbuf), - "Broadcast Message from %s@%s", - whom, hostname); + (void)sprintf(lbuf, "Broadcast Message from %s@%s", + whom, hostname); (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); - (void)snprintf(lbuf, sizeof(lbuf), - " (%s) at %d:%02d ...", ttyname(2), - lt->tm_hour, lt->tm_min); + (void)sprintf(lbuf, " (%s) at %d:%02d ...", + where, 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 1ae67df3..e33165f7 100644 --- a/misc-utils/Makefile +++ b/misc-utils/Makefile @@ -9,7 +9,7 @@ include ../MCONFIG # Where to put man pages? -MAN1= cal.1 chkdupexe.1 ddate.1 hostid.1 kill.1 \ +MAN1= cal.1 chkdupexe.1 ddate.1 kill.1 \ logger.1 look.1 mcookie.1 namei.1 script.1 \ setterm.1 tsort.1 whereis.1 write.1 @@ -18,7 +18,7 @@ MAN1= cal.1 chkdupexe.1 ddate.1 hostid.1 kill.1 \ BIN= kill -USRBIN= cal chkdupexe ddate hostid logger look mcookie \ +USRBIN= cal chkdupexe ddate logger look mcookie \ namei script setterm tsort whereis write ifeq "$(HAVE_CLEAR)" "no" @@ -39,10 +39,14 @@ endif NEEDS_CURSES= setterm -all: $(BIN) $(USRBIN) $(USRBIN.NONSHADOW) $(USRGAMES) getoptprog +all: $(BIN) $(USRBIN) $(USRBIN.NONSHADOW) $(USRGAMES) $(NEEDS_CURSES): +ifeq "$(HAVE_NCURSES)" "yes" $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) +else + @echo $@ not made since it requires ncurses +endif %: %.sh cp $@.sh $@ @@ -57,28 +61,24 @@ $(NEEDS_CURSES): cal: cal.o $(BSD)/getopt.o $(BSD)/err.o chkdupexe: chkdupexe.pl clear: clear.sh -getoptprog: getoptprog.o $(BSD)/getopt.o -hostid: hostid.o kill: kill.o procs.o logger: logger.o $(BSD)/getopt.o mcookie: mcookie.o md5.o 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 +ifeq "$(HAVE_NCURSES)" "yes" +setterm: setterm.o +endif + install: all $(INSTALLDIR) $(BINDIR) $(USRBINDIR) $(INSTALLBIN) $(BIN) $(BINDIR) $(INSTALLBIN) $(USRBIN) $(USRBINDIR) - $(INSTALLBIN) getoptprog $(USRBINDIR)/getopt $(INSTALLDIR) $(MAN1DIR) $(MAN8DIR) $(INSTALLMAN) $(MAN1) $(MAN1DIR) - $(INSTALLMAN) getoptprog.1 $(MAN1DIR)/getopt.1 ifeq "$(USE_TTY_GROUP)" "yes" chgrp tty $(USRBINDIR)/write chmod g+s $(USRBINDIR)/write @@ -86,4 +86,4 @@ endif .PHONY: clean clean: - -rm -f *.o *~ core $(BIN) $(USRBIN) getoptprog + -rm -f *.o *~ core $(BIN) $(USRBIN) diff --git a/misc-utils/cal.c b/misc-utils/cal.c index ecdc7998..9d44d327 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -34,12 +34,6 @@ * SUCH DAMAGE. */ -static char copyright[] = -"@(#) Copyright (c) 1989, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"; -static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94"; - - /* 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? diff --git a/misc-utils/getoptprog.1 b/misc-utils/getoptprog.1 deleted file mode 100644 index 12853af7..00000000 --- a/misc-utils/getoptprog.1 +++ /dev/null @@ -1,104 +0,0 @@ -.Dd June 21, 1993 -.Dt GETOPT 1 -.Os -.Sh NAME -.Nm getopt -.Nd parse command options -.Sh SYNOPSIS -.Nm set \-\- \`getopt optstring $*\` -.Sh DESCRIPTION -.Nm Getopt -is used to break up options in command lines for easy parsing by -shell procedures, and to check for legal options. -.Op Optstring -is a string of recognized option letters (see -.Xr getopt 3 -); -if a letter is followed by a colon, the option -is expected to have an argument which may or may not be -separated from it by white space. -The special option -.B \-\- -is used to delimit the end of the options. -.Nm Getopt -will place -.B \-\- -in the arguments at the end of the options, -or recognize it if used explicitly. -The shell arguments -(\fB$1 $2\fR ...) are reset so that each option is -preceded by a -.B \- -and in its own shell argument; -each option argument is also in its own shell argument. -.Sh EXAMPLE -The following code fragment shows how one might process the arguments -for a command that can take the options -.Op a -and -.Op b , -and the option -.Op o , -which requires an argument. -.Pp -.Bd -literal -offset indent -set \-\- \`getopt abo: $*\` -if test $? != 0 -then - echo 'Usage: ...' - exit 2 -fi -for i -do - case "$i" - in - \-a|\-b) - flag=$i; shift;; - \-o) - oarg=$2; shift; shift;; - \-\-) - shift; break;; - esac -done -.Ed -.Pp -This code will accept any of the following as equivalent: -.Pp -.Bd -literal -offset indent -cmd \-aoarg file file -cmd \-a \-o arg file file -cmd \-oarg -a file file -cmd \-a \-oarg \-\- file file -.Ed -.Sh SEE ALSO -.Xr sh 1 , -.Xr getopt 3 -.Sh DIAGNOSTICS -.Nm Getopt -prints an error message on the standard error output when it -encounters an option letter not included in -.Op optstring . -.Sh HISTORY -Written by Henry Spencer, working from a Bell Labs manual page. -Behavior believed identical to the Bell version. -.Sh BUGS -Whatever -.Xr getopt 3 -has. -.Pp -Arguments containing white space or imbedded shell metacharacters -generally will not survive intact; this looks easy to fix but isn't. -.Pp -The error message for an invalid option is identified as coming -from -.Nm getopt -rather than from the shell procedure containing the invocation -of -.Nm getopt ; -this again is hard to fix. -.Pp -The precise best way to use the -.Nm set -command to set the arguments without disrupting the value(s) of -shell options varies from one shell version to another. -varies from one shell version to another. diff --git a/misc-utils/getoptprog.c b/misc-utils/getoptprog.c deleted file mode 100644 index 94eac145..00000000 --- a/misc-utils/getoptprog.c +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include - -int -main(argc, argv) -int argc; -char *argv[]; -{ - extern int optind; - extern char *optarg; - int c; - int status = 0; - - optind = 2; /* Past the program name and the option letters. */ - while ((c = getopt(argc, argv, argv[1])) != EOF) - switch (c) { - case '?': - status = 1; /* getopt routine gave message */ - break; - default: - if (optarg != NULL) - printf(" -%c %s", c, optarg); - else - printf(" -%c", c); - break; - } - printf(" --"); - for (; optind < argc; optind++) - printf(" %s", argv[optind]); - printf("\n"); - return status; -} diff --git a/misc-utils/hostid.1 b/misc-utils/hostid.1 deleted file mode 100644 index 9830a53d..00000000 --- a/misc-utils/hostid.1 +++ /dev/null @@ -1,23 +0,0 @@ -.TH hostid 1 -.SH NAME -hostid \- set or print system's host id. -.SH SYNTAX -.B hostid -[\-v] [\|\fIdecimal-id\fR\|] -.SH DESCRIPTION -.\".NXR "hostid command" -The -.B hostid -command prints the current host id number in hexadecimal and both -decimal and hexadecimal in parenthesis if the \-v option is given. -This numeric value is expected to be unique across all hosts -and is normally set to resemble the host's Internet address. - -Only the super-user can set the hostid by giving an argument. This value is -stored in the file /etc/hostid and need only be performed once. - -.SH AUTHOR -Hostid is written by Mitch DSouza \- (m.dsouza@mrc-apu.cam.ac.uk) - -.SH SEE ALSO -gethostid(2), sethostid(2) diff --git a/misc-utils/hostid.c b/misc-utils/hostid.c deleted file mode 100644 index 211e4ce5..00000000 --- a/misc-utils/hostid.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Mitch DSouza - (m.dsouza@mrc-apu.cam.ac.uk) */ - -#include -#include -#include -#include -#include - -int main (int argc, char **argv) -{ - int verbose = 0; - - if(argc == 2 && strcmp(argv[1], "-v") == 0) { - verbose = 1; - argc--; - argv++; - } - - if (argc==2) { - if (sethostid(atoi(argv[1]))!=0) { - perror("sethostid"); - exit(1); - } - } else if (argc==1) { - unsigned long id = gethostid(); - - if(id && verbose) { - printf("Hostid is %lu (0x%lx)\n",id,id); - } else if(id) { - printf("0x%lx\n", id); - } else { - printf("Usage: %s hostid_number\n",*argv); - } - } - return 0; -} diff --git a/misc-utils/logger.c b/misc-utils/logger.c index 3fd3b6b2..e59fe12b 100644 --- a/misc-utils/logger.c +++ b/misc-utils/logger.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1983, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - #include #include #include diff --git a/misc-utils/look.c b/misc-utils/look.c index 13cb6787..1d2848b5 100644 --- a/misc-utils/look.c +++ b/misc-utils/look.c @@ -34,16 +34,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1991, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/14/93"; -#endif /* not lint */ - /* * look -- find lines in a sorted list. * diff --git a/misc-utils/namei.c b/misc-utils/namei.c index 2c985002..36a17dfd 100644 --- a/misc-utils/namei.c +++ b/misc-utils/namei.c @@ -41,10 +41,6 @@ chdir to /, or if it encounters an unknown file type. -------------------------------------------------------------*/ -#ifndef lint -static char *RCSid = "$Id: namei.c,v 1.6 1997/07/06 00:13:09 aebr Exp $"; -#endif - #include #include #include @@ -75,7 +71,6 @@ int argc; char *argv[]; { void namei(), usage(); - char *getwd(); int getopt(); extern int optind; register int c; @@ -100,7 +95,7 @@ char *argv[]; } } - if(getwd(curdir) == NULL){ + if(getcwd(curdir, sizeof(curdir)) == NULL){ (void)fprintf(stderr, "namei: unable to get current directory - %s\n", curdir); exit(1); } diff --git a/misc-utils/script.c b/misc-utils/script.c index ba322fe5..af4013d3 100644 --- a/misc-utils/script.c +++ b/misc-utils/script.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)script.c 5.13 (Berkeley) 3/5/91"; -#endif /* not lint */ - /* * script */ @@ -88,7 +78,6 @@ main(argc, argv) int argc; char *argv[]; { - extern char *optarg; extern int optind; int ch; void finish(); diff --git a/misc-utils/setterm.c b/misc-utils/setterm.c index 60145d9f..49903f3b 100644 --- a/misc-utils/setterm.c +++ b/misc-utils/setterm.c @@ -118,6 +118,7 @@ _syscall3(int, klogctl, int, type, char*, buf, int, len); #define klogctl syslog #endif #endif +extern int klogctl(int type, char *buf, int len); /* Constants. */ diff --git a/misc-utils/tsort.c b/misc-utils/tsort.c index a5a44dae..61e9e844 100644 --- a/misc-utils/tsort.c +++ b/misc-utils/tsort.c @@ -34,16 +34,6 @@ * SUCH DAMAGE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)tsort.c 5.3 (Berkeley) 6/1/90"; -#endif /* not lint */ - #include #include #include diff --git a/misc-utils/whereis.1 b/misc-utils/whereis.1 index 4d55ac6d..ff44513c 100644 --- a/misc-utils/whereis.1 +++ b/misc-utils/whereis.1 @@ -62,53 +62,7 @@ Prefixes of resulting from use of source code control are also dealt with. .B whereis then attempts to locate the desired program in -a list of standard Linux places: -.IP -.nf -.ft B -/bin -/usr/bin -/etc -/usr/etc -/sbin -/usr/sbin -/usr/games -/usr/games/bin -/usr/emacs/etc -/usr/lib/emacs/19.22/etc -/usr/lib/emacs/19.23/etc -/usr/lib/emacs/19.24/etc -/usr/lib/emacs/19.25/etc -/usr/lib/emacs/19.26/etc -/usr/lib/emacs/19.27/etc -/usr/lib/emacs/19.28/etc -/usr/lib/emacs/19.29/etc -/usr/lib/emacs/19.30/etc -/usr/TeX/bin -/usr/tex/bin -/usr/interviews/bin/LINUX -/usr/bin/X11 -/usr/X11/bin -/usr/X11R5/bin -/usr/X11R6/bin -/usr/X386/bin -/usr/local/bin -/usr/local/etc -/usr/local/sbin -/usr/local/games -/usr/local/games/bin -/usr/local/emacs/etc -/usr/local/TeX/bin -/usr/local/tex/bin -/usr/local/bin/X11 - -/usr/contrib", -/usr/hosts", -/usr/include", - -/usr/g++-include", -.ft R -.fi +a list of standard Linux places. .SH OPTIONS .TP \fB\-b @@ -170,19 +124,14 @@ example% whereis \-u \-M /usr/man/man1 \-S /usr/src \-f * .fi .ft R .SH FILES -.PD 0 .TP 20 .B /{bin,sbin,etc} .TP .B /usr/{lib,bin,old,new,local,games,include,etc,src,man,sbin, .B X386,TeX,g++-include} .TP -.B /usr/local/{X386,TeX,X11,include,lib,man,etc,bin,games, -.B emacs} -.TP -.B -.PD -.SH SEE ALSO +.B /usr/local/{X386,TeX,X11,include,lib,man,etc,bin,games,emacs} +.SH "SEE ALSO" .BR chdir (2V) .SH BUGS Since @@ -196,3 +145,7 @@ or .B \-B must be full; that is, they must begin with a .RB ` / '. +.PP +.B whereis +has a hard-coded path, so may not always find what +you're looking for. diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c index 84136011..1a8e1edd 100644 --- a/misc-utils/whereis.c +++ b/misc-utils/whereis.c @@ -31,18 +31,11 @@ * SUCH DAMAGE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)whereis.c 5.5 (Berkeley) 4/18/91"; -#endif /* not lint */ +/* *:aeb */ #include #include +#include #include #include #include @@ -59,40 +52,33 @@ void findin(char *, char *); int itsit(char *, char *); static char *bindirs[] = { -#ifdef __linux__ "/bin", "/usr/bin", - "/etc", - "/usr/etc", "/sbin", "/usr/sbin", + "/etc", + "/usr/etc", + "/lib", + "/usr/lib", "/usr/games", "/usr/games/bin", + "/usr/games/lib", "/usr/emacs/etc", - "/usr/lib/emacs/19.22/etc", - "/usr/lib/emacs/19.23/etc", - "/usr/lib/emacs/19.24/etc", - "/usr/lib/emacs/19.25/etc", - "/usr/lib/emacs/19.26/etc", - "/usr/lib/emacs/19.27/etc", - "/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/lib/emacs/*/etc", "/usr/TeX/bin", "/usr/tex/bin", "/usr/interviews/bin/LINUX", + "/usr/X11R6/bin", + "/usr/X386/bin", "/usr/bin/X11", "/usr/X11/bin", "/usr/X11R5/bin", - "/usr/X11R6/bin", - "/usr/X386/bin", "/usr/local/bin", - "/usr/local/etc", "/usr/local/sbin", + "/usr/local/etc", + "/usr/local/lib", "/usr/local/games", "/usr/local/games/bin", "/usr/local/emacs/etc", @@ -105,129 +91,33 @@ static char *bindirs[] = { "/usr/include", "/usr/g++-include", -#else - "/bin", - "/sbin", - "/usr/ucb", - "/usr/bin", - "/usr/sbin", - "/usr/old", - "/usr/contrib", - "/usr/games", - "/usr/local", - "/usr/libexec", - "/usr/include", - "/usr/hosts", - "/usr/share", /*?*/ - "/etc", -#ifdef notdef - /* before reorg */ - "/etc", - "/bin", - "/usr/bin", - "/usr/games", - "/lib", - "/usr/ucb", - "/usr/lib", - "/usr/local", - "/usr/new", - "/usr/old", - "/usr/hosts", - "/usr/include", -#endif -#endif + + "/usr/ucb", + "/usr/old", + "/usr/new", + "/usr/local", + "/usr/libexec", + "/usr/share", + 0 }; -/* This needs to be redone - man pages live with sources */ + static char *mandirs[] = { - "/usr/man/man1", - "/usr/man/man2", - "/usr/man/man3", - "/usr/man/man4", - "/usr/man/man5", - "/usr/man/man6", - "/usr/man/man7", - "/usr/man/man8", -#ifdef __linux__ - "/usr/man/man9", -#endif - "/usr/man/manl", - "/usr/man/mann", - "/usr/man/mano", -#ifdef __linux__ - "/usr/X386/man/man1", - "/usr/X386/man/man2", - "/usr/X386/man/man3", - "/usr/X386/man/man4", - "/usr/X386/man/man5", - "/usr/X386/man/man6", - "/usr/X386/man/man7", - "/usr/X386/man/man8", - "/usr/X11/man/man1", - "/usr/X11/man/man2", - "/usr/X11/man/man3", - "/usr/X11/man/man4", - "/usr/X11/man/man5", - "/usr/X11/man/man6", - "/usr/X11/man/man7", - "/usr/X11/man/man8", - "/usr/TeX/man/man1", - "/usr/TeX/man/man2", - "/usr/TeX/man/man3", - "/usr/TeX/man/man4", - "/usr/TeX/man/man5", - "/usr/TeX/man/man6", - "/usr/TeX/man/man7", - "/usr/TeX/man/man8", + "/usr/man/*", + "/usr/X386/man/*", + "/usr/X11/man/*", + "/usr/TeX/man/*", "/usr/interviews/man/mann", -#endif 0 }; + static char *srcdirs[] = { - "/usr/src/bin", - "/usr/src/sbin", - "/usr/src/etc", - "/usr/src/pgrm", - "/usr/src/usr.bin", - "/usr/src/usr.sbin", - "/usr/src/usr.ucb", - "/usr/src/usr.new", - "/usr/src/usr.lib", - "/usr/src/libexec", - "/usr/src/libdata", - "/usr/src/share", - "/usr/src/contrib", - "/usr/src/athena", - "/usr/src/devel", - "/usr/src/games", - "/usr/src/local", - "/usr/src/man", - "/usr/src/root", - "/usr/src/old", - "/usr/src/include", - /* still need libs */ -#ifdef notdef /* before reorg */ - "/usr/src/bin", - "/usr/src/usr.bin", - "/usr/src/etc", - "/usr/src/ucb", - "/usr/src/games", - "/usr/src/usr.lib", - "/usr/src/lib", - "/usr/src/local", - "/usr/src/new", - "/usr/src/old", - "/usr/src/include", - "/usr/src/lib/libc/gen", - "/usr/src/lib/libc/stdio", - "/usr/src/lib/libc/sys", - "/usr/src/lib/libc/net/common", - "/usr/src/lib/libc/net/inet", - "/usr/src/lib/libc/net/misc", + "/usr/src/*", + "/usr/src/lib/libc/*", + "/usr/src/lib/libc/net/*", "/usr/src/ucb/pascal", "/usr/src/ucb/pascal/utilities", "/usr/src/undoc", -#endif 0 }; @@ -307,13 +197,7 @@ usage: } void -getlist(argcp, argvp, flagp, cntp) - char ***argvp; - int *argcp; - char ***flagp; - int *cntp; -{ - +getlist(int *argcp, char ***argvp, char ***flagp, int *cntp) { (*argvp)++; *flagp = *argvp; *cntp = 0; @@ -335,9 +219,7 @@ int count; int print; void -lookup(cp) - register char *cp; -{ +lookup(char *cp) { register char *dp; for (dp = cp; *dp; dp++) @@ -387,9 +269,7 @@ again: } void -looksrc(cp) - char *cp; -{ +looksrc(char *cp) { if (Sflag == 0) { find(srcdirs, cp); } else @@ -397,9 +277,7 @@ looksrc(cp) } void -lookbin(cp) - char *cp; -{ +lookbin(char *cp) { if (Bflag == 0) find(bindirs, cp); else @@ -407,9 +285,7 @@ lookbin(cp) } void -lookman(cp) - char *cp; -{ +lookman(char *cp) { if (Mflag == 0) { find(mandirs, cp); } else @@ -417,33 +293,54 @@ lookman(cp) } void -findv(dirv, dirc, cp) - char **dirv; - int dirc; - char *cp; -{ - +findv(char **dirv, int dirc, char *cp) { while (dirc > 0) findin(*dirv++, cp), dirc--; } void -find(dirs, cp) - char **dirs; - char *cp; -{ - +find(char **dirs, char *cp) { while (*dirs) findin(*dirs++, cp); } void -findin(dir, cp) - char *dir, *cp; -{ +findin(char *dir, char *cp) { DIR *dirp; struct direct *dp; + char *d, *dd; + int l; + char dirbuf[1024]; + struct stat statbuf; + + dd = index(dir, '*'); + if (!dd) + goto noglob; + + l = strlen(dir); + if (l < sizeof(dirbuf)) { /* refuse excessively long names */ + strcpy (dirbuf, dir); + d = index(dirbuf, '*'); + *d = 0; + dirp = opendir(dirbuf); + if (dirp == NULL) + return; + while ((dp = readdir(dirp)) != NULL) { + if (strlen(dp->d_name) + l > sizeof(dirbuf)) + continue; + sprintf(d, "%s", dp->d_name); + if (stat(dirbuf, &statbuf)) + continue; + if (!S_ISDIR(statbuf.st_mode)) + continue; + strcat(d, dd+1); + findin(dirbuf, cp); + } + closedir(dirp); + } + return; + noglob: dirp = opendir(dir); if (dirp == NULL) return; @@ -458,13 +355,17 @@ findin(dir, cp) } int -itsit(cp, dp) - register char *cp, *dp; -{ - register int i = strlen(dp); +itsit(char *cp, char *dp) { + int i = strlen(dp); if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp+2)) return (1); + if (!strcmp(dp+i-2, ".Z")) + i -= 2; + else if (!strcmp(dp+i-3, ".gz")) + i -= 3; + else if (!strcmp(dp+i-4, ".bz2")) + i -= 4; while (*cp && *dp && *cp == *dp) cp++, dp++, i--; if (*cp == 0 && *dp == 0) diff --git a/misc-utils/write.c b/misc-utils/write.c index 545404b4..e43b0bf9 100644 --- a/misc-utils/write.c +++ b/misc-utils/write.c @@ -42,18 +42,6 @@ * - ANSIed it since I was working on it anyway. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1989, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#define _GNU_SOURCE /* for snprintf */ - #include #include #include @@ -276,7 +264,9 @@ int term_chk(char *tty, int *msgsokP, time_t *atimeP, int showerror) struct stat s; char path[MAXPATHLEN]; - (void)snprintf(path, sizeof(path), "/dev/%s", tty); + if (strlen(tty) + 6 > sizeof(path)) + return(1); + (void)sprintf(path, "/dev/%s", tty); if (stat(path, &s) < 0) { if (showerror) (void)fprintf(stderr, @@ -307,7 +297,9 @@ void do_write(char *tty, char *mytty, uid_t myuid) else login = "???"; - (void)snprintf(path, sizeof(path), "/dev/%s", tty); + if (strlen(tty) + 6 > sizeof(path)) + exit(1); + (void)sprintf(path, "/dev/%s", tty); if ((freopen(path, "w", stdout)) == NULL) { (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno)); exit(1); diff --git a/mount/Makefile b/mount/Makefile index cfbedd59..32272a9b 100644 --- a/mount/Makefile +++ b/mount/Makefile @@ -66,16 +66,20 @@ swapon: swapon.o version.o losetup: losetup.o $(LINK) $^ $(LDLIBS) -o $@ +mount.o: linux_fs.h + 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 +mount.o umount.o losetup.o lomount.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 @@ -95,8 +99,6 @@ 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 @@ -107,6 +109,7 @@ nfs_mountversion.h: echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \ fi > nfs_mountversion.h +SWAPH=/usr/include/linux/swap.h swap.h: rm -f swap.h if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi @@ -115,14 +118,11 @@ swapargs.h: sh swap.configure loop.h: - rm -f loop.h - if [ -f $(LOOPH) ]; then cp $(LOOPH) .; else touch loop.h; fi + sh mk_loop_h clean: - rm -f a.out core *~ *.o swapargs.h $(PROGS) - -cleaner: clean + rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff rm -f swap.h loop.h nfs_mountversion.h -clobber distclean realclean: cleaner +clobber distclean realclean: clean # rm -f $(GEN_FILES) diff --git a/mount/Makefile.standalone b/mount/Makefile.standalone index 9576cdb1..2cedcd23 100644 --- a/mount/Makefile.standalone +++ b/mount/Makefile.standalone @@ -135,9 +135,7 @@ loop.h: 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 +clobber distclean realclean: clean rm -f $(GEN_FILES) diff --git a/mount/fstab.5 b/mount/fstab.5 index e276350c..8af521b2 100644 --- a/mount/fstab.5 +++ b/mount/fstab.5 @@ -36,6 +36,7 @@ .\" Sat Nov 20 20:47:38 1993: hpfs documentation added .\" Sat Nov 27 20:23:32 1993: Updated authorship information .\" Wed Jul 26 00:00:00 1995: Updated some nfs stuff, joey@infodrom.north.de +.\" Tue Apr 2 00:38:28 1996: added info about "noauto", "user", etc. .\" .TH FSTAB 5 "27 November 1993" "Linux 0.99" "Linux Programmer's Manual" .SH NAME @@ -53,7 +54,10 @@ is described on a separate line; fields on each line are separated by tabs or spaces. The order of records in .B fstab is important because -.BR fsck "(8), " mount "(8), and " umount "(8) +.BR fsck (8), +.BR mount (8), +and +.BR umount (8) sequentially iterate through .B fstab doing their thing. @@ -122,6 +126,10 @@ see .BR mount (8). For documentation on all nfs-specific options have a look at .BR nfs (5). +Common for all types of file system are the options ``noauto'' +(do not mount when "mount -a" is given, e.g., at boot time), +and ``user'' (allow a user to mount). For more details, see +.BR mount (8). The fifth field, .RI ( fs_freq ), diff --git a/mount/fstab.c b/mount/fstab.c index 524779a6..6a2adc65 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -372,12 +372,12 @@ update_mtab (const char *dir, struct mntent *instead) { 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, + fprintf(stderr, "error changing mode of %s: %s\n", MOUNTED_TEMP, strerror (errno)); endmntent (ftmp); if (rename (MOUNTED_TEMP, MOUNTED) < 0) - fprintf(stderr, "can't rename %s to %s: %s", MOUNTED_TEMP, MOUNTED, + fprintf(stderr, "can't rename %s to %s: %s\n", MOUNTED_TEMP, MOUNTED, strerror(errno)); leave: diff --git a/mount/h/loop.h b/mount/h/loop.h index a78dff72..1bd7fa87 100644 --- a/mount/h/loop.h +++ b/mount/h/loop.h @@ -25,20 +25,12 @@ struct loop_info { char reserved[4]; }; -/* - * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet - */ - #define LO_CRYPT_NONE 0 #define LO_CRYPT_XOR 1 #define LO_CRYPT_DES 2 #define LO_CRYPT_IDEA 3 #define MAX_LO_CRYPT 4 -/* - * IOCTL commands --- we will commandeer 0x4C ('L') - */ - #define LOOP_SET_FD 0x4C00 #define LOOP_CLR_FD 0x4C01 #define LOOP_SET_STATUS 0x4C02 diff --git a/mount/linux_fs.h b/mount/linux_fs.h new file mode 100644 index 00000000..4e73c3b0 --- /dev/null +++ b/mount/linux_fs.h @@ -0,0 +1,59 @@ +/* Including became more and more painful. + Below a very abbreviated version of some declarations, + only designed to be able to check a magic number + in case no filesystem type was given. */ + +#ifndef BLKGETSIZE +#define BLKGETSIZE 0x1260 /* return device size */ +#endif + +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +struct minix_super_block { + u_char s_dummy[16]; + u_char s_magic[2]; +}; +#define minixmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define ISODCL(from, to) (to - from + 1) +#define ISO_STANDARD_ID "CD001" +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +#define HS_STANDARD_ID "CDROM" +struct hs_volume_descriptor { + char foo[ISODCL ( 1, 8)]; /* 733 */ + char type[ISODCL ( 9, 9)]; /* 711 */ + char id[ISODCL ( 10, 14)]; + char version[ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + +#define EXT_SUPER_MAGIC 0x137D +struct ext_super_block { + u_char s_dummy[56]; + u_char s_magic[2]; +}; +#define extmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define EXT2_PRE_02B_MAGIC 0xEF51 +#define EXT2_SUPER_MAGIC 0xEF53 +struct ext2_super_block { + u_char s_dummy[56]; + u_char s_magic[2]; +}; +#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define _XIAFS_SUPER_MAGIC 0x012FD16D +struct xiafs_super_block { + u_char s_boot_segment[512]; /* 1st sector reserved for boot */ + u_char s_dummy[60]; + u_char s_magic[4]; +}; +#define xiafsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) diff --git a/mount/lomount.c b/mount/lomount.c index a6ad187a..276ab4e4 100644 --- a/mount/lomount.c +++ b/mount/lomount.c @@ -18,13 +18,12 @@ #include #include -#if defined(__GLIBC__) -#define _SOCKETBITS_H -#endif /* __GLIBC */ -#include "sundries.h" /* for xstrdup */ #include "loop.h" #include "lomount.h" +char *xstrdup (const char *s); /* not: #include "sundries.h" */ +void error (const char *fmt, ...); /* idem */ + #ifdef LOOP_SET_FD struct crypt_type_struct { int id; @@ -137,17 +136,17 @@ find_unused_loop_device (void) if (loop_known == 1) error( "mount: Could not find any loop device.\n" -" Maybe /dev/loop# has a wrong major number?\n"); +" Maybe /dev/loop# has a wrong major number?"); 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); +" (If so, then recompile or `insmod loop.o'.)", 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"); +" maybe /dev/loop# has the wrong major number?"); } else error("mount: could not find any free loop device"); return 0; @@ -180,7 +179,7 @@ set_loop (const char *device, const char *file, int offset, 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); + fprintf (stderr, "Unsupported encryption type %s\n", encryption); return 1; } loopinfo.lo_offset = offset; diff --git a/mount/losetup.c b/mount/losetup.c index ae5886ac..8f9dbe52 100644 --- a/mount/losetup.c +++ b/mount/losetup.c @@ -56,7 +56,7 @@ static void show_loop(const char *device) { struct loop_info loopinfo; int fd; - + if ((fd = open(device, O_RDWR)) < 0) { perror(device); return; @@ -80,7 +80,7 @@ int set_loop(const char *device, const char *file, int offset, 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)) { @@ -98,7 +98,7 @@ int set_loop(const char *device, const char *file, int offset, 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); + fprintf(stderr,"Unsupported encryption type %s\n",encryption); exit(1); } loopinfo.lo_offset = offset; diff --git a/mount/mk_loop_h b/mount/mk_loop_h new file mode 100644 index 00000000..9351b57e --- /dev/null +++ b/mount/mk_loop_h @@ -0,0 +1,30 @@ +#!/bin/sh +# +# Figure out (i) the type of dev_t (ii) the defines for loop stuff +# + +rm -f loop.h + +# Since 1.3.79 there is an include file +# that defines __kernel_dev_t. +# (The file itself appeared in 1.3.78, but there it defined __dev_t.) +# If it exists, we use it. Otherwise we guess that __kernel_dev_t +# is an unsigned short (which is true on i386, but false on alpha). + +if [ -f /usr/include/asm/posix_types.h ]; then + echo '#include ' >> loop.h + echo '#define dev_t __kernel_dev_t' >> loop.h +else + echo '#define dev_t unsigned short' >> loop.h +fi + +# Next we have to find the loop stuff itself. +# First try kernel source, then a private version. + +if [ -f /usr/include/linux/loop.h ]; then + echo '#include ' >> loop.h +else + echo '#include "h/loop.h"' >> loop.h +fi + +echo '#undef dev_t' >> loop.h diff --git a/mount/mount.8 b/mount/mount.8 index e1ed6f4a..097dee00 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -27,21 +27,22 @@ .\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, .\" USA. .\" -.\" 960705, aeb: version for mount-2.5k +.\" 960705, aeb: version for mount-2.7g .\" 970114, aeb: xiafs and ext are dead; romfs is new .\" 970623, aeb: -F option +.\" 970914, reg: -s option .\" -.TH MOUNT 8 "5 July 1996" "Linux 2.0" "Linux Programmer's Manual" +.TH MOUNT 8 "14 September 1997" "Linux 2.0" "Linux Programmer's Manual" .SH NAME mount \- mount a file system .SH SYNOPSIS .BI "mount [\-hV]" .LP -.BI "mount \-a [\-fFnrvw] [\-t " vfstype ] +.BI "mount \-a [\-fFnrsvw] [\-t " vfstype ] .br -.BI "mount [\-fnrvw] [\-o " options " [,...]] " "device " | " dir" +.BI "mount [\-fnrsvw] [\-o " options " [,...]] " "device " | " dir" .br -.BI "mount [\-fnrvw] [\-t " vfstype "] [\-o " options "] " "device dir" +.BI "mount [\-fnrsvw] [\-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 @@ -224,7 +225,8 @@ Mount all filesystems (of the given types) mentioned in (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 will do the mounts on different devices or different NFS servers +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 @@ -249,6 +251,12 @@ This is necessary for example when .I /etc is on a read-only file system. .TP +.B \-s +Tolerate sloppy mount options rather than failing. This will ignore +mount options not supported by a filesystem type. Not all filesystems +support this option. This option exists for support of the Linux +autofs\-based automounter. +.TP .B \-r Mount the file system read-only. A synonym is .BR "\-o ro" . diff --git a/mount/mount.c b/mount/mount.c index 98093956..19c50764 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -27,6 +27,9 @@ * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect * * Since then, many changes - aeb. + * + * Wed Oct 1 23:55:28 1997: Dick Streefland + * Implemented the "bg", "fg" and "retry" mount options for NFS. */ #include @@ -34,6 +37,7 @@ #include #include #include +#include #include #include @@ -41,27 +45,26 @@ #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 - -#if defined(__GLIBC__) -#define _SOCKETBITS_H -#endif /* __GLIBC */ +#include "mount_constants.h" #include "sundries.h" #include "fstab.h" #include "lomount.h" #include "loop.h" +#include "linux_fs.h" #define PROC_FILESYSTEMS "/proc/filesystems" #define SIZE(a) (sizeof(a)/sizeof(a[0])) +#define DO_PS_FIDDLING + +#ifdef DO_PS_FIDDLING +#define PROC_NAME "mount: " +static int argc0; +static char** argv0; +static char** envp0; +extern char** environ; +#endif + /* True for fake mount (-f). */ int fake = 0; @@ -74,6 +77,9 @@ int readonly = 0; /* Nonzero for chatty (-v). */ int verbose = 0; +/* Nonzero for sloppy (-s). */ +int sloppy = 0; + /* True for explicit read/write (-w). */ int readwrite = 0; @@ -145,6 +151,10 @@ const struct opt_map opt_map[] = { #ifdef MS_NOATIME { "atime", 0, 1, MS_NOATIME }, /* Update access time */ { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */ +#endif +#ifdef MS_NODIRATIME + { "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */ + { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */ #endif { NULL, 0, 0, 0 } }; @@ -307,30 +317,6 @@ fix_opts_string (int flags, char *extra_opts) 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); @@ -348,7 +334,7 @@ swapped(unsigned short a) { 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 + Added romfs - aeb Currently supports: minix, ext, ext2, xiafs, iso9660, romfs */ @@ -394,20 +380,20 @@ fstype(const char *device) if (fd < 0) return 0; - if (lseek(fd, BLOCK_SIZE, SEEK_SET) != BLOCK_SIZE + if (lseek(fd, 1024, SEEK_SET) != 1024 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) goto io_error; - if (sb.e2s.s_magic == EXT2_SUPER_MAGIC - || sb.e2s.s_magic == EXT2_PRE_02B_MAGIC - || sb.e2s.s_magic == swapped(EXT2_SUPER_MAGIC)) + if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC + || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC + || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) type = "ext2"; - else if (sb.ms.s_magic == MINIX_SUPER_MAGIC - || sb.ms.s_magic == MINIX_SUPER_MAGIC2) + else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC + || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2) type = "minix"; - else if (sb.es.s_magic == EXT_SUPER_MAGIC) + else if (extmagic(sb.es) == EXT_SUPER_MAGIC) type = "ext"; if (!type) { @@ -415,7 +401,7 @@ fstype(const char *device) || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) goto io_error; - if (xsb.xiasb.s_magic == _XIAFS_SUPER_MAGIC) + if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) type = "xiafs"; else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) type = "romfs"; @@ -590,9 +576,16 @@ try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { return -1; } +/* + * try_mount_one() + * Try to mount one file system. When "bg" is 1, this is a retry + * in the background. One additional exit code EX_BG is used here. + * It is used to instruct the caller to retry the mount in the + * background. + */ static int -mount_one (char *spec0, char *node0, char *type0, char *opts0, - int freq, int pass) +try_mount_one (char *spec0, char *node0, char *type0, char *opts0, + int freq, int pass, int bg) { struct mntentchn mcn; struct mntent mnt; @@ -603,31 +596,13 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, static int added_ro = 0; int loop, looptype, offset; char *spec, *node, *type, *opts, *loopdev, *loopfile; + struct stat statbuf; 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 */ @@ -645,10 +620,13 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, mount_opts = extra_opts; /* - * A loop mount? - * Only test for explicitly specified loop here, - * and try implicit loop if the mount fails. + * 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. */ + loopdev = opt_loopdev; looptype = (type && strncmp("lo@", type, 3) == 0); @@ -691,14 +669,16 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, } } - if (!fake && type && streq (type, "nfs")) + if (!fake && type && streq (type, "nfs")) { #ifdef HAVE_NFS - if (nfsmount (spec, node, &flags, &extra_opts, &mount_opts) != 0) - return EX_FAIL; + mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, bg); + if (mnt_err) + return mnt_err; #else die (EX_SOFTWARE, "mount: this version was compiled " "without support for the type `nfs'"); #endif + } /* * Call mount.TYPE for types that require a separate @@ -711,7 +691,6 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, if (strlen (type) < 100) #endif { - struct stat statbuf; char mountprog[120]; sprintf(mountprog, "/sbin/mount.%s", type); @@ -805,7 +784,6 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, { case EPERM: 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 @@ -822,29 +800,26 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, } break; case ENOENT: - { struct stat statbuf; - if (lstat (node, &statbuf)) - error ("mount: mount point %s does not exist", node); - else if (stat (node, &statbuf)) - error ("mount: mount point %s is a symbolic link to nowhere", - node); - else if (stat (spec, &statbuf)) - error ("mount: special device %s does not exist", spec); - else { + if (lstat (node, &statbuf)) + error ("mount: mount point %s does not exist", node); + else if (stat (node, &statbuf)) + error ("mount: mount point %s is a symbolic link to nowhere", + node); + else if (stat (spec, &statbuf)) + error ("mount: special device %s does not exist", spec); + else { errno = mnt_err; perror("mount"); - } - break; } + break; case ENOTDIR: error ("mount: mount point %s is not a directory", node); break; case EINVAL: { int fd, size; - struct stat statbuf; if (flags & MS_REMOUNT) { - error ("mount: %s not mounted already, or bad option\n", node); + error ("mount: %s not mounted already, or bad option", node); } else { error ("mount: wrong fs type, bad option, bad superblock on %s,\n" " or too many mounted file systems", @@ -854,7 +829,7 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, && (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"); + " instead of some logical partition inside?)"); close(fd); } } @@ -892,19 +867,16 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, spec, type); break; case ENOTBLK: - { 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'?)", + 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); - } + else + error ("mount: %s is not a block device", spec); break; case ENXIO: error ("mount: %s is not a valid block device", spec); break; @@ -929,7 +901,7 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, type = 0; error ("mount: %s%s is write-protected, mounting read-only", loop ? "" : "block device ", spec0); - return mount_one (spec0, node0, type, opts, freq, pass); + return try_mount_one (spec0, node0, type, opts, freq, pass, bg); } break; default: @@ -938,6 +910,90 @@ mount_one (char *spec0, char *node0, char *type0, char *opts0, return EX_FAIL; } +/* + * set_proc_name() + * Update the argument vector, so that this process may be easily + * identified in a "ps" listing. + */ +static void +set_proc_name (char *spec) +{ +#ifdef DO_PS_FIDDLING + int i, l; + + /* + * Move the environment so we can reuse the memory. + * (Code borrowed from sendmail.) + * WARNING: ugly assumptions on memory layout here; if this ever causes + * problems, #undef DO_PS_FIDDLING + */ + for (i = 0; envp0[i] != NULL; i++) + continue; + environ = (char **) xmalloc(sizeof(char *) * (i + 1)); + for (i = 0; envp0[i] != NULL; i++) + environ[i] = xstrdup(envp0[i]); + environ[i] = NULL; + + if (i > 0) + l = envp0[i-1] + strlen(envp0[i-1]) - argv0[0]; + else + l = argv0[argc0-1] + strlen(argv0[argc0-1]) - argv0[0]; + if (l > sizeof(PROC_NAME)) { + strcpy(argv0[0], PROC_NAME); + strncpy(argv0[0] + sizeof(PROC_NAME) - 1, spec, l - sizeof(PROC_NAME) - 1); + argv0[1] = NULL; + } +#endif +} + +static int +mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts, + int freq, int pass) +{ + int status; + int status2; + + /* Merge the fstab and command line options. */ + if (opts == NULL) + opts = cmdlineopts; + else if (cmdlineopts != NULL) + opts = xstrconcat3(opts, ",", cmdlineopts); + + 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"); + } + } + + /* + * Try to mount the file system. When the exit status is EX_BG, + * we will retry in the background. Otherwise, we're done. + */ + status = try_mount_one (spec, node, type, opts, freq, pass, 0); + if (status != EX_BG) + return status; + + /* + * Retry in the background. + */ + printf ("mount: backgrounding \"%s\"\n", spec); + fflush( stdout ); /* prevent duplicate output */ + if (fork() > 0) + return 0; /* parent returns "success" */ + spec = xstrdup(spec); /* arguments will be destroyed */ + node = xstrdup(node); /* by set_proc_name() */ + type = xstrdup(type); + opts = xstrdup(opts); + set_proc_name (spec); /* make a nice "ps" listing */ + status2 = try_mount_one (spec, node, type, opts, freq, pass, 1); + if (verbose && status2) + printf ("mount: giving up \"%s\"\n", spec); + exit (0); /* child stops here */ +} + /* Check if an fsname/dir pair was already in the old mtab. */ static int mounted (char *spec, char *node) { @@ -956,23 +1012,25 @@ mounted (char *spec, char *node) { /* 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) +#define DISKMAJOR(m) (((int) m) & ~0xf) static int -mount_all (string_list types) { +mount_all (string_list types, char *options) { struct mntentchn *mc, *mtmp; - int status = 0, m; + int status = 0; struct stat statbuf; struct child { pid_t pid; - dev_t major; + char *group; struct mntentchn *mec; struct mntentchn *meclast; struct child *nxt; } childhead, *childtail, *cp; + char major[22]; + char *g, *colon; /* build a chain of what we have to do, or maybe - several chains, one for each major */ + several chains, one for each major or NFS host */ childhead.nxt = 0; childtail = &childhead; for (mc = fstab_head()->nxt; mc; mc = mc->nxt) { @@ -987,13 +1045,25 @@ mount_all (string_list types) { 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) { + g = NULL; + if (optfork) { + if (stat(mc->mnt_fsname, &statbuf) == 0 && + S_ISBLK(statbuf.st_mode)) { + sprintf(major, "#%x", DISKMAJOR(statbuf.st_rdev)); + g = major; + } +#ifdef HAVE_NFS + if (strcmp(mc->mnt_type, "nfs") == 0) { + g = xstrdup(mc->mnt_fsname); + colon = strchr(g, ':'); + if (colon) + *colon = '\0'; + } +#endif + } + if (g) { for (cp = childhead.nxt; cp; cp = cp->nxt) - if (cp->major == m) { + if (cp->group && strcmp(cp->group, g) == 0) { cp->meclast->nxt = mtmp; cp->meclast = mtmp; goto fnd; @@ -1002,7 +1072,7 @@ mount_all (string_list types) { cp = (struct child *) xmalloc(sizeof *cp); cp->nxt = 0; cp->mec = cp->meclast = mtmp; - cp->major = m; + cp->group = xstrdup(g); cp->pid = 0; childtail->nxt = cp; childtail = cp; @@ -1026,7 +1096,8 @@ mount_all (string_list types) { 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); + mc->mnt_type, mc->mnt_opts, + options, 0, 0); if (mountcount) status |= EX_SOMEOK; if (p == 0) @@ -1076,9 +1147,9 @@ static struct option longopts[] = const char *usage_string = "\ usage: mount [-hV]\n\ - mount -a [-nfFrvw] [-t vfstypes]\n\ - mount [-nfrvw] [-o options] special | node\n\ - mount [-nfrvw] [-t vfstype] [-o options] special node\n\ + mount -a [-nfFrsvw] [-t vfstypes]\n\ + mount [-nfrsvw] [-o options] special | node\n\ + mount [-nfrsvw] [-t vfstype] [-o options] special node\n\ "; static void @@ -1096,7 +1167,13 @@ main (int argc, char *argv[]) { string_list types = NULL; struct mntentchn *mc; - while ((c = getopt_long (argc, argv, "afFhno:rvVwt:", longopts, NULL)) +#ifdef DO_PS_FIDDLING + argc0 = argc; + argv0 = argv; + envp0 = environ; +#endif + + while ((c = getopt_long (argc, argv, "afFhno:rsvVwt:", longopts, NULL)) != EOF) switch (c) { case 'a': /* mount everything in fstab */ @@ -1124,6 +1201,9 @@ main (int argc, char *argv[]) { readonly = 1; readwrite = 0; break; + case 's': /* allow sloppy mount options */ + sloppy = 1; + break; case 't': /* specify file system types */ types = parse_list (optarg); break; @@ -1147,11 +1227,10 @@ main (int argc, char *argv[]) { argc -= optind; argv += optind; - if (argc == 0) { + if (argc == 0 && !all) { if (options) usage (stderr, EX_USAGE); - if (!all) - return print_all (types); + return print_all (types); } if (getuid () != geteuid ()) { @@ -1169,7 +1248,7 @@ main (int argc, char *argv[]) { switch (argc) { case 0: /* mount -a */ - result = mount_all (types); + result = mount_all (types, options); if (result == 0 && verbose) error("not mounted anything"); break; @@ -1186,22 +1265,18 @@ main (int argc, char *argv[]) { 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 = mc->mnt_opts; - else - options = xstrconcat3(mc->mnt_opts, ",", options); - result = mount_one (xstrdup (mc->mnt_fsname), xstrdup (mc->mnt_dir), - xstrdup (mc->mnt_type), options, 0, 0); + xstrdup (mc->mnt_type), mc->mnt_opts, options, 0, 0); break; case 2: /* mount [-nfrvw] [-t vfstype] [-o options] special node */ if (types == NULL) - result = mount_one (argv[0], argv[1], NULL, options, 0, 0); + result = mount_one (argv[0], argv[1], + NULL, NULL, options, 0, 0); else if (cdr (types) == NULL) - result = mount_one (argv[0], argv[1], car (types), options, 0, 0); + result = mount_one (argv[0], argv[1], + car (types), NULL, options, 0, 0); else usage (stderr, EX_USAGE); break; diff --git a/mount/mount_constants.h b/mount/mount_constants.h index c0ae4984..5f033452 100644 --- a/mount/mount_constants.h +++ b/mount/mount_constants.h @@ -5,13 +5,12 @@ #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. */ - +#define MS_NODIRATIME 2048 /* Do not update directory access times */ /* * Magic mount flag number. Has to be or-ed to the flag values. */ +#ifndef MS_MGC_VAL #define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */ +#endif #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ diff --git a/mount/nfs.5 b/mount/nfs.5 index cdfba803..59f199b2 100644 --- a/mount/nfs.5 +++ b/mount/nfs.5 @@ -21,7 +21,7 @@ Here is an example from an \fI/etc/fstab\fP file from an NFS mount. .sp .nf .ta 2.5i +0.75i +0.75i +1.0i -server:/usr/local/pub /pub nfs timeo=14,intr +server:/usr/local/pub /pub nfs rsize=8192,wsize=8192,timeo=14,intr .fi .DT .SS Options @@ -29,10 +29,14 @@ server:/usr/local/pub /pub nfs timeo=14,intr .I rsize=n The number of bytes NFS uses when reading files from an NFS server. The default value is dependent on the kernel, currently 1024 bytes. +(However, throughput is improved greatly by asking for +.IR rsize=8192 .) .TP 1.5i .I wsize=n The number of bytes NFS uses when writing files to an NFS server. The default value is dependent on the kernel, currently 1024 bytes. +(However, throughput is improved greatly by asking for +.IR wsize=8192 .) .TP 1.5i .I timeo=n The value in tenths of a second before sending the @@ -85,9 +89,9 @@ to the same value. There is no default value. .TP 1.5i .I retry=n -The number of times to retry a backgrounded NFS mount operation -before giving up. -The default value is 10000 times. +The number of minutes to retry an NFS mount operation +in the foreground or background before giving up. +The default value is 10000 minutes, which is roughly one week. .TP 1.5i .I namlen=n When an NFS server does not support version two of the @@ -140,13 +144,20 @@ for hosts that can run multiple NFS servers. The default value is version 2. .TP 1.5i .I bg -If the first NFS mount attempt times out, continue trying the mount +If the first NFS mount attempt times out, retry the mount in the background. -The default is to not to background the mount on timeout but fail. +After a mount operation is backgrounded, all subsequent mounts +on the same NFS server will be backgrounded immediately, without +first attempting the mount. +A missing mount point is treated as a timeout, +to allow for nested NFS mounts. .TP 1.5i .I fg -If the first NFS mount attempt times out, fail immediately. -This is the default. +If the first NFS mount attempt times out, retry the mount +in the foreground. +This is the complement of the +.I bg +option, and also the default behavior. .TP 1.5i .I soft If an NFS file operation has a major timeout then report an I/O error to @@ -173,7 +184,7 @@ two of the RPC mount protocol. Many NFS servers support only version one. .TP 1.5i .I nocto -Supress the retrieval of new attributes when creating a file. +Suppress the retrieval of new attributes when creating a file. .TP 1.5i .I noac Disable all forms of attribute caching entirely. This extracts a @@ -199,7 +210,7 @@ interrupted. .SH AUTHOR "Rick Sladkey" .SH BUGS -The bg, fg, retry, posix, and nocto options are parsed by mount +The posix, and nocto options are parsed by mount but currently are silently ignored. .P The tcp and namlen options are implemented but are not currently diff --git a/mount/nfsmount.c b/mount/nfsmount.c index ee869dc4..fd936466 100644 --- a/mount/nfsmount.c +++ b/mount/nfsmount.c @@ -17,6 +17,9 @@ * * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : * Omit the call to connect() for Linux version 1.3.11 or later. + * + * Wed Oct 1 23:55:28 1997: Dick Streefland + * Implemented the "bg", "fg" and "retry" mount options for NFS. */ /* @@ -34,17 +37,14 @@ #include #include #include +#include #include #include "sundries.h" #include "nfsmount.h" -#if defined(__GLIBC__) -#define _LINUX_SOCKET_H -#endif /* __GLIBC__ */ -#define _I386_BITOPS_H -#include #include +#include "mount_constants.h" #include "nfs_mount3.h" static char *nfs_strerror(int stat); @@ -96,8 +96,9 @@ find_kernel_nfs_mount_version(void) { } int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts) + char **extra_opts, char **mount_opts, int running_bg) { + static char *prev_bg_host; char hostdir[1024]; CLIENT *mclient; char *hostname; @@ -115,8 +116,9 @@ int nfsmount(const char *spec, const char *node, int *flags, struct sockaddr_in server_addr; struct sockaddr_in mount_server_addr; int msock, fsock; - struct timeval pertry_timeout; + struct timeval retry_timeout; struct fhstatus status; + struct stat statbuf; char *s; int port; int mountport; @@ -133,9 +135,14 @@ int nfsmount(const char *spec, const char *node, int *flags, int mountvers; int nfsprog; int nfsvers; + int retval; + time_t t; + time_t prevt; + time_t timeout; find_kernel_nfs_mount_version(); + retval = EX_FAIL; msock = fsock = -1; mclient = NULL; if (strlen(spec) >= sizeof(hostdir)) { @@ -148,21 +155,30 @@ int nfsmount(const char *spec, const char *node, int *flags, hostname = hostdir; dirname = s + 1; *s = '\0'; - } - else { + } else { fprintf(stderr, "mount: " "directory to mount not in host:dir format\n"); goto fail; } server_addr.sin_family = AF_INET; - if (!inet_aton(hostname, &server_addr.sin_addr)) { +#if 1 /* old libc's do not have inet_aton() -- change 1 to 0 */ + if (!inet_aton(hostname, &server_addr.sin_addr)) +#endif + { 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); + } else { + if (hp->h_length > sizeof(struct in_addr)) { + fprintf(stderr, + "mount: got bad hp->h_length\n"); + hp->h_length = sizeof(struct in_addr); + } + memcpy(&server_addr.sin_addr, + hp->h_addr, hp->h_length); + } } memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); @@ -203,7 +219,7 @@ int nfsmount(const char *spec, const char *node, int *flags, nocto = 0; nolock = 0; noac = 0; - retry = 10000; + retry = 10000; /* 10000 minutes ~ 1 week */ tcp = 0; mountprog = MOUNTPROG; @@ -306,9 +322,11 @@ int nfsmount(const char *spec, const char *node, int *flags, else printf("Warning: option nolock is not supported.\n"); } else { - printf("unknown nfs mount option: " - "%s%s\n", val ? "" : "no", opt); - goto fail; + if (!sloppy) { + printf("unknown nfs mount option: " + "%s%s\n", val ? "" : "no", opt); + goto fail; + } } } } @@ -349,9 +367,6 @@ int nfsmount(const char *spec, const char *node, int *flags, printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0); #endif -#if 0 - goto fail; -#endif #endif data.version = nfs_mount_version; @@ -360,58 +375,132 @@ int nfsmount(const char *spec, const char *node, int *flags, if (*flags & MS_REMOUNT) return 0; + /* + * If the previous mount operation on the same host was + * backgrounded, and the "bg" for this mount is also set, + * give up immediately, to avoid the initial timeout. + */ + if (bg && !running_bg && + prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { + if (retry > 0) + retval = EX_BG; + return retval; + } + /* create mount deamon client */ /* See if the nfs host = mount host. */ if (mounthost) { if (mounthost[0] >= '0' && mounthost[0] <= '9') { mount_server_addr.sin_family = AF_INET; mount_server_addr.sin_addr.s_addr = inet_addr(hostname); - } - else if ((hp = gethostbyname(mounthost)) == NULL) { - fprintf(stderr, "mount: can't get address for %s\n", hostname); - goto fail; - } - else { - mount_server_addr.sin_family = AF_INET; - memcpy(&mount_server_addr.sin_addr, hp->h_addr, hp->h_length); + } else { + if ((hp = gethostbyname(mounthost)) == NULL) { + fprintf(stderr, "mount: can't get address for %s\n", + hostname); + goto fail; + } else { + if (hp->h_length > sizeof(struct in_addr)) { + fprintf(stderr, + "mount: got bad hp->h_length?\n"); + hp->h_length = sizeof(struct in_addr); + } + mount_server_addr.sin_family = AF_INET; + memcpy(&mount_server_addr.sin_addr, + hp->h_addr, hp->h_length); + } } } - mount_server_addr.sin_port = htons(mountport); - msock = RPC_ANYSOCK; - if ((mclient = clnttcp_create(&mount_server_addr, - mountprog, mountvers, &msock, 0, 0)) == NULL) { - mount_server_addr.sin_port = htons(mountport); - msock = RPC_ANYSOCK; - pertry_timeout.tv_sec = 3; - pertry_timeout.tv_usec = 0; - if ((mclient = clntudp_create(&mount_server_addr, - mountprog, mountvers, pertry_timeout, &msock)) == NULL) { - clnt_pcreateerror("mount clntudp_create"); + /* + * The following loop implements the mount retries. On the first + * call, "running_bg" is 0. When the mount times out, and the + * "bg" option is set, the exit status EX_BG will be returned. + * For a backgrounded mount, there will be a second call by the + * child process with "running_bg" set to 1. + * + * The case where the mount point is not present and the "bg" + * option is set, is treated as a timeout. This is done to + * support nested mounts. + * + * The "retry" count specified by the user is the number of + * minutes to retry before giving up. + * + * Only the first error message will be displayed. + */ + retry_timeout.tv_sec = 3; + retry_timeout.tv_usec = 0; + total_timeout.tv_sec = 20; + total_timeout.tv_usec = 0; + timeout = time(NULL) + 60 * retry; + prevt = 0; + t = 30; + val = 1; + for (;;) { + if (bg && stat(node, &statbuf) == -1) { + if (running_bg) { + sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ + val *= 2; + if (val > 30) + val = 30; + } + } else { + /* be careful not to use too many CPU cycles */ + if (t - prevt < 30) + sleep(30); + + /* contact the mount daemon via TCP */ + mount_server_addr.sin_port = htons(mountport); + msock = RPC_ANYSOCK; + mclient = clnttcp_create(&mount_server_addr, + mountprog, mountvers, + &msock, 0, 0); + + /* if this fails, contact the mount daemon via UDP */ + if (!mclient) { + mount_server_addr.sin_port = htons(mountport); + msock = RPC_ANYSOCK; + mclient = clntudp_create(&mount_server_addr, + mountprog, mountvers, + retry_timeout, &msock); + } + if (mclient) { + /* try to mount hostname:dirname */ + mclient->cl_auth = authunix_create_default(); + clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, + (xdrproc_t) xdr_dirpath, (caddr_t) &dirname, + (xdrproc_t) xdr_fhstatus, (caddr_t) &status, + total_timeout); + if (clnt_stat == RPC_SUCCESS) + break; /* we're done */ + if (errno != ECONNREFUSED) { + clnt_perror(mclient, "mount"); + goto fail; /* don't retry */ + } + if (!running_bg && prevt == 0) + clnt_perror(mclient, "mount"); + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + mclient = 0; + close(msock); + } else { + if (!running_bg && prevt == 0) + clnt_pcreateerror("mount"); + } + prevt = t; + } + if (!bg) + goto fail; + if (!running_bg) { + prev_bg_host = xstrdup(hostname); + if (retry > 0) + retval = EX_BG; goto fail; } -#ifdef NFS_MOUNT_DEBUG - printf("using UDP for mount deamon\n"); -#endif + t = time(NULL); + if (t >= timeout) + goto fail; } -#ifdef NFS_MOUNT_DEBUG - else - printf("using TCP for mount deamon\n"); -#endif - mclient->cl_auth = authunix_create_default(); - total_timeout.tv_sec = 20; - total_timeout.tv_usec = 0; - /* try to mount hostname:dirname */ - - clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, - (xdrproc_t) xdr_dirpath, &dirname, - (xdrproc_t) xdr_fhstatus, &status, - total_timeout); - if (clnt_stat != RPC_SUCCESS) { - clnt_perror(mclient, "rpc mount"); - goto fail; - } if (status.fhs_status != 0) { fprintf(stderr, "mount: %s:%s failed, reason given by server: %s\n", @@ -485,15 +574,16 @@ int nfsmount(const char *spec, const char *node, int *flags, fail: if (msock != -1) { - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); + if (mclient) { + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + } close(msock); } if (fsock != -1) close(fsock); - return 1; -} - + return retval; +} /* * We need to translate between nfs status return values and @@ -554,3 +644,33 @@ static char *nfs_strerror(int stat) return buf; } +#if 0 +int +my_getport(struct in_addr server, struct timeval *timeo, ...) +{ + struct sockaddr_in sin; + struct pmap pmap; + CLIENT *clnt; + int sock = RPC_ANYSOCK, port; + + pmap.pm_prog = prog; + pmap.pm_vers = vers; + pmap.pm_prot = prot; + pmap.pm_port = 0; + sin.sin_family = AF_INET; + sin.sin_addr = server; + sin.sin_port = htons(111); + clnt = clntudp_create(&sin, 100000, 2, *timeo, &sock); + status = clnt_call(clnt, PMAP_GETPORT, + &pmap, (xdrproc_t) xdr_pmap, + &port, (xdrproc_t) xdr_uint); + if (status != SUCCESS) { + /* natter */ + port = 0; + } + + clnt_destroy(clnt); + close(sock); + return port; +} +#endif diff --git a/mount/nfsmount_clnt.c b/mount/nfsmount_clnt.c index a77f4c5e..ef575258 100644 --- a/mount/nfsmount_clnt.c +++ b/mount/nfsmount_clnt.c @@ -66,7 +66,9 @@ mountproc_mnt_1(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, + (caddr_t) argp, (xdrproc_t) xdr_fhstatus, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -80,7 +82,9 @@ mountproc_dump_1(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, + (caddr_t) argp, (xdrproc_t) xdr_mountlist, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -94,7 +98,9 @@ mountproc_umnt_1(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, + (caddr_t) argp, (xdrproc_t) xdr_void, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return ((void *)&clnt_res); @@ -108,7 +114,9 @@ mountproc_umntall_1(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, + (caddr_t) argp, (xdrproc_t) xdr_void, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return ((void *)&clnt_res); @@ -122,7 +130,9 @@ mountproc_export_1(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, + (caddr_t) argp, (xdrproc_t) xdr_exports, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -136,8 +146,10 @@ mountproc_exportall_1(argp, 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); + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, + (caddr_t) argp, (xdrproc_t) xdr_exports, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); } return (&clnt_res); } @@ -164,7 +176,9 @@ mountproc_mnt_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_MNT, (xdrproc_t) xdr_dirpath, + (caddr_t) argp, (xdrproc_t) xdr_fhstatus, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -178,7 +192,9 @@ mountproc_dump_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_DUMP, (xdrproc_t) xdr_void, argp, + (xdrproc_t) xdr_mountlist, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -192,7 +208,9 @@ mountproc_umnt_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_UMNT, (xdrproc_t) xdr_dirpath, + (caddr_t) argp, (xdrproc_t) xdr_void, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return ((void *)&clnt_res); @@ -206,7 +224,9 @@ mountproc_umntall_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_UMNTALL, (xdrproc_t) xdr_void, + (caddr_t) argp, (xdrproc_t) xdr_void, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return ((void *)&clnt_res); @@ -220,7 +240,9 @@ mountproc_export_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_EXPORT, (xdrproc_t) xdr_void, + argp, (xdrproc_t) xdr_exports, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -234,7 +256,9 @@ mountproc_exportall_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_EXPORTALL, (xdrproc_t) xdr_void, argp, + (xdrproc_t) xdr_exports, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); @@ -248,7 +272,9 @@ mountproc_pathconf_2(argp, 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) { + if (clnt_call(clnt, MOUNTPROC_PATHCONF, (xdrproc_t) xdr_dirpath, + (caddr_t) argp, (xdrproc_t) xdr_ppathcnf, + (caddr_t) &clnt_res, TIMEOUT) != RPC_SUCCESS) { return (NULL); } return (&clnt_res); diff --git a/mount/realpath.c b/mount/realpath.c index 4214cad7..0eebba3a 100644 --- a/mount/realpath.c +++ b/mount/realpath.c @@ -46,9 +46,6 @@ extern char *realpath(const char *path, char *resolved_path); #include /* for MAXPATHLEN */ #endif #include -#ifndef STDC_HEADERS -extern int errno; -#endif #include /* for S_IFLNK */ @@ -183,4 +180,3 @@ char *resolved_path; *new_path = '\0'; return resolved_path; } - diff --git a/mount/sundries.h b/mount/sundries.h index 0c96f865..cad87a1c 100644 --- a/mount/sundries.h +++ b/mount/sundries.h @@ -1,6 +1,6 @@ /* + * sundries.h * Support function prototypes. Functions are in sundries.c. - * sundries.h,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp */ #include @@ -9,12 +9,13 @@ #include #include #include -#ifndef bool_t +#if !defined(bool_t) && !defined(__GLIBC__) #include #endif extern int mount_quiet; extern int verbose; +extern int sloppy; #define streq(s, t) (strcmp ((s), (t)) == 0) @@ -31,9 +32,6 @@ typedef struct string_list string_list cons (char *a, const string_list); -/* Quiet compilation with -Wmissing-prototypes. */ -int main (int argc, char *argv[]); - /* Functions in sundries.c that are used in mount.c and umount.c */ void block_signals (int how); char *canonicalize (const char *path); @@ -61,7 +59,7 @@ void die (int errcode, const char *fmt, ...); #ifdef HAVE_NFS int nfsmount (const char *spec, const char *node, int *flags, - char **orig_opts, char **opt_args); + char **orig_opts, char **opt_args, int running_bg); #endif /* exit status - bits below are ORed */ @@ -72,3 +70,5 @@ int nfsmount (const char *spec, const char *node, int *flags, #define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ #define EX_FAIL 32 /* mount failure */ #define EX_SOMEOK 64 /* some mount succeeded */ + +#define EX_BG 256 /* retry in background (internal only) */ diff --git a/mount/swap.configure b/mount/swap.configure index 70bce506..a557e187 100644 --- a/mount/swap.configure +++ b/mount/swap.configure @@ -1,5 +1,7 @@ -# find out whether we can include +# Find out whether we can include # and whether libc thinks that swapon() has two arguments. +# Of course this will fail if exists but belongs +# to a libc that is not in use at present. CC=${CC-cc} compile="$CC -o conftest conftest.c >/dev/null 2>&1" rm -f conftest conftest.c swapargs.h diff --git a/mount/umount.c b/mount/umount.c index de80fd1b..6f28213b 100644 --- a/mount/umount.c +++ b/mount/umount.c @@ -100,13 +100,18 @@ nfs_umount_rpc_call(const char *spec, const char *opts) if (hostname[0] >= '0' && hostname[0] <= '9') saddr.sin_addr.s_addr = inet_addr(hostname); - else + else { if ((hostp = gethostbyname(hostname)) == NULL) { - fprintf(stderr, "mount: can't get address for %s\n", + fprintf(stderr, "umount: can't get address for %s\n", hostname); return 1; - } else - memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); + } + if (hostp->h_length > sizeof(struct in_addr)) { + fprintf(stderr, "umount: got bad hostp->h_length\n"); + hostp->h_length = sizeof(struct in_addr); + } + memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length); + } saddr.sin_family = AF_INET; saddr.sin_port = 0; diff --git a/mount/version.c b/mount/version.c index c17613e0..0c9363d3 100644 --- a/mount/version.c +++ b/mount/version.c @@ -1 +1 @@ -char version[] = "mount-2.7e"; +char version[] = "mount-2.8"; diff --git a/sys-utils/Makefile b/sys-utils/Makefile index 9513717e..9085fa96 100644 --- a/sys-utils/Makefile +++ b/sys-utils/Makefile @@ -11,35 +11,27 @@ include ../MCONFIG MAN1= arch.1 readprofile.1 -MAN8= chroot.8 ctrlaltdel.8 cytune.8 dmesg.8 \ +MAN8= 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. . . +BIN= arch dmesg + +USRBIN= cytune ipcrm ipcs renice readprofile setsid tunelp + SBIN= sln ctrlaltdel kbdrate ifneq "$(CPU)" "sparc" +MAN8:= $(MAN8) hwclock.8 SBIN:=$(SBIN) hwclock endif -BIN= arch dmesg - -USRSBIN= chroot - -USRBIN= cytune ipcrm ipcs renice readprofile setsid tunelp - ifeq "$(CPU)" "intel" +MAN8:= $(MAN8) rdev.8 USRBIN:=$(USRBIN) rdev endif @@ -47,7 +39,7 @@ endif USRINFO= ipc.info -all: $(SBIN) $(BIN) $(USRSBIN) $(USRBIN) +all: $(SBIN) $(BIN) $(USRBIN) sln: sln.c $(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@ @@ -55,7 +47,6 @@ sln: sln.c # Rules for everything else arch: arch.o -chroot: chroot.o hwclock.o: hwclock.c shhopt.h hwclock: hwclock.o shhopt.o ctrlaltdel: ctrlaltdel.o @@ -68,10 +59,9 @@ readprofile: readprofile.o setsid: setsid.o install: all - $(INSTALLDIR) $(SBINDIR) $(BINDIR) $(USRSBINDIR) $(USRBINDIR) + $(INSTALLDIR) $(SBINDIR) $(BINDIR) $(USRBINDIR) $(INSTALLBIN) $(SBIN) $(SBINDIR) $(INSTALLBIN) $(BIN) $(BINDIR) - $(INSTALLBIN) $(USRSBIN) $(USRSBINDIR) $(INSTALLBIN) $(USRBIN) $(USRBINDIR) (cd $(USRBINDIR); ln -sf rdev swapdev) (cd $(USRBINDIR); ln -sf rdev ramsize) @@ -83,4 +73,4 @@ install: all $(INSTALLMAN) $(USRINFO) $(INFODIR) clean: - -rm -f *.o *~ core $(SBIN) $(BIN) $(USRSBIN) $(USRBIN) + -rm -f *.o *~ core $(SBIN) $(BIN) $(USRBIN) diff --git a/sys-utils/arch.1 b/sys-utils/arch.1 index a2830ed3..9ce88db5 100644 --- a/sys-utils/arch.1 +++ b/sys-utils/arch.1 @@ -9,10 +9,25 @@ arch \- print machine architecture .SH DESCRIPTION .B arch is equivalent to -.B uname -m +.BR "uname -m" . On current Linux systems, .B arch -prints things such as "i386" or "i486". +prints things such as "i386", "i486", "i586", "alpha", "sparc", +"arm", "m68k", "mips", "ppc". .SH SEE ALSO .BR uname (1) ", " uname (2) +.\" +.\" Details: +.\" arch prints the machine part of the system_utsname struct +.\" This struct is defined in version.c, and this field is +.\" initialized with UTS_MACHINE, which is defined as $ARCH +.\" in the main Makefile. +.\" That gives the possibilities +.\" alpha arm i386 m68k mips ppc sparc sparc64 +.\" +.\" If Makefile is not edited, ARCH is guessed by +.\" ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) +.\" Then how come we get these i586 values? +.\" Well, the routine check_bugs() does system_utsname.machine[1] = '0' + x86; +.\" (called in init/main.c, defined in ./include/asm-i386/bugs.h) diff --git a/sys-utils/chroot.8 b/sys-utils/chroot.8 deleted file mode 100644 index 4beadbfd..00000000 --- a/sys-utils/chroot.8 +++ /dev/null @@ -1,16 +0,0 @@ -.\" Rick Sladkey -.\" In the public domain. -.\" Pathname modified by faith@cs.unc.edu -.TH CHROOT 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -chroot \- change root directory and execute a program there -.SH SYNOPSIS -.BI chroot " directory program" " [ " "arg ..." " ]" -.SH DESCRIPTION -.B chroot -changes the root directory for a process to a new directory -executes a program there. -.SH "SEE ALSO" -.BR chroot (2) -.SH AUTHOR -Rick Sladkey diff --git a/sys-utils/chroot.c b/sys-utils/chroot.c deleted file mode 100644 index 7ddbe791..00000000 --- a/sys-utils/chroot.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * chroot.c -- change root directory and execute a command there - * Rick Sladkey - * In the public domain. - */ - -#include -#include -#include - -int main(int argc, char *argv[]) -{ - if (argc < 3) { - fprintf(stderr, "usage: %s directory program [arg ...]\n", - argv[0]); - exit(1); - } - if (chroot(argv[1]) < 0) { - perror("chroot"); - exit(1); - } - execvp(argv[2], argv + 2); - perror("execvp"); - exit(1); -} diff --git a/sys-utils/cytune.c b/sys-utils/cytune.c index f7fe1ee3..510703b9 100644 --- a/sys-utils/cytune.c +++ b/sys-utils/cytune.c @@ -44,7 +44,10 @@ #include #include #include -#include +#if 0 +#include /* required for old kernels */ + /* compilation errors on other kernels */ +#endif #include #include diff --git a/sys-utils/dmesg.8 b/sys-utils/dmesg.8 index d2e4ce1b..f453d714 100644 --- a/sys-utils/dmesg.8 +++ b/sys-utils/dmesg.8 @@ -1,10 +1,10 @@ .\" Copyright 1993 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH DMESG 8 "28 October 1993" "Linux 0.99" "Linux Programmer's Manual" +.TH DMESG 8 .SH NAME dmesg \- print or control the kernel ring buffer .SH SYNOPSIS -.BI "dmesg [ \-c ] [ \-n " level " ]" +.BI "dmesg [ \-c ] [ \-n " level " ] [ \-s " bufsize " ]" .SH DESCRIPTION .B dmesg is used to examine or control the kernel ring buffer. @@ -22,6 +22,12 @@ file to whoever can debug their problem. .B \-c clear the ring buffer contents after printing. .TP +.BI \-s bufsize +use a buffer of bufsize to query the kernel ring buffer. This is +8196 by default (this matches the default kernel syslog buffer size in +2.0.33 and 2.1.103). If you have set the kernel buffer to larger than +the default then this option can be used to view the entire buffer. +.TP .BI \-n level set the .I level diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index 56beb3fe..bfb488f9 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -4,6 +4,8 @@ * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu) * This program comes with ABSOLUTELY NO WARRANTY. * Modifications by Rick Sladkey (jrs@world.std.com) + * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch + * by Peeter Joot. This was also suggested by John Hudson. */ #include @@ -29,12 +31,13 @@ static char *progname; void usage() { - fprintf( stderr, "Usage: %s [-c] [-n level]\n", progname ); + fprintf( stderr, "Usage: %s [-c] [-n level] [-s bufsize]\n", progname ); } int main( int argc, char *argv[] ) { - char buf[4096]; + char *buf; + int bufsize=8196; int i; int n; int c; @@ -43,7 +46,7 @@ int main( int argc, char *argv[] ) int cmd = 3; progname = argv[0]; - while ((c = getopt( argc, argv, "cn:" )) != EOF) { + while ((c = getopt( argc, argv, "cn:s:" )) != EOF) { switch (c) { case 'c': cmd = 4; @@ -52,6 +55,9 @@ int main( int argc, char *argv[] ) cmd = 8; level = atoi(optarg); break; + case 's': + bufsize = atoi(optarg); + break; case '?': default: usage(); @@ -75,7 +81,9 @@ int main( int argc, char *argv[] ) exit( 0 ); } - n = klogctl( cmd, buf, sizeof( buf ) ); + if (bufsize < 4096) bufsize = 4096; + buf = (char*)malloc(bufsize); + n = klogctl( cmd, buf, bufsize ); if (n < 0) { perror( "klogctl" ); exit( 1 ); diff --git a/sys-utils/hwclock.8 b/sys-utils/hwclock.8 index a7308a60..ec8b0076 100644 --- a/sys-utils/hwclock.8 +++ b/sys-utils/hwclock.8 @@ -1,18 +1,26 @@ -.TH CLOCK 8 "23 September 1996" +.TH CLOCK 8 "02 March 1998" .SH NAME -clock \- query and set the ISA hardware clock (RTC) +clock \- query and set the hardware clock (RTC) .SH SYNOPSIS -.B "hwclock --show [ --utc ] [ --test ] [ --debug ]" +.B "hwclock --show" .br -.B "hwclock --set --date=newdate [ --utc ] [ --test ] [ --debug ]" +.B "hwclock --set --date=newdate" .br -.B "hwclock --systohc [ --utc ] [ --test ] [ --debug ]" +.B "hwclock --systohc" .br -.B "hwclock --hctosys [ --utc ] [ --test ] [ --debug ]" +.B "hwclock --hctosys" .br -.B "hwclock --adjust [ --utc ] [ --test ] [ --debug ]" +.B "hwclock --getepoch" .br -.B "hwclock --version [ --debug ] +.B "hwclock --setepoch --epoch=year" +.br +.B "hwclock --adjust" +.br +.B "hwclock --version" +.PP +other options: +.PP +.B "--utc --directisa --test --debug" .PP Minimum unique abbreviations of all options are acceptable. .PP @@ -58,6 +66,23 @@ 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 \-\-getepoch +Print out standard output the kernel's Hardware Clock epoch value. +This is the number of years into AD to which a zero year value in the +Hardware Clock refers. For example, if you are using the convention +that the year counter in your Hardware Clock contains the number of +full years since 1952, then the kernel's Hardware Counter epoch value +must be 1952. + +This epoch value is used whenever hwclock reads or sets the Hardware Clock. +.TP +.B \-\-setepoch +Set the kernel's Hardware Clock epoch value to the value specified by the +.B \-\-epoch +option. See the +.B \-\-getepoch +option for details. +.TP .B \-\-version Print the version of .I hwclock @@ -74,11 +99,21 @@ option is an argument to the program. For example, .sp .I hwclock --set --date="9/22/96 16:45:05" +.TP +.B \-\-epoch=year +Specifies the year which is the beginning of the Hardware Clock's +epoch. I.e. the number of years into AD to which a zero value in the +Hardware Clock's year counter refers. + +For example, +.sp +.I hwclock --setepoch --epoch=1952 + .PP The following options apply to most functions. .TP .B \-\-utc -Indicates that the Hardware Clock is kept in Universal Coordinated +Indicates that the Hardware Clock is kept in Coordinated Universal 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 @@ -89,9 +124,22 @@ If you don't specify when you should, or vice versa, both setting and querying of the Hardware Clock will be messed up. .TP +.B \-\-directisa +is meaningful only on an ISA machine. For all other machines, it has +no effect. This option tells +.I hwclock +to use explicit I/O instructions to access the Hardware Clock. +Without this option, +.I hwclock +will try to use the /dev/rtc device (which it assumes to be driven by the +rtc device driver). If it is unable to open the device (for read), it will +use the explicit I/O instructions anyway. +.PP +The rtc device driver was new in Linux Release 2. +.TP .B \-\-test -Do everything except actually updating the Hardware Clock. This is -useful, especially in conjunction with +Do everything except actually updating the Hardware Clock or anything +else. This is useful, especially in conjunction with .B \-\-debug, in learning about .I hwclock. @@ -112,11 +160,12 @@ 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. +in the CPU and even when the machine is powered off. + +On an ISA system, this clock 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 @@ -127,11 +176,12 @@ 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. +a timer interrupt. (On an ISA machine, the timer interrupt is part of +the ISA standard). 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 @@ -150,6 +200,66 @@ Clock. You can also use the program to smoothly adjust the System Time while the system runs. +.SH How hwclock Accesses the Hardware Clock +.PP +.I +hwclock +Uses many different ways to get and set Hardware Clock values. +The most normal way is to do I/O to the device special file /dev/rtc, +which is presumed to be driven by the rtc device driver. However, +this method is not always available. For one thing, the rtc driver is +a relatively recent addition to Linux. Older systems don't have it. +.PP +On older systems, the method of accessing the Hardware Clock depends on +the system hardware. +.PP +On an ISA system, +.I +hwclock +can directly access the "CMOS memory" registers that constitute the clock, +by doing I/O to Ports 0x70 and 0x71. It can only do this if running with +superuser effective userid. + +This is a really poor method of accessing the clock, for all the +reasons that user space programs are generally not supposed to do +direct I/O and disable interrupts. Hwclock provides it because it is +the only method available with older Linux kernels for ISA machines. + +.PP +On an m68k system, +.I +hwclock +can access the clock via the console driver, via the device special +file /dev/tty1. +.PP +On an Alpha, +.I +/dev/rtc +is the only choice. + +There are or were some Alpha Linux systems that don't have /dev/rtc +and there are or were programs that accessed the clock via almost +direct I/O using /dev/port. However, this is not as good a method as +/dev/rtc and such programs were not widely enough used that hwclock +has any need to be backward compatible with them. So hwclock does not +provide the /dev/port method and consequently will not work on an +Alpha that doesn't have /dev/rtc. + +.PP +.I +hwclock +tries to use /dev/rtc. If it is compiled for a kernel that doesn't have +that function or it is unable to open /dev/rtc, +.I +hwclock +will fall back to another method, if available. On an ISA +machine, you can force +.I +hwclock +to use the direct manipulation of the CMOS registers without even trying +/dev/rtc by specifying the --directisa option. + + .SH The Adjust Function .PP The Hardware Clock is usually not very accurate. However, much of its @@ -210,7 +320,7 @@ will do the adjustment then. It is good to do a .I hwclock --adjust just before the -.I hwclock --set +.I hwclock --hctosys at system startup time, and maybe periodically while the system is running via cron. .PP @@ -238,7 +348,8 @@ program with adjtimex(8), date(1), gettimeofday(2), settimeofday(2), crontab(1) .SH AUTHORS -Written By Bryan Henderson, September 1996, based on work done on the +Written By Bryan Henderson, September 1996 (bryanh@giraffe-data.com), +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 index 9f4d7714..643ccda5 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -8,7 +8,7 @@ See man page for details. - By Bryan Henderson, 96.09.19 + By Bryan Henderson, 96.09.19. bryanh@giraffe-data.com Based on work by others; see history at end of source code. @@ -26,7 +26,7 @@ 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 + 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). @@ -59,9 +59,9 @@ 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. + If we're setting the clock to the system clock value, we wait for + the system clock 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 @@ -71,6 +71,23 @@ complications that might cause, we set the clock as soon as possible after an oscillator tick. + + About synchronizing to the Hardware Clock when reading the time: The + precision of the Hardware Clock counters themselves is one second. + You can't read the counters and find out that is 12:01:02.5. But if + you consider the location in time of the counter's ticks as part of + its value, then its precision is as infinite as time is continuous! + What I'm saying is this: To find out the _exact_ time in the + hardware clock, we wait until the next clock tick (the next time the + second counter changes) and measure how long we had to wait. We + then read the value of the clock counters and subtract the wait time + and we know precisely what time it was when we set out to query the + time. + + hwclock uses this method, and considers the Hardware Clock to have + infinite precision. + + Enhancements needed: - When waiting for whole second boundary in set_hardware_clock_exact, @@ -79,8 +96,6 @@ ****************************************************************************/ -#define _GNU_SOURCE /* for snprintf */ - #include #include #include @@ -96,7 +111,7 @@ #include "../version.h" #define MYNAME "hwclock" -#define VERSION "2.1" +#define VERSION "2.2" #define FLOOR(arg) ((arg >= 0 ? (int) arg : ((int) arg) - 1)); @@ -129,7 +144,7 @@ struct adjtime { }; -enum clock_access_method {ISA, RTC_IOCTL, KD}; +enum clock_access_method {ISA, RTC_IOCTL, KD, NOCLOCK}; /* A method for accessing (reading, writing) the hardware clock: ISA: @@ -140,14 +155,14 @@ enum clock_access_method {ISA, RTC_IOCTL, KD}; 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. + via the console driver, using device special file /dev/tty1. + This is the m68k ioctl interface, known as KDGHWCLK. NO_CLOCK: - Unable to determine a accessmethod for the system clock. + Unable to determine a usable access method for the system clock. */ - +#ifdef __i386__ /* 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 @@ -157,12 +172,24 @@ enum clock_access_method {ISA, RTC_IOCTL, KD}; */ static unsigned short clock_ctl_addr = 0x70; static unsigned short clock_data_addr = 0x71; +#endif 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 + what we're doing to standard output. Because of the pervasive and yet background nature of this value, this is a global variable. */ +bool interrupts_enabled; + /* Interrupts are enabled as normal. We, unfortunately, turn interrupts + on the machine off in some places where we do the direct ISA accesses + to the Hardware Clock. It is in extremely poor form for a user space + program to do this, but that's the price we have to pay to run on an + ISA machine without the rtc driver in the kernel. + + Code which turns interrupts off uses this value to determine if they + need to be turned back on. + */ + #include /* Check if the /dev/rtc interface is available in this version of @@ -173,11 +200,35 @@ bool debug; #include static const bool got_rtc = TRUE; #else -/* Dummy to make it compile */ -#define RTC_SET_TIME 0 static const bool got_rtc = FALSE; +/* Dummy definitions to make it compile. If any lines containing these + macros ever execute, there is a bug in the code. + */ +#define RTC_SET_TIME -1 +#define RTC_RD_TIME -1 +#define RTC_UIE_ON -1 +#define RTC_UIE_OFF -1 #endif +/* The RTC_EPOCH_READ and RTC_EPOCH_SET macros are supposed to be + defined by linux/mc146818rtc.h, included above. However, these are + recent inventions and at the time of this writing, not in any + official Linux. Since these values aren't even necessary for most + uses of hwclock, we don't want compilation to depend on the user + having some arcane version of this header file on his system. Thus, + we define the macros ourselves if the header file failed to do so. + 98.03.03. +*/ + +#ifndef RTC_EPOCH_READ +#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ + /* Not all kernels have this ioctl */ +#endif + +#ifndef RTC_EPOCH_SET +#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ + /* Not all kernels have this ioctl */ +#endif #if defined(KDGHWCLK) @@ -187,13 +238,54 @@ 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;}; +struct hwclk_time {int sec;}; /* Never used; just to make compile work */ #endif +/* We're going to assume that if the CPU is in the Intel x86 family, + this is an ISA family machine. For all practical purposes, this is + the case at the time of this writing, especially after we assume a + Linux kernel is running on it. + */ +const bool isa_machine = +#ifdef __i386__ +TRUE +#else +FALSE; +#endif +; + +const bool alpha_machine = +#ifdef __alpha__ +TRUE +#else +FALSE; +#endif +; -float + + +static int +i386_iopl(const int level) { +/*---------------------------------------------------------------------------- + When compiled for an Intel target, this is just the iopl() kernel call. + When compiled for any other target, this is a dummy function. + + We do it this way in order to keep the conditional compilation stuff + out of the way so it doesn't mess up readability of the code. +-----------------------------------------------------------------------------*/ +#ifdef __i386__ + extern int iopl(const int level); + return iopl(level); +#else + return -1; +#endif +} + + + +static float time_diff(struct timeval subtrahend, struct timeval subtractor) { /*--------------------------------------------------------------------------- The difference in seconds between two times in "timeval" format. @@ -203,7 +295,7 @@ time_diff(struct timeval subtrahend, struct timeval subtractor) { } -struct timeval +static struct timeval time_inc(struct timeval addend, float increment) { /*---------------------------------------------------------------------------- The time, in "timeval" format, which is seconds after @@ -231,18 +323,28 @@ static inline unsigned char hclock_read(unsigned char reg) { /*--------------------------------------------------------------------------- Relative byte of the Hardware Clock value. + + On non-ISA machine, just return 0. ---------------------------------------------------------------------------*/ -#ifdef __i386__ register unsigned char ret; +#ifdef __i386__ + const bool interrupts_were_enabled = interrupts_enabled; + __asm__ volatile ("cli"); + interrupts_enabled = FALSE; /* & 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; + if (interrupts_were_enabled) { + __asm__ volatile ("sti"); + interrupts_enabled = TRUE; + } +#else + ret = 0; #endif + return ret; } @@ -251,6 +353,8 @@ static inline void hclock_write(unsigned char reg, unsigned char val) { /*---------------------------------------------------------------------------- Set relative byte of the Hardware Clock value to . + + On non-ISA machine, do nothing. ----------------------------------------------------------------------------*/ #ifdef __i386__ /* & 0x7f ensures that we are not disabling NMI while we read. @@ -276,7 +380,7 @@ hclock_write_bcd(int addr, int value) { } -void +static void read_adjtime(struct adjtime *adjtime_p, int *rc_p) { /*---------------------------------------------------------------------------- Read the adjustment parameters out of the /etc/adjtime file. @@ -348,7 +452,7 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) { -void +static void synchronize_to_clock_tick_ISA(int *retcode_p) { /*---------------------------------------------------------------------------- Same as synchronize_to_clock_tick(), but just for ISA. @@ -371,14 +475,56 @@ synchronize_to_clock_tick_ISA(int *retcode_p) { -void +static void +busywait_for_rtc_clock_tick(const int rtc_fd, int *retcode_p) { +/*---------------------------------------------------------------------------- + Wait for the top of a clock tick by reading /dev/rtc in a busy loop until + we see it. +-----------------------------------------------------------------------------*/ + struct tm start_time; + /* The time when we were called (and started waiting) */ + int rc; + + if (debug) + printf("Waiting in loop for time from /dev/rtc to change\n"); + + rc = ioctl(rtc_fd, RTC_RD_TIME, &start_time); + if (rc == -1) { + fprintf(stderr, "ioctl() to /dev/rtc to read time failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 1; + } else { + /* Wait for change. 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. + */ + struct tm nowtime; + int i; /* local loop index */ + int rc; /* Return code from ioctl */ + + for (i = 0; + (rc = ioctl(rtc_fd, RTC_RD_TIME, &nowtime)) != -1 + && start_time.tm_sec == nowtime.tm_sec && i < 1000000; + i++); + if (i >= 1000000) { + fprintf(stderr, "Timed out waiting for time change.\n"); + *retcode_p = 2; + } else if (rc == -1) { + fprintf(stderr, "ioctl() to /dev/rtc to read time failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 3; + } else *retcode_p = 0; + } +} + + + +static 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 */ +int rtc_fd; /* File descriptor of /dev/rtc */ rtc_fd = open("/dev/rtc",O_RDONLY); if (rtc_fd == -1) { @@ -386,45 +532,97 @@ synchronize_to_clock_tick_RTC(int *retcode_p) { strerror(errno), errno); *retcode_p = 1; } else { + int rc; /* Return code from ioctl */ /* 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 { + if (rc == -1 && errno == EINVAL) { + /* This rtc device doesn't have interrupt functions. This is typical + on an Alpha, where the Hardware Clock interrupts are used by the + kernel for the system clock, so aren't at the user's disposal. + */ + if (debug) printf("/dev/rtc does not have interrupt functions. "); + busywait_for_rtc_clock_tick(rtc_fd, retcode_p); + } else if (rc != -1) { + int rc; /* return code from ioctl */ unsigned long dummy; - /* this blocks */ - rc = read(rtc_fd, &dummy, sizeof(unsigned long)); + /* this blocks until the next update interrupt */ + rc = read(rtc_fd, &dummy, sizeof(dummy)); 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); - } } + /* 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); + } + } else { + fprintf(stderr, "ioctl() to /dev/rtc to turn on update interrupts " + "failed unexpectedly, errno = %s (%d).\n", + strerror(errno), errno); + *retcode_p = 1; } 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) { + +static void +synchronize_to_clock_tick_KD(int *retcode_p) { +/*---------------------------------------------------------------------------- + Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until + we see it. +-----------------------------------------------------------------------------*/ + int con_fd; + + if (debug) + printf("Waiting in loop for time from KDGHWCLK to change\n"); + + con_fd = open("/dev/tty1", O_RDONLY); + if (con_fd < 0) { + fprintf(stderr, "open() failed to open /dev/tty1, errno = %s (%d).\n", + strerror(errno), errno); + *retcode_p = 1; + } else { + int rc; /* return code from ioctl() */ + int i; /* local loop index */ + /* The time when we were called (and started waiting) */ + struct hwclk_time start_time, nowtime; + + rc = ioctl(con_fd, kdghwclk_ioctl, &start_time); + if (rc == -1) { + fprintf(stderr, "KDGHWCLK to read time failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 3; + } + + for (i = 0; + (rc = ioctl(con_fd, kdghwclk_ioctl, &nowtime)) != -1 + && start_time.sec == nowtime.sec && i < 1000000; + i++); + if (i >= 1000000) { + fprintf(stderr, "Timed out waiting for time change.\n"); + *retcode_p = 2; + } else if (rc == -1) { + fprintf(stderr, "KDGHWCLK to read time failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 3; + } else *retcode_p = 0; + close(con_fd); + } +} + + + +static void +synchronize_to_clock_tick(enum clock_access_method clock_access, + int *retcode_p) { /*----------------------------------------------------------------------------- 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 @@ -440,35 +638,27 @@ synchronize_to_clock_tick(enum clock_access_method clock_access) { 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. + Return *retcode_p == 0 if it worked, nonzero if it didn't. -----------------------------------------------------------------------------*/ - 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; + case ISA: synchronize_to_clock_tick_ISA(retcode_p); break; + case RTC_IOCTL: synchronize_to_clock_tick_RTC(retcode_p); break; + case KD: synchronize_to_clock_tick_KD(retcode_p); break; default: fprintf(stderr, "Internal error in synchronize_to_clock_tick. Invalid " "value for clock_access argument.\n"); - retcode = 1; + *retcode_p = 1; } if (debug) printf("...got clock tick\n"); - return(retcode); + return; } -time_t +static time_t mktime_tz(struct tm tm, const bool universal) { /*----------------------------------------------------------------------------- Convert a time in broken down format (hours, minutes, etc.) into standard @@ -489,7 +679,7 @@ mktime_tz(struct tm tm, const bool universal) { if (universal) { /* Set timezone to UTC */ - (void) putenv("TZ="); + setenv("TZ", "", TRUE); /* Note: tzset() gets called implicitly by the time code, but only the first time. When changing the environment variable, better call tzset() explicitly. @@ -504,10 +694,8 @@ mktime_tz(struct tm tm, const bool universal) { } /* now put back the original zone. */ - if (zone) - setenv ("TZ", zone, 1); - else - putenv ("TZ"); + if (zone) setenv("TZ", zone, TRUE); + else unsetenv("TZ"); tzset(); if (debug) @@ -519,20 +707,23 @@ mktime_tz(struct tm tm, const bool universal) { -void +static 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 + argument. Use ioctls to /dev/tty1 on what we assume is an m68k machine. + + Note that we don't use /dev/console here. That might be a serial + console. -----------------------------------------------------------------------------*/ #ifdef KDGHWCLK int con_fd; struct hwclk_time t; - con_fd = open("/dev/console", O_RDONLY); + con_fd = open("/dev/tty1", O_RDONLY); if (con_fd < 0) { - fprintf(stderr, "open() failed to open /dev/console, errno = %s (%d).\n", + fprintf(stderr, "open() failed to open /dev/tty1, errno = %s (%d).\n", strerror(errno), errno); exit(5); } else { @@ -540,7 +731,7 @@ read_hardware_clock_kd(struct tm *tm) { rc = ioctl(con_fd, kdghwclk_ioctl, &t); if (rc == -1) { - fprintf(stderr, "ioctl() failed to read time from /dev/console, " + fprintf(stderr, "ioctl() failed to read time from /dev/tty1, " "errno = %s (%d).\n", strerror(errno), errno); exit(5); @@ -565,7 +756,7 @@ read_hardware_clock_kd(struct tm *tm) { -void +static void read_hardware_clock_rtc_ioctl(struct tm *tm) { /*---------------------------------------------------------------------------- Read the hardware clock and return the current time via @@ -600,52 +791,85 @@ read_hardware_clock_rtc_ioctl(struct tm *tm) { -void +static 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. + + This function is not totally reliable. It takes a finite and + unpredictable amount of time to execute the code below. During that + time, the clock may change and we may even read an invalid value in + the middle of an update. We do a few checks to minimize this + possibility, but only the kernel can actually read the clock + properly, since it can execute code in a short and predictable + amount of time (by turning of interrupts). + + In practice, the chance of this function returning the wrong time is + extremely remote. + -----------------------------------------------------------------------------*/ - /* 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. + bool got_time; + /* We've successfully read a time from the Hardware Clock */ + + got_time = FALSE; + while (!got_time) { + /* Bit 7 of Byte 10 of the Hardware Clock value is the Update In Progress + (UIP) bit, which is on while and 244 uS before the Hardware Clock + updates itself. It updates the counters individually, so reading + them during an update would produce garbage. The update takes 2mS, + so we could be spinning here that long waiting for this bit to turn + off. + + Furthermore, it is pathologically possible for us to be in this + code so long that even if the UIP bit is not on at first, the + clock has changed while we were running. We check for that too, + and if it happens, we start over. + */ + + if ((hclock_read(10) & 0x80) == 0) { + /* No clock update in progress, go ahead and read */ + 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) - 3; + tm->tm_mday = hclock_read_bcd(7); + tm->tm_mon = hclock_read_bcd(8) - 1; + 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. + */ + } + /* Unless the clock changed while we were reading, consider this + a good clock read . */ + if (tm->tm_sec == hclock_read_bcd (0)) got_time = TRUE; + /* Yes, in theory we could have been running for 60 seconds and + the above test wouldn't work! + */ } - } 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 +static void read_hardware_clock(const enum clock_access_method method, struct tm *tm){ /*---------------------------------------------------------------------------- Read the hardware clock and return the current time via argument. @@ -674,39 +898,41 @@ read_hardware_clock(const enum clock_access_method method, struct tm *tm){ -void +static 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. + /dev/tty1 on what we assume is an m68k machine. + + Note that we don't use /dev/console here. That might be a serial console. ----------------------------------------------------------------------------*/ #ifdef KDGHWCLK - int con_fd; /* File descriptor of /dev/console */ + int con_fd; /* File descriptor of /dev/tty1 */ struct hwclk_time t; - con_fd = open("/dev/console", O_RDONLY); + con_fd = open("/dev/tty1", O_RDONLY); if (con_fd < 0) { - fprintf(stderr, "Error opening /dev/console. Errno: %s (%d)\n", + fprintf(stderr, "Error opening /dev/tty1. 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; + 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. " + fprintf(stderr, "ioctl() to open /dev/tty1 failed. " "Errno: %s (%d)\n", strerror(errno), errno); exit(1); @@ -723,7 +949,7 @@ set_hardware_clock_kd(const struct tm new_broken_time, -void +static void set_hardware_clock_rtc_ioctl(const struct tm new_broken_time, const bool testing) { /*---------------------------------------------------------------------------- @@ -739,14 +965,19 @@ set_hardware_clock_rtc_ioctl(const struct tm new_broken_time, 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"); + if (testing) + printf("Not setting Hardware Clock because running in test mode.\n"); + 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) + printf("ioctl(RTC_SET_TIME) was successful.\n"); + } } close(rtc_fd); } @@ -754,7 +985,7 @@ set_hardware_clock_rtc_ioctl(const struct tm new_broken_time, -void +static void set_hardware_clock_isa(const struct tm new_broken_time, const bool testing) { /*---------------------------------------------------------------------------- @@ -763,12 +994,16 @@ set_hardware_clock_isa(const struct tm new_broken_time, an ISA Hardware Clock. ----------------------------------------------------------------------------*/ unsigned char save_control, save_freq_select; +#ifdef __i386__ + const bool interrupts_were_enabled = interrupts_enabled; +#endif if (testing) printf("Not setting Hardware Clock because running in test mode.\n"); else { #ifdef __i386__ __asm__ volatile ("cli"); + interrupts_enabled = FALSE; #endif save_control = hclock_read(11); /* tell the clock it's being set */ hclock_write(11, (save_control | 0x80)); @@ -801,13 +1036,16 @@ set_hardware_clock_isa(const struct tm new_broken_time, hclock_write (11, save_control); hclock_write (10, save_freq_select); #ifdef __i386__ - __asm__ volatile ("sti"); + if (interrupts_were_enabled) { + __asm__ volatile ("sti"); + interrupts_enabled = TRUE; + } #endif } } -void +static void set_hardware_clock(const enum clock_access_method method, const time_t newtime, const bool universal, @@ -852,7 +1090,7 @@ set_hardware_clock(const enum clock_access_method method, -void +static void set_hardware_clock_exact(const time_t settime, const struct timeval ref_time, const enum clock_access_method clock_access, @@ -897,7 +1135,91 @@ set_hardware_clock_exact(const time_t settime, -void +static void +get_epoch(unsigned long *epoch_p, int *retcode_p) { +/*---------------------------------------------------------------------------- + Get the Hardware Clock epoch setting from the kernel. +----------------------------------------------------------------------------*/ + int rtc_fd; + + rtc_fd = open("/dev/rtc", O_RDONLY); + if (rtc_fd < 0) { + if (errno == ENOENT) + fprintf(stderr, "To manipulate the epoch value in the kernel, we must " + "access the Linux 'rtc' device driver via the device special " + "file /dev/rtc. This file does not exist on this system.\n"); + else + fprintf(stderr, "Unable to open /dev/rtc, open() errno = %s (%d)\n", + strerror(errno), errno); + *retcode_p = 1; + } else { + int rc; /* return code from ioctl */ + rc = ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p); + if (rc == -1) { + fprintf(stderr, "ioctl(RTC_EPOCH_READ) to /dev/rtc failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 1; + } else { + *retcode_p = 0; + if (debug) printf("we have read epoch %ld from /dev/rtc " + "with RTC_EPOCH_READ ioctl.\n", *epoch_p); + } + close(rtc_fd); + } + return; +} + + + +static void +set_epoch(unsigned long epoch, const bool testing, int *retcode_p) { +/*---------------------------------------------------------------------------- + Set the Hardware Clock epoch in the kernel. +----------------------------------------------------------------------------*/ + if (epoch < 1900) + /* kernel would not accept this epoch value */ + fprintf(stderr, "The epoch value may not be less than 1900. " + "You requested %ld\n", epoch); + else { + int rtc_fd; + + rtc_fd = open("/dev/rtc", O_RDONLY); + if (rtc_fd < 0) { + if (errno == ENOENT) + fprintf(stderr, "To manipulate the epoch value in the kernel, we must " + "access the Linux 'rtc' device driver via the device special " + "file /dev/rtc. This file does not exist on this system.\n"); + fprintf(stderr, "Unable to open /dev/rtc, open() errno = %s (%d)\n", + strerror(errno), errno); + *retcode_p = 1; + } else { + if (debug) printf("setting epoch to %ld " + "with RTC_EPOCH_SET ioctl to /dev/rtc.\n", epoch); + if (testing) { + printf("Not setting epoch because running in test mode.\n"); + *retcode_p = 0; + } else { + int rc; /* return code from ioctl */ + rc = ioctl(rtc_fd, RTC_EPOCH_SET, epoch); + if (rc == -1) { + if (errno == EINVAL) + fprintf(stderr, "The kernel (specifically, the device driver " + "for /dev/rtc) does not have the RTC_EPOCH_SET ioctl. " + "Get a newer driver.\n"); + else + fprintf(stderr, "ioctl(RTC_EPOCH_SET) to /dev/rtc failed, " + "errno = %s (%d).\n", strerror(errno), errno); + *retcode_p = 1; + } else *retcode_p = 0; + } + close(rtc_fd); + } + } +} + + + +static void display_time(const time_t systime, const float sync_duration) { /*---------------------------------------------------------------------------- Put the time "systime" on standard output in display format. @@ -917,8 +1239,8 @@ display_time(const time_t systime, const float sync_duration) { -int -interpret_date_string(const char *date_opt, const time_t *time_p) { +static int +interpret_date_string(const char *date_opt, time_t * const 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 @@ -927,16 +1249,16 @@ interpret_date_string(const char *date_opt, const time_t *time_p) { The specified time is in the local time zone. - Our output, "*newtime", is a seconds-into-epoch time. + Our output, "*time_p", 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. + If anything goes wrong (and many things can), we return return code + 10 and arbitrary *time_p. Otherwise, return code is 0 and *time_p + is valid. ----------------------------------------------------------------------------*/ - FILE *date_child_fp; char date_resp[100]; const char magic[]="seconds-into-epoch="; @@ -974,7 +1296,8 @@ interpret_date_string(const char *date_opt, const time_t *time_p) { date_command, date_resp); retcode = 8; } else { - rc = sscanf(date_resp + sizeof(magic)-1, "%d", (int *) time_p); + int seconds_since_epoch; + rc = sscanf(date_resp + sizeof(magic)-1, "%d", &seconds_since_epoch); if (rc < 1) { fprintf(stderr, "The date command issued by " MYNAME " returned" "something other than an integer where the converted" @@ -984,6 +1307,7 @@ interpret_date_string(const char *date_opt, const time_t *time_p) { retcode = 6; } else { retcode = 0; + *time_p = seconds_since_epoch; if (debug) printf("date string %s equates to %d seconds since 1969.\n", date_opt, (int) *time_p); @@ -997,8 +1321,8 @@ interpret_date_string(const char *date_opt, const time_t *time_p) { -int -set_system_clock(const time_t newtime, const int testing) { +static int +set_system_clock(const time_t newtime, const bool testing) { struct timeval tv; int retcode; /* our eventual return code */ @@ -1009,9 +1333,8 @@ set_system_clock(const time_t newtime, const int testing) { 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 ); + printf( "\ttv.tv_sec = %ld, tv.tv_usec = %ld\n", + (long) tv.tv_sec, (long) tv.tv_usec ); } if (testing) { printf("Not setting system clock because running in test mode.\n"); @@ -1032,7 +1355,7 @@ set_system_clock(const time_t newtime, const int testing) { } -void +static void adjust_drift_factor(struct adjtime *adjtime_p, const time_t nowtime, const time_t hclocktime ) { @@ -1081,7 +1404,7 @@ adjust_drift_factor(struct adjtime *adjtime_p, -void +static void calculate_adjustment( const float factor, const time_t last_time, @@ -1121,7 +1444,7 @@ calculate_adjustment( -void +static void save_adjtime(const struct adjtime adjtime, const bool testing) { /*----------------------------------------------------------------------------- Write the contents of the structure to its disk file. @@ -1130,16 +1453,18 @@ save_adjtime(const struct adjtime adjtime, const bool testing) { bother. -----------------------------------------------------------------------------*/ FILE *adjfile; - char newfile[162]; /* Stuff to write to disk file */ + char newfile[405]; /* 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", + /* snprintf is not always available, but this is safe + as long as libc does not use more than 100 positions for %ld or %f */ + sprintf(newfile, "%f %ld %f\n%ld\n", adjtime.drift_factor, - adjtime.last_adj_time, + (long) adjtime.last_adj_time, adjtime.not_adjusted, - adjtime.last_calib_time ); + (long) adjtime.last_calib_time ); if (testing) { printf("Not updating adjtime file because of testing mode.\n"); @@ -1180,7 +1505,7 @@ save_adjtime(const struct adjtime adjtime, const bool testing) { -void +static void do_adjustment(struct adjtime *adjtime_p, const time_t hclocktime, const struct timeval read_time, const enum clock_access_method clock_access, @@ -1236,7 +1561,7 @@ do_adjustment(struct adjtime *adjtime_p, -void +static void determine_clock_access_method(const bool user_requests_ISA, enum clock_access_method *clock_access_p) { /*---------------------------------------------------------------------------- @@ -1245,6 +1570,8 @@ determine_clock_access_method(const bool user_requests_ISA, using compile-time constants. means the user explicitly asked for the ISA method. + Even if he did, we will not select the ISA method if this is not an + ISA machine. -----------------------------------------------------------------------------*/ bool rtc_works; /* The /dev/rtc method is available and seems to work on this machine */ @@ -1261,15 +1588,20 @@ determine_clock_access_method(const bool user_requests_ISA, "falling back to more primitive clock access method.\n", strerror(errno), errno); } - } else rtc_works = TRUE; + } else { + if (debug) + printf("The Linux kernel for which this copy of hwclock() was built " + "is too old to have /dev/rtc\n"); + rtc_works = FALSE; + } - if (user_requests_ISA) *clock_access_p = ISA; + if (user_requests_ISA && isa_machine) *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); + con_fd = open("/dev/tty1", O_RDONLY); if (con_fd >= 0) { if (ioctl( con_fd, kdghwclk_ioctl, &t ) >= 0) *clock_access_p = KD; @@ -1287,17 +1619,18 @@ determine_clock_access_method(const bool user_requests_ISA, } else { *clock_access_p = KD; fprintf(stderr, - "Can't open /dev/console. open() errno = %s (%d).\n", + "Can't open /dev/tty1. open() errno = %s (%d).\n", strerror(errno), errno); } close(con_fd); - } else { + } else if (isa_machine) { *clock_access_p = ISA; - } + } else + *clock_access_p = NOCLOCK; 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 KD: printf("Using KDGHWCLK interface to m68k 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", @@ -1308,14 +1641,14 @@ determine_clock_access_method(const bool user_requests_ISA, -void +static 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 + int *retcode_p ) { /*--------------------------------------------------------------------------- Do all the normal work of hwclock - read, set clock, etc. @@ -1338,10 +1671,10 @@ manipulate_clock(const bool show, const bool adjust, bool no_auth; /* User lacks necessary authorization to access the clock */ if (clock_access == ISA) { - rc = iopl(3); + rc = i386_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" + "I.e. iopl(2) returned nonzero return code %d.\n" "This is often because the program isn't running " "with superuser privilege, which it needs.\n", rc); @@ -1349,56 +1682,108 @@ manipulate_clock(const bool show, const bool adjust, } else no_auth = FALSE; } else no_auth = FALSE; - if (no_auth) *retcode = 1; + if (no_auth) *retcode_p = 1; else { - if (adjust || set) + if (adjust || set || systohc) 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; + if (rc != 0) *retcode_p = 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; + synchronize_to_clock_tick(clock_access, retcode_p); + /* this takes up to 1 second */ + if (*retcode_p == 0) { + /* 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_p = 0; + } else if (set) { + set_hardware_clock_exact(set_time, startup_time, + clock_access, universal, testing); + adjust_drift_factor(&adjtime, set_time, hclocktime); + *retcode_p = 0; + } else if (adjust) { + do_adjustment(&adjtime, hclocktime, read_time, clock_access, + universal, testing); + *retcode_p = 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_p = 0; + adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclocktime); + } else if (hctosys) { + rc = set_system_clock(hclocktime, testing); + if (rc != 0) { + printf("Unable to set system clock.\n"); + *retcode_p = 1; + } else *retcode_p = 0; + } + save_adjtime(adjtime, testing); + } + } + } +} + + + +static void +manipulate_epoch(const bool getepoch, const bool setepoch, + const int epoch_opt, const bool testing) { +/*---------------------------------------------------------------------------- + Get or set the Hardware Clock epoch value in the kernel, as appropriate. + , , and are hwclock invocation options. + + == -1 if the user did not specify an "epoch" option. + +-----------------------------------------------------------------------------*/ + /* + Maintenance note: This should work on non-Alpha machines, but the + evidence today (98.03.04) indicates that the kernel only keeps the + epoch value on Alphas. If that is ever fixed, this function should be + changed. + */ + + if (!alpha_machine) + fprintf(stderr, "The kernel keeps an epoch value for the Hardware Clock " + "only on an Alpha machine.\nThis copy of hwclock was built for " + "a machine other than Alpha\n(and thus is presumably not running " + "on an Alpha now). No action taken.\n"); + else { + if (getepoch) { + unsigned long epoch; + int retcode; + + get_epoch(&epoch, &retcode); + if (retcode != 0) + printf("Unable to get the epoch value from the kernel.\n"); + else + printf("Kernel is assuming an epoch value of %lu\n", epoch); + } else if (setepoch) { + if (epoch_opt == -1) + fprintf(stderr, "To set the epoch value, you must use the 'epoch' " + "option to tell to what value to set it.\n"); + else { + int rc; + set_epoch(epoch_opt, testing, &rc); + if (rc != 0) + printf("Unable to set the epoch value in the kernel.\n"); } - save_adjtime(adjtime, testing); } } } @@ -1430,38 +1815,47 @@ main(int argc, char **argv, char **envp) { 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 show, set, systohc, hctosys, adjust, getepoch, setepoch, version; bool universal, testing, directisa; char *date_opt; + int epoch_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 }, + { 0, (char *) "getepoch", OPT_FLAG, &getepoch, 0 }, + { 0, (char *) "setepoch", OPT_FLAG, &setepoch, 0 }, { 'a', (char *) "adjust", OPT_FLAG, &adjust, 0 }, { 'v', (char *) "version", OPT_FLAG, &version, 0 }, { 0, (char *) "date", OPT_STRING, &date_opt, 0 }, + { 0, (char *) "epoch", OPT_UINT, &epoch_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 } + { 'D', (char *) "debug", OPT_FLAG, &debug, 0 }, + { 0, (char *) NULL, OPT_END, NULL, 0 } }; int argc_parse; /* argc, except we modify it as we parse */ char **argv_parse; /* argv, except we modify it as we parse */ + interrupts_enabled = TRUE; /* Since we haven't messed with them yet */ + gettimeofday(&startup_time, NULL); /* Remember what time we were invoked */ /* set option defaults */ - show = set = systohc = hctosys = adjust = version = universal = + show = set = systohc = hctosys = adjust = getepoch = setepoch = + version = universal = directisa = testing = debug = FALSE; date_opt = NULL; + epoch_opt = -1; 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 + debug, set, date_opt, getepoch, setepoch, epoch_opt */ if (argc_parse - 1 > 0) { @@ -1471,7 +1865,8 @@ main(int argc, char **argv, char **envp) { exit(100); } - if (show + set + systohc + hctosys + adjust + version > 1) { + if (show + set + systohc + hctosys + adjust + + getepoch + setepoch + version > 1) { fprintf(stderr, "You have specified multiple function options.\n" "You can only perform one function at a time.\n"); exit(100); @@ -1485,29 +1880,50 @@ main(int argc, char **argv, char **envp) { } } - if (!(show | set | systohc | hctosys | adjust | version)) - show = 1; /* default to show */ + if (directisa && !isa_machine) { + fprintf(stderr, "You have requested direct access to the ISA Hardware " + "Clock using machine instructions from the user process. " + "But this method only works on an ISA machine with an x86 " + "CPU, and this is not one!\n"); + exit(100); + } - if (set || hctosys || systohc || adjust) { - /* program is designed to run setuid, be secure! */ + if (!(show | set | systohc | hctosys | adjust | getepoch | setepoch | + version)) + show = 1; /* default to show */ - if (getuid() != 0) { + + if (getuid() == 0) permitted = TRUE; + else { + /* program is designed to run setuid (in some situations) -- be secure! */ + if (set || hctosys || systohc || adjust) { fprintf(stderr, - "Sorry, only superuser can change the Hardware Clock.\n"); + "Sorry, only the superuser can change the Hardware Clock.\n"); + permitted = FALSE; + } else if (setepoch) { + fprintf(stderr, + "Sorry, only the superuser can change " + "the Hardware Clock epoch in the kernel.\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 if (getepoch || setepoch) { + manipulate_epoch(getepoch, setepoch, epoch_opt, testing); } else { determine_clock_access_method(directisa, &clock_access); - - manipulate_clock(show, adjust, set, set_time, hctosys, systohc, - startup_time, clock_access, universal, testing, &rc); + if (clock_access == NOCLOCK) + fprintf(stderr, "Cannot access the Hardware Clock via any known " + "method. Use --debug option to see the details of our " + "search for an access method.\n"); + else + manipulate_clock(show, adjust, set, set_time, hctosys, systohc, + startup_time, clock_access, universal, testing, &rc); } } exit(retcode); @@ -1518,6 +1934,18 @@ main(int argc, char **argv, char **envp) { History of this program: + 98.03.05 BJH. Version 2.2. + + Add --getepoch and --setepoch. + + Fix some word length things so it works on Alpha. + + Make it work when /dev/rtc doesn't have the interrupt functions. + In this case, busywait for the top of a second instead of blocking and + waiting for the update complete interrupt. + + Fix a bunch of bugs too numerous to mention. + 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). diff --git a/sys-utils/kbdrate.c b/sys-utils/kbdrate.c index e61fb890..07a7e40e 100644 --- a/sys-utils/kbdrate.c +++ b/sys-utils/kbdrate.c @@ -62,6 +62,7 @@ beats rebuilding the kernel! #include #include #include +#include #include #include #include @@ -99,7 +100,6 @@ int main( int argc, char **argv ) int c; int i; extern char *optarg; - extern int optind; while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF ) switch (c) { diff --git a/sys-utils/readprofile.c b/sys-utils/readprofile.c index 4c52cf1f..4462a811 100644 --- a/sys-utils/readprofile.c +++ b/sys-utils/readprofile.c @@ -121,7 +121,7 @@ int popenMap; /* flag to tell if popen() has been used */ * Use an fd for the profiling buffer, to skip stdio overhead */ if ( ((proFd=open(proFile,O_RDONLY)) < 0) - || ((len=lseek(proFd,0,SEEK_END)) < 0) + || ((int)(len=lseek(proFd,0,SEEK_END)) < 0) || (lseek(proFd,0,SEEK_SET)<0) ) { fprintf(stderr,"%s: %s: %s\n",prgname,proFile,strerror(errno)); diff --git a/sys-utils/renice.c b/sys-utils/renice.c index 63af8cd4..8867d002 100644 --- a/sys-utils/renice.c +++ b/sys-utils/renice.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1983, 1989, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93"; -#endif /* not lint */ - #include #include #include @@ -56,9 +46,8 @@ int donice(int,int,int); * or groups of processes which are already * running. */ -void -main(argc, argv) - char **argv; +int +main(int argc, char **argv) { int which = PRIO_PROCESS; int who = 0, prio, errs = 0; @@ -107,7 +96,7 @@ main(argc, argv) } errs += donice(which, who, prio); } - exit(errs != 0); + return (errs != 0); } int diff --git a/sys-utils/tunelp.c b/sys-utils/tunelp.c index 6bdebda7..e3b015ba 100644 --- a/sys-utils/tunelp.c +++ b/sys-utils/tunelp.c @@ -6,8 +6,11 @@ * for information on distribution conditions. * \****************************************************************************/ -/* $Id: tunelp.c,v 1.8 1997/07/06 00:14:06 aebr Exp $ +/* $Id: tunelp.c,v 1.9 1998/06/08 19:37:11 janl Exp $ * $Log: tunelp.c,v $ + * Revision 1.9 1998/06/08 19:37:11 janl + * Thus compiles tunelp with 2.1.103 kernels + * * Revision 1.8 1997/07/06 00:14:06 aebr * Fixes to silence -Wall. * @@ -45,6 +48,8 @@ #include #include #include +/* This is for (some) 2.1 kernels */ +#define LP_NEED_CAREFUL #include #include #include diff --git a/text-utils/Makefile b/text-utils/Makefile index d5c80b29..c657be72 100644 --- a/text-utils/Makefile +++ b/text-utils/Makefile @@ -37,7 +37,11 @@ NEEDS_NCURSES= more ul all: $(BIN) $(USRBIN) $(NEEDS_NCURSES): +ifeq "$(HAVE_NCURSES)" "yes" $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) +else + @echo $@ not made since it requires ncurses +endif # Rules for hexdump @@ -57,10 +61,12 @@ colcrt: colcrt.o colrm: colrm.o column: column.o $(BSD)/err.o more.o: more.c $(BSD)/pathnames.h -more: more.o rev: rev.o strings: strings.o $(BSD)/getopt.o +ifeq "$(HAVE_NCURSES)" "yes" +more: more.o ul: ul.o +endif install install.shadow install.text-utils: all $(INSTALLDIR) $(BINDIR) $(USRBINDIR) $(USRLIBDIR) $(MAN1DIR) diff --git a/text-utils/col.c b/text-utils/col.c index 700e5919..1cbaeb5b 100644 --- a/text-utils/col.c +++ b/text-utils/col.c @@ -39,16 +39,6 @@ * (cchris@connected.com) */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1990 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)col.c 5.3 (Berkeley) 2/2/91"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/colcrt.c b/text-utils/colcrt.c index 544c20de..a4d19bb5 100644 --- a/text-utils/colcrt.c +++ b/text-utils/colcrt.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1980, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)colcrt.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - #include #include /* for close() */ #include diff --git a/text-utils/colrm.c b/text-utils/colrm.c index 1ec5db58..3051c866 100644 --- a/text-utils/colrm.c +++ b/text-utils/colrm.c @@ -31,17 +31,8 @@ * SUCH DAMAGE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)colrm.c 5.4 (Berkeley) 6/1/90"; -#endif /* not lint */ - #include + /* COLRM removes unwanted columns from a file Jeff Schriebman UC Berkeley 11-74 diff --git a/text-utils/column.c b/text-utils/column.c index 463adf5c..09f52ebb 100644 --- a/text-utils/column.c +++ b/text-utils/column.c @@ -31,16 +31,6 @@ * 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[] = "@(#)column.c 8.3 (Berkeley) 4/2/94"; -#endif /* not lint */ - #include #include diff --git a/text-utils/conv.c b/text-utils/conv.c index e2e9690a..2a256fa2 100644 --- a/text-utils/conv.c +++ b/text-utils/conv.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char sccsid[] = "@(#)conv.c 5.4 (Berkeley) 6/1/90"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/display.c b/text-utils/display.c index d906cfc9..27d4e724 100644 --- a/text-utils/display.c +++ b/text-utils/display.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char sccsid[] = "@(#)display.c 5.11 (Berkeley) 3/9/91"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/hexdump.c b/text-utils/hexdump.c index 7329d119..2b3b1bf7 100644 --- a/text-utils/hexdump.c +++ b/text-utils/hexdump.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)hexdump.c 5.5 (Berkeley) 6/1/90"; -#endif /* not lint */ - #include #include #include "hexdump.h" diff --git a/text-utils/hexsyntax.c b/text-utils/hexsyntax.c index 4a6638a0..13671601 100644 --- a/text-utils/hexsyntax.c +++ b/text-utils/hexsyntax.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char sccsid[] = "@(#)hexsyntax.c 5.2 (Berkeley) 5/8/90"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/more.c b/text-utils/more.c index 123ef06e..6e076316 100644 --- a/text-utils/more.c +++ b/text-utils/more.c @@ -15,16 +15,6 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980 Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)more.c 5.19 (Berkeley) 6/29/88"; -#endif /* not lint */ - /* ** more.c - General purpose tty output filter and file perusal program ** @@ -69,7 +59,7 @@ 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,TCSETSF,argp) +#define stty(fd,argp) tcsetattr(fd,TCSANOW,argp) /* some function declarations */ void initterm(void); @@ -165,20 +155,31 @@ struct { } context, screen_start; /* extern */ char PC; /* pad character */ +void +idummy(int *kk) {} + +void +Fdummy(FILE **ff) {} int main(int argc, char **argv) { - register FILE *f; - register char *s; - register char *p; - register char ch; - register int left; - int prnames = 0; - int initopt = 0; - int srchopt = 0; - int clearit = 0; - int initline = 0; - char initbuf[80]; - FILE *checkf(); + FILE *f; + char *s; + char *p; + char ch; + int left; + int prnames = 0; + int initopt = 0; + int srchopt = 0; + int clearit = 0; + int initline = 0; + char initbuf[80]; + FILE *checkf(); + + /* avoid gcc complaints about register variables that + may be clobbered by a longjmp, by forcing our variables here + to be non-register */ + Fdummy(&f); idummy(&left); idummy(&prnames); + idummy(&initopt); idummy(&srchopt); idummy(&initline); nfiles = argc; fnames = argv; @@ -806,8 +807,16 @@ int get_line(register FILE *f, int *length) column = 1 + (column | 7); else if (c == '\b' && column > 0) column--; - else if (c == '\r') + else if (c == '\r') { + int next = Getc(f); + if (next == '\n') { + p--; + Currline++; + break; + } + Ungetc(next,f); column = 0; + } else if (c == '\f' && stop_opt) { p[-1] = '^'; *p++ = 'L'; @@ -1505,7 +1514,7 @@ void initterm() #ifdef do_SIGTTOU retry: #endif - no_tty = ioctl(fileno(stdout), TCGETS, &otty); + no_tty = tcgetattr(fileno(stdout), &otty); if (!no_tty) { docrterase = (otty.c_cc[VERASE] != 255); docrtkill = (otty.c_cc[VKILL] != 255); @@ -1551,6 +1560,7 @@ retry: hard++; /* Hard copy terminal */ Lpp = 24; } + if (tigetflag("xenl")) eatnl++; /* Eat newline at last column + 1; dec, concept */ if (Mcol <= 0) @@ -1608,13 +1618,16 @@ retry: if ((shell = getenv("SHELL")) == NULL) shell = "/bin/sh"; } - no_intty = ioctl(fileno(stdin), TCGETS, &otty); - ioctl(fileno(stderr), TCGETS, &otty); + no_intty = tcgetattr(fileno(stdin), &otty); + tcgetattr(fileno(stderr), &otty); savetty0 = otty; slow_tty = (otty.c_cflag & CBAUD) < B1200; hardtabs = (otty.c_oflag & TABDLY) != XTABS; - if (!no_tty) + if (!no_tty) { otty.c_lflag &= ~(ICANON|ECHO); + otty.c_cc[VMIN] = 1; + otty.c_cc[VTIME] = 0; + } } int readch () @@ -1833,6 +1846,8 @@ void rdline (register FILE *f) void onsusp () { + sigset_t signals, oldmask; + /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ signal(SIGTTOU, SIG_IGN); reset_tty (); @@ -1840,10 +1855,17 @@ void onsusp () signal(SIGTTOU, SIG_DFL); /* Send the TSTP signal to suspend our process group */ signal(SIGTSTP, SIG_DFL); -/* sigsetmask(0);*/ + + /* unblock SIGTSTP or we won't be able to suspend ourself */ + sigemptyset(&signals); + sigaddset(&signals, SIGTSTP); + sigprocmask(SIG_UNBLOCK, &signals, &oldmask); + kill (0, SIGTSTP); /* Pause for station break */ + sigprocmask(SIG_SETMASK, &oldmask, NULL); + /* We're back */ signal (SIGTSTP, onsusp); set_tty (); diff --git a/text-utils/odsyntax.c b/text-utils/odsyntax.c index 120928bf..cc543c33 100644 --- a/text-utils/odsyntax.c +++ b/text-utils/odsyntax.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char sccsid[] = "@(#)odsyntax.c 5.4 (Berkeley) 3/8/91"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/parse.c b/text-utils/parse.c index 27280982..ececd131 100644 --- a/text-utils/parse.c +++ b/text-utils/parse.c @@ -31,10 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char sccsid[] = "@(#)parse.c 5.6 (Berkeley) 3/9/91"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/rev.c b/text-utils/rev.c index 3b4e4210..5c3a8406 100644 --- a/text-utils/rev.c +++ b/text-utils/rev.c @@ -35,27 +35,16 @@ * * Wed Sep 14 22:26:00 1994: Patch from bjdouma to handle * last line that has no newline correctly. + * 3-Jun-1998: Patched by Nicolai Langfeldt to work better on Linux: + * Handle any-length-lines. Code copied from util-linux' setpwnam.c */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1987, 1992 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -/*static char sccsid[] = "from: @(#)rev.c 5.2 (Berkeley) 3/21/92";*/ -static char rcsid[] = "$Id: rev.c,v 1.4 1996/07/02 20:08:07 janl Exp $"; -#endif /* not lint */ - #include #include #include #include #include -#ifdef __linux__ #include -#endif /* linux */ void usage __P((void)); void warn __P((const char *, ...)); @@ -65,63 +54,76 @@ main(argc, argv) int argc; char *argv[]; { - register char *filename, *t; -#ifdef __linux__ - char p[512]; -#else /* linux */ - char *p; -#endif /* linux */ - FILE *fp; - size_t len; - int ch, rval; - - while ((ch = getopt(argc, argv, "")) != EOF) - switch(ch) { - case '?': - default: - usage(); - } - - argc -= optind; - argv += optind; - - fp = stdin; - filename = "stdin"; - rval = 0; - do { - if (*argv) { - if ((fp = fopen(*argv, "r")) == NULL) { - warn("%s: %s", *argv, strerror(errno)); - rval = 1; - ++argv; - continue; - } - filename = *argv++; - } -#ifndef __linux__ - while (p = fgetline(fp, &len)) { - t = p + len - 1; - for (t = p + len - 1; t >= p; --t) - putchar(*t); - } -#else /* linux */ - while (fgets(p, 511, fp)) { - len = strlen(p); - t = p + len - 1 - (*(p+len-1)=='\r' - || *(p+len-1)=='\n'); - for ( ; t >= p; --t) - if(strcmp(t, "\0") != 0) - putchar(*t); -#endif /* linux */ - putchar('\n'); - } - if (ferror(fp)) { - warn("%s: %s", filename, strerror(errno)); - rval = 1; - } - (void)fclose(fp); - } while(*argv); - exit(rval); + register char *filename, *t; + size_t buflen=512; + char *p=malloc(buflen); + size_t len; + FILE *fp; + int ch, rval; + + while ((ch = getopt(argc, argv, "")) != EOF) + switch(ch) { + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + fp = stdin; + filename = "stdin"; + rval = 0; + do { + if (*argv) { + if ((fp = fopen(*argv, "r")) == NULL) { + warn("%s: %s", *argv, strerror(errno)); + rval = 1; + ++argv; + continue; + } + filename = *argv++; + } + + while (fgets(p, buflen, fp)) { + + len = strlen(p); + + /* This is my hack from setpwnam.c -janl */ + while (p[len-1] != '\n' && !feof(fp)) { + /* Extend input buffer if it failed getting the whole line */ + + /* So now we double the buffer size */ + buflen *= 2; + + p = realloc(p, buflen); + if (p == NULL) { + fprintf(stderr,"Unable to allocate bufferspace\n"); + exit(1); + } + + /* And fill the rest of the buffer */ + if (fgets(&p[len], buflen/2, fp) == NULL) break; + + len = strlen(p); + + /* That was a lot of work for nothing. Gimme perl! */ + } + + t = p + len - 1 - (*(p+len-1)=='\r' + || *(p+len-1)=='\n'); + for ( ; t >= p; --t) + if(strcmp(t, "\0") != 0) + putchar(*t); + putchar('\n'); + } + if (ferror(fp)) { + warn("%s: %s", filename, strerror(errno)); + rval = 1; + } + (void)fclose(fp); + } while(*argv); + exit(rval); } #if __STDC__ diff --git a/text-utils/strings.c b/text-utils/strings.c index cbcda818..6c201a74 100644 --- a/text-utils/strings.c +++ b/text-utils/strings.c @@ -34,16 +34,6 @@ * Added internationalization patches from Vitor Duarte */ -#ifndef lint -char copyright[] = -"@(#) Copyright (c) 1980, 1987 The Regents of the University of California.\n\ - All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)strings.c 5.10 (Berkeley) 5/23/91"; -#endif /* not lint */ - #include #include #include diff --git a/text-utils/ul.c b/text-utils/ul.c index 4d3cf262..f10d2245 100644 --- a/text-utils/ul.c +++ b/text-utils/ul.c @@ -31,16 +31,6 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1980, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -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. @@ -50,6 +40,7 @@ static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93"; #include /* for getopt(), isatty() */ #include /* for bzero() */ #include /* for setupterm() */ +#include /* for getenv() */ void filter(FILE *f); void flushln(void); @@ -103,7 +94,6 @@ int main(int argc, char **argv) int c, ret; char *termtype; FILE *f; - char *getenv(), *strcpy(); termtype = getenv("TERM"); if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) diff --git a/version.h b/version.h index 64fb6d81..030f8497 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,2 @@ #define UTIL_LINUX 1 -char *util_linux_version="util-linux 2.6"; +char *util_linux_version="util-linux 2.8";