-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.
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
+++ /dev/null
-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.
-
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
Keywords: essential utilities
Author: several
-Maintained-by: Nicolai Langfeldt <util-linux@math.uio.no>
+Maintained-by: Nicolai Langfeldt <util-linux@math.uio.no> 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
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, ...
# 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
#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
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
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
# May be distributed under the terms of the GNU GPL.
#
-VERSION=2.7.1
+VERSION=2.8
include ./MCONFIG
endif
SUBDIRS= bsd \
+ getopt \
disk-utils \
games \
login-utils \
+++ /dev/null
-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
- <armbru@pond.sub.org> 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 <wietse@wzv.win.tue.nl>)
-
- 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
- <sct@dcs.ed.ac.uk> 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
- <ajh@gec-mrc.co.uk>, 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 <alfie@dcs.warwick.ac.uk>'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
-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!
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
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
- 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:
* 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 <err.h>
#include <errno.h>
#include <stdio.h>
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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
# Rules for everything else
fdformat: fdformat.o
-fdisk: fdisk.o fdisklabel.o llseek.o
-sfdisk: sfdisk.o
fsck.minix: fsck.minix.o
fsck.minix.o: fsck.minix.c bitops.h
mkfs: mkfs.o
mkfs.minix.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
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.
* >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu
* Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto
* <jtklehto@stekt.oulu.fi>
- * 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 <leisner@sdsp.mc.xerox.com>
*
****************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <fcntl.h>
-#include <curses.h>
+#ifdef SLCURSES
+ #include <slcurses.h>
+#else
+#if NCH
+ #include <ncurses.h>
+#else
+ #include <curses.h>
+#endif
+#endif
#include <signal.h>
#include <math.h>
+#include <locale.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <linux/types.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/fs.h> /* for BLKRRPART */
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"
#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"
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 {
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;
/* 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;
[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)",
[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",
[0x80] = "Old MINIX",
[0x93] = "Amoeba",
[0x94] = "Amoeba BBT",
+ [0xA5] = "BSD/386",
+ [0xA6] = "OpenBSD",
+ [0xA7] = "NEXTSTEP",
[0xB7] = "BSDI fs",
[0xB8] = "BSDI swap",
[0xC7] = "Syrinx",
[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)
{
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");
fatal(BAD_WRITE);
}
+void dos_copy_to_info(char *to, int tosz, char *from, int fromsz) {
+ int i;
+
+ for(i=0; i<tosz && i<fromsz && isascii(from[i]); i++)
+ to[i] = from[i];
+ to[i] = 0;
+}
+
void get_dos_label(int i)
{
- char label[LABELSZ+1];
+ char sector[128];
+#define DOS_OSTYPE_OFFSET 3
+#define DOS_LABEL_OFFSET 43
+#define DOS_FSTYPE_OFFSET 54
+#define DOS_OSTYPE_SZ 8
+#define DOS_LABEL_SZ 11
+#define DOS_FSTYPE_SZ 8
+ ext2_loff_t offset;
+
+ offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset)
+ * SECTOR_SIZE;
+ if (ext2_llseek(fd, offset, SEEK_SET) == offset
+ && read(fd, §or, sizeof(sector)) == sizeof(sector)) {
+ dos_copy_to_info(p_info[i].ostype, OSTYPESZ,
+ sector+DOS_OSTYPE_OFFSET, DOS_OSTYPE_SZ);
+ dos_copy_to_info(p_info[i].volume_label, LABELSZ,
+ sector+DOS_LABEL_OFFSET, DOS_LABEL_SZ);
+ dos_copy_to_info(p_info[i].fstype, FSTYPESZ,
+ sector+DOS_FSTYPE_OFFSET, DOS_FSTYPE_SZ);
+ }
+}
+
+void get_ext2_label(int i)
+{
+#define EXT2_SUPER_MAGIC 0xEF53
+#define EXT2LABELSZ 16
+ struct ext2_super_block {
+ char s_dummy0[56];
+ unsigned char s_magic[2];
+ char s_dummy1[62];
+ char s_volume_name[EXT2LABELSZ];
+ char s_last_mounted[64];
+ char s_dummy2[824];
+ } sb;
+ char *label = sb.s_volume_name;
ext2_loff_t offset;
int j;
offset = ((ext2_loff_t) p_info[i].first_sector + p_info[i].offset)
- * SECTOR_SIZE + 43;
+ * SECTOR_SIZE + 1024;
if (ext2_llseek(fd, offset, SEEK_SET) == offset
- && read(fd, &label, LABELSZ) == LABELSZ) {
- for(j=0; j<LABELSZ; j++)
- if(!isascii(label[j]))
+ && read(fd, &sb, sizeof(sb)) == sizeof(sb)
+ && sb.s_magic[0] + 256*sb.s_magic[1] == EXT2_SUPER_MAGIC) {
+ for(j=0; j<EXT2LABELSZ; j++)
+ if(!isprint(label[j]))
label[j] = 0;
- label[LABELSZ] = 0;
- strcpy(p_info[i].dos_label, label);
+ label[EXT2LABELSZ] = 0;
+ strncpy(p_info[i].volume_label, label, LABELSZ);
+ strncpy(p_info[i].fstype, "ext2", FSTYPESZ);
}
}
p_info[i].flags = 0;
p_info[i].id = FREE_SPACE;
p_info[i].num = PRI_OR_LOG;
- p_info[i].dos_label[0] = 0;
+ p_info[i].volume_label[0] = 0;
+ p_info[i].fstype[0] = 0;
+ p_info[i].ostype[0] = 0;
num_parts++;
}
ext_info.flags = flags;
ext_info.id = id;
ext_info.num = num;
- ext_info.dos_label[0] = 0;
+ ext_info.volume_label[0] = 0;
+ ext_info.fstype[0] = 0;
+ ext_info.ostype[0] = 0;
return 0;
} else {
return -1; /* explicit extended logical */
p_info[i].flags = flags;
p_info[i].id = id;
p_info[i].num = num;
- p_info[i].dos_label[0] = 0;
- if (want_label && is_dos_partition(id))
- get_dos_label(i);
+ p_info[i].volume_label[0] = 0;
+ p_info[i].fstype[0] = 0;
+ p_info[i].ostype[0] = 0;
+ if (want_label) {
+ if (may_have_dos_label(id))
+ get_dos_label(i);
+ else if (id == LINUX)
+ get_ext2_label(i);
+ }
check_part_info();
while( !key )
{
/* Display the menu */
- ylast = menuUpdate( y, x, menuItems, itemLength, available, menuType, current );
+ ylast = menuUpdate( y, x, menuItems, itemLength, available,
+ menuType, current );
refresh();
key = getch();
/* Clear out all prompts and such */
return key;
}
-/* A function which displays "Press a key to continue" and waits for a keypress *
- * Perhaps calling function menuSelect is a bit overkill but who cares? */
+/* A function which displays "Press a key to continue" *
+ * and waits for a keypress. *
+ * Perhaps calling function menuSelect is a bit overkill but who cares? */
void menuContinue(void)
{
opentype = O_RDWR;
opened = TRUE;
- read_sector(buffer.c.b, 0);
+ /* Blocks are visible in more than one way:
+ e.g. as block on /dev/hda and as block on /dev/hda3
+ By a bug in the Linux buffer cache, we will see the old
+ contents of /dev/hda when the change was made to /dev/hda3.
+ In order to avoid this, discard all blocks on /dev/hda.
+ Note that partition table blocks do not live in /dev/hdaN,
+ so this only plays a role if we want to show volume labels. */
+ ioctl(fd, BLKFLSBUF); /* ignore errors */
+ /* e.g. Permission Denied */
if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
if (!heads)
}
if (!heads || !sectors || !cylinders)
- fatal(BAD_GEOMETRY);
+ fatal(BAD_GEOMETRY); /* probably a file or cdrom */
+
+ read_sector(buffer.c.b, 0);
clear_p_info();
ec = end / heads;
}
- fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %9d\n",
+ fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %8d %9d\n",
num+1, flags, sh, ss, sc, id, eh, es, ec, first, size);
}
fp_printf(fp, "Partition Table for %s\n", disk_device);
fp_printf(fp, "\n");
- fp_printf(fp, " ---Starting--- ----Ending---- Start Number of\n");
- fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n");
- fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- ---------\n");
+ fp_printf(fp, " ---Starting--- ----Ending---- Start Number of\n");
+ fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n");
+ fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- -------- ---------\n");
for (i = 0; i < 4; i++) {
for (j = 0;
"allows you to create, delete and modify partitions on your hard",
"disk drive.",
"",
- "Copyright (C) 1994-1997 Kevin E. Martin & aeb",
+ "Copyright (C) 1994-1998 Kevin E. Martin & aeb",
"",
"Command Meaning",
"------- -------",
{
int size, j;
int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN;
+ char *t;
if (!arrow_cursor) {
move(y, 0);
if (p_info[i].id > 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");
(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;
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;
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)
};
curses_started = 1;
initscr();
+ init_const();
+
old_SIGINT = signal(SIGINT, die);
old_SIGTERM = signal(SIGTERM, die);
#ifdef DEBUG
noecho();
nonl();
- init_const();
-
fill_p_info();
draw_screen();
char c;
int i, len;
+ setlocale(LC_CTYPE, "");
+
while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF)
switch (c) {
case 'a':
print_part_table();
} else
do_curses_fdisk();
+
return 0;
}
.\" 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
/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"
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
.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.
* 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.
*/
#include <ctype.h>
#include <setjmp.h>
#include <errno.h>
+#include <getopt.h>
+#include <sys/stat.h>
#include <sys/ioctl.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/fs.h>
+#include <linux/hdreg.h> /* for HDIO_GETGEO */
+#include <linux/fs.h> /* for BLKRRPART, BLKGETSIZE */
#include "fdisk.h"
+#if defined(sparc)
+#include "fdisksunlabel.h"
+#endif
#define hex_val(c) ({ \
char _c = (c); \
})
-#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)
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;
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 */
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;
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);
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"
" 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"
" 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;
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);
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);
}
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",
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);
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 "
}
}
-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);
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)
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;
{
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;
}
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;
*/
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;
}
{
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);
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;
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;
}
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,
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)) {
}
}
-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)
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);
}
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)
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,
}
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]) {
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++)
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);
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;
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
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;
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");
"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);
}
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]);
}
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;
}
}
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
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<argc; k++)
+ try(argv[k], 1);
+ } else {
+ try("/dev/hda", 0);
+ try("/dev/hdb", 0);
+ try("/dev/hdc", 0); /* often a CDROM */
+ try("/dev/hdd", 0);
+ try("/dev/sda", 0);
+ try("/dev/sdb", 0);
+ try("/dev/sdc", 0);
+ try("/dev/sdd", 0);
+ try("/dev/sde", 0);
+ try("/dev/sdf", 0);
+ try("/dev/sdg", 0);
+ try("/dev/sdh", 0);
+ try("/dev/eda", 0);
+ try("/dev/edb", 0);
+ try("/dev/edc", 0);
+ try("/dev/edd", 0);
+ }
+ exit(0);
+ }
+
+ if (opts) {
+ /* Silly assumptions here about device naming */
+ nowarn = 1;
+ disk_device = (char *) malloc(9);
+ type_open = O_RDONLY;
+
+ opts = argc - optind;
+ if (opts <= 0)
+ fatal(usage);
+
+ for (j = optind; j < argc; j++) {
+ part = argv[j];
+ if (strlen(part) < 9)
+ fatal(usage);
+ if (!(i = atoi(part + 8)))
fatal(usage);
+ i--; /* count from 0 */
+ strncpy(disk_device, part, 8);
+ disk_device[8] = 0;
+ if ((fd = open(disk_device, type_open)) < 0)
+ fatal(unable_to_open);
+ close(fd);
+ if (get_boot(require) < 0)
+ exit(1);
+ if (i >= 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();
}
}
}
+
*/
#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)
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;
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 */
#include <sys/ioctl.h>
#include <sys/param.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/fs.h>
+#include <linux/hdreg.h> /* for HDIO_GETGEO */
#include "fdisk.h"
+#define NETBSD_PARTITION 0xa5
#define DKTYPENAMES
#include "fdisklabel.h"
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
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
" 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
);
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;
case 'w':
xbsd_write_disklabel ();
break;
-#if defined (i386)
+#if defined (i386) || defined (sparc)
case 'r':
return;
case 'x':
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;
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);
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__)
{
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__)
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)
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);
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);
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
static void
xbsd_list_types (void)
{
- list_types (xbsd_fstypes, BSD_FSMAXTYPES);
+ list_types (xbsd_fstypes);
}
static u_short
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;
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;
{
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
{
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
sleep (4);
}
-#if defined (i386)
+#if defined (i386) || defined (sparc)
static int
xbsd_translate_fstype (int linux_type)
{
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);
}
#if defined (__alpha__)
+#if 0
+typedef unsigned long long u_int64_t;
+#endif
+
void
alpha_bootblock_checksum (char *boot)
{
* SUCH DAMAGE.
*/
+#include <linux/types.h> /* for __u32 etc */
+
#ifndef BSD_DISKMAGIC /* perhaps from <linux/genhd.h> */
#define BSD_DISKMAGIC ((__u32) 0x82564557)
#endif
#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 */
{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
/*
--- /dev/null
+/*
+ * 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 <stdio.h> /* stderr */
+#include <stdlib.h> /* uint */
+#include <string.h> /* strstr */
+#include <unistd.h> /* write */
+#include <sys/ioctl.h> /* ioctl */
+#include <sys/stat.h> /* stat */
+
+#include <endian.h>
+#include <scsi/scsi.h>
+#include <linux/major.h> /* FLOPPY_MAJOR */
+#include <linux/hdreg.h> /* 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 */
--- /dev/null
+#include <linux/types.h> /* 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);
+
*
* 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)
#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;
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);
{
struct minix_inode * inode;
- if (!nr || nr >= INODES)
+ if (!nr || nr > INODES)
return NULL;
total++;
inode = Inode + nr;
{
struct minix2_inode *inode;
- if (!nr || nr >= INODES)
+ if (!nr || nr > INODES)
return NULL;
total++;
inode = Inode2 + nr;
{
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;
{
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;
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);
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);
{
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)) {
{
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)) {
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);
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);
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++;
* under the terms of the GNU Public License.
*/
-#define FOR_UTIL_LINUX
-
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
-#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__
#define my_llseek lseek
-#elif __i386__
-
-#include <linux/unistd.h>
-
-#ifndef __NR__llseek
-#define __NR__llseek 140
-#endif
+#else
+#include <linux/unistd.h> /* for __NR__llseek */
static int _llseek (unsigned int, unsigned long,
unsigned long, ext2_loff_t *, unsigned int);
return (retval == -1 ? (ext2_loff_t) retval : result);
}
-#else
-
-#error "llseek() is not available"
-
#endif /* __alpha__ */
#endif /* HAVE_LLSEEK */
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 */
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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <string.h>
#include <getopt.h>
#include <limits.h>
# 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"
char progname[NAME_MAX];
char *fstype = NULL;
int i, more = 0, verbose = 0;
+ char *oldpath, *newpath;
/* Check commandline options. */
opterr = 0;
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;
.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.
#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;
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);
}
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
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;
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<ZONES ; i++)
unmark_zone(i);
- for (i = MINIX_ROOT_INO ; i<INODES ; i++)
+ for (i = MINIX_ROOT_INO ; i<=INODES ; i++)
unmark_inode(i);
inode_buffer = malloc(INODE_BUFFER_SIZE);
if (!inode_buffer)
if (PAGES < 10) {
fprintf(stderr,
"%s: error: swap area needs to be at least %ldkB\n",
- program_name, 10 * PAGE_SIZE / 1024);
+ program_name, (long)(10 * PAGE_SIZE / 1024));
usage();
}
if (PAGES > 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);
}
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;
}
.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.)
*/
#define PROGNAME "sfdisk"
-#define VERSION "3.06"
-#define DATE "970626"
+#define VERSION "3.07"
+#define DATE "980518"
#include <stdio.h>
#include <stdlib.h> /* atoi, free */
#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 <linux/genhd.h>
{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"},
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);
}
/*
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 *
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 */
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);
/* 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) {
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++)
}
/* 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;
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;
}
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;
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");
}
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;
}
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;
}
{ "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);
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)
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);
* 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 ...
--- /dev/null
+ 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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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.
--- /dev/null
+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
--- /dev/null
+.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)
--- /dev/null
+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 <frodol@dds.nl>.
+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
+<http://huizen.dds.nl/~frodol>.
--- /dev/null
+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?
--- /dev/null
+.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 <frodol@dds.nl>
+.SH "SEE ALSO"
+.BR getopt (3),
+.BR bash (1),
+.BR tcsh (1).
+
--- /dev/null
+/*
+ getopt.c - Enhanced implementation of BSD getopt(1)
+ Copyright (c) 1997, 1998 Frodo Looijaard <frodol@dds.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#if LIBCGETOPT
+#include <getopt.h>
+#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 \<ws> */
+ *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));
+}
--- /dev/null
+/* 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. */
+\f
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined (__STDC__) || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* 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 <gnu-versions.h>
+#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 <stdlib.h>
+#include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+#include <unixlib.h>
+#if HAVE_STRING_H - 0
+#include <string.h>
+#endif
+#endif
+
+#if defined (WIN32) && !defined (__CYGWIN32__)
+/* It's not Unix, really. See? Capital letters. */
+#include <windows.h>
+#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 <libintl.h>
+# 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;
+\f
+#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 <string.h>
+#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__ */
+\f
+/* 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;
+}
+\f
+/* 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. */
+\f
+#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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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. */
+\f
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 <stdio.h>
+
+/* 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 <gnu-versions.h>
+#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 <stdlib.h>
+#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. */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+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 */
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/bin/bash
+if `getopt -T >/dev/null 2>&1` ; [ $? = 4 ] ; then
+ echo "Enhanced getopt(1)"
+else
+ echo "Old getopt(1)"
+fi
--- /dev/null
+#!/bin/tcsh
+getopt -T >&/dev/null
+if ( $status == 4) then
+ echo "Enhanced getopt(1)"
+else
+ echo "Old getopt(1)"
+endif
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
-f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
*/
-#ifndef lint
-char sccsid[] = "@(#) agetty.c 1.29 9/1/91 23:22:00";
-#endif
-
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <termio.h>
#include <signal.h>
int mypid = getpid();
long time();
long lseek();
- char *strncpy();
struct utmp *utp;
/*
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
Fixed by JDS June 1996 to clear lists and close files
*/
-#define _GNU_SOURCE /* for snprintf */
-
#include <sys/types.h>
#include <sys/param.h>
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 */
* 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 <A.Main@dcs.warwick.ac.uk>
*
*/
-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 <sys/types.h>
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
+#include "my_crypt.h"
#include "../version.h"
#if REQUIRE_PASSWORD && USE_PAM
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.");
* 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 <A.Main@dcs.warwick.ac.uk>
*
*/
-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
#include <errno.h>
#include <ctype.h>
#include <getopt.h>
+#include "my_crypt.h"
#include "../version.h"
#if REQUIRE_PASSWORD && USE_PAM
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.");
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);
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 */
* 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
*/
* 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
#include <sys/syslog.h>
#include <sys/sysmacros.h>
#include <netdb.h>
+#include "my_crypt.h"
#ifdef __linux__
# include <sys/sysmacros.h>
# include <security/pam_misc.h>
# 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__
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);
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;
}
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,
(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);
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);
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);
}
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);
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__
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.
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);
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);
}
*
*/
-#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 <sys/types.h>
#include <sys/stat.h>
--- /dev/null
+#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
+#include <crypt.h>
+#endif
/* Vesa Roukonen added code for asking password */
/* Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ */
-#define _XOPEN_SOURCE /* for crypt() */
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <stdio.h>
#include <errno.h>
#include "pathnames.h"
+#include "my_crypt.h"
#ifndef TRUE
# define TRUE 1
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
/*
* Sun Oct 15 13:18:34 1995 Martin Schulze <joey@finlandia.infodrom.north.de>
*
- * 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
#include <string.h>
#include <errno.h>
#include <sys/resource.h>
-
-#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
-#include <crypt.h>
-#endif
+#include "my_crypt.h"
#if 0
# include "../version.h"
*
*/
-#ifndef lint
-static char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93";
-#endif /* not lint */
-
#include <sys/types.h>
#include <sys/uio.h>
#include <signal.h>
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;
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
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);
}
}
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);
}
(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);
}
* 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 <sys/types.h>
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));
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());
* 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".
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);
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);
* 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", " ");
# 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
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"
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 $@
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
.PHONY: clean
clean:
- -rm -f *.o *~ core $(BIN) $(USRBIN) getoptprog
+ -rm -f *.o *~ core $(BIN) $(USRBIN)
* 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?
+++ /dev/null
-.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.
+++ /dev/null
-#include <stdio.h>
-#include <unistd.h>
-
-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;
-}
+++ /dev/null
-.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)
+++ /dev/null
-/* Mitch DSouza - (m.dsouza@mrc-apu.cam.ac.uk) */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <getopt.h>
-
-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;
-}
* 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 <errno.h>
#include <unistd.h>
#include <stdlib.h>
* 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.
*
-------------------------------------------------------------*/
-#ifndef lint
-static char *RCSid = "$Id: namei.c,v 1.6 1997/07/06 00:13:09 aebr Exp $";
-#endif
-
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char *argv[];
{
void namei(), usage();
- char *getwd();
int getopt();
extern int optind;
register int c;
}
}
- if(getwd(curdir) == NULL){
+ if(getcwd(curdir, sizeof(curdir)) == NULL){
(void)fprintf(stderr, "namei: unable to get current directory - %s\n", curdir);
exit(1);
}
* 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
*/
int argc;
char *argv[];
{
- extern char *optarg;
extern int optind;
int ch;
void finish();
#define klogctl syslog
#endif
#endif
+extern int klogctl(int type, char *buf, int len);
/* Constants. */
* 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 <sys/types.h>
#include <errno.h>
#include <stdio.h>
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
.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
.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.
* 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 <sys/param.h>
#include <sys/dir.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
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",
"/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
};
}
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;
int print;
void
-lookup(cp)
- register char *cp;
-{
+lookup(char *cp) {
register char *dp;
for (dp = cp; *dp; dp++)
}
void
-looksrc(cp)
- char *cp;
-{
+looksrc(char *cp) {
if (Sflag == 0) {
find(srcdirs, cp);
} else
}
void
-lookbin(cp)
- char *cp;
-{
+lookbin(char *cp) {
if (Bflag == 0)
find(bindirs, cp);
else
}
void
-lookman(cp)
- char *cp;
-{
+lookman(char *cp) {
if (Mflag == 0) {
find(mandirs, cp);
} else
}
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;
}
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)
* - 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 <unistd.h>
#include <utmp.h>
#include <ctype.h>
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,
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);
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
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
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
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)
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)
.\" 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
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.
.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 ),
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:
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
--- /dev/null
+/* Including <linux/fs.h> 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))
#include <sys/ioctl.h>
#include <sys/stat.h>
-#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;
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;
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;
{
struct loop_info loopinfo;
int fd;
-
+
if ((fd = open(device, O_RDWR)) < 0) {
perror(device);
return;
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)) {
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;
--- /dev/null
+#!/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 <asm/posix_types.h>
+# 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 <asm/posix_types.h>' >> 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 <linux/loop.h>' >> loop.h
+else
+ echo '#include "h/loop.h"' >> loop.h
+fi
+
+echo '#undef dev_t' >> loop.h
.\" 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
(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
.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" .
* 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 <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
*/
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
+#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/mount.h>
-#if !defined(__GLIBC__)
-#define _LINUX_TYPES_H /* kludge to prevent inclusion */
-#endif /* __GLIBC */
-#define _LINUX_WAIT_H /* idem */
-#define _I386_BITOPS_H /* idem */
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/iso_fs.h>
-
-#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;
/* Nonzero for chatty (-v). */
int verbose = 0;
+/* Nonzero for sloppy (-s). */
+int sloppy = 0;
+
/* True for explicit read/write (-w). */
int readwrite = 0;
#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 }
};
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);
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
*/
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) {
|| 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";
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;
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 */
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);
}
}
- 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
if (strlen (type) < 100)
#endif
{
- struct stat statbuf;
char mountprog[120];
sprintf(mountprog, "/sbin/mount.%s", type);
{
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
}
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",
&& (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);
}
}
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;
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:
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) {
/* 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) {
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;
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;
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)
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
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 */
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;
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 ()) {
switch (argc) {
case 0:
/* mount -a */
- result = mount_all (types);
+ result = mount_all (types, options);
if (result == 0 && verbose)
error("not mounted anything");
break;
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;
#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 */
.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
.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
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
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
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
.SH AUTHOR
"Rick Sladkey" <jrs@world.std.com>
.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
*
* Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
* Omit the call to connect() for Linux version 1.3.11 or later.
+ *
+ * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
+ * Implemented the "bg", "fg" and "retry" mount options for NFS.
*/
/*
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/utsname.h>
+#include <sys/stat.h>
#include <arpa/inet.h>
#include "sundries.h"
#include "nfsmount.h"
-#if defined(__GLIBC__)
-#define _LINUX_SOCKET_H
-#endif /* __GLIBC__ */
-#define _I386_BITOPS_H
-#include <linux/fs.h>
#include <linux/nfs.h>
+#include "mount_constants.h"
#include "nfs_mount3.h"
static char *nfs_strerror(int stat);
}
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;
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;
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)) {
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));
nocto = 0;
nolock = 0;
noac = 0;
- retry = 10000;
+ retry = 10000; /* 10000 minutes ~ 1 week */
tcp = 0;
mountprog = MOUNTPROG;
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;
+ }
}
}
}
printf("tcp = %d\n",
(data.flags & NFS_MOUNT_TCP) != 0);
#endif
-#if 0
- goto fail;
-#endif
#endif
data.version = nfs_mount_version;
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",
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
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
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);
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);
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);
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);
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);
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);
}
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);
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);
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);
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);
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);
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);
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);
#include <sys/param.h> /* for MAXPATHLEN */
#endif
#include <errno.h>
-#ifndef STDC_HEADERS
-extern int errno;
-#endif
#include <sys/stat.h> /* for S_IFLNK */
*new_path = '\0';
return resolved_path;
}
-
/*
+ * 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 <sys/types.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
-#ifndef bool_t
+#if !defined(bool_t) && !defined(__GLIBC__)
#include <rpc/types.h>
#endif
extern int mount_quiet;
extern int verbose;
+extern int sloppy;
#define streq(s, t) (strcmp ((s), (t)) == 0)
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);
#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 */
#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) */
-# find out whether we can include <sys/swap.h>
+# Find out whether we can include <sys/swap.h>
# and whether libc thinks that swapon() has two arguments.
+# Of course this will fail if <sys/swap.h> 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
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;
-char version[] = "mount-2.7e";
+char version[] = "mount-2.8";
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
USRINFO= ipc.info
-all: $(SBIN) $(BIN) $(USRSBIN) $(USRBIN)
+all: $(SBIN) $(BIN) $(USRBIN)
sln: sln.c
$(CC) -static $(CFLAGS) $(LDFLAGS) $< -o $@
# Rules for everything else
arch: arch.o
-chroot: chroot.o
hwclock.o: hwclock.c shhopt.h
hwclock: hwclock.o shhopt.o
ctrlaltdel: ctrlaltdel.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)
$(INSTALLMAN) $(USRINFO) $(INFODIR)
clean:
- -rm -f *.o *~ core $(SBIN) $(BIN) $(USRSBIN) $(USRBIN)
+ -rm -f *.o *~ core $(SBIN) $(BIN) $(USRBIN)
.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)
+++ /dev/null
-.\" Rick Sladkey <jrs@world.std.com>
-.\" In the public domain.
-.\" Pathname modified by faith@cs.unc.edu
-.TH CHROOT 8 "20 November 1993" "Linux 0.99" "Linux Programmer's Manual"
-.SH NAME
-chroot \- change root directory and execute a program there
-.SH SYNOPSIS
-.BI chroot " directory program" " [ " "arg ..." " ]"
-.SH DESCRIPTION
-.B chroot
-changes the root directory for a process to a new directory
-executes a program there.
-.SH "SEE ALSO"
-.BR chroot (2)
-.SH AUTHOR
-Rick Sladkey <jrs@world.std.com>
+++ /dev/null
-/*
- * chroot.c -- change root directory and execute a command there
- * Rick Sladkey <jrs@world.std.com>
- * In the public domain.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-int main(int argc, char *argv[])
-{
- if (argc < 3) {
- fprintf(stderr, "usage: %s directory program [arg ...]\n",
- argv[0]);
- exit(1);
- }
- if (chroot(argv[1]) < 0) {
- perror("chroot");
- exit(1);
- }
- execvp(argv[2], argv + 2);
- perror("execvp");
- exit(1);
-}
#include <errno.h>
#include <linux/tty.h>
#include <termios.h>
-#include <linux/tqueue.h>
+#if 0
+#include <linux/tqueue.h> /* required for old kernels */
+ /* compilation errors on other kernels */
+#endif
#include <linux/cyclades.h>
#include <signal.h>
.\" 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.
.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
* 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 <linux/unistd.h>
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;
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;
cmd = 8;
level = atoi(optarg);
break;
+ case 's':
+ bufsize = atoi(optarg);
+ break;
case '?':
default:
usage();
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 );
-.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
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
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
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.
.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
.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
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
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
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.
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.
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).
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
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,
****************************************************************************/
-#define _GNU_SOURCE /* for snprintf */
-
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "../version.h"
#define MYNAME "hwclock"
-#define VERSION "2.1"
+#define VERSION "2.2"
#define FLOOR(arg) ((arg >= 0 ? (int) arg : ((int) arg) - 1));
};
-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:
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
*/
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 <linux/version.h>
/* Check if the /dev/rtc interface is available in this version of
#include <linux/kd.h>
static const bool got_rtc = TRUE;
#else
-/* Dummy to make it compile */
-#define RTC_SET_TIME 0
static const bool got_rtc = FALSE;
+/* 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)
#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.
}
-struct timeval
+static struct timeval
time_inc(struct timeval addend, float increment) {
/*----------------------------------------------------------------------------
The time, in "timeval" format, which is <increment> seconds after
hclock_read(unsigned char reg) {
/*---------------------------------------------------------------------------
Relative byte <reg> 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;
}
hclock_write(unsigned char reg, unsigned char val) {
/*----------------------------------------------------------------------------
Set relative byte <reg> of the Hardware Clock value to <val>.
+
+ On non-ISA machine, do nothing.
----------------------------------------------------------------------------*/
#ifdef __i386__
/* & 0x7f ensures that we are not disabling NMI while we read.
}
-void
+static void
read_adjtime(struct adjtime *adjtime_p, int *rc_p) {
/*----------------------------------------------------------------------------
Read the adjustment parameters out of the /etc/adjtime file.
-void
+static void
synchronize_to_clock_tick_ISA(int *retcode_p) {
/*----------------------------------------------------------------------------
Same as synchronize_to_clock_tick(), but just for ISA.
-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) {
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
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
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.
}
/* 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)
-void
+static void
read_hardware_clock_kd(struct tm *tm) {
/*----------------------------------------------------------------------------
Read the hardware clock and return the current time via <tm>
- argument. Use ioctls to /dev/console on what we assume is an Alpha
+ 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 {
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);
-void
+static void
read_hardware_clock_rtc_ioctl(struct tm *tm) {
/*----------------------------------------------------------------------------
Read the hardware clock and return the current time via <tm>
-void
+static void
read_hardware_clock_isa(struct tm *tm) {
/*----------------------------------------------------------------------------
Read the hardware clock and return the current time via <tm> argument.
Assume we have an ISA machine and read the clock directly with CPU I/O
instructions.
+
+ 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 <tm> argument.
-void
+static void
set_hardware_clock_kd(const struct tm new_broken_time,
const bool testing) {
/*----------------------------------------------------------------------------
Set the Hardware Clock to the time <new_broken_time>. Use ioctls to
- /dev/console on what we assume is an Alpha machine.
+ /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);
-void
+static void
set_hardware_clock_rtc_ioctl(const struct tm new_broken_time,
const bool testing) {
/*----------------------------------------------------------------------------
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);
}
-void
+static void
set_hardware_clock_isa(const struct tm new_broken_time,
const bool testing) {
/*----------------------------------------------------------------------------
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));
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,
-void
+static void
set_hardware_clock_exact(const time_t settime,
const struct timeval ref_time,
const enum clock_access_method clock_access,
-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.
-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
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=";
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"
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);
-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 */
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");
}
-void
+static void
adjust_drift_factor(struct adjtime *adjtime_p,
const time_t nowtime,
const time_t hclocktime ) {
-void
+static void
calculate_adjustment(
const float factor,
const time_t last_time,
-void
+static void
save_adjtime(const struct adjtime adjtime, const bool testing) {
/*-----------------------------------------------------------------------------
Write the contents of the <adjtime> structure to its disk file.
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");
-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,
-void
+static void
determine_clock_access_method(const bool user_requests_ISA,
enum clock_access_method *clock_access_p) {
/*----------------------------------------------------------------------------
using compile-time constants.
<user_requests_ISA> 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 */
"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;
} 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",
-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.
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);
} 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.
+ <getepoch>, <setepoch>, and <epoch> are hwclock invocation options.
+
+ <epoch> == -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);
}
}
}
are given by the option_def. The only exception is <show>, which
may be modified after parsing is complete to effect an implied option.
*/
- bool show, set, systohc, hctosys, adjust, version;
+ bool 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) {
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);
}
}
- 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);
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).
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
+#include <errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <linux/version.h>
int c;
int i;
extern char *optarg;
- extern int optind;
while ( (c = getopt( argc, argv, "r:d:sv" )) != EOF )
switch (c) {
* 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));
* SUCH DAMAGE.
*/
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1983, 1989, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93";
-#endif /* not lint */
-
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
* 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;
}
errs += donice(which, who, prio);
}
- exit(errs != 0);
+ return (errs != 0);
}
int
* 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.
*
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
+/* This is for (some) 2.1 kernels */
+#define LP_NEED_CAREFUL
#include<linux/lp.h>
#include<linux/fs.h>
#include<sys/ioctl.h>
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
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)
* (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 <stdlib.h>
#include <malloc.h>
#include <errno.h>
* 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 <stdio.h>
#include <unistd.h> /* for close() */
#include <string.h>
* 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 <stdio.h>
+
/*
COLRM removes unwanted columns from a file
Jeff Schriebman UC Berkeley 11-74
* 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 <sys/types.h>
#include <sys/ioctl.h>
* SUCH DAMAGE.
*/
-#ifndef lint
-static char sccsid[] = "@(#)conv.c 5.4 (Berkeley) 6/1/90";
-#endif /* not lint */
-
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
* SUCH DAMAGE.
*/
-#ifndef lint
-static char sccsid[] = "@(#)display.c 5.11 (Berkeley) 3/9/91";
-#endif /* not lint */
-
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
* 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 <sys/types.h>
#include <stdio.h>
#include "hexdump.h"
* SUCH DAMAGE.
*/
-#ifndef lint
-static char sccsid[] = "@(#)hexsyntax.c 5.2 (Berkeley) 5/8/90";
-#endif /* not lint */
-
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
* 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
**
#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);
} 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;
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';
#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);
hard++; /* Hard copy terminal */
Lpp = 24;
}
+
if (tigetflag("xenl"))
eatnl++; /* Eat newline at last column + 1; dec, concept */
if (Mcol <= 0)
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 ()
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 ();
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 ();
* SUCH DAMAGE.
*/
-#ifndef lint
-static char sccsid[] = "@(#)odsyntax.c 5.4 (Berkeley) 3/8/91";
-#endif /* not lint */
-
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
* SUCH DAMAGE.
*/
-#ifndef lint
-static char sccsid[] = "@(#)parse.c 5.6 (Berkeley) 3/9/91";
-#endif /* not lint */
-
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
*
* Wed Sep 14 22:26:00 1994: Patch from bjdouma <bjdouma@xs4all.nl> 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 <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#ifdef __linux__
#include <unistd.h>
-#endif /* linux */
void usage __P((void));
void warn __P((const char *, ...));
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__
* Added internationalization patches from Vitor Duarte <vad@fct.unl.pt>
*/
-#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 <sys/types.h>
#include <fcntl.h>
#include <errno.h>
* 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 <jongk@cs.utwente.nl> to use terminfo instead
** of termcap.
#include <unistd.h> /* for getopt(), isatty() */
#include <string.h> /* for bzero() */
#include <term.h> /* for setupterm() */
+#include <stdlib.h> /* for getenv() */
void filter(FILE *f);
void flushln(void);
int c, ret;
char *termtype;
FILE *f;
- char *getenv(), *strcpy();
termtype = getenv("TERM");
if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
#define UTIL_LINUX 1
-char *util_linux_version="util-linux 2.6";
+char *util_linux_version="util-linux 2.8";