From 956ef430e979f410898608dc5099f0c54e05e2b1 Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Sun, 4 Apr 1993 00:00:00 +0000 Subject: [PATCH] Add the source code for fdisk, quotacheck, and mount_pcfs to sbin This patch adds the source code for the fdisk program that Julian Elischer wrote. Includes manual pages and lattest bug fixes as of 4/4/93. This patch adds the source code for the quotacheck program from the Net/2 release tape. There are 2 uninitialized variables in the Net/2 code. dev_bsize is initialized in the wrong place; this bug only shows itself if quotacheck is run on more than one disk partition. This patch adds the source code for the mount_pcfs program that is part of the pcfs package by Pual Popelka. AUTHOR: Julian Elischer (???) (fdisk) AUTHOR: Rodney W. Grimes (rgrimes@agora.rain.com) (Net/2 quotacheck) AUTHOR: Paul Popelka (paulp@uts.amdahl.com) (mount_pcfs) AUTHOR: Kent Talarico (kent@shipwreck.tsoft.net) (Net/2 quotacheck fixes) 386BSD-Patchkit: patch00111 --- usr/src/sbin/Makefile | 18 +- usr/src/sbin/fdisk/Makefile | 9 + usr/src/sbin/fdisk/fdisk.8 | 177 +++++++ usr/src/sbin/fdisk/fdisk.c | 686 +++++++++++++++++++++++++++ usr/src/sbin/mount_pcfs/Makefile | 5 + usr/src/sbin/mount_pcfs/mount_pcfs.c | 65 +++ usr/src/sbin/quotacheck/Makefile | 8 + usr/src/sbin/quotacheck/quotacheck.8 | 157 ++++++ usr/src/sbin/quotacheck/quotacheck.c | 595 +++++++++++++++++++++++ 9 files changed, 1717 insertions(+), 3 deletions(-) create mode 100644 usr/src/sbin/fdisk/Makefile create mode 100644 usr/src/sbin/fdisk/fdisk.8 create mode 100644 usr/src/sbin/fdisk/fdisk.c create mode 100644 usr/src/sbin/mount_pcfs/Makefile create mode 100644 usr/src/sbin/mount_pcfs/mount_pcfs.c create mode 100644 usr/src/sbin/quotacheck/Makefile create mode 100644 usr/src/sbin/quotacheck/quotacheck.8 create mode 100644 usr/src/sbin/quotacheck/quotacheck.c diff --git a/usr/src/sbin/Makefile b/usr/src/sbin/Makefile index ef2a67522e..73d335241f 100644 --- a/usr/src/sbin/Makefile +++ b/usr/src/sbin/Makefile @@ -1,8 +1,20 @@ # @(#)Makefile 5.4.1.1 (Berkeley) 5/7/91 +# +# PATCHES MAGIC LEVEL PATCH THAT GOT US HERE +# -------------------- ----- ---------------------- +# CURRENT PATCH LEVEL: 1 00111 +# -------------------- ----- ---------------------- +# +# 04 Apr 93 Rodney W. Grimes Add fdisk, mount_pcfs, quotacheck +# Comments about not ported and missing +# -SUBDIR= badsect clri disklabel dmesg dump dumpfs fastboot fsck \ - halt ifconfig init mknod mount mount_isofs mountd newfs \ - nfsd nfsiod ping reboot restore route routed savecore \ +SUBDIR= badsect clri disklabel dmesg dump dumpfs fastboot fdisk fsck \ + halt ifconfig init mknod mount mount_isofs mount_pcfs mountd newfs \ + nfsd nfsiod ping quotacheck reboot restore route routed savecore \ shutdown slattach swapon tunefs umount +# Not ported: XNSrouted enpload +# Missing: icheck ncheck + .include diff --git a/usr/src/sbin/fdisk/Makefile b/usr/src/sbin/fdisk/Makefile new file mode 100644 index 0000000000..38e3faddaa --- /dev/null +++ b/usr/src/sbin/fdisk/Makefile @@ -0,0 +1,9 @@ +# @(#)Makefile 1.1 (Julian Elischer) 3/28/93 +# +# + +PROG= fdisk +SRCS= fdisk.c +MAN8= fdisk.0 + +.include diff --git a/usr/src/sbin/fdisk/fdisk.8 b/usr/src/sbin/fdisk/fdisk.8 new file mode 100644 index 0000000000..078ae5ea38 --- /dev/null +++ b/usr/src/sbin/fdisk/fdisk.8 @@ -0,0 +1,177 @@ +.Dd April 4, 1993 +.Dt FDISK 8 +.\".Os BSD 4 +.Sh NAME +.Nm fdisk +.Nd DOS partition maintainance program +.Sh SYNOPSIS +.Nm +.Op Fl i +.Op Fl u +.Bl -tag -width time +.It Fl i +Initializes sector 0 of the disk. +.It Fl u +Is used for updating (editing) sector 0 of the disk. +.El +.Sh PROLOGUE +In order for the BIOS to boot the kernel, +certain conventions must be adhered to. +Sector 0 of the disk must contain boot code, +a partition table, +and a magic number. +BIOS partitions can be used to break the disk up into several pieces. +The BIOS brings in sector 0 +(does it really use the code?) +and verifies the magic number. +It then searches the 4 BIOS partitions described by sector 0 +to determine which of them is +.Em active. +This boot then brings in the secondary boot block from the +.Em active +partition and runs it. +Under DOS, +you could have one or more partitions with one +.Em active. +The DOS +.Nm +program can be used to divide space on the disk into partitions and set one +.Em active. +.Sh DESCRIPTION +The 386bsd program +.Nm +serves a similar purpose to the DOS program. +When called with no arguments, it prints the sector 0 partition table. +An example follows: + +.Bd -literal + ******* Working on device /dev/rwd0d ******* + parameters extracted from in-core disklabel are: + cylinders=769 heads=15 sectors/track=33 (495 blks/cyl) + + parameters to be used for BIOS calculations are: + cylinders=769 heads=15 sectors/track=33 (495 blks/cyl) + + Warning: BIOS sector numbering starts with sector 1 + Information from DOS bootblock is: + The data for partition 0 is: + sysid 165,(386BSD) + start 495, size 380160 (185 Meg), flag 0 + beg: cyl 1/ sector 1/ head 0; + end: cyl 768/ sector 33/ head 14 + The data for partition 1 is: + sysid 164,(unknown) + start 378180, size 2475 (1 Meg), flag 0 + beg: cyl 764/ sector 1/ head 0; + end: cyl 768/ sector 33/ head 14 + The data for partition 2 is: + + The data for partition 3 is: + sysid 99,(ISC UNIX, other System V/386, GNU HURD or Mach) + start 380656, size 224234 (109 Meg), flag 80 + beg: cyl 769/ sector 2/ head 0; + end: cyl 197/ sector 33/ head 14 +.Ed +.Pp +The disk is divided into three parititions that happen to fill the disk. +The second partition overlaps the end of the first. +(Used for debugging purposes) +.Bl -tag -width "cyl, sector and head" +.It Em "sysid" +is used to label the partition. 386bsd reserves the +magic number 165 decimal (A5 in hex). +.It Em "start and size" +fields provide the start address +and size of a parition in sectors. +.It Em "flag 80" +specifies that this is the active partition. +.It Em "cyl, sector and head" +fields are used to specify the beginning address +and end address for the parititon. +.It Em "Note:" +these numbers are calculated using BIOS's understanding of the disk geometry +and saved in the bootblock. +.El +.Pp +The flags +.Fl i +or +.Fl u +are used to indicate that the paritition data is to be updated. +The +.Nm +program will enter a conversational mode. +This mode is designed not to change any data unless you explicitly tell it to. +.Nm +selects defaults for its questions to guarantee the above behaviour. +.Pp +It displays each partition +and ask if you want to edit it. +If you say yes, +it will step through each field showing the old value +and asking for a new one. +When you are done with a partition, +.Nm +will display it and ask if it is correct. +.Nm +will then procede to the next entry. +.Pp +Getting the +.Em cyl, sector, +and +.Em head +fields correct is tricky. +So by default, +they will be calculated for you; +you can specify them if you choose. +.Pp +After all the partitions are processed, +you are given the option to change the +.Em active +partition. +Finally, +when the all the data for the first sector has been accumulated, +you are asked if you really want to rewrite sector 0. +Only if you answer yes, +will the data be written to disk. +.Pp +The difference between the +.Fl u +flag and +.Fl i +flag is that +the +.Fl u +flag just edits the fields as they appear on the disk. +While the +.Fl i +flag is used to "initialize" sector 0; +it will setup the last BIOS partition to use the whole disk for 386bsd; +and make it active. +.Sh NOTES +.Pp +The automatic calculation of starting cylinder etc. uses +a set of figures that represent what the BIOS thinks is the +geometry of the drive. +These figures are by default taken from the incore disklabel, +but the program initially gives you an oportunity to change them. +This allows the user to create a bootblock that can work with drives +that use geometry translation under the BIOS. +.Pp +If you hand craft your disk layout, +please make sure that the 386bsd partition starts on a cylinder boundary. +A number of decisions made later may assume this. +(This might not be necessary later.) +.Pp +Editing an existing partition will most likely cause you to +lose all the data in that partition. +.Pp +You should run this program interactively once or twice to see how it works. +This is completely safe as long as you answer the last question in the negative. +There are subtleties +that the program detects +that are not fully explained in this manual page. +.Sh SEE ALSO +.Xr disklabel 8 +.Sh BUGS +One less now, but probably more diff --git a/usr/src/sbin/fdisk/fdisk.c b/usr/src/sbin/fdisk/fdisk.c new file mode 100644 index 0000000000..7fb728d67d --- /dev/null +++ b/usr/src/sbin/fdisk/fdisk.c @@ -0,0 +1,686 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include +#include +#include +#include +#include + +int iotest; + +#define LBUF 100 +static char lbuf[LBUF]; + +/* + * + * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 + * + * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University + * Copyright (c) 1989 Robert. V. Baron + * Created. + */ + +#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp +#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp +#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } + +#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) + +#define SECSIZE 512 + +char *disk = "/dev/rwd0d"; +char *name; + +struct disklabel disklabel; /* disk parameters */ + +int cyls, sectors, heads, cylsecs, disksecs; + +struct mboot +{ + unsigned char padding[2]; /* force the longs to be long alligned */ + unsigned char bootinst[DOSPARTOFF]; + struct dos_partition parts[4]; + unsigned short int signature; +}; +struct mboot mboot; + +#define ACTIVE 0x80 +#define BOOT_MAGIC 0xAA55 + +int dos_cyls; +int dos_heads; +int dos_sectors; +int dos_cylsecs; + +#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) +#define DOSCYL(c) (c & 0xff) +static int dos(); +char *get_type(); +static int partition = -1; + + +static int a_flag = 0; /* set active partition */ +static int i_flag = 0; /* replace partition data */ +static int u_flag = 0; /* update partition data */ + +static unsigned char bootcode[] = { +0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf, +0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe, +0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd, +0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74, +0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00, +0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe, +0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00, +0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10, +0xeb, 0xf4, 0xfb, 0xeb, 0xfe, +'M', 'i', 's', 's', 'i', 'n', 'g', ' ', + 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, +'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ', + 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, +'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', + 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0, +'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ', + 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +struct part_type +{ + unsigned char type; + char *name; +}part_types[] = +{ + {0x00, "unused"} + ,{0x01, "Primary DOS with 12 bit FAT"} + ,{0x02, "XENIX / filesystem"} + ,{0x03, "XENIX /usr filesystem"} + ,{0x04, "Primary DOS with 16 bit FAT"} + ,{0x05, "Extended DOS"} + ,{0x06, "Primary 'big' DOS (> 32MB)"} + ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"} + ,{0x08, "AIX filesystem"} + ,{0x09, "AIX boot partition or Coherent"} + ,{0x0A, "OS/2 Boot Manager or OPUS"} + ,{0x10, "OPUS"} + ,{0x40, "VENIX 286"} + ,{0x50, "DM"} + ,{0x51, "DM"} + ,{0x52, "CP/M or Microport SysV/AT"} + ,{0x56, "GB"} + ,{0x61, "Speed"} + ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} + ,{0x64, "Novell Netware 2.xx"} + ,{0x65, "Novell Netware 3.xx"} + ,{0x75, "PCIX"} + ,{0x80, "Minix 1.1 ... 1.4a"} + ,{0x81, "Minix 1.4b ... 1.5.10"} + ,{0x82, "Linux"} + ,{0x93, "Amoeba filesystem"} + ,{0x94, "Amoeba bad block table"} + ,{0xA5, "386BSD"} + ,{0xB7, "BSDI BSD/386 filesystem"} + ,{0xB8, "BSDI BSD/386 swap"} + ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} + ,{0xE1, "Speed"} + ,{0xE3, "Speed"} + ,{0xE4, "Speed"} + ,{0xF1, "Speed"} + ,{0xF2, "DOS 3.3+ Secondary"} + ,{0xF4, "Speed"} + ,{0xFF, "BBT (Bad Blocks Table)"} +}; + + +main(argc, argv) +char **argv; +{ +int i; + + name = *argv; + {register char *cp = name; + while (*cp) if (*cp++ == '/') name = cp; + } + + for ( argv++ ; --argc ; argv++ ) { register char *token = *argv; + if (*token++ != '-' || !*token) + break; + else { register int flag; + for ( ; flag = *token++ ; ) { + switch (flag) { + case '0': + partition = 0; + break; + case '1': + partition = 1; + break; + case '2': + partition = 2; + break; + case '3': + partition = 3; + break; + case 'a': + a_flag = 1; + break; + case 'i': + i_flag = 1; + case 'u': + u_flag = 1; + break; + default: + goto usage; + } + } + } + } + + if (argc > 0) + disk = argv[0]; + + if (open_disk(u_flag) < 0) + exit(1); + + printf("******* Working on device %s *******\n",disk); + if(u_flag) + { + get_params_to_use(); + } + else + { + print_params(); + } + + if (read_s0()) + init_sector0(1); + + printf("Warning: BIOS sector numbering starts with sector 1\n"); + printf("Information from DOS bootblock is:\n"); + if (partition == -1) + for (i = 0; i < NDOSPART; i++) + change_part(i); + else + change_part(partition); + + if (u_flag || a_flag) + change_active(partition); + + if (u_flag || a_flag) { + printf("\nWe haven't changed the partition table yet. "); + printf("This is your last chance.\n"); + print_s0(-1); + if (ok("Should we write new partition table?")) + write_s0(); + } + + exit(0); + +usage: + printf("fdisk {-a|-i|-r} {disk}\n"); +} + +print_s0(which) +{ +int i; + + print_params(); + printf("Information from DOS bootblock is:\n"); + if (which == -1) + for (i = 0; i < NDOSPART; i++) + printf("%d: ", i), print_part(i); + else + print_part(which); +} + +static struct dos_partition mtpart = { 0 }; + +print_part(i) +{ +struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i; + + + if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { + printf("\n"); + return; + } + printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); + printf(" start %d, size %d (%d Meg), flag %x\n", + partp->dp_start, + partp->dp_size, partp->dp_size * 512 / (1024 * 1024), + partp->dp_flag); + printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" + ,DPCYL(partp->dp_scyl, partp->dp_ssect) + ,DPSECT(partp->dp_ssect) + ,partp->dp_shd + ,DPCYL(partp->dp_ecyl, partp->dp_esect) + ,DPSECT(partp->dp_esect) + ,partp->dp_ehd); +} + +init_sector0(start) +{ +struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); +int size = disksecs - start; +int rest; + + memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); + mboot.signature = BOOT_MAGIC; + + partp->dp_typ = DOSPTYP_386BSD; + partp->dp_flag = ACTIVE; + partp->dp_start = start; + partp->dp_size = size; + + dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); +} + +change_part(i) +{ +struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i; + + printf("The data for partition %d is:\n", i); + print_part(i); + + if (u_flag && ok("Do you want to change it?")) { + int tmp; + + if (i_flag) { + bzero((char *)partp, sizeof (struct dos_partition)); + if (i == 3) { + init_sector0(1); + printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n"); + print_part(i); + } + } + + do { + Decimal("sysid", partp->dp_typ, tmp); + Decimal("start", partp->dp_start, tmp); + Decimal("size", partp->dp_size, tmp); + + if (ok("Explicitly specifiy beg/end address ?")) + { + int tsec,tcyl,thd; + tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); + thd = partp->dp_shd; + tsec = DPSECT(partp->dp_ssect); + Decimal("beginning cylinder", tcyl, tmp); + Decimal("beginning head", thd, tmp); + Decimal("beginning sector", tsec, tmp); + partp->dp_scyl = DOSCYL(tcyl); + partp->dp_ssect = DOSSECT(tsec,tcyl); + partp->dp_shd = thd; + + tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); + thd = partp->dp_ehd; + tsec = DPSECT(partp->dp_esect); + Decimal("ending cylinder", tcyl, tmp); + Decimal("ending head", thd, tmp); + Decimal("ending sector", tsec, tmp); + partp->dp_ecyl = DOSCYL(tcyl); + partp->dp_esect = DOSSECT(tsec,tcyl); + partp->dp_ehd = thd; + } else { + dos(partp->dp_start, + &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start+partp->dp_size - 1, + &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); + } + + print_part(i); + } while (!ok("Are we happy with this entry?")); + } +} + +print_params() +{ + printf("parameters extracted from in-core disklabel are:\n"); + printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" + ,cyls,heads,sectors,cylsecs); + if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) + printf(" Figures below won't work with BIOS for partitions not in cyl 1\n"); + printf("parameters to be used for BIOS calculations are:\n"); + printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" + ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); +} + +change_active(which) +{ +int i; +int active = 3, tmp; +struct dos_partition *partp = ((struct dos_partition *) &mboot.parts); + + if (a_flag && which != -1) + active = which; + if (ok("Do you want to change the active partition?")) { + do + Decimal("active partition", active, tmp); + while(!ok("Are you happy with this choice")); + } + for (i = 0; i < NDOSPART; i++) + partp[i].dp_flag = 0; + partp[active].dp_flag = ACTIVE; +} + +get_params_to_use() +{ + int tmp; + print_params(); + if (ok("Do you want to change our idea of what BIOS thinks ?")) + { + do + { + Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); + Decimal("BIOS's idea of #heads", dos_heads, tmp); + Decimal("BIOS's idea of #sectors", dos_sectors, tmp); + dos_cylsecs = dos_heads * dos_sectors; + print_params(); + } + while(!ok("Are you happy with this choice")); + } +} + +/***********************************************\ +* Change real numbers into strange dos numbers * +\***********************************************/ +static +dos(sec, c, s, h) +int sec; +unsigned char *c, *s, *h; +{ +int cy; +int hd; + + cy = sec / ( dos_cylsecs ); + sec = sec - cy * ( dos_cylsecs ); + + hd = sec / dos_sectors; + sec = (sec - hd * dos_sectors) + 1; + + *h = hd; + *c = cy & 0xff; + *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); +} + +int fd; + + /* Getting device status */ + +open_disk(u_flag) +{ +struct stat st; + + if (stat(disk, &st) == -1) { + fprintf(stderr, "%s: Can't get file status of %s\n", + name, disk); + return -1; + } else if ( !(st.st_mode & S_IFCHR) ) { + fprintf(stderr,"%s: Device %s is not character special\n", + name, disk); + return -1; + } + if ((fd = open(disk, u_flag?O_RDWR:O_RDONLY)) == -1) { + fprintf(stderr,"%s: Can't open device %s\n", name, disk); + return -1; + } + if (get_params(0) == -1) { + fprintf(stderr, "%s: Can't get disk parameters on %s\n", + name, disk); + return -1; + } + return fd; +} + + +read_disk(sector, buf) +{ + lseek(fd,(sector * 512), 0); + return read(fd, buf, 512); +} + +write_disk(sector, buf) +{ + lseek(fd,(sector * 512), 0); + return write(fd, buf, 512); +} + +get_params(verbose) +{ + + if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { + return -1; + } + + dos_cyls = cyls = disklabel.d_ncylinders; + dos_heads = heads = disklabel.d_ntracks; + dos_sectors = sectors = disklabel.d_nsectors; + dos_cylsecs = cylsecs = heads * sectors; + disksecs = cyls * heads * sectors; + + return (disksecs); +} + + +read_s0() +{ + if (read_disk(0, (char *) mboot.bootinst) == -1) { + fprintf(stderr, "%s: Can't read fdisk partition table\n", name); + return -1; + } + if (mboot.signature != BOOT_MAGIC) { + fprintf(stderr, "%s: Invalid fdisk partition table found\n", + name); + /* So should we initialize things */ + return -1; + } + return 0; +} + +write_s0() +{ + int flag; + if (iotest) { + print_s0(-1); + return 0; + } + /* + * write enable label sector before write (if necessary), + * disable after writing. + * needed if the disklabel protected area also protects + * sector 0. (e.g. empty disk) + */ + flag = 1; + if (ioctl(fd, DIOCWLABEL, &flag) < 0) + perror("ioctl DIOCWLABEL"); + if (write_disk(0, (char *) mboot.bootinst) == -1) { + fprintf(stderr, "%s: Can't write fdisk partition table\n", + name); + return -1; + flag = 0; + (void) ioctl(fd, DIOCWLABEL, &flag); + } +} + + + +ok(str) +char *str; +{ + printf("%s [n] ", str); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (*lbuf && + (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || + !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) + return 1; + else + return 0; +} + +decimal(str, num, deflt) +char *str; +int *num; +{ +int acc = 0, c; +char *cp; + + while (1) { + printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + cp = lbuf; + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) + return 0; + while (c = *cp++) { + if (c <= '9' && c >= '0') + acc = acc * 10 + c - '0'; + else + break; + } + if (c == ' ' || c == '\t') + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) { + *num = acc; + return 1; + } else + printf("%s is an invalid decimal number. Try again\n", + lbuf); + } + +} + +hex(str, num, deflt) +char *str; +int *num; +{ +int acc = 0, c; +char *cp; + + while (1) { + printf("Supply a hex value for \"%s\" [%x] ", str, deflt); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + cp = lbuf; + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) + return 0; + while (c = *cp++) { + if (c <= '9' && c >= '0') + acc = (acc << 4) + c - '0'; + else if (c <= 'f' && c >= 'a') + acc = (acc << 4) + c - 'a' + 10; + else if (c <= 'F' && c >= 'A') + acc = (acc << 4) + c - 'A' + 10; + else + break; + } + if (c == ' ' || c == '\t') + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) { + *num = acc; + return 1; + } else + printf("%s is an invalid hex number. Try again\n", + lbuf); + } + +} + +string(str, ans) +char *str; +char **ans; +{ +int c; +char *cp = lbuf; + + while (1) { + printf("Supply a string value for \"%s\" [%s] ", str, *ans); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (c == '"') { + c = *++cp; + *ans = cp; + while ((c = *cp) && c != '"') cp++; + } else { + *ans = cp; + while ((c = *cp) && c != ' ' && c != '\t') cp++; + } + + if (c) + *cp = 0; + return 1; + } +} + +char *get_type(type) +int type; +{ + int numentries = (sizeof(part_types)/sizeof(struct part_type)); + int counter = 0; + struct part_type *ptr = part_types; + + + while(counter < numentries) + { + if(ptr->type == type) + { + return(ptr->name); + } + ptr++; + counter++; + } + return("unknown"); +} diff --git a/usr/src/sbin/mount_pcfs/Makefile b/usr/src/sbin/mount_pcfs/Makefile new file mode 100644 index 0000000000..ea9fe0f5d9 --- /dev/null +++ b/usr/src/sbin/mount_pcfs/Makefile @@ -0,0 +1,5 @@ +PROG = mount_pcfs +CFLAGS += -DPCFS +NOMAN = noman + +.include diff --git a/usr/src/sbin/mount_pcfs/mount_pcfs.c b/usr/src/sbin/mount_pcfs/mount_pcfs.c new file mode 100644 index 0000000000..847ff69423 --- /dev/null +++ b/usr/src/sbin/mount_pcfs/mount_pcfs.c @@ -0,0 +1,65 @@ +/* + * 06 Apr 93, Rodney W. Grimes, changed MOUNT_PCFS to MOUNT_MSDOS, whole + * thing should be renamed msdosfs... + * + * No copyright as supplied to the patchkit??? + * Who wrote this??? + * + */ +#include +#include +#include + +char *progname; + +void +usage () +{ + fprintf (stderr, "usage: %s bdev dir\n", progname); + exit (1); +} + +int +main (argc, argv) +int argc; +char **argv; +{ + char *dev; + char *dir; + struct pcfs_args args; + int c; + extern char *optarg; + extern int optind; + int opts; + + progname = argv[0]; + + opts = 0; + + while ((c = getopt (argc, argv, "F:")) != EOF) { + switch (c) { + case 'F': + opts |= atoi (optarg); + break; + default: + usage (); + } + } + + if (optind + 2 != argc) + usage (); + + dev = argv[optind]; + dir = argv[optind + 1]; + + args.fspec = dev; + args.exflags = 0; + args.exroot = 0; + + if (mount (MOUNT_MSDOS, dir, opts, &args) < 0) { + perror ("mount"); + exit (1); + } + + exit (0); +} diff --git a/usr/src/sbin/quotacheck/Makefile b/usr/src/sbin/quotacheck/Makefile new file mode 100644 index 0000000000..fa74932251 --- /dev/null +++ b/usr/src/sbin/quotacheck/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 5.3 (Berkeley) 5/11/90 + +PROG= quotacheck +SRCS= quotacheck.c preen.c +MAN8= quotacheck.0 +.PATH: ${.CURDIR}/../fsck + +.include diff --git a/usr/src/sbin/quotacheck/quotacheck.8 b/usr/src/sbin/quotacheck/quotacheck.8 new file mode 100644 index 0000000000..dca7216ce9 --- /dev/null +++ b/usr/src/sbin/quotacheck/quotacheck.8 @@ -0,0 +1,157 @@ +.\" Copyright (c) 1983, 1990, 1991 Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Robert Elz at The University of Melbourne. +.\" +.\" 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. +.\" +.\" @(#)quotacheck.8 6.7 (Berkeley) 3/16/91 +.\" +.Dd March 16, 1991 +.Dt QUOTACHECK 8 +.Os BSD 4.2 +.Sh NAME +.Nm quotacheck +.Nd filesystem quota consistency checker +.Sh SYNOPSIS +.Nm quotacheck +.Op Fl g +.Op Fl u +.Op Fl v +.Ar filesystem Ar ... +.Nm quotacheck +.Op Fl g +.Op Fl u +.Op Fl v +.Fl a +.Sh DESCRIPTION +.Nm Quotacheck +examines each filesystem, +builds a table of current disk usage, +and compares this table against that recorded +in the disk quota file for the filesystem. +If any inconsistencies are detected, both the +quota file and the current system copy of the +incorrect quotas are updated (the latter only +occurs if an active filesystem is checked). +By default both user and group quotas are checked. +.Pp +Available options: +.Bl -tag -width Ds +.It Fl a +If the +.Fl a +flag is supplied in place of any filesystem names, +.Nm quotacheck +will check all the filesystems indicated in +.Pa /etc/fstab +to be read-write with disk quotas. +By default only the types of quotas listed in +.Pa /etc/fstab +are checked. +.It Fl g +Only group quotas listed in +.Pa /etc/fstab +are to be checked. +.It Fl u +Only user quotas listed in +.Pa /etc/fstab +are to be checked. +.It Fl v +.Nm quotacheck +reports discrepancies between the +calculated and recorded disk quotas. +.El +.Pp +Specifying both +.Fl g +and +.Fl u +is equivalent to the default. +Parallel passes are run on the filesystems required, +using the pass numbers in +.Pa /etc/fstab +in an identical fashion to +.Xr fsck 8 . +.Pp +Normally +.Nm quotacheck +operates silently. +.Pp +.Nm Quotacheck +expects each filesystem to be checked to have a +quota files named +.Pa quota.user +and +.Pa quota.group +which are located at the root of the associated file system. +These defaults may be overridden in +.Pa /etc/fstab . +If a file is not present, +.Nm quotacheck +will create it. +.Pp +.Nm Quotacheck +is normally run at boot time from the +.Pa /etc/rc.local +file, see +.Xr rc 8 , +before enabling disk quotas with +.Xr quotaon 8 . +.Pp +.Nm Quotacheck +accesses the raw device in calculating the actual +disk usage for each user. +Thus, the filesystems +checked should be quiescent while +.Nm quotacheck +is running. +.Sh FILES +.Bl -tag -width quota.group -compact +.It Pa quota.user +at the filesystem root with user quotas +.It Pa quota.group +at the filesystem root with group quotas +.It Pa /etc/fstab +default filesystems +.El +.Sh SEE ALSO +.Xr quota 1 , +.Xr quotactl 2 , +.Xr fstab 5 , +.Xr edquota 8 , +.Xr fsck 8 , +.Xr quotaon 8 , +.Xr repquota 8 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.2 . diff --git a/usr/src/sbin/quotacheck/quotacheck.c b/usr/src/sbin/quotacheck/quotacheck.c new file mode 100644 index 0000000000..5d6dafa2af --- /dev/null +++ b/usr/src/sbin/quotacheck/quotacheck.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 1980, 1990 Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Robert Elz at The University of Melbourne. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980, 1990 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)quotacheck.c 5.16 (Berkeley) 2/28/91"; +#endif /* not lint */ + +/* + * Fix up / report on disk quotas & usage + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *qfname = QUOTAFILENAME; +char *qfextension[] = INITQFNAMES; +char *quotagroup = QUOTAGROUP; + +union { + struct fs sblk; + char dummy[MAXBSIZE]; +} un; +#define sblock un.sblk +long dev_bsize; +long maxino; + +struct quotaname { + long flags; + char grpqfname[MAXPATHLEN + 1]; + char usrqfname[MAXPATHLEN + 1]; +}; +#define HASUSR 1 +#define HASGRP 2 + +struct fileusage { + struct fileusage *fu_next; + u_long fu_curinodes; + u_long fu_curblocks; + u_long fu_id; + char fu_name[1]; + /* actually bigger */ +}; +#define FUHASH 1024 /* must be power of two */ +struct fileusage *fuhead[MAXQUOTAS][FUHASH]; +struct fileusage *lookup(); +struct fileusage *addid(); +struct dinode *getnextinode(); + +int aflag; /* all file systems */ +int gflag; /* check group quotas */ +int uflag; /* check user quotas */ +int vflag; /* verbose */ +int fi; /* open disk file descriptor */ +u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */ + +main(argc, argv) + int argc; + char **argv; +{ + register struct fstab *fs; + register struct passwd *pw; + register struct group *gr; + int i, argnum, maxrun = 0, errs = 0; + long auxdata, done = 0; + char ch, *name, *blockcheck(); + int needchk(), chkquota(); + extern char *optarg; + extern int optind; + + while ((ch = getopt(argc, argv, "aguvl:")) != EOF) { + switch(ch) { + case 'a': + aflag++; + break; + case 'g': + gflag++; + break; + case 'u': + uflag++; + break; + case 'v': + vflag++; + break; + case 'l': + maxrun = atoi(optarg); + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if ((argc == 0 && !aflag) || (argc > 0 && aflag)) + usage(); + if (!gflag && !uflag) { + gflag++; + uflag++; + } + if (gflag) { + setgrent(); + while ((gr = getgrent()) != 0) + (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); + endgrent(); + } + if (uflag) { + setpwent(); + while ((pw = getpwent()) != 0) + (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); + endpwent(); + } + if (aflag) + exit(checkfstab(1, maxrun, needchk, chkquota)); + if (setfsent() == 0) { + fprintf(stderr, "Can't open "); + perror(FSTAB); + exit(8); + } + while ((fs = getfsent()) != NULL) { + if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || + (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && + (auxdata = needchk(fs)) && + (name = blockcheck(fs->fs_spec))) { + done |= 1 << argnum; + errs += chkquota(name, fs->fs_file, auxdata); + } + } + endfsent(); + for (i = 0; i < argc; i++) + if ((done & (1 << i)) == 0) + fprintf(stderr, "%s not found in %s\n", + argv[i], FSTAB); + exit(errs); +} + +usage() +{ + (void) fprintf(stderr, "usage:\t%s\n\t%s\n", + "quotacheck -a [-guv]", + "quotacheck [-guv] filesys ..."); + exit(1); +} + +needchk(fs) + register struct fstab *fs; +{ + register struct quotaname *qnp; + char *qfnp; + + if (strcmp(fs->fs_vfstype, "ufs") || + strcmp(fs->fs_type, FSTAB_RW)) + return (0); + if ((qnp = (struct quotaname *)malloc(sizeof *qnp)) == 0) { + fprintf(stderr, "out of memory for quota structures\n"); + exit(1); + } + qnp->flags = 0; + if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) { + strcpy(qnp->grpqfname, qfnp); + qnp->flags |= HASGRP; + } + if (uflag && hasquota(fs, USRQUOTA, &qfnp)) { + strcpy(qnp->usrqfname, qfnp); + qnp->flags |= HASUSR; + } + if (qnp->flags) + return ((int)qnp); + free((char *)qnp); + return (0); +} + +/* + * Scan the specified filesystem to check quota(s) present on it. + */ +chkquota(fsname, mntpt, qnp) + char *fsname, *mntpt; + register struct quotaname *qnp; +{ + register struct fileusage *fup; + register struct dinode *dp; + int cg, i, mode, errs = 0; + ino_t ino; + + if ((fi = open(fsname, 0)) < 0) { + perror(fsname); + return (1); + } + if (vflag) { + fprintf(stdout, "*** Checking "); + if (qnp->flags & HASUSR) + fprintf(stdout, "%s%s", qfextension[USRQUOTA], + (qnp->flags & HASGRP) ? " and " : ""); + if (qnp->flags & HASGRP) + fprintf(stdout, "%s", qfextension[GRPQUOTA]); + fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt); + } + sync(); + dev_bsize = 1; + bread(SBOFF, (char *)&sblock, (long)SBSIZE); + dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1); + maxino = sblock.fs_ncg * sblock.fs_ipg; + resetinodebuf(); + for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) { + for (i = 0; i < sblock.fs_ipg; i++, ino++) { + if (ino < ROOTINO) + continue; + if ((dp = getnextinode(ino)) == NULL) + continue; + if ((mode = dp->di_mode & IFMT) == 0) + continue; + if (qnp->flags & HASGRP) { + fup = addid((u_long)dp->di_gid, GRPQUOTA, + (char *)0); + fup->fu_curinodes++; + if (mode == IFREG || mode == IFDIR || + mode == IFLNK) + fup->fu_curblocks += dp->di_blocks; + } + if (qnp->flags & HASUSR) { + fup = addid((u_long)dp->di_uid, USRQUOTA, + (char *)0); + fup->fu_curinodes++; + if (mode == IFREG || mode == IFDIR || + mode == IFLNK) + fup->fu_curblocks += dp->di_blocks; + } + } + } + freeinodebuf(); + if (qnp->flags & HASUSR) + errs += update(mntpt, qnp->usrqfname, USRQUOTA); + if (qnp->flags & HASGRP) + errs += update(mntpt, qnp->grpqfname, GRPQUOTA); + close(fi); + return (errs); +} + +/* + * Update a specified quota file. + */ +update(fsname, quotafile, type) + char *fsname, *quotafile; + register int type; +{ + register struct fileusage *fup; + register FILE *qfi, *qfo; + register u_long id, lastid; + struct dqblk dqbuf; + static int warned = 0; + static struct dqblk zerodqbuf; + static struct fileusage zerofileusage; + + if ((qfo = fopen(quotafile, "r+")) == NULL) { + if (errno == ENOENT) + qfo = fopen(quotafile, "w+"); + if (qfo) { + (void) fprintf(stderr, + "quotacheck: creating quota file %s\n", quotafile); +#define MODE (S_IRUSR|S_IWUSR|S_IRGRP) + (void) fchown(fileno(qfo), getuid(), getquotagid()); + (void) fchmod(fileno(qfo), MODE); + } else { + (void) fprintf(stderr, + "quotacheck: %s: %s\n", quotafile, strerror(errno)); + return (1); + } + } + if ((qfi = fopen(quotafile, "r")) == NULL) { + (void) fprintf(stderr, + "quotacheck: %s: %s\n", quotafile, strerror(errno)); + (void) fclose(qfo); + return (1); + } + if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 && + errno == EOPNOTSUPP && !warned && vflag) { + warned++; + fprintf(stdout, "*** Warning: %s\n", + "Quotas are not compiled into this kernel"); + } + for (lastid = highid[type], id = 0; id <= lastid; id++) { + if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) + dqbuf = zerodqbuf; + if ((fup = lookup(id, type)) == 0) + fup = &zerofileusage; + if (dqbuf.dqb_curinodes == fup->fu_curinodes && + dqbuf.dqb_curblocks == fup->fu_curblocks) { + fup->fu_curinodes = 0; + fup->fu_curblocks = 0; + fseek(qfo, (long)sizeof(struct dqblk), 1); + continue; + } + if (vflag) { + if (aflag) + printf("%s: ", fsname); + printf("%-8s fixed:", fup->fu_name); + if (dqbuf.dqb_curinodes != fup->fu_curinodes) + fprintf(stdout, "\tinodes %d -> %d", + dqbuf.dqb_curinodes, fup->fu_curinodes); + if (dqbuf.dqb_curblocks != fup->fu_curblocks) + fprintf(stdout, "\tblocks %d -> %d", + dqbuf.dqb_curblocks, fup->fu_curblocks); + fprintf(stdout, "\n"); + } + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it. + */ + if (dqbuf.dqb_bsoftlimit && + dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && + fup->fu_curblocks >= dqbuf.dqb_bsoftlimit) + dqbuf.dqb_btime = 0; + if (dqbuf.dqb_isoftlimit && + dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit && + fup->fu_curblocks >= dqbuf.dqb_isoftlimit) + dqbuf.dqb_itime = 0; + dqbuf.dqb_curinodes = fup->fu_curinodes; + dqbuf.dqb_curblocks = fup->fu_curblocks; + fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo); + (void) quotactl(fsname, QCMD(Q_SETUSE, type), id, + (caddr_t)&dqbuf); + fup->fu_curinodes = 0; + fup->fu_curblocks = 0; + } + fclose(qfi); + fflush(qfo); + ftruncate(fileno(qfo), + (off_t)((highid[type] + 1) * sizeof(struct dqblk))); + fclose(qfo); + return (0); +} + +/* + * Check to see if target appears in list of size cnt. + */ +oneof(target, list, cnt) + register char *target, *list[]; + int cnt; +{ + register int i; + + for (i = 0; i < cnt; i++) + if (strcmp(target, list[i]) == 0) + return (i); + return (-1); +} + +/* + * Determine the group identifier for quota files. + */ +getquotagid() +{ + struct group *gr; + + if (gr = getgrnam(quotagroup)) + return (gr->gr_gid); + return (-1); +} + +/* + * Check to see if a particular quota is to be enabled. + */ +hasquota(fs, type, qfnamep) + register struct fstab *fs; + int type; + char **qfnamep; +{ + register char *opt; + char *cp, *index(), *strtok(); + static char initname, usrname[100], grpname[100]; + static char buf[BUFSIZ]; + + if (!initname) { + sprintf(usrname, "%s%s", qfextension[USRQUOTA], qfname); + sprintf(grpname, "%s%s", qfextension[GRPQUOTA], qfname); + initname = 1; + } + strcpy(buf, fs->fs_mntops); + for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) { + if (cp = index(opt, '=')) + *cp++ = '\0'; + if (type == USRQUOTA && strcmp(opt, usrname) == 0) + break; + if (type == GRPQUOTA && strcmp(opt, grpname) == 0) + break; + } + if (!opt) + return (0); + if (cp) { + *qfnamep = cp; + return (1); + } + (void) sprintf(buf, "%s/%s.%s", fs->fs_file, qfname, qfextension[type]); + *qfnamep = buf; + return (1); +} + +/* + * Routines to manage the file usage table. + * + * Lookup an id of a specific type. + */ +struct fileusage * +lookup(id, type) + u_long id; + int type; +{ + register struct fileusage *fup; + + for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next) + if (fup->fu_id == id) + return (fup); + return ((struct fileusage *)0); +} + +/* + * Add a new file usage id if it does not already exist. + */ +struct fileusage * +addid(id, type, name) + u_long id; + int type; + char *name; +{ + struct fileusage *fup, **fhp; + int len; + + if (fup = lookup(id, type)) + return (fup); + if (name) + len = strlen(name); + else + len = 10; + if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) { + fprintf(stderr, "out of memory for fileusage structures\n"); + exit(1); + } + fhp = &fuhead[type][id & (FUHASH - 1)]; + fup->fu_next = *fhp; + *fhp = fup; + fup->fu_id = id; + if (id > highid[type]) + highid[type] = id; + if (name) { + bcopy(name, fup->fu_name, len + 1); + } else { + sprintf(fup->fu_name, "%u", id); + } + return (fup); +} + +/* + * Special purpose version of ginode used to optimize pass + * over all the inodes in numerical order. + */ +ino_t nextino, lastinum; +long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; +struct dinode *inodebuf; +#define INOBUFSIZE 56*1024 /* size of buffer to read inodes */ + +struct dinode * +getnextinode(inumber) + ino_t inumber; +{ + long size; + daddr_t dblk; + static struct dinode *dp; + + if (inumber != nextino++ || inumber > maxino) { + fprintf(stderr, "bad inode number %d to nextinode\n", inumber); + exit(1); + } + if (inumber >= lastinum) { + readcnt++; + dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); + if (readcnt % readpercg == 0) { + size = partialsize; + lastinum += partialcnt; + } else { + size = inobufsize; + lastinum += fullcnt; + } + bread(dblk, (char *)inodebuf, size); + dp = inodebuf; + } + return (dp++); +} + +/* + * Prepare to scan a set of inodes. + */ +resetinodebuf() +{ + + nextino = 0; + lastinum = 0; + readcnt = 0; + inobufsize = blkroundup(&sblock, INOBUFSIZE); + fullcnt = inobufsize / sizeof(struct dinode); + readpercg = sblock.fs_ipg / fullcnt; + partialcnt = sblock.fs_ipg % fullcnt; + partialsize = partialcnt * sizeof(struct dinode); + if (partialcnt != 0) { + readpercg++; + } else { + partialcnt = fullcnt; + partialsize = inobufsize; + } + if (inodebuf == NULL && + (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) { + fprintf(stderr, "Cannot allocate space for inode buffer\n"); + exit(1); + } + while (nextino < ROOTINO) + getnextinode(nextino); +} + +/* + * Free up data structures used to scan inodes. + */ +freeinodebuf() +{ + + if (inodebuf != NULL) + free((char *)inodebuf); + inodebuf = NULL; +} + +/* + * Read specified disk blocks. + */ +bread(bno, buf, cnt) + daddr_t bno; + char *buf; + long cnt; +{ + + if (lseek(fi, bno * dev_bsize, 0) < 0) { + perror("lseek"); + exit(1); + } + + if (read(fi, buf, cnt) != cnt) { + perror("read"); + exit(1); + } +} -- 2.20.1