Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/df.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* df -- free disk block report
26
*/
27
28
static const char usage[] =
29
"[-?\n@(#)$Id: df (AT&T Research) 2010-08-11 $\n]"
30
USAGE_LICENSE
31
"[+NAME?df - summarize disk free space]"
32
"[+DESCRIPTION?\bdf\b displays the available disk space for the filesystem"
33
" of each file argument. If no \afile\a arguments are given then all"
34
" mounted filesystems are displayed.]"
35
36
"[b:blockbytes?Measure disk usage in 512 byte blocks. This is the default"
37
" if \bgetconf CONFORMANCE\b is \bstandard\b.]"
38
"[D:define?Define \akey\a with optional \avalue\a. \avalue\a will be expanded"
39
" when \b%(\b\akey\a\b)\b is specified in \b--format\b. \akey\a may"
40
" override internal \b--format\b identifiers.]:[key[=value]]]"
41
"[e:decimal-scale|thousands?Scale disk usage to powers of 1000.]"
42
"[f:format?Append to the listing format string. The \bls\b(1), \bpax\b(1) and"
43
" \bps\b(1) commands also have \b--format\b options in this same style."
44
" \aformat\a follows \bprintf\b(3) conventions, except that \bsfio\b(3)"
45
" inline ids are used instead of arguments:"
46
" %[#-+]][\awidth\a[.\aprecis\a[.\abase\a]]]]]](\aid\a[:\asubformat\a]])\achar\a."
47
" If \b#\b is specified then the internal width and precision are used."
48
" If \abase\a is non-zero and \b--posix\b is not on then the field values"
49
" are wrapped when they exceed the field width. If \achar\a is \bs\b then"
50
" the string form of the item is listed, otherwise the corresponding"
51
" numeric form is listed. If \achar\a is \bq\b then the string form of"
52
" the item is $'...' quoted if it contains space or non-printing"
53
" characters. If \awidth\a is omitted then the default width"
54
" is assumed. \asubformat\a overrides the default formatting for \aid\a."
55
" Supported \aid\as and \asubformat\as are:]:[format]{\fformats\f}"
56
"[g:gigabytes?Measure disk usage in 1024M byte blocks.]"
57
"[h!:header|heading?Display a heading line.]"
58
"[i:inodes?Display inode usage instead of block usage. There is at least one"
59
" inode for each active file and directory on a filesystem.]"
60
"[k:kilobytes?Measure disk usage in 1024 byte blocks.]"
61
"[K:scale|binary-scale|human-readable?Scale disk usage to powers of 1024."
62
" This is the default if \bgetconf CONFORMANCE\b is not \bstandard\b.]"
63
"[l:local?List information on local filesystems only, i.e., network"
64
" mounts are omitted.]"
65
"[m:megabytes?Measure disk usage in 1024K byte blocks.]"
66
"[n:native-block?Measure disk usage in the native filesystem block size."
67
" This size may vary between filesystems; it is displayed by the"
68
" \bsize\b format identifier.]"
69
"[O:options?Display the \bmount\b(1) options.]"
70
"[P:portable?Display each filesystem on one line. By default output is"
71
" folded for readability. Also implies \b--blockbytes\b.]"
72
"[s:sync?Call \bsync\b(2) before querying the filesystems.]"
73
"[F|t:type?Display all filesystems of type \atype\a. Unknown types are"
74
" listed as \blocal\b. Typical (but not supported on all systems) values"
75
" are:]:[type]{"
76
" [+ufs?default UNIX file system]"
77
" [+ext2?default linux file system]"
78
" [+xfs?sgi XFS]"
79
" [+nfs?network file system version 2]"
80
" [+nfs3?network file system version 3]"
81
" [+afs3?Andrew file system]"
82
" [+proc?process file system]"
83
" [+fat?DOS FAT file system]"
84
" [+ntfs?nt file system]"
85
" [+reg?windows/nt registry file system]"
86
" [+lofs?loopback file system for submounts]"
87
"}"
88
"[v:verbose?Report all filesystem query errors.]"
89
"[q|T?Ignored by this implementation.]"
90
91
"\n"
92
"\n[ file ... ]\n"
93
"\n"
94
"[+EXAMPLES?The default \b--format\b is"
95
" \"%#..1(filesystem)s %#(type)s %#(blocks)s %#(used)s %#(available)s %#(capacity)s %(mounted)s\"]"
96
"[+SEE ALSO?\bgetconf\b(1), \bmount\b(1), \bls\b(1), \bpax\b(1), \bps\b(1),"
97
" \bmount\b(2)]"
98
;
99
100
#include <ast.h>
101
#include <error.h>
102
#include <cdt.h>
103
#include <ls.h>
104
#include <mnt.h>
105
#include <sig.h>
106
#include <sfdisc.h>
107
108
typedef struct /* df entry */
109
{
110
Mnt_t* mnt; /* mnt info */
111
struct statvfs vfs; /* statvfs() info */
112
unsigned long avail;
113
unsigned long tavail;
114
unsigned long total;
115
unsigned long ttotal;
116
unsigned long used;
117
unsigned long tused;
118
unsigned long itotal;
119
unsigned long iavail;
120
unsigned long iused;
121
int percent;
122
int fraction;
123
int ipercent;
124
} Df_t;
125
126
typedef struct /* sfkeyprintf() keys */
127
{
128
char* name; /* key name */
129
char* heading; /* key heading */
130
char* description; /* key description */
131
short index; /* key index */
132
short width; /* default width */
133
short abbrev; /* abbreviation width */
134
short disable; /* macro being expanded */
135
char* macro; /* macro definition */
136
Dtlink_t hashed; /* hash link */
137
} Key_t;
138
139
#define KEY_environ (-1)
140
141
#define KEY_available 1
142
#define KEY_blocks 2
143
#define KEY_capacity 3
144
#define KEY_filesystem 4
145
#define KEY_iavailable 5
146
#define KEY_icapacity 6
147
#define KEY_inodes 7
148
#define KEY_iused 8
149
#define KEY_mounted 9
150
#define KEY_native 10
151
#define KEY_options 11
152
#define KEY_type 12
153
#define KEY_used 13
154
155
static Key_t keys[] =
156
{
157
158
{
159
0
160
},
161
{
162
"available",
163
"Available",
164
"Unused block count.",
165
KEY_available,
166
0,
167
5
168
},
169
{
170
"blocks",
171
0,
172
"Total block count.",
173
KEY_blocks,
174
0,
175
0
176
},
177
{
178
"capacity",
179
"Capacity",
180
"Percent of total blocks used.",
181
KEY_capacity,
182
4,
183
3
184
},
185
{
186
"filesystem",
187
"Filesystem",
188
"Filesystem special device name.",
189
KEY_filesystem,
190
-19,
191
0
192
},
193
{
194
"iavailable",
195
"Iavailable",
196
"Unused inode count.",
197
KEY_iavailable,
198
7,
199
6
200
},
201
{
202
"icapacity",
203
"Icapacity",
204
"Percent of total inodes used.",
205
KEY_icapacity,
206
4,
207
4
208
},
209
{
210
"inodes",
211
"Inodes",
212
"Total inode count.",
213
KEY_inodes,
214
7,
215
3
216
},
217
{
218
"iused",
219
"Iused",
220
"Used inode count.",
221
KEY_iused,
222
7,
223
3
224
},
225
{
226
"mounted",
227
"Mounted on",
228
"Mounted on path.",
229
KEY_mounted,
230
-19,
231
5
232
},
233
{
234
"size",
235
"Size",
236
"Native block size.",
237
KEY_native,
238
4,
239
3
240
},
241
{
242
"options",
243
"Options",
244
"\bmount\b(1) options.",
245
KEY_options,
246
-29,
247
3
248
},
249
{
250
"type",
251
"Type",
252
"Filesystem type.",
253
KEY_type,
254
10,
255
3
256
},
257
{
258
"used",
259
"Used",
260
"Used block count.",
261
KEY_used,
262
0,
263
3
264
},
265
266
};
267
268
static const char fmt_def[] = "%#..1(filesystem)s %#(type)s %#(blocks)s %#(used)s %#(available)s %#(capacity)s %(mounted)s";
269
static const char fmt_ino[] = "%#..1(filesystem)s %#(type)s %#(blocks)s %#(available)s %#(capacity)s %#(inodes)s %#(iavailable)s %#(icapacity)s %(mounted)s";
270
static const char fmt_opt[] = "%#..1(filesystem)s %#(type)s %#(options)s %(mounted)s";
271
static const char fmt_std[] = "%#..1(filesystem)s %#(blocks)s %#(used)s %#(available)s %8(capacity)s %(mounted)s";
272
273
/*
274
* man page and header comments notwithstanding
275
* some systems insist on reporting block counts in 512 units
276
* let me know how you probe for this
277
*/
278
279
#if _SCO_COFF || _SCO_ELF
280
#define F_FRSIZE(v) (512)
281
#else
282
#if _mem_f_frsize_statvfs
283
#define F_FRSIZE(v) ((v)->f_frsize?(v)->f_frsize:(v)->f_bsize?(v)->f_bsize:1024)
284
#else
285
#define F_FRSIZE(v) ((v)->f_bsize?(v)->f_bsize:1024)
286
#endif
287
#endif
288
289
#if _mem_f_basetype_statvfs
290
#define F_BASETYPE(v,p) ((v)->f_basetype)
291
#else
292
static char*
293
basetype(const char* path)
294
{
295
struct stat st;
296
297
return stat(path, &st) ? "ufs" : fmtfs(&st);
298
}
299
#define F_BASETYPE(v,p) (basetype(p))
300
#endif
301
302
#define REALITY(n) ((((long)(n))<0)?0:(n))
303
#define UNKNOWN "local"
304
305
#if _lib_sync
306
extern void sync(void);
307
#endif
308
309
static struct
310
{
311
int block; /* block unit */
312
int local; /* local mounts only */
313
int posix; /* posix format */
314
int scale; /* metric scale power */
315
int sync; /* sync() first */
316
int timeout; /* status() timed out */
317
int verbose; /* verbose message level {-1,1} */
318
char* type; /* type pattern */
319
Sfio_t* mac; /* temporary macro stream */
320
Sfio_t* tmp; /* really temporary stream */
321
Dt_t* keys; /* format key table */
322
char buf[1024]; /* format item buffer */
323
} state;
324
325
/*
326
* optget() info discipline function
327
*/
328
329
static int
330
optinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
331
{
332
register int i;
333
334
if (streq(s, "formats"))
335
for (i = 1; i < elementsof(keys); i++)
336
{
337
sfprintf(sp, "[+%s?%s The title string ", keys[i].name, keys[i].description);
338
if (keys[i].heading)
339
sfprintf(sp, "is \b%s\b ", keys[i].heading, keys[i].width);
340
sfprintf(sp, "and the default width ");
341
if (keys[i].width)
342
sfprintf(sp, "is %d.]", keys[i].width);
343
else
344
sfprintf(sp, "%s determined by the \b-b\b, \b-g\b, \b-k\b, \b-m\b and \b-n\b options.]", keys[i].heading ? "is" : "are");
345
}
346
return 0;
347
}
348
349
/*
350
* append format string to fmt
351
*/
352
353
static void
354
append(Sfio_t* fmt, const char* format)
355
{
356
if (sfstrtell(fmt))
357
sfputc(fmt, ' ');
358
sfputr(fmt, format, -1);
359
}
360
361
/*
362
* scale <m,w,p> into op
363
*/
364
365
static char*
366
scale(int m, unsigned long w, unsigned long p)
367
{
368
Sfulong_t n;
369
370
if (state.scale)
371
{
372
n = w;
373
n *= state.block;
374
return fmtscale(n, state.scale);
375
}
376
if (state.block < 1024 * 1024)
377
sfsprintf(state.buf, sizeof(state.buf), "%lu", w);
378
else if (!m || !w && !p || w > 9)
379
sfsprintf(state.buf, sizeof(state.buf), "%lu", w);
380
else
381
sfsprintf(state.buf, sizeof(state.buf), "%lu.%lu", w, p);
382
return state.buf;
383
}
384
385
/*
386
* sfkeyprintf() lookup
387
* handle==0 for heading
388
*/
389
390
static int
391
key(void* handle, register Sffmt_t* fp, const char* arg, char** ps, Sflong_t* pn)
392
{
393
register Df_t* df = (Df_t*)handle;
394
register char* s = 0;
395
register Sflong_t n = 0;
396
register Key_t* kp;
397
char* t;
398
399
if (!fp->t_str)
400
return 0;
401
if (!(kp = (Key_t*)dtmatch(state.keys, fp->t_str)))
402
{
403
if (*fp->t_str != '$')
404
{
405
error(3, "%s: unknown format key", fp->t_str);
406
return 0;
407
}
408
if (!(kp = newof(0, Key_t, 1, strlen(fp->t_str) + 1)))
409
error(3, "out of space [key]");
410
kp->name = strcpy((char*)(kp + 1), fp->t_str);
411
kp->macro = getenv(fp->t_str + 1);
412
kp->index = KEY_environ;
413
kp->disable = 1;
414
dtinsert(state.keys, kp);
415
}
416
if (kp->macro && !kp->disable)
417
{
418
kp->disable = 1;
419
sfkeyprintf(state.mac, handle, kp->macro, key, NiL);
420
if (!(*ps = sfstruse(state.mac)))
421
error(ERROR_SYSTEM|3, "out of space");
422
kp->disable = 0;
423
}
424
else if (!df)
425
{
426
if (fp->base >= 0)
427
fp->base = -1;
428
s = kp->heading;
429
if (fp->flags & SFFMT_ALTER)
430
{
431
if (!kp->width)
432
kp->width = keys[KEY_blocks].width;
433
if ((fp->width = kp->width) < 0)
434
{
435
fp->width = -fp->width;
436
fp->flags |= SFFMT_LEFT;
437
}
438
fp->precis = fp->width;
439
}
440
if (fp->width > 0 && fp->width < strlen(kp->heading))
441
{
442
if (fp->width < kp->abbrev)
443
{
444
fp->width = kp->abbrev;
445
if (fp->precis >= 0 && fp->precis < fp->width)
446
fp->precis = fp->width;
447
}
448
if (t = newof(0, char, kp->abbrev, 1))
449
s = kp->heading = (char*)memcpy(t, kp->heading, kp->abbrev);
450
}
451
kp->width = fp->width;
452
if (fp->flags & SFFMT_LEFT)
453
kp->width = -kp->width;
454
fp->fmt = 's';
455
*ps = s;
456
}
457
else
458
{
459
if ((fp->flags & SFFMT_ALTER) && (fp->width = kp->width) < 0)
460
{
461
fp->width = -fp->width;
462
fp->flags |= SFFMT_LEFT;
463
}
464
switch (kp->index)
465
{
466
case KEY_available:
467
s = (df->total || df->ttotal) ? scale(df->fraction, df->avail, df->tavail) : "-";
468
break;
469
case KEY_blocks:
470
s = (df->total || df->ttotal) ? scale(df->fraction, df->total, df->ttotal) : "-";
471
break;
472
case KEY_capacity:
473
s = (df->total || df->ttotal) ? (sfsprintf(state.buf, sizeof(state.buf), "%3d%%", df->percent), state.buf) : "-";
474
break;
475
case KEY_environ:
476
if (!(s = kp->macro))
477
return 0;
478
break;
479
case KEY_filesystem:
480
if (!(s = df->mnt->fs))
481
s = "";
482
break;
483
case KEY_iavailable:
484
if (df->total || df->ttotal)
485
n = df->iavail;
486
else
487
s = "-";
488
break;
489
case KEY_icapacity:
490
s = (df->total || df->ttotal) ? (sfsprintf(state.buf, sizeof(state.buf), "%3d%%", df->ipercent), state.buf) : "-";
491
break;
492
case KEY_inodes:
493
if (df->total || df->ttotal)
494
n = df->itotal;
495
else
496
s = "-";
497
break;
498
case KEY_iused:
499
if (df->total || df->ttotal)
500
n = df->iused;
501
else
502
s = "-";
503
break;
504
case KEY_mounted:
505
if (!(s = df->mnt->dir))
506
s = "";
507
break;
508
case KEY_native:
509
if ((n = F_FRSIZE(&df->vfs)) >= 1024)
510
sfsprintf(state.buf, sizeof(state.buf), "%I*3dk", sizeof(n), n / 1024);
511
else
512
sfsprintf(state.buf, sizeof(state.buf), "%I*4d", sizeof(n), n);
513
s = state.buf;
514
break;
515
case KEY_options:
516
if (!(s = df->mnt->options))
517
s = "";
518
break;
519
case KEY_type:
520
if (!(s = df->mnt->type))
521
s = "";
522
break;
523
case KEY_used:
524
s = (df->total || df->ttotal) ? scale(df->fraction, df->used, df->tused) : "-";
525
break;
526
default:
527
return 0;
528
}
529
if (s)
530
{
531
if (fp->base >= 0)
532
{
533
fp->base = -1;
534
if (!state.posix && strlen(s) >= fp->width)
535
{
536
sfprintf(state.tmp, "%s%-*.*s", s, fp->width + 1, fp->width + 1, "\n");
537
if (!(s = sfstruse(state.tmp)))
538
error(ERROR_SYSTEM|3, "out of space");
539
}
540
}
541
*ps = s;
542
}
543
else
544
*pn = n;
545
}
546
return 1;
547
}
548
549
/*
550
* catch statvfs() timeout
551
*/
552
553
static void
554
timeout(int sig)
555
{
556
state.timeout = 1;
557
}
558
559
/*
560
* statvfs() with timeout
561
*/
562
563
static int
564
status(const char* path, struct statvfs* vfs)
565
{
566
int r;
567
568
state.timeout = 0;
569
signal(SIGALRM, timeout);
570
alarm(4);
571
r = statvfs(path, vfs);
572
alarm(0);
573
signal(SIGALRM, SIG_DFL);
574
if (r)
575
{
576
if (state.timeout)
577
error(ERROR_SYSTEM|2, "%s: filesystem stat timed out", path);
578
else
579
error(ERROR_SYSTEM|2, "%s: cannot stat filesystem", path);
580
}
581
return r;
582
}
583
584
/*
585
* list one entry
586
*/
587
588
static void
589
entry(Df_t* df, const char* format)
590
{
591
unsigned long b;
592
int s;
593
594
if ((!state.type || strmatch(df->mnt->type, state.type)) && (!state.local || !(df->mnt->flags & MNT_REMOTE)))
595
{
596
if (REALITY(df->vfs.f_blocks) == 0)
597
{
598
df->total = df->avail = df->used = 0;
599
df->percent = 0;
600
}
601
else
602
{
603
/*
604
* NOTE: on some systems vfs.f_* are unsigned,
605
* and on others signed negative values
606
* denote error
607
*/
608
609
df->total = df->vfs.f_blocks;
610
df->used = ((long)df->vfs.f_blocks <= (long)df->vfs.f_bfree) ? 0 : (df->vfs.f_blocks - df->vfs.f_bfree);
611
df->avail = ((long)df->vfs.f_bavail < 0) ? 0 : df->vfs.f_bavail;
612
df->percent = (df->ttotal = df->avail + df->used) ? (unsigned long)(((double)df->used / (double)df->ttotal + 0.005) * 100.0) : 0;
613
}
614
df->fraction = 0;
615
df->ttotal = df->tavail = df->tused = 0;
616
if (state.scale)
617
state.block = F_FRSIZE(&df->vfs);
618
else if (state.block)
619
{
620
b = F_FRSIZE(&df->vfs);
621
if (b > state.block)
622
{
623
s = b / state.block;
624
df->total *= s;
625
df->avail *= s;
626
df->used *= s;
627
}
628
else if (b < state.block)
629
{
630
s = state.block / b;
631
if (df->fraction = s / 10)
632
{
633
df->ttotal = (df->total / df->fraction) % 10;
634
df->tavail = (df->avail / df->fraction) % 10;
635
df->tused = (df->used / df->fraction) % 10;
636
}
637
df->total /= s;
638
df->avail /= s;
639
df->used /= s;
640
}
641
}
642
df->itotal = REALITY(df->vfs.f_files);
643
df->iavail = REALITY(df->vfs.f_ffree);
644
if (df->itotal < df->iavail)
645
df->iused = 0;
646
else
647
df->iused = df->itotal - df->iavail;
648
df->iavail = REALITY(df->vfs.f_favail);
649
df->ipercent = (s = df->iused + df->iavail) ? (unsigned long)(((double)df->iused / (double)s + 0.005) * 100.0) : 0;
650
sfkeyprintf(sfstdout, df, format, key, NiL);
651
}
652
}
653
654
int
655
main(int argc, register char** argv)
656
{
657
register int n;
658
int rem;
659
int head;
660
int i;
661
int* match;
662
dev_t dirdev;
663
dev_t mntdev;
664
dev_t* dev;
665
void* mp;
666
Sfio_t* fmt;
667
Key_t* kp;
668
char* s;
669
char* format;
670
struct stat st;
671
struct statvfs vfs;
672
Dtdisc_t keydisc;
673
Optdisc_t optdisc;
674
Mnt_t mnt;
675
Df_t df;
676
677
error_info.id = "df";
678
state.block = -1;
679
state.posix = -1;
680
state.verbose = -1;
681
dev = 0;
682
head = 1;
683
684
/*
685
* set up the disciplines
686
*/
687
688
optinit(&optdisc, optinfo);
689
memset(&keydisc, 0, sizeof(keydisc));
690
keydisc.key = offsetof(Key_t, name);
691
keydisc.size = -1;
692
keydisc.link = offsetof(Key_t, hashed);
693
694
/*
695
* initialize the tables and string streams
696
*/
697
698
if (!(fmt = sfstropen()) || !(state.mac = sfstropen()) || !(state.tmp = sfstropen()))
699
error(3, "out of space [fmt]");
700
if (!(state.keys = dtopen(&keydisc, Dtset)))
701
error(3, "out of space [dict]");
702
for (n = 1; n < elementsof(keys); n++)
703
dtinsert(state.keys, keys + n);
704
705
/*
706
* grab the options
707
*/
708
709
for (;;)
710
{
711
switch (optget(argv, usage))
712
{
713
case 'b':
714
state.block = 512;
715
continue;
716
case 'D':
717
if (s = strchr(opt_info.arg, '='))
718
*s++ = 0;
719
if (*opt_info.arg == 'n' && *(opt_info.arg + 1) == 'o')
720
{
721
opt_info.arg += 2;
722
s = 0;
723
}
724
if (!(kp = (Key_t*)dtmatch(state.keys, opt_info.arg)))
725
{
726
if (!s)
727
continue;
728
if (!(kp = newof(0, Key_t, 1, strlen(opt_info.arg) + 1)))
729
error(ERROR_SYSTEM|3, "out of space [macro]");
730
kp->name = strcpy((char*)(kp + 1), opt_info.arg);
731
dtinsert(state.keys, kp);
732
}
733
if (kp->macro = s)
734
stresc(s);
735
continue;
736
case 'e':
737
state.scale = 1000;
738
continue;
739
case 'f':
740
append(fmt, opt_info.arg);
741
continue;
742
case 'F':
743
case 't':
744
state.type = opt_info.arg;
745
continue;
746
case 'g':
747
state.block = 1024 * 1024 * 1024;
748
continue;
749
case 'h':
750
head = opt_info.num;
751
continue;
752
case 'i':
753
append(fmt, fmt_ino);
754
continue;
755
case 'k':
756
state.block = 1024;
757
continue;
758
case 'K':
759
state.scale = 1024;
760
continue;
761
case 'l':
762
state.local = 1;
763
continue;
764
case 'm':
765
state.block = 1024 * 1024;
766
continue;
767
case 'n':
768
state.block = 0;
769
continue;
770
case 'O':
771
append(fmt, fmt_opt);
772
continue;
773
case 'P':
774
state.posix = 1;
775
continue;
776
case 'q':
777
continue;
778
case 's':
779
state.sync = opt_info.num;
780
continue;
781
case 'T':
782
continue;
783
case 'v':
784
state.verbose = ERROR_SYSTEM|1;
785
continue;
786
case '?':
787
error(ERROR_USAGE|4, "%s", opt_info.arg);
788
break;
789
case ':':
790
error(2, "%s", opt_info.arg);
791
break;
792
}
793
break;
794
}
795
if (error_info.errors)
796
error(ERROR_USAGE|4, "%s", optusage(NiL));
797
argc -= opt_info.index;
798
argv += opt_info.index;
799
if (!sfstrtell(fmt))
800
append(fmt, state.posix > 0 ? fmt_std : fmt_def);
801
sfputc(fmt, '\n');
802
if (!(format = sfstruse(fmt)))
803
error(ERROR_SYSTEM|3, "out of space");
804
stresc(format);
805
if (state.posix < 0)
806
state.posix = !!conformance(0, 0);
807
if (state.block < 0)
808
{
809
if (state.posix)
810
state.block = 512;
811
else
812
{
813
state.block = 1024 * 1024;
814
if (!state.scale)
815
state.scale = 1024;
816
}
817
}
818
s = 0;
819
if (state.scale)
820
{
821
n = 5;
822
s = "Size";
823
}
824
else if (state.block <= 512)
825
{
826
n = 10;
827
if (!state.block)
828
s = "blocks";
829
}
830
else if (state.block <= 1024)
831
{
832
n = 8;
833
if (state.block == 1024)
834
s = "Kbytes";
835
}
836
else if (state.block <= 1024 * 1024)
837
{
838
n = 6;
839
if (state.block == 1024 * 1024)
840
s = "Mbytes";
841
}
842
else if (state.block <= 1024 * 1024 * 1024)
843
{
844
n = 6;
845
if (state.block == 1024 * 1024 * 1024)
846
s = "Gbytes";
847
}
848
if (!s)
849
{
850
sfprintf(state.mac, "%d-blocks", state.block);
851
if (!(s = strdup(sfstruse(state.mac))))
852
error(ERROR_SYSTEM|3, "out of space [heading]");
853
n = strlen(s);
854
}
855
keys[KEY_blocks].width = n;
856
keys[KEY_blocks].heading = s;
857
#if _lib_sync
858
if (state.sync)
859
sync();
860
#endif
861
if (!(mp = mntopen(NiL, "r")))
862
{
863
error(ERROR_SYSTEM|(argc > 0 ? 1 : 3), "cannot access mount table");
864
sfkeyprintf(head ? sfstdout : state.tmp, NiL, format, key, NiL);
865
sfstrseek(state.tmp, 0, SEEK_SET);
866
df.mnt = &mnt;
867
mnt.dir = UNKNOWN;
868
mnt.type = 0;
869
mnt.flags = 0;
870
while (mnt.fs = *argv++)
871
if (!status(mnt.fs, &df.vfs))
872
entry(&df, format);
873
}
874
else
875
{
876
sfkeyprintf(head ? sfstdout : state.tmp, NiL, format, key, NiL);
877
sfstrseek(state.tmp, 0, SEEK_SET);
878
if (argc)
879
{
880
rem = argc;
881
if (!(dev = newof(0, dev_t, argc, 0)))
882
error(ERROR_SYSTEM|3, "out of space [dev_t]");
883
for (n = 0; n < argc; n++)
884
if (stat(argv[n], &st))
885
{
886
error(ERROR_SYSTEM|2, "%s: cannot stat", argv[n]);
887
argv[n] = 0;
888
rem--;
889
}
890
else
891
dev[n] =
892
#if _mem_st_rdev_stat
893
S_ISBLK(st.st_mode) ? st.st_rdev :
894
#endif
895
st.st_dev;
896
}
897
else
898
rem = 0;
899
if (rem && (match = newof(0, int, n, 0)))
900
{
901
/*
902
* scan the mount table (up to 3x) for prefix matches
903
* to avoid the more expensive stat() and statvfs()
904
* calls in the final loop below
905
*/
906
907
while (df.mnt = mntread(mp))
908
909
for (n = 0; n < argc; n++)
910
if (argv[n] && (i = strlen(df.mnt->dir)) > 1 && i > match[n] && strneq(argv[n], df.mnt->dir, i) && (argv[n][i] == '/' || !argv[n][i]))
911
match[n] = i;
912
mntclose(mp);
913
if (!(mp = mntopen(NiL, "r")))
914
error(ERROR_SYSTEM|3, "cannot reopen mount table");
915
while (rem && (df.mnt = mntread(mp)))
916
for (n = 0; n < argc; n++)
917
if (match[n] && (i = strlen(df.mnt->dir)) == match[n] && strneq(argv[n], df.mnt->dir, i) && (argv[n][i] == '/' || !argv[n][i]))
918
{
919
argv[n][match[n]] = 0;
920
if (!status(argv[n], &df.vfs))
921
{
922
entry(&df, format);
923
argv[n] = 0;
924
match[n] = 0;
925
if (!--rem)
926
break;
927
}
928
}
929
free(match);
930
if (rem)
931
{
932
mntclose(mp);
933
if (!(mp = mntopen(NiL, "r")))
934
error(ERROR_SYSTEM|3, "cannot reopen mount table");
935
}
936
}
937
while ((!argc || rem) && (df.mnt = mntread(mp)))
938
{
939
if (stat(df.mnt->dir, &st))
940
{
941
if (errno != ENOENT && errno != ENOTDIR)
942
error(state.verbose, "%s: cannot stat", df.mnt->dir);
943
continue;
944
}
945
dirdev = st.st_dev;
946
mntdev = (!rem || *df.mnt->fs != '/' || stat(df.mnt->fs, &st)) ? dirdev : st.st_dev;
947
if (rem)
948
{
949
for (n = 0; n < argc; n++)
950
if (argv[n] && (dev[n] == dirdev || dev[n] == mntdev))
951
{
952
argv[n] = 0;
953
rem--;
954
break;
955
}
956
if (n >= argc)
957
continue;
958
}
959
if (!status(df.mnt->dir, &df.vfs) || !status(df.mnt->fs, &df.vfs))
960
entry(&df, format);
961
if (rem)
962
{
963
while (++n < argc)
964
if (dev[n] == dirdev || dev[n] == mntdev)
965
{
966
argv[n] = 0;
967
rem--;
968
}
969
if (rem <= 0)
970
break;
971
}
972
}
973
mntclose(mp);
974
if (argc > 0)
975
{
976
df.mnt = &mnt;
977
memset(&mnt, 0, sizeof(mnt));
978
for (n = 0; n < argc; n++)
979
if ((mnt.dir = argv[n]) && !status(mnt.dir, &vfs))
980
entry(&df, format);
981
}
982
}
983
return error_info.errors != 0;
984
}
985
986