git-svn: trunk@814
Tomasz Kojm authored on 2004/08/31 20:44:51... | ... |
@@ -1,3 +1,10 @@ |
1 |
+Tue Aug 31 00:09:42 CEST 2004 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * sigtool: --md5 now can generate MD5 sigs from file list (requested by |
|
4 |
+ Christoph Cordes) |
|
5 |
+ * Fix minor file descriptor leaks (reported by Christophe GRENIER |
|
6 |
+ <grenier*cgsecurity.org>) |
|
7 |
+ |
|
1 | 8 |
Tue Aug 31 10:46:48 CEST 2004 (acab) |
2 | 9 |
------------------------------------ |
3 | 10 |
* libclamav/petite.c: Fixed inflooping (thx Christoph) |
... | ... |
@@ -14,7 +21,7 @@ Mon Aug 30 14:00:43 CEST 2004 (tk) |
14 | 14 |
Mon Aug 30 12:36:49 BST 2004 (njh) |
15 | 15 |
---------------------------------- |
16 | 16 |
* libclamav/blob.c: Fix compilation errors on AIX and OSF reported by |
17 |
- Fajar A. Nugraha <fajar@telkom.co.id> |
|
17 |
+ Fajar A. Nugraha <fajar*telkom.co.id> |
|
18 | 18 |
|
19 | 19 |
Sat Aug 28 20:25:44 CEST 2004 (tk) |
20 | 20 |
---------------------------------- |
... | ... |
@@ -165,7 +172,7 @@ Sat Aug 21 12:59:43 BST 2004 (njh) |
165 | 165 |
---------------------------------- |
166 | 166 |
* libclamav: Changed the handling of miltipart messages, that is scanning |
167 | 167 |
emails with attachments. Reports on impact on memory |
168 |
- usage and speed welcome to clamav-devel@lists.sf.net. |
|
168 |
+ usage and speed welcome to clamav-devel*lists.sf.net. |
|
169 | 169 |
|
170 | 170 |
Fri Aug 20 21:05:04 CEST 2004 (tk) |
171 | 171 |
---------------------------------- |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
.\" Manual page created by Tomasz Kojm, 20020629 |
2 |
-.TH "sigtool" "1" "August 18, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
2 |
+.TH "sigtool" "1" "August 31, 2004" "Tomasz Kojm" "Clam AntiVirus" |
|
3 | 3 |
.SH "NAME" |
4 | 4 |
.LP |
5 | 5 |
sigtool \- signature and database management tool |
... | ... |
@@ -29,8 +29,8 @@ Write all messages to standard output (stdout), instead of standard error output |
29 | 29 |
\fB\-\-hex\-dump\fR |
30 | 30 |
Read data from stdin and write hex string to stdout. |
31 | 31 |
.TP |
32 |
-\fB\-\-md5\fR |
|
33 |
-Generate MD5 checksum from stdin. |
|
32 |
+\fB\-\-md5 [FILES]\fR |
|
33 |
+Generate MD5 checksum from stdin or MD5 sigs for FILES. |
|
34 | 34 |
.TP |
35 | 35 |
\fB\-i, \-\-info\fR |
36 | 36 |
Print a CVD information and verify MD5 and a digital signature. |
... | ... |
@@ -564,11 +564,15 @@ int get_database(const char *dbfile, int socketfd, const char *file, const char |
564 | 564 |
|
565 | 565 |
if ((bread = recv(socketfd, buffer, FILEBUFF, 0)) == -1) { |
566 | 566 |
mprintf("@Error while reading database from %s\n", hostname); |
567 |
+ close(fd); |
|
568 |
+ unlink(file); |
|
567 | 569 |
return 52; |
568 | 570 |
} |
569 | 571 |
|
570 | 572 |
if ((strstr(buffer, "HTTP/1.1 404")) != NULL) { |
571 | 573 |
mprintf("@%s not found on remote server\n", dbfile); |
574 |
+ close(fd); |
|
575 |
+ unlink(file); |
|
572 | 576 |
return 58; |
573 | 577 |
} |
574 | 578 |
|
... | ... |
@@ -124,6 +124,7 @@ int cli_untgz(int fd, const char *destdir) |
124 | 124 |
cli_errmsg("Invalid size in header.\n"); |
125 | 125 |
free(fullname); |
126 | 126 |
gzclose(infile); |
127 |
+ fclose(outfile); |
|
127 | 128 |
return -1; |
128 | 129 |
} |
129 | 130 |
|
... | ... |
@@ -369,8 +370,12 @@ int cli_cvdload(FILE *fd, struct cl_node **root, int *virnum) |
369 | 369 |
return CL_ETMPFILE; |
370 | 370 |
} |
371 | 371 |
|
372 |
- if(!(buffer = (char *) cli_malloc(FILEBUFF))) |
|
372 |
+ if(!(buffer = (char *) cli_malloc(FILEBUFF))) { |
|
373 |
+ free(dir); |
|
374 |
+ free(tmp); |
|
375 |
+ fclose(tmpd); |
|
373 | 376 |
return CL_EMEM; |
377 |
+ } |
|
374 | 378 |
|
375 | 379 |
while((bytes = fread(buffer, 1, FILEBUFF, fd)) > 0) |
376 | 380 |
fwrite(buffer, 1, bytes, tmpd); |
... | ... |
@@ -384,6 +389,7 @@ int cli_cvdload(FILE *fd, struct cl_node **root, int *virnum) |
384 | 384 |
cli_errmsg("cli_cvdload(): Can't unpack CVD file.\n"); |
385 | 385 |
cli_rmdirs(dir); |
386 | 386 |
free(dir); |
387 |
+ fclose(tmpd); |
|
387 | 388 |
unlink(tmp); |
388 | 389 |
free(tmp); |
389 | 390 |
return CL_ECVDEXTR; |
... | ... |
@@ -123,10 +123,8 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
123 | 123 |
}; |
124 | 124 |
|
125 | 125 |
|
126 |
- if((fs = fopen(cfgfile, "r")) == NULL) { |
|
126 |
+ if((fs = fopen(cfgfile, "r")) == NULL) |
|
127 | 127 |
return NULL; |
128 |
- } |
|
129 |
- |
|
130 | 128 |
|
131 | 129 |
while(fgets(buff, LINE_LENGTH, fs)) { |
132 | 130 |
|
... | ... |
@@ -138,6 +136,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
138 | 138 |
if(!strncmp("Example", buff, 7)) { |
139 | 139 |
if(messages) |
140 | 140 |
fprintf(stderr, "ERROR: Please edit the example config file %s.\n", cfgfile); |
141 |
+ fclose(fs); |
|
141 | 142 |
return NULL; |
142 | 143 |
} |
143 | 144 |
|
... | ... |
@@ -155,6 +154,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
155 | 155 |
if(!arg) { |
156 | 156 |
if(messages) |
157 | 157 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
158 |
+ fclose(fs); |
|
158 | 159 |
return NULL; |
159 | 160 |
} |
160 | 161 |
copt = regcfg(copt, name, arg, 0); |
... | ... |
@@ -163,6 +163,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
163 | 163 |
if(!arg) { |
164 | 164 |
if(messages) |
165 | 165 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires string as argument.\n", line, name); |
166 |
+ fclose(fs); |
|
166 | 167 |
return NULL; |
167 | 168 |
} |
168 | 169 |
/* FIXME: this one is an ugly hack of the above case */ |
... | ... |
@@ -175,6 +176,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
175 | 175 |
if(!arg || !isnumb(arg)) { |
176 | 176 |
if(messages) |
177 | 177 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical argument.\n", line, name); |
178 |
+ fclose(fs); |
|
178 | 179 |
return NULL; |
179 | 180 |
} |
180 | 181 |
copt = regcfg(copt, name, NULL, atoi(arg)); |
... | ... |
@@ -184,6 +186,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
184 | 184 |
if(!arg) { |
185 | 185 |
if(messages) |
186 | 186 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires argument.\n", line, name); |
187 |
+ fclose(fs); |
|
187 | 188 |
return NULL; |
188 | 189 |
} |
189 | 190 |
ctype = tolower(arg[strlen(arg) - 1]); |
... | ... |
@@ -193,6 +196,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
193 | 193 |
if(!isnumb(cpy)) { |
194 | 194 |
if(messages) |
195 | 195 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
196 |
+ fclose(fs); |
|
196 | 197 |
return NULL; |
197 | 198 |
} |
198 | 199 |
if(ctype == 'm') |
... | ... |
@@ -204,6 +208,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
204 | 204 |
if(!isnumb(arg)) { |
205 | 205 |
if(messages) |
206 | 206 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s requires numerical (raw/K/M) argument.\n", line, name); |
207 |
+ fclose(fs); |
|
207 | 208 |
return NULL; |
208 | 209 |
} |
209 | 210 |
calc = atoi(arg); |
... | ... |
@@ -215,6 +220,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
215 | 215 |
if(arg) { |
216 | 216 |
if(messages) |
217 | 217 |
fprintf(stderr, "ERROR: Parse error at line %d: Option %s doesn't support arguments (got '%s').\n", line, name, arg); |
218 |
+ fclose(fs); |
|
218 | 219 |
return NULL; |
219 | 220 |
} |
220 | 221 |
copt = regcfg(copt, name, NULL, 0); |
... | ... |
@@ -237,6 +243,7 @@ struct cfgstruct *parsecfg(const char *cfgfile, int messages) |
237 | 237 |
if(!found) { |
238 | 238 |
if(messages) |
239 | 239 |
fprintf(stderr, "ERROR: Parse error at line %d: Unknown option %s.\n", line, name); |
240 |
+ fclose(fs); |
|
240 | 241 |
return NULL; |
241 | 242 |
} |
242 | 243 |
} |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* |
2 |
- * Copyright (C) 2001-2003 Tomasz Kojm <zolw@konarski.edu.pl> |
|
2 |
+ * Copyright (C) 2001-2002 Tomasz Kojm <zolw@konarski.edu.pl> |
|
3 | 3 |
* |
4 | 4 |
* This program is free software; you can redistribute it and/or modify |
5 | 5 |
* it under the terms of the GNU General Public License as published by |
... | ... |
@@ -14,6 +14,7 @@ |
14 | 14 |
* You should have received a copy of the GNU General Public License |
15 | 15 |
* along with this program; if not, write to the Free Software |
16 | 16 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 |
+ * |
|
17 | 18 |
*/ |
18 | 19 |
|
19 | 20 |
#if HAVE_CONFIG_H |
... | ... |
@@ -27,14 +28,9 @@ |
27 | 27 |
#define _GNU_SOURCE |
28 | 28 |
#include "getopt.h" |
29 | 29 |
|
30 |
-#if defined(C_LINUX) && defined(CL_DEBUG) |
|
31 |
-#include <sys/resource.h> |
|
32 |
-#endif |
|
33 |
- |
|
34 | 30 |
#include "options.h" |
35 |
-#include "others.h" |
|
36 |
-#include "output.h" |
|
37 | 31 |
#include "memory.h" |
32 |
+#include "output.h" |
|
38 | 33 |
|
39 | 34 |
void sigtool(struct optstruct *opt); |
40 | 35 |
|
... | ... |
@@ -43,7 +39,7 @@ int main(int argc, char **argv) |
43 | 43 |
int ret, opt_index, i, len; |
44 | 44 |
struct optstruct *opt; |
45 | 45 |
|
46 |
- const char *getopt_parameters = "hvVc:s:f:b:i:u:l::"; |
|
46 |
+ const char *getopt_parameters = "hvVb:i:u:l::"; |
|
47 | 47 |
|
48 | 48 |
static struct option long_options[] = { |
49 | 49 |
{"help", 0, 0, 'h'}, |
... | ... |
@@ -64,18 +60,11 @@ int main(int argc, char **argv) |
64 | 64 |
{0, 0, 0, 0} |
65 | 65 |
}; |
66 | 66 |
|
67 |
-#if defined(C_LINUX) && defined(CL_DEBUG) |
|
68 |
- /* njh@bandsman.co.uk: create a dump if needed */ |
|
69 |
- struct rlimit rlim; |
|
70 |
- |
|
71 |
- rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; |
|
72 |
- if(setrlimit(RLIMIT_CORE, &rlim) < 0) |
|
73 |
- perror("setrlimit"); |
|
74 |
-#endif |
|
75 | 67 |
|
76 |
- opt=(struct optstruct*)mcalloc(1, sizeof(struct optstruct)); |
|
68 |
+ opt=(struct optstruct*) mcalloc(1, sizeof(struct optstruct)); |
|
77 | 69 |
opt->optlist = NULL; |
78 | 70 |
|
71 |
+ |
|
79 | 72 |
while(1) { |
80 | 73 |
|
81 | 74 |
opt_index=0; |
... | ... |
@@ -90,9 +79,13 @@ int main(int argc, char **argv) |
90 | 90 |
break; |
91 | 91 |
|
92 | 92 |
default: |
93 |
- if(strchr(getopt_parameters, ret)) |
|
94 |
- register_char_option(opt, ret); |
|
95 |
- else { |
|
93 |
+ if(strchr(getopt_parameters, ret)) { |
|
94 |
+ if(opt_index) |
|
95 |
+ register_char_option(opt, ret, long_options[opt_index].name); |
|
96 |
+ else |
|
97 |
+ register_char_option(opt, ret, NULL); |
|
98 |
+ |
|
99 |
+ } else { |
|
96 | 100 |
mprintf("!Unknown option passed.\n"); |
97 | 101 |
free_opt(opt); |
98 | 102 |
exit(40); |
... | ... |
@@ -115,23 +108,22 @@ int main(int argc, char **argv) |
115 | 115 |
for(i=optind; i<argc; i++) { |
116 | 116 |
strncat(opt->filename, argv[i], strlen(argv[i])); |
117 | 117 |
if(i != argc-1) |
118 |
- strncat(opt->filename, " ", 1); |
|
118 |
+ strncat(opt->filename, "\t", 1); |
|
119 | 119 |
} |
120 | 120 |
|
121 |
- } else |
|
122 |
- /* FIXME !!! Without this, we have segfault */ |
|
123 |
- opt->filename=(char*)mcalloc(1, sizeof(char)); |
|
124 |
- |
|
121 |
+ } |
|
125 | 122 |
|
126 | 123 |
sigtool(opt); |
124 |
+ free_opt(opt); |
|
127 | 125 |
|
128 |
- return(0); |
|
126 |
+ return 0; |
|
129 | 127 |
} |
130 | 128 |
|
131 |
-void register_char_option(struct optstruct *opt, char ch) |
|
129 |
+void register_char_option(struct optstruct *opt, char ch, const char *longname) |
|
132 | 130 |
{ |
133 | 131 |
struct optnode *newnode; |
134 | 132 |
|
133 |
+ |
|
135 | 134 |
newnode = (struct optnode *) mmalloc(sizeof(struct optnode)); |
136 | 135 |
newnode->optchar = ch; |
137 | 136 |
if(optarg != NULL) { |
... | ... |
@@ -148,6 +140,7 @@ void register_long_option(struct optstruct *opt, const char *optname) |
148 | 148 |
{ |
149 | 149 |
struct optnode *newnode; |
150 | 150 |
|
151 |
+ |
|
151 | 152 |
newnode = (struct optnode *) mmalloc(sizeof(struct optnode)); |
152 | 153 |
newnode->optchar = 0; |
153 | 154 |
if(optarg != NULL) { |
... | ... |
@@ -231,10 +224,9 @@ void free_opt(struct optstruct *opt) |
231 | 231 |
{ |
232 | 232 |
struct optnode *handler, *prev; |
233 | 233 |
|
234 |
- if(!opt || !opt->optlist) |
|
234 |
+ if(!opt) |
|
235 | 235 |
return; |
236 | 236 |
|
237 |
- mprintf("*Freeing option list... "); |
|
238 | 237 |
handler = opt->optlist; |
239 | 238 |
|
240 | 239 |
while(handler != NULL) { |
... | ... |
@@ -246,7 +238,7 @@ void free_opt(struct optstruct *opt) |
246 | 246 |
free(prev); |
247 | 247 |
} |
248 | 248 |
|
249 |
- free(opt->filename); |
|
249 |
+ if (opt->filename) |
|
250 |
+ free(opt->filename); |
|
250 | 251 |
free(opt); |
251 |
- mprintf("*done\n"); |
|
252 | 252 |
} |
... | ... |
@@ -33,14 +33,10 @@ struct optstruct { |
33 | 33 |
|
34 | 34 |
int optc(const struct optstruct *opt, char ch); |
35 | 35 |
int optl(const struct optstruct *opt, const char *optname); |
36 |
-void register_char_option(struct optstruct *opt, char ch); |
|
36 |
+void register_char_option(struct optstruct *opt, char ch, const char *longname); |
|
37 | 37 |
void register_long_option(struct optstruct *opt, const char *optname); |
38 | 38 |
char *getargc(const struct optstruct *opt, char ch); |
39 |
-char *getfirstargc(const struct optstruct *opt, char ch, struct optnode **optnode); |
|
40 |
-char *getnextargc(struct optnode **optnode, char ch); |
|
41 | 39 |
char *getargl(const struct optstruct *opt, const char *optname); |
42 |
-char *getfirstargl(const struct optstruct *opt, const char *optname, struct optnode **optnode); |
|
43 |
-char *getnextargl(struct optnode **optnode, const char *optname); |
|
44 | 40 |
void free_opt(struct optstruct *opt); |
45 | 41 |
|
46 | 42 |
#endif |
... | ... |
@@ -21,7 +21,6 @@ |
21 | 21 |
#include "clamav-config.h" |
22 | 22 |
#endif |
23 | 23 |
|
24 |
- |
|
25 | 24 |
#include <stdio.h> |
26 | 25 |
#include <stdlib.h> |
27 | 26 |
#include <string.h> |
... | ... |
@@ -52,10 +51,6 @@ |
52 | 52 |
#include "../libclamav/others.h" |
53 | 53 |
#include "../libclamav/str.h" |
54 | 54 |
|
55 |
-#define LINE 1024 |
|
56 |
- |
|
57 |
-#define MIN_LENGTH 15 |
|
58 |
-#define MAX_LENGTH 200 |
|
59 | 55 |
|
60 | 56 |
void help(void); |
61 | 57 |
char *getdsig(const char *host, const char *user, const char *data); |
... | ... |
@@ -65,21 +60,16 @@ int unpack(struct optstruct *opt); |
65 | 65 |
int listdb(const char *filename); |
66 | 66 |
int listdir(const char *dirname); |
67 | 67 |
void listsigs(struct optstruct *opt); |
68 |
-int cli_rmdirs(const char *dirname); /* libclamav's internal */ |
|
69 | 68 |
|
70 | 69 |
|
71 | 70 |
void sigtool(struct optstruct *opt) |
72 | 71 |
{ |
73 |
- char buffer[FILEBUFF]; |
|
74 |
- int bytes; |
|
75 |
- char *pt; |
|
76 |
- |
|
77 | 72 |
|
78 |
- if(optl(opt, "quiet")) mprintf_quiet = 1; |
|
79 |
- else mprintf_quiet = 0; |
|
73 |
+ if(optl(opt, "quiet")) |
|
74 |
+ mprintf_quiet = 1; |
|
80 | 75 |
|
81 |
- if(optl(opt, "stdout")) mprintf_stdout = 1; |
|
82 |
- else mprintf_stdout = 0; |
|
76 |
+ if(optl(opt, "stdout")) |
|
77 |
+ mprintf_stdout = 1; |
|
83 | 78 |
|
84 | 79 |
if(optl(opt, "debug")) |
85 | 80 |
cl_debug(); |
... | ... |
@@ -95,6 +85,9 @@ void sigtool(struct optstruct *opt) |
95 | 95 |
} |
96 | 96 |
|
97 | 97 |
if(optl(opt, "hex-dump")) { |
98 |
+ char buffer[FILEBUFF]; |
|
99 |
+ int bytes; |
|
100 |
+ char *pt; |
|
98 | 101 |
|
99 | 102 |
while((bytes = read(0, buffer, FILEBUFF)) > 0) { |
100 | 103 |
pt = cli_str2hex(buffer, bytes); |
... | ... |
@@ -103,10 +96,37 @@ void sigtool(struct optstruct *opt) |
103 | 103 |
} |
104 | 104 |
|
105 | 105 |
} else if(optl(opt, "md5")) { |
106 |
+ char *md5, *filename; |
|
107 |
+ int i; |
|
108 |
+ struct stat sb; |
|
106 | 109 |
|
107 |
- char *md5 = cli_md5stream(stdin); |
|
108 |
- mprintf("%s\n", md5); |
|
109 |
- free(md5); |
|
110 |
+ mprintf_stdout = 1; |
|
111 |
+ |
|
112 |
+ if(opt->filename) { |
|
113 |
+ |
|
114 |
+ for(i = 0; (filename = cli_strtok(opt->filename, i, "\t")); i++) { |
|
115 |
+ if(stat(filename, &sb) == -1) { |
|
116 |
+ mprintf("!Can't access file %s\n", filename); |
|
117 |
+ perror(filename); |
|
118 |
+ } else { |
|
119 |
+ if((sb.st_mode & S_IFMT) == S_IFREG) { |
|
120 |
+ if((md5 = cli_md5file(filename))) { |
|
121 |
+ mprintf("%s:%d:%s\n", md5, sb.st_size, filename); |
|
122 |
+ free(md5); |
|
123 |
+ } else |
|
124 |
+ mprintf("!Can't generate MD5 checksum for %s\n", filename); |
|
125 |
+ } |
|
126 |
+ } |
|
127 |
+ |
|
128 |
+ free(filename); |
|
129 |
+ } |
|
130 |
+ |
|
131 |
+ } else { |
|
132 |
+ |
|
133 |
+ md5 = cli_md5stream(stdin); |
|
134 |
+ mprintf("%s\n", md5); |
|
135 |
+ free(md5); |
|
136 |
+ } |
|
110 | 137 |
|
111 | 138 |
} else if(optc(opt, 'b')) { |
112 | 139 |
if(!optl(opt, "server")) { |
... | ... |
@@ -137,7 +157,6 @@ void sigtool(struct optstruct *opt) |
137 | 137 |
help(); |
138 | 138 |
} |
139 | 139 |
|
140 |
- free_opt(opt); |
|
141 | 140 |
} |
142 | 141 |
|
143 | 142 |
int countlines(const char *filename) |
... | ... |
@@ -539,6 +558,7 @@ int listdb(const char *filename) |
539 | 539 |
|
540 | 540 |
if(!(buffer = (char *) mmalloc(FILEBUFF))) { |
541 | 541 |
mprintf("!listdb(): Can't allocate memory.\n"); |
542 |
+ fclose(fd); |
|
542 | 543 |
return -1; |
543 | 544 |
} |
544 | 545 |
|
... | ... |
@@ -596,6 +616,7 @@ int listdb(const char *filename) |
596 | 596 |
mprintf("!listdb(): Can't unpack CVD file.\n"); |
597 | 597 |
cli_rmdirs(dir); |
598 | 598 |
free(dir); |
599 |
+ fclose(tmpd); |
|
599 | 600 |
unlink(tmp); |
600 | 601 |
free(tmp); |
601 | 602 |
free(buffer); |
... | ... |
@@ -718,7 +739,8 @@ void help(void) |
718 | 718 |
mprintf(" --stdout write to stdout instead of stderr\n"); |
719 | 719 |
mprintf(" --hex-dump convert data from stdin to a hex\n"); |
720 | 720 |
mprintf(" string and print it on stdout\n"); |
721 |
- mprintf(" --md5 generate MD5 checksum from stdin\n"); |
|
721 |
+ mprintf(" --md5 [FILES] generate MD5 checksum from stdin\n"); |
|
722 |
+ mprintf(" or MD5 sigs for FILES\n"); |
|
722 | 723 |
mprintf(" --info=FILE -i FILE print database information\n"); |
723 | 724 |
mprintf(" --build=NAME -b NAME build a CVD file\n"); |
724 | 725 |
mprintf(" --server=ADDR ClamAV Signing Service address\n"); |