1 #include "config.h"
2
3 #include <sys/types.h>
4 #include <sys/param.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #include "argcargv.h"
13 #include "list.h"
14
15 #define K_CLIENT 0
16 #define K_SERVER 1
17
18 extern int errno;
19
20 off_t lsize( char *tpath );
21 off_t kfile_size( char *kfile, int location );
22
23 static struct list *kfile_list;
24 static char kdir[ MAXPATHLEN ];
25
26 off_t
lsize(char * tpath)27 lsize( char *tpath )
28 {
29 FILE *tfp = NULL;
30 unsigned long long totalsize = 0, cursize = 0;
31 char **tav = NULL;
32 char line[ MAXPATHLEN * 2 ];
33 int tac, linenum = 1;
34
35 if (( tfp = fopen( tpath, "r" )) == NULL ) {
36 fprintf( stderr, "fopen %s: %s\n", tpath, strerror( errno ));
37 exit( 2 );
38 }
39
40 while ( fgets( line, MAXPATHLEN * 2, tfp ) != NULL ) {
41 linenum++;
42 if (( tac = argcargv( line, &tav )) != 8 ) {
43 continue;
44 }
45
46 if ( *tav[ 0 ] != 'a' && *tav[ 0 ] != 'f' ) {
47 continue;
48 }
49
50 /* XXX - use strtoofft */
51 cursize = strtoull( tav[ 6 ], NULL, 10 );
52 if ( errno == ERANGE || errno == EINVAL ) {
53 fprintf( stderr, "line %d: strtoull %s: %s\n",
54 linenum, tav[ 6 ], strerror( errno ));
55 exit( 2 );
56 }
57
58 totalsize += cursize;
59 }
60
61 ( void )fclose( tfp );
62
63 return( totalsize );
64 }
65
66 off_t
kfile_size(char * kfile,int location)67 kfile_size( char *kfile, int location )
68 {
69 FILE *fp;
70 off_t cursize = 0, total = 0;
71 int length, ac, linenum = 0;
72 char line[ MAXPATHLEN ];
73 char fullpath[ MAXPATHLEN ];
74 char *subpath;
75 char **av;
76
77 if (( fp = fopen( kfile, "r" )) == NULL ) {
78 perror( kfile );
79 return( -1 );
80 }
81
82 while ( fgets( line, sizeof( line ), fp ) != NULL ) {
83 linenum++;
84 length = strlen( line );
85 if ( line[ length - 1 ] != '\n' ) {
86 fprintf( stderr, "command: line %d: line too long\n", linenum );
87 return( -1 );
88 }
89
90 /* skips blank lines and comments */
91 if ((( ac = argcargv( line, &av )) == 0 ) || ( *av[ 0 ] == '#' )) {
92 continue;
93 }
94
95 if ( ac != 2 ) {
96 fprintf( stderr, "command: line %d: expected 2 arguments, got %d\n",
97 linenum, ac );
98 return( -1 );
99 }
100
101 switch( location ) {
102 case K_CLIENT:
103 if ( snprintf( fullpath, MAXPATHLEN, "%s%s", kdir,
104 av[ 1 ] ) >= MAXPATHLEN ) {
105 fprintf( stderr, "command: line %d: path too long\n",
106 linenum );
107 fprintf( stderr, "command: line %d: %s%s\n",
108 linenum, kdir, av[ 1 ] );
109 return( -1 );
110 }
111 break;
112
113 case K_SERVER:
114 if ( *av[ 0 ] == 'k' ) {
115 subpath = "command";
116 } else {
117 subpath = "transcript";
118 }
119 if ( snprintf( fullpath, MAXPATHLEN, "%s/%s/%s", _RADMIND_PATH,
120 subpath, av[ 1 ] ) >= MAXPATHLEN ) {
121 fprintf( stderr, "command: line %d: path too long\n",
122 linenum );
123 fprintf( stderr, "command: line %d: %s%s\n",
124 linenum, kdir, av[ 1 ] );
125 return( -1 );
126 }
127 break;
128
129 default:
130 fprintf( stderr, "unknown location\n" );
131 return( -1 );
132 }
133
134 switch( *av[ 0 ] ) {
135 case 'k': /* command file */
136 if ( list_check( kfile_list, fullpath )) {
137 fprintf( stderr,
138 "%s: line %d: command file loop: %s already included\n",
139 kfile, linenum, av[ 1 ] );
140 return( -1 );
141 }
142 if ( list_insert( kfile_list, fullpath ) != 0 ) {
143 perror( "list_insert" );
144 return( -1 );
145 }
146
147 if (( cursize = kfile_size( fullpath, location )) < 0 ) {
148 return( -1 );
149 }
150 total += cursize;
151 break;
152
153 case 'n': /* negative */
154 /* XXX - include sizes from negative? */
155 continue;
156
157 case 'p': /* positive */
158 total += lsize( fullpath );
159 break;
160
161 case 's': /* special */
162 /* XXX - provide -h option to indicate client? */
163 continue;
164
165 default:
166 fprintf( stderr, "command: line %d: '%s' invalid\n",
167 linenum, av[ 0 ] );
168 return( -1 );
169 }
170 }
171
172 if ( fclose( fp ) != 0 ) {
173 perror( kfile );
174 return( -1 );
175 }
176
177 return( total );
178 }
179
180 int
main(int ac,char * av[])181 main( int ac, char *av[] )
182 {
183 char *path = NULL, *ext = NULL, *p;
184 double totalsize = 0;
185 int c, factor = 1024, err = 0, kfile = 0;
186 extern int optind;
187
188 while (( c = getopt( ac, av, "bgkm" )) != EOF ) {
189 switch ( c ) {
190 case 'b': /* bytes */
191 factor = 1;
192 break;
193
194 case 'g': /* gigabytes */
195 factor = ( 1024 * 1024 * 1024 );
196 break;
197
198 case 'k': /* kilobytes (default) */
199 factor = 1024;
200 break;
201
202 case 'm': /* megabytes */
203 factor = ( 1024 * 1024 );
204 break;
205
206 case '?':
207 err++;
208 }
209 }
210
211 path = av[ optind ];
212
213 if ( err || ( ac - optind ) != 1 ) {
214 fprintf( stderr, "Usage: %s [ -bgkmt ] { commandfile "
215 "| transcript }\n", av[ 0 ] );
216 exit( 1 );
217 }
218
219 if (( ext = strrchr( path, '.' )) != NULL ) {
220 if ( strcmp( ++ext, "K" ) == 0 ) {
221 kfile = 1;
222 if ( strlen( path ) >= MAXPATHLEN ) {
223 fprintf( stderr, "%s: path too long\n", path );
224 exit( 2 );
225 }
226 strcpy( kdir, path );
227
228 if (( p = strrchr( kdir, '/' )) == NULL ) {
229 /* use working directory */
230 strcpy( kdir, "./" );
231 } else {
232 p++;
233 *p = (char)'\0';
234 }
235 if (( kfile_list = list_new()) == NULL ) {
236 perror( "list_new" );
237 exit( 2 );
238 }
239 if ( list_insert( kfile_list, path ) != 0 ) {
240 perror( "list_insert" );
241 exit( 2 );
242 }
243 }
244 /* otherwise assume it's a transcript */
245 }
246
247 if ( kfile ) {
248 if (( totalsize = ( double )kfile_size( path, K_SERVER )) < 0 ) {
249 exit( 2 );
250 }
251 } else {
252 totalsize = ( double )lsize( path );
253 }
254
255 totalsize /= ( double )factor;
256
257 printf( "%.2f\n", totalsize );
258
259 return( 0 );
260 }
261