+1998-03-10 17:54 Ulrich Drepper <drepper@cygnus.com>
+
+ * libc.map: Add _dl_debug_message.
+ * elf/dl-misc.c: Make _dl_debug_message a function. Print the PID
+ before every line.
+ * elf/fini.c: Correctly use new _dl_debug_message function.
+ * elf/init.c: Likewise.
+ * elf/dl-lookup.c: Likewise.
+ * sysdeps/unix/sysv/linux/libc-start.c: Likewise.
+ * elf/dl-load.c: Likewise. Add more debugging prints.
+ * elf/dl-reloc.c: Likewise.
+ * elf/dl-version.c: Likewise.
+ * elf/dl-support.c: Add variables for debugging.
+ * elf/rtld.c: Likewise. Recognize new debug options.
+ * elf/link.h: Declare new variables.
+
+ * elf/dl-deps.c (_dl_map_object_deps): Little optimizations.
+
1998-03-10 Ulrich Drepper <drepper@cygnus.com>
+ * sysdeps/unix/sysv/linux/sys/quota.h: Extract information from
+ kernel headers. Patch by a sun <asun@saul7.u.washington.edu>.
+
+1998-03-11 00:16 Tim Waugh <tim@cyberelk.demon.co.uk>
+
+ * posix/wordexp-test.c (command_line_test): New function to allow
+ testing of specific cases from the command-line.
+
+1998-03-10 Ulrich Drepper <drepper@cygnus.com>
+
+ * elf/dl-init.c (_dl_init_next): Print nicer messages.
+ * elf/dl-fini.c (_dl_fini): Likewise.
+ * sysdeps/unix/sysv/linux/libc-start.c (__libc_start_main): Likewise.
+
* elf/dl-lookup.c (_dl_lookup_versioned_symbol): Print version
symbol in debug message.
(_dl_lookup_versioned_symbol_skip): Likewise.
{
struct link_map *l = runp->map;
- if (l->l_info[AUXTAG] || l->l_info[FILTERTAG] || l->l_info[DT_NEEDED])
+ if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG])
{
const char *strtab = ((void *) l->l_addr
+ l->l_info[DT_STRTAB]->d_un.d_ptr);
newp = alloca (sizeof (struct list));
/* Copy the content of the current entry over. */
- memcpy (newp, orig, sizeof (*newp));
+ orig->dup = memcpy (newp, orig, sizeof (*newp));
/* Initialize new entry. */
orig->done = 0;
orig->map = args.aux;
- orig->dup = newp;
/* We must handle two situations here: the map is new,
so we must add it in all three lists. If the map
if (runp->done)
do
runp = runp->unique;
- while (runp && runp->done);
+ while (runp != NULL && runp->done);
}
/* Store the search list we built in the object. It will be used for
{
/* When debugging print a message first. */
if (_dl_debug_impcalls)
- _dl_debug_message ("\n\tcalling fini: ",
+ _dl_debug_message (1, "\ncalling fini: ",
l->l_name[0] ? l->l_name : _dl_argv[0],
- "\n", NULL);
+ "\n\n", NULL);
(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
}
/* Print a debug message if wanted. */
if (_dl_debug_impcalls)
- _dl_debug_message ("\tcalling init: ",
+ _dl_debug_message (1, "\ncalling init: ",
l->l_name[0] ? l->l_name : _dl_argv[0],
"\n\n", NULL);
#include <sys/stat.h>
#include <sys/types.h>
#include "dynamic-link.h"
+#include <stdio-common/_itoa.h>
/* On some systems, no flag bits are given to specify file mapping. */
const ElfW(Ehdr) *header;
const ElfW(Phdr) *phdr;
const ElfW(Phdr) *ph;
+ size_t maplength;
int type;
/* Look again to see if the real name matched another already loaded. */
return l;
}
+ /* Print debugging message. */
+ if (_dl_debug_files)
+ _dl_debug_message (1, "file=", name, "; generating link map\n", NULL);
+
/* Map in the first page to read the header. */
header = map (0, sizeof *header);
/* Now process the load commands and map segments into memory. */
c = loadcmds;
+ /* Length of the sections to be loaded. */
+ maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
+
if (type == ET_DYN || type == ET_REL)
{
/* This is a position-independent shared object. We can let the
the OS can do whatever it likes. */
caddr_t mapat;
ElfW(Addr) mappref;
- size_t maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart)
- MAP_BASE_ADDR (l));
mapat = map_segment (mappref, maplength, c->prot, 0, c->mapoff);
l->l_entry += l->l_addr;
+ if (_dl_debug_files)
+ {
+ const size_t nibbles = sizeof (void *) * 2;
+ char buf1[nibbles + 1];
+ char buf2[nibbles + 1];
+ char buf3[nibbles + 1];
+
+ buf1[nibbles] = '\0';
+ buf2[nibbles] = '\0';
+ buf3[nibbles] = '\0';
+
+ memset (buf1, '0', nibbles);
+ memset (buf2, '0', nibbles);
+ memset (buf3, '0', nibbles);
+ _itoa_word ((unsigned long int) l->l_ld, &buf1[nibbles], 16, 0);
+ _itoa_word ((unsigned long int) l->l_addr, &buf2[nibbles], 16, 0);
+ _itoa_word (maplength, &buf3[nibbles], 16, 0);
+
+ _dl_debug_message (1, " dynamic: 0x", buf1, " base: 0x", buf2,
+ " size: 0x", buf3, "\n", NULL);
+ memset (buf1, '0', nibbles);
+ memset (buf2, '0', nibbles);
+ memset (buf3, ' ', nibbles);
+ _itoa_word ((unsigned long int) l->l_entry, &buf1[nibbles], 16, 0);
+ _itoa_word ((unsigned long int) l->l_phdr, &buf2[nibbles], 16, 0);
+ _itoa_word (l->l_phnum, &buf3[nibbles], 10, 0);
+ _dl_debug_message (1, " entry: 0x", buf1, " phdr: 0x", buf2,
+ " phnum: ", buf3, "\n\n", NULL);
+ }
+
elf_get_dynamic_info (l->l_ld, l->l_info);
if (l->l_info[DT_HASH])
_dl_setup_hash (l);
{
int first = 1;
- _dl_debug_message ("\t search path=", NULL);
+ _dl_debug_message (1, " search path=", NULL);
while (*list != NULL && (*list)->what == what) /* Yes, ==. */
{
if ((*list)->machdirstatus != nonexisting)
{
buf[(*list)->machdirnamelen - 1] = '\0';
- _dl_debug_message (first ? "" : ":", buf, NULL);
+ _dl_debug_message (0, first ? "" : ":", buf, NULL);
first = 0;
}
if ((*list)->dirstatus != nonexisting)
{
buf[(*list)->dirnamelen - 1] = '\0';
- _dl_debug_message (first ? "" : ":", buf, NULL);
+ _dl_debug_message (0, first ? "" : ":", buf, NULL);
first = 0;
}
++list;
}
if (name != NULL)
- _dl_debug_message ("\t\t(", what, " from file ",
+ _dl_debug_message (0, "\t\t(", what, " from file ",
name[0] ? name : _dl_argv[0], ")\n", NULL);
else
- _dl_debug_message ("\t\t(", what, ")\n", NULL);
+ _dl_debug_message (0, "\t\t(", what, ")\n", NULL);
}
\f
/* Try to open NAME in one of the directories in DIRS.
/* Print name we try if this is wanted. */
if (_dl_debug_libs)
- _dl_debug_message ("\t trying file=", buf, "\n", NULL);
+ _dl_debug_message (1, " trying file=", buf, "\n", NULL);
fd = __open (buf, O_RDONLY);
if (this_dir->machdirstatus == unknown)
/* Print name we try if this is wanted. */
if (_dl_debug_libs)
- _dl_debug_message ("\t trying file=", buf, "\n", NULL);
+ _dl_debug_message (1, " trying file=", buf, "\n", NULL);
fd = __open (buf, O_RDONLY);
if (this_dir->dirstatus == unknown)
return l;
}
+ /* Display information if we are debugging. */
+ if (_dl_debug_files && loader != NULL)
+ _dl_debug_message (1, "\nfile=", name, "; needed by ",
+ loader->l_name[0] ? loader->l_name : _dl_argv[0],
+ "\n", NULL);
+
if (strchr (name, '/') == NULL)
{
/* Search for NAME in several places. */
size_t namelen = strlen (name) + 1;
if (_dl_debug_libs)
- _dl_debug_message ("\tfind library=", name, "; searching\n", NULL);
+ _dl_debug_message (1, "find library=", name, "; searching\n", NULL);
fd = -1;
/* Add another newline when we a tracing the library loading. */
if (_dl_debug_libs)
- _dl_debug_message ("\n", NULL);
+ _dl_debug_message (1, "\n", NULL);
}
else
{
/* Print some debugging info if wanted. */
if (_dl_debug_symbols)
- _dl_debug_message ("\tsymbol=", undef_name, "; lookup in file=",
+ _dl_debug_message (1, "symbol=", undef_name, "; lookup in file=",
map->l_name[0] ? map->l_name : _dl_argv[0],
"\n", NULL);
}
if (_dl_debug_bindings)
- _dl_debug_message ("\tbinding file ", reference_name, " to ",
+ _dl_debug_message (1, "binding file ", reference_name, " to ",
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
": symbol `", undef_name, "'\n", NULL);
}
if (_dl_debug_bindings)
- _dl_debug_message ("\tbinding file ", reference_name, " to ",
+ _dl_debug_message (1, "binding file ", reference_name, " to ",
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
": symbol `", undef_name, "'\n", NULL);
}
if (_dl_debug_bindings)
- _dl_debug_message ("\tbinding file ", reference_name, " to ",
+ _dl_debug_message (1, "binding file ", reference_name, " to ",
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
": symbol `", undef_name, "' [", version->name,
}
if (_dl_debug_bindings)
- _dl_debug_message ("\tbinding file ", reference_name, " to ",
+ _dl_debug_message (1, "binding file ", reference_name, " to ",
current_value.m->l_name[0]
? current_value.m->l_name : _dl_argv[0],
": symbol `", undef_name, "' [", version->name,
#include <unistd.h>
#include <stdarg.h>
#include <string.h>
+#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <stdio-common/_itoa.h>
#ifndef MAP_ANON
/* This is the only dl-sysdep.c function that is actually needed at run-time
size_t len = strlen (msg);
__write (fd, msg, len);
msg = va_arg (ap, const char *);
- } while (msg);
+ }
+ while (msg != NULL);
+ va_end (ap);
+}
+
+
+void
+_dl_debug_message (int new_line, const char *msg, ...)
+{
+ /* We print the strings we get passed one after the other but start all
+ lines using the current PID. */
+ static int pid;
+ va_list ap;
+
+ if (pid == 0)
+ pid = getpid ();
+
+ va_start (ap, msg);
+ do
+ if (msg[0] == '\0')
+ /* Get the next argument. */
+ msg = va_arg (ap, const char *);
+ else
+ {
+ const char *endp;
+
+ /* We actually will print something in this line. So print the
+ PID now if needed. */
+ if (new_line)
+ {
+ char buf[7] = "00000:\t";
+ __write (_dl_debug_fd, _itoa_word (pid, &buf[5], 10, 0), 7);
+ new_line = 0;
+ }
+
+ endp = strchr (msg, '\n');
+ if (endp == NULL)
+ {
+ __write (_dl_debug_fd, msg, strlen (msg));
+ msg = va_arg (ap, const char *);
+ }
+ else
+ {
+ __write (_dl_debug_fd, msg, endp - msg + 1);
+ msg = endp + 1;
+ new_line = 1;
+ }
+ }
+ while (msg != NULL);
va_end (ap);
}
if (l->l_relocated)
return;
+ if (_dl_debug_reloc)
+ _dl_debug_message (1, "\nrelocation processing: ",
+ l->l_name[0] ? l->l_name : _dl_argv[0], "\n", NULL);
+
if (l->l_info[DT_TEXTREL])
{
/* Bletch. We must make read-only segments writable
int _dl_debug_impcalls;
int _dl_debug_bindings;
int _dl_debug_symbols;
+int _dl_debug_versions;
+int _dl_debug_reloc;
+int _dl_debug_files;
/* If nonzero print warnings about problematic situations. */
int _dl_verbose;
ElfW(Addr) def_offset;
ElfW(Verdef) *def;
+ /* Display information about what we are doing while debugging. */
+ if (_dl_debug_versions)
+ _dl_debug_message (1, "checking for version `", string, "' in file ",
+ map->l_name[0] ? map->l_name : _dl_argv[0],
+ " required by file ", name, "\n", NULL);
+
if (map->l_info[VERSTAG (DT_VERDEF)] == NULL)
{
/* The file has no symbol versioning. I.e., the dependent
extern int _dl_debug_impcalls;
extern int _dl_debug_bindings;
extern int _dl_debug_symbols;
+extern int _dl_debug_versions;
+extern int _dl_debug_reloc;
+extern int _dl_debug_files;
/* File deccriptor to write debug messages to. */
extern int _dl_debug_fd;
/* OS-dependent function to write a debug message on the specified
descriptor for this. All arguments are `const char *'; args until
- a null pointer are concatenated to form the message to print. */
-#define _dl_debug_message(string, args...) \
- _dl_sysdep_output (_dl_debug_fd, string, ##args)
+ a null pointer are concatenated to form the message to print. If
+ NEW_LINE is nonzero it is assumed that the message starts on a new
+ line.*/
+extern void _dl_debug_message (int new_line, const char *string, ...);
/* OS-dependent function to write a message on the standard output.
All arguments are `const char *'; args until a null pointer
int _dl_debug_impcalls;
int _dl_debug_bindings;
int _dl_debug_symbols;
+int _dl_debug_versions;
+int _dl_debug_reloc;
+int _dl_debug_files;
/* Set nonzero during loading and initialization of executable and
libraries, cleared before the executable's entry point runs. This
++dl_debug;
if (*dl_debug != '\0')
{
- if (strncmp (dl_debug, "bindings", 8) == 0
- && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
+ if (strncmp (dl_debug, "files", 5) == 0
+ && (issep (dl_debug[5]) || dl_debug[5] == '\0'))
{
- _dl_debug_bindings = 1;
+ _dl_debug_files = 1;
_dl_debug_impcalls = 1;
any_debug = 1;
- dl_debug += 8;
+ dl_debug += 5;
}
- else if (strncmp (dl_debug, "libs", 4) == 0
- && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+ else if (strncmp (dl_debug, "bindings", 8) == 0
+ && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
{
- _dl_debug_libs = 1;
+ _dl_debug_bindings = 1;
_dl_debug_impcalls = 1;
any_debug = 1;
- dl_debug += 4;
+ dl_debug += 8;
}
else if (strncmp (dl_debug, "help", 4) == 0
&& (issep (dl_debug[4]) || dl_debug[4] == '\0'))
Valid options for the LD_DEBUG environment variable are:\n\
\n\
bindings display information about symbol binding\n\
+ files display processing of files and libraries\n\
help display this help message and exit\n\
libs display library search paths\n\
+ reloc display relocation processing\n\
symbols display symbol table processing\n\
+ versions display version dependencies\n\
\n\
To direct the debugging output into a file instead of standard output\n\
a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n",
NULL);
_exit (0);
}
+ else if (strncmp (dl_debug, "libs", 4) == 0
+ && (issep (dl_debug[4]) || dl_debug[4] == '\0'))
+ {
+ _dl_debug_libs = 1;
+ _dl_debug_impcalls = 1;
+ any_debug = 1;
+ dl_debug += 4;
+ }
+ else if (strncmp (dl_debug, "reloc", 4) == 0
+ && (issep (dl_debug[5]) || dl_debug[5] == '\0'))
+ {
+ _dl_debug_reloc = 1;
+ _dl_debug_impcalls = 1;
+ any_debug = 1;
+ dl_debug += 5;
+ }
else if (strncmp (dl_debug, "symbols", 7) == 0
&& (issep (dl_debug[7]) || dl_debug[7] == '\0'))
{
any_debug = 1;
dl_debug += 7;
}
+ else if (strncmp (dl_debug, "versions", 8) == 0
+ && (issep (dl_debug[8]) || dl_debug[8] == '\0'))
+ {
+ _dl_debug_versions = 1;
+ _dl_debug_impcalls = 1;
+ any_debug = 1;
+ dl_debug += 8;
+ }
else
{
/* Display a warning and skip everything until next
_rpc_dtablesize; _null_auth; _seterr_reply;
__res_randomid; __getpid;
__strcasecmp; __write; _strerror_internal; _dl_sysdep_output;
+ _dl_debug_message;
__ffs;
# Exception handling support functions from libgcc
static int testit (struct test_case_struct *tc);
+void
+command_line_test (const char *words)
+{
+ wordexp_t we;
+ int i;
+ int retval = wordexp (words, &we, 0);
+ printf ("wordexp returned %d\n", retval);
+ for (i = 0; i < we.we_wordc; i++)
+ printf ("we_wordv[%d] = \"%s\"\n", i, we.we_wordv[i]);
+}
+
int
-main (int argc, char * argv[])
+main (int argc, char *argv[])
{
struct passwd *pw;
int test;
if (testit (&test_case[test]))
++fail;
+ if (argc > 1)
+ {
+ command_line_test (argv[1]);
+ return 0;
+ }
+
pw = getpwnam ("root");
if (pw != NULL)
{
/* Call the initializer of the libc. */
#ifdef PIC
if (_dl_debug_impcalls)
- _dl_debug_message ("\tinitialize libc\n\n", NULL);
+ _dl_debug_message (1, "\ninitialize libc\n\n", NULL);
#endif
__libc_init_first (argc, argv, __environ);
/* Call the initializer of the program. */
#ifdef PIC
if (_dl_debug_impcalls)
- _dl_debug_message ("\tinitialize program: ", argv[0], "\n\n", NULL);
+ _dl_debug_message (1, "\ninitialize program: ", argv[0], "\n\n", NULL);
#endif
(*init) ();
#ifdef PIC
if (_dl_debug_impcalls)
- _dl_debug_message ("\ttransferring control: ", argv[0], "\n\n", NULL);
+ _dl_debug_message (1, "\ntransferring control: ", argv[0], "\n\n", NULL);
#endif
exit ((*main) (argc, argv, __environ));
-/* The kernel header file contains all declarations and definitions. */
+/* This just represents the non-kernel parts of <linux/quota.h>.
+ *
+ * here's the corresponding copyright:
+ * Copyright (c) 1982, 1986 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.
+ *
+ * Version: $Id$
+ */
+
+#ifndef _SYS_QUOTA_H
+#define _SYS_QUOTA_H 1
+
+#include <features.h>
#include <sys/types.h>
-#include <linux/quota.h>
+
+/*
+ * Convert diskblocks to blocks and the other way around.
+ * currently only to fool the BSD source. :-)
+ */
+#define dbtob(num) ((num) << 10)
+#define btodb(num) ((num) >> 10)
+
+/*
+ * Convert count of filesystem blocks to diskquota blocks, meant
+ * for filesystems where i_blksize != BLOCK_SIZE
+ */
+#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */
+
+#define MAXQUOTAS 2
+#define USRQUOTA 0 /* element used for user quotas */
+#define GRPQUOTA 1 /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+ "user", /* USRQUOTA */ \
+ "group", /* GRPQUOTA */ \
+ "undefined", \
+};
+
+#define QUOTAFILENAME "quota"
+#define QUOTAGROUP "staff"
+
+#define NR_DQHASH 43 /* Just an arbitrary number any suggestions ? */
+#define NR_DQUOTS 256 /* Number of quotas active at one time */
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK 0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_QUOTAON 0x0100 /* enable quotas */
+#define Q_QUOTAOFF 0x0200 /* disable quotas */
+#define Q_GETQUOTA 0x0300 /* get limits and usage */
+#define Q_SETQUOTA 0x0400 /* set limits and usage */
+#define Q_SETUSE 0x0500 /* set usage */
+#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+#define Q_SETQLIM 0x0700 /* set limits */
+#define Q_GETSTATS 0x0800 /* get collected stats */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct dqblk
+ {
+ u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */
+ u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */
+ u_int32_t dqb_curblocks; /* current block count */
+ u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */
+ u_int32_t dqb_isoftlimit; /* preferred inode limit */
+ u_int32_t dqb_curinodes; /* current # allocated inodes */
+ time_t dqb_btime; /* time limit for excessive disk use */
+ time_t dqb_itime; /* time limit for excessive files */
+ };
+
+/*
+ * Shorthand notation.
+ */
+#define dq_bhardlimit dq_dqb.dqb_bhardlimit
+#define dq_bsoftlimit dq_dqb.dqb_bsoftlimit
+#define dq_curblocks dq_dqb.dqb_curblocks
+#define dq_ihardlimit dq_dqb.dqb_ihardlimit
+#define dq_isoftlimit dq_dqb.dqb_isoftlimit
+#define dq_curinodes dq_dqb.dqb_curinodes
+#define dq_btime dq_dqb.dqb_btime
+#define dq_itime dq_dqb.dqb_itime
+
+#define dqoff(UID) ((loff_t)((UID) * sizeof (struct dqblk)))
+
+struct dqstats
+ {
+ u_int32_t lookups;
+ u_int32_t drops;
+ u_int32_t reads;
+ u_int32_t writes;
+ u_int32_t cache_hits;
+ u_int32_t pages_allocated;
+ u_int32_t allocated_dquots;
+ u_int32_t free_dquots;
+ u_int32_t syncs;
+ };
+
+__BEGIN_DECLS
+
+extern int quotactl __P ((int __cmd, const char *__special, int __id,
+ caddr_t __addr));
+
+__END_DECLS
+
+#endif /* sys/quota.h */