📄 du.c
字号:
/* du -- summarize disk usage
Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc.
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.
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. */
/* Differences from the Unix du:
* Doesn't simply ignore the names of regular files given as arguments
when -a is given.
* Additional options:
-l Count the size of all files, even if they have appeared
already in another hard link.
-x Do not cross file-system boundaries during the recursion.
-c Write a grand total of all of the arguments after all
arguments have been processed. This can be used to find
out the disk usage of a directory, with some files excluded.
-k Print sizes in kilobytes instead of 512 byte blocks
(the default required by POSIX).
-b Print sizes in bytes (added by POSIX).
By tege@sics.se, Torbjorn Granlund,
and djm@ai.mit.edu, David MacKenzie. */
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <sys/types.h>
#include "system.h"
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *malloc ();
char *realloc ();
extern int errno;
#endif
/* Initial number of entries in each hash table entry's table of inodes. */
#define INITIAL_HASH_MODULE 100
/* Initial number of entries in the inode hash table. */
#define INITIAL_ENTRY_TAB_SIZE 70
/* Initial size to allocate for `path'. */
#define INITIAL_PATH_SIZE 100
/* Hash structure for inode and device numbers. The separate entry
structure makes it easier to rehash "in place". */
struct entry
{
ino_t ino;
dev_t dev;
struct entry *coll_link;
};
/* Structure for a hash table for inode numbers. */
struct htab
{
unsigned modulus; /* Size of the `hash' pointer vector. */
struct entry *entry_tab; /* Pointer to dynamically growing vector. */
unsigned entry_tab_size; /* Size of current `entry_tab' allocation. */
unsigned first_free_entry; /* Index in `entry_tab'. */
struct entry *hash[1]; /* Vector of pointers in `entry_tab'. */
};
/* Structure for dynamically resizable strings. */
typedef struct
{
unsigned alloc; /* Size of allocation for the text. */
unsigned length; /* Length of the text currently. */
char *text; /* Pointer to the text. */
} *string, stringstruct;
char *savedir ();
char *xmalloc ();
char *xrealloc ();
int hash_insert ();
int hash_insert2 ();
long count_entry ();
void error ();
void hash_init ();
void hash_reset ();
void str_concatc ();
void str_copyc ();
void str_init ();
void str_trunc ();
/* Name under which this program was invoked. */
char *program_name;
/* If nonzero, display only a total for each argument. */
int opt_summarize_only = 0;
/* If nonzero, display counts for all files, not just directories. */
int opt_all = 0;
/* If nonzero, count each hard link of files with multiple links. */
int opt_count_all = 0;
/* If nonzero, do not cross file-system boundaries. */
int opt_one_file_system = 0;
/* If nonzero, print a grand total at the end. */
int opt_combined_arguments = 0;
enum output_size
{
size_blocks, /* Default. */
size_kilobytes, /* -k. */
size_bytes /* -b. */
};
/* The units to count in. */
enum output_size output_size = size_blocks;
/* Accumulated path for file or directory being processed. */
string path;
/* Pointer to hash structure, used by the hash routines. */
struct htab *htab;
/* Globally used stat buffer. */
struct stat stat_buf;
struct option long_options[] =
{
{"all", 0, &opt_all, 1},
{"bytes", 0, NULL, 'b'},
{"count-links", 0, &opt_count_all, 1},
{"kilobytes", 0, NULL, 'k'},
{"one-file-system", 0, &opt_one_file_system, 1},
{"summarize", 0, &opt_summarize_only, 1},
{"total", 0, &opt_combined_arguments, 1},
{NULL, 0, NULL, 0}
};
void
usage (reason)
char *reason;
{
if (reason != NULL)
fprintf (stderr, "%s: %s\n", program_name, reason);
fprintf (stderr, "\
Usage: %s [-abcklsx] [+all] [+total] [+count-links] [+summarize]\n\
[+bytes] [+kilobytes] [+one-file-system] [path...]\n",
program_name);
exit (2);
}
void
main (argc, argv)
int argc;
char *argv[];
{
int c;
int ind;
program_name = argv[0];
while ((c = getopt_long (argc, argv, "abcklsx", long_options, &ind)) != EOF)
{
switch (c)
{
case 0: /* Long option. */
break;
case 'a':
opt_all = 1;
break;
case 'b':
output_size = size_bytes;
break;
case 'c':
opt_combined_arguments = 1;
break;
case 'x':
opt_one_file_system = 1;
break;
case 'k':
output_size = size_kilobytes;
break;
case 'l':
opt_count_all = 1;
break;
case 's':
opt_summarize_only = 1;
break;
default:
usage ((char *) 0);
}
}
if (opt_all && opt_summarize_only)
usage ("cannot both summarize and show all entries");
/* Initialize the hash structure for inode numbers. */
hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
str_init (&path, INITIAL_PATH_SIZE);
if (optind == argc)
{
str_copyc (path, ".");
/* Initialize the hash structure for inode numbers. */
hash_reset ();
/* Get the size of the current directory only. */
count_entry (".", 1, 0);
}
else
{
char wd[PATH_MAX + 2];
char *arg;
ino_t initial_ino; /* Initial directory's inode. */
dev_t initial_dev; /* Initial directory's device. */
long tot_size = 0; /* Grand total size of all args. */
if (getwd (wd) == NULL)
error (1, errno, "cannot get current directory");
/* Remember the inode and device number of the current directory. */
if (stat (".", &stat_buf))
error (1, errno, "current directory");
initial_ino = stat_buf.st_ino;
initial_dev = stat_buf.st_dev;
do
{
int s;
arg = argv[optind];
/* Delete final slash in the argument, unless the slash is alone. */
s = strlen (arg) - 1;
if (s != 0)
{
if (arg[s] == '/')
arg[s] = 0;
str_copyc (path, arg);
}
else if (arg[0] == '/')
str_trunc (path, 0);/* Null path for root directory. */
else
str_copyc (path, arg);
if (!opt_combined_arguments)
hash_reset ();
tot_size += count_entry (arg, 1, 0);
/* chdir if `count_entry' has changed the working directory. */
if (stat (".", &stat_buf))
error (1, errno, ".");
if ((stat_buf.st_ino != initial_ino
|| stat_buf.st_dev != initial_dev)
&& chdir (wd) < 0)
error (1, errno, "cannot change to directory %s", wd);
optind++;
}
while (optind < argc);
if (opt_combined_arguments)
{
printf ("%ld\ttotal\n", output_size == size_bytes ? tot_size
: convert_blocks (tot_size, output_size == size_kilobytes));
fflush (stdout);
}
}
exit (0);
}
/* Print (if appropriate) and return the size
(in units determined by `output_size') of file or directory ENT.
TOP is one for external calls, zero for recursive calls.
LAST_DEV is the device that the parent directory of ENT is on. */
long
count_entry (ent, top, last_dev)
char *ent;
int top;
dev_t last_dev;
{
long size;
if (lstat (ent, &stat_buf) < 0)
{
error (0, errno, "%s", path->text);
return 0;
}
if (!opt_count_all
&& stat_buf.st_nlink > 1
&& hash_insert (stat_buf.st_ino, stat_buf.st_dev))
return 0; /* Have counted this already. */
if (output_size == size_bytes)
size = stat_buf.st_size;
else
{
size = ST_NBLOCKS (stat_buf);
#ifdef HPUX_NFS_BUG
if (size >= 2 * (stat_buf.st_size + DEV_BSIZE - 1) / DEV_BSIZE)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -