From 5c36a0eb7cdb0360f9afd5d747c321f423b35984 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 7 Dec 2006 00:25:37 +0100 Subject: Imported from util-linux-2.9i tarball. --- ANNOUNCE | 21 +- HISTORY | 559 ++++++++ INSTALL | 57 + LSM | 13 +- MAINTAINERS | 23 +- MCONFIG | 57 +- Makefile | 13 +- README | 503 -------- attic/pidof.c | 95 ++ attic/strings.1 | 96 ++ attic/strings.c | 212 +++ bsd/Makefile | 17 - bsd/err.c | 185 --- bsd/err.h | 70 - bsd/getopt.3 | 210 --- bsd/getopt.c | 116 -- bsd/pathnames.h | 101 -- disk-utils/Makefile | 47 - disk-utils/README.cfdisk | 45 - disk-utils/README.fdisk | 579 --------- disk-utils/cfdisk.8 | 403 ------ disk-utils/cfdisk.8.bak | 407 ------ disk-utils/cfdisk.c | 2560 ------------------------------------ disk-utils/cfdisk.c.bak | 2066 ----------------------------- disk-utils/cfdisk.c.orig | 2066 ----------------------------- disk-utils/fdformat.c | 12 +- disk-utils/fdisk.8 | 213 --- disk-utils/fdisk.c | 1940 ---------------------------- disk-utils/fdisk.h | 72 -- disk-utils/fdisklabel.c | 815 ------------ disk-utils/fdisklabel.h | 229 ---- disk-utils/fdisksunlabel.c | 661 ---------- disk-utils/fdisksunlabel.h | 73 -- disk-utils/fdprm | 2 + disk-utils/frag.8 | 47 - disk-utils/frag.c | 311 ----- disk-utils/fsck.minix.c | 28 +- disk-utils/llseek.c | 102 -- disk-utils/mkfs.8 | 9 +- disk-utils/mkfs.minix.c | 4 +- disk-utils/mkswap.8 | 163 ++- disk-utils/mkswap.c | 271 +++- disk-utils/setfdprm.c | 3 +- disk-utils/sfdisk.8 | 497 ------- disk-utils/sfdisk.c | 2857 ---------------------------------------- disk-utils/sfdisk.examples | 264 ---- example.files/filesystems | 19 + example.files/issue0 | 1 + example.files/syslog.conf | 12 - example.files/syslog.conf.alt | 22 - fdisk/Makefile | 68 + fdisk/README.cfdisk | 45 + fdisk/README.fdisk | 583 +++++++++ fdisk/cfdisk.8 | 406 ++++++ fdisk/cfdisk.c | 2642 +++++++++++++++++++++++++++++++++++++ fdisk/fdisk.8 | 223 ++++ fdisk/fdisk.c | 2046 +++++++++++++++++++++++++++++ fdisk/fdisk.h | 85 ++ fdisk/fdiskaixlabel.c | 64 + fdisk/fdiskaixlabel.h | 34 + fdisk/fdiskbsdlabel.c | 825 ++++++++++++ fdisk/fdiskbsdlabel.h | 229 ++++ fdisk/fdisksgilabel.c | 888 +++++++++++++ fdisk/fdisksgilabel.h | 133 ++ fdisk/fdisksunlabel.c | 690 ++++++++++ fdisk/fdisksunlabel.h | 74 ++ fdisk/llseek.c | 102 ++ fdisk/sfdisk.8 | 506 ++++++++ fdisk/sfdisk.c | 2864 +++++++++++++++++++++++++++++++++++++++++ fdisk/sfdisk.examples | 264 ++++ games/Makefile | 2 +- getopt-1.0.3a/COPYING | 339 +++++ getopt-1.0.3a/Changelog | 14 + getopt-1.0.3a/Makefile | 52 + getopt-1.0.3a/README | 80 ++ getopt-1.0.3a/TODO | 6 + getopt-1.0.3a/getopt.1 | 436 +++++++ getopt-1.0.3a/getopt.c | 448 +++++++ getopt-1.0.3a/gnu/getopt.c | 1050 +++++++++++++++ getopt-1.0.3a/gnu/getopt.h | 131 ++ getopt-1.0.3a/gnu/getopt1.c | 187 +++ getopt-1.0.3a/parse.bash | 47 + getopt-1.0.3a/parse.tcsh | 77 ++ getopt-1.0.3a/test.bash | 6 + getopt-1.0.3a/test.tcsh | 7 + getopt/COPYING | 339 ----- getopt/Changelog | 8 - getopt/Makefile | 56 - getopt/README | 80 -- getopt/TODO | 4 - getopt/getopt.1 | 436 ------- getopt/getopt.c | 448 ------- getopt/gnu/getopt.c | 1050 --------------- getopt/gnu/getopt.h | 131 -- getopt/gnu/getopt1.c | 187 --- getopt/parse.bash | 47 - getopt/parse.tcsh | 76 -- getopt/test.bash | 6 - getopt/test.tcsh | 7 - lib/Makefile | 17 + lib/err.c | 185 +++ lib/err.h | 70 + lib/linux_reboot.h | 30 + lib/my_reboot.c | 40 + lib/pathnames.h | 104 ++ lib/setproctitle.c | 117 ++ lib/setproctitle.h | 7 + login-utils/Makefile | 51 +- login-utils/agetty.c | 8 +- login-utils/checktty.c | 24 +- login-utils/chfn.c | 17 +- login-utils/chsh.1 | 4 +- login-utils/chsh.c | 5 - login-utils/last.1.orig | 49 - login-utils/last.c | 26 +- login-utils/last.c.orig | 381 ------ login-utils/login.1 | 6 +- login-utils/login.c | 141 +- login-utils/passwd.1 | 9 +- login-utils/passwd.c | 19 +- login-utils/shutdown.8 | 32 +- login-utils/shutdown.c | 239 ++-- login-utils/simpleinit.c | 18 +- login-utils/vipw.c | 5 +- misc-utils/Makefile | 13 +- misc-utils/cal.1 | 4 +- misc-utils/cal.c | 51 +- misc-utils/chkdupexe.pl | 8 +- misc-utils/ddate.1 | 12 +- misc-utils/ddate.c | 14 +- misc-utils/hostname.c.orig | 187 --- misc-utils/kill.c | 130 +- misc-utils/look.c | 163 +-- misc-utils/mcookie.1 | 9 +- misc-utils/mcookie.c | 7 +- misc-utils/procs.c | 8 +- misc-utils/script.c | 28 +- misc-utils/setterm.c | 6 +- misc-utils/whereis.c | 2 + misc-utils/write.c | 19 +- mkminix-0.1/README | 47 + mkminix-0.1/linux/minix_fs.h | 135 ++ mkminix-0.1/mkmin-dj.h | 43 + mkminix-0.1/mkminix.diff | 46 + mount/Makefile | 45 +- mount/Makefile.standalone | 50 +- mount/fstab.5 | 2 +- mount/fstab.c | 305 +++-- mount/fstab.h | 5 +- mount/getusername.c | 14 + mount/getusername.h | 1 + mount/linux_fs.h | 21 +- mount/losetup.c | 4 +- mount/mk_loop_h | 7 +- mount/mntent.c | 214 +++ mount/mntent.h | 16 + mount/mount.8 | 84 +- mount/mount.c | 534 ++++---- mount/mount_by_label.c | 143 ++ mount/mount_by_label.h | 2 + mount/mount_constants.h | 20 + mount/mount_guess_fstype.c | 252 ++++ mount/mount_guess_fstype.h | 15 + mount/nfsmount.c | 24 +- mount/nfsmount_xdr.c | 49 +- mount/sundries.c | 12 +- mount/swap.configure | 22 +- mount/swap_constants.h | 15 + mount/swapon.8 | 14 +- mount/swapon.c | 30 +- mount/umount.c | 145 ++- mount/version.c | 3 +- sys-utils/Makefile | 16 +- sys-utils/ctrlaltdel.c | 10 +- sys-utils/hwclock.8 | 130 +- sys-utils/hwclock.c | 362 ++++-- sys-utils/ipcrm.c | 15 + sys-utils/ipcs.c | 30 +- sys-utils/kbdrate.8 | 7 + sys-utils/kbdrate.c | 15 +- sys-utils/lpcntl.8 | 30 - sys-utils/lpcntl.c | 54 - sys-utils/sln.1 | 22 - sys-utils/sln.8 | 23 + text-utils/Makefile | 19 +- text-utils/colcrt.c | 7 +- text-utils/colrm.c | 5 +- text-utils/column.c | 1 - text-utils/more.c | 129 +- text-utils/strings.1 | 96 -- text-utils/strings.c | 212 --- text-utils/ul.c | 90 +- uio.h-diff | 20 - util-linux-2.1.Announce | 48 - util-linux-2.1.bin.Notes | 549 -------- util-linux-2.1.lsm | 23 - version.h | 5 +- 197 files changed, 20725 insertions(+), 23453 deletions(-) create mode 100644 HISTORY create mode 100644 INSTALL delete mode 100644 README create mode 100644 attic/pidof.c create mode 100644 attic/strings.1 create mode 100644 attic/strings.c delete mode 100644 bsd/Makefile delete mode 100644 bsd/err.c delete mode 100644 bsd/err.h delete mode 100644 bsd/getopt.3 delete mode 100644 bsd/getopt.c delete mode 100644 bsd/pathnames.h delete mode 100644 disk-utils/README.cfdisk delete mode 100644 disk-utils/README.fdisk delete mode 100644 disk-utils/cfdisk.8 delete mode 100644 disk-utils/cfdisk.8.bak delete mode 100644 disk-utils/cfdisk.c delete mode 100644 disk-utils/cfdisk.c.bak delete mode 100644 disk-utils/cfdisk.c.orig delete mode 100644 disk-utils/fdisk.8 delete mode 100644 disk-utils/fdisk.c delete mode 100644 disk-utils/fdisk.h delete mode 100644 disk-utils/fdisklabel.c delete mode 100644 disk-utils/fdisklabel.h delete mode 100644 disk-utils/fdisksunlabel.c delete mode 100644 disk-utils/fdisksunlabel.h delete mode 100644 disk-utils/frag.8 delete mode 100644 disk-utils/frag.c delete mode 100644 disk-utils/llseek.c delete mode 100644 disk-utils/sfdisk.8 delete mode 100644 disk-utils/sfdisk.c delete mode 100644 disk-utils/sfdisk.examples create mode 100644 example.files/filesystems create mode 100644 example.files/issue0 delete mode 100644 example.files/syslog.conf delete mode 100644 example.files/syslog.conf.alt create mode 100644 fdisk/Makefile create mode 100644 fdisk/README.cfdisk create mode 100644 fdisk/README.fdisk create mode 100644 fdisk/cfdisk.8 create mode 100644 fdisk/cfdisk.c create mode 100644 fdisk/fdisk.8 create mode 100644 fdisk/fdisk.c create mode 100644 fdisk/fdisk.h create mode 100644 fdisk/fdiskaixlabel.c create mode 100644 fdisk/fdiskaixlabel.h create mode 100644 fdisk/fdiskbsdlabel.c create mode 100644 fdisk/fdiskbsdlabel.h create mode 100644 fdisk/fdisksgilabel.c create mode 100644 fdisk/fdisksgilabel.h create mode 100644 fdisk/fdisksunlabel.c create mode 100644 fdisk/fdisksunlabel.h create mode 100644 fdisk/llseek.c create mode 100644 fdisk/sfdisk.8 create mode 100644 fdisk/sfdisk.c create mode 100644 fdisk/sfdisk.examples create mode 100644 getopt-1.0.3a/COPYING create mode 100644 getopt-1.0.3a/Changelog create mode 100644 getopt-1.0.3a/Makefile create mode 100644 getopt-1.0.3a/README create mode 100644 getopt-1.0.3a/TODO create mode 100644 getopt-1.0.3a/getopt.1 create mode 100644 getopt-1.0.3a/getopt.c create mode 100644 getopt-1.0.3a/gnu/getopt.c create mode 100644 getopt-1.0.3a/gnu/getopt.h create mode 100644 getopt-1.0.3a/gnu/getopt1.c create mode 100644 getopt-1.0.3a/parse.bash create mode 100644 getopt-1.0.3a/parse.tcsh create mode 100644 getopt-1.0.3a/test.bash create mode 100644 getopt-1.0.3a/test.tcsh delete mode 100644 getopt/COPYING delete mode 100644 getopt/Changelog delete mode 100644 getopt/Makefile delete mode 100644 getopt/README delete mode 100644 getopt/TODO delete mode 100644 getopt/getopt.1 delete mode 100644 getopt/getopt.c delete mode 100644 getopt/gnu/getopt.c delete mode 100644 getopt/gnu/getopt.h delete mode 100644 getopt/gnu/getopt1.c delete mode 100644 getopt/parse.bash delete mode 100644 getopt/parse.tcsh delete mode 100644 getopt/test.bash delete mode 100644 getopt/test.tcsh create mode 100644 lib/Makefile create mode 100644 lib/err.c create mode 100644 lib/err.h create mode 100644 lib/linux_reboot.h create mode 100644 lib/my_reboot.c create mode 100644 lib/pathnames.h create mode 100644 lib/setproctitle.c create mode 100644 lib/setproctitle.h delete mode 100644 login-utils/last.1.orig delete mode 100644 login-utils/last.c.orig mode change 100644 => 100755 misc-utils/chkdupexe.pl delete mode 100644 misc-utils/hostname.c.orig create mode 100644 mkminix-0.1/README create mode 100644 mkminix-0.1/linux/minix_fs.h create mode 100644 mkminix-0.1/mkmin-dj.h create mode 100644 mkminix-0.1/mkminix.diff create mode 100644 mount/getusername.c create mode 100644 mount/getusername.h create mode 100644 mount/mntent.c create mode 100644 mount/mntent.h create mode 100644 mount/mount_by_label.c create mode 100644 mount/mount_by_label.h create mode 100644 mount/mount_guess_fstype.c create mode 100644 mount/mount_guess_fstype.h create mode 100644 mount/swap_constants.h delete mode 100644 sys-utils/lpcntl.8 delete mode 100644 sys-utils/lpcntl.c delete mode 100644 sys-utils/sln.1 create mode 100644 sys-utils/sln.8 delete mode 100644 text-utils/strings.1 delete mode 100644 text-utils/strings.c delete mode 100644 uio.h-diff delete mode 100644 util-linux-2.1.Announce delete mode 100644 util-linux-2.1.bin.Notes delete mode 100644 util-linux-2.1.lsm diff --git a/ANNOUNCE b/ANNOUNCE index 0d762863c..1eed25ef1 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,14 +1,14 @@ -util-linux-2.8.tar.gz (source only distribution) +util-linux-2.9.tar.gz (source only distribution) READ the README file and the stuff below. -util-linux-2.8.tar.gz (source only distribution) +util-linux-2.9.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 Debian +Its 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. @@ -20,12 +20,13 @@ and Linux 2.0/Libc 5 and has also been tested with libc 6 on intel, alpha and sparc. People are encouraged to make _nice_ patches to util-linux and submitting them to util-linux@math.uio.no. Thank you. -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 - sunsite.unc.edu:/pub/Linux/system/Misc, as well as +Util-Linux 2.9 is imediately available from + ftp.win.tue.nl:/pub/linux/util +and will probably appear soon at + ftp.math.uio.no:/pub/linux + sunsite.uio.no:/pub/unix/linux/packages/util-linux + sunsite.unc.edu:/pub/Linux/system/Misc tsx-11.mit.edu:/pub/linux/packages/utils -when the people in charge there get time. -Nicolai Langfeldt +Andries Brouwer + diff --git a/HISTORY b/HISTORY new file mode 100644 index 000000000..f0ccc9ab5 --- /dev/null +++ b/HISTORY @@ -0,0 +1,559 @@ +util-linux 2.9i: + +* fixed 2.9h typo in more +* added -m: `Monday is 1st day' option to cal (Jean-Francois Bignolles) +* changed PAM stuff in login.c (+- mjohnson) +* added warning to cfdisk in case of multiple bootable partitions +* added 2048-byte sector support in fdisk (Oliver Schaertel) + +util-linux 2.9h: + +* mount recognizes "uid=useruid" and "gid=usergid" in /etc/fstab. +* documented the fact that "mount -t smb" will call /sbin/mount.smb. +* mount gives clear error message when fstab does not end in newline. +* swapon checks mode of file +* cfdisk got a more specific exit status (Enrique Zanardi) + +util-linux 2.9g: + +* mount updates (locking, "users" keyword, "/etc/filesystems", + "proto" and "vers" options in nfsmount, ...) + +util-linux 2.9f: + +* made ul handle lines of arbitrary length (Scott Maxwell) +* killed some C/H/S nonsense in fdisk +* fixes for archs with unsigned char type (Ambrose Li) +* fdisk fixes for power pc (Tom Rini) +* added a define for NCURSES_CONST +* fixes for list of signals in kill.c +* fixes for user name length in last.c + +util-linux 2.9e: + +* added a forgotten declaration to login.c (Christian Oyarzun) + +util-linux 2.9d: + +* fixed segfault in umount caused by Wilcox' patch (Steffen Zahn) +* added lnz stuff to fdisk + +util-linux 2.9c: + +* refixed PAM stuff in login.c that was broken in 2.8. + +util-linux 2.9b: + +* split README into INSTALL and HISTORY +* added a sentence to swapon.8 +* behaviour of write on non-ASCII fixed +* hwclock adapted to survive a failing mktime() + +util-linux 2.9a: + +* added an include to lib/my_reboot.c so that __GLIBC__ is defined +* added setlocale() to login-utils/chfn.c +* do not recompute MAIL in login-utils/login.c + +util-linux 2.9: + +HIGHLIGHTS for version 2.9: + +1) Removed programs: + - strings. There is a version in binutils. + - frag. (Moved to historic in 2.4, crept back in 2.5. Gone again.) +1a) Not yet removed program: + - setfdprm. It also is in fdutils-5.2 (with an exceptionally + ugly man page). +1b) Removed directory: + - bsd. (The routine getopt() is in libc. err() moved to lib.) +2) Improvements: + - ddate has been fixed to count down to the new, right X-day + - look is now willing to search non-English dictionaries + (i.e., uses locale) + - cal now knows that Dutch day abbreviations have length 2 only + - mcookie does not block when no random stuff is available + - shutdown got a configuration file /etc/shutdown.conf + - fdisk now reads SGI disk labels (thanks to Andreas Neuper) + - mkswap now knows about new swap areas; mkswap.8 has been rewritten + - umount knows about umount2() and forced unmounting of nfs mounts + (however, I don't think it really works) + - mount is now willing to handle file names with embedded spaces + - mount can now mount things by UUID or volume name +3) Uglifications: + - swap.h has been replaced by a private swap_constants.h since + does not compile + - reboot has become a private routine, since libc5 and glibc2 conflict + - a mkminix-0.1 directory contains some patches to let mkfs.minix + work under DOS. (Untested.) +4) Numerous other small changes. + +0xF) Send questions and/or patches to util-linux@math.uio.no + +util-linux 2.8: + +HIGHLIGHTS for version 2.8: + +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 + - 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) + + +util-linux 2.7: + +HIGLIGHTS for version 2.7: + +1) util-linux now _requires_ ncurses. Several programs are completely + converted to use terminfo (instead of termcap). + +2) Removed progams: + - clock: Dropped entirely. Use hwclock (included). + - sync: is in gnu fileutils. + - setserial: Is being maintained by Ted Ts'o, he recommends + setserial-2.12 (2.13 is bad luck) + - clear: Included in ncurses + - hostname, domainname, dnsdomainname: It's in net-utils. + - lpcntl. + +3) Bugfixes, additions: + - cfdisk: A much improved version. All known bugs have been fixed. + - sfdisk: A command line fdisk type utility, formerly called fdisk-3.04. + - SECURITY: All known holes in login, chfn, chsh and others have been + plugged. UPGRADE NOW if you haven't already fixed them yourself. + - Should work with libc 4, 5 and 6 (gnulibc), on m68k, intel, alpha + and sparc. + +4) Problems: + - The rpcgen that comes in NetKit-B-0.09 is broken. At least as + packaged with RedHat 4.2 (NetKit-B-0.09-6). There are several + ways to deal with this: + - Don't run rpcgen, the needed pre-generated sources are included + (nfsmount_xdr.c). You must hack mount/Makefile to do this. + - Edit the source emitted by rpcgen so it can compile. This is very + simple if you know C. + - Disable the NFS parts of mount. You have to edit mount/Makefile + to do this. + - Use some other rpcgen. + +util-linux 2.6.1 + +This release was never made public + +See notes for 2.6 for installation instructions. + +This is a incremental release containing some fixes. A new release +will be made later fixing the outstanding bugs. +- Things compiles and works better with recent releases of kernel, + ncurses, and so forth: fdisk, more +- Some fixes to make things compile out of the box on alphas. +- There has been reported a problem with login and /etc/usertty. It + should be fixed. If you still have problems get a recent MAKEDEV and + use it to make new tty devices. They were renumbered sometime during + the 1.3 phase of the kernel. +- ipcs now displays the key of the structures. +- A (harmless?) overflow bug was fixed in login. + +Outstanding bugs: +- login/getty has a denial of service problem. +- Several places needs a bit more polish. +- There are a _lot_ of nonfatal warnings when compiling mount. This will + not necesarily be fixed. + + +util-linux 2.6 + +HIGHLIGHTS for version 2.6: + +0) The first release with me at the helm. PLEASE SEND PATCHES AND + UPDATES TO: util-linux@math.uio.no. + +1) Removed programs: + - md5sum, dsplit: available in GNU textutils. + - syslogd: Sysklogd is now prefered. It is available at + tsx-11.mit.edu:/pub/sources/sbin + sunsite.unc.edu:/pub/Linux/system/Daemons + +2) Bugfixes, additions: + - SECURITY: All known holes in mount have been fixed. UPGRADE NOW + if you haven't already! + - Portability enhancments to the minix filesystem utils (m68k and + Arm patches). + - passwd/chsh/chfn will not mess up the passwd file on a NIS machine + - others too numerous to enumerate. + +3) New programs: + - vigr (it's like vipw) + - Introducing hwclock. A complete rewrite of the latest available + clock source. It supports intel/CMOS, /dev/rtc and linux/m68k + system clock interfaces. Clock supports the same things but is now + obsolete and will not be present in the next release. Start using + hwclock now. Please. + + +util-linux 2.5 + +HIGHLIGHTS for version 2.5: +0) Nicolai Langfeldt is taking over maintenance of util-linux, with the + help of a few others (Michael K. Johnson, Andries Brouwer, and Rik + Faith). + + PLEASE SEND PATCHES AND UPDATES TO: util-linux@math.uio.no + +1) The following packages have been removed. Please use the up-to-date, + canonical versions of these packages from the listed places: + + timezone support (/usr/lib/zoneinfo, libz.a, zic, zdump): + elsie.nci.nih.gov:/pub/tzcode95d.tar.gz + elsie.nci.nih.gov:/pub/tzdata95h.tar.gz + MAKEDEV-C: + sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-C-1.5.tar.gz + MAKEDEV: + sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-2.2.tar.gz + md5sum: + prep.ai.mit.edu:/pub/gnu/textutils-1.3.tar.gz + [The GNU version is now compatible with the Plumb/Lankester + version.] + ksymoops: + Now bundled with the kernel in linux/scripts. + +2) update_state has been removed +3) fdisk now supports NetBSD disklabels courtesy of Bernhard Fastenrath + (and > 8GB disks, courtesy of + Andries Brouwer) +4) mount improved -- many patches from Andries Brouwer for greatly improved + error reporting +5) ddate, chkdupexe, and other programs have been improved and bug fixed +6) util-linux is now a source-only distribution +7) mcookie generates better random numbers and will use /dev/random or + /dev/audio if available +8) chfn, chsh, passwd, and vipw have been updated with security patches + from Zefram . Now, they all use the same + locking, and several security holes have been patched. Further, chsh + and chfn can be configured at compile time to require a password before + updates and chsh can be configured to only use shells from /etc/shells. + + +HIGHLIGHTS for version 2.4 (2.3 was never released): +0) Michael K. Johnson is the interim maintainer + while Rik Faith is working on PhD work. +1) login now makes the login tty mode 600 and places it in group "tty" +2) wall, and write will not write dangerous escape sequences +3) wall and write can be run setgid "tty". If util-linux is compiled for + this option, "mesg y" will only set group write instead of group/other + write. +4) fdisk and cfdisk have been patched with the latest llseek.c. Although I + had a lot of bug reports about fdisk from util-linux-2.2, I was unable + to reproduce any of the problems. Some of the problems appeared to be + releated to a failure to reboot the machine after changing the partition + table, and some may have been due to a specific kernel revision problem. + However, this doesn't seem to account for all of the bug reports -- if + this version gives you problem, please send as complete a bug report as + possible. +5) chkdupexe from Nicolai Langfeldt (janl@ifi.uio.no) +6) ctrlaltdel now installs into /sbin instead of /usr/sbin +7) mkfs replacement from Ron Sommeling (sommel@sci.kun.nl) +8) lpcntl removed. Use tunelp instead. +9) ksymoops from Greg McGary +10) mkfs.minix now clears the first 512 bytes of the file system so that + Minix disks won't be confused with MSDOS disks (Daniel Quinlan + (quinlan@yggdrasil.com)) +11) mkswap should now work on an Alpha running Linux +12) frag removed. See + sunsite.unc.edu:/pub/Linux/system/Filesystems/defrag-0.6.tar.gz for the + latest version. +13) mount patches from Andries.Brouwer@cwi.nl and Dan Quinlan + (quinlan@yggdrasil.com). +14) MAKEDEV and MAKEDEV-C updated to the latest versions. +15) Paths updated for FSSTND 1.2. This means that you may need to make + some links. The links you need to make we system dependent. The + ultimate goal is to rename /var/adm to /var/log and have a symbolic + link from /var/adm to /var/log during the transition period. If you + are running an ELF system, you probably won't have to do anything. The + bottom line is that the following files must exist or be pointers to + the old version (used internally by the a.out libraries): + + New Old + + /var/log/wtmp /var/adm/wtmp + /var/log/lastlog /var/adm/lastlog + /var/run/utmp /var/adm/utmp + +HIGHLIGHTS for version 2.2: +1) This is primarily a quick bug-fix release for version 2.1 +2) mkfs wrapper added back in, since e2fsprogs only supplies an fsck wrapper +3) selection removed, since someone appears to be maintaining it now. See + sunsite.unc.edu:/pub/linux/kernel/patches/console for recent sources. + For the time being, I'm keeping a copy in the historic subdirectory of + util-linux. A "make install" should work find from within that + directory. +4) Note that other floppy utilities are available from: + ftp.imag.fr:pub/Linux/ZLIBC/fdutils/fdutils-4.1.src.tar.gz + sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.1.src.tar.gz + tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.1.src.tar.gz + + +HIGHLIGHTS for version 2.1: + +1) Directory structure rearrange, with configuration support for those who + use shadow passwords and System V init (no support is provided for these + things, but your utilities won't get overwritten if you do a "make + install" after you properly edit MCONFIG). +2) fdisk and cfdisk should work as expected with 2GB+ disk drives +3) As usual, lots of stuff was updated and added, including mount, vipw, + readprofile +4) Some stuff was also deleted, and can now be found elsewhere: + fsck wrapper: tsx-11.mit.edu:/pub/linux/ALPHA/ext2fs/e2fsprogs* + pwd, su: prep.ai.mit.edu:/pub/gnu/sh-utils* + ed: prep.ai.mit.edu:/pub/gnu/ed* + od: prep.ai.mit.edu:/pub/gnu/textutils* + uudecode/uuencode: prep.ai.mit.edu:/pub/gnu/sharutils* + bdflush/update: ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/v1.1/bdflush* + + + +PARTIAL HISTORY OF UTIL-LINUX: + +bsd: + Nothing in this directory gets installed, but some BSD programs need + this support: + err.c: 8.1 (Berkeley) 6/4/93 + err.h: 8.1 (Berkeley) 6/2/93 + getopt.c: 4.13 (Berkeley) 2/23/91 + pathnames.h: 5.3 (Berkeley) 5/9/89 with extensive modifications for + Linux + +disk-utils: + cfdisk: 0.8 BETA (>2GB) from Kevin E. Martin (martin@cs.unc.edu) with + modifications for disks > 2GB. + ftp.cs.unc.edu:/pub/users/martin/linux/cfdisk-0.8.tar.gz + fdformat: Werner Almesberger (almesber@nessie.cs.id.ethz.ch), with + modifications by Marcel Mol (marcel@dutecad.et.tudelft.nl)). + Later, updated with a September 1992 version by Werner. + fdisk: A. V. Le Blanc (LeBlanc@mcc.ac.uk) fdisk 1.5 release, with + patched from Kevin Martin for DOS and OS/2 compatibility (1.5a); + Rik Faith (1.5b, 2.0). + fsck.minix, mkfs.minix: Linus Torvalds, with modifications by: Rik + Faith (faith@cs.unc.edu), Scott Heavner + (sdh@po.cwru.edu), Dr. Wettstein + (greg%wind.uucp@plains.nodak.edu), Daniel + Quinlan (quinlan@yggdrasil.com). + mkfs: David Engel (david@ods.com) and Fred N. van Kempen + (waltje@uWalt.NL.Mugnet.ORG) + Version 1.9 from Ron Sommeling (sommel@sci.kun.nl) + mkswap: Linus Torvalds, with modifications by Mike Jagdis + (jaggy@purplet.demon.co.uk. ) + Version for Alpha from + cage.cs.arizona.edu:/pub/davidm/linux/mkswap-axp-950503.tar.gz + setfdprm: Werner Almesberger (almesber@nessie.cs.id.ethz.ch) + Note that more floppy utilities are available from: + ftp.imag.fr:pub/Linux/ZLIBC/fdutils/fdutils-4.1.src.tar.gz + sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.1.src.tar.gz + tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.1.src.tar.gz + llseek.c: from Remy Card's e2fsprogs-0.5b.tar.gz (21Mar95 version) from: + sunsite.unc.edu:/pub/Linux/system/Filesystems/ext2 + +games: + banner: (8.3 (Berkeley) 4/2/94) + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + +login-utils: + agetty: W. Z. Venema, ported by Peter Orbaek . + ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz + chfn: Salvatore Valente + chsh: Salvatore Valente + last: 5.11 w/year (Berkeley) 6/29/88; Port by Michael Haardt with + changes by Peter Orbaek. + ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz + login: 5.40 (Berkeley) 5/9/89; with ports by Michael Glad and Peter Orbaek + ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz + mesg: 8.2 (Berkeley) 1/21/94 + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + newgrp: Michael Haardt, with modifications by Peter Orbaek. + ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz + passwd: Peter Orbaek, with yp modifications by Alvaro Martinez + Echevarria (alvaro@enano.etsit.upm.es) + ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz + shutdown: Peter Orbaek, with new modifications by Stephen Tweedie, Rik + Faith, and Dave (gentzel@nova.enet.dec.com). + ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz + simpleinit: Peter Orbaek + ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz + vipw: 5.16 (Berkeley) 3/3/91, with modifications by Mike Grupenhoff + + wall: 8.2 (Berkeley) 11/16/93 (With changes so that damaging escape + sequences cannot be sent.) + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + + +misc-utils: + cal: 8.4 (Berkeley) 4/2/94, with modifications by Rik Faith and + Hein@student.tu-clausthal.de (Jochen Hein). + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + chkdupexe: Version 1.2 from "Nicolai Langfeldt" + clear: Rik Faith + ddate: Druel the Chaotic aka Jeremy Johnson aka mpython@gnu.ai.mit.edu, + with modifications by Lee Harvey Oswald Smith, K.S.C. and + substantial updates from Rev. Bro. Lee H:. O:. Smith, KYTP + domainname: Peter Orbaek + ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz + dsplit: David Arnstein (arnstein@netcom.com) + gatekeeper.dec.com:/pub/usenet/comp.sources.misc/volume40/dsplit + getopt (getoptprog): jhunix.hcf.jhu.edu: + /pub/public_domain_software/NetBSD/usr/src/usr.bin/getopt + replaced by getopt-1.0.3.tar.gz from Frodo Looijaard, + found at http://huizen.dds.nl/~frodol + hostid: Mitch DSouza (m.dsouza@mrc-apu.cam.ac.uk) + ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz + hostname/dnsdomainname: Peter Tobias + This version (1.6) should also be available soon in: + nic.funet.fi:/pub/OS/Linux/PEOPLE/Linus/net-source/base/NetKit-A* + kill: BSD version, modified by Salvatore Valente + logger: 8.1 (Berkeley) 6/6/93, with modifications by Rik Faith + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + look.c: 8.1 (Berkeley) 6/14/93, with modifications by Rik Faith + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + mcookie: Rik Faith (faith@cs.unc.edu) + md5sum: Branki Lankester and Colin Plumb. The MD5 message-digest + algorithm is in the Public Domain. This implementation + calculates message-digest information only, and can NOT be used + for encryption. Therefore it is exportable from the USA. + Original sources in the MIT version of PGP 2.6.2. + namei: Roger S. Southwick, with modifications by Steve Tell. + reset: Rik Faith + script: 5.13 (Berkeley) 3/5/91, with modifications by Rick Sladkey + (jrs@world.std.com), Harald Koenig + (koenig@nova.tat.physik.uni-tuebingen.de). + setterm: Gordon Irlam (gordoni@cs.ua.oz.au), with modifications by + Peter MacDonald, Mika Liljeberg (liljeber@cs.Helsinki.FI), + John Walder (j-walder@uiuc.edu) [for dosemu]. + tsort: 5.3 (Berkeley) 6/1/90 + wuarchive.wustl.edu:/mirrors/4.3-reno + whereis: 5.5 (Berkeley) 4/18/91 + wuarchive.wustl.edu:/mirrors/4.3-reno + write: 8.1 (Berkeley) 6/6/93, with modifications by Mike Grupenhoff + (kashmir@umiacs.umd.edu). With changes so that damaging escape + sequences cannot be sent. + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + + +mount: + mount, umount, swapon + + Rick Sladkey put together the mount-0.99.6.tar.Z package, and Stephen + Tweedie provided updates. The utilities were originally from that + package (all appear to be by Doug Quale (quale@saavik.cs.wisc.edu), + with modifications by H. J. Lu (hlu@eecs.wsu.edu) on 11/25/92; Rick + Sladkey (jrs@world.std.com) in January 1993; and Stephen Tweedie + on 8 October 1993. 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. Mike Grupenhoff + added a probe of the superblock for the type + before /proc/filesystems is checked. Andries.Brouwer@cwi.nl fixed up + error reporting. + + Updated with patches from Andries.Brouwer@cwi.nl and Dan Quinlan + (quinlan@yggdrasil.com). And more patches from Andries and others. + +historic/selection: The complete selection-1.5 package, by Andrew Haylett + , 17th June 1993, is included in the historic tree. + 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. + +sys-utils: + arch: Rik Faith + chroot: Rick Sladkey + clock: Originally from the timesrc-1.2.tar.Z package, Charles Hedrick, + hedrick@cs.rutgers.edu (V1.0); Rob Hooft, hooft@chem.ruu.nl + (V1.1); Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de) + (V1.2). With additional changes: Hamish Coleman + (hamish@zot.apana.org.au) (V1.2a); Alan Modra + (alan@spri.levels.unisa.edu.au (V1.3, V1.4). + ctrlaltdel: Peter Orbaek + ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz + cytune: Nick Simicish (njs@scifi.emi.net) and Rik Faith (faith@cs.unc.edu) + dmesg: Theodore Ts'o (tytso@athena.mit.edu); Rick Sladkey + (jrs@world.std.com) + ipcrm: From the ipcdelta.tar.z distribution by krishna + balasub@cis.ohio-state.edu on 3/15/93. ipc.info and ipc.texi + are also from that distribution. + ipcs: Also from the ipcdelta.tar.z distribution by krishna + balasub@cis.ohio-state.edu, with patches from Mike Jagdis + (jaggy@purplet.demon.co.uk) + kbdrate: Rik Faith (faith@cs.unc.edu), with patches from + Andries.Brouwer@cwi.nl and John Bowman + (bowman@hagar.ph.utexas.edu) + ksymoops: 1.7 from Greg McGary + rdev: almesber@nessie.cs.id.ethz.ch (Werner Almesberger), with + modifications from Peter MacDonald, Stephen Tweedie + (sct@dcs.ed.ac.uk), and Dave (gentzel@nova.enet.dec.com) + readprofile: Alessandro Rubini from readprofile-2.0.tar.gz + renice: 8.1 (Berkeley) 6/9/93 + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + setserial: 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. + setsid: Rick Sladkey + sln: Mike Parker and David MacKenzie (from Linux's libc) + sync: Nick Holloway, with thanks to James Bonfield + tunelp: Michael K. Johnson (johnsonm@nigel.vnet.net) + + +syslogd: + 5.45 (Berkeley) 3/2/91 + + 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). + +text-utils: + col: 5.3 (Berkeley) 2/2/91; with patches from Andries.Brouwer@cwi.nl + and Carl Christofferson (cchris@connected.com) + wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} + colcrt: 8.1 (Berkeley) 6/6/93 (Bill Joy) + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + colrm: 5.4 (Berkeley) 6/1/90 (Jeff Schriebman) + column: 8.3 (Berkeley) 4/2/94 + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + hexdump: 5.5 (Berkeley) 6/1/90 + wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} + more: 5.19 (Berkeley) 6/29/88 (Eric Shienbrood, Geoff Peck, John Foderaro) + rev: 5.2 (Berkeley) 3/21/92; with modifications by Charles Hannum + (mycroft@gnu.ai.mit.edu), Brian Koehmstedt (bpk@gnu.ai.mit.edu), + bjdouma@xs4all.nl + wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} + strings: 5.10 (Berkeley) 5/23/91; with patches from Vitor Duarte + + wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} + ul: 8.1 (Berkeley) 6/6/93 + ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin + diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..c6a463e88 --- /dev/null +++ b/INSTALL @@ -0,0 +1,57 @@ + +WARNING: THE PROGRAMS IN THIS SUITE DO *NOT* SUPPORT SHADOW PASSWORD FILES! + UNLESS YOU USE PAM. + +WARNING: THIS COLLECTION CONFLICTS WITH SYSTEM V INITTAB. + UNLESS YOU CONFIGURE IT NOT TO. + +WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! + +WARNING: DO *NOT* INSTALL WITHOUT THINKING. + +WARNING: The simpleinit and some other programs in this package are + *NOT* System V compliant. These utilities are meant to be + used by people who build their own systems. If you are not + a wizard, do *NOT* blindly install these utilities: they could + prevent you from logging into your system. Have a boot floppy + ready, especially if you don't know what you are doing. 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.9.tar.gz somewhere +3) cd util-linux-2.9 +4) Edit MCONFIG +5) make +6) make install +7) If you want to use simpleinit and agetty, then make softlinks from + /sbin/init to simpleinit and from /sbin/getty to agetty, but make sure + that your /etc/inittab is set up right (this is *NOT* the System V + compatible init!), or you will be hosed. If you are using the SysV + init and/or some other getty, they you can keep using those. + + +If you have compilation problems: + +- with -lcrypt: you forgot to edit MCONFIG and write HAVE_LIBCRYPT=no. +- in cfdisk or setterm: you forgot to edit MCONFIG and write HAVE_NCURSES=no + (or you forgot to write CURSESFLAGS=-I/usr/include/ncurses -DNCH=0)? +- in fdisksunlabel.c: change #if 1 into #if 0 if there is no . +- in mount/nfsmount.c: change #if 1 into #if 0 if there is no inet_aton(). +- in sys-utils/ipcs.c: change #if 0 into #if 1 if is needed. +- in sys-utils/cytune.c: change #if 0 into #if 1 if is needed. + +elsewhere: tell util-linux@math.uio.no about it. + + +If you have runtime problems: + +- with non-ASCII characters: perhaps you forgot to set LC_CTYPE or LC_ALL? + (For example, in Norway one can say LC_ALL=no_NO; export LC_ALL and + then various utilities will treat Scandinavian non-ASCII letters as + letters.) + +otherwise: tell util-linux@math.uio.no about it. + diff --git a/LSM b/LSM index 0906306c0..41edbbf37 100644 --- a/LSM +++ b/LSM @@ -1,22 +1,23 @@ Begin3 Title: util-linux: Miscellaneous utilities for Linux -Version: 2.8 +Version: 2.9g Description: agetty arch cal cfdisk chfn chkdupexe chsh clear hwclock col colcrt colrm column ctrlaltdel - cytune ddate dmesg dsplit fastboot fasthalt fdformat + cytune ddate dmesg fastboot fasthalt fdformat 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 setfdprm setsid setterm sfdisk shutdown simpleinit sln - strings swapdev swapoff swapon tsort tunelp ul umount + swapdev swapoff swapon tsort tunelp ul umount vidmode vipw wall whereis write Keywords: essential utilities Author: several -Maintained-by: Nicolai Langfeldt and others -Primary-site: ftp.math.uio.no /pub/linux - ~567k util-linux-2.8.tar.gz +Maintained-by: Andries Brouwer and others +Primary-site: ftp.win.tue.nl /pub/linux/util +Alternate-site: ftp.math.uio.no /pub/linux + ~567k util-linux-2.9g.tar.gz Alternate-site: sunsite.uio.no /pub/unix/linux/packages/util-linux Alternate-site: sunsite.unc.edu /pub/Linux/system/misc Alternate-site: tsx-11.mit.edu /pub/linux/packages/utils diff --git a/MAINTAINERS b/MAINTAINERS index 623bd5204..623b77883 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,19 +1,6 @@ -util-linux is maintained by a group of people, all reachable at -util-linux@math.uio.no. +util-linux is maintained by a group of people +(Rik, Andries, Peter, Michael, Erik, Nicolai), +all reachable at util-linux@math.uio.no. -Some have specific interests, others just do everything else. - -This is a partial list of interests: - -Rik: Founding father -Andries: *fdisk, mount, ... -Peter: login, passwd, simpleinit, agetty, last, newgrp, shutdown, - domainname, ctrlaltdel -Michael: Spirit of advice -Erik: General hackery -Nicolai: mail-queue processor (batch oriented) - -Bryan: hwclock master, he's not on the list but the mail queue - processor forwards mail to him. - -Unassigned programs (defaulting to Nicolai): chfn, chsh, write, wall, ... +Bryan, the hwclock master, is not on the list +but the mail queue processor forwards mail to him. diff --git a/MCONFIG b/MCONFIG index 2823988ef..147fc1ae2 100644 --- a/MCONFIG +++ b/MCONFIG @@ -1,32 +1,32 @@ # MCONFIG -- Configuration stuff for util-linux # 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) +# For a user-mode install, make (at least) three changes: +# - remove the `-o root' part in INSTALLSUID +# - set USE_TTY_GROUP=no +# - define DESTDIR + # 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 # installed as it is not PAM aware. HAVE_PAM=no -#HAVE_PAM=yes # If HAVE_SHADOW is set to "yes", then login, chfn, chsh, newgrp, passwd, # and vipw will not be built or installed from the login-utils # subdirectory. -HAVE_SHADOW=no -#HAVE_SHADOW=yes +HAVE_SHADOW=yes # If HAVE_PASSWD is set to "yes", then passwd will not be built or # installed from the login-utils subdirectory (but login, chfn, chsh, # newgrp, and vipw *will* be installed). HAVE_PASSWD=no -#HAVE_PASSWD=yes # If you use chfn and chsh from this package, REQUIRE_PASSWORD will require # non-root users to enter the account password before updating /etc/passwd. @@ -44,21 +44,18 @@ ONLY_LISTED_SHELLS=yes # be built or installed from the login-utils subdirectory. (The shutdown # and halt that come with the SysVinit package should be used with the init # found in that package.) -#HAVE_SYSVINIT=no HAVE_SYSVINIT=yes # If HAVE_SYSVINIT_UTILS is set to "yes", then last, mesg, and wall will # not be built or installed from the login-utils subdirectory. (The # shutdown and init from the SysVinit package do not depend on the last, # mesg, and wall from that package.) -#HAVE_SYSVINIT_UTILS=no HAVE_SYSVINIT_UTILS=yes # If HAVE_GETTY is set to "yes", then agetty will not be built or # installed from the login-utils subdirectory. Note that agetty can # co-exist with other gettys, so this option should never be used. HAVE_GETTY=no -#HAVE_GETTY=yes # If USE_TTY_GROUP is set to "yes", then wall and write will be installed # setgid to the "tty" group, and mesg will only set the group write bit. @@ -67,24 +64,18 @@ HAVE_GETTY=no # xterm will do it correctly if X is compiled with USE_TTY_GROUP set # properly.] USE_TTY_GROUP=yes -#USE_TTY_GROUP=no -# If HAVE_STRINGS is set to "yes", then strings won't be installed. This -# is the quick fix until the strings in GNU binutils is in wide use and has -# internationalization support. -#HAVE_STRINGS=no -HAVE_STRINGS=yes +# If HAVE_OPENPTY is set to "yes", then script will use the Unix98 ptys +HAVE_OPENPTY=no # If HAVE_RESET is set to "yes", then reset won't be installed. The version # of reset that comes with the ncurses package is less aggressive. -#HAVE_RESET=no HAVE_RESET=yes -# If HAVE_MOUNT is set to "yes", then 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 -# HAVE_MOUNT=yes +# If HAVE_SLN is set to "yes", then sln won't be installed +# (but the man page sln.8 will be installed anyway). +# sln also comes with libc and glibc. +HAVE_SLN=no CC= gcc @@ -99,11 +90,15 @@ else endif endif -BSD= ../bsd +ERR_O=$(LIB)/err.o + +LIB=../lib LDFLAGS = -s WARNFLAGS = -Wall -CFLAGS = $(OPT) -I. -I$(BSD) $(WARNFLAGS) $(CURSESFLAGS) $(SLANGFLAGS) \ + +CFLAGS = $(OPT) -I. -I$(LIB) $(WARNFLAGS) \ + $(CURSESFLAGS) $(SLANGFLAGS) \ $(EXTRACFLAGS) \ -DSBINDIR=\"$(SBINDIR)\" \ -DUSRSBINDIR=\"$(USRSBINDIR)\" \ @@ -123,7 +118,7 @@ HAVE_NCURSES=yes # No such subdirectory - is the ncurses one. # CURSESFLAGS=-DNCH=0 # Pick your choice. -CURSESFLAGS=-DNCH=0 +CURSESFLAGS=-I/usr/include/ncurses -DNCH=0 LIBCURSES=-lncurses # Set HAVE_SLANG to yes if you have slang (and prefer to use that for cfdisk) @@ -147,11 +142,11 @@ BINDIR= $(DESTDIR)/bin VARPATH= $(DESTDIR)/var LOGDIR= $(DESTDIR)/var/log MANDIR= $(DESTDIR)/usr/man -MAN1DIR= $(DESTDIR)/usr/man/man1 -MAN3DIR= $(DESTDIR)/usr/man/man3 -MAN5DIR= $(DESTDIR)/usr/man/man5 -MAN6DIR= $(DESTDIR)/usr/man/man6 -MAN8DIR= $(DESTDIR)/usr/man/man8 +MAN1DIR= $(MANDIR)/man1 +MAN3DIR= $(MANDIR)/man3 +MAN5DIR= $(MANDIR)/man5 +MAN6DIR= $(MANDIR)/man6 +MAN8DIR= $(MANDIR)/man8 INFODIR= $(DESTDIR)/usr/info # Directory for shutdown, halt, reboot, etc. @@ -169,7 +164,7 @@ BINMODE= 755 MANMODE= 644 DATMODE= 644 INFOMODE= 644 -SUIDMODE= 4711 +SUIDMODE= 4755 CHMOD= chmod INSTALL= install diff --git a/Makefile b/Makefile index 5bbbdc25c..92c9cae58 100644 --- a/Makefile +++ b/Makefile @@ -5,21 +5,18 @@ # May be distributed under the terms of the GNU GPL. # -VERSION=2.8 +VERSION=2.9 include ./MCONFIG -ifeq "$(HAVE_MOUNT)" "no" - MOUNTDIR=mount -endif - -SUBDIRS= bsd \ - getopt \ +SUBDIRS=lib \ + getopt-1.0.3a \ disk-utils \ games \ login-utils \ misc-utils \ - $(MOUNTDIR) \ + mount \ + fdisk \ sys-utils \ text-utils diff --git a/README b/README deleted file mode 100644 index cf30bf0ae..000000000 --- a/README +++ /dev/null @@ -1,503 +0,0 @@ -util-linux 2.8: - -WARNING: THE PROGRAMS IN THIS SUITE DO *NOT* SUPPORT SHADOW PASSWORD FILES! - UNLESS YOU USE PAM. - -WARNING: THIS COLLECTION CONFLICTS WITH SYSTEM V INITTAB. - UNLESS YOU CONFIGURE IT NOT TO. - -WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! - -WARNING: DO *NOT* INSTALL WITHOUT THINKING. - -WARNING: The simpleinit and some other programs in this package are - *NOT* System V compliant. These utilities are meant to be - used by people who build their own systems. If you are not - a wizard, do *NOT* blindly install these utilities: they could - prevent you from logging into your system. Have a boot floppy - ready, especially if you don't know what you are doing. 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.8.tar.gz in /usr/src -3) cd util-linux-2.8 -4) Edit MCONFIG -5) make -6) make install -7) If you want to use simpleinit and agetty, then make softlinks from - /sbin/init to simpleinit and from /sbin/getty to agetty, but make sure - that your /etc/inittab is set up right (this is *NOT* the System V - compatible init!), or you will be hosed. If you are using the SysV - init and/or some other getty, they you can keep using those. - -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 - converted to use terminfo (instead of termcap). - -2) Removed progams: - - clock: Dropped entierly. Use hwclock (included). - - sync: is in gnu fileutils. - - setserial: Is being maintained by Ted Ts'o, he recommends - setserial-2.12 (2.13 is bad luck) - - clear: Included in ncurses - - hostname, domainname, dnsdomainname: It's in net-utils. - -3) Bugfixes, additions: - - cfdisk: A much improved version. All known bugs have been fixed. - - sfdisk: A command line fdisk type utility, formerly called fdisk-3.04. - - SECURITY: All known holes in login, chfn, chsh and others have been - plugged. UPGRADE NOW if you haven't already fixed them yourself. - - Should work with libc 4, 5 and 6 (gnulibc), on m68k, intel, alpha - and sparc. - -4) Problems: - - The rpcgen that comes in NetKit-B-0.09 is broken. At least as - packaged with RedHat 4.2 (NetKit-B-0.09-6). There are several - ways to deal with this: - - Don't run rpcgen, the needed pre-generated sources are included - (nfsmount_xdr.c). You must hack mount/Makefile to do this. - - Edit the source emited by rpcgen so it can compile. This is very - simple if you know C. - - Disable the NFS parts of mount. You have to edit mount/Makefile - to do this. - - Use some other rpcgen - -util-linux 2.6.1 - -This release was never made public - -See notes for 2.6 for installation instructions. - -This is a incremental release containing some fixes. A new release -will be made later fixing the outstanding bugs. -- Things compiles and works better with recent releases of kernel, - ncurses, and so forth: fdisk, more -- Some fixes to make things compile out of the box on alphas. -- There has been reported a problem with login and /etc/usertty. It - should be fixed. If you still have problems get a recent MAKEDEV and - use it to make new tty devices. They were renumbered sometime during - the 1.3 phase of the kernel. -- ipcs now displays the key of the structures. -- A (harmless?) overflow bug was fixed in login. - -Outstanding bugs: -- login/getty has a denial of service problem. -- Several places needs a bit more polish. -- There are a _lot_ of nonfatal warnings when compiling mount. This will - not necesarily be fixed. - - -util-linux 2.6 - -HIGHLIGHTS for version 2.6: - -0) The first release with me at the helm. PLEASE SEND PATCHES AND - UPDATES TO: util-linux@math.uio.no. - -1) Removed programs: - - md5sum: available in GNU textutils. - - syslogd: Sysklogd is now prefered. It is available at - tsx-11.mit.edu:/pub/sources/sbin - sunsite.unc.edu:/pub/Linux/system/Daemons - -2) Bugfixes, additions: - - SECURITY: All known holes in mount have been fixed. UPGRADE NOW - if you haven't already! - - Portability enhancments to the minix filesystem utils (m68k and - Arm patches). - - passwd/chsh/chfn will not mess up the passwd file on a NIS machine - - others too numerous to enumerate. - -3) New programs: - - vigr (it's like vipw) - - Introducing hwclock. A complete rewrite of the latest available - clock source. It supports intel/CMOS, /dev/rtc and linux/m68k - system clock interfaces. Clock supports the same things but is now - obsolete and will not be present in the next release. Start using - hwclock now. Please. - - -util-linux 2.5 - -HIGHLIGHTS for version 2.5: -0) Nicolai Langfeldt is taking over maintenance of util-linux, with the - help of a few others (Michael K. Johnson, Andries Brouwer, and Rik - Faith). - - PLEASE SEND PATCHES AND UPDATES TO: util-linux@math.uio.no - -1) The following packages have been removed. Please use the up-to-date, - canonical versions of these packages from the listed places: - - timezone support (/usr/lib/zoneinfo, libz.a, zic, zdump): - elsie.nci.nih.gov:/pub/tzcode95d.tar.gz - elsie.nci.nih.gov:/pub/tzdata95h.tar.gz - MAKEDEV-C: - sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-C-1.5.tar.gz - MAKEDEV: - sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-2.2.tar.gz - md5sum: - prep.ai.mit.edu:/pub/gnu/textutils-1.3.tar.gz - [The GNU version is now compatible with the Plumb/Lankester - version.] - ksymoops: - Now bundled with the kernel in linux/scripts. - -2) update_state has been removed -3) fdisk now supports NetBSD disklabels courtesy of Bernhard Fastenrath - (and > 8GB disks, courtesy of - Andries Brouwer) -4) mount improved -- many patches from Andries Brouwer for greatly improved - error reporting -5) ddate, chkdupexe, and other programs have been improved and bug fixed -6) util-linux is now a source-only distribution -7) mcookie generates better random numbers and will use /dev/random or - /dev/audio if available -8) chfn, chsh, passwd, and vipw have been updated with security patches - from Zefram . Now, they all use the same - locking, and several security holes have been patched. Further, chsh - and chfn can be configured at compile time to require a password before - updates and chsh can be configured to only use shells from /etc/shells. - - -HIGHLIGHTS for version 2.4 (2.3 was never released): -0) Michael K. Johnson is the interim maintainer - while Rik Faith is working on PhD work. -1) login now makes the login tty mode 600 and places it in group "tty" -2) wall, and write will not write dangerous escape sequences -3) wall and write can be run setgid "tty". If util-linux is compiled for - this option, "mesg y" will only set group write instead of group/other - write. -4) fdisk and cfdisk have been patched with the latest llseek.c. Although I - had a lot of bug reports about fdisk from util-linux-2.2, I was unable - to reproduce any of the problems. Some of the problems appeared to be - releated to a failure to reboot the machine after changing the partition - table, and some may have been due to a specific kernel revision problem. - However, this doesn't seem to account for all of the bug reports -- if - this version gives you problem, please send as complete a bug report as - possible. -5) chkdupexe from Nicolai Langfeldt (janl@ifi.uio.no) -6) ctrlaltdel now installs into /sbin instead of /usr/sbin -7) mkfs replacement from Ron Sommeling (sommel@sci.kun.nl) -8) lpcntl removed. Use tunelp instead. -9) ksymoops from Greg McGary -10) mkfs.minix now clears the first 512 bytes of the file system so that - Minix disks won't be confused with MSDOS disks (Daniel Quinlan - (quinlan@yggdrasil.com)) -11) mkswap should now work on an Alpha running Linux -12) frag removed. See - sunsite.unc.edu:/pub/Linux/system/Filesystems/defrag-0.6.tar.gz for the - latest version. -13) mount patches from Andries.Brouwer@cwi.nl and Dan Quinlan - (quinlan@yggdrasil.com). -14) MAKEDEV and MAKEDEV-C updated to the latest versions. -15) Paths updated for FSSTND 1.2. This means that you may need to make - some links. The links you need to make we system dependent. The - ultimate goal is to rename /var/adm to /var/log and have a symbolic - link from /var/adm to /var/log during the transition period. If you - are running an ELF system, you probably won't have to do anything. The - bottom line is that the following files must exist or be pointers to - the old version (used internally by the a.out libraries): - - New Old - - /var/log/wtmp /var/adm/wtmp - /var/log/lastlog /var/adm/lastlog - /var/run/utmp /var/adm/utmp - -HIGHLIGHTS for version 2.2: -1) This is primarily a quick bug-fix release for version 2.1 -2) mkfs wrapper added back in, since e2fsprogs only supplies an fsck wrapper -3) selection removed, since someone appears to be maintaining it now. See - sunsite.unc.edu:/pub/linux/kernel/patches/console for recent sources. - For the time being, I'm keeping a copy in the historic subdirectory of - util-linux. A "make install" should work find from within that - directory. -4) Note that other floppy utilities are available from: - ftp.imag.fr:pub/Linux/ZLIBC/fdutils/fdutils-4.1.src.tar.gz - sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.1.src.tar.gz - tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.1.src.tar.gz - - -HIGHLIGHTS for version 2.1: - -1) Directory structure rearrange, with configuration support for those who - use shadow passwords and System V init (no support is provided for these - things, but your utilities won't get overwritten if you do a "make - install" after you properly edit MCONFIG). -2) fdisk and cfdisk should work as expected with 2GB+ disk drives -3) As usual, lots of stuff was updated and added, including mount, vipw, - readprofile -4) Some stuff was also deleted, and can now be found elsewhere: - fsck wrapper: tsx-11.mit.edu:/pub/linux/ALPHA/ext2fs/e2fsprogs* - pwd, su: prep.ai.mit.edu:/pub/gnu/sh-utils* - ed: prep.ai.mit.edu:/pub/gnu/ed* - od: prep.ai.mit.edu:/pub/gnu/textutils* - uudecode/uuencode: prep.ai.mit.edu:/pub/gnu/sharutils* - bdflush/update: ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/v1.1/bdflush* - - - -PARTIAL HISTORY OF UTIL-LINUX: - -bsd: - Nothing in this directory gets installed, but some BSD programs need - this support: - err.c: 8.1 (Berkeley) 6/4/93 - err.h: 8.1 (Berkeley) 6/2/93 - getopt.c: 4.13 (Berkeley) 2/23/91 - pathnames.h: 5.3 (Berkeley) 5/9/89 with extensive modifications for - Linux - -disk-utils: - cfdisk: 0.8 BETA (>2GB) from Kevin E. Martin (martin@cs.unc.edu) with - modifications for disks > 2GB. - ftp.cs.unc.edu:/pub/users/martin/linux/cfdisk-0.8.tar.gz - fdformat: Werner Almesberger (almesber@nessie.cs.id.ethz.ch), with - modifications by Marcel Mol (marcel@dutecad.et.tudelft.nl)). - Later, updated with a September 1992 version by Werner. - fdisk: A. V. Le Blanc (LeBlanc@mcc.ac.uk) fdisk 1.5 release, with - patched from Kevin Martin for DOS and OS/2 compatibility (1.5a); - Rik Faith (1.5b, 2.0). - fsck.minix, mkfs.minix: Linus Torvalds, with modifications by: Rik - Faith (faith@cs.unc.edu), Scott Heavner - (sdh@po.cwru.edu), Dr. Wettstein - (greg%wind.uucp@plains.nodak.edu), Daniel - Quinlan (quinlan@yggdrasil.com). - mkfs: David Engel (david@ods.com) and Fred N. van Kempen - (waltje@uWalt.NL.Mugnet.ORG) - Version 1.9 from Ron Sommeling (sommel@sci.kun.nl) - mkswap: Linus Torvalds, with modifications by Mike Jagdis - (jaggy@purplet.demon.co.uk. ) - Version for Alpha from - cage.cs.arizona.edu:/pub/davidm/linux/mkswap-axp-950503.tar.gz - setfdprm: Werner Almesberger (almesber@nessie.cs.id.ethz.ch) - Note that more floppy utilities are available from: - ftp.imag.fr:pub/Linux/ZLIBC/fdutils/fdutils-4.1.src.tar.gz - sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.1.src.tar.gz - tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.1.src.tar.gz - llseek.c: from Remy Card's e2fsprogs-0.5b.tar.gz (21Mar95 version) from: - sunsite.unc.edu:/pub/Linux/system/Filesystems/ext2 - -games: - banner: (8.3 (Berkeley) 4/2/94) - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - -login-utils: - agetty: W. Z. Venema, ported by Peter Orbaek . - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz - chfn: Salvatore Valente - chsh: Salvatore Valente - last: 5.11 w/year (Berkeley) 6/29/88; Port by Michael Haardt with - changes by Peter Orbaek. - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz - login: 5.40 (Berkeley) 5/9/89; with ports by Michael Glad and Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz - mesg: 8.2 (Berkeley) 1/21/94 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - newgrp: Michael Haardt, with modifications by Peter Orbaek. - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz - passwd: Peter Orbaek, with yp modifications by Alvaro Martinez - Echevarria (alvaro@enano.etsit.upm.es) - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz - shutdown: Peter Orbaek, with new modifications by Stephen Tweedie, Rik - Faith, and Dave (gentzel@nova.enet.dec.com). - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz - simpleinit: Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz - vipw: 5.16 (Berkeley) 3/3/91, with modifications by Mike Grupenhoff - - wall: 8.2 (Berkeley) 11/16/93 (With changes so that damaging escape - sequences cannot be sent. - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - - -misc-utils: - cal: 8.4 (Berkeley) 4/2/94, with modifications by Rik Faith and - Hein@student.tu-clausthal.de (Jochen Hein). - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - chkdupexe: Version 1.2 from "Nicolai Langfeldt" - clear: Rik Faith - ddate: Druel the Chaotic aka Jeremy Johnson aka mpython@gnu.ai.mit.edu, - with modifications by Lee Harvey Oswald Smith, K.S.C. and - substantial updates from Rev. Bro. Lee H:. O:. Smith, KYTP - domainname: Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz - dsplit: David Arnstein (arnstein@netcom.com) - gatekeeper.dec.com:/pub/usenet/comp.sources.misc/volume40/dsplit - getopt (getoptprog): jhunix.hcf.jhu.edu: - /pub/public_domain_software/NetBSD/usr/src/usr.bin/getopt - hostid: Mitch DSouza (m.dsouza@mrc-apu.cam.ac.uk) - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.37.tar.gz - hostname/dnsdomainname: Peter Tobias - This version (1.6) should also be available soon in: - nic.funet.fi:/pub/OS/Linux/PEOPLE/Linus/net-source/base/NetKit-A* - kill: BSD version, modified by Salvatore Valente - logger: 8.1 (Berkeley) 6/6/93, with modifications by Rik Faith - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - look.c: 8.1 (Berkeley) 6/14/93, with modifications by Rik Faith - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - mcookie: Rik Faith (faith@cs.unc.edu) - md5sum: Branki Lankester and Colin Plumb. The MD5 message-digest - algorithm is in the Public Domain. This implementation - calculates message-digest information only, and can NOT be used - for encryption. Therefore it is exportable from the USA. - Original sources in the MIT version of PGP 2.6.2. - namei: Roger S. Southwick, with modifications by Steve Tell. - reset: Rik Faith - script: 5.13 (Berkeley) 3/5/91, with modifications by Rick Sladkey - (jrs@world.std.com), Harald Koenig - (koenig@nova.tat.physik.uni-tuebingen.de). - setterm: Gordon Irlam (gordoni@cs.ua.oz.au), with modifications by - Peter MacDonald, Mika Liljeberg (liljeber@cs.Helsinki.FI), - John Walder (j-walder@uiuc.edu) [for dosemu]. - tsort: 5.3 (Berkeley) 6/1/90 - wuarchive.wustl.edu:/mirrors/4.3-reno - whereis: 5.5 (Berkeley) 4/18/91 - wuarchive.wustl.edu:/mirrors/4.3-reno - write: 8.1 (Berkeley) 6/6/93, with modifications by Mike Grupenhoff - (kashmir@umiacs.umd.edu). With changes so that damaging escape - sequences cannot be sent. - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - - -mount: - mount, umount, swapon - - Rick Sladkey put together the mount-0.99.6.tar.Z package, and Stephen - Tweedie provided updates. The utilities were originally from that - package (all appear to be by Doug Quale (quale@saavik.cs.wisc.edu), - with modifications by H. J. Lu (hlu@eecs.wsu.edu) on 11/25/92; Rick - Sladkey (jrs@world.std.com) in January 1993; and Stephen Tweedie - on 8 October 1993. 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. Mike Grupenhoff - added a probe of the superblock for the type - before /proc/filesystems is checked. Andries.Brouwer@cwi.nl fixed up - error reporting. - - Updated with patches from Andries.Brouwer@cwi.nl and Dan Quinlan - (quinlan@yggdrasil.com). And more patches from Andries and others. - -historic/selection: The complete selection-1.5 package, by Andrew Haylett - , 17th June 1993, is included in the historic tree. - 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. - -sys-utils: - arch: Rik Faith - chroot: Rick Sladkey - clock: Originally from the timesrc-1.2.tar.Z package, Charles Hedrick, - hedrick@cs.rutgers.edu (V1.0); Rob Hooft, hooft@chem.ruu.nl - (V1.1); Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de) - (V1.2). With additional changes: Hamish Coleman - (hamish@zot.apana.org.au) (V1.2a); Alan Modra - (alan@spri.levels.unisa.edu.au (V1.3, V1.4). - ctrlaltdel: Peter Orbaek - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.16.tar.gz - cytune: Nick Simicish (njs@scifi.emi.net) and Rik Faith (faith@cs.unc.edu) - dmesg: Theodore Ts'o (tytso@athena.mit.edu); Rick Sladkey - (jrs@world.std.com) - ipcrm: From the ipcdelta.tar.z distribution by krishna - balasub@cis.ohio-state.edu on 3/15/93. ipc.info and ipc.texi - are also from that distribution. - ipcs: Also from the ipcdelta.tar.z distribution by krishna - balasub@cis.ohio-state.edu, with patches from Mike Jagdis - (jaggy@purplet.demon.co.uk) - kbdrate: Rik Faith (faith@cs.unc.edu), with patches from - Andries.Brouwer@cwi.nl and John Bowman - (bowman@hagar.ph.utexas.edu) - ksymoops: 1.7 from Greg McGary - rdev: almesber@nessie.cs.id.ethz.ch (Werner Almesberger), with - modifications from Peter MacDonald, Stephen Tweedie - (sct@dcs.ed.ac.uk), and Dave (gentzel@nova.enet.dec.com) - readprofile: Alessandro Rubini - renice: 8.1 (Berkeley) 6/9/93 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - setserial: 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. - setsid: Rick Sladkey - sln: Mike Parker and David MacKenzie (from Linux's libc) - sync: Nick Holloway, with thanks to James Bonfield - tunelp: Michael K. Johnson (johnsonm@nigel.vnet.net) - - -syslogd: - 5.45 (Berkeley) 3/2/91 - - 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). - -text-utils: - col: 5.3 (Berkeley) 2/2/91; with patches from Andries.Brouwer@cwi.nl - and Carl Christofferson (cchris@connected.com) - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - colcrt: 8.1 (Berkeley) 6/6/93 (Bill Joy) - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - colrm: 5.4 (Berkeley) 6/1/90 (Jeff Schriebman) - column: 8.3 (Berkeley) 4/2/94 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - hexdump: 5.5 (Berkeley) 6/1/90 - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - more: 5.19 (Berkeley) 6/29/88 (Eric Shienbrood, Geoff Peck, John Foderaro) - rev: 5.2 (Berkeley) 3/21/92; with modifications by Charles Hannum - (mycroft@gnu.ai.mit.edu), Brian Koehmstedt (bpk@gnu.ai.mit.edu), - bjdouma@xs4all.nl - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - strings: 5.10 (Berkeley) 5/23/91; with patches from Vitor Duarte - - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - ul: 8.1 (Berkeley) 6/6/93 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - diff --git a/attic/pidof.c b/attic/pidof.c new file mode 100644 index 000000000..74709c78d --- /dev/null +++ b/attic/pidof.c @@ -0,0 +1,95 @@ +/* pid -- display the process id of a running command + + Copyright (c) 1994 Salvatore Valente + Copyright (c) 1996 Bruno Haible + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +#include +#include +#include + +extern int* get_pids (char*, int); + +char version_string[] = "pid 1.0"; +char* program_name; + +int usage (int status) +{ + FILE* fp = (status == 0 ? stdout : stderr); + fprintf(fp, "Usage: %s command ...\n", program_name); + return status; +} + +static int compar_int (const void* i1, const void* i2) +{ + return *((int *)i1) - *((int *)i2); +} + +int main (int argc, char *argv[]) +{ + int i; + int *pids, *pids0; + int num_allpids = 0; + int *allpids = (int*)0; + int allpids_size = 0; + + program_name = argv[0]; + + /* Argument processing. */ + for (i = 1; i < argc; i++) { + char* arg = argv[i]; + if (!strcmp(arg, "--help")) + return usage(0); + else if (!strcmp(arg, "--version")) { + printf("%s\n", version_string); + return 0; + } + } + + /* Gather the pids. */ + for (i = 1; i < argc; i++) { + char* arg = argv[i]; + pids0 = pids = get_pids(arg, 1); + if (pids) { + while (*pids >= 0) { + int pid = *pids++; + if (num_allpids >= allpids_size) { + allpids_size = 2*allpids_size+1; + allpids = (int*) realloc(allpids, sizeof(int)*allpids_size); + if (!allpids) { + fprintf(stderr, "%s: out of memory\n", program_name); + exit(1); + } + } + allpids[num_allpids++] = pid; + } + free(pids0); + } + } + + /* Sort them. */ + if (num_allpids > 1) + qsort(allpids, num_allpids, sizeof(int), compar_int); + + /* Print them. */ + for (pids = allpids, i = num_allpids; i > 0; pids++, i--) + printf("%d\n", *pids); + + return 0; +} diff --git a/attic/strings.1 b/attic/strings.1 new file mode 100644 index 000000000..08dda5bfd --- /dev/null +++ b/attic/strings.1 @@ -0,0 +1,96 @@ +.\" Copyright (c) 1980, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)strings.1 6.11 (Berkeley) 5/9/91 +.\" +.Dd May 9, 1991 +.Dt STRINGS 1 +.Os BSD 3 +.Sh NAME +.Nm strings +.Nd find printable strings in a file +.Sh SYNOPSIS +.Nm strings +.Op Fl afo +.Op Fl n Ar number +.Op Ar file ... +.Sh DESCRIPTION +.Nm Strings +displays the sequences of printable characters in each of the specified +files, or in the standard input, by default. +By default, a sequence must be at least four characters in length +before being displayed. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +By default, +.Nm strings +only searches the text and data segments of object files. +The +.Fl a +option causes +.Nm strings +to search the entire object file. +.It Fl f +Each string is preceded by the name of the file +in which it was found. +.It Fl n +Specifies the minimum number of characters in a sequence to be +.Ar number , +instead of four. +.It Fl o +Each string is preceded by its decimal offset in the +file. +.El +.Pp +.Nm Strings +is useful for identifying random binaries, among other things. +.Sh SEE ALSO +.Xr hexdump 1 +.Sh BUGS +The algorithm for identifying strings is extremely primitive. +In particular, machine code instructions on certain architectures +can resemble sequences of ASCII bytes, which +will fool the algorithm. +.Sh COMPATIBILITY +Historic implementations of +.Nm +only search the initialized data portion of the object file. +This was reasonable as strings were normally stored there. +Given new compiler technology which installs strings in the +text portion of the object file, the default behavior was +changed. +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/attic/strings.c b/attic/strings.c new file mode 100644 index 000000000..6c201a744 --- /dev/null +++ b/attic/strings.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1980, 1987 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Wed Jun 22 22:22:37 1994, faith@cs.unc.edu: + * Added internationalization patches from Vitor Duarte + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEF_LEN 4 /* default minimum string length */ +#if 0 +#define ISSTR(ch) (isascii(ch) && (isprint(ch) || ch == '\t')) +#else +#define ISSTR(ch) (isprint(ch) || ch == '\t') +#endif + +typedef struct exec EXEC; /* struct exec cast */ + +static long foff; /* offset in the file */ +static int hcnt, /* head count */ + head_len, /* length of header */ + read_len; /* length to read */ +static u_char hbfr[sizeof(EXEC)]; /* buffer for struct exec */ + +static void usage(); + +main(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind; + register int ch, cnt; + register u_char *C; + EXEC *head; + int exitcode, minlen; + short asdata, oflg, fflg; + u_char *bfr; + char *file, *p; + + setlocale(LC_CTYPE, ""); + + + /* + * for backward compatibility, allow '-' to specify 'a' flag; no + * longer documented in the man page or usage string. + */ + asdata = exitcode = fflg = oflg = 0; + minlen = -1; + while ((ch = getopt(argc, argv, "-0123456789an:of")) != EOF) + switch((char)ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + /* + * kludge: strings was originally designed to take + * a number after a dash. + */ + if (minlen == -1) { + p = argv[optind - 1]; + if (p[0] == '-' && p[1] == ch && !p[2]) + minlen = atoi(++p); + else + minlen = atoi(argv[optind] + 1); + } + break; + case '-': + case 'a': + asdata = 1; + break; + case 'f': + fflg = 1; + break; + case 'n': + minlen = atoi(optarg); + break; + case 'o': + oflg = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (minlen == -1) + minlen = DEF_LEN; + + if (!(bfr = malloc((u_int)minlen))) { + (void)fprintf(stderr, "strings: %s\n", strerror(errno)); + exit(1); + } + bfr[minlen] = '\0'; + file = "stdin"; + do { + if (*argv) { + file = *argv++; + if (!freopen(file, "r", stdin)) { + (void)fprintf(stderr, + "strings; %s: %s\n", file, strerror(errno)); + exitcode = 1; + goto nextfile; + } + } + foff = 0; +#define DO_EVERYTHING() {read_len = -1; head_len = 0; goto start;} + read_len = -1; + if (asdata) + DO_EVERYTHING() + else { + head = (EXEC *)hbfr; + if ((head_len = + read(fileno(stdin), head, sizeof(EXEC))) == -1) + DO_EVERYTHING() + if (head_len == sizeof(EXEC) && !N_BADMAG(*head)) { + foff = N_TXTOFF(*head); + if (fseek(stdin, foff, SEEK_SET) == -1) + DO_EVERYTHING() + read_len = head->a_text + head->a_data; + head_len = 0; + } + else + hcnt = 0; + } +start: + for (cnt = 0; (ch = getch()) != EOF;) { + if (ISSTR(ch)) { + if (!cnt) + C = bfr; + *C++ = ch; + if (++cnt < minlen) + continue; + if (fflg) + printf("%s:", file); + if (oflg) + printf("%07ld %s", + foff - minlen, (char *)bfr); + else + printf("%s", bfr); + while ((ch = getch()) != EOF && ISSTR(ch)) + putchar((char)ch); + putchar('\n'); + } + cnt = 0; + } +nextfile: ; + } while (*argv); + exit(exitcode); +} + +/* + * getch -- + * get next character from wherever + */ +getch() +{ + ++foff; + if (head_len) { + if (hcnt < head_len) + return((int)hbfr[hcnt++]); + head_len = 0; + } + if (read_len == -1 || read_len-- > 0) + return(getchar()); + return(EOF); +} + +static void +usage() +{ + (void)fprintf(stderr, + "usage: strings [-afo] [-n length] [file ... ]\n"); + exit(1); +} diff --git a/bsd/Makefile b/bsd/Makefile deleted file mode 100644 index 8783c5b30..000000000 --- a/bsd/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Makefile -- Makefile for util-linux Linux utilities -# Created: Sat Dec 26 20:09:40 1992 -# Revised: Fri Mar 10 21:20:41 1995 by faith@cs.unc.edu -# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) -# - -include ../MCONFIG - -all: err.o getopt.o -err.o: err.c -getopt.o: getopt.c - -.PHONY: clean distclean -clean: - -rm -f *.o *~ core - -install install.shadow: diff --git a/bsd/err.c b/bsd/err.c deleted file mode 100644 index 2731a714f..000000000 --- a/bsd/err.c +++ /dev/null @@ -1,185 +0,0 @@ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#ifdef __STDC__ -#include -#else -#include -#endif - -extern char *__progname; /* Program name, from crt0. */ -#ifdef __linux__ -char *__progname; -#endif - -__dead void -#ifdef __STDC__ -err(int eval, const char *fmt, ...) -#else -err(eval, fmt, va_alist) - int eval; - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - verr(eval, fmt, ap); - va_end(ap); -} - -__dead void -verr(eval, fmt, ap) - int eval; - const char *fmt; - va_list ap; -{ - int sverrno; - - sverrno = errno; - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) { - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, ": "); - } - (void)fprintf(stderr, "%s\n", strerror(sverrno)); - exit(eval); -} - -__dead void -#if __STDC__ -errx(int eval, const char *fmt, ...) -#else -errx(eval, fmt, va_alist) - int eval; - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - verrx(eval, fmt, ap); - va_end(ap); -} - -__dead void -verrx(eval, fmt, ap) - int eval; - const char *fmt; - va_list ap; -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); - exit(eval); -} - -void -#if __STDC__ -warn(const char *fmt, ...) -#else -warn(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - vwarn(fmt, ap); - va_end(ap); -} - -void -vwarn(fmt, ap) - const char *fmt; - va_list ap; -{ - int sverrno; - - sverrno = errno; - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) { - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, ": "); - } - (void)fprintf(stderr, "%s\n", strerror(sverrno)); -} - -void -#ifdef __STDC__ -warnx(const char *fmt, ...) -#else -warnx(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - vwarnx(fmt, ap); - va_end(ap); -} - -void -vwarnx(fmt, ap) - const char *fmt; - va_list ap; -{ - (void)fprintf(stderr, "%s: ", __progname); - if (fmt != NULL) - (void)vfprintf(stderr, fmt, ap); - (void)fprintf(stderr, "\n"); -} diff --git a/bsd/err.h b/bsd/err.h deleted file mode 100644 index da4be150c..000000000 --- a/bsd/err.h +++ /dev/null @@ -1,70 +0,0 @@ -/*- - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)err.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _ERR_H_ -#define _ERR_H_ - -#ifdef __linux__ -#include -#define _BSD_VA_LIST_ va_list -#define __dead /* */ -#else -/* - * Don't use va_list in the err/warn prototypes. Va_list is typedef'd in two - * places ( and ), so if we include one - * of them here we may collide with the utility's includes. It's unreasonable - * for utilities to have to include one of them to include err.h, so we get - * _BSD_VA_LIST_ from and use it. - */ -#include -#endif -#include - -__BEGIN_DECLS -__dead void err __P((int, const char *, ...)); -__dead void verr __P((int, const char *, _BSD_VA_LIST_)); -__dead void errx __P((int, const char *, ...)); -__dead void verrx __P((int, const char *, _BSD_VA_LIST_)); -void warn __P((const char *, ...)); -void vwarn __P((const char *, _BSD_VA_LIST_)); -void warnx __P((const char *, ...)); -void vwarnx __P((const char *, _BSD_VA_LIST_)); -__END_DECLS - -#ifdef __linux__ -#undef _BSD_VA_LIST_ -#endif - -#endif /* !_ERR_H_ */ diff --git a/bsd/getopt.3 b/bsd/getopt.3 deleted file mode 100644 index c21a0a725..000000000 --- a/bsd/getopt.3 +++ /dev/null @@ -1,210 +0,0 @@ -.\" Copyright (c) 1988, 1991 Regents of the University of California. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)getopt.3 6.16 (Berkeley) 4/19/91 -.\" -.Dd April 19, 1991 -.Dt GETOPT 3 -.Os BSD 4.3 -.Sh NAME -.Nm getopt -.Nd get option letter from argv -.Sh SYNOPSIS -.Fd #include -.Vt extern char *optarg -.Vt extern int optind -.Vt extern int opterr -.Ft int -.Fn getopt "int argc" "char * const *argv" "const char *optstring" -.Sh DESCRIPTION -The -.Fn getopt -function gets -the next -.Em known -option character from -.Fa argv . -An option character is -.Em known -if it has been specified in the string of accepted option characters, -.Fa optstring . -.Pp -The option string -.Fa optstring -may contain the following characters; letters and -letters followed by a colon to indicate an option argument -is to follow. It does not matter to -.Fn getopt -if a following argument has leading white space. -.Pp -On return from -.Fn getopt , -.Va optarg -points to an option argument, if it is anticipated, -and the variable -.Va optind -contains the index to the next -.Fa argv -argument for a subsequent call -to -.Fn getopt . -.Pp -The variable -.Va opterr -and -.Va optind -are both initialized to 1. -In order to use -.Fn getopt -to evaluate multiple sets of arguments, or to evaluate a single set of -arguments multiple times, -.Va optind -must be initialized to the number of argv entries to be skipped in each -evaluation. -.Pp -The -.Fn getopt -function -returns an -.Dv EOF -when the argument list is exhausted, or a non-recognized -option is encountered. -The interpretation of options in the argument list may be cancelled -by the option -.Ql -- -(double dash) which causes -.Fn getopt -to signal the end of argument processing and return an -.Dv EOF . -When all options have been processed (i.e., up to the first non-option -argument), -.Fn getopt -returns -.Dv EOF . -.Sh DIAGNOSTICS -If the -.Fn getopt -function encounters a character not found in the string -.Va optarg -or detects -a missing option argument -it writes error message -.Ql ? -to the -.Em stderr . -Setting -.Va opterr -to a zero will disable these error messages. -.Sh EXAMPLE -.Bd -literal -compact -extern char *optarg; -extern int optind; -int bflag, ch, fd; - -bflag = 0; -while ((ch = getopt(argc, argv, "bf:")) != EOF) - switch(ch) { - case 'b': - bflag = 1; - break; - case 'f': - if ((fd = open(optarg, O_RDONLY, 0)) < 0) { - (void)fprintf(stderr, - "myname: unable to read file %s.\en", optarg); - exit(1) ; - } - break; - case '?': - default: - usage(); -} -argc -= optind; -argv += optind; -.Ed -.Sh HISTORY -The -.Fn getopt -function appeared -.Bx 4.3 . -.Sh BUGS -Option arguments are allowed to begin with -.Dq Li \- ; -this is reasonable but -reduces the amount of error checking possible. -.Pp -A single dash -.Dq Li - -may be specified as an character in -.Fa optstring , -however it should -.Em never -have an argument associated with it. -This allows -.Fn getopt -to be used with programs that expect -.Dq Li - -as an option flag. -This practice is wrong, and should not be used in any current development. -It is provided for backward compatibility -.Em only . -By default, a single dash causes -.Fn getopt -to return -.Dv EOF . -This is, we believe, compatible with System V. -.Pp -It is also possible to handle digits as option letters. -This allows -.Fn getopt -to be used with programs that expect a number -.Pq Dq Li \&-\&3 -as an option. -This practice is wrong, and should not be used in any current development. -It is provided for backward compatibility -.Em only . -The following code fragment works fairly well. -.Bd -literal -offset indent -int length; -char *p; - -while ((c = getopt(argc, argv, "0123456789")) != EOF) - switch (c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - p = argv[optind - 1]; - if (p[0] == '-' && p[1] == ch && !p[2]) - length = atoi(++p); - else - length = atoi(argv[optind] + 1); - break; - } -} -.Ed diff --git a/bsd/getopt.c b/bsd/getopt.c deleted file mode 100644 index be621bd92..000000000 --- a/bsd/getopt.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 1987 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -/* - * get option letter from argument vector - */ -int opterr = 1, /* if error message should be printed */ - optind = 1, /* index into parent argv vector */ - optopt; /* character checked for validity */ -char *optarg; /* argument associated with option */ - -#define BADCH (int)'?' -#define EMSG "" - -int -getopt(nargc, nargv, ostr) - int nargc; - char * const *nargv; - const char *ostr; -{ - static char *place = EMSG; /* option letter processing */ - register char *oli; /* option letter list index */ - char *p; - - if (!*place) { /* update scanning pointer */ - if (optind >= nargc || *(place = nargv[optind]) != '-') { - place = EMSG; - return(EOF); - } - if (place[1] && *++place == '-') { /* found "--" */ - ++optind; - place = EMSG; - return(EOF); - } - } /* option letter okay? */ - if ((optopt = (int)*place++) == (int)':' || - !(oli = index(ostr, optopt))) { - /* - * if the user didn't specify '-' as an option, - * assume it means EOF. - */ - if (optopt == (int)'-') - return(EOF); - if (!*place) - ++optind; - if (opterr) { - if (!(p = rindex(*nargv, '/'))) - p = *nargv; - else - ++p; - (void)fprintf(stderr, "%s: illegal option -- %c\n", - p, optopt); - } - return(BADCH); - } - if (*++oli != ':') { /* don't need argument */ - optarg = NULL; - if (!*place) - ++optind; - } - else { /* need an argument */ - if (*place) /* no white space */ - optarg = place; - else if (nargc <= ++optind) { /* no arg */ - place = EMSG; - if (!(p = rindex(*nargv, '/'))) - p = *nargv; - else - ++p; - if (opterr) - (void)fprintf(stderr, - "%s: option requires an argument -- %c\n", - p, optopt); - return(BADCH); - } - else /* white space */ - optarg = nargv[optind]; - place = EMSG; - ++optind; - } - return(optopt); /* dump back option letter */ -} diff --git a/bsd/pathnames.h b/bsd/pathnames.h deleted file mode 100644 index f6e467214..000000000 --- a/bsd/pathnames.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 - * - * Changed: Sun Nov 21 12:30:54 1993 by faith@cs.unc.edu - * Changed: Wed Jun 22 20:47:27 1994 by faith@cs.unc.edu, based on changes - * from poe@daimi.aau.dk - * Changed: Wed Jun 22 22:50:13 1994 by faith@cs.unc.edu - * Changed: Sat Feb 4 16:02:10 1995 by faith@cs.unc.edu - * Changed: Tue Jul 2 09:37:36 1996 by janl@math.uio.no, axp patches - * Changed: Thu Nov 9 21:58:36 1995 by joey@infodrom.north.de - */ - -#ifndef __STDC__ -# error "we need an ANSI compiler" -#endif - -/* The paths for some of these are wrong in /usr/include/paths.h, but we - re-define them here. */ - -#undef _PATH_UTMP -#undef _PATH_WTMP -#undef _PATH_DEFPATH -#undef _PATH_DEFPATH_ROOT -#undef _PATH_LASTLOG -#undef _PATH_MAILDIR - -#ifndef SBINDIR -#define SBINDIR "/sbin" -#endif - -#ifndef USRSBINDIR -#define USRSBINDIR "/usr/sbin" -#endif - -#ifndef LOGDIR -#define LOGDIR "/var/log" -#endif - -#ifndef VARPATH -#define VARPATH "/var" -#endif - -#ifndef UT_NAMESIZE -#define UT_NAMESIZE 8 -#endif - -#define _PATH_BSHELL "/bin/sh" -#define _PATH_CSHELL "/bin/csh" -#define _PATH_TTY "/dev/tty" -#define TTYTYPES "/etc/ttytype" -#define SECURETTY "/etc/securetty" -#define _PATH_UTMP "/var/run/utmp" -#define _PATH_WTMP LOGDIR "/wtmp" -#define _PATH_WTMPLOCK "/etc/wtmplock" - -#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin:." -#define _PATH_DEFPATH_ROOT SBINDIR ":/bin:" USRSBINDIR ":/usr/bin" -#define _PATH_HUSHLOGIN ".hushlogin" -#define _PATH_LASTLOG LOGDIR "/lastlog" -#define _PATH_MAILDIR VARPATH "/spool/mail" -#define _PATH_MOTDFILE "/etc/motd" -#define _PATH_NOLOGIN "/etc/nologin" - -#define _PATH_LOGIN "/bin/login" -#define _PATH_INITTAB "/etc/inittab" -#define _PATH_RC "/etc/rc" -#define _PATH_REBOOT SBINDIR "/reboot" -#define _PATH_SINGLE "/etc/singleboot" -#define _PATH_SECURE "/etc/securesingle" -#define _PATH_USERTTY "/etc/usertty" - -#define _PATH_MTAB "/etc/mtab" -#define _PATH_UMOUNT "/bin/umount" -#define UMOUNT_ARGS "umount", "-a" -#define SWAPOFF_ARGS "swapoff", "-a" - -#define _PATH_PASSWD "/etc/passwd" -#define _PATH_PTMP "/etc/ptmp" -#define _PATH_PTMPTMP "/etc/ptmptmp" - -#define _PATH_GROUP "/etc/group" -#define _PATH_GTMP "/etc/gtmp" -#define _PATH_GTMPTMP "/etc/gtmptmp" - -#define _PATH_WORDS "/usr/dict/words" -#define _PATH_WORDS_ALT "/usr/dict/web2" diff --git a/disk-utils/Makefile b/disk-utils/Makefile index d21cedb9e..aec38630a 100644 --- a/disk-utils/Makefile +++ b/disk-utils/Makefile @@ -23,48 +23,12 @@ ifneq "$(CPU)" "sparc" # 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 # Where to put datebase files? 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 - rm -f activate - ln -s sfdisk activate - -# Rules for everything else - fdformat: fdformat.o fsck.minix: fsck.minix.o fsck.minix.o: fsck.minix.c bitops.h @@ -73,17 +37,6 @@ mkfs.minix: mkfs.minix.o mkfs.minix.o: mkfs.minix.c bitops.h mkswap: mkswap.o setfdprm: setfdprm.o -sfdisk: sfdisk.o - -ifeq "$(CPU)" "sparc" -fdisk: fdisk.o fdisklabel.o fdisksunlabel.o llseek.o -fdisksunlabel.o: fdisksunlabel.c fdisksunlabel.h fdisk.h -else -fdisk: fdisk.o fdisklabel.o llseek.o -endif - -fdisk.o: fdisk.c fdisk.h -fdisklabel.o: fdisklabel.c fdisk.h fdisklabel.h install: all $(INSTALLDIR) $(SBINDIR) $(USRBINDIR) $(ETCDIR) diff --git a/disk-utils/README.cfdisk b/disk-utils/README.cfdisk deleted file mode 100644 index 5241ad136..000000000 --- a/disk-utils/README.cfdisk +++ /dev/null @@ -1,45 +0,0 @@ -Announcing the new curses based fdisk program... cfdisk - -cfdisk is a curses based disk drive partitioning program that can -create partitions for a wide variety of operating systems including -Linux, MS-DOS and OS/2. cfdisk was inspired by the fdisk program, by -A. V. Le Blanc (LeBlanc@mcc.ac.uk). I hope that this program will be -useful to both new and old Linux users, and I hope it will make the -installation process easier. - - - **** WARNING **** -If you write a bad partition table to disk, it may destroy data and -partitions. - - -You can FTP cfdisk from ftp.cs.unc.edu in the /pub/martin/linux -directory. - -I would also like comments (good and bad) on the user interface, logic -and ease of use. If you have any suggestions for improvements, I -would be happy to hear them. - -My e-mail address is martin@cs.unc.edu. - -------------------------------------------------------------------- - - Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) - -cfdisk 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. - -cfdisk 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 cfdisk; if not, write to the Free Software Foundation, -Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -___ -Kevin E. Martin University of North Carolina at Chapel Hill -martin@cs.unc.edu Department of Computer Science diff --git a/disk-utils/README.fdisk b/disk-utils/README.fdisk deleted file mode 100644 index 40f54b4b9..000000000 --- a/disk-utils/README.fdisk +++ /dev/null @@ -1,579 +0,0 @@ -`fdisk': the Linux partition table editor -========================================= - -`fdisk' is the Linux partition table editor. In this section we -examine this utility and try to describe it thoroughly enough so that -anyone can use it. - -* Contents: - -* Disks and how they are described. -* Dividing up your disk. -* The `fdisk' command. -* Deleting and adding partitions. -* Active flags and system types. -* Extra commands for experts. -* Warnings for `fdisk' users. - - -Disks and how they are described --------------------------------- - -A typical disk consists physically of one or more circular objects -called "platters", which rotate about a central axis. Devices called -"heads" move to specified places on the disk surface to read or write -information. There is usually one head on each side of every platter, -and all these heads are attached to a comb-like controller arm which -moves all of them at the same time, either closer to the centre of the -disk, or closer to the outer edge. - -Suppose the arm is in one position, putting an area of the disk -surface within reach of one or another of the heads. This total area, -everything that is accessible without moving the arm, is called a -"cylinder". (A cylinder is a barrel-shaped cross section of a disk, -consisting of a circular strip from each side of each platter.) The -part of a cylinder that one head can read or write without moving is -called a "track". - -Each track is divided into several pie-shaped slices called -"sectors", which are the smallest parts of the disk which can be read -or written at a time. The sectors on one disk are usually all the same -size. - -In fact, there are not always two heads to every platter, there are -some disks which do not have the same amount of data in every cylinder, -and there may be disks which do not have the same amount of data in -every sector. These features are usually hidden on PCs by the -controller card or the BIOS, which map the physical geometry of a disk -onto a logical geometry, which is what is actually used to access the -disk. - -The numbers which describe the "geometry" of a disk are - - 1. The number of cylinders it contains. - - 2. The number of tracks per cylinder, which is the number of heads. - - 3. The number of sectors per track. - - 4. The number of bytes per sector. - -These numbers vary from disk to disk, but a typical PC disk might -have about 1000 cylinders, half a dozen heads, and 15 or 20 sectors per -track, with each sector containing 512 bytes or characters; such a disk -contains 40 to 60 megabytes of data. A "double density" floppy disk -contains 40 cylinders, with 2 heads (2 tracks per cylinder), and with 9 -sectors per track; such a disk contains 360 kilobytes, or 360 * 1024 -characters. A "high density" 3.5 inch floppy contains 80 cylinders, -with 2 heads and 18 sectors per track, or 1.44 megabytes, or 1440 * -1024 characters. - -The exact size of a track or cylinder in bytes varies from one disk -to another. This `fdisk' for Linux deals mainly with cylinders, since -this is the best unit to use when allocating space for partitions. It -reports partition sizes in "blocks" of 1024 bytes, or 2 sectors, since -`mkswap' and the various `mkfs' programs require this number. A block -is the smallest amount of space which can be set aside for a file in -the current file systems. - -An operating system, such as Linux or DOS or OS/2, may use a disk in -any way that it wishes, but if two operating systems share the same -disk, they must agree on who owns what, or else one will interfere with -the other (that is, by damaging the other's files). A "partition" is a -section of a hard disk which is handled as a unit by all operating -systems which can access the disk. The standard way to define -partitions (for the moment) is the "partition table", a list of -information which is stored in parts of the disk that don't belong to -any of the systems using the disk. The beginning of the partition -table is stored in the disk's primary boot sector, and the rest is -stored in a chain of sectors scattered throughout the disk. - -The first sector on the disk is called the "primary boot block" or -"primary boot sector" because (1) it comes first, before other, similar -sectors; (2) it tells where the other, similar sectors are found, so -that it is logically `prior' to them; and (3) it usually contains code -which is executed when the system boots up. This sector contains a -table describing at most four partitions. These areas are called -"primary partitions". - -The partition table in the primary boot sector may also describe at -most one "extended partition". This is a large area of the disk, -usually containing all the space which is not in any primary partition. -Within this space we can set aside other areas which are called -"logical partitions", because they look almost exactly like primary -partitions. In fact, the main difference between them is that we can -boot from primary partitions, while we cannot boot from logical -partitions. This happens because the address of a primary partition is -in a fixed place, whereas the address of a secondary partition is not, -so we require a more complicated process to discover it, one which is -too difficult for most primary boot programs. - - -Dividing up your disk ---------------------- - -It is a good idea to plan ahead before you start creating partitions -on your disk. If you set aside a partition for some purpose, it is not -easy to change its size: you must backup all the data from the partition, -whether to floppies, to another partition, to another hard disk, or -somewhere else; then you must edit the table which describes this -partition, so changing its size; then you must reboot and initialise -the new partition, formatting it, for example, under DOS, or running -`mkfs' under Linux; finally you can copy all the data back. It is -possible, if you have several partitions, to copy data back and forth -between them while you change their sizes, but this is a bit risky and -time consuming. It is better to plan ahead what you will need, since -it is hard to change it afterwards. - -Many people with large disks and recent versions of DOS have their -entire file system on one large partition. They usually ask, `Isn't -there any way I can reformat my disk without copying everything off?' -There is no way to do it using standard DOS utilities, and there is no -truly safe way to do it using commercial software, because, if you make -a mistake, you will lose the entire contents of your disk. If you are -going to back up your disk anyway, you might as well copy the data back -safely. The Linux FAQ contains references to tools and procedures -which will allow you to do this, if you dare. - -DOS and Linux both allow you to access several partitions on a -single disk; on DOS these are treated as if they were separate disks or -drives, and under Linux they are treated as different "devices". - -You can have up to 64 partitions on a single IDE disk, or up to 16 -partitions on a single SCSI disk, at least as far as Linux is -concerned; in practice you will rarely want so many. The maximum size -of a Linux file system on a single partition depends on the type of -file system you use. Minix file systems are limited to 64 megabytes. -You may have all of your Linux files in a single partition, or you may -have two, three, or more Linux file systems. Similarly you may have -one or more DOS partitions. If you have several small partitions, you -run much less risk of losing all your files if your disk gets -corrupted. On the other hand, you may run out of space on a small -partition more easily. - -Under DOS, you must refer to each partition by a separate drive -letter, but all partitions are automatically accessible. Under Linux -only the root partition is automatically accessible, but once we mount -another partition, it is indistinguishable from the rest of the file -system. Disks are usually mounted by a command in one of the system -startup files, `/etc/rc', so you need not worry about having to do it -yourself whenever you boot the system. But even ordinary users may -be allowed to mount removable hard disks and floppy disks. - -Linux requires at least one partition, which is the `root' of the -file system. You may prefer to have a separate partition for `/usr', -which contains most of the executable files, or for `/home', which -contains most of your private files. You may also wish to set aside a -partition to use for swap space, depending on the amount of memory your -PC has. You will certainly need swap space if you have less than 4 Mb -of RAM and wish to compile anything substantial. You can reserve swap -space in a file, but you need a partition big enough to hold it, and -this will probably be less efficient than having a partition devoted to -swap. - -The disk space you need for Linux is discussed in README.prepare. - -Are you going to boot Linux from the hard disk, or will you boot -from a floppy? Some boot programs place severe restrictions on where -the boot partition can be. LILO is more relaxed about this, but does -require either the Master Boot Record on your first hard disk, or the -boot record on one of the first four partitions on your first hard disk. - -If you have an extended partition with logical partitions in it, you -can have only three primary partitions containing data. - - -The `fdisk' command -------------------- - -Every operating system, whether DOS, OS/2, or Linux, should provide -its own utility for editing hard disk partition tables. At least four -of these utilities have been called `fdisk', for `Fixed DISK setup -program', where `fixed' means `not removable'. I believe the first PC -program named `fdisk' came from Microsoft in about 1985; before that -time disks were too small to divide into separate sections. - -Every operating system has its own peculiarities. Normally you -should set up a partition for the use of one operating system by using -its own `fdisk' program. Do not use the Linux `fdisk' to create -partitions for DOS or for any system other than Linux; otherwise you -may have problems. - -An `fdisk' program performs two functions: it reports how the disk is -configured, and it changes that configuration by adding or deleting -partitions. Most `fdisk' programs can also change other information in -partition tables. - -This `fdisk' for Linux operates on one hard disk at a time. If you -give the command - - fdisk - -it reports on, and is able to change, `/dev/hda', the first hard -disk. (If you have no `/dev/hda', `fdisk' uses `/dev/sda' as the -default device.) To look at or change the second hard disk, `/dev/hdb', -give the command - - fdisk /dev/hdb - -To look at or change the first SCSI disk, give the command - - fdisk /dev/sda - -There are some special forms of the `fdisk' command. One of them, -suggested by Jim Winstead, simply lists all partitions on all available -disks: - - fdisk -l (where `l' is a letter, not the digit `1') - -The option `-v' is provided to list the current version of the -`fdisk' command. Finally, there is an option `-s' which is not really -intended for interactive use. It causes fdisk to print the size of a -partition in blocks of 1024 bytes as follows: - - fdisk -s /dev/hda7 - 39934 - -Because this is intended to be used by `mkfs' and `mkswap' programs, -it does not return the size of extended partitions or of partitions -whose system type code is less than 10 (hexadecimal a). If you start -`fdisk' without using one of these special options, it responds by -asking for a command: - - Command (m for help): _ - -Each `fdisk' command consists of a single letter, which must be -followed by before it is obeyed. Upper and lower case are not -distinguished. Anything you type after the first character is ignored. -Give the command `m', and you should see this menu: - Command action - a toggle a bootable flag - d delete a partition - l list known partition types - m print this menu - n add a new partition - p print the partition table - q quit without saving changes - t change a partition's system id - u change display/entry units - v verify the partition table - w write table to disk and exit - x extra functionality (experts only) - - Command (m for help): _ - -The simplest commands are Print, Verify, and Quit. On a small disk, the -Print command might produce a display like this one: - - Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders - Units = cylinders of 85 * 512 bytes - - Device Boot Begin Start End Blocks Id System - /dev/hda1 * 1 1 236 10021+ 1 DOS 12-bit FAT - /dev/hda2 837 837 977 5992+ 5 Extended - /dev/hda3 * 237 237 836 25500 83 Linux native - /dev/hda5 837 837 936 4249+ 82 Linux swap - /dev/hda6 942 942 977 1522 1 DOS 12-bit FAT - -There are 5 partitions reported; `/dev/hda4' does not appear because -it is not allocated. Partitions 1 and 3 are flagged as bootable. The -size of each partition is reported in 1 kilobyte blocks; hence the -primary Linux partition, partition 3, is 25 1/2 megabytes in size. The -`+' after three of the sizes warns that these partitions contain an odd -number of sectors: Linux normally allocates filespace in 1 kilobyte -blocks, so the extra sector in partition 5 is wasted. Id numbers are -reported in hexadecimal and explained in English. - -The display/entry units may be either cylinders or sectors. The -default is cylinders, but changing the units makes the print command -display the following table for the system reported above: - - Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders - Units = sectors of 1 * 512 bytes - - Device Boot Begin Start End Blocks Id System - /dev/hda1 * 1 17 20059 10021+ 1 DOS 12-bit FAT - /dev/hda2 71060 71060 83044 5992+ 5 Extended - /dev/hda3 * 20060 20060 71059 25500 83 Linux native - /dev/hda5 71061 71061 79559 4249+ 82 Linux swap - /dev/hda6 79985 80001 83044 1522 1 DOS 12-bit FAT - -The start of data in both DOS partitions is 16 sectors after the -beginning of the partition: this is one reason why you should use DOS's -own `FDISK' to create DOS partitions. Changing the units to sectors -also affects the way in which the new partition command asks for the -beginning and end of a new partition. - -*Warning*: it is dangerous to create a new partition when the -display/entry units are sectors. - -The Verify command is useful because - - 1. It warns you if anything is wrong. *Always* do a Verify command - to check your work before writing any changes to disk. - - 2. It reports how many unallocated sectors there are on the disk. - -The Quit command is also useful. `fdisk' does not actually change -any data on your disk unless you give a Write command. If you are -unhappy about any changes you may have made, give the Quit command, and -your disk will remain as it was before you ran `fdisk'. You can also -interrupt `fdisk' with `CTRL-C'. - - -Deleting and adding partitions ------------------------------- - -Deleting a partition is simple. Give the Delete command by typing -`d'. `fdisk' asks: - - Partition number (1-6): _ - -Once you get this far, you must either delete a partition or -interrupt the program with `CTRL-C' (or whatever your current interrupt -character is). Note: - - 1. You may delete a nonexistent partition. You will get a warning - message. - - 2. You may delete an extended partition. This has the side effect of - deleting all partitions greater than or equal to 5. - - 3. You may delete a logical partition. In that case, all partitions - above it are renumbered at once. For example, if you delete - partition 5, then partition 6 becomes known as partition 5, and - partition 7 as partition 6. - -Adding a partition is just a bit more complicated. Give the New -command by typing `n'. `fdisk' allows you to - - 1. Create a primary partition, if there is a free slot in the primary - partition table. - - 2. Create an extended partition if there is a free slot in the - primary partition table, and if there is no extended partition. - - 3. Create a logical partition if an extended partition exists. - -If more than one of these actions is possible, you will be asked to -select Primary, Extended, or Logical, depending on what is currently -permissible. Before you create a primary or an extended partition, you -are asked what slot it is to have in the table (1-4). - -You may not add a primary or an extended partition if the selected -slot in the primary partition table is already occupied: in that case -you simply return to the main menu. You are not allowed to add a new -primary partition unless there are sectors available outside the -extended partition. You are not allowed to add a new logical partition -unless there are sectors available inside the extended partition. - -If space is available, you are prompted for the first cylinder: - - First sector ([237]-977): _ - -The limits are the lowest and the highest cylinders in which sectors -are available in the appropriate part of the disk. The square-bracketed -number is what you'll get if you simply press enter. Not all numbers in -this range are necessarily available: they may fall inside an existing -partition. If you select a cylinder which is already in use, you are -told off and prompted again for the first cylinder. After selecting the -first cylinder, you are prompted again: - - Last cylinder or +size or +sizeM or +sizeK (237-[836]): _ - -The limits are the cylinder you have chosen as the first cylinder, -and the highest cylinder which contains a legitimate upper boundary for -the new partition. The square-bracketed number is what you'll get if -you simply press enter. In other words, all numbers in the given range are -legitimate, unlike those in the first range of cylinders. You may also -specify the size of a partition in megabytes, kilobytes, or in the -current units (cylinders or sectors). A plus sign `+' indicates that -your answer is a size rather than a boundary, and the suffix `m' or `k' -(upper or lower case) indicates that the size is not given in units of -sectors or cyliners, but in megabytes or kilobytes respectively. Thus -possible answers to the last cylinder request above are - -700 - Make cylinder 700 the last cylinder in the partition. - -+300 - Make cylinder 237 + 300 = 537 the last cylinder in the partition. - -+15m - Make the partition at least 15 megabytes in size. - -+12500k - Make the partition at least 12,500 kilobytes in size. - -If you specify a size which is too large or an end which is out of -range, fdisk complains and repeats the prompt. - -Adding or deleting partitions has no effect unless you subsequently -give the Write command. Please remember to give the Verify command -first, just before giving the Write command: this is a safety -precaution. After giving the Write command, you will see this message: - - The partition table has been altered! - Calling ioctl() to re-read partition table. - Syncing disks. - -If there are no further messages, the kernel has successfully copied -the information from the partition table into its own internal table. -But sometimes you will see a message like this one: - - Re-read table failed with error 16: Device or resource busy. - Reboot your system to ensure the partition table is updated. - -In this case, depending on what you have changed in the partition -table, it may be dangerous to continue working without rebooting, -since you may lose or corrupt your data. - - -Here are some important things to note: - - 1. Before you reboot, you *may* run `fdisk' again, either to manage - another disk, or to make additional changes to the same disk, or - just to check that the changes have been made as you expected. - This is true even after you receive the message warning you to - reboot. - - 2. It is not a good idea to run any of the programs `mkfs', `mkswap', - `mount', or `swapon' if you have received the warning message but - have not rebooted. In this case it is dangerous to run any program, - but these in particular may cause serious damage to the data on your - disk, including the partition tables themselves. - - -Active flags and system types ------------------------------ - -The active flag is a bit in the partition table entry which marks a -partition as bootable. This is important to some primary boot sector -programs, which will not boot from an unflagged partition. Other such -programs do not allow more than one partition to be flagged. Some, -like LILO, ignore the flags completely. I prefer to flag all bootable -partitions as active so that they stand out on the menu which `fdisk' -lists. Fdisk prints a star after the name of a partition's device file -if its active flag is set. - -The Active command changes, or toggles, a partition's active flag. -Give the Active command, and select a partition by number. If it was -marked inactive, it will be flagged as active; if it was flagged as -active, it will be marked inactive. You may set the active flag on an -extended or logical partition, though the meaning of such a flag is by -no means clear. This can be used to install LILO as a secondary boot -loader to boot a Linux which lives on a second hard disk. - -The Type command changes the ID number which describes what type a -partition is. `fdisk' currently recognises 30 system IDs, in the sense -that it prints a string for each of them, but it allows you to change -any system ID to any other, with the following exceptions: you may not -change any partition to or from the type Extended, and you may not -change a partition whose type is Empty (0) to any other type. You may, -however, change the type of any data partition to 0, which is -equivalent to deleting it. - -The new system ID or type code is a hexadecimal number. There are -two ways of listing the numbers which `fdisk' recognises: use the List -command, which prints the list, or use the Type command, which, when it -prompts you for the code, says - - Hex code (type L to list codes): _ - -where the upper case `L' is used for clarity. The codes printed are: -Some of these numbers are a trifle uncertain. By default `fdisk' uses -a type of 83. It used to use 81, the type code used by the MINIX -`fdisk'. It seemed prudent to change the default since (a) many Linux -`minix' file systems are no longer compatible with MINIX, (b) the ext2 -file system, a native Linux file system, is fairly stable, as is the -Xia file system, and (c) the number 81 causes problems with DR-DOS. -Linux does not usually care what values you use for type codes, but -other systems, in particular DOS, OS/2, and DR-DOS, may. - -The value of 82 for Linux swap partitions is my own invention, and -is intended to give some recognisable distinction to the partitions -when the values are displayed in hexadecimal. - -New active flags and new system type codes are not written to the -disk until you exit from `fdisk' with the Write command, as described -above, in the section on deleting and adding partitions. - - -Extra commands for experts --------------------------- - -The eXtra command `x' puts `fdisk' into `expert' mode, in which a -slightly different set of commands is available. The Active, Delete, -List, New, Type, Verify, and `eXpert' commands are not available in -expert mode. The commands Write and Quit are available as in ordinary -mode, the Print command is available, but produces output in a slightly -different format, and of course the Menu command prints the expert -menu. There are several new commands. - - 1. The Return command brings you back to the main menu. - - 2. The Extended command prints the list of table entries which point - to other tables. Ordinary users do not need this information. - The data is shown as it is stored. The same format is used for - the expert Print command. - - 3. The dangerous Begin command allows you to move the start of data - in a partition away from its beginning. Other systems create - partitions with this format, and it is sometimes useful to be able - to reproduce it. - - 4. The slightly dangerous Cylinders command allows you to change the - available number of cylinders. For SCSI disk owners, note that we - require not the actual number of physical cylinders, but the - number of logical cylinders used by DOS and other operating - systems. - - 5. The extremely dangerous Heads and Sectors commands allow you to - change the number of heads and sectors. It should not be - necessary to use these commands unless you have a SCSI disk, whose - geometry Linux is not always able to determine. SCSI disk owners - note that we need not the actual number of heads or of sectors per - track, but the number believed to exist by DOS and other operating - systems. *Warning*: If you set either of these numbers to a bad - value, you may lose all data on your disk. - -Always, after giving any of the commands Begin, Cylinder, Heads, or -Sectors, you should Return to the main menu and give the Verify command. - - -Warnings for `fdisk' users --------------------------- - -In general, you should not use this `fdisk' program to create -partitions for other operating systems, only for Linux. Nor should you -use `fdisk' commands from other operating systems to create partitions -for Linux. - -DR-DOS 5.0 and 6.0 are reported to have difficulties with partition -ID codes of 80 or more. The Linux `fdisk' used to set the system type -of new partitions to hexadecimal 81. DR-DOS seems to confuse this with -hexadecimal 1, a DOS code. The values 82 for swap and 83 for file -systems should not cause problems with DR-DOS. If they do, you may use -the `fdisk' command `t' to change the system code of any Linux -partitions to some number less than hexadecimal 80; I suggest 42 and 43 -for the moment. - -Partitioning a hard disk may destroy data which is on that disk if you -are not careful. Go slowly, write down a description of the partition -tables before you changed them, and always verify before you write. - -Most operating systems and utilities expect that all partitions begin and -end at cylinder boundaries. This version of `fdisk' does so by default, -but you can use it to create partitions which begin or end anywhere. -This does not normally affect Linux, but it is very dangerous, as other -operating systems (including DOS) may try to `correct' the partition -boundaries. - -It is dangerous to create a new partition when the display/entry -units are sectors. - -The Verify command warns you if anything is wrong. *Always* give a -Verify command before writing any changes to disk. - -If you set the disk geometry (tracks per cylinder, or sectors per -track) to an incorrect value, you may lose all data on your disk. diff --git a/disk-utils/cfdisk.8 b/disk-utils/cfdisk.8 deleted file mode 100644 index c7ac94171..000000000 --- a/disk-utils/cfdisk.8 +++ /dev/null @@ -1,403 +0,0 @@ -.\" cfdisk.8 -- man page for cfdisk -.\" Copyright 1994 Kevin E. Martin (martin@cs.unc.edu) -.\" -.\" Permission is granted to make and distribute verbatim copies of this -.\" manual provided the copyright notice and this permission notice are -.\" preserved on all copies. -.\" -.\" Permission is granted to copy and distribute modified versions of this -.\" manual under the conditions for verbatim copying, provided that the -.\" entire resulting derived work is distributed under the terms of a -.\" permission notice identical to this one. -.\" -.\" " for hilit mode -.TH CFDISK 8 "3 June 1995" "The BOGUS Linux Release" "Linux Programmer's Manual" -.SH NAME -cfdisk \- Curses based disk partition table manipulator for Linux -.SH SYNOPSIS -.BI "cfdisk [ \-avz ] [ \-c " cylinders " ] [ \-h " heads " ]" -.BI "[ \-s " sectors-per-track " ] [ -P " opt " ] [ " device " ]" -.SH DESCRIPTION -.B cfdisk -is a curses based program for partitioning a hard disk drive. The -.I device -can be any one of the following: -.sp -.nf -.RS -/dev/hda [default] -/dev/hdb -/dev/sda -/dev/sdb -/dev/sdc -/dev/sdd -.RE -.fi - -.B cfdisk -first tries to read the geometry of the hard disk. If it fails, an -error message is displayed and -.B cfdisk -exits. This should only happen when partitioning a SCSI drive on an -adapter without a BIOS. To correct this problem, you can set the -.IR cylinders ", " heads " and " sectors-per-track -on the command line. Next, -.B cfdisk -tries to read the current partition table from the disk drive. If it -is unable to figure out the partition table, an error is displayed and -the program will exit. This might also be caused by incorrect -geometry information, and can be overridden on the command line. -Another way around this problem is with the -.B \-z -option. This will ignore the partition table on the disk. - -The main display is composed of four sections, from top to bottom: the -header, the partitions, the command line and a warning line. The -header contains the program name and version number followed by the -disk drive and its geometry. The partitions section always displays -the current partition table. The command line is the place where -commands and text are entered. The available commands are usually -displayed in brackets. The warning line is usually empty except when -there is important information to be displayed. The current partition -is highlighted with reverse video (or an arrow if the -.B \-a -option is given). All partition specific commands apply to the -current partition. - -The format of the partition table in the partitions section is, from -left to right: Name, Flags, Partition Type, Filesystem Type and Size. -The name is the partition device name. The flags can be -.IR Boot , -which designates a bootable partition or -.IR NC , -which stands for "Not Compatible with DOS or OS/2". DOS, OS/2 and -possibly other operating systems require the first sector of the first -partition on the disk and all logical partitions to begin on the -second head. This wastes the second through the last sector of the -first track of the first head (the first sector is taken by the -partition table itself). -.B cfdisk -allows you to recover these "lost" sectors with the maximize command -.RB ( m ). -.I Note: -.BR fdisk (8) -and some early versions of DOS create all partitions with the number -of sectors already maximized. For more information, see the maximize -command below. The partition type can be one of -.IR Primary " or " Logical . -For unallocated space on the drive, the partition type can also be -.IR Pri/Log , -or empty (if the space is unusable). The filesystem type section -displays the name of the filesystem used on the partition, if known. -If it is unknown, then -.I Unknown -and the hex value of the filesystem type are displayed. A special -case occurs when there are sections of the disk drive that cannot be -used (because all of the primary partitions are used). When this is -detected, the filesystem type is displayed as -.IR Unusable . -The size field displays the size of the partition in megabytes (by -default). It can also display the size in sectors and cylinders (see -the change units command below). If an asterisks -.RB ( * ) -appears after the size, this means that the partition is not aligned -on cylinder boundaries. -.SH "DOS 6.x WARNING" - -The DOS 6.x FORMAT command looks for some information in the first -sector of the data area of the partition, and treats this information -as more reliable than the information in the partition table. DOS -FORMAT expects DOS FDISK to clear the first 512 bytes of the data area -of a partition whenever a size change occurs. DOS FORMAT will look at -this extra information even if the /U flag is given -- we consider -this a bug in DOS FORMAT and DOS FDISK. - -The bottom line is that if you use cfdisk or fdisk to change the size of a -DOS partition table entry, then you must also use -.B dd -to zero the first 512 bytes of that partition before using DOS FORMAT to -format the partition. For example, if you were using cfdisk to make a DOS -partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk -and rebooting Linux so that the partition table information is valid) you -would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero -the first 512 bytes of the partition. 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 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. - -.SH COMMANDS -.B cfdisk -commands can be entered by pressing the desired key (pressing -.I Enter -after the command is not necessary). Here is a list of the available -commands: -.TP -.B b -Toggle bootable flag of the current partition. This allows you to -select which primary partition is bootable on the drive. -.TP -.B d -Delete the current partition. This will convert the current partition -into free space and merge it with any free space immediately -surrounding the current partition. A partition already marked as free -space or marked as unusable cannot be deleted. -.TP -.B g -Change the disk geometry (cylinders, heads, or sectors-per-track). -.B WARNING: -This option should only be used by people who know what they are -doing. A command line option is also available to change the disk -geometry. While at the change disk geometry command line, you can -choose to change cylinders -.RB ( c ), -heads -.RB ( h ), -and sectors per track -.RB ( s ). -The default value will be printed at the prompt which you can accept -by simply pressing the -.I Enter -key, or you can exit without changes by pressing the -.I ESC -key. If you want to change the default value, simply enter the -desired value and press -.IR Enter . -The altered disk parameter values do not take effect until you return -the main menu (by pressing -.IR Enter " or " ESC -at the change disk geometry command line. If you change the geometry -such that the disk appears larger, the extra sectors are added at the -end of the disk as free space. If the disk appears smaller, the -partitions that are beyond the new last sector are deleted and the -last partition on the drive (or the free space at the end of the -drive) is made to end at the new last sector. -.TP -.B h -Print the help screen. -.TP -.B m -Maximize disk usage of the current partition. This command will -recover the the unused space between the partition table and the -beginning of the partition, but at the cost of making the partition -incompatible with DOS, OS/2 and possibly other operating systems. -This option will toggle between maximal disk usage and DOS, OS/2, -etc. compatible disk usage. The default when creating a partition is -to create DOS, OS/2, etc. compatible partitions. -.TP -.B n -Create new partition from free space. If the partition type is -.IR Primary " or " Logical , -a partition of that type will be created, but if the partition type is -.IR Pri/Log , -you will be prompted for the type you want to create. Be aware that -(1) there are only four slots available for primary partitions and (2) -since there can be only one extended partition, which contains all of -the logical drives, all of the logical drives must be contiguous (with -no intervening primary partition). -.B cfdisk -next prompts you for the size of the partition you want to create. -The default size, equal to the entire free space of the current -partition, is display in megabytes. You can either press the -.I Enter -key to accept the default size or enter a different size at the -prompt. -.B cfdisk -accepts size entries in megabytes -.RB ( M ) -[default], kilobytes -.RB ( K ), -cylinders -.RB ( C ) -and sectors -.RB ( S ) -by entering the number immediately followed by one of -.RB ( M ", " K ", " C " or " S ). -If the partition fills the free space available, the partition is -created and you are returned to the main command line. Otherwise, the -partition can be created at the beginning or the end of the free -space, and -.B cfdisk -will ask you to choose where to place the partition. After the -partition is created, -.B cfdisk -automatically adjusts the other partition's partition types if all of -the primary partitions are used. -.TP -.B p -Print the partition table to the screen or to a file. There are -several different formats for the partition that you can choose from: -.sp -.RS -.TP -.B r -Raw data format (exactly what would be written to disk) -.TP -.B s -Partition table in sector order format -.TP -.B t -Partition table in raw format -.RE - -.RS -The -.I raw data format -will print the sectors that would be written to disk if a -.BR w rite -command is selected. First, the primary partition table is printed, -followed by the partition tables associated with each logical -partition. The data is printed in hex byte by byte with 16 bytes per -line. - -The -.I partition table in sector order format -will print the partition table ordered by sector number. The fields, -from left to right, are the number of the partition, the partition -type, the first sector, the last sector, the offset from the first -sector of the partition to the start of the data, the length of the -partition, the filesystem type (with the hex value in parenthesis), -and the flags (with the hex value in parenthesis). In addition to the -primary and logical partitions, free and unusable space is printed and -the extended partition is printed before the first logical partition. - -If a partition does not start or end on a cylinder boundary or if the -partition length is not divisible by the cylinder size, an asterisks -.RB ( * ) -is printed after the non-aligned sector number/count. This usually -indicates that a partition was created by an operating system that -either does not align partitions to cylinder boundaries or that used -different disk geometry information. If you know the disk geometry of -the other operating system, you could enter the geometry information -with the change geometry command -.RB ( g ). - -For the first partition on the disk and for all logical partitions, if -the offset from the beginning of the partition is not equal to the -number of sectors per track (i.e., the data does not start on the -first head), a number sign -.RB ( # ) -is printed after the offset. For the remaining partitions, if the -offset is not zero, a number sign will be printed after the offset. -This corresponds to the -.I NC -flag in the partitions section of the main display. - -The -.I partition table in raw format -will print the partition table ordered by partition number. It will -leave out all free and unusable space. The fields, from left to -right, are the number of the partition, the flags (in hex), the -starting head, sector and cylinder, the filesystem ID (in hex), the -ending head, sector and cylinder, the starting sector in the partition -and the number of sectors in the partition. The information in this -table can be directly translated to the -.IR "raw data format" . - -The partition table entries only have 10 bits available to represent -the starting and ending cylinders. Thus, when the absolute starting -(ending) sector number is on a cylinder greater than 1023, the maximal -values for starting (ending) head, sector and cylinder are printed. -This is the method used by OS/2, and thus fixes the problems -associated with OS/2's fdisk rewriting the partition table when it is -not in this format. Since Linux and OS/2 use absolute sector counts, -the values in the starting and ending head, sector and cylinder are -not used. -.RE -.TP -.B q -Quit program. This will exit the program without writing any data to -disk. -.TP -.B t -Change the filesystem type. By default, new partitions are created as -.I Linux -partitions, but since -.B cfdisk -can create partitions for other operating systems, change partition -type allows you to enter the hex value of the filesystem you desire. -A list of the know filesystem types is displayed. You can type in the -filesystem type at the prompt or accept the default filesystem type -.RI [ Linux ]. -.TP -.B u -Change units of the partition size display. It will rotate through -megabytes, sectors and cylinders. -.TP -.B W -Write partition table to disk (must enter an upper case W). Since -this might destroy data on the disk, you must either confirm or deny -the write by entering `yes' or `no'. If you enter `yes', -.B cfdisk -will write the partition table to disk and the tell the kernel to -re-read the partition table from the disk. The re-reading of the -partition table works is most cases, but I have seen it fail. Don't -panic. It will be correct after you reboot the system. In all cases, -I still recommend rebooting the system--just to be safe. -.TP -.I Up Arrow -.TP -.I Down Arrow -Move cursor to the previous or next partition. If there are more -partitions than can be displayed on a screen, you can display the next -(previous) set of partitions by moving down (up) at the last (first) -partition displayed on the screen. -.TP -.I CTRL-L -Redraws the screen. In case something goes wrong and you cannot read -anything, you can refresh the screen from the main command line. -.TP -.B ? -Print the help screen. - -.RE -All of the commands can be entered with either upper or lower case -letters (except for -.BR W rites). -When in a sub-menu or at a prompt to enter a filename, you can hit the -.I ESC -key to return to the main command line. -.SH OPTIONS -.TP -.B \-a -Use an arrow cursor instead of reverse video for highlighting the -current partition. -.TP -.B \-v -Print the version number and copyright. -.TP -.B \-z -Start with zeroed partition table. This option is useful when you -want to repartition your entire disk. -.I Note: -this option does not zero the partition table on the disk; rather, it -simply starts the program without reading the existing partition -table. -.TP -.BI \-c " cylinders" -.TP -.BI \-h " heads" -.TP -.BI \-s " sectors-per-track" -Override the number of cylinders, heads and sectors per track read -from the BIOS. If your BIOS or adapter does not supply this -information or if it supplies incorrect information, use these options -to set the disk geometry values. -.TP -.BI \-P " opt" -Prints the partition table in specified formats. -.I opt -can be one or more of "r", "s" or "t". See the -.BR p rint -command (above) for more information on the print formats. -.SH "SEE ALSO" -fdisk(8) -.SH BUGS -The current version does not support multiple disks (future addition). -.SH AUTHOR -Kevin E. Martin (martin@cs.unc.edu) diff --git a/disk-utils/cfdisk.8.bak b/disk-utils/cfdisk.8.bak deleted file mode 100644 index cb23149fb..000000000 --- a/disk-utils/cfdisk.8.bak +++ /dev/null @@ -1,407 +0,0 @@ -.\" cfdisk.8 -- man page for cfdisk -.\" Copyright 1994 Kevin E. Martin (martin@cs.unc.edu) -.\" -.\" Permission is granted to make and distribute verbatim copies of this -.\" manual provided the copyright notice and this permission notice are -.\" preserved on all copies. -.\" -.\" Permission is granted to copy and distribute modified versions of this -.\" manual under the conditions for verbatim copying, provided that the -.\" entire resulting derived work is distributed under the terms of a -.\" permission notice identical to this one. -.\" -.\" " for hilit mode -.TH CFDISK 8 "25 April 1994" "The BOGUS Linux Release" "Linux Programmer's Manual" -.SH NAME -cfdisk \- Curses based disk partition table manipulator for Linux -.SH SYNOPSIS -.BI "cfdisk [ \-avz ] [ \-c " cylinders " ] [ \-h " heads " ]" -.BI "[ \-s " sectors-per-track " ] [ -P " opt " ] [ " device " ]" -.SH DESCRIPTION -.B cfdisk -is a curses based program for partitioning a hard disk drive. The -.I device -can be any one of the following: -.sp -.nf -.RS -/dev/hda [default] -/dev/hdb -/dev/sda -/dev/sdb -/dev/sdc -/dev/sdd -.RE -.fi - -.B cfdisk -first tries to read the geometry of the hard disk. If it fails, an -error message is displayed and -.B cfdisk -exits. This should only happen when partitioning a SCSI drive on an -adapter without a BIOS. To correct this problem, you can set the -.IR cylinders ", " heads " and " sectors-per-track -on the command line. Next, -.B cfdisk -tries to read the current partition table from the disk drive. If it -is unable to figure out the partition table, an error is displayed and -the program will exit. This might also be caused by incorrect -geometry information, and can be overridden on the command line. -Another way around this problem is with the -.B \-z -option. This will ignore the partition table on the disk. - -The main display is composed of four sections, from top to bottom: the -header, the partitions, the command line and a warning line. The -header contains the program name and version number followed by the -disk drive and its geometry. The partitions section always displays -the current partition table. The command line is the place where -commands and text are entered. The available commands are usually -displayed in brackets. The warning line is usually empty except when -there is important information to be displayed. The current partition -is highlighted with reverse video (or an arrow if the -.B \-a -option is given). All partition specific commands apply to the -current partition. - -The format of the partition table in the partitions section is, from -left to right: Name, Flags, Partition Type, Filesystem Type and Size. -The name is the partition device name. The flags can be -.IR Boot , -which designates a bootable partition or -.IR NC , -which stands for "Not Compatible with DOS or OS/2". DOS, OS/2 and -possibly other operating systems require the first sector of the first -partition on the disk and all logical partitions to begin on the -second head. This wastes the second through the last sector of the -first track of the first head (the first sector is taken by the -partition table itself). -.B cfdisk -allows you to recover these "lost" sectors with the maximize command -.RB ( m ). -.I Note: -.BR fdisk (8) -and some early versions of DOS create all partitions with the number -of sectors already maximized. For more information, see the maximize -command below. The partition type can be one of -.IR Primary " or " Logical . -For unallocated space on the drive, the partition type can also be -.IR Pri/Log , -or empty (if the space is unusable). The filesystem type section -displays the name of the filesystem used on the partition, if known. -If it is unknown, then -.I Unknown -and the hex value of the filesystem type are displayed. A special -case occurs when there are sections of the disk drive that cannot be -used (because all of the primary partitions are used). When this is -detected, the filesystem type is displayed as -.IR Unusable . -The size field displays the size of the partition in megabytes (by -default). It can also display the size in sectors and cylinders (see -the change units command below). If an asterisks -.RB ( * ) -appears after the size, this means that the partition is not aligned -on cylinder boundaries. -.SH "DOS 6.x WARNING" - -The DOS 6.x FORMAT command looks for some information in the first -sector of the data area of the partition, and treats this information -as more reliable than the information in the partition table. DOS -FORMAT expects DOS FDISK to clear the first 512 bytes of the data area -of a partition whenever a size change occurs. DOS FORMAT will look at -this extra information even if the /U flag is given -- we consider -this a bug in DOS FORMAT and DOS FDISK. - -The bottom line is that if you use cfdisk or fdisk to change the size of a -DOS partition table entry, then you must also use -.B dd -to zero the first 512 bytes of that partition before using DOS FORMAT to -format the partition. For example, if you were using cfdisk to make a DOS -partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk -and rebooting Linux so that the partition table information is valid) you -would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero -the first 512 bytes of the partition. -.B BE EXTREMELY CAREFUL -if you use the -.B dd -command, since a small typo can make all of the data on your disk useless. - -.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 -program. For example, you should make DOS partitions with the DOS FDISK -program and Linux partitions with the Linux fdisk or Linux cfdisk program. - -.SH COMMANDS -.B cfdisk -commands can be entered by pressing the desired key (pressing -.I Enter -after the command is not necessary). Here is a list of the available -commands: -.TP -.B b -Toggle bootable flag of the current partition. This allows you to -select which primary partition is bootable on the drive. -.TP -.B d -Delete the current partition. This will convert the current partition -into free space and merge it with any free space immediately -surrounding the current partition. A partition already marked as free -space or marked as unusable cannot be deleted. -.TP -.B g -Change the disk geometry (cylinders, heads, or sectors-per-track). -.B WARNING: -This option should only be used by people who know what they are -doing. A command line option is also available to change the disk -geometry. While at the change disk geometry command line, you can -choose to change cylinders -.RB ( c ), -heads -.RB ( h ), -and sectors per track -.RB ( s ). -The default value will be printed at the prompt which you can accept -by simply pressing the -.I Enter -key, or you can exit without changes by pressing the -.I ESC -key. If you want to change the default value, simply enter the -desired value and press -.IR Enter . -The altered disk parameter values do not take effect until you return -the main menu (by pressing -.IR Enter " or " ESC -at the change disk geometry command line. If you change the geometry -such that the disk appears larger, the extra sectors are added at the -end of the disk as free space. If the disk appears smaller, the -partitions that are beyond the new last sector are deleted and the -last partition on the drive (or the free space at the end of the -drive) is made to end at the new last sector. -.TP -.B h -Print the help screen. -.TP -.B m -Maximize disk usage of the current partition. This command will -recover the the unused space between the partition table and the -beginning of the partition, but at the cost of making the partition -incompatible with DOS, OS/2 and possibly other operating systems. -This option will toggle between maximal disk usage and DOS, OS/2, -etc. compatible disk usage. The default when creating a partition is -to create DOS, OS/2, etc. compatible partitions. -.TP -.B n -Create new partition from free space. If the partition type is -.IR Primary " or " Logical , -a partition of that type will be created, but if the partition type is -.IR Pri/Log , -you will be prompted for the type you want to create. Be aware that -(1) there are only four slots available for primary partitions and (2) -since there can be only one extended partition, which contains all of -the logical drives, all of the logical drives must be contiguous (with -no intervening primary partition). -.B cfdisk -next prompts you for the size of the partition you want to create. -The default size, equal to the entire free space of the current -partition, is display in megabytes. You can either press the -.I Enter -key to accept the default size or enter a different size at the -prompt. -.B cfdisk -accepts size entries in megabytes -.RB ( M ) -[default], kilobytes -.RB ( K ), -cylinders -.RB ( C ) -and sectors -.RB ( S ) -by entering the number immediately followed by one of -.RB ( M ", " K ", " C " or " S ). -If the partition fills the free space available, the partition is -created and you are returned to the main command line. Otherwise, the -partition can be created at the beginning or the end of the free -space, and -.B cfdisk -will ask you to choose where to place the partition. After the -partition is created, -.B cfdisk -automatically adjusts the other partition's partition types if all of -the primary partitions are used. -.TP -.B p -Print the partition table to the screen or to a file. There are -several different formats for the partition that you can choose from: -.sp -.RS -.TP -.B r -Raw data format (exactly what would be written to disk) -.TP -.B s -Partition table in sector order format -.TP -.B t -Partition table in raw format -.RE - -.RS -The -.I raw data format -will print the sectors that would be written to disk if a -.BR w rite -command is selected. First, the primary partition table is printed, -followed by the partition tables associated with each logical -partition. The data is printed in hex byte by byte with 16 bytes per -line. - -The -.I partition table in sector order format -will print the partition table ordered by sector number. The fields, -from left to right, are the number of the partition, the partition -type, the first sector, the last sector, the offset from the first -sector of the partition to the start of the data, the length of the -partition, the filesystem type (with the hex value in parenthesis), -and the flags (with the hex value in parenthesis). In addition to the -primary and logical partitions, free and unusable space is printed and -the extended partition is printed before the first logical partition. - -If a partition does not start or end on a cylinder boundary or if the -partition length is not divisible by the cylinder size, an asterisks -.RB ( * ) -is printed after the non-aligned sector number/count. This usually -indicates that a partition was created by an operating system that -either does not align partitions to cylinder boundaries or that used -different disk geometry information. If you know the disk geometry of -the other operating system, you could enter the geometry information -with the change geometry command -.RB ( g ). - -For the first partition on the disk and for all logical partitions, if -the offset from the beginning of the partition is not equal to the -number of sectors per track (i.e., the data does not start on the -first head), a number sign -.RB ( # ) -is printed after the offset. For the remaining partitions, if the -offset is not zero, a number sign will be printed after the offset. -This corresponds to the -.I NC -flag in the partitions section of the main display. - -The -.I partition table in raw format -will print the partition table ordered by partition number. It will -leave out all free and unusable space. The fields, from left to -right, are the number of the partition, the flags (in hex), the -starting head, sector and cylinder, the filesystem ID (in hex), the -ending head, sector and cylinder, the starting sector in the partition -and the number of sectors in the partition. The information in this -table can be directly translated to the -.IR "raw data format" . - -The partition table entries only have 10 bits available to represent -the starting and ending cylinders. Thus, when the absolute starting -(ending) sector number is on a cylinder greater than 1023, the maximal -values for starting (ending) head, sector and cylinder are printed. -This is the method used by OS/2, and thus fixes the problems -associated with OS/2's fdisk rewriting the partition table when it is -not in this format. Since Linux and OS/2 use absolute sector counts, -the values in the starting and ending head, sector and cylinder are -not used. -.RE -.TP -.B q -Quit program. This will exit the program without writing any data to -disk. -.TP -.B t -Change the filesystem type. By default, new partitions are created as -.I Linux -partitions, but since -.B cfdisk -can create partitions for other operating systems, change partition -type allows you to enter the hex value of the filesystem you desire. -A list of the know filesystem types is displayed. You can type in the -filesystem type at the prompt or accept the default filesystem type -.RI [ Linux ]. -.TP -.B u -Change units of the partition size display. It will rotate through -megabytes, sectors and cylinders. -.TP -.B W -Write partition table to disk (must enter an upper case W). Since -this might destroy data on the disk, you must either confirm or deny -the write by entering `yes' or `no'. If you enter `yes', -.B cfdisk -will write the partition table to disk and the tell the kernel to -re-read the partition table from the disk. The re-reading of the -partition table works is most cases, but I have seen it fail. Don't -panic. It will be correct after you reboot the system. In all cases, -I still recommend rebooting the system--just to be safe. -.TP -.I Up Arrow -.TP -.I Down Arrow -Move cursor to the previous or next partition. If there are more -partitions than can be displayed on a screen, you can display the next -(previous) set of partitions by moving down (up) at the last (first) -partition displayed on the screen. -.TP -.I CTRL-L -Redraws the screen. In case something goes wrong and you cannot read -anything, you can refresh the screen from the main command line. -.TP -.B ? -Print the help screen. - -.RE -All of the commands can be entered with either upper or lower case -letters (except for -.BR W rites). -When in a sub-menu or at a prompt to enter a filename, you can hit the -.I ESC -key to return to the main command line. -.SH OPTIONS -.TP -.B \-a -Use an arrow cursor instead of reverse video for highlighting the -current partition. -.TP -.B \-v -Print the version number and copyright. -.TP -.B \-z -Start with zeroed partition table. This option is useful when you -want to repartition your entire disk. -.I Note: -this option does not zero the partition table on the disk; rather, it -simply starts the program without reading the existing partition -table. -.TP -.BI \-c " cylinders" -.TP -.BI \-h " heads" -.TP -.BI \-s " sectors-per-track" -Override the number of cylinders, heads and sectors per track read -from the BIOS. If your BIOS or adapter does not supply this -information or if it supplies incorrect information, use these options -to set the disk geometry values. -.TP -.BI \-P " opt" -Prints the partition table in specified formats. -.I opt -can be one or more of "r", "s" or "t". See the -.BR p rint -command (above) for more information on the print formats. -.SH "SEE ALSO" -fdisk(8) -.SH BUGS -The current version does not support multiple disks (future addition). -.SH AUTHOR -Kevin E. Martin (martin@cs.unc.edu) diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c deleted file mode 100644 index f0b5482f1..000000000 --- a/disk-utils/cfdisk.c +++ /dev/null @@ -1,2560 +0,0 @@ -/**************************************************************************** - * - * CFDISK - * - * cfdisk is a curses based disk drive partitioning program that can - * create partitions for a wide variety of operating systems including - * Linux, MS-DOS and OS/2. - * - * cfdisk was inspired by the fdisk program, by A. V. Le Blanc - * (LeBlanc@mcc.ac.uk). - * - * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) - * - * cfdisk 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. - * - * cfdisk 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 cfdisk; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu - * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu - * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto - * - * Versions 0.8e-l: aeb@cwi.nl - * Recognition of NTFS / HPFS difference inspired by patches - * from Marty Leisner - * - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef SLCURSES - #include -#else -#if NCH - #include -#else - #include -#endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for BLKRRPART */ - -#if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long ext2_loff_t; -#else -typedef long ext2_loff_t; -#endif - -extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, - unsigned int origin); - -#define VERSION "0.8l" - -#define DEFAULT_DEVICE "/dev/hda" -#define ALTERNATE_DEVICE "/dev/sda" - -#define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 - -#define SECTOR_SIZE 512 - -#define MAX_CYLINDERS 65535 -#define MAX_HEADS 255 -#define MAX_SECTORS 63 - -#define ACTIVE_FLAG 0x80 -#define PART_TABLE_FLAG 0xAA55 - -#define UNUSABLE -1 -#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 ADD_EXISTS "This partition is already in use" -#define ADD_UNUSABLE "This partition is unusable" -#define DEL_EMPTY "Cannot delete an empty partition" -#define ID_EMPTY "Cannot change FS Type to empty" -#define ID_EXT "Cannot change FS Type to extended" -#define NEED_EXT "No room to create the extended partition" -#define NO_FLAGS "Cannot make this partition bootable" -#define NO_MORE_PARTS "No more partitions" -#define PRINT_OPEN_ERR "Cannot open file '%s'" -#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" -#define TYPE_EMPTY "Cannot change the type of an empty partition" -#define BAD_COMMAND "Illegal command" -#define MAX_UNMAXABLE "Cannot maximize this partition" -#define BAD_OPEN "Cannot open disk drive" -#define BAD_SEEK "Cannot seek on disk drive" -#define BAD_READ "Cannot read disk drive" -#define BAD_WRITE "Cannot write disk drive" -#define BAD_GEOMETRY "Cannot read disk drive geometry" -#define BAD_PRIMARY "Bad primary partition" -#define BAD_LOGICAL "Bad logical partition" -#define BAD_CYLINDERS "Illegal cylinders value" -#define BAD_HEADS "Illegal heads value" -#define BAD_SECTORS "Illegal sectors value" -#define READONLY_WARN "Opened disk read-only - you have no permission to write" -#define WRITE_WARN "Warning!! This may destroy data on your disk!" -#define YES_NO "Please enter `yes' or `no'" -#define WRITING_PART "Writing partition table to disk..." -#define YES_WRITE "Wrote partition table to disk" -#define NO_WRITE "Did not write partition table to disk" -#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." - -#define PRI_OR_LOG -1 -#define PRIMARY -2 -#define LOGICAL -3 - -#define COL_ID_WIDTH 20 - -#define CR '\015' -#define ESC '\033' -#define DEL '\177' -#define BELL '\007' -/* '\014' == ^L */ -#define REDRAWKEY '\014' - -/* Display units */ -#define MEGABYTES 1 -#define SECTORS 2 -#define CYLINDERS 3 - -#define GS_DEFAULT -1 -#define GS_ESCAPE -2 - -#define PRINT_RAW_TABLE 1 -#define PRINT_SECTOR_TABLE 2 -#define PRINT_PARTITION_TABLE 4 - -#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) -#define IS_LOGICAL(p) ((p) > 3) - -#define round_int(d) ((double)((int)(d+0.5))) -#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) - -#define set_hsc(h,s,c,sector) \ -{ \ - s = sector % sectors + 1; \ - sector /= sectors; \ - h = sector % heads; \ - sector /= heads; \ - c = sector & 0xFF; \ - s |= (sector >> 2) & 0xC0;\ -} - -#define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \ - (x) == LINUX_EXTENDED) - -#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 { - struct { - unsigned char align[ALIGNMENT]; - unsigned char b[SECTOR_SIZE]; - } c; - struct { - unsigned char align[ALIGNMENT]; - unsigned char buffer[0x1BE]; - struct partition part[4]; - unsigned short flag; - } p; -} partition_table; - -typedef struct { - int first_sector; /* first sector in partition */ - int last_sector; /* last sector in partition */ - int offset; /* offset from first sector to start of data */ - int flags; /* active == 0x80 */ - int id; /* filesystem type */ - int num; /* number of partition -- primary vs. logical */ -#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; -int fd; -int heads = 0; -int sectors = 0; -int cylinders = 0; -int changed = FALSE; -int opened = FALSE; -int opentype; -int curses_started = 0; - -partition_info p_info[MAXIMUM_PARTS]; -partition_info ext_info; -int num_parts = 0; - -int logical = 0; -int logical_sectors[MAXIMUM_PARTS]; - -__sighandler_t old_SIGINT, old_SIGTERM; - -int arrow_cursor = FALSE; -int display_units = MEGABYTES; -int zero_table = FALSE; -int print_only = 0; - -/* Curses screen information */ -int cur_part = 0; -int warning_last_time = FALSE; -int defined = FALSE; -int COLUMNS = 80; -int NUM_ON_SCREEN = 1; - -/* Y coordinates */ -int HEADER_START = 0; -int DISK_TABLE_START = 5; -int WARNING_START = 23; -int COMMAND_LINE_Y = 21; - -/* X coordinates */ -int NAME_START = 4; -int FLAGS_START = 16; -int PTYPE_START = 28; -int FSTYPE_START = 38; -int LABEL_START = 54; -int SIZE_START = 70; -int COMMAND_LINE_X = 5; - -#define NUM_PART_TYPES 256 -char *partition_type[NUM_PART_TYPES] = { - [LINUX_MINIX] = "Linux/MINIX", - [LINUX_SWAP] = "Linux Swap", - [LINUX] = "Linux", - [FREE_SPACE] = "Free Space", - [DOS_EXTENDED]= "Extended", - [LINUX_EXTENDED] = "Linux extended", - [0x01] = "DOS FAT12", - [0x02] = "XENIX root", - [0x03] = "XENIX usr", - [0x04] = "DOS FAT16", - [0x06] = "DOS FAT16 (big)", - [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)", - [0x0E] = "Win95 FAT16 (LBA)", - [0x0F] = "Win95 Extended (LBA)", - [0x11] = "Hidden DOS FAT12", - [0x14] = "Hidden DOS FAT16", - [0x16] = "Hidden DOS FAT16 (big)", - [0x17] = "Hidden OS/2 HPFS or NTFS", - [0x40] = "Venix 80286", - [0x51] = "Novell?", - [0x52] = "Microport", - [0x63] = "GNU HURD", - [0x64] = "Novell Netware 286", - [0x65] = "Novell Netware 386", - [0x75] = "PC/IX", - [0x80] = "Old MINIX", - [0x93] = "Amoeba", - [0x94] = "Amoeba BBT", - [0xA5] = "BSD/386", - [0xA6] = "OpenBSD", - [0xA7] = "NEXTSTEP", - [0xB7] = "BSDI fs", - [0xB8] = "BSDI swap", - [0xC7] = "Syrinx", - [0xDB] = "CP/M", - [0xE1] = "DOS access", - [0xE3] = "DOS R/O", - [0xF2] = "DOS secondary", - [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) - close(fd); - - if (changed) { - fprintf(stderr, "Disk has been changed.\n"); - fprintf(stderr, "Reboot the system to ensure the partition " - "table is correctly updated.\n"); - - fprintf( stderr, "\nWARNING: If you have created or modified any\n" - "DOS 6.x partitions, please see the cfdisk manual\n" - "page for additional information.\n" ); - } - - exit(ret); -} - -int get_string(char *str, int len, char *def) -{ - char c; - int i = 0; - int x, y; - int use_def = FALSE; - - getyx(stdscr, y, x); - clrtoeol(); - - str[i] = 0; - - if (def != NULL) { - mvaddstr(y, x, def); - move(y, x); - use_def = TRUE; - } - - refresh(); - while ((c = getch()) != '\n' && c != CR) { - switch (c) { - case ESC: - move(y, x); - clrtoeol(); - refresh(); - return GS_ESCAPE; - case DEL: - case '\b': - if (i > 0) { - str[--i] = 0; - mvaddch(y, x+i, ' '); - move(y, x+i); - } else if (use_def) { - clrtoeol(); - use_def = FALSE; - } else - putchar(BELL); - break; - default: - if (i < len && isprint(c)) { - mvaddch(y, x+i, c); - if (use_def) { - clrtoeol(); - use_def = FALSE; - } - str[i++] = c; - str[i] = 0; - } else - putchar(BELL); - } - refresh(); - } - - if (use_def) - return GS_DEFAULT; - else - return i; -} - -void clear_warning(void) -{ - int i; - - if (!curses_started || !warning_last_time) - return; - - move(WARNING_START,0); - for (i = 0; i < COLS; i++) - addch(' '); - - warning_last_time = FALSE; -} - -void print_warning(char *s) -{ - if (!curses_started) { - fprintf(stderr, "%s\n", s); - } else { - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ - - warning_last_time = TRUE; - } -} - -void die_x(int ret); - -void fatal(char *s) -{ - char str[LINE_LENGTH]; - - if (curses_started) { - sprintf(str, "FATAL ERROR: %s", s); - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "Press any key to exit fdisk"); - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - refresh(); - (void)getch(); - die_x(1); - } else { - fprintf(stderr, "FATAL ERROR: %s\n", s); - exit(1); - } -} - -void die(int dummy) -{ - die_x(0); -} - -void die_x(int ret) -{ - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); -#ifdef SLCURSES - SLsmg_gotorc(LINES-1, 0); - SLsmg_refresh(); -#else - mvcur(0, COLS-1, LINES-1, 0); -#endif - nl(); - endwin(); - printf("\n"); - fdexit(ret); -} - -void read_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_READ); -} - -void write_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_WRITE); -} - -void dos_copy_to_info(char *to, int tosz, char *from, int fromsz) { - int i; - - for(i=0; i 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (is_extended(ext_info.id)) - if (log > 0) - pri++; - else { - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; - } - - if (pri >= 4) { - for (i = 0; i < num_parts; i++) - if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) - if (is_extended(ext_info.id)) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else - p_info[i].id = UNUSABLE; - else /* if (!is_extended(ext_info.id)) */ - p_info[i].id = UNUSABLE; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } else { /* if (pri < 4) */ - for (i = 0; i < num_parts; i++) { - if (p_info[i].id == UNUSABLE) - p_info[i].id = FREE_SPACE; - if (p_info[i].id == FREE_SPACE) - if (is_extended(ext_info.id)) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) - p_info[i].num = LOGICAL; - else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else - p_info[i].num = PRIMARY; - else /* if (!is_extended(ext_info.id)) */ - p_info[i].num = PRI_OR_LOG; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } - } -} - -void remove_part(int i) -{ - int p; - - for (p = i; p < num_parts; p++) - p_info[p] = p_info[p+1]; - - num_parts--; -} - -void insert_empty_part(int i, int first, int last) -{ - int p; - - for (p = num_parts; p > i; p--) - p_info[p] = p_info[p-1]; - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - p_info[i].volume_label[0] = 0; - p_info[i].fstype[0] = 0; - p_info[i].ostype[0] = 0; - - num_parts++; -} - -void del_part(int i) -{ - int num = p_info[i].num; - - if (i > 0 && (p_info[i-1].id == FREE_SPACE || - p_info[i-1].id == UNUSABLE)) { - /* Merge with previous partition */ - p_info[i-1].last_sector = p_info[i].last_sector; - remove_part(i--); - } - - if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || - p_info[i+1].id == UNUSABLE)) { - /* Merge with next partition */ - p_info[i+1].first_sector = p_info[i].first_sector; - remove_part(i); - } - - if (i > 0) - p_info[i].first_sector = p_info[i-1].last_sector + 1; - else - p_info[i].first_sector = 0; - - if (i < num_parts - 1) - p_info[i].last_sector = p_info[i+1].first_sector - 1; - else - p_info[i].last_sector = sectors*heads*cylinders - 1; - - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - - if (IS_LOGICAL(num)) { - /* We have a logical partition --> shrink the extended partition - * if (1) this is the first logical drive, or (2) this is the - * last logical drive; and if there are any other logical drives - * then renumber the ones after "num". - */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) { - ext_info.first_sector = p_info[i].last_sector + 1; - ext_info.offset = 0; - } - if (i == num_parts-1 || - (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) - ext_info.last_sector = p_info[i].first_sector - 1; - for (i = 0; i < num_parts; i++) - if (p_info[i].num > num) - p_info[i].num--; - } - - /* Clean up the rest of the partitions */ - check_part_info(); -} - -int add_part(int num, int id, int flags, int first, int last, int offset, - int want_label) -{ - int i, pri = 0, log = 0; - - if (num_parts == MAXIMUM_PARTS || - first < 0 || - first >= cylinders*heads*sectors || - last < 0 || - last >= cylinders*heads*sectors) { - return -1; /* bad start or end */ - } - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (is_extended(ext_info.id) && log > 0) - pri++; - - if (IS_PRIMARY(num)) - if (pri >= 4) { - return -1; /* no room for more */ - } else - pri++; - - for (i = 0; i < num_parts && p_info[i].last_sector < first; i++); - - if (i == num_parts || p_info[i].id != FREE_SPACE - || last > p_info[i].last_sector) { - return -1; - } - - if (is_extended(id)) { - if (ext_info.id != FREE_SPACE) { - return -1; /* second extended */ - } - else if (IS_PRIMARY(num)) { - ext_info.first_sector = first; - ext_info.last_sector = last; - ext_info.offset = offset; - ext_info.flags = flags; - ext_info.id = id; - ext_info.num = num; - ext_info.volume_label[0] = 0; - ext_info.fstype[0] = 0; - ext_info.ostype[0] = 0; - return 0; - } else { - return -1; /* explicit extended logical */ - } - } - - if (IS_LOGICAL(num)) { - if (!is_extended(ext_info.id)) { - print_warning("!!!! Internal error creating logical " - "drive with no extended partition !!!!"); - } else { - /* We might have a logical partition outside of the extended - * partition's range --> we have to extend the extended - * partition's range to encompass this new partition, but we - * must make sure that there are no primary partitions between - * it and the closest logical drive in extended partition. - */ - if (first < ext_info.first_sector) { - if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else { - if (first == 0) { - ext_info.first_sector = 0; - ext_info.offset = first = offset; - } else { - ext_info.first_sector = first; - } - } - } else if (last > ext_info.last_sector) { - if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else { - ext_info.last_sector = last; - } - } - } - } - - if (first != p_info[i].first_sector && - !(IS_LOGICAL(num) && first == offset)) { - insert_empty_part(i, p_info[i].first_sector, first-1); - i++; - } - - if (last != p_info[i].last_sector) - insert_empty_part(i+1, last+1, p_info[i].last_sector); - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - p_info[i].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(); - - return 0; -} - -int find_primary(void) -{ - int num = 0, cur = 0; - - while (cur < num_parts && IS_PRIMARY(num)) - if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (is_extended(ext_info.id) && ext_info.num == num)) { - num++; - cur = 0; - } else - cur++; - - if (!IS_PRIMARY(num)) - return -1; - else - return num; -} - -int find_logical(int i) -{ - int num = -1; - int j; - - for (j = i; j < num_parts && num == -1; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - num = p_info[j].num; - - if (num == -1) { - num = 4; - for (j = 0; j < num_parts; j++) - if (p_info[j].id > 0 && p_info[j].num == num) - num++; - } - - return num; -} - -void inc_logical(int i) -{ - int j; - - for (j = i; j < num_parts; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - p_info[j].num++; -} - -/* Command menu support by Janne Kukonlehto September 1994 */ - -/* Constants for menuType parameter of menuSelect function */ -#define MENU_HORIZ 1 -#define MENU_VERT 2 -#define MENU_ACCEPT_OTHERS 4 -#define MENU_BUTTON 8 -/* Miscellenous constants */ -#define MENU_SPACING 2 -#define MENU_MAX_ITEMS 256 /* for simpleMenu function */ -#define MENU_UP 1 -#define MENU_DOWN 2 -#define MENU_RIGHT 3 -#define MENU_LEFT 4 - -struct MenuItem -{ - char key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */ - char *name; /* Item name, should be eight characters with current implementation */ - char *desc; /* Item description to be printed when item is selected */ -}; - -/* Actual function which prints the button bar and highlights the active button * - * Should not be called directly. Call function menuSelect instead. */ - -int menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int current ) -{ - int i, lmargin = x, ymargin = y; - /* Print available buttons */ - move( y, x ); clrtoeol(); - for( i = 0; menuItems[i].key; i++ ) - { - char buff[20]; - int lenName; - /* Search next available button */ - while( menuItems[i].key && !strchr(available, menuItems[i].key) ) - { - i++; - } - if( !menuItems[i].key ) break; /* No more menu items */ - /* If selected item is not available and we have bypassed it, make current item selected */ - if( current < i && menuItems[current].key < 0 ) current = i; - /* If current item is selected, highlight it */ - if( current == i ) /*attron( A_REVERSE )*/ standout (); - /* Print item */ - lenName = strlen( menuItems[i].name ); - if(lenName > itemLength) - print_warning("Menu item too long. Menu may look odd."); - if( menuType & MENU_BUTTON ) - sprintf( buff, "[%*s%-*s]", (itemLength - lenName) / 2, "", - (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name ); - else - sprintf( buff, "%*s%-*s", (itemLength - lenName) / 2, "", - (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name ); - mvaddstr( y, x, buff ); - /* Lowlight after selected item */ - if( current == i ) /*attroff( A_REVERSE )*/ standend (); - /* Calculate position for the next item */ - if( menuType & MENU_VERT ) - { - y += 1; - if( y >= WARNING_START ) - { - y = ymargin; - x += itemLength + MENU_SPACING; - if( menuType & MENU_BUTTON ) x += 2; - } - } - else - { - x += itemLength + MENU_SPACING; - if( menuType & MENU_BUTTON ) x += 2; - if( x > COLUMNS - lmargin - 12 ) - { - x = lmargin; - y ++ ; - } - } - } - /* Print the description of selected item */ - mvaddstr( WARNING_START + 1, (COLUMNS - strlen( menuItems[current].desc )) / 2, menuItems[current].desc ); - return y; -} - -/* This function takes a list of menu items, lets the user choose one of them * - * and returns the value keyboard shortcut of the selected menu item */ - -int menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int menuDefault ) -{ - int i, ylast = y, key = 0, current = menuDefault; - if( !( menuType & ( MENU_HORIZ | MENU_VERT ) ) ) - { - print_warning("Menu without direction. Defaulting horizontal."); - menuType |= MENU_HORIZ; - } - /* Make sure that the current is one of the available items */ - while( !strchr(available, menuItems[current].key) ) - { - current ++ ; - if( !menuItems[current].key ) current = 0; - } - /* Repeat until allowable choice has been made */ - while( !key ) - { - /* Display the menu */ - ylast = menuUpdate( y, x, menuItems, itemLength, available, - menuType, current ); - refresh(); - key = getch(); - /* Clear out all prompts and such */ - clear_warning(); - for( i = y; i < ylast; i ++ ) - { - move( i, x ); - clrtoeol(); - } - move( WARNING_START + 1, 0 ); - clrtoeol(); - /* Cursor keys */ - if( key == ESC ) - { - /* Check whether this is a real ESC or one of extended keys */ - /*nodelay(stdscr, TRUE);*/ - key = getch(); - /*nodelay(stdscr, FALSE);*/ - if( key == /*ERR*/ ESC ) - { - /* This is a real ESC */ - key = ESC; - } - if( key == '[' ) - { - /* This is one extended keys */ - switch( getch() ) - { - case 'A': /* Up arrow */ - if( menuType & MENU_VERT ) - { - do { - current -- ; - if( current < 0 ) while( menuItems[current+1].key ) current ++ ; - } while( !strchr( available, menuItems[current].key ) ); - key = 0; - } - else - key = MENU_UP; - break; - case 'B': /* Down arrow */ - if( menuType & MENU_VERT ) - { - do { - current ++ ; - if( !menuItems[current].key ) current = 0 ; - } while( !strchr( available, menuItems[current].key ) ); - key = 0; - } - else - key = MENU_DOWN; - break; - case 'C': /* Right arrow */ - if( menuType & MENU_HORIZ ) - { - do { - current ++ ; - if( !menuItems[current].key ) - { - current = 0 ; - } - } while( !strchr( available, menuItems[current].key ) ); - key = 0; - } - else - key = MENU_RIGHT; - break; - case 'D': /* Left arrow */ - if( menuType & MENU_HORIZ ) - { - do { - current -- ; - if( current < 0 ) - { - while( menuItems[current + 1].key ) current ++ ; - } - } while( !strchr( available, menuItems[current].key ) ); - key = 0; - } - else - key = MENU_LEFT; - break; - } - } - } - /* Enter equals to the keyboard shortcut of current menu item */ - if( key == 13 ) - { - key = menuItems[current].key; - } - /* Should all keys to be accepted? */ - if( key && (menuType & MENU_ACCEPT_OTHERS) ) break; - /* Is pressed key among acceptable ones */ - if( key && (strchr(available, tolower(key)) || strchr(available, key)) ) break; - /* The key has not been accepted so far -> let's reject it */ - if( key ) - { - key = 0; - putchar( BELL ); - print_warning("Illegal key"); - } - } - /* Clear out prompts and such */ - clear_warning(); - for( i = y; i <= ylast; i ++ ) - { - move( i, x ); - clrtoeol(); - } - move( WARNING_START + 1, 0 ); - clrtoeol(); - 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? */ - -void menuContinue(void) -{ - static struct MenuItem menuContinueBtn[]= - { - { 'c', "", "Press a key to continue" }, - { 0, NULL, NULL } - }; - - menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, - menuContinueBtn, 0, "c", MENU_HORIZ | MENU_ACCEPT_OTHERS, 0 ); -} - -/* Function menuSelect takes way too many parameters * - * Luckily, most of time we can do with this function */ - -int menuSimple(struct MenuItem *menuItems, int menuDefault) -{ - int i, j, itemLength = 0; - char available[MENU_MAX_ITEMS]; - for(i = 0; menuItems[i].key; i++) - { - j = strlen( menuItems[i].name ); - if( j > itemLength ) itemLength = j; - available[i] = menuItems[i].key; - } - available[i] = 0; - return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength, - available, MENU_HORIZ | MENU_BUTTON, menuDefault); -} - -/* End of command menu support code */ - -void new_part(int i) -{ - char response[LINE_LENGTH], def[LINE_LENGTH]; - char c; - int first = p_info[i].first_sector; - int last = p_info[i].last_sector; - int offset = 0; - int flags = 0; - int id = LINUX; - int num = -1; - int num_sects = last - first + 1; - int len, ext, j; - - if (p_info[i].num == PRI_OR_LOG) { - static struct MenuItem menuPartType[]= - { - { 'p', "Primary", "Create a new primary partition" }, - { 'l', "Logical", "Create a new logical partition" }, - { ESC, "Cancel", "Don't create a partition" }, - { 0, NULL, NULL } - }; - - c = menuSimple( menuPartType, 0 ); - if (toupper(c) == 'P') - num = find_primary(); - else if (toupper(c) == 'L') - num = find_logical(i); - else - return; - } else if (p_info[i].num == PRIMARY) - num = find_primary(); - else if (p_info[i].num == LOGICAL) - num = find_logical(i); - else - print_warning("!!! Internal error !!!"); - - sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); - if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && - len != GS_DEFAULT) - return; - else if (len > 0) { -#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) - for (j = 0; - j < len-1 && (isdigit(response[j]) || response[j] == '.'); - j++); - if (toupper(response[j]) == 'K') { - num_sects = num_cyls(atof(response)*1024)*sectors*heads; - } else if (toupper(response[j]) == 'M') { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } else if (toupper(response[j]) == 'C') { - num_sects = round_int(atof(response))*sectors*heads; - } else if (toupper(response[j]) == 'S') { - num_sects = round_int(atof(response)); - } else { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } - } - - if (num_sects <= 0 || - num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) - return; - - move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol(); - if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { - /* Determine where inside free space to put partition. - */ - static struct MenuItem menuPlace[]= - { - { 'b', "Beginning", "Add partition at beginning of free space" }, - { 'e', "End", "Add partition at end of free space" }, - { ESC, "Cancel", "Don't create a partition" }, - { 0, NULL, NULL } - }; - c = menuSimple( menuPlace, 0 ); - if (toupper(c) == 'B') - last = first + num_sects - 1; - else if (toupper(c) == 'E') - first = last - num_sects + 1; - else - return; - } - - if (IS_LOGICAL(num) && !is_extended(ext_info.id)) { - /* We want to add a logical partition, but need to create an - * extended partition first. - */ - if ((ext = find_primary()) < 0) { - print_warning(NEED_EXT); - return; - } - (void) add_part(ext, DOS_EXTENDED, 0, first, last, - (first == 0 ? sectors : 0), 0); - first = ext_info.first_sector + ext_info.offset; - } - - if (IS_LOGICAL(num)) - inc_logical(i); - - /* Now we have a complete partition to ourselves */ - if (first == 0 || IS_LOGICAL(num)) - offset = sectors; - - (void) add_part(num, id, flags, first, last, offset, 0); -} - -void clear_p_info(void) -{ - num_parts = 1; - p_info[0].first_sector = 0; - p_info[0].last_sector = sectors*heads*cylinders - 1; - p_info[0].offset = 0; - p_info[0].flags = 0; - p_info[0].id = FREE_SPACE; - p_info[0].num = PRI_OR_LOG; - - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; -} - -void fill_p_info(void) -{ - int p, i; - struct hd_geometry geometry; - partition_table buffer; - partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; - - if ((fd = open(disk_device, O_RDWR)) < 0) { - if ((fd = open(disk_device, O_RDONLY)) < 0) - fatal(BAD_OPEN); - opentype = O_RDONLY; - print_warning(READONLY_WARN); - if (curses_started) { - refresh(); - getch(); - clear_warning(); - } - } else - opentype = O_RDWR; - opened = TRUE; - - /* 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) - heads = geometry.heads; - if (!sectors) - sectors = geometry.sectors; - if (!cylinders) - cylinders = geometry.cylinders; - } - - if (!heads || !sectors || !cylinders) - fatal(BAD_GEOMETRY); /* probably a file or cdrom */ - - read_sector(buffer.c.b, 0); - - clear_p_info(); - - if (!zero_table) { - for (i = 0; i < 4; i++) { - int bs = buffer.p.part[i].start_sect; - - if (buffer.p.part[i].sys_ind > 0 && - add_part(i, - buffer.p.part[i].sys_ind, - buffer.p.part[i].boot_ind, - ((bs <= sectors) ? 0 : bs), - buffer.p.part[i].start_sect + - buffer.p.part[i].nr_sects - 1, - ((bs <= sectors) ? bs : 0), - 1)) { - fatal(BAD_PRIMARY); - } - if (is_extended(buffer.p.part[i].sys_ind)) - tmp_ext = ext_info; - } - - if (is_extended(tmp_ext.id)) { - ext_info = tmp_ext; - logical_sectors[logical] = - ext_info.first_sector + ext_info.offset; - read_sector(buffer.c.b, logical_sectors[logical++]); - i = 4; - do { - for (p = 0; - p < 4 && (!buffer.p.part[p].sys_ind || - is_extended(buffer.p.part[p].sys_ind)); - p++); - - if (p < 4 && add_part(i++, - buffer.p.part[p].sys_ind, - buffer.p.part[p].boot_ind, - logical_sectors[logical-1], - logical_sectors[logical-1] + - buffer.p.part[p].start_sect + - buffer.p.part[p].nr_sects - 1, - buffer.p.part[p].start_sect, - 1)) { - fatal(BAD_LOGICAL); - } - - for (p = 0; - p < 4 && !is_extended(buffer.p.part[p].sys_ind); - p++); - if (p < 4) { - logical_sectors[logical] = ext_info.first_sector - + ext_info.offset + buffer.p.part[p].start_sect; - read_sector(buffer.c.b, logical_sectors[logical++]); - } - } while (p < 4 && logical < MAXIMUM_PARTS-4); - } - } -} - -void fill_part_table(struct partition *p, partition_info *pi) -{ - int sects; - - p->boot_ind = pi->flags; - p->sys_ind = pi->id; - if (IS_LOGICAL(pi->num)) - p->start_sect = pi->offset; - else - p->start_sect = pi->first_sector + pi->offset; - p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1; - sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector+pi->offset); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); -} - -void fill_primary_table(partition_table *buffer) -{ - int i; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - for (i = 0; i < num_parts; i++) - if (IS_PRIMARY(p_info[i].num)) - fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); - - if (is_extended(ext_info.id)) - fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); - - buffer->p.flag = PART_TABLE_FLAG; -} - -void fill_logical_table(partition_table *buffer, partition_info *pi) -{ - struct partition *p; - int i, sects; - - for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); - if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG) - for (i = 0; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - fill_part_table(&(buffer->p.part[0]), pi); - - for (i = 0; - i < num_parts && pi->num != p_info[i].num - 1; - i++); - - if (i < num_parts) { - p = &(buffer->p.part[1]); - pi = &(p_info[i]); - - p->boot_ind = 0; - p->sys_ind = DOS_EXTENDED; - p->start_sect = pi->first_sector - ext_info.first_sector - ext_info.offset; - p->nr_sects = pi->last_sector - pi->first_sector + 1; - sects = ((pi->first_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); - } - - buffer->p.flag = PART_TABLE_FLAG; -} - -void write_part_table(void) -{ - int i, done = FALSE, len; - partition_table buffer; - struct stat s; - int is_bdev; - char response[LINE_LENGTH]; - - if (opentype == O_RDONLY) { - print_warning(READONLY_WARN); - refresh(); - getch(); - clear_warning(); - return; - } - - is_bdev = 0; - if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode)) - is_bdev = 1; - - if (is_bdev) { - print_warning(WRITE_WARN); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Are you sure you want write the partition table " - "to disk? (yes or no): "); - len = get_string(response, LINE_LENGTH, NULL); - clear_warning(); - if (len == GS_ESCAPE) - return; - else if (len == 2 && - toupper(response[0]) == 'N' && - toupper(response[1]) == 'O') { - print_warning(NO_WRITE); - return; - } else if (len == 3 && - toupper(response[0]) == 'Y' && - toupper(response[1]) == 'E' && - toupper(response[2]) == 'S') - done = TRUE; - else - print_warning(YES_NO); - } - - clear_warning(); - print_warning(WRITING_PART); - refresh(); - } - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - write_sector(buffer.c.b, 0); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - write_sector(buffer.c.b, p_info[i].first_sector); - } - - if (is_bdev) { - sync(); - sleep(2); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; - sync(); - sleep(4); - - clear_warning(); - if (changed) - print_warning(YES_WRITE); - else - print_warning(RRPART_FAILED); - } else - print_warning(YES_WRITE); -} - -void fp_printf(FILE *fp, char *format, ...) -{ - va_list args; - char buf[1024]; - int y, x; - - va_start(args, format); - vsprintf(buf, format, args); - va_end(args); - - if (fp == NULL) { - /* The following works best if the string to be printed has at - most only one newline. */ - printw("%s", buf); - getyx(stdscr, y, x); - if (y >= COMMAND_LINE_Y-2) { - menuContinue(); - erase(); - move(0, 0); - } - } else - fprintf(fp, "%s", buf); -} - -#define MAX_PER_LINE 16 -void print_file_buffer(FILE *fp, char *buffer) -{ - int i,l; - - for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { - if (l == 0) - fp_printf(fp, "0x%03X:", i); - fp_printf(fp, " %02X", (unsigned char) buffer[i]); - if (l == MAX_PER_LINE - 1) { - fp_printf(fp, "\n"); - l = -1; - } - } - if (l > 0) - fp_printf(fp, "\n"); - fp_printf(fp, "\n"); -} - -void print_raw_table(void) -{ - int i, to_file; - partition_table buffer; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Disk Drive: %s\n", disk_device); - - fp_printf(fp, "Sector 0:\n"); - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - print_file_buffer(fp, buffer.c.b); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - fp_printf(fp, "Sector %d:\n", p_info[i].first_sector); - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - print_file_buffer(fp, buffer.c.b); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - menuContinue(); - } -} - -void print_p_info_entry(FILE *fp, partition_info *p) -{ - int size; - char part_str[40]; - - if (p->id == UNUSABLE) - fp_printf(fp, " None "); - else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) - fp_printf(fp, " Pri/Log"); - else if (p->id == FREE_SPACE && p->num == PRIMARY) - fp_printf(fp, " Primary"); - else if (p->id == FREE_SPACE && p->num == LOGICAL) - fp_printf(fp, " Logical"); - else - fp_printf(fp, "%2d %-7.7s", p->num+1, - IS_LOGICAL(p->num) ? "Logical" : "Primary"); - - fp_printf(fp, " "); - - fp_printf(fp, "%8d%c", p->first_sector, - ((p->first_sector/(sectors*heads)) != - ((float)p->first_sector/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, "%8d%c", p->last_sector, - (((p->last_sector+1)/(sectors*heads)) != - ((float)(p->last_sector+1)/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, "%7d%c", p->offset, - ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && - (p->offset != sectors)) || - (p->first_sector != 0 && IS_PRIMARY(p->num) && - p->offset != 0)) ? - '#' : ' ')); - - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%8d%c", size, - ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - if (p->id == UNUSABLE) - sprintf(part_str, "%.17s", "Unusable"); - else if (p->id == FREE_SPACE) - sprintf(part_str, "%.17s", "Free Space"); - else if (partition_type[p->id]) - sprintf(part_str, "%.17s (%02X)", partition_type[p->id], p->id); - else - sprintf(part_str, "%.17s (%02X)", "Unknown", p->id); - fp_printf(fp, "%-22.22s", part_str); - - fp_printf(fp, " "); - - if (p->flags == ACTIVE_FLAG) - fp_printf(fp, "Boot (%02X)", p->flags); - else if (p->flags != 0) - fp_printf(fp, "Unknown (%02X)", p->flags); - else - fp_printf(fp, "None (%02X)", p->flags); - - fp_printf(fp, "\n"); -} - -void print_p_info(void) -{ - char fname[LINE_LENGTH]; - FILE *fp; - int i, to_file, pext = is_extended(ext_info.id); - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Partition Table for %s\n", disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, " First Last\n"); - fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); - fp_printf(fp, "-- ------- -------- --------- ------ --------- ---------------------- ---------\n"); - - for (i = 0; i < num_parts; i++) { - if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { - print_p_info_entry(fp,&ext_info); - pext = FALSE; - } - print_p_info_entry(fp, &(p_info[i])); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - menuContinue(); - } -} - -void print_part_entry(FILE *fp, int num, partition_info *pi) -{ - int first = 0, start = 0, end = 0, size = 0; - int ss = 0, sh = 0, sc = 0; - int es = 0, eh = 0, ec = 0; - int flags = 0, id = 0; - - if (pi != NULL) { - flags = pi->flags; - id = pi->id; - - if (IS_LOGICAL(num)) - first = pi->offset; - else - first = pi->first_sector + pi->offset; - - start = pi->first_sector + pi->offset; - end = pi->last_sector; - size = end - start + 1; - if ((start/(sectors*heads)) > 1023) - start = heads*sectors*1024 - 1; - if ((end/(sectors*heads)) > 1023) - end = heads*sectors*1024 - 1; - - ss = start % sectors + 1; - start /= sectors; - sh = start % heads; - sc = start / heads; - - es = end % sectors + 1; - end /= sectors; - eh = end % heads; - ec = end / heads; - } - - 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); -} - - -void print_part_table(void) -{ - int i, j, to_file; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - 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"); - - for (i = 0; i < 4; i++) { - for (j = 0; - j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); - j++); - if (j < num_parts) { - print_part_entry(fp, i, &(p_info[j])); - } else if (is_extended(ext_info.id) && ext_info.num == i) { - print_part_entry(fp, i, &ext_info); - } else { - print_part_entry(fp, i, NULL); - } - } - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) - print_part_entry(fp, p_info[i].num, &(p_info[i])); - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - menuContinue(); - } -} - -void print_tables(void) -{ - int done = FALSE; - - static struct MenuItem menuFormat[]= - { - { 'r', "Raw", "Print the table using raw data format" }, - { 's', "Sectors", "Print the table ordered by sectors" }, - { 't', "Table", "Just print the partition table" }, - { ESC, "Cancel", "Don't print the table" }, - { 0, NULL, NULL } - }; - - while (!done) - switch ( toupper(menuSimple( menuFormat, 2)) ) { - case 'R': - print_raw_table(); - done = TRUE; - break; - case 'S': - print_p_info(); - done = TRUE; - break; - case 'T': - print_part_table(); - done = TRUE; - break; - case ESC: - done = TRUE; - break; - } -} - -#define END_OF_HELP "EOHS!" -#define NEW_HELP_SCREEN "SNHS!" -void display_help() -{ - char *help_text[] = { - "Help Screen for cfdisk " VERSION, - "", - "This is cfdisk, a curses based disk partitioning programs, which", - "allows you to create, delete and modify partitions on your hard", - "disk drive.", - "", - "Copyright (C) 1994-1998 Kevin E. Martin & aeb", - "", - "Command Meaning", - "------- -------", - " b Toggle bootable flag of the current partition", - " d Delete the current partition", - " g Change cylinders, heads, sectors-per-track parameters", - " WARNING: This option should only be used by people who", - " know what they are doing.", - " h Print this screen", - " m Maximize disk usage of the current partition", - " Note: This may make the partition incompatible with", - " DOS, OS/2, ...", - " n Create new partition from free space", - " p Print partition table to the screen or to a file", - " There are several different formats for the partition", - " that you can choose from:", - " r - Raw data (exactly what would be written to disk)", - " s - Table ordered by sectors", - " t - Table in raw format", - " q Quit program without writing partition table", - " t Change the filesystem type", - " u Change units of the partition size display", - " Rotates through Mb, sectors and cylinders", - " W Write partition table to disk (must enter upper case W)", - " Since this might destroy data on the disk, you must", - " either confirm or deny the write by entering `yes' or", - " `no'", - "Up Arrow Move cursor to the previous partition", - "Down Arrow Move cursor to the next partition", - "CTRL-L Redraws the screen", - " ? Print this screen", - "", - "Note: All of the commands can be entered with either upper or lower", - "case letters (except for Writes).", - END_OF_HELP - }; - - int cur_line = 0; - FILE *fp = NULL; - - erase(); - move(0, 0); - while (strcmp(help_text[cur_line], END_OF_HELP)) - if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { - menuContinue(); - erase(); - move(0, 0); - cur_line++; - } else - fp_printf(fp, "%s\n", help_text[cur_line++]); - - menuContinue(); -} - -int change_geometry(void) -{ - int ret_val = FALSE; - int done = FALSE; - char def[LINE_LENGTH]; - char response[LINE_LENGTH]; - int tmp_val; - - while (!done) { - static struct MenuItem menuGeometry[]= - { - { 'c', "Cylinders", "Change cylinder geometry" }, - { 'h', "Heads", "Change head geometry" }, - { 's', "Sectors", "Change sector geometry" }, - { 'd', "Done", "Done with changing geometry" }, - { 0, NULL, NULL } - }; - move(COMMAND_LINE_Y, COMMAND_LINE_X); - clrtoeol(); - refresh(); - - clear_warning(); - - switch (toupper( menuSimple(menuGeometry, 3) )) { - case 'C': - sprintf(def, "%d", cylinders); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of cylinders: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { - cylinders = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_CYLINDERS); - } - break; - case 'H': - sprintf(def, "%d", heads); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of heads: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_HEADS) { - heads = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_HEADS); - } - break; - case 'S': - sprintf(def, "%d", sectors); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of sectors per track: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { - sectors = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_SECTORS); - } - break; - case ESC: - case 'D': - done = TRUE; - break; - default: - putchar(BELL); - break; - } - } - - if (ret_val) { - int disk_end = heads*sectors*cylinders-1; - - if (p_info[num_parts-1].last_sector > disk_end) { - while (p_info[num_parts-1].first_sector > disk_end) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) - remove_part(num_parts-1); - else - del_part(num_parts-1); - } - - p_info[num_parts-1].last_sector = disk_end; - - if (ext_info.last_sector > disk_end) - ext_info.last_sector = disk_end; - } else if (p_info[num_parts-1].last_sector < disk_end) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = disk_end; - } else { - insert_empty_part(num_parts, - p_info[num_parts-1].last_sector+1, - disk_end); - } - } - - /* Make sure the partitions are correct */ - check_part_info(); - } - - return ret_val; -} - -void change_id(int i) -{ - char id[LINE_LENGTH], def[LINE_LENGTH]; - int num_types = 0; - int num_across, num_down; - int len, new_id = LINUX; - int y_start, y_end; - int j, pos; - - for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) - num_types++; - - num_across = COLS/COL_ID_WIDTH; - num_down = (((float)num_types)/num_across + 1); - y_start = COMMAND_LINE_Y - 1 - num_down; - if (y_start > DISK_TABLE_START+cur_part+4) - y_start = DISK_TABLE_START+cur_part+4; - y_end = y_start + num_down - 1; - - for (j = y_start - 1; j <= y_end + 1; j++) { - move(j, 0); - clrtoeol(); - } - - for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) { - move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); - printw("%02X %-16.16s", j, partition_type[j]); - pos++; - } - - sprintf(def, "%02X", new_id); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); - if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) - return; - - if (len != GS_DEFAULT) { - if (!isxdigit(id[0])) - return; - new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); - if (len == 2) - if (isxdigit(id[1])) - new_id = new_id*16 + - (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); - else - return; - } - - if (new_id == 0) - print_warning(ID_EMPTY); - else if (is_extended(new_id)) - print_warning(ID_EXT); - else - p_info[i].id = new_id; -} - -void draw_partition(int i) -{ - 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); - for (j = 0; j < COLS; j++) - addch(' '); - } - - if (p_info[i].id > 0) { - mvprintw(y, NAME_START, - "%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"); - else - mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - addstr(", NC"); - } else { - if (p_info[i].offset != 0) - addstr(", NC"); - } - } else { - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - mvaddstr(y, FLAGS_START, "NC"); - } else { - if (p_info[i].offset != 0) - mvaddstr(y, FLAGS_START, "NC"); - } - } - } - mvaddstr(y, PTYPE_START, - (p_info[i].id == UNUSABLE ? "" : - (IS_LOGICAL(p_info[i].num) ? "Logical" : - (p_info[i].num >= 0 ? "Primary" : - (p_info[i].num == PRI_OR_LOG ? "Pri/Log" : - (p_info[i].num == PRIMARY ? "Primary" : "Logical")))))); - - t = partition_type_text(i); - if (t) - mvaddstr(y, FSTYPE_START, t); - else - mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); - - 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; - if (display_units == SECTORS) - mvprintw(y, SIZE_START, "%9d", size); - else if (display_units == CYLINDERS) - mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); - else - mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); - if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || - ((p_info[i].first_sector/(sectors*heads)) != - ceiling(p_info[i].first_sector/(sectors*heads)))) - mvprintw(y, COLUMNS-1, "*"); -} - -void init_const(void) -{ - if (!defined) { - NAME_START = (((float)NAME_START)/COLUMNS)*COLS; - 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; - - COMMAND_LINE_Y = LINES - 4; - WARNING_START = LINES - 2; - - if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) - NUM_ON_SCREEN = 1; - - COLUMNS = COLS; - defined = TRUE; - } -} - -void draw_screen(void) -{ - int i; - char *line; - - line = (char *)malloc((COLS+1)*sizeof(char)); - - if (warning_last_time) { - for (i = 0; i < COLS; i++) { - move(WARNING_START, i); - line[i] = inch(); - } - line[COLS] = 0; - } - - erase(); - - if (warning_last_time) - mvaddstr(WARNING_START, 0, line); - - - sprintf(line, "cfdisk %s", VERSION); - mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); - sprintf(line, "Disk Drive: %s", disk_device); - mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); - sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", - heads, sectors, cylinders); - mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); - - mvaddstr(DISK_TABLE_START, NAME_START, "Name"); - mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags"); - 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) - mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); - else - mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); - - move(DISK_TABLE_START+1, 1); - for (i = 1; i < COLS-1; i++) - addch('-'); - - if (NUM_ON_SCREEN >= num_parts) - for (i = 0; i < num_parts; i++) - draw_partition(i); - else - for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && - i < num_parts; - i++) - draw_partition(i); - - free(line); -} - -int draw_cursor(int move) -{ - if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) - return -1; - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); - else - draw_partition(cur_part); - - cur_part += move; - - if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) - draw_screen(); - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); - else { - standout(); - draw_partition(cur_part); - standend(); - } - - return 0; -} - -void do_curses_fdisk(void) -{ - int done = FALSE; - char command; - - static struct MenuItem menuMain[]= - { - { 'b', "Bootable", "Toggle bootable flag of the current partition" }, - { 'd', "Delete", "Delete the current partition" }, - { 'g', "Geometry", "Change disk geometry (experts only)" }, - { 'h', "Help", "Print help screen" }, - { 'm', "Maximize", "Maximize disk usage of the current partition (experts only)" }, - { 'n', "New", "Create new partition from free space" }, - { 'p', "Print", "Print partition table to the screen or to a file" }, - { 'q', "Quit", "Quit program without writing partition table" }, - { 't', "Type", "Change the filesystem type (DOS, Linux, OS/2 and so on)" }, - { 'u', "Units", "Change units of the partition size display (MB, sect, cyl)" }, - { 'W', "Write", "Write partition table to disk (this might destroy data)" }, - { 0, NULL, NULL } - }; - curses_started = 1; - initscr(); - init_const(); - - old_SIGINT = signal(SIGINT, die); - old_SIGTERM = signal(SIGTERM, die); -#ifdef DEBUG - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); -#endif - - cbreak(); - noecho(); - nonl(); - - fill_p_info(); - - draw_screen(); - - while (!done) { - char *s; - - (void)draw_cursor(0); - - if (p_info[cur_part].id == FREE_SPACE) { - s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, - s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - } else if (p_info[cur_part].id > 0) { - s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, - s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - } else { - s = ((opentype == O_RDWR) ? "hpquW" : "hpqu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, - s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - } - switch ( command ) { - case 'B': - case 'b': - if (p_info[cur_part].id > 0) - p_info[cur_part].flags ^= 0x80; - else - print_warning(NO_FLAGS); - break; - case 'D': - case 'd': - if (p_info[cur_part].id > 0) { - del_part(cur_part); - if (cur_part >= num_parts) - cur_part = num_parts - 1; - draw_screen(); - } else - print_warning(DEL_EMPTY); - break; - case 'G': - case 'g': - if (change_geometry()) - draw_screen(); - break; - case 'M': - case 'm': - if (p_info[cur_part].id > 0) { - if (p_info[cur_part].first_sector == 0 || - IS_LOGICAL(p_info[cur_part].num)) { - if (p_info[cur_part].offset == sectors) - p_info[cur_part].offset = 1; - else - p_info[cur_part].offset = sectors; - draw_screen(); - } else if (p_info[cur_part].offset != 0) - p_info[cur_part].offset = 0; - else - print_warning(MAX_UNMAXABLE); - } else - print_warning(MAX_UNMAXABLE); - break; - case 'N': - case 'n': - if (p_info[cur_part].id == FREE_SPACE) { - new_part(cur_part); - draw_screen(); - } else if (p_info[cur_part].id == UNUSABLE) - print_warning(ADD_UNUSABLE); - else - print_warning(ADD_EXISTS); - break; - case 'P': - case 'p': - print_tables(); - draw_screen(); - break; - case 'Q': - case 'q': - done = TRUE; - break; - case 'T': - case 't': - if (p_info[cur_part].id > 0) { - change_id(cur_part); - draw_screen(); - } else - print_warning(TYPE_EMPTY); - break; - case 'U': - case 'u': - if (display_units == MEGABYTES) - display_units = SECTORS; - else if (display_units == SECTORS) - display_units = CYLINDERS; - else if (display_units == CYLINDERS) - display_units = MEGABYTES; - draw_screen(); - break; - case 'W': - write_part_table(); - break; - case 'H': - case 'h': - case '?': - display_help(); - draw_screen(); - break; - case MENU_UP : /* Up arrow */ - if (!draw_cursor(-1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case MENU_DOWN : /* Down arrow */ - if (!draw_cursor(1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case REDRAWKEY: - clear(); - draw_screen(); - break; - default: - print_warning(BAD_COMMAND); - putchar(BELL); /* CTRL-G */ - } - } - - die_x(0); -} - -void copyright(void) -{ - fprintf(stderr, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n"); -} - -void usage(char *prog_name) -{ - fprintf(stderr, "\nUsage:\n"); - fprintf(stderr, "Print version:\n"); - fprintf(stderr, "\t%s -v\n", prog_name); - fprintf(stderr, "Print partition table:\n"); - fprintf(stderr, "\t%s -P {r|s|t} [options] device\n", prog_name); - fprintf(stderr, "Interactive use:\n"); - fprintf(stderr, "\t%s [options] device\n", prog_name); - fprintf(stderr, " -Options: --a: Use arrow instead of highlighting; --z: Start with a zero partition table, instead of reading the pt from disk; --c C -h H -s S: Override the kernel's idea of the number of cylinders, - the number of heads and the number of sectors/track.\n\n"); - - copyright(); -} - -int main(int argc, char **argv) -{ - char c; - int i, len; - - setlocale(LC_CTYPE, ""); - - while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) - switch (c) { - case 'a': - arrow_cursor = TRUE; - break; - case 'c': - cylinders = atoi(optarg); - if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); - exit(1); - } - break; - case 'h': - heads = atoi(optarg); - if (heads <= 0 || heads > MAX_HEADS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); - exit(1); - } - break; - case 's': - sectors = atoi(optarg); - if (sectors <= 0 || sectors > MAX_SECTORS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); - exit(1); - } - break; - case 'v': - fprintf(stderr, "cfdisk %s\n", VERSION); - copyright(); - exit(0); - case 'z': - zero_table = TRUE; - break; - case 'P': - len = strlen(optarg); - for (i = 0; i < len; i++) { - switch (optarg[i]) { - case 'r': - print_only |= PRINT_RAW_TABLE; - break; - case 's': - print_only |= PRINT_SECTOR_TABLE; - break; - case 't': - print_only |= PRINT_PARTITION_TABLE; - break; - default: - usage(argv[0]); - break; - } - } - break; - default: - usage(argv[0]); - exit(1); - } - - if (argc-optind == 1) - disk_device = argv[optind]; - else if (argc-optind != 0) { - usage(argv[0]); - exit(1); - } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - - if (print_only) { - fill_p_info(); - if (print_only & PRINT_RAW_TABLE) - print_raw_table(); - if (print_only & PRINT_SECTOR_TABLE) - print_p_info(); - if (print_only & PRINT_PARTITION_TABLE) - print_part_table(); - } else - do_curses_fdisk(); - - return 0; -} diff --git a/disk-utils/cfdisk.c.bak b/disk-utils/cfdisk.c.bak deleted file mode 100644 index 3b9f22f58..000000000 --- a/disk-utils/cfdisk.c.bak +++ /dev/null @@ -1,2066 +0,0 @@ -/**************************************************************************** - * - * CFDISK - * - * cfdisk is a curses based disk drive partitioning program that can - * create partitions for a wide variety of operating systems including - * Linux, MS-DOS and OS/2. - * - * cfdisk was inspired by the fdisk program, by A. V. Le Blanc - * (LeBlanc@mcc.ac.uk). - * - * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) - * - * cfdisk 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. - * - * cfdisk 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 cfdisk; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu - * - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for BLKRRPART */ - -typedef long ext2_loff_t; -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); - -#define VERSION "0.8 BETA (>2GB)" - -#define DEFAULT_DEVICE "/dev/hda" -#define ALTERNATE_DEVICE "/dev/sda" - -#define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 - -#define SECTOR_SIZE 512 - -#define MAX_CYLINDERS 65535 -#define MAX_HEADS 255 -#define MAX_SECTORS 63 - -#define ACTIVE_FLAG 0x80 -#define PART_TABLE_FLAG 0xAA55 - -#define UNUSABLE -1 -#define FREE_SPACE 0x00 -#define EXTENDED 0x05 -#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" -#define DEL_EMPTY "Cannot delete an empty partition" -#define ID_EMPTY "Cannot change FS Type to empty" -#define ID_EXT "Cannot change FS Type to extended" -#define NEED_EXT "No room to create the extended partition" -#define NO_FLAGS "Cannot make this partition bootable" -#define NO_MORE_PARTS "No more partitions" -#define PRINT_OPEN_ERR "Cannot open file '%s'" -#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" -#define TYPE_EMPTY "Cannot change the type of an empty partition" -#define BAD_COMMAND "Illegal command" -#define MAX_UNMAXABLE "Cannot maximize this partition" -#define BAD_OPEN "Cannot open disk drive" -#define BAD_SEEK "Cannot seek on disk drive" -#define BAD_READ "Cannot read disk drive" -#define BAD_WRITE "Cannot write disk drive" -#define BAD_GEOMETRY "Cannot read disk drive geometry" -#define BAD_PRIMARY "Bad primary partition" -#define BAD_LOGICAL "Bad logical partition" -#define BAD_CYLINDERS "Illegal cylinders value" -#define BAD_HEADS "Illegal heads value" -#define BAD_SECTORS "Illegal sectors value" -#define WRITE_WARN "Warning!! This may destroy data on your disk!" -#define YES_NO "Please enter `yes' or `no'" -#define WRITING_PART "Writing partition table to disk..." -#define YES_WRITE "Wrote partition table to disk" -#define NO_WRITE "Did not write partition table to disk" -#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." - -#define PRI_OR_LOG -1 -#define PRIMARY -2 -#define LOGICAL -3 - -#define COL_ID_WIDTH 20 - -#define CR '\015' -#define ESC '\033' -#define DEL '\177' -#define BELL '\007' -/* '\014' == ^L */ -#define REDRAWKEY '\014' - -/* Display units */ -#define MEGABYTES 1 -#define SECTORS 2 -#define CYLINDERS 3 - -#define GS_DEFAULT -1 -#define GS_ESCAPE -2 - -#define PRINT_RAW_TABLE 1 -#define PRINT_SECTOR_TABLE 2 -#define PRINT_PARTITION_TABLE 4 - -#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) -#define IS_LOGICAL(p) ((p) > 3) - -#define round_int(d) ((double)((int)(d+0.5))) -#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) - -#define set_hsc(h,s,c,sector) \ -{ \ - s = sector % sectors + 1; \ - sector /= sectors; \ - h = sector % heads; \ - sector /= heads; \ - c = sector & 0xFF; \ - s |= (sector >> 2) & 0xC0;\ -} - -#define ALIGNMENT 2 -typedef union { - struct { - unsigned char align[ALIGNMENT]; - unsigned char b[SECTOR_SIZE]; - } c; - struct { - unsigned char align[ALIGNMENT]; - unsigned char buffer[0x1BE]; - struct partition part[4]; - unsigned short flag; - } p; -} partition_table; - -typedef struct { - int first_sector; /* first sector in partition */ - int last_sector; /* last sector in partition */ - int offset; /* offset from first sector to start of data */ - int flags; /* active == 0x80 */ - int id; /* filesystem type */ - int num; /* number of partition -- primary vs. logical */ -} partition_info; - -char *disk_device = DEFAULT_DEVICE; -int fd; -int heads = 0; -int sectors = 0; -int cylinders = 0; -int changed = FALSE; -int opened = FALSE; - -partition_info p_info[MAXIMUM_PARTS]; -partition_info ext_info; -int num_parts = 0; - -int logical = 0; -int logical_sectors[MAXIMUM_PARTS]; - -__sighandler_t old_SIGINT, old_SIGTERM; - -int arrow_cursor = FALSE; -int display_units = MEGABYTES; -int zero_table = FALSE; -int print_only = 0; - -/* Curses screen information */ -int cur_part = 0; -int warning_last_time = FALSE; -int defined = FALSE; -int COLUMNS = 80; -int NUM_ON_SCREEN = 1; - -/* Y coordinates */ -int HEADER_START = 0; -int DISK_TABLE_START = 5; -int WARNING_START = 23; -int COMMAND_LINE_Y = 21; - -/* X coordinates */ -int NAME_START = 4; -int FLAGS_START = 16; -int PTYPE_START = 30; -int FSTYPE_START = 45; -int SIZE_START = 70; -int COMMAND_LINE_X = 5; - -#define NUM_PART_TYPES 256 -char *partition_type[NUM_PART_TYPES] = { - [LINUX_MINIX] = "Linux/MINIX", - [LINUX_SWAP] = "Linux Swap", - [LINUX] = "Linux", - [FREE_SPACE] = "Free Space", - [EXTENDED] = "Extended", - [0x01] = "DOS 12-bit FAT", - [0x04] = "DOS 16-bit < 32Mb", - [0x06] = "DOS 16-bit >=32Mb", - [0x07] = "OS/2 HPFS", - [0x0A] = "OS/2 Boot Manager", - [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. - */ - - [0x02] = "XENIX root", - [0x03] = "XENIX usr", - [0x08] = "AIX", - [0x09] = "AIX bootable", - [0x40] = "Venix 80286", - [0x51] = "Novell?", - [0x52] = "Microport", - [0x63] = "GNU HURD", - [0x64] = "Novell", - [0x75] = "PC/IX", - [0x80] = "Old MINIX", - [0x93] = "Amoeba", - [0x94] = "Amoeba BBT", - [0xB7] = "BSDI fs", - [0xB8] = "BSDI swap", - [0xC7] = "Syrinx", - [0xDB] = "CP/M", - [0xE1] = "DOS access", - [0xE3] = "DOS R/O", - [0xF2] = "DOS secondary", - [0xFF] = "BBT" -}; - -void fdexit(int ret) -{ - if (opened) - close(fd); - - if (changed) { - fprintf(stderr, "Disk has been changed.\n"); - fprintf(stderr, "Reboot the system to ensure the partition " - "table is correctly updated.\n"); - - fprintf( stderr, "\nWARNING: If you have created or modified any\n" - "DOS 6.x partitions, please see the cfdisk manual\n" - "page for additional information.\n" ); - } - - - exit(ret); -} - -int get_string(char *str, int len, char *def) -{ - char c; - int i = 0; - int x, y; - int use_def = FALSE; - - getyx(stdscr, y, x); - clrtoeol(); - - str[i] = 0; - - if (def != NULL) { - mvaddstr(y, x, def); - move(y, x); - use_def = TRUE; - } - - refresh(); - while ((c = getch()) != '\n' && c != CR) { - switch (c) { - case ESC: - move(y, x); - clrtoeol(); - refresh(); - return GS_ESCAPE; - case DEL: - case '\b': - if (i > 0) { - str[--i] = 0; - mvaddch(y, x+i, ' '); - move(y, x+i); - } else if (use_def) { - clrtoeol(); - use_def = FALSE; - } else - putchar(BELL); - break; - default: - if (i < len && isprint(c)) { - mvaddch(y, x+i, c); - if (use_def) { - clrtoeol(); - use_def = FALSE; - } - str[i++] = c; - str[i] = 0; - } else - putchar(BELL); - } - refresh(); - } - - if (use_def) - return GS_DEFAULT; - else - return i; -} - -void clear_warning(void) -{ - int i; - - if (!warning_last_time) - return; - - move(WARNING_START,0); - for (i = 0; i < COLS; i++) - addch(' '); - - warning_last_time = FALSE; -} - -void print_warning(char *s) -{ - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ - - warning_last_time = TRUE; -} - -void fatal(char *s) -{ - char str[LINE_LENGTH]; - - sprintf(str, "FATAL ERROR: %s", s); - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "Press any key to exit fdisk"); - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - - refresh(); - - (void)getch(); - - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(1); -} - -void read_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_READ); -} - -void write_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_WRITE); -} - -void check_part_info(void) -{ - int i, pri = 0, log = 0; - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (ext_info.id == EXTENDED) - if (log > 0) - pri++; - else { - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; - } - - if (pri >= 4) - for (i = 0; i < num_parts; i++) - if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) - if (ext_info.id == EXTENDED) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else - p_info[i].id = UNUSABLE; - else /* if (ext_info.id != EXTENDED) */ - p_info[i].id = UNUSABLE; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - else /* if (pri < 4) */ - for (i = 0; i < num_parts; i++) { - if (p_info[i].id == UNUSABLE) - p_info[i].id = FREE_SPACE; - if (p_info[i].id == FREE_SPACE) - if (ext_info.id == EXTENDED) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) - p_info[i].num = LOGICAL; - else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else - p_info[i].num = PRIMARY; - else /* if (ext_info.id != EXTENDED) */ - p_info[i].num = PRI_OR_LOG; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } -} - -void remove_part(int i) -{ - int p; - - for (p = i; p < num_parts; p++) - p_info[p] = p_info[p+1]; - - num_parts--; -} - -void insert_part(int i, int num, int id, int flags, int first, int last, - int offset) -{ - int p; - - for (p = num_parts; p > i; p--) - p_info[p] = p_info[p-1]; - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - - num_parts++; -} - -void del_part(int i) -{ - int num = p_info[i].num; - - if (i > 0 && (p_info[i-1].id == FREE_SPACE || - p_info[i-1].id == UNUSABLE)) { - /* Merge with previous partition */ - p_info[i-1].last_sector = p_info[i].last_sector; - remove_part(i--); - } - - if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || - p_info[i+1].id == UNUSABLE)) { - /* Merge with next partition */ - p_info[i+1].first_sector = p_info[i].first_sector; - remove_part(i); - } - - if (i > 0) - p_info[i].first_sector = p_info[i-1].last_sector + 1; - else - p_info[i].first_sector = 0; - - if (i < num_parts - 1) - p_info[i].last_sector = p_info[i+1].first_sector - 1; - else - p_info[i].last_sector = sectors*heads*cylinders - 1; - - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - - if (IS_LOGICAL(num)) { - /* We have a logical partition --> shrink the extended partition - * if (1) this is the first logical drive, or (2) this is the - * last logical drive; and if there are any other logical drives - * then renumber the ones after "num". - */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) - ext_info.first_sector = p_info[i].last_sector + 1; - if (i == num_parts-1 || - (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) - ext_info.last_sector = p_info[i].first_sector - 1; - for (i = 0; i < num_parts; i++) - if (p_info[i].num > num) - p_info[i].num--; - } - - /* Clean up the rest of the partitions */ - check_part_info(); -} - -int add_part(int num, int id, int flags, int first, int last, int offset) -{ - int i, pri = 0, log = 0; - - if (num_parts == MAXIMUM_PARTS || - first < 0 || - first >= cylinders*heads*sectors || - last < 0 || - last >= cylinders*heads*sectors) - return -1; - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (ext_info.id == EXTENDED && log > 0) - pri++; - - if (IS_PRIMARY(num)) - if (pri >= 4) - return -1; - else - pri++; - - for (i = 0; p_info[i].last_sector < first; i++); - - if (p_info[i].id != FREE_SPACE || last > p_info[i].last_sector) - return -1; - - if (id == EXTENDED) - if (ext_info.id != FREE_SPACE) - return -1; - else if (IS_PRIMARY(num)) { - ext_info.first_sector = first; - ext_info.last_sector = last; - ext_info.offset = offset; - ext_info.flags = flags; - ext_info.id = EXTENDED; - ext_info.num = num; - - return 0; - } else - return -1; - - if (IS_LOGICAL(num)) { - if (ext_info.id != EXTENDED) { - print_warning("!!!! Internal error creating logical " - "drive with no extended partition !!!!"); - } else { - /* We might have a logical partition outside of the extended - * partition's range --> we have to extend the extended - * partition's range to encompass this new partition, but we - * must make sure that there are no primary partitions between - * it and the closest logical drive in extended partition. - */ - if (first < ext_info.first_sector) { - if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else { - if (first == 0) { - ext_info.first_sector = 0; - ext_info.offset = first = offset; - } else - ext_info.first_sector = first; - } - } else if (last > ext_info.last_sector) { - if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else - ext_info.last_sector = last; - } - } - } - - if (first != p_info[i].first_sector && - !(IS_LOGICAL(num) && first == offset)) { - insert_part(i, PRI_OR_LOG, FREE_SPACE, 0, - p_info[i].first_sector, first-1, 0); - i++; - } - - if (last != p_info[i].last_sector) - insert_part(i+1, PRI_OR_LOG, FREE_SPACE, 0, - last+1, p_info[i].last_sector, 0); - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - - check_part_info(); - - return 0; -} - -int find_primary(void) -{ - int num = 0, cur = 0; - - while (cur < num_parts && IS_PRIMARY(num)) - if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (ext_info.id == EXTENDED && ext_info.num == num)) { - num++; - cur = 0; - } else - cur++; - - if (!IS_PRIMARY(num)) - return -1; - else - return num; -} - -int find_logical(int i) -{ - int num = -1; - int j; - - for (j = i; j < num_parts && num == -1; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - num = p_info[j].num; - - if (num == -1) { - num = 4; - for (j = 0; j < num_parts; j++) - if (p_info[j].id > 0 && p_info[j].num == num) - num++; - } - - return num; -} - -void inc_logical(int i) -{ - int j; - - for (j = i; j < num_parts; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - p_info[j].num++; -} - -void new_part(int i) -{ - char response[LINE_LENGTH], def[LINE_LENGTH]; - char c; - int first = p_info[i].first_sector; - int last = p_info[i].last_sector; - int offset = 0; - int flags = 0; - int id = LINUX; - int num = -1; - int num_sects = last - first + 1; - int len, ext, j; - - if (p_info[i].num == PRI_OR_LOG) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Primary or logical [pl]: "); - clrtoeol(); - refresh(); - while (toupper(c = getch()) != 'P' && toupper(c) != 'L' && c != ESC); - if (toupper(c) == 'P') - num = find_primary(); - else if (toupper(c) == 'L') - num = find_logical(i); - else - return; - } else if (p_info[i].num == PRIMARY) - num = find_primary(); - else if (p_info[i].num == LOGICAL) - num = find_logical(i); - else - print_warning("!!! Internal error !!!"); - - sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); - if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && - len != GS_DEFAULT) - return; - else if (len > 0) { -#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) - for (j = 0; - j < len-1 && (isdigit(response[j]) || response[j] == '.'); - j++); - if (toupper(response[j]) == 'K') { - num_sects = num_cyls(atof(response)*1024)*sectors*heads; - } else if (toupper(response[j]) == 'M') { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } else if (toupper(response[j]) == 'C') { - num_sects = round_int(atof(response))*sectors*heads; - } else if (toupper(response[j]) == 'S') { - num_sects = round_int(atof(response)); - } else { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } - } - - if (num_sects <= 0 || - num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) - return; - - if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { - /* Determine where inside free space to put partition. - */ - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Add partition at beginning or end of free space [be]: "); - clrtoeol(); - refresh(); - while (toupper(c = getch()) != 'B' && toupper(c) != 'E' && c != ESC); - if (toupper(c) == 'B') - last = first + num_sects - 1; - else if (toupper(c) == 'E') - first = last - num_sects + 1; - else - return; - } - - if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { - /* We want to add a logical partition, but need to create an - * extended partition first. - */ - if ((ext = find_primary()) < 0) { - print_warning(NEED_EXT); - return; - } - (void)add_part(ext, EXTENDED, 0, first, last, - (first == 0 ? sectors : 0)); - } - - if (IS_LOGICAL(num)) - inc_logical(i); - - /* Now we have a complete partition to ourselves */ - if (first == 0 || IS_LOGICAL(num)) - offset = sectors; - - (void)add_part(num, id, flags, first, last, offset); -} - -void clear_p_info(void) -{ - num_parts = 1; - p_info[0].first_sector = 0; - p_info[0].last_sector = sectors*heads*cylinders - 1; - p_info[0].offset = 0; - p_info[0].flags = 0; - p_info[0].id = FREE_SPACE; - p_info[0].num = PRI_OR_LOG; - - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; -} - -void fill_p_info(void) -{ - int p, i; - struct hd_geometry geometry; - partition_table buffer; - partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; - - if ((fd = open(disk_device, O_RDWR)) < 0) - fatal(BAD_OPEN); - read_sector(buffer.c.b, 0); - - if (!ioctl(fd, HDIO_GETGEO, &geometry)) { - if (!heads) - heads = geometry.heads; - if (!sectors) - sectors = geometry.sectors; - if (!cylinders) - cylinders = geometry.cylinders; - } - - if (!heads || !sectors || !cylinders) - fatal(BAD_GEOMETRY); - - clear_p_info(); - - if (!zero_table) { - for (i = 0; i < 4; i++) { - if (buffer.p.part[i].sys_ind > 0 && - add_part(i, - buffer.p.part[i].sys_ind, - buffer.p.part[i].boot_ind, - ((buffer.p.part[i].start_sect <= sectors) ? - 0 : buffer.p.part[i].start_sect), - buffer.p.part[i].start_sect + - buffer.p.part[i].nr_sects - 1, - ((buffer.p.part[i].start_sect <= sectors) ? - buffer.p.part[i].start_sect : 0))) { - fatal(BAD_PRIMARY); - } - if (buffer.p.part[i].sys_ind == EXTENDED) - tmp_ext = ext_info; - } - - if (tmp_ext.id == EXTENDED) { - ext_info = tmp_ext; - logical_sectors[logical] = ext_info.first_sector; - read_sector(buffer.c.b, logical_sectors[logical++]); - i = 4; - do { - for (p = 0; - p < 4 && (!buffer.p.part[p].sys_ind || - buffer.p.part[p].sys_ind == 5); - p++); - if (p > 3) - fatal(BAD_LOGICAL); - - if (add_part(i++, - buffer.p.part[p].sys_ind, - buffer.p.part[p].boot_ind, - logical_sectors[logical-1], - logical_sectors[logical-1] + - buffer.p.part[p].start_sect + - buffer.p.part[p].nr_sects - 1, - buffer.p.part[p].start_sect)) { - fatal(BAD_LOGICAL); - } - - for (p = 0; - p < 4 && buffer.p.part[p].sys_ind != 5; - p++); - if (p < 4) { - logical_sectors[logical] = - ext_info.first_sector + buffer.p.part[p].start_sect; - read_sector(buffer.c.b, logical_sectors[logical++]); - } - } while (p < 4 && logical < MAXIMUM_PARTS-4); - } - } -} - -void fill_part_table(struct partition *p, partition_info *pi) -{ - int sects; - - p->boot_ind = pi->flags; - p->sys_ind = pi->id; - if (IS_LOGICAL(pi->num)) - p->start_sect = pi->offset; - else - p->start_sect = pi->first_sector + pi->offset; - p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1; - sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector+pi->offset); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); -} - -void fill_primary_table(partition_table *buffer) -{ - int i; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - for (i = 0; i < num_parts; i++) - if (IS_PRIMARY(p_info[i].num)) - fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); - - if (ext_info.id == EXTENDED) - fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); - - buffer->p.flag = PART_TABLE_FLAG; -} - -void fill_logical_table(partition_table *buffer, partition_info *pi) -{ - struct partition *p; - int i, sects; - - for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); - if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG) - for (i = 0; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - fill_part_table(&(buffer->p.part[0]), pi); - - for (i = 0; - i < num_parts && pi->num != p_info[i].num - 1; - i++); - - if (i < num_parts) { - p = &(buffer->p.part[1]); - pi = &(p_info[i]); - - p->boot_ind = 0; - p->sys_ind = 5; - p->start_sect = pi->first_sector - ext_info.first_sector; - p->nr_sects = pi->last_sector - pi->first_sector + 1; - sects = ((pi->first_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); - } - - buffer->p.flag = PART_TABLE_FLAG; -} - -void write_part_table(void) -{ - int i, done = FALSE, len; - partition_table buffer; - char response[LINE_LENGTH]; - - print_warning(WRITE_WARN); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Are you sure you want write the partition table to disk? (yes or no): "); - - len = get_string(response, LINE_LENGTH, NULL); - - clear_warning(); - - if (len == GS_ESCAPE) - return; - else if (len == 2 && - toupper(response[0]) == 'N' && - toupper(response[1]) == 'O') { - print_warning(NO_WRITE); - return; - } else if (len == 3 && - toupper(response[0]) == 'Y' && - toupper(response[1]) == 'E' && - toupper(response[2]) == 'S') - done = TRUE; - else - print_warning(YES_NO); - } - - clear_warning(); - print_warning(WRITING_PART); - refresh(); - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - write_sector(buffer.c.b, 0); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - /* Read the extended partition table from disk ??? KEM */ - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - write_sector(buffer.c.b, p_info[i].first_sector); - } - - sync(); - sleep(2); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; - sync(); - sleep(4); - - clear_warning(); - if (changed) - print_warning(YES_WRITE); - else - print_warning(RRPART_FAILED); -} - -void fp_printf(FILE *fp, char *format, ...) -{ - va_list args; - char buf[1024]; - int y, x; - - va_start(args, format); - vsprintf(buf, format, args); - va_end(args); - - if (fp == NULL) { - /* The following works best if the string to be printed has at - most only one newline. */ - printw("%s", buf); - getyx(stdscr, y, x); - if (y >= COMMAND_LINE_Y-2) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - erase(); - move(0, 0); - } - } else - fprintf(fp, "%s", buf); -} - -#define MAX_PER_LINE 16 -void print_file_buffer(FILE *fp, char *buffer) -{ - int i,l; - - for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { - if (l == 0) - fp_printf(fp, "0x%03X:", i); - fp_printf(fp, " %02X", (unsigned char) buffer[i]); - if (l == MAX_PER_LINE - 1) { - fp_printf(fp, "\n"); - l = -1; - } - } - if (l > 0) - fp_printf(fp, "\n"); - fp_printf(fp, "\n"); -} - -void print_raw_table(void) -{ - int i, to_file; - partition_table buffer; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Disk Drive: %s\n", disk_device); - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - print_file_buffer(fp, buffer.c.b); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - print_file_buffer(fp, buffer.c.b); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_p_info_entry(FILE *fp, partition_info *p) -{ - int size; - char part_str[21]; - - if (p->id == UNUSABLE) - fp_printf(fp, " None "); - else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) - fp_printf(fp, " Pri/Log"); - else if (p->id == FREE_SPACE && p->num == PRIMARY) - fp_printf(fp, " Primary"); - else if (p->id == FREE_SPACE && p->num == LOGICAL) - fp_printf(fp, " Logical"); - else - fp_printf(fp, "%2d %-7.7s", p->num+1, - IS_LOGICAL(p->num) ? "Logical" : "Primary"); - - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->first_sector, - ((p->first_sector/(sectors*heads)) != - ((float)p->first_sector/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->last_sector, - (((p->last_sector+1)/(sectors*heads)) != - ((float)(p->last_sector+1)/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - fp_printf(fp, "%6d%c", p->offset, - ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && - (p->offset != sectors)) || - (p->first_sector != 0 && IS_PRIMARY(p->num) && - p->offset != 0)) ? - '#' : ' ')); - - fp_printf(fp, " "); - - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%7d%c", size, - ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - if (p->id == UNUSABLE) - sprintf(part_str, "%.16s", "Unusable"); - else if (p->id == FREE_SPACE) - sprintf(part_str, "%.16s", "Free Space"); - else if (partition_type[p->id]) - sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); - else - sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); - fp_printf(fp, "%-21.21s", part_str); - - fp_printf(fp, " "); - - if (p->flags == ACTIVE_FLAG) - fp_printf(fp, "Boot (%02X)", p->flags); - else if (p->flags != 0) - fp_printf(fp, "Unknown (%02X)", p->flags); - else - fp_printf(fp, "None (%02X)", p->flags); - - fp_printf(fp, "\n"); -} - -void print_p_info(void) -{ - char fname[LINE_LENGTH]; - FILE *fp; - int i, to_file, pext = (ext_info.id == EXTENDED); - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Partition Table for %s\n", disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, " First Last\n"); - fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); - fp_printf(fp, "-- ------- -------- -------- ------- -------- --------------------- ---------\n"); - - for (i = 0; i < num_parts; i++) { - if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { - print_p_info_entry(fp,&ext_info); - pext = FALSE; - } - print_p_info_entry(fp, &(p_info[i])); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_part_entry(FILE *fp, int num, partition_info *pi) -{ - int first = 0, start = 0, end = 0, size = 0; - int ss = 0, sh = 0, sc = 0; - int es = 0, eh = 0, ec = 0; - int flags = 0, id = 0; - - if (pi != NULL) { - flags = pi->flags; - id = pi->id; - - if (IS_LOGICAL(num)) - first = pi->offset; - else - first = pi->first_sector + pi->offset; - - start = pi->first_sector + pi->offset; - end = pi->last_sector; - size = end - start + 1; - if ((start/(sectors*heads)) > 1023) - start = heads*sectors*1024 - 1; - if ((end/(sectors*heads)) > 1023) - end = heads*sectors*1024 - 1; - - ss = start % sectors + 1; - start /= sectors; - sh = start % heads; - sc = start / heads; - - es = end % sectors + 1; - end /= sectors; - eh = end % heads; - ec = end / heads; - } - - fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", - num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); -} - - -void print_part_table(void) -{ - int i, j, to_file; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Partition Table for %s\n", disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, " ---Starting--- ----Ending---- Start Number\n"); - fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); - fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- -------\n"); - - for (i = 0; i < 4; i++) { - for (j = 0; - j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); - j++); - if (j < num_parts) { - print_part_entry(fp, i, &(p_info[j])); - } else if (ext_info.id == EXTENDED && ext_info.num == i) { - print_part_entry(fp, i, &ext_info); - } else { - print_part_entry(fp, i, NULL); - } - } - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) - print_part_entry(fp, p_info[i].num, &(p_info[i])); - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_tables(void) -{ - int done = FALSE; - - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Print format [rst]: "); - clrtoeol(); - refresh(); - - while (!done) - switch (toupper(getch())) { - case 'R': - print_raw_table(); - done = TRUE; - break; - case 'S': - print_p_info(); - done = TRUE; - break; - case 'T': - print_part_table(); - done = TRUE; - break; - case ESC: - done = TRUE; - break; - } -} - -#define END_OF_HELP "EOHS!" -#define NEW_HELP_SCREEN "SNHS!" -void display_help() -{ - char *help_text[] = { - "Help Screen for cfdisk " VERSION, - "", - "This is cfdisk, a curses based disk partitioning programs, which", - "allows you to create, delete and modify partitions on your hard", - "disk drive.", - "", - "Copyright (C) 1994 Kevin E. Martin", - "", - "Command Meaning", - "------- -------", - " b Toggle bootable flag of the current partition", - " d Delete the current partition", - " g Change cylinders, heads, sectors-per-track parameters", - " WARNING: This option should only be used by people who", - " know what they are doing.", - " h Print this screen", - " m Maximize disk usage of the current partition", - " Note: This may make the partition incompatible with", - " DOS, OS/2, ...", - " n Create new partition from free space", - " p Print partition table to the screen or to a file", - " There are several different formats for the partition", - " that you can choose from:", - " r - Raw data (exactly what would be written to disk)", - " s - Table ordered by sectors", - " t - Table in raw format", - " q Quit program without writing partition table", - " t Change the filesystem type", - " u Change units of the partition size display", - " Rotates through Mb, sectors and cylinders", - " W Write partition table to disk (must enter upper case W)", - " Since this might destroy data on the disk, you must", - " either confirm or deny the write by entering `yes' or", - " `no'", - "Up Arrow Move cursor to the previous partition", - "Down Arrow Move cursor to the next partition", - "CTRL-L Redraws the screen", - " ? Print this screen", - "", - "Note: All of the commands can be entered with either upper or lower", - "case letters (except for Writes).", - END_OF_HELP - }; - - int cur_line = 0; - FILE *fp = NULL; - - erase(); - move(0, 0); - while (strcmp(help_text[cur_line], END_OF_HELP)) - if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - erase(); - move(0, 0); - cur_line++; - } else - fp_printf(fp, "%s\n", help_text[cur_line++]); - - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); -} - -int change_geometry(void) -{ - int ret_val = FALSE; - int done = FALSE; - char def[LINE_LENGTH]; - char response[LINE_LENGTH]; - int tmp_val; - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Change disk geometry information [chs]: "); - clrtoeol(); - refresh(); - - clear_warning(); - - switch (toupper(getch())) { - case 'C': - sprintf(def, "%d", cylinders); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of cylinders: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { - cylinders = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_CYLINDERS); - } - break; - case 'H': - sprintf(def, "%d", heads); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of heads: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_HEADS) { - heads = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_HEADS); - } - break; - case 'S': - sprintf(def, "%d", sectors); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of sectors per track: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { - sectors = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_SECTORS); - } - break; - case ESC: - case CR: - done = TRUE; - break; - default: - putchar(BELL); - break; - } - } - - if (ret_val) { - if (p_info[num_parts-1].last_sector > heads*sectors*cylinders-1) { - while (p_info[num_parts-1].first_sector > heads*sectors*cylinders-1) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) - remove_part(num_parts-1); - else - del_part(num_parts-1); - } - - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; - - if (ext_info.last_sector > heads*sectors*cylinders-1) - ext_info.last_sector = heads*sectors*cylinders - 1; - } else if (p_info[num_parts-1].last_sector < heads*sectors*cylinders-1) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; - } else { - insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, - p_info[num_parts-1].last_sector+1, - heads*sectors*cylinders-1, 0); - } - } - - /* Make sure the partitions are correct */ - check_part_info(); - } - - return ret_val; -} - -void change_id(int i) -{ - char id[LINE_LENGTH], def[LINE_LENGTH]; - int num_types = 0; - int num_across, num_down; - int len, new_id = LINUX; - int y_start, y_end; - int j, pos; - - for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) - num_types++; - - num_across = COLS/COL_ID_WIDTH; - num_down = (((float)num_types)/num_across + 1); - y_start = COMMAND_LINE_Y - 1 - num_down; - if (y_start > DISK_TABLE_START+cur_part+4) - y_start = DISK_TABLE_START+cur_part+4; - y_end = y_start + num_down - 1; - - for (j = y_start - 1; j <= y_end + 1; j++) { - move(j, 0); - clrtoeol(); - } - - for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) { - move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); - printw("%02X %-16.16s", j, partition_type[j]); - pos++; - } - - sprintf(def, "%02X", new_id); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); - if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) - return; - - if (len != GS_DEFAULT) { - if (!isxdigit(id[0])) - return; - new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); - if (len == 2) - if (isxdigit(id[1])) - new_id = new_id*16 + - (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); - else - return; - } - - if (new_id == 0) - print_warning(ID_EMPTY); - else if (new_id == EXTENDED) - print_warning(ID_EXT); - else - p_info[i].id = new_id; -} - -void draw_partition(int i) -{ - int size, j; - int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - - if (!arrow_cursor) { - move(y, 0); - for (j = 0; j < COLS; j++) - addch(' '); - } - - if (p_info[i].id > 0) { - mvprintw(y, NAME_START, - "%s%d", disk_device, p_info[i].num+1); - if (p_info[i].flags) { - if (p_info[i].flags == ACTIVE_FLAG) - mvaddstr(y, FLAGS_START, "Boot"); - else - mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - addstr(", NC"); - } else { - if (p_info[i].offset != 0) - addstr(", NC"); - } - } else { - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - mvaddstr(y, FLAGS_START, "NC"); - } else { - if (p_info[i].offset != 0) - mvaddstr(y, FLAGS_START, "NC"); - } - } - } - mvaddstr(y, PTYPE_START, - (p_info[i].id == UNUSABLE ? "" : - (IS_LOGICAL(p_info[i].num) ? "Logical" : - (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]); - else - mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); - - size = p_info[i].last_sector - p_info[i].first_sector + 1; - if (display_units == SECTORS) - mvprintw(y, SIZE_START, "%9d", size); - else if (display_units == CYLINDERS) - mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); - else - mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); - if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || - ((p_info[i].first_sector/(sectors*heads)) != - ceiling(p_info[i].first_sector/(sectors*heads)))) - mvprintw(y, COLUMNS-1, "*"); -} - -void init_const(void) -{ - if (!defined) { - NAME_START = (((float)NAME_START)/COLUMNS)*COLS; - FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; - PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; - FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; - SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; - COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; - - COMMAND_LINE_Y = LINES - 4; - WARNING_START = LINES - 2; - - if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) - NUM_ON_SCREEN = 1; - - COLUMNS = COLS; - defined = TRUE; - } -} - -void draw_screen(void) -{ - int i; - char *line; - - line = (char *)malloc((COLS+1)*sizeof(char)); - - if (warning_last_time) { - for (i = 0; i < COLS; i++) { - move(WARNING_START, i); - line[i] = inch(); - } - line[COLS] = 0; - } - - erase(); - - if (warning_last_time) - mvaddstr(WARNING_START, 0, line); - - - sprintf(line, "cfdisk %s", VERSION); - mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); - sprintf(line, "Disk Drive: %s", disk_device); - mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); - sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", - heads, sectors, cylinders); - mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); - - 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, FSTYPE_START, "FS Type"); - if (display_units == SECTORS) - mvaddstr(DISK_TABLE_START, SIZE_START, " Sectors"); - else if (display_units == CYLINDERS) - mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); - else - mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); - - move(DISK_TABLE_START+1, 1); - for (i = 1; i < COLS-1; i++) - addch('-'); - - if (NUM_ON_SCREEN >= num_parts) - for (i = 0; i < num_parts; i++) - draw_partition(i); - else - for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && - i < num_parts; - i++) - draw_partition(i); - - free(line); -} - -int draw_cursor(int move) -{ - if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) - return -1; - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); - else - draw_partition(cur_part); - - cur_part += move; - - if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) - draw_screen(); - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); - else { - standout(); - draw_partition(cur_part); - standend(); - } - - return 0; -} - -void die(int dummy) -{ - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - -void do_curses_fdisk(void) -{ - int done = FALSE; - char command; - - initscr(); - old_SIGINT = signal(SIGINT, die); - old_SIGTERM = signal(SIGTERM, die); -#ifdef DEBUG - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); -#endif - - cbreak(); - noecho(); - nonl(); - - init_const(); - - fill_p_info(); - - draw_screen(); - - while (!done) { - (void)draw_cursor(0); - - if (p_info[cur_part].id == FREE_SPACE) - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hnpquW?]: "); - else if (p_info[cur_part].id > 0) - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [bdhmpqtuW?]: "); - else - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hpquW?]: "); - - clrtoeol(); - refresh(); - - clear_warning(); - - switch (command = getch()) { - case 'B': - case 'b': - if (p_info[cur_part].id > 0) - p_info[cur_part].flags ^= 0x80; - else - print_warning(NO_FLAGS); - break; - case 'D': - case 'd': - if (p_info[cur_part].id > 0) { - del_part(cur_part); - if (cur_part >= num_parts) - cur_part = num_parts - 1; - draw_screen(); - } else - print_warning(DEL_EMPTY); - break; - case 'G': - case 'g': - if (change_geometry()) - draw_screen(); - break; - case 'M': - case 'm': - if (p_info[cur_part].id > 0) { - if (p_info[cur_part].first_sector == 0 || - IS_LOGICAL(p_info[cur_part].num)) { - if (p_info[cur_part].offset == sectors) - p_info[cur_part].offset = 1; - else - p_info[cur_part].offset = sectors; - draw_screen(); - } else if (p_info[cur_part].offset != 0) - p_info[cur_part].offset = 0; - else - print_warning(MAX_UNMAXABLE); - } else - print_warning(MAX_UNMAXABLE); - break; - case 'N': - case 'n': - if (p_info[cur_part].id == FREE_SPACE) { - new_part(cur_part); - draw_screen(); - } else if (p_info[cur_part].id == UNUSABLE) - print_warning(ADD_UNUSABLE); - else - print_warning(ADD_EXISTS); - break; - case 'P': - case 'p': - print_tables(); - draw_screen(); - break; - case 'Q': - case 'q': - done = TRUE; - break; - case 'T': - case 't': - if (p_info[cur_part].id > 0) { - change_id(cur_part); - draw_screen(); - } else - print_warning(TYPE_EMPTY); - break; - case 'U': - case 'u': - if (display_units == MEGABYTES) - display_units = SECTORS; - else if (display_units == SECTORS) - display_units = CYLINDERS; - else if (display_units == CYLINDERS) - display_units = MEGABYTES; - draw_screen(); - break; - case 'W': - write_part_table(); - break; - case 'H': - case 'h': - case '?': - display_help(); - draw_screen(); - break; - case ESC: - if ((command = getch()) == '[') { - command = getch(); - switch (command) { - case 'A' : /* Up arrow */ - if (!draw_cursor(-1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case 'B' : /* Down arrow */ - if (!draw_cursor(1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case 'C' : /* Right arrow */ - case 'D' : /* Left arrow */ - } - } - if (command) - putchar(BELL); /* CTRL-G */ - break; - case REDRAWKEY: - clear(); - draw_screen(); - break; - default: - print_warning(BAD_COMMAND); - putchar(BELL); /* CTRL-G */ - } - } - - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - -void copyright(void) -{ - fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\n"); -} - -void usage(char *prog_name) -{ - fprintf(stderr, - "%s: [-avz] [-c # cylinders] [-h # heads] [-s # sectors/track]\n", - prog_name); - fprintf(stderr, - "[ -P opt ] device\n"); - copyright(); -} - -void main(int argc, char **argv) -{ - char c; - int i, len; - - while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) - switch (c) { - case 'a': - arrow_cursor = TRUE; - break; - case 'c': - cylinders = atoi(optarg); - if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); - exit(1); - } - break; - case 'h': - heads = atoi(optarg); - if (heads <= 0 || heads > MAX_HEADS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); - exit(1); - } - break; - case 's': - sectors = atoi(optarg); - if (sectors <= 0 || sectors > MAX_SECTORS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); - exit(1); - } - break; - case 'v': - fprintf(stderr, "cfdisk %s\n", VERSION); - copyright(); - exit(0); - case 'z': - zero_table = TRUE; - break; - case 'P': - len = strlen(optarg); - for (i = 0; i < len; i++) { - switch (optarg[i]) { - case 'r': - print_only |= PRINT_RAW_TABLE; - break; - case 's': - print_only |= PRINT_SECTOR_TABLE; - break; - case 't': - print_only |= PRINT_PARTITION_TABLE; - break; - default: - usage(argv[0]); - break; - } - } - break; - default: - usage(argv[0]); - exit(1); - } - - if (argc-optind == 1) - disk_device = argv[optind]; - else if (argc-optind != 0) { - usage(argv[0]); - exit(1); - } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - - if (print_only) { - fill_p_info(); - if (print_only & PRINT_RAW_TABLE) - print_raw_table(); - if (print_only & PRINT_SECTOR_TABLE) - print_p_info(); - if (print_only & PRINT_PARTITION_TABLE) - print_part_table(); - } else - do_curses_fdisk(); -} diff --git a/disk-utils/cfdisk.c.orig b/disk-utils/cfdisk.c.orig deleted file mode 100644 index 3b9f22f58..000000000 --- a/disk-utils/cfdisk.c.orig +++ /dev/null @@ -1,2066 +0,0 @@ -/**************************************************************************** - * - * CFDISK - * - * cfdisk is a curses based disk drive partitioning program that can - * create partitions for a wide variety of operating systems including - * Linux, MS-DOS and OS/2. - * - * cfdisk was inspired by the fdisk program, by A. V. Le Blanc - * (LeBlanc@mcc.ac.uk). - * - * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) - * - * cfdisk 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. - * - * cfdisk 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 cfdisk; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu - * - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for BLKRRPART */ - -typedef long ext2_loff_t; -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); - -#define VERSION "0.8 BETA (>2GB)" - -#define DEFAULT_DEVICE "/dev/hda" -#define ALTERNATE_DEVICE "/dev/sda" - -#define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 - -#define SECTOR_SIZE 512 - -#define MAX_CYLINDERS 65535 -#define MAX_HEADS 255 -#define MAX_SECTORS 63 - -#define ACTIVE_FLAG 0x80 -#define PART_TABLE_FLAG 0xAA55 - -#define UNUSABLE -1 -#define FREE_SPACE 0x00 -#define EXTENDED 0x05 -#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" -#define DEL_EMPTY "Cannot delete an empty partition" -#define ID_EMPTY "Cannot change FS Type to empty" -#define ID_EXT "Cannot change FS Type to extended" -#define NEED_EXT "No room to create the extended partition" -#define NO_FLAGS "Cannot make this partition bootable" -#define NO_MORE_PARTS "No more partitions" -#define PRINT_OPEN_ERR "Cannot open file '%s'" -#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" -#define TYPE_EMPTY "Cannot change the type of an empty partition" -#define BAD_COMMAND "Illegal command" -#define MAX_UNMAXABLE "Cannot maximize this partition" -#define BAD_OPEN "Cannot open disk drive" -#define BAD_SEEK "Cannot seek on disk drive" -#define BAD_READ "Cannot read disk drive" -#define BAD_WRITE "Cannot write disk drive" -#define BAD_GEOMETRY "Cannot read disk drive geometry" -#define BAD_PRIMARY "Bad primary partition" -#define BAD_LOGICAL "Bad logical partition" -#define BAD_CYLINDERS "Illegal cylinders value" -#define BAD_HEADS "Illegal heads value" -#define BAD_SECTORS "Illegal sectors value" -#define WRITE_WARN "Warning!! This may destroy data on your disk!" -#define YES_NO "Please enter `yes' or `no'" -#define WRITING_PART "Writing partition table to disk..." -#define YES_WRITE "Wrote partition table to disk" -#define NO_WRITE "Did not write partition table to disk" -#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." - -#define PRI_OR_LOG -1 -#define PRIMARY -2 -#define LOGICAL -3 - -#define COL_ID_WIDTH 20 - -#define CR '\015' -#define ESC '\033' -#define DEL '\177' -#define BELL '\007' -/* '\014' == ^L */ -#define REDRAWKEY '\014' - -/* Display units */ -#define MEGABYTES 1 -#define SECTORS 2 -#define CYLINDERS 3 - -#define GS_DEFAULT -1 -#define GS_ESCAPE -2 - -#define PRINT_RAW_TABLE 1 -#define PRINT_SECTOR_TABLE 2 -#define PRINT_PARTITION_TABLE 4 - -#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) -#define IS_LOGICAL(p) ((p) > 3) - -#define round_int(d) ((double)((int)(d+0.5))) -#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) - -#define set_hsc(h,s,c,sector) \ -{ \ - s = sector % sectors + 1; \ - sector /= sectors; \ - h = sector % heads; \ - sector /= heads; \ - c = sector & 0xFF; \ - s |= (sector >> 2) & 0xC0;\ -} - -#define ALIGNMENT 2 -typedef union { - struct { - unsigned char align[ALIGNMENT]; - unsigned char b[SECTOR_SIZE]; - } c; - struct { - unsigned char align[ALIGNMENT]; - unsigned char buffer[0x1BE]; - struct partition part[4]; - unsigned short flag; - } p; -} partition_table; - -typedef struct { - int first_sector; /* first sector in partition */ - int last_sector; /* last sector in partition */ - int offset; /* offset from first sector to start of data */ - int flags; /* active == 0x80 */ - int id; /* filesystem type */ - int num; /* number of partition -- primary vs. logical */ -} partition_info; - -char *disk_device = DEFAULT_DEVICE; -int fd; -int heads = 0; -int sectors = 0; -int cylinders = 0; -int changed = FALSE; -int opened = FALSE; - -partition_info p_info[MAXIMUM_PARTS]; -partition_info ext_info; -int num_parts = 0; - -int logical = 0; -int logical_sectors[MAXIMUM_PARTS]; - -__sighandler_t old_SIGINT, old_SIGTERM; - -int arrow_cursor = FALSE; -int display_units = MEGABYTES; -int zero_table = FALSE; -int print_only = 0; - -/* Curses screen information */ -int cur_part = 0; -int warning_last_time = FALSE; -int defined = FALSE; -int COLUMNS = 80; -int NUM_ON_SCREEN = 1; - -/* Y coordinates */ -int HEADER_START = 0; -int DISK_TABLE_START = 5; -int WARNING_START = 23; -int COMMAND_LINE_Y = 21; - -/* X coordinates */ -int NAME_START = 4; -int FLAGS_START = 16; -int PTYPE_START = 30; -int FSTYPE_START = 45; -int SIZE_START = 70; -int COMMAND_LINE_X = 5; - -#define NUM_PART_TYPES 256 -char *partition_type[NUM_PART_TYPES] = { - [LINUX_MINIX] = "Linux/MINIX", - [LINUX_SWAP] = "Linux Swap", - [LINUX] = "Linux", - [FREE_SPACE] = "Free Space", - [EXTENDED] = "Extended", - [0x01] = "DOS 12-bit FAT", - [0x04] = "DOS 16-bit < 32Mb", - [0x06] = "DOS 16-bit >=32Mb", - [0x07] = "OS/2 HPFS", - [0x0A] = "OS/2 Boot Manager", - [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. - */ - - [0x02] = "XENIX root", - [0x03] = "XENIX usr", - [0x08] = "AIX", - [0x09] = "AIX bootable", - [0x40] = "Venix 80286", - [0x51] = "Novell?", - [0x52] = "Microport", - [0x63] = "GNU HURD", - [0x64] = "Novell", - [0x75] = "PC/IX", - [0x80] = "Old MINIX", - [0x93] = "Amoeba", - [0x94] = "Amoeba BBT", - [0xB7] = "BSDI fs", - [0xB8] = "BSDI swap", - [0xC7] = "Syrinx", - [0xDB] = "CP/M", - [0xE1] = "DOS access", - [0xE3] = "DOS R/O", - [0xF2] = "DOS secondary", - [0xFF] = "BBT" -}; - -void fdexit(int ret) -{ - if (opened) - close(fd); - - if (changed) { - fprintf(stderr, "Disk has been changed.\n"); - fprintf(stderr, "Reboot the system to ensure the partition " - "table is correctly updated.\n"); - - fprintf( stderr, "\nWARNING: If you have created or modified any\n" - "DOS 6.x partitions, please see the cfdisk manual\n" - "page for additional information.\n" ); - } - - - exit(ret); -} - -int get_string(char *str, int len, char *def) -{ - char c; - int i = 0; - int x, y; - int use_def = FALSE; - - getyx(stdscr, y, x); - clrtoeol(); - - str[i] = 0; - - if (def != NULL) { - mvaddstr(y, x, def); - move(y, x); - use_def = TRUE; - } - - refresh(); - while ((c = getch()) != '\n' && c != CR) { - switch (c) { - case ESC: - move(y, x); - clrtoeol(); - refresh(); - return GS_ESCAPE; - case DEL: - case '\b': - if (i > 0) { - str[--i] = 0; - mvaddch(y, x+i, ' '); - move(y, x+i); - } else if (use_def) { - clrtoeol(); - use_def = FALSE; - } else - putchar(BELL); - break; - default: - if (i < len && isprint(c)) { - mvaddch(y, x+i, c); - if (use_def) { - clrtoeol(); - use_def = FALSE; - } - str[i++] = c; - str[i] = 0; - } else - putchar(BELL); - } - refresh(); - } - - if (use_def) - return GS_DEFAULT; - else - return i; -} - -void clear_warning(void) -{ - int i; - - if (!warning_last_time) - return; - - move(WARNING_START,0); - for (i = 0; i < COLS; i++) - addch(' '); - - warning_last_time = FALSE; -} - -void print_warning(char *s) -{ - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ - - warning_last_time = TRUE; -} - -void fatal(char *s) -{ - char str[LINE_LENGTH]; - - sprintf(str, "FATAL ERROR: %s", s); - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "Press any key to exit fdisk"); - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - - refresh(); - - (void)getch(); - - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(1); -} - -void read_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_READ); -} - -void write_sector(char *buffer, int sect_num) -{ - if (ext2_llseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(BAD_SEEK); - if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(BAD_WRITE); -} - -void check_part_info(void) -{ - int i, pri = 0, log = 0; - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (ext_info.id == EXTENDED) - if (log > 0) - pri++; - else { - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; - } - - if (pri >= 4) - for (i = 0; i < num_parts; i++) - if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) - if (ext_info.id == EXTENDED) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else - p_info[i].id = UNUSABLE; - else /* if (ext_info.id != EXTENDED) */ - p_info[i].id = UNUSABLE; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - else /* if (pri < 4) */ - for (i = 0; i < num_parts; i++) { - if (p_info[i].id == UNUSABLE) - p_info[i].id = FREE_SPACE; - if (p_info[i].id == FREE_SPACE) - if (ext_info.id == EXTENDED) - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) - p_info[i].num = LOGICAL; - else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else - p_info[i].num = PRIMARY; - else /* if (ext_info.id != EXTENDED) */ - p_info[i].num = PRI_OR_LOG; - else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } -} - -void remove_part(int i) -{ - int p; - - for (p = i; p < num_parts; p++) - p_info[p] = p_info[p+1]; - - num_parts--; -} - -void insert_part(int i, int num, int id, int flags, int first, int last, - int offset) -{ - int p; - - for (p = num_parts; p > i; p--) - p_info[p] = p_info[p-1]; - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - - num_parts++; -} - -void del_part(int i) -{ - int num = p_info[i].num; - - if (i > 0 && (p_info[i-1].id == FREE_SPACE || - p_info[i-1].id == UNUSABLE)) { - /* Merge with previous partition */ - p_info[i-1].last_sector = p_info[i].last_sector; - remove_part(i--); - } - - if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || - p_info[i+1].id == UNUSABLE)) { - /* Merge with next partition */ - p_info[i+1].first_sector = p_info[i].first_sector; - remove_part(i); - } - - if (i > 0) - p_info[i].first_sector = p_info[i-1].last_sector + 1; - else - p_info[i].first_sector = 0; - - if (i < num_parts - 1) - p_info[i].last_sector = p_info[i+1].first_sector - 1; - else - p_info[i].last_sector = sectors*heads*cylinders - 1; - - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - - if (IS_LOGICAL(num)) { - /* We have a logical partition --> shrink the extended partition - * if (1) this is the first logical drive, or (2) this is the - * last logical drive; and if there are any other logical drives - * then renumber the ones after "num". - */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) - ext_info.first_sector = p_info[i].last_sector + 1; - if (i == num_parts-1 || - (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) - ext_info.last_sector = p_info[i].first_sector - 1; - for (i = 0; i < num_parts; i++) - if (p_info[i].num > num) - p_info[i].num--; - } - - /* Clean up the rest of the partitions */ - check_part_info(); -} - -int add_part(int num, int id, int flags, int first, int last, int offset) -{ - int i, pri = 0, log = 0; - - if (num_parts == MAXIMUM_PARTS || - first < 0 || - first >= cylinders*heads*sectors || - last < 0 || - last >= cylinders*heads*sectors) - return -1; - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (ext_info.id == EXTENDED && log > 0) - pri++; - - if (IS_PRIMARY(num)) - if (pri >= 4) - return -1; - else - pri++; - - for (i = 0; p_info[i].last_sector < first; i++); - - if (p_info[i].id != FREE_SPACE || last > p_info[i].last_sector) - return -1; - - if (id == EXTENDED) - if (ext_info.id != FREE_SPACE) - return -1; - else if (IS_PRIMARY(num)) { - ext_info.first_sector = first; - ext_info.last_sector = last; - ext_info.offset = offset; - ext_info.flags = flags; - ext_info.id = EXTENDED; - ext_info.num = num; - - return 0; - } else - return -1; - - if (IS_LOGICAL(num)) { - if (ext_info.id != EXTENDED) { - print_warning("!!!! Internal error creating logical " - "drive with no extended partition !!!!"); - } else { - /* We might have a logical partition outside of the extended - * partition's range --> we have to extend the extended - * partition's range to encompass this new partition, but we - * must make sure that there are no primary partitions between - * it and the closest logical drive in extended partition. - */ - if (first < ext_info.first_sector) { - if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else { - if (first == 0) { - ext_info.first_sector = 0; - ext_info.offset = first = offset; - } else - ext_info.first_sector = first; - } - } else if (last > ext_info.last_sector) { - if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { - print_warning(TWO_EXTENDEDS); - return -1; - } else - ext_info.last_sector = last; - } - } - } - - if (first != p_info[i].first_sector && - !(IS_LOGICAL(num) && first == offset)) { - insert_part(i, PRI_OR_LOG, FREE_SPACE, 0, - p_info[i].first_sector, first-1, 0); - i++; - } - - if (last != p_info[i].last_sector) - insert_part(i+1, PRI_OR_LOG, FREE_SPACE, 0, - last+1, p_info[i].last_sector, 0); - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - - check_part_info(); - - return 0; -} - -int find_primary(void) -{ - int num = 0, cur = 0; - - while (cur < num_parts && IS_PRIMARY(num)) - if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (ext_info.id == EXTENDED && ext_info.num == num)) { - num++; - cur = 0; - } else - cur++; - - if (!IS_PRIMARY(num)) - return -1; - else - return num; -} - -int find_logical(int i) -{ - int num = -1; - int j; - - for (j = i; j < num_parts && num == -1; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - num = p_info[j].num; - - if (num == -1) { - num = 4; - for (j = 0; j < num_parts; j++) - if (p_info[j].id > 0 && p_info[j].num == num) - num++; - } - - return num; -} - -void inc_logical(int i) -{ - int j; - - for (j = i; j < num_parts; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - p_info[j].num++; -} - -void new_part(int i) -{ - char response[LINE_LENGTH], def[LINE_LENGTH]; - char c; - int first = p_info[i].first_sector; - int last = p_info[i].last_sector; - int offset = 0; - int flags = 0; - int id = LINUX; - int num = -1; - int num_sects = last - first + 1; - int len, ext, j; - - if (p_info[i].num == PRI_OR_LOG) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Primary or logical [pl]: "); - clrtoeol(); - refresh(); - while (toupper(c = getch()) != 'P' && toupper(c) != 'L' && c != ESC); - if (toupper(c) == 'P') - num = find_primary(); - else if (toupper(c) == 'L') - num = find_logical(i); - else - return; - } else if (p_info[i].num == PRIMARY) - num = find_primary(); - else if (p_info[i].num == LOGICAL) - num = find_logical(i); - else - print_warning("!!! Internal error !!!"); - - sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); - if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && - len != GS_DEFAULT) - return; - else if (len > 0) { -#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) - for (j = 0; - j < len-1 && (isdigit(response[j]) || response[j] == '.'); - j++); - if (toupper(response[j]) == 'K') { - num_sects = num_cyls(atof(response)*1024)*sectors*heads; - } else if (toupper(response[j]) == 'M') { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } else if (toupper(response[j]) == 'C') { - num_sects = round_int(atof(response))*sectors*heads; - } else if (toupper(response[j]) == 'S') { - num_sects = round_int(atof(response)); - } else { - num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; - } - } - - if (num_sects <= 0 || - num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) - return; - - if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { - /* Determine where inside free space to put partition. - */ - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Add partition at beginning or end of free space [be]: "); - clrtoeol(); - refresh(); - while (toupper(c = getch()) != 'B' && toupper(c) != 'E' && c != ESC); - if (toupper(c) == 'B') - last = first + num_sects - 1; - else if (toupper(c) == 'E') - first = last - num_sects + 1; - else - return; - } - - if (IS_LOGICAL(num) && ext_info.id != EXTENDED) { - /* We want to add a logical partition, but need to create an - * extended partition first. - */ - if ((ext = find_primary()) < 0) { - print_warning(NEED_EXT); - return; - } - (void)add_part(ext, EXTENDED, 0, first, last, - (first == 0 ? sectors : 0)); - } - - if (IS_LOGICAL(num)) - inc_logical(i); - - /* Now we have a complete partition to ourselves */ - if (first == 0 || IS_LOGICAL(num)) - offset = sectors; - - (void)add_part(num, id, flags, first, last, offset); -} - -void clear_p_info(void) -{ - num_parts = 1; - p_info[0].first_sector = 0; - p_info[0].last_sector = sectors*heads*cylinders - 1; - p_info[0].offset = 0; - p_info[0].flags = 0; - p_info[0].id = FREE_SPACE; - p_info[0].num = PRI_OR_LOG; - - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; -} - -void fill_p_info(void) -{ - int p, i; - struct hd_geometry geometry; - partition_table buffer; - partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; - - if ((fd = open(disk_device, O_RDWR)) < 0) - fatal(BAD_OPEN); - read_sector(buffer.c.b, 0); - - if (!ioctl(fd, HDIO_GETGEO, &geometry)) { - if (!heads) - heads = geometry.heads; - if (!sectors) - sectors = geometry.sectors; - if (!cylinders) - cylinders = geometry.cylinders; - } - - if (!heads || !sectors || !cylinders) - fatal(BAD_GEOMETRY); - - clear_p_info(); - - if (!zero_table) { - for (i = 0; i < 4; i++) { - if (buffer.p.part[i].sys_ind > 0 && - add_part(i, - buffer.p.part[i].sys_ind, - buffer.p.part[i].boot_ind, - ((buffer.p.part[i].start_sect <= sectors) ? - 0 : buffer.p.part[i].start_sect), - buffer.p.part[i].start_sect + - buffer.p.part[i].nr_sects - 1, - ((buffer.p.part[i].start_sect <= sectors) ? - buffer.p.part[i].start_sect : 0))) { - fatal(BAD_PRIMARY); - } - if (buffer.p.part[i].sys_ind == EXTENDED) - tmp_ext = ext_info; - } - - if (tmp_ext.id == EXTENDED) { - ext_info = tmp_ext; - logical_sectors[logical] = ext_info.first_sector; - read_sector(buffer.c.b, logical_sectors[logical++]); - i = 4; - do { - for (p = 0; - p < 4 && (!buffer.p.part[p].sys_ind || - buffer.p.part[p].sys_ind == 5); - p++); - if (p > 3) - fatal(BAD_LOGICAL); - - if (add_part(i++, - buffer.p.part[p].sys_ind, - buffer.p.part[p].boot_ind, - logical_sectors[logical-1], - logical_sectors[logical-1] + - buffer.p.part[p].start_sect + - buffer.p.part[p].nr_sects - 1, - buffer.p.part[p].start_sect)) { - fatal(BAD_LOGICAL); - } - - for (p = 0; - p < 4 && buffer.p.part[p].sys_ind != 5; - p++); - if (p < 4) { - logical_sectors[logical] = - ext_info.first_sector + buffer.p.part[p].start_sect; - read_sector(buffer.c.b, logical_sectors[logical++]); - } - } while (p < 4 && logical < MAXIMUM_PARTS-4); - } - } -} - -void fill_part_table(struct partition *p, partition_info *pi) -{ - int sects; - - p->boot_ind = pi->flags; - p->sys_ind = pi->id; - if (IS_LOGICAL(pi->num)) - p->start_sect = pi->offset; - else - p->start_sect = pi->first_sector + pi->offset; - p->nr_sects = pi->last_sector - (pi->first_sector+pi->offset) + 1; - sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector+pi->offset); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); -} - -void fill_primary_table(partition_table *buffer) -{ - int i; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - for (i = 0; i < num_parts; i++) - if (IS_PRIMARY(p_info[i].num)) - fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); - - if (ext_info.id == EXTENDED) - fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); - - buffer->p.flag = PART_TABLE_FLAG; -} - -void fill_logical_table(partition_table *buffer, partition_info *pi) -{ - struct partition *p; - int i, sects; - - for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); - if (i == logical || buffer->p.flag != (unsigned short)PART_TABLE_FLAG) - for (i = 0; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - fill_part_table(&(buffer->p.part[0]), pi); - - for (i = 0; - i < num_parts && pi->num != p_info[i].num - 1; - i++); - - if (i < num_parts) { - p = &(buffer->p.part[1]); - pi = &(p_info[i]); - - p->boot_ind = 0; - p->sys_ind = 5; - p->start_sect = pi->first_sector - ext_info.first_sector; - p->nr_sects = pi->last_sector - pi->first_sector + 1; - sects = ((pi->first_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->first_sector); - set_hsc(p->head, p->sector, p->cyl, sects); - sects = ((pi->last_sector/(sectors*heads) > 1023) ? - heads*sectors*1024 - 1 : pi->last_sector); - set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); - } - - buffer->p.flag = PART_TABLE_FLAG; -} - -void write_part_table(void) -{ - int i, done = FALSE, len; - partition_table buffer; - char response[LINE_LENGTH]; - - print_warning(WRITE_WARN); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Are you sure you want write the partition table to disk? (yes or no): "); - - len = get_string(response, LINE_LENGTH, NULL); - - clear_warning(); - - if (len == GS_ESCAPE) - return; - else if (len == 2 && - toupper(response[0]) == 'N' && - toupper(response[1]) == 'O') { - print_warning(NO_WRITE); - return; - } else if (len == 3 && - toupper(response[0]) == 'Y' && - toupper(response[1]) == 'E' && - toupper(response[2]) == 'S') - done = TRUE; - else - print_warning(YES_NO); - } - - clear_warning(); - print_warning(WRITING_PART); - refresh(); - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - write_sector(buffer.c.b, 0); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - /* Read the extended partition table from disk ??? KEM */ - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - write_sector(buffer.c.b, p_info[i].first_sector); - } - - sync(); - sleep(2); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; - sync(); - sleep(4); - - clear_warning(); - if (changed) - print_warning(YES_WRITE); - else - print_warning(RRPART_FAILED); -} - -void fp_printf(FILE *fp, char *format, ...) -{ - va_list args; - char buf[1024]; - int y, x; - - va_start(args, format); - vsprintf(buf, format, args); - va_end(args); - - if (fp == NULL) { - /* The following works best if the string to be printed has at - most only one newline. */ - printw("%s", buf); - getyx(stdscr, y, x); - if (y >= COMMAND_LINE_Y-2) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - erase(); - move(0, 0); - } - } else - fprintf(fp, "%s", buf); -} - -#define MAX_PER_LINE 16 -void print_file_buffer(FILE *fp, char *buffer) -{ - int i,l; - - for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { - if (l == 0) - fp_printf(fp, "0x%03X:", i); - fp_printf(fp, " %02X", (unsigned char) buffer[i]); - if (l == MAX_PER_LINE - 1) { - fp_printf(fp, "\n"); - l = -1; - } - } - if (l > 0) - fp_printf(fp, "\n"); - fp_printf(fp, "\n"); -} - -void print_raw_table(void) -{ - int i, to_file; - partition_table buffer; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Disk Drive: %s\n", disk_device); - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - print_file_buffer(fp, buffer.c.b); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - print_file_buffer(fp, buffer.c.b); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_p_info_entry(FILE *fp, partition_info *p) -{ - int size; - char part_str[21]; - - if (p->id == UNUSABLE) - fp_printf(fp, " None "); - else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) - fp_printf(fp, " Pri/Log"); - else if (p->id == FREE_SPACE && p->num == PRIMARY) - fp_printf(fp, " Primary"); - else if (p->id == FREE_SPACE && p->num == LOGICAL) - fp_printf(fp, " Logical"); - else - fp_printf(fp, "%2d %-7.7s", p->num+1, - IS_LOGICAL(p->num) ? "Logical" : "Primary"); - - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->first_sector, - ((p->first_sector/(sectors*heads)) != - ((float)p->first_sector/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - fp_printf(fp, "%7d%c", p->last_sector, - (((p->last_sector+1)/(sectors*heads)) != - ((float)(p->last_sector+1)/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - fp_printf(fp, "%6d%c", p->offset, - ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && - (p->offset != sectors)) || - (p->first_sector != 0 && IS_PRIMARY(p->num) && - p->offset != 0)) ? - '#' : ' ')); - - fp_printf(fp, " "); - - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%7d%c", size, - ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? - '*' : ' ')); - - fp_printf(fp, " "); - - if (p->id == UNUSABLE) - sprintf(part_str, "%.16s", "Unusable"); - else if (p->id == FREE_SPACE) - sprintf(part_str, "%.16s", "Free Space"); - else if (partition_type[p->id]) - sprintf(part_str, "%.16s (%02X)", partition_type[p->id], p->id); - else - sprintf(part_str, "%.16s (%02X)", "Unknown", p->id); - fp_printf(fp, "%-21.21s", part_str); - - fp_printf(fp, " "); - - if (p->flags == ACTIVE_FLAG) - fp_printf(fp, "Boot (%02X)", p->flags); - else if (p->flags != 0) - fp_printf(fp, "Unknown (%02X)", p->flags); - else - fp_printf(fp, "None (%02X)", p->flags); - - fp_printf(fp, "\n"); -} - -void print_p_info(void) -{ - char fname[LINE_LENGTH]; - FILE *fp; - int i, to_file, pext = (ext_info.id == EXTENDED); - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Partition Table for %s\n", disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, " First Last\n"); - fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); - fp_printf(fp, "-- ------- -------- -------- ------- -------- --------------------- ---------\n"); - - for (i = 0; i < num_parts; i++) { - if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { - print_p_info_entry(fp,&ext_info); - pext = FALSE; - } - print_p_info_entry(fp, &(p_info[i])); - } - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_part_entry(FILE *fp, int num, partition_info *pi) -{ - int first = 0, start = 0, end = 0, size = 0; - int ss = 0, sh = 0, sc = 0; - int es = 0, eh = 0, ec = 0; - int flags = 0, id = 0; - - if (pi != NULL) { - flags = pi->flags; - id = pi->id; - - if (IS_LOGICAL(num)) - first = pi->offset; - else - first = pi->first_sector + pi->offset; - - start = pi->first_sector + pi->offset; - end = pi->last_sector; - size = end - start + 1; - if ((start/(sectors*heads)) > 1023) - start = heads*sectors*1024 - 1; - if ((end/(sectors*heads)) > 1023) - end = heads*sectors*1024 - 1; - - ss = start % sectors + 1; - start /= sectors; - sh = start % heads; - sc = start / heads; - - es = end % sectors + 1; - end /= sectors; - eh = end % heads; - ec = end / heads; - } - - fp_printf(fp, "%2d 0x%02X %4d %4d %4d 0x%02X %4d %4d %4d %7d %7d\n", - num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); -} - - -void print_part_table(void) -{ - int i, j, to_file; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter filename or press RETURN to display on screen: "); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - sprintf(errstr, PRINT_OPEN_ERR, fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, "Partition Table for %s\n", disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, " ---Starting--- ----Ending---- Start Number\n"); - fp_printf(fp, " # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n"); - fp_printf(fp, "-- ----- ---- ---- ---- ---- ---- ---- ---- ------- -------\n"); - - for (i = 0; i < 4; i++) { - for (j = 0; - j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); - j++); - if (j < num_parts) { - print_part_entry(fp, i, &(p_info[j])); - } else if (ext_info.id == EXTENDED && ext_info.num == i) { - print_part_entry(fp, i, &ext_info); - } else { - print_part_entry(fp, i, NULL); - } - } - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) - print_part_entry(fp, p_info[i].num, &(p_info[i])); - - if (to_file) { - if (!print_only) - fclose(fp); - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - } -} - -void print_tables(void) -{ - int done = FALSE; - - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Print format [rst]: "); - clrtoeol(); - refresh(); - - while (!done) - switch (toupper(getch())) { - case 'R': - print_raw_table(); - done = TRUE; - break; - case 'S': - print_p_info(); - done = TRUE; - break; - case 'T': - print_part_table(); - done = TRUE; - break; - case ESC: - done = TRUE; - break; - } -} - -#define END_OF_HELP "EOHS!" -#define NEW_HELP_SCREEN "SNHS!" -void display_help() -{ - char *help_text[] = { - "Help Screen for cfdisk " VERSION, - "", - "This is cfdisk, a curses based disk partitioning programs, which", - "allows you to create, delete and modify partitions on your hard", - "disk drive.", - "", - "Copyright (C) 1994 Kevin E. Martin", - "", - "Command Meaning", - "------- -------", - " b Toggle bootable flag of the current partition", - " d Delete the current partition", - " g Change cylinders, heads, sectors-per-track parameters", - " WARNING: This option should only be used by people who", - " know what they are doing.", - " h Print this screen", - " m Maximize disk usage of the current partition", - " Note: This may make the partition incompatible with", - " DOS, OS/2, ...", - " n Create new partition from free space", - " p Print partition table to the screen or to a file", - " There are several different formats for the partition", - " that you can choose from:", - " r - Raw data (exactly what would be written to disk)", - " s - Table ordered by sectors", - " t - Table in raw format", - " q Quit program without writing partition table", - " t Change the filesystem type", - " u Change units of the partition size display", - " Rotates through Mb, sectors and cylinders", - " W Write partition table to disk (must enter upper case W)", - " Since this might destroy data on the disk, you must", - " either confirm or deny the write by entering `yes' or", - " `no'", - "Up Arrow Move cursor to the previous partition", - "Down Arrow Move cursor to the next partition", - "CTRL-L Redraws the screen", - " ? Print this screen", - "", - "Note: All of the commands can be entered with either upper or lower", - "case letters (except for Writes).", - END_OF_HELP - }; - - int cur_line = 0; - FILE *fp = NULL; - - erase(); - move(0, 0); - while (strcmp(help_text[cur_line], END_OF_HELP)) - if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); - erase(); - move(0, 0); - cur_line++; - } else - fp_printf(fp, "%s\n", help_text[cur_line++]); - - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Press any key to continue..."); - clrtoeol(); - refresh(); - (void)getch(); -} - -int change_geometry(void) -{ - int ret_val = FALSE; - int done = FALSE; - char def[LINE_LENGTH]; - char response[LINE_LENGTH]; - int tmp_val; - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Change disk geometry information [chs]: "); - clrtoeol(); - refresh(); - - clear_warning(); - - switch (toupper(getch())) { - case 'C': - sprintf(def, "%d", cylinders); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of cylinders: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { - cylinders = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_CYLINDERS); - } - break; - case 'H': - sprintf(def, "%d", heads); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of heads: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_HEADS) { - heads = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_HEADS); - } - break; - case 'S': - sprintf(def, "%d", sectors); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - "Enter the number of sectors per track: "); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoi(response); - if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { - sectors = tmp_val; - ret_val = TRUE; - } else - print_warning(BAD_SECTORS); - } - break; - case ESC: - case CR: - done = TRUE; - break; - default: - putchar(BELL); - break; - } - } - - if (ret_val) { - if (p_info[num_parts-1].last_sector > heads*sectors*cylinders-1) { - while (p_info[num_parts-1].first_sector > heads*sectors*cylinders-1) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) - remove_part(num_parts-1); - else - del_part(num_parts-1); - } - - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; - - if (ext_info.last_sector > heads*sectors*cylinders-1) - ext_info.last_sector = heads*sectors*cylinders - 1; - } else if (p_info[num_parts-1].last_sector < heads*sectors*cylinders-1) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = heads*sectors*cylinders - 1; - } else { - insert_part(num_parts, PRI_OR_LOG, FREE_SPACE, 0, - p_info[num_parts-1].last_sector+1, - heads*sectors*cylinders-1, 0); - } - } - - /* Make sure the partitions are correct */ - check_part_info(); - } - - return ret_val; -} - -void change_id(int i) -{ - char id[LINE_LENGTH], def[LINE_LENGTH]; - int num_types = 0; - int num_across, num_down; - int len, new_id = LINUX; - int y_start, y_end; - int j, pos; - - for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) - num_types++; - - num_across = COLS/COL_ID_WIDTH; - num_down = (((float)num_types)/num_across + 1); - y_start = COMMAND_LINE_Y - 1 - num_down; - if (y_start > DISK_TABLE_START+cur_part+4) - y_start = DISK_TABLE_START+cur_part+4; - y_end = y_start + num_down - 1; - - for (j = y_start - 1; j <= y_end + 1; j++) { - move(j, 0); - clrtoeol(); - } - - for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) - if (partition_type[j]) { - move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); - printw("%02X %-16.16s", j, partition_type[j]); - pos++; - } - - sprintf(def, "%02X", new_id); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); - if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) - return; - - if (len != GS_DEFAULT) { - if (!isxdigit(id[0])) - return; - new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); - if (len == 2) - if (isxdigit(id[1])) - new_id = new_id*16 + - (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); - else - return; - } - - if (new_id == 0) - print_warning(ID_EMPTY); - else if (new_id == EXTENDED) - print_warning(ID_EXT); - else - p_info[i].id = new_id; -} - -void draw_partition(int i) -{ - int size, j; - int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - - if (!arrow_cursor) { - move(y, 0); - for (j = 0; j < COLS; j++) - addch(' '); - } - - if (p_info[i].id > 0) { - mvprintw(y, NAME_START, - "%s%d", disk_device, p_info[i].num+1); - if (p_info[i].flags) { - if (p_info[i].flags == ACTIVE_FLAG) - mvaddstr(y, FLAGS_START, "Boot"); - else - mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - addstr(", NC"); - } else { - if (p_info[i].offset != 0) - addstr(", NC"); - } - } else { - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - mvaddstr(y, FLAGS_START, "NC"); - } else { - if (p_info[i].offset != 0) - mvaddstr(y, FLAGS_START, "NC"); - } - } - } - mvaddstr(y, PTYPE_START, - (p_info[i].id == UNUSABLE ? "" : - (IS_LOGICAL(p_info[i].num) ? "Logical" : - (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]); - else - mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); - - size = p_info[i].last_sector - p_info[i].first_sector + 1; - if (display_units == SECTORS) - mvprintw(y, SIZE_START, "%9d", size); - else if (display_units == CYLINDERS) - mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); - else - mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); - if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || - ((p_info[i].first_sector/(sectors*heads)) != - ceiling(p_info[i].first_sector/(sectors*heads)))) - mvprintw(y, COLUMNS-1, "*"); -} - -void init_const(void) -{ - if (!defined) { - NAME_START = (((float)NAME_START)/COLUMNS)*COLS; - FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; - PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; - FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; - SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; - COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; - - COMMAND_LINE_Y = LINES - 4; - WARNING_START = LINES - 2; - - if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) - NUM_ON_SCREEN = 1; - - COLUMNS = COLS; - defined = TRUE; - } -} - -void draw_screen(void) -{ - int i; - char *line; - - line = (char *)malloc((COLS+1)*sizeof(char)); - - if (warning_last_time) { - for (i = 0; i < COLS; i++) { - move(WARNING_START, i); - line[i] = inch(); - } - line[COLS] = 0; - } - - erase(); - - if (warning_last_time) - mvaddstr(WARNING_START, 0, line); - - - sprintf(line, "cfdisk %s", VERSION); - mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); - sprintf(line, "Disk Drive: %s", disk_device); - mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); - sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", - heads, sectors, cylinders); - mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); - - 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, FSTYPE_START, "FS Type"); - if (display_units == SECTORS) - mvaddstr(DISK_TABLE_START, SIZE_START, " Sectors"); - else if (display_units == CYLINDERS) - mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); - else - mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); - - move(DISK_TABLE_START+1, 1); - for (i = 1; i < COLS-1; i++) - addch('-'); - - if (NUM_ON_SCREEN >= num_parts) - for (i = 0; i < num_parts; i++) - draw_partition(i); - else - for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && - i < num_parts; - i++) - draw_partition(i); - - free(line); -} - -int draw_cursor(int move) -{ - if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) - return -1; - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); - else - draw_partition(cur_part); - - cur_part += move; - - if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) - draw_screen(); - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); - else { - standout(); - draw_partition(cur_part); - standend(); - } - - return 0; -} - -void die(int dummy) -{ - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - -void do_curses_fdisk(void) -{ - int done = FALSE; - char command; - - initscr(); - old_SIGINT = signal(SIGINT, die); - old_SIGTERM = signal(SIGTERM, die); -#ifdef DEBUG - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); -#endif - - cbreak(); - noecho(); - nonl(); - - init_const(); - - fill_p_info(); - - draw_screen(); - - while (!done) { - (void)draw_cursor(0); - - if (p_info[cur_part].id == FREE_SPACE) - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hnpquW?]: "); - else if (p_info[cur_part].id > 0) - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [bdhmpqtuW?]: "); - else - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Command [hpquW?]: "); - - clrtoeol(); - refresh(); - - clear_warning(); - - switch (command = getch()) { - case 'B': - case 'b': - if (p_info[cur_part].id > 0) - p_info[cur_part].flags ^= 0x80; - else - print_warning(NO_FLAGS); - break; - case 'D': - case 'd': - if (p_info[cur_part].id > 0) { - del_part(cur_part); - if (cur_part >= num_parts) - cur_part = num_parts - 1; - draw_screen(); - } else - print_warning(DEL_EMPTY); - break; - case 'G': - case 'g': - if (change_geometry()) - draw_screen(); - break; - case 'M': - case 'm': - if (p_info[cur_part].id > 0) { - if (p_info[cur_part].first_sector == 0 || - IS_LOGICAL(p_info[cur_part].num)) { - if (p_info[cur_part].offset == sectors) - p_info[cur_part].offset = 1; - else - p_info[cur_part].offset = sectors; - draw_screen(); - } else if (p_info[cur_part].offset != 0) - p_info[cur_part].offset = 0; - else - print_warning(MAX_UNMAXABLE); - } else - print_warning(MAX_UNMAXABLE); - break; - case 'N': - case 'n': - if (p_info[cur_part].id == FREE_SPACE) { - new_part(cur_part); - draw_screen(); - } else if (p_info[cur_part].id == UNUSABLE) - print_warning(ADD_UNUSABLE); - else - print_warning(ADD_EXISTS); - break; - case 'P': - case 'p': - print_tables(); - draw_screen(); - break; - case 'Q': - case 'q': - done = TRUE; - break; - case 'T': - case 't': - if (p_info[cur_part].id > 0) { - change_id(cur_part); - draw_screen(); - } else - print_warning(TYPE_EMPTY); - break; - case 'U': - case 'u': - if (display_units == MEGABYTES) - display_units = SECTORS; - else if (display_units == SECTORS) - display_units = CYLINDERS; - else if (display_units == CYLINDERS) - display_units = MEGABYTES; - draw_screen(); - break; - case 'W': - write_part_table(); - break; - case 'H': - case 'h': - case '?': - display_help(); - draw_screen(); - break; - case ESC: - if ((command = getch()) == '[') { - command = getch(); - switch (command) { - case 'A' : /* Up arrow */ - if (!draw_cursor(-1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case 'B' : /* Down arrow */ - if (!draw_cursor(1)) - command = 0; - else - print_warning(NO_MORE_PARTS); - break; - case 'C' : /* Right arrow */ - case 'D' : /* Left arrow */ - } - } - if (command) - putchar(BELL); /* CTRL-G */ - break; - case REDRAWKEY: - clear(); - draw_screen(); - break; - default: - print_warning(BAD_COMMAND); - putchar(BELL); /* CTRL-G */ - } - } - - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); - mvcur(0, COLS-1, LINES-1, 0); - nl(); - endwin(); - fdexit(0); -} - -void copyright(void) -{ - fprintf(stderr, "Copyright (C) 1994 Kevin E. Martin\n"); -} - -void usage(char *prog_name) -{ - fprintf(stderr, - "%s: [-avz] [-c # cylinders] [-h # heads] [-s # sectors/track]\n", - prog_name); - fprintf(stderr, - "[ -P opt ] device\n"); - copyright(); -} - -void main(int argc, char **argv) -{ - char c; - int i, len; - - while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) - switch (c) { - case 'a': - arrow_cursor = TRUE; - break; - case 'c': - cylinders = atoi(optarg); - if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); - exit(1); - } - break; - case 'h': - heads = atoi(optarg); - if (heads <= 0 || heads > MAX_HEADS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); - exit(1); - } - break; - case 's': - sectors = atoi(optarg); - if (sectors <= 0 || sectors > MAX_SECTORS) { - fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); - exit(1); - } - break; - case 'v': - fprintf(stderr, "cfdisk %s\n", VERSION); - copyright(); - exit(0); - case 'z': - zero_table = TRUE; - break; - case 'P': - len = strlen(optarg); - for (i = 0; i < len; i++) { - switch (optarg[i]) { - case 'r': - print_only |= PRINT_RAW_TABLE; - break; - case 's': - print_only |= PRINT_SECTOR_TABLE; - break; - case 't': - print_only |= PRINT_PARTITION_TABLE; - break; - default: - usage(argv[0]); - break; - } - } - break; - default: - usage(argv[0]); - exit(1); - } - - if (argc-optind == 1) - disk_device = argv[optind]; - else if (argc-optind != 0) { - usage(argv[0]); - exit(1); - } else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - - if (print_only) { - fill_p_info(); - if (print_only & PRINT_RAW_TABLE) - print_raw_table(); - if (print_only & PRINT_SECTOR_TABLE) - print_p_info(); - if (print_only & PRINT_PARTITION_TABLE) - print_part_table(); - } else - do_curses_fdisk(); -} diff --git a/disk-utils/fdformat.c b/disk-utils/fdformat.c index 46b9e2320..7f792c5c9 100644 --- a/disk-utils/fdformat.c +++ b/disk-utils/fdformat.c @@ -56,9 +56,19 @@ static void verify_disk(char *name) fflush(stdout); if ((fd = open(name,O_RDONLY)) < 0) PERROR(name); for (cyl = 0; cyl < param.track; cyl++) { + int read_bytes; + printf("%3d\b\b\b",cyl); fflush(stdout); - if (read(fd,data,cyl_size) != cyl_size) PERROR("read"); + read_bytes = read(fd,data,cyl_size); + if(read_bytes != cyl_size) { + if(read_bytes < 0) + perror("Read: "); + fprintf(stderr, + "Problem reading cylinder %d, expected %d, read %d\n", + cyl, cyl_size, read_bytes); + exit(1); + } for (count = 0; count < cyl_size; count++) if (data[count] != FD_FILL_BYTE) { printf("bad data in cyl %d\nContinuing ... ",cyl); diff --git a/disk-utils/fdisk.8 b/disk-utils/fdisk.8 deleted file mode 100644 index 576bce2ec..000000000 --- a/disk-utils/fdisk.8 +++ /dev/null @@ -1,213 +0,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 "11 June 1998" "Linux 2.0" "Linux Programmer's Manual" -.SH NAME -fdisk \- Partition table manipulator for Linux -.SH SYNOPSIS -.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 -(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: -.br -.nf -.RS -/dev/hda -/dev/hdb -/dev/sda -/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 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 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). - -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. - -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" - -The DOS 6.x FORMAT command looks for some information in the first -sector of the data area of the partition, and treats this information -as more reliable than the information in the partition table. DOS -FORMAT expects DOS FDISK to clear the first 512 bytes of the data area -of a partition whenever a size change occurs. DOS FORMAT will look at -this extra information even if the /U flag is given -- we consider -this a bug in DOS FORMAT and DOS FDISK. - -The bottom line is that if you use cfdisk or fdisk to change the size of a -DOS partition table entry, then you must also use -.B dd -to zero the first 512 bytes of that partition before using DOS FORMAT to -format the partition. For example, if you were using cfdisk to make a DOS -partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk -and rebooting Linux so that the partition table information is valid) you -would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero -the first 512 bytes of the partition. - -.B BE EXTREMELY CAREFUL -if you use the -.B dd -command, since a small typo can make all of the data on your disk useless. - -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. - -.SH OPTIONS -.TP -.B \-v -Print version number of -.B fdisk -program and exit. -.TP -.B \-l -List the partition tables for -.BR /dev/hd[a-d] , -.BR /dev/sd[a-h] , -.BR /dev/ed[a-d] , -and then exit. -.TP -.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 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. -(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 -need not have the same idea about partition numbering -(e.g., in case you have BSD slices), and have different -ideas about the size of an extended partition. -.SH BUGS -There are several *fdisk programs around. -Each has its problems and strengths. -Try them in the order -.BR cfdisk , -.BR fdisk , -.BR sfdisk . -.\" .SH AUTHORS -.\" A. V. Le Blanc (LeBlanc@mcc.ac.uk) -.\" Bernhard Fastenrath (fasten@informatik.uni-bonn.de) -.\" Jakub Jelinek (jj@sunsite.mff.cuni.cz) -.\" and many others. diff --git a/disk-utils/fdisk.c b/disk-utils/fdisk.c deleted file mode 100644 index d99a8b452..000000000 --- a/disk-utils/fdisk.c +++ /dev/null @@ -1,1940 +0,0 @@ -/* fdisk.c -- Partition table manipulator for Linux. - * - * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk) - * - * This program is free software. You can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation: either version 1 or - * (at your option) any later version. - * - * Before Linux version 0.95c, this program requires a kernel patch. - * - * Modified, Tue Feb 2 18:46:49 1993, faith@cs.unc.edu to better support SCSI. - * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support. - * Modified, Sat Mar 6 10:14:12 1993, faith@cs.unc.edu: added more comments. - * Modified, Sat Mar 6 12:25:45 1993, faith@cs.unc.edu: - * Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de - * or mbi@mo.math.nat.tu-bs.de) to fix the following problems: - * 1) Incorrect mapping of head/sector/cylinder to absolute sector - * 2) Odd sector count causes one sector to be lost - * Modified, Sat Mar 6 12:25:52 1993, faith@cs.unc.edu: improved verification. - * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l. - * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug. - * Modified, Wed May 5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr. - * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk: - * more stderr for messages, avoid division by 0, and - * give reboot message only if ioctl(fd, BLKRRPART) fails. - * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu: - * 1) Added support for DOS, OS/2, ... compatibility. We should be able - * use this fdisk to partition our drives for other operating systems. - * 2) Added a print the raw data in the partition table command. - * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu: - * Added/changed a few partition type names to conform to cfdisk. - * (suggested by Sujal, smpatel@wam.umd.edu) - * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open - * devices RDONLY (instead of RDWR). This allows you to - * have the disks as rw-r----- with group disk (and if you - * want is safe to setguid fdisk to disk). - * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu - * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com: - * It's user-interface cleanup time. - * Actual error messages for out-of-bounds values (what a concept!). - * Enable read-only access to partition table for learners. - * Smart defaults for most numeric prompts. - * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801. - * Read partition table twice to avoid kernel bug - * (from Daniel Quinlan ), Tue Sep 26 10:25:28 1995 - * Modified, Sat Jul 1 23:43:16 MET DST 1995, fasten@cs.bonn.edu: - * editor for NetBSD/i386 (and Linux/Alpha?) disklabels. - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include /* for HDIO_GETGEO */ -#include /* for BLKRRPART, BLKGETSIZE */ - -#include "fdisk.h" -#if defined(sparc) -#include "fdisksunlabel.h" -#endif - -#define hex_val(c) ({ \ - char _c = (c); \ - isdigit(_c) ? _c - '0' : \ - tolower(_c) + 10 - 'a'; \ - }) - - -#define VERSION "2.8" /* util-linux version */ - -#define DEFAULT_DEVICE "/dev/hda" -#define ALTERNATE_DEVICE "/dev/sda" -#define LINE_LENGTH 80 -#define offset(b, n) ((struct partition *)((b) + 0x1be + \ - (n) * sizeof(struct partition))) -#define sector(s) ((s) & 0x3f) -#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) - -#define calculate(h,s,c) (sector(s) - 1 + sectors * \ - ((h) + heads * cylinder(s,c))) -#define set_hsc(h,s,c,sector) { \ - s = sector % sectors + 1; \ - sector /= sectors; \ - h = sector % heads; \ - sector /= heads; \ - c = sector & 0xff; \ - 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 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; - -char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ - *line_ptr, /* interactive input */ - line_buffer[LINE_LENGTH], - changed[MAXIMUM_PARTS], /* marks changed buffers */ - buffer[SECTOR_SIZE], /* first four partitions */ - *buffers[MAXIMUM_PARTS] /* pointers to buffers */ - = {buffer, buffer, buffer, buffer}; - -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 */ - -uint heads, - sectors, - cylinders, - sector_offset = 1, - display_factor = 1, /* in units/sector */ - unit_flag = 1, - full_bits = 0, /* 1024 cylinders in sectors */ - 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[] = { - {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; - -void fatal(enum failure why) -{ - char error[LINE_LENGTH], - *message = error; - - if (listing) { - close(fd); - longjmp(listingbuf, 1); - } - - switch (why) { - case usage: message = -"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); - break; - case unable_to_read: - sprintf(error, "Unable to read %s\n", disk_device); - break; - case unable_to_seek: - sprintf(error, "Unable to seek on %s\n", disk_device); - break; - case unable_to_write: - sprintf(error, "Unable to write %s\n", disk_device); - break; - case out_of_memory: - message = "Unable to allocate any more memory\n"; - break; - default: message = "Fatal error\n"; - } - - fputc('\n', stderr); - fputs(message, stderr); - exit(1); -} - -void menu(void) -{ - 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" - " 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" - " 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)" - ); -} - -void xmenu(void) -{ - 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" /* sun */ - " h change number of heads\n" - " 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" - ); -} - -char *partition_type(unsigned char type) -{ - 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; -} - -void list_types(struct systypes *sys) -{ - 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; - - do { - printf("%c%2x %-15.15s", i ? ' ' : '\n', - sys[next].index, sys[next].name); - next = last[i++] + done; - if (i > 3 || next >= last[i]) { - i = 0; - next = ++done; - } - } while (done < last[0]); - putchar('\n'); -} - -void clear_partition(struct partition *p) -{ - p->boot_ind = 0; - p->head = 0; - p->sector = 0; - p->cyl = 0; - p->sys_ind = 0; - p->end_head = 0; - p->end_sector = 0; - p->end_cyl = 0; - set_start_sect(p,0); - set_nr_sects(p,0); -} - -void set_partition(int i, struct partition *p, uint start, uint stop, - int sysid, uint offset) -{ - p->boot_ind = 0; - 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); - if (dos_compatible_flag && (stop/(sectors*heads) > 1023)) - stop = heads*sectors*1024 - 1; - set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); - changed[i] = 1; -} - -int test_c(char **m, char *mesg) -{ - int val = 0; - if (!*m) - fprintf(stderr, "You must set"); - else { - fprintf(stderr, " %s", *m); - val = 1; - } - *m = mesg; - return val; -} - -int warn_geometry(void) -{ - char *m = NULL; - int prev = 0; - if (!heads) - prev = test_c(&m, "heads"); - if (!sectors) - prev = test_c(&m, "sectors"); - if (!cylinders) - prev = test_c(&m, "cylinders"); - if (!m) - return 0; - fprintf(stderr, - "%s%s.\nYou can do this from the extra functions menu.\n", - prev ? " and " : " ", m); - return 1; -} - -uint rounded(uint calcul, uint start) -{ - uint i; - if (!full_bits) - return calcul; - while ((i = calcul + full_bits) <= start) - calcul = i; - return calcul; -} - -void update_units(void) -{ - full_bits = 1024 * heads * sectors; - if (unit_flag && full_bits) - display_factor = full_bits >> 10; - else display_factor = 1; -} - -void warn_cylinders(void) -{ - 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 from other OSs\n" - " (e.g., DOS FDISK, OS/2 FDISK)\n", - cylinders); -} - -void read_extended(struct partition *p) -{ - int i; - struct partition *q; - - ext_pointers[ext_index] = part_table[ext_index]; - if (!get_start_sect(p)) - fprintf(stderr, "Bad offset in primary extended partition\n"); - else while (IS_EXTENDED (p->sys_ind)) { - if (partitions >= MAXIMUM_PARTS) { - fprintf(stderr, - "Warning: deleting partitions after %d\n", - partitions); - clear_partition(ext_pointers[partitions - 1]); - changed[partitions - 1] = 1; - return; - } - offsets[partitions] = extended_offset + get_start_sect(p); - if (!extended_offset) - extended_offset = get_start_sect(p); - if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] - * SECTOR_SIZE, SEEK_SET) < 0) - fatal(unable_to_seek); - if (!(buffers[partitions] = (char *) malloc(SECTOR_SIZE))) - fatal(out_of_memory); - if (SECTOR_SIZE != read(fd, buffers[partitions], SECTOR_SIZE)) - fatal(unable_to_read); - part_table[partitions] = ext_pointers[partitions] = NULL; - q = p = offset(buffers[partitions], 0); - for (i = 0; i < 4; i++, p++) { - if (IS_EXTENDED (p->sys_ind)) - if (ext_pointers[partitions]) - fprintf(stderr, "Warning: extra link " - "pointer in partition table " - "%d\n", partitions + 1); - else - ext_pointers[partitions] = p; - else if (p->sys_ind) - if (part_table[partitions]) - fprintf(stderr, - "Warning: ignoring extra data " - "in partition table %d\n", - partitions + 1); - else - part_table[partitions] = p; - } - if (!part_table[partitions]) - if (q != ext_pointers[partitions]) - part_table[partitions] = q; - else part_table[partitions] = q + 1; - if (!ext_pointers[partitions]) - if (q != part_table[partitions]) - ext_pointers[partitions] = q; - else ext_pointers[partitions] = q + 1; - p = ext_pointers[partitions++]; - } -} - -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 (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); - -#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; - if (dos_compatible_flag) - sector_offset = sectors; - } else { - if (!ioctl(fd, BLKGETSIZE, §ors)) { - heads = 1; - cylinders = 1; - } else { - heads = cylinders = sectors = 0; - } - } - update_units(); - -got_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(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 (!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 0; -} - -int read_line(void) -{ - if (!fgets(line_buffer, LINE_LENGTH, stdin)) - return 0; - line_ptr = line_buffer; - while (*line_ptr && !isgraph(*line_ptr)) - line_ptr++; - return *line_ptr; -} - -char read_char(char *mesg) -{ - do { - fputs(mesg, stdout); - } while (!read_line()); - return *line_ptr; -} - -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; - - while (1) - { - read_char("Hex code (type L to list codes): "); - if (tolower(*line_ptr) == 'l') - list_types(sys); - else if (isxdigit (*line_ptr)) - { - hex = 0; - do - hex = hex << 4 | hex_val(*line_ptr++); - while (isxdigit(*line_ptr)); - return hex; - } - } -} - - -uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) -{ - uint i, use_default = 1; - char ms[70]; - - switch(base) { - case lower: - sprintf(ms, "%s ([%d]-%d): ", mesg, low, high); - break; - case upper: - sprintf(ms, "%s (%d-[%d]): ", mesg, low, high); - break; - case deflt: - sprintf(ms, "%s (%d-[%d]-%d): ", mesg, low, dflt, high); - break; - default: - sprintf(ms, "%s (%d-%d): ", mesg, low, high); - break; - } - - while (1) { - 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; - i = atoi(line_ptr); - while (isdigit(*line_ptr)) - { - line_ptr++; - use_default = 0; - } - switch (*line_ptr) { - case 'c': - case 'C': if (!unit_flag) - i *= heads * sectors; - break; - case 'k': - case 'K': i *= 2; - i /= display_factor; - break; - case 'm': - case 'M': i *= 2048; - i /= display_factor; - break; - default: break; - } - switch(base) { - case lower: i += low; break; - case upper: i += high; break; - case deflt: i += dflt; break; - case ignore: - } - } - else - { - i = atoi(line_ptr); - while (isdigit(*line_ptr)) - { - line_ptr++; - use_default = 0; - } - } - if (use_default) - printf("Using default value %d\n", i = dflt); - if (i >= low && i <= high) - break; - else - printf("Value out of range.\n"); - } - return i; -} - -int get_partition(int warn, int max) -{ - /* - * try to pick a default least likely to do damage, - * in case luser just types a newline - */ - int i = read_int(1, max, max, ignore, "Partition number") - 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; -} - -char *const str_units(void) -{ - return unit_flag ? "cylinder" : "sector"; -} - -void change_units(void) -{ - if ((unit_flag = !unit_flag)) - display_factor = 1; - else display_factor = heads * sectors; - update_units(); - printf("Changing display/entry units to %ss\n", - str_units()); -} - -void toggle_active(int i) -{ - struct partition *p = part_table[i]; - - if (IS_EXTENDED (p->sys_ind) && !p->boot_ind) - fprintf(stderr, - "WARNING: Partition %d is an extended partition\n", - i + 1); - if (p->boot_ind) - p->boot_ind = 0; - else p->boot_ind = ACTIVE_FLAG; - changed[i] = 1; -} - -void toggle_dos(void) -{ - dos_compatible_flag = ~dos_compatible_flag; - printf("DOS Compatibility flag is "); - if (dos_compatible_flag) - sector_offset = sectors; - else { - sector_offset = 1; - printf("not "); - } - printf("set\n"); -} - -void delete_partition(int i) -{ - struct partition *p = part_table[i], *q = ext_pointers[i]; - -/* Note that for the fifth partition (i == 4) we don't actually - * decrement partitions. - */ - - if (warn_geometry()) - return; - changed[i] = 1; -#if defined(sparc) - if (sun_label) { - sun_delete_partition(i); - return; - } -#endif - if (i < 4) { - if (IS_EXTENDED (p->sys_ind) && i == ext_index) { - while (partitions > 4) - free(buffers[--partitions]); - ext_pointers[ext_index] = NULL; - extended_offset = 0; - } - clear_partition(p); - } - else if (!q->sys_ind && i > 4) { - free(buffers[--partitions]); - clear_partition(ext_pointers[--i]); - } - else if (i > 3) { - if (i > 4) { - p = ext_pointers[i - 1]; - p->boot_ind = 0; - p->head = q->head; - p->sector = q->sector; - p->cyl = q->cyl; - p->sys_ind = EXTENDED; - p->end_head = q->end_head; - p->end_sector = q->end_sector; - p->end_cyl = q->end_cyl; - 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 */ - set_start_sect(part_table[5], - get_start_sect(part_table[5]) + - offsets[5] - extended_offset); - offsets[5] = extended_offset; - changed[5] = 1; - } - if (partitions > 5) { - partitions--; - free(buffers[i]); - while (i < partitions) { - changed[i] = changed[i + 1]; - buffers[i] = buffers[i + 1]; - offsets[i] = offsets[i + 1]; - part_table[i] = part_table[i + 1]; - ext_pointers[i] = ext_pointers[i + 1]; - i++; - } - } - else - clear_partition(part_table[i]); - } -} - -void change_sysid(void) -{ - char *temp; - int i = get_partition(0, partitions), sys, origsys; - struct partition *p = part_table[i]; - -#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 - - 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 (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, - * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, - * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. - * Lubkin Oct. 1991). */ - -static void long2chs(ulong ls, uint *c, uint *h, uint *s) -{ - int spc = heads * sectors; - - *c = ls / spc; - ls = ls % spc; - *h = ls / sectors; - *s = ls % sectors + 1; /* sectors count from 1 */ -} - -static void check_consistency(struct partition *p, int partition) -{ - uint pbc, pbh, pbs; /* physical beginning c, h, s */ - uint pec, peh, pes; /* physical ending c, h, s */ - uint lbc, lbh, lbs; /* logical beginning c, h, s */ - uint lec, leh, les; /* logical ending c, h, s */ - - if (!heads || !sectors || (partition >= 4)) - return; /* do not check extended partitions */ - -/* physical beginning c, h, s */ - pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300); - pbh = p->head; - pbs = p->sector & 0x3f; - -/* physical ending c, h, s */ - pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); - peh = p->end_head; - pes = p->end_sector & 0x3f; - -/* compute logical beginning (c, h, s) */ - long2chs(get_start_sect(p), &lbc, &lbh, &lbs); - -/* compute logical ending (c, h, s) */ - 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)) { - printf("Partition %d has different physical/logical " - "beginnings (non-Linux?):\n", partition + 1); - printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); - printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs); - } - -/* Same physical / logical ending? */ - if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { - printf("Partition %d has different physical/logical " - "endings:\n", partition + 1); - printf(" phys=(%d, %d, %d) ", pec, peh, pes); - printf("logical=(%d, %d, %d)\n",lec, leh, les); - } - -#if 0 -/* Beginning on cylinder boundary? */ - if (pbh != !pbc || pbs != 1) { - printf("Partition %i does not start on cylinder " - "boundary:\n", partition + 1); - printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); - printf("should be (%d, %d, 1)\n", pbc, !pbc); - } -#endif - -/* Ending on cylinder boundary? */ - if (peh != (heads - 1) || pes != sectors) { - printf("Partition %i does not end on cylinder boundary:\n", - partition + 1); - printf(" phys=(%d, %d, %d) ", pec, peh, pes); - printf("should be (%d, %d, %d)\n", - pec, heads - 1, sectors); - } -} - -void list_table(int xtra) -{ - struct partition *p; - char *type; - 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 %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) { - 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), - 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) -{ - struct partition *p, **q; - int i; - - if (extend) - q = ext_pointers; - else - q = part_table; - printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n", - disk_device, heads, sectors, cylinders); - printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); - for (i = 0 ; i < partitions; i++) - if ((p = q[i]) != NULL) { - printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n", - i + 1, p->boot_ind, p->head, - sector(p->sector), - cylinder(p->sector, p->cyl), p->end_head, - sector(p->end_sector), - cylinder(p->end_sector, p->end_cyl), - get_start_sect(p), get_nr_sects(p), p->sys_ind); - if (p->sys_ind) - check_consistency(p, i); - } -} - -void check_bounds(uint *first, uint *last) -{ - int i; - uint max = 0xffffffff; /* used to be 256 * 63 * 1024 - but that made it impossible to add a - partition crossing cylinder 8064 */ - struct partition *p = part_table[0]; - - 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 { - first[i] = rounded(calculate(p->head, p->sector, - 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) -{ - uint total, real_s, real_c, i; - - real_s = sector(s) - 1; - real_c = cylinder(s, c); - total = (real_c * sectors + real_s) * heads + h; - if (full_bits) - while ((i = total + full_bits) <= start) { - real_c += 1024; - total = i; - } - if (!total) - fprintf(stderr, "Warning: partition %d contains sector 0\n", n); - if (h >= heads) - fprintf(stderr, - "Partition %d: head %d greater than maximum %d\n", - n, h + 1, heads); - if (real_s >= sectors) - fprintf(stderr, "Partition %d: sector %d greater than " - "maximum %d\n", n, s, sectors); - if (real_c >= cylinders) - fprintf(stderr, "Partitions %d: cylinder %d greater than " - "maximum %d\n", n, real_c + 1, cylinders); - if (cylinders <= 1024 && start != total) - fprintf(stderr, - "Partition %d: previous sectors %d disagrees with " - "total %d\n", n, start, total); -} - - -void verify(void) -{ - int i, j; - uint total = 1, - first[partitions], last[partitions]; - struct partition *p = part_table[0]; - - 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 && !IS_EXTENDED (p->sys_ind)) { - check_consistency(p, 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, - last[i]); - total += last[i] + 1 - first[i]; - for (j = 0; j < i; j++) - if ((first[i] >= first[j] && first[i] <= last[j]) - || ((last[i] <= last[j] && last[i] >= first[j]))) { - printf("Warning: partition %d overlaps " - "partition %d.\n", j + 1, i + 1); - total += first[i] >= first[j] ? - first[i] : first[j]; - total -= last[i] <= last[j] ? - last[i] : last[j]; - } - } - - if (extended_offset) { - 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]) { - total++; - if (!p->sys_ind) { - if (i != 4 || i + 1 < partitions) - printf("Warning: partition %d " - "is empty\n", i + 1); - } - else if (first[i] < extended_offset || - last[i] > e_last) - printf("Logical partition %d not entirely in " - "partition %d\n", i + 1, ext_index + 1); - } - } - - if (total > heads * sectors * cylinders) - printf("Total allocated sectors %d greater than the maximum " - "%d\n", total, heads * sectors * cylinders); - else if ((total = heads * sectors * cylinders - total) != 0) - printf("%d unallocated sectors\n", total); -} - -void add_partition(int n, int sys) -{ - char mesg[48]; - int i, read = 0; - struct partition *p = part_table[n], *q = part_table[ext_index]; - uint start, stop = 0, limit, temp, - first[partitions], last[partitions]; - - if (p->sys_ind) { - printf("Partition %d is already defined. Delete " - "it before re-adding it.\n", n + 1); - return; - } - check_bounds(first, last); - if (n < 4) { - start = sector_offset; - limit = heads * sectors * cylinders - 1; - if (extended_offset) { - first[ext_index] = extended_offset; - last[ext_index] = get_start_sect(q) + - get_nr_sects(q) - 1; - } - } else { - start = extended_offset + sector_offset; - limit = get_start_sect(q) + get_nr_sects(q) - 1; - } - if (unit_flag) - for (i = 0; i < partitions; i++) - first[i] = (cround(first[i]) - 1) * display_factor; - - sprintf(mesg, "First %s", str_units()); - do { - temp = start; - for (i = 0; i < partitions; i++) { - int lastplusoff; - - if (start == offsets[i]) - start += 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+display_factor && read) { - printf("Sector %d is already allocated\n", temp); - temp = start; - read = 0; - } - if (!read && start == temp) { - uint i; - 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); - if (n > 4) /* NOT for fifth partition */ - offsets[n] = start - sector_offset; - - for (i = 0; i < partitions; i++) { - if (start < offsets[i] && limit >= offsets[i]) - limit = offsets[i] - 1; - if (start < first[i] && limit >= first[i]) - limit = first[i] - 1; - } - if (start > limit) { - printf("No free sectors available\n"); - if (n > 4) { - free(buffers[n]); - partitions--; - } - return; - } - if (cround(start) == cround(limit)) - stop = start; - else { - sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", - str_units()); - stop = read_int(cround(start), cround(limit), cround(limit), - lower, mesg); - if (unit_flag) { - stop = stop * display_factor - 1; - if (stop >limit) - stop = limit; - } - } - - set_partition(n, p, start, stop, sys, offsets[n]); - - if (IS_EXTENDED (sys)) { - ext_index = n; - offsets[4] = extended_offset = start; - ext_pointers[n] = p; - if (!(buffers[4] = calloc(1, SECTOR_SIZE))) - fatal(out_of_memory); - part_table[4] = offset(buffers[4], 0); - ext_pointers[4] = part_table[4] + 1; - changed[4] = 1; - partitions = 5; - } - else { - if (n > 4) - set_partition(n - 1, ext_pointers[n - 1], - start - sector_offset, stop, EXTENDED, - extended_offset); -#if 0 - if ((limit = get_nr_sects(p)) & 1) - printf("Warning: partition %d has an odd " - "number of sectors.\n", n + 1); -#endif - } -} - -void add_logical(void) -{ - if (partitions > 5 || part_table[4]->sys_ind) { - if (!(buffers[partitions] = calloc(1, SECTOR_SIZE))) - fatal(out_of_memory); - part_table[partitions] = offset(buffers[partitions], 0); - ext_pointers[partitions] = part_table[partitions] + 1; - offsets[partitions] = 0; - partitions++; - } - add_partition(partitions - 1, LINUX_NATIVE); -} - -void new_partition(void) -{ - int i, free_primary = 0; - - 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; - } - - for (i = 0; i < 4; i++) - free_primary += !part_table[i]->sys_ind; - if (!free_primary) - if (extended_offset) - add_logical(); - else - printf("You must delete some partition and add " - "an extended partition first\n"); - else { - char c, line[LINE_LENGTH]; - sprintf(line, "Command action\n %s\n p primary " - "partition (1-4)\n", extended_offset ? - "l logical (5 or over)" : "e extended"); - while (1) - if ((c = tolower(read_char(line))) == 'p') { - add_partition(get_partition(0, 4), - LINUX_NATIVE); - return; - } - else if (c == 'l' && extended_offset) { - add_logical(); - return; - } - else if (c == 'e' && !extended_offset) { - add_partition(get_partition(0, 4), - EXTENDED); - return; - } - else - printf("Invalid partition number " - "for type `%c'\n", c); - - } -} - -void write_table(void) -{ - int i, error = 0; - - changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; - if (!sun_label) { - for (i = 3; i < partitions; i++) { - if (changed[i]) { - 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"); - - printf("Calling ioctl() to re-read partition table.\n"); - sync(); - sleep(2); - if ((i = ioctl(fd, BLKRRPART)) != 0) { - error = errno; - } else { - /* some kernel versions (1.2.x) seem to have trouble - rereading the partition table, but if asked to do it - twice, the second time works. - biro@yggdrasil.com */ - sync(); - sleep(2); - if((i = ioctl(fd, BLKRRPART)) != 0) - error = errno; - } - - close(fd); - - printf("Syncing disks.\n"); - sync(); - sleep(4); /* for sync() */ - - if (i < 0) - printf("Re-read table failed with error %d: %s.\nReboot your " - "system to ensure the partition table is updated.\n", - error, strerror(error)); - - 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"); - - exit(0); -} - -#define MAX_PER_LINE 16 -void print_buffer(char buffer[]) -{ - int i, - l; - - for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { - if (l == 0) - printf("0x%03X:", i); - printf(" %02X", (unsigned char) buffer[i]); - if (l == MAX_PER_LINE - 1) { - printf("\n"); - l = -1; - } - } - if (l > 0) - printf("\n"); - printf("\n"); -} - -void print_raw(void) -{ - int i; - - printf("Device: %s\n", disk_device); - if (sun_label) - print_buffer(buffer); - else for (i = 3; i < partitions; i++) - print_buffer(buffers[i]); -} - -void move_begin(int i) -{ - struct partition *p = part_table[i]; - uint new, first; - - if (warn_geometry()) - return; - 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), - get_start_sect(p) + offsets[i]); - new = read_int(first, first, - get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1, - lower, "New beginning of data") - offsets[i]; - - 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; - } -} - -void xselect(void) -{ - while(1) { - putchar('\n'); - switch (tolower(read_char("Expert command (m for help): "))) { -#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(); - } - } -} - -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(try_only) < 0) { - if (btrydev(device) < 0) - fprintf(stderr, - "Disk doesn't contain a valid " - "partition table\n"); - close(fd); - } else { - close(fd); - list_table(0); - if (!sun_label && partitions > 4) - delete_partition(ext_index); - } - } else { - /* Ignore other errors, since we try IDE - and SCSI hard disks which may not be - installed on the system. */ - if(errno == EACCES) { - fprintf(stderr, "Cannot open %s\n", device); - return; - } - } - } -} - -void -dummy(int *kk) {} - -void main(int argc, char **argv) -{ - 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); - } - } - - if (optl) { - listing = 1; - nowarn = 1; - type_open = O_RDONLY; - if (argc > optind) { - int k; - /* avoid gcc warning: - variable `k' might be clobbered by `longjmp' */ - dummy(&k); - for(k=optind; k= partitions) - exit(1); -#if defined(sparc) - if (!sun_label) { - int id = sunlabel->infos[i].id; - - if (!(id > 1 && id != WHOLE_DISK)) - exit(1); - s = get_num_sectors(sunlabel->partitions[i]); - } else -#endif - s = get_nr_sects(part_table[i]); - if (opts == 1) - printf("%d\n", s/2); - else - printf("%s: %d\n", argv[j], s/2); - } - exit(0); - } - - if (argc-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(fdisk); - - while (1) { - putchar('\n'); - switch (tolower(read_char("Command (m for help): "))) { - 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 - toggle_dos(); - break; - case 'd': - delete_partition( - get_partition(1, partitions)); - break; - case 'l': -#if defined(sparc) - if (sun_label) - list_types(sun_sys_types); - else -#endif - list_types(sys_types); - break; - case 'n': - new_partition(); - break; - case 'o': - create_doslabel(); - break; - case 'p': - list_table(0); - break; - case 'q': - close(fd); - exit(0); -#if defined(sparc) - case 's': - create_sunlabel(); - break; -#endif - case 't': - change_sysid(); - break; - case 'u': - change_units(); - break; - case 'v': - verify(); - break; - case 'w': - write_table(); /* does not return */ - break; - case 'x': - xselect(); - break; - default: menu(); - } - } -} - diff --git a/disk-utils/fdisk.h b/disk-utils/fdisk.h deleted file mode 100644 index 11f529d48..000000000 --- a/disk-utils/fdisk.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - fdisk.h -*/ - -#define SECTOR_SIZE 512 -#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) -typedef long long ext2_loff_t; -#else -typedef long ext2_loff_t; -#endif - -extern ext2_loff_t ext2_llseek(unsigned int fd, - ext2_loff_t offset, - unsigned int origin); - -struct partition { - unsigned char boot_ind; /* 0x80 - active */ - unsigned char head; /* starting head */ - unsigned char sector; /* starting sector */ - unsigned char cyl; /* starting cylinder */ - unsigned char sys_ind; /* What partition type */ - unsigned char end_head; /* end head */ - unsigned char end_sector; /* end sector */ - unsigned char end_cyl; /* end cylinder */ - unsigned char start4[4]; /* starting sector counting from 0 */ - unsigned char size4[4]; /* nr of sectors in partition */ -}; - -enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, - unable_to_write, out_of_memory}; - -enum offset {ignore, lower, deflt, upper}; - -enum action {fdisk, require, try_only, create_empty}; - -struct systypes { - unsigned char index; - char *name; -}; - -/* prototypes for fdisk.c */ -extern char *disk_device, - *line_ptr; -extern int fd, - partitions; -extern uint unit_flag, - display_factor; -extern struct partition *part_table[]; -extern void fatal(enum failure why); -extern int get_boot(enum action what); -extern int get_partition(int warn, int max); -extern void list_types(struct systypes *sys); -extern int read_line (void); -extern char read_char(char *mesg); -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 int btrydev (char * dev); - -/* prototypes for fdisksunlabel.c */ diff --git a/disk-utils/fdisklabel.c b/disk-utils/fdisklabel.c deleted file mode 100644 index d98d49d0d..000000000 --- a/disk-utils/fdisklabel.c +++ /dev/null @@ -1,815 +0,0 @@ -/* - NetBSD disklabel editor for Linux fdisk - Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de) - with code from the NetBSD disklabel command: - - Copyright (c) 1987, 1988 Regents of the University of California. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by the University of - California, Berkeley and its contributors. - 4. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include /* for HDIO_GETGEO */ - -#include "fdisk.h" -#define NETBSD_PARTITION 0xa5 -#define DKTYPENAMES -#include "fdisklabel.h" - -static void xbsd_delete_part (void); -static void xbsd_new_part (void); -static void xbsd_print_disklabel (int show_all); -static void xbsd_write_disklabel (void); -static int xbsd_create_disklabel (void); -static void xbsd_edit_disklabel (void); -static void xbsd_write_bootstrap (void); -static void xbsd_change_fstype (void); -static int xbsd_get_part_index (int max); -static int xbsd_check_new_partition (int *i); -static void xbsd_list_types (void); -static u_short xbsd_dkcksum (struct xbsd_disklabel *lp); -static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex); -static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d); -static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d); -static void sync_disks (void); -#if defined (i386) || defined (sparc) -static int xbsd_translate_fstype (int linux_type); -static void xbsd_link_part (void); -#endif -#if defined (__alpha__) -void alpha_bootblock_checksum (char *boot); -#endif - -static struct xbsd_disklabel xbsd_dlabel; -static char buffer[BSD_BBSIZE]; -#if defined (i386) || defined (sparc) -static struct partition *xbsd_part; -static int xbsd_part_index; -#endif - -int -btrydev (char * dev) { - if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) - return -1; - printf("\nBSD label for device: %s\n", dev); - xbsd_print_disklabel (0); - return 0; -} - -void -bmenu (void) -{ - puts ("Command action\n" - " d delete a BSD partition\n" - " e edit drive data\n" - " i install bootstrap\n" - " l list known filesystem types\n" - " m print this menu\n" - " n add a new BSD partition\n" - " p print BSD partition table\n" - " q quit without saving changes\n" -#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) || defined (sparc) - " x link BSD partition to non-BSD partition" -#endif - ); -} - -void -bselect (void) -{ -#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; - 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, ss + BSD_LABELSECTOR); - if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0) - if (xbsd_create_disklabel () == 0) - return; - break; - } - - if (t == 4) - { - printf ("There is no NetBSD partition on %s.\n", disk_device); - return; - } - -#elif defined (__alpha__) - - if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) - if (xbsd_create_disklabel () == 0) - exit ( EXIT_SUCCESS ); - -#endif - - while (1) - { - putchar ('\n'); - switch (tolower (read_char ("BSD disklabel command (m for help): "))) - { - case 'd': - xbsd_delete_part (); - break; - case 'e': - xbsd_edit_disklabel (); - break; - case 'i': - xbsd_write_bootstrap (); - break; - case 'l': - xbsd_list_types (); - break; - case 'n': - xbsd_new_part (); - break; - case 'p': - xbsd_print_disklabel (0); - break; - case 'q': - close (fd); - exit ( EXIT_SUCCESS ); - case 's': - xbsd_print_disklabel (1); - break; - case 't': - xbsd_change_fstype (); - break; - case 'w': - xbsd_write_disklabel (); - break; -#if defined (i386) || defined (sparc) - case 'r': - return; - case 'x': - xbsd_link_part (); - break; -#endif - default: - bmenu (); - break; - } - } -} - -static void -xbsd_delete_part (void) -{ - int i; - - i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); - xbsd_dlabel.d_partitions[i].p_size = 0; - xbsd_dlabel.d_partitions[i].p_offset = 0; - xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; - if (xbsd_dlabel.d_npartitions == i + 1) - while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0) - xbsd_dlabel.d_npartitions--; -} - -static void -xbsd_new_part (void) -{ - uint begin, end; - char mesg[48]; - int i; - - if (!xbsd_check_new_partition (&i)) - return; - -#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; -#endif - - sprintf (mesg, "First %s", str_units()); - begin = read_int (cround (begin), cround (begin), cround (end), ignore, mesg); - - sprintf (mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); - end = read_int (cround (begin), cround (end), cround (end), ignore, mesg); - - if (unit_flag) - { - begin = (begin - 1) * display_factor; - end = end * display_factor - 1; - } - xbsd_dlabel.d_partitions[i].p_size = end - begin + 1; - xbsd_dlabel.d_partitions[i].p_offset = begin; - xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; -} - -static void -xbsd_print_disklabel (int show_all) -{ - struct xbsd_disklabel *lp = &xbsd_dlabel; - struct xbsd_partition *pp; - FILE *f = stdout; - int i, j; - - if (show_all) - { -#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); -#endif - if ((unsigned) lp->d_type < BSD_DKMAXTYPES) - fprintf(f, "type: %s\n", xbsd_dktypenames[lp->d_type]); - else - fprintf(f, "type: %d\n", lp->d_type); - fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename); - fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname); - fprintf(f, "flags:"); - if (lp->d_flags & BSD_D_REMOVABLE) - fprintf(f, " removable"); - if (lp->d_flags & BSD_D_ECC) - fprintf(f, " ecc"); - if (lp->d_flags & BSD_D_BADSECT) - fprintf(f, " badsect"); - fprintf(f, "\n"); - /* On various machines the fields of *lp are short/int/long */ - /* In order to avoid problems, we cast them all to long. */ - fprintf(f, "bytes/sector: %ld\n", (long) lp->d_secsize); - fprintf(f, "sectors/track: %ld\n", (long) lp->d_nsectors); - fprintf(f, "tracks/cylinder: %ld\n", (long) lp->d_ntracks); - fprintf(f, "sectors/cylinder: %ld\n", (long) lp->d_secpercyl); - fprintf(f, "cylinders: %ld\n", (long) lp->d_ncylinders); - fprintf(f, "rpm: %d\n", lp->d_rpm); - fprintf(f, "interleave: %d\n", lp->d_interleave); - fprintf(f, "trackskew: %d\n", lp->d_trackskew); - fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); - fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long) lp->d_headswitch); - fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long) lp->d_trkseek); - fprintf(f, "drivedata: "); - for (i = NDDATA - 1; i >= 0; i--) - if (lp->d_drivedata[i]) - break; - if (i < 0) - i = 0; - for (j = 0; j <= i; j++) - fprintf(f, "%ld ", (long) lp->d_drivedata[j]); - } - fprintf (f, "\n%d partitions:\n", lp->d_npartitions); - fprintf (f, "# size offset fstype [fsize bsize cpg]\n"); - pp = lp->d_partitions; - for (i = 0; i < lp->d_npartitions; i++, pp++) { - if (pp->p_size) { - fprintf(f, " %c: %8ld %8ld ", 'a' + i, - (long) pp->p_size, (long) pp->p_offset); - if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) - fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name); - else - fprintf(f, "%8x", pp->p_fstype); - switch (pp->p_fstype) - { - case BSD_FS_UNUSED: - fprintf(f, " %5ld %5ld %5.5s ", - (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, ""); - break; - - case BSD_FS_BSDFFS: - fprintf(f, " %5ld %5ld %5d ", - (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, - pp->p_cpg); - break; - - default: - fprintf(f, "%20.20s", ""); - break; - } - fprintf(f, "\t# (Cyl. %4ld", (long) -#if 0 - pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ -#else - pp->p_offset / lp->d_secpercyl + 1); -#endif - if (pp->p_offset % lp->d_secpercyl) - putc('*', f); - else - putc(' ', f); - fprintf(f, "- %ld", - (long) (pp->p_offset + - pp->p_size + lp->d_secpercyl - 1) / -#if 0 - lp->d_secpercyl - 1); /* differs from Linux fdisk */ -#else - lp->d_secpercyl); -#endif - if (pp->p_size % lp->d_secpercyl) - putc('*', f); - fprintf(f, ")\n"); - } - } -} - -static void -xbsd_write_disklabel (void) -{ -#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__) - printf ("Writing disklabel to %s.\n", disk_device); - xbsd_writelabel (NULL, &xbsd_dlabel); -#endif -} - -static int -xbsd_create_disklabel (void) -{ - char c; - -#if defined (i386) || defined (sparc) - fprintf (stderr, "%s%d contains no disklabel.\n", - disk_device, xbsd_part_index+1); -#elif defined (__alpha__) - fprintf (stderr, "%s contains no disklabel.\n", disk_device); -#endif - - while (1) - if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') - { -#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) -#endif - { - xbsd_print_disklabel (1); - return 1; - } - else - return 0; - } - else if (c == 'n') - return 0; -} - -static int -edit_int (int def, char *mesg) -{ - do { - fputs (mesg, stdout); - printf (" (%d): ", def); - if (!read_line ()) - return def; - } - while (!isdigit (*line_ptr)); - return atoi (line_ptr); -} - -static void -xbsd_edit_disklabel (void) -{ - struct xbsd_disklabel *d; - - d = &xbsd_dlabel; - -#ifdef __alpha__ - d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); - d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,"sectors/track"); - d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,"tracks/cylinder"); - d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,"cylinders"); -#endif - - /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */ - while (1) - { - d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks, - "sectors/cylinder"); - if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks) - break; - - printf ("Must be <= sectors/track * tracks/cylinder (default).\n"); - } - d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,"rpm"); - d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,"interleave"); - d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,"trackskew"); - d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,"cylinderskew"); - d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,"headswitch"); - d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,"track-to-track seek"); - - d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; -} - -static int -xbsd_get_bootstrap (char *path, void *ptr, int size) -{ - int fd; - - if ((fd = open (path, O_RDONLY)) < 0) - { - perror (path); - return 0; - } - if (read (fd, ptr, size) < 0) - { - perror (path); - close (fd); - return 0; - } - printf (" ... %s\n", path); - close (fd); - return 1; -} - -static void -xbsd_write_bootstrap (void) -{ - char *bootdir = BSD_LINUX_BOOTDIR; - char path[MAXPATHLEN]; - char *dkbasename; - struct xbsd_disklabel dl; - char *d, *p, *e; - int sector; - - if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI) - dkbasename = "sd"; - else - dkbasename = "wd"; - - printf ("Bootstrap: %sboot -> boot%s (%s): ", dkbasename, dkbasename, dkbasename); - if (read_line ()) - { - line_ptr[strlen (line_ptr)-1] = '\0'; - dkbasename = line_ptr; - } - sprintf (path, "%s/%sboot", bootdir, dkbasename); - if (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize)) - return; - - /* We need a backup of the disklabel (xbsd_dlabel might have changed). */ - d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; - bcopy (d, &dl, sizeof (struct xbsd_disklabel)); - - /* The disklabel will be overwritten by 0's from bootxx anyway */ - bzero (d, sizeof (struct xbsd_disklabel)); - - sprintf (path, "%s/boot%s", bootdir, dkbasename); - if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize], - (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize)) - return; - - e = d + sizeof (struct xbsd_disklabel); - for (p=d; p < e; p++) - if (*p) - { - fprintf (stderr, "Bootstrap overlaps with disk label!\n"); - exit ( EXIT_FAILURE ); - } - - bcopy (&dl, d, sizeof (struct xbsd_disklabel)); - -#if defined (i386) || defined (sparc) - sector = get_start_sect(xbsd_part); -#elif defined (__alpha__) - sector = 0; - alpha_bootblock_checksum (buffer); -#endif - - if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) - fatal (unable_to_seek); - if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) - fatal (unable_to_write); - -#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); -#endif - - sync_disks (); -} - -static void -xbsd_change_fstype (void) -{ - int i; - - i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); - xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes); -} - -static int -xbsd_get_part_index (int max) -{ - char prompt[40]; - char l; - - sprintf (prompt, "Partition (a-%c): ", 'a' + max - 1); - do - l = tolower (read_char (prompt)); - while (l < 'a' || l > 'a' + max - 1); - return l - 'a'; -} - -static int -xbsd_check_new_partition (int *i) -{ - int t; - - if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) - { - for (t=0; t < BSD_MAXPARTITIONS; t++) - if (xbsd_dlabel.d_partitions[t].p_size == 0) - break; - - if (t == BSD_MAXPARTITIONS) - { - fprintf (stderr, "The maximum number of partitions has been created\n"); - return 0; - } - } - *i = xbsd_get_part_index (BSD_MAXPARTITIONS); - - if (*i >= xbsd_dlabel.d_npartitions) - xbsd_dlabel.d_npartitions = (*i) + 1; - - if (xbsd_dlabel.d_partitions[*i].p_size != 0) - { - fprintf (stderr, "This partition already exists.\n"); - return 0; - } - return 1; -} - -static void -xbsd_list_types (void) -{ - list_types (xbsd_fstypes); -} - -static u_short -xbsd_dkcksum (struct xbsd_disklabel *lp) -{ - register u_short *start, *end; - register u_short sum = 0; - - start = (u_short *)lp; - end = (u_short *)&lp->d_partitions[lp->d_npartitions]; - while (start < end) - sum ^= *start++; - return (sum); -} - -static int -xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) -{ - struct hd_geometry geometry; - struct xbsd_partition *pp; - - if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) - { - perror ("ioctl"); - return 0; - } - bzero (d, sizeof (struct xbsd_disklabel)); - - d -> d_magic = BSD_DISKMAGIC; - - if (strncmp (disk_device, "/dev/sd", 7) == 0) - d -> d_type = BSD_DTYPE_SCSI; - else - d -> d_type = BSD_DTYPE_ST506; - -#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */ - d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; -#endif - -#if defined (i386) || defined (sparc) - d -> d_flags = BSD_D_DOSPART; -#else - d -> d_flags = 0; -#endif - d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ - d -> d_nsectors = geometry.sectors; /* sectors/track */ - d -> d_ntracks = geometry.heads; /* tracks/cylinder (heads) */ - d -> d_ncylinders = geometry.cylinders; - d -> d_secpercyl = geometry.sectors * geometry.heads; /* sectors/cylinder */ - d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; - - d -> d_rpm = 3600; - d -> d_interleave = 1; - d -> d_trackskew = 0; - d -> d_cylskew = 0; - d -> d_headswitch = 0; - d -> d_trkseek = 0; - - d -> d_magic2 = BSD_DISKMAGIC; - d -> d_bbsize = BSD_BBSIZE; - d -> d_sbsize = BSD_SBSIZE; - -#if defined (i386) || defined (sparc) - d -> d_npartitions = 4; - pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */ - 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; - pp -> p_size = d -> d_secperunit; - pp -> p_fstype = BSD_FS_UNUSED; -#elif defined (__alpha__) - d -> d_npartitions = 3; - pp = &d -> d_partitions[2]; /* Partition C should be the whole disk */ - pp -> p_offset = 0; - pp -> p_size = d -> d_secperunit; - pp -> p_fstype = BSD_FS_UNUSED; -#endif - - return 1; -} - -static int -xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d) -{ - int t, sector; - -#if defined (i386) || defined (sparc) - sector = (p ? get_start_sect(p) : 0); -#elif defined (__alpha__) - sector = 0; -#endif - - if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) - fatal (unable_to_seek); - if (BSD_BBSIZE != read (fd, buffer, BSD_BBSIZE)) - fatal (unable_to_read); - - bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - d, sizeof (struct xbsd_disklabel)); - - for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) - { - d -> d_partitions[t].p_size = 0; - d -> d_partitions[t].p_offset = 0; - d -> d_partitions[t].p_fstype = BSD_FS_UNUSED; - } - if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC) - return 0; - - if (d -> d_npartitions > BSD_MAXPARTITIONS) - fprintf (stderr, "Warning: too many partitions (%d, maximum is %d).\n", - d -> d_npartitions, BSD_MAXPARTITIONS); - return 1; -} - -static int -xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d) -{ - int sector; - -#if defined (i386) || defined (sparc) - sector = get_start_sect(p) + BSD_LABELSECTOR; -#elif defined (__alpha__) - sector = BSD_LABELSECTOR; -#endif - - d -> d_checksum = 0; - d -> d_checksum = xbsd_dkcksum (d); - - /* This is necessary if we want to write the bootstrap later, - otherwise we'd write the old disklabel with the bootstrap. - */ - bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], - sizeof (struct xbsd_disklabel)); - -#if defined (__alpha__) && BSD_LABELSECTOR == 0 - alpha_bootblock_checksum (buffer); - if (ext2_llseek (fd, 0, SEEK_SET) == -1) - fatal (unable_to_seek); - if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) - fatal (unable_to_write); -#else - if (ext2_llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1) - fatal (unable_to_seek); - if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel))) - fatal (unable_to_write); -#endif - - sync_disks (); - - return 1; -} - -static void -sync_disks (void) -{ - printf ("\nSyncing disks.\n"); - sync (); - sleep (4); -} - -#if defined (i386) || defined (sparc) -static int -xbsd_translate_fstype (int linux_type) -{ - switch (linux_type) - { - case 0x01: /* DOS 12-bit FAT */ - case 0x04: /* DOS 16-bit <32M */ - case 0x06: /* DOS 16-bit >=32M */ - case 0xe1: /* DOS access */ - case 0xe3: /* DOS R/O */ - case 0xf2: /* DOS secondary */ - return BSD_FS_MSDOS; - case 0x07: /* OS/2 HPFS */ - return BSD_FS_HPFS; - default: - return BSD_FS_OTHER; - } -} - -static void -xbsd_link_part (void) -{ - int k, i; - - k = get_partition (1, partitions); - - if (!xbsd_check_new_partition (&i)) - return; - - 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); -} -#endif - -#if defined (__alpha__) - -#if 0 -typedef unsigned long long u_int64_t; -#endif - -void -alpha_bootblock_checksum (char *boot) -{ - u_int64_t *dp, sum; - int i; - - dp = (u_int64_t *)boot; - sum = 0; - for (i = 0; i < 63; i++) - sum += dp[i]; - dp[63] = sum; -} -#endif /* __alpha__ */ diff --git a/disk-utils/fdisklabel.h b/disk-utils/fdisklabel.h deleted file mode 100644 index 06435f4d1..000000000 --- a/disk-utils/fdisklabel.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (c) 1987, 1988 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include /* for __u32 etc */ - -#ifndef BSD_DISKMAGIC /* perhaps from */ -#define BSD_DISKMAGIC ((__u32) 0x82564557) -#endif - -#ifndef BSD_MAXPARTITIONS -#define BSD_MAXPARTITIONS 8 -#endif - -#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" - -#if defined (i386) || defined (sparc) -#define BSD_LABELSECTOR 1 -#define BSD_LABELOFFSET 0 -#elif defined (__alpha__) -#define BSD_LABELSECTOR 0 -#define BSD_LABELOFFSET 64 -#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 */ - __s16 d_subtype; /* controller/d_type specific */ - char d_typename[16]; /* type name, e.g. "eagle" */ - char d_packname[16]; /* pack identifier */ - /* disk geometry: */ - __u32 d_secsize; /* # of bytes per sector */ - __u32 d_nsectors; /* # of data sectors per track */ - __u32 d_ntracks; /* # of tracks per cylinder */ - __u32 d_ncylinders; /* # of data cylinders per unit */ - __u32 d_secpercyl; /* # of data sectors per cylinder */ - __u32 d_secperunit; /* # of data sectors per unit */ - /* - * Spares (bad sector replacements) below - * are not counted in d_nsectors or d_secpercyl. - * Spare sectors are assumed to be physical sectors - * which occupy space at the end of each track and/or cylinder. - */ - __u16 d_sparespertrack; /* # of spare sectors per track */ - __u16 d_sparespercyl; /* # of spare sectors per cylinder */ - /* - * Alternate cylinders include maintenance, replacement, - * configuration description areas, etc. - */ - __u32 d_acylinders; /* # of alt. cylinders per unit */ - - /* hardware characteristics: */ - /* - * d_interleave, d_trackskew and d_cylskew describe perturbations - * in the media format used to compensate for a slow controller. - * Interleave is physical sector interleave, set up by the formatter - * or controller when formatting. When interleaving is in use, - * logically adjacent sectors are not physically contiguous, - * but instead are separated by some number of sectors. - * It is specified as the ratio of physical sectors traversed - * per logical sector. Thus an interleave of 1:1 implies contiguous - * layout, while 2:1 implies that logical sector 0 is separated - * by one sector from logical sector 1. - * d_trackskew is the offset of sector 0 on track N - * relative to sector 0 on track N-1 on the same cylinder. - * Finally, d_cylskew is the offset of sector 0 on cylinder N - * relative to sector 0 on cylinder N-1. - */ - __u16 d_rpm; /* rotational speed */ - __u16 d_interleave; /* hardware sector interleave */ - __u16 d_trackskew; /* sector 0 skew, per track */ - __u16 d_cylskew; /* sector 0 skew, per cylinder */ - __u32 d_headswitch; /* head switch time, usec */ - __u32 d_trkseek; /* track-to-track seek, usec */ - __u32 d_flags; /* generic flags */ -#define NDDATA 5 - __u32 d_drivedata[NDDATA]; /* drive-type specific information */ -#define NSPARE 5 - __u32 d_spare[NSPARE]; /* reserved for future use */ - __u32 d_magic2; /* the magic number (again) */ - __u16 d_checksum; /* xor of data incl. partitions */ - /* filesystem and partition information: */ - __u16 d_npartitions; /* number of partitions in following */ - __u32 d_bbsize; /* size of boot area at sn0, bytes */ - __u32 d_sbsize; /* max size of fs superblock, bytes */ - struct xbsd_partition { /* the partition table */ - __u32 p_size; /* number of sectors in partition */ - __u32 p_offset; /* starting sector */ - __u32 p_fsize; /* filesystem basic fragment size */ - __u8 p_fstype; /* filesystem type, see below */ - __u8 p_frag; /* filesystem fragments per block */ - __u16 p_cpg; /* filesystem cylinders per group */ - } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ -}; - -/* d_type values: */ -#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ -#define BSD_DTYPE_MSCP 2 /* MSCP */ -#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ -#define BSD_DTYPE_SCSI 4 /* SCSI */ -#define BSD_DTYPE_ESDI 5 /* ESDI interface */ -#define BSD_DTYPE_ST506 6 /* ST506 etc. */ -#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ -#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ -#define BSD_DTYPE_FLOPPY 10 /* floppy */ - -/* d_subtype values: */ -#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ -#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ -#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ - -#ifdef DKTYPENAMES -static char *xbsd_dktypenames[] = { - "unknown", - "SMD", - "MSCP", - "old DEC", - "SCSI", - "ESDI", - "ST506", - "HP-IB", - "HP-FL", - "type 9", - "floppy", - 0 -}; -#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1) -#endif - -/* - * Filesystem type and version. - * Used to interpret other filesystem-specific - * per-partition information. - */ -#define BSD_FS_UNUSED 0 /* unused */ -#define BSD_FS_SWAP 1 /* swap */ -#define BSD_FS_V6 2 /* Sixth Edition */ -#define BSD_FS_V7 3 /* Seventh Edition */ -#define BSD_FS_SYSV 4 /* System V */ -#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ -#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ -#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ -#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ -#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ -#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ -#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ -#define BSD_FS_ISOFS BSD_FS_ISO9660 -#define BSD_FS_BOOT 13 /* partition contains bootstrap */ -#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ -#define BSD_FS_HFS 15 /* Macintosh HFS */ - -/* this is annoying, but it's also the way it is :-( */ -#ifdef __alpha__ -#define BSD_FS_EXT2 8 /* MS-DOS file system */ -#else -#define BSD_FS_MSDOS 8 /* MS-DOS file system */ -#endif - -#ifdef DKTYPENAMES -static struct systypes xbsd_fstypes[] = { - {BSD_FS_UNUSED, "unused"}, - {BSD_FS_SWAP, "swap"}, - {BSD_FS_V6, "Version 6"}, - {BSD_FS_V7, "Version 7"}, - {BSD_FS_SYSV, "System V"}, - {BSD_FS_V71K, "4.1BSD"}, - {BSD_FS_V8, "Eighth Edition"}, - {BSD_FS_BSDFFS, "4.2BSD"}, -#ifdef __alpha__ - {BSD_FS_EXT2, "ext2"}, -#else - {BSD_FS_MSDOS, "MS-DOS"}, -#endif - {BSD_FS_BSDLFS, "4.4LFS"}, - {BSD_FS_OTHER, "unknown"}, - {BSD_FS_HPFS, "HPFS"}, - {BSD_FS_ISO9660,"ISO-9660"}, - {BSD_FS_BOOT, "boot"}, - {BSD_FS_ADOS, "ADOS"}, - {BSD_FS_HFS, "HFS"}, - { 0, NULL } -}; -#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1) - -#endif - -/* - * flags shared by various drives: - */ -#define BSD_D_REMOVABLE 0x01 /* removable media */ -#define BSD_D_ECC 0x02 /* supports ECC */ -#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ -#define BSD_D_RAMDISK 0x08 /* disk emulator */ -#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ -#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ diff --git a/disk-utils/fdisksunlabel.c b/disk-utils/fdisksunlabel.c deleted file mode 100644 index a5a87b8d4..000000000 --- a/disk-utils/fdisksunlabel.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * fdisksunlabel.c - * - * I think this is mostly, or entirely, due to - * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996 - * - * Merged with fdisk for other architectures, aeb, June 1998. - */ -#if defined (sparc) - -#include /* stderr */ -#include /* uint */ -#include /* strstr */ -#include /* write */ -#include /* ioctl */ -#include /* stat */ - -#include -#include -#include /* FLOPPY_MAJOR */ -#include /* HDIO_GETGEO */ - -#include "fdisk.h" -#include "fdisksunlabel.h" - -int other_endian = 0; -int scsi_disk = 0; -int floppy = 0; - -#define LINUX_SWAP 0x82 -#define LINUX_NATIVE 0x83 - -struct systypes sun_sys_types[] = { - {0, "Empty"}, - {1, "Boot"}, - {2, "SunOS root"}, - {SUNOS_SWAP, "SunOS swap"}, - {4, "SunOS usr"}, - {WHOLE_DISK, "Whole disk"}, - {6, "SunOS stand"}, - {7, "SunOS var"}, - {8, "SunOS home"}, - {LINUX_SWAP, "Linux swap"}, - {LINUX_NATIVE, "Linux native"}, - { 0, NULL } -}; - -inline unsigned short __swap16(unsigned short x) { - return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); -} -inline __u32 __swap32(__u32 x) { - return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24); -} - -int -get_num_sectors(struct sun_partition p) { - return SSWAP32(p.num_sectors); -} - -void guess_device_type(int fd) { - struct stat bootstat; - - if (fstat (fd, &bootstat) < 0) { - scsi_disk = 0; - floppy = 0; - } else if (S_ISBLK(bootstat.st_mode) - && ((bootstat.st_rdev >> 8) == IDE0_MAJOR || - (bootstat.st_rdev >> 8) == IDE1_MAJOR)) { - scsi_disk = 0; - floppy = 0; - } else if (S_ISBLK(bootstat.st_mode) - && (bootstat.st_rdev >> 8) == FLOPPY_MAJOR) { - scsi_disk = 0; - floppy = 1; - } else { - scsi_disk = 1; - floppy = 0; - } -} - -void set_sun_partition(int i, uint start, uint stop, int sysid) -{ - sunlabel->infos[i].id = sysid; - sunlabel->partitions[i].start_cylinder = - SSWAP32(start / (heads * sectors)); - sunlabel->partitions[i].num_sectors = - SSWAP32(stop - start); - changed[i] = 1; -} - -int check_sun_label(void) -{ - unsigned short *ush; - int csum; - - if (sunlabel->magic != SUN_LABEL_MAGIC && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) { - sun_label = 0; - other_endian = 0; - return 0; - } - other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED); - ush = ((unsigned short *) (sunlabel + 1)) - 1; - for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--; - if (csum) { - fprintf(stderr, "Detected sun disklabel with wrong checksum.\n" - "Probably you'll have to set all the values,\n" - "e.g. heads, sectors, cylinders and partitions\n" - "or force a fresh label (s command in main menu)\n"); - } else { - heads = SSWAP16(sunlabel->ntrks); - cylinders = SSWAP16(sunlabel->ncyl); - sectors = SSWAP16(sunlabel->nsect); - } - update_units(); - sun_label = 1; - partitions = 8; - return 1; -} - -struct sun_predefined_drives { - char *vendor; - char *model; - unsigned short sparecyl; - unsigned short ncyl; - unsigned short nacyl; - unsigned short pcylcount; - unsigned short ntrks; - unsigned short nsect; - unsigned short rspeed; -} sun_drives[] = { -{"Quantum","ProDrive 80S",1,832,2,834,6,34,3662}, -{"Quantum","ProDrive 105S",1,974,2,1019,6,35,3662}, -{"CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600}, -{"","SUN0104",1,974,2,1019,6,35,3662}, -{"","SUN0207",4,1254,2,1272,9,36,3600}, -{"","SUN0327",3,1545,2,1549,9,46,3600}, -{"","SUN0340",0,1538,2,1544,6,72,4200}, -{"","SUN0424",2,1151,2,2500,9,80,4400}, -{"","SUN0535",0,1866,2,2500,7,80,5400}, -{"","SUN0669",5,1614,2,1632,15,54,3600}, -{"","SUN1.0G",5,1703,2,1931,15,80,3597}, -{"","SUN1.05",0,2036,2,2038,14,72,5400}, -{"","SUN1.3G",6,1965,2,3500,17,80,5400}, -{"","SUN2.1G",0,2733,2,3500,19,80,5400}, -{"IOMEGA","Jaz",0,1019,2,1021,64,32,5394}, -}; - -void create_sunlabel(void) -{ - struct hd_geometry geometry; - unsigned int ndiv; - int i; - unsigned char c; - struct sun_predefined_drives *p = NULL; - - fprintf(stderr, "Building a new sun disklabel. Changes will remain in memory only,\n" - "until you decide to write them. After that, of course, the previous\n" - "content won't be recoverable.\n\n"); -#if BYTE_ORDER == LITTLE_ENDIAN - other_endian = 1; -#else - other_endian = 0; -#endif - memset(buffer, 0, SECTOR_SIZE); - sunlabel->magic = SSWAP16(SUN_LABEL_MAGIC); - if (!floppy) { - puts("Drive type\n" - " ? auto configure\n" - " 0 custom (with hardware detected defaults)"); - for (i = 0; i < SIZE(sun_drives); i++) { - printf(" %c %s%s%s\n", - i + 'a', sun_drives[i].vendor, - (*sun_drives[i].vendor) ? " " : "", - sun_drives[i].model); - } - for (;;) { - c = read_char("Select type (? for auto, 0 for custom): "); - if (c >= 'a' && c < 'a' + SIZE(sun_drives)) { - p = sun_drives + c - 'a'; - break; - } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) { - p = sun_drives + c - 'A'; - break; - } else if (c == '0') - break; - else if (c == '?' && scsi_disk) { - unsigned int id[2]; - char buffer[2048]; - char buffer2[2048]; - FILE *pfd; - char *vendor; - char *model; - char *q; - - if (!ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id)) { - sprintf(buffer, "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n", -#if 0 - ((id[0]>>24)&0xff)-/*PROC_SCSI_SCSI+PROC_SCSI_FILE*/33, -#else - /* This is very wrong (works only if you have one HBA), but I haven't find a way how to get hostno from the current kernel */ - 0, -#endif - (id[0]>>16)&0xff, - id[0]&0xff, - (id[0]>>8)&0xff); - pfd = fopen("/proc/scsi/scsi","r"); - if (pfd) { - while (fgets(buffer2,2048,pfd)) { - if (!strcmp(buffer, buffer2)) { - if (fgets(buffer2,2048,pfd)) { - q = strstr(buffer2,"Vendor: "); - if (q) { - q += 8; - vendor = q; - q = strstr(q," Model: "); - if (q) { - *q = 0; - q += 8; - model = q; - q = strstr(q," Rev: "); - if (q) { - *q = 0; - for (i = 0; i < SIZE(sun_drives); i++) { - if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor)) - continue; - if (!strstr(model, sun_drives[i].model)) - continue; - printf("Autoconfigure found a %s%s%s\n",sun_drives[i].vendor,(*sun_drives[i].vendor) ? " " : "",sun_drives[i].model); - p = sun_drives + i; - break; - } - } - } - } - } - break; - } - } - fclose(pfd); - } - } - if (!p) - printf("Autoconfigure failed.\n"); - else - break; - } - } - } - if (!p || floppy) { -#ifdef HDIO_REQ - if (!ioctl(fd, HDIO_REQ, &geometry)) { -#else - if (!ioctl(fd, HDIO_GETGEO, &geometry)) { -#endif - heads = geometry.heads; - sectors = geometry.sectors; - cylinders = geometry.cylinders; - } else { - heads = 0; - sectors = 0; - cylinders = 0; - } - if (floppy) { - sunlabel->nacyl = 0; - sunlabel->pcylcount = SSWAP16(cylinders); - sunlabel->rspeed = SSWAP16(300); - sunlabel->ilfact = SSWAP16(1); - sunlabel->sparecyl = 0; - } else { - if (heads) - heads = read_int(1,heads,1024,deflt,"Heads"); - else - heads = read_int(1,1,1024,ignore,"Heads"); - if (sectors) - sectors = read_int(1,sectors,1024,deflt,"Sectors/track"); - else - sectors = read_int(1,1,1024,ignore,"Sectors/track"); - if (cylinders) - cylinders = read_int(1,cylinders-2,65535,deflt,"Cylinders"); - else - cylinders = read_int(1,1,65535,ignore,"Cylinders"); - sunlabel->nacyl = SSWAP16(read_int(0,2,65535,deflt,"Alternate cylinders")); - sunlabel->pcylcount = SSWAP16(read_int(0,cylinders + SSWAP16(sunlabel->nacyl),65535,deflt,"Physical cylinders")); - sunlabel->rspeed = SSWAP16(read_int(1,5400,100000,deflt,"Rotation speed (rpm)")); - sunlabel->ilfact = SSWAP16(read_int(1,1,32,deflt,"Interleave factor")); - sunlabel->sparecyl = SSWAP16(read_int(0,0,sectors,deflt,"Extra sectors per cylinder")); - } - } else { - sunlabel->sparecyl = SSWAP16(p->sparecyl); - sunlabel->ncyl = SSWAP16(p->ncyl); - sunlabel->nacyl = SSWAP16(p->nacyl); - sunlabel->pcylcount = SSWAP16(p->pcylcount); - sunlabel->ntrks = SSWAP16(p->ntrks); - sunlabel->nsect = SSWAP16(p->nsect); - sunlabel->rspeed = SSWAP16(p->rspeed); - cylinders = p->ncyl; - heads = p->ntrks; - sectors = p->nsect; - puts("You may change all the disk params from the x menu"); - } - sprintf(buffer, "%s%s%s cyl %d alt %d hd %d sec %d", - p ? p->vendor : "", (p && *p->vendor) ? " " : "", p ? p->model : (floppy ? "3,5\" floppy" : "Linux custom"), - cylinders, SSWAP16(sunlabel->nacyl), heads, sectors); - sunlabel->ntrks = SSWAP16(heads); - sunlabel->nsect = SSWAP16(sectors); - sunlabel->ncyl = SSWAP16(cylinders); - if (floppy) - set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE); - else { - if (cylinders * heads * sectors >= 150 * 2048) { - ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */ - } else - ndiv = cylinders * 2 / 3; - set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE); - set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP); - sunlabel->infos[1].flags |= 0x01; /* Not mountable */ - } - set_sun_partition(2, 0, cylinders * heads * sectors, WHOLE_DISK); - { - unsigned short *ush = (unsigned short *)sunlabel; - unsigned short csum = 0; - while(ush < (unsigned short *)(&sunlabel->csum)) - csum ^= *ush++; - sunlabel->csum = csum; - } - for (i = 1; i < MAXIMUM_PARTS; i++) - changed[i] = 0; - changed[0] = 1; - get_boot(create_empty); -} - -void toggle_sunflags(int i, unsigned char mask) -{ - if (sunlabel->infos[i].flags & mask) - sunlabel->infos[i].flags &= ~mask; - else sunlabel->infos[i].flags |= mask; - changed[i] = 1; -} - -void fetch_sun(uint *starts, uint *lens, uint *start, uint *stop) -{ - int i, continuous = 1; - *start = 0; *stop = cylinders * heads * sectors; - for (i = 0; i < partitions; i++) { - if (sunlabel->partitions[i].num_sectors && sunlabel->infos[i].id && sunlabel->infos[i].id != WHOLE_DISK) { - starts[i] = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; - lens[i] = SSWAP32(sunlabel->partitions[i].num_sectors); - if (continuous) { - if (starts[i] == *start) - *start += lens[i]; - else if (starts[i] + lens[i] >= *stop) - *stop = starts[i]; - else - continuous = 0; /* There will be probably more gaps than one, so lets check afterwards */ - } - } else { - starts[i] = 0; - lens[i] = 0; - } - } -} - -static uint *verify_sun_starts; -int verify_sun_cmp(int *a, int *b) -{ - if (*a == -1) return 1; - if (*b == -1) return -1; - if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1; - return -1; -} - -void verify_sun(void) -{ - uint starts[8], lens[8], start, stop; - int i,j,k,starto,endo; - int array[8]; - - verify_sun_starts = starts; - fetch_sun(starts,lens,&start,&stop); - for (k = 0; k < 7; k++) { - for (i = 0; i < 8; i++) { - if (k && (lens[i] % (heads * sectors))) { - printf("Partition %d doesn't end on cylinder boundary\n", i+1); - } - if (lens[i]) { - for (j = 0; j < i; j++) - if (lens[j]) { - if (starts[j] == starts[i]+lens[i]) { - starts[j] = starts[i]; lens[j] += lens[i]; - lens[i] = 0; - } else if (starts[i] == starts[j]+lens[j]){ - lens[j] += lens[i]; - lens[i] = 0; - } else if (!k) { - if (starts[i] < starts[j]+lens[j] && - starts[j] < starts[i]+lens[i]) { - starto = starts[i]; - if (starts[j] > starto) - starto = starts[j]; - endo = starts[i]+lens[i]; - if (starts[j]+lens[j] < endo) - endo = starts[j]+lens[j]; - printf("Partition %d overlaps with others in " - "sectors %d-%d\n", i+1, starto, endo); - } - } - } - } - } - } - for (i = 0; i < 8; i++) { - if (lens[i]) - array[i] = i; - else - array[i] = -1; - } - qsort(array,SIZE(array),sizeof(array[0]), - (int (*)(const void *,const void *)) verify_sun_cmp); - if (array[0] == -1) { - printf("No partitions defined\n"); - return; - } - stop = cylinders * heads * sectors; - if (starts[array[0]]) - printf("Unused gap - sectors 0-%d\n",starts[array[0]]); - for (i = 0; i < 7 && array[i+1] != -1; i++) { - printf("Unused gap - sectors %d-%d\n",starts[array[i]]+lens[array[i]],starts[array[i+1]]); - } - start = starts[array[i]]+lens[array[i]]; - if (start < stop) - printf("Unused gap - sectors %d-%d\n",start,stop); -} - -void add_sun_partition(int n, int sys) -{ - uint start, stop, stop2; - uint starts[8], lens[8]; - int whole_disk = 0; - - char mesg[48]; - int i, first, last; - - if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) { - printf("Partition %d is already defined. Delete " - "it before re-adding it.\n", n + 1); - return; - } - - fetch_sun(starts,lens,&start,&stop); - if (stop <= start) { - if (n == 2) - whole_disk = 1; - else { - printf("Other partitions already cover the whole disk.\nDelete " - "some/shrink them before retry.\n"); - return; - } - } - sprintf(mesg, "First %s", str_units()); - for (;;) { - if (whole_disk) - first = read_int(0, 0, 0, deflt, mesg); - else - first = read_int(scround(start), scround(start), scround(stop), - ignore, mesg); - if (unit_flag) - first *= display_factor; - else - first = (first + heads * sectors - 1) / (heads * sectors); /* Starting sector has to be properly aligned */ - if (n == 2 && first != 0) printf ("It is highly recommended that third partition covers the whole disk\n" - "and is of type `Whole disk'\n"); - for (i = 0; i < partitions; i++) - if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first) - break; - if (i < partitions && !whole_disk) { - if (n == 2 && !first) { - whole_disk = 1; - break; - } - printf("Sector %d is already allocated\n", first); - } else - break; - } - stop = cylinders * heads * sectors; - stop2 = stop; - for (i = 0; i < partitions; i++) { - if (starts[i] > first && starts[i] < stop) - stop = starts[i]; - } - sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); - if (whole_disk) - last = read_int(scround(stop2), scround(stop2), scround(stop2), - deflt, mesg); - else if (n == 2 && !first) - last = read_int(scround(first), scround(stop2), scround(stop2), - upper, mesg); - else - last = read_int(scround(first), scround(stop), scround(stop), - lower, mesg); - if (unit_flag) - last *= display_factor; - if (n == 2 && !first) { - if (last >= stop2) { - whole_disk = 1; - last = stop2; - } else if (last > stop) { - printf ("You haven't covered whole disk with 3rd partition, but your value\n" - "%d %s coveres some other partition. Your entry have been changed\n" - "to %d %s\n", scround(last), str_units(), scround(stop), str_units()); - last = stop; - } - } else if (!whole_disk && last > stop) - last = stop; - - if (whole_disk) sys = WHOLE_DISK; - set_sun_partition(n, first, last, sys); -} - -void -sun_delete_partition(int i) { - if (i == 2 && sunlabel->infos[i].id == WHOLE_DISK && - !sunlabel->partitions[i].start_cylinder && - SSWAP32(sunlabel->partitions[i].num_sectors) == heads * sectors * cylinders) - printf("If you want to maintain SunOS/Solaris compatibility, consider leaving this\n" - "partition as Whole disk (5), starting at 0, with %d sectors\n", - SSWAP32(sunlabel->partitions[i].num_sectors)); - sunlabel->infos[i].id = 0; - sunlabel->partitions[i].num_sectors = 0; -} - -void -sun_change_sysid(int i, int sys) { - if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) { - read_chars( - "It is highly recommended that the partition at offset 0\n" - "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n" - "there may destroy your partition table and bootblock.\n" - "Type YES if you're very sure you would like that partition\n" - "tagged with 82 (Linux swap): "); - if (strcmp (line_ptr, "YES\n")) - return; - } - switch (sys) { - case SUNOS_SWAP: - case LINUX_SWAP: - /* swaps are not mountable by default */ - sunlabel->infos[i].flags |= 0x01; - break; - default: - /* assume other types are mountable; - user can change it anyway */ - sunlabel->infos[i].flags &= ~0x01; - break; - } - sunlabel->infos[i].id = sys; -} - -void -sun_list_table(int xtra) { - int i, w; - char *type; - - w = strlen(disk_device); - if (xtra) - printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n" - "%d cylinders, %d alternate cylinders, %d physical cylinders\n" - "%d extra sects/cyl, interleave %d:1\n" - "%s\n" - "Units = %ss of %d * 512 bytes\n\n", - disk_device, heads, sectors, SSWAP16(sunlabel->rspeed), - cylinders, SSWAP16(sunlabel->nacyl), - SSWAP16(sunlabel->pcylcount), - SSWAP16(sunlabel->sparecyl), - SSWAP16(sunlabel->ilfact), - (char *)sunlabel, - str_units(), display_factor); - else - printf("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n" - "Units = %ss of %d * 512 bytes\n\n", - disk_device, heads, sectors, cylinders, - str_units(), display_factor); - - printf("%*s Flag %s Start End Blocks Id System\n", - w + 1, "Device", show_begin ? " Begin " : " "); - for (i = 0 ; i < partitions; i++) { - if (sunlabel->partitions[i].num_sectors) { - __u32 start = SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors; - __u32 len = SSWAP32(sunlabel->partitions[i].num_sectors); - printf( - show_begin - ? "%*s%-2d %c%c%9d%9d%9d%9d%c %2x %s\n" - : "%*s%-2d %c%c%c%9d%9d%9d%c %2x %s\n", -/* device */ w, disk_device, i + 1, -/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', - (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ', -/* begin */ show_begin ? scround(start) : ' ', -/* start */ scround(start), -/* end */ scround(start+len), -/* odd flag on end */ len / 2, len & 1 ? '+' : ' ', -/* type id */ sunlabel->infos[i].id, -/* type name */ (type = partition_type(sunlabel->infos[i].id)) - ? type : "Unknown"); - } - } -} - -void -sun_set_alt_cyl(void) { - sunlabel->nacyl = SSWAP16(read_int(0,SSWAP16(sunlabel->nacyl), - 65535, deflt, - "Number of alternate cylinders")); -} - -void -sun_set_ncyl(int cyl) { - sunlabel->ncyl = SSWAP16(cyl); -} - -void -sun_set_xcyl(void) { - sunlabel->sparecyl = SSWAP16(read_int(0, SSWAP16(sunlabel->sparecyl), - sectors, deflt, - "Extra sectors per cylinder")); -} - -void -sun_set_ilfact(void) { - sunlabel->ilfact = SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), - 32, deflt, - "Interleave factor")); -} - -void -sun_set_rspeed(void) { - sunlabel->rspeed = SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), - 100000, deflt, - "Rotation speed (rpm)")); -} - -void -sun_set_pcylcount(void) { - sunlabel->pcylcount=SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), - 65535, deflt, - "Number of physical cylinders")); -} - -void -sun_write_table(void) { - unsigned short *ush = (unsigned short *)sunlabel; - unsigned short csum = 0; - - while(ush < (unsigned short *)(&sunlabel->csum)) - csum ^= *ush++; - sunlabel->csum = csum; - if (lseek(fd, 0, SEEK_SET) < 0) - fatal(unable_to_seek); - if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE) - fatal(unable_to_write); -} - -#endif /* sparc */ diff --git a/disk-utils/fdisksunlabel.h b/disk-utils/fdisksunlabel.h deleted file mode 100644 index 037e437c6..000000000 --- a/disk-utils/fdisksunlabel.h +++ /dev/null @@ -1,73 +0,0 @@ -#include /* for __u32 etc */ - -typedef struct { - unsigned char info[128]; /* Informative text string */ - unsigned char spare0[14]; - struct sun_info { - unsigned char spare1; - unsigned char id; - unsigned char spare2; - unsigned char flags; - } infos[8]; - unsigned char spare1[246]; /* Boot information etc. */ - unsigned short rspeed; /* Disk rotational speed */ - unsigned short pcylcount; /* Physical cylinder count */ - unsigned short sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ - unsigned short ilfact; /* Interleave factor */ - unsigned short ncyl; /* Data cylinder count */ - unsigned short nacyl; /* Alt. cylinder count */ - unsigned short ntrks; /* Tracks per cylinder */ - unsigned short nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ - struct sun_partition { - __u32 start_cylinder; - __u32 num_sectors; - } partitions[8]; - unsigned short magic; /* Magic number */ - unsigned short csum; /* Label xor'd checksum */ -} sun_partition; - -#define SUN_LABEL_MAGIC 0xDABE -#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA -#define sunlabel ((sun_partition *)buffer) -#define SSWAP16(x) (other_endian ? __swap16(x) \ - : (__u16)(x)) -#define SSWAP32(x) (other_endian ? __swap32(x) \ - : (__u32)(x)) - -#define scround(x) ((x+(display_factor-1)*unit_flag)/display_factor) - -/* fdisk.c */ -extern char changed[MAXIMUM_PARTS]; -extern char buffer[SECTOR_SIZE]; -extern uint heads, sectors, cylinders; -extern int show_begin; -extern int sun_label; -extern char *partition_type(unsigned char type); -extern void update_units(void); -extern char read_chars(char *mesg); - -/* fdisksunlabel.c */ -#define SUNOS_SWAP 3 -#define WHOLE_DISK 5 - -extern struct systypes sun_sys_types[]; -extern int get_num_sectors(struct sun_partition p); -extern void guess_device_type(int fd); -extern int check_sun_label(void); -extern void create_sunlabel(void); -extern void sun_delete_partition(int i); -extern void sun_change_sysid(int i, int sys); -extern void sun_list_table(int xtra); -extern void verify_sun(void); -extern void add_sun_partition(int n, int sys); -extern void sun_write_table(void); -extern void sun_set_alt_cyl(void); -extern void sun_set_ncyl(int cyl); -extern void sun_set_xcyl(void); -extern void sun_set_ilfact(void); -extern void sun_set_rspeed(void); -extern void sun_set_pcylcount(void); -extern void toggle_sunflags(int i, unsigned char mask); - diff --git a/disk-utils/fdprm b/disk-utils/fdprm index 2a59da018..a9282e1e6 100644 --- a/disk-utils/fdprm +++ b/disk-utils/fdprm @@ -24,3 +24,5 @@ 1680/1440 3360 21 2 80 0 0x0C 0x00 0xCF 0x6C # ????? # Add user-specific formats here +cbm1581 1600 10 2 80 2 0x2A 0x02 0xDF 0x2E +800/720 1600 10 2 80 0 0x2A 0x02 0xDF 0x2E diff --git a/disk-utils/frag.8 b/disk-utils/frag.8 deleted file mode 100644 index c2f67b581..000000000 --- a/disk-utils/frag.8 +++ /dev/null @@ -1,47 +0,0 @@ -.\" Copyright 1992,1993,1994 Rickard E. Faith (faith@cs.unc.edu) -.\" May be distributed under the GNU General Public License -.TH FRAG 8 "8 January 1994" "Linux 0.99" "Linux Programmer's Manual" -.SH NAME -frag \- simple fragmentation checker -.SH SYNOPSIS -.B /usr/sbin/frag -.B "[ \-s [ \-s ]]" -filename ... -.SH DESCRIPTION -.B frag -will report the file system fragmentation on a specified -.IR filename . -If the -.I filename -is a directory, -.B frag -will recursively descend the directory. -.SH OPTIONS -.TP -.B \-s -Silent (may be set to 1 or 2). The first -.B \-s -eliminates the file by file statistics, and just prints the -examined directories and a summary. The second -.B \-s -eliminates the printing of the directories, and just prints a -summary. This option is useful when -.B frag -is used on a directory. -.SH "SEE ALSO" -.BR mkfs (8), -.BR fsck (8), -.BR mkefs (8), -.BR efsck (8) -.SH BUGS -.B frag -will get caught in an infinite loop in the /proc filesystem. -.SH AUTHORS -V1.0 by Werner Almesberger -.br -V1.1 by Steffen Zahn, adding directory recursion -.br -V1.2 by Rob Hooft, adding hole counts -.br -V1.3 by Steffen Zahn, ignore symlinks, -don't cross filesys borders, get filesystem block size at runtime diff --git a/disk-utils/frag.c b/disk-utils/frag.c deleted file mode 100644 index 0098e02f2..000000000 --- a/disk-utils/frag.c +++ /dev/null @@ -1,311 +0,0 @@ -/* frag.c - simple fragmentation checker - V1.0 by Werner Almesberger - V1.1 by Steffen Zahn, adding directory recursion - V1.2 by Rob Hooft, adding hole counts - V1.3 by Steffen Zahn, email: szahn%masterix@emndev.siemens.co.at - 14 Nov 93 - - ignore symlinks, - - don't cross filesys borders - - get filesystem block size at runtime - V1.4 by Michael Bischoff to handle - indirect blocks better, but only for ext2fs - (applied by faith@cs.unc.edu, Sat Feb 4 22:06:27 1995) - - TODO: - handle hard links - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for FIBMAP */ - -typedef struct StackElem { - struct StackElem *backref, *next; - char name[NAME_MAX]; - char dir_seen; - char from_cmd_line; -} StackElem; - -StackElem *top = NULL; - - -void discard( void ) -{ - StackElem *se = top; - if( se == NULL ) - return ; - top = se->next; - free(se); -} - -void push( StackElem * se ) -{ - se -> next = top; - top = se; -} - -char *p2s( StackElem *se, char *path ) -{ - char *s; - if( se->backref!=NULL ) { - path = p2s( se->backref, path ); - if( path[-1]!='/' ) - *path++ = '/'; - } - s = se->name; - while( *s ) - *path++ = *s++; - return path; -} - -char *path2str( StackElem *se, char *path ) -{ - *(p2s( se, path ))=0; - return path; -} - -void *xmalloc( size_t size ) -{ - void *p; - if( (p=malloc(size))==NULL ) { - fprintf(stderr,"\nvirtual memory exhausted.\n"); - exit(1); - } - return p; -} - -int main(int argc,char **argv) -{ - int fd,last_phys_block, - fragments_in_file, blocks_in_file, - blocks,current_phys_block, - this_fragment, largest_fragment, i; - long sum_blocks=0, sum_frag_blocks=0, sum_files=0, sum_frag_files=0; - long num_hole=0, sum_hole=0, hole; - struct stat st; - struct statfs stfs; - StackElem *se, *se1; - char path[PATH_MAX], pathlink[PATH_MAX], *p; - DIR *dir; - struct dirent *de; - char silent_flag=0; - dev_t local_fs; - int block_size; - - if (argc < 2) - { - fprintf(stderr,"usage: %s [-s [-s]] filename ...\n",argv[0]); - exit(1); - } - argc--; argv++; - while (argc>0) - { - p = *argv; - if( *p=='-' ) - while( *++p ) - switch( *p ) - { - case 's': - silent_flag++; /* may be 1 or 2 */ - break; - default: - fprintf(stderr,"\nunknown flag %c\n", *p ); - exit(1); - } - else - { - se = xmalloc( sizeof(StackElem) ); - se->backref=NULL; se->dir_seen=0; se->from_cmd_line=1; - strcpy( se->name, p ); - push(se); - } - argc--; argv++; - } - while ( top != NULL) - { - se = top; - if( se->dir_seen ) - discard(); - else - { - path2str( se, path ); - if( readlink( path, pathlink, sizeof(pathlink) )>=0 ) - { /* ignore symlinks */ - if(silent_flag<1) - { - printf("symlink %s\n", path ); - } - discard(); - } - else if( stat( path,&st) < 0) - { - perror( path ); - discard(); - } - else if( !se->from_cmd_line && (local_fs!=st.st_dev) ) - { /* do not cross filesystem borders */ - if(silent_flag<2) - { - printf("different filesystem %s\n", path ); - } - discard(); - } - else - { - if( se->from_cmd_line ) - { - local_fs = st.st_dev; - if ( statfs( path, &stfs )<0 ) - { - perror( path ); - block_size = 1024; - } - else - block_size = stfs.f_bsize; - } - if( S_ISREG(st.st_mode)) /* regular file */ - { - if ( (fd = open( path ,O_RDONLY)) < 0 ) - { - perror( path ); - discard(); - } - else - { - last_phys_block = -1; - fragments_in_file = 0; - hole = 0; this_fragment=0; - largest_fragment=0; - blocks_in_file = (st.st_size+block_size-1)/block_size; - for (blocks = 0; blocks < blocks_in_file; blocks++) - { - current_phys_block = blocks; - if (ioctl(fd,FIBMAP,¤t_phys_block) < 0) - { - perror(path); - break; - } - if (current_phys_block) { /* no hole here */ - int indirect; - /* indirect is the number of indirection */ - /* blocks which must be skipped */ - indirect = 0; - /* every 256 blocks there is an indirect block, - the first of these is before block 12 */ - if (blocks >= 12 && (blocks-12) % 256 == 0) - ++indirect; - /* there is a block pointing to the indirect - blocks every 64K blocks */ - if (blocks >= 256+12 && (blocks-256-12) % 65536 == 0) - ++indirect; /* 2nd indirect block */ - /* there is a single triple indirect block */ - if (blocks == 65536 + 256 + 12) - ++indirect; - if (last_phys_block == current_phys_block-1-indirect) - this_fragment++; - else { /* start of first or new fragment */ - if( largest_fragment1 ) - { - sum_frag_blocks+=blocks_in_file-largest_fragment; - sum_frag_files++; - } - discard(); - close(fd); - } - } - else if( S_ISDIR( st.st_mode ) ) /* push dir contents */ - { - if( (dir=opendir( path ))==NULL ) - { - perror(path); - discard(); - } - else - { - if( silent_flag<2 ) - printf("reading %s\n", path); - while( (de=readdir(dir))!=NULL ) - { - if( (strcmp(de->d_name,".")!=0) - && (strcmp(de->d_name,"..")!=0) ) - { - se1 = xmalloc( sizeof(StackElem) ); - se1->backref=se; se1->dir_seen=0; - se1->from_cmd_line=0; - strcpy( se1->name, de->d_name ); - push(se1); - } - } - closedir( dir ); - se->dir_seen=1; - } - } - else /* if( S_ISREG(st.st_mode)) */ - discard(); - } - } /* if( se->dir_seen ) */ - } /* while ( top != NULL) */ - if (sum_files>1) - { - printf("\nsummary:\n"); - printf(" %3ld%% file fragmentation (%ld of %ld files contain fragments)\n", - sum_files<1 ? 0L : sum_frag_files*100/sum_files, - sum_frag_files, sum_files); - printf(" %3ld%% block fragmentation (%ld of %ld blocks are in fragments)\n", - sum_blocks<1 ? 0L : sum_frag_blocks*100/sum_blocks, - sum_frag_blocks, sum_blocks); - if (num_hole>1) - printf(" %ld files contain %ld blocks in holes\n", - num_hole,sum_hole); - } - exit(0); -} diff --git a/disk-utils/fsck.minix.c b/disk-utils/fsck.minix.c index ae1d7b1a8..ba64bf34f 100644 --- a/disk-utils/fsck.minix.c +++ b/disk-utils/fsck.minix.c @@ -317,7 +317,7 @@ int check_zone_nr(unsigned short * nr, int * corrected) return 0; } - +#ifdef HAVE_MINIX2 int check_zone_nr2 (unsigned int *nr, int *corrected) { if (!*nr) @@ -336,6 +336,7 @@ int check_zone_nr2 (unsigned int *nr, int *corrected) } return 0; } +#endif /* * read-block reads block nr into the buffer at addr. @@ -627,11 +628,12 @@ struct minix_inode * get_inode(unsigned int nr) nr); print_current_name(); printf("'\n"); - if (repair) + if (repair) { if (ask("Mark in use",1)) mark_inode(nr); - else + } else { errors_uncorrected = 1; + } } if (S_ISDIR(inode->i_mode)) directory++; @@ -762,7 +764,7 @@ static int add_zone(unsigned short * znr, int * corrected) return block; } - +#ifdef HAVE_MINIX2 static int add_zone2 (unsigned int *znr, int *corrected) { int result; @@ -795,6 +797,7 @@ static int add_zone2 (unsigned int *znr, int *corrected) zone_count[block]--; return block; } +#endif static void add_zone_ind(unsigned short * znr, int * corrected) { @@ -812,7 +815,9 @@ static void add_zone_ind(unsigned short * znr, int * corrected) write_block(block, blk); } -static void add_zone_ind2 (unsigned int *znr, int *corrected) +#ifdef HAVE_MINIX2 +static void +add_zone_ind2 (unsigned int *znr, int *corrected) { static char blk[BLOCK_SIZE]; int i, chg_blk = 0; @@ -827,6 +832,7 @@ static void add_zone_ind2 (unsigned int *znr, int *corrected) if (chg_blk) write_block (block, blk); } +#endif static void add_zone_dind(unsigned short * znr, int * corrected) { @@ -844,6 +850,7 @@ static void add_zone_dind(unsigned short * znr, int * corrected) write_block(block, blk); } +#ifdef HAVE_MINIX2 static void add_zone_dind2 (unsigned int *znr, int *corrected) { @@ -877,6 +884,7 @@ add_zone_tind2 (unsigned int *znr, int *corrected) if (blk_chg) write_block (block, blk); } +#endif void check_zones(unsigned int i) { @@ -945,18 +953,20 @@ void check_file(struct minix_inode * dir, unsigned int offset) name_depth++; inode = get_inode(ino); name_depth--; - if (!offset) + if (!offset) { if (!inode || strcmp(".",name)) { print_current_name(); printf(": bad directory: '.' isn't first\n"); errors_uncorrected = 1; } else return; - if (offset == dirsize) + } + if (offset == dirsize) { if (!inode || strcmp("..",name)) { print_current_name(); printf(": bad directory: '..' isn't second\n"); errors_uncorrected = 1; } else return; + } if (!inode) return; if (name_depth < MAX_DEPTH) @@ -1230,12 +1240,12 @@ int main(int argc, char ** argv) #endif while (argc-- > 1) { argv++; - if (argv[0][0] != '-') + if (argv[0][0] != '-') { if (device_name) usage(); else device_name = argv[0]; - else while (*++argv[0]) + } else while (*++argv[0]) switch (argv[0][0]) { case 'l': list=1; break; case 'a': automatic=1; repair=1; break; diff --git a/disk-utils/llseek.c b/disk-utils/llseek.c deleted file mode 100644 index a9cd5a3ac..000000000 --- a/disk-utils/llseek.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * llseek.c -- stub calling the llseek system call - * - * Copyright (C) 1994 Remy Card. This file may be redistributed - * under the terms of the GNU Public License. - */ - -#include - -#include -#include - -#if defined(__GNUC__) || defined(HAS_LONG_LONG) -typedef long long ext2_loff_t; -#else -typedef long ext2_loff_t; -#endif - -extern ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); - -#ifdef __linux__ - -#ifdef HAVE_LLSEEK -#include - -#else /* HAVE_LLSEEK */ - -#ifdef __alpha__ - -#define my_llseek lseek - -#else -#include /* for __NR__llseek */ - -static int _llseek (unsigned int, unsigned long, - unsigned long, ext2_loff_t *, unsigned int); - -static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, - unsigned long, offset_low,ext2_loff_t *,result, - unsigned int, origin) - -static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset, - unsigned int origin) -{ - ext2_loff_t result; - int retval; - - retval = _llseek (fd, ((unsigned long long) offset) >> 32, - ((unsigned long long) offset) & 0xffffffff, - &result, origin); - return (retval == -1 ? (ext2_loff_t) retval : result); -} - -#endif /* __alpha__ */ - -#endif /* HAVE_LLSEEK */ - -ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, - unsigned int origin) -{ - ext2_loff_t result; - static int do_compat = 0; - - if (!do_compat) { - result = my_llseek (fd, offset, origin); - if (!(result == -1 && errno == ENOSYS)) - return result; - - /* - * Just in case this code runs on top of an old kernel - * which does not support the llseek system call - */ - do_compat = 1; - /* - * Now try ordinary lseek. - */ - } - - 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 */ - -ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, - unsigned int origin) -{ - if ((sizeof(off_t) < sizeof(ext2_loff_t)) && - (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { - errno = EINVAL; - return -1; - } - return lseek (fd, (off_t) offset, origin); -} - -#endif /* linux */ - - diff --git a/disk-utils/mkfs.8 b/disk-utils/mkfs.8 index 57132a483..2dd616484 100644 --- a/disk-utils/mkfs.8 +++ b/disk-utils/mkfs.8 @@ -55,13 +55,8 @@ This is really only useful for testing. .TP .BI -t \ fstype Specifies the type of file system to be built. -If not specified, the type is deduced by searching for -.I filesys -in -.I /etc/fstab -and using the corresponding entry. -If the type can not be deduced, the default file system type -(currently minix) is used. +If not specified, the default file system type +(currently ext2) is used. .TP .B fs-options File system-specific options to be passed to the real file diff --git a/disk-utils/mkfs.minix.c b/disk-utils/mkfs.minix.c index db7aefaea..c34da5326 100644 --- a/disk-utils/mkfs.minix.c +++ b/disk-utils/mkfs.minix.c @@ -624,7 +624,7 @@ int main(int argc, char ** argv) #endif while (argc-- > 1) { argv++; - if (argv[0][0] != '-') + if (argv[0][0] != '-') { if (device_name) { BLOCKS = strtol(argv[0],&tmp,0); if (*tmp) { @@ -634,7 +634,7 @@ int main(int argc, char ** argv) } } else device_name = argv[0]; - else { + } else { if(argv[0][1] == 'l') { listfile = argv[1]; argv++; diff --git a/disk-utils/mkswap.8 b/disk-utils/mkswap.8 index 1e14167b8..2df606c57 100644 --- a/disk-utils/mkswap.8 +++ b/disk-utils/mkswap.8 @@ -1,83 +1,93 @@ -.\" 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 -.\" Modified with suggestions from Linus, Mon Feb 1 21:40:49 1993 -.\" Modified with patches from Kai, Wed Jun 22 21:54:56 1994 -.\" Patches from jaggy@purplet.demon.co.uk (Mike Jagdis), Wed Feb 8 1995 -.\" Added comments from Nick Holloway, Sat Feb 11 1995, faith@cs.unc.edu -.\" " -.TH MKSWAP 8 "February 1995" "Linux 1.0" "Linux Programmer's Manual" +.\" Rewritten for 2.1.117, aeb, 981010. +.\" +.TH MKSWAP 8 "1 December 1998" "Linux 2.1.117" "Linux Programmer's Manual" .SH NAME mkswap \- set up a Linux swap area .SH SYNOPSIS -.B "mkswap [ \-c ]" -.IB device " [" size-in-blocks "]" +.BI "mkswap [\-c] [\-v" N "] [\-f] " device " [" size "]" .SH DESCRIPTION .B mkswap sets up a Linux swap area on a device or in a file. +(After creating the swap area, you need the +.B swapon +command to start using it. Usually swap areas are listed in +.I /etc/fstab +so that they can be taken into use at boot time by a +.B swapon -a +command in some boot script.) + The .I device -is usually of the following form: - -.nf -.RS -/dev/hda[1-8] -/dev/hdb[1-8] -/dev/sda[1-8] -/dev/sdb[1-8] -.RE -.fi +argument will usually be a disk partition (something like +.I /dev/hda4 +or +.IR /dev/sdb7 ) +but can also be a file. +The Linux kernel does not look at partition Id's, but +many installation scripts will assume that partitions +of hex type 82 (LINUX_SWAP) are meant to be swap partitions. The -.I size-in-blocks -parameter is the desired size of the file system, in blocks. This -information is determined automatically by +.I size +parameter is superfluous but retained for backwards compatibility. +(It specifies the desired size of the swap area in 1024-byte blocks. .B mkswap -if it is omitted. Block counts are rounded down so that the total -size is an integer multiple of the machine's page size. Only block -counts in the range MINCOUNT..MAXCOUNT are allowed. If the block count -exceeds the MAXCOUNT, it is truncated to that value and a warning -message is issued. +will use the entire partition or file if it is omitted.) -The MINCOUNT and MAXCOUNT values for a swap area are: +Linux knows about two styles of swap areas, old style and new style. +The last 10 bytes of the first page of the swap area distinguishes +them: old style has `SWAP_SPACE', new style has `SWAPSPACE2' as +signature. -.RS -MINCOUNT = 10 * PAGE_SIZE / 1024 -.br -MAXCOUNT = (PAGE_SIZE - 10) * 8 * PAGE_SIZE / 1024 -.RE +In the old style, the rest of this first page was a bit map, +with a 1 bit for each usable page of the swap area. +Since the first page holds this bit map, the first bit is 0. +Also, the last 10 bytes hold the signature. So, if the page +size is S, an old style swap area can describe at most +8*(S-10)-1 pages used for swapping. +With S=4096 (as on i386), the useful area is at most 133890048 bytes +(almost 128 MB if you believe in 1 MB=2^20 bytes), and the rest is wasted. +On an alpha and sparc64, with S=8192, the useful area is at most +535560992 bytes (almost 512 MB with the same proviso). -For example, on a machine with 4kB pages (e.g., x86), we get: +The old setup wastes most of this bitmap page, because zero bits +denote bad blocks or blocks past the end of the swap space, +and a simple integer suffices to indicate the size of the swap space, +while the bad blocks, if any, can simply be listed. Nobody wants +to use a swap space with hundreds of bad blocks. (I would not even +use a swap space with 1 bad block.) +In the new style swap area this is precisely what is done. +The maximum useful size of a swap area is now (2^31 - 2*S) bytes, +roughly 2 GB. -.RS -MINCOUNT = 10 * 4096 / 1024 = 40 -.br -MAXCOUNT = (4096 - 10) * 8 * 4096 / 1024 = 130752 -.RE +Note that before 2.1.117 the kernel allocated one byte for each page, +while it now allocates two bytes, so that taking a swap area of 2 GB +in use might require 2 MB of kernel memory. -As each block is 1kB large, the swap area in this example could have a -size that is anywhere in the range from 40kB up to 127.6875MB. +Presently, Linux allows 8 swap areas. The areas in use can be seen +in the file +.I /proc/swaps +(since 2.1.25). -If you don't know the page size that your machine uses, you may be -able to look it up with "cat /proc/cpuinfo". +.B mkswap +refuses areas smaller than 10 pages. -The reason for the limit on MAXCOUNT is that a single page is used to -hold the swap bitmap at the start of the swap area, where each bit -represents a single page. The reason for the -10, is that the -signature is "SWAP-SPACE" -- 10 characters. +If you don't know the page size that your machine uses, you may be +able to look it up with "cat /proc/cpuinfo" (or you may not - +the contents of this file depend on architecture and kernel version). To setup a swap file, it is necessary to create that file before running -.B mkswap . -A sequence of commands similar to the following is reasonable for this -purpose: +.B mkswap , +e.g. using a command like .nf .RS -# dd if=/dev/zero of=swapfile bs=1024 count=8192 -# mkswap swapfile 8192 -# sync -# swapon swapfile +# dd if=/dev/zero of=swapfile bs=1024 count=65536 .RE .fi @@ -88,19 +98,34 @@ to create the file is not acceptable). .SH OPTIONS .TP .B \-c -Check the device for bad blocks before creating the file system. If any -are found, the count is printed. This option is meant to be used for swap -partitions -.BR only , -and should -.B not -be used for regular files! To make sure that regular files do not contain -bad blocks, the partition that contains the regular file should have been -created with -.BR "mkfs -c" . +Check the device (if it is a block device) for bad blocks +before creating the swap area. +If any are found, the count is printed. +.TP +.B \-f +On SPARC, force creation of the swap area. +Without this option +.B mkswap +will refuse to create a v0 swap on a device with a valid SPARC superblock, +as that probably means one is going to erase the partition table. +.TP +.B \-v0 +Create an old style swap area. +.TP +.B \-v1 +Create a new style swap area. + +.LP +If no \-v option is given, +.B mkswap +will default to old style if the size of the swap area does not +exceed the maximum size of an old style swap area, and also if +the current kernel is older than 2.1.117 (and also if PAGE_SIZE +is less than 2048). +The new style header does not touch the first block, so may be +preferable (also if the swap area is small), in case you have +a boot loader or disk label there. + .SH "SEE ALSO" -.BR fsck (8), -.BR mkfs (8), -.BR fdisk (8) -.SH AUTHOR -Linus Torvalds (torvalds@cs.helsinki.fi) +.BR fdisk (8), +.BR swapon (8) diff --git a/disk-utils/mkswap.c b/disk-utils/mkswap.c index 49447f2af..b3402366c 100644 --- a/disk-utils/mkswap.c +++ b/disk-utils/mkswap.c @@ -8,15 +8,21 @@ /* * 20.12.91 - time began. Got VM working yesterday by doing this by hand. * - * Usuage: mkswap [-c] device [size-in-blocks] + * Usuage: mkswap [-c] [-vN] [-f] device [size-in-blocks] * - * -c for readablility checking (use it unless you are SURE!) + * -c for readability checking. (Use it unless you are SURE!) + * -vN for swap areas version N. (Only N=0,1 known today.) + * -f for forcing swap creation even if it would smash partition table. * - * The device may be a block device or a image of one, but this isn't + * The device may be a block device or an image of one, but this isn't * enforced (but it's not much fun on a character device :-). * * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. + * + * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. + * + * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. */ #include @@ -24,26 +30,85 @@ #include #include #include -#include +#include /* for _IO */ +#include #include -#include +#include /* for PAGE_SIZE and PAGE_SHIFT */ +#ifndef _IO +/* pre-1.3.45 */ #define BLKGETSIZE 0x1260 - -#ifndef __linux__ -# define volatile +#else +/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ +#define BLKGETSIZE _IO(0x12,96) #endif -#define TEST_BUFFER_PAGES 8 - static char * program_name = "mkswap"; static char * device_name = NULL; static int DEV = -1; static long PAGES = 0; static int check = 0; static int badpages = 0; +static int version = -1; + +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) + +static int +linux_version_code(void) { + struct utsname my_utsname; + int p, q, r; + + if (uname(&my_utsname) == 0) { + p = atoi(strtok(my_utsname.release, ".")); + q = atoi(strtok(NULL, ".")); + r = atoi(strtok(NULL, ".")); + return MAKE_VERSION(p,q,r); + } + return 0; +} + +/* + * The definition of the union swap_header uses the constant PAGE_SIZE. + * Unfortunately, on some architectures this depends on the hardware model, + * and can only be found at run time -- we use getpagesize(). + */ + +static int pagesize; +static int *signature_page; -static int signature_page[PAGE_SIZE/sizeof(int)]; +struct swap_header_v1 { + char bootbits[1024]; /* Space for disklabel etc. */ + unsigned int version; + unsigned int last_page; + unsigned int nr_badpages; + unsigned int padding[125]; + unsigned int badpages[1]; +} *p; + +static void +init_signature_page() { + pagesize = getpagesize(); + +#ifdef PAGE_SIZE + if (pagesize != PAGE_SIZE) + fprintf(stderr, "Assuming pages of size %d\n", pagesize); +#endif + signature_page = (int *) malloc(pagesize); + memset(signature_page,0,pagesize); + p = (struct swap_header_v1 *) signature_page; +} + +static void +write_signature(char *sig) { + char *sp = (char *) signature_page; + + strncpy(sp+pagesize-10, sig, 10); +} + +#define V0_MAX_PAGES (8 * (pagesize - 10)) +#define V1_MAX_PAGES ((0x7fffffff / pagesize) - 1) + +#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) static void bit_set (unsigned int *addr, unsigned int nr) { @@ -66,41 +131,56 @@ static int bit_test_and_clear (unsigned int *addr, unsigned int nr) return (r & m) != 0; } -/* - * Volatile to let gcc know that this doesn't return. When trying - * to compile this under minix, volatile gives a warning, as - * exit() isn't defined as volatile under minix. - */ -volatile void fatal_error(const char * fmt_string) +void fatal_error(const char * fmt_string) { fprintf(stderr,fmt_string,program_name,device_name); exit(1); } -#define usage() fatal_error("Usage: %s [-c] /dev/name [blocks]\n") +#define usage() fatal_error("Usage: %s [-c] [-v0|-v1] /dev/name [blocks]\n") #define die(str) fatal_error("%s: " str "\n") -void check_blocks(void) -{ +void +page_ok(int page) { + if (version==0) + bit_set(signature_page, page); +} + +void +page_bad(int page) { + if (version == 0) + bit_test_and_clear(signature_page, page); + else { + if (badpages == MAX_BADPAGES) + die("too many bad pages"); + p->badpages[badpages] = page; + } + badpages++; +} + +void +check_blocks(void) { unsigned int current_page; int do_seek = 1; - static char buffer[PAGE_SIZE]; + char *buffer; + buffer = malloc(pagesize); + if (!buffer) + die("Out of memory"); current_page = 0; while (current_page < PAGES) { if (!check) { - bit_set(signature_page,current_page++); + page_ok(current_page++); continue; } - if (do_seek && lseek(DEV,current_page*PAGE_SIZE,SEEK_SET) != - current_page*PAGE_SIZE) + if (do_seek && lseek(DEV,current_page*pagesize,SEEK_SET) != + current_page*pagesize) die("seek failed in check_blocks"); - if ((do_seek = (PAGE_SIZE != read(DEV, buffer, PAGE_SIZE)))) { - bit_test_and_clear(signature_page,current_page++); - badpages++; + if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { + page_bad(current_page++); continue; } - bit_set(signature_page,current_page++); + page_ok(current_page++); } if (badpages) printf("%d bad page%s\n",badpages,(badpages>1)?"s":""); @@ -117,12 +197,13 @@ static long valid_offset (int fd, int offset) return 1; } -static int count_blocks (int fd) +static int +find_size (int fd) { - int high, low; + unsigned int high, low; low = 0; - for (high = 1; valid_offset (fd, high); high *= 2) + for (high = 1; high > 0 && valid_offset (fd, high); high *= 2) low = high; while (low < high - 1) { @@ -133,26 +214,27 @@ static int count_blocks (int fd) else high = mid; } - valid_offset (fd, 0); return (low + 1); } -static int get_size(const char *file) +/* return size in pages, to avoid integer overflow */ +static int +get_size(const char *file) { int fd; int size; - fd = open(file, O_RDWR); + fd = open(file, O_RDONLY); if (fd < 0) { perror(file); exit(1); } if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); + int sectors_per_page = pagesize/512; + size /= sectors_per_page; + } else { + size = find_size(fd) / pagesize; } - - size = count_blocks(fd); close(fd); return size; } @@ -161,28 +243,41 @@ int main(int argc, char ** argv) { char * tmp; struct stat statbuf; + int maxpages; int goodpages; + int offset; + int force = 0; - memset(signature_page,0,PAGE_SIZE); if (argc && *argv) program_name = *argv; + + init_signature_page(); /* get pagesize */ + while (argc-- > 1) { argv++; - if (argv[0][0] != '-') + if (argv[0][0] != '-') { if (device_name) { - PAGES = strtol(argv[0],&tmp,0)>>(PAGE_SHIFT-10); + int blocks_per_page = pagesize/1024; + PAGES = strtol(argv[0],&tmp,0)/blocks_per_page; if (*tmp) usage(); } else device_name = argv[0]; - else while (*++argv[0]) - switch (argv[0][0]) { - case 'c': check=1; break; - default: usage(); + } else { + switch (argv[0][1]) { + case 'c': + check=1; + break; + case 'f': + force=1; + break; + case 'v': + version=atoi(argv[0]+2); + break; + default: + usage(); } - } - if (device_name && !PAGES) { - PAGES = get_size(device_name) / PAGE_SIZE; + } } if (!device_name) { fprintf(stderr, @@ -190,17 +285,38 @@ int main(int argc, char ** argv) program_name); usage(); } + if (!PAGES) { + PAGES = get_size(device_name); + } + + if (version == -1) { + if (PAGES <= V0_MAX_PAGES) + version = 0; + else if (linux_version_code() < MAKE_VERSION(2,1,117)) + version = 0; + else if (pagesize < 2048) + version = 0; + else + version = 1; + } + if (version != 0 && version != 1) { + fprintf(stderr, "%s: error: unknown version %d\n", + program_name, version); + usage(); + } if (PAGES < 10) { fprintf(stderr, "%s: error: swap area needs to be at least %ldkB\n", - program_name, (long)(10 * PAGE_SIZE / 1024)); + program_name, (long)(10 * pagesize / 1024)); usage(); } - if (PAGES > 8 * (PAGE_SIZE - 10)) { - PAGES = 8 * (PAGE_SIZE - 10); + maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); + if (PAGES > maxpages) { + PAGES = maxpages; fprintf(stderr, "%s: warning: truncating swap area to %ldkB\n", - program_name, PAGES * PAGE_SIZE / 1024); + program_name, PAGES * pagesize / 1024); } + DEV = open(device_name,O_RDWR); if (DEV < 0 || fstat(DEV, &statbuf) < 0) { perror(device_name); @@ -210,19 +326,56 @@ int main(int argc, char ** argv) check=0; else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) die("Will not try to make swapdevice on '%s'"); - check_blocks(); - if (!bit_test_and_clear(signature_page,0)) + +#ifdef __sparc__ + if (!force && version == 0) { + /* Don't overwrite partition table unless forced */ + unsigned char *buffer = (unsigned char *)signature_page; + unsigned short *q, sum; + + if (read(DEV, buffer, 512) != 512) + die("fatal: first page unreadable"); + if (buffer[508] == 0xDA && buffer[509] == 0xBE) { + q = (unsigned short *)(buffer + 510); + for (sum = 0; q >= (unsigned short *) buffer;) + sum ^= *q--; + if (!sum) { + fprintf(stderr, "\ +%s: Device '%s' contains a valid Sun disklabel.\n\ +This probably means creating v0 swap would destroy your partition table\n\ +No swap created. If you really want to create swap v0 on that device, use\n\ +the -f option to force it.\n", + program_name, device_name); + exit(1); + } + } + } +#endif + + if (version == 0 || check) + check_blocks(); + if (version == 0 && !bit_test_and_clear(signature_page,0)) die("fatal: first page unreadable"); + if (version == 1) { + p->version = version; + p->last_page = PAGES-1; + p->nr_badpages = badpages; + } + goodpages = PAGES - badpages - 1; if (goodpages <= 0) die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace, size = %ld bytes\n", - (long)(goodpages*PAGE_SIZE)); - strncpy((char*)signature_page+PAGE_SIZE-10, "SWAP-SPACE", 10); - if (lseek(DEV, 0, SEEK_SET)) + printf("Setting up swapspace version %d, size = %ld bytes\n", + version, (long)(goodpages*pagesize)); + write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); + + offset = ((version == 0) ? 0 : 1024); + if (lseek(DEV, offset, SEEK_SET) != offset) die("unable to rewind swap-device"); - if (PAGE_SIZE != write(DEV, signature_page, PAGE_SIZE)) + if (write(DEV,(char*)signature_page+offset, pagesize-offset) + != pagesize-offset) die("unable to write signature page"); + /* * A subsequent swapon() will fail if the signature * is not actually on disk. (This is a kernel bug.) diff --git a/disk-utils/setfdprm.c b/disk-utils/setfdprm.c index fee55300d..62234f3ac 100644 --- a/disk-utils/setfdprm.c +++ b/disk-utils/setfdprm.c @@ -103,7 +103,7 @@ gap rate spec1 fmt_gap\n",name); exit(1); } -void +int main(int argc,char **argv) { int fd; @@ -153,4 +153,5 @@ main(int argc,char **argv) else find_params(cmd,fd,argv[2]); /* not reached */ + return 0; } diff --git a/disk-utils/sfdisk.8 b/disk-utils/sfdisk.8 deleted file mode 100644 index 33f10dabd..000000000 --- a/disk-utils/sfdisk.8 +++ /dev/null @@ -1,497 +0,0 @@ -.\" Copyright 1995 Andries E. Brouwer (aeb@cwi.nl) -.\" May be distributed under the GNU General Public License -.\" The `DOS 6.x Warning' was taken from the old fdisk.8, which says -.\" -- Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) -.\" -- May be distributed under the GNU General Public License -.\" The `DRDOS Warning' was taken from a net post by Stephen Tweedie. -.\" -.TH SFDISK 8 "1 September 1995" "Linux 1.3.23" "Linux Programmer's Manual" -.SH NAME -sfdisk \- Partition table manipulator for Linux -.SH SYNOPSIS -.BR sfdisk " [options] device" -.br -.BR "sfdisk \-s " [partition] -.SH DESCRIPTION -.B sfdisk -has four (main) uses: list the size of a partition, list the partitions -on a device, check the partitions on a device, and - very dangerous - -repartition a device. - -.SS "List Sizes" -.BI "sfdisk \-s " partition -gives the size of -.I partition -in blocks. This may be useful in connection with programs like -.B mkswap -or so. Here -.I partition -is usually something like -.I /dev/hda1 -or -.IR /dev/sdb12 , -but may also be an entire disk, like -.IR /dev/xda . -.br -.RS -.nf -.if t .ft CW -% sfdisk \-s /dev/hda9 -81599 -% -.if t .ft R -.fi -.RE -If the partition argument is omitted, -.B sfdisk -will list the sizes of all disks, and the total: -.br -.RS -.nf -.if t .ft CW -% sfdisk \-s -/dev/hda: 208896 -/dev/hdb: 1025136 -/dev/hdc: 1031063 -/dev/sda: 8877895 -/dev/sdb: 1758927 -total: 12901917 blocks -% -.if t .ft R -.fi -.RE - -.SS "List Partitions" -The second type of invocation: -.BI "sfdisk \-l " "[options] device" -will list the partitions on this device. -If the device argument is omitted, the partitions on all hard disks -are listed. -.br -.nf -.if t .ft CW -% sfdisk \-l /dev/hdc - -Disk /dev/hdc: 16 heads, 63 sectors, 2045 cylinders -Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0 - - Device Boot Start End #cyls #blocks Id System -/dev/hdc1 0+ 406 407\- 205096+ 83 Linux native -/dev/hdc2 407 813 407 205128 83 Linux native -/dev/hdc3 814 2044 1231 620424 83 Linux native -/dev/hdc4 0 \- 0 0 0 Empty -% -.if t .ft R -.fi -The trailing \- and + signs indicate that rounding has taken place, -and that the actual value is slightly less (more). -To see the exact values, ask for a listing with sectors as unit. - -.SS "Check partitions" -The third type of invocation: -.BI "sfdisk \-V " device -will apply various consistency checks to the partition tables on -.IR device . -It prints `OK' or complains. The \-V option can be used together -with \-l. In a shell script one might use -.BI "sfdisk \-V \-q " device -which only returns a status. - -.SS "Create partitions" -The fourth type of invocation: -.BI "sfdisk " device -will cause -.B sfdisk -to read the specification for the desired partitioning of -.I device -from its standard input, and then to change the partition tables -on that disk. Thus, it is possible to use -.B sfdisk -from a shell script. When -.B sfdisk -determines that its standard input is a terminal, it will be -conversational; otherwise it will abort on any error. -.LP -BE EXTREMELY CAREFUL - ONE TYPING MISTAKE AND ALL YOUR DATA IS LOST -.LP -As a precaution, one can save the sectors changed by -.BR sfdisk : -.RS -.nf -.if t .ft CW -% sfdisk /dev/hdd \-O hdd-partition-sectors.save -% -.if t .ft R -.fi -.RE -.LP -Then, if you discover that you did something stupid before anything -else has been written to disk, it may be possible to recover -the old situation with -.RS -.nf -.if t .ft CW -% sfdisk /dev/hdd \-I hdd-partition-sectors.save -% -.if t .ft R -.fi -.RE - -There are many options. - -.SH OPTIONS -.TP -.BR \-v " or " \-\-version -Print version number of -.B sfdisk -and exit immediately. -.TP -.BR \-? " or " \-\-help -Print a usage message and exit immediately. -.TP -.BR \-T " or " \-\-list-types -Print the recognized types (system Id's). -.TP -.BR \-s " or " \-\-show\-size -List the size of a partition. -.TP -.BR \-g " or " \-\-show\-geometry -List the kernel's idea of the geometry of the indicated disk(s). -.TP -.BR \-l " or " \-\-list -List the partitions of a device. -.TP -.BR \-d -Dump the partitions of a device in a format useful as input -to sfdisk. For example, -.br -.nf -.if t .ft CW - % sfdisk -d /dev/hda > hda.out - % sfdisk /dev/hda < hda.out -.if t .ft R -.fi -will correct the bad last extended partition that the OS/2 -fdisk creates. -.TP -.BR \-V " or " \-\-verify -Test whether partitions seem correct. (See above.) -.TP -.BR \-i " or " \-\-increment -Number cylinders etc. starting from 1 instead of 0. -.TP -.BI \-N " number" -Change only the single partition indicated. For example: -.br -.nf -.if t .ft CW - % sfdisk /dev/hdb \-N5 - ,,,* - % -.if t .ft R -.fi -will make the fifth partition on /dev/hdb bootable (`active') -and change nothing else. (Probably this fifth partition -is called /dev/hdb5, but you are free to call it something else, -like `/my_equipment/disks/2/5' or so). -.TP -.BI \-A " number" -Make the indicated partition(s) active, and all others inactive. -.TP -.BI \-c " or " \-\-id " number [Id]" -If no Id argument given: print the partition Id of the indicated -partition. If an Id argument is present: change the type (Id) of -the indicated partition to the given value. -This option has the two very long forms \-\-print\-id and \-\-change\-id. -For example: -.br -.nf -.if t .ft CW - % sfdisk --print-id /dev/hdb 5 - 6 - % sfdisk --change-id /dev/hdb 5 83 - OK -.if t .ft R -.fi -first reports that /dev/hdb5 has Id 6, and then changes that into 83. -.TP -.BR \-uS " or " \-uB " or " \-uC " or " \-uM -Accept or report in units of sectors (blocks, cylinders, megabytes, -respectively). The default is cylinders, at least when the geometry -is known. -.TP -.BR \-x " or " \-\-show\-extended -Also list non-primary extended partitions on output, -and expect descriptors for them on input. -.TP -.BI \-C " cylinders" -Specify the number of cylinders, possibly overriding what the kernel thinks. -.TP -.BI \-H " heads" -Specify the number of heads, possibly overriding what the kernel thinks. -.TP -.BI \-S " sectors" -Specify the number of sectors, possibly overriding what the kernel thinks. -.TP -.BR \-f " or " \-\-force -Do what I say, even if it is stupid. -.TP -.BR \-q " or " \-\-quiet -Suppress warning messages. -.TP -.BR \-L " or " \-\-Linux -Do not complain about things irrelevant for Linux. -.TP -.BR \-D " or " \-\-DOS -For DOS-compatibility: waste a little space. -(More precisely: if a partition cannot contain sector 0, -e.g. because that is the MBR of the device, or contains -the partition table of an extended partition, then -.B sfdisk -would make it start the next sector. However, when this -option is given it skips to the start of the next track, -wasting for example 33 sectors (in case of 34 sectors/track), -just like certain versions of DOS do.) -Certain Disk Managers and boot loaders (such as OSBS, but not -LILO or the OS/2 Boot Manager) also live in this empty space, -so maybe you want this option if you use one. -.TP -.BR \-\-IBM " or " \-\-leave\-last -Certain IBM diagnostic programs assume that they can use the -last cylinder on a disk for disk-testing purposes. If you think -you might ever run such programs, use this option to tell -.B sfdisk -that it should not allocate the last cylinder. -Sometimes the last cylinder contains a bad sector table. -.TP -.B \-n -Go through all the motions, but do not actually write to disk. -.TP -.B \-R -Only execute the BLKRRPART ioctl (to make the kernel re-read -the partition table). This can be useful for checking in advance -that the final BLKRRPART will be successful, and also when you -changed the partition table `by hand' (e.g., using dd from a backup). -If the kernel complains (`device busy for revalidation (usage = 2)') -then something still uses the device, and you still have to unmount -some file system, or say swapoff to some swap partition. -.TP -.B \-\-no\-reread -When starting a repartitioning of a disk, sfdisk checks that this disk -is not mounted, or in use as a swap device, and refuses to continue -if it is. This option suppresses the test. (On the other hand, the \-f -option would force sfdisk to continue even when this test fails.) -.TP -.BI \-O " file" -Just before writing the new partition, output the sectors -that are going to be overwritten to -.I file -(where hopefully -.I file -resides on another disk, or on a floppy). -.TP -.BI \-I " file" -After destroying your filesystems with an unfortunate -.B sfdisk -command, you would have been able to restore the old situation -if only you had preserved it using the \-O flag. - -.SH THEORY -Block 0 of a disk (the Master Boot Record) contains among -other things four partition descriptors. The partitions -described here are called -.I primary -partitions. -.LP -A partition descriptor has 6 fields: -.br -.nf -.RS -struct partition { - unsigned char bootable; /* 0 or 0x80 */ - hsc begin_hsc; - unsigned char id; - hsc end_hsc; - unsigned int starting_sector; - unsigned int nr_of_sectors; -} -.RE -.fi -.LP -The two hsc fields indicate head, sector and cylinder of the -begin and the end of the partition. Since each hsc field only -takes 3 bytes, only 24 bits are available, which does not -suffice for big disks (say > 8GB). In fact, due to the wasteful -representation (that uses a byte for the number of heads, which -is typically 16), problems already start with 0.5GB. -However Linux does not use these fields, and problems can arise -only at boot time, before Linux has been started. For more -details, see the -.B lilo -documentation. -.LP -Each partition has a type, its `Id', and if this type is 5 -.IR "" "(`" "extended partition" "')" -the starting sector of the partition -again contains 4 partition descriptors. MSDOS only uses the -first two of these: the first one an actual data partition, -and the second one again an extended partition (or empty). -In this way one gets a chain of extended partitions. -Other operating systems have slightly different conventions. -Linux also accepts type 85 as equivalent to 5 - this can be -useful if one wants to have extended partitions under Linux past -the 1024 cylinder boundary, without DOS FDISK hanging. -(If there is no good reason, you should just use 5, which is -understood by other systems.) -.LP -Partitions that are not primary or extended are called -.IR logical . -Often, one cannot boot from logical partitions (because the -process of finding them is more involved than just looking -at the MBR). -Note that of an extended partition only the Id and the start -are used. There are various conventions about what to write -in the other fields. One should not try to use extended partitions -for data storage or swap. - -.SH "INPUT FORMAT" -.B sfdisk -reads lines of the form -.br -.RS - -.RE -where each line fills one partition descriptor. -.LP -Fields are separated by whitespace, or comma or semicolon possibly -followed by whitespace; initial and trailing whitespace is ignored. -Numbers can be octal, decimal or hexadecimal, decimal is default. -When a field is absent or empty, a default value is used. -.LP -The parts can (and probably should) be omitted - -.B sfdisk -computes them from and and the disk geometry -as given by the kernel or specified using the \-H, \-S, \-C flags. -.LP -Bootable is specified as [*|\-], with as default not-bootable. -(The value of this field is irrelevant for Linux - when Linux -runs it has been booted already - but might play a role for -certain boot loaders and for other operating systems. -For example, when there are several primary DOS partitions, -DOS assigns C: to the first among these that is bootable.) -.LP -Id is given in hex, without the 0x prefix, or is [E|S|L|X], where -L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), E -is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED (85). -.LP -The default value of start is the first nonassigned sector/cylinder/... -.LP -The default value of size is as much as possible (until next -partition or end-of-disk). -.LP -However, for the four partitions inside an extended partition, -the defaults are: Linux partition, Extended partition, Empty, Empty. -.LP -But when the \-N option (change a single partition only) is given, -the default for each field is its previous value. - -.SH EXAMPLE -The command -.RS -.nf -.if t .ft CW -sfdisk /dev/hdc << EOF -0,407 -,407 -; -; -EOF -.if t .ft R -.fi -.RE -will partition /dev/hdc just as indicated above. - -With the \-x option, the number of input lines must be a multiple of 4: -you have to list the two empty partitions that you never want -using two blank lines. Without the \-x option, you give one line -for the partitions inside a extended partition, instead of four, -and terminate with end-of-file (^D). -(And -.B sfdisk -will assume that your input line represents the first of four, -that the second one is extended, and the 3rd and 4th are empty.) - -.SH "DOS 6.x WARNING" - -The DOS 6.x FORMAT command looks for some information in the first -sector of the data area of the partition, and treats this information -as more reliable than the information in the partition table. DOS -FORMAT expects DOS FDISK to clear the first 512 bytes of the data area -of a partition whenever a size change occurs. DOS FORMAT will look at -this extra information even if the /U flag is given -- we consider -this a bug in DOS FORMAT and DOS FDISK. -.LP -The bottom line is that if you use sfdisk to change the size of a -DOS partition table entry, then you must also use -.B dd -to zero the first 512 bytes of that partition before using DOS FORMAT to -format the partition. For example, if you were using sfdisk to make a DOS -partition table entry for /dev/hda1, then (after exiting sfdisk and -rebooting Linux so that the partition table information is valid) you -would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero -the first 512 bytes of the partition. -.B BE EXTREMELY CAREFUL -if you use the -.B dd -command, since a small typo can make all of the data on your disk useless. - -For best results, you should always use an OS-specific partition table -program. For example, you should make DOS partitions with the DOS FDISK -program and Linux partitions with the Linux sfdisk program. - -.SH "DRDOS WARNINGS" - -Stephen Tweedie reported (930515): `Most reports of superblock -corruption turn out to be due to bad partitioning, with one filesystem -overrunning the start of the next and corrupting its superblock. -I have even had this problem with the supposedly-reliable DRDOS. This -was quite possibly due to DRDOS-6.0's FDISK command. Unless I created -a blank track or cylinder between the DRDOS partition and the -immediately following one, DRDOS would happily stamp all over the -start of the next partition. Mind you, as long as I keep a little -free disk space after any DRDOS partition, I don't have any other -problems with the two coexisting on the one drive.' - -A. V. Le Blanc writes in README.esfdisk: `Dr. DOS 5.0 and 6.0 has been -reported to have problems cooperating with Linux, and with this version -of efdisk in particular. This efdisk sets the system type -to hexadecimal 81. Dr. DOS seems to confuse -this with hexadecimal 1, a DOS code. If you use Dr. DOS, use the -efdisk command 't' to change the system code of any Linux partitions -to some number less than hexadecimal 80; I suggest 41 and 42 for -the moment.' - -A. V. Le Blanc writes in his README.fdisk: `DR-DOS 5.0 and 6.0 -are reported to have difficulties with partition ID codes of 80 or more. -The Linux `fdisk' used to set the system type -of new partitions to hexadecimal 81. DR-DOS seems to confuse this with -hexadecimal 1, a DOS code. The values 82 for swap and 83 for file -systems should not cause problems with DR-DOS. If they do, you may use -the `fdisk' command `t' to change the system code of any Linux -partitions to some number less than hexadecimal 80; I suggest 42 and 43 -for the moment.' - -In fact, it seems that only 4 bits are significant for the DRDOS FDISK, -so that for example 11 and 21 are listed as DOS 2.0. However, DRDOS -itself seems to use the full byte. I have not been able to reproduce -any corruption with DRDOS or its fdisk. - -.SH BUGS -A corresponding interactive -.B cfdisk -(with curses interface) is still lacking. -.LP -There are too many options. - -.SH AUTHOR -A. E. Brouwer (aeb@cwi.nl) diff --git a/disk-utils/sfdisk.c b/disk-utils/sfdisk.c deleted file mode 100644 index 8fbe778fe..000000000 --- a/disk-utils/sfdisk.c +++ /dev/null @@ -1,2857 +0,0 @@ -/* - * sfdisk version 3.0 - aeb - 950813 - * - * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) - * - * This program is free software. You can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation: either Version 1 - * or (at your option) any later version. - * - * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, - * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, - * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) - * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. - * This program had (head,sector,cylinder) as basic unit, and was - * (therefore) broken in several ways for the use on larger disks - - * for example, my last patch (from 2.0d to 2.0e) was required - * to allow a partition to cross cylinder 8064, and to write an - * extended partition past the 4GB mark. - * - * The current program is a rewrite from scratch, and I started a - * version numbering at 3.0. - * Andries Brouwer, aeb@cwi.nl, 950813 - * - * Well, a good user interface is still lacking. On the other hand, - * many configurations cannot be handled by any other fdisk. - * I changed the name to sfdisk to prevent confusion. - aeb, 970501 - */ - -#define PROGNAME "sfdisk" -#define VERSION "3.07" -#define DATE "980518" - -#include -#include /* atoi, free */ -#include /* varargs */ -#include /* read, write */ -#include /* O_RDWR */ -#include /* ERANGE */ -#include /* index() */ -#include -#include -#include -#include -#include /* _syscall */ -#include /* HDIO_GETGEO */ -#include /* BLKGETSIZE */ - -#define SIZE(a) (sizeof(a)/sizeof(a[0])) - -/* - * Table of contents: - * A. About seeking - * B. About sectors - * C. About heads, sectors and cylinders - * D. About system Ids - * E. About partitions - * F. The standard input - * G. The command line - * H. Listing the current situation - * I. Writing the new situation - */ -int exit_status = 0; - -int force = 0; /* 1: do what I say, even if it is stupid ... */ -int quiet = 0; /* 1: suppress all warnings */ -int Linux = 0; /* 1: suppress warnings irrelevant for Linux */ -int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */ -int dump = 0; /* 1: list in a format suitable for later input */ -int verify = 0; /* 1: check that listed partition is reasonable */ -int no_write = 0; /* 1: do not actually write to disk */ -int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */ -int leave_last = 0; /* 1: don't allocate the last cylinder */ -int opt_list = 0; -char *save_sector_file = NULL; -char *restore_sector_file = NULL; - -void -warn(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - if (!quiet) - vfprintf (stderr, s, p); - va_end(p); -} - -void -error(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - fprintf(stderr, "\n" PROGNAME ": "); - vfprintf(stderr, s, p); - va_end(p); -} - -void -fatal(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - fprintf(stderr, "\n" PROGNAME ": "); - vfprintf(stderr, s, p); - va_end(p); - exit(1); -} - -/* - * A. About seeking - */ - -/* - * sseek: seek to specified sector - return 0 on failure - * - * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. - * On the other hand, a 32 bit sector number is OK until 2TB. - * The routines _llseek and sseek below are the only ones that - * know about the loff_t type. - */ -#ifndef __alpha__ -static -_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, - loff_t *, res, uint, wh); -#endif - -int -sseek(char *dev, unsigned int fd, unsigned long s) { - loff_t in, out; - in = ((loff_t) s << 9); - out = 1; - -#ifndef __alpha__ - if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) { -#else - if ((out = lseek(fd, in, SEEK_SET)) != in) { -#endif - perror("llseek"); - error("seek error on %s - cannot seek to %lu\n", dev, s); - return 0; - } - - if (in != out) { - error("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n", - (uint)(in>>32), (uint)(in & 0xffffffff), - (uint)(out>>32), (uint)(out & 0xffffffff)); - return 0; - } - return 1; -} - -/* - * B. About sectors - */ - -/* - * We preserve all sectors read in a chain - some of these will - * have to be modified and written back. - */ -struct sector { - struct sector *next; - unsigned long sectornumber; - int to_be_written; - char data[512]; -} *sectorhead; - -void -free_sectors(void) { - struct sector *s; - - while (sectorhead) { - s = sectorhead; - sectorhead = s->next; - free(s); - } -} - -struct sector * -get_sector(char *dev, int fd, unsigned long sno) { - struct sector *s; - - for(s = sectorhead; s; s = s->next) - if(s->sectornumber == sno) - return s; - - if (!sseek(dev, fd, sno)) - return 0; - - if (!(s = (struct sector *) malloc(sizeof(struct sector)))) - fatal("out of memory - giving up\n"); - - if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { - perror("read"); - error("read error on %s - cannot read sector %lu\n", dev, sno); - free(s); - return 0; - } - - s->next = sectorhead; - sectorhead = s; - s->sectornumber = sno; - s->to_be_written = 0; - - return s; -} - -int -msdos_signature (struct sector *s) { - if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) { - error("ERROR: sector %lu does not have an msdos signature\n", - s->sectornumber); - return 0; - } - return 1; -} - -int -write_sectors(char *dev, int fd) { - struct sector *s; - - for (s = sectorhead; s; s = s->next) - if (s->to_be_written) { - if (!sseek(dev, fd, s->sectornumber)) - return 0; - if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { - perror("write"); - error("write error on %s - cannot write sector %lu\n", - dev, s->sectornumber); - return 0; - } - s->to_be_written = 0; - } - return 1; -} - -void -ulong_to_chars(unsigned long u, char *uu) { - int i; - - for(i=0; i<4; i++) { - uu[i] = (u & 0xff); - u >>= 8; - } -} - -unsigned long -chars_to_ulong(unsigned char *uu) { - int i; - unsigned long u = 0; - - for(i=3; i>=0; i--) - u = (u << 8) | uu[i]; - return u; -} - -int -save_sectors(char *dev, int fdin) { - struct sector *s; - char ss[516]; - int fdout; - - fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); - if (fdout < 0) { - perror(save_sector_file); - error("cannot open partition sector save file (%s)\n", - save_sector_file); - return 0; - } - - for (s = sectorhead; s; s = s->next) - if (s->to_be_written) { - ulong_to_chars(s->sectornumber, ss); - if (!sseek(dev, fdin, s->sectornumber)) - return 0; - if (read(fdin, ss+4, 512) != 512) { - perror("read"); - error("read error on %s - cannot read sector %lu\n", - dev, s->sectornumber); - return 0; - } - if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { - perror("write"); - error("write error on %s\n", save_sector_file); - return 0; - } - } - return 1; -} - -void reread_disk_partition(char *dev, int fd); - -int -restore_sectors(char *dev) { - int fdin, fdout, ct; - struct stat statbuf; - char *ss0, *ss; - unsigned long sno; - - if (stat(restore_sector_file, &statbuf) < 0) { - perror(restore_sector_file); - error("cannot stat partition restore file (%s)\n", - restore_sector_file); - return 0; - } - if (statbuf.st_size % 516) { - error("partition restore file has wrong size - not restoring\n"); - return 0; - } - if (!(ss = (char *) malloc(statbuf.st_size))) { - error("out of memory?\n"); - return 0; - } - fdin = open(restore_sector_file, O_RDONLY); - if (fdin < 0) { - perror(restore_sector_file); - error("cannot open partition restore file (%s)\n", - restore_sector_file); - return 0; - } - if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { - perror("read"); - error("error reading %s\n", restore_sector_file); - return 0; - } - - fdout = open(dev, O_WRONLY); - if (fdout < 0) { - perror(dev); - error("cannot open device %s for writing\n", dev); - return 0; - } - - ss0 = ss; - ct = statbuf.st_size/516; - while(ct--) { - sno = chars_to_ulong(ss); - if (!sseek(dev, fdout, sno)) - return 0; - if (write(fdout, ss+4, 512) != 512) { - perror(dev); - error("error writing sector %lu on %s\n", sno, dev); - return 0; - } - ss += 516; - } - free(ss0); - - reread_disk_partition(dev, fdout); - - return 1; -} - -/* - * C. About heads, sectors and cylinders - */ - -/* - * defines HDIO_GETGEO and - * struct hd_geometry { - * unsigned char heads; - * unsigned char sectors; - * unsigned short cylinders; - * unsigned long start; - * }; - */ - -unsigned long cylindersize; -unsigned long heads, sectors, cylinders; -unsigned long specified_heads, specified_sectors, specified_cylinders; - -void -get_cylindersize(char *dev, int fd, int silent) { - struct hd_geometry g; - int ioctl_ok = 0; - - heads = sectors = cylinders = 0; - - if (!ioctl(fd, HDIO_GETGEO, &g)) { - ioctl_ok = 1; - - heads = g.heads; - sectors = g.sectors; - cylinders = g.cylinders; - } - - if (specified_heads) - heads = specified_heads; - if (specified_sectors) - sectors = specified_sectors; - if (specified_cylinders) - cylinders = specified_cylinders; - - cylindersize = heads * sectors; - - if (ioctl_ok) { - if (g.start && !force) { - warn( - "Warning: start=%d - this looks like a partition rather than\n" - "the entire disk. Using fdisk on it is probably meaningless.\n" - "[Use the --force option if you really want this]\n", g.start); - exit(1); - } - if (heads != g.heads) - warn("Warning: HDIO_GETGEO says that there are %d heads\n", - g.heads); - if (sectors != g.sectors) - warn("Warning: HDIO_GETGEO says that there are %d sectors\n", - g.sectors); - if (cylinders != g.cylinders) - warn("Warning: HDIO_GETGEO says that there are %d cylinders\n", - g.cylinders); - } else if (!silent) - if (!heads || !sectors || !cylinders) - printf("Disk %s: cannot get geometry\n", dev); - if (sectors > 63) - warn("Warning: unlikely number of sectors (%d) - usually at most 63\n" - "This will give problems with all software that uses C/H/S addressing.\n", - sectors); - if (!silent) - printf("\nDisk %s: %lu heads, %lu sectors, %lu cylinders\n", - dev, heads, sectors, cylinders); -} - -typedef struct { unsigned char h,s,c; } chs; /* has some c bits in s */ -chs zero_chs = { 0,0,0 }; - -typedef struct { unsigned long h,s,c; } longchs; -longchs zero_longchs; - -chs -longchs_to_chs (longchs aa) { - chs a; - - if (aa.h < 256 && aa.s < 64 && aa.c < 1024) { - a.h = aa.h; - a.s = aa.s | ((aa.c >> 2) & 0xc0); - a.c = (aa.c & 0xff); - } else if (heads && sectors) { - a.h = heads - 1; - a.s = sectors | 0xc0; - a.c = 0xff; - } else - a = zero_chs; - return a; -} - -longchs -chs_to_longchs (chs a) { - longchs aa; - - aa.h = a.h; - aa.s = (a.s & 0x3f); - aa.c = (a.s & 0xc0); - aa.c = (aa.c << 2) + a.c; - return aa; -} - -longchs -ulong_to_longchs (unsigned long sno) { - longchs aa; - - if (heads && sectors && cylindersize) { - aa.s = 1 + sno % sectors; - aa.h = (sno / sectors) % heads; - aa.c = sno / cylindersize; - return aa; - } else { - return zero_longchs; - } -} - -unsigned long -longchs_to_ulong (longchs aa) { - return (aa.c*cylindersize + aa.h*sectors + aa.s - 1); -} - -chs -ulong_to_chs (unsigned long sno) { - return longchs_to_chs(ulong_to_longchs(sno)); -} - -unsigned long -chs_to_ulong (chs a) { - return longchs_to_ulong(chs_to_longchs(a)); -} - -int -is_equal_chs (chs a, chs b) { - return (a.h == b.h && a.s == b.s && a.c == b.c); -} - -int -chs_ok (chs a, char *v, char *w) { - longchs aa = chs_to_longchs(a); - int ret = 1; - - if (is_equal_chs(a, zero_chs)) - return 1; - if (heads && aa.h >= heads) { - warn("%s of partition %s has impossible value for head: " - "%d (should be in 0-%d)\n", w, v, aa.h, heads-1); - ret = 0; - } - if (sectors && (aa.s == 0 || aa.s > sectors)) { - warn("%s of partition %s has impossible value for sector: " - "%d (should be in 1-%d)\n", w, v, aa.s, sectors); - ret = 0; - } - if (cylinders && aa.c >= cylinders) { - warn("%s of partition %s has impossible value for cylinders: " - "%d (should be in 0-%d)\n", w, v, aa.c, cylinders-1); - ret = 0; - } - return ret; -} - -/* - * D. About system Ids - */ - -#define EMPTY_PARTITION 0 -#define EXTENDED_PARTITION 5 -#define 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 - * and SFS and several other sources. - */ -struct systypes { - unsigned char type; - char *name; -} sys_types[] = { - {0, "Empty"}, - {1, "DOS 12-bit FAT"}, /* Primary DOS with 12-bit FAT */ - {2, "XENIX /"}, /* XENIX / filesystem */ - {3, "XENIX /usr"}, /* XENIX /usr filesystem */ - {4, "DOS 16-bit FAT <32M"}, /* Primary DOS with 16-bit FAT */ - {5, "DOS Extended"}, /* DOS 3.3+ extended partition */ - {6, "DOS 16-bit FAT >=32M"}, - {7, "HPFS / NTFS"}, - {8, "AIX boot or SplitDrive"}, - {9, "AIX data or Coherent"}, - {0x0a, "OS/2 Boot Manager"}, - {0x0b, "Win95 FAT32"}, - {0x0c, "Win95 FAT32 (LBA)"}, - {0x0e, "Win95 FAT16 (LBA)"}, - {0x0f, "Win95 Extended (LBA)"}, - {0x10, "OPUS"}, - {0x11, "Hidden DOS FAT12"}, - {0x12, "Compaq diagnostics"}, - {0x14, "Hidden DOS FAT16"}, - {0x16, "Hidden DOS FAT16 (big)"}, - {0x17, "Hidden HPFS/NTFS"}, - {0x18, "AST Windows swapfile"}, - {0x24, "NEC DOS"}, - {0x3c, "PartitionMagic recovery"}, - {0x40, "Venix 80286"}, - {0x41, "Linux/MINIX (sharing disk with DRDOS)"}, - {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, - {0x43, "Linux native (sharing disk with DRDOS)"}, - {0x50, "DM (disk manager)"}, - {0x51, "DM6 Aux1 (or Novell)"}, - {0x52, "CP/M or Microport SysV/AT"}, - {0x53, "DM6 Aux3"}, - {0x54, "DM6"}, - {0x55, "EZ-Drive (disk manager)"}, - {0x56, "Golden Bow (disk manager)"}, - {0x5c, "Priam Edisk (disk manager)"}, - {0x61, "SpeedStor"}, - {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"}, - {0x64, "Novell Netware 286"}, - {0x65, "Novell Netware 386"}, - {0x70, "DiskSecure Multi-Boot"}, - {0x75, "PC/IX"}, - {0x77, "QNX4.x"}, - {0x78, "QNX4.x 2nd part"}, - {0x79, "QNX4.x 3rd part"}, - {0x80, "MINIX until 1.4a"}, - {0x81, "MINIX / old Linux"}, - {0x82, "Linux swap"}, - {0x83, "Linux native"}, - {0x84, "OS/2 hidden C: drive"}, - {0x85, "Linux extended"}, - {0x86, "NTFS volume set"}, - {0x87, "NTFS volume set"}, - {0x93, "Amoeba"}, - {0x94, "Amoeba BBT"}, /* (bad block table) */ - {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */ - {0xa5, "BSD/386"}, /* 386BSD */ - {0xa6, "OpenBSD"}, - {0xa7, "NeXTSTEP 486"}, - {0xb7, "BSDI fs"}, - {0xb8, "BSDI swap"}, - {0xc1, "DRDOS/sec (FAT-12)"}, - {0xc4, "DRDOS/sec (FAT-16, < 32M)"}, - {0xc6, "DRDOS/sec (FAT-16, >= 32M)"}, - {0xc7, "Syrinx"}, - {0xdb, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, - {0xe1, "DOS access or SpeedStor 12-bit FAT extended partition"}, - {0xe3, "DOS R/O or SpeedStor"}, - {0xe4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, - {0xf1, "SpeedStor"}, - {0xf2, "DOS 3.3+ secondary"}, - {0xf4, "SpeedStor large partition"}, - {0xfe, "SpeedStor >1024 cyl. or LANstep"}, - {0xff, "Xenix Bad Block Table"} -}; - - -const char * -sysname(unsigned char type) { - struct systypes *s; - - for (s = sys_types; s - sys_types < SIZE(sys_types); s++) - if (s->type == type) - return s->name; - return "Unknown"; -} - -void -list_types(void) { - struct systypes *s; - - printf("Id Name\n\n"); - for (s = sys_types; s - sys_types < SIZE(sys_types); s++) - printf("%2x %s\n", s->type, s->name); -} - -int -is_extended(unsigned char type) { - return (type == EXTENDED_PARTITION - || type == LINUX_EXTENDED - || type == WIN98_EXTENDED); -} - -int -is_bsd(unsigned char type) { - return (type == BSD_PARTITION); -} - -/* - * E. About partitions - */ - -/* MS/DOS partition */ - -struct partition { - unsigned char bootable; /* 0 or 0x80 */ - chs begin_chs; - unsigned char sys_type; - chs end_chs; - unsigned int start_sect; /* starting sector counting from 0 */ - unsigned int nr_sects; /* nr of sectors in partition */ -}; - -/* Unfortunately, partitions are not aligned, and non-Intel machines - are unhappy with non-aligned integers. So, we need a copy by hand. */ -int -copy_to_int(unsigned char *cp) { - unsigned int m; - - m = *cp++; - m += (*cp++ << 8); - m += (*cp++ << 16); - m += (*cp++ << 24); - return m; -} - -void -copy_from_int(int m, char *cp) { - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); -} - -void -copy_to_part(char *cp, struct partition *p) { - p->bootable = *cp++; - p->begin_chs.h = *cp++; - p->begin_chs.s = *cp++; - p->begin_chs.c = *cp++; - p->sys_type = *cp++; - p->end_chs.h = *cp++; - p->end_chs.s = *cp++; - p->end_chs.c = *cp++; - p->start_sect = copy_to_int(cp); - p->nr_sects = copy_to_int(cp+4); -} - -void -copy_from_part(struct partition *p, char *cp) { - *cp++ = p->bootable; - *cp++ = p->begin_chs.h; - *cp++ = p->begin_chs.s; - *cp++ = p->begin_chs.c; - *cp++ = p->sys_type; - *cp++ = p->end_chs.h; - *cp++ = p->end_chs.s; - *cp++ = p->end_chs.c; - copy_from_int(p->start_sect, cp); - copy_from_int(p->nr_sects, cp+4); -} - -/* Roughly speaking, Linux doesn't use any of the above fields except - for partition type, start sector and number of sectors. (However, - see also linux/drivers/scsi/fdomain.c.) - The only way partition type is used (in the kernel) is the comparison - for equality with EXTENDED_PARTITION (and these Disk Manager types). */ - -struct part_desc { - unsigned long start; - unsigned long size; - unsigned long sector, offset; /* disk location of this info */ - struct partition p; - struct part_desc *ep; /* extended partition containing this one */ - int ptype; -#define DOS_TYPE 0 -#define BSD_TYPE 1 -} zero_part_desc; - -struct part_desc * -outer_extended_partition(struct part_desc *p) { - while (p->ep) - p = p->ep; - return p; -} - -int -is_parent(struct part_desc *pp, struct part_desc *p) { - while (p) { - if (pp == p) - return 1; - p = p->ep; - } - return 0; -} - -struct disk_desc { - struct part_desc partitions[128]; - int partno; -} oldp, newp; - -/* determine where on the disk this information goes */ -void -add_sector_and_offset(struct disk_desc *z) { - int pno; - struct part_desc *p; - - for (pno = 0; pno < z->partno; pno++) { - p = &(z->partitions[pno]); - p->offset = 0x1be + (pno%4)*sizeof(struct partition); - p->sector = (p->ep ? p->ep->start : 0); - } -} - -/* tell the kernel to reread the partition tables */ -int reread_ioctl(int fd) { - if(ioctl(fd, BLKRRPART)) { - perror("BLKRRPART"); - return -1; - } - return 0; -} - -/* reread after writing */ -void -reread_disk_partition(char *dev, int fd) { - printf("Re-reading the partition table ...\n"); - fflush(stdout); - sync(); - sleep(3); /* superfluous since 1.3.20 */ - - if(reread_ioctl(fd)) - printf("The command to re-read the partition table failed\n" - "Reboot your system now, before using mkfs\n"); - - if (close(fd)) { - perror(dev); - printf("Error closing %s\n", dev); - } - printf("\n"); -} - -/* find Linux name of this partition, assuming that it will have a name */ -int -index_to_linux(int pno, struct disk_desc *z) { - int i, ct = 1; - struct part_desc *p = &(z->partitions[0]); - for (i=0; isize > 0 && !is_extended(p->p.sys_type))) - ct++; - return ct; -} - -int -linux_to_index(int lpno, struct disk_desc *z) { - int i, ct = 0; - struct part_desc *p = &(z->partitions[0]); - for (i=0; ipartno && ct < lpno; i++,p++) - if((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) - && ++ct == lpno) - return i; - return -1; -} - -int -asc_to_index(char *pnam, struct disk_desc *z) { - int pnum, pno; - - if (*pnam == '#') { - pno = atoi(pnam+1); - } else { - pnum = atoi(pnam); - pno = linux_to_index(pnum, z); - } - if (!(pno >= 0 && pno < z->partno)) - fatal("%s: no such partition\n", pnam); - return pno; -} - -/* - * List partitions - in terms of sectors, blocks or cylinders - */ -#define F_SECTOR 1 -#define F_BLOCK 2 -#define F_CYLINDER 3 -#define F_MEGABYTE 4 - -int default_format = F_MEGABYTE; -int specified_format = 0; -int show_extended = 0; -int one_only = 0; -int one_only_pno; -int increment = 0; - -void -set_format(char c) { - switch(c) { - default: - printf("unrecognized format - using sectors\n"); - case 'S': specified_format = F_SECTOR; break; - case 'B': specified_format = F_BLOCK; break; - case 'C': specified_format = F_CYLINDER; break; - case 'M': specified_format = F_MEGABYTE; break; - } -} - -unsigned long -unitsize(int format) { - default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); - if (!format && !(format = specified_format)) - format = default_format; - - switch(format) { - default: - case F_CYLINDER: - if(cylindersize) return cylindersize; - case F_SECTOR: - return 1; - case F_BLOCK: - return 2; - case F_MEGABYTE: - return 2048; - } -} - -unsigned long -get_disksize(int format) { - unsigned long cs = cylinders; - if (cs && leave_last) - cs--; - return (cs * cylindersize) / unitsize(format); -} - -void -out_partition_header(char *dev, int format) { - if (dump) { - printf("# partition table of %s\n", dev); - printf("unit: sectors\n\n"); - return; - } - - default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); - if (!format && !(format = specified_format)) - format = default_format; - - switch(format) { - default: - printf("unimplemented format - using %s\n", - cylindersize ? "cylinders" : "sectors"); - case F_CYLINDER: - if (cylindersize) { - printf("Units = cylinders of %lu bytes, blocks of 1024 bytes" - ", counting from %d\n\n", - cylindersize<<9, increment); - printf(" Device Boot Start End #cyls #blocks Id System\n"); - break; - } - /* fall through */ - case F_SECTOR: - printf("Units = sectors of 512 bytes, counting from %d\n\n", - increment); - printf(" Device Boot Start End #sectors Id System\n"); - break; - case F_BLOCK: - printf("Units = blocks of 1024 bytes, counting from %d\n\n", - increment); - printf(" Device Boot Start End #blocks Id System\n"); - break; - case F_MEGABYTE: - printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes" - ", counting from %d\n\n", increment); - printf(" Device Boot Start End MB #blocks Id System\n"); - break; - } -} - -static void -out_rounddown(int width, unsigned long n, unsigned long unit, int inc) { - printf("%*lu", width, inc + n/unit); - if (unit != 1) - putchar((n % unit) ? '+' : ' '); - putchar(' '); -} - -static void -out_roundup(int width, unsigned long n, unsigned long unit, int inc) { - if (n == (unsigned long)(-1)) - printf("%*s", width, "-"); - else - printf("%*lu", width, inc + n/unit); - if (unit != 1) - putchar(((n+1) % unit) ? '-' : ' '); - putchar(' '); -} - -static void -out_roundup_size(int width, unsigned long n, unsigned long unit) { - printf("%*lu", width, (n+unit-1)/unit); - if (unit != 1) - putchar((n % unit) ? '-' : ' '); - putchar(' '); -} - -void -out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { - unsigned long start, end, size; - int pno, lpno; - - if (!format && !(format = specified_format)) - format = default_format; - - pno = p - &(z->partitions[0]); /* our index */ - lpno = index_to_linux(pno, z); /* name of next one that has a name */ - if(pno == linux_to_index(lpno, z)) /* was that us? */ - printf("%8s%-2u", dev, lpno); /* yes */ - else if(show_extended) - printf(" - "); - else - return; - putchar(dump ? ':' : ' '); - - start = p->start; - end = p->start + p->size - 1; - size = p->size; - - if (dump) { - printf(" start=%9lu", start); - printf(", size=%8lu", size); - if (p->ptype == DOS_TYPE) { - printf(", Id=%2x", p->p.sys_type); - if (p->p.bootable == 0x80) - printf(", bootable"); - } - printf("\n"); - return; - } - - if(p->ptype != DOS_TYPE || p->p.bootable == 0) - printf(" "); - else if(p->p.bootable == 0x80) - printf(" * "); - else - printf(" ? "); /* garbage */ - - switch(format) { - case F_CYLINDER: - if (cylindersize) { - out_rounddown(6, start, cylindersize, increment); - out_roundup(6, end, cylindersize, increment); - out_roundup_size(6, size, cylindersize); - out_rounddown(8, size, 2, 0); - break; - } - /* fall through */ - default: - case F_SECTOR: - out_rounddown(9, start, 1, increment); - out_roundup(9, end, 1, increment); - out_rounddown(9, size, 1, 0); - break; - case F_BLOCK: -#if 0 - printf("%8lu,%3lu ", - p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset); -#endif - out_rounddown(8, start, 2, increment); - out_roundup(8, end, 2, increment); - out_rounddown(8, size, 2, 0); - break; - case F_MEGABYTE: - out_rounddown(5, start, 2048, increment); - out_roundup(5, end, 2048, increment); - out_roundup_size(5, size, 2048); - out_rounddown(8, size, 2, 0); - break; - } - 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 && p->ptype == DOS_TYPE) { - chs a, b; - longchs aa, bb; - a = (size ? ulong_to_chs(start) : zero_chs); - b = p->p.begin_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if(a.s && !is_equal_chs(a, b)) - printf("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", - aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - a = (size ? ulong_to_chs(end) : zero_chs); - b = p->p.end_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if(a.s && !is_equal_chs(a, b)) - printf("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", - aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - if(cylinders && cylinders < 1024 && bb.c > cylinders) - printf("partition ends on cylinder %ld, beyond the end of the disk\n", - bb.c); - } -} - -void -out_partitions(char *dev, struct disk_desc *z) { - int pno, format = 0; - - if (z->partno == 0) - printf("No partitions found\n"); - else { - out_partition_header(dev, format); - for(pno=0; pno < z->partno; pno++) { - out_partition(dev, format, &(z->partitions[pno]), z); - if(show_extended && pno%4==3) - printf("\n"); - } - } -} - -static int -disj(struct part_desc *p, struct part_desc *q) { - return - ((p->start + p->size <= q->start) - || (is_extended(p->p.sys_type) - && q->start + q->size <= p->start + p->size)); -} - -char * -pnumber(struct part_desc *p, struct disk_desc *z) { - static char buf[20]; - int this, next; - struct part_desc *p0 = &(z->partitions[0]); - - this = index_to_linux(p-p0, z); - next = index_to_linux(p-p0+1, z); - - if (next > this) - sprintf(buf, "%d", this); - else - sprintf(buf, "[%d]", this); - return buf; -} - -int -partitions_ok(struct disk_desc *z) { - struct part_desc *partitions = &(z->partitions[0]), *p, *q; - int partno = z->partno; - -#define PNO(p) pnumber(p, z) - - /* Have at least 4 partitions been defined? */ - if (partno < 4) { - if (!partno) - fatal("no partition table present.\n"); - else - fatal("strange, only %d partitions defined.\n", partno); - return 0; - } - - /* Are the partitions of size 0 marked empty? - And do they have start = 0? And bootable = 0? */ - for (p = partitions; p - partitions < partno; p++) - if (p->size == 0) { - if(p->p.sys_type != EMPTY_PARTITION) - warn("Warning: partition %s has size 0 but is not marked Empty\n", - PNO(p)); - else if(p->p.bootable != 0) - warn("Warning: partition %s has size 0 and is bootable\n", - PNO(p)); - else if(p->p.start_sect != 0) - warn("Warning: partition %s has size 0 and nonzero start\n", - PNO(p)); - /* all this is probably harmless, no error return */ - } - - /* Are the logical partitions contained in their extended partitions? */ - for (p = partitions+4; p < partitions+partno; p++) - if (p->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) { - warn("Warning: partition %s ", PNO(p)); - warn("is not contained in partition %s\n", PNO(q)); - return 0; - } - } - - /* Are the data partitions mutually disjoint? */ - for (p = partitions; p < partitions+partno; p++) - if (p->size && !is_extended(p->p.sys_type)) - for (q = p+1; q < partitions+partno; q++) - if (q->size && !is_extended(q->p.sys_type)) - if(!((p->start > q-> start) ? disj(q,p) : disj(p,q))) { - warn("Warning: partitions %s ", PNO(p)); - warn("and %s overlap\n", PNO(q)); - return 0; - } - - /* 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++) - if (p->size) { - if(p->start == 0) { - warn("Warning: partition %s starts at sector 0\n", PNO(p)); - return 0; - } - if (p->size && p->start + p->size > ds) { - warn("Warning: partition %s extends past end of disk\n", PNO(p)); - return 0; - } - } - } - - /* At most one chain of DOS extended partitions ? */ - /* It seems that the OS/2 fdisk has the additional requirement - that the extended partition must be the fourth one */ - { int ect = 0; - for (p = partitions; p < partitions+4; p++) - if (p->p.sys_type == EXTENDED_PARTITION) - ect++; - if (ect > 1 && !Linux) { - warn("Among the primary partitions, at most one can be extended\n"); - warn(" (although this is not a problem under Linux)\n"); - return 0; - } - } - - /* - * Do all partitions start at a cylinder boundary ? - * (this is not required for Linux) - * The first partition starts after MBR. - * Logical partitions start slightly after the containing extended partn. - */ - if (cylindersize) { - for(p = partitions; p < partitions+partno; p++) - if (p->size) { - if(p->start % cylindersize != 0 - && (!p->ep || p->start / cylindersize != p->ep->start / cylindersize) - && (p->p.start_sect >= cylindersize)) { - warn("Warning: partition %s does not start " - "at a cylinder boundary\n", PNO(p)); - if (!Linux) - return 0; - } - if((p->start + p->size) % cylindersize) { - warn("Warning: partition %s does not end " - "at a cylinder boundary\n", PNO(p)); - if (!Linux) - return 0; - } - } - } - - /* Usually, one can boot only from primary partitions. */ - /* In fact, from a unique one only. */ - /* do not warn about bootable extended partitions - - often LILO is there */ - { int pno = -1; - for(p = partitions; p < partitions+partno; p++) - if (p->p.bootable) { - if (pno == -1) - pno = p - partitions; - else if (p - partitions < 4) { - warn("Warning: more than one primary partition is marked " - "bootable (active)\n" - "This does not matter for LILO, but the DOS MBR will " - "not boot this disk.\n"); - break; - } - if (p - partitions >= 4) { - warn("Warning: usually one can boot from primary partitions " - "only\n" "LILO disregards the `bootable' flag.\n"); - break; - } - } - if (pno == -1 || pno >= 4) - warn("Warning: no primary partition is marked bootable (active)\n" - "This does not matter for LILO, but the DOS MBR will " - "not boot this disk.\n"); - } - - /* Is chs as we expect? */ - for(p = partitions; p < partitions+partno; p++) - if(p->ptype == DOS_TYPE) { - chs a, b; - longchs aa, bb; - a = p->size ? ulong_to_chs(p->start) : zero_chs; - b = p->p.begin_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (!chs_ok(b, PNO(p), "start")) - return 0; - if(a.s && !is_equal_chs(a, b)) - warn("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", - PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - a = p->size ? ulong_to_chs(p->start + p->size - 1) : zero_chs; - b = p->p.end_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (!chs_ok(b, PNO(p), "end")) - return 0; - if(a.s && !is_equal_chs(a, b)) - warn("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", - PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - if(cylinders && cylinders < 1024 && bb.c > cylinders) - warn("partition %s ends on cylinder %ld, beyond the end of the disk\n", - PNO(p), bb.c); - } - - return 1; - -#undef PNO -} - -static void -extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { - char *cp; - struct sector *s; - unsigned long start, here, next; - int i, moretodo = 1; - struct partition p; - struct part_desc *partitions = &(z->partitions[0]); - int pno = z->partno; - - here = start = ep->start; - - while (moretodo) { - moretodo = 0; - - if (!(s = get_sector(dev, fd, here))) - break; - - if (!msdos_signature(s)) - break; - - cp = s->data + 0x1be; - - if (pno+4 >= SIZE(z->partitions)) { - printf("too many partitions - ignoring those past nr (%d)\n", - pno-1); - break; - } - - next = 0; - - for (i=0; i<4; i++,cp += sizeof(struct partition)) { - partitions[pno].sector = here; - partitions[pno].offset = cp - s->data; - partitions[pno].ep = ep; - copy_to_part(cp,&p); - if (is_extended(p.sys_type)) { - if (next) - printf("tree of partitions?\n"); - partitions[pno].start = next = start + p.start_sect; - moretodo = 1; - } else { - partitions[pno].start = here + p.start_sect; - } - partitions[pno].size = p.nr_sects; - partitions[pno].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; - char *cp; - struct partition pt; - struct sector *s; - struct part_desc *partitions = &(z->partitions[0]); - int pno = z->partno; - - if (!(s = get_sector(dev, fd, start))) - return 0; - - if (!msdos_signature(s)) - return 0; - - cp = s->data + 0x1be; - copy_to_part(cp,&pt); - - /* If I am not mistaken, recent kernels will hide this from us, - so we will never actually see traces of a Disk Manager */ - if (pt.sys_type == DM6_PARTITION - || pt.sys_type == EZD_PARTITION - || pt.sys_type == DM6_AUX1PARTITION - || pt.sys_type == DM6_AUX3PARTITION) { - printf("detected Disk Manager - unable to handle that\n"); - return 0; - } - { unsigned int sig = *(unsigned short *)(s->data + 2); - if (sig <= 0x1ae - && *(unsigned short *)(s->data + sig) == 0x55aa - && (1 & *(unsigned char *)(s->data + sig + 2))) { - printf("DM6 signature found - giving up\n"); - return 0; - } - } - - for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) { - partitions[pno].sector = start; - partitions[pno].offset = cp - s->data; - copy_to_part(cp,&pt); - partitions[pno].start = start + pt.start_sect; - partitions[pno].size = pt.nr_sects; - partitions[pno].ep = 0; - partitions[pno].p = pt; - } - - z->partno = pno; - - for (i=0; i<4; i++) { - if (is_extended(partitions[i].p.sys_type)) { - if (!partitions[i].size) { - printf("strange..., an extended partition of size 0?\n"); - continue; - } - extended_partition(dev, fd, &partitions[i], z); - } - 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; -} - -static int -osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -static int -sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -static int -amiga_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -void -get_partitions(char *dev, int fd, struct disk_desc *z) { - z->partno = 0; - - if (!msdos_partition(dev, fd, 0, z) - && !osf_partition(dev, fd, 0, z) - && !sun_partition(dev, fd, 0, z) - && !amiga_partition(dev, fd, 0, z)) { - printf(" %s: unrecognized partition\n", dev); - return; - } -} - -int -write_partitions(char *dev, int fd, struct disk_desc *z) { - struct sector *s; - struct part_desc *partitions = &(z->partitions[0]), *p; - int pno = z->partno; - - if (no_write) { - printf("-n flag was given: Nothing changed\n"); - exit(0); - } - - for (p = partitions; p < partitions+pno; p++) { - s = get_sector(dev, fd, p->sector); - if (!s) return 0; - s->to_be_written = 1; - copy_from_part(&(p->p), s->data + p->offset); - *(unsigned short *)(&(s->data[0x1fe])) = 0xaa55; - } - if (save_sector_file) { - if (!save_sectors(dev, fd)) { - fatal("Failed saving the old sectors - aborting\n"); - return 0; - } - } - if (!write_sectors(dev, fd)) { - error("Failed writing the partition on %s\n", dev); - return 0; - } - return 1; -} - -/* - * F. The standard input - */ - -/* - * Input format: - * - * Fields are separated by whitespace or comma or semicolon possibly - * followed by whitespace; initial and trailing whitespace is ignored. - * Numbers can be octal, decimal or hexadecimal, decimal is default - * The parts can (and probably should) be omitted. - * Bootable is specified as [*|-], with as default not-bootable. - * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where - * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E - * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85). - * The default value of start is the first nonassigned sector/cylinder/... - * The default value of size is as much as possible (until next - * partition or end-of-disk). - * .: end of chain of extended partitions. - * - * On interactive input an empty line means: all defaults. - * Otherwise empty lines are ignored. - */ - -int eof, eob; - -struct dumpfld { - int fldno; - char *fldname; - int is_bool; -} dumpflds[] = { - { 0, "start", 0 }, - { 1, "size", 0 }, - { 2, "Id", 0 }, - { 3, "bootable", 1 }, - { 4, "bh", 0 }, - { 5, "bs", 0 }, - { 6, "bc", 0 }, - { 7, "eh", 0 }, - { 8, "es", 0 }, - { 9, "ec", 0 } -}; - -/* - * Read a line, split it into fields - * - * (some primitive handwork, but a more elaborate parser seems - * unnecessary) - */ -#define RD_EOF (-1) -#define RD_CMD (-2) - -int -read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) { - unsigned char *lp, *ip; - int c, fno; - - /* boolean true and empty string at start */ - line[0] = '*'; - line[1] = 0; - for (fno=0; fno < fieldssize; fno++) - fields[fno] = line + 1; - fno = 0; - - /* read a line from stdin */ - lp = fgets(line+2, linesize, stdin); - if (lp == NULL) { - eof = 1; - return RD_EOF; - } - if (!(lp = index(lp, '\n'))) - fatal("long or incomplete input line - quitting\n"); - *lp = 0; - - /* remove comments, if any */ - if ((lp = index(line+2, '#')) != 0) - *lp = 0; - - /* recognize a few commands - to be expanded */ - if (!strcmp(line+2, "unit: sectors")) { - specified_format = F_SECTOR; - return RD_CMD; - } - - /* dump style? - then bad input is fatal */ - if ((ip = index(line+2, ':')) != 0) { - struct dumpfld *d; - - nxtfld: - ip++; - while(isspace(*ip)) - ip++; - if (*ip == 0) - return fno; - for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) { - if(!strncmp(ip, d->fldname, strlen(d->fldname))) { - ip += strlen(d->fldname); - while(isspace(*ip)) - ip++; - if (d->is_bool) - fields[d->fldno] = line; - else if (*ip == '=') { - while(isspace(*++ip)) ; - fields[d->fldno] = ip; - while(isalnum(*ip)) /* 0x07FF */ - ip++; - } else - fatal("input error: `=' expected after %s field\n", - d->fldname); - if (fno <= d->fldno) - fno = d->fldno + 1; - if(*ip == 0) - return fno; - if(*ip != ',' && *ip != ';') - fatal("input error: unexpected character %c after %s field\n", - *ip, d->fldname); - *ip = 0; - goto nxtfld; - } - } - fatal("unrecognized input: %s\n", ip); - } - - /* split line into fields */ - lp = ip = line+2; - fields[fno++] = lp; - while((c = *ip++) != 0) { - if (!lp[-1] && (c == '\t' || c == ' ')) - ; - else if (c == '\t' || c == ' ' || c == ',' || c == ';') { - *lp++ = 0; - if (fno < fieldssize) - fields[fno++] = lp; - continue; - } else - *lp++ = c; - } - - if (lp == fields[fno-1]) - fno--; - return fno; -} - -/* read a number, use default if absent */ -int -get_ul(char *u, unsigned long *up, unsigned long def, int base) { - char *nu; - - if (*u) { - errno = 0; - *up = strtoul(u, &nu, base); - if (errno == ERANGE) { - printf("number too big\n"); - return -1; - } - if (*nu) { - printf("trailing junk after number\n"); - return -1; - } - } else - *up = def; - return 0; -} - -/* There are two common ways to structure extended partitions: - as nested boxes, and as a chain. Sometimes the partitions - must be given in order. Sometimes all logical partitions - must lie inside the outermost extended partition. -NESTED: every partition is contained in the surrounding partitions - and is disjoint from all others. -CHAINED: every data partition is contained in the surrounding partitions - and disjoint from all others, but extended partitions may lie outside - (insofar as allowed by all_logicals_inside_outermost_extended). -ONESECTOR: all data partitions are mutually disjoint; extended partitions - each use one sector only (except perhaps for the outermost one). -*/ -int partitions_in_order = 0; -int all_logicals_inside_outermost_extended = 1; -enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED; - -/* find the default value for - assuming entire units */ -unsigned long -first_free(int pno, int is_extended, struct part_desc *ep, int format, - unsigned long mid, struct disk_desc *z) { - unsigned long ff, fff; - unsigned long unit = unitsize(format); - struct part_desc *partitions = &(z->partitions[0]), *pp = 0; - - /* if containing ep undefined, look at its container */ - if (ep && ep->p.sys_type == EMPTY_PARTITION) - ep = ep->ep; - - if (ep) { - if (boxes == NESTED || (boxes == CHAINED && !is_extended)) - pp = ep; - else if (all_logicals_inside_outermost_extended) - pp = outer_extended_partition(ep); - } -#if 0 - ff = pp ? (pp->start + unit - 1) / unit : 0; -#else - /* rounding up wastes almost an entire cylinder - round down - and leave it to compute_start_sect() to fix the difference */ - ff = pp ? pp->start / unit : 0; -#endif - /* MBR and 1st sector of an extended partition are never free */ - if (unit == 1) - ff++; - - again: - for(pp = partitions; pp < partitions+pno; pp++) { - if (!is_parent(pp, ep) && pp->size > 0) { - if ((partitions_in_order || pp->start / unit <= ff - || (mid && pp->start / unit <= mid)) - && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) { - ff = fff; - goto again; - } - } - } - - return ff; -} - -/* find the default value for - assuming entire units */ -unsigned long -max_length(int pno, int is_extended, struct part_desc *ep, int format, - unsigned long start, struct disk_desc *z) { - unsigned long fu; - unsigned long unit = unitsize(format); - struct part_desc *partitions = &(z->partitions[0]), *pp = 0; - - /* if containing ep undefined, look at its container */ - if (ep && ep->p.sys_type == EMPTY_PARTITION) - ep = ep->ep; - - if (ep) { - if (boxes == NESTED || (boxes == CHAINED && !is_extended)) - pp = ep; - else if (all_logicals_inside_outermost_extended) - pp = outer_extended_partition(ep); - } - fu = pp ? (pp->start + pp->size) / unit : get_disksize(format); - - for(pp = partitions; pp < partitions+pno; pp++) - if (!is_parent(pp, ep) && pp->size > 0 - && pp->start / unit >= start && pp->start / unit < fu) - fu = pp->start / unit; - - return (fu > start) ? fu - start : 0; -} - -/* compute starting sector of a partition inside an extended one */ -/* ep is 0 or points to surrounding extended partition */ -int -compute_start_sect(struct part_desc *p, struct part_desc *ep) { - unsigned long base; - int inc = (DOS && sectors) ? sectors : 1; - int delta; - - if (ep && p->start + p->size >= ep->start + 1) - delta = p->start - ep->start - inc; - else if (p->start == 0 && p->size > 0) - delta = -inc; - else - delta = 0; - if (delta < 0) { - p->start -= delta; - p->size += delta; - if (is_extended(p->p.sys_type) && boxes == ONESECTOR) - p->size = inc; - else if ((int)(p->size) <= 0) { - warn("no room for partition descriptor\n"); - return 0; - } - } - base = (!ep ? 0 - : (is_extended(p->p.sys_type) ? - outer_extended_partition(ep) : ep)->start); - p->ep = ep; - if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) { - p->p.start_sect = 0; - p->p.begin_chs = zero_chs; - p->p.end_chs = zero_chs; - } else { - p->p.start_sect = p->start - base; - p->p.begin_chs = ulong_to_chs(p->start); - p->p.end_chs = ulong_to_chs(p->start + p->size - 1); - } - p->p.nr_sects = p->size; - return 1; -} - -/* build the extended partition surrounding a given logical partition */ -int -build_surrounding_extended(struct part_desc *p, struct part_desc *ep, - struct disk_desc *z) { - int inc = (DOS && sectors) ? sectors : 1; - int format = F_SECTOR; - struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep; - - if (boxes == NESTED) { - ep->start = first_free(ep-p0, 1, eep, format, p->start, z); - ep->size = max_length(ep-p0, 1, eep, format, ep->start, z); - if (ep->start > p->start || ep->start + ep->size < p->start + p->size) { - warn("cannot build surrounding extended partition\n"); - return 0; - } - } else { - ep->start = p->start; - if(boxes == CHAINED) - ep->size = p->size; - else - ep->size = inc; - } - - ep->p.nr_sects = ep->size; - ep->p.bootable = 0; - ep->p.sys_type = EXTENDED_PARTITION; - if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) { - ep->p.sys_type = EMPTY_PARTITION; - ep->size = 0; - return 0; - } - - return 1; -} - -int -read_line(int pno, struct part_desc *ep, char *dev, int interactive, - struct disk_desc *z) { - unsigned char line[1000]; - unsigned char *fields[11]; - int fno, pct = pno%4; - struct part_desc p, *orig; - unsigned long ff, ff1, ul, ml, ml1, def; - int format, lpno, is_extd; - - if (eof || eob) - return -1; - - lpno = index_to_linux(pno, z); - - if (interactive) { - if (pct == 0 && (show_extended || pno == 0)) - warn("\n"); - warn("%8s%d: ", dev, lpno); - } - - /* read input line - skip blank lines when reading from a file */ - do { - fno = read_stdin(fields, line, SIZE(fields), SIZE(line)); - } while(fno == RD_CMD || (fno == 0 && !interactive)); - if (fno == RD_EOF) { - return -1; - } else if (fno > 10 && *(fields[10]) != 0) { - printf("too many input fields\n"); - return 0; - } - - if (fno == 1 && !strcmp(fields[0], ".")) { - eob = 1; - return -1; - } - - /* use specified format, but round to cylinders if F_MEGABYTE specified */ - format = 0; - if (cylindersize && specified_format == F_MEGABYTE) - format = F_CYLINDER; - - orig = (one_only ? &(oldp.partitions[pno]) : 0); - - p = zero_part_desc; - p.ep = ep; - - /* first read the type - we need to know whether it is extended */ - /* stop reading when input blank (defaults) and all is full */ - is_extd = 0; - if (fno == 0) { /* empty line */ - if (orig && is_extended(orig->p.sys_type)) - is_extd = 1; - ff = first_free(pno, is_extd, ep, format, 0, z); - ml = max_length(pno, is_extd, ep, format, ff, z); - if (ml == 0 && is_extd == 0) { - is_extd = 1; - ff = first_free(pno, is_extd, ep, format, 0, z); - ml = max_length(pno, is_extd, ep, format, ff, z); - } - if (ml == 0 && pno >= 4) { - /* no free blocks left - don't read any further */ - warn("No room for more\n"); - return -1; - } - } - if (fno < 3 || !*(fields[2])) - ul = orig ? orig->p.sys_type : - (is_extd || (pno > 3 && pct == 1 && show_extended)) - ? EXTENDED_PARTITION : LINUX_NATIVE; - else if(!strcmp(fields[2], "L")) - ul = LINUX_NATIVE; - else if(!strcmp(fields[2], "S")) - ul = LINUX_SWAP; - else if(!strcmp(fields[2], "E")) - ul = EXTENDED_PARTITION; - else if(!strcmp(fields[2], "X")) - ul = LINUX_EXTENDED; - else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16)) - return 0; - if (ul > 255) { - warn("Illegal type\n"); - return 0; - } - p.p.sys_type = ul; - is_extd = is_extended(ul); - - /* find start */ - ff = first_free(pno, is_extd, ep, format, 0, z); - ff1 = ff * unitsize(format); - def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1; - if (fno < 1 || !*(fields[0])) - p.start = def; - else { - if (get_ul(fields[0], &ul, def / unitsize(0), 0)) - return 0; - p.start = ul * unitsize(0); - p.start -= (p.start % unitsize(format)); - } - - /* find length */ - ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z); - ml1 = ml * unitsize(format); - def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1; - if (fno < 2 || !*(fields[1])) - p.size = def; - else { - if (get_ul(fields[1], &ul, def / unitsize(0), 0)) - return 0; - p.size = ul * unitsize(0) + unitsize(format) - 1; - p.size -= (p.size % unitsize(format)); - } - if (p.size > ml1) { - warn("Warning: exceeds max allowable size (%lu)\n", ml1 / unitsize(0)); - if (!force) - return 0; - } - if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) { - warn("Warning: empty partition\n"); - if (!force) - return 0; - } - p.p.nr_sects = p.size; - - if (p.size == 0 && !orig) { - if(fno < 1 || !*(fields[0])) - p.start = 0; - if(fno < 3 || !*(fields[2])) - p.p.sys_type = EMPTY_PARTITION; - } - - if (p.start < ff1 && p.size > 0) { - warn("Warning: bad partition start (earliest %lu)\n", - (ff1 + unitsize(0) - 1) / unitsize(0)); - if (!force) - return 0; - } - - if (fno < 4 || !*(fields[3])) - ul = (orig ? orig->p.bootable : 0); - else if (!strcmp(fields[3], "-")) - ul = 0; - else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+")) - ul = 0x80; - else { - warn("unrecognized bootable flag - choose - or *\n"); - return 0; - } - p.p.bootable = ul; - - if (ep && ep->p.sys_type == EMPTY_PARTITION) { - if(!build_surrounding_extended(&p, ep, z)) - return 0; - } else - if(!compute_start_sect(&p, ep)) - return 0; - - { longchs aa = chs_to_longchs(p.p.begin_chs), bb; - - if (fno < 5) { - bb = aa; - } else if (fno < 7) { - warn("partial c,h,s specification?\n"); - return 0; - } else if(get_ul(fields[4], &bb.c, aa.c, 0) || - get_ul(fields[5], &bb.h, aa.h, 0) || - get_ul(fields[6], &bb.s, aa.s, 0)) - return 0; - p.p.begin_chs = longchs_to_chs(bb); - } - { longchs aa = chs_to_longchs(p.p.end_chs), bb; - - if (fno < 8) { - bb = aa; - } else if (fno < 10) { - warn("partial c,h,s specification?\n"); - return 0; - } else if(get_ul(fields[7], &bb.c, aa.c, 0) || - get_ul(fields[8], &bb.h, aa.h, 0) || - get_ul(fields[9], &bb.s, aa.s, 0)) - return 0; - p.p.end_chs = longchs_to_chs(bb); - } - - if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION - && (is_extended(p.p.sys_type) != (pct == 1))) { - warn("Extended partition not where expected\n"); - if (!force) - return 0; - } - - z->partitions[pno] = p; - if (pno >= z->partno) - z->partno += 4; /* reqd for out_partition() */ - - if (interactive) - out_partition(dev, 0, &(z->partitions[pno]), z); - - return 1; -} - -/* ep either points to the extended partition to contain this one, - or to the empty partition that may become extended or is 0 */ -int -read_partition(char *dev, int interactive, int pno, struct part_desc *ep, - struct disk_desc *z) { - struct part_desc *p = &(z->partitions[pno]); - int i; - - if (one_only) { - *p = oldp.partitions[pno]; - if (one_only_pno != pno) - goto ret; - } else if (!show_extended && pno > 4 && pno%4) - goto ret; - - while (!(i = read_line(pno, ep, dev, interactive, z))) - if (!interactive) - fatal("bad input\n"); - if (i < 0) { - p->ep = ep; - return 0; - } - - ret: - p->ep = ep; - if (pno >= z->partno) - z->partno += 4; - return 1; -} - -void -read_partition_chain(char *dev, int interactive, struct part_desc *ep, - struct disk_desc *z) { - int i, base; - - eob = 0; - while (1) { - base = z->partno; - if (base+4 > SIZE(z->partitions)) { - printf("too many partitions\n"); - break; - } - for (i=0; i<4; i++) - if (!read_partition(dev, interactive, base+i, ep, z)) - return; - for (i=0; i<4; i++) { - ep = &(z->partitions[base+i]); - if (is_extended(ep->p.sys_type) && ep->size) - break; - } - if (i == 4) { - /* nothing found - maybe an empty partition is going - to be extended */ - if (one_only || show_extended) - break; - ep = &(z->partitions[base+1]); - if (ep->size || ep->p.sys_type != EMPTY_PARTITION) - break; - } - } -} - -void -read_input(char *dev, int interactive, struct disk_desc *z) { - int i; - struct part_desc *partitions = &(z->partitions[0]), *ep; - - for (i=0; i < SIZE(z->partitions); i++) - partitions[i] = zero_part_desc; - z->partno = 0; - - if (interactive) - warn(" -Input in the following format; absent fields get a default value. - -Usually you only need to specify and (and perhaps ). -"); - eof = 0; - - for (i=0; i<4; i++) - read_partition(dev, interactive, i, 0, z); - for (i=0; i<4; i++) { - ep = partitions+i; - if (is_extended(ep->p.sys_type) && ep->size) - read_partition_chain(dev, interactive, ep, z); - } - add_sector_and_offset(z); -} - -/* - * G. The command line - */ - -static void version(void) { - printf(PROGNAME " version " VERSION " (aeb@cwi.nl, " DATE ")\n"); -} - -static void -usage(void) { - version(); - printf("Usage: - " PROGNAME " [options] device ... -device: something like /dev/hda or /dev/sda -useful options: - -s [or --show-size]: list size of a partition - -c [or --id]: print or change partition Id - -l [or --list]: list partitions of each device - -d [or --dump]: idem, but in a format suitable for later input - -i [or --increment]: number cylinders etc. from 1 instead of from 0 - -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB - -T [or --list-types]:list the known partition types - -D [or --DOS]: for DOS-compatibility: waste a little space - -R [or --re-read]: make kernel reread partition table - -N# : change only the partition with number # - -n : do not actually write to disk - -O file : save the sectors that will be overwritten to file - -I file : restore these sectors again - -v [or --version]: print version - -? [or --help]: print this message -dangerous options: - -g [or --show-geometry]: print the kernel's idea of the geometry - -x [or --show-extended]: also list extended partitions on output - or expect descriptors for them on input - -L [or --Linux]: do not complain about things irrelevant for Linux - -q [or --quiet]: suppress warning messages - You can override the detected geometry using: - -C# [or --cylinders #]:set the number of cylinders to use - -H# [or --heads #]: set the number of heads to use - -S# [or --sectors #]: set the number of sectors to use - You can disable all consistency checking with: - -f [or --force]: do what I say, even if it is stupid -"); - exit(1); -} - -static void -activate_usage(char *progn) { - printf("Usage: - %s device list active partitions on device - %s device n1 n2 ... activate partitions n1 ..., inactivate the rest - %s device activate partition n, inactivate the other ones -", progn, progn, PROGNAME " -An"); - exit(1); -} - -static void -unhide_usage(char *progn) { - exit(1); -} - -static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V"; - -#define PRINT_ID 0400 -#define CHANGE_ID 01000 - -static const struct option long_opts[] = { - { "change-id", no_argument, NULL, 'c' + CHANGE_ID }, - { "print-id", no_argument, NULL, 'c' + PRINT_ID }, - { "id", no_argument, NULL, 'c' }, - { "dump", no_argument, NULL, 'd' }, - { "force", no_argument, NULL, 'f' }, - { "show-geometry", no_argument, NULL, 'g' }, - { "increment", no_argument, NULL, 'i' }, - { "list", no_argument, NULL, 'l' }, - { "quiet", no_argument, NULL, 'q' }, - { "show-size", no_argument, NULL, 's' }, - { "unit", required_argument, NULL, 'u' }, - { "version", no_argument, NULL, 'v' }, - { "show-extended", no_argument, NULL, 'x' }, - { "help", no_argument, NULL, '?' }, - { "one-only", no_argument, NULL, '1' }, - { "cylinders", required_argument, NULL, 'C' }, - { "heads", required_argument, NULL, 'H' }, - { "sectors", required_argument, NULL, 'S' }, - { "activate", optional_argument, NULL, 'A' }, - { "DOS", no_argument, NULL, 'D' }, - { "Linux", no_argument, NULL, 'L' }, - { "re-read", no_argument, NULL, 'R' }, - { "list-types", no_argument, NULL, 'T' }, - { "unhide", optional_argument, NULL, 'U' }, - { "no-reread", no_argument, NULL, 160 }, - { "IBM", no_argument, NULL, 161 }, - { "leave-last", no_argument, NULL, 161 }, -/* undocumented flags - not all completely implemented */ - { "in-order", no_argument, NULL, 128 }, - { "not-in-order", no_argument, NULL, 129 }, - { "inside-outer", no_argument, NULL, 130 }, - { "not-inside-outer", no_argument, NULL, 131 }, - { "nested", no_argument, NULL, 132 }, - { "chained", no_argument, NULL, 133 }, - { "onesector", no_argument, NULL, 134 }, - { NULL, 0, NULL, 0 } -}; - -/* default devices to list */ -static struct devd { - char *pref, *letters; -} defdevs[] = { - { "hd", "abcdefgh" }, - { "sd", "abcde" }, - { "xd", "ab" } -}; - -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); -void do_fdisk(char *dev); -void do_reread(char *dev); -void do_change_id(char *dev, char *part, char *id); -void do_unhide(char **av, int ac, char *arg); -void do_activate(char **av, int ac, char *arg); - -int total_size; - -int -main(int argc, char **argv) { - char *progn; - int c; - char *dev; - int opt_size = 0; - int opt_out_geom = 0; - int opt_reread = 0; - int activate = 0; - int do_id = 0; - int unhide = 0; - int fdisk = 0; - char *activatearg = 0; - char *unhidearg = 0; - - if (argc < 1) - fatal("no command?\n"); - if ((progn = rindex(argv[0], '/')) == NULL) - progn = argv[0]; - else - progn++; - if (!strcmp(progn, "activate")) - activate = 1; /* equivalent to `fdisk -A' */ -#if 0 /* not important enough to deserve a name */ - else if (!strcmp(progn, "unhide")) - unhide = 1; /* equivalent to `fdisk -U' */ -#endif - else - fdisk = 1; - - while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { - switch (c) { - case 'f': - force = 1; break; /* does not imply quiet */ - case 'g': - opt_out_geom = 1; break; - case 'i': - increment = 1; break; - case 'c': - case 'c' + PRINT_ID: - case 'c' + CHANGE_ID: - do_id = c; break; - case 'd': - dump = 1; /* fall through */ - case 'l': - opt_list = 1; break; - case 'n': - no_write = 1; break; - case 'q': - quiet = 1; break; - case 's': - opt_size = 1; break; - case 'u': - set_format(*optarg); break; - case 'v': - version(); - exit(0); - case 'x': - show_extended = 1; break; - case 'A': - activatearg = optarg; - activate = 1; break; - case 'C': - specified_cylinders = atoi(optarg); break; - case 'D': - DOS = 1; break; - case 'H': - specified_heads = atoi(optarg); break; - case 'L': - Linux = 1; break; - case 'N': - one_only = atoi(optarg); break; - case 'I': - restore_sector_file = optarg; break; - case 'O': - save_sector_file = optarg; break; - case 'R': - opt_reread = 1; break; - case 'S': - specified_sectors = atoi(optarg); break; - case 'T': - list_types(); - exit(0); - case 'U': - unhidearg = optarg; - unhide = 1; break; - case 'V': - verify = 1; break; - case '?': - default: - usage(); break; - - /* undocumented flags */ - case 128: - partitions_in_order = 1; break; - case 129: - partitions_in_order = 0; break; - case 130: - all_logicals_inside_outermost_extended = 1; break; - case 131: - all_logicals_inside_outermost_extended = 0; break; - case 132: - boxes = NESTED; break; - case 133: - boxes = CHAINED; break; - case 134: - boxes = ONESECTOR; break; - - /* more flags */ - case 160: - no_reread = 1; break; - case 161: - leave_last = 1; break; - } - } - - if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) { - struct devd *dp; - char *lp; - char device[10]; - - total_size = 0; - - for(dp = defdevs; dp-defdevs < SIZE(defdevs); dp++) { - lp = dp->letters; - while(*lp) { - sprintf(device, "/dev/%s%c", dp->pref, *lp++); - if (!strcmp(dp->pref, "hd") && is_ide_cdrom(device)) - continue; - if (opt_out_geom) - do_geom(device, 1); - if (opt_size) - do_size(device, 1); - if (opt_list || verify) - do_list(device, 1); - } - } - - if (opt_size) - printf("total: %d blocks\n", total_size); - - exit(exit_status); - } - - if (optind == argc) { - if (activate) - activate_usage(fdisk ? "fdisk -A" : progn); - else if (unhide) - unhide_usage(fdisk ? "fdisk -U" : progn); - else - usage(); - } - - if (opt_list || opt_out_geom || opt_size || verify) { - while (optind < argc) { - if (opt_out_geom) - do_geom(argv[optind], 0); - if (opt_size) - do_size(argv[optind], 0); - if (opt_list || verify) - do_list(argv[optind], 0); - optind++; - } - exit(exit_status); - } - - if (activate) { - do_activate(argv+optind, argc-optind, activatearg); - exit(exit_status); - } - if (unhide) { - do_unhide(argv+optind, argc-optind, unhidearg); - exit(exit_status); - } - if (do_id) { - if ((do_id & PRINT_ID) != 0 && optind != argc-2) - fatal("usage: fdisk --print-id device partition-number\n"); - else if ((do_id & CHANGE_ID) != 0 && optind != argc-3) - fatal("usage: fdisk --change-id device partition-number Id\n"); - else if (optind != argc-3 && optind != argc-2) - fatal("usage: fdisk --id device partition-number [Id]\n"); - do_change_id(argv[optind], argv[optind+1], - (optind == argc-2) ? 0 : argv[optind+2]); - exit(exit_status); - } - - if (optind != argc-1) - fatal("can specify only one device (except with -l or -s)\n"); - dev = argv[optind]; - - if (opt_reread) - do_reread(dev); - else if (restore_sector_file) - restore_sectors(dev); - else - do_fdisk(dev); - - return 0; -} - -/* - * H. Listing the current situation - */ - -int -my_open (char *dev, int rw, int silent) { - int fd, mode; - - mode = (rw ? O_RDWR : O_RDONLY); - fd = open(dev, mode); - if (fd < 0 && !silent) { - perror(dev); - fatal("cannot open %s %s\n", dev, rw ? "read-write" : "for reading"); - } - return fd; -} - -void -do_list (char *dev, int silent) { - int fd; - struct disk_desc *z; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - z = &oldp; - - free_sectors(); - get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1); - get_partitions(dev, fd, z); - - if (opt_list) - out_partitions(dev, z); - - if (verify) { - if (partitions_ok(z)) - warn("%s: OK\n", dev); - else - exit_status = 1; - } -} - -void -do_geom (char *dev, int silent) { - int fd; - struct hd_geometry g; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - /* get_cylindersize(dev, fd, silent); */ - if (!ioctl(fd, HDIO_GETGEO, &g)) - printf("%s: %d cylinders, %d heads, %d sectors/track\n", - dev, g.cylinders, g.heads, g.sectors); - else - printf("%s: unknown geometry\n", dev); -} - -/* for compatibility with earlier fdisk: provide option -s */ -void -do_size (char *dev, int silent) { - int fd, size; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - if(ioctl(fd, BLKGETSIZE, &size)) { - if(!silent) { - perror(dev); - fatal("BLKGETSIZE ioctl failed for %s\n", dev); - } - return; - } - - size /= 2; /* convert sectors to blocks */ - if (silent) - printf("%s: %9d\n", dev, size); - else - printf("%d\n", size); - - total_size += size; -} - -/* - * Activate: usually one wants to have a single primary partition - * to be active. OS/2 fdisk makes non-bootable logical partitions - * active - I don't know what that means to OS/2 Boot Manager. - * - * Call: activate /dev/hda 2 5 7 make these partitions active - * and the remaining ones inactive - * Or: fdisk -A /dev/hda 2 5 7 - * - * If only a single partition must be active, one may also use the form - * fdisk -A2 /dev/hda - * - * With "activate /dev/hda" or "fdisk -A /dev/hda" the active partitions - * are listed but not changed. To get zero active partitions, use - * "activate /dev/hda none" or "fdisk -A /dev/hda none". - * Use something like `echo ",,,*" | fdisk -N2 /dev/hda' to only make - * /dev/hda2 active, without changing other partitions. - * - * A warning will be given if after the change not precisely one primary - * partition is active. - * - * The present syntax was chosen to be (somewhat) compatible with the - * activate from the LILO package. - */ -void -set_active (struct disk_desc *z, char *pnam) { - int pno; - - pno = asc_to_index(pnam, z); - z->partitions[pno].p.bootable = 0x80; -} - -void -do_activate (char **av, int ac, char *arg) { - char *dev = av[0]; - int fd; - int rw, i, pno, lpno; - struct disk_desc *z; - - z = &oldp; - - rw = (!no_write && (arg || ac > 1)); - fd = my_open(dev, rw, 0); - - free_sectors(); - get_cylindersize(dev, fd, 1); - get_partitions(dev, fd, z); - - if (!arg && ac == 1) { - /* list active partitions */ - for (pno=0; pno < z->partno; pno++) { - if (z->partitions[pno].p.bootable) { - lpno = index_to_linux(pno, z); - if (pno == linux_to_index(lpno, z)) - printf("%s%d\n", dev, lpno); - else - printf("%s#%d\n", dev, pno); - if (z->partitions[pno].p.bootable != 0x80) - warn("bad active byte: 0x%x instead of 0x80\n", - z->partitions[pno].p.bootable); - } - } - } else { - /* clear `active byte' everywhere */ - for (pno=0; pno < z->partno; pno++) - z->partitions[pno].p.bootable = 0; - - /* then set where desired */ - if (ac == 1) - set_active(z, arg); - else for(i=1; ipartno && pno < 4; pno++) - if (z->partitions[pno].p.bootable) - i++; - if (i != 1) - warn("You have %d active primary partitions. This does not matter for LILO,\n" - "but the DOS MBR will only boot a disk with 1 active partition.\n", i); -} - -void -set_unhidden (struct disk_desc *z, char *pnam) { - int pno; - unsigned char id; - - pno = asc_to_index(pnam, z); - id = z->partitions[pno].p.sys_type; - if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17) - id -= 0x10; - else - fatal("partition %s has id %x and is not hidden\n", pnam, id); - z->partitions[pno].p.sys_type = id; -} - -/* - * maybe remove and make part of --change-id - */ -void -do_unhide (char **av, int ac, char *arg) { - char *dev = av[0]; - int fd, rw, i; - struct disk_desc *z; - - z = &oldp; - - rw = !no_write; - fd = my_open(dev, rw, 0); - - free_sectors(); - get_cylindersize(dev, fd, 1); - get_partitions(dev, fd, z); - - /* unhide where desired */ - if (ac == 1) - set_unhidden(z, arg); - else for(i=1; ipartitions[pno].p.sys_type); - return; - } - i = strtoul(id, NULL, 16); - if (i > 255) - fatal("Bad Id %x\n", i); - z->partitions[pno].p.sys_type = i; - - if(write_partitions(dev, fd, z)) - warn("Done\n\n"); - else - exit_status = 1; -} - -void -do_reread(char *dev) { - int fd; - - fd = my_open(dev, 0, 0); - if(reread_ioctl(fd)) - printf("This disk is currently in use.\n"); -} - -/* - * I. Writing the new situation - */ - -void -do_fdisk(char *dev){ - int fd; - int c, answer; - struct stat statbuf; - int interactive = isatty(0); - struct disk_desc *z; - - if (stat(dev, &statbuf) < 0) { - perror(dev); - fatal("Fatal error: cannot find %s\n", dev); - } - if (!S_ISBLK(statbuf.st_mode)) { - warn("Warning: %s is not a block device\n", dev); - } - fd = my_open(dev, !no_write, 0); - - if(!no_write && !no_reread) { - warn("Checking that no-one is using this disk right now ...\n"); - if(reread_ioctl(fd)) { - printf(" -This disk is currently in use - repartitioning is probably a bad idea. -Umount all file systems, and swapoff all swap partitions on this disk. -Use the --no-reread flag to suppress this check.\n"); - if (!force) { - printf("Use the --force flag to overrule all checks.\n"); - exit(1); - } - } else - warn("OK"); - } - - z = &oldp; - - free_sectors(); - get_cylindersize(dev, fd, 0); - get_partitions(dev, fd, z); - - printf("Old situation:\n"); - out_partitions(dev, z); - - if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0) - fatal("Partition %d does not exist, cannot change it\n", one_only); - - z = &newp; - - while(1) { - - read_input(dev, interactive, z); - - printf("New situation:\n"); - out_partitions(dev, z); - - if (!partitions_ok(z) && !force) { - if(!interactive) - fatal("I don't like these partitions - nothing changed.\n" - "(If you really want this, use the --force option.)\n"); - else - printf("I don't like this - probably you should answer No\n"); - } - ask: - if (interactive) { - if (no_write) - printf("Are you satisfied with this? [ynq] "); - else - printf("Do you want to write this to disk? [ynq] "); - answer = c = getchar(); - while (c != '\n' && c != EOF) - c = getchar(); - if (c == EOF) - printf("\nfdisk: premature end of input\n"); - if (c == EOF || answer == 'q' || answer == 'Q') { - fatal("Quitting - nothing changed\n"); - } else if (answer == 'n' || answer == 'N') { - continue; - } else if (answer == 'y' || answer == 'Y') { - break; - } else { - printf("Please answer one of y,n,q\n"); - goto ask; - } - } else - break; - } - - if(write_partitions(dev, fd, z)) - printf("Successfully wrote the new partition table\n\n"); - else - exit_status = 1; - - reread_disk_partition(dev, fd); - - warn("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n" - "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n" - "(See fdisk(8).)\n"); - - sync(); /* superstition */ - sleep(3); - exit(exit_status); -} diff --git a/disk-utils/sfdisk.examples b/disk-utils/sfdisk.examples deleted file mode 100644 index 13e671d48..000000000 --- a/disk-utils/sfdisk.examples +++ /dev/null @@ -1,264 +0,0 @@ -Examples of the use of sfdisk 3.0 (to partition a disk) -Input lines have fields ,,... - see sfdisk.8. -Usually no is given, and input lines start with a comma. - -Before doing anything with a disk, make sure it is not in use; -unmount all its file systems, and say swapoff to its swap partitions. -(The final BLKRRPART ioctl will fail if anything else still uses -the disk, and you will have to reboot. It is easier to first make -sure that nothing uses the disk, e.g., by testing: - % umount /dev/sdb1 - % sfdisk -R /dev/sdb - BLKRRPART: Device or resource busy - * Device busy for revalidation (usage=2) - % swapoff /dev/sdb3 - % sfdisk -R /dev/sdb - * sdb: sdb1 < sdb5 sdb6 > sdb3 - % -Note that the starred messages are kernel messages, that may be -logged somewhere, or written to some other console. -In sfdisk 3.01 sfdisk automatically does this check, unless told not to.) - -1. One big partition: - sfdisk /dev/hda << EOF - ; - EOF - -(If there was garbage on the disk before, you may get error messages -like: `ERROR: sector 0 does not have an msdos signature' -and `/dev/hda: unrecognized partition'. This does not matter -if you write an entirely fresh partition table anyway.) - -The output will be: ------------------------------------------------------------------------ -Old situation: -... -New situation: -Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 - - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 1023 1024- 208895+ 83 Linux native -Successfully wrote the new partition table - hda: hda1 ------------------------------------------------------------------------ -Writing and rereading the partition table takes a few seconds - -don't be alarmed if nothing happens for six seconds or so. - - -2. Three primary partitions: two of size 50MB and the rest: - sfdisk /dev/hda -uM << EOF - ,50 - ,50 - ; - EOF ------------------------------------------------------------------------ -New situation: -Units = megabytes of 1048576 bytes, blocks of 1024 bytes, counting from 0 - - Device Boot Start End MB #blocks Id System -/dev/hda1 0+ 50- 51- 51203+ 83 Linux native -/dev/hda2 50+ 100- 51- 51204 83 Linux native -/dev/hda3 100+ 203 104- 106488 83 Linux native -Successfully wrote the new partition table - hda: hda1 hda2 hda3 ------------------------------------------------------------------------ -/dev/hda1 is one block (in fact only half a block) shorter than -/dev/hda2 because its start had to be shifted away from zero in -order to leave room for the Master Boot Record (MBR). - - -3. A 1MB OS2 Boot Manager partition, a 50MB DOS partition, - and three extended partitions (DOS D:, Linux swap, Linux): - sfdisk /dev/hda -uM << EOF - ,1,a - ,50,6 - ,,E - ; - ,20,4 - ,16,S - ; - EOF ------------------------------------------------------------------------ - Device Boot Start End MB #blocks Id System -/dev/hda1 0+ 1- 2- 1223+ a OS/2 Boot Manager -/dev/hda2 1+ 51- 51- 51204 6 DOS 16-bit FAT >=32M -/dev/hda3 51+ 203 153- 156468 5 Extended -/dev/hda4 0 - 0 0 0 Empty -/dev/hda5 51+ 71- 21- 20603+ 4 DOS 16-bit FAT <32M -/dev/hda6 71+ 87- 17- 16523+ 82 Linux swap -/dev/hda7 87+ 203 117- 119339+ 83 Linux native -Successfully wrote the new partition table - hda: hda1 hda2 hda3 < hda5 hda6 hda7 > ------------------------------------------------------------------------ -All these rounded numbers look better in cylinder units: - % sfdisk -l /dev/hda ------------------------------------------------------------------------ - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager -/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M -/dev/hda3 257 1023 767 156468 5 Extended -/dev/hda4 0 - 0 0 0 Empty -/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M -/dev/hda6 358+ 438 81- 16523+ 82 Linux swap -/dev/hda7 439+ 1023 585- 119339+ 83 Linux native ------------------------------------------------------------------------ -But still - why does /dev/hda5 not start on a cylinder boundary? -Because it is contained in an extended partition that does. -Of the chain of extended partitions, usually only the first is -shown. (The others have no name under Linux anyway.) But -these additional extended partitions can be made visible: - % sfdisk -l -x /dev/hda ------------------------------------------------------------------------ - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager -/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M -/dev/hda3 257 1023 767 156468 5 Extended -/dev/hda4 0 - 0 0 0 Empty - -/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M - - 358 1023 666 135864 5 Extended - - 257 256 0 0 0 Empty - - 257 256 0 0 0 Empty - -/dev/hda6 358+ 438 81- 16523+ 82 Linux swap - - 439 1023 585 119340 5 Extended - - 358 357 0 0 0 Empty - - 358 357 0 0 0 Empty - -/dev/hda7 439+ 1023 585- 119339+ 83 Linux native - - 439 438 0 0 0 Empty - - 439 438 0 0 0 Empty - - 439 438 0 0 0 Empty ------------------------------------------------------------------------ - -Why the empty 4th input line? The description of the extended partitions -starts after that of the four primary partitions. -You force an empty partition with a ",0" input line, but here all -space was divided already, so the fourth partition became empty -automatically. - -How did I know about 4,6,a,E,S? Well, E,S,L stand for Extended, -Swap and Linux. The other values are hexadecimal and come from -the table: - % sfdisk -T - Id Name - - 0 Empty - 1 DOS 12-bit FAT - 2 XENIX root - 3 XENIX usr - 4 DOS 16-bit FAT <32M - 5 Extended - 6 DOS 16-bit FAT >=32M - 7 OS/2 HPFS or QNX or Advanced UNIX - 8 AIX data - 9 AIX boot or Coherent - a OS/2 Boot Manager - ... - - -4. Preserving the sectors changed by sfdisk. - % sfdisk -O save-hdd-partition-sectors /dev/hda - ... - will write the sectors overwritten by sfdisk to file. - If you notice that you trashed some partition, you may - be able to restore things by - % sfdisk -I save-hdd-partition-sectors /dev/hda - % - -5. Preserving some old partitions. - % sfdisk -N2 /dev/hda - ... - will only change the partition /dev/hda2, and leave the rest - unchanged. The most obvious application is to change an Id: - % sfdisk -N7 /dev/hda - ,,63 - % ------------------------------------------------------------------------ -Old situation: - - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager -... -/dev/hda6 358+ 438 81- 16523+ 82 Linux swap -/dev/hda7 439+ 1023 585- 119339+ 83 Linux native - -New situation: - - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager -... -/dev/hda6 358+ 438 81- 16523+ 82 Linux swap -/dev/hda7 439+ 1023 585- 119339+ 63 GNU HURD ------------------------------------------------------------------------ - Note that changing a logical partition into an empty partition - will decrease the number of all subsequent logical partitions. - -6. Deleting a partition. -At first I thought of having an option -X# for deleting partitions, -but there are several ways in which a partition can be deleted, and -it is probably better to handle this just as a general change. - % sfdisk -d /dev/hda > ohda -will write the current tables on the file `ohda'. ------------------------------------------------------------------------ -% cat ohda -# partition table of /dev/hda -unit: sectors - -/dev/hda1 : start= 1, size= 40799, Id= 5 -/dev/hda2 : start= 40800, size= 40800, Id=83 -/dev/hda3 : start= 81600, size= 336192, Id=83 -/dev/hda4 : start= 0, size= 0, Id= 0 -/dev/hda5 : start= 2, size= 40798, Id=83 ------------------------------------------------------------------------ -In order to delete the partition on /dev/hda3, edit this file -and feed the result to sfdisk again. ------------------------------------------------------------------------ -% emacs ohda -% cat ohda -# partition table of /dev/hda -unit: sectors - -/dev/hda1 : start= 1, size= 40799, Id= 5 -/dev/hda2 : start= 40800, size= 40800, Id=83 -/dev/hda3 : start= 0, size= 0, Id= 0 -/dev/hda4 : start= 0, size= 0, Id= 0 -/dev/hda5 : start= 2, size= 40798, Id=83 -% sfdisk /dev/hda < ohda -Old situation: -Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 - - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 99 100- 20399+ 5 Extended -/dev/hda2 100 199 100 20400 83 Linux native -/dev/hda3 200 1023 824 168096 83 Linux native -/dev/hda4 0 - 0 0 0 Empty -/dev/hda5 0+ 99 100- 20399 83 Linux native -New situation: -Units = sectors of 512 bytes, counting from 0 - - Device Boot Start End #sectors Id System -/dev/hda1 1 40799 40799 5 Extended -/dev/hda2 40800 81599 40800 83 Linux native -/dev/hda3 0 - 0 0 Empty -/dev/hda4 0 - 0 0 Empty -/dev/hda5 2 40799 40798 83 Linux native -Successfully wrote the new partition table -% sfdisk -l -V /dev/hda - -Disk /dev/hda: 12 heads, 34 sectors, 1024 cylinders -Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 - - Device Boot Start End #cyls #blocks Id System -/dev/hda1 0+ 99 100- 20399+ 5 Extended -/dev/hda2 100 199 100 20400 83 Linux native -/dev/hda3 0 - 0 0 0 Empty -/dev/hda4 0 - 0 0 0 Empty -/dev/hda5 0+ 99 100- 20399 83 Linux native -/dev/hda: OK ------------------------------------------------------------------------ -This is a good way of making changes: dump the current status -to file, edit the file, and feed it to sfdisk. -Preserving the file on some other disk could be useful: -if ever the MBR gets thrashed it can be used to restore -the old situation. diff --git a/example.files/filesystems b/example.files/filesystems new file mode 100644 index 000000000..74e1b517f --- /dev/null +++ b/example.files/filesystems @@ -0,0 +1,19 @@ + ext2 + vfat + umsdos + msdos + iso9660 + minix + ntfs + hpfs + ufs + sysv + romfs + reiserfs +nodev autofs +nodev proc +nodev smbfs +nodev nfs +nodev coda +nodev devpts +nodev devfs diff --git a/example.files/issue0 b/example.files/issue0 new file mode 100644 index 000000000..285f71afc --- /dev/null +++ b/example.files/issue0 @@ -0,0 +1 @@ +This is \n (\s \m \r) \d diff --git a/example.files/syslog.conf b/example.files/syslog.conf deleted file mode 100644 index 66e436b43..000000000 --- a/example.files/syslog.conf +++ /dev/null @@ -1,12 +0,0 @@ -kern.* /var/adm/kernlog -mark.info;daemon.notice;mail.crit /var/adm/syslog -mail.info;mail.debug /var/adm/maillog -daemon.info /var/adm/daemon -lpr.info /var/adm/lpd-errs -auth.notice /var/adm/authlog -*.err /var/adm/syslog -*.notice;auth.debug /var/adm/sysdebug -*.alert /dev/console -news.alert;news.crit;news.err /var/adm/news -news.warning;news.notice /var/adm/news -news.info;news.debug /var/adm/news diff --git a/example.files/syslog.conf.alt b/example.files/syslog.conf.alt deleted file mode 100644 index c5923c4ce..000000000 --- a/example.files/syslog.conf.alt +++ /dev/null @@ -1,22 +0,0 @@ -# Log all kernel messages to the console. -# Logging much else clutters up the screen. -kern.* /dev/console -#kern.* /dev/cua1 - -# Log anything (except mail) of level info or higher. -# Don't log private authentication messages! -*.info;mail.none;authpriv.none /var/adm/messages - -# The authpriv file has restricted access. -authpriv.* /var/adm/secure - -# Log all the mail messages in one place. -mail.* /var/adm/maillog - -# Everybody gets emergency messages, plus log them on another -# machine. -*.emerg * - -# Save mail and news errors of level err and higher in a -# special file. -uucp,news.crit /var/adm/spooler diff --git a/fdisk/Makefile b/fdisk/Makefile new file mode 100644 index 000000000..e5415acdc --- /dev/null +++ b/fdisk/Makefile @@ -0,0 +1,68 @@ +# Makefile -- Makefile for util-linux Linux utilities +# Created: Sat Dec 26 20:09:40 1992 +# Revised: Fri Oct 6 21:02:21 1995 by r.faith@ieee.org +# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu) +# + +include ../MCONFIG + +MAN8= +SBIN= + +ifneq "$(CPU)" "sparc" +# fsck and mkfs will compile, but there is no kernel support on sparc +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 + +all: $(SBIN) + +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 + rm -f activate + ln -s sfdisk activate + +fdisk: fdisk.o llseek.o fdiskbsdlabel.o fdisksgilabel.o fdisksunlabel.o \ + fdiskaixlabel.o +fdisk.o: fdisk.c fdisk.h +fdiskbsdlabel.o: fdiskbsdlabel.c fdisk.h fdiskbsdlabel.h +fdisksunlabel.o: fdisksunlabel.c fdisksunlabel.h fdisk.h +fdiskaixlabel.o: fdiskaixlabel.c fdiskaixlabel.h fdisk.h +sfdisk: sfdisk.o + +install: all + $(INSTALLDIR) $(SBINDIR) + $(INSTALLBIN) $(SBIN) $(SBINDIR) + $(INSTALLDIR) $(MAN8DIR) + $(INSTALLMAN) $(MAN8) $(MAN8DIR) + +.PHONY: clean +clean: + -rm -f *.o *~ core $(SBIN) diff --git a/fdisk/README.cfdisk b/fdisk/README.cfdisk new file mode 100644 index 000000000..5241ad136 --- /dev/null +++ b/fdisk/README.cfdisk @@ -0,0 +1,45 @@ +Announcing the new curses based fdisk program... cfdisk + +cfdisk is a curses based disk drive partitioning program that can +create partitions for a wide variety of operating systems including +Linux, MS-DOS and OS/2. cfdisk was inspired by the fdisk program, by +A. V. Le Blanc (LeBlanc@mcc.ac.uk). I hope that this program will be +useful to both new and old Linux users, and I hope it will make the +installation process easier. + + + **** WARNING **** +If you write a bad partition table to disk, it may destroy data and +partitions. + + +You can FTP cfdisk from ftp.cs.unc.edu in the /pub/martin/linux +directory. + +I would also like comments (good and bad) on the user interface, logic +and ease of use. If you have any suggestions for improvements, I +would be happy to hear them. + +My e-mail address is martin@cs.unc.edu. + +------------------------------------------------------------------- + + Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) + +cfdisk 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. + +cfdisk 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 cfdisk; if not, write to the Free Software Foundation, +Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +___ +Kevin E. Martin University of North Carolina at Chapel Hill +martin@cs.unc.edu Department of Computer Science diff --git a/fdisk/README.fdisk b/fdisk/README.fdisk new file mode 100644 index 000000000..86b182525 --- /dev/null +++ b/fdisk/README.fdisk @@ -0,0 +1,583 @@ +`fdisk': the Linux partition table editor +========================================= + +`fdisk' is the Linux partition table editor. In this section we +examine this utility and try to describe it thoroughly enough so that +anyone can use it. + +* Contents: + +* Disks and how they are described. +* Dividing up your disk. +* The `fdisk' command. +* Deleting and adding partitions. +* Active flags and system types. +* Extra commands for experts. +* Warnings for `fdisk' users. + + +Disks and how they are described +-------------------------------- + +A typical disk consists physically of one or more circular objects +called "platters", which rotate about a central axis. Devices called +"heads" move to specified places on the disk surface to read or write +information. There is usually one head on each side of every platter, +and all these heads are attached to a comb-like controller arm which +moves all of them at the same time, either closer to the centre of the +disk, or closer to the outer edge. + +Suppose the arm is in one position, putting an area of the disk +surface within reach of one or another of the heads. This total area, +everything that is accessible without moving the arm, is called a +"cylinder". (A cylinder is a barrel-shaped cross section of a disk, +consisting of a circular strip from each side of each platter.) The +part of a cylinder that one head can read or write without moving is +called a "track". + +Each track is divided into several pie-shaped slices called +"sectors", which are the smallest parts of the disk which can be read +or written at a time. The sectors on one disk are usually all the same +size. + +In fact, there are not always two heads to every platter, there are +some disks which do not have the same amount of data in every cylinder, +and there may be disks which do not have the same amount of data in +every sector. These features are usually hidden on PCs by the +controller card or the BIOS, which map the physical geometry of a disk +onto a logical geometry, which is what is actually used to access the +disk. + +The numbers which describe the "geometry" of a disk are + + 1. The number of cylinders it contains. + + 2. The number of tracks per cylinder, which is the number of heads. + + 3. The number of sectors per track. + + 4. The number of bytes per sector. + +These numbers vary from disk to disk, but a typical PC disk might +have about 1000 cylinders, half a dozen heads, and 15 or 20 sectors per +track, with each sector containing 512 bytes or characters; such a disk +contains 40 to 60 megabytes of data. A "double density" floppy disk +contains 40 cylinders, with 2 heads (2 tracks per cylinder), and with 9 +sectors per track; such a disk contains 360 kilobytes, or 360 * 1024 +characters. A "high density" 3.5 inch floppy contains 80 cylinders, +with 2 heads and 18 sectors per track, or 1.44 megabytes, or 1440 * +1024 characters. + +The exact size of a track or cylinder in bytes varies from one disk +to another. This `fdisk' for Linux deals mainly with cylinders, since +this is the best unit to use when allocating space for partitions. It +reports partition sizes in "blocks" of 1024 bytes, or 2 sectors, since +`mkswap' and the various `mkfs' programs require this number. A block +is the smallest amount of space which can be set aside for a file in +the current file systems. + +An operating system, such as Linux or DOS or OS/2, may use a disk in +any way that it wishes, but if two operating systems share the same +disk, they must agree on who owns what, or else one will interfere with +the other (that is, by damaging the other's files). A "partition" is a +section of a hard disk which is handled as a unit by all operating +systems which can access the disk. The standard way to define +partitions (for the moment) is the "partition table", a list of +information which is stored in parts of the disk that don't belong to +any of the systems using the disk. The beginning of the partition +table is stored in the disk's primary boot sector, and the rest is +stored in a chain of sectors scattered throughout the disk. + +The first sector on the disk is called the "primary boot block" or +"primary boot sector" because (1) it comes first, before other, similar +sectors; (2) it tells where the other, similar sectors are found, so +that it is logically `prior' to them; and (3) it usually contains code +which is executed when the system boots up. This sector contains a +table describing at most four partitions. These areas are called +"primary partitions". + +The partition table in the primary boot sector may also describe at +most one "extended partition". This is a large area of the disk, +usually containing all the space which is not in any primary partition. +Within this space we can set aside other areas which are called +"logical partitions", because they look almost exactly like primary +partitions. In fact, the main difference between them is that we can +boot from primary partitions, while we cannot boot from logical +partitions. This happens because the address of a primary partition is +in a fixed place, whereas the address of a secondary partition is not, +so we require a more complicated process to discover it, one which is +too difficult for most primary boot programs. + + +Dividing up your disk +--------------------- + +It is a good idea to plan ahead before you start creating partitions +on your disk. If you set aside a partition for some purpose, it is not +easy to change its size: you must backup all the data from the partition, +whether to floppies, to another partition, to another hard disk, or +somewhere else; then you must edit the table which describes this +partition, so changing its size; then you must reboot and initialise +the new partition, formatting it, for example, under DOS, or running +`mkfs' under Linux; finally you can copy all the data back. It is +possible, if you have several partitions, to copy data back and forth +between them while you change their sizes, but this is a bit risky and +time consuming. It is better to plan ahead what you will need, since +it is hard to change it afterwards. + +Many people with large disks and recent versions of DOS have their +entire file system on one large partition. They usually ask, `Isn't +there any way I can reformat my disk without copying everything off?' +There is no way to do it using standard DOS utilities, and there is no +truly safe way to do it using commercial software, because, if you make +a mistake, you will lose the entire contents of your disk. If you are +going to back up your disk anyway, you might as well copy the data back +safely. The Linux FAQ contains references to tools and procedures +which will allow you to do this, if you dare. + +DOS and Linux both allow you to access several partitions on a +single disk; on DOS these are treated as if they were separate disks or +drives, and under Linux they are treated as different "devices". + +You can have up to 64 partitions on a single IDE disk, or up to 16 +partitions on a single SCSI disk, at least as far as Linux is +concerned; in practice you will rarely want so many. The maximum size +of a Linux file system on a single partition depends on the type of +file system you use. Minix file systems are limited to 64 megabytes. +You may have all of your Linux files in a single partition, or you may +have two, three, or more Linux file systems. Similarly you may have +one or more DOS partitions. If you have several small partitions, you +run much less risk of losing all your files if your disk gets +corrupted. On the other hand, you may run out of space on a small +partition more easily. + +Under DOS, you must refer to each partition by a separate drive +letter, but all partitions are automatically accessible. Under Linux +only the root partition is automatically accessible, but once we mount +another partition, it is indistinguishable from the rest of the file +system. Disks are usually mounted by a command in one of the system +startup files, `/etc/rc', so you need not worry about having to do it +yourself whenever you boot the system. But even ordinary users may +be allowed to mount removable hard disks and floppy disks. + +Linux requires at least one partition, which is the `root' of the +file system. You may prefer to have a separate partition for `/usr', +which contains most of the executable files, or for `/home', which +contains most of your private files. You may also wish to set aside a +partition to use for swap space, depending on the amount of memory your +PC has. You will certainly need swap space if you have less than 4 Mb +of RAM and wish to compile anything substantial. You can reserve swap +space in a file, but you need a partition big enough to hold it, and +this will probably be less efficient than having a partition devoted to +swap. + +The disk space you need for Linux is discussed in README.prepare. + +Are you going to boot Linux from the hard disk, or will you boot +from a floppy? Some boot programs place severe restrictions on where +the boot partition can be. LILO is more relaxed about this, but does +require either the Master Boot Record on your first hard disk, or the +boot record on one of the first four partitions on your first hard disk. + +If you have an extended partition with logical partitions in it, you +can have only three primary partitions containing data. + + +The `fdisk' command +------------------- + +Every operating system, whether DOS, OS/2, or Linux, should provide +its own utility for editing hard disk partition tables. At least four +of these utilities have been called `fdisk', for `Fixed DISK setup +program', where `fixed' means `not removable'. I believe the first PC +program named `fdisk' came from Microsoft in about 1985; before that +time disks were too small to divide into separate sections. + +Every operating system has its own peculiarities. Normally you +should set up a partition for the use of one operating system by using +its own `fdisk' program. Do not use the Linux `fdisk' to create +partitions for DOS or for any system other than Linux; otherwise you +may have problems. + +An `fdisk' program performs two functions: it reports how the disk is +configured, and it changes that configuration by adding or deleting +partitions. Most `fdisk' programs can also change other information in +partition tables. + +This `fdisk' for Linux operates on one hard disk at a time. If you +give the command + + fdisk + +it reports on, and is able to change, `/dev/hda', the first hard +disk. (If you have no `/dev/hda', `fdisk' uses `/dev/sda' as the +default device.) To look at or change the second hard disk, `/dev/hdb', +give the command + + fdisk /dev/hdb + +To look at or change the first SCSI disk, give the command + + fdisk /dev/sda + +There are some special forms of the `fdisk' command. One of them, +suggested by Jim Winstead, simply lists all partitions on all available +disks: + + fdisk -l (where `l' is a letter, not the digit `1') + +The option `-v' is provided to list the current version of the +`fdisk' command. Finally, there is an option `-s' which is not really +intended for interactive use. It causes fdisk to print the size of a +partition in blocks of 1024 bytes as follows: + + fdisk -s /dev/hda7 + 39934 + +Because this is intended to be used by `mkfs' and `mkswap' programs, +it does not return the size of extended partitions or of partitions +whose system type code is less than 10 (hexadecimal a). If you start +`fdisk' without using one of these special options, it responds by +asking for a command: + + Command (m for help): _ + +Each `fdisk' command consists of a single letter, which must be +followed by before it is obeyed. Upper and lower case are not +distinguished. Anything you type after the first character is ignored. +Give the command `m', and you should see this menu: + Command action + a toggle a bootable flag + d delete a partition + l list known partition types + m print this menu + n add a new partition + p print the partition table + q quit without saving changes + t change a partition's system id + u change display/entry units + v verify the partition table + w write table to disk and exit + x extra functionality (experts only) + + Command (m for help): _ + +The simplest commands are Print, Verify, and Quit. On a small disk, the +Print command might produce a display like this one: + + Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders + Units = cylinders of 85 * 512 bytes + + Device Boot Begin Start End Blocks Id System + /dev/hda1 * 1 1 236 10021+ 1 DOS 12-bit FAT + /dev/hda2 837 837 977 5992+ 5 Extended + /dev/hda3 * 237 237 836 25500 83 Linux native + /dev/hda5 837 837 936 4249+ 82 Linux swap + /dev/hda6 942 942 977 1522 1 DOS 12-bit FAT + +There are 5 partitions reported; `/dev/hda4' does not appear because +it is not allocated. Partitions 1 and 3 are flagged as bootable. The +size of each partition is reported in 1 kilobyte blocks; hence the +primary Linux partition, partition 3, is 25 1/2 megabytes in size. The +`+' after three of the sizes warns that these partitions contain an odd +number of sectors: Linux normally allocates filespace in 1 kilobyte +blocks, so the extra sector in partition 5 is wasted. Id numbers are +reported in hexadecimal and explained in English. + +The display/entry units may be either cylinders or sectors. The +default is cylinders, but changing the units makes the print command +display the following table for the system reported above: + + Disk /dev/hda: 5 heads, 17 sectors, 977 cylinders + Units = sectors of 1 * 512 bytes + + Device Boot Begin Start End Blocks Id System + /dev/hda1 * 1 17 20059 10021+ 1 DOS 12-bit FAT + /dev/hda2 71060 71060 83044 5992+ 5 Extended + /dev/hda3 * 20060 20060 71059 25500 83 Linux native + /dev/hda5 71061 71061 79559 4249+ 82 Linux swap + /dev/hda6 79985 80001 83044 1522 1 DOS 12-bit FAT + +The start of data in both DOS partitions is 16 sectors after the +beginning of the partition: this is one reason why you should use DOS's +own `FDISK' to create DOS partitions. Changing the units to sectors +also affects the way in which the new partition command asks for the +beginning and end of a new partition. + +*Warning*: it is dangerous to create a new partition when the +display/entry units are sectors. + +The Verify command is useful because + + 1. It warns you if anything is wrong. *Always* do a Verify command + to check your work before writing any changes to disk. + + 2. It reports how many unallocated sectors there are on the disk. + +The Quit command is also useful. `fdisk' does not actually change +any data on your disk unless you give a Write command. If you are +unhappy about any changes you may have made, give the Quit command, and +your disk will remain as it was before you ran `fdisk'. You can also +interrupt `fdisk' with `CTRL-C'. + + +Deleting and adding partitions +------------------------------ + +Deleting a partition is simple. Give the Delete command by typing +`d'. `fdisk' asks: + + Partition number (1-6): _ + +Once you get this far, you must either delete a partition or +interrupt the program with `CTRL-C' (or whatever your current interrupt +character is). Note: + + 1. You may delete a nonexistent partition. You will get a warning + message. + + 2. You may delete an extended partition. This has the side effect of + deleting all partitions greater than or equal to 5. + + 3. You may delete a logical partition. In that case, all partitions + above it are renumbered at once. For example, if you delete + partition 5, then partition 6 becomes known as partition 5, and + partition 7 as partition 6. + +Adding a partition is just a bit more complicated. Give the New +command by typing `n'. `fdisk' allows you to + + 1. Create a primary partition, if there is a free slot in the primary + partition table. + + 2. Create an extended partition if there is a free slot in the + primary partition table, and if there is no extended partition. + + 3. Create a logical partition if an extended partition exists. + +If more than one of these actions is possible, you will be asked to +select Primary, Extended, or Logical, depending on what is currently +permissible. Before you create a primary or an extended partition, you +are asked what slot it is to have in the table (1-4). + +You may not add a primary or an extended partition if the selected +slot in the primary partition table is already occupied: in that case +you simply return to the main menu. You are not allowed to add a new +primary partition unless there are sectors available outside the +extended partition. You are not allowed to add a new logical partition +unless there are sectors available inside the extended partition. + +If space is available, you are prompted for the first cylinder: + + First sector ([237]-977): _ + +The limits are the lowest and the highest cylinders in which sectors +are available in the appropriate part of the disk. The square-bracketed +number is what you'll get if you simply press enter. Not all numbers in +this range are necessarily available: they may fall inside an existing +partition. If you select a cylinder which is already in use, you are +told off and prompted again for the first cylinder. After selecting the +first cylinder, you are prompted again: + + Last cylinder or +size or +sizeM or +sizeK (237-[836]): _ + +The limits are the cylinder you have chosen as the first cylinder, +and the highest cylinder which contains a legitimate upper boundary for +the new partition. The square-bracketed number is what you'll get if +you simply press enter. In other words, all numbers in the given range are +legitimate, unlike those in the first range of cylinders. You may also +specify the size of a partition in megabytes, kilobytes, or in the +current units (cylinders or sectors). A plus sign `+' indicates that +your answer is a size rather than a boundary, and the suffix `m' or `k' +(upper or lower case) indicates that the size is not given in units of +sectors or cyliners, but in megabytes or kilobytes respectively. Thus +possible answers to the last cylinder request above are + +700 + Make cylinder 700 the last cylinder in the partition. + ++300 + Make cylinder 237 + 300 = 537 the last cylinder in the partition. + ++15m + Make the partition at least 15 megabytes in size. + ++12500k + Make the partition at least 12,500 kilobytes in size. + +If you specify a size which is too large or an end which is out of +range, fdisk complains and repeats the prompt. + +Adding or deleting partitions has no effect unless you subsequently +give the Write command. Please remember to give the Verify command +first, just before giving the Write command: this is a safety +precaution. After giving the Write command, you will see this message: + + The partition table has been altered! + Calling ioctl() to re-read partition table. + Syncing disks. + +If there are no further messages, the kernel has successfully copied +the information from the partition table into its own internal table. +But sometimes you will see a message like this one: + + Re-read table failed with error 16: Device or resource busy. + Reboot your system to ensure the partition table is updated. + +In this case, depending on what you have changed in the partition +table, it may be dangerous to continue working without rebooting, +since you may lose or corrupt your data. + + +Here are some important things to note: + + 1. Before you reboot, you *may* run `fdisk' again, either to manage + another disk, or to make additional changes to the same disk, or + just to check that the changes have been made as you expected. + This is true even after you receive the message warning you to + reboot. + + 2. It is not a good idea to run any of the programs `mkfs', `mkswap', + `mount', or `swapon' if you have received the warning message but + have not rebooted. In this case it is dangerous to run any program, + but these in particular may cause serious damage to the data on your + disk, including the partition tables themselves. + + +Active flags and system types +----------------------------- + +The active flag is a bit in the partition table entry which marks a +partition as bootable. This is important to some primary boot sector +programs, which will not boot from an unflagged partition. Other such +programs do not allow more than one partition to be flagged. Some, +like LILO, ignore the flags completely. I prefer to flag all bootable +partitions as active so that they stand out on the menu which `fdisk' +lists. Fdisk prints a star after the name of a partition's device file +if its active flag is set. + +The Active command changes, or toggles, a partition's active flag. +Give the Active command, and select a partition by number. If it was +marked inactive, it will be flagged as active; if it was flagged as +active, it will be marked inactive. You may set the active flag on an +extended or logical partition, though the meaning of such a flag is by +no means clear. This can be used to install LILO as a secondary boot +loader to boot a Linux which lives on a second hard disk. + +The Type command changes the ID number which describes what type a +partition is. `fdisk' currently recognises 30 system IDs, in the sense +that it prints a string for each of them, but it allows you to change +any system ID to any other, with the following exceptions: you may not +change any partition to or from the type Extended, and you may not +change a partition whose type is Empty (0) to any other type. You may, +however, change the type of any data partition to 0, which is +equivalent to deleting it. + +The new system ID or type code is a hexadecimal number. There are +two ways of listing the numbers which `fdisk' recognises: use the List +command, which prints the list, or use the Type command, which, when it +prompts you for the code, says + + Hex code (type L to list codes): _ + +where the upper case `L' is used for clarity. The codes printed are: +Some of these numbers are a trifle uncertain. By default `fdisk' uses +a type of 83. It used to use 81, the type code used by the MINIX +`fdisk'. It seemed prudent to change the default since (a) many Linux +`minix' file systems are no longer compatible with MINIX, (b) the ext2 +file system, a native Linux file system, is fairly stable, as is the +Xia file system, and (c) the number 81 causes problems with DR-DOS. +Linux does not usually care what values you use for type codes, but +other systems, in particular DOS, OS/2, and DR-DOS, may. + +The value of 82 for Linux swap partitions is my own invention, and +is intended to give some recognisable distinction to the partitions +when the values are displayed in hexadecimal. + +New active flags and new system type codes are not written to the +disk until you exit from `fdisk' with the Write command, as described +above, in the section on deleting and adding partitions. + + +Extra commands for experts +-------------------------- + +The eXtra command `x' puts `fdisk' into `expert' mode, in which a +slightly different set of commands is available. The Active, Delete, +List, New, Type, Verify, and `eXpert' commands are not available in +expert mode. The commands Write and Quit are available as in ordinary +mode, the Print command is available, but produces output in a slightly +different format, and of course the Menu command prints the expert +menu. There are several new commands. + + 1. The Return command brings you back to the main menu. + + 2. The Extended command prints the list of table entries which point + to other tables. Ordinary users do not need this information. + The data is shown as it is stored. The same format is used for + the expert Print command. + + 3. The dangerous Begin command allows you to move the start of data + in a partition away from its beginning. Other systems create + partitions with this format, and it is sometimes useful to be able + to reproduce it. + + 4. The slightly dangerous Cylinders command allows you to change the + available number of cylinders. For SCSI disk owners, note that we + require not the actual number of physical cylinders, but the + number of logical cylinders used by DOS and other operating + systems. + + 5. The extremely dangerous Heads and Sectors commands allow you to + change the number of heads and sectors. It should not be + necessary to use these commands unless you have a SCSI disk, whose + geometry Linux is not always able to determine. SCSI disk owners + note that we need not the actual number of heads or of sectors per + track, but the number believed to exist by DOS and other operating + systems. *Warning*: If you set either of these numbers to a bad + value, you may lose all data on your disk. + +Always, after giving any of the commands Begin, Cylinder, Heads, or +Sectors, you should Return to the main menu and give the Verify command. + + +Warnings for `fdisk' users +-------------------------- + +In general, you should not use this `fdisk' program to create +partitions for other operating systems, only for Linux. Nor should you +use `fdisk' commands from other operating systems to create partitions +for Linux. + +DR-DOS 5.0 and 6.0 are reported to have difficulties with partition +ID codes of 80 or more. The Linux `fdisk' used to set the system type +of new partitions to hexadecimal 81. DR-DOS seems to confuse this with +hexadecimal 1, a DOS code. The values 82 for swap and 83 for file +systems should not cause problems with DR-DOS. If they do, you may use +the `fdisk' command `t' to change the system code of any Linux +partitions to some number less than hexadecimal 80; I suggest 42 and 43 +for the moment. + +Partitioning a hard disk may destroy data which is on that disk if you +are not careful. Go slowly, write down a description of the partition +tables before you changed them, and always verify before you write. + +Most operating systems and utilities expect that all partitions begin and +end at cylinder boundaries. This version of `fdisk' does so by default, +but you can use it to create partitions which begin or end anywhere. +This does not normally affect Linux, but it is very dangerous, as other +operating systems (including DOS) may try to `correct' the partition +boundaries. + +It is dangerous to create a new partition when the display/entry +units are sectors. + +The Verify command warns you if anything is wrong. *Always* give a +Verify command before writing any changes to disk. + +If you set the disk geometry (tracks per cylinder, or sectors per +track) to an incorrect value, you may lose all data on your disk. + +Do create BSD/SUN and/or IRIX/SGI disk labels only when you are sure +that you want them. Both features are intended to allow you READing +those labels and prevent unintentional formatting of these disks. diff --git a/fdisk/cfdisk.8 b/fdisk/cfdisk.8 new file mode 100644 index 000000000..c8391af2a --- /dev/null +++ b/fdisk/cfdisk.8 @@ -0,0 +1,406 @@ +.\" cfdisk.8 -- man page for cfdisk +.\" Copyright 1994 Kevin E. Martin (martin@cs.unc.edu) +.\" +.\" Permission is granted to make and distribute verbatim copies of this +.\" manual provided the copyright notice and this permission notice are +.\" preserved on all copies. +.\" +.\" Permission is granted to copy and distribute modified versions of this +.\" manual under the conditions for verbatim copying, provided that the +.\" entire resulting derived work is distributed under the terms of a +.\" permission notice identical to this one. +.\" +.\" " for hilit mode +.TH CFDISK 8 "3 June 1995" "The BOGUS Linux Release" "Linux Programmer's Manual" +.SH NAME +cfdisk \- Curses based disk partition table manipulator for Linux +.SH SYNOPSIS +.BI "cfdisk [ \-avz ] [ \-c " cylinders " ] [ \-h " heads " ]" +.BI "[ \-s " sectors-per-track " ] [ -P " opt " ] [ " device " ]" +.SH DESCRIPTION +.B cfdisk +is a curses based program for partitioning a hard disk drive. The +.I device +can be any one of the following: +.sp +.nf +.RS +/dev/hda [default] +/dev/hdb +/dev/sda +/dev/sdb +/dev/sdc +/dev/sdd +.RE +.fi + +.B cfdisk +first tries to read the geometry of the hard disk. If it fails, an +error message is displayed and +.B cfdisk +exits. This should only happen when partitioning a SCSI drive on an +adapter without a BIOS. To correct this problem, you can set the +.IR cylinders ", " heads " and " sectors-per-track +on the command line. Next, +.B cfdisk +tries to read the current partition table from the disk drive. If it +is unable to figure out the partition table, an error is displayed and +the program will exit. This might also be caused by incorrect +geometry information, and can be overridden on the command line. +Another way around this problem is with the +.B \-z +option. This will ignore the partition table on the disk. + +The main display is composed of four sections, from top to bottom: the +header, the partitions, the command line and a warning line. The +header contains the program name and version number followed by the +disk drive and its geometry. The partitions section always displays +the current partition table. The command line is the place where +commands and text are entered. The available commands are usually +displayed in brackets. The warning line is usually empty except when +there is important information to be displayed. The current partition +is highlighted with reverse video (or an arrow if the +.B \-a +option is given). All partition specific commands apply to the +current partition. + +The format of the partition table in the partitions section is, from +left to right: Name, Flags, Partition Type, Filesystem Type and Size. +The name is the partition device name. The flags can be +.IR Boot , +which designates a bootable partition or +.IR NC , +which stands for "Not Compatible with DOS or OS/2". DOS, OS/2 and +possibly other operating systems require the first sector of the first +partition on the disk and all logical partitions to begin on the +second head. This wastes the second through the last sector of the +first track of the first head (the first sector is taken by the +partition table itself). +.B cfdisk +allows you to recover these "lost" sectors with the maximize command +.RB ( m ). +.I Note: +.BR fdisk (8) +and some early versions of DOS create all partitions with the number +of sectors already maximized. For more information, see the maximize +command below. The partition type can be one of +.IR Primary " or " Logical . +For unallocated space on the drive, the partition type can also be +.IR Pri/Log , +or empty (if the space is unusable). The filesystem type section +displays the name of the filesystem used on the partition, if known. +If it is unknown, then +.I Unknown +and the hex value of the filesystem type are displayed. A special +case occurs when there are sections of the disk drive that cannot be +used (because all of the primary partitions are used). When this is +detected, the filesystem type is displayed as +.IR Unusable . +The size field displays the size of the partition in megabytes (by +default). It can also display the size in sectors and cylinders (see +the change units command below). If an asterisks +.RB ( * ) +appears after the size, this means that the partition is not aligned +on cylinder boundaries. +.SH "DOS 6.x WARNING" + +The DOS 6.x FORMAT command looks for some information in the first +sector of the data area of the partition, and treats this information +as more reliable than the information in the partition table. DOS +FORMAT expects DOS FDISK to clear the first 512 bytes of the data area +of a partition whenever a size change occurs. DOS FORMAT will look at +this extra information even if the /U flag is given -- we consider +this a bug in DOS FORMAT and DOS FDISK. + +The bottom line is that if you use cfdisk or fdisk to change the size of a +DOS partition table entry, then you must also use +.B dd +to zero the first 512 bytes of that partition before using DOS FORMAT to +format the partition. For example, if you were using cfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk +and rebooting Linux so that the partition table information is valid) you +would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero +the first 512 bytes of the partition. 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 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. + +.SH COMMANDS +.B cfdisk +commands can be entered by pressing the desired key (pressing +.I Enter +after the command is not necessary). Here is a list of the available +commands: +.TP +.B b +Toggle bootable flag of the current partition. This allows you to +select which primary partition is bootable on the drive. +.TP +.B d +Delete the current partition. This will convert the current partition +into free space and merge it with any free space immediately +surrounding the current partition. A partition already marked as free +space or marked as unusable cannot be deleted. +.TP +.B g +Change the disk geometry (cylinders, heads, or sectors-per-track). +.B WARNING: +This option should only be used by people who know what they are +doing. A command line option is also available to change the disk +geometry. While at the change disk geometry command line, you can +choose to change cylinders +.RB ( c ), +heads +.RB ( h ), +and sectors per track +.RB ( s ). +The default value will be printed at the prompt which you can accept +by simply pressing the +.I Enter +key, or you can exit without changes by pressing the +.I ESC +key. If you want to change the default value, simply enter the +desired value and press +.IR Enter . +The altered disk parameter values do not take effect until you return +the main menu (by pressing +.IR Enter " or " ESC +at the change disk geometry command line. If you change the geometry +such that the disk appears larger, the extra sectors are added at the +end of the disk as free space. If the disk appears smaller, the +partitions that are beyond the new last sector are deleted and the +last partition on the drive (or the free space at the end of the +drive) is made to end at the new last sector. +.TP +.B h +Print the help screen. +.TP +.B m +Maximize disk usage of the current partition. This command will +recover the the unused space between the partition table and the +beginning of the partition, but at the cost of making the partition +incompatible with DOS, OS/2 and possibly other operating systems. +This option will toggle between maximal disk usage and DOS, OS/2, +etc. compatible disk usage. The default when creating a partition is +to create DOS, OS/2, etc. compatible partitions. +.TP +.B n +Create new partition from free space. If the partition type is +.IR Primary " or " Logical , +a partition of that type will be created, but if the partition type is +.IR Pri/Log , +you will be prompted for the type you want to create. Be aware that +(1) there are only four slots available for primary partitions and (2) +since there can be only one extended partition, which contains all of +the logical drives, all of the logical drives must be contiguous (with +no intervening primary partition). +.B cfdisk +next prompts you for the size of the partition you want to create. +The default size, equal to the entire free space of the current +partition, is display in megabytes. You can either press the +.I Enter +key to accept the default size or enter a different size at the +prompt. +.B cfdisk +accepts size entries in megabytes +.RB ( M ) +[default], kilobytes +.RB ( K ), +cylinders +.RB ( C ) +and sectors +.RB ( S ) +by entering the number immediately followed by one of +.RB ( M ", " K ", " C " or " S ). +If the partition fills the free space available, the partition is +created and you are returned to the main command line. Otherwise, the +partition can be created at the beginning or the end of the free +space, and +.B cfdisk +will ask you to choose where to place the partition. After the +partition is created, +.B cfdisk +automatically adjusts the other partition's partition types if all of +the primary partitions are used. +.TP +.B p +Print the partition table to the screen or to a file. There are +several different formats for the partition that you can choose from: +.sp +.RS +.TP +.B r +Raw data format (exactly what would be written to disk) +.TP +.B s +Partition table in sector order format +.TP +.B t +Partition table in raw format +.RE + +.RS +The +.I raw data format +will print the sectors that would be written to disk if a +.BR w rite +command is selected. First, the primary partition table is printed, +followed by the partition tables associated with each logical +partition. The data is printed in hex byte by byte with 16 bytes per +line. + +The +.I partition table in sector order format +will print the partition table ordered by sector number. The fields, +from left to right, are the number of the partition, the partition +type, the first sector, the last sector, the offset from the first +sector of the partition to the start of the data, the length of the +partition, the filesystem type (with the hex value in parenthesis), +and the flags (with the hex value in parenthesis). In addition to the +primary and logical partitions, free and unusable space is printed and +the extended partition is printed before the first logical partition. + +If a partition does not start or end on a cylinder boundary or if the +partition length is not divisible by the cylinder size, an asterisks +.RB ( * ) +is printed after the non-aligned sector number/count. This usually +indicates that a partition was created by an operating system that +either does not align partitions to cylinder boundaries or that used +different disk geometry information. If you know the disk geometry of +the other operating system, you could enter the geometry information +with the change geometry command +.RB ( g ). + +For the first partition on the disk and for all logical partitions, if +the offset from the beginning of the partition is not equal to the +number of sectors per track (i.e., the data does not start on the +first head), a number sign +.RB ( # ) +is printed after the offset. For the remaining partitions, if the +offset is not zero, a number sign will be printed after the offset. +This corresponds to the +.I NC +flag in the partitions section of the main display. + +The +.I partition table in raw format +will print the partition table ordered by partition number. It will +leave out all free and unusable space. The fields, from left to +right, are the number of the partition, the flags (in hex), the +starting head, sector and cylinder, the filesystem ID (in hex), the +ending head, sector and cylinder, the starting sector in the partition +and the number of sectors in the partition. The information in this +table can be directly translated to the +.IR "raw data format" . + +The partition table entries only have 10 bits available to represent +the starting and ending cylinders. Thus, when the absolute starting +(ending) sector number is on a cylinder greater than 1023, the maximal +values for starting (ending) head, sector and cylinder are printed. +This is the method used by OS/2, and thus fixes the problems +associated with OS/2's fdisk rewriting the partition table when it is +not in this format. Since Linux and OS/2 use absolute sector counts, +the values in the starting and ending head, sector and cylinder are +not used. +.RE +.TP +.B q +Quit program. This will exit the program without writing any data to +disk. +.TP +.B t +Change the filesystem type. By default, new partitions are created as +.I Linux +partitions, but since +.B cfdisk +can create partitions for other operating systems, change partition +type allows you to enter the hex value of the filesystem you desire. +A list of the know filesystem types is displayed. You can type in the +filesystem type at the prompt or accept the default filesystem type +.RI [ Linux ]. +.TP +.B u +Change units of the partition size display. It will rotate through +megabytes, sectors and cylinders. +.TP +.B W +Write partition table to disk (must enter an upper case W). Since +this might destroy data on the disk, you must either confirm or deny +the write by entering `yes' or `no'. If you enter `yes', +.B cfdisk +will write the partition table to disk and the tell the kernel to +re-read the partition table from the disk. The re-reading of the +partition table works is most cases, but I have seen it fail. Don't +panic. It will be correct after you reboot the system. In all cases, +I still recommend rebooting the system--just to be safe. +.TP +.I Up Arrow +.TP +.I Down Arrow +Move cursor to the previous or next partition. If there are more +partitions than can be displayed on a screen, you can display the next +(previous) set of partitions by moving down (up) at the last (first) +partition displayed on the screen. +.TP +.I CTRL-L +Redraws the screen. In case something goes wrong and you cannot read +anything, you can refresh the screen from the main command line. +.TP +.B ? +Print the help screen. + +.RE +All of the commands can be entered with either upper or lower case +letters (except for +.BR W rites). +When in a sub-menu or at a prompt to enter a filename, you can hit the +.I ESC +key to return to the main command line. +.SH OPTIONS +.TP +.B \-a +Use an arrow cursor instead of reverse video for highlighting the +current partition. +.TP +.B \-v +Print the version number and copyright. +.TP +.B \-z +Start with zeroed partition table. This option is useful when you +want to repartition your entire disk. +.I Note: +this option does not zero the partition table on the disk; rather, it +simply starts the program without reading the existing partition +table. +.TP +.BI \-c " cylinders" +.TP +.BI \-h " heads" +.TP +.BI \-s " sectors-per-track" +Override the number of cylinders, heads and sectors per track read +from the BIOS. If your BIOS or adapter does not supply this +information or if it supplies incorrect information, use these options +to set the disk geometry values. +.TP +.BI \-P " opt" +Prints the partition table in specified formats. +.I opt +can be one or more of "r", "s" or "t". See the +.BR p rint +command (above) for more information on the print formats. +.SH "EXIT STATUS" +0: No errors; 1: Invocation error; 2: I/O error; +3: cannot get geometry; 4: bad partition table on disk. +.SH "SEE ALSO" +fdisk(8) +.SH BUGS +The current version does not support multiple disks. +.SH AUTHOR +Kevin E. Martin (martin@cs.unc.edu) diff --git a/fdisk/cfdisk.c b/fdisk/cfdisk.c new file mode 100644 index 000000000..96ddbbf24 --- /dev/null +++ b/fdisk/cfdisk.c @@ -0,0 +1,2642 @@ +/**************************************************************************** + * + * CFDISK + * + * cfdisk is a curses based disk drive partitioning program that can + * create partitions for a wide variety of operating systems including + * Linux, MS-DOS and OS/2. + * + * cfdisk was inspired by the fdisk program, by A. V. Le Blanc + * (LeBlanc@mcc.ac.uk). + * + * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) + * + * cfdisk 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. + * + * cfdisk 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 cfdisk; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu + * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu + * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto + * + * Versions 0.8e-n: aeb@cwi.nl + * Recognition of NTFS / HPFS difference inspired by patches + * from Marty Leisner + * Exit codes by Enrique Zanardi : + * 0: all went well + * 1: command line error + * 2: hardware problems [BAD_SEEK, BAD_READ, BAD_WRITE or BAD_OPEN]. + * 3: ioctl(fd, HDIO_GETGEO,...) failed [BAD_GEOMETRY]. + * 4: bad partition table on disk. [BAD_PRIMARY or BAD_LOGICAL]. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SLCURSES + #include +#else +#if NCH + #include +#else + #include +#endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for BLKRRPART */ + +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +extern ext2_loff_t ext2_llseek(unsigned int fd, ext2_loff_t offset, + unsigned int origin); + +#define VERSION "0.8n" + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" + +#define LINE_LENGTH 80 +#define MAXIMUM_PARTS 60 + +#define SECTOR_SIZE 512 + +#define MAX_CYLINDERS 65535 +#define MAX_HEADS 255 +#define MAX_SECTORS 63 + +#define ACTIVE_FLAG 0x80 +#define PART_TABLE_FLAG0 0x55 +#define PART_TABLE_FLAG1 0xAA + +#define UNUSABLE -1 +#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 ADD_EXISTS "This partition is already in use" +#define ADD_UNUSABLE "This partition is unusable" +#define DEL_EMPTY "Cannot delete an empty partition" +#define ID_EMPTY "Cannot change FS Type to empty" +#define ID_EXT "Cannot change FS Type to extended" +#define NEED_EXT "No room to create the extended partition" +#define NO_FLAGS "Cannot make this partition bootable" +#define NO_MORE_PARTS "No more partitions" +#define PRINT_OPEN_ERR "Cannot open file '%s'" +#define TWO_EXTENDEDS "Cannot create logical drive here -- would create two extended partitions" +#define TYPE_EMPTY "Cannot change the type of an empty partition" +#define BAD_COMMAND "Illegal command" +#define MAX_UNMAXABLE "Cannot maximize this partition" +#define BAD_OPEN "Cannot open disk drive" +#define BAD_SEEK "Cannot seek on disk drive" +#define BAD_READ "Cannot read disk drive" +#define BAD_WRITE "Cannot write disk drive" +#define BAD_GEOMETRY "Cannot read disk drive geometry" +#define BAD_PRIMARY "Bad primary partition" +#define BAD_LOGICAL "Bad logical partition" +#define BAD_CYLINDERS "Illegal cylinders value" +#define BAD_HEADS "Illegal heads value" +#define BAD_SECTORS "Illegal sectors value" +#define READONLY_WARN "Opened disk read-only - you have no permission to write" +#define WRITE_WARN "Warning!! This may destroy data on your disk!" +#define YES_NO "Please enter `yes' or `no'" +#define WRITING_PART "Writing partition table to disk..." +#define YES_WRITE "Wrote partition table to disk" +#define NO_WRITE "Did not write partition table to disk" +#define RRPART_FAILED "Wrote partition table, but re-read table failed. Reboot to update table." +#define NOT_DOS_MBR_BOOTABLE "Not precisely one primary partition is bootable. DOS MBR cannot boot this." + +#define PRI_OR_LOG -1 +#define PRIMARY -2 +#define LOGICAL -3 + +#define COL_ID_WIDTH 20 + +#define CR '\015' +#define ESC '\033' +#define DEL '\177' +#define BELL '\007' +/* '\014' == ^L */ +#define REDRAWKEY '\014' + +/* Display units */ +#define MEGABYTES 1 +#define SECTORS 2 +#define CYLINDERS 3 + +#define GS_DEFAULT -1 +#define GS_ESCAPE -2 + +#define PRINT_RAW_TABLE 1 +#define PRINT_SECTOR_TABLE 2 +#define PRINT_PARTITION_TABLE 4 + +#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) +#define IS_LOGICAL(p) ((p) > 3) + +#define round_int(d) ((double)((int)(d+0.5))) +#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) + +#define set_hsc(h,s,c,sector) \ +{ \ + s = sector % sectors + 1; \ + sector /= sectors; \ + h = sector % heads; \ + sector /= heads; \ + c = sector & 0xFF; \ + s |= (sector >> 2) & 0xC0;\ +} + +#define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \ + (x) == LINUX_EXTENDED) + +#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) + +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 */ +}; + +/* 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 ALIGNMENT 2 +typedef union { + struct { + unsigned char align[ALIGNMENT]; + unsigned char b[SECTOR_SIZE]; + } c; + struct { + unsigned char align[ALIGNMENT]; + unsigned char buffer[0x1BE]; + struct partition part[4]; + unsigned char magicflag[2]; + } p; +} partition_table; + +typedef struct { + int first_sector; /* first sector in partition */ + int last_sector; /* last sector in partition */ + int offset; /* offset from first sector to start of data */ + int flags; /* active == 0x80 */ + int id; /* filesystem type */ + int num; /* number of partition -- primary vs. logical */ +#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; +int fd; +int heads = 0; +int sectors = 0; +int cylinders = 0; +int changed = FALSE; +int opened = FALSE; +int opentype; +int curses_started = 0; + +partition_info p_info[MAXIMUM_PARTS]; +partition_info ext_info; +int num_parts = 0; + +int logical = 0; +int logical_sectors[MAXIMUM_PARTS]; + +__sighandler_t old_SIGINT, old_SIGTERM; + +int arrow_cursor = FALSE; +int display_units = MEGABYTES; +int zero_table = FALSE; +int print_only = 0; + +/* Curses screen information */ +int cur_part = 0; +int warning_last_time = FALSE; +int defined = FALSE; +int COLUMNS = 80; +int NUM_ON_SCREEN = 1; + +/* Y coordinates */ +int HEADER_START = 0; +int DISK_TABLE_START = 5; +int WARNING_START = 23; +int COMMAND_LINE_Y = 21; + +/* X coordinates */ +int NAME_START = 4; +int FLAGS_START = 16; +int PTYPE_START = 28; +int FSTYPE_START = 38; +int LABEL_START = 54; +int SIZE_START = 70; +int COMMAND_LINE_X = 5; + +#define NUM_PART_TYPES 256 +char *partition_type[NUM_PART_TYPES] = { + [LINUX_MINIX] = "Linux/MINIX", + [LINUX_SWAP] = "Linux Swap", + [LINUX] = "Linux", + [FREE_SPACE] = "Free Space", + [DOS_EXTENDED]= "Extended", + [LINUX_EXTENDED] = "Linux extended", + [0x01] = "DOS FAT12", + [0x02] = "XENIX root", + [0x03] = "XENIX usr", + [0x04] = "DOS FAT16", + [0x06] = "DOS FAT16 (big)", + [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)", + [0x0E] = "Win95 FAT16 (LBA)", + [0x0F] = "Win95 Extended (LBA)", + [0x11] = "Hidden DOS FAT12", + [0x14] = "Hidden DOS FAT16", + [0x16] = "Hidden DOS FAT16 (big)", + [0x17] = "Hidden OS/2 HPFS or NTFS", + [0x40] = "Venix 80286", + [0x41] = "PPC PReP boot", + [0x51] = "Novell?", + [0x52] = "Microport", + [0x63] = "GNU HURD", + [0x64] = "Novell Netware 286", + [0x65] = "Novell Netware 386", + [0x75] = "PC/IX", + [0x80] = "Old MINIX", + [0x93] = "Amoeba", + [0x94] = "Amoeba BBT", + [0xA5] = "BSD/386", + [0xA6] = "OpenBSD", + [0xA7] = "NEXTSTEP", + [0xB7] = "BSDI fs", + [0xB8] = "BSDI swap", + [0xC7] = "Syrinx", + [0xDB] = "CP/M", + [0xE1] = "DOS access", + [0xE3] = "DOS R/O", + [0xEB] = "BeOS fs", + [0xF2] = "DOS secondary", + [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) + close(fd); + + if (changed) { + fprintf(stderr, "Disk has been changed.\n"); + fprintf(stderr, "Reboot the system to ensure the partition " + "table is correctly updated.\n"); + + fprintf( stderr, "\nWARNING: If you have created or modified any\n" + "DOS 6.x partitions, please see the cfdisk manual\n" + "page for additional information.\n" ); + } + + exit(ret); +} + +int get_string(char *str, int len, char *def) +{ + char c; + int i = 0; + int x, y; + int use_def = FALSE; + + getyx(stdscr, y, x); + clrtoeol(); + + str[i] = 0; + + if (def != NULL) { + mvaddstr(y, x, def); + move(y, x); + use_def = TRUE; + } + + refresh(); + while ((c = getch()) != '\n' && c != CR) { + switch (c) { + case ESC: + move(y, x); + clrtoeol(); + refresh(); + return GS_ESCAPE; + case DEL: + case '\b': + if (i > 0) { + str[--i] = 0; + mvaddch(y, x+i, ' '); + move(y, x+i); + } else if (use_def) { + clrtoeol(); + use_def = FALSE; + } else + putchar(BELL); + break; + default: + if (i < len && isprint(c)) { + mvaddch(y, x+i, c); + if (use_def) { + clrtoeol(); + use_def = FALSE; + } + str[i++] = c; + str[i] = 0; + } else + putchar(BELL); + } + refresh(); + } + + if (use_def) + return GS_DEFAULT; + else + return i; +} + +void clear_warning(void) +{ + int i; + + if (!curses_started || !warning_last_time) + return; + + move(WARNING_START,0); + for (i = 0; i < COLS; i++) + addch(' '); + + warning_last_time = FALSE; +} + +void print_warning(char *s) +{ + if (!curses_started) { + fprintf(stderr, "%s\n", s); + } else { + mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); + putchar(BELL); /* CTRL-G */ + + warning_last_time = TRUE; + } +} + +void die_x(int ret); + +void fatal(char *s, int ret) +{ + char str[LINE_LENGTH]; + + if (curses_started) { + sprintf(str, "FATAL ERROR: %s", s); + mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); + sprintf(str, "Press any key to exit fdisk"); + mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); + putchar(BELL); /* CTRL-G */ + refresh(); + (void)getch(); + die_x(ret); + } else { + fprintf(stderr, "FATAL ERROR: %s\n", s); + exit(ret); + } +} + +void die(int dummy) +{ + die_x(0); +} + +void die_x(int ret) +{ + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); +#ifdef SLCURSES + SLsmg_gotorc(LINES-1, 0); + SLsmg_refresh(); +#else + mvcur(0, COLS-1, LINES-1, 0); +#endif + nl(); + endwin(); + printf("\n"); + fdexit(ret); +} + +void read_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK, 2); + if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_READ, 2); +} + +void write_sector(char *buffer, int sect_num) +{ + if (ext2_llseek(fd, ((ext2_loff_t) sect_num)*SECTOR_SIZE, SEEK_SET) < 0) + fatal(BAD_SEEK, 2); + if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) + fatal(BAD_WRITE, 2); +} + +void dos_copy_to_info(char *to, int tosz, char *from, int fromsz) { + int i; + + for(i=0; i 0 && IS_PRIMARY(p_info[i].num)) + pri++; + else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) + log++; + if (is_extended(ext_info.id)) { + if (log > 0) + pri++; + else { + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; + } + } + + if (pri >= 4) { + for (i = 0; i < num_parts; i++) + if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) { + if (is_extended(ext_info.id)) { + if (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) { + p_info[i].id = FREE_SPACE; + p_info[i].num = LOGICAL; + } else + p_info[i].id = UNUSABLE; + } else /* if (!is_extended(ext_info.id)) */ + p_info[i].id = UNUSABLE; + } else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + } else { /* if (pri < 4) */ + for (i = 0; i < num_parts; i++) { + if (p_info[i].id == UNUSABLE) + p_info[i].id = FREE_SPACE; + if (p_info[i].id == FREE_SPACE) { + if (is_extended(ext_info.id)) { + if (p_info[i].first_sector >= ext_info.first_sector && + p_info[i].last_sector <= ext_info.last_sector) + p_info[i].num = LOGICAL; + else if (i > 0 && + p_info[i-1].first_sector >= + ext_info.first_sector && + p_info[i-1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else if (i < num_parts-1 && + p_info[i+1].first_sector >= + ext_info.first_sector && + p_info[i+1].last_sector <= + ext_info.last_sector) + p_info[i].num = PRI_OR_LOG; + else + p_info[i].num = PRIMARY; + } else /* if (!is_extended(ext_info.id)) */ + p_info[i].num = PRI_OR_LOG; + } else /* if (p_info[i].id > 0) */ + while (0); /* Leave these alone */ + } + } +} + +void remove_part(int i) +{ + int p; + + for (p = i; p < num_parts; p++) + p_info[p] = p_info[p+1]; + + num_parts--; +} + +void insert_empty_part(int i, int first, int last) +{ + int p; + + for (p = num_parts; p > i; p--) + p_info[p] = p_info[p-1]; + + p_info[i].first_sector = first; + p_info[i].last_sector = last; + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + p_info[i].volume_label[0] = 0; + p_info[i].fstype[0] = 0; + p_info[i].ostype[0] = 0; + + num_parts++; +} + +void del_part(int i) +{ + int num = p_info[i].num; + + if (i > 0 && (p_info[i-1].id == FREE_SPACE || + p_info[i-1].id == UNUSABLE)) { + /* Merge with previous partition */ + p_info[i-1].last_sector = p_info[i].last_sector; + remove_part(i--); + } + + if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || + p_info[i+1].id == UNUSABLE)) { + /* Merge with next partition */ + p_info[i+1].first_sector = p_info[i].first_sector; + remove_part(i); + } + + if (i > 0) + p_info[i].first_sector = p_info[i-1].last_sector + 1; + else + p_info[i].first_sector = 0; + + if (i < num_parts - 1) + p_info[i].last_sector = p_info[i+1].first_sector - 1; + else + p_info[i].last_sector = sectors*heads*cylinders - 1; + + p_info[i].offset = 0; + p_info[i].flags = 0; + p_info[i].id = FREE_SPACE; + p_info[i].num = PRI_OR_LOG; + + if (IS_LOGICAL(num)) { + /* We have a logical partition --> shrink the extended partition + * if (1) this is the first logical drive, or (2) this is the + * last logical drive; and if there are any other logical drives + * then renumber the ones after "num". + */ + if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) { + ext_info.first_sector = p_info[i].last_sector + 1; + ext_info.offset = 0; + } + if (i == num_parts-1 || + (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) + ext_info.last_sector = p_info[i].first_sector - 1; + for (i = 0; i < num_parts; i++) + if (p_info[i].num > num) + p_info[i].num--; + } + + /* Clean up the rest of the partitions */ + check_part_info(); +} + +int add_part(int num, int id, int flags, int first, int last, int offset, + int want_label) +{ + int i, pri = 0, log = 0; + + if (num_parts == MAXIMUM_PARTS || + first < 0 || + first >= cylinders*heads*sectors || + last < 0 || + last >= cylinders*heads*sectors) { + return -1; /* bad start or end */ + } + + for (i = 0; i < num_parts; i++) + if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) + pri++; + else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) + log++; + if (is_extended(ext_info.id) && log > 0) + pri++; + + if (IS_PRIMARY(num)) { + if (pri >= 4) { + return -1; /* no room for more */ + } else + pri++; + } + + for (i = 0; i < num_parts && p_info[i].last_sector < first; i++); + + if (i == num_parts || p_info[i].id != FREE_SPACE + || last > p_info[i].last_sector) { + return -1; + } + + if (is_extended(id)) { + if (ext_info.id != FREE_SPACE) { + return -1; /* second extended */ + } + else if (IS_PRIMARY(num)) { + ext_info.first_sector = first; + ext_info.last_sector = last; + ext_info.offset = offset; + ext_info.flags = flags; + ext_info.id = id; + ext_info.num = num; + ext_info.volume_label[0] = 0; + ext_info.fstype[0] = 0; + ext_info.ostype[0] = 0; + return 0; + } else { + return -1; /* explicit extended logical */ + } + } + + if (IS_LOGICAL(num)) { + if (!is_extended(ext_info.id)) { + print_warning("!!!! Internal error creating logical " + "drive with no extended partition !!!!"); + } else { + /* We might have a logical partition outside of the extended + * partition's range --> we have to extend the extended + * partition's range to encompass this new partition, but we + * must make sure that there are no primary partitions between + * it and the closest logical drive in extended partition. + */ + if (first < ext_info.first_sector) { + if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { + print_warning(TWO_EXTENDEDS); + return -1; + } else { + if (first == 0) { + ext_info.first_sector = 0; + ext_info.offset = first = offset; + } else { + ext_info.first_sector = first; + } + } + } else if (last > ext_info.last_sector) { + if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { + print_warning(TWO_EXTENDEDS); + return -1; + } else { + ext_info.last_sector = last; + } + } + } + } + + if (first != p_info[i].first_sector && + !(IS_LOGICAL(num) && first == offset)) { + insert_empty_part(i, p_info[i].first_sector, first-1); + i++; + } + + if (last != p_info[i].last_sector) + insert_empty_part(i+1, last+1, p_info[i].last_sector); + + p_info[i].first_sector = first; + p_info[i].last_sector = last; + p_info[i].offset = offset; + p_info[i].flags = flags; + p_info[i].id = id; + p_info[i].num = num; + p_info[i].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(); + + return 0; +} + +int find_primary(void) +{ + int num = 0, cur = 0; + + while (cur < num_parts && IS_PRIMARY(num)) + if ((p_info[cur].id > 0 && p_info[cur].num == num) || + (is_extended(ext_info.id) && ext_info.num == num)) { + num++; + cur = 0; + } else + cur++; + + if (!IS_PRIMARY(num)) + return -1; + else + return num; +} + +int find_logical(int i) +{ + int num = -1; + int j; + + for (j = i; j < num_parts && num == -1; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + num = p_info[j].num; + + if (num == -1) { + num = 4; + for (j = 0; j < num_parts; j++) + if (p_info[j].id > 0 && p_info[j].num == num) + num++; + } + + return num; +} + +void inc_logical(int i) +{ + int j; + + for (j = i; j < num_parts; j++) + if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) + p_info[j].num++; +} + +/* Command menu support by Janne Kukonlehto September 1994 */ + +/* Constants for menuType parameter of menuSelect function */ +#define MENU_HORIZ 1 +#define MENU_VERT 2 +#define MENU_ACCEPT_OTHERS 4 +#define MENU_BUTTON 8 +/* Miscellenous constants */ +#define MENU_SPACING 2 +#define MENU_MAX_ITEMS 256 /* for simpleMenu function */ +#define MENU_UP 1 +#define MENU_DOWN 2 +#define MENU_RIGHT 3 +#define MENU_LEFT 4 + +struct MenuItem +{ + int key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */ + char *name; /* Item name, should be eight characters with current implementation */ + char *desc; /* Item description to be printed when item is selected */ +}; + +/* + * Actual function which prints the button bar and highlights the active button + * Should not be called directly. Call function menuSelect instead. + */ + +int menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength, + char *available, int menuType, int current ) +{ + int i, lmargin = x, ymargin = y; + /* Print available buttons */ + move( y, x ); clrtoeol(); + for( i = 0; menuItems[i].key; i++ ) + { + char buff[20]; + int lenName; + /* Search next available button */ + while( menuItems[i].key && !strchr(available, menuItems[i].key) ) + { + i++; + } + if( !menuItems[i].key ) break; /* No more menu items */ + /* If selected item is not available and we have bypassed it, + make current item selected */ + if( current < i && menuItems[current].key < 0 ) current = i; + /* If current item is selected, highlight it */ + if( current == i ) /*attron( A_REVERSE )*/ standout (); + /* Print item */ + lenName = strlen( menuItems[i].name ); + if(lenName > itemLength) + print_warning("Menu item too long. Menu may look odd."); + if( menuType & MENU_BUTTON ) + sprintf( buff, "[%*s%-*s]", (itemLength - lenName) / 2, "", + (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name ); + else + sprintf( buff, "%*s%-*s", (itemLength - lenName) / 2, "", + (itemLength - lenName + 1) / 2 + lenName, menuItems[i].name ); + mvaddstr( y, x, buff ); + /* Lowlight after selected item */ + if( current == i ) /*attroff( A_REVERSE )*/ standend (); + /* Calculate position for the next item */ + if( menuType & MENU_VERT ) + { + y += 1; + if( y >= WARNING_START ) + { + y = ymargin; + x += itemLength + MENU_SPACING; + if( menuType & MENU_BUTTON ) x += 2; + } + } + else + { + x += itemLength + MENU_SPACING; + if( menuType & MENU_BUTTON ) x += 2; + if( x > COLUMNS - lmargin - 12 ) + { + x = lmargin; + y ++ ; + } + } + } + /* Print the description of selected item */ + mvaddstr( WARNING_START + 1, + (COLUMNS - strlen( menuItems[current].desc )) / 2, + menuItems[current].desc ); + return y; +} + +/* This function takes a list of menu items, lets the user choose one of them * + * and returns the value keyboard shortcut of the selected menu item */ + +int menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength, char *available, int menuType, int menuDefault ) +{ + int i, ylast = y, key = 0, current = menuDefault; + if( !( menuType & ( MENU_HORIZ | MENU_VERT ) ) ) + { + print_warning("Menu without direction. Defaulting horizontal."); + menuType |= MENU_HORIZ; + } + /* Make sure that the current is one of the available items */ + while( !strchr(available, menuItems[current].key) ) + { + current ++ ; + if( !menuItems[current].key ) current = 0; + } + /* Repeat until allowable choice has been made */ + while( !key ) + { + /* Display the menu */ + ylast = menuUpdate( y, x, menuItems, itemLength, available, + menuType, current ); + refresh(); + key = getch(); + /* Clear out all prompts and such */ + clear_warning(); + for( i = y; i < ylast; i ++ ) + { + move( i, x ); + clrtoeol(); + } + move( WARNING_START + 1, 0 ); + clrtoeol(); + /* Cursor keys */ + if( key == ESC ) + { + /* Check whether this is a real ESC or one of extended keys */ + /*nodelay(stdscr, TRUE);*/ + key = getch(); + /*nodelay(stdscr, FALSE);*/ + if( key == /*ERR*/ ESC ) + { + /* This is a real ESC */ + key = ESC; + } + if( key == '[' ) + { + /* This is one extended keys */ + switch( getch() ) + { + case 'A': /* Up arrow */ + if( menuType & MENU_VERT ) + { + do { + current -- ; + if( current < 0 ) while( menuItems[current+1].key ) current ++ ; + } while( !strchr( available, menuItems[current].key ) ); + key = 0; + } + else + key = MENU_UP; + break; + case 'B': /* Down arrow */ + if( menuType & MENU_VERT ) + { + do { + current ++ ; + if( !menuItems[current].key ) current = 0 ; + } while( !strchr( available, menuItems[current].key ) ); + key = 0; + } + else + key = MENU_DOWN; + break; + case 'C': /* Right arrow */ + if( menuType & MENU_HORIZ ) + { + do { + current ++ ; + if( !menuItems[current].key ) + { + current = 0 ; + } + } while( !strchr( available, menuItems[current].key ) ); + key = 0; + } + else + key = MENU_RIGHT; + break; + case 'D': /* Left arrow */ + if( menuType & MENU_HORIZ ) + { + do { + current -- ; + if( current < 0 ) + { + while( menuItems[current + 1].key ) current ++ ; + } + } while( !strchr( available, menuItems[current].key ) ); + key = 0; + } + else + key = MENU_LEFT; + break; + } + } + } + /* Enter equals to the keyboard shortcut of current menu item */ + if( key == 13 ) + { + key = menuItems[current].key; + } + /* Should all keys to be accepted? */ + if( key && (menuType & MENU_ACCEPT_OTHERS) ) break; + /* Is pressed key among acceptable ones */ + if( key && (strchr(available, tolower(key)) || strchr(available, key))) + break; + /* The key has not been accepted so far -> let's reject it */ + if( key ) + { + key = 0; + putchar( BELL ); + print_warning("Illegal key"); + } + } + /* Clear out prompts and such */ + clear_warning(); + for( i = y; i <= ylast; i ++ ) + { + move( i, x ); + clrtoeol(); + } + move( WARNING_START + 1, 0 ); + clrtoeol(); + 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? */ + +void menuContinue(void) +{ + static struct MenuItem menuContinueBtn[]= + { + { 'c', "", "Press a key to continue" }, + { 0, NULL, NULL } + }; + + menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, + menuContinueBtn, 0, "c", MENU_HORIZ | MENU_ACCEPT_OTHERS, 0 ); +} + +/* Function menuSelect takes way too many parameters * + * Luckily, most of time we can do with this function */ + +int menuSimple(struct MenuItem *menuItems, int menuDefault) +{ + int i, j, itemLength = 0; + char available[MENU_MAX_ITEMS]; + for(i = 0; menuItems[i].key; i++) + { + j = strlen( menuItems[i].name ); + if( j > itemLength ) itemLength = j; + available[i] = menuItems[i].key; + } + available[i] = 0; + return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength, + available, MENU_HORIZ | MENU_BUTTON, menuDefault); +} + +/* End of command menu support code */ + +void new_part(int i) +{ + char response[LINE_LENGTH], def[LINE_LENGTH]; + char c; + int first = p_info[i].first_sector; + int last = p_info[i].last_sector; + int offset = 0; + int flags = 0; + int id = LINUX; + int num = -1; + int num_sects = last - first + 1; + int len, ext, j; + + if (p_info[i].num == PRI_OR_LOG) { + static struct MenuItem menuPartType[]= + { + { 'p', "Primary", "Create a new primary partition" }, + { 'l', "Logical", "Create a new logical partition" }, + { ESC, "Cancel", "Don't create a partition" }, + { 0, NULL, NULL } + }; + + c = menuSimple( menuPartType, 0 ); + if (toupper(c) == 'P') + num = find_primary(); + else if (toupper(c) == 'L') + num = find_logical(i); + else + return; + } else if (p_info[i].num == PRIMARY) + num = find_primary(); + else if (p_info[i].num == LOGICAL) + num = find_logical(i); + else + print_warning("!!! Internal error !!!"); + + sprintf(def, "%.2f", ceiling(num_sects/20.48)/100); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Size (in MB): "); + if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && + len != GS_DEFAULT) + return; + else if (len > 0) { +#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/(sectors*heads))) + for (j = 0; + j < len-1 && (isdigit(response[j]) || response[j] == '.'); + j++); + if (toupper(response[j]) == 'K') { + num_sects = num_cyls(atof(response)*1024)*sectors*heads; + } else if (toupper(response[j]) == 'M') { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } else if (toupper(response[j]) == 'C') { + num_sects = round_int(atof(response))*sectors*heads; + } else if (toupper(response[j]) == 'S') { + num_sects = round_int(atof(response)); + } else { + num_sects = num_cyls(atof(response)*1024*1024)*sectors*heads; + } + } + + if (num_sects <= 0 || + num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) + return; + + move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol(); + if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { + /* Determine where inside free space to put partition. + */ + static struct MenuItem menuPlace[]= + { + { 'b', "Beginning", "Add partition at beginning of free space" }, + { 'e', "End", "Add partition at end of free space" }, + { ESC, "Cancel", "Don't create a partition" }, + { 0, NULL, NULL } + }; + c = menuSimple( menuPlace, 0 ); + if (toupper(c) == 'B') + last = first + num_sects - 1; + else if (toupper(c) == 'E') + first = last - num_sects + 1; + else + return; + } + + if (IS_LOGICAL(num) && !is_extended(ext_info.id)) { + /* We want to add a logical partition, but need to create an + * extended partition first. + */ + if ((ext = find_primary()) < 0) { + print_warning(NEED_EXT); + return; + } + (void) add_part(ext, DOS_EXTENDED, 0, first, last, + (first == 0 ? sectors : 0), 0); + first = ext_info.first_sector + ext_info.offset; + } + + if (IS_LOGICAL(num)) + inc_logical(i); + + /* Now we have a complete partition to ourselves */ + if (first == 0 || IS_LOGICAL(num)) + offset = sectors; + + (void) add_part(num, id, flags, first, last, offset, 0); +} + +void clear_p_info(void) +{ + num_parts = 1; + p_info[0].first_sector = 0; + p_info[0].last_sector = sectors*heads*cylinders - 1; + p_info[0].offset = 0; + p_info[0].flags = 0; + p_info[0].id = FREE_SPACE; + p_info[0].num = PRI_OR_LOG; + + ext_info.first_sector = 0; + ext_info.last_sector = 0; + ext_info.offset = 0; + ext_info.flags = 0; + ext_info.id = FREE_SPACE; + ext_info.num = PRIMARY; +} + +void fill_p_info(void) +{ + int pn, i, bs, bsz; + struct partition *p; + struct hd_geometry geometry; + partition_table buffer; + partition_info tmp_ext = { 0, 0, 0, 0, FREE_SPACE, PRIMARY }; + + if ((fd = open(disk_device, O_RDWR)) < 0) { + if ((fd = open(disk_device, O_RDONLY)) < 0) + fatal(BAD_OPEN, 2); + opentype = O_RDONLY; + print_warning(READONLY_WARN); + if (curses_started) { + refresh(); + getch(); + clear_warning(); + } + } else + opentype = O_RDWR; + opened = TRUE; + + /* 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) + heads = geometry.heads; + if (!sectors) + sectors = geometry.sectors; + if (!cylinders) + cylinders = geometry.cylinders; + } + + if (!heads || !sectors || !cylinders) + fatal(BAD_GEOMETRY, 3); /* probably a file or cdrom */ + + read_sector(buffer.c.b, 0); + + clear_p_info(); + + if (!zero_table) { + for (i = 0; i < 4; i++) { + p = & buffer.p.part[i]; + bs = get_start_sect(p); + bsz = get_nr_sects(p); + + if (p->sys_ind > 0 && + add_part(i, p->sys_ind, p->boot_ind, + ((bs <= sectors) ? 0 : bs), + bs + bsz - 1, + ((bs <= sectors) ? bs : 0), + 1)) { + fatal(BAD_PRIMARY, 4); + } + if (is_extended(buffer.p.part[i].sys_ind)) + tmp_ext = ext_info; + } + + if (is_extended(tmp_ext.id)) { + ext_info = tmp_ext; + logical_sectors[logical] = + ext_info.first_sector + ext_info.offset; + read_sector(buffer.c.b, logical_sectors[logical++]); + i = 4; + do { + for (pn = 0; + pn < 4 && (!buffer.p.part[pn].sys_ind || + is_extended(buffer.p.part[pn].sys_ind)); + pn++); + + if (pn < 4) { + p = & buffer.p.part[pn]; + bs = get_start_sect(p); + bsz = get_nr_sects(p); + + if (add_part(i++, p->sys_ind, p->boot_ind, + logical_sectors[logical-1], + logical_sectors[logical-1] + bs + bsz - 1, + bs, 1)) + fatal(BAD_LOGICAL, 4); + } + + for (pn = 0; + pn < 4 && !is_extended(buffer.p.part[pn].sys_ind); + pn++); + if (pn < 4) { + p = & buffer.p.part[pn]; + bs = get_start_sect(p); + logical_sectors[logical] = ext_info.first_sector + + ext_info.offset + bs; + read_sector(buffer.c.b, logical_sectors[logical++]); + } + } while (pn < 4 && logical < MAXIMUM_PARTS-4); + } + } +} + +void fill_part_table(struct partition *p, partition_info *pi) +{ + int sects; + + p->boot_ind = pi->flags; + p->sys_ind = pi->id; + if (IS_LOGICAL(pi->num)) + set_start_sect(p,pi->offset); + else + set_start_sect(p,pi->first_sector + pi->offset); + set_nr_sects(p, pi->last_sector - (pi->first_sector+pi->offset) + 1); + sects = (((pi->first_sector+pi->offset)/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector+pi->offset); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); +} + +void fill_primary_table(partition_table *buffer) +{ + int i; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + for (i = 0; i < num_parts; i++) + if (IS_PRIMARY(p_info[i].num)) + fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); + + if (is_extended(ext_info.id)) + fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); + + buffer->p.magicflag[0] = PART_TABLE_FLAG0; + buffer->p.magicflag[1] = PART_TABLE_FLAG1; +} + +void fill_logical_table(partition_table *buffer, partition_info *pi) +{ + struct partition *p; + int i, sects; + + for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); + if (i == logical || buffer->p.magicflag[0] != PART_TABLE_FLAG0 + || buffer->p.magicflag[1] != PART_TABLE_FLAG1) + for (i = 0; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + /* Zero out existing table */ + for (i = 0x1BE; i < SECTOR_SIZE; i++) + buffer->c.b[i] = 0; + + fill_part_table(&(buffer->p.part[0]), pi); + + for (i = 0; + i < num_parts && pi->num != p_info[i].num - 1; + i++); + + if (i < num_parts) { + p = &(buffer->p.part[1]); + pi = &(p_info[i]); + + p->boot_ind = 0; + p->sys_ind = DOS_EXTENDED; + set_start_sect(p, pi->first_sector - ext_info.first_sector - ext_info.offset); + set_nr_sects(p, pi->last_sector - pi->first_sector + 1); + sects = ((pi->first_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->first_sector); + set_hsc(p->head, p->sector, p->cyl, sects); + sects = ((pi->last_sector/(sectors*heads) > 1023) ? + heads*sectors*1024 - 1 : pi->last_sector); + set_hsc(p->end_head, p->end_sector, p->end_cyl, sects); + } + + buffer->p.magicflag[0] = PART_TABLE_FLAG0; + buffer->p.magicflag[1] = PART_TABLE_FLAG1; +} + +void write_part_table(void) +{ + int i, ct, done = FALSE, len; + partition_table buffer; + struct stat s; + int is_bdev; + char response[LINE_LENGTH]; + + if (opentype == O_RDONLY) { + print_warning(READONLY_WARN); + refresh(); + getch(); + clear_warning(); + return; + } + + is_bdev = 0; + if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode)) + is_bdev = 1; + + if (is_bdev) { + print_warning(WRITE_WARN); + + while (!done) { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Are you sure you want write the partition table " + "to disk? (yes or no): "); + len = get_string(response, LINE_LENGTH, NULL); + clear_warning(); + if (len == GS_ESCAPE) + return; + else if (len == 2 && + toupper(response[0]) == 'N' && + toupper(response[1]) == 'O') { + print_warning(NO_WRITE); + return; + } else if (len == 3 && + toupper(response[0]) == 'Y' && + toupper(response[1]) == 'E' && + toupper(response[2]) == 'S') + done = TRUE; + else + print_warning(YES_NO); + } + + clear_warning(); + print_warning(WRITING_PART); + refresh(); + } + + read_sector(buffer.c.b, 0); + fill_primary_table(&buffer); + write_sector(buffer.c.b, 0); + + for (i = 0; i < num_parts; i++) + if (IS_LOGICAL(p_info[i].num)) { + read_sector(buffer.c.b, p_info[i].first_sector); + fill_logical_table(&buffer, &(p_info[i])); + write_sector(buffer.c.b, p_info[i].first_sector); + } + + if (is_bdev) { + sync(); + sleep(2); + if (!ioctl(fd,BLKRRPART)) + changed = TRUE; + sync(); + sleep(4); + + clear_warning(); + if (changed) + print_warning(YES_WRITE); + else + print_warning(RRPART_FAILED); + } else + print_warning(YES_WRITE); + + /* Check: unique bootable primary partition? */ + ct = 0; + for (i = 0; i < num_parts; i++) + if (IS_PRIMARY(i) && p_info[i].flags == ACTIVE_FLAG) + ct++; + if (ct != 1) + print_warning(NOT_DOS_MBR_BOOTABLE); +} + +void fp_printf(FILE *fp, char *format, ...) +{ + va_list args; + char buf[1024]; + int y, x; + + va_start(args, format); + vsprintf(buf, format, args); + va_end(args); + + if (fp == NULL) { + /* The following works best if the string to be printed has at + most only one newline. */ + printw("%s", buf); + getyx(stdscr, y, x); + if (y >= COMMAND_LINE_Y-2) { + menuContinue(); + erase(); + move(0, 0); + } + } else + fprintf(fp, "%s", buf); +} + +#define MAX_PER_LINE 16 +void print_file_buffer(FILE *fp, char *buffer) +{ + int i,l; + + for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { + if (l == 0) + fp_printf(fp, "0x%03X:", i); + fp_printf(fp, " %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + fp_printf(fp, "\n"); + l = -1; + } + } + if (l > 0) + fp_printf(fp, "\n"); + fp_printf(fp, "\n"); +} + +void print_raw_table(void) +{ + int i, to_file; + partition_table buffer; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + fp_printf(fp, "Disk Drive: %s\n", disk_device); + + fp_printf(fp, "Sector 0:\n"); + read_sector(buffer.c.b, 0); + fill_primary_table(&buffer); + print_file_buffer(fp, buffer.c.b); + + for (i = 0; i < num_parts; i++) + if (IS_LOGICAL(p_info[i].num)) { + fp_printf(fp, "Sector %d:\n", p_info[i].first_sector); + read_sector(buffer.c.b, p_info[i].first_sector); + fill_logical_table(&buffer, &(p_info[i])); + print_file_buffer(fp, buffer.c.b); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + menuContinue(); + } +} + +void print_p_info_entry(FILE *fp, partition_info *p) +{ + int size; + char part_str[40]; + + if (p->id == UNUSABLE) + fp_printf(fp, " None "); + else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) + fp_printf(fp, " Pri/Log"); + else if (p->id == FREE_SPACE && p->num == PRIMARY) + fp_printf(fp, " Primary"); + else if (p->id == FREE_SPACE && p->num == LOGICAL) + fp_printf(fp, " Logical"); + else + fp_printf(fp, "%2d %-7.7s", p->num+1, + IS_LOGICAL(p->num) ? "Logical" : "Primary"); + + fp_printf(fp, " "); + + fp_printf(fp, "%8d%c", p->first_sector, + ((p->first_sector/(sectors*heads)) != + ((float)p->first_sector/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, "%8d%c", p->last_sector, + (((p->last_sector+1)/(sectors*heads)) != + ((float)(p->last_sector+1)/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, "%7d%c", p->offset, + ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && + (p->offset != sectors)) || + (p->first_sector != 0 && IS_PRIMARY(p->num) && + p->offset != 0)) ? + '#' : ' ')); + + size = p->last_sector - p->first_sector + 1; + fp_printf(fp, "%8d%c", size, + ((size/(sectors*heads)) != ((float)size/(sectors*heads)) ? + '*' : ' ')); + + fp_printf(fp, " "); + + if (p->id == UNUSABLE) + sprintf(part_str, "%.17s", "Unusable"); + else if (p->id == FREE_SPACE) + sprintf(part_str, "%.17s", "Free Space"); + else if (partition_type[p->id]) + sprintf(part_str, "%.17s (%02X)", partition_type[p->id], p->id); + else + sprintf(part_str, "%.17s (%02X)", "Unknown", p->id); + fp_printf(fp, "%-22.22s", part_str); + + fp_printf(fp, " "); + + if (p->flags == ACTIVE_FLAG) + fp_printf(fp, "Boot (%02X)", p->flags); + else if (p->flags != 0) + fp_printf(fp, "Unknown (%02X)", p->flags); + else + fp_printf(fp, "None (%02X)", p->flags); + + fp_printf(fp, "\n"); +} + +void print_p_info(void) +{ + char fname[LINE_LENGTH]; + FILE *fp; + int i, to_file, pext = is_extended(ext_info.id); + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + fp_printf(fp, "Partition Table for %s\n", disk_device); + fp_printf(fp, "\n"); + fp_printf(fp, " First Last\n"); + fp_printf(fp, " # Type Sector Sector Offset Length Filesystem Type (ID) Flags\n"); + fp_printf(fp, "-- ------- -------- --------- ------ --------- ---------------------- ---------\n"); + + for (i = 0; i < num_parts; i++) { + if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { + print_p_info_entry(fp,&ext_info); + pext = FALSE; + } + print_p_info_entry(fp, &(p_info[i])); + } + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + menuContinue(); + } +} + +void print_part_entry(FILE *fp, int num, partition_info *pi) +{ + int first = 0, start = 0, end = 0, size = 0; + int ss = 0, sh = 0, sc = 0; + int es = 0, eh = 0, ec = 0; + int flags = 0, id = 0; + + if (pi != NULL) { + flags = pi->flags; + id = pi->id; + + if (IS_LOGICAL(num)) + first = pi->offset; + else + first = pi->first_sector + pi->offset; + + start = pi->first_sector + pi->offset; + end = pi->last_sector; + size = end - start + 1; + if ((start/(sectors*heads)) > 1023) + start = heads*sectors*1024 - 1; + if ((end/(sectors*heads)) > 1023) + end = heads*sectors*1024 - 1; + + ss = start % sectors + 1; + start /= sectors; + sh = start % heads; + sc = start / heads; + + es = end % sectors + 1; + end /= sectors; + eh = end % heads; + ec = end / heads; + } + + 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); +} + + +void print_part_table(void) +{ + int i, j, to_file; + char fname[LINE_LENGTH]; + FILE *fp; + + if (print_only) { + fp = stdout; + to_file = TRUE; + } else { + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter filename or press RETURN to display on screen: "); + + if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) + return; + + if (to_file) { + if ((fp = fopen(fname, "w")) == NULL) { + char errstr[LINE_LENGTH]; + sprintf(errstr, PRINT_OPEN_ERR, fname); + print_warning(errstr); + return; + } + } else { + fp = NULL; + erase(); + move(0, 0); + } + } + + 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"); + + for (i = 0; i < 4; i++) { + for (j = 0; + j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); + j++); + if (j < num_parts) { + print_part_entry(fp, i, &(p_info[j])); + } else if (is_extended(ext_info.id) && ext_info.num == i) { + print_part_entry(fp, i, &ext_info); + } else { + print_part_entry(fp, i, NULL); + } + } + + for (i = 0; i < num_parts; i++) + if (IS_LOGICAL(p_info[i].num)) + print_part_entry(fp, p_info[i].num, &(p_info[i])); + + if (to_file) { + if (!print_only) + fclose(fp); + } else { + menuContinue(); + } +} + +void print_tables(void) +{ + int done = FALSE; + + static struct MenuItem menuFormat[]= + { + { 'r', "Raw", "Print the table using raw data format" }, + { 's', "Sectors", "Print the table ordered by sectors" }, + { 't', "Table", "Just print the partition table" }, + { ESC, "Cancel", "Don't print the table" }, + { 0, NULL, NULL } + }; + + while (!done) + switch ( toupper(menuSimple( menuFormat, 2)) ) { + case 'R': + print_raw_table(); + done = TRUE; + break; + case 'S': + print_p_info(); + done = TRUE; + break; + case 'T': + print_part_table(); + done = TRUE; + break; + case ESC: + done = TRUE; + break; + } +} + +#define END_OF_HELP "EOHS!" +#define NEW_HELP_SCREEN "SNHS!" +void display_help() +{ + char *help_text[] = { + "Help Screen for cfdisk " VERSION, + "", + "This is cfdisk, a curses based disk partitioning programs, which", + "allows you to create, delete and modify partitions on your hard", + "disk drive.", + "", + "Copyright (C) 1994-1998 Kevin E. Martin & aeb", + "", + "Command Meaning", + "------- -------", + " b Toggle bootable flag of the current partition", + " d Delete the current partition", + " g Change cylinders, heads, sectors-per-track parameters", + " WARNING: This option should only be used by people who", + " know what they are doing.", + " h Print this screen", + " m Maximize disk usage of the current partition", + " Note: This may make the partition incompatible with", + " DOS, OS/2, ...", + " n Create new partition from free space", + " p Print partition table to the screen or to a file", + " There are several different formats for the partition", + " that you can choose from:", + " r - Raw data (exactly what would be written to disk)", + " s - Table ordered by sectors", + " t - Table in raw format", + " q Quit program without writing partition table", + " t Change the filesystem type", + " u Change units of the partition size display", + " Rotates through Mb, sectors and cylinders", + " W Write partition table to disk (must enter upper case W)", + " Since this might destroy data on the disk, you must", + " either confirm or deny the write by entering `yes' or", + " `no'", + "Up Arrow Move cursor to the previous partition", + "Down Arrow Move cursor to the next partition", + "CTRL-L Redraws the screen", + " ? Print this screen", + "", + "Note: All of the commands can be entered with either upper or lower", + "case letters (except for Writes).", + END_OF_HELP + }; + + int cur_line = 0; + FILE *fp = NULL; + + erase(); + move(0, 0); + while (strcmp(help_text[cur_line], END_OF_HELP)) + if (!strcmp(help_text[cur_line], NEW_HELP_SCREEN)) { + menuContinue(); + erase(); + move(0, 0); + cur_line++; + } else + fp_printf(fp, "%s\n", help_text[cur_line++]); + + menuContinue(); +} + +int change_geometry(void) +{ + int ret_val = FALSE; + int done = FALSE; + char def[LINE_LENGTH]; + char response[LINE_LENGTH]; + int tmp_val; + + while (!done) { + static struct MenuItem menuGeometry[]= + { + { 'c', "Cylinders", "Change cylinder geometry" }, + { 'h', "Heads", "Change head geometry" }, + { 's', "Sectors", "Change sector geometry" }, + { 'd', "Done", "Done with changing geometry" }, + { 0, NULL, NULL } + }; + move(COMMAND_LINE_Y, COMMAND_LINE_X); + clrtoeol(); + refresh(); + + clear_warning(); + + switch (toupper( menuSimple(menuGeometry, 3) )) { + case 'C': + sprintf(def, "%d", cylinders); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of cylinders: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_CYLINDERS) { + cylinders = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_CYLINDERS); + } + break; + case 'H': + sprintf(def, "%d", heads); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of heads: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_HEADS) { + heads = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_HEADS); + } + break; + case 'S': + sprintf(def, "%d", sectors); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, + "Enter the number of sectors per track: "); + if (get_string(response, LINE_LENGTH, def) > 0) { + tmp_val = atoi(response); + if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { + sectors = tmp_val; + ret_val = TRUE; + } else + print_warning(BAD_SECTORS); + } + break; + case ESC: + case 'D': + done = TRUE; + break; + default: + putchar(BELL); + break; + } + } + + if (ret_val) { + int disk_end = heads*sectors*cylinders-1; + + if (p_info[num_parts-1].last_sector > disk_end) { + while (p_info[num_parts-1].first_sector > disk_end) { + if (p_info[num_parts-1].id == FREE_SPACE || + p_info[num_parts-1].id == UNUSABLE) + remove_part(num_parts-1); + else + del_part(num_parts-1); + } + + p_info[num_parts-1].last_sector = disk_end; + + if (ext_info.last_sector > disk_end) + ext_info.last_sector = disk_end; + } else if (p_info[num_parts-1].last_sector < disk_end) { + if (p_info[num_parts-1].id == FREE_SPACE || + p_info[num_parts-1].id == UNUSABLE) { + p_info[num_parts-1].last_sector = disk_end; + } else { + insert_empty_part(num_parts, + p_info[num_parts-1].last_sector+1, + disk_end); + } + } + + /* Make sure the partitions are correct */ + check_part_info(); + } + + return ret_val; +} + +void change_id(int i) +{ + char id[LINE_LENGTH], def[LINE_LENGTH]; + int num_types = 0; + int num_across, num_down; + int len, new_id = ((p_info[i].id == LINUX) ? LINUX_SWAP : LINUX); + int y_start, y_end; + int j, pos; + + for (num_types = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) + num_types++; + + num_across = COLS/COL_ID_WIDTH; + num_down = (((float)num_types)/num_across + 1); + y_start = COMMAND_LINE_Y - 1 - num_down; + if (y_start > DISK_TABLE_START+cur_part+4) + y_start = DISK_TABLE_START+cur_part+4; + y_end = y_start + num_down - 1; + + for (j = y_start - 1; j <= y_end + 1; j++) { + move(j, 0); + clrtoeol(); + } + + for (pos = 0, j = 1; j < NUM_PART_TYPES; j++) + if (partition_type[j]) { + move(y_start + pos % num_down, (pos/num_down)*COL_ID_WIDTH + 1); + printw("%02X %-16.16s", j, partition_type[j]); + pos++; + } + + sprintf(def, "%02X", new_id); + mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, "Enter filesystem type: "); + if ((len = get_string(id, 2, def)) <= 0 && len != GS_DEFAULT) + return; + + if (len != GS_DEFAULT) { + if (!isxdigit(id[0])) + return; + new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); + if (len == 2) { + if (isxdigit(id[1])) + new_id = new_id*16 + + (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); + else + return; + } + } + + if (new_id == 0) + print_warning(ID_EMPTY); + else if (is_extended(new_id)) + print_warning(ID_EXT); + else + p_info[i].id = new_id; +} + +void draw_partition(int i) +{ + 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); + for (j = 0; j < COLS; j++) + addch(' '); + } + + if (p_info[i].id > 0) { + mvprintw(y, NAME_START, + "%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"); + else + mvprintw(y, FLAGS_START, "Unk(%02X)", p_info[i].flags); + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + addstr(", NC"); + } else { + if (p_info[i].offset != 0) + addstr(", NC"); + } + } else { + if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { + if (p_info[i].offset != sectors) + mvaddstr(y, FLAGS_START, "NC"); + } else { + if (p_info[i].offset != 0) + mvaddstr(y, FLAGS_START, "NC"); + } + } + } + mvaddstr(y, PTYPE_START, + (p_info[i].id == UNUSABLE ? "" : + (IS_LOGICAL(p_info[i].num) ? "Logical" : + (p_info[i].num >= 0 ? "Primary" : + (p_info[i].num == PRI_OR_LOG ? "Pri/Log" : + (p_info[i].num == PRIMARY ? "Primary" : "Logical")))))); + + t = partition_type_text(i); + if (t) + mvaddstr(y, FSTYPE_START, t); + else + mvprintw(y, FSTYPE_START, "Unknown (%02X)", p_info[i].id); + + 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; + if (display_units == SECTORS) + mvprintw(y, SIZE_START, "%9d", size); + else if (display_units == CYLINDERS) + mvprintw(y, SIZE_START, "%9d", size/(sectors*heads)); + else + mvprintw(y, SIZE_START, "%9.2f", ceiling(size/20.48)/100); + if (((size/(sectors*heads)) != ceiling(size/(sectors*(float)heads))) || + ((p_info[i].first_sector/(sectors*heads)) != + ceiling(p_info[i].first_sector/(sectors*heads)))) + mvprintw(y, COLUMNS-1, "*"); +} + +void init_const(void) +{ + if (!defined) { + NAME_START = (((float)NAME_START)/COLUMNS)*COLS; + 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; + + COMMAND_LINE_Y = LINES - 4; + WARNING_START = LINES - 2; + + if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) + NUM_ON_SCREEN = 1; + + COLUMNS = COLS; + defined = TRUE; + } +} + +void draw_screen(void) +{ + int i; + char *line; + + line = (char *)malloc((COLS+1)*sizeof(char)); + + if (warning_last_time) { + for (i = 0; i < COLS; i++) { + move(WARNING_START, i); + line[i] = inch(); + } + line[COLS] = 0; + } + + erase(); + + if (warning_last_time) + mvaddstr(WARNING_START, 0, line); + + + sprintf(line, "cfdisk %s", VERSION); + mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); + sprintf(line, "Disk Drive: %s", disk_device); + mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); + sprintf(line, "Heads: %d Sectors per Track: %d Cylinders: %d", + heads, sectors, cylinders); + mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); + + mvaddstr(DISK_TABLE_START, NAME_START, "Name"); + mvaddstr(DISK_TABLE_START, FLAGS_START, "Flags"); + 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) + mvaddstr(DISK_TABLE_START, SIZE_START, "Cylinders"); + else + mvaddstr(DISK_TABLE_START, SIZE_START, "Size (MB)"); + + move(DISK_TABLE_START+1, 1); + for (i = 1; i < COLS-1; i++) + addch('-'); + + if (NUM_ON_SCREEN >= num_parts) + for (i = 0; i < num_parts; i++) + draw_partition(i); + else + for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; + i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && + i < num_parts; + i++) + draw_partition(i); + + free(line); +} + +int draw_cursor(int move) +{ + if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) + return -1; + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); + else + draw_partition(cur_part); + + cur_part += move; + + if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) + draw_screen(); + + if (arrow_cursor) + mvaddstr(DISK_TABLE_START + cur_part + 2 + - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); + else { + standout(); + draw_partition(cur_part); + standend(); + } + + return 0; +} + +void do_curses_fdisk(void) +{ + int done = FALSE; + char command; + + static struct MenuItem menuMain[]= + { + { 'b', "Bootable", "Toggle bootable flag of the current partition" }, + { 'd', "Delete", "Delete the current partition" }, + { 'g', "Geometry", "Change disk geometry (experts only)" }, + { 'h', "Help", "Print help screen" }, + { 'm', "Maximize", "Maximize disk usage of the current partition (experts only)" }, + { 'n', "New", "Create new partition from free space" }, + { 'p', "Print", "Print partition table to the screen or to a file" }, + { 'q', "Quit", "Quit program without writing partition table" }, + { 't', "Type", "Change the filesystem type (DOS, Linux, OS/2 and so on)" }, + { 'u', "Units", "Change units of the partition size display (MB, sect, cyl)" }, + { 'W', "Write", "Write partition table to disk (this might destroy data)" }, + { 0, NULL, NULL } + }; + curses_started = 1; + initscr(); + init_const(); + + old_SIGINT = signal(SIGINT, die); + old_SIGTERM = signal(SIGTERM, die); +#ifdef DEBUG + signal(SIGINT, old_SIGINT); + signal(SIGTERM, old_SIGTERM); +#endif + + cbreak(); + noecho(); + nonl(); + + fill_p_info(); + + draw_screen(); + + while (!done) { + char *s; + + (void)draw_cursor(0); + + if (p_info[cur_part].id == FREE_SPACE) { + s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else if (p_info[cur_part].id > 0) { + s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } else { + s = ((opentype == O_RDWR) ? "hpquW" : "hpqu"); + command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 8, + s, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); + } + switch ( command ) { + case 'B': + case 'b': + if (p_info[cur_part].id > 0) + p_info[cur_part].flags ^= 0x80; + else + print_warning(NO_FLAGS); + break; + case 'D': + case 'd': + if (p_info[cur_part].id > 0) { + del_part(cur_part); + if (cur_part >= num_parts) + cur_part = num_parts - 1; + draw_screen(); + } else + print_warning(DEL_EMPTY); + break; + case 'G': + case 'g': + if (change_geometry()) + draw_screen(); + break; + case 'M': + case 'm': + if (p_info[cur_part].id > 0) { + if (p_info[cur_part].first_sector == 0 || + IS_LOGICAL(p_info[cur_part].num)) { + if (p_info[cur_part].offset == sectors) + p_info[cur_part].offset = 1; + else + p_info[cur_part].offset = sectors; + draw_screen(); + } else if (p_info[cur_part].offset != 0) + p_info[cur_part].offset = 0; + else + print_warning(MAX_UNMAXABLE); + } else + print_warning(MAX_UNMAXABLE); + break; + case 'N': + case 'n': + if (p_info[cur_part].id == FREE_SPACE) { + new_part(cur_part); + draw_screen(); + } else if (p_info[cur_part].id == UNUSABLE) + print_warning(ADD_UNUSABLE); + else + print_warning(ADD_EXISTS); + break; + case 'P': + case 'p': + print_tables(); + draw_screen(); + break; + case 'Q': + case 'q': + done = TRUE; + break; + case 'T': + case 't': + if (p_info[cur_part].id > 0) { + change_id(cur_part); + draw_screen(); + } else + print_warning(TYPE_EMPTY); + break; + case 'U': + case 'u': + if (display_units == MEGABYTES) + display_units = SECTORS; + else if (display_units == SECTORS) + display_units = CYLINDERS; + else if (display_units == CYLINDERS) + display_units = MEGABYTES; + draw_screen(); + break; + case 'W': + write_part_table(); + break; + case 'H': + case 'h': + case '?': + display_help(); + draw_screen(); + break; + case MENU_UP : /* Up arrow */ + if (!draw_cursor(-1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case MENU_DOWN : /* Down arrow */ + if (!draw_cursor(1)) + command = 0; + else + print_warning(NO_MORE_PARTS); + break; + case REDRAWKEY: + clear(); + draw_screen(); + break; + default: + print_warning(BAD_COMMAND); + putchar(BELL); /* CTRL-G */ + } + } + + die_x(0); +} + +void copyright(void) +{ + fprintf(stderr, "Copyright (C) 1994-1997 Kevin E. Martin & aeb\n"); +} + +void usage(char *prog_name) +{ + fprintf(stderr, "\nUsage:\n"); + fprintf(stderr, "Print version:\n"); + fprintf(stderr, "\t%s -v\n", prog_name); + fprintf(stderr, "Print partition table:\n"); + fprintf(stderr, "\t%s -P {r|s|t} [options] device\n", prog_name); + fprintf(stderr, "Interactive use:\n"); + fprintf(stderr, "\t%s [options] device\n", prog_name); + fprintf(stderr, " +Options: +-a: Use arrow instead of highlighting; +-z: Start with a zero partition table, instead of reading the pt from disk; +-c C -h H -s S: Override the kernel's idea of the number of cylinders, + the number of heads and the number of sectors/track.\n\n"); + + copyright(); +} + +int +main(int argc, char **argv) +{ + int c; + int i, len; + + setlocale(LC_CTYPE, ""); + + while ((c = getopt(argc, argv, "ac:h:s:vzP:")) != EOF) + switch (c) { + case 'a': + arrow_cursor = TRUE; + break; + case 'c': + cylinders = atoi(optarg); + if (cylinders <= 0 || cylinders > MAX_CYLINDERS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_CYLINDERS); + exit(1); + } + break; + case 'h': + heads = atoi(optarg); + if (heads <= 0 || heads > MAX_HEADS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_HEADS); + exit(1); + } + break; + case 's': + sectors = atoi(optarg); + if (sectors <= 0 || sectors > MAX_SECTORS) { + fprintf(stderr, "%s: %s\n", argv[0], BAD_SECTORS); + exit(1); + } + break; + case 'v': + fprintf(stderr, "cfdisk %s\n", VERSION); + copyright(); + exit(0); + case 'z': + zero_table = TRUE; + break; + case 'P': + len = strlen(optarg); + for (i = 0; i < len; i++) { + switch (optarg[i]) { + case 'r': + print_only |= PRINT_RAW_TABLE; + break; + case 's': + print_only |= PRINT_SECTOR_TABLE; + break; + case 't': + print_only |= PRINT_PARTITION_TABLE; + break; + default: + usage(argv[0]); + break; + } + } + break; + default: + usage(argv[0]); + exit(1); + } + + if (argc-optind == 1) + disk_device = argv[optind]; + else if (argc-optind != 0) { + usage(argv[0]); + exit(1); + } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); + + if (print_only) { + fill_p_info(); + if (print_only & PRINT_RAW_TABLE) + print_raw_table(); + if (print_only & PRINT_SECTOR_TABLE) + print_p_info(); + if (print_only & PRINT_PARTITION_TABLE) + print_part_table(); + } else + do_curses_fdisk(); + + return 0; +} diff --git a/fdisk/fdisk.8 b/fdisk/fdisk.8 new file mode 100644 index 000000000..6307b98ec --- /dev/null +++ b/fdisk/fdisk.8 @@ -0,0 +1,223 @@ +.\" 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 "11 June 1998" "Linux 2.0" "Linux Programmer's Manual" +.SH NAME +fdisk \- Partition table manipulator for Linux +.SH SYNOPSIS +.BI "fdisk [\-u] [" device ] +.sp +.BI "fdisk \-l [\-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 +(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: +.br +.nf +.RS +/dev/hda +/dev/hdb +/dev/sda +/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 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. + +An IRIX/SGI type disklabel can describe 16 partitions, +the eleventh of which should be an entire `volume' partition, +while the ninth should be labeled `volume header'. +The volume header will also cover the partition table, i.e., +it starts at block zero and extends by default over five cylinders. +The remaining space in the volume header may be used by header +directory entries. No partitions may overlap with the volume header. +Also do not change its type and make some file system on it, since +you will lose the partition table. Use this type of label only when +working with Linux on IRIX/SGI machines or IRIX/SGI disks under Linux. + +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 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). + +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. + +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" + +The DOS 6.x FORMAT command looks for some information in the first +sector of the data area of the partition, and treats this information +as more reliable than the information in the partition table. DOS +FORMAT expects DOS FDISK to clear the first 512 bytes of the data area +of a partition whenever a size change occurs. DOS FORMAT will look at +this extra information even if the /U flag is given -- we consider +this a bug in DOS FORMAT and DOS FDISK. + +The bottom line is that if you use cfdisk or fdisk to change the size of a +DOS partition table entry, then you must also use +.B dd +to zero the first 512 bytes of that partition before using DOS FORMAT to +format the partition. For example, if you were using cfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting fdisk or cfdisk +and rebooting Linux so that the partition table information is valid) you +would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero +the first 512 bytes of the partition. + +.B BE EXTREMELY CAREFUL +if you use the +.B dd +command, since a small typo can make all of the data on your disk useless. + +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. + +.SH OPTIONS +.TP +.B \-v +Print version number of +.B fdisk +program and exit. +.TP +.B \-l +List the partition tables for +.BR /dev/hd[a-d] , +.BR /dev/sd[a-h] , +.BR /dev/ed[a-d] , +and then exit. +.TP +.B \-u +When listing partition tables, give sizes in sectors instead +of cylinders. +.TP +.BI "\-s " partition +The +.I size +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. +(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 +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 . +.PP +The IRIX/SGI type disklabel is currently not supported by the kernel. +Moreover, IRIX/SGI header directories are not fully supported yet. +.PP +The option `dump partition table to file' is missing. +.\" .SH AUTHORS +.\" A. V. Le Blanc (LeBlanc@mcc.ac.uk) +.\" Bernhard Fastenrath (fasten@informatik.uni-bonn.de) +.\" Jakub Jelinek (jj@sunsite.mff.cuni.cz) +.\" Andreas Neuper (ANeuper@GUUG.de) +.\" and many others. diff --git a/fdisk/fdisk.c b/fdisk/fdisk.c new file mode 100644 index 000000000..8cdc6df84 --- /dev/null +++ b/fdisk/fdisk.c @@ -0,0 +1,2046 @@ +/* fdisk.c -- Partition table manipulator for Linux. + * + * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk) + * + * This program is free software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation: either version 1 or + * (at your option) any later version. + * + * Before Linux version 0.95c, this program requires a kernel patch. + * + * Modified, Tue Feb 2 18:46:49 1993, faith@cs.unc.edu to better support SCSI. + * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support. + * Modified, Sat Mar 6 10:14:12 1993, faith@cs.unc.edu: added more comments. + * Modified, Sat Mar 6 12:25:45 1993, faith@cs.unc.edu: + * Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de + * or mbi@mo.math.nat.tu-bs.de) to fix the following problems: + * 1) Incorrect mapping of head/sector/cylinder to absolute sector + * 2) Odd sector count causes one sector to be lost + * Modified, Sat Mar 6 12:25:52 1993, faith@cs.unc.edu: improved verification. + * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l. + * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug. + * Modified, Wed May 5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr. + * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk: + * more stderr for messages, avoid division by 0, and + * give reboot message only if ioctl(fd, BLKRRPART) fails. + * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu: + * 1) Added support for DOS, OS/2, ... compatibility. We should be able + * use this fdisk to partition our drives for other operating systems. + * 2) Added a print the raw data in the partition table command. + * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu: + * Added/changed a few partition type names to conform to cfdisk. + * (suggested by Sujal, smpatel@wam.umd.edu) + * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open + * devices RDONLY (instead of RDWR). This allows you to + * have the disks as rw-r----- with group disk (and if you + * want is safe to setguid fdisk to disk). + * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu + * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com: + * It's user-interface cleanup time. + * Actual error messages for out-of-bounds values (what a concept!). + * Enable read-only access to partition table for learners. + * Smart defaults for most numeric prompts. + * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801. + * Read partition table twice to avoid kernel bug + * (from Daniel Quinlan ), Tue Sep 26 10:25:28 1995 + * Modified, Sat Jul 1 23:43:16 MET DST 1995, fasten@cs.bonn.edu: + * editor for NetBSD/i386 (and Linux/Alpha?) disklabels. + * 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. + * Fixed for using variable blocksizes (needed by magnet-optical drive-patch) + * (from orschaer@cip.informatik.uni-erlangen.de) + * 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. + * Modified, Sat Oct 3 14:40:17 MET DST 1998, ANeuper@GUUG.de + * Support SGI's partitioning -- an, 980930. + * Do the verify using LBA, not CHS, limits -- aeb, 981206. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include /* for HDIO_GETGEO */ +#include /* for BLKRRPART, BLKGETSIZE */ + +#include "fdisk.h" + +#include "fdisksunlabel.h" +#include "fdisksgilabel.h" +#include "fdiskaixlabel.h" + +#include "../version.h" + +#define hex_val(c) ({ \ + char _c = (c); \ + isdigit(_c) ? _c - '0' : \ + tolower(_c) + 10 - 'a'; \ + }) + + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" +#define LINE_LENGTH 80 +#define offset(b, n) ((struct partition *)((b) + 0x1be + \ + (n) * sizeof(struct partition))) +#define sector(s) ((s) & 0x3f) +#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) + +#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \ + ((h) + heads * cylinder(s,c))) +#define set_hsc(h,s,c,sector) { \ + s = sector % sectors + 1; \ + sector /= sectors; \ + h = sector % heads; \ + sector /= heads; \ + c = sector & 0xff; \ + 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); +} + +/* normally O_RDWR, -l option gives O_RDONLY */ +static int type_open = O_RDWR; + +char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ + *line_ptr, /* interactive input */ + line_buffer[LINE_LENGTH], + changed[MAXIMUM_PARTS], /* marks changed buffers */ + buffer[MAX_SECTOR_SIZE], /* first four partitions */ + *buffers[MAXIMUM_PARTS] /* pointers to buffers */ + = {buffer, buffer, buffer, buffer}; + +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 */ + dos_compatible_flag = ~0, + partitions = 4; /* maximum partition + 1 */ + +uint heads, + sectors, + cylinders, + sector_size = DEFAULT_SECTOR_SIZE, + sector_offset = 1, + display_factor = 1, /* in units/sector */ + unit_flag = 1, + extended_offset = 0, /* offset of link pointers */ + offsets[MAXIMUM_PARTS] = {0, 0, 0, 0}; + +int sun_label = 0; /* looking at sun disklabel */ +int sgi_label = 0; /* looking at sgi disklabel */ +int aix_label = 0; /* looking at aix 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[] = { + {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)"}, + {0x11, "Hidden DOS FAT12"}, + {0x14, "Hidden DOS FAT16"}, + {0x16, "Hidden DOS FAT16 (big)"}, + {0x17, "Hidden OS/2 HPFS or NTFS"}, + {0x40, "Venix 80286"}, + {0x41, "PPC PReP Boot"}, + {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"}, + {0xeb, "BeOS fs"}, + {0xf2, "DOS secondary"}, + {0xff, "BBT"}, /* (bad track table) */ + { 0, NULL } +}; + +jmp_buf listingbuf; + +void fatal(enum failure why) +{ + char error[LINE_LENGTH], + *message = error; + + if (listing) { + close(fd); + longjmp(listingbuf, 1); + } + + switch (why) { + case usage: message = +"Usage: fdisk [-b SSZ] [-u] [DISK] Change partition table\n" +" fdisk -l [-b SSZ] [-u] [DISK] List partition table(s)\n" +" fdisk -s PARTITION Give partition size(s) in blocks\n" +" fdisk -v Give fdisk version\n" +"Here DISK is something like /dev/hdb or /dev/sda\n" +"and PARTITION is something like /dev/hda7\n" +"-u: give Start and End in sector (instead of cylinder) units\n" +"-b 2048: (for certain MO drives) use 2048-byte sectors\n"; + break; + case no_device: + message = "A disk block device is needed.\n"; + break; + case no_partition: + message = "Given name does not refer to a partition,\n" + "or maybe not even to a block device.\n"; + break; + case unable_to_open: + sprintf(error, "Unable to open %s\n", disk_device); + break; + case unable_to_read: + sprintf(error, "Unable to read %s\n", disk_device); + break; + case unable_to_seek: + sprintf(error, "Unable to seek on %s\n", disk_device); + break; + case unable_to_write: + sprintf(error, "Unable to write %s\n", disk_device); + break; + case out_of_memory: + message = "Unable to allocate any more memory\n"; + break; + default: message = "Fatal error\n"; + } + + fputc('\n', stderr); + fputs(message, stderr); + exit(1); +} + +void menu(void) +{ + 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 if(sgi_label) + puts("Command action\n" + " a select bootable partition\n" /* sgi flavour */ + " b edit bootfile entry\n" /* sgi */ + " c select sgi swap partition\n" /* sgi flavour */ + " 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" + " u change display/entry units\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + ); + else if(aix_label) + puts("Command action\n" + " m print this menu\n" + " o create a new empty DOS partition table\n" + " q quit without saving changes\n" + ); + else + puts("Command action\n" + " a toggle a bootable flag\n" + " 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" + " 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)" + ); +} + +void xmenu(void) +{ + 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" /* !sun */ + " g create an IRIX partition table\n" /* sgi */ + " h change number of heads\n" + " 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" + ); +} + +int +get_sysid(int i) { + return ( + sun_label ? sunlabel->infos[i].id : + sgi_label ? sgi_get_sysid(i) : part_table[i]->sys_ind); +} + +struct systypes * +get_sys_types(void) { + return ( + sun_label ? sun_sys_types : + sgi_label ? sgi_sys_types : sys_types); +} + +char *partition_type(unsigned char type) +{ + int i; + struct systypes *types = get_sys_types(); + + for (i=0; types[i].name; i++) + if (types[i].index == type) + return types[i].name; + + return NULL; +} + +void list_types(struct systypes *sys) +{ + 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; + + do { + printf("%c%2x %-15.15s", i ? ' ' : '\n', + sys[next].index, sys[next].name); + next = last[i++] + done; + if (i > 3 || next >= last[i]) { + i = 0; + next = ++done; + } + } while (done < last[0]); + putchar('\n'); +} + +void clear_partition(struct partition *p) +{ + p->boot_ind = 0; + p->head = 0; + p->sector = 0; + p->cyl = 0; + p->sys_ind = 0; + p->end_head = 0; + p->end_sector = 0; + p->end_cyl = 0; + set_start_sect(p,0); + set_nr_sects(p,0); +} + +void set_partition(int i, struct partition *p, uint start, uint stop, + int sysid, uint offset) +{ + p->boot_ind = 0; + 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); + if (dos_compatible_flag && (stop/(sectors*heads) > 1023)) + stop = heads*sectors*1024 - 1; + set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); + changed[i] = 1; +} + +int test_c(char **m, char *mesg) +{ + int val = 0; + if (!*m) + fprintf(stderr, "You must set"); + else { + fprintf(stderr, " %s", *m); + val = 1; + } + *m = mesg; + return val; +} + +int warn_geometry(void) +{ + char *m = NULL; + int prev = 0; + if (!heads) + prev = test_c(&m, "heads"); + if (!sectors) + prev = test_c(&m, "sectors"); + if (!cylinders) + prev = test_c(&m, "cylinders"); + if (!m) + return 0; + fprintf(stderr, + "%s%s.\nYou can do this from the extra functions menu.\n", + prev ? " and " : " ", m); + return 1; +} + +void update_units(void) +{ + int cyl_units = heads * sectors; + + if (unit_flag && cyl_units) + display_factor = cyl_units; + else + display_factor = 1; /* in sectors */ +} + +void warn_cylinders(void) +{ + if (!sun_label && !sgi_label && cylinders > 1024 && !nowarn) + fprintf(stderr, "\n\ +The number of cylinders for this disk is set to %d.\n\ +There is nothing wrong with that, but this is larger than 1024,\n\ +and could in certain setups cause problems with:\n\ +1) software that runs at boot time (e.g., LILO)\n\ +2) booting and partitioning software from other OSs\n\ + (e.g., DOS FDISK, OS/2 FDISK)\n", + cylinders); +} + +void read_extended(struct partition *p) +{ + int i; + struct partition *q; + + ext_pointers[ext_index] = part_table[ext_index]; + if (!get_start_sect(p)) + fprintf(stderr, "Bad offset in primary extended partition\n"); + else while (IS_EXTENDED (p->sys_ind)) { + if (partitions >= MAXIMUM_PARTS) { + fprintf(stderr, + "Warning: deleting partitions after %d\n", + partitions); + clear_partition(ext_pointers[partitions - 1]); + changed[partitions - 1] = 1; + return; + } + offsets[partitions] = extended_offset + get_start_sect(p); + if (!extended_offset) + extended_offset = get_start_sect(p); + if (ext2_llseek(fd, (ext2_loff_t)offsets[partitions] + * sector_size, SEEK_SET) < 0) + fatal(unable_to_seek); + if (!(buffers[partitions] = (char *) malloc(sector_size))) + fatal(out_of_memory); + if (sector_size != read(fd, buffers[partitions], sector_size)) + fatal(unable_to_read); + part_table[partitions] = ext_pointers[partitions] = NULL; + q = p = offset(buffers[partitions], 0); + for (i = 0; i < 4; i++, p++) { + if (IS_EXTENDED (p->sys_ind)) { + if (ext_pointers[partitions]) + fprintf(stderr, "Warning: extra link " + "pointer in partition table " + "%d\n", partitions + 1); + else + ext_pointers[partitions] = p; + } else if (p->sys_ind) { + if (part_table[partitions]) + fprintf(stderr, + "Warning: ignoring extra data " + "in partition table %d\n", + partitions + 1); + else + part_table[partitions] = p; + } + } + if (!part_table[partitions]) { + if (q != ext_pointers[partitions]) + part_table[partitions] = q; + else part_table[partitions] = q + 1; + } + if (!ext_pointers[partitions]) { + if (q != part_table[partitions]) + ext_pointers[partitions] = q; + else ext_pointers[partitions] = q + 1; + } + p = ext_pointers[partitions++]; + } +} + +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"); + + sun_nolabel(); /* otherwise always recognised as sun */ + sgi_nolabel(); /* otherwise always recognised as sgi */ + + 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, sec_fac; + struct hd_geometry geometry; + + partitions = 4; + sec_fac = sector_size / 512; + + 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"); + } + + guess_device_type(fd); + + if (sector_size != read(fd, buffer, sector_size)) + fatal(unable_to_read); + +#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; + cylinders /= sec_fac; /* do not round up */ + if (dos_compatible_flag) + sector_offset = sectors; + } else { + if (!ioctl(fd, BLKGETSIZE, §ors)) { + heads = 1; + cylinders = 1; + sectors /= sec_fac; + } else { + heads = cylinders = sectors = 0; + } + } + update_units(); + +got_table: + + if (check_sun_label()) + return 0; + + if (check_sgi_label()) + return 0; + + if (check_aix_label()) + return 0; + + if (!valid_part_table_flag(buffer)) { + switch(what) { + case fdisk: + fprintf(stderr, + "Device contains neither a valid DOS partition" + " table, nor Sun or SGI 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(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 (!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 0; +} + +/* read line; return 0 or first char */ +int +read_line(void) +{ + line_ptr = line_buffer; + if (!fgets(line_buffer, LINE_LENGTH, stdin)) + return 0; + while (*line_ptr && !isgraph(*line_ptr)) + line_ptr++; + return *line_ptr; +} + +char +read_char(char *mesg) +{ + do { + fputs(mesg, stdout); + } while (!read_line()); + return *line_ptr; +} + +char +read_chars(char *mesg) +{ + fputs(mesg, stdout); + if (!read_line()) { + *line_ptr = '\n'; + line_ptr[1] = 0; + } + return *line_ptr; +} + +int +read_hex(struct systypes *sys) +{ + int hex; + + while (1) + { + read_char("Hex code (type L to list codes): "); + if (tolower(*line_ptr) == 'l') + list_types(sys); + else if (isxdigit (*line_ptr)) + { + hex = 0; + do + hex = hex << 4 | hex_val(*line_ptr++); + while (isxdigit(*line_ptr)); + return hex; + } + } +} + +/* + * Print the message MESG, then read an integer between LOW and HIGH. + * If the user hits Enter, DFLT is returned. + * Answers like +10 are interpreted as offsets from BASE. + * + * There is no default if DFLT is not between LOW and HIGH. + */ +uint +read_int(uint low, uint dflt, uint high, uint base, char *mesg) +{ + uint i; + int default_ok = 1; + static char *ms = NULL; + static int mslen = 0; + + if (!ms || strlen(mesg)+50 > mslen) { + mslen = strlen(mesg)+100; + if (!(ms = realloc(ms,mslen))) + fatal(out_of_memory); + } + + if (dflt < low || dflt > high) + default_ok = 0; + + if (default_ok) + sprintf(ms, "%s (%d-%d, default %d): ", mesg, low, high, dflt); + else + sprintf(ms, "%s (%d-%d): ", mesg, low, high); + + while (1) { + int use_default = default_ok; + + /* ask question and read answer */ + while (read_chars(ms) != '\n' && !isdigit(*line_ptr) + && *line_ptr != '-' && *line_ptr != '+') + continue; + + if (*line_ptr == '+' || *line_ptr == '-') { + i = atoi(line_ptr+1); + if (*line_ptr == '-') + i = -i; + while (isdigit(*++line_ptr)) + use_default = 0; + switch (*line_ptr) { + case 'c': + case 'C': + if (!unit_flag) + i *= heads * sectors; + break; + case 'k': + case 'K': + i *= 2; + i /= (sector_size / 512); + i /= display_factor; + break; + case 'm': + case 'M': + i *= 2048; + i /= (sector_size / 512); + i /= display_factor; + break; + case 'g': + case 'G': + i *= 2048000; + i /= (sector_size / 512); + i /= display_factor; + break; + default: + break; + } + i += base; + } else { + i = atoi(line_ptr); + while (isdigit(*line_ptr)) { + line_ptr++; + use_default = 0; + } + } + if (use_default) + printf("Using default value %d\n", i = dflt); + if (i >= low && i <= high) + break; + else + printf("Value out of range.\n"); + } + return i; +} + +int get_partition(int warn, int max) +{ + int i = read_int(1, 0, max, 0, "Partition number") - 1; + + if (warn && ( + (!sun_label && !sgi_label && !part_table[i]->sys_ind) + || (sun_label && + (!sunlabel->partitions[i].num_sectors || + !sunlabel->infos[i].id)) + || (sgi_label && (!sgi_get_num_sectors(i))) + )) fprintf(stderr, "Warning: partition %d has empty type\n", i+1); + return i; +} + +char *const str_units(void) +{ + return unit_flag ? "cylinder" : "sector"; +} + +void change_units(void) +{ + if ((unit_flag = !unit_flag)) + display_factor = 1; + else display_factor = heads * sectors; + update_units(); + printf("Changing display/entry units to %ss\n", + str_units()); +} + +void toggle_active(int i) +{ + struct partition *p = part_table[i]; + + if (IS_EXTENDED (p->sys_ind) && !p->boot_ind) + fprintf(stderr, + "WARNING: Partition %d is an extended partition\n", + i + 1); + if (p->boot_ind) + p->boot_ind = 0; + else p->boot_ind = ACTIVE_FLAG; + changed[i] = 1; +} + +void toggle_dos(void) +{ + dos_compatible_flag = ~dos_compatible_flag; + printf("DOS Compatibility flag is "); + if (dos_compatible_flag) + sector_offset = sectors; + else { + sector_offset = 1; + printf("not "); + } + printf("set\n"); +} + +void delete_partition(int i) +{ + struct partition *p = part_table[i], *q = ext_pointers[i]; + +/* Note that for the fifth partition (i == 4) we don't actually + * decrement partitions. + */ + + if (warn_geometry()) + return; + changed[i] = 1; + + if (sun_label) { + sun_delete_partition(i); + return; + } + if (sgi_label) { + sgi_delete_partition(i); + return; + } + if (i < 4) { + if (IS_EXTENDED (p->sys_ind) && i == ext_index) { + while (partitions > 4) + free(buffers[--partitions]); + ext_pointers[ext_index] = NULL; + extended_offset = 0; + } + clear_partition(p); + } + else if (!q->sys_ind && i > 4) { + free(buffers[--partitions]); + clear_partition(ext_pointers[--i]); + } + else if (i > 3) { + if (i > 4) { + p = ext_pointers[i - 1]; + p->boot_ind = 0; + p->head = q->head; + p->sector = q->sector; + p->cyl = q->cyl; + p->sys_ind = EXTENDED; + p->end_head = q->end_head; + p->end_sector = q->end_sector; + p->end_cyl = q->end_cyl; + 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 */ + set_start_sect(part_table[5], + get_start_sect(part_table[5]) + + offsets[5] - extended_offset); + offsets[5] = extended_offset; + changed[5] = 1; + } + if (partitions > 5) { + partitions--; + free(buffers[i]); + while (i < partitions) { + changed[i] = changed[i + 1]; + buffers[i] = buffers[i + 1]; + offsets[i] = offsets[i + 1]; + part_table[i] = part_table[i + 1]; + ext_pointers[i] = ext_pointers[i + 1]; + i++; + } + } + else + clear_partition(part_table[i]); + } +} + +void change_sysid(void) +{ + char *temp; + int i = get_partition(0, partitions), sys, origsys; + struct partition *p = part_table[i]; + + origsys = sys = get_sysid(i); + + if (!sys && !sgi_label) + printf("Partition %d does not exist yet!\n", i + 1); + else while (1) { + sys = read_hex (get_sys_types()); + + if (!sys && !sgi_label) { + printf("Type 0 means free space to many systems\n" + "(but not to Linux). Having partitions of\n" + "type 0 is probably unwise. You can delete\n" + "a partition using the `d' command.\n"); + /* break; */ + } + + if (!sun_label && !sgi_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 (sys < 256) { + 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\n"); + if (sgi_label && ((i == 10 && sys != ENTIRE_DISK) + || (i == 8 && sys != 0))) + printf("Consider leaving partition 9 " + "as volume header (0),\nand " + "partition 11 as entire volume (6)" + "as IRIX expects it.\n\n"); + if (sys == origsys) + break; + + if (sun_label) { + sun_change_sysid(i, sys); + } else + if (sgi_label) { + sgi_change_sysid(i, sys); + } else + 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, + * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, + * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. + * Lubkin Oct. 1991). */ + +static void long2chs(ulong ls, uint *c, uint *h, uint *s) +{ + int spc = heads * sectors; + + *c = ls / spc; + ls = ls % spc; + *h = ls / sectors; + *s = ls % sectors + 1; /* sectors count from 1 */ +} + +static void check_consistency(struct partition *p, int partition) +{ + uint pbc, pbh, pbs; /* physical beginning c, h, s */ + uint pec, peh, pes; /* physical ending c, h, s */ + uint lbc, lbh, lbs; /* logical beginning c, h, s */ + uint lec, leh, les; /* logical ending c, h, s */ + + if (!heads || !sectors || (partition >= 4)) + return; /* do not check extended partitions */ + +/* physical beginning c, h, s */ + pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300); + pbh = p->head; + pbs = p->sector & 0x3f; + +/* physical ending c, h, s */ + pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300); + peh = p->end_head; + pes = p->end_sector & 0x3f; + +/* compute logical beginning (c, h, s) */ + long2chs(get_start_sect(p), &lbc, &lbh, &lbs); + +/* compute logical ending (c, h, s) */ + 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)) { + printf("Partition %d has different physical/logical " + "beginnings (non-Linux?):\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); + printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs); + } + +/* Same physical / logical ending? */ + if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { + printf("Partition %d has different physical/logical " + "endings:\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pec, peh, pes); + printf("logical=(%d, %d, %d)\n",lec, leh, les); + } + +#if 0 +/* Beginning on cylinder boundary? */ + if (pbh != !pbc || pbs != 1) { + printf("Partition %i does not start on cylinder " + "boundary:\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); + printf("should be (%d, %d, 1)\n", pbc, !pbc); + } +#endif + +/* Ending on cylinder boundary? */ + if (peh != (heads - 1) || pes != sectors) { + printf("Partition %i does not end on cylinder boundary:\n", + partition + 1); + printf(" phys=(%d, %d, %d) ", pec, peh, pes); + printf("should be (%d, %d, %d)\n", + pec, heads - 1, sectors); + } +} + +void list_disk_geometry(void) +{ + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = " + "%ss of %d * %d bytes\n\n", disk_device, heads, sectors, + cylinders, str_units(), display_factor, sector_size); +} + +void list_table(int xtra) +{ + struct partition *p; + char *type; + int digit_last = 0; + int i, w; + + if (sun_label) { + sun_list_table(xtra); + return; + } + + if (sgi_label) { + sgi_list_table(xtra); + return; + } + + w = strlen(disk_device); + /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3, + but if the device name ends in a digit, say /dev/foo1, + then the partition is called /dev/foo1p3. */ + if (isdigit(disk_device[w-1])) + digit_last = 1; + + list_disk_geometry(); + + if (w < 5) + w = 5; + printf("%*s Boot Start End Blocks Id System\n", + (digit_last ? w + 2 : w + 1), "Device"); + + for (i = 0 ; i < partitions; i++) { + if ((p = part_table[i])->sys_ind) { + unsigned int psects = get_nr_sects(p); + unsigned int pblocks = psects; + unsigned int podd = 0; + + if (sector_size < 1024) { + pblocks /= (1024 / sector_size); + podd = psects % (1024 / sector_size); + } + if (sector_size > 1024) + pblocks *= (sector_size / 1024); + printf( + "%*s%s%-2d %c %9ld %9ld %9ld%c %2x %s\n", +/* device */ w, disk_device, (digit_last ? "p" : ""), i+1, +/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG + ? '*' : '?', +/* start */ (long) cround(get_start_sect(p) + offsets[i]), +/* end */ (long) cround(get_start_sect(p) + offsets[i] + psects + - (psects ? 1 : 0)), +/* odd flag on end */ (long) pblocks, podd ? '+' : ' ', +/* 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) +{ + struct partition *p, **q; + int i; + + if (extend) + q = ext_pointers; + else + q = part_table; + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n", + disk_device, heads, sectors, cylinders); + printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); + for (i = 0 ; i < partitions; i++) + if ((p = q[i]) != NULL) { + printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n", + i + 1, p->boot_ind, p->head, + sector(p->sector), + cylinder(p->sector, p->cyl), p->end_head, + sector(p->end_sector), + cylinder(p->end_sector, p->end_cyl), + get_start_sect(p), get_nr_sects(p), p->sys_ind); + if (p->sys_ind) + check_consistency(p, i); + } +} + +void fill_bounds(uint *first, uint *last) +{ + int i; + struct partition *p = part_table[0]; + + for (i = 0; i < partitions; p = part_table[++i]) { + if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) { + first[i] = 0xffffffff; + last[i] = 0; + } else { + first[i] = get_start_sect(p) + offsets[i]; + last[i] = first[i] + get_nr_sects(p) - 1; + } + } +} + +void check(int n, uint h, uint s, uint c, uint start) +{ + uint total, real_s, real_c; + + real_s = sector(s) - 1; + real_c = cylinder(s, c); + total = (real_c * sectors + real_s) * heads + h; + if (!total) + fprintf(stderr, "Warning: partition %d contains sector 0\n", n); + if (h >= heads) + fprintf(stderr, + "Partition %d: head %d greater than maximum %d\n", + n, h + 1, heads); + if (real_s >= sectors) + fprintf(stderr, "Partition %d: sector %d greater than " + "maximum %d\n", n, s, sectors); + if (real_c >= cylinders) + fprintf(stderr, "Partitions %d: cylinder %d greater than " + "maximum %d\n", n, real_c + 1, cylinders); + if (cylinders <= 1024 && start != total) + fprintf(stderr, + "Partition %d: previous sectors %d disagrees with " + "total %d\n", n, start, total); +} + + +void verify(void) +{ + int i, j; + uint total = 1; + uint first[partitions], last[partitions]; + struct partition *p = part_table[0]; + + if (warn_geometry()) + return; + + if (sun_label) { + verify_sun(); + return; + } + + if (sgi_label) { + verify_sgi(1); + return; + } + + fill_bounds(first, last); + for (i = 0; i < partitions; p = part_table[++i]) + if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) { + check_consistency(p, 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, + last[i]); + total += last[i] + 1 - first[i]; + for (j = 0; j < i; j++) + if ((first[i] >= first[j] && first[i] <= last[j]) + || ((last[i] <= last[j] && last[i] >= first[j]))) { + printf("Warning: partition %d overlaps " + "partition %d.\n", j + 1, i + 1); + total += first[i] >= first[j] ? + first[i] : first[j]; + total -= last[i] <= last[j] ? + last[i] : last[j]; + } + } + + if (extended_offset) { + 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]) { + total++; + if (!p->sys_ind) { + if (i != 4 || i + 1 < partitions) + printf("Warning: partition %d " + "is empty\n", i + 1); + } + else if (first[i] < extended_offset || + last[i] > e_last) + printf("Logical partition %d not entirely in " + "partition %d\n", i + 1, ext_index + 1); + } + } + + if (total > heads * sectors * cylinders) + printf("Total allocated sectors %d greater than the maximum " + "%d\n", total, heads * sectors * cylinders); + else if ((total = heads * sectors * cylinders - total) != 0) + printf("%d unallocated sectors\n", total); +} + +void add_partition(int n, int sys) +{ + char mesg[48]; + int i, read = 0; + struct partition *p = part_table[n], *q = part_table[ext_index]; + uint start, stop = 0, limit, temp, + first[partitions], last[partitions]; + + if (p->sys_ind) { + printf("Partition %d is already defined. Delete " + "it before re-adding it.\n", n + 1); + return; + } + fill_bounds(first, last); + if (n < 4) { + start = sector_offset; + limit = heads * sectors * cylinders - 1; + if (extended_offset) { + first[ext_index] = extended_offset; + last[ext_index] = get_start_sect(q) + + get_nr_sects(q) - 1; + } + } else { + start = extended_offset + sector_offset; + limit = get_start_sect(q) + get_nr_sects(q) - 1; + } + if (unit_flag) + for (i = 0; i < partitions; i++) + first[i] = (cround(first[i]) - 1) * display_factor; + + sprintf(mesg, "First %s", str_units()); + do { + temp = start; + for (i = 0; i < partitions; i++) { + int lastplusoff; + + if (start == offsets[i]) + start += 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+display_factor && read) { + printf("Sector %d is already allocated\n", temp); + temp = start; + read = 0; + } + if (!read && start == temp) { + uint i; + i = start; + start = read_int(cround(i), cround(i), cround(limit), + 0, mesg); + if (unit_flag) { + start = (start - 1) * display_factor; + if (start < i) start = i; + } + read = 1; + } + } while (start != temp || !read); + if (n > 4) /* NOT for fifth partition */ + offsets[n] = start - sector_offset; + + for (i = 0; i < partitions; i++) { + if (start < offsets[i] && limit >= offsets[i]) + limit = offsets[i] - 1; + if (start < first[i] && limit >= first[i]) + limit = first[i] - 1; + } + if (start > limit) { + printf("No free sectors available\n"); + if (n > 4) { + free(buffers[n]); + partitions--; + } + return; + } + if (cround(start) == cround(limit)) + stop = start; + else { + sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", + str_units()); + stop = read_int(cround(start), cround(limit), cround(limit), + cround(start), mesg); + if (unit_flag) { + stop = stop * display_factor - 1; + if (stop >limit) + stop = limit; + } + } + + set_partition(n, p, start, stop, sys, offsets[n]); + + if (IS_EXTENDED (sys)) { + ext_index = n; + offsets[4] = extended_offset = start; + ext_pointers[n] = p; + if (!(buffers[4] = calloc(1, sector_size))) + fatal(out_of_memory); + part_table[4] = offset(buffers[4], 0); + ext_pointers[4] = part_table[4] + 1; + changed[4] = 1; + partitions = 5; + } + else { + if (n > 4) + set_partition(n - 1, ext_pointers[n - 1], + start - sector_offset, stop, EXTENDED, + extended_offset); +#if 0 + if ((limit = get_nr_sects(p)) & 1) + printf("Warning: partition %d has an odd " + "number of sectors.\n", n + 1); +#endif + } +} + +void add_logical(void) +{ + if (partitions > 5 || part_table[4]->sys_ind) { + if (!(buffers[partitions] = calloc(1, sector_size))) + fatal(out_of_memory); + part_table[partitions] = offset(buffers[partitions], 0); + ext_pointers[partitions] = part_table[partitions] + 1; + offsets[partitions] = 0; + partitions++; + } + add_partition(partitions - 1, LINUX_NATIVE); +} + +void new_partition(void) +{ + int i, free_primary = 0; + + if (warn_geometry()) + return; + + if (sun_label) { + add_sun_partition(get_partition(0, partitions), LINUX_NATIVE); + return; + } + + if (sgi_label) { + sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE); + return; + } + + if (partitions >= MAXIMUM_PARTS) { + printf("The maximum number of partitions has been created\n"); + return; + } + + for (i = 0; i < 4; i++) + free_primary += !part_table[i]->sys_ind; + if (!free_primary) { + if (extended_offset) + add_logical(); + else + printf("You must delete some partition and add " + "an extended partition first\n"); + } else { + char c, line[LINE_LENGTH]; + sprintf(line, "Command action\n %s\n p primary " + "partition (1-4)\n", extended_offset ? + "l logical (5 or over)" : "e extended"); + while (1) + if ((c = tolower(read_char(line))) == 'p') { + add_partition(get_partition(0, 4), + LINUX_NATIVE); + return; + } + else if (c == 'l' && extended_offset) { + add_logical(); + return; + } + else if (c == 'e' && !extended_offset) { + add_partition(get_partition(0, 4), + EXTENDED); + return; + } + else + printf("Invalid partition number " + "for type `%c'\n", c); + + } +} + +void write_table(void) +{ + int i, error = 0; + + changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; + if (!sun_label && !sgi_label) { + for (i = 3; i < partitions; i++) { + if (changed[i]) { + 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 (sgi_label) { + /* no test on change? the printf below might be mistaken */ + sgi_write_table(); + } else if (sun_label) { + if (changed[3] || changed[4] || changed[5] || + changed[6] || changed[7]) { + sun_write_table(); + } + } + + printf("The partition table has been altered!\n\n"); + + printf("Calling ioctl() to re-read partition table.\n"); + sync(); + sleep(2); + if ((i = ioctl(fd, BLKRRPART)) != 0) { + error = errno; + } else { + /* some kernel versions (1.2.x) seem to have trouble + rereading the partition table, but if asked to do it + twice, the second time works. - biro@yggdrasil.com */ + sync(); + sleep(2); + if((i = ioctl(fd, BLKRRPART)) != 0) + error = errno; + } + + close(fd); + + printf("Syncing disks.\n"); + sync(); + sleep(4); /* for sync() */ + + if (i < 0) + printf("Re-read table failed with error %d: %s.\nReboot your " + "system to ensure the partition table is updated.\n", + error, strerror(error)); + + if (!sun_label && !sgi_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"); + + exit(0); +} + +#define MAX_PER_LINE 16 +void print_buffer(char buffer[]) +{ + int i, + l; + + for (i = 0, l = 0; i < sector_size; i++, l++) { + if (l == 0) + printf("0x%03X:", i); + printf(" %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + printf("\n"); + l = -1; + } + } + if (l > 0) + printf("\n"); + printf("\n"); +} + +void print_raw(void) +{ + int i; + + printf("Device: %s\n", disk_device); + if (sun_label || sgi_label) + print_buffer(buffer); + else for (i = 3; i < partitions; i++) + print_buffer(buffers[i]); +} + +void move_begin(int i) +{ + struct partition *p = part_table[i]; + uint new, first; + + if (warn_geometry()) + return; + 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 = get_start_sect(p) + offsets[i]; + new = read_int(first, first, + get_start_sect(p) + get_nr_sects(p) + offsets[i] - 1, + first, "New beginning of data") - offsets[i]; + + 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; + } +} + +void xselect(void) +{ + while(1) { + putchar('\n'); + switch (tolower(read_char("Expert command (m for help): "))) { + case 'a': + if (sun_label) + sun_set_alt_cyl(); + break; + case 'b': + if (!sun_label && !sgi_label) + move_begin(get_partition(0, partitions)); + break; + case 'c': + cylinders = read_int(1, cylinders, 65535, + 0, "Number of cylinders"); + if (sun_label) + sun_set_ncyl(cylinders); + warn_cylinders(); + break; + case 'd': + print_raw(); + break; + case 'e': + if (sgi_label) + sgi_set_xcyl(); + else if (sun_label) + sun_set_xcyl(); + else + x_list_table(1); + break; + case 'g': + create_sgilabel(); + break; + case 'h': + heads = read_int(1, heads, 256, 0, + "Number of heads"); + update_units(); + break; + case 'i': + if (sun_label) + sun_set_ilfact(); + break; + case 'o': + if (sun_label) + sun_set_rspeed(); + break; + case 'p': + if (sun_label) + list_table(1); + else + x_list_table(0); + break; + case 'q': + close(fd); + exit(0); + case 'r': + return; + case 's': + sectors = read_int(1, sectors, 63, 0, + "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; + case 'y': + if (sun_label) + sun_set_pcylcount(); + break; + default: + xmenu(); + } + } +} + +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; + + if (strncmp("/dev/hd", device, 7)) + return 0; + 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(try_only) < 0) { + list_disk_geometry(); + if (btrydev(device) < 0) + fprintf(stderr, + "Disk %s doesn't contain a valid " + "partition table\n", device); + close(fd); + } else { + close(fd); + list_table(0); + if (!sun_label && partitions > 4) + delete_partition(ext_index); + } + } else { + /* Ignore other errors, since we try IDE + and SCSI hard disks which may not be + installed on the system. */ + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + return; + } + } + } +} + +void +dummy(int *kk) {} + +int +main(int argc, char **argv) +{ + int i, j, s, c; + int optl = 0, opts = 0; + char *part; + + + /* + * Calls: + * fdisk -v + * fdisk -l [-b sectorsize] [-u] [device] ... + * fdisk -s [partition] ... + * fdisk [-b sectorsize] [-u] [device] + */ + while ((c = getopt(argc, argv, "b:lsuv")) != EOF) { + switch (c) { + case 'b': + sector_size = atoi(optarg); + if (sector_size != 512 && sector_size != 1024 && + sector_size != 2048) + fatal(usage); + sector_offset = 2; + break; + case 'l': + optl = 1; + break; + case 's': + opts = 1; + break; + case 'u': + unit_flag = 0; + break; + case 'v': + printf("fdisk v" UTIL_LINUX_VERSION "\n"); + exit(0); + default: + fatal(usage); + } + } + + if (optl) { + listing = 1; + nowarn = 1; + type_open = O_RDONLY; + if (argc > optind) { + int k; + /* avoid gcc warning: + variable `k' might be clobbered by `longjmp' */ + dummy(&k); + for(k=optind; k= partitions) + exit(1); +#if defined(sparc) + if (!sun_label) { + int id = sunlabel->infos[i].id; + + if (!(id > 1 && id != WHOLE_DISK)) + exit(1); + s = get_num_sectors(sunlabel->partitions[i]); + } else +#endif + s = get_nr_sects(part_table[i]); + if (opts == 1) + printf("%d\n", s/2); + else + printf("%s: %d\n", argv[j], s/2); + } + exit(0); + } + + if (argc-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(fdisk); + + while (1) { + putchar('\n'); + switch (tolower(read_char("Command (m for help): "))) { + case 'a': + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x01); + else + if (sgi_label) + sgi_set_bootpartition( + get_partition(1, partitions)); + else + toggle_active(get_partition(1, partitions)); + break; + case 'b': + if (sgi_label) { + printf("\nThe current boot file is: %s\n", + sgi_get_bootfile()); + if (read_chars("Please enter the name of the " + "new boot file: ") == '\n') + printf("Boot file unchanged\n"); + else + sgi_set_bootfile(line_ptr); + } else + bselect(); + break; + case 'c': + if (sun_label) + toggle_sunflags(get_partition(1, partitions), + 0x10); + else + if (sgi_label) + sgi_set_swappartition( + get_partition(1, partitions)); + else + toggle_dos(); + break; + case 'd': + delete_partition( + get_partition(1, partitions)); + break; + case 'i': + if (sgi_label) + create_sgiinfo(); + else + menu(); + case 'l': + list_types(get_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); + case 's': + create_sunlabel(); + break; + case 't': + change_sysid(); + break; + case 'u': + change_units(); + break; + case 'v': + verify(); + break; + case 'w': + write_table(); /* does not return */ + break; + case 'x': + if( sgi_label ) { + fprintf(stderr, + "\n\tSorry, no experts menu for SGI " + "partition tables available.\n\n"); + } else + xselect(); + break; + default: menu(); + } + } + return 0; +} diff --git a/fdisk/fdisk.h b/fdisk/fdisk.h new file mode 100644 index 000000000..080515e5f --- /dev/null +++ b/fdisk/fdisk.h @@ -0,0 +1,85 @@ +/* + fdisk.h +*/ + +#define DEFAULT_SECTOR_SIZE 512 +#define MAX_SECTOR_SIZE 2048 +#define SECTOR_SIZE 512 /* still used in BSD code */ +#define MAXIMUM_PARTS 60 + +#define ACTIVE_FLAG 0x80 + +#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) + +#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) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +extern ext2_loff_t ext2_llseek(unsigned int fd, + ext2_loff_t offset, + unsigned int origin); + +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned char start4[4]; /* starting sector counting from 0 */ + unsigned char size4[4]; /* nr of sectors in partition */ +}; + +enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, + unable_to_write, out_of_memory, no_partition, no_device}; + +enum action {fdisk, require, try_only, create_empty}; + +struct systypes { + unsigned char index; + char *name; +}; + +/* prototypes for fdisk.c */ +extern char *disk_device, + *line_ptr; +extern int fd, + partitions; +extern uint unit_flag, + display_factor; +extern struct partition *part_table[]; +extern void fatal(enum failure why); +extern int get_boot(enum action what); +extern int get_partition(int warn, int max); +extern void list_types(struct systypes *sys); +extern int read_line (void); +extern char read_char(char *mesg); +extern int read_hex(struct systypes *sys); +uint read_int(uint low, uint dflt, uint high, uint 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 fdiskbsdlabel.c */ +extern void bselect(void); +extern int btrydev (char * dev); + +/* prototypes for fdisksgilabel.c */ +extern int valid_part_table_flag(unsigned char *b); diff --git a/fdisk/fdiskaixlabel.c b/fdisk/fdiskaixlabel.c new file mode 100644 index 000000000..848a6ece8 --- /dev/null +++ b/fdisk/fdiskaixlabel.c @@ -0,0 +1,64 @@ +#include /* stderr */ +#include /* uint */ +#include /* strstr */ +#include /* write */ + +#include + +#include "fdisk.h" +#include "fdiskaixlabel.h" + +static int other_endian = 0; +static short volumes=1; + +/* + * only dealing with free blocks here + */ + +void +aix_info( void ) +{ + printf( + "\n\tThere is a valid AIX label on this disk.\n" + "\tUnfortunately Linux cannot handle these\n" + "\tdisks at the moment. Nevertheless some\n" + "\tadvice:\n" + "\t1. fdisk will destroy its contents on write.\n" + "\t2. Be sure that this disk is NOT a still vital\n" + "\t part of a volume group. (Otherwise you may\n" + "\t erase the other disks as well, if unmirrored.)\n" + "\t3. Before deleting this physical volume be sure\n" + "\t to remove the disk logically from your AIX\n" + "\t machine. (Otherwise you become an AIXpert).\n" + ); +} + +void +aix_nolabel( void ) +{ + aixlabel->magic = 0; + aix_label = 0; + partitions = 4; + memset( buffer, 0, sizeof(buffer) ); /* avoid fdisk cores */ + return; +} + +int +check_aix_label( void ) +{ + if (aixlabel->magic != AIX_LABEL_MAGIC && + aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) { + aix_label = 0; + other_endian = 0; + return 0; + } + other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED); + update_units(); + aix_label = 1; + partitions= 1016; + volumes = 15; + aix_info(); + aix_nolabel(); /* %% */ + aix_label = 1; /* %% */ + return 1; +} diff --git a/fdisk/fdiskaixlabel.h b/fdisk/fdiskaixlabel.h new file mode 100644 index 000000000..fd95bc015 --- /dev/null +++ b/fdisk/fdiskaixlabel.h @@ -0,0 +1,34 @@ +#include /* for __u32 etc */ +/* + * Copyright (C) Andreas Neuper, Sep 1998. + * This file may be redistributed under + * the terms of the GNU Public License. + */ + +typedef struct { + unsigned int magic; /* expect AIX_LABEL_MAGIC */ + unsigned int fillbytes1[124]; + unsigned int physical_volume_id; + unsigned int fillbytes2[124]; +} aix_partition; + +#define AIX_LABEL_MAGIC 0xc9c2d4c1 +#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9 +#define AIX_INFO_MAGIC 0x00072959 +#define AIX_INFO_MAGIC_SWAPPED 0x59290700 + +/* fdisk.c */ +#define aixlabel ((aix_partition *)buffer) +extern char buffer[MAX_SECTOR_SIZE]; +extern char changed[MAXIMUM_PARTS]; +extern uint heads, sectors, cylinders; +extern int show_begin; +extern int aix_label; +extern char *partition_type(unsigned char type); +extern void update_units(void); +extern char read_chars(char *mesg); + +/* fdiskaixlabel.c */ +extern struct systypes aix_sys_types[]; +extern void aix_nolabel( void ); +extern int check_aix_label( void ); diff --git a/fdisk/fdiskbsdlabel.c b/fdisk/fdiskbsdlabel.c new file mode 100644 index 000000000..8edec2331 --- /dev/null +++ b/fdisk/fdiskbsdlabel.c @@ -0,0 +1,825 @@ +/* + NetBSD disklabel editor for Linux fdisk + Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de) + with code from the NetBSD disklabel command: + + Copyright (c) 1987, 1988 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include /* for HDIO_GETGEO */ + +#include "fdisk.h" +#define NETBSD_PARTITION 0xa5 +#define DKTYPENAMES +#include "fdiskbsdlabel.h" + +static void xbsd_delete_part (void); +static void xbsd_new_part (void); +static void xbsd_print_disklabel (int show_all); +static void xbsd_write_disklabel (void); +static int xbsd_create_disklabel (void); +static void xbsd_edit_disklabel (void); +static void xbsd_write_bootstrap (void); +static void xbsd_change_fstype (void); +static int xbsd_get_part_index (int max); +static int xbsd_check_new_partition (int *i); +static void xbsd_list_types (void); +static u_short xbsd_dkcksum (struct xbsd_disklabel *lp); +static int xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex); +static int xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d); +static int xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d); +static void sync_disks (void); +#if defined (i386) || defined (sparc) +static int xbsd_translate_fstype (int linux_type); +static void xbsd_link_part (void); +#endif +#if defined (__alpha__) +void alpha_bootblock_checksum (char *boot); +#endif + +static struct xbsd_disklabel xbsd_dlabel; +static char buffer[BSD_BBSIZE]; +#if defined (i386) || defined (sparc) +static struct partition *xbsd_part; +static int xbsd_part_index; +#endif + +int +btrydev (char * dev) { + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + return -1; + printf("\nBSD label for device: %s\n", dev); + xbsd_print_disklabel (0); + return 0; +} + +void +bmenu (void) +{ + puts ("Command action\n" + " d delete a BSD partition\n" + " e edit drive data\n" + " i install bootstrap\n" + " l list known filesystem types\n" + " m print this menu\n" + " n add a new BSD partition\n" + " p print BSD partition table\n" + " q quit without saving changes\n" +#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) || defined (sparc) + " x link BSD partition to non-BSD partition" +#endif + ); +} + +int +hidden(int type) { + return type ^ 0x10; +} + +int +is_netbsd_partition_type(int type) { + return (type == NETBSD_PARTITION || type == hidden(NETBSD_PARTITION)); +} + +void +bselect (void) { +#if defined (i386) || defined (sparc) + int t, ss; + + for (t=0; t<4; t++) + if (is_netbsd_partition_type(part_table[t] -> sys_ind)) { + xbsd_part = part_table[t]; + xbsd_part_index = t; + 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, ss + BSD_LABELSECTOR); + if (xbsd_readlabel (xbsd_part, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) + return; + break; + } + + if (t == 4) { + printf ("There is no *BSD partition on %s.\n", disk_device); + return; + } + +#elif defined (__alpha__) + + if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0) + if (xbsd_create_disklabel () == 0) + exit ( EXIT_SUCCESS ); + +#endif + + while (1) + { + putchar ('\n'); + switch (tolower (read_char ("BSD disklabel command (m for help): "))) + { + case 'd': + xbsd_delete_part (); + break; + case 'e': + xbsd_edit_disklabel (); + break; + case 'i': + xbsd_write_bootstrap (); + break; + case 'l': + xbsd_list_types (); + break; + case 'n': + xbsd_new_part (); + break; + case 'p': + xbsd_print_disklabel (0); + break; + case 'q': + close (fd); + exit ( EXIT_SUCCESS ); + case 's': + xbsd_print_disklabel (1); + break; + case 't': + xbsd_change_fstype (); + break; + case 'w': + xbsd_write_disklabel (); + break; +#if defined (i386) || defined (sparc) + case 'r': + return; + case 'x': + xbsd_link_part (); + break; +#endif + default: + bmenu (); + break; + } + } +} + +static void +xbsd_delete_part (void) +{ + int i; + + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_size = 0; + xbsd_dlabel.d_partitions[i].p_offset = 0; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + if (xbsd_dlabel.d_npartitions == i + 1) + while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0) + xbsd_dlabel.d_npartitions--; +} + +static void +xbsd_new_part (void) +{ + uint begin, end; + char mesg[48]; + int i; + + if (!xbsd_check_new_partition (&i)) + return; + +#if defined (i386) || defined (sparc) + begin = get_start_sect(xbsd_part); + end = begin + get_nr_sects(xbsd_part) - 1; +#elif defined (__alpha__) || defined (__powerpc__) + begin = 0; + end = xbsd_dlabel.d_secperunit; +#endif + + sprintf (mesg, "First %s", str_units()); + begin = read_int (cround (begin), cround (begin), cround (end), + 0, mesg); + + sprintf (mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); + end = read_int (cround (begin), cround (end), cround (end), + cround (begin), mesg); + + if (unit_flag) + { + begin = (begin - 1) * display_factor; + end = end * display_factor - 1; + } + xbsd_dlabel.d_partitions[i].p_size = end - begin + 1; + xbsd_dlabel.d_partitions[i].p_offset = begin; + xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; +} + +static void +xbsd_print_disklabel (int show_all) +{ + struct xbsd_disklabel *lp = &xbsd_dlabel; + struct xbsd_partition *pp; + FILE *f = stdout; + int i, j; + + if (show_all) + { +#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); +#endif + if ((unsigned) lp->d_type < BSD_DKMAXTYPES) + fprintf(f, "type: %s\n", xbsd_dktypenames[lp->d_type]); + else + fprintf(f, "type: %d\n", lp->d_type); + fprintf(f, "disk: %.*s\n", (int) sizeof(lp->d_typename), lp->d_typename); + fprintf(f, "label: %.*s\n", (int) sizeof(lp->d_packname), lp->d_packname); + fprintf(f, "flags:"); + if (lp->d_flags & BSD_D_REMOVABLE) + fprintf(f, " removable"); + if (lp->d_flags & BSD_D_ECC) + fprintf(f, " ecc"); + if (lp->d_flags & BSD_D_BADSECT) + fprintf(f, " badsect"); + fprintf(f, "\n"); + /* On various machines the fields of *lp are short/int/long */ + /* In order to avoid problems, we cast them all to long. */ + fprintf(f, "bytes/sector: %ld\n", (long) lp->d_secsize); + fprintf(f, "sectors/track: %ld\n", (long) lp->d_nsectors); + fprintf(f, "tracks/cylinder: %ld\n", (long) lp->d_ntracks); + fprintf(f, "sectors/cylinder: %ld\n", (long) lp->d_secpercyl); + fprintf(f, "cylinders: %ld\n", (long) lp->d_ncylinders); + fprintf(f, "rpm: %d\n", lp->d_rpm); + fprintf(f, "interleave: %d\n", lp->d_interleave); + fprintf(f, "trackskew: %d\n", lp->d_trackskew); + fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); + fprintf(f, "headswitch: %ld\t\t# milliseconds\n", (long) lp->d_headswitch); + fprintf(f, "track-to-track seek: %ld\t# milliseconds\n", (long) lp->d_trkseek); + fprintf(f, "drivedata: "); + for (i = NDDATA - 1; i >= 0; i--) + if (lp->d_drivedata[i]) + break; + if (i < 0) + i = 0; + for (j = 0; j <= i; j++) + fprintf(f, "%ld ", (long) lp->d_drivedata[j]); + } + fprintf (f, "\n%d partitions:\n", lp->d_npartitions); + fprintf (f, "# size offset fstype [fsize bsize cpg]\n"); + pp = lp->d_partitions; + for (i = 0; i < lp->d_npartitions; i++, pp++) { + if (pp->p_size) { + fprintf(f, " %c: %8ld %8ld ", 'a' + i, + (long) pp->p_size, (long) pp->p_offset); + if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) + fprintf(f, "%8.8s", xbsd_fstypes[pp->p_fstype].name); + else + fprintf(f, "%8x", pp->p_fstype); + switch (pp->p_fstype) + { + case BSD_FS_UNUSED: + fprintf(f, " %5ld %5ld %5.5s ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, ""); + break; + + case BSD_FS_BSDFFS: + fprintf(f, " %5ld %5ld %5d ", + (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, + pp->p_cpg); + break; + + default: + fprintf(f, "%20.20s", ""); + break; + } + fprintf(f, "\t# (Cyl. %4ld", (long) +#if 0 + pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ +#else + pp->p_offset / lp->d_secpercyl + 1); +#endif + if (pp->p_offset % lp->d_secpercyl) + putc('*', f); + else + putc(' ', f); + fprintf(f, "- %ld", + (long) (pp->p_offset + + pp->p_size + lp->d_secpercyl - 1) / +#if 0 + lp->d_secpercyl - 1); /* differs from Linux fdisk */ +#else + lp->d_secpercyl); +#endif + if (pp->p_size % lp->d_secpercyl) + putc('*', f); + fprintf(f, ")\n"); + } + } +} + +static void +xbsd_write_disklabel (void) +{ +#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__) + printf ("Writing disklabel to %s.\n", disk_device); + xbsd_writelabel (NULL, &xbsd_dlabel); +#endif +} + +static int +xbsd_create_disklabel (void) +{ + char c; + +#if defined (i386) || defined (sparc) + fprintf (stderr, "%s%d contains no disklabel.\n", + disk_device, xbsd_part_index+1); +#elif defined (__alpha__) + fprintf (stderr, "%s contains no disklabel.\n", disk_device); +#endif + + while (1) + if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') + { +#if defined (i386) || defined (sparc) + if (xbsd_initlabel (xbsd_part, &xbsd_dlabel, xbsd_part_index) == 1) +#elif defined (__alpha__) || defined (__powerpc__) + if (xbsd_initlabel (NULL, &xbsd_dlabel, 0) == 1) +#endif + { + xbsd_print_disklabel (1); + return 1; + } + else + return 0; + } + else if (c == 'n') + return 0; +} + +static int +edit_int (int def, char *mesg) +{ + do { + fputs (mesg, stdout); + printf (" (%d): ", def); + if (!read_line ()) + return def; + } + while (!isdigit (*line_ptr)); + return atoi (line_ptr); +} + +static void +xbsd_edit_disklabel (void) +{ + struct xbsd_disklabel *d; + + d = &xbsd_dlabel; + +#ifdef __alpha__ + d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); + d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,"sectors/track"); + d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,"tracks/cylinder"); + d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,"cylinders"); +#endif + + /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */ + while (1) + { + d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks, + "sectors/cylinder"); + if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks) + break; + + printf ("Must be <= sectors/track * tracks/cylinder (default).\n"); + } + d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,"rpm"); + d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,"interleave"); + d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,"trackskew"); + d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,"cylinderskew"); + d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,"headswitch"); + d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,"track-to-track seek"); + + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; +} + +static int +xbsd_get_bootstrap (char *path, void *ptr, int size) +{ + int fd; + + if ((fd = open (path, O_RDONLY)) < 0) + { + perror (path); + return 0; + } + if (read (fd, ptr, size) < 0) + { + perror (path); + close (fd); + return 0; + } + printf (" ... %s\n", path); + close (fd); + return 1; +} + +static void +xbsd_write_bootstrap (void) +{ + char *bootdir = BSD_LINUX_BOOTDIR; + char path[MAXPATHLEN]; + char *dkbasename; + struct xbsd_disklabel dl; + char *d, *p, *e; + int sector; + + if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI) + dkbasename = "sd"; + else + dkbasename = "wd"; + + printf ("Bootstrap: %sboot -> boot%s (%s): ", dkbasename, dkbasename, dkbasename); + if (read_line ()) + { + line_ptr[strlen (line_ptr)-1] = '\0'; + dkbasename = line_ptr; + } + sprintf (path, "%s/%sboot", bootdir, dkbasename); + if (!xbsd_get_bootstrap (path, buffer, (int) xbsd_dlabel.d_secsize)) + return; + + /* We need a backup of the disklabel (xbsd_dlabel might have changed). */ + d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; + bcopy (d, &dl, sizeof (struct xbsd_disklabel)); + + /* The disklabel will be overwritten by 0's from bootxx anyway */ + bzero (d, sizeof (struct xbsd_disklabel)); + + sprintf (path, "%s/boot%s", bootdir, dkbasename); + if (!xbsd_get_bootstrap (path, &buffer[xbsd_dlabel.d_secsize], + (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize)) + return; + + e = d + sizeof (struct xbsd_disklabel); + for (p=d; p < e; p++) + if (*p) + { + fprintf (stderr, "Bootstrap overlaps with disk label!\n"); + exit ( EXIT_FAILURE ); + } + + bcopy (&dl, d, sizeof (struct xbsd_disklabel)); + +#if defined (i386) || defined (sparc) + sector = get_start_sect(xbsd_part); +#elif defined (__powerpc__) + sector = 0; +#elif defined (__alpha__) + sector = 0; + alpha_bootblock_checksum (buffer); +#endif + + if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); + +#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); +#endif + + sync_disks (); +} + +static void +xbsd_change_fstype (void) +{ + int i; + + i = xbsd_get_part_index (xbsd_dlabel.d_npartitions); + xbsd_dlabel.d_partitions[i].p_fstype = read_hex (xbsd_fstypes); +} + +static int +xbsd_get_part_index (int max) +{ + char prompt[40]; + char l; + + sprintf (prompt, "Partition (a-%c): ", 'a' + max - 1); + do + l = tolower (read_char (prompt)); + while (l < 'a' || l > 'a' + max - 1); + return l - 'a'; +} + +static int +xbsd_check_new_partition (int *i) +{ + int t; + + if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) + { + for (t=0; t < BSD_MAXPARTITIONS; t++) + if (xbsd_dlabel.d_partitions[t].p_size == 0) + break; + + if (t == BSD_MAXPARTITIONS) + { + fprintf (stderr, "The maximum number of partitions has been created\n"); + return 0; + } + } + *i = xbsd_get_part_index (BSD_MAXPARTITIONS); + + if (*i >= xbsd_dlabel.d_npartitions) + xbsd_dlabel.d_npartitions = (*i) + 1; + + if (xbsd_dlabel.d_partitions[*i].p_size != 0) + { + fprintf (stderr, "This partition already exists.\n"); + return 0; + } + return 1; +} + +static void +xbsd_list_types (void) +{ + list_types (xbsd_fstypes); +} + +static u_short +xbsd_dkcksum (struct xbsd_disklabel *lp) +{ + register u_short *start, *end; + register u_short sum = 0; + + start = (u_short *)lp; + end = (u_short *)&lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return (sum); +} + +static int +xbsd_initlabel (struct partition *p, struct xbsd_disklabel *d, int pindex) +{ + struct hd_geometry geometry; + struct xbsd_partition *pp; + + if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) + { + perror ("ioctl"); + return 0; + } + bzero (d, sizeof (struct xbsd_disklabel)); + + d -> d_magic = BSD_DISKMAGIC; + + if (strncmp (disk_device, "/dev/sd", 7) == 0) + d -> d_type = BSD_DTYPE_SCSI; + else + d -> d_type = BSD_DTYPE_ST506; + +#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */ + d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; +#endif + +#if defined (i386) || defined (sparc) + d -> d_flags = BSD_D_DOSPART; +#else + d -> d_flags = 0; +#endif + d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ + d -> d_nsectors = geometry.sectors; /* sectors/track */ + d -> d_ntracks = geometry.heads; /* tracks/cylinder (heads) */ + d -> d_ncylinders = geometry.cylinders; + d -> d_secpercyl = geometry.sectors * geometry.heads; /* sectors/cylinder */ + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; + + d -> d_rpm = 3600; + d -> d_interleave = 1; + d -> d_trackskew = 0; + d -> d_cylskew = 0; + d -> d_headswitch = 0; + d -> d_trkseek = 0; + + d -> d_magic2 = BSD_DISKMAGIC; + d -> d_bbsize = BSD_BBSIZE; + d -> d_sbsize = BSD_SBSIZE; + +#if defined (i386) || defined (sparc) + d -> d_npartitions = 4; + pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */ + 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; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#elif defined (__alpha__) + d -> d_npartitions = 3; + pp = &d -> d_partitions[2]; /* Partition C should be the whole disk */ + pp -> p_offset = 0; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#endif + + return 1; +} + +static int +xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d) +{ + int t, sector; + +#if defined (i386) || defined (sparc) + sector = (p ? get_start_sect(p) : 0); +#elif defined (__alpha__) + sector = 0; +#endif + + if (ext2_llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != read (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_read); + + bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], + d, sizeof (struct xbsd_disklabel)); + + for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) + { + d -> d_partitions[t].p_size = 0; + d -> d_partitions[t].p_offset = 0; + d -> d_partitions[t].p_fstype = BSD_FS_UNUSED; + } + if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC) + return 0; + + if (d -> d_npartitions > BSD_MAXPARTITIONS) + fprintf (stderr, "Warning: too many partitions (%d, maximum is %d).\n", + d -> d_npartitions, BSD_MAXPARTITIONS); + return 1; +} + +static int +xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d) +{ + int sector; + +#if defined (i386) || defined (sparc) + sector = get_start_sect(p) + BSD_LABELSECTOR; +#elif defined (__alpha__) || defined (__powerpc__) + sector = BSD_LABELSECTOR; +#endif + + d -> d_checksum = 0; + d -> d_checksum = xbsd_dkcksum (d); + + /* This is necessary if we want to write the bootstrap later, + otherwise we'd write the old disklabel with the bootstrap. + */ + bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], + sizeof (struct xbsd_disklabel)); + +#if defined (__alpha__) && BSD_LABELSECTOR == 0 + alpha_bootblock_checksum (buffer); + if (ext2_llseek (fd, 0, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); +#else + if (ext2_llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1) + fatal (unable_to_seek); + if (sizeof (struct xbsd_disklabel) != write (fd, d, sizeof (struct xbsd_disklabel))) + fatal (unable_to_write); +#endif + + sync_disks (); + + return 1; +} + +static void +sync_disks (void) +{ + printf ("\nSyncing disks.\n"); + sync (); + sleep (4); +} + +#if defined (i386) || defined (sparc) +static int +xbsd_translate_fstype (int linux_type) +{ + switch (linux_type) + { + case 0x01: /* DOS 12-bit FAT */ + case 0x04: /* DOS 16-bit <32M */ + case 0x06: /* DOS 16-bit >=32M */ + case 0xe1: /* DOS access */ + case 0xe3: /* DOS R/O */ + case 0xf2: /* DOS secondary */ + return BSD_FS_MSDOS; + case 0x07: /* OS/2 HPFS */ + return BSD_FS_HPFS; + default: + return BSD_FS_OTHER; + } +} + +static void +xbsd_link_part (void) +{ + int k, i; + + k = get_partition (1, partitions); + + if (!xbsd_check_new_partition (&i)) + return; + + 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); +} +#endif + +#if defined (__alpha__) + +#if 0 +typedef unsigned long long u_int64_t; +#endif + +void +alpha_bootblock_checksum (char *boot) +{ + u_int64_t *dp, sum; + int i; + + dp = (u_int64_t *)boot; + sum = 0; + for (i = 0; i < 63; i++) + sum += dp[i]; + dp[63] = sum; +} +#endif /* __alpha__ */ diff --git a/fdisk/fdiskbsdlabel.h b/fdisk/fdiskbsdlabel.h new file mode 100644 index 000000000..b9f2c9c38 --- /dev/null +++ b/fdisk/fdiskbsdlabel.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1987, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include /* for __u32 etc */ + +#ifndef BSD_DISKMAGIC /* perhaps from */ +#define BSD_DISKMAGIC ((__u32) 0x82564557) +#endif + +#ifndef BSD_MAXPARTITIONS +#define BSD_MAXPARTITIONS 8 +#endif + +#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" + +#if defined (i386) || defined (sparc) +#define BSD_LABELSECTOR 1 +#define BSD_LABELOFFSET 0 +#elif defined (__alpha__) || defined (__powerpc__) +#define BSD_LABELSECTOR 0 +#define BSD_LABELOFFSET 64 +#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 */ + __s16 d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + char d_packname[16]; /* pack identifier */ + /* disk geometry: */ + __u32 d_secsize; /* # of bytes per sector */ + __u32 d_nsectors; /* # of data sectors per track */ + __u32 d_ntracks; /* # of tracks per cylinder */ + __u32 d_ncylinders; /* # of data cylinders per unit */ + __u32 d_secpercyl; /* # of data sectors per cylinder */ + __u32 d_secperunit; /* # of data sectors per unit */ + /* + * Spares (bad sector replacements) below + * are not counted in d_nsectors or d_secpercyl. + * Spare sectors are assumed to be physical sectors + * which occupy space at the end of each track and/or cylinder. + */ + __u16 d_sparespertrack; /* # of spare sectors per track */ + __u16 d_sparespercyl; /* # of spare sectors per cylinder */ + /* + * Alternate cylinders include maintenance, replacement, + * configuration description areas, etc. + */ + __u32 d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the formatter + * or controller when formatting. When interleaving is in use, + * logically adjacent sectors are not physically contiguous, + * but instead are separated by some number of sectors. + * It is specified as the ratio of physical sectors traversed + * per logical sector. Thus an interleave of 1:1 implies contiguous + * layout, while 2:1 implies that logical sector 0 is separated + * by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N + * relative to sector 0 on track N-1 on the same cylinder. + * Finally, d_cylskew is the offset of sector 0 on cylinder N + * relative to sector 0 on cylinder N-1. + */ + __u16 d_rpm; /* rotational speed */ + __u16 d_interleave; /* hardware sector interleave */ + __u16 d_trackskew; /* sector 0 skew, per track */ + __u16 d_cylskew; /* sector 0 skew, per cylinder */ + __u32 d_headswitch; /* head switch time, usec */ + __u32 d_trkseek; /* track-to-track seek, usec */ + __u32 d_flags; /* generic flags */ +#define NDDATA 5 + __u32 d_drivedata[NDDATA]; /* drive-type specific information */ +#define NSPARE 5 + __u32 d_spare[NSPARE]; /* reserved for future use */ + __u32 d_magic2; /* the magic number (again) */ + __u16 d_checksum; /* xor of data incl. partitions */ + /* filesystem and partition information: */ + __u16 d_npartitions; /* number of partitions in following */ + __u32 d_bbsize; /* size of boot area at sn0, bytes */ + __u32 d_sbsize; /* max size of fs superblock, bytes */ + struct xbsd_partition { /* the partition table */ + __u32 p_size; /* number of sectors in partition */ + __u32 p_offset; /* starting sector */ + __u32 p_fsize; /* filesystem basic fragment size */ + __u8 p_fstype; /* filesystem type, see below */ + __u8 p_frag; /* filesystem fragments per block */ + __u16 p_cpg; /* filesystem cylinders per group */ + } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +}; + +/* d_type values: */ +#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define BSD_DTYPE_MSCP 2 /* MSCP */ +#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define BSD_DTYPE_SCSI 4 /* SCSI */ +#define BSD_DTYPE_ESDI 5 /* ESDI interface */ +#define BSD_DTYPE_ST506 6 /* ST506 etc. */ +#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ +#define BSD_DTYPE_FLOPPY 10 /* floppy */ + +/* d_subtype values: */ +#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ +#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ +#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ + +#ifdef DKTYPENAMES +static char *xbsd_dktypenames[] = { + "unknown", + "SMD", + "MSCP", + "old DEC", + "SCSI", + "ESDI", + "ST506", + "HP-IB", + "HP-FL", + "type 9", + "floppy", + 0 +}; +#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1) +#endif + +/* + * Filesystem type and version. + * Used to interpret other filesystem-specific + * per-partition information. + */ +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ +#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ +#define BSD_FS_ISOFS BSD_FS_ISO9660 +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ + +/* this is annoying, but it's also the way it is :-( */ +#ifdef __alpha__ +#define BSD_FS_EXT2 8 /* MS-DOS file system */ +#else +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#endif + +#ifdef DKTYPENAMES +static struct systypes xbsd_fstypes[] = { + {BSD_FS_UNUSED, "unused"}, + {BSD_FS_SWAP, "swap"}, + {BSD_FS_V6, "Version 6"}, + {BSD_FS_V7, "Version 7"}, + {BSD_FS_SYSV, "System V"}, + {BSD_FS_V71K, "4.1BSD"}, + {BSD_FS_V8, "Eighth Edition"}, + {BSD_FS_BSDFFS, "4.2BSD"}, +#ifdef __alpha__ + {BSD_FS_EXT2, "ext2"}, +#else + {BSD_FS_MSDOS, "MS-DOS"}, +#endif + {BSD_FS_BSDLFS, "4.4LFS"}, + {BSD_FS_OTHER, "unknown"}, + {BSD_FS_HPFS, "HPFS"}, + {BSD_FS_ISO9660,"ISO-9660"}, + {BSD_FS_BOOT, "boot"}, + {BSD_FS_ADOS, "ADOS"}, + {BSD_FS_HFS, "HFS"}, + { 0, NULL } +}; +#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1) + +#endif + +/* + * flags shared by various drives: + */ +#define BSD_D_REMOVABLE 0x01 /* removable media */ +#define BSD_D_ECC 0x02 /* supports ECC */ +#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ +#define BSD_D_RAMDISK 0x08 /* disk emulator */ +#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ +#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ diff --git a/fdisk/fdisksgilabel.c b/fdisk/fdisksgilabel.c new file mode 100644 index 000000000..42f7363e4 --- /dev/null +++ b/fdisk/fdisksgilabel.c @@ -0,0 +1,888 @@ +/* + * + * fdisksgilabel.c + * + * Copyright (C) Andreas Neuper, Sep 1998. + * This file may be modified and redistributed under + * the terms of the GNU Public License. + */ +#include /* stderr */ +#include /* uint */ +#include /* strstr */ +#include /* write */ +#include /* ioctl */ +#include /* stat */ +#include /* assert */ + +#include +#include /* FLOPPY_MAJOR */ +#include /* HDIO_GETGEO */ + +#include "fdisk.h" +#include "fdisksgilabel.h" + +static int other_endian = 0; +static int debug = 0; +static short volumes=1; + +/* + * only dealing with free blocks here + */ + +typedef struct { int first; int last; } freeblocks; +static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */ +void setfreelist( int i, int f, int l ) \ + { freelist[i].first = f; freelist[i].last = l; return; } +void add2freelist( int f, int l ) \ + { int i = 0; for( ; i<17 ; i++ ) { if(freelist[i].last==0) break; }\ + setfreelist( i, f, l ); return; } +void clearfreelist( void ) \ + { int i = 0; for( ; i<17 ; i++ ) { setfreelist( i, 0, 0 ); } return; } +int isinfreelist( int b ) \ + { int i = 0; for( ; i<17 ; i++ )\ + { if( ( freelist[i].first <= b ) && ( freelist[i].last >= b) )\ + { return freelist[i].last; } } return 0; } + /* return last vacant block of this stride (never 0). */ + /* the '>=' is not quite correct, but simplifies the code */ +/* + * end of free blocks section + */ + +struct systypes sgi_sys_types[] = { + {SGI_VOLHDR, "SGI volhdr"}, + {0x01, "SGI trkrepl"}, + {0x02, "SGI secrepl"}, + {SGI_SWAP, "SGI raw"}, + {0x04, "SGI bsd"}, + {0x05, "SGI sysv"}, + {ENTIRE_DISK, "SGI volume"}, + {SGI_EFS, "SGI efs"}, + {0x08, "SGI lvol"}, + {0x09, "SGI rlvol"}, + {0x0A, "SGI xfs"}, + {0x0B, "SGI xlvol"}, + {0x0C, "SGI rxlvol"}, + {LINUX_SWAP, "Linux swap"}, + {LINUX_NATIVE,"Linux native"}, + {0, NULL } +}; + +static inline unsigned short __swap16(unsigned short x) { + return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); +} +static inline __u32 __swap32(__u32 x) { + return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24); +} + +static +int +sgi_get_nsect( void ) +{ + return SSWAP16(sgilabel->devparam.nsect); +} + +static +int +sgi_get_ntrks( void ) +{ + return SSWAP16(sgilabel->devparam.ntrks); +} + +#if 0 +static int +sgi_get_head_vol0( void ) +{ + return SSWAP16(sgilabel->devparam.head_vol0); +} + +static int +sgi_get_bytes( void ) +{ + return SSWAP16(sgilabel->devparam.bytes); +} +#endif + +static +int +sgi_get_pcylcount( void ) +{ + return SSWAP16(sgilabel->devparam.pcylcount); +} + +void +sgi_nolabel() +{ + sgilabel->magic = 0; + sgi_label = 0; + partitions = 4; +} + +unsigned int +two_s_complement_32bit_sum( + unsigned int* base, + int size /* in bytes */ ) +{ + int i=0; + unsigned int sum=0; + size = size / sizeof( unsigned int ); + for( i=0; i 512) { + fprintf(stderr, + "According to MIPS Computer Systems, Inc the " + "Label must not contain more than 512 bytes\n"); + exit(1); + } + + if (sgilabel->magic != SGI_LABEL_MAGIC && + sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) { + sgi_label = 0; + other_endian = 0; + return 0; + } + + other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED); + /* + * test for correct checksum + */ + if( two_s_complement_32bit_sum( (unsigned int*)sgilabel, + sizeof(*sgilabel) ) ) + { + fprintf( stderr, "Detected sgi disklabel with wrong checksum.\n" ); + } else + { + heads = sgi_get_ntrks(); + cylinders = sgi_get_pcylcount(); + sectors = sgi_get_nsect(); + } + update_units(); + sgi_label = 1; + partitions= 16; + volumes = 15; + return 1; +} + +void +sgi_list_table( int xtra ) +{ + int i, w; + char *type; + + w = strlen( disk_device ); + + if( xtra ) + { + printf( "\nDisk %s (SGI disk label): %d heads, %d sectors\n" + "%d 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, cylinders, + SSWAP16(sgiparam.pcylcount), + SSWAP16(sgiparam.sparecyl), + SSWAP16(sgiparam.ilfact), + (char *)sgilabel, + str_units(), display_factor); + } else + { + printf( "\nDisk %s (SGI 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("----- partitions -----\n" + "%*s Info Start End Sectors Id System\n", + w + 1, "Device"); + for (i = 0 ; i < partitions; i++) + { + if( sgi_get_num_sectors(i) || debug ) + { + __u32 start = sgi_get_start_sector(i); + __u32 len = sgi_get_num_sectors(i); + printf( + "%*s%-2d %4s %9ld %9ld %9ld %2x %s\n", +/* device */ w, disk_device, i + 1, +/* flags */ (sgi_get_swappartition() == i) ? "swap" : +/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ", +/* start */ (long) scround(start), +/* end */ (long) scround(start+len)-1, +/* no odd flag on end */ (long) len, +/* type id */ sgi_get_sysid(i), +/* type name */ (type = partition_type(sgi_get_sysid(i))) + ? type : "Unknown"); + } + } + printf( "----- bootinfo -----\nBootfile: %s\n" + "----- directory entries -----\n", + sgilabel->boot_file ); + for (i = 0 ; i < volumes; i++) + { + if (sgilabel->directory[i].vol_file_size) + { + __u32 start = SSWAP32(sgilabel->directory[i].vol_file_start); + __u32 len = SSWAP32(sgilabel->directory[i].vol_file_size); + char*name = sgilabel->directory[i].vol_file_name; + printf("%2d: %-10s sector%5u size%8u\n", + i, name, (unsigned int) start, (unsigned int) len); + } + } +} + +int +sgi_get_start_sector( int i ) +{ + return SSWAP32(sgilabel->partitions[i].start_sector); +} + +int +sgi_get_num_sectors( int i ) +{ + return SSWAP32(sgilabel->partitions[i].num_sectors); +} + +int +sgi_get_sysid( int i ) +{ + return SSWAP32(sgilabel->partitions[i].id); +} + +int +sgi_get_bootpartition( void ) +{ + return SSWAP16(sgilabel->boot_part); +} + +int +sgi_get_swappartition( void ) +{ + return SSWAP16(sgilabel->swap_part); +} + +void +sgi_set_bootpartition( int i ) +{ + sgilabel->boot_part = SSWAP16(((short)i)); + return; +} + +int +sgi_get_lastblock( void ) +{ + return heads * sectors * cylinders; +} + +void +sgi_set_swappartition( int i ) +{ + sgilabel->swap_part = SSWAP16(((short)i)); + return; +} + +static int +sgi_check_bootfile( const char* aFile ) +{ + if( strlen( aFile ) < 3 ) /* "/a\n" is minimum */ + { + printf( "\nInvalid Bootfile!\n" + "\tThe bootfile must be an absolute non-zero pathname,\n" + "\te.g. \"/unix\" or \"/unix.save\".\n" ); + return 0; + } else + if( strlen( aFile ) > 16 ) + { + printf( "\n\tName of Bootfile too long: 16 bytes maximum.\n" ); + return 0; + } else + if( aFile[0] != '/' ) + { + printf( "\n\tBootfile must have a fully qualified pathname.\n" ); + return 0; + } + if( strncmp( aFile, sgilabel->boot_file, 16 ) ) + { + printf( "\n\tBe aware, that the bootfile is not checked for existence.\n\t" + "SGI's default is \"/unix\" and for backup \"/unix.save\".\n" ); + /* filename is correct and did change */ + return 1; + } + return 0; /* filename did not change */ +} + +const char * +sgi_get_bootfile(void) { + return sgilabel->boot_file; +} + +void +sgi_set_bootfile( const char* aFile ) +{ + int i = 0; + if( sgi_check_bootfile( aFile ) ) + { + while( i<16 ) + { + if( (aFile[i] != '\n') /* in principle caught again by next line */ + && (strlen( aFile ) > i ) ) + sgilabel->boot_file[i] = aFile[i]; + else + sgilabel->boot_file[i] = 0; + i++; + } + printf( "\n\tBootfile is changed to \"%s\".\n", sgilabel->boot_file ); + } + return; +} + +void +create_sgiinfo( void ) +{ + /* I keep SGI's habit to write the sgilabel to the second block */ + sgilabel->directory[0].vol_file_start = SSWAP32( 2 ); + sgilabel->directory[0].vol_file_size = SSWAP32( sizeof( sgiinfo ) ); + strncpy( sgilabel->directory[0].vol_file_name, "sgilabel",8 ); + return; +} + +sgiinfo * fill_sgiinfo( void ); + +void +sgi_write_table( void ) +{ + sgilabel->csum = 0; + sgilabel->csum = SSWAP32( two_s_complement_32bit_sum( + (unsigned int*)sgilabel, + sizeof(*sgilabel) ) ); + assert( two_s_complement_32bit_sum( + (unsigned int*)sgilabel, sizeof(*sgilabel) ) == 0 ); + if( lseek(fd, 0, SEEK_SET) < 0 ) + fatal(unable_to_seek); + if( write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE ) + fatal(unable_to_write); + if( ! strncmp( sgilabel->directory[0].vol_file_name, "sgilabel",8 ) ) + { + /* + * keep this habbit of first writing the "sgilabel". + * I never tested whether it works without (AN 981002). + */ + sgiinfo*info = fill_sgiinfo(); /* fills the block appropriately */ + int infostartblock = SSWAP32( sgilabel->directory[0].vol_file_start ); + if( ext2_llseek(fd, (ext2_loff_t)infostartblock* + SECTOR_SIZE, SEEK_SET) < 0 ) + fatal(unable_to_seek); + if( write(fd, info, SECTOR_SIZE) != SECTOR_SIZE ) + fatal(unable_to_write); + free( info ); + } + return; +} + +static +int +compare_start( int*x, int*y ) +{ + /* + * sort according to start sectors + * and prefers largest partition: + * entry zero is entire disk entry + */ + int i = *x; + int j = *y; + int a = sgi_get_start_sector(i); + int b = sgi_get_start_sector(j); + int c = sgi_get_num_sectors(i); + int d = sgi_get_num_sectors(j); + if( a == b ) + { + return( d - c ); + } + return( a - b ); +} + +static +int +sgi_gaps() +{ + /* + * returned value is: + * = 0 : disk is properly filled to the rim + * < 0 : there is an overlap + * > 0 : there is still some vacant space + */ + return verify_sgi(0); +} + +int +verify_sgi( int verbose ) +{ + int Index[16]; /* list of valid partitions */ + int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */ + int compare_start();/* comparison function above */ + int entire = 0, i = 0; /* local counters */ + int start = 0; + int gap = 0; /* count unused blocks */ + int lastblock = sgi_get_lastblock(); + /* + */ + clearfreelist(); + for( i=0; i<16; i++ ) + { + if( sgi_get_num_sectors(i)!=0 ) + { + Index[sortcount++]=i; + if( sgi_get_sysid(i) == ENTIRE_DISK ) + { + if( entire++ == 1 ) + { + if(verbose) + printf("More than one entire disk entriy present.\n"); + } + } + } + } + if( sortcount == 0 ) + { + if(verbose) + printf("No partitions defined\n"); + return lastblock; + } + qsort( Index, sortcount, sizeof(Index[0]), (void*)compare_start ); + if( sgi_get_sysid( Index[0] ) == ENTIRE_DISK ) + { + if( ( Index[0] != 10 ) && verbose ) + printf( "IRIX likes when Partition 11 covers the entire disk.\n" ); + if( ( sgi_get_start_sector( Index[0] ) != 0 ) && verbose ) + printf( "The entire disk partition should start at block 0,\nnot " + "at diskblock %d.\n", sgi_get_start_sector(Index[0] ) ); + if(debug) /* I do not understand how some disks fulfil it */ + if( ( sgi_get_num_sectors( Index[0] ) != lastblock ) && verbose ) + printf( "The entire disk partition is only %d diskblock large,\n" + "but the disk is %d diskblocks long.\n", + sgi_get_num_sectors( Index[0] ), lastblock ); + lastblock = sgi_get_num_sectors( Index[0] ); + } else + { + if( verbose ) + printf( "One Partition (#11) should cover the entire disk.\n" ); + if(debug>2) + printf( "sysid=%d\tpartition=%d\n", + sgi_get_sysid( Index[0] ), Index[0]+1 ); + } + for( i=1, start=0; i sgi_get_start_sector( Index[i] ) ) + { + if( verbose ) + printf( "The Partition %d and %d overlap by %d sectors.\n", + Index[i-1]+1, Index[i]+1, + start - sgi_get_start_sector( Index[i] ) ); + if( gap > 0 ) gap = -gap; + if( gap == 0 ) gap = -1; + } + if( start < sgi_get_start_sector( Index[i] ) ) + { + if( verbose ) + printf( "Unused gap of %8d sectors - sectors %8d-%d\n", + sgi_get_start_sector( Index[i] ) - start, + start, sgi_get_start_sector( Index[i] )-1 ); + gap += sgi_get_start_sector( Index[i] ) - start; + add2freelist( start, sgi_get_start_sector( Index[i] ) ); + } + start = sgi_get_start_sector( Index[i] ) + + sgi_get_num_sectors( Index[i] ); + if(debug>1) + { + if( verbose ) + printf( "%2d:%12d\t%12d\t%12d\n", Index[i], + sgi_get_start_sector(Index[i]), + sgi_get_num_sectors(Index[i]), + sgi_get_sysid(Index[i]) ); + } + } + if( ( start < lastblock ) ) + { + if( verbose ) + printf( "Unused gap of %8d sectors - sectors %8d-%d\n", + lastblock - start, start, lastblock-1 ); + gap += lastblock - start; + add2freelist( start, lastblock ); + } + /* + * Done with arithmetics + * Go for details now + */ + if( verbose ) + { + if( !sgi_get_num_sectors( sgi_get_bootpartition() ) ) + { + printf( "\nThe boot partition does not exist.\n" ); + } + if( !sgi_get_num_sectors( sgi_get_swappartition() ) ) + { + printf( "\nThe swap partition does not exist.\n" ); + } else + if( ( sgi_get_sysid( sgi_get_swappartition() ) != SGI_SWAP ) + && ( sgi_get_sysid( sgi_get_swappartition() ) != LINUX_SWAP ) ) + { + printf( "\nThe swap partition has no swap type.\n" ); + } + if( sgi_check_bootfile( "/unix" ) ) + { + printf( "\tYou have chosen an unusual boot file name.\n" ); + } + } + return gap; +} + +void +sgi_change_sysid( int i, int sys ) +{ + if( sgi_get_num_sectors(i) == 0 ) /* caught already before, ... */ + { + printf("Sorry You may change the Tag of non-empty partitions.\n"); + return; + } + if( ((sys != ENTIRE_DISK ) && (sys != SGI_VOLHDR)) + && (sgi_get_start_sector(i)<1) ) + { + read_chars( + "It is highly recommended that the partition at offset 0\n" + "is of type \"SGI volhdr\", the IRIX system will rely on it to\n" + "retrieve from its directory standalone tools like sash and fx.\n" + "Only the \"SGI volume\" entire disk section may violate this.\n" + "Type YES if you are sure about tagging this partition differently.\n" ); + if (strcmp (line_ptr, "YES\n")) + return; + } + sgilabel->partitions[i].id = SSWAP32(sys); + return; +} + +int +sgi_entire( void ) +{ /* returns partition index of first entry marked as entire disk */ + int i=0; + for( i=0; i<16; i++ ) + if( sgi_get_sysid(i) == SGI_VOLUME ) + return i; + return -1; +} + +int +sgi_num_partitions( void ) +{ + int i=0, + n=0; + for( i=0; i<16; i++ ) + if( sgi_get_num_sectors(i)!=0 ) + n++; + return n; +} + +static +void +sgi_set_partition( int i, uint start, uint length, int sys ) +{ + sgilabel->partitions[i].id = + SSWAP32( sys ); + sgilabel->partitions[i].num_sectors = + SSWAP32( length ); + sgilabel->partitions[i].start_sector = + SSWAP32( start ); + changed[i] = 1; + if( sgi_gaps(0) < 0 ) /* rebuild freelist */ + { + printf( "Do You know, You got a partition overlap on the disk?\n" ); + } + return; +} + +static +void +sgi_set_entire( void ) +{ + int n; + for( n=10; nsys_ind ) + { + old[i].sysid = part_table[i]->sys_ind; + old[i].start = get_start_sect( part_table[i] ); + old[i].nsect = get_nr_sects( part_table[i] ); + printf( "Trying to keep parameters of partition %d.\n", i ); + if( debug ) + printf( "ID=%02x\tSTART=%d\tLENGTH=%d\n", + old[i].sysid, old[i].start, old[i].nsect ); + } + } + } + memset(buffer, 0, SECTOR_SIZE); + sgilabel->magic = SSWAP32(SGI_LABEL_MAGIC); + sgilabel->boot_part = SSWAP16(0); + sgilabel->swap_part = SSWAP16(1); strncpy( + sgilabel->boot_file , "/unix\0\0\0\0\0\0\0\0\0\0\0", 16 ); + sgilabel->devparam.skew = (0); + sgilabel->devparam.gap1 = (0); + sgilabel->devparam.gap2 = (0); + sgilabel->devparam.sparecyl = (0); + sgilabel->devparam.pcylcount = SSWAP16(geometry.cylinders); + sgilabel->devparam.head_vol0 = SSWAP16(0); + sgilabel->devparam.ntrks = SSWAP16(geometry.heads); + /* tracks/cylinder (heads) */ + sgilabel->devparam.cmd_tag_queue_depth = (0); + sgilabel->devparam.unused0 = (0); + sgilabel->devparam.unused1 = SSWAP16(0); + sgilabel->devparam.nsect = SSWAP16(geometry.sectors); + /* sectors/track */ + sgilabel->devparam.bytes = SSWAP16(512); + sgilabel->devparam.ilfact = SSWAP16(1); + sgilabel->devparam.flags = SSWAP32(TRACK_FWD|\ + IGNORE_ERRORS|RESEEK); + sgilabel->devparam.datarate = SSWAP32(0); + sgilabel->devparam.retries_on_error = SSWAP32(1); + sgilabel->devparam.ms_per_word = SSWAP32(0); + sgilabel->devparam.xylogics_gap1 = SSWAP16(0); + sgilabel->devparam.xylogics_syncdelay = SSWAP16(0); + sgilabel->devparam.xylogics_readdelay = SSWAP16(0); + sgilabel->devparam.xylogics_gap2 = SSWAP16(0); + sgilabel->devparam.xylogics_readgate = SSWAP16(0); + sgilabel->devparam.xylogics_writecont = SSWAP16(0); + memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 ); + memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partition)*16 ); + sgi_label = 1; + partitions = 16; + volumes = 15; + sgi_set_entire(); + sgi_set_volhdr(); + for (i = 0; i < 4; i++) + { + if( old[i].sysid ) + { + sgi_set_partition( i, old[i].start, old[i].nsect, old[i].sysid ); + } + } + return; +} + +void +sgi_set_ilfact( void ) +{ + /* do nothing in the beginning */ +} + +void +sgi_set_rspeed( void ) +{ + /* do nothing in the beginning */ +} + +void +sgi_set_pcylcount( void ) +{ + /* do nothing in the beginning */ +} + +void +sgi_set_xcyl( void ) +{ + /* do nothing in the beginning */ +} + +void +sgi_set_ncyl( void ) +{ + /* do nothing in the beginning */ +} + +/* _____________________________________________________________ + */ + +sgiinfo* +fill_sgiinfo( void ) +{ + sgiinfo*info=calloc( 1, sizeof(sgiinfo) ); + info->magic=SSWAP32(SGI_INFO_MAGIC); + info->b1=SSWAP32(-1); + info->b2=SSWAP16(-1); + info->b3=SSWAP16(1); + /* You may want to replace this string !!!!!!! */ + strcpy( info->scsi_string, "IBM OEM 0662S12 3 30" ); + strcpy( info->serial, "0000" ); + info->check1816 = SSWAP16(18*256 +16 ); + strcpy( info->installer, "Sfx version 5.3, Oct 18, 1994" ); + return info; +} diff --git a/fdisk/fdisksgilabel.h b/fdisk/fdisksgilabel.h new file mode 100644 index 000000000..6eb7293f9 --- /dev/null +++ b/fdisk/fdisksgilabel.h @@ -0,0 +1,133 @@ +#include /* for __u32 etc */ +/* + * Copyright (C) Andreas Neuper, Sep 1998. + * This file may be modified and redistributed under + * the terms of the GNU Public License. + */ + +struct device_parameter { /* 48 bytes */ + unsigned char skew; + unsigned char gap1; + unsigned char gap2; + unsigned char sparecyl; + unsigned short pcylcount; + unsigned short head_vol0; + unsigned short ntrks; /* tracks in cyl 0 or vol 0 */ + unsigned char cmd_tag_queue_depth; + unsigned char unused0; + unsigned short unused1; + unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */ + unsigned short bytes; + unsigned short ilfact; + unsigned int flags; /* controller flags */ + unsigned int datarate; + unsigned int retries_on_error; + unsigned int ms_per_word; + unsigned short xylogics_gap1; + unsigned short xylogics_syncdelay; + unsigned short xylogics_readdelay; + unsigned short xylogics_gap2; + unsigned short xylogics_readgate; + unsigned short xylogics_writecont; +}; + +#define SGI_VOLUME 0x06 +#define SGI_EFS 0x07 +#define SGI_SWAP 0x03 +#define SGI_VOLHDR 0x00 +#define ENTIRE_DISK SGI_VOLUME +/* + * controller flags + */ +#define SECTOR_SLIP 0x01 +#define SECTOR_FWD 0x02 +#define TRACK_FWD 0x04 +#define TRACK_MULTIVOL 0x08 +#define IGNORE_ERRORS 0x10 +#define RESEEK 0x20 +#define ENABLE_CMDTAGQ 0x40 + +typedef struct { + unsigned int magic; /* expect SGI_LABEL_MAGIC */ + unsigned short boot_part; /* active boot partition */ + unsigned short swap_part; /* active swap partition */ + unsigned char boot_file[16]; /* name of the bootfile */ + struct device_parameter devparam; /* 1 * 48 bytes */ + struct volume_directory { /* 15 * 16 bytes */ + unsigned char vol_file_name[8]; /* an character array */ + unsigned int vol_file_start; /* number of logical block */ + unsigned int vol_file_size; /* number of bytes */ + } directory[15]; + struct sgi_partition { /* 16 * 12 bytes */ + unsigned int num_sectors; /* number of blocks */ + unsigned int start_sector; /* sector must be cylinder aligned */ + unsigned int id; + } partitions[16]; + unsigned int csum; + unsigned int fillbytes; +} sgi_partition; + +typedef struct { + unsigned int magic; /* looks like a magic number */ + unsigned int a2; + unsigned int a3; + unsigned int a4; + unsigned int b1; + unsigned short b2; + unsigned short b3; + unsigned int c[16]; + unsigned short d[3]; + unsigned char scsi_string[50]; + unsigned char serial[137]; + unsigned short check1816; + unsigned char installer[225]; +} sgiinfo; + +#define SGI_LABEL_MAGIC 0x0be5a941 +#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b +#define SGI_INFO_MAGIC 0x00072959 +#define SGI_INFO_MAGIC_SWAPPED 0x59290700 +#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 */ +#define sgilabel ((sgi_partition *)buffer) +#define sgiparam (sgilabel->devparam) +extern char buffer[MAX_SECTOR_SIZE]; +extern char changed[MAXIMUM_PARTS]; +extern uint heads, sectors, cylinders; +extern int show_begin; +extern int sgi_label; +extern char *partition_type(unsigned char type); +extern void update_units(void); +extern char read_chars(char *mesg); + +/* fdisksgilabel.c */ +extern struct systypes sgi_sys_types[]; +extern void sgi_nolabel( void ); +extern int check_sgi_label( void ); +extern void sgi_list_table( int xtra ); +extern void sgi_change_sysid( int i, int sys ); +extern int sgi_get_start_sector( int i ); +extern int sgi_get_num_sectors( int i ); +extern int sgi_get_sysid( int i ); +extern void sgi_delete_partition( int i ); +extern void sgi_add_partition( int n, int sys ); +extern void create_sgilabel( void ); +extern void create_sgiinfo( void ); +extern int verify_sgi( int verbose ); +extern void sgi_write_table( void ); +extern void sgi_set_ilfact( void ); +extern void sgi_set_rspeed( void ); +extern void sgi_set_pcylcount( void ); +extern void sgi_set_xcyl( void ); +extern void sgi_set_ncyl( void ); +extern void sgi_set_bootpartition( int i ); +extern void sgi_set_swappartition( int i ); +extern int sgi_get_bootpartition( void ); +extern int sgi_get_swappartition( void ); +extern void sgi_set_bootfile( const char* aFile ); +extern const char *sgi_get_bootfile( void ); diff --git a/fdisk/fdisksunlabel.c b/fdisk/fdisksunlabel.c new file mode 100644 index 000000000..708377379 --- /dev/null +++ b/fdisk/fdisksunlabel.c @@ -0,0 +1,690 @@ +/* + * 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. + */ + +#include /* stderr */ +#include /* uint */ +#include /* strstr */ +#include /* write */ +#include /* ioctl */ +#include /* stat */ + +#include +#if 1 +#include /* SCSI_IOCTL_GET_IDLUN */ +#endif +#include /* FLOPPY_MAJOR */ +#include /* HDIO_GETGEO */ + +#include "fdisk.h" +#include "fdisksunlabel.h" + +static int other_endian = 0; +static int scsi_disk = 0; +static 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 } +}; + +static inline unsigned short __swap16(unsigned short x) { + return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); +} +static 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; +} + +void sun_nolabel(void) +{ + sun_label = 0; + sunlabel->magic = 0; + partitions = 4; +} + +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}, +}; + +struct sun_predefined_drives * +sun_autoconfigure_scsi() { + struct sun_predefined_drives *p = NULL; + +#ifdef SCSI_IOCTL_GET_IDLUN + unsigned int id[2]; + char buffer[2048]; + char buffer2[2048]; + FILE *pfd; + char *vendor; + char *model; + char *q; + int i; + + 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 found 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); + } + } +#endif + return p; +} + +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) { + p = sun_autoconfigure_scsi(); + 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 { + heads = read_int(1,heads,1024,0,"Heads"); + sectors = read_int(1,sectors,1024,0,"Sectors/track"); + if (cylinders) + cylinders = read_int(1,cylinders-2,65535,0,"Cylinders"); + else + cylinders = read_int(1,0,65535,0,"Cylinders"); + sunlabel->nacyl = + SSWAP16(read_int(0,2,65535,0, + "Alternate cylinders")); + sunlabel->pcylcount = + SSWAP16(read_int(0,cylinders+SSWAP16(sunlabel->nacyl), + 65535,0,"Physical cylinders")); + sunlabel->rspeed = + SSWAP16(read_int(1,5400,100000,0, + "Rotation speed (rpm)")); + sunlabel->ilfact = + SSWAP16(read_int(1,1,32,0,"Interleave factor")); + sunlabel->sparecyl = + SSWAP16(read_int(0,0,sectors,0, + "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, 0, mesg); + else + first = read_int(scround(start), scround(stop)+1, + scround(stop), 0, mesg); + if (unit_flag) + first *= display_factor; + else + /* Starting sector has to be properly aligned */ + first = (first + heads * sectors - 1) / (heads * sectors); + if (n == 2 && first != 0) + printf ("\ +It is highly recommended that the 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), + 0, mesg); + else if (n == 2 && !first) + last = read_int(scround(first), scround(stop2), scround(stop2), + scround(first), mesg); + else + last = read_int(scround(first), scround(stop), scround(stop), + scround(first), 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 %u " + "sectors\n", + (uint) 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 Start End Blocks Id System\n", + w + 1, "Device"); + 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( + "%*s%-2d %c%c %9ld %9ld %9ld%c %2x %s\n", +/* device */ w, disk_device, i + 1, +/* flags */ (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', + (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ', +/* start */ (long) scround(start), +/* end */ (long) scround(start+len), +/* odd flag on end */ (long) 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, 0, + "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, 0, + "Extra sectors per cylinder")); +} + +void +sun_set_ilfact(void) { + sunlabel->ilfact = + SSWAP16(read_int(1, SSWAP16(sunlabel->ilfact), 32, 0, + "Interleave factor")); +} + +void +sun_set_rspeed(void) { + sunlabel->rspeed = + SSWAP16(read_int(1, SSWAP16(sunlabel->rspeed), 100000, 0, + "Rotation speed (rpm)")); +} + +void +sun_set_pcylcount(void) { + sunlabel->pcylcount = + SSWAP16(read_int(0, SSWAP16(sunlabel->pcylcount), 65535, 0, + "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); +} + diff --git a/fdisk/fdisksunlabel.h b/fdisk/fdisksunlabel.h new file mode 100644 index 000000000..d9d3706d3 --- /dev/null +++ b/fdisk/fdisksunlabel.h @@ -0,0 +1,74 @@ +#include /* for __u32 etc */ + +typedef struct { + unsigned char info[128]; /* Informative text string */ + unsigned char spare0[14]; + struct sun_info { + unsigned char spare1; + unsigned char id; + unsigned char spare2; + unsigned char flags; + } infos[8]; + unsigned char spare1[246]; /* Boot information etc. */ + unsigned short rspeed; /* Disk rotational speed */ + unsigned short pcylcount; /* Physical cylinder count */ + unsigned short sparecyl; /* extra sects per cylinder */ + unsigned char spare2[4]; /* More magic... */ + unsigned short ilfact; /* Interleave factor */ + unsigned short ncyl; /* Data cylinder count */ + unsigned short nacyl; /* Alt. cylinder count */ + unsigned short ntrks; /* Tracks per cylinder */ + unsigned short nsect; /* Sectors per track */ + unsigned char spare3[4]; /* Even more magic... */ + struct sun_partition { + __u32 start_cylinder; + __u32 num_sectors; + } partitions[8]; + unsigned short magic; /* Magic number */ + unsigned short csum; /* Label xor'd checksum */ +} sun_partition; + +#define SUN_LABEL_MAGIC 0xDABE +#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA +#define sunlabel ((sun_partition *)buffer) +#define SSWAP16(x) (other_endian ? __swap16(x) \ + : (__u16)(x)) +#define SSWAP32(x) (other_endian ? __swap32(x) \ + : (__u32)(x)) + +#define scround(x) ((x+(display_factor-1)*unit_flag)/display_factor) + +/* fdisk.c */ +extern char changed[MAXIMUM_PARTS]; +extern char buffer[MAX_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 sun_nolabel(void); +extern void create_sunlabel(void); +extern void sun_delete_partition(int i); +extern void sun_change_sysid(int i, int sys); +extern void sun_list_table(int xtra); +extern void verify_sun(void); +extern void add_sun_partition(int n, int sys); +extern void sun_write_table(void); +extern void sun_set_alt_cyl(void); +extern void sun_set_ncyl(int cyl); +extern void sun_set_xcyl(void); +extern void sun_set_ilfact(void); +extern void sun_set_rspeed(void); +extern void sun_set_pcylcount(void); +extern void toggle_sunflags(int i, unsigned char mask); + diff --git a/fdisk/llseek.c b/fdisk/llseek.c new file mode 100644 index 000000000..a9cd5a3ac --- /dev/null +++ b/fdisk/llseek.c @@ -0,0 +1,102 @@ +/* + * llseek.c -- stub calling the llseek system call + * + * Copyright (C) 1994 Remy Card. This file may be redistributed + * under the terms of the GNU Public License. + */ + +#include + +#include +#include + +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +extern ext2_loff_t ext2_llseek (unsigned int, ext2_loff_t, unsigned int); + +#ifdef __linux__ + +#ifdef HAVE_LLSEEK +#include + +#else /* HAVE_LLSEEK */ + +#ifdef __alpha__ + +#define my_llseek lseek + +#else +#include /* for __NR__llseek */ + +static int _llseek (unsigned int, unsigned long, + unsigned long, ext2_loff_t *, unsigned int); + +static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, + unsigned long, offset_low,ext2_loff_t *,result, + unsigned int, origin) + +static ext2_loff_t my_llseek (unsigned int fd, ext2_loff_t offset, + unsigned int origin) +{ + ext2_loff_t result; + int retval; + + retval = _llseek (fd, ((unsigned long long) offset) >> 32, + ((unsigned long long) offset) & 0xffffffff, + &result, origin); + return (retval == -1 ? (ext2_loff_t) retval : result); +} + +#endif /* __alpha__ */ + +#endif /* HAVE_LLSEEK */ + +ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, + unsigned int origin) +{ + ext2_loff_t result; + static int do_compat = 0; + + if (!do_compat) { + result = my_llseek (fd, offset, origin); + if (!(result == -1 && errno == ENOSYS)) + return result; + + /* + * Just in case this code runs on top of an old kernel + * which does not support the llseek system call + */ + do_compat = 1; + /* + * Now try ordinary lseek. + */ + } + + 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 */ + +ext2_loff_t ext2_llseek (unsigned int fd, ext2_loff_t offset, + unsigned int origin) +{ + if ((sizeof(off_t) < sizeof(ext2_loff_t)) && + (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { + errno = EINVAL; + return -1; + } + return lseek (fd, (off_t) offset, origin); +} + +#endif /* linux */ + + diff --git a/fdisk/sfdisk.8 b/fdisk/sfdisk.8 new file mode 100644 index 000000000..e7f3e82b6 --- /dev/null +++ b/fdisk/sfdisk.8 @@ -0,0 +1,506 @@ +.\" Copyright 1995 Andries E. Brouwer (aeb@cwi.nl) +.\" May be distributed under the GNU General Public License +.\" The `DOS 6.x Warning' was taken from the old fdisk.8, which says +.\" -- Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu) +.\" -- May be distributed under the GNU General Public License +.\" The `DRDOS Warning' was taken from a net post by Stephen Tweedie. +.\" +.TH SFDISK 8 "1 September 1995" "Linux 1.3.23" "Linux Programmer's Manual" +.SH NAME +sfdisk \- Partition table manipulator for Linux +.SH SYNOPSIS +.BR sfdisk " [options] device" +.br +.BR "sfdisk \-s " [partition] +.SH DESCRIPTION +.B sfdisk +has four (main) uses: list the size of a partition, list the partitions +on a device, check the partitions on a device, and - very dangerous - +repartition a device. + +.SS "List Sizes" +.BI "sfdisk \-s " partition +gives the size of +.I partition +in blocks. This may be useful in connection with programs like +.B mkswap +or so. Here +.I partition +is usually something like +.I /dev/hda1 +or +.IR /dev/sdb12 , +but may also be an entire disk, like +.IR /dev/xda . +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s /dev/hda9 +81599 +% +.if t .ft R +.fi +.RE +If the partition argument is omitted, +.B sfdisk +will list the sizes of all disks, and the total: +.br +.RS +.nf +.if t .ft CW +% sfdisk \-s +/dev/hda: 208896 +/dev/hdb: 1025136 +/dev/hdc: 1031063 +/dev/sda: 8877895 +/dev/sdb: 1758927 +total: 12901917 blocks +% +.if t .ft R +.fi +.RE + +.SS "List Partitions" +The second type of invocation: +.BI "sfdisk \-l " "[options] device" +will list the partitions on this device. +If the device argument is omitted, the partitions on all hard disks +are listed. +.br +.nf +.if t .ft CW +% sfdisk \-l /dev/hdc + +Disk /dev/hdc: 16 heads, 63 sectors, 2045 cylinders +Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hdc1 0+ 406 407\- 205096+ 83 Linux native +/dev/hdc2 407 813 407 205128 83 Linux native +/dev/hdc3 814 2044 1231 620424 83 Linux native +/dev/hdc4 0 \- 0 0 0 Empty +% +.if t .ft R +.fi +The trailing \- and + signs indicate that rounding has taken place, +and that the actual value is slightly less (more). +To see the exact values, ask for a listing with sectors as unit. + +.SS "Check partitions" +The third type of invocation: +.BI "sfdisk \-V " device +will apply various consistency checks to the partition tables on +.IR device . +It prints `OK' or complains. The \-V option can be used together +with \-l. In a shell script one might use +.BI "sfdisk \-V \-q " device +which only returns a status. + +.SS "Create partitions" +The fourth type of invocation: +.BI "sfdisk " device +will cause +.B sfdisk +to read the specification for the desired partitioning of +.I device +from its standard input, and then to change the partition tables +on that disk. Thus, it is possible to use +.B sfdisk +from a shell script. When +.B sfdisk +determines that its standard input is a terminal, it will be +conversational; otherwise it will abort on any error. +.LP +BE EXTREMELY CAREFUL - ONE TYPING MISTAKE AND ALL YOUR DATA IS LOST +.LP +As a precaution, one can save the sectors changed by +.BR sfdisk : +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-O hdd-partition-sectors.save +\&... +% +.if t .ft R +.fi +.RE +.LP +Then, if you discover that you did something stupid before anything +else has been written to disk, it may be possible to recover +the old situation with +.RS +.nf +.if t .ft CW +% sfdisk /dev/hdd \-I hdd-partition-sectors.save +% +.if t .ft R +.fi +.RE +.LP +(This is not the same as saving the old partition table: +a readable version of the old partition table can be saved +using the \-d option. However, if you create logical partitions, +the sectors describing them are located somewhere on disk, +possibly on sectors that were not part of the partition table +before. Thus, the information the \-O option saves is not a binary +version of the output of \-d.) + +There are many options. + +.SH OPTIONS +.TP +.BR \-v " or " \-\-version +Print version number of +.B sfdisk +and exit immediately. +.TP +.BR \-? " or " \-\-help +Print a usage message and exit immediately. +.TP +.BR \-T " or " \-\-list-types +Print the recognized types (system Id's). +.TP +.BR \-s " or " \-\-show\-size +List the size of a partition. +.TP +.BR \-g " or " \-\-show\-geometry +List the kernel's idea of the geometry of the indicated disk(s). +.TP +.BR \-l " or " \-\-list +List the partitions of a device. +.TP +.BR \-d +Dump the partitions of a device in a format useful as input +to sfdisk. For example, +.br +.nf +.if t .ft CW + % sfdisk -d /dev/hda > hda.out + % sfdisk /dev/hda < hda.out +.if t .ft R +.fi +will correct the bad last extended partition that the OS/2 +fdisk creates. +.TP +.BR \-V " or " \-\-verify +Test whether partitions seem correct. (See above.) +.TP +.BR \-i " or " \-\-increment +Number cylinders etc. starting from 1 instead of 0. +.TP +.BI \-N " number" +Change only the single partition indicated. For example: +.br +.nf +.if t .ft CW + % sfdisk /dev/hdb \-N5 + ,,,* + % +.if t .ft R +.fi +will make the fifth partition on /dev/hdb bootable (`active') +and change nothing else. (Probably this fifth partition +is called /dev/hdb5, but you are free to call it something else, +like `/my_equipment/disks/2/5' or so). +.TP +.BI \-A "number" +Make the indicated partition(s) active, and all others inactive. +.TP +.BI \-c " or " \-\-id " number [Id]" +If no Id argument given: print the partition Id of the indicated +partition. If an Id argument is present: change the type (Id) of +the indicated partition to the given value. +This option has the two very long forms \-\-print\-id and \-\-change\-id. +For example: +.br +.nf +.if t .ft CW + % sfdisk --print-id /dev/hdb 5 + 6 + % sfdisk --change-id /dev/hdb 5 83 + OK +.if t .ft R +.fi +first reports that /dev/hdb5 has Id 6, and then changes that into 83. +.TP +.BR \-uS " or " \-uB " or " \-uC " or " \-uM +Accept or report in units of sectors (blocks, cylinders, megabytes, +respectively). The default is cylinders, at least when the geometry +is known. +.TP +.BR \-x " or " \-\-show\-extended +Also list non-primary extended partitions on output, +and expect descriptors for them on input. +.TP +.BI \-C " cylinders" +Specify the number of cylinders, possibly overriding what the kernel thinks. +.TP +.BI \-H " heads" +Specify the number of heads, possibly overriding what the kernel thinks. +.TP +.BI \-S " sectors" +Specify the number of sectors, possibly overriding what the kernel thinks. +.TP +.BR \-f " or " \-\-force +Do what I say, even if it is stupid. +.TP +.BR \-q " or " \-\-quiet +Suppress warning messages. +.TP +.BR \-L " or " \-\-Linux +Do not complain about things irrelevant for Linux. +.TP +.BR \-D " or " \-\-DOS +For DOS-compatibility: waste a little space. +(More precisely: if a partition cannot contain sector 0, +e.g. because that is the MBR of the device, or contains +the partition table of an extended partition, then +.B sfdisk +would make it start the next sector. However, when this +option is given it skips to the start of the next track, +wasting for example 33 sectors (in case of 34 sectors/track), +just like certain versions of DOS do.) +Certain Disk Managers and boot loaders (such as OSBS, but not +LILO or the OS/2 Boot Manager) also live in this empty space, +so maybe you want this option if you use one. +.TP +.BR \-\-IBM " or " \-\-leave\-last +Certain IBM diagnostic programs assume that they can use the +last cylinder on a disk for disk-testing purposes. If you think +you might ever run such programs, use this option to tell +.B sfdisk +that it should not allocate the last cylinder. +Sometimes the last cylinder contains a bad sector table. +.TP +.B \-n +Go through all the motions, but do not actually write to disk. +.TP +.B \-R +Only execute the BLKRRPART ioctl (to make the kernel re-read +the partition table). This can be useful for checking in advance +that the final BLKRRPART will be successful, and also when you +changed the partition table `by hand' (e.g., using dd from a backup). +If the kernel complains (`device busy for revalidation (usage = 2)') +then something still uses the device, and you still have to unmount +some file system, or say swapoff to some swap partition. +.TP +.B \-\-no\-reread +When starting a repartitioning of a disk, sfdisk checks that this disk +is not mounted, or in use as a swap device, and refuses to continue +if it is. This option suppresses the test. (On the other hand, the \-f +option would force sfdisk to continue even when this test fails.) +.TP +.BI \-O " file" +Just before writing the new partition, output the sectors +that are going to be overwritten to +.I file +(where hopefully +.I file +resides on another disk, or on a floppy). +.TP +.BI \-I " file" +After destroying your filesystems with an unfortunate +.B sfdisk +command, you would have been able to restore the old situation +if only you had preserved it using the \-O flag. + +.SH THEORY +Block 0 of a disk (the Master Boot Record) contains among +other things four partition descriptors. The partitions +described here are called +.I primary +partitions. +.LP +A partition descriptor has 6 fields: +.br +.nf +.RS +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + hsc begin_hsc; + unsigned char id; + hsc end_hsc; + unsigned int starting_sector; + unsigned int nr_of_sectors; +} +.RE +.fi +.LP +The two hsc fields indicate head, sector and cylinder of the +begin and the end of the partition. Since each hsc field only +takes 3 bytes, only 24 bits are available, which does not +suffice for big disks (say > 8GB). In fact, due to the wasteful +representation (that uses a byte for the number of heads, which +is typically 16), problems already start with 0.5GB. +However Linux does not use these fields, and problems can arise +only at boot time, before Linux has been started. For more +details, see the +.B lilo +documentation. +.LP +Each partition has a type, its `Id', and if this type is 5 +.IR "" "(`" "extended partition" "')" +the starting sector of the partition +again contains 4 partition descriptors. MSDOS only uses the +first two of these: the first one an actual data partition, +and the second one again an extended partition (or empty). +In this way one gets a chain of extended partitions. +Other operating systems have slightly different conventions. +Linux also accepts type 85 as equivalent to 5 - this can be +useful if one wants to have extended partitions under Linux past +the 1024 cylinder boundary, without DOS FDISK hanging. +(If there is no good reason, you should just use 5, which is +understood by other systems.) +.LP +Partitions that are not primary or extended are called +.IR logical . +Often, one cannot boot from logical partitions (because the +process of finding them is more involved than just looking +at the MBR). +Note that of an extended partition only the Id and the start +are used. There are various conventions about what to write +in the other fields. One should not try to use extended partitions +for data storage or swap. + +.SH "INPUT FORMAT" +.B sfdisk +reads lines of the form +.br +.RS + +.RE +where each line fills one partition descriptor. +.LP +Fields are separated by whitespace, or comma or semicolon possibly +followed by whitespace; initial and trailing whitespace is ignored. +Numbers can be octal, decimal or hexadecimal, decimal is default. +When a field is absent or empty, a default value is used. +.LP +The parts can (and probably should) be omitted - +.B sfdisk +computes them from and and the disk geometry +as given by the kernel or specified using the \-H, \-S, \-C flags. +.LP +Bootable is specified as [*|\-], with as default not-bootable. +(The value of this field is irrelevant for Linux - when Linux +runs it has been booted already - but might play a role for +certain boot loaders and for other operating systems. +For example, when there are several primary DOS partitions, +DOS assigns C: to the first among these that is bootable.) +.LP +Id is given in hex, without the 0x prefix, or is [E|S|L|X], where +L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), E +is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED (85). +.LP +The default value of start is the first nonassigned sector/cylinder/... +.LP +The default value of size is as much as possible (until next +partition or end-of-disk). +.LP +However, for the four partitions inside an extended partition, +the defaults are: Linux partition, Extended partition, Empty, Empty. +.LP +But when the \-N option (change a single partition only) is given, +the default for each field is its previous value. + +.SH EXAMPLE +The command +.RS +.nf +.if t .ft CW +sfdisk /dev/hdc << EOF +0,407 +,407 +; +; +EOF +.if t .ft R +.fi +.RE +will partition /dev/hdc just as indicated above. + +With the \-x option, the number of input lines must be a multiple of 4: +you have to list the two empty partitions that you never want +using two blank lines. Without the \-x option, you give one line +for the partitions inside a extended partition, instead of four, +and terminate with end-of-file (^D). +(And +.B sfdisk +will assume that your input line represents the first of four, +that the second one is extended, and the 3rd and 4th are empty.) + +.SH "DOS 6.x WARNING" + +The DOS 6.x FORMAT command looks for some information in the first +sector of the data area of the partition, and treats this information +as more reliable than the information in the partition table. DOS +FORMAT expects DOS FDISK to clear the first 512 bytes of the data area +of a partition whenever a size change occurs. DOS FORMAT will look at +this extra information even if the /U flag is given -- we consider +this a bug in DOS FORMAT and DOS FDISK. +.LP +The bottom line is that if you use sfdisk to change the size of a +DOS partition table entry, then you must also use +.B dd +to zero the first 512 bytes of that partition before using DOS FORMAT to +format the partition. For example, if you were using sfdisk to make a DOS +partition table entry for /dev/hda1, then (after exiting sfdisk and +rebooting Linux so that the partition table information is valid) you +would use the command "dd if=/dev/zero of=/dev/hda1 bs=512 count=1" to zero +the first 512 bytes of the partition. +.B BE EXTREMELY CAREFUL +if you use the +.B dd +command, since a small typo can make all of the data on your disk useless. + +For best results, you should always use an OS-specific partition table +program. For example, you should make DOS partitions with the DOS FDISK +program and Linux partitions with the Linux sfdisk program. + +.SH "DRDOS WARNINGS" + +Stephen Tweedie reported (930515): `Most reports of superblock +corruption turn out to be due to bad partitioning, with one filesystem +overrunning the start of the next and corrupting its superblock. +I have even had this problem with the supposedly-reliable DRDOS. This +was quite possibly due to DRDOS-6.0's FDISK command. Unless I created +a blank track or cylinder between the DRDOS partition and the +immediately following one, DRDOS would happily stamp all over the +start of the next partition. Mind you, as long as I keep a little +free disk space after any DRDOS partition, I don't have any other +problems with the two coexisting on the one drive.' + +A. V. Le Blanc writes in README.esfdisk: `Dr. DOS 5.0 and 6.0 has been +reported to have problems cooperating with Linux, and with this version +of efdisk in particular. This efdisk sets the system type +to hexadecimal 81. Dr. DOS seems to confuse +this with hexadecimal 1, a DOS code. If you use Dr. DOS, use the +efdisk command 't' to change the system code of any Linux partitions +to some number less than hexadecimal 80; I suggest 41 and 42 for +the moment.' + +A. V. Le Blanc writes in his README.fdisk: `DR-DOS 5.0 and 6.0 +are reported to have difficulties with partition ID codes of 80 or more. +The Linux `fdisk' used to set the system type +of new partitions to hexadecimal 81. DR-DOS seems to confuse this with +hexadecimal 1, a DOS code. The values 82 for swap and 83 for file +systems should not cause problems with DR-DOS. If they do, you may use +the `fdisk' command `t' to change the system code of any Linux +partitions to some number less than hexadecimal 80; I suggest 42 and 43 +for the moment.' + +In fact, it seems that only 4 bits are significant for the DRDOS FDISK, +so that for example 11 and 21 are listed as DOS 2.0. However, DRDOS +itself seems to use the full byte. I have not been able to reproduce +any corruption with DRDOS or its fdisk. + +.SH BUGS +A corresponding interactive +.B cfdisk +(with curses interface) is still lacking. +.LP +There are too many options. + +.SH AUTHOR +A. E. Brouwer (aeb@cwi.nl) diff --git a/fdisk/sfdisk.c b/fdisk/sfdisk.c new file mode 100644 index 000000000..c3f470f89 --- /dev/null +++ b/fdisk/sfdisk.c @@ -0,0 +1,2864 @@ +/* + * sfdisk version 3.0 - aeb - 950813 + * + * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) + * + * This program is free software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: either Version 1 + * or (at your option) any later version. + * + * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, + * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, + * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) + * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. + * This program had (head,sector,cylinder) as basic unit, and was + * (therefore) broken in several ways for the use on larger disks - + * for example, my last patch (from 2.0d to 2.0e) was required + * to allow a partition to cross cylinder 8064, and to write an + * extended partition past the 4GB mark. + * + * The current program is a rewrite from scratch, and I started a + * version numbering at 3.0. + * Andries Brouwer, aeb@cwi.nl, 950813 + * + * Well, a good user interface is still lacking. On the other hand, + * many configurations cannot be handled by any other fdisk. + * I changed the name to sfdisk to prevent confusion. - aeb, 970501 + */ + +#define PROGNAME "sfdisk" +#define VERSION "3.07" +#define DATE "980518" + +#include +#include /* atoi, free */ +#include /* varargs */ +#include /* read, write */ +#include /* O_RDWR */ +#include /* ERANGE */ +#include /* index() */ +#include +#include +#include +#include +#include /* _syscall */ +#include /* HDIO_GETGEO */ +#include /* BLKGETSIZE */ + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* + * Table of contents: + * A. About seeking + * B. About sectors + * C. About heads, sectors and cylinders + * D. About system Ids + * E. About partitions + * F. The standard input + * G. The command line + * H. Listing the current situation + * I. Writing the new situation + */ +int exit_status = 0; + +int force = 0; /* 1: do what I say, even if it is stupid ... */ +int quiet = 0; /* 1: suppress all warnings */ +int Linux = 0; /* 1: suppress warnings irrelevant for Linux */ +int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */ +int dump = 0; /* 1: list in a format suitable for later input */ +int verify = 0; /* 1: check that listed partition is reasonable */ +int no_write = 0; /* 1: do not actually write to disk */ +int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */ +int leave_last = 0; /* 1: don't allocate the last cylinder */ +int opt_list = 0; +char *save_sector_file = NULL; +char *restore_sector_file = NULL; + +void +warn(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + if (!quiet) + vfprintf (stderr, s, p); + va_end(p); +} + +void +error(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); +} + +void +fatal(char *s, ...) { + va_list p; + + va_start(p, s); + fflush(stdout); + fprintf(stderr, "\n" PROGNAME ": "); + vfprintf(stderr, s, p); + va_end(p); + exit(1); +} + +/* + * A. About seeking + */ + +/* + * sseek: seek to specified sector - return 0 on failure + * + * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. + * On the other hand, a 32 bit sector number is OK until 2TB. + * The routines _llseek and sseek below are the only ones that + * know about the loff_t type. + */ +#ifndef __alpha__ +static +_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, + loff_t *, res, uint, wh); +#endif + +int +sseek(char *dev, unsigned int fd, unsigned long s) { + loff_t in, out; + in = ((loff_t) s << 9); + out = 1; + +#ifndef __alpha__ + if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) { +#else + if ((out = lseek(fd, in, SEEK_SET)) != in) { +#endif + perror("llseek"); + error("seek error on %s - cannot seek to %lu\n", dev, s); + return 0; + } + + if (in != out) { + error("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n", + (uint)(in>>32), (uint)(in & 0xffffffff), + (uint)(out>>32), (uint)(out & 0xffffffff)); + return 0; + } + return 1; +} + +/* + * B. About sectors + */ + +/* + * We preserve all sectors read in a chain - some of these will + * have to be modified and written back. + */ +struct sector { + struct sector *next; + unsigned long sectornumber; + int to_be_written; + char data[512]; +} *sectorhead; + +void +free_sectors(void) { + struct sector *s; + + while (sectorhead) { + s = sectorhead; + sectorhead = s->next; + free(s); + } +} + +struct sector * +get_sector(char *dev, int fd, unsigned long sno) { + struct sector *s; + + for(s = sectorhead; s; s = s->next) + if(s->sectornumber == sno) + return s; + + if (!sseek(dev, fd, sno)) + return 0; + + if (!(s = (struct sector *) malloc(sizeof(struct sector)))) + fatal("out of memory - giving up\n"); + + if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", dev, sno); + free(s); + return 0; + } + + s->next = sectorhead; + sectorhead = s; + s->sectornumber = sno; + s->to_be_written = 0; + + return s; +} + +int +msdos_signature (struct sector *s) { + if (*(unsigned short *) (s->data + 0x1fe) != 0xaa55) { + error("ERROR: sector %lu does not have an msdos signature\n", + s->sectornumber); + return 0; + } + return 1; +} + +int +write_sectors(char *dev, int fd) { + struct sector *s; + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + if (!sseek(dev, fd, s->sectornumber)) + return 0; + if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { + perror("write"); + error("write error on %s - cannot write sector %lu\n", + dev, s->sectornumber); + return 0; + } + s->to_be_written = 0; + } + return 1; +} + +void +ulong_to_chars(unsigned long u, char *uu) { + int i; + + for(i=0; i<4; i++) { + uu[i] = (u & 0xff); + u >>= 8; + } +} + +unsigned long +chars_to_ulong(unsigned char *uu) { + int i; + unsigned long u = 0; + + for(i=3; i>=0; i--) + u = (u << 8) | uu[i]; + return u; +} + +int +save_sectors(char *dev, int fdin) { + struct sector *s; + char ss[516]; + int fdout; + + fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); + if (fdout < 0) { + perror(save_sector_file); + error("cannot open partition sector save file (%s)\n", + save_sector_file); + return 0; + } + + for (s = sectorhead; s; s = s->next) + if (s->to_be_written) { + ulong_to_chars(s->sectornumber, ss); + if (!sseek(dev, fdin, s->sectornumber)) + return 0; + if (read(fdin, ss+4, 512) != 512) { + perror("read"); + error("read error on %s - cannot read sector %lu\n", + dev, s->sectornumber); + return 0; + } + if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { + perror("write"); + error("write error on %s\n", save_sector_file); + return 0; + } + } + return 1; +} + +void reread_disk_partition(char *dev, int fd); + +int +restore_sectors(char *dev) { + int fdin, fdout, ct; + struct stat statbuf; + char *ss0, *ss; + unsigned long sno; + + if (stat(restore_sector_file, &statbuf) < 0) { + perror(restore_sector_file); + error("cannot stat partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (statbuf.st_size % 516) { + error("partition restore file has wrong size - not restoring\n"); + return 0; + } + if (!(ss = (char *) malloc(statbuf.st_size))) { + error("out of memory?\n"); + return 0; + } + fdin = open(restore_sector_file, O_RDONLY); + if (fdin < 0) { + perror(restore_sector_file); + error("cannot open partition restore file (%s)\n", + restore_sector_file); + return 0; + } + if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { + perror("read"); + error("error reading %s\n", restore_sector_file); + return 0; + } + + fdout = open(dev, O_WRONLY); + if (fdout < 0) { + perror(dev); + error("cannot open device %s for writing\n", dev); + return 0; + } + + ss0 = ss; + ct = statbuf.st_size/516; + while(ct--) { + sno = chars_to_ulong(ss); + if (!sseek(dev, fdout, sno)) + return 0; + if (write(fdout, ss+4, 512) != 512) { + perror(dev); + error("error writing sector %lu on %s\n", sno, dev); + return 0; + } + ss += 516; + } + free(ss0); + + reread_disk_partition(dev, fdout); + + return 1; +} + +/* + * C. About heads, sectors and cylinders + */ + +/* + * defines HDIO_GETGEO and + * struct hd_geometry { + * unsigned char heads; + * unsigned char sectors; + * unsigned short cylinders; + * unsigned long start; + * }; + */ + +unsigned long cylindersize; +unsigned long heads, sectors, cylinders; +unsigned long specified_heads, specified_sectors, specified_cylinders; + +void +get_cylindersize(char *dev, int fd, int silent) { + struct hd_geometry g; + int ioctl_ok = 0; + + heads = sectors = cylinders = 0; + + if (!ioctl(fd, HDIO_GETGEO, &g)) { + ioctl_ok = 1; + + heads = g.heads; + sectors = g.sectors; + cylinders = g.cylinders; + } + + if (specified_heads) + heads = specified_heads; + if (specified_sectors) + sectors = specified_sectors; + if (specified_cylinders) + cylinders = specified_cylinders; + + cylindersize = heads * sectors; + + if (ioctl_ok) { + if (g.start && !force) { + warn( + "Warning: start=%d - this looks like a partition rather than\n" + "the entire disk. Using fdisk on it is probably meaningless.\n" + "[Use the --force option if you really want this]\n", g.start); + exit(1); + } + if (heads != g.heads) + warn("Warning: HDIO_GETGEO says that there are %d heads\n", + g.heads); + if (sectors != g.sectors) + warn("Warning: HDIO_GETGEO says that there are %d sectors\n", + g.sectors); + if (cylinders != g.cylinders) + warn("Warning: HDIO_GETGEO says that there are %d cylinders\n", + g.cylinders); + } else if (!silent) + if (!heads || !sectors || !cylinders) + printf("Disk %s: cannot get geometry\n", dev); + if (sectors > 63) + warn("Warning: unlikely number of sectors (%d) - usually at most 63\n" + "This will give problems with all software that uses C/H/S addressing.\n", + sectors); + if (!silent) + printf("\nDisk %s: %lu heads, %lu sectors, %lu cylinders\n", + dev, heads, sectors, cylinders); +} + +typedef struct { unsigned char h,s,c; } chs; /* has some c bits in s */ +chs zero_chs = { 0,0,0 }; + +typedef struct { unsigned long h,s,c; } longchs; +longchs zero_longchs; + +chs +longchs_to_chs (longchs aa) { + chs a; + + if (aa.h < 256 && aa.s < 64 && aa.c < 1024) { + a.h = aa.h; + a.s = aa.s | ((aa.c >> 2) & 0xc0); + a.c = (aa.c & 0xff); + } else if (heads && sectors) { + a.h = heads - 1; + a.s = sectors | 0xc0; + a.c = 0xff; + } else + a = zero_chs; + return a; +} + +longchs +chs_to_longchs (chs a) { + longchs aa; + + aa.h = a.h; + aa.s = (a.s & 0x3f); + aa.c = (a.s & 0xc0); + aa.c = (aa.c << 2) + a.c; + return aa; +} + +longchs +ulong_to_longchs (unsigned long sno) { + longchs aa; + + if (heads && sectors && cylindersize) { + aa.s = 1 + sno % sectors; + aa.h = (sno / sectors) % heads; + aa.c = sno / cylindersize; + return aa; + } else { + return zero_longchs; + } +} + +unsigned long +longchs_to_ulong (longchs aa) { + return (aa.c*cylindersize + aa.h*sectors + aa.s - 1); +} + +chs +ulong_to_chs (unsigned long sno) { + return longchs_to_chs(ulong_to_longchs(sno)); +} + +unsigned long +chs_to_ulong (chs a) { + return longchs_to_ulong(chs_to_longchs(a)); +} + +int +is_equal_chs (chs a, chs b) { + return (a.h == b.h && a.s == b.s && a.c == b.c); +} + +int +chs_ok (chs a, char *v, char *w) { + longchs aa = chs_to_longchs(a); + int ret = 1; + + if (is_equal_chs(a, zero_chs)) + return 1; + if (heads && aa.h >= heads) { + warn("%s of partition %s has impossible value for head: " + "%d (should be in 0-%d)\n", w, v, aa.h, heads-1); + ret = 0; + } + if (sectors && (aa.s == 0 || aa.s > sectors)) { + warn("%s of partition %s has impossible value for sector: " + "%d (should be in 1-%d)\n", w, v, aa.s, sectors); + ret = 0; + } + if (cylinders && aa.c >= cylinders) { + warn("%s of partition %s has impossible value for cylinders: " + "%d (should be in 0-%d)\n", w, v, aa.c, cylinders-1); + ret = 0; + } + return ret; +} + +/* + * D. About system Ids + */ + +#define EMPTY_PARTITION 0 +#define EXTENDED_PARTITION 5 +#define 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 + * and SFS and several other sources. + */ +struct systypes { + unsigned char type; + char *name; +} sys_types[] = { + {0, "Empty"}, + {1, "DOS 12-bit FAT"}, /* Primary DOS with 12-bit FAT */ + {2, "XENIX /"}, /* XENIX / filesystem */ + {3, "XENIX /usr"}, /* XENIX /usr filesystem */ + {4, "DOS 16-bit FAT <32M"}, /* Primary DOS with 16-bit FAT */ + {5, "DOS Extended"}, /* DOS 3.3+ extended partition */ + {6, "DOS 16-bit FAT >=32M"}, + {7, "HPFS / NTFS"}, + {8, "AIX boot or SplitDrive"}, + {9, "AIX data or Coherent"}, + {0x0a, "OS/2 Boot Manager"}, + {0x0b, "Win95 FAT32"}, + {0x0c, "Win95 FAT32 (LBA)"}, + {0x0e, "Win95 FAT16 (LBA)"}, + {0x0f, "Win95 Extended (LBA)"}, + {0x10, "OPUS"}, + {0x11, "Hidden DOS FAT12"}, + {0x12, "Compaq diagnostics"}, + {0x14, "Hidden DOS FAT16"}, + {0x16, "Hidden DOS FAT16 (big)"}, + {0x17, "Hidden HPFS/NTFS"}, + {0x18, "AST Windows swapfile"}, + {0x24, "NEC DOS"}, + {0x3c, "PartitionMagic recovery"}, + {0x40, "Venix 80286"}, + {0x41, "Linux/MINIX (sharing disk with DRDOS)"}, + {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, + {0x43, "Linux native (sharing disk with DRDOS)"}, + {0x50, "DM (disk manager)"}, + {0x51, "DM6 Aux1 (or Novell)"}, + {0x52, "CP/M or Microport SysV/AT"}, + {0x53, "DM6 Aux3"}, + {0x54, "DM6"}, + {0x55, "EZ-Drive (disk manager)"}, + {0x56, "Golden Bow (disk manager)"}, + {0x5c, "Priam Edisk (disk manager)"}, + {0x61, "SpeedStor"}, + {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"}, + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x70, "DiskSecure Multi-Boot"}, + {0x75, "PC/IX"}, + {0x77, "QNX4.x"}, + {0x78, "QNX4.x 2nd part"}, + {0x79, "QNX4.x 3rd part"}, + {0x80, "MINIX until 1.4a"}, + {0x81, "MINIX / old Linux"}, + {0x82, "Linux swap"}, + {0x83, "Linux native"}, + {0x84, "OS/2 hidden C: drive"}, + {0x85, "Linux extended"}, + {0x86, "NTFS volume set"}, + {0x87, "NTFS volume set"}, + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa0, "IBM Thinkpad hibernation"}, /* according to dan@fch.wimsey.bc.ca */ + {0xa5, "BSD/386"}, /* 386BSD */ + {0xa6, "OpenBSD"}, + {0xa7, "NeXTSTEP 486"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc1, "DRDOS/sec (FAT-12)"}, + {0xc4, "DRDOS/sec (FAT-16, < 32M)"}, + {0xc6, "DRDOS/sec (FAT-16, >= 32M)"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, + {0xe1, "DOS access or SpeedStor 12-bit FAT extended partition"}, + {0xe3, "DOS R/O or SpeedStor"}, + {0xe4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, + {0xeb, "BeOS fs"}, + {0xf1, "SpeedStor"}, + {0xf2, "DOS 3.3+ secondary"}, + {0xf4, "SpeedStor large partition"}, + {0xfe, "SpeedStor >1024 cyl. or LANstep"}, + {0xff, "Xenix Bad Block Table"} +}; + + +const char * +sysname(unsigned char type) { + struct systypes *s; + + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + if (s->type == type) + return s->name; + return "Unknown"; +} + +void +list_types(void) { + struct systypes *s; + + printf("Id Name\n\n"); + for (s = sys_types; s - sys_types < SIZE(sys_types); s++) + printf("%2x %s\n", s->type, s->name); +} + +int +is_extended(unsigned char type) { + return (type == EXTENDED_PARTITION + || type == LINUX_EXTENDED + || type == WIN98_EXTENDED); +} + +int +is_bsd(unsigned char type) { + return (type == BSD_PARTITION); +} + +/* + * E. About partitions + */ + +/* MS/DOS partition */ + +struct partition { + unsigned char bootable; /* 0 or 0x80 */ + chs begin_chs; + unsigned char sys_type; + chs end_chs; + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +/* Unfortunately, partitions are not aligned, and non-Intel machines + are unhappy with non-aligned integers. So, we need a copy by hand. */ +int +copy_to_int(unsigned char *cp) { + unsigned int m; + + m = *cp++; + m += (*cp++ << 8); + m += (*cp++ << 16); + m += (*cp++ << 24); + return m; +} + +void +copy_from_int(int m, char *cp) { + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); m >>= 8; + *cp++ = (m & 0xff); +} + +void +copy_to_part(char *cp, struct partition *p) { + p->bootable = *cp++; + p->begin_chs.h = *cp++; + p->begin_chs.s = *cp++; + p->begin_chs.c = *cp++; + p->sys_type = *cp++; + p->end_chs.h = *cp++; + p->end_chs.s = *cp++; + p->end_chs.c = *cp++; + p->start_sect = copy_to_int(cp); + p->nr_sects = copy_to_int(cp+4); +} + +void +copy_from_part(struct partition *p, char *cp) { + *cp++ = p->bootable; + *cp++ = p->begin_chs.h; + *cp++ = p->begin_chs.s; + *cp++ = p->begin_chs.c; + *cp++ = p->sys_type; + *cp++ = p->end_chs.h; + *cp++ = p->end_chs.s; + *cp++ = p->end_chs.c; + copy_from_int(p->start_sect, cp); + copy_from_int(p->nr_sects, cp+4); +} + +/* Roughly speaking, Linux doesn't use any of the above fields except + for partition type, start sector and number of sectors. (However, + see also linux/drivers/scsi/fdomain.c.) + The only way partition type is used (in the kernel) is the comparison + for equality with EXTENDED_PARTITION (and these Disk Manager types). */ + +struct part_desc { + unsigned long start; + unsigned long size; + unsigned long sector, offset; /* disk location of this info */ + struct partition p; + struct part_desc *ep; /* extended partition containing this one */ + int ptype; +#define DOS_TYPE 0 +#define BSD_TYPE 1 +} zero_part_desc; + +struct part_desc * +outer_extended_partition(struct part_desc *p) { + while (p->ep) + p = p->ep; + return p; +} + +int +is_parent(struct part_desc *pp, struct part_desc *p) { + while (p) { + if (pp == p) + return 1; + p = p->ep; + } + return 0; +} + +struct disk_desc { + struct part_desc partitions[128]; + int partno; +} oldp, newp; + +/* determine where on the disk this information goes */ +void +add_sector_and_offset(struct disk_desc *z) { + int pno; + struct part_desc *p; + + for (pno = 0; pno < z->partno; pno++) { + p = &(z->partitions[pno]); + p->offset = 0x1be + (pno%4)*sizeof(struct partition); + p->sector = (p->ep ? p->ep->start : 0); + } +} + +/* tell the kernel to reread the partition tables */ +int reread_ioctl(int fd) { + if(ioctl(fd, BLKRRPART)) { + perror("BLKRRPART"); + return -1; + } + return 0; +} + +/* reread after writing */ +void +reread_disk_partition(char *dev, int fd) { + printf("Re-reading the partition table ...\n"); + fflush(stdout); + sync(); + sleep(3); /* superfluous since 1.3.20 */ + + if(reread_ioctl(fd)) + printf("The command to re-read the partition table failed\n" + "Reboot your system now, before using mkfs\n"); + + if (close(fd)) { + perror(dev); + printf("Error closing %s\n", dev); + } + printf("\n"); +} + +/* find Linux name of this partition, assuming that it will have a name */ +int +index_to_linux(int pno, struct disk_desc *z) { + int i, ct = 1; + struct part_desc *p = &(z->partitions[0]); + for (i=0; isize > 0 && !is_extended(p->p.sys_type))) + ct++; + return ct; +} + +int +linux_to_index(int lpno, struct disk_desc *z) { + int i, ct = 0; + struct part_desc *p = &(z->partitions[0]); + for (i=0; ipartno && ct < lpno; i++,p++) + if((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) + && ++ct == lpno) + return i; + return -1; +} + +int +asc_to_index(char *pnam, struct disk_desc *z) { + int pnum, pno; + + if (*pnam == '#') { + pno = atoi(pnam+1); + } else { + pnum = atoi(pnam); + pno = linux_to_index(pnum, z); + } + if (!(pno >= 0 && pno < z->partno)) + fatal("%s: no such partition\n", pnam); + return pno; +} + +/* + * List partitions - in terms of sectors, blocks or cylinders + */ +#define F_SECTOR 1 +#define F_BLOCK 2 +#define F_CYLINDER 3 +#define F_MEGABYTE 4 + +int default_format = F_MEGABYTE; +int specified_format = 0; +int show_extended = 0; +int one_only = 0; +int one_only_pno; +int increment = 0; + +void +set_format(char c) { + switch(c) { + default: + printf("unrecognized format - using sectors\n"); + case 'S': specified_format = F_SECTOR; break; + case 'B': specified_format = F_BLOCK; break; + case 'C': specified_format = F_CYLINDER; break; + case 'M': specified_format = F_MEGABYTE; break; + } +} + +unsigned long +unitsize(int format) { + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + case F_CYLINDER: + if(cylindersize) return cylindersize; + case F_SECTOR: + return 1; + case F_BLOCK: + return 2; + case F_MEGABYTE: + return 2048; + } +} + +unsigned long +get_disksize(int format) { + unsigned long cs = cylinders; + if (cs && leave_last) + cs--; + return (cs * cylindersize) / unitsize(format); +} + +void +out_partition_header(char *dev, int format) { + if (dump) { + printf("# partition table of %s\n", dev); + printf("unit: sectors\n\n"); + return; + } + + default_format = (cylindersize ? F_CYLINDER : F_MEGABYTE); + if (!format && !(format = specified_format)) + format = default_format; + + switch(format) { + default: + printf("unimplemented format - using %s\n", + cylindersize ? "cylinders" : "sectors"); + case F_CYLINDER: + if (cylindersize) { + printf("Units = cylinders of %lu bytes, blocks of 1024 bytes" + ", counting from %d\n\n", + cylindersize<<9, increment); + printf(" Device Boot Start End #cyls #blocks Id System\n"); + break; + } + /* fall through */ + case F_SECTOR: + printf("Units = sectors of 512 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #sectors Id System\n"); + break; + case F_BLOCK: + printf("Units = blocks of 1024 bytes, counting from %d\n\n", + increment); + printf(" Device Boot Start End #blocks Id System\n"); + break; + case F_MEGABYTE: + printf("Units = megabytes of 1048576 bytes, blocks of 1024 bytes" + ", counting from %d\n\n", increment); + printf(" Device Boot Start End MB #blocks Id System\n"); + break; + } +} + +static void +out_rounddown(int width, unsigned long n, unsigned long unit, int inc) { + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar((n % unit) ? '+' : ' '); + putchar(' '); +} + +static void +out_roundup(int width, unsigned long n, unsigned long unit, int inc) { + if (n == (unsigned long)(-1)) + printf("%*s", width, "-"); + else + printf("%*lu", width, inc + n/unit); + if (unit != 1) + putchar(((n+1) % unit) ? '-' : ' '); + putchar(' '); +} + +static void +out_roundup_size(int width, unsigned long n, unsigned long unit) { + printf("%*lu", width, (n+unit-1)/unit); + if (unit != 1) + putchar((n % unit) ? '-' : ' '); + putchar(' '); +} + +void +out_partition(char *dev, int format, struct part_desc *p, struct disk_desc *z) { + unsigned long start, end, size; + int pno, lpno; + + if (!format && !(format = specified_format)) + format = default_format; + + pno = p - &(z->partitions[0]); /* our index */ + lpno = index_to_linux(pno, z); /* name of next one that has a name */ + if(pno == linux_to_index(lpno, z)) /* was that us? */ + printf("%8s%-2u", dev, lpno); /* yes */ + else if(show_extended) + printf(" - "); + else + return; + putchar(dump ? ':' : ' '); + + start = p->start; + end = p->start + p->size - 1; + size = p->size; + + if (dump) { + printf(" start=%9lu", start); + printf(", size=%8lu", size); + if (p->ptype == DOS_TYPE) { + printf(", Id=%2x", p->p.sys_type); + if (p->p.bootable == 0x80) + printf(", bootable"); + } + printf("\n"); + return; + } + + if(p->ptype != DOS_TYPE || p->p.bootable == 0) + printf(" "); + else if(p->p.bootable == 0x80) + printf(" * "); + else + printf(" ? "); /* garbage */ + + switch(format) { + case F_CYLINDER: + if (cylindersize) { + out_rounddown(6, start, cylindersize, increment); + out_roundup(6, end, cylindersize, increment); + out_roundup_size(6, size, cylindersize); + out_rounddown(8, size, 2, 0); + break; + } + /* fall through */ + default: + case F_SECTOR: + out_rounddown(9, start, 1, increment); + out_roundup(9, end, 1, increment); + out_rounddown(9, size, 1, 0); + break; + case F_BLOCK: +#if 0 + printf("%8lu,%3lu ", + p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset); +#endif + out_rounddown(8, start, 2, increment); + out_roundup(8, end, 2, increment); + out_rounddown(8, size, 2, 0); + break; + case F_MEGABYTE: + out_rounddown(5, start, 2048, increment); + out_roundup(5, end, 2048, increment); + out_roundup_size(5, size, 2048); + out_rounddown(8, size, 2, 0); + break; + } + 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 && p->ptype == DOS_TYPE) { + chs a, b; + longchs aa, bb; + a = (size ? ulong_to_chs(start) : zero_chs); + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = (size ? ulong_to_chs(end) : zero_chs); + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if(a.s && !is_equal_chs(a, b)) + printf("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + printf("partition ends on cylinder %ld, beyond the end of the disk\n", + bb.c); + } +} + +void +out_partitions(char *dev, struct disk_desc *z) { + int pno, format = 0; + + if (z->partno == 0) + printf("No partitions found\n"); + else { + out_partition_header(dev, format); + for(pno=0; pno < z->partno; pno++) { + out_partition(dev, format, &(z->partitions[pno]), z); + if(show_extended && pno%4==3) + printf("\n"); + } + } +} + +static int +disj(struct part_desc *p, struct part_desc *q) { + return + ((p->start + p->size <= q->start) + || (is_extended(p->p.sys_type) + && q->start + q->size <= p->start + p->size)); +} + +char * +pnumber(struct part_desc *p, struct disk_desc *z) { + static char buf[20]; + int this, next; + struct part_desc *p0 = &(z->partitions[0]); + + this = index_to_linux(p-p0, z); + next = index_to_linux(p-p0+1, z); + + if (next > this) + sprintf(buf, "%d", this); + else + sprintf(buf, "[%d]", this); + return buf; +} + +int +partitions_ok(struct disk_desc *z) { + struct part_desc *partitions = &(z->partitions[0]), *p, *q; + int partno = z->partno; + +#define PNO(p) pnumber(p, z) + + /* Have at least 4 partitions been defined? */ + if (partno < 4) { + if (!partno) + fatal("no partition table present.\n"); + else + fatal("strange, only %d partitions defined.\n", partno); + return 0; + } + + /* Are the partitions of size 0 marked empty? + And do they have start = 0? And bootable = 0? */ + for (p = partitions; p - partitions < partno; p++) + if (p->size == 0) { + if(p->p.sys_type != EMPTY_PARTITION) + warn("Warning: partition %s has size 0 but is not marked Empty\n", + PNO(p)); + else if(p->p.bootable != 0) + warn("Warning: partition %s has size 0 and is bootable\n", + PNO(p)); + else if(p->p.start_sect != 0) + warn("Warning: partition %s has size 0 and nonzero start\n", + PNO(p)); + /* all this is probably harmless, no error return */ + } + + /* Are the logical partitions contained in their extended partitions? */ + for (p = partitions+4; p < partitions+partno; p++) + if (p->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) { + warn("Warning: partition %s ", PNO(p)); + warn("is not contained in partition %s\n", PNO(q)); + return 0; + } + } + + /* Are the data partitions mutually disjoint? */ + for (p = partitions; p < partitions+partno; p++) + if (p->size && !is_extended(p->p.sys_type)) + for (q = p+1; q < partitions+partno; q++) + if (q->size && !is_extended(q->p.sys_type)) + if(!((p->start > q-> start) ? disj(q,p) : disj(p,q))) { + warn("Warning: partitions %s ", PNO(p)); + warn("and %s overlap\n", PNO(q)); + return 0; + } + + /* 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++) + if (p->size) { + if(p->start == 0) { + warn("Warning: partition %s starts at sector 0\n", PNO(p)); + return 0; + } + if (p->size && p->start + p->size > ds) { + warn("Warning: partition %s extends past end of disk\n", PNO(p)); + return 0; + } + } + } + + /* At most one chain of DOS extended partitions ? */ + /* It seems that the OS/2 fdisk has the additional requirement + that the extended partition must be the fourth one */ + { int ect = 0; + for (p = partitions; p < partitions+4; p++) + if (p->p.sys_type == EXTENDED_PARTITION) + ect++; + if (ect > 1 && !Linux) { + warn("Among the primary partitions, at most one can be extended\n"); + warn(" (although this is not a problem under Linux)\n"); + return 0; + } + } + + /* + * Do all partitions start at a cylinder boundary ? + * (this is not required for Linux) + * The first partition starts after MBR. + * Logical partitions start slightly after the containing extended partn. + */ + if (cylindersize) { + for(p = partitions; p < partitions+partno; p++) + if (p->size) { + if(p->start % cylindersize != 0 + && (!p->ep || p->start / cylindersize != p->ep->start / cylindersize) + && (p->p.start_sect >= cylindersize)) { + warn("Warning: partition %s does not start " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + if((p->start + p->size) % cylindersize) { + warn("Warning: partition %s does not end " + "at a cylinder boundary\n", PNO(p)); + if (!Linux) + return 0; + } + } + } + + /* Usually, one can boot only from primary partitions. */ + /* In fact, from a unique one only. */ + /* do not warn about bootable extended partitions - + often LILO is there */ + { int pno = -1; + for(p = partitions; p < partitions+partno; p++) + if (p->p.bootable) { + if (pno == -1) + pno = p - partitions; + else if (p - partitions < 4) { + warn("Warning: more than one primary partition is marked " + "bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + break; + } + if (p - partitions >= 4) { + warn("Warning: usually one can boot from primary partitions " + "only\n" "LILO disregards the `bootable' flag.\n"); + break; + } + } + if (pno == -1 || pno >= 4) + warn("Warning: no primary partition is marked bootable (active)\n" + "This does not matter for LILO, but the DOS MBR will " + "not boot this disk.\n"); + } + + /* Is chs as we expect? */ + for(p = partitions; p < partitions+partno; p++) + if(p->ptype == DOS_TYPE) { + chs a, b; + longchs aa, bb; + a = p->size ? ulong_to_chs(p->start) : zero_chs; + b = p->p.begin_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "start")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + a = p->size ? ulong_to_chs(p->start + p->size - 1) : zero_chs; + b = p->p.end_chs; + aa = chs_to_longchs(a); + bb = chs_to_longchs(b); + if (!chs_ok(b, PNO(p), "end")) + return 0; + if(a.s && !is_equal_chs(a, b)) + warn("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n", + PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); + if(cylinders && cylinders < 1024 && bb.c > cylinders) + warn("partition %s ends on cylinder %ld, beyond the end of the disk\n", + PNO(p), bb.c); + } + + return 1; + +#undef PNO +} + +static void +extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { + char *cp; + struct sector *s; + unsigned long start, here, next; + int i, moretodo = 1; + struct partition p; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + here = start = ep->start; + + while (moretodo) { + moretodo = 0; + + if (!(s = get_sector(dev, fd, here))) + break; + + if (!msdos_signature(s)) + break; + + cp = s->data + 0x1be; + + if (pno+4 >= SIZE(z->partitions)) { + printf("too many partitions - ignoring those past nr (%d)\n", + pno-1); + break; + } + + next = 0; + + for (i=0; i<4; i++,cp += sizeof(struct partition)) { + partitions[pno].sector = here; + partitions[pno].offset = cp - s->data; + partitions[pno].ep = ep; + copy_to_part(cp,&p); + if (is_extended(p.sys_type)) { + if (next) + printf("tree of partitions?\n"); + partitions[pno].start = next = start + p.start_sect; + moretodo = 1; + } else { + partitions[pno].start = here + p.start_sect; + } + partitions[pno].size = p.nr_sects; + partitions[pno].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; + char *cp; + struct partition pt; + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]); + int pno = z->partno; + + if (!(s = get_sector(dev, fd, start))) + return 0; + + if (!msdos_signature(s)) + return 0; + + cp = s->data + 0x1be; + copy_to_part(cp,&pt); + + /* If I am not mistaken, recent kernels will hide this from us, + so we will never actually see traces of a Disk Manager */ + if (pt.sys_type == DM6_PARTITION + || pt.sys_type == EZD_PARTITION + || pt.sys_type == DM6_AUX1PARTITION + || pt.sys_type == DM6_AUX3PARTITION) { + printf("detected Disk Manager - unable to handle that\n"); + return 0; + } + { unsigned int sig = *(unsigned short *)(s->data + 2); + if (sig <= 0x1ae + && *(unsigned short *)(s->data + sig) == 0x55aa + && (1 & *(unsigned char *)(s->data + sig + 2))) { + printf("DM6 signature found - giving up\n"); + return 0; + } + } + + for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) { + partitions[pno].sector = start; + partitions[pno].offset = cp - s->data; + copy_to_part(cp,&pt); + partitions[pno].start = start + pt.start_sect; + partitions[pno].size = pt.nr_sects; + partitions[pno].ep = 0; + partitions[pno].p = pt; + } + + z->partno = pno; + + for (i=0; i<4; i++) { + if (is_extended(partitions[i].p.sys_type)) { + if (!partitions[i].size) { + printf("strange..., an extended partition of size 0?\n"); + continue; + } + extended_partition(dev, fd, &partitions[i], z); + } + 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; +} + +static int +osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +static int +sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +static int +amiga_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { + return 0; +} + +void +get_partitions(char *dev, int fd, struct disk_desc *z) { + z->partno = 0; + + if (!msdos_partition(dev, fd, 0, z) + && !osf_partition(dev, fd, 0, z) + && !sun_partition(dev, fd, 0, z) + && !amiga_partition(dev, fd, 0, z)) { + printf(" %s: unrecognized partition\n", dev); + return; + } +} + +int +write_partitions(char *dev, int fd, struct disk_desc *z) { + struct sector *s; + struct part_desc *partitions = &(z->partitions[0]), *p; + int pno = z->partno; + + if (no_write) { + printf("-n flag was given: Nothing changed\n"); + exit(0); + } + + for (p = partitions; p < partitions+pno; p++) { + s = get_sector(dev, fd, p->sector); + if (!s) return 0; + s->to_be_written = 1; + copy_from_part(&(p->p), s->data + p->offset); + *(unsigned short *)(&(s->data[0x1fe])) = 0xaa55; + } + if (save_sector_file) { + if (!save_sectors(dev, fd)) { + fatal("Failed saving the old sectors - aborting\n"); + return 0; + } + } + if (!write_sectors(dev, fd)) { + error("Failed writing the partition on %s\n", dev); + return 0; + } + return 1; +} + +/* + * F. The standard input + */ + +/* + * Input format: + * + * Fields are separated by whitespace or comma or semicolon possibly + * followed by whitespace; initial and trailing whitespace is ignored. + * Numbers can be octal, decimal or hexadecimal, decimal is default + * The parts can (and probably should) be omitted. + * Bootable is specified as [*|-], with as default not-bootable. + * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where + * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E + * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85). + * The default value of start is the first nonassigned sector/cylinder/... + * The default value of size is as much as possible (until next + * partition or end-of-disk). + * .: end of chain of extended partitions. + * + * On interactive input an empty line means: all defaults. + * Otherwise empty lines are ignored. + */ + +int eof, eob; + +struct dumpfld { + int fldno; + char *fldname; + int is_bool; +} dumpflds[] = { + { 0, "start", 0 }, + { 1, "size", 0 }, + { 2, "Id", 0 }, + { 3, "bootable", 1 }, + { 4, "bh", 0 }, + { 5, "bs", 0 }, + { 6, "bc", 0 }, + { 7, "eh", 0 }, + { 8, "es", 0 }, + { 9, "ec", 0 } +}; + +/* + * Read a line, split it into fields + * + * (some primitive handwork, but a more elaborate parser seems + * unnecessary) + */ +#define RD_EOF (-1) +#define RD_CMD (-2) + +int +read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) { + unsigned char *lp, *ip; + int c, fno; + + /* boolean true and empty string at start */ + line[0] = '*'; + line[1] = 0; + for (fno=0; fno < fieldssize; fno++) + fields[fno] = line + 1; + fno = 0; + + /* read a line from stdin */ + lp = fgets(line+2, linesize, stdin); + if (lp == NULL) { + eof = 1; + return RD_EOF; + } + if (!(lp = index(lp, '\n'))) + fatal("long or incomplete input line - quitting\n"); + *lp = 0; + + /* remove comments, if any */ + if ((lp = index(line+2, '#')) != 0) + *lp = 0; + + /* recognize a few commands - to be expanded */ + if (!strcmp(line+2, "unit: sectors")) { + specified_format = F_SECTOR; + return RD_CMD; + } + + /* dump style? - then bad input is fatal */ + if ((ip = index(line+2, ':')) != 0) { + struct dumpfld *d; + + nxtfld: + ip++; + while(isspace(*ip)) + ip++; + if (*ip == 0) + return fno; + for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) { + if(!strncmp(ip, d->fldname, strlen(d->fldname))) { + ip += strlen(d->fldname); + while(isspace(*ip)) + ip++; + if (d->is_bool) + fields[d->fldno] = line; + else if (*ip == '=') { + while(isspace(*++ip)) ; + fields[d->fldno] = ip; + while(isalnum(*ip)) /* 0x07FF */ + ip++; + } else + fatal("input error: `=' expected after %s field\n", + d->fldname); + if (fno <= d->fldno) + fno = d->fldno + 1; + if(*ip == 0) + return fno; + if(*ip != ',' && *ip != ';') + fatal("input error: unexpected character %c after %s field\n", + *ip, d->fldname); + *ip = 0; + goto nxtfld; + } + } + fatal("unrecognized input: %s\n", ip); + } + + /* split line into fields */ + lp = ip = line+2; + fields[fno++] = lp; + while((c = *ip++) != 0) { + if (!lp[-1] && (c == '\t' || c == ' ')) + ; + else if (c == '\t' || c == ' ' || c == ',' || c == ';') { + *lp++ = 0; + if (fno < fieldssize) + fields[fno++] = lp; + continue; + } else + *lp++ = c; + } + + if (lp == fields[fno-1]) + fno--; + return fno; +} + +/* read a number, use default if absent */ +int +get_ul(char *u, unsigned long *up, unsigned long def, int base) { + char *nu; + + if (*u) { + errno = 0; + *up = strtoul(u, &nu, base); + if (errno == ERANGE) { + printf("number too big\n"); + return -1; + } + if (*nu) { + printf("trailing junk after number\n"); + return -1; + } + } else + *up = def; + return 0; +} + +/* There are two common ways to structure extended partitions: + as nested boxes, and as a chain. Sometimes the partitions + must be given in order. Sometimes all logical partitions + must lie inside the outermost extended partition. +NESTED: every partition is contained in the surrounding partitions + and is disjoint from all others. +CHAINED: every data partition is contained in the surrounding partitions + and disjoint from all others, but extended partitions may lie outside + (insofar as allowed by all_logicals_inside_outermost_extended). +ONESECTOR: all data partitions are mutually disjoint; extended partitions + each use one sector only (except perhaps for the outermost one). +*/ +int partitions_in_order = 0; +int all_logicals_inside_outermost_extended = 1; +enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED; + +/* find the default value for - assuming entire units */ +unsigned long +first_free(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long mid, struct disk_desc *z) { + unsigned long ff, fff; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } +#if 0 + ff = pp ? (pp->start + unit - 1) / unit : 0; +#else + /* rounding up wastes almost an entire cylinder - round down + and leave it to compute_start_sect() to fix the difference */ + ff = pp ? pp->start / unit : 0; +#endif + /* MBR and 1st sector of an extended partition are never free */ + if (unit == 1) + ff++; + + again: + for(pp = partitions; pp < partitions+pno; pp++) { + if (!is_parent(pp, ep) && pp->size > 0) { + if ((partitions_in_order || pp->start / unit <= ff + || (mid && pp->start / unit <= mid)) + && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) { + ff = fff; + goto again; + } + } + } + + return ff; +} + +/* find the default value for - assuming entire units */ +unsigned long +max_length(int pno, int is_extended, struct part_desc *ep, int format, + unsigned long start, struct disk_desc *z) { + unsigned long fu; + unsigned long unit = unitsize(format); + struct part_desc *partitions = &(z->partitions[0]), *pp = 0; + + /* if containing ep undefined, look at its container */ + if (ep && ep->p.sys_type == EMPTY_PARTITION) + ep = ep->ep; + + if (ep) { + if (boxes == NESTED || (boxes == CHAINED && !is_extended)) + pp = ep; + else if (all_logicals_inside_outermost_extended) + pp = outer_extended_partition(ep); + } + fu = pp ? (pp->start + pp->size) / unit : get_disksize(format); + + for(pp = partitions; pp < partitions+pno; pp++) + if (!is_parent(pp, ep) && pp->size > 0 + && pp->start / unit >= start && pp->start / unit < fu) + fu = pp->start / unit; + + return (fu > start) ? fu - start : 0; +} + +/* compute starting sector of a partition inside an extended one */ +/* ep is 0 or points to surrounding extended partition */ +int +compute_start_sect(struct part_desc *p, struct part_desc *ep) { + unsigned long base; + int inc = (DOS && sectors) ? sectors : 1; + int delta; + + if (ep && p->start + p->size >= ep->start + 1) + delta = p->start - ep->start - inc; + else if (p->start == 0 && p->size > 0) + delta = -inc; + else + delta = 0; + if (delta < 0) { + p->start -= delta; + p->size += delta; + if (is_extended(p->p.sys_type) && boxes == ONESECTOR) + p->size = inc; + else if ((int)(p->size) <= 0) { + warn("no room for partition descriptor\n"); + return 0; + } + } + base = (!ep ? 0 + : (is_extended(p->p.sys_type) ? + outer_extended_partition(ep) : ep)->start); + p->ep = ep; + if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) { + p->p.start_sect = 0; + p->p.begin_chs = zero_chs; + p->p.end_chs = zero_chs; + } else { + p->p.start_sect = p->start - base; + p->p.begin_chs = ulong_to_chs(p->start); + p->p.end_chs = ulong_to_chs(p->start + p->size - 1); + } + p->p.nr_sects = p->size; + return 1; +} + +/* build the extended partition surrounding a given logical partition */ +int +build_surrounding_extended(struct part_desc *p, struct part_desc *ep, + struct disk_desc *z) { + int inc = (DOS && sectors) ? sectors : 1; + int format = F_SECTOR; + struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep; + + if (boxes == NESTED) { + ep->start = first_free(ep-p0, 1, eep, format, p->start, z); + ep->size = max_length(ep-p0, 1, eep, format, ep->start, z); + if (ep->start > p->start || ep->start + ep->size < p->start + p->size) { + warn("cannot build surrounding extended partition\n"); + return 0; + } + } else { + ep->start = p->start; + if(boxes == CHAINED) + ep->size = p->size; + else + ep->size = inc; + } + + ep->p.nr_sects = ep->size; + ep->p.bootable = 0; + ep->p.sys_type = EXTENDED_PARTITION; + if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) { + ep->p.sys_type = EMPTY_PARTITION; + ep->size = 0; + return 0; + } + + return 1; +} + +int +read_line(int pno, struct part_desc *ep, char *dev, int interactive, + struct disk_desc *z) { + unsigned char line[1000]; + unsigned char *fields[11]; + int fno, pct = pno%4; + struct part_desc p, *orig; + unsigned long ff, ff1, ul, ml, ml1, def; + int format, lpno, is_extd; + + if (eof || eob) + return -1; + + lpno = index_to_linux(pno, z); + + if (interactive) { + if (pct == 0 && (show_extended || pno == 0)) + warn("\n"); + warn("%8s%d: ", dev, lpno); + } + + /* read input line - skip blank lines when reading from a file */ + do { + fno = read_stdin(fields, line, SIZE(fields), SIZE(line)); + } while(fno == RD_CMD || (fno == 0 && !interactive)); + if (fno == RD_EOF) { + return -1; + } else if (fno > 10 && *(fields[10]) != 0) { + printf("too many input fields\n"); + return 0; + } + + if (fno == 1 && !strcmp(fields[0], ".")) { + eob = 1; + return -1; + } + + /* use specified format, but round to cylinders if F_MEGABYTE specified */ + format = 0; + if (cylindersize && specified_format == F_MEGABYTE) + format = F_CYLINDER; + + orig = (one_only ? &(oldp.partitions[pno]) : 0); + + p = zero_part_desc; + p.ep = ep; + + /* first read the type - we need to know whether it is extended */ + /* stop reading when input blank (defaults) and all is full */ + is_extd = 0; + if (fno == 0) { /* empty line */ + if (orig && is_extended(orig->p.sys_type)) + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + if (ml == 0 && is_extd == 0) { + is_extd = 1; + ff = first_free(pno, is_extd, ep, format, 0, z); + ml = max_length(pno, is_extd, ep, format, ff, z); + } + if (ml == 0 && pno >= 4) { + /* no free blocks left - don't read any further */ + warn("No room for more\n"); + return -1; + } + } + if (fno < 3 || !*(fields[2])) + ul = orig ? orig->p.sys_type : + (is_extd || (pno > 3 && pct == 1 && show_extended)) + ? EXTENDED_PARTITION : LINUX_NATIVE; + else if(!strcmp(fields[2], "L")) + ul = LINUX_NATIVE; + else if(!strcmp(fields[2], "S")) + ul = LINUX_SWAP; + else if(!strcmp(fields[2], "E")) + ul = EXTENDED_PARTITION; + else if(!strcmp(fields[2], "X")) + ul = LINUX_EXTENDED; + else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16)) + return 0; + if (ul > 255) { + warn("Illegal type\n"); + return 0; + } + p.p.sys_type = ul; + is_extd = is_extended(ul); + + /* find start */ + ff = first_free(pno, is_extd, ep, format, 0, z); + ff1 = ff * unitsize(format); + def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1; + if (fno < 1 || !*(fields[0])) + p.start = def; + else { + if (get_ul(fields[0], &ul, def / unitsize(0), 0)) + return 0; + p.start = ul * unitsize(0); + p.start -= (p.start % unitsize(format)); + } + + /* find length */ + ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z); + ml1 = ml * unitsize(format); + def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1; + if (fno < 2 || !*(fields[1])) + p.size = def; + else { + if (get_ul(fields[1], &ul, def / unitsize(0), 0)) + return 0; + p.size = ul * unitsize(0) + unitsize(format) - 1; + p.size -= (p.size % unitsize(format)); + } + if (p.size > ml1) { + warn("Warning: exceeds max allowable size (%lu)\n", ml1 / unitsize(0)); + if (!force) + return 0; + } + if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) { + warn("Warning: empty partition\n"); + if (!force) + return 0; + } + p.p.nr_sects = p.size; + + if (p.size == 0 && !orig) { + if(fno < 1 || !*(fields[0])) + p.start = 0; + if(fno < 3 || !*(fields[2])) + p.p.sys_type = EMPTY_PARTITION; + } + + if (p.start < ff1 && p.size > 0) { + warn("Warning: bad partition start (earliest %lu)\n", + (ff1 + unitsize(0) - 1) / unitsize(0)); + if (!force) + return 0; + } + + if (fno < 4 || !*(fields[3])) + ul = (orig ? orig->p.bootable : 0); + else if (!strcmp(fields[3], "-")) + ul = 0; + else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+")) + ul = 0x80; + else { + warn("unrecognized bootable flag - choose - or *\n"); + return 0; + } + p.p.bootable = ul; + + if (ep && ep->p.sys_type == EMPTY_PARTITION) { + if(!build_surrounding_extended(&p, ep, z)) + return 0; + } else + if(!compute_start_sect(&p, ep)) + return 0; + + { longchs aa = chs_to_longchs(p.p.begin_chs), bb; + + if (fno < 5) { + bb = aa; + } else if (fno < 7) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[4], &bb.c, aa.c, 0) || + get_ul(fields[5], &bb.h, aa.h, 0) || + get_ul(fields[6], &bb.s, aa.s, 0)) + return 0; + p.p.begin_chs = longchs_to_chs(bb); + } + { longchs aa = chs_to_longchs(p.p.end_chs), bb; + + if (fno < 8) { + bb = aa; + } else if (fno < 10) { + warn("partial c,h,s specification?\n"); + return 0; + } else if(get_ul(fields[7], &bb.c, aa.c, 0) || + get_ul(fields[8], &bb.h, aa.h, 0) || + get_ul(fields[9], &bb.s, aa.s, 0)) + return 0; + p.p.end_chs = longchs_to_chs(bb); + } + + if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION + && (is_extended(p.p.sys_type) != (pct == 1))) { + warn("Extended partition not where expected\n"); + if (!force) + return 0; + } + + z->partitions[pno] = p; + if (pno >= z->partno) + z->partno += 4; /* reqd for out_partition() */ + + if (interactive) + out_partition(dev, 0, &(z->partitions[pno]), z); + + return 1; +} + +/* ep either points to the extended partition to contain this one, + or to the empty partition that may become extended or is 0 */ +int +read_partition(char *dev, int interactive, int pno, struct part_desc *ep, + struct disk_desc *z) { + struct part_desc *p = &(z->partitions[pno]); + int i; + + if (one_only) { + *p = oldp.partitions[pno]; + if (one_only_pno != pno) + goto ret; + } else if (!show_extended && pno > 4 && pno%4) + goto ret; + + while (!(i = read_line(pno, ep, dev, interactive, z))) + if (!interactive) + fatal("bad input\n"); + if (i < 0) { + p->ep = ep; + return 0; + } + + ret: + p->ep = ep; + if (pno >= z->partno) + z->partno += 4; + return 1; +} + +void +read_partition_chain(char *dev, int interactive, struct part_desc *ep, + struct disk_desc *z) { + int i, base; + + eob = 0; + while (1) { + base = z->partno; + if (base+4 > SIZE(z->partitions)) { + printf("too many partitions\n"); + break; + } + for (i=0; i<4; i++) + if (!read_partition(dev, interactive, base+i, ep, z)) + return; + for (i=0; i<4; i++) { + ep = &(z->partitions[base+i]); + if (is_extended(ep->p.sys_type) && ep->size) + break; + } + if (i == 4) { + /* nothing found - maybe an empty partition is going + to be extended */ + if (one_only || show_extended) + break; + ep = &(z->partitions[base+1]); + if (ep->size || ep->p.sys_type != EMPTY_PARTITION) + break; + } + } +} + +void +read_input(char *dev, int interactive, struct disk_desc *z) { + int i; + struct part_desc *partitions = &(z->partitions[0]), *ep; + + for (i=0; i < SIZE(z->partitions); i++) + partitions[i] = zero_part_desc; + z->partno = 0; + + if (interactive) + warn(" +Input in the following format; absent fields get a default value. + +Usually you only need to specify and (and perhaps ). +"); + eof = 0; + + for (i=0; i<4; i++) + read_partition(dev, interactive, i, 0, z); + for (i=0; i<4; i++) { + ep = partitions+i; + if (is_extended(ep->p.sys_type) && ep->size) + read_partition_chain(dev, interactive, ep, z); + } + add_sector_and_offset(z); +} + +/* + * G. The command line + */ + +static void version(void) { + printf(PROGNAME " version " VERSION " (aeb@cwi.nl, " DATE ")\n"); +} + +static void +usage(void) { + version(); + printf("Usage: + " PROGNAME " [options] device ... +device: something like /dev/hda or /dev/sda +useful options: + -s [or --show-size]: list size of a partition + -c [or --id]: print or change partition Id + -l [or --list]: list partitions of each device + -d [or --dump]: idem, but in a format suitable for later input + -i [or --increment]: number cylinders etc. from 1 instead of from 0 + -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB + -T [or --list-types]:list the known partition types + -D [or --DOS]: for DOS-compatibility: waste a little space + -R [or --re-read]: make kernel reread partition table + -N# : change only the partition with number # + -n : do not actually write to disk + -O file : save the sectors that will be overwritten to file + -I file : restore these sectors again + -v [or --version]: print version + -? [or --help]: print this message +dangerous options: + -g [or --show-geometry]: print the kernel's idea of the geometry + -x [or --show-extended]: also list extended partitions on output + or expect descriptors for them on input + -L [or --Linux]: do not complain about things irrelevant for Linux + -q [or --quiet]: suppress warning messages + You can override the detected geometry using: + -C# [or --cylinders #]:set the number of cylinders to use + -H# [or --heads #]: set the number of heads to use + -S# [or --sectors #]: set the number of sectors to use + You can disable all consistency checking with: + -f [or --force]: do what I say, even if it is stupid +"); + exit(1); +} + +static void +activate_usage(char *progn) { + printf("Usage: + %s device list active partitions on device + %s device n1 n2 ... activate partitions n1 ..., inactivate the rest + %s device activate partition n, inactivate the other ones +", progn, progn, PROGNAME " -An"); + exit(1); +} + +static void +unhide_usage(char *progn) { + exit(1); +} + +static char short_opts[] = "cdfgilnqsu:vx?1A::C:DH:I:LN:O:RS:TU::V"; + +#define PRINT_ID 0400 +#define CHANGE_ID 01000 + +static const struct option long_opts[] = { + { "change-id", no_argument, NULL, 'c' + CHANGE_ID }, + { "print-id", no_argument, NULL, 'c' + PRINT_ID }, + { "id", no_argument, NULL, 'c' }, + { "dump", no_argument, NULL, 'd' }, + { "force", no_argument, NULL, 'f' }, + { "show-geometry", no_argument, NULL, 'g' }, + { "increment", no_argument, NULL, 'i' }, + { "list", no_argument, NULL, 'l' }, + { "quiet", no_argument, NULL, 'q' }, + { "show-size", no_argument, NULL, 's' }, + { "unit", required_argument, NULL, 'u' }, + { "version", no_argument, NULL, 'v' }, + { "show-extended", no_argument, NULL, 'x' }, + { "help", no_argument, NULL, '?' }, + { "one-only", no_argument, NULL, '1' }, + { "cylinders", required_argument, NULL, 'C' }, + { "heads", required_argument, NULL, 'H' }, + { "sectors", required_argument, NULL, 'S' }, + { "activate", optional_argument, NULL, 'A' }, + { "DOS", no_argument, NULL, 'D' }, + { "Linux", no_argument, NULL, 'L' }, + { "re-read", no_argument, NULL, 'R' }, + { "list-types", no_argument, NULL, 'T' }, + { "unhide", optional_argument, NULL, 'U' }, + { "no-reread", no_argument, NULL, 160 }, + { "IBM", no_argument, NULL, 161 }, + { "leave-last", no_argument, NULL, 161 }, +/* undocumented flags - not all completely implemented */ + { "in-order", no_argument, NULL, 128 }, + { "not-in-order", no_argument, NULL, 129 }, + { "inside-outer", no_argument, NULL, 130 }, + { "not-inside-outer", no_argument, NULL, 131 }, + { "nested", no_argument, NULL, 132 }, + { "chained", no_argument, NULL, 133 }, + { "onesector", no_argument, NULL, 134 }, + { NULL, 0, NULL, 0 } +}; + +/* default devices to list */ +static struct devd { + char *pref, *letters; +} defdevs[] = { + { "hd", "abcdefgh" }, + { "sd", "abcde" }, + { "xd", "ab" }, + { "ed", "abcd" } +}; + +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); +void do_fdisk(char *dev); +void do_reread(char *dev); +void do_change_id(char *dev, char *part, char *id); +void do_unhide(char **av, int ac, char *arg); +void do_activate(char **av, int ac, char *arg); + +int total_size; + +int +main(int argc, char **argv) { + char *progn; + int c; + char *dev; + int opt_size = 0; + int opt_out_geom = 0; + int opt_reread = 0; + int activate = 0; + int do_id = 0; + int unhide = 0; + int fdisk = 0; + char *activatearg = 0; + char *unhidearg = 0; + + if (argc < 1) + fatal("no command?\n"); + if ((progn = rindex(argv[0], '/')) == NULL) + progn = argv[0]; + else + progn++; + if (!strcmp(progn, "activate")) + activate = 1; /* equivalent to `sfdisk -A' */ +#if 0 /* not important enough to deserve a name */ + else if (!strcmp(progn, "unhide")) + unhide = 1; /* equivalent to `sfdisk -U' */ +#endif + else + fdisk = 1; + + while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { + switch (c) { + case 'f': + force = 1; break; /* does not imply quiet */ + case 'g': + opt_out_geom = 1; break; + case 'i': + increment = 1; break; + case 'c': + case 'c' + PRINT_ID: + case 'c' + CHANGE_ID: + do_id = c; break; + case 'd': + dump = 1; /* fall through */ + case 'l': + opt_list = 1; break; + case 'n': + no_write = 1; break; + case 'q': + quiet = 1; break; + case 's': + opt_size = 1; break; + case 'u': + set_format(*optarg); break; + case 'v': + version(); + exit(0); + case 'x': + show_extended = 1; break; + case 'A': + activatearg = optarg; + activate = 1; break; + case 'C': + specified_cylinders = atoi(optarg); break; + case 'D': + DOS = 1; break; + case 'H': + specified_heads = atoi(optarg); break; + case 'L': + Linux = 1; break; + case 'N': + one_only = atoi(optarg); break; + case 'I': + restore_sector_file = optarg; break; + case 'O': + save_sector_file = optarg; break; + case 'R': + opt_reread = 1; break; + case 'S': + specified_sectors = atoi(optarg); break; + case 'T': + list_types(); + exit(0); + case 'U': + unhidearg = optarg; + unhide = 1; break; + case 'V': + verify = 1; break; + case '?': + default: + usage(); break; + + /* undocumented flags */ + case 128: + partitions_in_order = 1; break; + case 129: + partitions_in_order = 0; break; + case 130: + all_logicals_inside_outermost_extended = 1; break; + case 131: + all_logicals_inside_outermost_extended = 0; break; + case 132: + boxes = NESTED; break; + case 133: + boxes = CHAINED; break; + case 134: + boxes = ONESECTOR; break; + + /* more flags */ + case 160: + no_reread = 1; break; + case 161: + leave_last = 1; break; + } + } + + if (optind == argc && (opt_list || opt_out_geom || opt_size || verify)) { + struct devd *dp; + char *lp; + char device[10]; + + total_size = 0; + + for(dp = defdevs; dp-defdevs < SIZE(defdevs); dp++) { + lp = dp->letters; + while(*lp) { + sprintf(device, "/dev/%s%c", dp->pref, *lp++); + if (!strcmp(dp->pref, "hd") && is_ide_cdrom(device)) + continue; + if (opt_out_geom) + do_geom(device, 1); + if (opt_size) + do_size(device, 1); + if (opt_list || verify) + do_list(device, 1); + } + } + + if (opt_size) + printf("total: %d blocks\n", total_size); + + exit(exit_status); + } + + if (optind == argc) { + if (activate) + activate_usage(fdisk ? "sfdisk -A" : progn); + else if (unhide) + unhide_usage(fdisk ? "sfdisk -U" : progn); + else + usage(); + } + + if (opt_list || opt_out_geom || opt_size || verify) { + while (optind < argc) { + if (opt_out_geom) + do_geom(argv[optind], 0); + if (opt_size) + do_size(argv[optind], 0); + if (opt_list || verify) + do_list(argv[optind], 0); + optind++; + } + exit(exit_status); + } + + if (activate) { + do_activate(argv+optind, argc-optind, activatearg); + exit(exit_status); + } + if (unhide) { + do_unhide(argv+optind, argc-optind, unhidearg); + exit(exit_status); + } + if (do_id) { + if ((do_id & PRINT_ID) != 0 && optind != argc-2) + fatal("usage: sfdisk --print-id device partition-number\n"); + else if ((do_id & CHANGE_ID) != 0 && optind != argc-3) + fatal("usage: sfdisk --change-id device partition-number Id\n"); + else if (optind != argc-3 && optind != argc-2) + fatal("usage: sfdisk --id device partition-number [Id]\n"); + do_change_id(argv[optind], argv[optind+1], + (optind == argc-2) ? 0 : argv[optind+2]); + exit(exit_status); + } + + if (optind != argc-1) + fatal("can specify only one device (except with -l or -s)\n"); + dev = argv[optind]; + + if (opt_reread) + do_reread(dev); + else if (restore_sector_file) + restore_sectors(dev); + else + do_fdisk(dev); + + return 0; +} + +/* + * H. Listing the current situation + */ + +int +my_open (char *dev, int rw, int silent) { + int fd, mode; + + mode = (rw ? O_RDWR : O_RDONLY); + fd = open(dev, mode); + if (fd < 0 && !silent) { + perror(dev); + fatal("cannot open %s %s\n", dev, rw ? "read-write" : "for reading"); + } + return fd; +} + +void +do_list (char *dev, int silent) { + int fd; + struct disk_desc *z; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1); + get_partitions(dev, fd, z); + + if (opt_list) + out_partitions(dev, z); + + if (verify) { + if (partitions_ok(z)) + warn("%s: OK\n", dev); + else + exit_status = 1; + } +} + +void +do_geom (char *dev, int silent) { + int fd; + struct hd_geometry g; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + /* get_cylindersize(dev, fd, silent); */ + if (!ioctl(fd, HDIO_GETGEO, &g)) + printf("%s: %d cylinders, %d heads, %d sectors/track\n", + dev, g.cylinders, g.heads, g.sectors); + else + printf("%s: unknown geometry\n", dev); +} + +/* for compatibility with earlier fdisk: provide option -s */ +void +do_size (char *dev, int silent) { + int fd, size; + + fd = my_open(dev, 0, silent); + if (fd < 0) + return; + + if(ioctl(fd, BLKGETSIZE, &size)) { + if(!silent) { + perror(dev); + fatal("BLKGETSIZE ioctl failed for %s\n", dev); + } + return; + } + + size /= 2; /* convert sectors to blocks */ + + /* a CDROM drive without mounted CD yields MAXINT */ + if (silent && size == ((1<<30)-1)) + return; + + if (silent) + printf("%s: %9d\n", dev, size); + else + printf("%d\n", size); + + total_size += size; +} + +/* + * Activate: usually one wants to have a single primary partition + * to be active. OS/2 fdisk makes non-bootable logical partitions + * active - I don't know what that means to OS/2 Boot Manager. + * + * Call: activate /dev/hda 2 5 7 make these partitions active + * and the remaining ones inactive + * Or: sfdisk -A /dev/hda 2 5 7 + * + * If only a single partition must be active, one may also use the form + * sfdisk -A2 /dev/hda + * + * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions + * are listed but not changed. To get zero active partitions, use + * "activate /dev/hda none" or "sfdisk -A /dev/hda none". + * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make + * /dev/hda2 active, without changing other partitions. + * + * A warning will be given if after the change not precisely one primary + * partition is active. + * + * The present syntax was chosen to be (somewhat) compatible with the + * activate from the LILO package. + */ +void +set_active (struct disk_desc *z, char *pnam) { + int pno; + + pno = asc_to_index(pnam, z); + z->partitions[pno].p.bootable = 0x80; +} + +void +do_activate (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd; + int rw, i, pno, lpno; + struct disk_desc *z; + + z = &oldp; + + rw = (!no_write && (arg || ac > 1)); + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + if (!arg && ac == 1) { + /* list active partitions */ + for (pno=0; pno < z->partno; pno++) { + if (z->partitions[pno].p.bootable) { + lpno = index_to_linux(pno, z); + if (pno == linux_to_index(lpno, z)) + printf("%s%d\n", dev, lpno); + else + printf("%s#%d\n", dev, pno); + if (z->partitions[pno].p.bootable != 0x80) + warn("bad active byte: 0x%x instead of 0x80\n", + z->partitions[pno].p.bootable); + } + } + } else { + /* clear `active byte' everywhere */ + for (pno=0; pno < z->partno; pno++) + z->partitions[pno].p.bootable = 0; + + /* then set where desired */ + if (ac == 1) + set_active(z, arg); + else for(i=1; ipartno && pno < 4; pno++) + if (z->partitions[pno].p.bootable) + i++; + if (i != 1) + warn("You have %d active primary partitions. This does not matter for LILO,\n" + "but the DOS MBR will only boot a disk with 1 active partition.\n", i); +} + +void +set_unhidden (struct disk_desc *z, char *pnam) { + int pno; + unsigned char id; + + pno = asc_to_index(pnam, z); + id = z->partitions[pno].p.sys_type; + if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17) + id -= 0x10; + else + fatal("partition %s has id %x and is not hidden\n", pnam, id); + z->partitions[pno].p.sys_type = id; +} + +/* + * maybe remove and make part of --change-id + */ +void +do_unhide (char **av, int ac, char *arg) { + char *dev = av[0]; + int fd, rw, i; + struct disk_desc *z; + + z = &oldp; + + rw = !no_write; + fd = my_open(dev, rw, 0); + + free_sectors(); + get_cylindersize(dev, fd, 1); + get_partitions(dev, fd, z); + + /* unhide where desired */ + if (ac == 1) + set_unhidden(z, arg); + else for(i=1; ipartitions[pno].p.sys_type); + return; + } + i = strtoul(id, NULL, 16); + if (i > 255) + fatal("Bad Id %x\n", i); + z->partitions[pno].p.sys_type = i; + + if(write_partitions(dev, fd, z)) + warn("Done\n\n"); + else + exit_status = 1; +} + +void +do_reread(char *dev) { + int fd; + + fd = my_open(dev, 0, 0); + if(reread_ioctl(fd)) + printf("This disk is currently in use.\n"); +} + +/* + * I. Writing the new situation + */ + +void +do_fdisk(char *dev){ + int fd; + int c, answer; + struct stat statbuf; + int interactive = isatty(0); + struct disk_desc *z; + + if (stat(dev, &statbuf) < 0) { + perror(dev); + fatal("Fatal error: cannot find %s\n", dev); + } + if (!S_ISBLK(statbuf.st_mode)) { + warn("Warning: %s is not a block device\n", dev); + } + fd = my_open(dev, !no_write, 0); + + if(!no_write && !no_reread) { + warn("Checking that no-one is using this disk right now ...\n"); + if(reread_ioctl(fd)) { + printf(" +This disk is currently in use - repartitioning is probably a bad idea. +Umount all file systems, and swapoff all swap partitions on this disk. +Use the --no-reread flag to suppress this check.\n"); + if (!force) { + printf("Use the --force flag to overrule all checks.\n"); + exit(1); + } + } else + warn("OK"); + } + + z = &oldp; + + free_sectors(); + get_cylindersize(dev, fd, 0); + get_partitions(dev, fd, z); + + printf("Old situation:\n"); + out_partitions(dev, z); + + if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0) + fatal("Partition %d does not exist, cannot change it\n", one_only); + + z = &newp; + + while(1) { + + read_input(dev, interactive, z); + + printf("New situation:\n"); + out_partitions(dev, z); + + if (!partitions_ok(z) && !force) { + if(!interactive) + fatal("I don't like these partitions - nothing changed.\n" + "(If you really want this, use the --force option.)\n"); + else + printf("I don't like this - probably you should answer No\n"); + } + ask: + if (interactive) { + if (no_write) + printf("Are you satisfied with this? [ynq] "); + else + printf("Do you want to write this to disk? [ynq] "); + answer = c = getchar(); + while (c != '\n' && c != EOF) + c = getchar(); + if (c == EOF) + printf("\nsfdisk: premature end of input\n"); + if (c == EOF || answer == 'q' || answer == 'Q') { + fatal("Quitting - nothing changed\n"); + } else if (answer == 'n' || answer == 'N') { + continue; + } else if (answer == 'y' || answer == 'Y') { + break; + } else { + printf("Please answer one of y,n,q\n"); + goto ask; + } + } else + break; + } + + if(write_partitions(dev, fd, z)) + printf("Successfully wrote the new partition table\n\n"); + else + exit_status = 1; + + reread_disk_partition(dev, fd); + + warn("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n" + "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n" + "(See fdisk(8).)\n"); + + sync(); /* superstition */ + sleep(3); + exit(exit_status); +} diff --git a/fdisk/sfdisk.examples b/fdisk/sfdisk.examples new file mode 100644 index 000000000..13e671d48 --- /dev/null +++ b/fdisk/sfdisk.examples @@ -0,0 +1,264 @@ +Examples of the use of sfdisk 3.0 (to partition a disk) +Input lines have fields ,,... - see sfdisk.8. +Usually no is given, and input lines start with a comma. + +Before doing anything with a disk, make sure it is not in use; +unmount all its file systems, and say swapoff to its swap partitions. +(The final BLKRRPART ioctl will fail if anything else still uses +the disk, and you will have to reboot. It is easier to first make +sure that nothing uses the disk, e.g., by testing: + % umount /dev/sdb1 + % sfdisk -R /dev/sdb + BLKRRPART: Device or resource busy + * Device busy for revalidation (usage=2) + % swapoff /dev/sdb3 + % sfdisk -R /dev/sdb + * sdb: sdb1 < sdb5 sdb6 > sdb3 + % +Note that the starred messages are kernel messages, that may be +logged somewhere, or written to some other console. +In sfdisk 3.01 sfdisk automatically does this check, unless told not to.) + +1. One big partition: + sfdisk /dev/hda << EOF + ; + EOF + +(If there was garbage on the disk before, you may get error messages +like: `ERROR: sector 0 does not have an msdos signature' +and `/dev/hda: unrecognized partition'. This does not matter +if you write an entirely fresh partition table anyway.) + +The output will be: +----------------------------------------------------------------------- +Old situation: +... +New situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 1023 1024- 208895+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 +----------------------------------------------------------------------- +Writing and rereading the partition table takes a few seconds - +don't be alarmed if nothing happens for six seconds or so. + + +2. Three primary partitions: two of size 50MB and the rest: + sfdisk /dev/hda -uM << EOF + ,50 + ,50 + ; + EOF +----------------------------------------------------------------------- +New situation: +Units = megabytes of 1048576 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 50- 51- 51203+ 83 Linux native +/dev/hda2 50+ 100- 51- 51204 83 Linux native +/dev/hda3 100+ 203 104- 106488 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 +----------------------------------------------------------------------- +/dev/hda1 is one block (in fact only half a block) shorter than +/dev/hda2 because its start had to be shifted away from zero in +order to leave room for the Master Boot Record (MBR). + + +3. A 1MB OS2 Boot Manager partition, a 50MB DOS partition, + and three extended partitions (DOS D:, Linux swap, Linux): + sfdisk /dev/hda -uM << EOF + ,1,a + ,50,6 + ,,E + ; + ,20,4 + ,16,S + ; + EOF +----------------------------------------------------------------------- + Device Boot Start End MB #blocks Id System +/dev/hda1 0+ 1- 2- 1223+ a OS/2 Boot Manager +/dev/hda2 1+ 51- 51- 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 51+ 203 153- 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 51+ 71- 21- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 71+ 87- 17- 16523+ 82 Linux swap +/dev/hda7 87+ 203 117- 119339+ 83 Linux native +Successfully wrote the new partition table + hda: hda1 hda2 hda3 < hda5 hda6 hda7 > +----------------------------------------------------------------------- +All these rounded numbers look better in cylinder units: + % sfdisk -l /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native +----------------------------------------------------------------------- +But still - why does /dev/hda5 not start on a cylinder boundary? +Because it is contained in an extended partition that does. +Of the chain of extended partitions, usually only the first is +shown. (The others have no name under Linux anyway.) But +these additional extended partitions can be made visible: + % sfdisk -l -x /dev/hda +----------------------------------------------------------------------- + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +/dev/hda2 6 256 251 51204 6 DOS 16-bit FAT >=32M +/dev/hda3 257 1023 767 156468 5 Extended +/dev/hda4 0 - 0 0 0 Empty + +/dev/hda5 257+ 357 101- 20603+ 4 DOS 16-bit FAT <32M + - 358 1023 666 135864 5 Extended + - 257 256 0 0 0 Empty + - 257 256 0 0 0 Empty + +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap + - 439 1023 585 119340 5 Extended + - 358 357 0 0 0 Empty + - 358 357 0 0 0 Empty + +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty + - 439 438 0 0 0 Empty +----------------------------------------------------------------------- + +Why the empty 4th input line? The description of the extended partitions +starts after that of the four primary partitions. +You force an empty partition with a ",0" input line, but here all +space was divided already, so the fourth partition became empty +automatically. + +How did I know about 4,6,a,E,S? Well, E,S,L stand for Extended, +Swap and Linux. The other values are hexadecimal and come from +the table: + % sfdisk -T + Id Name + + 0 Empty + 1 DOS 12-bit FAT + 2 XENIX root + 3 XENIX usr + 4 DOS 16-bit FAT <32M + 5 Extended + 6 DOS 16-bit FAT >=32M + 7 OS/2 HPFS or QNX or Advanced UNIX + 8 AIX data + 9 AIX boot or Coherent + a OS/2 Boot Manager + ... + + +4. Preserving the sectors changed by sfdisk. + % sfdisk -O save-hdd-partition-sectors /dev/hda + ... + will write the sectors overwritten by sfdisk to file. + If you notice that you trashed some partition, you may + be able to restore things by + % sfdisk -I save-hdd-partition-sectors /dev/hda + % + +5. Preserving some old partitions. + % sfdisk -N2 /dev/hda + ... + will only change the partition /dev/hda2, and leave the rest + unchanged. The most obvious application is to change an Id: + % sfdisk -N7 /dev/hda + ,,63 + % +----------------------------------------------------------------------- +Old situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 83 Linux native + +New situation: + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 5 6- 1223+ a OS/2 Boot Manager +... +/dev/hda6 358+ 438 81- 16523+ 82 Linux swap +/dev/hda7 439+ 1023 585- 119339+ 63 GNU HURD +----------------------------------------------------------------------- + Note that changing a logical partition into an empty partition + will decrease the number of all subsequent logical partitions. + +6. Deleting a partition. +At first I thought of having an option -X# for deleting partitions, +but there are several ways in which a partition can be deleted, and +it is probably better to handle this just as a general change. + % sfdisk -d /dev/hda > ohda +will write the current tables on the file `ohda'. +----------------------------------------------------------------------- +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 81600, size= 336192, Id=83 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +----------------------------------------------------------------------- +In order to delete the partition on /dev/hda3, edit this file +and feed the result to sfdisk again. +----------------------------------------------------------------------- +% emacs ohda +% cat ohda +# partition table of /dev/hda +unit: sectors + +/dev/hda1 : start= 1, size= 40799, Id= 5 +/dev/hda2 : start= 40800, size= 40800, Id=83 +/dev/hda3 : start= 0, size= 0, Id= 0 +/dev/hda4 : start= 0, size= 0, Id= 0 +/dev/hda5 : start= 2, size= 40798, Id=83 +% sfdisk /dev/hda < ohda +Old situation: +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 200 1023 824 168096 83 Linux native +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +New situation: +Units = sectors of 512 bytes, counting from 0 + + Device Boot Start End #sectors Id System +/dev/hda1 1 40799 40799 5 Extended +/dev/hda2 40800 81599 40800 83 Linux native +/dev/hda3 0 - 0 0 Empty +/dev/hda4 0 - 0 0 Empty +/dev/hda5 2 40799 40798 83 Linux native +Successfully wrote the new partition table +% sfdisk -l -V /dev/hda + +Disk /dev/hda: 12 heads, 34 sectors, 1024 cylinders +Units = cylinders of 208896 bytes, blocks of 1024 bytes, counting from 0 + + Device Boot Start End #cyls #blocks Id System +/dev/hda1 0+ 99 100- 20399+ 5 Extended +/dev/hda2 100 199 100 20400 83 Linux native +/dev/hda3 0 - 0 0 0 Empty +/dev/hda4 0 - 0 0 0 Empty +/dev/hda5 0+ 99 100- 20399 83 Linux native +/dev/hda: OK +----------------------------------------------------------------------- +This is a good way of making changes: dump the current status +to file, edit the file, and feed it to sfdisk. +Preserving the file on some other disk could be useful: +if ever the MBR gets thrashed it can be used to restore +the old situation. diff --git a/games/Makefile b/games/Makefile index 49b9f981f..58a8f8f6b 100644 --- a/games/Makefile +++ b/games/Makefile @@ -20,7 +20,7 @@ all: $(USRGAMES) # Rules for everything else -banner: banner.o $(BSD)/getopt.o $(BSD)/err.o +banner: banner.o $(ERR_O) ddate: ddate.o install: all diff --git a/getopt-1.0.3a/COPYING b/getopt-1.0.3a/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/getopt-1.0.3a/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/getopt-1.0.3a/Changelog b/getopt-1.0.3a/Changelog new file mode 100644 index 000000000..24a4c3235 --- /dev/null +++ b/getopt-1.0.3a/Changelog @@ -0,0 +1,14 @@ +980628: Bumped up version number to 1.0.3 +980628: Removed remaining incompatibility with tcsh-6.02 from parse.tcsh +980626: Added separate Makefile for util-linux +980625: Removed several bugs from parse.tcsh, partly thanks to Volker Kuhlmann + (v.kuhlmann@elec.canterbury.ac.nz). +980612: Removed reference to getopt in util-linux +980611: Bumped up version number to 1.0.2 +980611: Fixed --version bug (was not available, though documented!) +980611: Removed compiler warnings. +980603: Bumped up version number to 1.0.1 +980603: Fixed sizeof() bug (should be strlen) in getopt.c, thanks to Bob Proulx + (rwp@hprwp.fc.hp.com). +980505: Changed date field in LSM to proper syntax +980505: Released version 1.0 diff --git a/getopt-1.0.3a/Makefile b/getopt-1.0.3a/Makefile new file mode 100644 index 000000000..0d4a5ad06 --- /dev/null +++ b/getopt-1.0.3a/Makefile @@ -0,0 +1,52 @@ +.SUFFIXES: + +include ../MCONFIG + +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 + +# -Wcast-align causes problems with the identifier stderr on alpha's +# with an old glibc. +# -Wbad-function-cast and -Wmissing-declarations are unknown for gcc 2.5.8. +WARNINGS=-Wall \ + -W -Wshadow -Wpointer-arith -Wcast-qual \ + -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) + +getopt: $(OBJECTS) + $(CC) $(LDFLAGS) $< -o $@ + +install: getopt + $(INSTALLDIR) $(USRBINDIR) $(MAN1DIR) $(GETOPTDIR) + $(INSTALLBIN) getopt $(USRBINDIR) + $(INSTALLMAN) getopt.1 $(MAN1DIR) + $(INSTALLBIN) parse.bash parse.tcsh test.bash test.tcsh $(GETOPTDIR) diff --git a/getopt-1.0.3a/README b/getopt-1.0.3a/README new file mode 100644 index 000000000..1d795f5e4 --- /dev/null +++ b/getopt-1.0.3a/README @@ -0,0 +1,80 @@ +This package contains a reimplementation of getopt(1). + +PREFACE + +Getopt(1) is a program to help shell scripts parse command-line parameters. +It is for example included in the util-linux distribution (upto version +2.7.1). But, there are some problems with that getopt(1) implementation, +as listed in the 'BUGS' section of its man-page: + +>BUGS +> Whatever getopt(3) has. +> +> Arguments containing white space or imbedded shell metacharacters gener- +> ally will not survive intact; this looks easy to fix but isn't. +> +> The error message for an invalid option is identified as coming from +> getopt rather than from the shell procedure containing the invocation of +> getopt; this again is hard to fix. +> +> The precise best way to use the set command to set the arguments without +> disrupting the value(s) of shell options varies from one shell version to +> another. + +This implementation of getopt(1) is written to solve some of these problems, +while still staying (for all practical purposes) completely compatible with +other getopt(1) implementations. + + +INSTALLATION + +Installation should be very easy. Just type 'make' to compile the sources. +It should compile cleanly, without any warnings, but even if it does not +you probably don't have to worry. You must use GNU Make and gcc, or you +will have to edit the Makefile. + +Type 'make install' to install the binary and the manual page. It installs +by default in /usr/local/bin and /usr/local/man/man1, to install in /usr/bin +and /usr/man/man1 try 'make install prefix=/usr'. + +The example files can be installed in /usr/local/lib/getopt by calling +'make install_doc'. + +If you do not trust the getopt(3) in your libc, or if you do not use a libc +with the GNU getopt(3) routines, you can use the gnu sources as provided +in the gnu directory. Try 'make LIBCGETOPT=0'. Ignore any compile warnings. + +You can check whether the new implementation of getopt is found first +in your path by calling 'bash test.bash'. + + +HIGHLIGHTS + +It can do anything that the GNU getopt(3) routines can do. + +It can cope with spaces and shell metacharacters within arguments. + +It can parse long parameters. + +It can shuffle parameters, so you can mix options and other parameters on +the command-line. + +It can be easily identified as an enhanced getopt(1) from within shell scripts. + +It can report parse errors as coming from the shell script. + +It is fully compatible with other getopt(1) implementations. + +COPYING + +This program comes under the GNU general public licence version 2. See the +file COPYING included in this package. Note that though you may freely +copy it, it is copyright (c) 1997 by Frodo Looijaard . +Files in the gnu directory are from glibc-2.0.4: copyright (C) 1987, 88, +89, 90, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. + + +DOWNLOADING + +You can find the latest version of this program at +. diff --git a/getopt-1.0.3a/TODO b/getopt-1.0.3a/TODO new file mode 100644 index 000000000..70f2ea9cb --- /dev/null +++ b/getopt-1.0.3a/TODO @@ -0,0 +1,6 @@ +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? + +Add a `test' target in Makefile. diff --git a/getopt-1.0.3a/getopt.1 b/getopt-1.0.3a/getopt.1 new file mode 100644 index 000000000..c3aaa0195 --- /dev/null +++ b/getopt-1.0.3a/getopt.1 @@ -0,0 +1,436 @@ +.TH GETOPT 1 "May 31, 1997" Linux "" +.SH NAME +getopt \- parse command options (enhanced) +.SH SYNOPSIS +.BR getopt " optstring parameters" + +.BR getopt " [options] [" -- "] optstring parameters" + +.BR getopt " [options] " -o | --options " optstring [options] [" -- "] parameters" +.SH DESCRIPTION +.B getopt +is used to break up +.RI ( parse ) +options in command lines for easy parsing by +shell procedures, and to check for legal options. +It uses the +.SM GNU +.BR getopt (3) +routines to do this. + +The parameters +.B getopt +is called with can be divided into two parts: options +which modify the way getopt will parse +.RI ( options +and +.I -o|--options optstring +in the +.BR SYNOPSIS), +and the parameters which are to be +parsed +.RI ( parameters +in the +.BR SYNOPSIS). +The second part will start at the first non-option parameter +that is not an option argument, or after the first occurence of +.RB ` -- '. +If no +.RB ` -o ' +or +.RB ` --options ' +option is found in the first part, the first +parameter of the second part is used as the short options string. + +If the environment variable +.B GETOPT_COMPATIBLE +is set, or if its first parameter +is not an option (does not start with a +.RB ` - ', +this is the first format in the +.BR SYNOPSIS), +.B getopt +will generate output that is compatible with that of other versions of +.BR getopt (1). +It will still do parameter shuffling and recognize optional +arguments (see section +.B COMPATIBILITY +for more information). + +Traditional implementations of +.BR getopt (1) +are unable to cope with whitespace and other (shell-specific) special characters +in arguments and non-option parameters. To solve this problem, this +implementation can generate +quoted output which must once again be interpreted by the shell (usually +by using the +.B eval +command). This has the effect of preserving those characters, but +you must call +.B getopt +in a way that is no longer compatible with other versions (the second +or third format in the +.BR SYNOPSIS). +To determine whether this enhanced version of +.BR getopt (1) +is installed, a special test option +.RB ( -T ) +can be used. +.SH OPTIONS +.IP "-a, --alternative" +Allow long options to start with a single +.RB ` - '. +.IP "-h, --help" +Output a small usage guide and exit succesfully. No other output is generated. +.IP "-l, --longoptions longopts" +The long (multi-character) options to be recognized. +More than one option name +may be specified at once, by separating the names with commas. This option +may be given more than once, the +.I longopts +are cummulative. +Each long option name +in +.I longopts +may be followed by one colon to indicate it has a required argument,and by two colons to indicate it has an optional argument. +.IP "-n, --name progname" +The name that will be used by the +.BR getopt (3) +routines when it reports errors. Note that errors of +.BR getopt (1) +are still reported as coming from getopt. +.IP "-o, --options shortopts" +The short (one-character) options to be recognized. If this options is not +found, the first parameter of +.B getopt +that does not start with +a +.RB ` - ' +(and is not an option argument) is used as the short options string. +Each short option character +in +.I shortopts +may be followed by one colon to indicate it has a required argument, +and by two colons to indicate it has an optional argument. +The first character of shortopts may be +.RB ` + ' +or +.RB ` - ' +to influence the way +options are parsed and output is generated (see section +.B SCANNING MODES +for details). +.IP "-q, --quiet" +Disable error reporting by getopt(3). +.IP "-Q, --quiet-output" +Do not generate normal output. Errors are still reported by +.BR getopt (3), +unless you also use +.IR -q . +.IP "-s, --shell shell" +Set quoting conventions to those of shell. If no -s argument is found, +the +.SM BASH +conventions are used. Valid arguments are currently +.RB ` sh ' +.RB ` bash ', +.RB ` csh ', +and +.RB ` tcsh '. +.IP "-u, --unquoted" +Do not quote the output. Note that whitespace and special (shell-dependent) +characters can cause havoc in this mode (like they do with other +.BR getopt (1) +implementations). +.IP "-T --test" +Test if your +.BR getopt (1) +is this enhanced version or an old version. This generates no output, +and sets the error status to 4. Other implementations of +.BR getopt (1), +and this version if the environment variable +.B GETOPT_COMPATIBLE +is set, +will return +.RB ` -- ' +and error status 0. +.IP "-V, --version" +Output version information and exit succesfully. No other output is generated. +.SH PARSING +This section specifies the format of the second part of the parameters of +.B getopt +(the +.I parameters +in the +.BR SYNOPSIS ). +The next section +.RB ( OUTPUT ) +describes the output that is +generated. These parameters were typically the parameters a shell function +was called with. +Care must be taken that each parameter the shell function was +called with corresponds to exactly one parameter in the parameter list of +.B getopt +(see the +.BR EXAMPLES ). +All parsing is done by the GNU +.BR getopt (3) +routines. + +The parameters are parsed from left to right. Each parameter is classified as a +short option, a long option, an argument to an option, +or a non-option parameter. + +A simple short option is a +.RB ` - ' +followed by a short option character. If +the option has a required argument, it may be written directly after the option +character or as the next parameter (ie. separated by whitespace on the +command line). If the +option has an optional argument, it must be written directly after the +option character if present. + +It is possible to specify several short options after one +.RB ` - ', +as long as all (except possibly the last) do not have required or optional +arguments. + +A long option normally begins with +.RB ` -- ' +followed by the long option name. +If the option has a required argument, it may be written directly after +the long option name, separated by +.RB ` = ', +or as the next argument (ie. separated by whitespace on the command line). +If the option has an optional argument, it must +be written directly after the long option name, separated by +.RB ` = ', +if present (if you add the +.RB ` = ' +but nothing behind it, it is interpreted +as if no argument was present; this is a slight bug, see the +.BR BUGS ). +Long options may be abbreviated, as long as the abbreviation is not +ambiguous. + +Each parameter not starting with a +.RB ` - ', +and not a required argument of +a previous option, is a non-option parameter. Each parameter after +a +.RB ` -- ' +parameter is always interpreted as a non-option parameter. +If the environment variable +.B POSIXLY_CORRECT +is set, or if the short +option string started with a +.RB ` + ', +all remaining parameters are interpreted +as non-option parameters as soon as the first non-option parameter is +found. +.SH OUTPUT +Output is generated for each element described in the previous section. +Output is done +in the same order as the elements are specified in the input, except +for non-option parameters. Output can be done in +.I compatible +.RI ( unquoted ) +mode, or in such way that whitespace and other special characters within +arguments and non-option parameters are preserved (see +.BR QUOTING ). +When the output is processed in the shell script, it will seem to be +composed of distinct elements that can be processed one by one (by using the +shift command in most shell languages). This is imperfect in unquoted mode, +as elements can be split at unexpected places if they contain whitespace +or special characters. + +If there are problems parsing the parameters, for example because a +required argument is not found or an option is not recognized, an error +will be reported on stderr, there will be no output for the offending +element, and a non-zero error status is returned. + +For a short option, a single +.RB ` - ' +and the option character are generated +as one parameter. If the option has an argument, the next +parameter will be the argument. If the option takes an optional argument, +but none was found, the next parameter will be generated but be empty in +quoting mode, +but no second parameter will be generated in unquoted (compatible) mode. +Note that many other +.BR getopt (1) +implemetations do not support optional arguments. + +If several short options were specified after a single +.RB ` - ', +each will be present in the output as a separate parameter. + +For a long option, +.RB ` -- ' +and the full option name are generated as one +parameter. This is done regardless whether the option was abbreviated or +specified with a single +.RB ` - ' +in the input. Arguments are handled as with short options. + +Normally, no non-option parameters output is generated until all options +and their arguments have been generated. Then +.RB ` -- ' +is generated as a +single parameter, and after it the non-option parameters in the order +they were found, each as a separate parameter. +Only if the first character of the short options string was a +.RB ` - ', +non-option parameter output is generated at the place they are found in the +input (this is not supported if the first format of the +.B SYNOPSIS +is used; in that case all preceding occurences of +.RB ` - ' +and +.RB ` + ' +are ignored). +.SH QUOTING +In compatible mode, whitespace or 'special' characters in arguments or +non-option parameters are not handled correctly. As the output is +fed to the shell script, the script does not know how it is supposed to break +the output into separate parameters. To circumvent this +problem, this implementation offers quoting. The idea is that output +is generated with quotes around each parameter. When this output is once +again fed to the shell (usually by a shell +.B eval +command), it is split correctly into separate parameters. + +Quoting is not enabled if the environment variable +.B GETOPT_COMPATIBLE +is set, if the first form of the +.B SYNOPSIS +is used, or if the option +.RB ` -u ' +is found. + +Different shells use different quoting conventions. You can use the +.RB ` -s ' +option to select the shell you are using. The following shells are +currently supported: +.RB ` sh ', +.RB ` bash ', +.RB ` csh ' +and +.RB ` tcsh '. +Actually, only two `flavors' are distinguished: sh-like quoting conventions +and csh-like quoting conventions. Chances are that if you use another shell +script language, one of these flavors can still be used. + +.SH "SCANNING MODES" +The first character of the short options string may be a +.RB ` - ' +or a +.RB ` + ' +to indicate a special scanning mode. If the first calling form +in the +.B SYNOPSIS +is used they are ignored; the environment variable +.B POSIXLY_CORRECT +is still examined, though. + +If the first character is +.RB ` + ', +or if the environment variable +.B POSIXLY_CORRECT +is set, parsing stops as soon as the first non-option parameter +(ie. a parameter that does not start with a +.RB ` - ') +is found that +is not an option argument. The remaining parameters are all interpreted as +non-option parameters. + +If the first character is a +.RB ` - ', +non-option parameters are outputed at the place where they are found; in normal +operation, they are all collected at the end of output after a +.RB ` -- ' +parameter has been generated. Note that this +.RB ` -- ' +parameter is still generated, but it will always be the last parameter in +this mode. +.SH COMPATIBILITY +This version of +.BR getopt (1) +is written to be as compatible as possible to +other versions. Usually you can just replace them with this version +without any modifications, and with some advantages. + +If the first character of the first parameter of getopt is not a +.RB ` - ', +getopt goes into compatibility mode. It will interpret its first parameter as +the string of short options, and all other arguments will be parsed. It +will still do parameter shuffling (ie. all non-option parameters are outputed +at the end), unless the environment variable +.B POSIXLY_CORRECT +is set. + +The environment variable +.B GETOPT_COMPATIBLE +forces +.B getopt +into compatibility mode. Setting both this environment variable and +.B POSIXLY_CORRECT +offers 100% compatibility for `difficult' programs. Usually, though, +neither is needed. + +In compatibility mode, leading +.RB ` - ' +and +.RB ` + ' +characters in the short options string are ignored. +.SH RETURN CODES +.B getopt +returns error code +.B 0 +for succesful parsing, +.B 1 +if +.BR getopt (3) +returns errors, +.B 2 +if it does not understand its own parameters, +.B 3 +if an internal error occurs like out-of-memory, and +.B 4 +if it is called with +.BR -T . +.SH EXAMPLES +Example scripts for (ba)sh and (t)csh are provided with the +.BR getopt (1) +distribution, and are optionally installed in +.B /usr/local/lib/getopt +or +.BR /usr/lib/getopt . +.SH ENVIRONMENT +.IP POSIXLY_CORRECT +This environment variable is examined by the +.BR getopt (3) +routines. +If it is set, parsing stops as soon as a parameter +is found that is not an option or an option argument. All remaining +parameters are also interpreted as non-option parameters, regardless +whether they start with a +.RB ` - '. +.IP GETOPT_COMPATIBLE +Forces +.B getopt +to use the first calling format as specified in the +.BR SYNOPSIS . +.SH BUGS +.BR getopt (3) +can parse long options with optional arguments that are given an empty optional +argument (but can not do this for short options). This +.BR getopt (1) +treats optional arguments that are empty as if they were not present. +.SH AUTHOR +Frodo Looijaard +.SH "SEE ALSO" +.BR getopt (3), +.BR bash (1), +.BR tcsh (1). + diff --git a/getopt-1.0.3a/getopt.c b/getopt-1.0.3a/getopt.c new file mode 100644 index 000000000..de643f1a7 --- /dev/null +++ b/getopt-1.0.3a/getopt.c @@ -0,0 +1,448 @@ +/* + getopt.c - Enhanced implementation of BSD getopt(1) + Copyright (c) 1997, 1998 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * Version 1.0-b4: Tue Sep 23 1997. First public release. + * Version 1.0: Wed Nov 19 1997. + * Bumped up the version number to 1.0 + * Fixed minor typo (CSH instead of TCSH) + * Version 1.0.1: Tue Jun 3 1998 + * Fixed sizeof instead of strlen bug + * Bumped up the version number to 1.0.1 + * Version 1.0.2: Thu Jun 11 1998 (not present) + * Fixed gcc-2.8.1 warnings + * Fixed --version/-V option (not present) + */ + +#include +#include +#include +#include +#include + +#if LIBCGETOPT +#include +#else +#include "getopt.h" +#endif + +/* NON_OPT is the code that is returned when a non-option is found in '+' + mode */ +#define NON_OPT 1 +/* LONG_OPT is the code that is returned when a long option is found. */ +#define LONG_OPT 2 + +/* The shells recognized. */ +typedef enum {BASH,TCSH} shell_t; + + +/* Some global variables that tells us how to parse. */ +shell_t shell=BASH; /* The shell we generate output for. */ +int quiet_errors=0; /* 0 is not quiet. */ +int quiet_output=0; /* 0 is not quiet. */ +int quote=1; /* 1 is do quote. */ +int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ + +/* Function prototypes */ +void *our_malloc(size_t size); +void *our_realloc(void *ptr, size_t size); +const char *normalize(const char *arg); +int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts); +int main(int argc, char *argv[]); +void parse_error(const char *message); +void add_long_options(char *options); +void add_longopt(const char *name,int has_arg); +void print_help(void); +void set_shell(const char *new_shell); +void set_initial_shell(void); + +void *our_malloc(size_t size) +{ + void *ret=malloc(size); + if (! ret) { + fputs("getopt: Out of memory!",stderr); + exit(3); + } + return(ret); +} + +void *our_realloc(void *ptr, size_t size) +{ + void *ret=realloc(ptr,size); + if (! ret && size) { + fputs("getopt: Out of memory!",stderr); + exit(3); + } + return(ret); +} + +/* + * This function 'normalizes' a single argument: it puts single quotes around + * it and escapes other special characters. If quote is false, it just + * returns its argument. + * Bash only needs special treatment for single quotes; tcsh also recognizes + * exclamation marks within single quotes, and nukes whitespace. + * This function returns a pointer to a buffer that is overwritten by + * each call. + */ +const char *normalize(const char *arg) +{ + static char *BUFFER=NULL; + const char *argptr=arg; + char *bufptr; + + if (BUFFER != NULL) + free(BUFFER); + + if (!quote) { /* Just copy arg */ + BUFFER=our_malloc(strlen(arg)+1); + + strcpy(BUFFER,arg); + return BUFFER; + } + + /* Each character in arg may take upto four characters in the result: + For a quote we need a closing quote, a backslash, a quote and an + opening quote! We need also the global opening and closing quote, + and one extra character for '\0'. */ + BUFFER=our_malloc(strlen(arg)*4+3); + + bufptr=BUFFER; + *bufptr++='\''; + + while (*argptr) { + if (*argptr == '\'') { + /* Quote: replace it with: '\'' */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='\''; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='!') { + /* Exclamation mark: replace it with: \! */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='!'; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='\n') { + /* Newline: replace it with: \n */ + *bufptr++='\\'; + *bufptr++='n'; + } else if (shell==TCSH && isspace(*argptr)) { + /* Non-newline whitespace: replace it with \ */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++=*argptr; + *bufptr++='\''; + } else + /* Just copy */ + *bufptr++=*argptr; + argptr++; + } + *bufptr++='\''; + *bufptr++='\0'; + return BUFFER; +} + +/* + * Generate the output. argv[0] is the program name (used for reporting errors). + * argv[1..] contains the options to be parsed. argc must be the number of + * elements in argv (ie. 1 if there are no options, only the program name), + * optstr must contain the short options, and longopts the long options. + * Other settings are found in global variables. + */ +int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts) +{ + int exit_code = 0; /* We assume everything will be OK */ + int opt; + int longindex; + const char *charptr; + + if (quiet_errors) /* No error reporting from getopt(3) */ + opterr=0; + optind=0; /* Reset getopt(3) */ + + while ((opt = (alternative? + getopt_long_only(argc,argv,optstr,longopts,&longindex): + getopt_long(argc,argv,optstr,longopts,&longindex))) + != EOF) + if (opt == '?' || opt == ':' ) + exit_code = 1; + else if (!quiet_output) + { + if (opt == LONG_OPT) { + printf(" --%s",longopts[longindex].name); + if (longopts[longindex].has_arg) + printf(" %s", + normalize(optarg?optarg:"")); + } else if (opt == NON_OPT) + printf(" %s",normalize(optarg)); + else { + printf(" -%c",opt); + charptr = strchr(optstr,opt); + if (charptr != NULL && *++charptr == ':') + printf(" %s", + normalize(optarg?optarg:"")); + } + } + + if (! quiet_output) { + printf(" --"); + while (optind < argc) + printf(" %s",normalize(argv[optind++])); + printf("\n"); + } + return exit_code; +} + +/* + * Report an error when parsing getopt's own arguments. + * If message is NULL, we already sent a message, we just exit with a helpful + * hint. + */ +void parse_error(const char *message) +{ + if (message) + fprintf(stderr,"getopt: %s\n",message); + fputs("Try `getopt --help' for more information.\n",stderr); + exit(2); +} + +static struct option *long_options=NULL; +static int long_options_length=0; /* Length of array */ +static int long_options_nr=0; /* Nr of used elements in array */ +#define LONG_OPTIONS_INCR 10 +#define init_longopt() add_longopt(NULL,0) + +/* Register a long option. The contents of name is copied. */ +void add_longopt(const char *name,int has_arg) +{ + char *tmp; + if (!name) { /* init */ + free(long_options); + long_options=NULL; + long_options_length=0; + long_options_nr=0; + } + + if (long_options_nr == long_options_length) { + long_options_length += LONG_OPTIONS_INCR; + long_options=our_realloc(long_options, + sizeof(struct option) * + long_options_length); + } + + long_options[long_options_nr].name=NULL; + long_options[long_options_nr].has_arg=0; + long_options[long_options_nr].flag=NULL; + long_options[long_options_nr].val=0; + + if (long_options_nr) { /* Not for init! */ + long_options[long_options_nr-1].has_arg=has_arg; + long_options[long_options_nr-1].flag=NULL; + long_options[long_options_nr-1].val=LONG_OPT; + tmp = our_malloc(strlen(name)+1); + strcpy(tmp,name); + long_options[long_options_nr-1].name=tmp; + } + long_options_nr++; +} + + +/* + * Register several long options. options is a string of long options, + * separated by commas or whitespace. + * This nukes options! + */ +void add_long_options(char *options) +{ + int arg_opt; + char *tokptr=strtok(options,", \t\n"); + while (tokptr) { + arg_opt=no_argument; + if (strlen(tokptr) > 0) { + if (tokptr[strlen(tokptr)-1] == ':') { + if (tokptr[strlen(tokptr)-2] == ':') { + tokptr[strlen(tokptr)-2]='\0'; + arg_opt=optional_argument; + } else { + tokptr[strlen(tokptr)-1]='\0'; + arg_opt=required_argument; + } + if (strlen(tokptr) == 0) + parse_error("empty long option after " + "-l or --long argument"); + } + add_longopt(tokptr,arg_opt); + } + tokptr=strtok(NULL,", \t\n"); + } +} + +void set_shell(const char *new_shell) +{ + if (!strcmp(new_shell,"bash")) + shell=BASH; + else if (!strcmp(new_shell,"tcsh")) + shell=TCSH; + else if (!strcmp(new_shell,"sh")) + shell=BASH; + else if (!strcmp(new_shell,"csh")) + shell=TCSH; + else + parse_error("unknown shell after -s or --shell argument"); +} + +void print_help(void) +{ + fputs("Usage: getopt optstring parameters\n",stderr); + fputs(" getopt [options] [--] optstring parameters\n",stderr); + fputs(" getopt [options] -o|--options optstring [options] [--]\n",stderr); + fputs(" parameters\n",stderr); + fputs(" -a, --alternative Allow long options starting with single -\n",stderr); + fputs(" -h, --help This small usage guide\n",stderr); + fputs(" -l, --longoptions=longopts Long options to be recognized\n",stderr); + fputs(" -n, --name=progname The name under which errors are reported\n",stderr); + fputs(" -o, --options=optstring Short options to be recognized\n",stderr); + fputs(" -q, --quiet Disable error reporting by getopt(3)\n",stderr); + fputs(" -Q, --quiet-output No normal output\n",stderr); + fputs(" -s, --shell=shell Set shell quoting conventions\n",stderr); + fputs(" -T, --test Test for getopt(1) version\n",stderr); + fputs(" -V, --version Output version information\n",stderr); + exit(2); +} + +/* Exit codes: + * 0) No errors, succesful operation. + * 1) getopt(3) returned an error. + * 2) A problem with parameter parsing for getopt(1). + * 3) Internal error, out of memory + * 4) Returned for -T + */ + +static struct option longopts[]={ {"options",required_argument,NULL,'o'}, + {"longoptions",required_argument,NULL,'l'}, + {"quiet",no_argument,NULL,'q'}, + {"quiet-output",no_argument,NULL,'Q'}, + {"shell",required_argument,NULL,'s'}, + {"test",no_argument,NULL,'T'}, + {"unquoted",no_argument,NULL,'u'}, + {"help",no_argument,NULL,'h'}, + {"alternative",no_argument,NULL,'a'}, + {"name",required_argument,NULL,'n'}, + {"version",no_argument,NULL,'V'}, + {NULL,0,NULL,0} + }; + +/* Stop scanning as soon as a non-option argument is found! */ +static const char *shortopts="+ao:l:n:qQs:TuhV"; + +int main(int argc, char *argv[]) +{ + char *optstr=NULL; + char *name=NULL; + int 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.3\n"); + exit(0); + case '?': + case ':': + parse_error(NULL); + default: + parse_error("internal error, contact the author."); + } + + if (!optstr) + { + if (optind >= argc) + parse_error("missing optstring argument"); + else { + optstr=our_malloc(strlen(argv[optind])+1); + strcpy(optstr,argv[optind]); + optind++; + } + } + if (name) + argv[optind-1]=name; + else + argv[optind-1]=argv[0]; + exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); +} diff --git a/getopt-1.0.3a/gnu/getopt.c b/getopt-1.0.3a/gnu/getopt.c new file mode 100644 index 000000000..59b51cd67 --- /dev/null +++ b/getopt-1.0.3a/gnu/getopt.c @@ -0,0 +1,1050 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 + Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#include +#endif /* GNU C library. */ + +#ifdef VMS +#include +#if HAVE_STRING_H - 0 +#include +#endif +#endif + +#if defined (WIN32) && !defined (__CYGWIN32__) +/* It's not Unix, really. See? Capital letters. */ +#include +#define getpid() GetCurrentProcessId() +#endif + +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* 1003.2 says this must be 1 before any call. */ +int optind = 1; + +/* Formerly, initialization of getopt depended on optind==0, which + causes problems with re-calling getopt as programs generally don't + know that. */ + +int __getopt_initialized = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return -1 with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +#ifdef _LIBC +/* Bash 2.0 gives us an environment variable containing flags + indicating ARGV elements that should not be considered arguments. */ + +/* Defined in getopt_init.c */ +extern char *__getopt_nonoption_flags; + +static int nonoption_flags_max_len; +static int nonoption_flags_len; + +static int original_argc; +static char *const *original_argv; + +extern pid_t __libc_pid; + +/* Make sure the environment variable bash 2.0 puts in the environment + is valid for the getopt call we must make sure that the ARGV passed + to getopt is that one passed to the process. */ +static void +__attribute__ ((unused)) +store_args_and_env (int argc, char *const *argv) +{ + /* XXX This is no good solution. We should rather copy the args so + that we can compare them later. But we must not use malloc(3). */ + original_argc = argc; + original_argv = argv; +} +text_set_element (__libc_subinit, store_args_and_env); + +# define SWAP_FLAGS(ch1, ch2) \ + if (nonoption_flags_len > 0) \ + { \ + char __tmp = __getopt_nonoption_flags[ch1]; \ + __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ + __getopt_nonoption_flags[ch2] = __tmp; \ + } +#else /* !_LIBC */ +# define SWAP_FLAGS(ch1, ch2) +#endif /* _LIBC */ + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +#if defined (__STDC__) && __STDC__ +static void exchange (char **); +#endif + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + +#ifdef _LIBC + /* First make sure the handling of the `__getopt_nonoption_flags' + string can work normally. Our top argument must be in the range + of the string. */ + if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) + { + /* We must extend the array. The user plays games with us and + presents new arguments. */ + char *new_str = malloc (top + 1); + if (new_str == NULL) + nonoption_flags_len = nonoption_flags_max_len = 0; + else + { + memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len); + memset (&new_str[nonoption_flags_max_len], '\0', + top + 1 - nonoption_flags_max_len); + nonoption_flags_max_len = top + 1; + __getopt_nonoption_flags = new_str; + } + } +#endif + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + SWAP_FLAGS (bottom + i, middle + i); + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +#if defined (__STDC__) && __STDC__ +static const char *_getopt_initialize (int, char *const *, const char *); +#endif +static const char * +_getopt_initialize (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + +#ifdef _LIBC + if (posixly_correct == NULL + && argc == original_argc && argv == original_argv) + { + if (nonoption_flags_max_len == 0) + { + if (__getopt_nonoption_flags == NULL + || __getopt_nonoption_flags[0] == '\0') + nonoption_flags_max_len = -1; + else + { + const char *orig_str = __getopt_nonoption_flags; + int len = nonoption_flags_max_len = strlen (orig_str); + if (nonoption_flags_max_len < argc) + nonoption_flags_max_len = argc; + __getopt_nonoption_flags = + (char *) malloc (nonoption_flags_max_len); + if (__getopt_nonoption_flags == NULL) + nonoption_flags_max_len = -1; + else + { + memcpy (__getopt_nonoption_flags, orig_str, len); + memset (&__getopt_nonoption_flags[len], '\0', + nonoption_flags_max_len - len); + } + } + } + nonoption_flags_len = nonoption_flags_max_len; + } + else + nonoption_flags_len = 0; +#endif + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns -1. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0 || !__getopt_initialized) + { + if (optind == 0) + optind = 1; /* Don't scan ARGV[0], the program name. */ + optstring = _getopt_initialize (argc, argv, optstring); + __getopt_initialized = 1; + } + + /* Test whether ARGV[optind] points to a non-option argument. + Either it does not have option syntax, or there is an environment flag + from the shell indicating it is not an option. The later information + is only used when the used in the GNU libc. */ +#ifdef _LIBC +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ + || (optind < nonoption_flags_len \ + && __getopt_nonoption_flags[optind] == '1')) +#else +#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') +#endif + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been + moved back by the user (who may also have changed the arguments). */ + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc && NONOPTION_P) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return -1; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if (NONOPTION_P) + { + if (ordering == REQUIRE_ORDER) + return -1; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) + == (unsigned int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + optopt = 0; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + + nextchar += strlen (nextchar); + + optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + optopt = 0; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), + argv[0], c); + else + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); + } + optopt = c; + return '?'; + } + /* Convenience. Treat POSIX -W foo same as long option --foo */ + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + + /* optarg is now the argument, see if it's in the + table of longopts. */ + + for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if ((unsigned int) (nameend - nextchar) == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + fprintf (stderr, _("\ +%s: option `-W %s' doesn't allow an argument\n"), + argv[0], pfound->name); + + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + nextchar = NULL; + return 'W'; /* Let the application handle it. */ + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == -1) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/getopt-1.0.3a/gnu/getopt.h b/getopt-1.0.3a/gnu/getopt.h new file mode 100644 index 000000000..d6ceb0eee --- /dev/null +++ b/getopt-1.0.3a/gnu/getopt.h @@ -0,0 +1,131 @@ +/* Declarations for getopt. + Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/getopt-1.0.3a/gnu/getopt1.c b/getopt-1.0.3a/gnu/getopt1.c new file mode 100644 index 000000000..4aa8de6f6 --- /dev/null +++ b/getopt-1.0.3a/gnu/getopt1.c @@ -0,0 +1,187 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#define GETOPT_INTERFACE_VERSION 2 +#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 +#include +#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION +#define ELIDE_CODE +#endif +#endif + +#ifndef ELIDE_CODE + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* Not ELIDE_CODE. */ + +#ifdef TEST + +#include + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == -1) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/getopt-1.0.3a/parse.bash b/getopt-1.0.3a/parse.bash new file mode 100644 index 000000000..864fc0add --- /dev/null +++ b/getopt-1.0.3a/parse.bash @@ -0,0 +1,47 @@ +#!/bin/bash + +# A small example program for using the new getopt(1) program. +# This program will only work with bash(1) +# An similar program using the tcsh(1) script language can be found +# as parse.tcsh + +# Example input and output (from the bash prompt): +# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " +# Option a +# Option c, no argument +# Option c, argument `more' +# Option b, argument ` very long ' +# Remaining arguments: +# --> `par1' +# --> `another arg' +# --> `wow!*\?' + +# Note that we use `"$@"' to let each command-line parameter expand to a +# separate word. The quotes around `$@' are essential! +# We need TEMP as the `eval set --' would nuke the return value of getopt. +TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ + -n 'example.bash' -- "$@"` + +if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi + +# Note the quotes around `$TEMP': they are essential! +eval set -- "$TEMP" + +while true ; do + case "$1" in + -a|--a-long) echo "Option a" ; shift ;; + -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; + -c|--c-long) + # c has an optional argument. As we are in quoted mode, + # an empty parameter will be generated if its optional + # argument is not found. + case "$2" in + "") echo "Option c, no argument"; shift 2 ;; + *) echo "Option c, argument \`$2'" ; shift 2 ;; + esac ;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac +done +echo "Remaining arguments:" +for arg do echo '--> '"\`$arg'" ; done diff --git a/getopt-1.0.3a/parse.tcsh b/getopt-1.0.3a/parse.tcsh new file mode 100644 index 000000000..2266d0e64 --- /dev/null +++ b/getopt-1.0.3a/parse.tcsh @@ -0,0 +1,77 @@ +#!/bin/tcsh + +# A small example program for using the new getopt(1) program. +# This program will only work with tcsh(1) +# An similar program using the bash(1) script language can be found +# as parse.bash + +# 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\) + +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:q\' ; 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:q\' + endif + shift; shift + breaksw + case --: + shift + break + default: + echo "Internal error!" ; exit 1 + endsw +end + +echo "Remaining arguments:" +# foreach el ($argv:q) created problems for some tcsh-versions (at least +# 6.02). So we use another shift-loop here: +while ($#argv > 0) + echo '--> '\`$1:q\' + shift +end diff --git a/getopt-1.0.3a/test.bash b/getopt-1.0.3a/test.bash new file mode 100644 index 000000000..149e1f9b0 --- /dev/null +++ b/getopt-1.0.3a/test.bash @@ -0,0 +1,6 @@ +#!/bin/bash +if `getopt -T >/dev/null 2>&1` ; [ $? = 4 ] ; then + echo "Enhanced getopt(1)" +else + echo "Old getopt(1)" +fi diff --git a/getopt-1.0.3a/test.tcsh b/getopt-1.0.3a/test.tcsh new file mode 100644 index 000000000..d661e767d --- /dev/null +++ b/getopt-1.0.3a/test.tcsh @@ -0,0 +1,7 @@ +#!/bin/tcsh +getopt -T >&/dev/null +if ( $status == 4) then + echo "Enhanced getopt(1)" +else + echo "Old getopt(1)" +endif diff --git a/getopt/COPYING b/getopt/COPYING deleted file mode 100644 index a43ea2126..000000000 --- a/getopt/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/getopt/Changelog b/getopt/Changelog deleted file mode 100644 index 0480a1ded..000000000 --- a/getopt/Changelog +++ /dev/null @@ -1,8 +0,0 @@ -980611: Bumped up version number to 1.0.2 -980611: Fixed --version bug (was not available, though documented!) -980611: Removed compiler warnings. -980603: Bumped up version number to 1.0.1 -980603: Fixed sizeof() bug (should be strlen) in getopt.c, thanks to Bob Proulx - (rwp@hprwp.fc.hp.com). -980505: Changed date field in LSM to proper syntax -980505: Released version 1.0 diff --git a/getopt/Makefile b/getopt/Makefile deleted file mode 100644 index 368291f0c..000000000 --- a/getopt/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -.SUFFIXES: - -include ../MCONFIG - -prefix=$(DESTDIR)/usr -bindir=$(USRBINDIR) -mandir=$(MANDIR) -man1dir=$(MAN1DIR)/man1 -getoptdir=$(USRLIBDIR)/getopt - -# Define this to 0 to use the getopt(3) routines in this package. -LIBCGETOPT=1 - -SHELL=/bin/sh - -LD=ld -RM=rm -f -INSTALL=install - -CPPFLAGS=-DLIBCGETOPT=$(LIBCGETOPT) -ifeq ($(LIBCGETOPT),0) -CPPFLAGS+=-I./gnu -endif -WARNINGS=-Wall \ - -W -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-qual \ - -Wcast-align -Wmissing-declarations \ - -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \ - -Wnested-externs -Winline -CFLAGS=$(WARNINGS) $(OPT) - -sources=getopt.c -ifeq ($(LIBCGETOPT),0) -sources+=gnu/getopt.c gnu/getopt1.c -endif - -objects=$(sources:.c=.o) - -binaries=getopt - -.PHONY: all clean realclean -all: $(binaries) - -clean: - -$(RM) $(objects) $(binaries) - -%.o: %.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) $*.c -o $*.o - -getopt: $(objects) - $(CC) $(LDFLAGS) -o $@ $(objects) - -install: getopt - $(INSTALL) -m 755 getopt $(bindir) - $(INSTALL) -m 644 getopt.1 $(man1dir) - $(INSTALL) -m 755 -d $(getoptdir) - $(INSTALL) -m 754 parse.bash parse.tcsh test.bash test.tcsh $(getoptdir) diff --git a/getopt/README b/getopt/README deleted file mode 100644 index 04addba98..000000000 --- a/getopt/README +++ /dev/null @@ -1,80 +0,0 @@ -This package contains a reimplementation of getopt(1). - -PREFACE - -Getopt(1) is a program to help shell scripts parse command-line parameters. -It is for example included in the util-linux distribution. But, there are -some problems with that getopt(1) implementation, as listed in the -'BUGS' section of its man-page: - ->BUGS -> Whatever getopt(3) has. -> -> Arguments containing white space or imbedded shell metacharacters gener- -> ally will not survive intact; this looks easy to fix but isn't. -> -> The error message for an invalid option is identified as coming from -> getopt rather than from the shell procedure containing the invocation of -> getopt; this again is hard to fix. -> -> The precise best way to use the set command to set the arguments without -> disrupting the value(s) of shell options varies from one shell version to -> another. - -This implementation of getopt(1) is written to solve some of these problems, -while still staying (for all practical purposes) completely compatible with -other getopt(1) implementations. - - -INSTALLATION - -Installation should be very easy. Just type 'make' to compile the sources. -It should compile cleanly, without any warnings, but even if it does not -you probably don't have to worry. You must use GNU Make and gcc, or you -will have to edit the Makefile. - -Type 'make install' to install the binary and the manual page. It installs -by default in /usr/local/bin and /usr/local/man/man1, to install in /usr/bin -and /usr/man/man1 try 'make install prefix=/usr'. - -The example files can be installed in /usr/local/lib/getopt by calling -'make install_doc'. - -If you do not trust the getopt(3) in your libc, or if you do not use a libc -with the GNU getopt(3) routines, you can use the gnu sources as provided -in the gnu directory. Try 'make LIBCGETOPT=0'. Ignore any compile warnings. - -You can check whether the new implementation of getopt is found first -in your path by calling 'bash test.bash'. - - -HIGHLIGHTS - -It can do anything that the GNU getopt(3) routines can do. - -It can cope with spaces and shell metacharacters within arguments. - -It can parse long parameters. - -It can shuffle parameters, so you can mix options and other parameters on -the command-line. - -It can be easily identified as an enhanced getopt(1) from within shell scripts. - -It can report parse errors as coming from the shell script. - -It is fully compatible with other getopt(1) implementations. - -COPYING - -This program comes under the GNU general public licence version 2. See the -file COPYING included in this package. Note that though you may freely -copy it, it is copyright (c) 1997 by Frodo Looijaard . -Files in the gnu directory are from glibc-2.0.4: copyright (C) 1987, 88, -89, 90, 91, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. - - -DOWNLOADING - -You can find the latest version of this program at -. diff --git a/getopt/TODO b/getopt/TODO deleted file mode 100644 index e701f6661..000000000 --- a/getopt/TODO +++ /dev/null @@ -1,4 +0,0 @@ -Other shells, like zsh and ash, should be supported (perhaps they will work -already, depending on quoting conventions). (zsh seems OK). - -Perhaps a nice configure script? diff --git a/getopt/getopt.1 b/getopt/getopt.1 deleted file mode 100644 index c3aaa0195..000000000 --- a/getopt/getopt.1 +++ /dev/null @@ -1,436 +0,0 @@ -.TH GETOPT 1 "May 31, 1997" Linux "" -.SH NAME -getopt \- parse command options (enhanced) -.SH SYNOPSIS -.BR getopt " optstring parameters" - -.BR getopt " [options] [" -- "] optstring parameters" - -.BR getopt " [options] " -o | --options " optstring [options] [" -- "] parameters" -.SH DESCRIPTION -.B getopt -is used to break up -.RI ( parse ) -options in command lines for easy parsing by -shell procedures, and to check for legal options. -It uses the -.SM GNU -.BR getopt (3) -routines to do this. - -The parameters -.B getopt -is called with can be divided into two parts: options -which modify the way getopt will parse -.RI ( options -and -.I -o|--options optstring -in the -.BR SYNOPSIS), -and the parameters which are to be -parsed -.RI ( parameters -in the -.BR SYNOPSIS). -The second part will start at the first non-option parameter -that is not an option argument, or after the first occurence of -.RB ` -- '. -If no -.RB ` -o ' -or -.RB ` --options ' -option is found in the first part, the first -parameter of the second part is used as the short options string. - -If the environment variable -.B GETOPT_COMPATIBLE -is set, or if its first parameter -is not an option (does not start with a -.RB ` - ', -this is the first format in the -.BR SYNOPSIS), -.B getopt -will generate output that is compatible with that of other versions of -.BR getopt (1). -It will still do parameter shuffling and recognize optional -arguments (see section -.B COMPATIBILITY -for more information). - -Traditional implementations of -.BR getopt (1) -are unable to cope with whitespace and other (shell-specific) special characters -in arguments and non-option parameters. To solve this problem, this -implementation can generate -quoted output which must once again be interpreted by the shell (usually -by using the -.B eval -command). This has the effect of preserving those characters, but -you must call -.B getopt -in a way that is no longer compatible with other versions (the second -or third format in the -.BR SYNOPSIS). -To determine whether this enhanced version of -.BR getopt (1) -is installed, a special test option -.RB ( -T ) -can be used. -.SH OPTIONS -.IP "-a, --alternative" -Allow long options to start with a single -.RB ` - '. -.IP "-h, --help" -Output a small usage guide and exit succesfully. No other output is generated. -.IP "-l, --longoptions longopts" -The long (multi-character) options to be recognized. -More than one option name -may be specified at once, by separating the names with commas. This option -may be given more than once, the -.I longopts -are cummulative. -Each long option name -in -.I longopts -may be followed by one colon to indicate it has a required argument,and by two colons to indicate it has an optional argument. -.IP "-n, --name progname" -The name that will be used by the -.BR getopt (3) -routines when it reports errors. Note that errors of -.BR getopt (1) -are still reported as coming from getopt. -.IP "-o, --options shortopts" -The short (one-character) options to be recognized. If this options is not -found, the first parameter of -.B getopt -that does not start with -a -.RB ` - ' -(and is not an option argument) is used as the short options string. -Each short option character -in -.I shortopts -may be followed by one colon to indicate it has a required argument, -and by two colons to indicate it has an optional argument. -The first character of shortopts may be -.RB ` + ' -or -.RB ` - ' -to influence the way -options are parsed and output is generated (see section -.B SCANNING MODES -for details). -.IP "-q, --quiet" -Disable error reporting by getopt(3). -.IP "-Q, --quiet-output" -Do not generate normal output. Errors are still reported by -.BR getopt (3), -unless you also use -.IR -q . -.IP "-s, --shell shell" -Set quoting conventions to those of shell. If no -s argument is found, -the -.SM BASH -conventions are used. Valid arguments are currently -.RB ` sh ' -.RB ` bash ', -.RB ` csh ', -and -.RB ` tcsh '. -.IP "-u, --unquoted" -Do not quote the output. Note that whitespace and special (shell-dependent) -characters can cause havoc in this mode (like they do with other -.BR getopt (1) -implementations). -.IP "-T --test" -Test if your -.BR getopt (1) -is this enhanced version or an old version. This generates no output, -and sets the error status to 4. Other implementations of -.BR getopt (1), -and this version if the environment variable -.B GETOPT_COMPATIBLE -is set, -will return -.RB ` -- ' -and error status 0. -.IP "-V, --version" -Output version information and exit succesfully. No other output is generated. -.SH PARSING -This section specifies the format of the second part of the parameters of -.B getopt -(the -.I parameters -in the -.BR SYNOPSIS ). -The next section -.RB ( OUTPUT ) -describes the output that is -generated. These parameters were typically the parameters a shell function -was called with. -Care must be taken that each parameter the shell function was -called with corresponds to exactly one parameter in the parameter list of -.B getopt -(see the -.BR EXAMPLES ). -All parsing is done by the GNU -.BR getopt (3) -routines. - -The parameters are parsed from left to right. Each parameter is classified as a -short option, a long option, an argument to an option, -or a non-option parameter. - -A simple short option is a -.RB ` - ' -followed by a short option character. If -the option has a required argument, it may be written directly after the option -character or as the next parameter (ie. separated by whitespace on the -command line). If the -option has an optional argument, it must be written directly after the -option character if present. - -It is possible to specify several short options after one -.RB ` - ', -as long as all (except possibly the last) do not have required or optional -arguments. - -A long option normally begins with -.RB ` -- ' -followed by the long option name. -If the option has a required argument, it may be written directly after -the long option name, separated by -.RB ` = ', -or as the next argument (ie. separated by whitespace on the command line). -If the option has an optional argument, it must -be written directly after the long option name, separated by -.RB ` = ', -if present (if you add the -.RB ` = ' -but nothing behind it, it is interpreted -as if no argument was present; this is a slight bug, see the -.BR BUGS ). -Long options may be abbreviated, as long as the abbreviation is not -ambiguous. - -Each parameter not starting with a -.RB ` - ', -and not a required argument of -a previous option, is a non-option parameter. Each parameter after -a -.RB ` -- ' -parameter is always interpreted as a non-option parameter. -If the environment variable -.B POSIXLY_CORRECT -is set, or if the short -option string started with a -.RB ` + ', -all remaining parameters are interpreted -as non-option parameters as soon as the first non-option parameter is -found. -.SH OUTPUT -Output is generated for each element described in the previous section. -Output is done -in the same order as the elements are specified in the input, except -for non-option parameters. Output can be done in -.I compatible -.RI ( unquoted ) -mode, or in such way that whitespace and other special characters within -arguments and non-option parameters are preserved (see -.BR QUOTING ). -When the output is processed in the shell script, it will seem to be -composed of distinct elements that can be processed one by one (by using the -shift command in most shell languages). This is imperfect in unquoted mode, -as elements can be split at unexpected places if they contain whitespace -or special characters. - -If there are problems parsing the parameters, for example because a -required argument is not found or an option is not recognized, an error -will be reported on stderr, there will be no output for the offending -element, and a non-zero error status is returned. - -For a short option, a single -.RB ` - ' -and the option character are generated -as one parameter. If the option has an argument, the next -parameter will be the argument. If the option takes an optional argument, -but none was found, the next parameter will be generated but be empty in -quoting mode, -but no second parameter will be generated in unquoted (compatible) mode. -Note that many other -.BR getopt (1) -implemetations do not support optional arguments. - -If several short options were specified after a single -.RB ` - ', -each will be present in the output as a separate parameter. - -For a long option, -.RB ` -- ' -and the full option name are generated as one -parameter. This is done regardless whether the option was abbreviated or -specified with a single -.RB ` - ' -in the input. Arguments are handled as with short options. - -Normally, no non-option parameters output is generated until all options -and their arguments have been generated. Then -.RB ` -- ' -is generated as a -single parameter, and after it the non-option parameters in the order -they were found, each as a separate parameter. -Only if the first character of the short options string was a -.RB ` - ', -non-option parameter output is generated at the place they are found in the -input (this is not supported if the first format of the -.B SYNOPSIS -is used; in that case all preceding occurences of -.RB ` - ' -and -.RB ` + ' -are ignored). -.SH QUOTING -In compatible mode, whitespace or 'special' characters in arguments or -non-option parameters are not handled correctly. As the output is -fed to the shell script, the script does not know how it is supposed to break -the output into separate parameters. To circumvent this -problem, this implementation offers quoting. The idea is that output -is generated with quotes around each parameter. When this output is once -again fed to the shell (usually by a shell -.B eval -command), it is split correctly into separate parameters. - -Quoting is not enabled if the environment variable -.B GETOPT_COMPATIBLE -is set, if the first form of the -.B SYNOPSIS -is used, or if the option -.RB ` -u ' -is found. - -Different shells use different quoting conventions. You can use the -.RB ` -s ' -option to select the shell you are using. The following shells are -currently supported: -.RB ` sh ', -.RB ` bash ', -.RB ` csh ' -and -.RB ` tcsh '. -Actually, only two `flavors' are distinguished: sh-like quoting conventions -and csh-like quoting conventions. Chances are that if you use another shell -script language, one of these flavors can still be used. - -.SH "SCANNING MODES" -The first character of the short options string may be a -.RB ` - ' -or a -.RB ` + ' -to indicate a special scanning mode. If the first calling form -in the -.B SYNOPSIS -is used they are ignored; the environment variable -.B POSIXLY_CORRECT -is still examined, though. - -If the first character is -.RB ` + ', -or if the environment variable -.B POSIXLY_CORRECT -is set, parsing stops as soon as the first non-option parameter -(ie. a parameter that does not start with a -.RB ` - ') -is found that -is not an option argument. The remaining parameters are all interpreted as -non-option parameters. - -If the first character is a -.RB ` - ', -non-option parameters are outputed at the place where they are found; in normal -operation, they are all collected at the end of output after a -.RB ` -- ' -parameter has been generated. Note that this -.RB ` -- ' -parameter is still generated, but it will always be the last parameter in -this mode. -.SH COMPATIBILITY -This version of -.BR getopt (1) -is written to be as compatible as possible to -other versions. Usually you can just replace them with this version -without any modifications, and with some advantages. - -If the first character of the first parameter of getopt is not a -.RB ` - ', -getopt goes into compatibility mode. It will interpret its first parameter as -the string of short options, and all other arguments will be parsed. It -will still do parameter shuffling (ie. all non-option parameters are outputed -at the end), unless the environment variable -.B POSIXLY_CORRECT -is set. - -The environment variable -.B GETOPT_COMPATIBLE -forces -.B getopt -into compatibility mode. Setting both this environment variable and -.B POSIXLY_CORRECT -offers 100% compatibility for `difficult' programs. Usually, though, -neither is needed. - -In compatibility mode, leading -.RB ` - ' -and -.RB ` + ' -characters in the short options string are ignored. -.SH RETURN CODES -.B getopt -returns error code -.B 0 -for succesful parsing, -.B 1 -if -.BR getopt (3) -returns errors, -.B 2 -if it does not understand its own parameters, -.B 3 -if an internal error occurs like out-of-memory, and -.B 4 -if it is called with -.BR -T . -.SH EXAMPLES -Example scripts for (ba)sh and (t)csh are provided with the -.BR getopt (1) -distribution, and are optionally installed in -.B /usr/local/lib/getopt -or -.BR /usr/lib/getopt . -.SH ENVIRONMENT -.IP POSIXLY_CORRECT -This environment variable is examined by the -.BR getopt (3) -routines. -If it is set, parsing stops as soon as a parameter -is found that is not an option or an option argument. All remaining -parameters are also interpreted as non-option parameters, regardless -whether they start with a -.RB ` - '. -.IP GETOPT_COMPATIBLE -Forces -.B getopt -to use the first calling format as specified in the -.BR SYNOPSIS . -.SH BUGS -.BR getopt (3) -can parse long options with optional arguments that are given an empty optional -argument (but can not do this for short options). This -.BR getopt (1) -treats optional arguments that are empty as if they were not present. -.SH AUTHOR -Frodo Looijaard -.SH "SEE ALSO" -.BR getopt (3), -.BR bash (1), -.BR tcsh (1). - diff --git a/getopt/getopt.c b/getopt/getopt.c deleted file mode 100644 index 00be49f34..000000000 --- a/getopt/getopt.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - getopt.c - Enhanced implementation of BSD getopt(1) - Copyright (c) 1997, 1998 Frodo Looijaard - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - * Version 1.0-b4: Tue Sep 23 1997. First public release. - * Version 1.0: Wed Nov 19 1997. - * Bumped up the version number to 1.0 - * Fixed minor typo (CSH instead of TCSH) - * Version 1.0.1: Tue Jun 3 1998 - * Fixed sizeof instead of strlen bug - * Bumped up the version number to 1.0.1 - * Version 1.0.2: Thu Jun 11 1998 (not present) - * Fixed gcc-2.8.1 warnings - * Fixed --version/-V option (not present) - */ - -#include -#include -#include -#include -#include - -#if LIBCGETOPT -#include -#else -#include "getopt.h" -#endif - -/* NON_OPT is the code that is returned when a non-option is found in '+' - mode */ -#define NON_OPT 1 -/* LONG_OPT is the code that is returned when a long option is found. */ -#define LONG_OPT 2 - -/* The shells recognized. */ -typedef enum {BASH,TCSH} shell_t; - - -/* Some global variables that tells us how to parse. */ -shell_t shell=BASH; /* The shell we generate output for. */ -int quiet_errors=0; /* 0 is not quiet. */ -int quiet_output=0; /* 0 is not quiet. */ -int quote=1; /* 1 is do quote. */ -int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ - -/* Function prototypes */ -void *our_malloc(size_t size); -void *our_realloc(void *ptr, size_t size); -const char *normalize(const char *arg); -int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts); -int main(int argc, char *argv[]); -void parse_error(const char *message); -void add_long_options(char *options); -void add_longopt(const char *name,int has_arg); -void print_help(void); -void set_shell(const char *new_shell); -void set_initial_shell(void); - -void *our_malloc(size_t size) -{ - void *ret=malloc(size); - if (! ret) { - fputs("getopt: Out of memory!",stderr); - exit(3); - } - return(ret); -} - -void *our_realloc(void *ptr, size_t size) -{ - void *ret=realloc(ptr,size); - if (! ret && size) { - fputs("getopt: Out of memory!",stderr); - exit(3); - } - return(ret); -} - -/* - * This function 'normalizes' a single argument: it puts single quotes around - * it and escapes other special characters. If quote is false, it just - * returns its argument. - * Bash only needs special treatment for single quotes; tcsh also recognizes - * exclamation marks within single quotes, and nukes whitespace. - * This function returns a pointer to a buffer that is overwritten by - * each call. - */ -const char *normalize(const char *arg) -{ - static char *BUFFER=NULL; - const char *argptr=arg; - char *bufptr; - - if (BUFFER != NULL) - free(BUFFER); - - if (!quote) { /* Just copy arg */ - BUFFER=our_malloc(strlen(arg)+1); - - strcpy(BUFFER,arg); - return BUFFER; - } - - /* Each character in arg may take upto four characters in the result: - For a quote we need a closing quote, a backslash, a quote and an - opening quote! We need also the global opening and closing quote, - and one extra character for '\0'. */ - BUFFER=our_malloc(strlen(arg)*4+3); - - bufptr=BUFFER; - *bufptr++='\''; - - while (*argptr) { - if (*argptr == '\'') { - /* Quote: replace it with: '\'' */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='\''; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='!') { - /* Exclamation mark: replace it with: \! */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='!'; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='\n') { - /* Newline: replace it with: \n */ - *bufptr++='\\'; - *bufptr++='n'; - } else if (shell==TCSH && isspace(*argptr)) { - /* Non-newline whitespace: replace it with \ */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++=*argptr; - *bufptr++='\''; - } else - /* Just copy */ - *bufptr++=*argptr; - argptr++; - } - *bufptr++='\''; - *bufptr++='\0'; - return BUFFER; -} - -/* - * Generate the output. argv[0] is the program name (used for reporting errors). - * argv[1..] contains the options to be parsed. argc must be the number of - * elements in argv (ie. 1 if there are no options, only the program name), - * optstr must contain the short options, and longopts the long options. - * Other settings are found in global variables. - */ -int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts) -{ - int exit_code = 0; /* We assume everything will be OK */ - int opt; - int longindex; - const char *charptr; - - if (quiet_errors) /* No error reporting from getopt(3) */ - opterr=0; - optind=0; /* Reset getopt(3) */ - - while ((opt = (alternative? - getopt_long_only(argc,argv,optstr,longopts,&longindex): - getopt_long(argc,argv,optstr,longopts,&longindex))) - != EOF) - if (opt == '?' || opt == ':' ) - exit_code = 1; - else if (!quiet_output) - { - if (opt == LONG_OPT) { - printf(" --%s",longopts[longindex].name); - if (longopts[longindex].has_arg) - printf(" %s", - normalize(optarg?optarg:"")); - } else if (opt == NON_OPT) - printf(" %s",normalize(optarg)); - else { - printf(" -%c",opt); - charptr = strchr(optstr,opt); - if (charptr != NULL && *++charptr == ':') - printf(" %s", - normalize(optarg?optarg:"")); - } - } - - if (! quiet_output) { - printf(" --"); - while (optind < argc) - printf(" %s",normalize(argv[optind++])); - printf("\n"); - } - return exit_code; -} - -/* - * Report an error when parsing getopt's own arguments. - * If message is NULL, we already sent a message, we just exit with a helpful - * hint. - */ -void parse_error(const char *message) -{ - if (message) - fprintf(stderr,"getopt: %s\n",message); - fputs("Try `getopt --help' for more information.\n",stderr); - exit(2); -} - -static struct option *long_options=NULL; -static int long_options_length=0; /* Length of array */ -static int long_options_nr=0; /* Nr of used elements in array */ -#define LONG_OPTIONS_INCR 10 -#define init_longopt() add_longopt(NULL,0) - -/* Register a long option. The contents of name is copied. */ -void add_longopt(const char *name,int has_arg) -{ - char *tmp; - if (!name) { /* init */ - free(long_options); - long_options=NULL; - long_options_length=0; - long_options_nr=0; - } - - if (long_options_nr == long_options_length) { - long_options_length += LONG_OPTIONS_INCR; - long_options=our_realloc(long_options, - sizeof(struct option) * - long_options_length); - } - - long_options[long_options_nr].name=NULL; - long_options[long_options_nr].has_arg=0; - long_options[long_options_nr].flag=NULL; - long_options[long_options_nr].val=0; - - if (long_options_nr) { /* Not for init! */ - long_options[long_options_nr-1].has_arg=has_arg; - long_options[long_options_nr-1].flag=NULL; - long_options[long_options_nr-1].val=LONG_OPT; - tmp = our_malloc(strlen(name)+1); - strcpy(tmp,name); - long_options[long_options_nr-1].name=tmp; - } - long_options_nr++; -} - - -/* - * Register several long options. options is a string of long options, - * separated by commas or whitespace. - * This nukes options! - */ -void add_long_options(char *options) -{ - int arg_opt; - char *tokptr=strtok(options,", \t\n"); - while (tokptr) { - arg_opt=no_argument; - if (strlen(tokptr) > 0) { - if (tokptr[strlen(tokptr)-1] == ':') { - if (tokptr[strlen(tokptr)-2] == ':') { - tokptr[strlen(tokptr)-2]='\0'; - arg_opt=optional_argument; - } else { - tokptr[strlen(tokptr)-1]='\0'; - arg_opt=required_argument; - } - if (strlen(tokptr) == 0) - parse_error("empty long option after " - "-l or --long argument"); - } - add_longopt(tokptr,arg_opt); - } - tokptr=strtok(NULL,", \t\n"); - } -} - -void set_shell(const char *new_shell) -{ - if (!strcmp(new_shell,"bash")) - shell=BASH; - else if (!strcmp(new_shell,"tcsh")) - shell=TCSH; - else if (!strcmp(new_shell,"sh")) - shell=BASH; - else if (!strcmp(new_shell,"csh")) - shell=TCSH; - else - parse_error("unknown shell after -s or --shell argument"); -} - -void print_help(void) -{ - fputs("Usage: getopt optstring parameters\n",stderr); - fputs(" getopt [options] [--] optstring parameters\n",stderr); - fputs(" getopt [options] -o|--options optstring [options] [--]\n",stderr); - fputs(" parameters\n",stderr); - fputs(" -a, --alternative Allow long options starting with single -\n",stderr); - fputs(" -h, --help This small usage guide\n",stderr); - fputs(" -l, --longoptions=longopts Long options to be recognized\n",stderr); - fputs(" -n, --name=progname The name under which errors are reported\n",stderr); - fputs(" -o, --options=optstring Short options to be recognized\n",stderr); - fputs(" -q, --quiet Disable error reporting by getopt(3)\n",stderr); - fputs(" -Q, --quiet-output No normal output\n",stderr); - fputs(" -s, --shell=shell Set shell quoting conventions\n",stderr); - fputs(" -T, --test Test for getopt(1) version\n",stderr); - fputs(" -V, --version Output version information\n",stderr); - exit(2); -} - -/* Exit codes: - * 0) No errors, succesful operation. - * 1) getopt(3) returned an error. - * 2) A problem with parameter parsing for getopt(1). - * 3) Internal error, out of memory - * 4) Returned for -T - */ - -static struct option longopts[]={ {"options",required_argument,NULL,'o'}, - {"longoptions",required_argument,NULL,'l'}, - {"quiet",no_argument,NULL,'q'}, - {"quiet-output",no_argument,NULL,'Q'}, - {"shell",required_argument,NULL,'s'}, - {"test",no_argument,NULL,'T'}, - {"unquoted",no_argument,NULL,'u'}, - {"help",no_argument,NULL,'h'}, - {"alternative",no_argument,NULL,'a'}, - {"name",required_argument,NULL,'n'}, - {"version",no_argument,NULL,'V'}, - {NULL,0,NULL,0} - }; - -/* Stop scanning as soon as a non-option argument is found! */ -static const char *shortopts="+ao:l:n:qQs:TuhV"; - -int main(int argc, char *argv[]) -{ - char *optstr=NULL; - char *name=NULL; - char opt; - int compatible=0; - - init_longopt(); - - if (getenv("GETOPT_COMPATIBLE")) - compatible=1; - - if (argc == 1) - { - if (compatible) { - /* For some reason, the original getopt gave no error - when there were no arguments. */ - printf(" --\n"); - exit(0); - } - else - parse_error("missing optstring argument"); - } - - if (argv[1][0] != '-' || compatible) { - quote=0; - optstr=our_malloc(strlen(argv[1])+1); - strcpy(optstr,argv[1]+strspn(argv[1],"-+")); - argv[1]=argv[0]; - exit(generate_output(argv+1,argc-1,optstr,long_options)); - } - - while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) - switch (opt) { - case 'a': - alternative=1; - break; - case 'h': - print_help(); - exit(0); - case 'o': - if (optstr) - free(optstr); - optstr=our_malloc(strlen(optarg)+1); - strcpy(optstr,optarg); - break; - case 'l': - add_long_options(optarg); - break; - case 'n': - if (name) - free(name); - name=our_malloc(strlen(optarg)+1); - strcpy(name,optarg); - break; - case 'q': - quiet_errors=1; - break; - case 'Q': - quiet_output=1; - break; - case 's': - set_shell(optarg); - break; - case 'T': - exit(4); - case 'V': - printf("getopt (enhanced) 1.0.2\n"); - exit(0); - case '?': - case ':': - parse_error(NULL); - default: - parse_error("internal error, contact the author."); - } - - if (!optstr) - { - if (optind >= argc) - parse_error("missing optstring argument"); - else { - optstr=our_malloc(strlen(argv[optind])+1); - strcpy(optstr,argv[optind]); - optind++; - } - } - if (name) - argv[optind-1]=name; - else - argv[optind-1]=argv[0]; - exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); -} diff --git a/getopt/gnu/getopt.c b/getopt/gnu/getopt.c deleted file mode 100644 index 59b51cd67..000000000 --- a/getopt/gnu/getopt.c +++ /dev/null @@ -1,1050 +0,0 @@ -/* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu - before changing it! - - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97 - Free Software Foundation, Inc. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* This tells Alpha OSF/1 not to define a getopt prototype in . - Ditto for AIX 3.2 and . */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -/* Don't include stdlib.h for non-GNU C libraries because some of them - contain conflicting prototypes for getopt. */ -#include -#include -#endif /* GNU C library. */ - -#ifdef VMS -#include -#if HAVE_STRING_H - 0 -#include -#endif -#endif - -#if defined (WIN32) && !defined (__CYGWIN32__) -/* It's not Unix, really. See? Capital letters. */ -#include -#define getpid() GetCurrentProcessId() -#endif - -#ifndef _ -/* This is for other GNU distributions with internationalized messages. - When compiling libc, the _ macro is predefined. */ -#ifdef HAVE_LIBINTL_H -# include -# define _(msgid) gettext (msgid) -#else -# define _(msgid) (msgid) -#endif -#endif - -/* This version of `getopt' appears to the caller like standard Unix `getopt' - but it behaves differently for the user, since it allows the user - to intersperse the options with the other arguments. - - As `getopt' works, it permutes the elements of ARGV so that, - when it is done, all the options precede everything else. Thus - all application programs are extended to handle flexible argument order. - - Setting the environment variable POSIXLY_CORRECT disables permutation. - Then the behavior is completely standard. - - GNU application programs can use a third alternative mode in which - they can distinguish the relative order of options and other arguments. */ - -#include "getopt.h" - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -char *optarg = NULL; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -/* 1003.2 says this must be 1 before any call. */ -int optind = 1; - -/* Formerly, initialization of getopt depended on optind==0, which - causes problems with re-calling getopt as programs generally don't - know that. */ - -int __getopt_initialized = 0; - -/* The next char to be scanned in the option-element - in which the last option character we returned was found. - This allows us to pick up the scan where we left off. - - If this is zero, or a null string, it means resume the scan - by advancing to the next ARGV-element. */ - -static char *nextchar; - -/* Callers store zero here to inhibit the error message - for unrecognized options. */ - -int opterr = 1; - -/* Set to an option character which was unrecognized. - This must be initialized on some systems to avoid linking in the - system's own getopt implementation. */ - -int optopt = '?'; - -/* Describe how to deal with options that follow non-option ARGV-elements. - - If the caller did not specify anything, - the default is REQUIRE_ORDER if the environment variable - POSIXLY_CORRECT is defined, PERMUTE otherwise. - - REQUIRE_ORDER means don't recognize them as options; - stop option processing when the first non-option is seen. - This is what Unix does. - This mode of operation is selected by either setting the environment - variable POSIXLY_CORRECT, or using `+' as the first character - of the list of option characters. - - PERMUTE is the default. We permute the contents of ARGV as we scan, - so that eventually all the non-options are at the end. This allows options - to be given in any order, even with programs that were not written to - expect this. - - RETURN_IN_ORDER is an option available to programs that were written - to expect options and other ARGV-elements in any order and that care about - the ordering of the two. We describe each non-option ARGV-element - as if it were the argument of an option with character code 1. - Using `-' as the first character of the list of option characters - selects this mode of operation. - - The special argument `--' forces an end of option-scanning regardless - of the value of `ordering'. In the case of RETURN_IN_ORDER, only - `--' can cause `getopt' to return -1 with `optind' != ARGC. */ - -static enum -{ - REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER -} ordering; - -/* Value of POSIXLY_CORRECT environment variable. */ -static char *posixly_correct; - -#ifdef __GNU_LIBRARY__ -/* We want to avoid inclusion of string.h with non-GNU libraries - because there are many ways it can cause trouble. - On some systems, it contains special magic macros that don't work - in GCC. */ -#include -#define my_index strchr -#else - -/* Avoid depending on library functions or files - whose names are inconsistent. */ - -char *getenv (); - -static char * -my_index (str, chr) - const char *str; - int chr; -{ - while (*str) - { - if (*str == chr) - return (char *) str; - str++; - } - return 0; -} - -/* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. */ -#ifdef __GNUC__ -/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. - That was relevant to code that was here before. */ -#if !defined (__STDC__) || !__STDC__ -/* gcc with -traditional declares the built-in strlen to return int, - and has done so at least since version 2.4.5. -- rms. */ -extern int strlen (const char *); -#endif /* not __STDC__ */ -#endif /* __GNUC__ */ - -#endif /* not __GNU_LIBRARY__ */ - -/* Handle permutation of arguments. */ - -/* Describe the part of ARGV that contains non-options that have - been skipped. `first_nonopt' is the index in ARGV of the first of them; - `last_nonopt' is the index after the last of them. */ - -static int first_nonopt; -static int last_nonopt; - -#ifdef _LIBC -/* Bash 2.0 gives us an environment variable containing flags - indicating ARGV elements that should not be considered arguments. */ - -/* Defined in getopt_init.c */ -extern char *__getopt_nonoption_flags; - -static int nonoption_flags_max_len; -static int nonoption_flags_len; - -static int original_argc; -static char *const *original_argv; - -extern pid_t __libc_pid; - -/* Make sure the environment variable bash 2.0 puts in the environment - is valid for the getopt call we must make sure that the ARGV passed - to getopt is that one passed to the process. */ -static void -__attribute__ ((unused)) -store_args_and_env (int argc, char *const *argv) -{ - /* XXX This is no good solution. We should rather copy the args so - that we can compare them later. But we must not use malloc(3). */ - original_argc = argc; - original_argv = argv; -} -text_set_element (__libc_subinit, store_args_and_env); - -# define SWAP_FLAGS(ch1, ch2) \ - if (nonoption_flags_len > 0) \ - { \ - char __tmp = __getopt_nonoption_flags[ch1]; \ - __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ - __getopt_nonoption_flags[ch2] = __tmp; \ - } -#else /* !_LIBC */ -# define SWAP_FLAGS(ch1, ch2) -#endif /* _LIBC */ - -/* Exchange two adjacent subsequences of ARGV. - One subsequence is elements [first_nonopt,last_nonopt) - which contains all the non-options that have been skipped so far. - The other is elements [last_nonopt,optind), which contains all - the options processed since those non-options were skipped. - - `first_nonopt' and `last_nonopt' are relocated so that they describe - the new indices of the non-options in ARGV after they are moved. */ - -#if defined (__STDC__) && __STDC__ -static void exchange (char **); -#endif - -static void -exchange (argv) - char **argv; -{ - int bottom = first_nonopt; - int middle = last_nonopt; - int top = optind; - char *tem; - - /* Exchange the shorter segment with the far end of the longer segment. - That puts the shorter segment into the right place. - It leaves the longer segment in the right place overall, - but it consists of two parts that need to be swapped next. */ - -#ifdef _LIBC - /* First make sure the handling of the `__getopt_nonoption_flags' - string can work normally. Our top argument must be in the range - of the string. */ - if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) - { - /* We must extend the array. The user plays games with us and - presents new arguments. */ - char *new_str = malloc (top + 1); - if (new_str == NULL) - nonoption_flags_len = nonoption_flags_max_len = 0; - else - { - memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len); - memset (&new_str[nonoption_flags_max_len], '\0', - top + 1 - nonoption_flags_max_len); - nonoption_flags_max_len = top + 1; - __getopt_nonoption_flags = new_str; - } - } -#endif - - while (top > middle && middle > bottom) - { - if (top - middle > middle - bottom) - { - /* Bottom segment is the short one. */ - int len = middle - bottom; - register int i; - - /* Swap it with the top part of the top segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[top - (middle - bottom) + i]; - argv[top - (middle - bottom) + i] = tem; - SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); - } - /* Exclude the moved bottom segment from further swapping. */ - top -= len; - } - else - { - /* Top segment is the short one. */ - int len = top - middle; - register int i; - - /* Swap it with the bottom part of the bottom segment. */ - for (i = 0; i < len; i++) - { - tem = argv[bottom + i]; - argv[bottom + i] = argv[middle + i]; - argv[middle + i] = tem; - SWAP_FLAGS (bottom + i, middle + i); - } - /* Exclude the moved top segment from further swapping. */ - bottom += len; - } - } - - /* Update records for the slots the non-options now occupy. */ - - first_nonopt += (optind - last_nonopt); - last_nonopt = optind; -} - -/* Initialize the internal data when the first call is made. */ - -#if defined (__STDC__) && __STDC__ -static const char *_getopt_initialize (int, char *const *, const char *); -#endif -static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - /* Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ - - first_nonopt = last_nonopt = optind; - - nextchar = NULL; - - posixly_correct = getenv ("POSIXLY_CORRECT"); - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (posixly_correct != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; - -#ifdef _LIBC - if (posixly_correct == NULL - && argc == original_argc && argv == original_argv) - { - if (nonoption_flags_max_len == 0) - { - if (__getopt_nonoption_flags == NULL - || __getopt_nonoption_flags[0] == '\0') - nonoption_flags_max_len = -1; - else - { - const char *orig_str = __getopt_nonoption_flags; - int len = nonoption_flags_max_len = strlen (orig_str); - if (nonoption_flags_max_len < argc) - nonoption_flags_max_len = argc; - __getopt_nonoption_flags = - (char *) malloc (nonoption_flags_max_len); - if (__getopt_nonoption_flags == NULL) - nonoption_flags_max_len = -1; - else - { - memcpy (__getopt_nonoption_flags, orig_str, len); - memset (&__getopt_nonoption_flags[len], '\0', - nonoption_flags_max_len - len); - } - } - } - nonoption_flags_len = nonoption_flags_max_len; - } - else - nonoption_flags_len = 0; -#endif - - return optstring; -} - -/* Scan elements of ARGV (whose length is ARGC) for option characters - given in OPTSTRING. - - If an element of ARGV starts with '-', and is not exactly "-" or "--", - then it is an option element. The characters of this element - (aside from the initial '-') are option characters. If `getopt' - is called repeatedly, it returns successively each of the option characters - from each of the option elements. - - If `getopt' finds another option character, it returns that character, - updating `optind' and `nextchar' so that the next call to `getopt' can - resume the scan with the following option character or ARGV-element. - - If there are no more option characters, `getopt' returns -1. - Then `optind' is the index in ARGV of the first ARGV-element - that is not an option. (The ARGV-elements have been permuted - so that those that are not options now come last.) - - OPTSTRING is a string containing the legitimate option characters. - If an option character is seen that is not listed in OPTSTRING, - return '?' after printing an error message. If you set `opterr' to - zero, the error message is suppressed but we still return '?'. - - If a char in OPTSTRING is followed by a colon, that means it wants an arg, - so the following text in the same ARGV-element, or the text of the following - ARGV-element, is returned in `optarg'. Two colons mean an option that - wants an optional arg; if there is text in the current ARGV-element, - it is returned in `optarg', otherwise `optarg' is set to zero. - - If OPTSTRING starts with `-' or `+', it requests different methods of - handling the non-option ARGV-elements. - See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. - - Long-named options begin with `--' instead of `-'. - Their names may be abbreviated as long as the abbreviation is unique - or is an exact match for some defined option. If they have an - argument, it follows the option name in the same ARGV-element, separated - from the option name by a `=', or else the in next ARGV-element. - When `getopt' finds a long-named option, it returns 0 if that option's - `flag' field is nonzero, the value of the option's `val' field - if the `flag' field is zero. - - The elements of ARGV aren't really const, because we permute them. - But we pretend they're const in the prototype to be compatible - with other systems. - - LONGOPTS is a vector of `struct option' terminated by an - element containing a name which is zero. - - LONGIND returns the index in LONGOPT of the long-named option found. - It is only valid when a long-named option has been found by the most - recent call. - - If LONG_ONLY is nonzero, '-' as well as '--' can introduce - long-named options. */ - -int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; -{ - optarg = NULL; - - if (optind == 0 || !__getopt_initialized) - { - if (optind == 0) - optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = _getopt_initialize (argc, argv, optstring); - __getopt_initialized = 1; - } - - /* Test whether ARGV[optind] points to a non-option argument. - Either it does not have option syntax, or there is an environment flag - from the shell indicating it is not an option. The later information - is only used when the used in the GNU libc. */ -#ifdef _LIBC -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ - || (optind < nonoption_flags_len \ - && __getopt_nonoption_flags[optind] == '1')) -#else -#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') -#endif - - if (nextchar == NULL || *nextchar == '\0') - { - /* Advance to the next ARGV-element. */ - - /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been - moved back by the user (who may also have changed the arguments). */ - if (last_nonopt > optind) - last_nonopt = optind; - if (first_nonopt > optind) - first_nonopt = optind; - - if (ordering == PERMUTE) - { - /* If we have just processed some options following some non-options, - exchange them so that the options come first. */ - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (last_nonopt != optind) - first_nonopt = optind; - - /* Skip any additional non-options - and extend the range of non-options previously skipped. */ - - while (optind < argc && NONOPTION_P) - optind++; - last_nonopt = optind; - } - - /* The special ARGV-element `--' means premature end of options. - Skip it like a null option, - then exchange with previous non-options as if it were an option, - then skip everything else like a non-option. */ - - if (optind != argc && !strcmp (argv[optind], "--")) - { - optind++; - - if (first_nonopt != last_nonopt && last_nonopt != optind) - exchange ((char **) argv); - else if (first_nonopt == last_nonopt) - first_nonopt = optind; - last_nonopt = argc; - - optind = argc; - } - - /* If we have done all the ARGV-elements, stop the scan - and back over any non-options that we skipped and permuted. */ - - if (optind == argc) - { - /* Set the next-arg-index to point at the non-options - that we previously skipped, so the caller will digest them. */ - if (first_nonopt != last_nonopt) - optind = first_nonopt; - return -1; - } - - /* If we have come to a non-option and did not permute it, - either stop the scan or describe it to the caller and pass it by. */ - - if (NONOPTION_P) - { - if (ordering == REQUIRE_ORDER) - return -1; - optarg = argv[optind++]; - return 1; - } - - /* We have found another option-ARGV-element. - Skip the initial punctuation. */ - - nextchar = (argv[optind] + 1 - + (longopts != NULL && argv[optind][1] == '-')); - } - - /* Decode the current option-ARGV-element. */ - - /* Check whether the ARGV-element is a long option. - - If long_only and the ARGV-element has the form "-f", where f is - a valid short option, don't consider it an abbreviated form of - a long option that starts with f. Otherwise there would be no - way to give the -f short option. - - On the other hand, if there's a long option "fubar" and - the ARGV-element is "-fu", do consider that an abbreviation of - the long option, just like "--fu", and not "-f" with arg "u". - - This distinction seems to be the most useful approach. */ - - if (longopts != NULL - && (argv[optind][1] == '-' - || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = -1; - int option_index; - - for (nameend = nextchar; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) - == (unsigned int) strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `%s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - optopt = 0; - return '?'; - } - - if (pfound != NULL) - { - option_index = indfound; - optind++; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - _("%s: option `--%s' doesn't allow an argument\n"), - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - _("%s: option `%c%s' doesn't allow an argument\n"), - argv[0], argv[optind - 1][0], pfound->name); - - nextchar += strlen (nextchar); - - optopt = pfound->val; - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - optopt = pfound->val; - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - - /* Can't find it as a long option. If this is not getopt_long_only, - or the option starts with '--' or is not a valid short - option, then it's an error. - Otherwise interpret it as a short option. */ - if (!long_only || argv[optind][1] == '-' - || my_index (optstring, *nextchar) == NULL) - { - if (opterr) - { - if (argv[optind][1] == '-') - /* --option */ - fprintf (stderr, _("%s: unrecognized option `--%s'\n"), - argv[0], nextchar); - else - /* +option or -option */ - fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), - argv[0], argv[optind][0], nextchar); - } - nextchar = (char *) ""; - optind++; - optopt = 0; - return '?'; - } - } - - /* Look at and handle the next short option-character. */ - - { - char c = *nextchar++; - char *temp = my_index (optstring, c); - - /* Increment `optind' when we start to process its last character. */ - if (*nextchar == '\0') - ++optind; - - if (temp == NULL || c == ':') - { - if (opterr) - { - if (posixly_correct) - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: illegal option -- %c\n"), - argv[0], c); - else - fprintf (stderr, _("%s: invalid option -- %c\n"), - argv[0], c); - } - optopt = c; - return '?'; - } - /* Convenience. Treat POSIX -W foo same as long option --foo */ - if (temp[0] == 'W' && temp[1] == ';') - { - char *nameend; - const struct option *p; - const struct option *pfound = NULL; - int exact = 0; - int ambig = 0; - int indfound = 0; - int option_index; - - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - return c; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - - /* optarg is now the argument, see if it's in the - table of longopts. */ - - for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) - /* Do nothing. */ ; - - /* Test all long options for either exact match - or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; p++, option_index++) - if (!strncmp (p->name, nextchar, nameend - nextchar)) - { - if ((unsigned int) (nameend - nextchar) == strlen (p->name)) - { - /* Exact match found. */ - pfound = p; - indfound = option_index; - exact = 1; - break; - } - else if (pfound == NULL) - { - /* First nonexact match found. */ - pfound = p; - indfound = option_index; - } - else - /* Second or later nonexact match found. */ - ambig = 1; - } - if (ambig && !exact) - { - if (opterr) - fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), - argv[0], argv[optind]); - nextchar += strlen (nextchar); - optind++; - return '?'; - } - if (pfound != NULL) - { - option_index = indfound; - if (*nameend) - { - /* Don't test has_arg with >, because some C compilers don't - allow it to be used on enums. */ - if (pfound->has_arg) - optarg = nameend + 1; - else - { - if (opterr) - fprintf (stderr, _("\ -%s: option `-W %s' doesn't allow an argument\n"), - argv[0], pfound->name); - - nextchar += strlen (nextchar); - return '?'; - } - } - else if (pfound->has_arg == 1) - { - if (optind < argc) - optarg = argv[optind++]; - else - { - if (opterr) - fprintf (stderr, - _("%s: option `%s' requires an argument\n"), - argv[0], argv[optind - 1]); - nextchar += strlen (nextchar); - return optstring[0] == ':' ? ':' : '?'; - } - } - nextchar += strlen (nextchar); - if (longind != NULL) - *longind = option_index; - if (pfound->flag) - { - *(pfound->flag) = pfound->val; - return 0; - } - return pfound->val; - } - nextchar = NULL; - return 'W'; /* Let the application handle it. */ - } - if (temp[1] == ':') - { - if (temp[2] == ':') - { - /* This is an option that accepts an argument optionally. */ - if (*nextchar != '\0') - { - optarg = nextchar; - optind++; - } - else - optarg = NULL; - nextchar = NULL; - } - else - { - /* This is an option that requires an argument. */ - if (*nextchar != '\0') - { - optarg = nextchar; - /* If we end this ARGV-element by taking the rest as an arg, - we must advance to the next element now. */ - optind++; - } - else if (optind == argc) - { - if (opterr) - { - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, - _("%s: option requires an argument -- %c\n"), - argv[0], c); - } - optopt = c; - if (optstring[0] == ':') - c = ':'; - else - c = '?'; - } - else - /* We already incremented `optind' once; - increment it again when taking next ARGV-elt as argument. */ - optarg = argv[optind++]; - nextchar = NULL; - } - } - return c; - } -} - -int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; -{ - return _getopt_internal (argc, argv, optstring, - (const struct option *) 0, - (int *) 0, - 0); -} - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -/* Compile with -DTEST to make an executable for use in testing - the above definition of `getopt'. */ - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - - c = getopt (argc, argv, "abc:d:0123456789"); - if (c == -1) - break; - - switch (c) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/getopt/gnu/getopt.h b/getopt/gnu/getopt.h deleted file mode 100644 index d6ceb0eee..000000000 --- a/getopt/gnu/getopt.h +++ /dev/null @@ -1,131 +0,0 @@ -/* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifndef _GETOPT_H -#define _GETOPT_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* For communication from `getopt' to the caller. - When `getopt' finds an option that takes an argument, - the argument value is returned here. - Also, when `ordering' is RETURN_IN_ORDER, - each non-option ARGV-element is returned here. */ - -extern char *optarg; - -/* Index in ARGV of the next element to be scanned. - This is used for communication to and from the caller - and for communication between successive calls to `getopt'. - - On entry to `getopt', zero means this is the first call; initialize. - - When `getopt' returns -1, this is the index of the first of the - non-option elements that the caller should itself scan. - - Otherwise, `optind' communicates from one call to the next - how much of ARGV has been scanned so far. */ - -extern int optind; - -/* Callers store zero here to inhibit the error message `getopt' prints - for unrecognized options. */ - -extern int opterr; - -/* Set to an option character which was unrecognized. */ - -extern int optopt; - -/* Describe the long-named options requested by the application. - The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector - of `struct option' terminated by an element containing a name which is - zero. - - The field `has_arg' is: - no_argument (or 0) if the option does not take an argument, - required_argument (or 1) if the option requires an argument, - optional_argument (or 2) if the option takes an optional argument. - - If the field `flag' is not NULL, it points to a variable that is set - to the value given in the field `val' when the option is found, but - left unchanged if the option is not found. - - To have a long-named option do something other than set an `int' to - a compiled-in constant, such as set a value from `optarg', set the - option's `flag' field to zero and its `val' field to a nonzero - value (the equivalent single-letter option character, if there is - one). For long options that have a zero `flag' field, `getopt' - returns the contents of the `val' field. */ - -struct option -{ -#if defined (__STDC__) && __STDC__ - const char *name; -#else - char *name; -#endif - /* has_arg can't be an enum because some compilers complain about - type mismatches in all the code that assumes it is an int. */ - int has_arg; - int *flag; - int val; -}; - -/* Names for the values of the `has_arg' field of `struct option'. */ - -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -#if defined (__STDC__) && __STDC__ -#ifdef __GNU_LIBRARY__ -/* Many other libraries have conflicting prototypes for getopt, with - differences in the consts, in stdlib.h. To avoid compilation - errors, only prototype getopt for the GNU C library. */ -extern int getopt (int argc, char *const *argv, const char *shortopts); -#else /* not __GNU_LIBRARY__ */ -extern int getopt (); -#endif /* __GNU_LIBRARY__ */ -extern int getopt_long (int argc, char *const *argv, const char *shortopts, - const struct option *longopts, int *longind); -extern int getopt_long_only (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind); - -/* Internal only. Users should not call this directly. */ -extern int _getopt_internal (int argc, char *const *argv, - const char *shortopts, - const struct option *longopts, int *longind, - int long_only); -#else /* not __STDC__ */ -extern int getopt (); -extern int getopt_long (); -extern int getopt_long_only (); - -extern int _getopt_internal (); -#endif /* __STDC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* _GETOPT_H */ diff --git a/getopt/gnu/getopt1.c b/getopt/gnu/getopt1.c deleted file mode 100644 index 4aa8de6f6..000000000 --- a/getopt/gnu/getopt1.c +++ /dev/null @@ -1,187 +0,0 @@ -/* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "getopt.h" - -#if !defined (__STDC__) || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include - -/* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#define GETOPT_INTERFACE_VERSION 2 -#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2 -#include -#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION -#define ELIDE_CODE -#endif -#endif - -#ifndef ELIDE_CODE - - -/* This needs to come after some library #include - to get __GNU_LIBRARY__ defined. */ -#ifdef __GNU_LIBRARY__ -#include -#endif - -#ifndef NULL -#define NULL 0 -#endif - -int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 0); -} - -/* Like getopt_long, but '-' as well as '--' can indicate a long option. - If an option that starts with '-' (not '--') doesn't match a long option, - but does match a short option, it is parsed as a short option - instead. */ - -int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; -{ - return _getopt_internal (argc, argv, options, long_options, opt_index, 1); -} - - -#endif /* Not ELIDE_CODE. */ - -#ifdef TEST - -#include - -int -main (argc, argv) - int argc; - char **argv; -{ - int c; - int digit_optind = 0; - - while (1) - { - int this_option_optind = optind ? optind : 1; - int option_index = 0; - static struct option long_options[] = - { - {"add", 1, 0, 0}, - {"append", 0, 0, 0}, - {"delete", 1, 0, 0}, - {"verbose", 0, 0, 0}, - {"create", 0, 0, 0}, - {"file", 1, 0, 0}, - {0, 0, 0, 0} - }; - - c = getopt_long (argc, argv, "abc:d:0123456789", - long_options, &option_index); - if (c == -1) - break; - - switch (c) - { - case 0: - printf ("option %s", long_options[option_index].name); - if (optarg) - printf (" with arg %s", optarg); - printf ("\n"); - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (digit_optind != 0 && digit_optind != this_option_optind) - printf ("digits occur in two different argv-elements.\n"); - digit_optind = this_option_optind; - printf ("option %c\n", c); - break; - - case 'a': - printf ("option a\n"); - break; - - case 'b': - printf ("option b\n"); - break; - - case 'c': - printf ("option c with value `%s'\n", optarg); - break; - - case 'd': - printf ("option d with value `%s'\n", optarg); - break; - - case '?': - break; - - default: - printf ("?? getopt returned character code 0%o ??\n", c); - } - } - - if (optind < argc) - { - printf ("non-option ARGV-elements: "); - while (optind < argc) - printf ("%s ", argv[optind++]); - printf ("\n"); - } - - exit (0); -} - -#endif /* TEST */ diff --git a/getopt/parse.bash b/getopt/parse.bash deleted file mode 100644 index 864fc0add..000000000 --- a/getopt/parse.bash +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# A small example program for using the new getopt(1) program. -# This program will only work with bash(1) -# An similar program using the tcsh(1) script language can be found -# as parse.tcsh - -# Example input and output (from the bash prompt): -# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long " -# Option a -# Option c, no argument -# Option c, argument `more' -# Option b, argument ` very long ' -# Remaining arguments: -# --> `par1' -# --> `another arg' -# --> `wow!*\?' - -# Note that we use `"$@"' to let each command-line parameter expand to a -# separate word. The quotes around `$@' are essential! -# We need TEMP as the `eval set --' would nuke the return value of getopt. -TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ - -n 'example.bash' -- "$@"` - -if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi - -# Note the quotes around `$TEMP': they are essential! -eval set -- "$TEMP" - -while true ; do - case "$1" in - -a|--a-long) echo "Option a" ; shift ;; - -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; - -c|--c-long) - # c has an optional argument. As we are in quoted mode, - # an empty parameter will be generated if its optional - # argument is not found. - case "$2" in - "") echo "Option c, no argument"; shift 2 ;; - *) echo "Option c, argument \`$2'" ; shift 2 ;; - esac ;; - --) shift ; break ;; - *) echo "Internal error!" ; exit 1 ;; - esac -done -echo "Remaining arguments:" -for arg do echo '--> '"\`$arg'" ; done diff --git a/getopt/parse.tcsh b/getopt/parse.tcsh deleted file mode 100644 index 7d4f42719..000000000 --- a/getopt/parse.tcsh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/tcsh - -# A small example program for using the new getopt(1) program. -# This program will only work with bash(1) -# An similar program using the tcsh(1) script language can be found -# as parse.tcsh - -# Example input and output (from the tcsh prompt): -# ./parse.tcsh -a par1 'another arg' --c-long 'wow\!*\?' -cmore -b " very long " -# Option a -# Option c, no argument -# Option c, argument `more' -# Option b, argument ` very long ' -# Remaining arguments: -# --> `par1' -# --> `another arg' -# --> `wow!*\?' - -# Note that we had to escape the exclamation mark in the wow-argument. This -# is _not_ a problem with getopt, but with the tcsh command parsing. If you -# would give the same line from the bash prompt (ie. call ./parse.tcsh), -# you could remove the exclamation mark. - -# This is a bit tricky. We use a temp variable, to be able to check the -# return value of getopt (eval nukes it). argv contains the command arguments -# as a list. The ':q` copies that list without doing any substitutions: -# each element of argv becomes a separate argument for getopt. The braces -# are needed because the result is also a list. -set temp=(`getopt -s tcsh -o ab:c:: --long a-long,b-long:,c-long:: -- $argv:q`) -if ($? != 0) then - echo "Terminating..." >/dev/stderr - exit 1 -endif - -# Now we do the eval part. As the result is a list, we need braces. But they -# must be quoted, because they must be evaluated when the eval is called. -# The 'q` stops doing any silly substitutions. -eval set argv=\($temp:q\) - -set - -while (1) - switch($1:q) - case -a: - case --a-long: - echo "Option a" ; shift - breaksw; - case -b: - case --b-long: - echo "Option b, argument "\`$2\' ; shift ; shift - breaksw - case -c: - case --c-long: - # c has an optional argument. As we are in quoted mode, - # an empty parameter will be generated if its optional - # argument is not found. - - if ($2:q == "") then - echo "Option c, no argument" - else - echo "Option c, argument "\`$2\' - endif - shift; shift - breaksw - case --: - shift - break - default: - echo "Internal error!" ; exit 1 - endsw -end - -echo "Remaining arguments:" -foreach el ($argv:q) - echo '--> '\`$el:q\' -end diff --git a/getopt/test.bash b/getopt/test.bash deleted file mode 100644 index 149e1f9b0..000000000 --- a/getopt/test.bash +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if `getopt -T >/dev/null 2>&1` ; [ $? = 4 ] ; then - echo "Enhanced getopt(1)" -else - echo "Old getopt(1)" -fi diff --git a/getopt/test.tcsh b/getopt/test.tcsh deleted file mode 100644 index d661e767d..000000000 --- a/getopt/test.tcsh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/tcsh -getopt -T >&/dev/null -if ( $status == 4) then - echo "Enhanced getopt(1)" -else - echo "Old getopt(1)" -endif diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 000000000..5503a6059 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,17 @@ +include ../MCONFIG + +CFLAGS=-I$(LIB) $(OPT) + +all: err.o my_reboot.o setproctitle.o + +err.o: err.c + +my_reboot.o: my_reboot.c linux_reboot.h + +setproctitle.o: setproctitle.h + +.PHONY: clean +clean: + -rm -f *.o *~ core + +install: diff --git a/lib/err.c b/lib/err.c new file mode 100644 index 000000000..2731a714f --- /dev/null +++ b/lib/err.c @@ -0,0 +1,185 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +extern char *__progname; /* Program name, from crt0. */ +#ifdef __linux__ +char *__progname; +#endif + +__dead void +#ifdef __STDC__ +err(int eval, const char *fmt, ...) +#else +err(eval, fmt, va_alist) + int eval; + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + verr(eval, fmt, ap); + va_end(ap); +} + +__dead void +verr(eval, fmt, ap) + int eval; + const char *fmt; + va_list ap; +{ + int sverrno; + + sverrno = errno; + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + (void)fprintf(stderr, "%s\n", strerror(sverrno)); + exit(eval); +} + +__dead void +#if __STDC__ +errx(int eval, const char *fmt, ...) +#else +errx(eval, fmt, va_alist) + int eval; + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + verrx(eval, fmt, ap); + va_end(ap); +} + +__dead void +verrx(eval, fmt, ap) + int eval; + const char *fmt; + va_list ap; +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); + exit(eval); +} + +void +#if __STDC__ +warn(const char *fmt, ...) +#else +warn(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarn(fmt, ap); + va_end(ap); +} + +void +vwarn(fmt, ap) + const char *fmt; + va_list ap; +{ + int sverrno; + + sverrno = errno; + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) { + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": "); + } + (void)fprintf(stderr, "%s\n", strerror(sverrno)); +} + +void +#ifdef __STDC__ +warnx(const char *fmt, ...) +#else +warnx(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; +#ifdef __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + vwarnx(fmt, ap); + va_end(ap); +} + +void +vwarnx(fmt, ap) + const char *fmt; + va_list ap; +{ + (void)fprintf(stderr, "%s: ", __progname); + if (fmt != NULL) + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, "\n"); +} diff --git a/lib/err.h b/lib/err.h new file mode 100644 index 000000000..da4be150c --- /dev/null +++ b/lib/err.h @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)err.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _ERR_H_ +#define _ERR_H_ + +#ifdef __linux__ +#include +#define _BSD_VA_LIST_ va_list +#define __dead /* */ +#else +/* + * Don't use va_list in the err/warn prototypes. Va_list is typedef'd in two + * places ( and ), so if we include one + * of them here we may collide with the utility's includes. It's unreasonable + * for utilities to have to include one of them to include err.h, so we get + * _BSD_VA_LIST_ from and use it. + */ +#include +#endif +#include + +__BEGIN_DECLS +__dead void err __P((int, const char *, ...)); +__dead void verr __P((int, const char *, _BSD_VA_LIST_)); +__dead void errx __P((int, const char *, ...)); +__dead void verrx __P((int, const char *, _BSD_VA_LIST_)); +void warn __P((const char *, ...)); +void vwarn __P((const char *, _BSD_VA_LIST_)); +void warnx __P((const char *, ...)); +void vwarnx __P((const char *, _BSD_VA_LIST_)); +__END_DECLS + +#ifdef __linux__ +#undef _BSD_VA_LIST_ +#endif + +#endif /* !_ERR_H_ */ diff --git a/lib/linux_reboot.h b/lib/linux_reboot.h new file mode 100644 index 000000000..780d75093 --- /dev/null +++ b/lib/linux_reboot.h @@ -0,0 +1,30 @@ +extern int my_reboot(int); + +/* + * Magic values required to use _reboot() system call. + */ + +#define LINUX_REBOOT_MAGIC1 0xfee1dead +#define LINUX_REBOOT_MAGIC2 672274793 +#define LINUX_REBOOT_MAGIC2A 85072278 +#define LINUX_REBOOT_MAGIC2B 369367448 + + +/* + * Commands accepted by the _reboot() system call. + * + * RESTART Restart system using default command and mode. + * HALT Stop OS and give system control to ROM monitor, if any. + * CAD_ON Ctrl-Alt-Del sequence causes RESTART command. + * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task. + * POWER_OFF Stop OS and remove all power from system, if possible. + * RESTART2 Restart system using given command string. + */ + +#define LINUX_REBOOT_CMD_RESTART 0x01234567 +#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 +#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF +#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 +#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC +#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 + diff --git a/lib/my_reboot.c b/lib/my_reboot.c new file mode 100644 index 000000000..12ea4c926 --- /dev/null +++ b/lib/my_reboot.c @@ -0,0 +1,40 @@ +/* Including makes sure that on a glibc system + is included, which again defines __GLIBC__ */ +#include +#include "linux_reboot.h" + +#define USE_LIBC + +#ifdef USE_LIBC + +/* libc version */ +#if defined __GLIBC__ && __GLIBC__ >= 2 +# include +# define REBOOT(cmd) reboot(cmd) +#else +extern int reboot(int, int, int); +# define REBOOT(cmd) reboot(LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,(cmd)) +#endif +int +my_reboot(int cmd) { + return REBOOT(cmd); +} + +#else /* no USE_LIBC */ + +/* direct syscall version */ +#include + +#ifdef _syscall3 +_syscall3(int, reboot, int, magic, int, magic_too, int, cmd); +#else +/* Let us hope we have a 3-argument reboot here */ +extern int reboot(int, int, int); +#endif + +int +my_reboot(int cmd) { + return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd); +} + +#endif diff --git a/lib/pathnames.h b/lib/pathnames.h new file mode 100644 index 000000000..ab7b97dc8 --- /dev/null +++ b/lib/pathnames.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)pathnames.h 5.3 (Berkeley) 5/9/89 + * + * Changed: Sun Nov 21 12:30:54 1993 by faith@cs.unc.edu + * Changed: Wed Jun 22 20:47:27 1994 by faith@cs.unc.edu, based on changes + * from poe@daimi.aau.dk + * Changed: Wed Jun 22 22:50:13 1994 by faith@cs.unc.edu + * Changed: Sat Feb 4 16:02:10 1995 by faith@cs.unc.edu + * Changed: Tue Jul 2 09:37:36 1996 by janl@math.uio.no, axp patches + * Changed: Thu Nov 9 21:58:36 1995 by joey@infodrom.north.de + */ + +#ifndef __STDC__ +# error "we need an ANSI compiler" +#endif + +/* The paths for some of these are wrong in /usr/include/paths.h, but we + re-define them here. */ + +#undef _PATH_UTMP +#undef _PATH_WTMP +#undef _PATH_DEFPATH +#undef _PATH_DEFPATH_ROOT +#undef _PATH_LASTLOG +#undef _PATH_MAILDIR + +#ifndef SBINDIR +#define SBINDIR "/sbin" +#endif + +#ifndef USRSBINDIR +#define USRSBINDIR "/usr/sbin" +#endif + +#ifndef LOGDIR +#define LOGDIR "/var/log" +#endif + +#ifndef VARPATH +#define VARPATH "/var" +#endif + +#ifndef UT_NAMESIZE +#define UT_NAMESIZE 8 +#endif + +#define _PATH_BSHELL "/bin/sh" +#define _PATH_CSHELL "/bin/csh" +#define _PATH_TTY "/dev/tty" +#define TTYTYPES "/etc/ttytype" +#define SECURETTY "/etc/securetty" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP LOGDIR "/wtmp" +#define _PATH_WTMPLOCK "/etc/wtmplock" + +/* no more . in DEFPATH */ +#define _PATH_DEFPATH "/usr/local/bin:/bin:/usr/bin" +#define _PATH_DEFPATH_ROOT SBINDIR ":/bin:" USRSBINDIR ":/usr/bin" +#define _PATH_HUSHLOGIN ".hushlogin" +#define _PATH_LASTLOG LOGDIR "/lastlog" +#define _PATH_MAILDIR VARPATH "/spool/mail" +#define _PATH_MOTDFILE "/etc/motd" +#define _PATH_NOLOGIN "/etc/nologin" + +#define _PATH_LOGIN "/bin/login" +#define _PATH_INITTAB "/etc/inittab" +#define _PATH_RC "/etc/rc" +#define _PATH_REBOOT SBINDIR "/reboot" +#define _PATH_SINGLE "/etc/singleboot" +#define _PATH_SHUTDOWN_CONF "/etc/shutdown.conf" + +#define _PATH_SECURE "/etc/securesingle" +#define _PATH_USERTTY "/etc/usertty" + +#define _PATH_MTAB "/etc/mtab" +#define _PATH_UMOUNT "/bin/umount" +#define UMOUNT_ARGS "umount", "-a" +#define SWAPOFF_ARGS "swapoff", "-a" + +#define _PATH_PASSWD "/etc/passwd" +#define _PATH_PTMP "/etc/ptmp" +#define _PATH_PTMPTMP "/etc/ptmptmp" + +#define _PATH_GROUP "/etc/group" +#define _PATH_GTMP "/etc/gtmp" +#define _PATH_GTMPTMP "/etc/gtmptmp" + +#define _PATH_WORDS "/usr/dict/words" +#define _PATH_WORDS_ALT "/usr/dict/web2" diff --git a/lib/setproctitle.c b/lib/setproctitle.c new file mode 100644 index 000000000..bff1362da --- /dev/null +++ b/lib/setproctitle.c @@ -0,0 +1,117 @@ +/* proctitle code - we know this to work only on linux... */ + +/* +** SETPROCTITLE -- set process title for ps (from sendmail) +** +** Parameters: +** fmt -- a printf style format string. +** +** Returns: +** none. +** +** Side Effects: +** Clobbers argv of our main procedure so ps(1) will +** display the title. +*/ + +#include +#include +#include +#include +#include "setproctitle.h" + +#ifndef SPT_PADCHAR +#define SPT_PADCHAR ' ' +#endif + +#ifndef SPT_BUFSIZE +#define SPT_BUFSIZE 2048 +#endif + +extern char** environ; + +static char** argv0; +static int argv_lth; + +void +initproctitle (int argc, char **argv) { + int i; + char **envp = environ; + + /* + * 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; envp[i] != NULL; i++) + continue; + environ = (char **) malloc(sizeof(char *) * (i + 1)); + if (environ == NULL) + return; + for (i = 0; envp[i] != NULL; i++) + if ((environ[i] = strdup(envp[i])) == NULL) + return; + environ[i] = NULL; + + argv0 = argv; + if (i > 0) + argv_lth = envp[i-1] + strlen(envp[i-1]) - argv0[0]; + else + argv_lth = argv0[argc-1] + strlen(argv0[argc-1]) - argv0[0]; +} + +#if 0 +/* Nice code, but many places do not know about vsnprintf ... */ +void +setproctitle (const char *fmt,...) { + char *p; + int i; + char buf[SPT_BUFSIZE]; + va_list ap; + + if (!argv0) + return; + + va_start(ap, fmt); + (void) vsnprintf(buf, SPT_BUFSIZE, fmt, ap); + va_end(ap); + + i = strlen (buf); + if (i > argv_lth - 2) { + i = argv_lth - 2; + buf[i] = '\0'; + } + (void) strcpy (argv0[0], buf); + p = &argv0[0][i]; + while (i < argv_lth) + *p++ = SPT_PADCHAR, i++; + argv0[1] = NULL; +} +#else +void +setproctitle (const char *prog, const char *txt) { + char *p; + int i; + char buf[SPT_BUFSIZE]; + + if (!argv0) + return; + + if (strlen(prog) + strlen(txt) + 5 > SPT_BUFSIZE) + return; + + (void) sprintf(buf, "%s -- %s", prog, txt); + + i = strlen (buf); + if (i > argv_lth - 2) { + i = argv_lth - 2; + buf[i] = '\0'; + } + (void) strcpy (argv0[0], buf); + p = &argv0[0][i]; + while (i < argv_lth) + *p++ = SPT_PADCHAR, i++; + argv0[1] = NULL; +} +#endif diff --git a/lib/setproctitle.h b/lib/setproctitle.h new file mode 100644 index 000000000..d57abda6b --- /dev/null +++ b/lib/setproctitle.h @@ -0,0 +1,7 @@ + +void initproctitle (int argc, char **argv); +#if 0 +void setproctitle (const char *fmt, ...); +#else +void setproctitle (const char *prog, const char *txt); +#endif diff --git a/login-utils/Makefile b/login-utils/Makefile index 9f41fcd19..f4bbc5a99 100644 --- a/login-utils/Makefile +++ b/login-utils/Makefile @@ -82,54 +82,53 @@ all-misc: $(USRBIN.MISC) # Rules for everything else -agetty.o: $(BSD)/pathnames.h +agetty.o: $(LIB)/pathnames.h agetty: agetty.o chfn: chfn.o islocal.o setpwnam.o - $(CC) -o $@ $^ $(CRYPT) $(PAM) + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM) chsh: chsh.o islocal.o setpwnam.o - $(CC) -o $@ $^ $(CRYPT) $(PAM) -islocal.o: $(BSD)/pathnames.h -last.o: $(BSD)/pathnames.h -last: last.o $(BSD)/getopt.o + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM) +islocal.o: $(LIB)/pathnames.h +last.o: $(LIB)/pathnames.h +last: last.o ifeq "$(HAVE_PAM)" "yes" -login: login.o - $(CC) -o $@ $^ $(CRYPT) $(PAM) +login: login.o $(LIB)/setproctitle.o + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM) else -login: login.o checktty.o - $(CC) -o $@ $^ $(CRYPT) +login: login.o $(LIB)/setproctitle.o checktty.o + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) endif -mesg: mesg.o $(BSD)/getopt.o $(BSD)/err.o +mesg: mesg.o $(ERR_O) newgrp: newgrp.o - $(CC) -o $@ $^ $(CRYPT) $(PAM) -setpwnam.o: $(BSD)/pathnames.h -shutdown.o: $(BSD)/pathnames.h -shutdown: shutdown.o -simpleinit.o: $(BSD)/pathnames.h -simpleinit: simpleinit.o $(CRYPT) -vipw.o: $(BSD)/pathnames.h + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) $(PAM) +setpwnam.o: $(LIB)/pathnames.h +shutdown.o: $(LIB)/pathnames.h $(LIB)/linux_reboot.h +shutdown: shutdown.o $(LIB)/my_reboot.o +simpleinit.o: $(LIB)/pathnames.h $(LIB)/linux_reboot.h +simpleinit: simpleinit.o $(LIB)/my_reboot.o +vipw.o: $(LIB)/pathnames.h vipw: vipw.o -newgrp.o: $(BSD)/pathnames.h +newgrp.o: $(LIB)/pathnames.h $(CC) -c $(CFLAGS) $(PAMFL) newgrp.c wall: wall.o ttymsg.o ifeq "$(USE_TTY_GROUP)" "yes" -login.o: login.c $(BSD)/pathnames.h +login.o: login.c $(LIB)/pathnames.h $(LIB)/setproctitle.c $(LIB)/setproctitle.h $(CC) -c $(CFLAGS) $(PAMFL) -DUSE_TTY_GROUP login.c -mesg.o: mesg.c $(BSD)/err.h +mesg.o: mesg.c $(LIB)/err.h $(CC) -c $(CFLAGS) -DUSE_TTY_GROUP mesg.c else -login.o: $(BSD)/pathnames.h +login.o: $(LIB)/pathnames.h $(CC) -c $(CFLAGS) $(PAMFL) login.c -mesg.o: $(BSD)/err.h +mesg.o: $(LIB)/err.h endif -passwd: passwd.o islocal.o setpwnam.o $(CRYPT) -passwd.o: passwd.c - $(CC) -c $(CFLAGS) passwd.c +passwd: passwd.o islocal.o setpwnam.o + $(CC) $(LDFLAGS) -o $@ $^ $(CRYPT) ifeq "$(REQUIRE_PASSWORD)" "yes" CHSH_FLAGS:=$(CHSH_FLAGS) -DREQUIRE_PASSWORD diff --git a/login-utils/agetty.c b/login-utils/agetty.c index 039589591..96d7b38d0 100644 --- a/login-utils/agetty.c +++ b/login-utils/agetty.c @@ -545,6 +545,9 @@ update_utmp(line) endutent(); { +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) + updwtmp(_PATH_WTMP, &ut); +#else int lf; if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { @@ -556,8 +559,9 @@ update_utmp(line) flock(lf, LOCK_UN); close(lf); } +#endif } -#else +#else /* not __linux__ */ if ((ut_fd = open(UTMP_FILE, 2)) < 0) { error("%s: open for update: %m", UTMP_FILE); } else { @@ -769,7 +773,7 @@ do_prompt(op, tp) #ifdef ISSUE FILE *fd; int oflag; - char c; + int c; struct utsname uts; (void) uname(&uts); diff --git a/login-utils/checktty.c b/login-utils/checktty.c index f01d0ee82..15873aa44 100644 --- a/login-utils/checktty.c +++ b/login-utils/checktty.c @@ -135,6 +135,8 @@ add_to_class(struct ttyclass *tc, char *tty) /* return true if tty is a pty. Very linux dependent */ +/* Note that the new dynamic ptys (say /dev/pty/0 etc) have major in 128-135 */ +/* We might try TIOCGPTN or so to recognise these new ones, if desired */ static int isapty(const char *tty) { @@ -146,20 +148,18 @@ isapty(const char *tty) return 0; sprintf(devname, "/dev/%s", tty); -#if defined(__linux__) && defined(PTY_SLAVE_MAJOR) - /* this is for linux 1.3 and newer */ - if((stat(devname, &stb) >= 0) - && major(stb.st_rdev) == PTY_SLAVE_MAJOR) { - return 1; - } +#if defined(__linux__) + if((stat(devname, &stb) >= 0) && S_ISCHR(stb.st_mode)) { + +#if defined(PTY_SLAVE_MAJOR) + /* this is for linux 1.3 and newer */ + if(major(stb.st_rdev) == PTY_SLAVE_MAJOR) + return 1; #endif -#if defined(__linux__) - /* this is for linux versions before 1.3, backward compat. */ - if((stat(devname, &stb) >= 0) - && major(stb.st_rdev) == TTY_MAJOR - && minor(stb.st_rdev) >= 192) { - return 1; + /* this is for linux versions before 1.3, backward compat. */ + if(major(stb.st_rdev) == TTY_MAJOR && minor(stb.st_rdev) >= 192) + return 1; } #endif return 0; diff --git a/login-utils/chfn.c b/login-utils/chfn.c index 8e962db05..3da2360f1 100644 --- a/login-utils/chfn.c +++ b/login-utils/chfn.c @@ -14,9 +14,6 @@ * patches from Zefram * * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, - * to allow peaceful coexistence with yp: using the changes by - * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from - * passwd.c (now moved to setpwnam.c); * to remove trailing empty fields. Oct 5, 96. * */ @@ -32,6 +29,7 @@ #include #include #include +#include #include "my_crypt.h" #include "../version.h" @@ -81,6 +79,9 @@ extern int setpwnam P((struct passwd *pwd)); #define memzero(ptr, size) memset((char *) ptr, 0, size) +/* we do not accept gecos field sizes lengther than MAX_FIELD_SIZE */ +#define MAX_FIELD_SIZE 256 + int main (argc, argv) int argc; char *argv[]; @@ -103,6 +104,9 @@ int main (argc, argv) for (cp = whoami; *cp; cp++) if (*cp == '/') whoami = cp + 1; + /* iscntrl() below should not reject actual names */ + setlocale(LC_ALL,""); + /* * "oldf" contains the users original finger information. * "newf" contains the changed finger information, and contains NULL @@ -393,6 +397,13 @@ static int check_gecos_string (msg, gecos) { int i, c; + if (strlen(gecos) > MAX_FIELD_SIZE) { + if (msg != NULL) + printf("%s: ", msg); + printf("field is too long.\n"); + return -1; + } + for (i = 0; i < strlen (gecos); i++) { c = gecos[i]; if (c == ',' || c == ':' || c == '=' || c == '"' || c == '\n') { diff --git a/login-utils/chsh.1 b/login-utils/chsh.1 index 57ded2902..42e87ca60 100644 --- a/login-utils/chsh.1 +++ b/login-utils/chsh.1 @@ -10,7 +10,7 @@ .\" $Revision: 1.1 $ .\" $Date: 1995/03/12 01:28:58 $ .\" -.TH CHSH 1 "October 13 1994" "chsh" "Linux Reference Manual" +.TH CHSH 1 "7 October 1998" "chsh" "Linux Reference Manual" .SH NAME chsh \- change your login shell .SH SYNOPSIS @@ -28,6 +28,8 @@ will accept the full pathname of any executable file on the system. However, it will issue a warning if the shell is not listed in the .I /etc/shells file. +On the other hand, it can also be configured such that it will +only accept shells listed in this file, unless you are root. .SH OPTIONS .TP .I "\-s, \-\-shell" diff --git a/login-utils/chsh.c b/login-utils/chsh.c index f64cd0b78..8e8a51bc0 100644 --- a/login-utils/chsh.c +++ b/login-utils/chsh.c @@ -17,11 +17,6 @@ * suggestion from Zefram. Disallowing users with shells not in /etc/shells * from changing their shell. * - * Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, - * to allow peaceful coexistence with yp: using the changes by - * Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, from - * passwd.c (now moved to setpwnam.c). Oct 5, 96. - * */ #if 0 diff --git a/login-utils/last.1.orig b/login-utils/last.1.orig deleted file mode 100644 index 4d0deb882..000000000 --- a/login-utils/last.1.orig +++ /dev/null @@ -1,49 +0,0 @@ -.TH LAST 1 "20 March 1992" -.SH NAME -last \(em indicate last logins by user or terminal -.SH SYNOPSIS -.ad l -.B last -.RB [ \-\fP\fInumber\fP ] -.RB [ \-f -.IR filename ] -.RB [ \-t -.IR tty ] -.RB [ \-h -.IR hostname ] -.RI [ name ...] -.ad b -.SH DESCRIPTION -\fBLast\fP looks back in the \fBwtmp\fP file which records all logins -and logouts for information about a user, a teletype or any group of -users and teletypes. Arguments specify names of users or teletypes of -interest. If multiple arguments are given, the information which -applies to any of the arguments is printed. For example ``\fBlast root -console\fP'' would list all of root's sessions as well as all sessions -on the console terminal. \fBLast\fP displays the sessions of the -specified users and teletypes, most recent first, indicating the times -at which the session began, the duration of the session, and the -teletype which the session took place on. If the session is still -continuing or was cut short by a reboot, \fBlast\fP so indicates. -.LP -The pseudo-user \fBreboot\fP logs in at reboots of the system. -.LP -\fBLast\fP with no arguments displays a record of all logins and -logouts, in reverse order. -.LP -If \fBlast\fP is interrupted, it indicates how far the search has -progressed in \fBwtmp\fP. If interrupted with a quit signal \fBlast\fP -indicates how far the search has progressed so far, and the search -continues. -.SH OPTIONS -.IP \fB\-\fP\fInumber\fP -limit the number of entries displayed to that specified by \fInumber\fP. -.IP "\fB\-\fP \fIfilename\fP" -Use \fIfilename\fP as the name of the accounting file instead of -.BR /etc/wtmp . -.IP "\fB\-t\fP \fItty\fP" -List only logins on \fItty\fP. -.IP "\fB\-h\fP \fIhostname\fP" -List only logins from \fhostname\fP. -.SH FILES -/etc/wtmp \(em login data base diff --git a/login-utils/last.c b/login-utils/last.c index 98ffef38f..cf59b8ea6 100644 --- a/login-utils/last.c +++ b/login-utils/last.c @@ -45,6 +45,16 @@ static struct utmp buf[1024]; /* utmp read buffer */ #define LMAX (int)sizeof(buf[0].ut_line) /* size of utmp tty field */ #define NMAX (int)sizeof(buf[0].ut_name) /* size of utmp name field */ +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* maximum sizes used for printing */ +/* probably we want a two-pass version that computes the right length */ +int hmax = MIN(HMAX, 16); +int lmax = MIN(LMAX, 8); +int nmax = MIN(NMAX, 16); + typedef struct arg { char *name; /* argument */ #define HOST_TYPE -2 @@ -142,19 +152,19 @@ print_partial_line(bp) char *ct; ct = ctime(&bp->ut_time); - printf("%-*.*s %-*.*s ", NMAX, NMAX, bp->ut_name, - LMAX, LMAX, bp->ut_line); + printf("%-*.*s %-*.*s ", nmax, nmax, bp->ut_name, + lmax, lmax, bp->ut_line); if (dolong) { if (bp->ut_addr) { struct in_addr foo; foo.s_addr = bp->ut_addr; - printf("%-*.*s ", HMAX, HMAX, inet_ntoa(foo)); + printf("%-*.*s ", hmax, hmax, inet_ntoa(foo)); } else { - printf("%-*.*s ", HMAX, HMAX, ""); + printf("%-*.*s ", hmax, hmax, ""); } } else { - printf("%-*.*s ", HMAX, HMAX, bp->ut_host); + printf("%-*.*s ", hmax, hmax, bp->ut_host); } if (doyear) { @@ -178,7 +188,7 @@ wtmp() lseek(), time(); int bytes, wfd; void onintr(); - char *ct, *crmsg; + char *ct, *crmsg = NULL; if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) { perror(file); @@ -191,7 +201,7 @@ wtmp() (void)signal(SIGQUIT, onintr); while (--bl >= 0) { - if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 || + if (lseek(wfd, (long)(bl * sizeof(buf)), SEEK_SET) == -1 || (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) { fprintf(stderr, "last: %s: ", file); perror((char *)NULL); @@ -206,7 +216,7 @@ wtmp() /* * utmp(5) also mentions that the user * name should be 'shutdown' or 'reboot'. - * Not checking the name causes i.e. runlevel + * Not checking the name causes e.g. runlevel * changes to be displayed as 'crash'. -thaele */ if (!strncmp(bp->ut_user, "reboot", NMAX) || diff --git a/login-utils/last.c.orig b/login-utils/last.c.orig deleted file mode 100644 index 788aa66a0..000000000 --- a/login-utils/last.c.orig +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 1987 Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * 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 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pathnames.h" - -#define SECDAY (24*60*60) /* seconds in a day */ -#define NO 0 /* false/no */ -#define YES 1 /* true/yes */ - -static struct utmp buf[1024]; /* utmp read buffer */ - -#define HMAX (int)sizeof(buf[0].ut_host) /* size of utmp host field */ -#define LMAX (int)sizeof(buf[0].ut_line) /* size of utmp tty field */ -#define NMAX (int)sizeof(buf[0].ut_name) /* size of utmp name field */ - -typedef struct arg { - char *name; /* argument */ -#define HOST_TYPE -2 -#define TTY_TYPE -3 -#define USER_TYPE -4 - int type; /* type of arg */ - struct arg *next; /* linked list pointer */ -} ARG; -ARG *arglist; /* head of linked list */ - -typedef struct ttytab { - long logout; /* log out time */ - char tty[LMAX + 1]; /* terminal name */ - struct ttytab *next; /* linked list pointer */ -} TTY; -TTY *ttylist; /* head of linked list */ - -static long currentout, /* current logout value */ - maxrec; /* records to display */ -static char *file = _PATH_WTMP; /* wtmp file */ - -static void wtmp(), addarg(), hostconv(); -static int want(); -TTY *addtty(); -static char *ttyconv(); - -int -main(argc, argv) - int argc; - char **argv; -{ - extern int optind; - extern char *optarg; - int ch; - - while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF) - switch((char)ch) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - /* - * kludge: last was originally designed to take - * a number after a dash. - */ - if (!maxrec) - maxrec = atol(argv[optind - 1] + 1); - break; - case 'f': - file = optarg; - break; - case 'h': - hostconv(optarg); - addarg(HOST_TYPE, optarg); - break; - case 't': - addarg(TTY_TYPE, ttyconv(optarg)); - break; - case '?': - default: - fputs("usage: last [-#] [-f file] [-t tty] [-h hostname] [user ...]\n", stderr); - exit(1); - } - for (argv += optind; *argv; ++argv) { -#define COMPATIBILITY -#ifdef COMPATIBILITY - /* code to allow "last p5" to work */ - addarg(TTY_TYPE, ttyconv(*argv)); -#endif - addarg(USER_TYPE, *argv); - } - wtmp(); - exit(0); -} - -/* - * wtmp -- - * read through the wtmp file - */ -static void -wtmp() -{ - register struct utmp *bp; /* current structure */ - register TTY *T; /* tty list entry */ - struct stat stb; /* stat of file for size */ - long bl, delta, /* time difference */ - lseek(), time(); - int bytes, wfd; - void onintr(); - char *ct, *crmsg; - - if ((wfd = open(file, O_RDONLY, 0)) < 0 || fstat(wfd, &stb) == -1) { - perror(file); - exit(1); - } - bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf); - - (void)time(&buf[0].ut_time); - (void)signal(SIGINT, onintr); - (void)signal(SIGQUIT, onintr); - - while (--bl >= 0) { - if (lseek(wfd, (long)(bl * sizeof(buf)), L_SET) == -1 || - (bytes = read(wfd, (char *)buf, sizeof(buf))) == -1) { - fprintf(stderr, "last: %s: ", file); - perror((char *)NULL); - exit(1); - } - for (bp = &buf[bytes / sizeof(buf[0]) - 1]; bp >= buf; --bp) { - /* - * if the terminal line is '~', the machine stopped. - * see utmp(5) for more info. - */ - if (!strncmp(bp->ut_line, "~", LMAX)) { - /* everybody just logged out */ - for (T = ttylist; T; T = T->next) - T->logout = -bp->ut_time; - currentout = -bp->ut_time; - crmsg = strncmp(bp->ut_name, "shutdown", NMAX) ? "crash" : "down "; - if (!bp->ut_name[0]) - (void)strcpy(bp->ut_name, "reboot"); - if (want(bp, NO)) { - ct = ctime(&bp->ut_time); - if(bp->ut_type != LOGIN_PROCESS) - printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s \n", NMAX, NMAX, bp->ut_name, LMAX, LMAX, bp->ut_line, HMAX, HMAX, bp->ut_host, ct, ct + 11); - if (maxrec && !--maxrec) - return; - } - continue; - } - /* find associated tty */ - for (T = ttylist;; T = T->next) { - if (!T) { - /* add new one */ - T = addtty(bp->ut_line); - break; - } - if (!strncmp(T->tty, bp->ut_line, LMAX)) - break; - } - if (bp->ut_name[0] && bp->ut_type != LOGIN_PROCESS - && want(bp, YES)) { - ct = ctime(&bp->ut_time); - printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ", NMAX, NMAX, bp->ut_name, LMAX, LMAX, bp->ut_line, HMAX, HMAX, bp->ut_host, ct, ct + 11); - if (!T->logout) - puts(" still logged in"); - else { - if (T->logout < 0) { - T->logout = -T->logout; - printf("- %s", crmsg); - } - else - printf("- %5.5s", ctime(&T->logout)+11); - delta = T->logout - bp->ut_time; - if (delta < SECDAY) - printf(" (%5.5s)\n", asctime(gmtime(&delta))+11); - else - printf(" (%ld+%5.5s)\n", delta / SECDAY, asctime(gmtime(&delta))+11); - } - if (maxrec != -1 && !--maxrec) - return; - } - T->logout = bp->ut_time; - } - } - ct = ctime(&buf[0].ut_time); - printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11); -} - -/* - * want -- - * see if want this entry - */ -static int -want(bp, check) - register struct utmp *bp; - int check; -{ - register ARG *step; - - if (check) - /* - * when uucp and ftp log in over a network, the entry in - * the utmp file is the name plus their process id. See - * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information. - */ - if (!strncmp(bp->ut_line, "ftp", sizeof("ftp") - 1)) - bp->ut_line[3] = '\0'; - else if (!strncmp(bp->ut_line, "uucp", sizeof("uucp") - 1)) - bp->ut_line[4] = '\0'; - if (!arglist) - return(YES); - - for (step = arglist; step; step = step->next) - switch(step->type) { - case HOST_TYPE: - if (!strncmp(step->name, bp->ut_host, HMAX)) - return(YES); - break; - case TTY_TYPE: - if (!strncmp(step->name, bp->ut_line, LMAX)) - return(YES); - break; - case USER_TYPE: - if (!strncmp(step->name, bp->ut_name, NMAX)) - return(YES); - break; - } - return(NO); -} - -/* - * addarg -- - * add an entry to a linked list of arguments - */ -static void -addarg(type, arg) - int type; - char *arg; -{ - register ARG *cur; - - if (!(cur = (ARG *)malloc((unsigned int)sizeof(ARG)))) { - fputs("last: malloc failure.\n", stderr); - exit(1); - } - cur->next = arglist; - cur->type = type; - cur->name = arg; - arglist = cur; -} - -/* - * addtty -- - * add an entry to a linked list of ttys - */ -TTY * -addtty(ttyname) - char *ttyname; -{ - register TTY *cur; - - if (!(cur = (TTY *)malloc((unsigned int)sizeof(TTY)))) { - fputs("last: malloc failure.\n", stderr); - exit(1); - } - cur->next = ttylist; - cur->logout = currentout; - memcpy(cur->tty, ttyname, LMAX); - return(ttylist = cur); -} - -/* - * hostconv -- - * convert the hostname to search pattern; if the supplied host name - * has a domain attached that is the same as the current domain, rip - * off the domain suffix since that's what login(1) does. - */ -static void -hostconv(arg) - char *arg; -{ - static int first = 1; - static char *hostdot, - name[MAXHOSTNAMELEN]; - char *argdot; - - if (!(argdot = strchr(arg, '.'))) - return; - if (first) { - first = 0; - if (gethostname(name, sizeof(name))) { - perror("last: gethostname"); - exit(1); - } - hostdot = strchr(name, '.'); - } - if (hostdot && !strcmp(hostdot, argdot)) - *argdot = '\0'; -} - -/* - * ttyconv -- - * convert tty to correct name. - */ -static char * -ttyconv(arg) - char *arg; -{ - char *mval; - - /* - * kludge -- we assume that all tty's end with - * a two character suffix. - */ - if (strlen(arg) == 2) { - /* either 6 for "ttyxx" or 8 for "console" */ - if (!(mval = malloc((unsigned int)8))) { - fputs("last: malloc failure.\n", stderr); - exit(1); - } - if (!strcmp(arg, "co")) - (void)strcpy(mval, "console"); - else { - (void)strcpy(mval, "tty"); - (void)strcpy(mval + 3, arg); - } - return(mval); - } - if (!strncmp(arg, "/dev/", sizeof("/dev/") - 1)) - return(arg + 5); - return(arg); -} - -/* - * onintr -- - * on interrupt, we inform the user how far we've gotten - */ -void -onintr(signo) - int signo; -{ - char *ct; - - ct = ctime(&buf[0].ut_time); - printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11); - if (signo == SIGINT) - exit(1); - (void)fflush(stdout); /* fix required for rsh */ -} diff --git a/login-utils/login.1 b/login-utils/login.1 index 92a082c67..a2acbd9f7 100644 --- a/login-utils/login.1 +++ b/login-utils/login.1 @@ -243,8 +243,7 @@ the user to for example run the command: xterm -e /bin/login. .PP .IP o A domain name suffix such as @.some.dom, meaning that the user may -rlogin/telnet from any host whose domain name has the suffix -.some.dom. +rlogin/telnet from any host whose domain name has the suffix .some.dom. .PP .IP o A range of IPv4 addresses, written @x.x.x.x/y.y.y.y where x.x.x.x is @@ -303,9 +302,6 @@ are allowed to log in from anywhere as is standard behavior. .BR shutdown (8) .SH BUGS -Linux, unlike other draconian operating systems, does not check -quotas. - The undocumented BSD .B \-r option is not supported. This may be required by some diff --git a/login-utils/login.c b/login-utils/login.c index ebb0a22da..c742af75c 100644 --- a/login-utils/login.c +++ b/login-utils/login.c @@ -148,6 +148,14 @@ #define SLEEP_EXIT_TIMEOUT 5 +#ifdef __linux__ +#define DO_PS_FIDDLING +#endif + +#ifdef DO_PS_FIDDLING +#include "setproctitle.h" +#endif + #if 0 /* from before we had a lastlog.h file in linux */ struct lastlog @@ -260,9 +268,7 @@ consoletty(int fd) int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { extern int errno, optind; extern char *optarg, **environ; @@ -270,8 +276,8 @@ main(argc, argv) register int ch; register char *p; int ask, fflag, hflag, pflag, cnt; - int quietlog, passwd_req, ioctlval; - char *domain, *salt, *ttyn, *pp; + int quietlog, passwd_req; + char *domain, *ttyn; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char *ctime(), *ttyname(), *stypeof(); time_t time(); @@ -286,7 +292,12 @@ main(argc, argv) pam_handle_t *pamh = NULL; struct pam_conv conv = { misc_conv, NULL }; pid_t childPid; - int childStatus; + void (*oldSigHandler) (); +#else + char *salt, *pp; +#endif +#ifndef __linux__ + int ioctlval; #endif signal(SIGALRM, timedout); @@ -298,6 +309,9 @@ main(argc, argv) #ifdef HAVE_QUOTA quota(Q_SETUID, 0, 0, 0); #endif +#ifdef DO_PS_FIDDLING + initproctitle(argc, argv); +#endif /* * -p is used by getty to tell login not to destroy the environment @@ -313,6 +327,7 @@ main(argc, argv) username = tty = hostname = NULL; fflag = hflag = pflag = 0; passwd_req = 1; + while ((ch = getopt(argc, argv, "fh:p")) != EOF) switch (ch) { case 'f': @@ -353,8 +368,13 @@ main(argc, argv) argc -= optind; argv += optind; if (*argv) { - username = *argv; + char *p = *argv; + username = strdup(p); ask = 0; + /* wipe name - some people mistype their password here */ + /* (of course we are too late, but perhaps this helps a little ..) */ + while(*p) + *p++ = ' '; } else ask = 1; @@ -377,7 +397,7 @@ main(argc, argv) */ ioctlval = 0; ioctl(0, FIOSNBIO, &ioctlval); -#endif +#endif /* ! __linux__ */ for (cnt = getdtablesize(); cnt > 2; cnt--) close(cnt); @@ -472,7 +492,7 @@ main(argc, argv) (retcode == PAM_AUTHINFO_UNAVAIL))) { pam_get_item(pamh, PAM_USER, (const void **) &username); syslog(LOG_NOTICE,"FAILED LOGIN %d FROM %s FOR %s, %s", - failcount, hostname,username,pam_strerror(pamh, 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); @@ -520,8 +540,8 @@ main(argc, argv) #else /* ! USE_PAM */ for (cnt = 0;; ask = 1) { - ioctlval = 0; # ifndef __linux__ + ioctlval = 0; ioctl(0, TIOCSETD, &ioctlval); # endif @@ -770,7 +790,7 @@ main(argc, argv) utmp.ut_line[sizeof(utmp.ut_line)-1] = 0; login(&utmp); } -#else +#else /* __linux__ defined */ /* for linux, write entries in utmp and wtmp */ { struct utmp ut; @@ -781,8 +801,19 @@ main(argc, argv) utmpname(_PATH_UTMP); setutent(); - while ((utp = getutent()) - && !(utp->ut_pid == mypid)) /* nothing */; + + /* Find mypid in utmp. +login sometimes overwrites the runlevel entry in /var/run/utmp, +confusing sysvinit. I added a test for the entry type, and the problem +was gone. (In a runlevel entry, st_pid is not really a pid but some number +calculated from the previous and current runlevel). +Michael Riepe + */ + while ((utp = getutent())) + if (utp->ut_pid == mypid + && utp->ut_type >= INIT_PROCESS + && utp->ut_type <= DEAD_PROCESS) + break; if (utp) { memcpy(&ut, utp, sizeof(ut)); @@ -813,7 +844,20 @@ main(argc, argv) pututline(&ut); endutent(); - + +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) + updwtmp(_PATH_WTMP, &ut); +#else +#if 0 + /* The O_APPEND open() flag should be enough to guarantee + atomic writes at end of file. */ + if((wtmp = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) { + write(wtmp, (char *)&ut, sizeof(ut)); + close(wtmp); + } +#else + /* Probably all this locking below is just nonsense, + and the short version is OK as well. */ { int lf; if ((lf = open(_PATH_WTMPLOCK, O_CREAT|O_WRONLY, 0660)) >= 0) { @@ -826,8 +870,10 @@ main(argc, argv) close(lf); } } - } #endif +#endif /* __GLIBC__ */ + } +#endif /* __linux__ */ dolastlog(quietlog); @@ -903,7 +949,8 @@ main(argc, argv) setenv("TERM", termenv, 1); /* mailx will give a funny error msg if you forget this one */ - { char tmp[MAXPATHLEN]; + { + char tmp[MAXPATHLEN]; /* avoid snprintf */ if (sizeof(_PATH_MAILDIR) + strlen(pwd->pw_name) + 1 < MAXPATHLEN) { sprintf(tmp, "%s/%s", _PATH_MAILDIR, pwd->pw_name); @@ -932,6 +979,10 @@ main(argc, argv) } } #endif + +#ifdef DO_PS_FIDDLING + setproctitle("login", username); +#endif if (tty[sizeof("tty")-1] == 'S') syslog(LOG_INFO, "DIALUP AT %s BY %s", tty, pwd->pw_name); @@ -956,41 +1007,53 @@ main(argc, argv) if (!quietlog) { struct stat st; + char *mail; motd(); - /* 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 " : ""); + mail = getenv("MAIL"); + if (mail && stat(mail, &st) == 0 && st.st_size != 0) { + printf("You have %smail.\n", + (st.st_mtime > st.st_atime) ? "new " : ""); } } signal(SIGALRM, SIG_DFL); signal(SIGQUIT, SIG_DFL); - signal(SIGINT, SIG_DFL); signal(SIGTSTP, SIG_IGN); signal(SIGHUP, SIG_DFL); + +#ifdef USE_PAM + /* We must fork before setuid() because we need to call + * pam_close_session() as root. + */ + 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 for child to finish, then cleanup session */ + wait(NULL); + PAM_END; + exit(0); + } + /* child */ +#endif + signal(SIGINT, SIG_DFL); /* discard permissions last so can't get killed and drop core */ if(setuid(pwd->pw_uid) < 0 && pwd->pw_uid) { syslog(LOG_ALERT, "setuid() failed"); -#ifdef USE_PAM - PAM_END; -#endif exit(1); } /* wait until here to change directory! */ if (chdir(pwd->pw_dir) < 0) { printf("No directory %s!\n", pwd->pw_dir); - if (chdir("/")) { -#ifdef USE_PAM - PAM_END; -#endif + if (chdir("/")) exit(0); - } pwd->pw_dir = "/"; printf("Logging in with home = \"/\".\n"); } @@ -1023,15 +1086,6 @@ main(argc, argv) childArgv[childArgc++] = NULL; -#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 */ - execvp(childArgv[0], childArgv + 1); if (!strcmp(childArgv[0], "/bin/sh")) @@ -1070,7 +1124,7 @@ getloginname() exit(0); } } - if (p > nbuf) + if (p > nbuf) { if (nbuf[0] == '-') fprintf(stderr, "login names may not start with '-'.\n"); @@ -1079,6 +1133,7 @@ getloginname() username = nbuf; break; } + } cnt2++; if (cnt2 > 50) { @@ -1190,7 +1245,7 @@ dolastlog(quiet) int fd; if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { - lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); if (!quiet) { if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ll.ll_time != 0) { @@ -1204,7 +1259,7 @@ dolastlog(quiet) printf("on %.*s\n", (int)sizeof(ll.ll_line), ll.ll_line); } - lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); + lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), SEEK_SET); } memset((char *)&ll, 0, sizeof(ll)); time(&ll.ll_time); diff --git a/login-utils/passwd.1 b/login-utils/passwd.1 index db44aa8e9..b6a25a3f6 100644 --- a/login-utils/passwd.1 +++ b/login-utils/passwd.1 @@ -34,10 +34,8 @@ reasons to choose a non-conformant password. The two argument form gives the .IR user " the " password -stated as the second argument. This may be useful when giving many -users an initial generated password. But it can also be extremely -dangerous. A simple script bug might change to root password to -something unknown. +stated as the second argument. Note that this password will +be visible to people doing `ps' or so. Avoid this form. Giving an empty string as the second argument erases the password for the user, but only in combination with the @@ -111,6 +109,3 @@ Peter Orbaek (poe@daimi.aau.dk). .br Martin Schulze (joey@infodrom.north.de) with extensive rewriting and improving done. -.br -.SH MAINTAINER -Nicolai Langfeldt (janl@math.uio.no) diff --git a/login-utils/passwd.c b/login-utils/passwd.c index 4ed1b74d7..0057a283b 100644 --- a/login-utils/passwd.c +++ b/login-utils/passwd.c @@ -3,17 +3,12 @@ * * Initially written for Linux by Peter Orbaek * Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ - - Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, - to allow peaceful coexistence with yp. Nov 94. - - Hacked to allow root to set passwd from command line. - by Arpad Magossanyi (mag@tas.vein.hu) - - Hacked by Peter Breitenlohner, peb@mppmu.mpg.de, - moved Alvaro's changes to setpwnam.c (so they get used - by chsh and chfn as well). Oct 5, 96. - + * + * Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, + * to allow peaceful coexistence with yp. Nov 94. + * + * Hacked to allow root to set passwd from command line. + * by Arpad Magossanyi (mag@tas.vein.hu) */ /* @@ -26,7 +21,7 @@ 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 + * root, too. Only root can turn this off using the -f * switch. Okay, I started with this to support -V version * information, but one thing comes to the next. *sigh* * In a later step perhaps we'll be able to support shadow diff --git a/login-utils/shutdown.8 b/login-utils/shutdown.8 index 443acc2af..961579bdc 100644 --- a/login-utils/shutdown.8 +++ b/login-utils/shutdown.8 @@ -1,6 +1,8 @@ .\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu) .\" May be distributed under the GNU General Public License -.TH SHUTDOWN 8 "20 November 1993" "Linux 1.2" "Linux Programmer's Manual" +.\" +.\" +.TH SHUTDOWN 8 "24 July 1998" "Linux 2.0" "Linux Programmer's Manual" .SH NAME shutdown \- close down the system .SH SYNOPSIS @@ -98,7 +100,29 @@ detects (and deletes). .I /etc/singleboot .I /etc/nologin .I /var/log/wtmp +.I /etc/shutdown.conf .fi +.SH CONFIG +The configuration file \fI/etc/shutdown.conf\fP is used to determine +the action to take when halting the machine. The currently supported +file format is extremely primitive. The first line must contain two +strings separated by whitespace. The first string must be +\fBHALT_ACTION\fP and the second specifies the action you wish to take +on halt. The options allowed are: +.TP +.B halt +This will simply halt the system. This is the default behaviour. +Note also that this is the fallback if another option fails. +.TP +.B power_off +This will use the kernel power shutdown facility. This is usually only +available on machines with Advanced Power Management (APM). +.TP +.I programname +This specifies a command to run to shut down the power. The first +character must be a "/". Bear in mind that this command will be run +with only the root filesystem mounted (and it will be read-only), and +no daemons running. .SH "SEE ALSO" .BR umount (8), .BR login (1), @@ -112,6 +136,6 @@ users are notified of shutdown only once or twice, instead of many times, and at shorter and shorter intervals as "apocalypse approaches." Some would construe this as a feature. .SH AUTHOR -Peter Orbaek (poe@daimi.aau.dk) -.br -Modified by jrs@world.std.com +This page documents the version of +.B shutdown +originally written by Peter Orbaek (poe@daimi.aau.dk). diff --git a/login-utils/shutdown.c b/login-utils/shutdown.c index a63cbd6e9..8ba13b647 100644 --- a/login-utils/shutdown.c +++ b/login-utils/shutdown.c @@ -1,6 +1,6 @@ /* shutdown.c - shutdown a Linux system * Initially written by poe@daimi.aau.dk - * Currently maintained at ftp://ftp.daimi.aau.dk/pub/linux/poe/ + * Currently maintained at ftp://ftp.daimi.aau.dk/pub/Software/Linux/ */ /* @@ -24,6 +24,9 @@ * Various changes and additions to resemble SunOS 4 shutdown/reboot/halt(8) * more closely by Scott Telford (s.telford@ed.ac.uk) 93/05/18. * (I butchered Scotts patches somewhat. - poe) + * + * Changes by Richard Gooch (butchered by aeb) + * introducing shutdown.conf. */ #include @@ -35,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -42,11 +46,12 @@ #include #include #include +#include "linux_reboot.h" #include "pathnames.h" -void usage(), int_handler(), write_user(struct utmp *); -void wall(), write_wtmp(), unmount_disks(), unmount_disks_ourselves(); -void swap_off(); +static void usage(), int_handler(), write_user(struct utmp *); +static void wall(), write_wtmp(), unmount_disks(), unmount_disks_ourselves(); +static void swap_off(), do_halt(char *); char *prog; /* name of the program */ int opt_reboot; /* true if -r option or reboot command */ @@ -57,10 +62,15 @@ char message[90]; /* reason for shutdown if any... */ int opt_single = 0; /* true is we want to boot singleuser */ char *whom; /* who is shutting the system down */ int opt_msgset = 0; /* message set on command line */ + /* change 1 to 0 if no file is to be used by default */ +int opt_use_config_file = 1; /* read _PATH_SHUTDOWN_CONF */ +char halt_action[256]; /* to find out what to do upon halt */ /* #define DEBUGGING */ #define WR(s) write(fd, s, strlen(s)) +#define ERRSTRING sys_errlist[errno] + void usage() @@ -70,19 +80,31 @@ usage() exit(1); } +void +my_puts(char *s) +{ + /* Use a fresh stdout after forking */ + freopen(_PATH_CONSOLE, "w", stdout); + puts(s); + fflush(stdout); +} + void int_handler() { unlink(_PATH_NOLOGIN); signal(SIGINT, SIG_DFL); - puts("Shutdown process aborted\n"); + my_puts("Shutdown process aborted"); exit(1); } int -main(argc, argv) - int argc; - char *argv[]; +iswhitespace(int a) { + return (a == ' ' || a == '\t'); +} + +int +main(int argc, char *argv[]) { int c,i; int fd; @@ -90,7 +112,8 @@ main(argc, argv) #ifndef DEBUGGING if(geteuid()) { - fprintf(stderr, "%s: Only root can shut a system down.\n", argv[0]); + fprintf(stderr, "%s: Only root can shut a system down.\n", + argv[0]); exit(1); } #endif @@ -98,7 +121,10 @@ main(argc, argv) if(*argv[0] == '-') argv[0]++; /* allow shutdown as login shell */ prog = argv[0]; if((ptr = strrchr(argv[0], '/'))) prog = ++ptr; - + + /* All names (halt, reboot, fasthalt, fastboot, shutdown) + refer to the same program with the same options, + only the defaults differ. */ if(!strcmp("halt", prog)) { opt_reboot = 0; opt_quiet = 1; @@ -114,78 +140,105 @@ main(argc, argv) opt_quiet = 1; opt_fast = 0; timeout = 0; - if(argc > 1 && !strcmp(argv[1], "-s")) opt_single = 1; } else if(!strcmp("fastboot", prog)) { opt_reboot = 1; opt_quiet = 1; opt_fast = 1; timeout = 0; - if(argc > 1 && !strcmp(argv[1], "-s")) opt_single = 1; } else { /* defaults */ opt_reboot = 0; opt_quiet = 0; opt_fast = 0; timeout = 2*60; + } - c = 0; - while(++c < argc) { - if(argv[c][0] == '-') { - for(i = 1; argv[c][i]; i++) { + c = 0; + while(++c < argc) { + if(argv[c][0] == '-') { + for(i = 1; argv[c][i]; i++) { switch(argv[c][i]) { - case 'h': - opt_reboot = 0; - break; - case 'r': - opt_reboot = 1; - break; - case 'f': - opt_fast = 1; - break; - case 'q': - opt_quiet = 1; - break; - case 's': - opt_single = 1; - break; + case 'C': + opt_use_config_file = 1; + break; + case 'h': + opt_reboot = 0; + break; + case 'r': + opt_reboot = 1; + break; + case 'f': + opt_fast = 1; + break; + case 'q': + opt_quiet = 1; + break; + case 's': + opt_single = 1; + break; - default: - usage(); + default: + usage(); } - } - } else if(!strcmp("now", argv[c])) { - timeout = 0; - } else if(argv[c][0] == '+') { - timeout = 60 * atoi(&argv[c][1]); - } else if (isdigit(argv[c][0])) { - char *colon; - int hour = 0; - int minute = 0; - time_t tics; - struct tm *tt; - int now, then; + } + } else if(!strcmp("now", argv[c])) { + timeout = 0; + } else if(argv[c][0] == '+') { + timeout = 60 * atoi(&argv[c][1]); + } else if (isdigit(argv[c][0])) { + char *colon; + int hour = 0; + int minute = 0; + time_t tics; + struct tm *tt; + int now, then; - if((colon = strchr(argv[c], ':'))) { - *colon = '\0'; - hour = atoi(argv[c]); - minute = atoi(++colon); - } else usage(); + if((colon = strchr(argv[c], ':'))) { + *colon = '\0'; + hour = atoi(argv[c]); + minute = atoi(++colon); + } else usage(); - (void) time(&tics); - tt = localtime(&tics); + (void) time(&tics); + tt = localtime(&tics); - now = 3600 * tt->tm_hour + 60 * tt->tm_min; - then = 3600 * hour + 60 * minute; - timeout = then - now; - if(timeout < 0) { - fprintf(stderr, "That must be tomorrow, can't you wait till then?\n"); - exit(1); - } - } else { - strncpy(message, argv[c], sizeof(message)); - message[sizeof(message)-1] = '\0'; - opt_msgset = 1; + now = 3600 * tt->tm_hour + 60 * tt->tm_min; + then = 3600 * hour + 60 * minute; + timeout = then - now; + if(timeout < 0) { + fprintf(stderr, "That must be tomorrow, " + "can't you wait till then?\n"); + exit(1); + } + } else { + strncpy(message, argv[c], sizeof(message)); + message[sizeof(message)-1] = '\0'; + opt_msgset = 1; + } + } + + halt_action[0] = 0; + + /* No doubt we shall want to extend this some day + and register a series of commands to be executed + at various points during the shutdown sequence, + and to define the number of milliseconds to sleep, etc. */ + if (opt_use_config_file) { + char line[256], *p; + FILE *fp; + + /* Read and parse the config file */ + halt_action[0] = '\0'; + if ((fp = fopen (_PATH_SHUTDOWN_CONF, "r")) != NULL) { + if (fgets (line, sizeof(line), fp) != NULL && + strncasecmp (line, "HALT_ACTION", 11) == 0 && + iswhitespace(line[11])) { + p = line+11; + while(iswhitespace(*p)) + p++; + strcpy(halt_action, p); } + fclose (fp); } } @@ -212,6 +265,7 @@ main(argc, argv) /* so much for option-processing, now begin termination... */ if(!(whom = getlogin())) whom = "ghost"; + if(strlen(whom) > 40) whom[40] = 0; /* see write_user() */ setpriority(PRIO_PROCESS, 0, PRIO_MIN); signal(SIGINT, int_handler); @@ -261,7 +315,8 @@ main(argc, argv) kill(1, SIGTSTP); /* tell init not to spawn more getty's */ write_wtmp(); if(opt_single) - close(open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644)); + if((fd = open(_PATH_SINGLE, O_CREAT|O_WRONLY, 0644)) >= 0) + close(fd); sync(); @@ -272,7 +327,7 @@ main(argc, argv) #ifndef DEBUGGING /* a gentle kill of all other processes except init */ kill(-1, SIGTERM); - sleep(2); + sleep(2); /* default 2, some people need 5 */ /* now use brute force... */ kill(-1, SIGKILL); @@ -292,14 +347,14 @@ main(argc, argv) sleep(1); if(opt_reboot) { - reboot(0xfee1dead, 672274793, 0x1234567); + my_reboot(LINUX_REBOOT_CMD_RESTART); /* RB_AUTOBOOT */ + my_puts("\nWhy am I still alive after reboot?"); } else { - freopen(_PATH_CONSOLE, "w", stdout); - printf("\nNow you can turn off the power...\n"); - fflush(stdout); + my_puts("\nNow you can turn off the power..."); + /* allow C-A-D now, faith@cs.unc.edu, re-fixed 8-Jul-96 */ - reboot(0xfee1dead, 672274793, 0x89abcdef); - reboot(0xfee1dead, 672274793, 0xcdef0123); + my_reboot(LINUX_REBOOT_CMD_CAD_ON); /* RB_ENABLE_CAD */ + do_halt(halt_action); } /* NOTREACHED */ exit(0); /* to quiet gcc */ @@ -307,6 +362,31 @@ main(argc, argv) /*** end of main() ***/ +void +do_halt(char *action) { + if (strcasecmp (action, "power_off") == 0) { + printf("Calling kernel power-off facility...\n"); + fflush(stdout); + my_reboot(LINUX_REBOOT_CMD_POWER_OFF); + printf("Error powering off\t%s\n", ERRSTRING); + fflush(stdout); + sleep (2); + } else + + /* This should be improved; e.g. Mike Jagdis wants "/sbin/mdstop -a" */ + /* Maybe we should also fork and wait */ + if (action[0] == '/') { + printf("Executing the program \"%s\" ...\n", action); + fflush(stdout); + execl(action, action, NULL); + printf("Error executing\t%s\n", ERRSTRING); + fflush(stdout); + sleep (2); + } + + my_reboot(LINUX_REBOOT_CMD_HALT); /* RB_HALT_SYSTEM */ +} + void write_user(struct utmp *ut) { @@ -319,7 +399,7 @@ write_user(struct utmp *ut) (void) strncat(term, ut->ut_line, sizeof(ut->ut_line)); /* try not to get stuck on a mangled ut_line entry... */ - if((fd = open(term, O_RDWR|O_NONBLOCK)) < 0) + if((fd = open(term, O_WRONLY|O_NONBLOCK)) < 0) return; sprintf(msg, "\007\r\nURGENT: broadcast message from %s:\r\n", whom); @@ -393,7 +473,7 @@ swap_off() sync(); if ((pid = fork()) < 0) { - printf("Cannot fork for swapoff. Shrug!\n"); + my_puts("Cannot fork for swapoff. Shrug!"); return; } if (!pid) { @@ -401,7 +481,8 @@ swap_off() execl("/etc/swapoff", SWAPOFF_ARGS, NULL); execl("/bin/swapoff", SWAPOFF_ARGS, NULL); execlp("swapoff", SWAPOFF_ARGS, NULL); - puts("Cannot exec swapoff, hoping umount will do the trick."); + my_puts("Cannot exec swapoff, " + "hoping umount will do the trick."); exit(0); } while ((result = wait(&status)) != -1 && result != pid) @@ -419,20 +500,20 @@ unmount_disks() sync(); if ((pid = fork()) < 0) { - printf("Cannot fork for umount, trying manually.\n"); + my_puts("Cannot fork for umount, trying manually."); unmount_disks_ourselves(); return; } if (!pid) { execl(_PATH_UMOUNT, UMOUNT_ARGS, NULL); - printf("Cannot exec %s, trying umount.\n", _PATH_UMOUNT); + my_puts("Cannot exec " _PATH_UMOUNT ", trying umount."); execlp("umount", UMOUNT_ARGS, NULL); - puts("Cannot exec umount, giving up on umount."); + my_puts("Cannot exec umount, giving up on umount."); exit(0); } while ((result = wait(&status)) != -1 && result != pid) ; - puts("Unmounting any remaining filesystems..."); + my_puts("Unmounting any remaining filesystems..."); unmount_disks_ourselves(); } @@ -450,7 +531,7 @@ unmount_disks_ourselves() sync(); if (!(mtab = setmntent(_PATH_MTAB, "r"))) { - printf("shutdown: Cannot open %s.\n", _PATH_MTAB); + my_puts("shutdown: Cannot open " _PATH_MTAB "."); return; } n = 0; diff --git a/login-utils/simpleinit.c b/login-utils/simpleinit.c index 14d8cfad2..1664404c3 100644 --- a/login-utils/simpleinit.c +++ b/login-utils/simpleinit.c @@ -16,10 +16,11 @@ #include #include #ifdef SHADOW_PWD -#include +# include #endif - +#include "my_crypt.h" #include "pathnames.h" +#include "linux_reboot.h" #define CMDSIZ 150 /* max size of a line in inittab */ #define NUMCMD 30 /* max number of lines in inittab */ @@ -411,13 +412,14 @@ void int_handler() sync(); sync(); - if((pid = fork()) == 0) { - /* reboot properly... */ + pid = fork(); + if (pid > 0) + return; + if (pid == 0) /* reboot properly... */ execl(_PATH_REBOOT, _PATH_REBOOT, (char *)0); - reboot(0xfee1dead, 672274793, 0x1234567); - } else if(pid < 0) - /* fork failed, try the hard way... */ - reboot(0xfee1dead, 672274793, 0x1234567); + + /* fork or exec failed, try the hard way... */ + my_reboot(LINUX_REBOOT_CMD_RESTART); } void set_tz() diff --git a/login-utils/vipw.c b/login-utils/vipw.c index a5763b105..50270a6e3 100644 --- a/login-utils/vipw.c +++ b/login-utils/vipw.c @@ -190,15 +190,14 @@ pw_unlock() void -pw_edit(notsetuid) - int notsetuid; +pw_edit(int notsetuid) { int pstat; pid_t pid; char *p, *editor; if (!(editor = getenv("EDITOR"))) - editor = _PATH_VI; + editor = strdup(_PATH_VI); /* adia@egnatia.ee.auth.gr */ if ((p = strrchr(strtok(editor," \t"), '/')) != NULL) ++p; else diff --git a/misc-utils/Makefile b/misc-utils/Makefile index e33165f7f..9ccf489b1 100644 --- a/misc-utils/Makefile +++ b/misc-utils/Makefile @@ -31,9 +31,10 @@ USRBIN:=$(USRBIN) reset MAN1:=$(MAN1) reset.1 endif -# ifeq "$(HAVE_SYSVINIT)" "no" -# USRBIN:=$(USRBIN) pidof -# endif +# For script only +ifeq "$(HAVE_OPENPTY)" "yes" +CFLAGS:=$(CFLAGS) -DHAVE_OPENPTY +endif # Programs requiring special compilation @@ -58,16 +59,16 @@ endif # Rules for everything else -cal: cal.o $(BSD)/getopt.o $(BSD)/err.o +cal: cal.o $(ERR_O) chkdupexe: chkdupexe.pl clear: clear.sh kill: kill.o procs.o -logger: logger.o $(BSD)/getopt.o +logger: logger.o mcookie: mcookie.o md5.o mcookie.o: mcookie.c md5.h md5.o: md5.c md5.h reset: reset.sh -# pidof: pidof.o procs.o + ifeq "$(HAVE_NCURSES)" "yes" setterm: setterm.o endif diff --git a/misc-utils/cal.1 b/misc-utils/cal.1 index 80d95b27d..9d41dc5ed 100644 --- a/misc-utils/cal.1 +++ b/misc-utils/cal.1 @@ -42,7 +42,7 @@ .Nd displays a calendar .Sh SYNOPSIS .Nm cal -.Op Fl jy +.Op Fl mjy .Op Ar month Op Ar year .Sh DESCRIPTION .Nm Cal @@ -51,6 +51,8 @@ If arguments are not specified, the current month is displayed. The options are as follows: .Bl -tag -width Ds +.It Fl m +Display monday as the first day of the week. .It Fl j Display julian dates (days one-based, numbered from January 1). .It Fl y diff --git a/misc-utils/cal.c b/misc-utils/cal.c index 9d44d327b..ab6420140 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -34,6 +34,10 @@ * SUCH DAMAGE. */ +/* 1999-02-01 Jean-Francois Bignolles: added option '-m' to display + * monday as the first day of the week. + */ + /* 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? @@ -72,7 +76,7 @@ #define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */ #define NUMBER_MISSING_DAYS 11 /* 11 day correction */ -#define MAXDAYS 42 /* max slots in a month array */ +#define MAXDAYS 43 /* max slots in a month array */ #define SPACE -1 /* used in day array */ static int days_in_month[2][13] = { @@ -87,6 +91,7 @@ int sep1752[MAXDAYS] = { SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE }, j_sep1752[MAXDAYS] = { SPACE, SPACE, 245, 246, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, @@ -94,6 +99,7 @@ int sep1752[MAXDAYS] = { SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE }, empty[MAXDAYS] = { SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, @@ -101,10 +107,13 @@ int sep1752[MAXDAYS] = { SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE }; char day_headings[] = " S M Tu W Th F S "; +/* week1stday = 1 => " M Tu W Th F S S " */ char j_day_headings[] = " S M Tu W Th F S "; +/* week1stday = 1 => " M Tu W Th F S S " */ const char *full_month[12]; /* leap year -- account for gregorian reformation in 1752 */ @@ -124,6 +133,8 @@ const char *full_month[12]; #define leap_years_since_year_1(yr) \ ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) +/* 0 => sunday (default), 1 => monday */ +int week1stday; int julian; void ascii_day __P((char *, int)); @@ -153,10 +164,12 @@ main(argc, argv) #endif setlocale(LC_ALL,""); - headers_init(); yflag = 0; - while ((ch = getopt(argc, argv, "jy")) != EOF) + while ((ch = getopt(argc, argv, "mjy")) != EOF) switch(ch) { + case 'm': + week1stday = 1; + break; case 'j': julian = 1; break; @@ -190,6 +203,7 @@ main(argc, argv) default: usage(); } + headers_init(); if (month) monthly(month, year); @@ -209,22 +223,28 @@ main(argc, argv) void headers_init(void) { - int i; + int i, wd; strcpy(day_headings,""); strcpy(j_day_headings,""); - - for(i = 0 ; i < 7 ; i++ ) { + #if defined(__linux__) && (_LINUX_C_LIB_VERSION_MAJOR > 4 || __GNU_LIBRARY__ > 1) - strncat(day_headings,nl_langinfo(ABDAY_1+i),2); - strcat(j_day_headings,nl_langinfo(ABDAY_1+i)); +# define weekday(wd) nl_langinfo(ABDAY_1+wd) #else - strncat(day_headings,_time_info->abbrev_wkday[i],2); - strcat(j_day_headings,_time_info->abbrev_wkday[i]); +# define weekday(wd) _time_info->abbrev_wkday[wd] #endif + + for(i = 0 ; i < 7 ; i++ ) { + wd = (i + week1stday) % 7; + strncat(day_headings,weekday(wd),2); + strcat(j_day_headings,weekday(wd)); + if (strlen(weekday(wd)) == 2) + strcat(j_day_headings," "); strcat(day_headings," "); strcat(j_day_headings," "); } + +#undef weekday for (i = 0; i < 12; i++) { #if defined(__linux__) && (_LINUX_C_LIB_VERSION_MAJOR > 4 || __GNU_LIBRARY__ > 1) @@ -341,15 +361,16 @@ day_array(month, year, days) int *days; { int day, dw, dm; + int *d_sep1752; if (month == 9 && year == 1752) { - memmove(days, - julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int)); + d_sep1752 = julian ? j_sep1752 : sep1752; + memcpy(days, d_sep1752 + week1stday, MAXDAYS * sizeof(int)); return; } - memmove(days, empty, MAXDAYS * sizeof(int)); + memcpy(days, empty, MAXDAYS * sizeof(int)); dm = days_in_month[leap_year(year)][month]; - dw = day_in_week(1, month, year); + dw = (day_in_week(1, month, year) - week1stday + 7) % 7; day = julian ? day_in_year(1, month, year) : 1; while (dm--) days[dw++] = day++; @@ -466,6 +487,6 @@ void usage() { - (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n"); + (void)fprintf(stderr, "usage: cal [-mjy] [[month] year]\n"); exit(1); } diff --git a/misc-utils/chkdupexe.pl b/misc-utils/chkdupexe.pl old mode 100644 new mode 100755 index f6111def1..82ee9e98b --- a/misc-utils/chkdupexe.pl +++ b/misc-utils/chkdupexe.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl5 -w +#!/usr/bin/perl -w # # chkdupexe version 2.1.1 # @@ -27,7 +27,7 @@ $execdirs='/bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin '. '/usr/X11/bin /usr/bin/X11 /usr/local/X11/bin '. '/usr/TeX/bin /usr/tex/bin /usr/games '. - '/usr/local/games /usr/intervies/bin/LINUX'; + '/usr/local/games'; # Values from /usr/include/linux/errno.h. Existence of linux/errno.ph is not # something to count on... :-( @@ -96,6 +96,8 @@ while (($prog,$paths)=each %progs) { } close(LS); +exit 0; + @unchecked=(); # Check if the users PATH contains something I've not checked. The site admin # might want to know about inconsistencies in user PATHs and chkdupexec @@ -108,6 +110,6 @@ foreach $dir (split(/:/,$ENV{'PATH'})) { $didthis{$device,$inode}=1; } -print "Warning: Your path contanis these directories which chkdupexe have not checked:\n",join(',',@unchecked), +print "Warning: Your path contains these directories which chkdupexe has not checked:\n",join(',',@unchecked), ".\nPlease review the execdirs list in chkdupexe.\n" if ($#unchecked>=$[); diff --git a/misc-utils/ddate.1 b/misc-utils/ddate.1 index 1ccc201f6..7d17c8248 100644 --- a/misc-utils/ddate.1 +++ b/misc-utils/ddate.1 @@ -43,8 +43,8 @@ Newline .IP %t Tab .IP %X -Number of days remaining until X-Day. (Not valid if the SubGenius options are not -compiled in.) +Number of days remaining until X-Day. (Not valid if the SubGenius options +are not compiled in.) .IP %{ .IP %} Used to enclose the part of the string which is to be replaced with the @@ -80,6 +80,12 @@ will produce undefined behaviour if asked to produce the date for St. Tib's day and its format string does not contain the St. Tib's Day delimiters %{ and %}. +.SH NOTE + +After `X-Day' passed without incident, the Church of the SubGenius +declared that it had got the year upside down - X-Day is actually in 8661 AD +rather than 1998 AD. Thus, the True X-Day is Cfn 40, 9827. + .SH AUTHOR .nh Original program by Druel the Chaotic aka Jeremy Johnson (mpython@gnu.ai.mit.edu) @@ -96,6 +102,8 @@ Public domain. All rites reversed. date(1), .br +http://www.subgenius.com/ +.br Malaclypse the Younger, .I "Principia Discordia, Or How I Found Goddess And What I Did To Her When I Found Her" diff --git a/misc-utils/ddate.c b/misc-utils/ddate.c index f838d1c63..09704e0b4 100644 --- a/misc-utils/ddate.c +++ b/misc-utils/ddate.c @@ -307,12 +307,20 @@ struct disc_time convert(int nday, int nyear) #ifdef KILL_BOB -/* Code for counting down to X-Day, X-Day being Cfn 40, 3164 */ +/* Code for counting down to X-Day, X-Day being Cfn 40, 3164 + * + * After `X-Day' passed without incident, the CoSG declared that it had + * got the year upside down --- X-Day is actually in 8661 AD rather than + * 1998 AD. + * + * Thus, the True X-Day is Cfn 40, 9827. + * + */ int xday_countdown(int yday, int year) { int r=(185-yday)+(((yday<59)&&(leapp(year)))?1:0); - while(year<3164) r+=(leapp(++year)?366:365); - while(year>3164) r-=(leapp(year--)?366:365); + while(year<9827) r+=(leapp(++year)?366:365); + while(year>9827) r-=(leapp(year--)?366:365); return r; } diff --git a/misc-utils/hostname.c.orig b/misc-utils/hostname.c.orig deleted file mode 100644 index b7e61d1f7..000000000 --- a/misc-utils/hostname.c.orig +++ /dev/null @@ -1,187 +0,0 @@ -/* hostname -- set the host name or show the host/domain name - - Copyright (C) 1994 Peter Tobias - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#define NO_OPT -1 - -static char *program_name; -static const char *version_string = "hostname 1.5"; - -static void sethname(char *); -static void showhname(char *, int); -static void usage(void); - -static void sethname(char *hname) -{ - if(sethostname(hname, strlen(hname))) { - switch(errno) { - case EPERM: - fprintf(stderr,"%s: you must be root to change the host name\n", program_name); - break; - case EINVAL: - fprintf(stderr,"%s: name too long\n", program_name); - break; - default: - } - exit(1); - }; -} - -static void showhname(char *hname, int c) -{ - struct hostent *hp; - register char *p; - - if (!(hp = gethostbyname(hname))) { - herror(program_name); - exit(1); - } - - if (!(p = strchr(hp->h_name, '.'))) { - fprintf(stderr,"%s: can't find a FQDN for the host name `%s'\n", program_name, hname); - exit(1); - } - - switch(c) { - case 'd': - printf("%s\n", ++p); - break; - case 'f': - printf("%s\n", hp->h_name); - break; - case 's': - *p = '\0'; - printf("%s\n", hp->h_name); - break; - default: - } -} - -static void usage(void) -{ - printf("Usage: %s [OPTION]... [hostname]\n\n\ - -d, --domain display the DNS domain name\n\ - -F, --file filename read the host name from file\n\ - -f, --fqdn, --long display the long host name (FQDN)\n\ - -s, --short display the short host name\n\ - -h, --help display this help and exit\n\ - -v, --version output version information and exit\n\ -\n\ - When the program is called without any arguments, it displays the\n\ - current host name as set by the hostname command. If an argument\n\ - is given, the program will set the value of the host name to the\n\ - value specified.\n\ - Unless you are using bind or NIS for host lookups you can change the\n\ - FQDN (Fully Qualified Domain Name) and the DNS domain name (which is\n\ - part of the FQDN) in the /etc/hosts file.\n", program_name); -} - -int main(int argc, char **argv) -{ - int c; - int option_index = 0; - - char myname[MAXHOSTNAMELEN+1]; - - static const struct option long_options[] = - { - {"domain", no_argument, 0, 'd'}, - {"file", required_argument, 0, 'F'}, - {"fqdn", no_argument, 0, 'f'}, - {"help", no_argument, 0, 'h'}, - {"long", no_argument, 0, 'f'}, - {"short", no_argument, 0, 's'}, - {"version", no_argument, 0, 'v'}, - {0, 0, 0, 0} - }; - - program_name = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0]; - - if (strcmp(program_name, "dnsdomainname") == 0) { - if (argc > 1) { - fprintf(stderr,"%s: You can't change the DNS domainname with this command\n", program_name); - fprintf(stderr,"\nUnless you are using bind or NIS for host lookups you can change the DNS\n"); - fprintf(stderr,"domain name (which is part of the FQDN) in the /etc/hosts file.\n"); - exit(1); - } - c = 'd'; - } else - c = getopt_long(argc, argv, "dfF:hsv", long_options, &option_index); - - gethostname(myname, sizeof(myname)); - - switch(c) - { - case 'd': - case 'f': - case 's': - showhname(myname, c); - break; - case 'F': - { - register FILE *fd; - register char *p; - char fline[MAXHOSTNAMELEN]; - - if ((fd = fopen(optarg, "r")) != NULL) { - while (fgets(fline, sizeof(fline), fd) != NULL) - if ((p = index(fline, '\n')) != NULL) { - *p = '\0'; - if (fline[0] == '#') - continue; - sethname(fline); - } - (void) fclose(fd); - } else { - fprintf(stderr,"%s: can't open `%s'\n", - program_name, optarg); - exit(1); - } - } - break; - case 'h': - usage(); - break; - case 'v': - printf("%s\n", version_string); - break; - case '?': - fprintf(stderr,"Try `%s --help' for more information.\n", program_name); - exit(1); - break; - case NO_OPT: - if (optind < argc) { - sethname(argv[optind]); - exit(0); - } - default: - printf("%s\n", myname); - - }; - exit(0); -} diff --git a/misc-utils/kill.c b/misc-utils/kill.c index 85911211a..629938137 100644 --- a/misc-utils/kill.c +++ b/misc-utils/kill.c @@ -43,20 +43,91 @@ #include #include -#ifdef __linux__ -/* - * sys_signame -- an ordered list of signals. - * lifted from /usr/include/linux/signal.h - * this particular order is only correct for linux. - * this is _not_ portable. - */ -char *sys_signame[NSIG] = { - "zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED", - "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", - "STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO", - "XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL -}; +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +struct signv { + char *name; + int val; +} sys_signame[] = { + /* POSIX signals */ + { "HUP", SIGHUP }, /* 1 */ + { "INT", SIGINT }, /* 2 */ + { "QUIT", SIGQUIT }, /* 3 */ + { "ILL", SIGILL }, /* 4 */ + { "ABRT", SIGABRT }, /* 6 */ + { "FPE", SIGFPE }, /* 8 */ + { "KILL", SIGKILL }, /* 9 */ + { "SEGV", SIGSEGV }, /* 11 */ + { "PIPE", SIGPIPE }, /* 13 */ + { "ALRM", SIGALRM }, /* 14 */ + { "TERM", SIGTERM }, /* 15 */ + { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */ + { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */ + { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */ + { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */ + { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */ + { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */ + { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */ + { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */ + /* Miscellaneous other signals */ +#ifdef SIGTRAP + { "TRAP", SIGTRAP }, /* 5 */ +#endif +#ifdef SIGIOT + { "IOT", SIGIOT }, /* 6, same as SIGABRT */ +#endif +#ifdef SIGEMT + { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */ +#endif +#ifdef SIGBUS + { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */ +#endif +#ifdef SIGSYS + { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */ +#endif +#ifdef SIGSTKFLT + { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */ +#endif +#ifdef SIGURG + { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */ +#endif +#ifdef SIGIO + { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */ +#endif +#ifdef SIGPOLL + { "POLL", SIGPOLL }, /* same as SIGIO */ +#endif +#ifdef SIGCLD + { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */ +#endif +#ifdef SIGXCPU + { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */ #endif +#ifdef SIGXFSZ + { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */ +#endif +#ifdef SIGVTALRM + { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */ +#endif +#ifdef SIGPROF + { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */ +#endif +#ifdef SIGPWR + { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */ +#endif +#ifdef SIGINFO + { "INFO", SIGINFO }, /* 29 (alpha) */ +#endif +#ifdef SIGLOST + { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */ +#endif +#ifdef SIGWINCH + { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */ +#endif +#ifdef SIGUNUSED + { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */ +#endif +}; int main (int argc, char *argv[]); extern char *mybasename(char *); @@ -197,9 +268,9 @@ int signame_to_signum (char *sig) if (! strncasecmp (sig, "sig", 3)) sig += 3; - for (n = 1; (n < NSIG) && (sys_signame[n] != NULL); n++) { - if (! strcasecmp (sys_signame[n], sig)) - return n; + for (n = 0; n < SIZE(sys_signame); n++) { + if (! strcasecmp (sys_signame[n].name, sig)) + return sys_signame[n].val; } return (-1); } @@ -226,22 +297,33 @@ void nosig (char *name) void printsig (int sig) { - printf ("%s\n", sys_signame[sig]); + int n; + + for (n = 0; n < SIZE(sys_signame); n++) { + if (sys_signame[n].val == sig) { + printf ("%s\n", sys_signame[n].name); + return; + } + } + printf("%d\n", sig); } void printsignals (FILE *fp) { - int n; + int n, lth; + int lpos = 0; - for (n = 1; (n < NSIG) && (sys_signame[n] != NULL); n++) { - fputs (sys_signame[n], fp); - if (n == (NSIG / 2) || n == (NSIG - 1)) + for (n = 0; n < SIZE(sys_signame); n++) { + lth = 1+strlen(sys_signame[n].name); + if (lpos+lth > 72) { fputc ('\n', fp); - else + lpos = 0; + } else if (lpos) fputc (' ', fp); + lpos += lth; + fputs (sys_signame[n].name, fp); } - if (n < (NSIG - 1)) - fputc ('\n', fp); + fputc ('\n', fp); } int usage (int status) diff --git a/misc-utils/look.c b/misc-utils/look.c index 1d2848b59..72256c197 100644 --- a/misc-utils/look.c +++ b/misc-utils/look.c @@ -54,42 +54,36 @@ #include #include #include +#include #include "pathnames.h" -/* - * FOLD and DICT convert characters to a normal form for comparison, - * according to the user specified flags. - * - * DICT expects integers because it uses a non-character value to - * indicate a character which should not participate in comparisons. - */ #define EQUAL 0 #define GREATER 1 #define LESS (-1) -#define NO_COMPARE (-2) - -#define FOLD(c) (isascii(c) && isupper(c) ? tolower(c) : (c)) -#define DICT(c) (isascii(c) && isalnum(c) ? (c) : NO_COMPARE) int dflag, fflag; +/* uglified the source a bit with globals, so that we only need + to allocate comparbuf once */ +int stringlen; +char *string; +char *comparbuf; -char *binary_search __P((char *, char *, char *)); -int compare __P((char *, char *, char *)); -void err __P((const char *fmt, ...)); -char *linear_search __P((char *, char *, char *)); -int look __P((char *, char *, char *)); -void print_from __P((char *, char *, char *)); - -static void usage __P((void)); +static char *binary_search (char *, char *); +static int compare (char *, char *, int); +static void err (const char *fmt, ...); +static char *linear_search (char *, char *); +static int look (char *, char *); +static void print_from (char *, char *); +static void usage (void); -void -main(argc, argv) - int argc; - char *argv[]; +int +main(int argc, char *argv[]) { struct stat sb; int ch, fd, termchar; - char *back, *file, *front, *string, *p; + char *back, *file, *front, *p; + + setlocale(LC_ALL, ""); file = _PATH_WORDS; termchar = '\0'; @@ -142,32 +136,35 @@ main(argc, argv) (off_t)0)) <= (void *)0) err("%s: %s", file, strerror(errno)); back = front + sb.st_size; - exit(look(string, front, back)); + return look(front, back); } int -look(string, front, back) - char *string, *front, *back; +look(char *front, char *back) { - register int ch; - register char *readp, *writep; + int ch; + char *readp, *writep; /* Reformat string string to avoid doing it multiple times later. */ - for (readp = writep = string; (ch = *readp++) != 0;) { - if (fflag) - ch = FOLD(ch); - if (dflag) - ch = DICT(ch); - if (ch != NO_COMPARE) - *(writep++) = ch; - } - *writep = '\0'; + if (dflag) { + for (readp = writep = string; (ch = *readp++) != 0;) { + if (isalnum(ch)) + *(writep++) = ch; + } + *writep = '\0'; + stringlen = writep - string; + } else + stringlen = strlen(string); + + comparbuf = malloc(stringlen+1); + if (comparbuf == NULL) + err("Out of memory"); - front = binary_search(string, front, back); - front = linear_search(string, front, back); + front = binary_search(front, back); + front = linear_search(front, back); if (front) - print_from(string, front, back); + print_from(front, back); return (front ? 0 : 1); } @@ -214,10 +211,9 @@ look(string, front, back) while (p < back && *p++ != '\n'); char * -binary_search(string, front, back) - register char *string, *front, *back; +binary_search(char *front, char *back) { - register char *p; + char *p; p = front + (back - front) / 2; SKIP_PAST_NEWLINE(p, back); @@ -227,7 +223,7 @@ binary_search(string, front, back) * infinitely loop. */ while (p < back && back > front) { - if (compare(string, p, back) == GREATER) + if (compare(p, back, 1) == GREATER) front = p; else back = p; @@ -249,11 +245,10 @@ binary_search(string, front, back) * o front is before or at the first line to be printed. */ char * -linear_search(string, front, back) - char *string, *front, *back; +linear_search(char *front, char *back) { while (front < back) { - switch (compare(string, front, back)) { + switch (compare(front, back, 1)) { case EQUAL: /* Found it. */ return (front); break; @@ -272,20 +267,26 @@ linear_search(string, front, back) * Print as many lines as match string, starting at front. */ void -print_from(string, front, back) - register char *string, *front, *back; +print_from(char *front, char *back) { - for (; front < back && compare(string, front, back) == EQUAL; ++front) { - for (; front < back && *front != '\n'; ++front) - if (putchar(*front) == EOF) - err("stdout: %s", strerror(errno)); - if (putchar('\n') == EOF) - err("stdout: %s", strerror(errno)); + int eol; + + while (front < back && compare(front, back, 1) == EQUAL) { + if (compare(front, back, fflag) == EQUAL) { + eol = 0; + while (front < back && !eol) { + if (putchar(*front) == EOF) + err("stdout: %s", strerror(errno)); + if (*front++ == '\n') + eol = 1; + } + } else + SKIP_PAST_NEWLINE(front, back); } } /* - * Return LESS, GREATER, or EQUAL depending on how the string1 compares with + * Return LESS, GREATER, or EQUAL depending on how string compares with * string2 (s1 ??? s2). * * o Matches up to len(s1) are EQUAL. @@ -294,32 +295,34 @@ print_from(string, front, back) * Compare understands about the -f and -d flags, and treats comparisons * appropriately. * - * The string "s1" is null terminated. The string s2 is '\n' terminated (or - * "back" terminated). + * The string "string" is null terminated. The string "s2" is '\n' terminated + * (or "s2end" terminated). + * + * We use strcasecmp etc, since it knows how to ignore case also + * in other locales. */ int -compare(s1, s2, back) - register char *s1, *s2, *back; -{ - register int ch; - - for (; *s1 && s2 < back && *s2 != '\n';) { - ch = *s2; - if (fflag) - ch = FOLD(ch); - if (dflag) - ch = DICT(ch); - - if (ch == NO_COMPARE) { - ++s2; /* Ignore character in comparison. */ - continue; - } - if (*s1 != ch) - return (*s1 < ch ? LESS : GREATER); - ++s1; - ++s2; +compare(char *s2, char *s2end, int nocase) { + int i; + char *p; + + /* copy, ignoring things that should be ignored */ + p = comparbuf; + i = stringlen; + while(s2 < s2end && *s2 != '\n' && i--) { + if (!dflag || isalnum(*s2)) + *p++ = *s2; + s2++; } - return (*s1 ? GREATER : EQUAL); + *p = 0; + + /* and compare */ + if (nocase) + i = strncasecmp(comparbuf, string, stringlen); + else + i = strncmp(comparbuf, string, stringlen); + + return ((i > 0) ? LESS : (i < 0) ? GREATER : EQUAL); } static void diff --git a/misc-utils/mcookie.1 b/misc-utils/mcookie.1 index 6d3a11c30..c6667e217 100644 --- a/misc-utils/mcookie.1 +++ b/misc-utils/mcookie.1 @@ -19,10 +19,11 @@ process id, the parent process id, the contents of an input file (if .B \-f is specified), and several bytes of information from the first of the following devices which is present: -.IR /dev/urandom ", " /dev/random ", " /dev/audio . -Other files in -.I /proc -may be used as a last resort. +.IR /dev/random , +.IR /dev/urandom , +files in +.IR /proc , +.IR /dev/audio . .SH BUGS The entropy in the generated 128-bit is probably quite small (and, therefore, vulnerable to attack) unless a non-pseudorandom number generator diff --git a/misc-utils/mcookie.c b/misc-utils/mcookie.c index 05136190f..33ae7630e 100644 --- a/misc-utils/mcookie.c +++ b/misc-utils/mcookie.c @@ -101,9 +101,12 @@ int main( int argc, char **argv ) } for (i = 0; i < RNGS; i++) { - if ((fd = open( rngs[i].path, O_RDONLY )) >= 0) { + if ((fd = open( rngs[i].path, O_RDONLY|O_NONBLOCK )) >= 0) { r = read( fd, buf, sizeof( buf ) ); - MD5Update( &ctx, buf, r ); + if (r > 0) + MD5Update( &ctx, buf, r ); + else + r = 0; close( fd ); if (Verbose) fprintf( stderr, "Got %d bytes from %s\n", r, rngs[i].path ); diff --git a/misc-utils/procs.c b/misc-utils/procs.c index 2ea3e098c..fd0e5add3 100644 --- a/misc-utils/procs.c +++ b/misc-utils/procs.c @@ -6,9 +6,9 @@ * modify it under the terms of the gnu general public license. * there is no warranty. * - * $Author: janl $ - * $Revision: 1.5 $ - * $Date: 1996/11/11 22:40:03 $ + * faith + * 1.2 + * 1995/02/23 01:20:40 * */ @@ -112,7 +112,6 @@ static char *parse_parens (char *buf) return cp; } - char *mybasename (char *path) { char *cp; @@ -120,3 +119,4 @@ char *mybasename (char *path) cp = strrchr (path, '/'); return (cp ? cp + 1 : path); } + diff --git a/misc-utils/script.c b/misc-utils/script.c index af4013d30..23c48ea6b 100644 --- a/misc-utils/script.c +++ b/misc-utils/script.c @@ -49,6 +49,10 @@ #include #endif +#ifdef HAVE_OPENPTY +#include +#endif + void done(void); void fail(void); void fixtty(void); @@ -70,10 +74,12 @@ struct termios tt; struct winsize win; int lb; int l; +#ifndef HAVE_OPENPTY char line[] = "/dev/ptyXX"; +#endif int aflg; -void +int main(argc, argv) int argc; char *argv[]; @@ -131,6 +137,8 @@ main(argc, argv) doshell(); } doinput(); + + return 0; } void @@ -140,6 +148,9 @@ doinput() char ibuf[BUFSIZ]; (void) fclose(fscript); +#ifdef HAVE_OPENPTY + (void) close(slave); +#endif while ((cc = read(0, ibuf, BUFSIZ)) > 0) (void) write(master, ibuf, cc); done(); @@ -170,6 +181,9 @@ dooutput() char obuf[BUFSIZ], *ctime(); (void) close(0); +#ifdef HAVE_OPENPTY + (void) close(slave); +#endif tvec = time((time_t *)NULL); fprintf(fscript, "Script started on %s", ctime(&tvec)); for (;;) { @@ -250,6 +264,14 @@ done() void getmaster() { +#ifdef HAVE_OPENPTY + (void) tcgetattr(0, &tt); + (void) ioctl(0, TIOCGWINSZ, (char *)&win); + if (openpty(&master, &slave, NULL, &tt, &win) < 0) { + fprintf(stderr, "openpty failed\n"); + fail(); + } +#else char *pty, *bank, *cp; struct stat stb; @@ -282,12 +304,13 @@ getmaster() } fprintf(stderr, "Out of pty's\n"); fail(); +#endif /* not HAVE_OPENPTY */ } void getslave() { - +#ifndef HAVE_OPENPTY line[strlen("/dev/")] = 't'; slave = open(line, O_RDWR); if (slave < 0) { @@ -296,6 +319,7 @@ getslave() } (void) tcsetattr(slave, TCSAFLUSH, &tt); (void) ioctl(slave, TIOCSWINSZ, (char *)&win); +#endif (void) setsid(); (void) ioctl(slave, TIOCSCTTY, 0); } diff --git a/misc-utils/setterm.c b/misc-utils/setterm.c index 49903f3b7..3b3e6c24f 100644 --- a/misc-utils/setterm.c +++ b/misc-utils/setterm.c @@ -95,6 +95,9 @@ #include #include #include +#ifndef NCURSES_CONST +#define NCURSES_CONST const /* define before including term.h */ +#endif #include #if NCH #include @@ -928,11 +931,12 @@ int vcterm; /* Set if terminal is a virtual console. */ /* -inversescreen [on|off]. Vc only (vt102). */ if (opt_inversescreen) { - if (vcterm) + if (vcterm) { if (opt_invsc_on) printf("\033[?5h"); else printf("\033[?5l"); + } } /* -bold [on|off]. Vc behaves as expected, otherwise off turns off diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c index 1a8e1edd7..494192417 100644 --- a/misc-utils/whereis.c +++ b/misc-utils/whereis.c @@ -99,6 +99,8 @@ static char *bindirs[] = { "/usr/libexec", "/usr/share", + "/opt/*/bin", + 0 }; diff --git a/misc-utils/write.c b/misc-utils/write.c index e43b0bf9a..07a113ea7 100644 --- a/misc-utils/write.c +++ b/misc-utils/write.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,6 @@ #ifdef __linux__ #include #include "pathnames.h" -#include #endif void search_utmp(char *, char *, char *, uid_t); @@ -67,7 +67,7 @@ int utmp_chk(char *, char *); extern int errno; -void +int main(int argc, char **argv) { register char *cp; @@ -77,9 +77,7 @@ main(int argc, char **argv) char tty[MAXPATHLEN], *mytty, *ttyname(); void done(); -#ifdef __linux__ setlocale(LC_CTYPE,""); -#endif /* check that sender has write enabled */ if (isatty(fileno(stdin))) @@ -143,6 +141,7 @@ main(int argc, char **argv) } done(); /* NOTREACHED */ + return 0; } @@ -291,11 +290,12 @@ void do_write(char *tty, char *mytty, uid_t myuid) void done(); /* Determine our login name before the we reopen() stdout */ - if ((login = getlogin()) == NULL) + if ((login = getlogin()) == NULL) { if ((pwd = getpwuid(myuid)) != NULL) login = pwd->pw_name; else login = "???"; + } if (strlen(tty) + 6 > sizeof(path)) exit(1); @@ -347,8 +347,13 @@ void wr_fputs(char *s) PUTC('\r'); PUTC('\n'); } else if (!isprint(c) && !isspace(c) && c != '\007') { - PUTC('^'); - PUTC(c^0x40); /* DEL to ?, others to alpha */ + if (c & 0x80) { + /* use some fallback? */ + (void)printf("\\%3o", (unsigned char) c); + } else { + PUTC('^'); + PUTC(c^0x40); /* DEL to ?, others to alpha */ + } } else PUTC(c); } diff --git a/mkminix-0.1/README b/mkminix-0.1/README new file mode 100644 index 000000000..d93c38e95 --- /dev/null +++ b/mkminix-0.1/README @@ -0,0 +1,47 @@ +Mkminix-0.1 by W. Black + +Description +----------- +This directory contains a hacked version of mkfs.minix from util-linux 2.8. +The hack in question was primarily a bit of #ifndef-ing to make it compile +successfully under DJGPP. Due to DOS's brain-damaged 8.3 filename limitation, +the executable has been renamed from mkfs.minix to mkminix.exe. +[Executable deleted in the util-linux distribution.] + +Distribution +------------ +This distribution should have come with both sources and executable. If +you're missing either, feel free to visit my site at +http://www.geocities.com/SiliconValley/Network/5508 to get a fresh one if +you need it. + +This program and its source program in util-linux are protected by the GNU +General Public License. See the file COPYING for details. + +Why +--- +Exactly why would anyone want to create a Minix filesystem under DOS? The +answer, as far as I am concerned, is in the interest of creating initial +ramdisks for Linux. By being able to configure an initrd from DOS (or Win +'95, etc.), you can make the transition to Linux that much easier (think +Win '95 autoplay Linux distributions, for example). + +Phase II of this project would logically be to be able to populate this initrd +with files. That is my goal for mkminix-0.2. + +Installation +------------ +At this point, everything is pretty much already installed. Just run MKMINIX +from the DOS prompt. The source will compile under DJGPP if and only if you +have a copy of linux/minix_fs.h. I included the one from Linux kernel 2.0.30, +but these files have a way of changing in annoying ways, so it's probably best +to use one that matches whatever version of Linux you are going to be running +concurrently. This is if you have to be ABSOLUTELY sure that everything +matches... BTW, compile line is as follows for DJGPP: + + gcc -o mkminix.exe mkminix.c + +Desperate Plea for Attention +---------------------------- +If you find this program useful (or silly, or a complete waste of time), please +drop me a line at wjblack@yahoo.com. Thanks! diff --git a/mkminix-0.1/linux/minix_fs.h b/mkminix-0.1/linux/minix_fs.h new file mode 100644 index 000000000..3bc020fcd --- /dev/null +++ b/mkminix-0.1/linux/minix_fs.h @@ -0,0 +1,135 @@ +#ifndef _LINUX_MINIX_FS_H +#define _LINUX_MINIX_FS_H + +/* + * The minix filesystem constants/structures + */ + +/* + * Thanks to Kees J Bot for sending me the definitions of the new + * minix filesystem (aka V2) with bigger inodes and 32-bit block + * pointers. + */ + +#define MINIX_ROOT_INO 1 + +/* Not the same as the bogus LINK_MAX in . Oh well. */ +#define MINIX_LINK_MAX 250 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 64 +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ +#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +#define MINIX_V1 0x0001 /* original minix fs */ +#define MINIX_V2 0x0002 /* minix V2 fs */ + +#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { + __u16 i_mode; + __u16 i_uid; + __u32 i_size; + __u32 i_time; + __u8 i_gid; + __u8 i_nlinks; + __u16 i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { + __u16 i_mode; + __u16 i_nlinks; + __u16 i_uid; + __u16 i_gid; + __u32 i_size; + __u32 i_atime; + __u32 i_mtime; + __u32 i_ctime; + __u32 i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + __u16 s_ninodes; + __u16 s_nzones; + __u16 s_imap_blocks; + __u16 s_zmap_blocks; + __u16 s_firstdatazone; + __u16 s_log_zone_size; + __u32 s_max_size; + __u16 s_magic; + __u16 s_state; + __u32 s_zones; +}; + +struct minix_dir_entry { + __u16 inode; + char name[0]; +}; + +#ifdef __KERNEL__ + +extern int minix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int minix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int minix_rmdir(struct inode * dir, const char * name, int len); +extern int minix_unlink(struct inode * dir, const char * name, int len); +extern int minix_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); +extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); +extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); +extern struct inode * minix_new_inode(const struct inode * dir); +extern void minix_free_inode(struct inode * inode); +extern unsigned long minix_count_free_inodes(struct super_block *sb); +extern int minix_new_block(struct super_block * sb); +extern void minix_free_block(struct super_block * sb, int block); +extern unsigned long minix_count_free_blocks(struct super_block *sb); + +extern int minix_bmap(struct inode *,int); + +extern struct buffer_head * minix_getblk(struct inode *, int, int); +extern struct buffer_head * minix_bread(struct inode *, int, int); + +extern void minix_truncate(struct inode *); +extern void minix_put_super(struct super_block *); +extern struct super_block *minix_read_super(struct super_block *,void *,int); +extern int init_minix_fs(void); +extern void minix_write_super(struct super_block *); +extern int minix_remount (struct super_block * sb, int * flags, char * data); +extern void minix_read_inode(struct inode *); +extern void minix_write_inode(struct inode *); +extern void minix_put_inode(struct inode *); +extern void minix_statfs(struct super_block *, struct statfs *, int); +extern int minix_sync_inode(struct inode *); +extern int minix_sync_file(struct inode *, struct file *); + +extern struct inode_operations minix_file_inode_operations; +extern struct inode_operations minix_dir_inode_operations; +extern struct inode_operations minix_symlink_inode_operations; + +#endif /* __KERNEL__ */ + +#endif diff --git a/mkminix-0.1/mkmin-dj.h b/mkminix-0.1/mkmin-dj.h new file mode 100644 index 000000000..1ed7b2161 --- /dev/null +++ b/mkminix-0.1/mkmin-dj.h @@ -0,0 +1,43 @@ +/* Stolen from linux/fs.h */ +#define BLOCK_SIZE 1024 + +/* Ugh */ +typedef unsigned char __u8; +typedef unsigned short __u16; +typedef unsigned int __u32; + +/* Stolen from linux/stat.h, since DJGPP's stat.h produces different values */ +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 diff --git a/mkminix-0.1/mkminix.diff b/mkminix-0.1/mkminix.diff new file mode 100644 index 000000000..45d6c8194 --- /dev/null +++ b/mkminix-0.1/mkminix.diff @@ -0,0 +1,46 @@ +48a49,51 +> * 09.29.98 - Modified to compile under DJGPP (minus mount-checking, etc.). +> * (wjblack@yahoo.com) +> * +69a73,78 +> +> /* DJGPP's IOCTL interface should probably not be trusted here. It's not +> needed, anyway. Nor does DJGPP have any clue about mounted filesystems. +> Oh, did I mention that the directory status, etc, doesn't match that of +> the Minix FS? */ +> #ifndef __DJGPP__ +74a84,91 +> #endif +> +> /* For those defs that DJGPP doesn't have (or has wrong) */ +> #ifdef __DJGPP__ +> #include "mkmin-dj.h" +> #endif +> +> /* DJGPP requires that you stick a linux/minix_fs.h somewhere appropriate */ +172a190 +> #ifndef __DJGPP__ +173a192,194 +> #else +> #define usage() fatal_error("Usage: %s [-c | -l filename] [-nXX] [-iXX] imagefile [blocks]\n",16) +> #endif +175a197 +> #ifndef __DJGPP__ +196a219 +> #endif /* __DJGPP__ */ +238a262 +> #ifndef __DJGPP__ +242a267 +> #endif +613a639 +> #ifndef __DJGPP__ +614a641 +> #endif +694a722 +> #ifndef __DJGPP__ +695a724 +> #endif +707a737 +> #ifndef __DJGPP__ +713a744 +> #endif diff --git a/mount/Makefile b/mount/Makefile index 32272a9b6..c61b4ae8c 100644 --- a/mount/Makefile +++ b/mount/Makefile @@ -3,18 +3,17 @@ include ../MCONFIG endif CC = gcc -CFLAGS = -O2 +CFLAGS = -I$(LIB) $(OPT) WARNFLAGS = -Wall -Wstrict-prototypes -Wmissing-prototypes DEFINES = -DHAVE_NFS -LDFLAGS = RPCSVCDIR = rpcsvc RPC_CFLAGS = -Wno-unused RPCGEN = rpcgen #INSTALL = install -#INSTALL_SUID = $(INSTALL) -m 4755 -o root -#INSTALL_PROG = $(INSTALL) -m 755 -#INSTALL_DATA = $(INSTALL) -m 644 +#INSTALLSUID = $(INSTALL) -m 4755 -o root +#INSTALLPROG = $(INSTALL) -m 755 +#INSTALLDATA = $(INSTALL) -m 644 ## for suid progs (mount, umount) #BINDIR = /bin @@ -54,32 +53,43 @@ install: $(PROGS) %.o: %.c $(COMPILE) $< -mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS) - $(LINK) $^ $(LDLIBS) -o $@ +mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \ + mount_guess_fstype.o mount_by_label.o getusername.o \ + $(LIB)/setproctitle.o $(NFS_OBJS) $(LO_OBJS) + $(LINK) $^ -o $@ -umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS) - $(LINK) $^ $(LDLIBS) -o $@ +umount: umount.o fstab.o sundries.o realpath.o mntent.o getusername.o \ + version.o $(LO_OBJS) + $(LINK) $^ -o $@ swapon: swapon.o version.o - $(LINK) $^ $(LDLIBS) -o $@ + $(LINK) $^ -o $@ losetup: losetup.o - $(LINK) $^ $(LDLIBS) -o $@ - -mount.o: linux_fs.h + $(LINK) $^ -o $@ mount.o umount.o nfsmount.o losetup.o fstab.o sundries.o: sundries.h mount.o umount.o fstab.o sundries.o: fstab.h +mount.o fstab.o mntent.o: mntent.h + +mount.o mount_guess_fstype.o: mount_guess_fstype.h + +mount.o: $(LIB)/setproctitle.h + +mount.o umount.o getusername.o: getusername.h + mount.o umount.o losetup.o lomount.o: lomount.h loop.h -swapon.o: swap.h swapargs.h +swapon.o: swap_constants.h swapargs.h sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h umount.o: mount_constants.h +mount.o mount_by_label.o mount_guess_fstype.o: linux_fs.h + nfsmount_clnt.o: nfsmount_clnt.c $(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c @@ -109,11 +119,6 @@ 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 - swapargs.h: sh swap.configure @@ -122,7 +127,7 @@ loop.h: clean: rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff - rm -f swap.h loop.h nfs_mountversion.h + rm -f loop.h nfs_mountversion.h clobber distclean realclean: clean # rm -f $(GEN_FILES) diff --git a/mount/Makefile.standalone b/mount/Makefile.standalone index 2cedcd235..1be375689 100644 --- a/mount/Makefile.standalone +++ b/mount/Makefile.standalone @@ -5,7 +5,7 @@ # For now: a standalone version CC = gcc -CFLAGS = -O2 +CFLAGS = -O2 -I../lib #WARNFLAGS = -Wall -Wstrict-prototypes # We really want @@ -23,11 +23,11 @@ RPC_CFLAGS = -Wno-unused RPCGEN = rpcgen INSTALL = install -INSTALL_SUID = $(INSTALL) -m 4755 -o root -INSTALL_PROG = $(INSTALL) -m 755 -INSTALL_DATA = $(INSTALL) -m 644 -INSTALL_DIR = mkdir -p -INSTALL_MAN = $(INSTALL_DATA) +INSTALLSUID = $(INSTALL) -m 4755 -o root +INSTALLPROG = $(INSTALL) -m 755 +INSTALLDATA = $(INSTALL) -m 644 +INSTALLDIR = mkdir -p +INSTALLMAN = $(INSTALLDATA) MANDIR = /usr/man ## for suid progs (mount, umount) @@ -57,21 +57,22 @@ LO_OBJS=lomount.o all: $(PROGS) install: $(PROGS) - $(INSTALL_DIR) $(BINDIR) $(SBINDIR) - $(INSTALL_SUID) -s $(SUID_PROGS) $(BINDIR) - $(INSTALL_PROG) -s $(NOSUID_PROGS) $(SBINDIR) + $(INSTALLDIR) $(BINDIR) $(SBINDIR) + $(INSTALLSUID) -s $(SUID_PROGS) $(BINDIR) + $(INSTALLPROG) -s $(NOSUID_PROGS) $(SBINDIR) (cd $(SBINDIR); ln -sf swapon swapoff) - $(INSTALL_DIR) $(MANDIR)/man5 $(MANDIR)/man8 - $(INSTALL_MAN) $(MAN5) $(MANDIR)/man5 - $(INSTALL_MAN) $(MAN8) $(MANDIR)/man8 + $(INSTALLDIR) $(MANDIR)/man5 $(MANDIR)/man8 + $(INSTALLMAN) $(MAN5) $(MANDIR)/man5 + $(INSTALLMAN) $(MAN8) $(MANDIR)/man8 %.o: %.c $(COMPILE) $< -mount: mount.o fstab.o sundries.o realpath.o version.o $(NFS_OBJS) $(LO_OBJS) +mount: mount.o fstab.o sundries.o realpath.o mntent.o version.o \ + mount_guess_fstype.o mount_by_label.o ../lib/setproctitle.o $(NFS_OBJS) $(LO_OBJS) $(LINK) $^ -o $@ -umount: umount.o fstab.o sundries.o realpath.o version.o $(LO_OBJS) +umount: umount.o fstab.o sundries.o realpath.o mntent.o version.o $(LO_OBJS) $(LINK) $^ -o $@ swapon: swapon.o version.o @@ -84,14 +85,20 @@ 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 fstab.o mntent.o: mntent.h -swapon.o: swap.h swapargs.h +mount.o mount_guess_fstype.o: mount_guess_fstype.h + +mount.o umount.o losetup.o lomount.o: lomount.h loop.h + +swapon.o: swap_constants.h swapargs.h sundries.o nfsmount.o nfsmount_xdr.o nfsmount_clnt.o: nfsmount.h umount.o: mount_constants.h +mount.o mount_by_label.o mount_guess_fstype.o: linux_fs.h + nfsmount_clnt.o: nfsmount_clnt.c $(COMPILE) $(RPC_CFLAGS) nfsmount_clnt.c @@ -110,8 +117,6 @@ nfsmount.x: nfsmount.o: nfs_mountversion.h nfs_mount3.h NFSMOUNTH=/usr/include/linux/nfs_mount.h -SWAPH=/usr/include/linux/swap.h -LOOPH=/usr/include/linux/loop.h nfs_mountversion.h: rm -f nfs_mountversion.h @@ -122,20 +127,15 @@ nfs_mountversion.h: echo '#define KERNEL_NFS_MOUNT_VERSION 0'; \ fi > nfs_mountversion.h -swap.h: - rm -f swap.h - if [ -f $(SWAPH) ]; then cp $(SWAPH) .; else touch swap.h; fi - swapargs.h: sh swap.configure loop.h: - rm -f loop.h - if [ -f $(LOOPH) ]; then cp $(LOOPH) .; else touch loop.h; fi + sh mk_loop_h clean: rm -f a.out core *~ *.o swapargs.h $(PROGS) swapoff - rm -f swap.h loop.h nfs_mountversion.h + rm -f loop.h nfs_mountversion.h clobber distclean realclean: clean rm -f $(GEN_FILES) diff --git a/mount/fstab.5 b/mount/fstab.5 index 8af521b2f..d343538db 100644 --- a/mount/fstab.5 +++ b/mount/fstab.5 @@ -111,7 +111,7 @@ a filesystem for mounting partitions from remote systems. a disk partition to be used for swapping. .PP If -.I vfs_fstype +.I fs_vfstype is specified as ``ignore'' the entry is ignored. This is useful to show disk partitions which are currently unused. diff --git a/mount/fstab.c b/mount/fstab.c index 6a2adc657..a67316ee9 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include "mntent.h" #include "fstab.h" #include "sundries.h" /* for xmalloc() etc */ @@ -88,30 +88,28 @@ fstab_head() { } static void -read_mntentchn(FILE *fp, const char *fnam, struct mntentchn *mc0) { - struct mntentchn *mc = mc0; - struct mntent *mnt; - - while (!feof(fp) && !ferror(fp)) { - if ((mnt = getmntent (fp)) != NULL /* ignore blank lines */ - && *mnt->mnt_fsname != '#' /* and comment lines */ - && !streq (mnt->mnt_type, MNTTYPE_IGNORE)) { - mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc)); - mc->nxt->prev = mc; - mc = mc->nxt; - mc->mnt_fsname = xstrdup(mnt->mnt_fsname); - mc->mnt_dir = xstrdup(mnt->mnt_dir); - mc->mnt_type = xstrdup(mnt->mnt_type); - mc->mnt_opts = xstrdup(mnt->mnt_opts); - mc->nxt = NULL; - } - } - mc0->prev = mc; - if (ferror (fp)) { - error("warning: error reading %s: %s", fnam, strerror (errno)); - mc0->nxt = mc0->prev = NULL; - } - endmntent(fp); +read_mntentchn(mntFILE *mfp, const char *fnam, struct mntentchn *mc0) { + struct mntentchn *mc = mc0; + struct mntent *mnt; + + while ((mnt = my_getmntent (mfp)) != NULL) { + if (!streq (mnt->mnt_type, MNTTYPE_IGNORE)) { + mc->nxt = (struct mntentchn *) xmalloc(sizeof(*mc)); + mc->nxt->prev = mc; + mc = mc->nxt; + mc->mnt_fsname = mnt->mnt_fsname; + mc->mnt_dir = mnt->mnt_dir; + mc->mnt_type = mnt->mnt_type; + mc->mnt_opts = mnt->mnt_opts; + mc->nxt = NULL; + } + } + mc0->prev = mc; + if (ferror (mfp->mntent_fp)) { + error("warning: error reading %s: %s", fnam, strerror (errno)); + mc0->nxt = mc0->prev = NULL; + } + my_endmntent(mfp); } /* @@ -121,7 +119,7 @@ read_mntentchn(FILE *fp, const char *fnam, struct mntentchn *mc0) { */ static void read_mounttable() { - FILE *fp = NULL; + mntFILE *mfp; const char *fnam; struct mntentchn *mc = &mounttable; @@ -129,10 +127,12 @@ read_mounttable() { mc->nxt = mc->prev = NULL; fnam = MOUNTED; - if ((fp = setmntent (fnam, "r")) == NULL) { + mfp = my_setmntent (fnam, "r"); + if (mfp == NULL || mfp->mntent_fp == NULL) { int errsv = errno; fnam = PROC_MOUNTS; - if ((fp = setmntent (fnam, "r")) == NULL) { + mfp = my_setmntent (fnam, "r"); + if (mfp == NULL || mfp->mntent_fp == NULL) { error("warning: can't open %s: %s", MOUNTED, strerror (errsv)); return; } @@ -140,12 +140,12 @@ read_mounttable() { printf ("mount: could not open %s - using %s instead\n", MOUNTED, PROC_MOUNTS); } - read_mntentchn(fp, fnam, mc); + read_mntentchn(mfp, fnam, mc); } static void read_fstab() { - FILE *fp = NULL; + mntFILE *mfp = NULL; const char *fnam; struct mntentchn *mc = &fstab; @@ -153,11 +153,12 @@ read_fstab() { mc->nxt = mc->prev = NULL; fnam = _PATH_FSTAB; - if ((fp = setmntent (fnam, "r")) == NULL) { + mfp = my_setmntent (fnam, "r"); + if (mfp == NULL || mfp->mntent_fp == NULL) { error("warning: can't open %s: %s", _PATH_FSTAB, strerror (errno)); return; } - read_mntentchn(fp, fnam, mc); + read_mntentchn(mfp, fnam, mc); } @@ -173,6 +174,24 @@ getmntfile (const char *name) { return mc; } +/* + * Given the name NAME, and the place MCPREV we found it last time, + * try to find more occurrences. + */ +struct mntentchn * +getmntfilesbackward (const char *name, struct mntentchn *mcprev) { + struct mntentchn *mc, *mh; + + mh = mtab_head(); + if (!mcprev) + mcprev = mh; + for (mc = mcprev->prev; mc && mc != mh; mc = mc->prev) + if (streq (mc->mnt_dir, name) || (streq (mc->mnt_fsname, name))) + return mc; + + return NULL; +} + /* Given the name FILE, try to find the option "loop=FILE" in mtab. */ struct mntentchn * getmntoptfile (const char *file) @@ -222,13 +241,41 @@ getfsspec (const char *spec) return mc; } -/* Updating mtab ----------------------------------------------*/ +/* Find the uuid UUID in fstab. */ +struct mntentchn * +getfsuuidspec (const char *uuid) +{ + struct mntentchn *mc; + + for (mc = fstab_head()->nxt; mc; mc = mc->nxt) + if (strncmp (mc->mnt_fsname, "UUID=", 5) == 0 + && streq(mc->mnt_fsname + 5, uuid)) + break; + + return mc; +} -/* File descriptor for lock. Value tested in unlock_mtab() to remove race. */ -static int lock = -1; +/* Find the label LABEL in fstab. */ +struct mntentchn * +getfsvolspec (const char *label) +{ + struct mntentchn *mc; + + for (mc = fstab_head()->nxt; mc; mc = mc->nxt) + if (strncmp (mc->mnt_fsname, "LABEL=", 6) == 0 + && streq(mc->mnt_fsname + 6, label)) + break; + + return mc; +} + +/* Updating mtab ----------------------------------------------*/ /* Flag for already existing lock file. */ -static int old_lockfile = 1; +static int we_created_lockfile = 0; + +/* Flag to indicate that signals have been set up. */ +static int signals_have_been_setup = 0; /* Ensure that the lock is released if we are interrupted. */ static void @@ -241,69 +288,122 @@ setlkw_timeout (int sig) { /* nothing, fcntl will fail anyway */ } -/* Create the lock file. The lock file will be removed if we catch a signal - or when we exit. The value of lock is tested to remove the race. */ +/* Create the lock file. + The lock file will be removed if we catch a signal or when we exit. */ +/* The old code here used flock on a lock file /etc/mtab~ and deleted + this lock file afterwards. However, as rgooch remarks, that has a + race: a second mount may be waiting on the lock and proceed as + soon as the lock file is deleted by the first mount, and immediately + afterwards a third mount comes, creates a new /etc/mtab~, applies + flock to that, and also proceeds, so that the second and third mount + now both are scribbling in /etc/mtab. + The new code uses a link() instead of a creat(), where we proceed + only if it was us that created the lock, and hence we always have + to delete the lock afterwards. Now the use of flock() is in principle + superfluous, but avoids an arbitrary sleep(). */ + +/* Where does the link point to? Obvious choices are mtab and mtab~~. + Maybe the latter is preferable. */ +#define MOUNTLOCK_LINKTARGET MOUNTED_LOCK "~" + void lock_mtab (void) { - int sig = 0; - struct sigaction sa; - struct flock flock; - - /* If this is the first time, ensure that the lock will be removed. */ - if (lock < 0) { - struct stat st; - sa.sa_handler = handler; - sa.sa_flags = 0; - sigfillset (&sa.sa_mask); - - while (sigismember (&sa.sa_mask, ++sig) != -1 && sig != SIGCHLD) { - if (sig == SIGALRM) - sa.sa_handler = setlkw_timeout; - else - sa.sa_handler = handler; - sigaction (sig, &sa, (struct sigaction *) 0); - } + int tries = 3; - /* This stat is performed so we know when not to be overly eager - when cleaning up after signals. The window between stat and - open is not significant. */ - if (lstat (MOUNTED_LOCK, &st) < 0 && errno == ENOENT) - old_lockfile = 0; - - lock = open (MOUNTED_LOCK, O_WRONLY|O_CREAT, 0); - if (lock < 0) { - die (EX_FILEIO, "can't create lock file %s: %s " - "(use -n flag to override)", - MOUNTED_LOCK, strerror (errno)); - } + if (!signals_have_been_setup) { + int sig = 0; + struct sigaction sa; - flock.l_type = F_WRLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - - alarm(LOCK_BUSY); - if (fcntl (lock, F_SETLKW, &flock) < 0) { - close (lock); - /* The file should not be removed */ - lock = -1; - die (EX_FILEIO, "can't lock lock file %s: %s", - MOUNTED_LOCK, - errno == EINTR ? "timed out" : strerror (errno)); - } - /* We have now access to the lock, and it can always be removed */ - old_lockfile = 0; - } + sa.sa_handler = handler; + sa.sa_flags = 0; + sigfillset (&sa.sa_mask); + + while (sigismember (&sa.sa_mask, ++sig) != -1 + && sig != SIGCHLD) { + if (sig == SIGALRM) + sa.sa_handler = setlkw_timeout; + else + sa.sa_handler = handler; + sigaction (sig, &sa, (struct sigaction *) 0); + } + signals_have_been_setup = 1; + } + + /* Repeat until it was us who made the link */ + while (!we_created_lockfile) { + struct flock flock; + int errsv, fd, i, j; + + i = open (MOUNTLOCK_LINKTARGET, O_WRONLY|O_CREAT, 0); + if (i < 0) { + /* MOUNTLOCK_LINKTARGET does not exist (as a file) + and we cannot create it. Read-only filesystem? + Too many files open in the system? Filesystem full? */ + die (EX_FILEIO, "can't create lock file %s: %s " + "(use -n flag to override)", + MOUNTLOCK_LINKTARGET, strerror (errno)); + } + close(i); + + j = link(MOUNTLOCK_LINKTARGET, MOUNTED_LOCK); + errsv = errno; + + (void) unlink(MOUNTLOCK_LINKTARGET); + + if (j < 0 && errsv != EEXIST) { + die (EX_FILEIO, "can't link lock file %s: %s " + "(use -n flag to override)", + MOUNTED_LOCK, strerror (errsv)); + } + + fd = open (MOUNTED_LOCK, O_WRONLY); + + if (fd < 0) { + /* Strange... Maybe the file was just deleted? */ + if (errno == ENOENT && tries-- > 0) + continue; + die (EX_FILEIO, "can't open lock file %s: %s " + "(use -n flag to override)", + MOUNTED_LOCK, strerror (errno)); + } + + flock.l_type = F_WRLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + + if (j == 0) { + /* We made the link. Now claim the lock. */ + if (fcntl (fd, F_SETLK, &flock) == -1) { + if (verbose) + printf("Can't lock lock file %s: %s\n", + MOUNTED_LOCK, strerror (errno)); + /* proceed anyway */ + } + we_created_lockfile = 1; + } else { + /* Someone else made the link. Wait. */ + alarm(LOCK_TIMEOUT); + if (fcntl (fd, F_SETLKW, &flock) == -1) { + die (EX_FILEIO, "can't lock lock file %s: %s", + MOUNTED_LOCK, (errno == EINTR) ? + "timed out" : strerror (errno)); + } + alarm(0); + /* Maybe limit the number of iterations? */ + } + + close(fd); + } } /* Remove lock file. */ void unlock_mtab (void) { - if (lock != -1) { - close (lock); - if (!old_lockfile) - unlink (MOUNTED_LOCK); - } + if (we_created_lockfile) { + unlink (MOUNTED_LOCK); + we_created_lockfile = 0; + } } /* @@ -322,27 +422,32 @@ update_mtab (const char *dir, struct mntent *instead) { struct mntent *next; struct mntent remnt; int added = 0; - FILE *fp, *ftmp; + mntFILE *mfp, *mftmp; if (mtab_does_not_exist() || mtab_is_a_symlink()) return; lock_mtab(); - if ((fp = setmntent(MOUNTED, "r")) == NULL) { + mfp = my_setmntent(MOUNTED, "r"); + if (mfp == NULL || mfp->mntent_fp == NULL) { error ("cannot open %s (%s) - mtab not updated", MOUNTED, strerror (errno)); goto leave; } - if ((ftmp = setmntent (MOUNTED_TEMP, "w")) == NULL) { + mftmp = my_setmntent (MOUNTED_TEMP, "w"); + if (mftmp == NULL || mfp->mntent_fp == NULL) { error ("can't open %s (%s) - mtab not updated", MOUNTED_TEMP, strerror (errno)); goto leave; } - while ((mnt = getmntent (fp))) { - if (streq (mnt->mnt_dir, dir)) { + while ((mnt = my_getmntent (mfp))) { + if (streq (mnt->mnt_dir, dir) + /* Matthew Wilcox */ + || (instead && instead->mnt_fsname && + (streq (mnt->mnt_fsname, instead->mnt_fsname)))) { added++; if (instead) { /* a remount */ remnt = *instead; @@ -362,19 +467,19 @@ update_mtab (const char *dir, struct mntent *instead) { next = NULL; } else next = mnt; - if (next && addmntent(ftmp, next) == 1) + if (next && my_addmntent(mftmp, next) == 1) die (EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); } - if (instead && !added && addmntent(ftmp, instead) == 1) + if (instead && !added && my_addmntent(mftmp, instead) == 1) die (EX_FILEIO, "error writing %s: %s", MOUNTED_TEMP, strerror (errno)); - endmntent (fp); - if (fchmod (fileno (ftmp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + my_endmntent (mfp); + if (fchmod (fileno (mftmp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) fprintf(stderr, "error changing mode of %s: %s\n", MOUNTED_TEMP, strerror (errno)); - endmntent (ftmp); + my_endmntent (mftmp); if (rename (MOUNTED_TEMP, MOUNTED) < 0) fprintf(stderr, "can't rename %s to %s: %s\n", MOUNTED_TEMP, MOUNTED, diff --git a/mount/fstab.h b/mount/fstab.h index f22f2e7cb..e0b3895c2 100644 --- a/mount/fstab.h +++ b/mount/fstab.h @@ -1,7 +1,7 @@ #define _PATH_FSTAB "/etc/fstab" #define MOUNTED_LOCK "/etc/mtab~" #define MOUNTED_TEMP "/etc/mtab.tmp" -#define LOCK_BUSY 10 +#define LOCK_TIMEOUT 10 int mtab_is_writable(void); int mtab_does_not_exist(void); @@ -18,10 +18,13 @@ struct mntentchn { struct mntentchn *mtab_head (void); struct mntentchn *getmntfile (const char *name); struct mntentchn *getmntoptfile (const char *file); +struct mntentchn *getmntfilesbackward (const char *file, struct mntentchn *mc); struct mntentchn *fstab_head (void); struct mntentchn *getfsfile (const char *file); struct mntentchn *getfsspec (const char *spec); +struct mntentchn *getfsuuidspec (const char *uuid); +struct mntentchn *getfsvolspec (const char *label); #include void lock_mtab (void); diff --git a/mount/getusername.c b/mount/getusername.c new file mode 100644 index 000000000..9835768ca --- /dev/null +++ b/mount/getusername.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include "getusername.h" + +char * +getusername() { + char *user = 0; + struct passwd *pw = getpwuid(getuid()); + + if (pw) + user = pw->pw_name; + return user; +} diff --git a/mount/getusername.h b/mount/getusername.h new file mode 100644 index 000000000..808ac9b88 --- /dev/null +++ b/mount/getusername.h @@ -0,0 +1 @@ +extern char *getusername(void); diff --git a/mount/linux_fs.h b/mount/linux_fs.h index 4e73c3b04..bdc548c21 100644 --- a/mount/linux_fs.h +++ b/mount/linux_fs.h @@ -4,7 +4,13 @@ in case no filesystem type was given. */ #ifndef BLKGETSIZE +#ifndef _IO +/* pre-1.3.45 */ #define BLKGETSIZE 0x1260 /* return device size */ +#else +/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ +#define BLKGETSIZE _IO(0x12,96) +#endif #endif #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ @@ -43,8 +49,11 @@ struct ext_super_block { #define EXT2_PRE_02B_MAGIC 0xEF51 #define EXT2_SUPER_MAGIC 0xEF53 struct ext2_super_block { - u_char s_dummy[56]; + u_char s_dummy1[56]; u_char s_magic[2]; + u_char s_dummy2[46]; + u_char s_uuid[16]; + u_char s_volume_name[16]; }; #define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) @@ -57,3 +66,13 @@ struct xiafs_super_block { #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)) + +/* From jj@sunsite.ms.mff.cuni.cz Mon Mar 23 15:19:05 1998 */ +#define UFS_SUPER_MAGIC 0x00011954 +struct ufs_super_block { + u_char s_dummy[0x55c]; + u_char s_magic[4]; +}; +#define ufsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) diff --git a/mount/losetup.c b/mount/losetup.c index 8f9dbe52b..8a75a9aef 100644 --- a/mount/losetup.c +++ b/mount/losetup.c @@ -202,12 +202,12 @@ int main(int argc, char **argv) if ((delete && (argc != optind+1 || encryption || offset)) || (!delete && (argc < optind+1 || argc > optind+2))) usage(); - if (argc == optind+1) + if (argc == optind+1) { if (delete) del_loop(argv[optind]); else show_loop(argv[optind]); - else { + } else { if (offset && sscanf(offset,"%d",&off) != 1) usage(); set_loop(argv[optind],argv[optind+1],off,encryption,&ro); diff --git a/mount/mk_loop_h b/mount/mk_loop_h index 9351b57e0..0f8a1a617 100644 --- a/mount/mk_loop_h +++ b/mount/mk_loop_h @@ -8,11 +8,12 @@ rm -f loop.h # Since 1.3.79 there is an include file # that defines __kernel_dev_t. # (The file itself appeared in 1.3.78, but there it defined __dev_t.) -# If it exists, we use it. Otherwise we guess that __kernel_dev_t +# If it exists, we use it, or, rather, which +# avoids namespace pollution. Otherwise we guess that __kernel_dev_t # is an unsigned short (which is true on i386, but false on alpha). -if [ -f /usr/include/asm/posix_types.h ]; then - echo '#include ' >> loop.h +if [ -f /usr/include/linux/posix_types.h ]; then + echo '#include ' >> loop.h echo '#define dev_t __kernel_dev_t' >> loop.h else echo '#define dev_t unsigned short' >> loop.h diff --git a/mount/mntent.c b/mount/mntent.c new file mode 100644 index 000000000..0be20e8ca --- /dev/null +++ b/mount/mntent.c @@ -0,0 +1,214 @@ +/* Private version of the libc *mntent() routines. */ +/* Note slightly different prototypes. */ + +#include +#include /* for index */ +#include /* for isdigit */ +#include "mntent.h" +#include "sundries.h" /* for xmalloc */ + +/* Unfortunately the classical Unix /etc/mtab and /etc/fstab + do not handle directory names containing spaces. + Here we mangle them, replacing a space by \040. + What do other Unices do? */ + +static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' }; + +static char * +mangle(unsigned char *s) { + char *ss, *sp; + int n; + + n = strlen(s); + ss = sp = xmalloc(4*n+1); + while(1) { + for (n = 0; n < sizeof(need_escaping); n++) { + if (*s == need_escaping[n]) { + *sp++ = '\\'; + *sp++ = '0' + ((*s & 0300) >> 6); + *sp++ = '0' + ((*s & 070) >> 3); + *sp++ = '0' + (*s & 07); + goto next; + } + } + *sp++ = *s; + if (*s == 0) + break; + next: + s++; + } + return ss; +} + +static int +is_space_or_tab (char c) { + return (c == ' ' || c == '\t'); +} + +static char * +skip_spaces(char *s) { + while (is_space_or_tab(*s)) + s++; + return s; +} + +static char * +skip_nonspaces(char *s) { + while (*s && !is_space_or_tab(*s)) + s++; + return s; +} + +#define isoctal(a) (((a) & ~7) == '0') + +/* returns malloced pointer - no more strdup required */ +static char * +unmangle(char *s) { + char *ret, *ss, *sp; + + ss = skip_nonspaces(s); + ret = sp = xmalloc(ss-s+1); + while(s != ss) { + if (*s == '\\' && isoctal(s[1]) && isoctal(s[2]) && isoctal(s[3])) { + *sp++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7); + s += 4; + } else + *sp++ = *s++; + } + *sp = 0; + return ret; +} + +/* + * fstat'ing the file and allocating a buffer holding all of it + * may be a bad idea: if the file is /proc/mounttab, the stat + * returns 0. + * (On the other hand, mangling and unmangling is meaningless + * for /proc/mounttab.) + */ + +mntFILE * +my_setmntent (const char *file, char *mode) { + mntFILE *mfp = xmalloc(sizeof(*mfp)); + + mfp->mntent_fp = fopen (file, mode); + mfp->mntent_file = xstrdup(file); + mfp->mntent_errs = (mfp->mntent_fp == NULL); + mfp->mntent_softerrs = 0; + mfp->mntent_lineno = 0; + return mfp; +} + +void +my_endmntent (mntFILE *mfp) { + if (mfp) { + if (mfp->mntent_fp) + fclose(mfp->mntent_fp); + if (mfp->mntent_file) + free(mfp->mntent_file); + free(mfp); + } +} + + +int +my_addmntent (mntFILE *mfp, struct mntent *mnt) { + char *m1, *m2, *m3, *m4; + int res; + + if (fseek (mfp->mntent_fp, 0, SEEK_END)) + return 1; /* failure */ + + m1 = mangle(mnt->mnt_fsname); + m2 = mangle(mnt->mnt_dir); + m3 = mangle(mnt->mnt_type); + m4 = mangle(mnt->mnt_opts); + + res = ((fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n", + m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno) + < 0) ? 1 : 0); + + free(m1); + free(m2); + free(m3); + free(m4); + return res; +} + +/* Read the next entry from the file fp. Stop reading at an incorrect entry. */ +struct mntent * +my_getmntent (mntFILE *mfp) { + static char buf[4096]; + static struct mntent me; + char *s; + + again: + if (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) + return NULL; + + /* read the next non-blank non-comment line */ + do { + if (fgets (buf, sizeof(buf), mfp->mntent_fp) == NULL) + return NULL; + + mfp->mntent_lineno++; + s = index (buf, '\n'); + if (s == NULL) { + /* Missing final newline? Otherwise extremely */ + /* long line - assume file was corrupted */ + if (feof(mfp->mntent_fp)) { + fprintf(stderr, "[mntent]: warning: no final " + "newline at the end of %s\n", + mfp->mntent_file); + s = index (buf, 0); + } else { + mfp->mntent_errs = 1; + goto err; + } + } + *s = 0; + s = skip_spaces(buf); + } while (*s == '\0' || *s == '#'); + + me.mnt_fsname = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_dir = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_type = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_opts = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + + if(isdigit(*s)) { + me.mnt_freq = atoi(s); + while(isdigit(*s)) s++; + } else + me.mnt_freq = 0; + if(*s && !is_space_or_tab(*s)) + goto err; + + s = skip_spaces(s); + if(isdigit(*s)) { + me.mnt_passno = atoi(s); + while(isdigit(*s)) s++; + } else + me.mnt_passno = 0; + if(*s && !is_space_or_tab(*s)) + goto err; + + /* allow more stuff, e.g. comments, on this line */ + + return &me; + + err: + mfp->mntent_softerrs++; + fprintf(stderr, "[mntent]: line %d in %s is bad%s\n", + mfp->mntent_lineno, mfp->mntent_file, + (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) ? + "; rest of file ignored" : ""); + goto again; +} diff --git a/mount/mntent.h b/mount/mntent.h new file mode 100644 index 000000000..9b46ba08d --- /dev/null +++ b/mount/mntent.h @@ -0,0 +1,16 @@ +#include /* for struct mntent */ + +#define ERR_MAX 5 + +typedef struct mntFILEstruct { + FILE *mntent_fp; + char *mntent_file; + int mntent_lineno; + int mntent_errs; + int mntent_softerrs; +} mntFILE; + +mntFILE *my_setmntent (const char *file, char *mode); +void my_endmntent (mntFILE *mfp); +int my_addmntent (mntFILE *mfp, struct mntent *mnt); +struct mntent *my_getmntent (mntFILE *mfp); diff --git a/mount/mount.8 b/mount/mount.8 index 097dee005..633671b19 100644 --- a/mount/mount.8 +++ b/mount/mount.8 @@ -31,6 +31,8 @@ .\" 970114, aeb: xiafs and ext are dead; romfs is new .\" 970623, aeb: -F option .\" 970914, reg: -s option +.\" 981111, K.Garloff: /etc/filesystems +.\" 990111, aeb: documented /sbin/mount.smbfs .\" .TH MOUNT 8 "14 September 1997" "Linux 2.0" "Linux Programmer's Manual" .SH NAME @@ -111,6 +113,8 @@ but there are other possibilities. For example, in the case of an NFS mount, .I device may look like .IR knuth.cwi.nl:/dir . +It is possible to indicate a block special device using its +volume label or UUID (see the \-L and \-U options below). The file .I /etc/fstab @@ -163,6 +167,14 @@ or .RE For more details, see .BR fstab (5). +Only the user that mounted a filesystem can unmount it again. +If any user should be able to unmount, then use +.B users +instead of +.B user +in the +.I fstab +line. The programs .B mount @@ -265,16 +277,46 @@ Mount the file system read-only. A synonym is Mount the file system read/write. This is the default. A synonym is .BR "\-o rw" . .TP +.BI \-L " label" +Mount the partition that has the specified +.IR label . +.TP +.BI \-U " uuid" +Mount the partition that has the specified +.IR uuid . +These two options require the file +.I /proc/partitions +(present since Linux 2.1.116) to exist. +.TP .BI \-t " vfstype" The argument following the .B \-t is used to indicate the file system type. The file system types which are currently supported are listed in .IR linux/fs/filesystems.c : -.IR minix ", " ext ", " ext2 ", " xiafs ", " hpfs , -.IR msdos ", " umsdos ", " vfat , -.IR proc ", " nfs ", " iso9660 ", " smbfs ", " ncpfs , -.IR affs ", " ufs ", " romfs , +.IR minix , +.IR xiafs , +.IR ext , +.IR ext2 , +.IR msdos , +.IR umsdos , +.IR vfat , +.IR proc , +.IR autofs , +.IR devpts , +.IR nfs , +.IR iso9660 , +.IR smbfs , +.IR ncpfs , +.IR adfs , +.IR affs , +.IR coda , +.IR hfs , +.IR hpfs , +.IR ntfs , +.IR qnx4 , +.IR romfs , +.IR ufs , .IR sysv ", " xenix ", " coherent . Note that the last three are equivalent and that .I xenix @@ -288,6 +330,23 @@ and .I xiafs do not exist anymore. +For most types all the +.B mount +program has to do is issue a simple +.IR mount (2) +system call, and no detailed knowledge of the filesystem type is required. +For a few types however (like nfs, smbfs, ncpfs) ad hoc code is +necessary. The nfs ad hoc code is built in, but smbfs and ncpfs +have a separate mount program. In order to make it possible to +treat all types in a uniform way, mount will execute the program +.I /sbin/mount.TYPE +(if that exists) when called with type smb or ncp. +Since various versions of the +.I smbmount +program have different calling conventions, +.I /sbin/mount.smb +may have to be a shell script that sets up the desired call. + The type .I iso9660 is the default. If no @@ -297,9 +356,11 @@ option is given, or if the type is specified, the superblock is probed for the filesystem type .RI ( minix ", " ext ", " ext2 ", " xiafs ", " iso9660 ", " romfs are supported). -If this probe fails and -.I /proc/filesystems -exists, then all of the filesystems listed there will be tried, +If this probe fails, mount will try to read the file +.IR /etc/filesystems , +or, if that does not exist, +.IR /proc/filesystems . +All of the filesystem types listed there will be tried, except for those that are labeled "nodev" (e.g., .I proc and @@ -308,6 +369,10 @@ and Note that the .B auto type may be useful for user-mounted floppies. +Creating a file +.I /etc/filesystems +can be useful to change the probe order (e.g., to try vfat before msdos) +or if you use a kernel module autoloader. Warning: the probing uses a heuristic (the presence of appropriate `magic'), and could recognize the wrong filesystem type. @@ -381,7 +446,8 @@ binaries for architectures other than its own. .TP .B nosuid Do not allow set-user-identifier or set-group-identifier bits to take -effect. +effect. (This seems safe, but is in fact rather unsafe if you have +suidperl(1) installed.) .TP .B nouser Forbid an ordinary (i.e., non-root) user to mount the file system. @@ -1000,4 +1066,4 @@ for the .SH HISTORY A .B mount -command appeared in Version 6 AT&T UNIX. +command existed in Version 5 AT&T UNIX. diff --git a/mount/mount.c b/mount/mount.c index 19c507640..5ee247daa 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -2,12 +2,6 @@ * A mount(8) for Linux 0.99. * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp * - * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam - * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used - * if no -t option is given. I modified his patches so that, if - * /proc/filesystems is not available, the behavior of mount is the same as - * it was previously. - * * Wed Sep 14 22:43:00 1994: Mitchum DSouza * (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting * the "loop" device. @@ -15,21 +9,22 @@ * Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl) * added support for remounting readonly file systems readonly. * - * Wed Feb 8 09:23:18 1995: Mike Grupenhoff added - * a probe of the superblock for the type before /proc/filesystems is - * checked. - * * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages. * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied. * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes * Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes * - * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect - * * Since then, many changes - aeb. * * Wed Oct 1 23:55:28 1997: Dick Streefland * Implemented the "bg", "fg" and "retry" mount options for NFS. + * + * Tue Aug 4 15:54:31 1998: aeb@cwi.nl: + * Open fd 0,1,2 so that printf's do not clobber /etc/mtab or so. + * Mangle filenames with embedded spaces. Add ufsmagic. Add locking. + * Avoid unnecessary error messages about /proc. + * Improve support for noncanonical names in /etc/fstab. + * Add support for volume labels and UUIDs. */ #include @@ -47,22 +42,19 @@ #include "mount_constants.h" #include "sundries.h" +#include "mntent.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])) +#include "linux_fs.h" /* for BLKGETSIZE */ +#include "mount_guess_fstype.h" +#include "mount_by_label.h" +#include "getusername.h" #define DO_PS_FIDDLING #ifdef DO_PS_FIDDLING -#define PROC_NAME "mount: " -static int argc0; -static char** argv0; -static char** envp0; -extern char** environ; +#include "setproctitle.h" #endif /* True for fake mount (-f). */ @@ -105,14 +97,15 @@ struct opt_map /* We can use the high-order 16 bits, since the mount call has MS_MGC_VAL there. */ #define MS_NOAUTO 0x80000000 -#define MS_USER 0x40000000 +#define MS_USERS 0x40000000 +#define MS_USER 0x20000000 #define MS_LOOP 0x00010000 /* Options that we keep the mount system call from seeing. */ -#define MS_NOSYS (MS_NOAUTO|MS_USER|MS_LOOP) +#define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_LOOP) /* Options that we keep from appearing in the options field in the mtab. */ -#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USER) +#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER) /* OPTIONS that we make ordinary users have by default. */ #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV) @@ -132,6 +125,8 @@ const struct opt_map opt_map[] = { { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */ { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */ { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */ + { "users", 0, 0, MS_USERS }, /* Allow ordinary user to mount */ + { "nousers", 0, 1, MS_USERS }, /* Forbid ordinary user to mount */ { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */ { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */ /* add new options here */ @@ -159,7 +154,7 @@ const struct opt_map opt_map[] = { { NULL, 0, 0, 0 } }; -char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption; +static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption; struct string_opt_map { char *tag; @@ -233,13 +228,12 @@ parse_opt (const char *opt, int *mask, char *extra_opts) const struct opt_map *om; for (om = opt_map; om->opt != NULL; om++) - if (streq (opt, om->opt)) - { + if (streq (opt, om->opt)) { if (om->inv) *mask &= ~om->mask; else *mask |= om->mask; - if (om->mask == MS_USER) + if (om->mask == MS_USER || om->mask == MS_USERS) *mask |= MS_SECURE; #ifdef MS_SILENT if (om->mask == MS_SILENT && om->inv) { @@ -284,8 +278,7 @@ parse_opts (char *opts, int *flags, char **extra_opts) /* Try to build a canonical options string. */ static char * -fix_opts_string (int flags, char *extra_opts) -{ +fix_opts_string (int flags, const char *extra_opts, const char *user) { const struct opt_map *om; const struct string_opt_map *m; char *new_opts; @@ -306,167 +299,14 @@ fix_opts_string (int flags, char *extra_opts) if (extra_opts && *extra_opts) { new_opts = xstrconcat3(new_opts, ",", extra_opts); } + if (user) { + new_opts = xstrconcat3(new_opts, ",user=", user); + } return new_opts; } -/* Most file system types can be recognized by a `magic' number - in the superblock. Note that the order of the tests is - significant: by coincidence a filesystem can have the - magic numbers for several file system types simultaneously. - For example, the romfs magic lives in the 1st sector; - xiafs does not touch the 1st sector and has its magic in - the 2nd sector; ext2 does not touch the first two sectors. */ - -static inline unsigned short -swapped(unsigned short a) { - return (a>>8) | (a<<8); -} - -/* - char *fstype(const char *device); - - Probes the device and attempts to determine the type of filesystem - contained within. - - Original routine by ; made into a function - for mount(8) by Mike Grupenhoff . - Read the superblock only once - aeb - Added a test for iso9660 - aeb - Added a test for high sierra (iso9660) - quinlan@bucknell.edu - Corrected the test for xiafs - aeb - Added romfs - aeb - - Currently supports: minix, ext, ext2, xiafs, iso9660, romfs -*/ -char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs" }; - static int -tested(const char *device) { - char **m; - - for (m = magic_known; m - magic_known < SIZE(magic_known); m++) - if (!strcmp(*m, device)) - return 1; - return 0; -} - -static char * -fstype(const char *device) -{ - int fd; - char *type = NULL; - union { - struct minix_super_block ms; - struct ext_super_block es; - struct ext2_super_block e2s; - } sb; - union { - struct xiafs_super_block xiasb; - char romfs_magic[8]; - } xsb; - union { - struct iso_volume_descriptor iso; - struct hs_volume_descriptor hs; - } isosb; - struct stat statbuf; - - /* opening and reading an arbitrary unknown path can have - undesired side effects - first check that `device' refers - to a block device */ - if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode)) - return 0; - - fd = open(device, O_RDONLY); - if (fd < 0) - return 0; - - if (lseek(fd, 1024, SEEK_SET) != 1024 - || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) - goto io_error; - - 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 (minixmagic(sb.ms) == MINIX_SUPER_MAGIC - || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2) - type = "minix"; - - else if (extmagic(sb.es) == EXT_SUPER_MAGIC) - type = "ext"; - - if (!type) { - if (lseek(fd, 0, SEEK_SET) != 0 - || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) - goto io_error; - - if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) - type = "xiafs"; - else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) - type = "romfs"; - } - - if (!type) { - if (lseek(fd, 0x8000, SEEK_SET) != 0x8000 - || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb)) - goto io_error; - - if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0 - || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0) - type = "iso9660"; - } - - close (fd); - return(type); - -io_error: - perror(device); - close(fd); - return 0; -} - -FILE *procfs; - -static void -procclose(void) { - if (procfs) - fclose (procfs); - procfs = 0; -} - -static int -procopen(void) { - return ((procfs = fopen(PROC_FILESYSTEMS, "r")) != NULL); -} - -static char * -procnext(void) { - char line[100]; - static char fsname[50]; - - while (fgets(line, sizeof(line), procfs)) { - if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; - if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; - return fsname; - } - return 0; -} - -static int -is_in_proc(char *type) { - char *fsname; - - if (procopen()) { - while ((fsname = procnext()) != NULL) - if (!strcmp(fsname, type)) - return 1; - } - return 0; -} - -static int -already (char *spec, char *node) { +already (const char *spec, const char *node) { struct mntentchn *mc; int ret = 1; @@ -488,11 +328,12 @@ create_mtab (void) { struct mntent mnt; int flags; char *extra_opts; - FILE *fp; + mntFILE *mfp; lock_mtab(); - if ((fp = setmntent (MOUNTED, "a+")) == NULL) + mfp = my_setmntent (MOUNTED, "a+"); + if (mfp == NULL || mfp->mntent_fp == NULL) die (EX_FILEIO, "mount: can't open %s for writing: %s", MOUNTED, strerror (errno)); @@ -502,18 +343,18 @@ create_mtab (void) { mnt.mnt_dir = "/"; mnt.mnt_fsname = canonicalize (fstab->mnt_fsname); mnt.mnt_type = fstab->mnt_type; - mnt.mnt_opts = fix_opts_string (flags, extra_opts); + mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL); mnt.mnt_freq = mnt.mnt_passno = 0; - if (addmntent (fp, &mnt) == 1) + if (my_addmntent (mfp, &mnt) == 1) die (EX_FILEIO, "mount: error writing %s: %s", MOUNTED, strerror (errno)); } - if (fchmod (fileno (fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) + if (fchmod (fileno (mfp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) if (errno != EROFS) die (EX_FILEIO, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno)); - endmntent (fp); + my_endmntent (mfp); unlock_mtab(); } @@ -522,8 +363,9 @@ create_mtab (void) { static int mountcount = 0; static int -mount5 (char *special, char *dir, char *type, int flags, void *data) { - int ret = mount (special, dir, type, 0xC0ED0000 | (flags), data); +mount5 (struct mountargs *args) { + int ret = mount (args->spec, args->node, args->type, + MS_MGC_VAL | (args->flags), args->data); if (ret == 0) mountcount++; return ret; @@ -534,46 +376,20 @@ mount5 (char *special, char *dir, char *type, int flags, void *data) { static int try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { - char *fsname; + struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts }; if (*type && strcasecmp (*type, "auto") == 0) *type = NULL; - if (!*type && !(flags & MS_REMOUNT)) { - *type = fstype(spec); - if (verbose) { - printf ("mount: you didn't specify a filesystem type for %s\n", - spec); - if (*type) - printf (" I will try type %s\n", *type); - else - printf (" I will try all types mentioned in %s\n", - PROC_FILESYSTEMS); - } - } + if (!*type && !(flags & MS_REMOUNT)) + *type = guess_fstype_from_superblock(spec); - if (*type || (flags & MS_REMOUNT)) - return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts); - - if (!procopen()) - return -1; - while ((fsname = procnext()) != NULL) { - if (tested (fsname)) - continue; - if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) { - *type = xstrdup(fsname); - procclose(); - return 0; - } else if (errno != EINVAL) { - *type = "guess"; - procclose(); - return 1; - } + if (*type || (flags & MS_REMOUNT)) { + args.type = *type; + return mount5 (&args); } - procclose(); - *type = NULL; - return -1; + return procfsloop(mount5, &args, type); } /* @@ -584,9 +400,8 @@ try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) { * background. */ static int -try_mount_one (char *spec0, char *node0, char *type0, char *opts0, - int freq, int pass, int bg) -{ +try_mount_one (const char *spec0, const char *node0, char *type0, + const char *opts0, int freq, int pass, int bg) { struct mntentchn mcn; struct mntent mnt; int mnt_err; @@ -595,7 +410,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, char *mount_opts; /* actually used on system call */ static int added_ro = 0; int loop, looptype, offset; - char *spec, *node, *type, *opts, *loopdev, *loopfile; + const char *opts; + char *spec, *node, *type, *loopdev, *loopfile; + char *user = 0; struct stat statbuf; spec = xstrdup(spec0); @@ -606,11 +423,15 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, parse_opts (xstrdup (opts), &flags, &extra_opts); /* root may allow certain types of mounts by ordinary users */ - if (suid && !(flags & MS_USER)) { - if (already (spec, node)) - die (EX_USAGE, "mount failed"); - else - die (EX_USAGE, "mount: only root can mount %s on %s", spec, node); + if (suid) { + if (!(flags & (MS_USER | MS_USERS))) { + if (already (spec, node)) + die (EX_USAGE, "mount failed"); + else + die (EX_USAGE, "mount: only root can mount %s on %s", spec, node); + } + if (flags & MS_USER) + user = getusername(); } /* quietly succeed for fstab entries that don't get mounted automatically */ @@ -661,8 +482,13 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, if (verbose) printf("mount: going to use the loop device %s\n", loopdev); offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0; - if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro)) + if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro)) { + if (verbose) + printf("mount: failed setting up loop device\n"); return EX_FAIL; + } + if (verbose > 1) + printf("mount: setup loop device successfully\n"); spec = loopdev; if (loopro) flags |= MS_RDONLY; @@ -686,7 +512,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, */ if (type) #ifndef ALWAYS_STAT - if (streq (type, "smb") || streq (type, "ncp")) + if (streq (type, "smb") || streq (type, "ncp") + /* || streq (type, "smbfs") || streq (type, "ncpfs") */ + ) #else if (strlen (type) < 100) #endif @@ -701,7 +529,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, setuid(getuid()); setgid(getgid()); - oo = fix_opts_string (flags, extra_opts); + oo = fix_opts_string (flags, extra_opts, NULL); mountargs[i++] = mountprog; mountargs[i++] = spec; mountargs[i++] = node; @@ -721,7 +549,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, wait(&status); return status; } else - error("cannot fork: %s", strerror(errno)); + error("mount: cannot fork: %s", strerror(errno)); } } @@ -737,7 +565,8 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, mcn.mnt_fsname = mnt.mnt_fsname = canonicalize (loop ? loopfile : spec); mcn.mnt_dir = mnt.mnt_dir = canonicalize (node); mcn.mnt_type = mnt.mnt_type = type ? type : "unknown"; - mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, extra_opts); + mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, + extra_opts, user); mcn.nxt = 0; mnt.mnt_freq = freq; mnt.mnt_passno = pass; @@ -751,16 +580,20 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, if (flags & MS_REMOUNT) update_mtab (mnt.mnt_dir, &mnt); else { - FILE *fp = setmntent(MOUNTED, "a+"); - if (fp == NULL) + mntFILE *mfp; + + lock_mtab(); + mfp = my_setmntent(MOUNTED, "a+"); + if (mfp == NULL || mfp->mntent_fp == NULL) { error("mount: can't open %s: %s", MOUNTED, strerror (errno)); - else { - if ((addmntent (fp, &mnt)) == 1) + } else { + if ((my_addmntent (mfp, &mnt)) == 1) error("mount: error writing %s: %s", MOUNTED, strerror (errno)); - endmntent(fp); + my_endmntent(mfp); } + unlock_mtab(); } } @@ -794,6 +627,12 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, case EBUSY: if (flags & MS_REMOUNT) { error ("mount: %s is busy", node); + } else if (!strcmp(type, "proc") && !strcmp(node, "/proc")) { + /* heuristic: if /proc/version exists, then probably proc is mounted */ + if (stat ("/proc/version", &statbuf)) /* proc mounted? */ + error ("mount: %s is busy", node); /* no */ + else if(!all || verbose) /* yes, don't mention it */ + error ("mount: proc already mounted"); } else { error ("mount: %s already mounted or %s busy", spec, node); already (spec, node); @@ -826,7 +665,7 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, spec); if (stat (spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode) - && (fd = open(spec, O_RDONLY)) >= 0) { + && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 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?)"); @@ -840,9 +679,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, case EIO: error ("mount: %s: can't read superblock", spec); break; case ENODEV: - if (is_in_proc(type) || !strcmp(type, "guess")) + if (is_in_procfs(type) || !strcmp(type, "guess")) error("mount: %s has wrong major or minor number", spec); - else if (procfs) { + else if (have_procfs()) { char *lowtype, *p; int u; @@ -857,9 +696,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, u++; } } - if (u && is_in_proc(lowtype)) + if (u && is_in_procfs(lowtype)) error ("mount: probably you meant %s", lowtype); - else if (!strncmp(lowtype, "iso", 3) && is_in_proc("iso9660")) + else if (!strncmp(lowtype, "iso", 3) && is_in_procfs("iso9660")) error ("mount: maybe you meant iso9660 ?"); free(lowtype); } else @@ -893,8 +732,9 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, type = type0; } if (opts) { - opts = realloc(xstrdup(opts), strlen(opts)+4); - strcat(opts, ",ro"); + char *opts1 = realloc(xstrdup(opts), strlen(opts)+4); + strcat(opts1, ",ro"); + opts = opts1; } else opts = "ro"; if (type && !strcmp(type, "guess")) @@ -916,42 +756,56 @@ try_mount_one (char *spec0, char *node0, char *type0, char *opts0, * identified in a "ps" listing. */ static void -set_proc_name (char *spec) +set_proc_name (const 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; - } + setproctitle ("mount", spec); #endif } +static char * +subst_string(const char *s, const char *sub, int sublen, const char *repl) { + char *n; + + n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1); + strncpy (n, s, sub-s); + strcpy (n + (sub-s), repl); + strcat (n, sub+sublen); + return n; +} + +static const char * +usersubst(const char *opts) { + char *s, *w; + char id[40]; + + s = "uid=useruid"; + if (opts && (w = strstr(opts, s)) != NULL) { + sprintf(id, "uid=%d", getuid()); + opts = subst_string(opts, w, strlen(s), id); + } + s = "gid=usergid"; + if (opts && (w = strstr(opts, s)) != NULL) { + sprintf(id, "gid=%d", getgid()); + opts = subst_string(opts, w, strlen(s), id); + } + return opts; +} + + +/* + * Return 0 for success (either mounted sth or -a and NOAUTO was given) + */ static int -mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts, - int freq, int pass) -{ +mount_one (const char *spec, const char *node, char *type, const char *opts, + char *cmdlineopts, int freq, int pass) { int status; int status2; + int specset = 0; + char *nspec; + + /* Substitute values in opts, if required */ + opts = usersubst(opts); /* Merge the fstab and command line options. */ if (opts == NULL) @@ -959,6 +813,26 @@ mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts, else if (cmdlineopts != NULL) opts = xstrconcat3(opts, ",", cmdlineopts); + if (!strncmp(spec, "UUID=", 5)) { + nspec = get_spec_by_uuid(spec+5); + specset = 1; + } else if (!strncmp(spec, "LABEL=", 6)) { + nspec = get_spec_by_volume_label(spec+6); + specset = 2; + } else + nspec = 0; /* just for gcc */ + + if (specset) { + if (nspec) { + spec = nspec; + if (verbose) + printf("mount: consider mounting %s by %s\n", spec, + (specset==1) ? "UUID" : "label"); + } else if(!all) + die (EX_USAGE, "mount: no such partition found"); + /* if -a then we may be rescued by a noauto option */ + } + if (type == NULL) { if (strchr (spec, ':') != NULL) { type = "nfs"; @@ -1146,10 +1020,11 @@ static struct option longopts[] = }; const char *usage_string = "\ -usage: mount [-hV]\n\ +Usage: mount [-hV]\n\ mount -a [-nfFrsvw] [-t vfstypes]\n\ mount [-nfrsvw] [-o options] special | node\n\ mount [-nfrsvw] [-t vfstype] [-o options] special node\n\ +A special device can be indicated by -L label or -U uuid . "; static void @@ -1162,18 +1037,26 @@ usage (FILE *fp, int n) int main (int argc, char *argv[]) { - int c, result = 0; - char *options = NULL, *spec; + int c, result = 0, specseen; + char *options = NULL, *spec, *node; + char *volumelabel = NULL; + char *uuid = NULL; string_list types = NULL; struct mntentchn *mc; + int fd; + + /* People report that a mount called from init without console + writes error messages to /etc/mtab + Let us try to avoid getting fd's 0,1,2 */ + while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ; + if (fd > 2) + close(fd); #ifdef DO_PS_FIDDLING - argc0 = argc; - argv0 = argv; - envp0 = environ; + initproctitle(argc, argv); #endif - while ((c = getopt_long (argc, argv, "afFhno:rsvVwt:", longopts, NULL)) + while ((c = getopt_long (argc, argv, "afFhL:no:rsU:vVwt:", longopts, NULL)) != EOF) switch (c) { case 'a': /* mount everything in fstab */ @@ -1188,6 +1071,9 @@ main (int argc, char *argv[]) { case 'h': /* help */ usage (stdout, 0); break; + case 'L': + volumelabel = optarg; + break; case 'n': /* mount without writing in /etc/mtab */ ++nomtab; break; @@ -1207,6 +1093,9 @@ main (int argc, char *argv[]) { case 't': /* specify file system types */ types = parse_list (optarg); break; + case 'U': + uuid = optarg; + break; case 'v': /* be chatty - very chatty if repeated */ ++verbose; break; @@ -1227,7 +1116,9 @@ main (int argc, char *argv[]) { argc -= optind; argv += optind; - if (argc == 0 && !all) { + specseen = (uuid || volumelabel) ? 1 : 0; /* yes, .. i know */ + + if (argc+specseen == 0 && !all) { if (options) usage (stderr, EX_USAGE); return print_all (types); @@ -1235,7 +1126,8 @@ main (int argc, char *argv[]) { if (getuid () != geteuid ()) { suid = 1; - if (types || options || readwrite || nomtab || all || fake || argc != 1) + if (types || options || readwrite || nomtab || all || fake || + (argc + specseen) != 1) die (EX_USAGE, "mount: only root can do that"); } @@ -1245,7 +1137,19 @@ main (int argc, char *argv[]) { create_mtab (); } - switch (argc) { + if (specseen) { + if (uuid) + spec = get_spec_by_uuid(uuid); + else + spec = get_spec_by_volume_label(volumelabel); + if (!spec) + die (EX_USAGE, "mount: no such partition found"); + if (verbose) + printf("mount: mounting %s\n", spec); + } else + spec = NULL; /* just for gcc */ + + switch (argc+specseen) { case 0: /* mount -a */ result = mount_all (types, options); @@ -1257,13 +1161,32 @@ main (int argc, char *argv[]) { /* mount [-nfrvw] [-o options] special | node */ if (types != NULL) usage (stderr, EX_USAGE); - - /* Try to find the other pathname in fstab. */ - spec = canonicalize (*argv); - if ((mc = getmntfile (spec)) == NULL && - (mc = getfsspec (spec)) == NULL && (mc = getfsfile (spec)) == NULL) - die (EX_USAGE, "mount: can't find %s in %s or %s", - spec, MOUNTED, _PATH_FSTAB); + if (specseen) { + /* We know the device. Where shall we mount it? */ + mc = (uuid ? getfsuuidspec (uuid) : getfsvolspec (volumelabel)); + if (mc == NULL) + mc = getfsspec (spec); + if (mc == NULL) + die (EX_USAGE, "mount: cannot find %s in %s", + spec, _PATH_FSTAB); + mc->mnt_fsname = spec; + } else { + /* Try to find the other pathname in fstab. */ + spec = canonicalize (*argv); + if ((mc = getfsspec (spec)) == NULL && + (mc = getfsfile (spec)) == NULL && + /* Try noncanonical name in fstab + perhaps /dev/cdrom or /dos is a symlink */ + (mc = getfsspec (*argv)) == NULL && + (mc = getfsfile (*argv)) == NULL && + /* Try mtab - maybe this was a remount */ + (mc = getmntfile (spec)) == NULL) + die (EX_USAGE, "mount: can't find %s in %s or %s", + spec, _PATH_FSTAB, MOUNTED); + /* Earlier mtab was tried first, but this would + sometimes try the wrong mount in case mtab had + the root device entry wrong. */ + } result = mount_one (xstrdup (mc->mnt_fsname), xstrdup (mc->mnt_dir), xstrdup (mc->mnt_type), mc->mnt_opts, options, 0, 0); @@ -1271,12 +1194,17 @@ main (int argc, char *argv[]) { case 2: /* mount [-nfrvw] [-t vfstype] [-o options] special node */ + if (specseen) { + /* we have spec already */ + node = argv[0]; + } else { + spec = argv[0]; + node = argv[1]; + } if (types == NULL) - result = mount_one (argv[0], argv[1], - NULL, NULL, options, 0, 0); + result = mount_one (spec, node, NULL, NULL, options, 0, 0); else if (cdr (types) == NULL) - result = mount_one (argv[0], argv[1], - car (types), NULL, options, 0, 0); + result = mount_one (spec, node, car (types), NULL, options, 0, 0); else usage (stderr, EX_USAGE); break; diff --git a/mount/mount_by_label.c b/mount/mount_by_label.c new file mode 100644 index 000000000..a48c9de19 --- /dev/null +++ b/mount/mount_by_label.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include "sundries.h" /* for xstrdup */ +#include "linux_fs.h" +#include "mount_by_label.h" + +#define PROC_PARTITIONS "/proc/partitions" +#define DEVLABELDIR "/dev" + +static FILE *procpt; + +static void +procptclose(void) { + if (procpt) + fclose (procpt); + procpt = 0; +} + +static int +procptopen(void) { + return ((procpt = fopen(PROC_PARTITIONS, "r")) != NULL); +} + +static char * +procptnext(void) { + char line[100]; + char *s; + int ma, mi, sz; + static char ptname[100]; + + while (fgets(line, sizeof(line), procpt)) { + if (sscanf (line, " %d %d %d %[^\n]\n", &ma, &mi, &sz, ptname) != 4) + continue; + + /* skip extended partitions (heuristic: size 1) */ + if (sz == 1) + continue; + + /* skip entire disk (minor 0, 64, ... on ide; 0, 16, ... on sd) */ + /* heuristic: partition name ends in a digit */ + for(s = ptname; *s; s++); + if (isdigit(s[-1])) + return ptname; + } + return 0; +} + +#define UUID 1 +#define VOL 2 + +/* for now, only ext2 is supported */ +static int +has_right_label(const char *device, int n, const char *label) { + + /* start with a test for ext2, taken from mount_guess_fstype */ + /* should merge these later */ + int fd; + char *s; + struct ext2_super_block e2sb; + + fd = open(device, O_RDONLY); + if (fd < 0) + return 0; + + if (lseek(fd, 1024, SEEK_SET) != 1024 + || read(fd, (char *) &e2sb, sizeof(e2sb)) != sizeof(e2sb) + || (ext2magic(e2sb) != EXT2_SUPER_MAGIC)) { + close(fd); + return 0; + } + + close(fd); + + /* superblock is ext2 - now what is its label? */ + s = ((n == UUID) ? e2sb.s_uuid : e2sb.s_volume_name); + return (strncmp(s, label, 16) == 0); +} + +static char * +get_spec_by_x(int n, const char *t) { + char *pt; + char device[110]; + + if(!procptopen()) + return NULL; + while((pt = procptnext()) != NULL) { + /* Note: this is a heuristic only - there is no reason + why these devices should live in /dev. + Perhaps this directory should be specifiable by option. + One might for example have /devlabel with links to /dev + for the devices that may be accessed in this way. + (This is useful, if the cdrom on /dev/hdc must not + be accessed.) + */ + sprintf(device, "%s/%s", DEVLABELDIR, pt); + if (has_right_label(device, n, t)) { + procptclose(); + return xstrdup(device); + } + } + procptclose(); + return NULL; +} + +static u_char +fromhex(char c) { + if (isdigit(c)) + return (c - '0'); + else if (islower(c)) + return (c - 'a' + 10); + else + return (c - 'A' + 10); +} + +char * +get_spec_by_uuid(const char *s) { + u_char uuid[16]; + int i; + + if (strlen(s) != 36 || + s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') + goto bad_uuid; + for (i=0; i<16; i++) { + if (*s == '-') s++; + if (!isxdigit(s[0]) || !isxdigit(s[1])) + goto bad_uuid; + uuid[i] = ((fromhex(s[0])<<4) | fromhex(s[1])); + s += 2; + } + return get_spec_by_x(UUID, uuid); + + bad_uuid: + die(EX_USAGE, "mount: bad UUID"); +} + +char * +get_spec_by_volume_label(const char *s) { + return get_spec_by_x(VOL, s); +} + diff --git a/mount/mount_by_label.h b/mount/mount_by_label.h new file mode 100644 index 000000000..21c2d844b --- /dev/null +++ b/mount/mount_by_label.h @@ -0,0 +1,2 @@ +char *get_spec_by_uuid(const char *uuid); +char *get_spec_by_volume_label(const char *volumelabel); diff --git a/mount/mount_constants.h b/mount/mount_constants.h index 5f033452d..aeb7edfb3 100644 --- a/mount/mount_constants.h +++ b/mount/mount_constants.h @@ -1,16 +1,36 @@ +#ifndef MS_RDONLY #define MS_RDONLY 1 /* Mount read-only */ +#endif +#ifndef MS_NOSUID #define MS_NOSUID 2 /* Ignore suid and sgid bits */ +#endif +#ifndef MS_NODEV #define MS_NODEV 4 /* Disallow access to device special files */ +#endif +#ifndef MS_NOEXEC #define MS_NOEXEC 8 /* Disallow program execution */ +#endif +#ifndef MS_SYNCHRONOUS #define MS_SYNCHRONOUS 16 /* Writes are synced at once */ +#endif +#ifndef MS_REMOUNT #define MS_REMOUNT 32 /* Alter flags of a mounted FS */ +#endif +#ifndef MS_MANDLOCK #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ +#endif +#ifndef MS_NOATIME #define MS_NOATIME 1024 /* Do not update access times. */ +#endif +#ifndef MS_NODIRATIME #define MS_NODIRATIME 2048 /* Do not update directory access times */ +#endif /* * 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 +#ifndef MS_MGC_MSK #define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ +#endif diff --git a/mount/mount_guess_fstype.c b/mount/mount_guess_fstype.c new file mode 100644 index 000000000..b6b9e6582 --- /dev/null +++ b/mount/mount_guess_fstype.c @@ -0,0 +1,252 @@ +/* + * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam + * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used + * if no -t option is given. I modified his patches so that, if + * /proc/filesystems is not available, the behavior of mount is the same as + * it was previously. + * + * Wed Feb 8 09:23:18 1995: Mike Grupenhoff added + * a probe of the superblock for the type before /proc/filesystems is + * checked. + * + * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect + * + * Wed Nov 11 11:33:55 1998: K.Garloff@ping.de, try /etc/filesystems before + * /proc/filesystems + * + * aeb - many changes. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "linux_fs.h" +#include "mount_guess_fstype.h" +#include "sundries.h" /* for xstrdup */ + +#define ETC_FILESYSTEMS "/etc/filesystems" +#define PROC_FILESYSTEMS "/proc/filesystems" + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +/* Most file system types can be recognized by a `magic' number + in the superblock. Note that the order of the tests is + significant: by coincidence a filesystem can have the + magic numbers for several file system types simultaneously. + For example, the romfs magic lives in the 1st sector; + xiafs does not touch the 1st sector and has its magic in + the 2nd sector; ext2 does not touch the first two sectors. */ + +static inline unsigned short +swapped(unsigned short a) { + return (a>>8) | (a<<8); +} + +/* + char *guess_fstype_from_superblock(const char *device); + + Probes the device and attempts to determine the type of filesystem + contained within. + + Original routine by ; made into a function + for mount(8) by Mike Grupenhoff . + Read the superblock only once - aeb + Added a test for iso9660 - aeb + Added a test for high sierra (iso9660) - quinlan@bucknell.edu + Corrected the test for xiafs - aeb + Added romfs - aeb + Added ufs from a patch by jj. But maybe there are several types of ufs? + + Currently supports: minix, ext, ext2, xiafs, iso9660, romfs, ufs +*/ +static char +*magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs", + "ufs" }; + +static int +tested(const char *device) { + char **m; + + for (m = magic_known; m - magic_known < SIZE(magic_known); m++) + if (!strcmp(*m, device)) + return 1; + return 0; +} + +static char * +fstype(const char *device) { + int fd; + char *type = NULL; + union { + struct minix_super_block ms; + struct ext_super_block es; + struct ext2_super_block e2s; + } sb; + union { + struct xiafs_super_block xiasb; + char romfs_magic[8]; + } xsb; + struct ufs_super_block ufssb; + union { + struct iso_volume_descriptor iso; + struct hs_volume_descriptor hs; + } isosb; + struct stat statbuf; + + /* opening and reading an arbitrary unknown path can have + undesired side effects - first check that `device' refers + to a block device */ + if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode)) + return 0; + + fd = open(device, O_RDONLY); + if (fd < 0) + return 0; + + if (lseek(fd, 1024, SEEK_SET) != 1024 + || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) + goto io_error; + + 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 (minixmagic(sb.ms) == MINIX_SUPER_MAGIC + || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2) + type = "minix"; + + else if (extmagic(sb.es) == EXT_SUPER_MAGIC) + type = "ext"; + + if (!type) { + if (lseek(fd, 0, SEEK_SET) != 0 + || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) + goto io_error; + + if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) + type = "xiafs"; + else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) + type = "romfs"; + } + + if (!type) { + if (lseek(fd, 8192, SEEK_SET) != 8192 + || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb)) + goto io_error; + + if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */ + type = "ufs"; + } + + if (!type) { + if (lseek(fd, 0x8000, SEEK_SET) != 0x8000 + || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb)) + goto io_error; + + if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0 + || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0) + type = "iso9660"; + } + + close (fd); + return(type); + +io_error: + perror(device); + close(fd); + return 0; +} + +char * +guess_fstype_from_superblock(const char *spec) { + char *type = fstype(spec); + if (verbose) { + printf ("mount: you didn't specify a filesystem type for %s\n", + spec); + if (type) + printf (" I will try type %s\n", type); + else + printf (" I will try all types mentioned in %s or %s\n", + ETC_FILESYSTEMS, PROC_FILESYSTEMS); + } + return type; +} + +static FILE *procfs; + +static void +procfsclose(void) { + if (procfs) + fclose (procfs); + procfs = 0; +} + +static int +procfsopen(void) { + procfs = fopen(ETC_FILESYSTEMS, "r"); + if (!procfs) + procfs = fopen(PROC_FILESYSTEMS, "r"); + return (procfs != NULL); +} + +static char * +procfsnext(void) { + char line[100]; + static char fsname[50]; + + while (fgets(line, sizeof(line), procfs)) { + if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; + if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; + return fsname; + } + return 0; +} + +int +is_in_procfs(const char *type) { + char *fsname; + + if (procfsopen()) { + while ((fsname = procfsnext()) != NULL) + if (!strcmp(fsname, type)) + return 1; + } + return 0; +} + +int +procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args, + char **type) { + char *fsname; + + if (!procfsopen()) + return -1; + while ((fsname = procfsnext()) != NULL) { + if (tested (fsname)) + continue; + args->type = fsname; + if ((*mount_fn) (args) == 0) { + *type = xstrdup(fsname); + procfsclose(); + return 0; + } else if (errno != EINVAL) { + *type = "guess"; + procfsclose(); + return 1; + } + } + procfsclose(); + *type = NULL; + + return -1; +} + +int +have_procfs(void) { + return procfs != NULL; +} diff --git a/mount/mount_guess_fstype.h b/mount/mount_guess_fstype.h new file mode 100644 index 000000000..3663f74ca --- /dev/null +++ b/mount/mount_guess_fstype.h @@ -0,0 +1,15 @@ +struct mountargs { + const char *spec; + const char *node; + const char *type; + int flags; + void *data; +}; + +extern int verbose; + +char *guess_fstype_from_superblock(const char *device); +int procfsloop(int (*mount_fn)(struct mountargs *), struct mountargs *args, + char **type); +int is_in_procfs(const char *fstype); +int have_procfs(void); diff --git a/mount/nfsmount.c b/mount/nfsmount.c index fd9364669..dd55d75a5 100644 --- a/mount/nfsmount.c +++ b/mount/nfsmount.c @@ -151,10 +151,17 @@ int nfsmount(const char *spec, const char *node, int *flags, goto fail; } strcpy(hostdir, spec); - if ((s = (strchr(hostdir, ':')))) { + if ((s = strchr(hostdir, ':'))) { hostname = hostdir; dirname = s + 1; *s = '\0'; + /* Ignore all but first hostname in replicated mounts + until they can be fully supported. (mack@sgi.com) */ + if ((s = strchr(hostdir, ','))) { + *s = '\0'; + fprintf(stderr, "mount: warning: " + "multiple hostnames not supported\n"); + } } else { fprintf(stderr, "mount: " "directory to mount not in host:dir format\n"); @@ -272,17 +279,24 @@ int nfsmount(const char *spec, const char *node, int *flags, mountvers = val; else if (!strcmp(opt, "nfsprog")) nfsprog = val; - else if (!strcmp(opt, "nfsvers")) + else if (!strcmp(opt, "nfsvers") || + !strcmp(opt, "vers")) nfsvers = val; - else if (!strcmp(opt, "namlen")) { + else if (!strcmp(opt, "proto")) { + if (!strncmp(opteq+1, "tcp", 3)) + tcp = 1; + else if (!strncmp(opteq+1, "udp", 3)) + tcp = 0; + else + printf("Warning: Unrecognized proto= option.\n"); + } else if (!strcmp(opt, "namlen")) { #if NFS_MOUNT_VERSION >= 2 if (nfs_mount_version >= 2) data.namlen = val; else #endif printf("Warning: Option namlen is not supported.\n"); - } - else if (!strcmp(opt, "addr")) + } else if (!strcmp(opt, "addr")) /* ignore */; else { printf("unknown nfs mount parameter: " diff --git a/mount/nfsmount_xdr.c b/mount/nfsmount_xdr.c index 6f539c24f..91fbeec6a 100644 --- a/mount/nfsmount_xdr.c +++ b/mount/nfsmount_xdr.c @@ -3,6 +3,9 @@ * It was generated using rpcgen. */ +#include +#include + #include "nfsmount.h" /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for @@ -40,9 +43,7 @@ /* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ bool_t -xdr_fhandle(xdrs, objp) - XDR *xdrs; - fhandle objp; +xdr_fhandle(XDR *xdrs, fhandle objp) { register long *buf; @@ -54,9 +55,7 @@ xdr_fhandle(xdrs, objp) } bool_t -xdr_fhstatus(xdrs, objp) - XDR *xdrs; - fhstatus *objp; +xdr_fhstatus(XDR *xdrs, fhstatus *objp) { register long *buf; @@ -70,14 +69,14 @@ xdr_fhstatus(xdrs, objp) return (FALSE); } break; + default: + break; } return (TRUE); } bool_t -xdr_dirpath(xdrs, objp) - XDR *xdrs; - dirpath *objp; +xdr_dirpath(XDR *xdrs, dirpath *objp) { register long *buf; @@ -89,9 +88,7 @@ xdr_dirpath(xdrs, objp) } bool_t -xdr_name(xdrs, objp) - XDR *xdrs; - name *objp; +xdr_name(XDR *xdrs, name *objp) { register long *buf; @@ -103,9 +100,7 @@ xdr_name(xdrs, objp) } bool_t -xdr_mountlist(xdrs, objp) - XDR *xdrs; - mountlist *objp; +xdr_mountlist(XDR *xdrs, mountlist *objp) { register long *buf; @@ -117,9 +112,7 @@ xdr_mountlist(xdrs, objp) } bool_t -xdr_mountbody(xdrs, objp) - XDR *xdrs; - mountbody *objp; +xdr_mountbody(XDR *xdrs, mountbody *objp) { register long *buf; @@ -137,9 +130,7 @@ xdr_mountbody(xdrs, objp) } bool_t -xdr_groups(xdrs, objp) - XDR *xdrs; - groups *objp; +xdr_groups(XDR *xdrs, groups *objp) { register long *buf; @@ -151,9 +142,7 @@ xdr_groups(xdrs, objp) } bool_t -xdr_groupnode(xdrs, objp) - XDR *xdrs; - groupnode *objp; +xdr_groupnode(XDR *xdrs, groupnode *objp) { register long *buf; @@ -168,9 +157,7 @@ xdr_groupnode(xdrs, objp) } bool_t -xdr_exports(xdrs, objp) - XDR *xdrs; - exports *objp; +xdr_exports(XDR *xdrs, exports *objp) { register long *buf; @@ -182,9 +169,7 @@ xdr_exports(xdrs, objp) } bool_t -xdr_exportnode(xdrs, objp) - XDR *xdrs; - exportnode *objp; +xdr_exportnode(XDR *xdrs, exportnode *objp) { register long *buf; @@ -202,9 +187,7 @@ xdr_exportnode(xdrs, objp) } bool_t -xdr_ppathcnf(xdrs, objp) - XDR *xdrs; - ppathcnf *objp; +xdr_ppathcnf(XDR *xdrs, ppathcnf *objp) { register long *buf; diff --git a/mount/sundries.c b/mount/sundries.c index 4506924aa..d7ace1b2d 100644 --- a/mount/sundries.c +++ b/mount/sundries.c @@ -29,12 +29,12 @@ xmalloc (size_t size) { void *t; if (size == 0) - return NULL; + return NULL; t = malloc (size); if (t == NULL) - die (EX_SYSERR, "not enough memory"); - + die (EX_SYSERR, "not enough memory"); + return t; } @@ -43,12 +43,12 @@ xstrdup (const char *s) { char *t; if (s == NULL) - return NULL; - + return NULL; + t = strdup (s); if (t == NULL) - die (EX_SYSERR, "not enough memory"); + die (EX_SYSERR, "not enough memory"); return t; } diff --git a/mount/swap.configure b/mount/swap.configure index a557e1871..ebd67ced6 100644 --- a/mount/swap.configure +++ b/mount/swap.configure @@ -1,24 +1,36 @@ # Find out whether we can include # and whether libc thinks that swapon() has two arguments. -# Of course this will fail if exists but belongs -# to a libc that is not in use at present. + +# Prepare test CC=${CC-cc} compile="$CC -o conftest conftest.c >/dev/null 2>&1" rm -f conftest conftest.c swapargs.h + +# What include files shall we try? +# Unfortunately, recent versions of swap.h use PAGE_SIZE and hence need page.h +# It is used only in mkswap, not in swapon/swapoff, so we might just pick any +# random value (like #define PAGE_SIZE 4096) instead of including page.h. SWAPH= -if [ -f /usr/include/sys/swap.h ]; then SWAPH="#include "; fi -echo $SWAPH > conftest.c +PAGEH= +if [ -f /usr/include/sys/swap.h ]; then + SWAPH="#include " + if [ -f /usr/include/asm/page.h ]; then + PAGEH="#include " + fi +fi +echo $PAGEH > conftest.c +echo $SWAPH >> conftest.c echo '#include main(){ exit(0); swapon("/dev/null", 0); }' >> conftest.c eval $compile if test -s conftest && ./conftest 2>/dev/null; then echo "#define SWAPON_HAS_TWO_ARGS" > swapargs.h + echo $PAGEH >> swapargs.h echo $SWAPH >> swapargs.h else echo > swapargs.h echo " Your libc thinks that swapon has 1 arg only. -Define SWAPON_NEEDS_TWO_ARGS in swapon.c if you want to use priorities. " 1>&2 fi rm -f conftest conftest.c diff --git a/mount/swap_constants.h b/mount/swap_constants.h new file mode 100644 index 000000000..c7e8b4c7e --- /dev/null +++ b/mount/swap_constants.h @@ -0,0 +1,15 @@ +/* + * It is too painful to get these out of + * (which again requires etc). + * These exist since Linux 1.3.2. + */ + +#ifndef SWAP_FLAG_PREFER +#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ +#endif +#ifndef SWAP_FLAG_PRIO_MASK +#define SWAP_FLAG_PRIO_MASK 0x7fff +#endif +#ifndef SWAP_FLAG_PRIO_SHIFT +#define SWAP_FLAG_PRIO_SHIFT 0 +#endif diff --git a/mount/swapon.8 b/mount/swapon.8 index 0ebb450a8..74f61eea4 100644 --- a/mount/swapon.8 +++ b/mount/swapon.8 @@ -74,7 +74,10 @@ Provide help Display version .TP .B \-s -Display swap usage summary by device +Display swap usage summary by device. +This option is only available if +.I /proc/swaps +exists (probably not before kernel 2.1.25). .TP .B \-a All devices marked as ``sw'' swap devices in @@ -104,6 +107,10 @@ entries in when the .B \-a flag is given. +.SH NOTE +You should not use +.B swapon +on a file with holes. .SH SEE ALSO .BR swapon "(2), " swapoff "(2), " fstab "(5), " init "(8), " mkswap (8), .BR rc "(8), " mount (8) @@ -120,8 +127,3 @@ ascii filesystem description table The .B swapon command appeared in 4.0BSD. -.SH AUTHORS -See the Linux -.BR mount (8) -man page for a complete author list. Primary contributors include Doug -Quale, H. J. Lu, Rick Sladkey, and Stephen Tweedie. diff --git a/mount/swapon.c b/mount/swapon.c index 5fdd15c5d..41d1f3fce 100644 --- a/mount/swapon.c +++ b/mount/swapon.c @@ -10,7 +10,8 @@ #include #include #include -#include "swap.h" +#include +#include "swap_constants.h" #include "swapargs.h" #define streq(s, t) (strcmp ((s), (t)) == 0) @@ -18,7 +19,7 @@ #define _PATH_FSTAB "/etc/fstab" #define PROC_SWAPS "/proc/swaps" -/* #define SWAPON_NEEDS_TWO_ARGS */ +#define SWAPON_NEEDS_TWO_ARGS /* Nonzero for chatty (-v). This is a nonstandard flag (not in BSD). */ int verbose = 0; @@ -77,12 +78,34 @@ static int swap (const char *special, int prio) { int status; + struct stat st; if (verbose) - printf("%s on device %s\n", program_name, special); + printf("%s on %s\n", program_name, special); if (streq (program_name, "swapon")) { + if (stat(special, &st) < 0) { + fprintf (stderr, "swapon: cannot stat %s: %s\n", special, strerror (errno)); + return -1; + } + + if ((st.st_mode & 07077) != 0) { + fprintf(stderr, "swapon: warning: %s has insecure permissions %04o, " + "0600 suggested\n", special, st.st_mode & 07777); + } + + /* test for holes by LBT */ + if (S_ISREG(st.st_mode)) { + if (st.st_blocks * 512 < st.st_size) { + fprintf(stderr, + "swapon: Skipping file %s - it appears to have holes.\n", + special); + return -1; + } + } + #ifdef SWAPON_NEEDS_TWO_ARGS + { int flags = 0; #ifdef SWAP_FLAG_PREFER @@ -94,6 +117,7 @@ swap (const char *special, int prio) } #endif status = swapon (special, flags); + } #else status = swapon (special); #endif diff --git a/mount/umount.c b/mount/umount.c index 6f28213b4..ac233a70b 100644 --- a/mount/umount.c +++ b/mount/umount.c @@ -18,6 +18,10 @@ * 960823: aeb - also try umount(spec) when umount(node) fails * 970307: aeb - canonise names from fstab * 970726: aeb - remount read-only in cases where umount fails + * 980810: aeb - umount2 support + * 981222: aeb - If mount point or special file occurs several times + * in mtab, try them all, with last one tried first + * - Differentiate "user" and "users" key words in fstab */ #include @@ -28,6 +32,7 @@ #include #include "mount_constants.h" #include "sundries.h" +#include "getusername.h" #include "lomount.h" #include "loop.h" #include "fstab.h" @@ -43,11 +48,33 @@ #include #endif +static int umount2(const char *path, int flags); -#ifdef notyet -/* Nonzero for force umount (-f). This needs kernel support we don't have. */ +#ifdef MNT_FORCE +/* Interesting ... it seems libc knows about MNT_FORCE and presumably + about umount2 as well -- need not do anything */ +#else /* MNT_FORCE */ + +/* Does the present kernel source know about umount2? */ +#include +#ifdef __NR_umount2 +_syscall2(int, umount2, const char *, path, int, flags); +#else /* __NR_umount2 */ +static int +umount2(const char *path, int flags) { + fprintf(stderr, "umount: compiled without support for -f\n"); + errno = ENOSYS; + return -1; +} +#endif /* __NR_umount2 */ + +/* dare not try to include -- lots of errors */ +#define MNT_FORCE 1 + +#endif /* MNT_FORCE */ + +/* Nonzero for force umount (-f). There is kernel support since 2.1.116. */ int force = 0; -#endif /* When umount fails, attempt a read-only remount (-r). */ int remount = 0; @@ -169,7 +196,7 @@ static void complain(int err, const char *dev) { on a non-fatal error. We lock/unlock around each umount. */ static int umount_one (const char *spec, const char *node, const char *type, - const char *opts) + const char *opts, struct mntentchn *mc) { int umnt_err, umnt_err2; int isroot; @@ -195,7 +222,22 @@ umount_one (const char *spec, const char *node, const char *type, umnt_err = umnt_err2 = 0; - res = umount (node); + if (force) { + /* completely untested - 2.1.116 only has some support in nfs case */ + /* probably this won't work */ + int flags = MNT_FORCE; + + res = umount2 (node, flags); + if (res == -1) { + perror("umount2"); + if (errno == ENOSYS) { + if (verbose) + printf("no umount2, trying umount...\n"); + res = umount (node); + } + } + } else + res = umount (node); if (res < 0) { umnt_err = errno; /* A device might have been mounted on a node that has since @@ -238,11 +280,9 @@ umount_one (const char *spec, const char *node, const char *type, printf ("%s umounted\n", spec); if (!nomtab && mtab_is_writable()) { - struct mntentchn *mc; /* Special stuff for loop devices */ - - if ((mc = getmntfile (spec)) || (mc = getmntfile (node))) { - char *opts; + if (mc) { + char *optl; /* old style mtab line? */ if (streq(mc->mnt_type, "loop")) @@ -250,10 +290,10 @@ umount_one (const char *spec, const char *node, const char *type, goto fail; /* new style mtab line? */ - opts = mc->mnt_opts ? xstrdup(mc->mnt_opts) : ""; - for (opts = strtok (opts, ","); opts; opts = strtok (NULL, ",")) { - if (!strncmp(opts, "loop=", 5)) { - if (del_loop(opts+5)) + optl = mc->mnt_opts ? xstrdup(mc->mnt_opts) : ""; + for (optl = strtok (optl, ","); optl; optl = strtok (NULL, ",")) { + if (!strncmp(optl, "loop=", 5)) { + if (del_loop(optl+5)) goto fail; break; } @@ -286,6 +326,28 @@ fail: return 1; } +/* + * Why this loop? + * 1. People who boot a system with a bad fstab root entry + * will get an incorrect "/dev/foo on /" in mtab. + * If later /dev/foo is actually mounted elsewhere, + * it will occur twice in mtab. + * 2. With overmounting one can get the situation that + * the same filename is used as mount point twice. + * In both cases, it is best to try the last occurrence first. + */ +static int +umount_one_bw (const char *file, struct mntentchn *mc) { + int res = 1; + + while (res && mc) { + res = umount_one(mc->mnt_fsname, mc->mnt_dir, + mc->mnt_type, mc->mnt_opts, mc); + mc = getmntfilesbackward (file, mc); + } + return res; +} + /* Unmount all filesystems of type VFSTYPES found in mtab. Since we are concurrently updating mtab after every succesful umount, we have to slurp in the entire file before we start. This isn't too bad, because @@ -302,7 +364,7 @@ umount_all (string_list types) { for (mc = hd->prev; mc != hd; mc = mc->prev) { if (matching_type (mc->mnt_type, types)) { errors |= umount_one (mc->mnt_fsname, mc->mnt_dir, - mc->mnt_type, mc->mnt_opts); + mc->mnt_type, mc->mnt_opts, mc); } } @@ -325,9 +387,9 @@ static struct option longopts[] = }; char *usage_string = "\ -usage: umount [-hV]\n\ - umount -a [-r] [-n] [-v] [-t vfstypes]\n\ - umount [-r] [-n] [-v] special | node...\n\ +Usage: umount [-hV]\n\ + umount -a [-f] [-r] [-n] [-v] [-t vfstypes]\n\ + umount [-f] [-r] [-n] [-v] special | node...\n\ "; static void @@ -350,22 +412,19 @@ main (int argc, char *argv[]) char *file; int result = 0; - while ((c = getopt_long (argc, argv, "afhnrvVt:", longopts, NULL)) != EOF) + while ((c = getopt_long (argc, argv, "afhnrt:vV", + longopts, NULL)) != EOF) switch (c) { case 'a': /* umount everything */ ++all; break; - case 'f': /* force umount (needs kernel support) */ -#if 0 + case 'f': /* force umount */ ++force; -#else - die (2, "umount: forced umount not supported yet"); -#endif break; case 'h': /* help */ usage (stdout, 0); break; - case 'n': + case 'n': /* do not write in /etc/mtab */ ++nomtab; break; case 'r': /* remount read-only if umount fails */ @@ -390,7 +449,7 @@ main (int argc, char *argv[]) if (getuid () != geteuid ()) { suid = 1; - if (all || types || nomtab) + if (all || types || nomtab || force) die (2, "umount: only root can do that"); } @@ -408,13 +467,15 @@ main (int argc, char *argv[]) if (verbose > 1) printf("Trying to umount %s\n", file); - mc = getmntfile (file); + mc = getmntfilesbackward (file, NULL); if (!mc && verbose) printf("Could not find %s in mtab\n", file); if (suid) { if (!mc) die (2, "umount: %s is not mounted (according to mtab)", file); + if (getmntfilesbackward (file, mc)) + die (2, "umount: it seems %s is mounted multiple times", file); if (!(fs = getfsspec (file)) && !(fs = getfsfile (file))) die (2, "umount: %s is not in the fstab (and you are not root)", file); @@ -424,22 +485,46 @@ main (int argc, char *argv[]) !streq (mc->mnt_dir, canonicalize (fs->mnt_dir)))) { die (2, "umount: %s mount disagrees with the fstab", file); } + + /* User mounting and unmounting is allowed only + if fstab contains the option `user' or `users' */ + /* The option `users' allows arbitrary users to mount + and unmount - this may be a security risk. */ + /* The option `user' only allows unmounting by the user + that mounted. */ + /* A convenient side effect is that the user who mounted + is visible in mtab. */ options = parse_list (fs->mnt_opts); while (options) { - if (streq (car (options), "user")) + if (streq (car (options), "user") || + streq (car (options), "users")) break; options = cdr (options); } if (!options) die (2, "umount: only root can unmount %s from %s", fs->mnt_fsname, fs->mnt_dir); + if (streq (car (options), "user")) { + char *user = getusername(); + + options = parse_list (mc->mnt_opts); + while (options) { + char *co = car (options); + if (!strncmp(co, "user=", 5)) { + if (!user || !streq(co+5,user)) + die(2, "umount: only %s can unmount %s from %s", + co+5, fs->mnt_fsname, fs->mnt_dir); + break; + } + options = cdr (options); + } + } } if (mc) - result = umount_one (xstrdup(mc->mnt_fsname), xstrdup(mc->mnt_dir), - xstrdup(mc->mnt_type), xstrdup(mc->mnt_opts)); + result = umount_one_bw (file, mc); else - result = umount_one (*argv, *argv, *argv, *argv); + result = umount_one (*argv, *argv, *argv, *argv, NULL); argv++; diff --git a/mount/version.c b/mount/version.c index 0c9363d37..790c447bf 100644 --- a/mount/version.c +++ b/mount/version.c @@ -1 +1,2 @@ -char version[] = "mount-2.8"; +#include "../version.h" +char version[] = "mount-" UTIL_LINUX_VERSION; diff --git a/sys-utils/Makefile b/sys-utils/Makefile index 9085fa965..91aa32d1d 100644 --- a/sys-utils/Makefile +++ b/sys-utils/Makefile @@ -11,9 +11,9 @@ include ../MCONFIG MAN1= arch.1 readprofile.1 -MAN8= ctrlaltdel.8 cytune.8 dmesg.8 \ +MAN8= ctrlaltdel.8 cytune.8 dmesg.8 hwclock.8 \ ipcrm.8 ipcs.8 kbdrate.8 ramsize.8 renice.8 \ - rootflags.8 setsid.8 swapdev.8 tunelp.8 \ + rootflags.8 setsid.8 sln.8 swapdev.8 tunelp.8 \ vidmode.8 # Where to put binaries? @@ -23,15 +23,14 @@ BIN= arch dmesg USRBIN= cytune ipcrm ipcs renice readprofile setsid tunelp -SBIN= sln ctrlaltdel kbdrate +SBIN= ctrlaltdel hwclock kbdrate -ifneq "$(CPU)" "sparc" -MAN8:= $(MAN8) hwclock.8 -SBIN:=$(SBIN) hwclock +ifeq "$(HAVE_SLN)" "no" +SBIN:=$(SBIN) sln endif ifeq "$(CPU)" "intel" -MAN8:= $(MAN8) rdev.8 +MAN8:=$(MAN8) rdev.8 USRBIN:=$(USRBIN) rdev endif @@ -49,7 +48,8 @@ sln: sln.c arch: arch.o hwclock.o: hwclock.c shhopt.h hwclock: hwclock.o shhopt.o -ctrlaltdel: ctrlaltdel.o +ctrlaltdel.o: ctrlaltdel.c $(LIB)/linux_reboot.h +ctrlaltdel: ctrlaltdel.o $(LIB)/my_reboot.o ipcrm: ipcrm.o ipcs: ipcs.o kbdrate: kbdrate.o diff --git a/sys-utils/ctrlaltdel.c b/sys-utils/ctrlaltdel.c index e5565d704..c754fd058 100644 --- a/sys-utils/ctrlaltdel.c +++ b/sys-utils/ctrlaltdel.c @@ -7,24 +7,24 @@ #include #include #include - -int reboot(int magic, int magictoo, int flag); +#include "linux_reboot.h" int main(int argc, char *argv[]) { if(geteuid()) { - fprintf(stderr, "You must be root to set the Ctrl-Alt-Del behaviour.\n"); + fprintf(stderr, + "You must be root to set the Ctrl-Alt-Del behaviour.\n"); exit(1); } if(argc == 2 && !strcmp("hard", argv[1])) { - if(reboot(0xfee1dead, 672274793, 0x89abcdef) < 0) { + if(my_reboot(LINUX_REBOOT_CMD_CAD_ON) < 0) { perror("ctrlaltdel: reboot"); exit(1); } } else if(argc == 2 && !strcmp("soft", argv[1])) { - if(reboot(0xfee1dead, 672274793, 0) < 0) { + if(my_reboot(LINUX_REBOOT_CMD_CAD_OFF) < 0) { perror("ctrlaltdel: reboot"); exit(1); } diff --git a/sys-utils/hwclock.8 b/sys-utils/hwclock.8 index ec8b00762..58f4a259e 100644 --- a/sys-utils/hwclock.8 +++ b/sys-utils/hwclock.8 @@ -55,8 +55,17 @@ Set the Hardware Clock to the time given by the option. .TP .B \-\-hctosys -Set the System Time from the Hardware Clock. This is a good option to use -in one of the system startup scripts. +Set the System Time from the Hardware Clock. + +Also set the kernel's timezone value to the local timezone as indicated by +the TZ environment variable and/or /usr/lib/zoneinfo, as tzset(3) would +interpret them. EXCEPT: always set the Daylight Savings Time part of +the kernel's timezone value to 0 ("not Daylight Savings Time"). If DST +is indicated, just add an hour to the base part. + +See the discussion of timezones below. + +This is a good option to use in one of the system startup scripts. .TP .B \-\-systohc Set the Hardware Clock to the current System Time. @@ -118,11 +127,19 @@ Time. It is your choice whether to keep your clock in UTC or local time, but nothing in the clock tells which you've chosen. So this option is how you give that information to .I hwclock. -.PP -If you don't specify -.B --utc -when you should, or vice versa, both setting and querying of the -Hardware Clock will be messed up. + +In order to avoid any possible misunderstandings: all conversation +with the program +.I hwclock +is done in local time. If you have your clock in UTC +(as is common on a Unix system) then the option +.B --utc +tells +.I hwclock +to do the appropriate conversions: `hwclock \-\-show \-\-utc' +will tell you the local time, assuming the hardware clock is in UTC, +and `hwclock \-\-set \-\-date="XXX" \-\-utc' will set the +hardware clock to the UTC equivalent of the local time XXX. .TP .B \-\-directisa is meaningful only on an ISA machine. For all other machines, it has @@ -134,7 +151,7 @@ Without this option, 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 @@ -198,7 +215,42 @@ time Linux starts up, it will do so with the adjusted time from the Hardware Clock. You can also use the program .I adjtimex(8) to smoothly adjust the System Time while the system runs. - +.PP +A Linux kernel maintains a concept of a local timezone for the system. +But don't be misled -- almost nobody cares what timezone the kernel +thinks it is in. Instead, programs that care about the timezone +(perhaps because they want to display a local time for you) almost +always use a more traditional method of determining the timezone: They +use the TZ environment variable and/or the /usr/local/timezone +directory, as explained in the man page for tzset(3). However, some +programs and fringe parts of the Linux kernel such as filesystems use +the kernel timezone value. An example is the vfat filesystem. If the +kernel timezone value is wrong, the vfat filesystem will report and +set the wrong timestamps on files. +.PP +.I hwclock +sets the kernel timezone to the value indicated by TZ and/or +/usr/local/timezone when you set the System Time using the +.B \-\-hctosys +option. +.PP +A complication is that the timezone value actually consists of two +parts: 1) how far from the Standard Meridian the locality is +geographically, and 2) whether or not a Daylight Savings Time (DST) +convention is in effect in the locality at the present time. In +practice, the DST part of the timezone value is almost never used, so +if the geographical part were to be set to its correct value, the +users of the timezone value would actually compute the wrong local +time. +.PP +Therefore, +.I +hwclock +violates the definition of the kernel's timezone value and always sets +the DST part to zero. If DST is supposed to be in effect, +.I +hwclock +simply adds an hour to the geographical part. .SH How hwclock Accesses the Hardware Clock .PP @@ -302,7 +354,11 @@ Another 24 hours goes by and you issue another does the same thing: subtracts 2 seconds and updates the adjtime file with the current time as the last time the clock was adjusted. .PP -Every time you calibrate (set) the clock, +Every time you calibrate (set) the clock (using +.I --set +or +.I --systohc +), .I hwclock recalculates the systematic drift rate based on how long it has been since the last calibration, how long it has been since the last @@ -324,12 +380,12 @@ just before the at system startup time, and maybe periodically while the system is running via cron. .PP -The format of the adjtime file is: +The format of the adjtime file is, in ASCII: .PP -Line 1: 3 numbers: 1) systematic drift rate in seconds per day, -floating point decimal; 2) Resulting number of seconds since 1969 UTC -of most recent adjustment or calibration, decimal integer; 3) zero -(for compatibility with +Line 1: 3 numbers, separated by blanks: 1) systematic drift rate in +seconds per day, floating point decimal; 2) Resulting number of +seconds since 1969 UTC of most recent adjustment or calibration, +decimal integer; 3) zero (for compatibility with .I clock ). .PP @@ -341,11 +397,51 @@ You can use an adjtime file that was previously used with the program with .I hwclock. + +.SH Automatic Hardware Clock Synchronization By the Kernel + +You should be aware of another way that the Hardware Clock is kept +synchronized in some systems. The Linux kernel has a mode wherein it +copies the System Time to the Hardware Clock every 11 minutes. +This is a good mode to use when you are using something sophisticated +like ntp to keep your System Time synchronized. (ntp is a way to keep +your System Time synchronized either to a time server somewhere on the +network or to a radio clock hooked up to your system. See RFC 1305). + +This mode (we'll call it "11 minute mode") is off until something +turns it on. The ntp daemon xntpd is one thing that turns it on. You +can turn it off by running anything, including +.I hwclock --hctosys +, that sets the System Time the old fashioned way. + +To see if it is on or +off, use the command +.I adjtimex --print +and look at the value of "status". If the "64" bit of this number +(expressed in binary) equal to 0, 11 minute mode is on. Otherwise, it +is off. + +If your system runs with 11 minute mode on, don't use +.I hwclock --adjust +or +.I hwclock --hctosys . +You'll just make a mess. It is acceptable to use a +.I hwclock --hctosys +at startup time to get a reasonable System Time until your system is +able to set the System Time from the external source and start 11 +minute mode. + + +.SH ENVIRONMENT VARIABLES +.I TZ + .SH FILES .I /etc/adjtime +.I /usr/lib/zoneinfo/ .SH SEE ALSO -adjtimex(8), date(1), gettimeofday(2), settimeofday(2), crontab(1) +adjtimex(8), date(1), gettimeofday(2), settimeofday(2), crontab(1), +tzset(3) .SH AUTHORS Written By Bryan Henderson, September 1996 (bryanh@giraffe-data.com), @@ -353,5 +449,3 @@ based on work done on the .I clock program by Charles Hedrick, Rob Hooft, and Harald Koenig. See the source code for complete history and credits. - - diff --git a/sys-utils/hwclock.c b/sys-utils/hwclock.c index 643ccda5b..02302da29 100644 --- a/sys-utils/hwclock.c +++ b/sys-utils/hwclock.c @@ -106,12 +106,14 @@ #include #include #include -#include +#ifdef __i386__ +#include /* for inb, outb */ +#endif #include #include "../version.h" #define MYNAME "hwclock" -#define VERSION "2.2" +#define VERSION "2.4" #define FLOOR(arg) ((arg >= 0 ? (int) arg : ((int) arg) - 1)); @@ -190,7 +192,6 @@ bool interrupts_enabled; need to be turned back on. */ - #include /* Check if the /dev/rtc interface is available in this version of the system headers. 131072 is linux 2.0.0. Might need to make @@ -658,17 +659,27 @@ synchronize_to_clock_tick(enum clock_access_method clock_access, -static time_t -mktime_tz(struct tm tm, const bool universal) { +static void +mktime_tz(struct tm tm, const bool universal, + bool *valid_p, time_t *systime_p) { /*----------------------------------------------------------------------------- Convert a time in broken down format (hours, minutes, etc.) into standard - unix time (seconds into epoch). + unix time (seconds into epoch). Return it as *systime_p. The broken down time is argument . This broken down time is either in local time zone or UTC, depending on value of logical argument "universal". True means it is in UTC. + + If the argument contains values that do not constitute a valid time, + and mktime() recognizes this, return *valid_p == false and + *systime_p undefined. However, mktime() sometimes goes ahead and + computes a fictional time "as if" the input values were valid, + e.g. if they indicate the 31st day of April, mktime() may compute + the time of May 1. In such a case, we return the same fictional + value mktime() does as *systime_p and return *valid_p == true. + -----------------------------------------------------------------------------*/ - time_t systime; /* our eventual return value */ + time_t mktime_result; /* The value returned by our mktime() call */ char *zone; /* Local time zone name */ /* We use the C library function mktime(), but since it only works on @@ -686,23 +697,31 @@ mktime_tz(struct tm tm, const bool universal) { */ tzset(); } - systime = mktime(&tm); - if (systime == -1) { - /* We don't expect this to happen. Consider this a crash */ - fprintf(stderr, "mktime() failed unexpectedly (rc -1). Aborting.\n"); - exit(2); + mktime_result = mktime(&tm); + if (mktime_result == -1) { + /* This apparently (not specified in mktime() documentation) means + the 'tm' structure does not contain valid values (however, not + containing valid values does _not_ imply mktime() returns -1). + */ + *valid_p = FALSE; + *systime_p = 0; + if (debug) + printf("Invalid values in hardware clock: " + "%2d/%.2d/%.2d %.2d:%.2d:%.2d\n", + tm.tm_year, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec + ); + } else { + *valid_p = TRUE; + *systime_p = mktime_result; + if (debug) + printf("Hw clock time : %.2d:%.2d:%.2d = %d seconds since 1969\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, (int) *systime_p); } - /* now put back the original zone. */ if (zone) setenv("TZ", zone, TRUE); else unsetenv("TZ"); tzset(); - - if (debug) - printf("Hw clock time : %.2d:%.2d:%.2d = %d seconds since 1969\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, (int) systime); - - return(systime); } @@ -837,32 +856,28 @@ read_hardware_clock_isa(struct tm *tm) { 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 . + /* We don't use the century byte (Byte 50) of the Hardware Clock. + Here's why: On older machines, it isn't defined. In at least + one reported case, a machine puts some arbitrary value in that + byte. Furthermore, the Linux standard time data structure doesn't + allow for times beyond about 2037 and no Linux systems were + running before 1937. Therefore, all the century byte could tell + us is that the clock is wrong or this whole program is obsolete! + + So we just say if the year of century is less than 37, it's the + 21st century, otherwise it's the 20th. */ - 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! - */ + + if (hclock_read_bcd(9) >= 37) tm->tm_year = hclock_read_bcd(9); + else tm->tm_year = hclock_read_bcd(9) + 100; } + /* 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! + */ } tm->tm_isdst = -1; /* don't know whether it's daylight */ } @@ -870,21 +885,25 @@ read_hardware_clock_isa(struct tm *tm) { static void -read_hardware_clock(const enum clock_access_method method, struct tm *tm){ +read_hardware_clock(const enum clock_access_method method, + const bool universal, bool *valid_p, time_t *systime_p){ /*---------------------------------------------------------------------------- Read the hardware clock and return the current time via argument. Use the method indicated by argument to access the hardware clock. -----------------------------------------------------------------------------*/ + struct tm tm; + + switch (method) { case ISA: - read_hardware_clock_isa(tm); + read_hardware_clock_isa(&tm); break; case RTC_IOCTL: - read_hardware_clock_rtc_ioctl(tm); + read_hardware_clock_rtc_ioctl(&tm); break; case KD: - read_hardware_clock_kd(tm); + read_hardware_clock_kd(&tm); break; default: fprintf(stderr, @@ -893,7 +912,8 @@ read_hardware_clock(const enum clock_access_method method, struct tm *tm){ } if (debug) printf ("Time read from Hardware Clock: %02d:%02d:%02d\n", - tm->tm_hour, tm->tm_min, tm->tm_sec); + tm.tm_hour, tm.tm_min, tm.tm_sec); + mktime_tz(tm, universal, valid_p, systime_p); } @@ -994,14 +1014,13 @@ set_hardware_clock_isa(const struct tm new_broken_time, an ISA Hardware Clock. ----------------------------------------------------------------------------*/ unsigned char save_control, save_freq_select; -#ifdef __i386__ - const bool interrupts_were_enabled = interrupts_enabled; -#endif if (testing) printf("Not setting Hardware Clock because running in test mode.\n"); else { #ifdef __i386__ + const bool interrupts_were_enabled = interrupts_enabled; + __asm__ volatile ("cli"); interrupts_enabled = FALSE; #endif @@ -1220,21 +1239,30 @@ set_epoch(unsigned long epoch, const bool testing, int *retcode_p) { static void -display_time(const time_t systime, const float sync_duration) { +display_time(const bool hclock_valid, const time_t systime, + const float sync_duration) { /*---------------------------------------------------------------------------- Put the time "systime" on standard output in display format. + Except if hclock_valid == false, just tell standard output that we don't + know what time it is. Include in the output the adjustment "sync_duration". -----------------------------------------------------------------------------*/ - char *ctime_now; /* Address of static storage containing time string */ - - /* For some strange reason, ctime() is designed to include a newline - character at the end. We have to remove that. - */ - ctime_now = ctime(&systime); /* Compute display value for time */ - *(ctime_now+strlen(ctime_now)-1) = '\0'; /* Cut off trailing newline */ + if (!hclock_valid) + fprintf(stderr, "The Hardware Clock registers contain values that are " + "either invalid (e.g. 50th day of month) or beyond the range " + "we can handle (e.g. Year 2095).\n"); + else { + char *ctime_now; /* Address of static storage containing time string */ - printf("%s %.6f seconds\n", ctime_now, -(sync_duration)); + /* For some strange reason, ctime() is designed to include a newline + character at the end. We have to remove that. + */ + ctime_now = ctime(&systime); /* Compute display value for time */ + *(ctime_now+strlen(ctime_now)-1) = '\0'; /* Cut off trailing newline */ + + printf("%s %.6f seconds\n", ctime_now, -(sync_duration)); + } } @@ -1322,34 +1350,69 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { static int -set_system_clock(const time_t newtime, const bool testing) { +set_system_clock(const bool hclock_valid, const time_t newtime, + const bool testing) { +/*---------------------------------------------------------------------------- + Set the System Clock to time 'newtime'. + + Also set the kernel time zone value to the value indicated by the + TZ environment variable and/or /usr/lib/zoneinfo/, interpreted as + tzset() would interpret them. Except: do not consider Daylight + Savings Time to be a separate component of the time zone. Include + any effect of DST in the basic timezone value and set the kernel + DST value to 0. - struct timeval tv; + EXCEPT: if hclock_valid is false, just issue an error message + saying there is no valid time in the Hardware Clock to which to set + the system time. + + If 'testing' is true, don't actually update anything -- just say we + would have. +-----------------------------------------------------------------------------*/ int retcode; /* our eventual return code */ - int rc; /* local return code */ - tv.tv_sec = newtime; - tv.tv_usec = 0; - - if (debug) { - printf( "Calling settimeofday:\n" ); - 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"); - retcode = 0; + if (!hclock_valid) { + fprintf(stderr,"The Hardware Clock does not contain a valid time, so " + "we cannot set the System Time from it.\n"); + retcode = 1; } else { - rc = settimeofday(&tv, NULL); - if (rc != 0) { - if (errno == EPERM) - fprintf(stderr, "Must be superuser to set system clock.\n"); - else - fprintf(stderr, - "settimeofday() failed, errno=%d:%s\n", - errno, strerror(errno)); - retcode = 1; - } else retcode = 0; + struct timeval tv; + int rc; /* local return code */ + + tv.tv_sec = newtime; + tv.tv_usec = 0; + + tzset(); /* init timezone, daylight from TZ or ...zoneinfo/localtime */ + /* An undocumented function of tzset() is to set global variabales + 'timezone' and 'daylight' + */ + + if (debug) { + printf( "Calling settimeofday:\n" ); + 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"); + retcode = 0; + } else { + /* For documentation of settimeofday(), in addition to its man page, + see kernel/time.c in the Linux source code. + */ + const struct timezone tz = { timezone/60 - 60*daylight, 0 }; + /* put daylight in minuteswest rather than dsttime, + since the latter is mostly ignored ... */ + rc = settimeofday(&tv, &tz); + if (rc != 0) { + if (errno == EPERM) + fprintf(stderr, "Must be superuser to set system clock.\n"); + else + fprintf(stderr, + "settimeofday() failed, errno=%d:%s\n", + errno, strerror(errno)); + retcode = 1; + } else retcode = 0; + } } return(retcode); } @@ -1358,7 +1421,7 @@ set_system_clock(const time_t newtime, const bool testing) { static void adjust_drift_factor(struct adjtime *adjtime_p, const time_t nowtime, - const time_t hclocktime ) { + const bool hclock_valid, const time_t hclocktime ) { /*--------------------------------------------------------------------------- Update the drift factor in <*adjtime_p> to reflect the fact that the Hardware Clock was calibrated to and before that was set @@ -1372,8 +1435,20 @@ adjust_drift_factor(struct adjtime *adjtime_p, We record in the adjtime file the time at which we last calibrated the clock so we can compute the drift rate each time we calibrate. + EXCEPT: if is false, assume Hardware Clock was not set + before to anything meaningful and regular adjustments have not been + done, so don't adjust the drift factor. + ----------------------------------------------------------------------------*/ - if ((hclocktime - adjtime_p->last_calib_time) >= 24 * 60 * 60) { + if (!hclock_valid) { + if (debug) + printf("Not adjusting drift factor because the Hardware Clock " + "previously contained garbage.\n"); + } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) { + if (debug) + printf("Not adjusting drift factor because it has been less than a " + "day since the last calibration.\n"); + } else { const float factor_adjust = ((float) (nowtime - hclocktime) / (hclocktime - adjtime_p->last_calib_time)) @@ -1387,18 +1462,15 @@ adjust_drift_factor(struct adjtime *adjtime_p, (int) (hclocktime - adjtime_p->last_calib_time), adjtime_p->drift_factor, factor_adjust ); - + adjtime_p->drift_factor += factor_adjust; - } else if (debug) - printf("Not adjusting drift factor because it has been less than a " - "day since the last calibration.\n"); - + } adjtime_p->last_calib_time = nowtime; adjtime_p->last_adj_time = nowtime; - + adjtime_p->not_adjusted = 0; - + adjtime_p->dirty = TRUE; } @@ -1507,7 +1579,8 @@ save_adjtime(const struct adjtime adjtime, const bool testing) { static void do_adjustment(struct adjtime *adjtime_p, - const time_t hclocktime, const struct timeval read_time, + const bool hclock_valid, const time_t hclocktime, + const struct timeval read_time, const enum clock_access_method clock_access, const bool universal, const bool testing) { /*--------------------------------------------------------------------------- @@ -1515,10 +1588,14 @@ do_adjustment(struct adjtime *adjtime_p, necessary), and 2) updating the last-adjusted time in the adjtime structure. + Do not update anything if the Hardware Clock does not currently present + a valid time. + arguments and are current values from the adjtime file. - is the current time set in the Hardware Clock. + means the Hardware Clock contains a valid time, and that + time is . is the current system time (to be precise, it is the system time at the time was read, which due to computational delay @@ -1534,29 +1611,34 @@ do_adjustment(struct adjtime *adjtime_p, frequently. ----------------------------------------------------------------------------*/ - int adjustment; + if (!hclock_valid) { + fprintf(stderr, "The Hardware Clock does not contain a valid time, " + "so we cannot adjust it.\n"); + } else { + int adjustment; /* Number of seconds we must insert in the Hardware Clock */ - float retro; + float retro; /* Fraction of second we have to remove from clock after inserting whole seconds. */ - calculate_adjustment(adjtime_p->drift_factor, - adjtime_p->last_adj_time, - adjtime_p->not_adjusted, - hclocktime, - &adjustment, &retro, - debug ); - if (adjustment > 0 || adjustment < -1) { - set_hardware_clock_exact(hclocktime + adjustment, - time_inc(read_time, -retro), - clock_access, universal, testing); - adjtime_p->last_adj_time = hclocktime + adjustment; - adjtime_p->not_adjusted = 0; - adjtime_p->dirty = TRUE; - } else - if (debug) - printf("Needed adjustment is less than one second, " - "so not setting clock.\n"); + calculate_adjustment(adjtime_p->drift_factor, + adjtime_p->last_adj_time, + adjtime_p->not_adjusted, + hclocktime, + &adjustment, &retro, + debug ); + if (adjustment > 0 || adjustment < -1) { + set_hardware_clock_exact(hclocktime + adjustment, + time_inc(read_time, -retro), + clock_access, universal, testing); + adjtime_p->last_adj_time = hclocktime + adjustment; + adjtime_p->not_adjusted = 0; + adjtime_p->dirty = TRUE; + } else + if (debug) + printf("Needed adjustment is less than one second, " + "so not setting clock.\n"); + } } @@ -1659,14 +1741,6 @@ manipulate_clock(const bool show, const bool adjust, ----------------------------------------------------------------------------*/ struct adjtime adjtime; /* Contents of the adjtime file, or what they should be. */ - struct tm tm; - time_t hclocktime; - /* The time the hardware clock had just after we synchronized to its - next clock tick when we started up. - */ - struct timeval read_time; - /* The time at which we read the Hardware Clock */ - int rc; /* local return code */ bool no_auth; /* User lacks necessary authorization to access the clock */ @@ -1674,7 +1748,7 @@ manipulate_clock(const bool show, const bool adjust, rc = i386_iopl(3); if (rc != 0) { fprintf(stderr, MYNAME " is unable to get I/O port access. " - "I.e. iopl(2) returned nonzero return code %d.\n" + "I.e. iopl(3) returned nonzero return code %d.\n" "This is often because the program isn't running " "with superuser privilege, which it needs.\n", rc); @@ -1696,21 +1770,36 @@ manipulate_clock(const bool show, const bool adjust, 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 */ + struct timeval read_time; + /* The time at which we read the Hardware Clock */ + + bool hclock_valid; + /* The Hardware Clock gives us a valid time, or at least something + close enough to fool mktime(). + */ + + time_t hclocktime; + /* The time the hardware clock had just after we + synchronized to its next clock tick when we started up. + Defined only if hclock_valid is true. + */ + gettimeofday(&read_time, NULL); - read_hardware_clock(clock_access, &tm); - hclocktime = mktime_tz(tm, universal); + read_hardware_clock(clock_access, universal, &hclock_valid, + &hclocktime); if (show) { - display_time(hclocktime, time_diff(read_time, startup_time)); + display_time(hclock_valid, 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); + adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime); *retcode_p = 0; } else if (adjust) { - do_adjustment(&adjtime, hclocktime, read_time, clock_access, + do_adjustment(&adjtime, hclock_valid, hclocktime, + read_time, clock_access, universal, testing); *retcode_p = 0; } else if (systohc) { @@ -1726,9 +1815,10 @@ manipulate_clock(const bool show, const bool adjust, 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); + adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, + hclocktime); } else if (hctosys) { - rc = set_system_clock(hclocktime, testing); + rc = set_system_clock(hclock_valid, hclocktime, testing); if (rc != 0) { printf("Unable to set system clock.\n"); *retcode_p = 1; @@ -1934,6 +2024,16 @@ main(int argc, char **argv, char **envp) { History of this program: + 98.08.12 BJH Version 2.4 + + Don't use century byte from Hardware Clock. Add comments telling why. + + + 98.06.20 BJH Version 2.3. + + Make --hctosys set the kernel timezone from TZ environment variable + and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com). + 98.03.05 BJH. Version 2.2. Add --getepoch and --setepoch. diff --git a/sys-utils/ipcrm.c b/sys-utils/ipcrm.c index eceb0b71c..c04b7fd44 100644 --- a/sys-utils/ipcrm.c +++ b/sys-utils/ipcrm.c @@ -6,9 +6,24 @@ #include #include #include + +#include +#include #include #include #include +#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif + int main(int argc, char **argv) { diff --git a/sys-utils/ipcs.c b/sys-utils/ipcs.c index 9505aff55..975bfd1a2 100644 --- a/sys-utils/ipcs.c +++ b/sys-utils/ipcs.c @@ -22,12 +22,38 @@ #include #include #include -#define __KERNEL__ +#if 0 +#define __KERNEL__ /* yuk */ #include +#endif +/* X/OPEN tells us to use for semctl() */ +/* X/OPEN tells us to use for msgctl() */ +/* X/OPEN tells us to use for shmctl() */ +#include +#include #include #include #include +/* The last arg of semctl is a union semun, but where is it defined? + X/OPEN tells us to define it ourselves, but until recently + Linux include files would also define it. */ +#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) +/* union semun is defined by including */ +#else +/* according to X/OPEN we have to define it ourselves */ +union semun { + int val; + struct semid_ds *buf; + unsigned short int *array; + struct seminfo *__buf; +}; +#endif +/* X/OPEN (Jan 1987) does not define fields key, seq in struct ipc_perm; + libc 4/5 does not mention struct ipc_term at all, but includes + , which defines a struct ipc_perm with such fields. + glibc-1.09 has no support for sysv ipc. + glibc 2 uses __key, __seq */ #if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 #define KEY __key #else @@ -237,7 +263,7 @@ void do_shm (char format) default: printf ("------ Shared Memory Segments --------\n"); - printf ("%-11s%-10s%-10s%-10s%-10s%-10s%-12s\n", "key","shmid", + printf ("%-10s%-10s%-10s%-10s%-10s%-10s%-12s\n", "key","shmid", "owner","perms","bytes","nattch","status"); break; } diff --git a/sys-utils/kbdrate.8 b/sys-utils/kbdrate.8 index 3fef3395f..88c6cbc1f 100644 --- a/sys-utils/kbdrate.8 +++ b/sys-utils/kbdrate.8 @@ -49,6 +49,13 @@ Not all keyboards have the rates mapped in the same way. Setting the repeat rate on the Gateway AnyKey keyboard does not work. If someone with a Gateway figures out how to program the keyboard, please send mail to faith@cs.unc.edu. +.PP +The above description is for i386 machines, and writing to some io port +won't work on other architectures. Nowadays +.B kbdrate +first tries if the KDKBDREP ioctl is available. If it is, it is used, +otherwise the old method is applied. + .SH FILES .I /etc/rc.local .br diff --git a/sys-utils/kbdrate.c b/sys-utils/kbdrate.c index 07a7e40e5..504429452 100644 --- a/sys-utils/kbdrate.c +++ b/sys-utils/kbdrate.c @@ -67,7 +67,7 @@ beats rebuilding the kernel! #include #include #if LINUX_VERSION_CODE >= 131072 -/* Kd.h is not available with all linux versions. 131072 is equivalent +/* kd.h is not available with all linux versions. 131072 is equivalent to linux 2.0.0 */ #include #endif @@ -130,10 +130,15 @@ int main( int argc, char **argv ) } else ioctl_possible = 1; if (ioctl_possible) { - kbdrep_s.rate = 1000.0 / rate; /* convert cps to msec */ - if (kbdrep_s.rate < 1) kbdrep_s.rate = 1; + if (rate == 0) /* switch repeat off */ + kbdrep_s.rate = 0; + else + kbdrep_s.rate = 1000.0 / rate; /* convert cps to msec */ + if (kbdrep_s.rate < 1) + kbdrep_s.rate = 1; kbdrep_s.delay = delay; - if (kbdrep_s.delay < 1) kbdrep_s.delay = 1; + if (kbdrep_s.delay < 1) + kbdrep_s.delay = 1; if (ioctl( 0, KDKBDREP, &kbdrep_s )) { perror( "ioctl(KDKBDREP)" ); @@ -192,7 +197,7 @@ int main( int argc, char **argv ) valid_rates[value & 0x1f] / 10.0, valid_delays[ (value & 0x60) >> 5 ] ); -#ifdef KDKBREP +#ifdef KDKBDREP } #endif diff --git a/sys-utils/lpcntl.8 b/sys-utils/lpcntl.8 deleted file mode 100644 index 87bcd039e..000000000 --- a/sys-utils/lpcntl.8 +++ /dev/null @@ -1,30 +0,0 @@ -.\" Public Domain 1994 Rik Faith (faith@cs.unc.edu) -.\" " -.TH LPCNTL 8 "18 July 1994" "Linux 1.1" "Linux Programmer's Manual" -.SH NAME -lpcntl \- interface to line printer ioctl -.SH SYNOPSIS -.BI "lpcntl " device " [ " irq " ]" -.SH DESCRIPTION -.B lpcntl -is used to manipulate the line printer driver. -.PP -.I device -specifies a line printer device (e.g., -.IR /dev/lp1 ). -.PP -If -.I irq -is specified, then the line printer driver is set to use that IRQ. If the -.I irq -is zero, then the polling driver is selected. Only the super user may -change the IRQ. -.PP -If no -.I irq -is specified, then -.B lpcntl -will report the interrupt number currently in use, or will report that the -polling driver is currently being used. -.SH AUTHOR -Nigel Gamble (nigel@gate.net) diff --git a/sys-utils/lpcntl.c b/sys-utils/lpcntl.c deleted file mode 100644 index bf164a632..000000000 --- a/sys-utils/lpcntl.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Simple command interface to ioctl(fd, LPSETIRQ, irq). - * Nigel Gamble (nigel@gate.net) - * e.g. - * lpcntl /dev/lp1 7 - */ - -#include -#include -#include -#include - -int -main(int argc, char **argv) -{ - unsigned int irq; - int fd; - int ret; - - if (argc < 2) { - fprintf(stderr, "usage: %s []\n", argv[0]); - exit(1); - } - - fd = open(argv[1], O_RDONLY); - if (fd == -1) { - perror(argv[1]); - exit(1); - } - - if (argc == 2) { - irq = ioctl(fd, LPGETIRQ); - if (irq == -1) { - perror(argv[1]); - exit(1); - } - if (irq) - printf("%s using IRQ %d\n", argv[1], irq); - else - printf("%s using polling\n", argv[1]); - } else { - irq = atoi(argv[2]); - ret = ioctl(fd, LPSETIRQ, irq); - if (ret == -1) { - if (errno == EPERM) - fprintf(stderr, "%s: only super-user can change the IRQ\n", argv[0]); - else - perror(argv[1]); - exit(1); - } - } - - return 0; -} diff --git a/sys-utils/sln.1 b/sys-utils/sln.1 deleted file mode 100644 index a89271936..000000000 --- a/sys-utils/sln.1 +++ /dev/null @@ -1,22 +0,0 @@ -.\" Nicolai Langfeldt (janl@math.uio.no) -.\" In the public domain. -.TH SLN 8 "20 June 1997" "Linux 2.0" "Linux Programmer's Manual" -.SH NAME -sln \- static ln -.SH SYNOPSIS -.BI sln " source dest" -.SH DESCRIPTION -.B sln -symbolically links -.I dest -to -.I source -It is statically linked, needing no dynamic linking at all. This that -sln is usefull to make symbolic links to dynamic libraries if the -dynamic linking system for some reason is nonfunctional. -.SH "SEE ALSO" -.BR ln(1) -.BR ldconfig(8) -.BR ld.so(8) -.SH AUTHOR -Mike Parker and David MacKenzie. diff --git a/sys-utils/sln.8 b/sys-utils/sln.8 new file mode 100644 index 000000000..f97683d47 --- /dev/null +++ b/sys-utils/sln.8 @@ -0,0 +1,23 @@ +.\" Nicolai Langfeldt (janl@math.uio.no) +.\" In the public domain. +.TH SLN 8 "20 June 1997" "Linux 2.0" "Linux Programmer's Manual" +.SH NAME +sln \- static ln +.SH SYNOPSIS +.BI sln " source dest" +.SH DESCRIPTION +.B sln +symbolically links +.I dest +to +.IR source . +It is statically linked, needing no dynamic linking at all. Thus +.B sln +is useful to make symbolic links to dynamic libraries if the +dynamic linking system for some reason is nonfunctional. +.SH "SEE ALSO" +.BR ln(1) +.BR ldconfig(8) +.BR ld.so(8) +.\" .SH AUTHOR +.\" Mike Parker and David MacKenzie. diff --git a/text-utils/Makefile b/text-utils/Makefile index c657be72b..686418d61 100644 --- a/text-utils/Makefile +++ b/text-utils/Makefile @@ -11,10 +11,6 @@ include ../MCONFIG MAN1= col.1 colcrt.1 colrm.1 column.1 hexdump.1 more.1 rev.1 \ ul.1 -ifeq "$(HAVE_STRINGS)" "no" -MAN1:=$(MAN1) strings.1 -endif - # Where to put binaries? # See the "install" rule for the links. . . @@ -22,10 +18,6 @@ BIN= more USRBIN= col colcrt colrm column hexdump rev ul -ifeq "$(HAVE_STRINGS)" "no" -USRBIN:=$(USRBIN) strings -endif - # Where to put datebase files? USRLIB= more.help @@ -45,8 +37,7 @@ endif # Rules for hexdump -hexdump: hexdump.o conv.o display.o hexsyntax.o odsyntax.o parse.o \ - $(BSD)/getopt.o +hexdump: hexdump.o conv.o display.o hexsyntax.o odsyntax.o parse.o hexdump.o: hexdump.c hexdump.h conv.o: conv.c hexdump.h display.o: display.c hexdump.h @@ -56,13 +47,13 @@ parse.o: parse.c hexdump.h # Rules for everything else -col: col.o $(BSD)/getopt.o +col: col.o colcrt: colcrt.o colrm: colrm.o -column: column.o $(BSD)/err.o -more.o: more.c $(BSD)/pathnames.h +column: column.o $(ERR_O) +more.o: more.c $(LIB)/pathnames.h rev: rev.o -strings: strings.o $(BSD)/getopt.o + ifeq "$(HAVE_NCURSES)" "yes" more: more.o ul: ul.o diff --git a/text-utils/colcrt.c b/text-utils/colcrt.c index a4d19bb5a..f21f76927 100644 --- a/text-utils/colcrt.c +++ b/text-utils/colcrt.c @@ -64,10 +64,11 @@ char printall; char *progname; FILE *f; -int main(int argc, char **argv) +int +main(int argc, char **argv) { - register c; - register char *cp, *dp; + int c; + char *cp, *dp; argc--; progname = *argv++; diff --git a/text-utils/colrm.c b/text-utils/colrm.c index 3051c866c..f189e25d2 100644 --- a/text-utils/colrm.c +++ b/text-utils/colrm.c @@ -40,9 +40,10 @@ COLRM removes unwanted columns from a file int getn(char *ap); -int main(int argc, char **argv) +int +main(int argc, char **argv) { - register c, ct, first, last; + register int c, ct, first, last; first = 0; last = 0; diff --git a/text-utils/column.c b/text-utils/column.c index 09f52ebba..4ae9522ef 100644 --- a/text-utils/column.c +++ b/text-utils/column.c @@ -164,7 +164,6 @@ r_columnate() int base, chcnt, cnt, col, endcol, numcols, numrows, row; maxlength = (maxlength + TAB) & ~(TAB - 1); - /* This could be 0 */ numcols = termwidth / maxlength; if (!numcols) numcols = 1; diff --git a/text-utils/more.c b/text-utils/more.c index 6e0763169..24045472d 100644 --- a/text-utils/more.c +++ b/text-utils/more.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1980 Regents Of the University of California. + * Copyright (C) 1980 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -49,6 +49,7 @@ #include #endif #include +#include #define HELPFILE "/usr/lib/more.help" #define VI "/usr/bin/vi" @@ -93,6 +94,8 @@ int get_line(register FILE *f, int *length); void prbuf (register char *s, register int n); int xprintf (char *fmt, ...); void execute (char *filename, char *cmd, ...); +void errwrite (char *txt); +void errwrite1 (char *sym); #define TBUFSIZ 1024 #define LINSIZ 256 @@ -149,7 +152,7 @@ int soglitch; /* terminal has standout mode glitch */ int ulglitch; /* terminal has underline mode glitch */ int pstate = 0; /* current UL state */ char *getenv(); -static magic(); +static int magic(); struct { long chrctr, line; } context, screen_start; @@ -165,7 +168,7 @@ int main(int argc, char **argv) { FILE *f; char *s; char *p; - char ch; + int ch; int left; int prnames = 0; int initopt = 0; @@ -183,6 +186,7 @@ int main(int argc, char **argv) { nfiles = argc; fnames = argv; + setlocale(LC_ALL, ""); initterm (); nscroll = Lpp/2 - 1; if (nscroll <= 0) @@ -286,8 +290,7 @@ int main(int argc, char **argv) { if (firstf) setjmp (restore); if (firstf) { firstf = 0; - if (srchopt) - { + if (srchopt) { search (initbuf, f, 1); if (noscroll) left--; @@ -300,11 +303,12 @@ int main(int argc, char **argv) { left = command (fnames[fnum], f); } if (left != 0) { - if ((noscroll || clearit) && (file_size != LONG_MAX)) + if ((noscroll || clearit) && (file_size != LONG_MAX)) { if (clreol) home (); else doclear (); + } if (prnames) { if (bad_so) erasep (0); @@ -434,21 +438,23 @@ magic(f, fs) FILE *f; char *fs; { - struct exec ex; + char twobytes[2]; - if (fread(&ex, sizeof(ex), 1, f) == 1) - switch(ex.a_info) { - case OMAGIC: - case NMAGIC: - case ZMAGIC: + if (fread(twobytes, 2, 1, f) == 1) { + switch(twobytes[0] + (twobytes[1]<<8)) { + case OMAGIC: /* 0407 */ + case NMAGIC: /* 0410 */ + case ZMAGIC: /* 0413 */ case 0405: case 0411: case 0177545: + case 0x457f: /* simple ELF detection */ xprintf("\n******** %s: Not a text file ********\n\n", fs); (void)fclose(f); return(1); } - (void)fseek(f, 0L, L_SET); /* rewind() not necessary */ + } + (void)fseek(f, 0L, SEEK_SET); /* rewind() not necessary */ return(0); } @@ -547,7 +553,7 @@ void onquit() Pause++; } else if (!dum_opt && notell) { - write (2, "[Use q or Q to quit]", 20); + errwrite("[Use q or Q to quit]"); promptlen += 20; notell = 0; } @@ -597,7 +603,7 @@ void end_it () fflush (stdout); } else - write (2, "\n", 1); + errwrite("\n"); _exit(0); } @@ -682,7 +688,7 @@ void scanstr (int n, char *str) *sptr = '\0'; } -static char my_bell = ctrl('G'); +#define ringbell() errwrite("\007"); #ifdef undef strlen (s) @@ -750,7 +756,7 @@ char *filename; fflush(stdout); } else - write (2, &my_bell, 1); + ringbell(); inwait++; } @@ -787,7 +793,7 @@ int get_line(register FILE *f, int *length) break; } *p++ = c; - if (c == '\t') + if (c == '\t') { if (!hardtabs || (column < promptlen && !hard)) { if (hardtabs && eraseln && !dumb) { column = 1 + (column | 7); @@ -805,9 +811,9 @@ int get_line(register FILE *f, int *length) } else column = 1 + (column | 7); - else if (c == '\b' && column > 0) + } else if (c == '\b' && column > 0) { column--; - else if (c == '\r') { + } else if (c == '\r') { int next = Getc(f); if (next == '\n') { p--; @@ -816,18 +822,16 @@ int get_line(register FILE *f, int *length) } Ungetc(next,f); column = 0; - } - else if (c == '\f' && stop_opt) { + } else if (c == '\f' && stop_opt) { p[-1] = '^'; *p++ = 'L'; column += 2; Pause++; - } - else if (c == EOF) { + } else if (c == EOF) { *length = p - Line; return (column); } - else if (c >= ' ' && c != RUBOUT) + else if (isprint(c)) column++; if (column >= Mcol && fold_opt) break; c = Getc (f); @@ -988,7 +992,7 @@ int command (char *filename, register FILE *f) { register int nlines; register int retval = 0; - register char c; + register int c; char colonch; FILE *helpf; int done; @@ -1030,7 +1034,7 @@ int command (char *filename, register FILE *f) register int initline; if (no_intty) { - write(2, &my_bell, 1); + ringbell(); return (-1); } @@ -1122,7 +1126,7 @@ int command (char *filename, register FILE *f) ret (dlines); } else { - write (2, &my_bell, 1); + ringbell(); break; } case '\'': @@ -1134,7 +1138,7 @@ int command (char *filename, register FILE *f) ret (dlines); } else { - write (2, &my_bell, 1); + ringbell(); break; } case '=': @@ -1151,12 +1155,12 @@ int command (char *filename, register FILE *f) promptlen = 1; fflush (stdout); if (lastp) { - write (2,"\r", 1); + errwrite ("\r"); search (NULL, f, nlines); /* Use previous r.e. */ } else { ttyin (cmdbuf, sizeof(cmdbuf)-2, '/'); - write (2, "\r", 1); + errwrite("\r"); search (cmdbuf, f, nlines); } ret (dlines-1); @@ -1195,7 +1199,7 @@ int command (char *filename, register FILE *f) fflush (stdout); } else - write (2, &my_bell, 1); + ringbell(); break; } if (done) break; @@ -1243,7 +1247,7 @@ int colon (char *filename, int cmd, int nlines) return (0); case 'p': if (no_intty) { - write (2, &my_bell, 1); + ringbell(); return (-1); } putchar ('\r'); @@ -1259,7 +1263,7 @@ int colon (char *filename, int cmd, int nlines) case 'Q': end_it (); default: - write (2, &my_bell, 1); + ringbell(); return (-1); } } @@ -1276,7 +1280,7 @@ int number(char *cmd) i = 0; ch = otty.c_cc[VKILL]; for (;;) { ch = readch (); - if (ch >= '0' && ch <= '9') + if (isdigit(ch)) i = i*10 + ch - '0'; else if (ch == otty.c_cc[VKILL]) i = 0; @@ -1306,7 +1310,7 @@ void do_shell (char *filename) } } fflush (stdout); - write (2, "\n", 1); + errwrite("\n"); promptlen = 0; shellp = 1; execute (filename, shell, shell, "-c", shell_line, 0); @@ -1337,7 +1341,7 @@ void search(char buf[], FILE *file, register int n) line1 = Ftell (file); rdline (file); lncount++; - if ((rv = re_exec (Line)) == 1) + if ((rv = re_exec (Line)) == 1) { if (--n == 0) { if (lncount > 3 || (lncount > 1 && no_intty)) { @@ -1349,29 +1353,31 @@ void search(char buf[], FILE *file, register int n) if (!no_intty) { Currline -= (lncount >= 3 ? 3 : lncount); Fseek (file, line3); - if (noscroll) + if (noscroll) { if (clreol) { home (); cleareol (); } else doclear (); + } } else { kill_line (); - if (noscroll) + if (noscroll) { if (clreol) { home (); cleareol (); } else doclear (); + } pr (Line); putchar ('\n'); } break; } - else if (rv == -1) + } else if (rv == -1) error ("Regular expression botch"); } if (feof (file)) { @@ -1435,7 +1441,7 @@ void execute (char * filename, char * cmd, ...) va_end(argp); /* balance {}'s for some UNIX's */ execv (cmd, args); - write (2, "exec failed\n", 12); + errwrite("exec failed\n"); exit (1); } if (id > 0) { @@ -1449,7 +1455,7 @@ void execute (char * filename, char * cmd, ...) if (catch_susp) signal(SIGTSTP, onsusp); } else - write(2, "can't fork\n", 11); + errwrite("can't fork\n"); set_tty (); pr ("------------------------\n"); prompt (filename); @@ -1460,7 +1466,7 @@ void execute (char * filename, char * cmd, ...) void skiplns (register int n, register FILE *f) { - register char c; + register int c; while (n > 0) { while ((c = Getc (f)) != '\n') @@ -1636,22 +1642,23 @@ int readch () extern int errno; errno = 0; - if (read (2, &ch, 1) <= 0) + if (read (2, &ch, 1) <= 0) { if (errno != EINTR) end_it(); else ch = otty.c_cc[VKILL]; + } return (ch); } -static char BS = '\b'; +static char *BS = "\b"; static char *BSB = "\b \b"; -static char CARAT = '^'; +static char *CARAT = "^"; #define ERASEONECHAR \ if (docrterase) \ - write (2, BSB, sizeof(BSB)); \ + errwrite(BSB); \ else \ - write (2, &BS, sizeof(BS)); + errwrite(BS); void ttyin (char buf[], register int nmax, char pchar) { @@ -1698,7 +1705,7 @@ void ttyin (char buf[], register int nmax, char pchar) erasep (1); else if (docrtkill) while (promptlen-- > 1) - write (2, BSB, sizeof(BSB)); + errwrite(BSB); promptlen = 1; } sptr = buf; @@ -1714,12 +1721,12 @@ void ttyin (char buf[], register int nmax, char pchar) *sptr++ = ch; if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { ch += ch == RUBOUT ? -0100 : 0100; - write (2, &CARAT, 1); + errwrite(CARAT); promptlen++; } cbuf = ch; if (ch != '\n' && ch != ESC) { - write (2, &cbuf, 1); + errwrite1(&cbuf); promptlen++; } else @@ -1778,14 +1785,24 @@ void show (register char ch) if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { ch += ch == RUBOUT ? -0100 : 0100; - write (2, &CARAT, 1); + errwrite(CARAT); promptlen++; } cbuf = ch; - write (2, &cbuf, 1); + errwrite1(&cbuf); promptlen++; } +void errwrite (char *txt) +{ + write (fileno(stderr), txt, strlen(txt)); +} + +void errwrite1 (char *sym) +{ + write (fileno(stderr), sym, 1); +} + void error (char *mess) { if (clreol) @@ -1809,6 +1826,8 @@ void error (char *mess) void set_tty () { otty.c_lflag &= ~(ICANON|ECHO); + otty.c_cc[VMIN] = 1; /* read at least 1 char */ + otty.c_cc[VTIME] = 0; /* no timeout */ stty(fileno(stderr), &otty); } @@ -1826,12 +1845,14 @@ void reset_tty () pstate = 0; } otty.c_lflag |= ICANON|ECHO; + otty.c_cc[VMIN] = savetty0.c_cc[VMIN]; + otty.c_cc[VTIME] = savetty0.c_cc[VTIME]; stty(fileno(stderr), &savetty0); } void rdline (register FILE *f) { - register char c; + register int c; register char *p; p = Line; diff --git a/text-utils/strings.1 b/text-utils/strings.1 deleted file mode 100644 index 08dda5bfd..000000000 --- a/text-utils/strings.1 +++ /dev/null @@ -1,96 +0,0 @@ -.\" Copyright (c) 1980, 1990 The Regents of the University of California. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)strings.1 6.11 (Berkeley) 5/9/91 -.\" -.Dd May 9, 1991 -.Dt STRINGS 1 -.Os BSD 3 -.Sh NAME -.Nm strings -.Nd find printable strings in a file -.Sh SYNOPSIS -.Nm strings -.Op Fl afo -.Op Fl n Ar number -.Op Ar file ... -.Sh DESCRIPTION -.Nm Strings -displays the sequences of printable characters in each of the specified -files, or in the standard input, by default. -By default, a sequence must be at least four characters in length -before being displayed. -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl a -By default, -.Nm strings -only searches the text and data segments of object files. -The -.Fl a -option causes -.Nm strings -to search the entire object file. -.It Fl f -Each string is preceded by the name of the file -in which it was found. -.It Fl n -Specifies the minimum number of characters in a sequence to be -.Ar number , -instead of four. -.It Fl o -Each string is preceded by its decimal offset in the -file. -.El -.Pp -.Nm Strings -is useful for identifying random binaries, among other things. -.Sh SEE ALSO -.Xr hexdump 1 -.Sh BUGS -The algorithm for identifying strings is extremely primitive. -In particular, machine code instructions on certain architectures -can resemble sequences of ASCII bytes, which -will fool the algorithm. -.Sh COMPATIBILITY -Historic implementations of -.Nm -only search the initialized data portion of the object file. -This was reasonable as strings were normally stored there. -Given new compiler technology which installs strings in the -text portion of the object file, the default behavior was -changed. -.Sh HISTORY -The -.Nm -command appeared in -.Bx 3.0 . diff --git a/text-utils/strings.c b/text-utils/strings.c deleted file mode 100644 index 6c201a744..000000000 --- a/text-utils/strings.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 1980, 1987 The Regents of the University of California. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Wed Jun 22 22:22:37 1994, faith@cs.unc.edu: - * Added internationalization patches from Vitor Duarte - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEF_LEN 4 /* default minimum string length */ -#if 0 -#define ISSTR(ch) (isascii(ch) && (isprint(ch) || ch == '\t')) -#else -#define ISSTR(ch) (isprint(ch) || ch == '\t') -#endif - -typedef struct exec EXEC; /* struct exec cast */ - -static long foff; /* offset in the file */ -static int hcnt, /* head count */ - head_len, /* length of header */ - read_len; /* length to read */ -static u_char hbfr[sizeof(EXEC)]; /* buffer for struct exec */ - -static void usage(); - -main(argc, argv) - int argc; - char **argv; -{ - extern char *optarg; - extern int optind; - register int ch, cnt; - register u_char *C; - EXEC *head; - int exitcode, minlen; - short asdata, oflg, fflg; - u_char *bfr; - char *file, *p; - - setlocale(LC_CTYPE, ""); - - - /* - * for backward compatibility, allow '-' to specify 'a' flag; no - * longer documented in the man page or usage string. - */ - asdata = exitcode = fflg = oflg = 0; - minlen = -1; - while ((ch = getopt(argc, argv, "-0123456789an:of")) != EOF) - switch((char)ch) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - /* - * kludge: strings was originally designed to take - * a number after a dash. - */ - if (minlen == -1) { - p = argv[optind - 1]; - if (p[0] == '-' && p[1] == ch && !p[2]) - minlen = atoi(++p); - else - minlen = atoi(argv[optind] + 1); - } - break; - case '-': - case 'a': - asdata = 1; - break; - case 'f': - fflg = 1; - break; - case 'n': - minlen = atoi(optarg); - break; - case 'o': - oflg = 1; - break; - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (minlen == -1) - minlen = DEF_LEN; - - if (!(bfr = malloc((u_int)minlen))) { - (void)fprintf(stderr, "strings: %s\n", strerror(errno)); - exit(1); - } - bfr[minlen] = '\0'; - file = "stdin"; - do { - if (*argv) { - file = *argv++; - if (!freopen(file, "r", stdin)) { - (void)fprintf(stderr, - "strings; %s: %s\n", file, strerror(errno)); - exitcode = 1; - goto nextfile; - } - } - foff = 0; -#define DO_EVERYTHING() {read_len = -1; head_len = 0; goto start;} - read_len = -1; - if (asdata) - DO_EVERYTHING() - else { - head = (EXEC *)hbfr; - if ((head_len = - read(fileno(stdin), head, sizeof(EXEC))) == -1) - DO_EVERYTHING() - if (head_len == sizeof(EXEC) && !N_BADMAG(*head)) { - foff = N_TXTOFF(*head); - if (fseek(stdin, foff, SEEK_SET) == -1) - DO_EVERYTHING() - read_len = head->a_text + head->a_data; - head_len = 0; - } - else - hcnt = 0; - } -start: - for (cnt = 0; (ch = getch()) != EOF;) { - if (ISSTR(ch)) { - if (!cnt) - C = bfr; - *C++ = ch; - if (++cnt < minlen) - continue; - if (fflg) - printf("%s:", file); - if (oflg) - printf("%07ld %s", - foff - minlen, (char *)bfr); - else - printf("%s", bfr); - while ((ch = getch()) != EOF && ISSTR(ch)) - putchar((char)ch); - putchar('\n'); - } - cnt = 0; - } -nextfile: ; - } while (*argv); - exit(exitcode); -} - -/* - * getch -- - * get next character from wherever - */ -getch() -{ - ++foff; - if (head_len) { - if (hcnt < head_len) - return((int)hbfr[hcnt++]); - head_len = 0; - } - if (read_len == -1 || read_len-- > 0) - return(getchar()); - return(EOF); -} - -static void -usage() -{ - (void)fprintf(stderr, - "usage: strings [-afo] [-n length] [file ... ]\n"); - exit(1); -} diff --git a/text-utils/ul.c b/text-utils/ul.c index f10d22456..8da3b3f7c 100644 --- a/text-utils/ul.c +++ b/text-utils/ul.c @@ -41,6 +41,7 @@ #include /* for bzero() */ #include /* for setupterm() */ #include /* for getenv() */ +#include /* for INT_MAX */ void filter(FILE *f); void flushln(void); @@ -52,6 +53,7 @@ void reverse(void); void initinfo(void); void outc(int c); void setmode(int newmode); +void setcol(int newcol); #define IESC '\033' #define SO '\016' @@ -59,7 +61,6 @@ void setmode(int newmode); #define HFWD '9' #define HREV '8' #define FREV '7' -#define MAXBUF 512 #define NORMAL 000 #define ALTSET 001 /* Reverse */ @@ -67,6 +68,7 @@ void setmode(int newmode); #define SUBSC 004 /* Dim | Ul */ #define UNDERL 010 /* Ul */ #define BOLD 020 /* Bold */ +#define INITBUF 512 int must_use_uc, must_overstrike; char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, @@ -78,7 +80,8 @@ struct CHAR { char c_char; } ; -struct CHAR obuf[MAXBUF]; +struct CHAR *obuf; +int obuflen; /* Tracks number of elements in obuf. */ int col, maxcol; int mode; int halfpos; @@ -150,23 +153,20 @@ int main(int argc, char **argv) void filter(FILE *f) { - register c; + int c; while ((c = getc(f)) != EOF) switch(c) { case '\b': - if (col > 0) - col--; + setcol(col - 1); continue; case '\t': - col = (col+8) & ~07; - if (col > maxcol) - maxcol = col; + setcol((col+8) & ~07); continue; case '\r': - col = 0; + setcol(0); continue; case SO: @@ -224,9 +224,7 @@ void filter(FILE *f) else obuf[col].c_char = '_'; case ' ': - col++; - if (col > maxcol) - maxcol = col; + setcol(col + 1); continue; case '\n': @@ -251,9 +249,7 @@ void filter(FILE *f) obuf[col].c_mode |= BOLD|mode; else obuf[col].c_mode = mode; - col++; - if (col > maxcol) - maxcol = col; + setcol(col + 1); continue; } if (maxcol) @@ -262,8 +258,8 @@ void filter(FILE *f) void flushln() { - register lastmode; - register i; + int lastmode; + int i; int hadmodes = 0; lastmode = NORMAL; @@ -274,9 +270,9 @@ void flushln() lastmode = obuf[i].c_mode; } if (obuf[i].c_char == '\0') { - if (upln) + if (upln) { PRINT(CURS_RIGHT); - else + } else outc(' '); } else outc(obuf[i].c_char); @@ -361,21 +357,30 @@ void iattr() void initbuf() { + if (obuf == NULL) { /* First time. */ + obuflen = INITBUF; + obuf = malloc(sizeof(struct CHAR) * obuflen); + if (obuf == NULL) { + fprintf(stderr, "Unable to allocate buffer.\n"); + exit(1); + } + } - bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ - col = 0; + /* assumes NORMAL == 0 */ + bzero((char *)obuf, sizeof(struct CHAR) * obuflen); + setcol(0); maxcol = 0; mode &= ALTSET; } void fwd() { - register oldcol, oldmax; + int oldcol, oldmax; oldcol = col; oldmax = maxcol; flushln(); - col = oldcol; + setcol(oldcol); maxcol = oldmax; } @@ -390,7 +395,7 @@ void reverse() void initinfo() { - char *getenv(), *tigetstr(); + char *tigetstr(); CURS_UP = tigetstr("cuu1"); CURS_RIGHT = tigetstr("cuf1"); @@ -495,3 +500,40 @@ void setmode(int newmode) } curmode = newmode; } + + + + +void setcol(int newcol) +{ + col = newcol; + + if (col < 0) + col = 0; + else if (col > maxcol) { + maxcol = col; + + /* If col >= obuflen, expand obuf until obuflen > col. */ + while (col >= obuflen) { + /* Paranoid check for obuflen == INT_MAX. */ + if (obuflen == INT_MAX) { + fprintf(stderr, + "Input line too long.\n"); + exit(1); + } + + /* Similar paranoia: double only up to INT_MAX. */ + obuflen = ((INT_MAX / 2) < obuflen) + ? INT_MAX + : obuflen * 2; + + /* Now we can try to expand obuf. */ + obuf = realloc(obuf, sizeof(struct CHAR) * obuflen); + if (obuf == NULL) { + fprintf(stderr, + "Out of memory when growing buffer.\n"); + exit(1); + } + } + } +} diff --git a/uio.h-diff b/uio.h-diff deleted file mode 100644 index 48be527b5..000000000 --- a/uio.h-diff +++ /dev/null @@ -1,20 +0,0 @@ ---- /usr/include/sys/uio.h~ Sun Jan 24 20:02:24 1993 -+++ /usr/include/sys/uio.h Thu Oct 12 12:29:00 1995 -@@ -32,6 +32,7 @@ - - /* Structure describing a section of memory. */ - -+#if 0 - struct iovec - { - /* Starting address. */ -@@ -39,6 +40,9 @@ - /* Length in bytes. */ - size_t iov_len; - }; -+#else -+#include -+#endif - - - __BEGIN_DECLS diff --git a/util-linux-2.1.Announce b/util-linux-2.1.Announce deleted file mode 100644 index 0906617eb..000000000 --- a/util-linux-2.1.Announce +++ /dev/null @@ -1,48 +0,0 @@ - -util-linux-2.1.tar.gz (source distribution) -util-linux-2.1.bin.tar.gz (binary distribution) - - WARNING: THIS COLLECTION DOES *NOT* SUPPORT SHADOW PASSWORDS. - - WARNING: THIS COLLECTION DOES *NOT* SUPPORT SYSTEM V INITTAB. - - WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! - - WARNING: DO *NOT* INSTALL WITHOUT THINKING. - - WARNING: *READ* the util-linux-2.1.bin.Notes file *BEFORE* and *AFTER* - installation: there are a few links you must make by hand. - - This is a collection of many assorted utilities for Linux. Some are - system utilities that are not easily available anywhere elsewhere - (e.g., mkfs.minix, mkswap); others are BSD ports of common utilities - that are not yet contained in any FSF package (e.g., col); others are - non-System-V alternatives to common utilities (e.g., simpleinit, - agetty, login, passwd). - - The arrangement, as nearly as I can determine, conforms to the Linux - Filesystem Structure, Interim Release 1.1, October 9, 1994, with *NO* - exceptions. A copy of the standards document can be found at - tsx-11.mit.edu:/pub/linux/docs/linux-standards/fsstnd/*. - - Many people provided patches and suggestions. I deeply appreciate - this. - - -HIGHLIGHTS for version 2.1: - -1) Directory structure rearrange, with configuration support for those who - use shadow passwords and System V init (no support is provided for these - things, but your utilities won't get overwritten if you do a "make - install" after you properly edit MCONFIG). -2) fdisk and cfdisk should work as expected with 2GB+ disk drives -3) As usual, lots of stuff was updated and added, including mount, vipw, - readprofile -4) Some stuff was also deleted, and can now be found elsewhere: - fsck wrapper: tsx-11.mit.edu:/pub/linux/ALPHA/ext2fs/e2fsprogs* - pwd, su: prep.ai.mit.edu:/pub/gnu/sh-utils* - ed: prep.ai.mit.edu:/pub/gnu/ed* - od: prep.ai.mit.edu:/pub/gnu/textutils* - uudecode/uuencode: prep.ai.mit.edu:/pub/gnu/sharutils* - bdflush/update: ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/v1.1/bdflush* - diff --git a/util-linux-2.1.bin.Notes b/util-linux-2.1.bin.Notes deleted file mode 100644 index a2ac394c0..000000000 --- a/util-linux-2.1.bin.Notes +++ /dev/null @@ -1,549 +0,0 @@ -util-linux: Miscellaneous utilities for Linux -%n util-linux -%v 2.1 -%c * -%l * -%b * -%d * -%f ftp.cs.unc.edu:/pub/users/faith/linux/utils -%t util-linux-2.1.tar.gz -%w utils -%% -# These lines describe an automated build procedure, please ignore them. -%setup -make -%doc COPYING.GPL COPYING.UCB -%doc ./time/README.time ./disk-utils/README.cfdisk -%doc ./disk-utils/README.fdisk ./disk-utils/README.bootutils-0.1 -%doc ./sys-utils/README.setserial ./makedev-1.4.1/README.MAKEDEV-C -%doc ./misc-utils/README.script ./misc-utils/README.hostname -%doc ./misc-utils/README.namei ./misc-utils/README.cal -%doc ./misc-utils/README1.namei ./text-utils/README.col -%doc ./mount/README.mount ./selection/README.selection -%doc ./login-utils/README.getty ./login-utils/README.admutil -%doc ./login-utils/README.poeigl -%doc util-linux-$VERSION.Announce util-linux-$VERSION.lsm -cp -a $BUILDDIR/$NAME-$VERSION/example.files /usr/doc/$WHERE/$NAME-$VERSION -* rm -rf /usr/lib/zoneinfo -* make install -%i set -x -%i /usr/sbin/zic -l US/Eastern -%i /usr/sbin/zic -p America/New_York -%i set +x -%i echo 'WARNING: Check time zone! (If necessary, change with zic).' -%i echo 'WARNING: Check /etc/rc for initalization of /var/adm/utmp' -%i echo 'WARNING: /etc/rc should run /sbin/update, *NOT* /sbin/bdflush' -exit -# Please ignore the previous lines. . . -# The informative part of the notes file starts here: - -WARNING: THE PROGRAMS IN THIS SUITE DO *NOT* SUPPORT SHADOW PASSWORD FILES! - -WARNING: THIS COLLECTION DOES *NOT* SUPPORT SYSTEM V INITTAB. - -WARNING: USE GNU TAR -- OTHER TARS WILL FAIL SILENTLY! - -WARNING: DO *NOT* INSTALL WITHOUT THINKING. - -WARNING: Read the util-linux-2.1.bin.Notes file *BEFORE* and *AFTER* - installation: there are a few links you must make by hand. - -WARNING: The agetty, simpleinit, login, passwd, and other programs in this - package are *NOT* System V compliant. These utilities are meant - to be used by people who build their own systems. If you are not - a wizard, do *NOT* blindly install these utilities: they could - prevent you from logging into your system. Have a boot floppy - ready, especially if you don't know what you are doing. - -WARNING: The binary distribution was tarred using GNU TAR AND THE -S OPTION! - This means that holes will be preserved, but that ONLY GNU TAR - WILL WORK ON THE BINARY DISTRIBUTION (in fact, other, inferior, - tar programs will fail silently). YOU HAVE BEEN WARNED! - -WARNING: localtime and posixtime default to US/Eastern -- change these now. - - - -To install from the binary distribution: - -1) Get binary distribution (see the .lsm file for locations) -2) cd / -3) gtar zpxvf util-linux-2.1.bin.tar.gz - (or: pms -i util-linux-2.1.bin.tar.gz) -4) *IF* you want to use agetty and simpleinit, then make softlinks from - /sbin/init to simpleinit and from /sbin/getty to agetty, but make sure - that your /etc/inittab is set up right (this is *NOT* the System V - compatible init!), or you will be hosed. -5) Run zic -l and/or zic -p to set your timezone. The distribution is set - up to use /usr/lib/zoneinfo/US/Eastern as the default. This was - installed with "zic -l US/Eastern" -6) Remove all the old binaries from previous locations. - - - -To install from source: - -1) Get source distribution (see the .lsm file for locations) -2) Untar util-linux-2.1.tar.gz in /usr/src -3) cd util-linux-2.1 -4) Edit MCONFIG: - - If you use the shadow password suite and do _not_ want to install - programs like login and passwd that do not support shadow passwords, - then set HAVE_SHADOW to yes - - If you use the System V init suite and do _not_ want to install programs - like agetty, simpleinit, and shutdown, then set HAVE_SYSVINIT to yes - - If you don't like the compile-time options or the directories, then - change them. Note that you also can say something like "make OPT=-g - LDFLAGS=" in order to make a complete debugging version without editing - the MCONFIG at all. - -5) make -6) make install -7) If you want to use simpleinit and agetty, then make softlinks from - /sbin/init to simpleinit and from /sbin/getty to agetty, but make sure - that your /etc/inittab is set up right (this is *NOT* the System V - compatible init!), or you will be hosed. If you are using the SysV - init and/or some other getty, they you can keep using those. -8) Run zic -l and/or zic -p to set your timezone. The distribution is set - up to use /usr/lib/zoneinfo/US/Eastern as the default. This was - installed with "zic -l US/Eastern" -9) Remove all the old binaries from previous locations. - - - -HIGHLIGHTS for version 2.1: - -1) Directory structure rearrange, with configuration support for those who - use shadow passwords and System V init (no support is provided for these - things, but your utilities won't get overwritten if you do a "make - install" after you properly edit MCONFIG). -2) fdisk and cfdisk should work as expected with 2GB+ disk drives -3) As usual, lots of stuff was updated and added, including mount, vipw, - readprofile -4) Some stuff was also deleted, and can now be found elsewhere: - fsck wrapper: tsx-11.mit.edu:/pub/linux/ALPHA/ext2fs/e2fsprogs* - pwd, su: prep.ai.mit.edu:/pub/gnu/sh-utils* - ed: prep.ai.mit.edu:/pub/gnu/ed* - od: prep.ai.mit.edu:/pub/gnu/textutils* - uudecode/uuencode: prep.ai.mit.edu:/pub/gnu/sharutils* - bdflush/update: ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/v1.1/bdflush* - - - -PARTIAL HISTORY OF UTIL-LINUX: - -bsd: - Nothing in this directory gets installed, but some BSD programs need - this support: - err.c: 8.1 (Berkeley) 6/4/93 - err.h: 8.1 (Berkeley) 6/2/93 - getopt.c: 4.13 (Berkeley) 2/23/91 - pathnames.h: 5.3 (Berkeley) 5/9/89 with extensive modifications for - Linux - -disk-utils: - cfdisk: 0.8 BETA (>2GB) from Kevin E. Martin (martin@cs.unc.edu) with - modifications for disks > 2GB. - ftp.cs.unc.edu:/pub/users/martin/linux/cfdisk-0.8.tar.gz - fdformat: Werner Almesberger (almesber@nessie.cs.id.ethz.ch), with - modifications by Marcel Mol (marcel@dutecad.et.tudelft.nl)). - Later, updated with a September 1992 version by Werner. - fdisk: A. V. Le Blanc (LeBlanc@mcc.ac.uk) fdisk 1.5 release, with - patched from Kevin Martin for DOS and OS/2 compatibility (1.5a); - Rik Faith (1.5b, 2.0). - frag: Werner Almesberger (1.0), Steffen Zahn (1.1), Rob Hooft (1.2), - Steffen Zahn (szahn%masterix@emndev.siemens.co.at) (1.3), Michael - Bischoff (1.4). - fsck.minix, mkfs.minix: Linus Torvalds, with modifications by: Rik - Faith (faith@cs.unc.edu), Scott Heavner - (sdh@po.cwru.edu), Dr. Wettstein - (greg%wind.uucp@plains.nodak.edu), Daniel - Quinlan (quinlan@yggdrasil.com). - mkswap: Linus Torvalds, with modifications by Mike Jagdis - (jaggy@purplet.demon.co.uk. ) - setfdprm: Werner Almesberger (almesber@nessie.cs.id.ethz.ch) - llseek.c: from Remy Card's e2fsprogs-0.5b-WIP.tar.gz - -games: - banner: (8.3 (Berkeley) 4/2/94) - ddate: Druel the Chaotic aka Jeremy Johnson aka mpython@gnu.ai.mit.edu, - with modifications by Lee Harvey Oswald Smith, K.S.C. - -login-utils: - agetty: W. Z. Venema, ported by Peter Orbaek . - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.32.tar.gz - chfn: Salvatore Valente - chsh: Salvatore Valente - last: 5.11 w/year (Berkeley) 6/29/88; Port by Michael Haardt with - changes by Peter Orbaek. - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.14.tar.gz - login: 5.40 (Berkeley) 5/9/89; with ports by Michael Glad and Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.32.tar.gz - mesg: Miquel van Smoorenburg (miquels@htsa.aha.nl, - miquels@drinkel.nl.mugnet.org). From his sysvinit.tar.Z package. - newgrp: Michael Haardt, with modifications by Peter Orbaek. - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.14.tar.gz - passwd: Peter Orbaek, with yp modifications by Alvaro Martinez - Echevarria (alvaro@enano.etsit.upm.es) - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.14.tar.gz - shutdown: Peter Orbaek, with new modifications by Stephen Tweedie, Rik - Faith, and Dave (gentzel@nova.enet.dec.com). - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.14.tar.gz - simpleinit: Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.32.tar.gz - vipw: 5.16 (Berkeley) 3/3/91, with modifications by Mike Grupenhoff - - wall: 5.14 (Berkeley) 3/2/91 [From the BSD NET-2 (4.3bsd-reno) - distribution at wuarchive.wustl.edu:/mirrors/4.3-reno] - -makedev-1.4: - MAKEDEV-C: David A. Holland (dholland@husc.harvard.edu) - This version MODIFIED by Rik Faith (faith@cs.unc.edu) - sunsite.unc.edu:/pub/Linux/system/Admin/MAKEDEV-C-1.4.tar.gz - - -misc-utils: - cal: 8.4 (Berkeley) 4/2/94, with modifications by Rik Faith and - Hein@student.tu-clausthal.de (Jochen Hein). - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - clear: Rik Faith - domainname: Peter Orbaek - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.32.tar.gz - dsplit: David Arnstein (arnstein@netcom.com) - gatekeeper.dec.com:/pub/usenet/comp.sources.misc/volume40/dsplit - getopt (getoptprog): jhunix.hcf.jhu.edu: - /pub/public_domain_software/NetBSD/usr/src/usr.bin/getopt - hostid: Mitch DSouza (m.dsouza@mrc-apu.cam.ac.uk) - ftp.daimi.aau.dk:/pub/linux/poe/poeigl-1.32.tar.gz - hostname/dnsdomainname: Peter Tobias - This version (1.6) should also be available soon in: - nic.funet.fi:/pub/OS/Linux/PEOPLE/Linus/net-source/base/NetKit-A* - kill: BSD version, modified by Salvatore Valente - logger: 8.1 (Berkeley) 6/6/93, with modifications by Rik Faith - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - look.c: 8.1 (Berkeley) 6/14/93, with modifications by Rik Faith - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - mcookie: Rik Faith (faith@cs.unc.edu) - md5sum: Branki Lankester and Colin Plumb. The MD5 message-digest - algorithm is in the Public Domain. This implementation - calculates message-digest information only, and can NOT be used - for encryption. Therefore it is exportable from the USA. - Original sources in the MIT version of PGP 2.6.2. - namei: Roger S. Southwick, with modifications by Steve Tell. - reset: Rik Faith - script: 5.13 (Berkeley) 3/5/91, with modifications by Rick Sladkey - (jrs@world.std.com), Harald Koenig - (koenig@nova.tat.physik.uni-tuebingen.de). - setterm: Gordon Irlam (gordoni@cs.ua.oz.au), with modifications by - Peter MacDonald, Mika Liljeberg (liljeber@cs.Helsinki.FI), - John Walder (j-walder@uiuc.edu) [for dosemu]. - tsort: 5.3 (Berkeley) 6/1/90 - wuarchive.wustl.edu:/mirrors/4.3-reno - whereis: 5.5 (Berkeley) 4/18/91 - wuarchive.wustl.edu:/mirrors/4.3-reno - write: 4.22 (Berkeley) 6/1/90, with modifications by Mike Grupenhoff - (kashmir@umiacs.umd.edu) . - wuarchive.wustl.edu:/mirrors/4.3-reno - -mount: - mount, umount, swapon - - Rick Sladkey put together the mount-0.99.6.tar.Z package, and Stephen - Tweedie provided updates. The utilities were originally from that - package (all appear to be by Doug Quale (quale@saavik.cs.wisc.edu), - with modifications by H. J. Lu (hlu@eecs.wsu.edu) on 11/25/92; Rick - Sladkey (jrs@world.std.com) in January 1993; and Stephen Tweedie - on 8 October 1993. 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. Mike Grupenhoff - added a probe of the superblock for the type - before /proc/filesystems is checked. Andries.Brouwer@cwi.nl fixed up - error reporting. - -selection: - The complete selection-1.5 package, by Andrew Haylett - , 17th June 1993, is included. Kernel patches are - no longer necessary for modern kernels, but these were tiny so I left - them in for historical reasons. The Makefile was modified for this - distribution. With changes from Rick Sladkey. - -sys-utils: - MAKEDEV: Nick Holloway - arch: Rik Faith - chroot: Rick Sladkey - clock: Originally from the timesrc-1.2.tar.Z package, Charles Hedrick, - hedrick@cs.rutgers.edu (V1.0); Rob Hooft, hooft@chem.ruu.nl - (V1.1); Harald Koenig (koenig@nova.tat.physik.uni-tuebingen.de) - (V1.2). With additional changes: Hamish Coleman - (hamish@zot.apana.org.au) (V1.2a); Alan Modra - (alan@spri.levels.unisa.edu.au (V1.3, V1.4). - ctrlaltdel: Peter Orbaek - ftp://ftp.daimi.aau.dk/pub/linux/poe/admutil-1.14.tar.gz - dmesg: Theodore Ts'o (tytso@athena.mit.edu); Rick Sladkey - (jrs@world.std.com) - ipcrm: From the ipcdelta.tar.z distribution by krishna - balasub@cis.ohio-state.edu on 3/15/93. ipc.info and ipc.texi - are also from that distribution. - ipcs: Also from the ipcdelta.tar.z distribution by krishna - balasub@cis.ohio-state.edu, with patches from Mike Jagdis - (jaggy@purplet.demon.co.uk) - kbdrate: Rik Faith (faith@cs.unc.edu), with patches from - Andries.Brouwer@cwi.nl and John Bowman - (bowman@hagar.ph.utexas.edu) - lpcntl: Nigel Gamble (nigel@gate.net) - rdev: almesber@nessie.cs.id.ethz.ch (Werner Almesberger), with - modifications from Peter MacDonald, Stephen Tweedie - (sct@dcs.ed.ac.uk), and Dave (gentzel@nova.enet.dec.com) - readprofile: Alessandro Rubini - renice: 8.1 (Berkeley) 6/9/93 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - setserial: 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. - setsid: Rick Sladkey - sln: Mike Parker and David MacKenzie (from Linux's libc) - sync: Nick Holloway, with thanks to James Bonfield - tunelp: Michael K. Johnson (johnsonm@nigel.vnet.net) - update_state: Rik Faith (faith@cs.unc.edu) - -syslogd: - 5.45 (Berkeley) 3/2/91 - - 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). - -text-utils: - col: 5.3 (Berkeley) 2/2/91; with patches from Andries.Brouwer@cwi.nl - and Carl Christofferson (cchris@connected.com) - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - colcrt: 8.1 (Berkeley) 6/6/93 (Bill Joy) - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - colrm: 5.4 (Berkeley) 6/1/90 (Jeff Schriebman) - column: 8.3 (Berkeley) 4/2/94 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - hexdump: 5.5 (Berkeley) 6/1/90 - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - more: 5.19 (Berkeley) 6/29/88 (Eric Shienbrood, Geoff Peck, John Foderaro) - rev: 5.2 (Berkeley) 3/21/92; with modifications by Charles Hannum - (mycroft@gnu.ai.mit.edu), Brian Koehmstedt (bpk@gnu.ai.mit.edu), - bjdouma@xs4all.nl - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - strings: 5.10 (Berkeley) 5/23/91; with patches from Vitor Duarte - - wuarchive.wustl.edu:/mirrors/4.3-reno/{bin,usr.bin} - ul: 8.1 (Berkeley) 6/6/93 - ftp.cdrom.com:/pub/bsd-sources/4.4BSD-Lite/usr/src/usr.bin - -time: - elsie.nci.nih.gov:/pub/classictzcode.tar.gz - elsie.nci.nih.gov:/pub/classictzdata.tar.gz - (The zoneinfo database was updated Dec 1994.) - -%% -* bin/arch -* bin/dmesg -* bin/dnsdomainname -* bin/domainname -* bin/hostname -* bin/kill -* bin/login -* bin/more -* bin/mount -* bin/setserial -* bin/sync -* bin/umount -* dev/MAKEDEV -* dev/MAKEDEV-C -* etc/DEVINFO -* etc/MAKEDEV.cfg -* etc/fdprm -* sbin/agetty -* sbin/cfdisk -* sbin/clock -* sbin/fastboot -* sbin/fasthalt -* sbin/fdisk -* sbin/fsck.minix -* sbin/halt -* sbin/kbdrate -* sbin/mkfs.minix -* sbin/mkswap -* sbin/reboot -* sbin/shutdown -* sbin/simpleinit -* sbin/sln -* sbin/swapoff -* sbin/swapon -* usr/bin/cal -* usr/bin/chfn -* usr/bin/chsh -* usr/bin/clear -* usr/bin/col -* usr/bin/colcrt -* usr/bin/colrm -* usr/bin/column -* usr/bin/dsplit -* usr/bin/fdformat -* usr/bin/getopt -* usr/bin/hexdump -* usr/bin/hostid -* usr/bin/ipcrm -* usr/bin/ipcs -* usr/bin/last -* usr/bin/logger -* usr/bin/look -* usr/bin/lpcntl -* usr/bin/mcookie -* usr/bin/md5sum -* usr/bin/mesg -* usr/bin/namei -* usr/bin/newgrp -* usr/bin/passwd -* usr/bin/ramsize -* usr/bin/rdev -* usr/bin/readprofile -* usr/bin/renice -* usr/bin/reset -* usr/bin/rev -* usr/bin/rootflags -* usr/bin/script -* usr/bin/selection -* usr/bin/setfdprm -* usr/bin/setsid -* usr/bin/setterm -* usr/bin/strings -* usr/bin/swapdev -* usr/bin/tsort -* usr/bin/tunelp -* usr/bin/ul -* usr/bin/vidmode -* usr/bin/wall -* usr/bin/whereis -* usr/bin/write -* usr/info/ipc.info -* usr/lib/libz.a -* usr/lib/more.help -* usr/lib/zoneinfo -* usr/man/man1/arch.1 -* usr/man/man1/cal.1 -* usr/man/man1/chfn.1 -* usr/man/man1/chsh.1 -* usr/man/man1/clear.1 -* usr/man/man1/col.1 -* usr/man/man1/colcrt.1 -* usr/man/man1/colrm.1 -* usr/man/man1/column.1 -* usr/man/man1/dnsdomainname.1 -* usr/man/man1/domainname.1 -* usr/man/man1/dsplit.1 -* usr/man/man1/getopt.1 -* usr/man/man1/hexdump.1 -* usr/man/man1/hostid.1 -* usr/man/man1/hostname.1 -* usr/man/man1/kill.1 -* usr/man/man1/last.1 -* usr/man/man1/logger.1 -* usr/man/man1/login.1 -* usr/man/man1/look.1 -* usr/man/man1/md5sum.1 -* usr/man/man1/mesg.1 -* usr/man/man1/more.1 -* usr/man/man1/namei.1 -* usr/man/man1/newgrp.1 -* usr/man/man1/passwd.1 -* usr/man/man1/readprofile.1 -* usr/man/man1/reset.1 -* usr/man/man1/rev.1 -* usr/man/man1/script.1 -* usr/man/man1/selection.1 -* usr/man/man1/setterm.1 -* usr/man/man1/strings.1 -* usr/man/man1/tsort.1 -* usr/man/man1/ul.1 -* usr/man/man1/wall.1 -* usr/man/man1/whereis.1 -* usr/man/man1/write.1 -* usr/man/man3/newctime.3 -* usr/man/man3/newtzset.3 -* usr/man/man5/DEVINFO.5 -* usr/man/man5/MAKEDEV.cfg.5 -* usr/man/man5/fstab.5 -* usr/man/man5/nfs.5 -* usr/man/man5/syslog.conf.5 -* usr/man/man5/tzfile.5 -* usr/man/man6/banner.6 -* usr/man/man6/ddate.6 -* usr/man/man8/MAKEDEV-C.8 -* usr/man/man8/MAKEDEV.8 -* usr/man/man8/agetty.8 -* usr/man/man8/cfdisk.8 -* usr/man/man8/chroot.8 -* usr/man/man8/clock.8 -* usr/man/man8/ctrlaltdel.8 -* usr/man/man8/dmesg.8 -* usr/man/man8/fastboot.8 -* usr/man/man8/fasthalt.8 -* usr/man/man8/fdformat.8 -* usr/man/man8/fdisk.8 -* usr/man/man8/frag.8 -* usr/man/man8/fsck.minix.8 -* usr/man/man8/halt.8 -* usr/man/man8/ipcrm.8 -* usr/man/man8/ipcs.8 -* usr/man/man8/kbdrate.8 -* usr/man/man8/lpcntl.8 -* usr/man/man8/mkfs.minix.8 -* usr/man/man8/mkswap.8 -* usr/man/man8/mount.8 -* usr/man/man8/ramsize.8 -* usr/man/man8/rdev.8 -* usr/man/man8/reboot.8 -* usr/man/man8/renice.8 -* usr/man/man8/rootflags.8 -* usr/man/man8/setfdprm.8 -* usr/man/man8/setserial.8 -* usr/man/man8/setsid.8 -* usr/man/man8/shutdown.8 -* usr/man/man8/simpleinit.8 -* usr/man/man8/swapdev.8 -* usr/man/man8/swapoff.8 -* usr/man/man8/swapon.8 -* usr/man/man8/sync.8 -* usr/man/man8/syslogd.8 -* usr/man/man8/tunelp.8 -* usr/man/man8/umount.8 -* usr/man/man8/update_state.8 -* usr/man/man8/vidmode.8 -* usr/man/man8/vipw.8 -* usr/man/man8/zdump.8 -* usr/man/man8/zic.8 -* usr/sbin/chroot -* usr/sbin/ctrlaltdel -* usr/sbin/frag -* usr/sbin/syslogd -* usr/sbin/update_state -* usr/sbin/vipw -* usr/sbin/zdump -* usr/sbin/zic diff --git a/util-linux-2.1.lsm b/util-linux-2.1.lsm deleted file mode 100644 index a3c8d51f8..000000000 --- a/util-linux-2.1.lsm +++ /dev/null @@ -1,23 +0,0 @@ -Begin3 -Title: util-linux: Miscellaneous utilities for Linux -Version: 2.1 -Entered-date: Thu Feb 16 09:23:18 1995 -Description: reboot shutdown simpleinit sln swapoff swapon cal chfn chsh - clear col colcrt colrm column dnsdomainname domainname - dsplit fdformat getopt hexdump hostid hostname ipcrm ipcs - last logger look lpcntl mcookie md5sum mesg namei newgrp - passwd ramsize rdev readprofile renice reset rev rootflags - script selection setfdprm setsid setterm strings swapdev - tsort tunelp ul vidmode wall whereis write chroot - ctrlaltdel frag syslogd update_state vipw zdump zic -Keywords: essential utilities -Author: several -Maintained-by: faith@cs.unc.edu (Rik Faith) -Primary-site: ftp.cs.unc.edu /pub/users/faith/linux - 640k util-linux-2.1.tar.gz - 570k util-linux-2.1.bin.tar.gz -Alternate-site: tsx-11.mit.edu /pub/linux/packages/utils -Alternate-site: sunsite.unc.edu /pub/Linux/system/Misc -Platforms: Linux 1.1.8x, GNU tar -Copying-policy: GPL, BSD, others -End diff --git a/version.h b/version.h index 030f84979..4b8deb079 100644 --- a/version.h +++ b/version.h @@ -1,2 +1,3 @@ -#define UTIL_LINUX 1 -char *util_linux_version="util-linux 2.8"; +#define UTIL_LINUX_VERSION "2.9i" + +const char * const util_linux_version = "util-linux " UTIL_LINUX_VERSION; -- cgit v1.2.3-55-g7522