1 /*
2  * Copyright (C) 2001, 2002, and 2003  Roy Keene
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  *      email: dact@rkeene.org
19  */
20 
21 #include "dact.h"
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28 #ifdef HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 #include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_WAIT_H
38 #include <sys/wait.h>
39 #endif
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h>
42 #endif
43 #include "parse.h"
44 #include "dendian.h"
45 #include "crc.h"
46 #include "math.h"
47 #include "dact_common.h"
48 #include "algorithms.h"
49 #include "libdact.h"
50 #include "ciphers.h"
51 #include "module.h"
52 #include "header.h"
53 #include "parse.h"
54 #include "net.h"
55 #include "ui.h"
56 #ifdef HAVE_ZLIB_H
57 #include <zlib.h>
58 #endif
59 #ifdef HAVE_BZLIB_H
60 #include <bzlib.h>
61 #endif
62 
63 
64 int print_help(int argc, char **argv);
65 int dact_shutdown(int retval);
66 int main(int argc, char **argv);
67 
68 extern char *optarg;
69 extern int optind, opterr, optopt;
70 
print_help(int argc,char ** argv)71 int print_help(int argc, char **argv) {
72 	printf("DACT %i.%i.%i-%s by Keene Enterprises <dact@rkeene.org>\n", DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION, DACT_VER_SUB);
73 	printf("usage: %s [options...] [file ...]\n",argv[0]);
74 	printf("Options:\n");
75 	printf("  -d          Decompress instead of compressing.\n");
76 	printf("  -s          Give statistics rather than compress or decompress.\n");
77 	printf("  -f          Force unsafe things to happen.\n");
78 	printf("  -c          (De)compress to stdout.\n");
79 	printf("  -v          Increase verbosity.\n");
80 	printf("  -l          List available algorithms.\n");
81 	printf("  -n          Toggle use of CRCs.\n");
82 	printf("  -i          Use stdin to read information from instead of /dev/tty.\n");
83 #ifndef DACT_UNSAFE
84 	printf("  -C          Complain when compression errors occur.\n");
85 #endif
86 	printf("  -H          Write only header (no data).\n");
87 	printf("  -O          Toggle writing original file name.\n");
88 	printf("  -S          Use speed-size as a metric rather than size.\n");
89 	printf("  -h          Give this help.\n");
90 	printf("  -V          Display DACT version (%i.%i.%i-%s).\n", DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION, DACT_VER_SUB);
91 	printf("  -N          Upgrade DACT.\n");
92 	printf("  -a          Upgrade DACT modules.\n");
93 	printf("  -x          Create self-extracting DACT file.\n");
94 	printf("  -b NN       Use a block size of NN bytes for compression.\n");
95 	printf("  -e NN       Exclude algorithm NN from being used.\n");
96 	printf("  -m CONF     Load config file CONF.\n");
97 	printf("  -o FILE     Send output to FILE.\n");
98 	printf("  -u URL      Specify download location as URL.\n");
99 	printf("  -p URL      Parse URL and print results, then exit.\n");
100 	printf("  -M COMMAND  Execute COMMAND as if it had appeared in a config file.\n");
101 	printf("  -D DESC     Specify a description of DESC.\n");
102 	printf("  -I NN       Use ONLY 2 algorithms, NN and 0.\n");
103 	printf("  -U FILE     Use FILE to select download location.\n");
104 	printf("  -E CIPHER   Use CIPHER to encrypt data (LIST  lists available ciphers.)\n");
105 	printf("  file...     File(s) to (de)compress.  (If none given, use standard input).\n");
106 	return(0);
107 }
108 
dact_upgrade_file(const char * name,const char * url_get,const char * url_ver,uint32_t version,const char * dest,const unsigned char * options)109 int dact_upgrade_file(const char *name, const char *url_get, const char *url_ver, uint32_t version, const char *dest, const unsigned char *options) {
110 	int newver, ifd=-1, ofd=-1, x=-1;
111 	char *real_dest, *real_url_get, buf[4096];
112 
113 	if (dest==NULL) {
114 		real_dest=parse_url_subst(DACT_BIN_DIR "@@FILE@@.so", name);
115 	} else {
116 		real_dest=parse_url_subst(dest, name);
117 	}
118 	real_url_get=parse_url_subst(url_get, name);
119 
120 	newver=dact_upgrade_file_checkver(name, url_ver, options);
121 	if (newver>version) {
122 		if (options[DACT_OPT_UPGRADE]) {
123 			fprintf(stderr, "There is a new version of %s.  NEW: %i.%i.%i, CURR: %i.%i.%i, fetching...\n", name, DACT_VER_PARTS(newver), DACT_VER_PARTS(version));
124 			if ((ifd=open_net(real_url_get, O_RDONLY, 0))>=0) {
125 				if ((ofd=open_net(real_dest, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU))>=0) {
126 					while ((x=read(ifd, buf, sizeof(buf)))>0) {
127 						write(ofd, buf, x);
128 					}
129 					close(ifd);
130 					close(ofd);
131 					if (x<0) PERROR("read");
132 				} else {
133 					PERROR_L(ofd, "open");
134 				}
135 			} else {
136 				PERROR_L(ifd, "open");
137 			}
138 		} else {
139 			fprintf(stderr, "There is a new version of %s.  NEW: %i.%i.%i, CURR: %i.%i.%i\n", name, DACT_VER_PARTS(newver), DACT_VER_PARTS(version));
140 		}
141 	}
142 	free(real_dest);
143 	free(real_url_get);
144 	return(x);
145 }
146 
dact_upgrade_file_checkver(const char * name,const char * url_ver,const unsigned char * options)147 int dact_upgrade_file_checkver(const char *name, const char *url_ver, const unsigned char *options) {
148 #ifdef CHECK_VERSION
149 	uint32_t rem_ver[4]={0, 0, 0, 0};
150 	int fd;
151 	char rem_vers[3][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0}};
152 	char *urlbuf, verbuf[9];
153 
154 	if (options[DACT_OPT_VERCHK]==0 && options[DACT_OPT_UPGRADE]==0) return(0);
155 
156 	urlbuf=parse_url_subst(url_ver, name);
157 	if ((fd=open_net(urlbuf, O_RDONLY, 0))>=0) {
158 		read(fd, &verbuf, 9);
159 		close(fd);
160 		memcpy(rem_vers[0], verbuf, 3);
161 		memcpy(rem_vers[1], verbuf+3, 3);
162 		memcpy(rem_vers[2], verbuf+6, 3);
163 		rem_ver[0]=atoi(rem_vers[0]);
164 		rem_ver[1]=atoi(rem_vers[1]);
165 		rem_ver[2]=atoi(rem_vers[2]);
166 		rem_ver[3]=(rem_ver[0]<<16)|(rem_ver[1]<<8)|(rem_ver[2]);
167 	}
168 	free(urlbuf);
169 	return(rem_ver[3]);
170 #else
171 	return(0);
172 #endif
173 }
174 
dact_upgrade(unsigned char * options)175 int dact_upgrade(unsigned char *options) {
176 #ifdef DACT_DEBIAN_UPGRADE_PROC
177 	char *buf;
178 	int status=0, i;
179 
180 	if (getuid()==0) {
181 		buf=dact_ui_getuserinput("Executing `apt-get update' okay [y/N]? ", 5, 0);
182 		if (toupper(buf[0])!='Y') {
183 			PRINTERR("Failed to upgrade DACT.");
184 			free(buf);
185 			return(-1);
186 		}
187 		free(buf);
188 
189 		if (fork()==0) {
190 			execl("/usr/bin/apt-get","apt-get","update",NULL);
191 			return(-1);  /* Couldn't run binary. */
192 		} else {
193 			i=wait(&status);
194 			if (WIFEXITED(status)) {
195 				if (WEXITSTATUS(status)) {
196 					PRINTERR("Failed to run `apt-get update'");
197 					return(-1);
198 				}
199 			}
200 		}
201 
202 		if (fork()==0) {
203 			execl("/usr/bin/apt-get","apt-get","install","dact",NULL);
204 			return(-1);  /* Couldn't run binary. */
205 		} else {
206 			i=wait(&status);
207 			if (WIFEXITED(status)) {
208 				if (WEXITSTATUS(status)) {
209 					PRINTERR("Failed to run `apt-get install dact'");
210 					return(-1);
211 				}
212 			}
213 		}
214 
215 		return(1);
216 	}
217 #else
218 	options[DACT_OPT_UPGRADE]=1;
219 	return(dact_upgrade_file("dact", DACT_BIN_URL, DACT_BIN_URL_VER, DACT_BIN_VER, DACT_BIN, options));
220 #endif
221 }
222 
223 #if 0
224 int dact_upgrade(const char *options, uint32_t *crcs) {
225 	char *urlsubst, *buf, *dact_binfilebuf;
226 	char dact_binfile[256];
227 	int inFd, outFd;
228 	uint32_t i;
229 
230 
231 #ifdef DACT_DEBIAN_UPGRADE_PROC
232 	int status=0;
233 
234 	if (getuid()==0) {
235 		buf=dact_ui_getuserinput("Executing `apt-get update' okay [y/N]? ", 5, 0);
236 		if (toupper(buf[0])!='Y') {
237 			PRINTERR("Failed to upgrade DACT.");
238 			free(buf);
239 			return(-1);
240 		}
241 		free(buf);
242 
243 		if (fork()==0) {
244 			execl("/usr/bin/apt-get","apt-get","update",NULL);
245 			return(-1);  /* Couldn't run binary. */
246 		} else {
247 			i=wait(&status);
248 			if (WIFEXITED(status)) {
249 				if (WEXITSTATUS(status)) {
250 					PRINTERR("Failed to run `apt-get update'");
251 					return(-1);
252 				}
253 			}
254 		}
255 
256 		if (fork()==0) {
257 			execl("/usr/bin/apt-get","apt-get","install","dact",NULL);
258 			return(-1);  /* Couldn't run binary. */
259 		} else {
260 			i=wait(&status);
261 			if (WIFEXITED(status)) {
262 				if (WEXITSTATUS(status)) {
263 					PRINTERR("Failed to run `apt-get install dact'");
264 					return(-1);
265 				}
266 			}
267 		}
268 
269 		return(1);
270 	}
271 #endif
272 
273 	if ((i=is_latest(options))) {
274 		PRINTERR("**+");
275 		PRINT_LINE; fprintf(stderr, "dact: **> CURR: DACT %i.%i.%i\n",DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION);
276 		PRINT_LINE; fprintf(stderr, "dact: **> NEW:  DACT %i.%i.%i\n",i>>16,(i>>8)&0xff,i&0xff);
277 		PRINTERR("**>");
278 		PRINTERR("**-");
279 	}
280 	if ((inFd=open_net("http://www.rkeene.org/projects/rget/rget.cgi?project=dact&file=info", O_RDONLY))>=0) {
281 		fprintf(stderr, "------------------------\n");
282 		buf=malloc(1024);
283 		while (1) {
284 			i=read_f(inFd, buf, 1024);
285 			write(STDERR_FILENO, buf, i);
286 			if (i!=1024) break;
287 		}
288 		fprintf(stderr, "------------------------\n");
289 		close(inFd);
290 		free(buf);
291 	}
292 
293 #ifdef GO32
294 	mkdir("c:/dact/", 0755);
295 	strcpy(dact_binfile,"c:/dact/dact.exe");
296 #else
297 	strncpy(dact_binfile,getenv("HOME"),sizeof(dact_binfile)-1);
298 	strncat(dact_binfile,"/.dact/",sizeof(dact_binfile)-strlen(dact_binfile)-1);
299 	mkdir(dact_binfile, 0755);
300 	dact_binfilebuf=parse_url_subst("@@OSNM@@-@@ARCH@@/", "");
301 	strncat(dact_binfile,dact_binfilebuf,sizeof(dact_binfile)-strlen(dact_binfile)-1);
302 	free(dact_binfilebuf);
303 	mkdir(dact_binfile, 0755);
304 
305 	strncat(dact_binfile,"dact.bin",sizeof(dact_binfile)-strlen(dact_binfile)-1);
306 #endif
307 	urlsubst=parse_url_subst("http://www.rkeene.org/projects/rget/rget.cgi?os=@@OSNM@@&arch=@@ARCH@@&project=dact&file=bin&meth=gz","");
308 	if ((outFd=open_net(dact_binfile, O_WRONLY|O_TRUNC|O_CREAT, 0755))<0) {
309 		PERROR_L(outFd, "open_net");
310 		return(-1);
311 	}
312 	if ((inFd=open_net(urlsubst, O_RDONLY, 0))<0) {
313 		PERROR_L(inFd, "open_net");
314 		return(-1);
315 	}
316 	if (!dact_process_file(inFd, outFd, DACT_MODE_DECMP, options, "dact", crcs, DACT_BLK_SIZE_DEF, -1)) {
317 		close(inFd);
318 		close(outFd);
319 		unlink(dact_binfile);
320 		PRINTERR("Failed to upgrade DACT.");
321 		return(-1);
322 	}
323 	close(inFd);
324 	close(outFd);
325 	if (!options[DACT_OPT_BINCHK]) {
326 		PRINTERR("Note: You do not have binary_check  set to `on' in your dact.conf.");
327 	}
328 	return(1);
329 }
330 
331 uint32_t is_latest (const char *options) {
332 #if defined(CHECK_VERSION)
333 	int fd;
334 	char ver_maj[4]={0,0,0,0}, ver_min[4]={0,0,0,0}, ver_rev[4]={0,0,0,0};
335 	char bigbuf[1024];
336 	int vers[3];
337 
338 	if (options[DACT_OPT_VERCHK]==0) return(0);
339 	if (getuid()==0) return(0);
340 
341 	if ((fd=createconnection_tcp("www.rkeene.org", 80))<0) return(0);
342 
343 	write(fd, "GET http://www.rkeene.org/devel/dact/VERSION\n", 45);
344 	read(fd, &bigbuf,1024);
345 
346 	memcpy(ver_maj,bigbuf,3);
347 	memcpy(ver_min,bigbuf+3,3);
348 	memcpy(ver_rev,bigbuf+6,3);
349 
350 	closeconnection(fd);
351 
352 	vers[0]=atoi(ver_maj);
353 	vers[1]=atoi(ver_min);
354 	vers[2]=atoi(ver_rev);
355 
356 	if ( ((vers[0]<<16)|(vers[1]<<8)|vers[2]) > ((DACT_VER_MAJOR<<16)|(DACT_VER_MINOR<<8)|DACT_VER_REVISION) ) {
357 		return((vers[0]<<16)|(vers[1]<<8)|vers[2]);
358 	} else {
359 		return(0);
360 	}
361 #else
362 	return(0);
363 #endif
364 }
365 #endif
366 
dact_shutdown(int retval)367 int dact_shutdown(int retval) {
368 	unload_modules();
369 	dact_ui_deinit();
370 	return(retval);
371 }
372 
dact_getoutfilename(const char * orig,const int mode,const char * ext)373 char *dact_getoutfilename(const char *orig, const int mode, const char *ext) {
374 	char *ret=NULL;
375 	size_t retlen;
376 
377 	switch (mode) {
378 		case DACT_MODE_COMPR:
379 			retlen=strlen(orig)+strlen(ext)+10;
380 			ret=malloc(retlen);
381 			snprintf(ret, retlen, "%s%s", orig, ext);
382 			break;
383 		case DACT_MODE_DECMP:
384 			if (strcmp(&orig[strlen(orig)-4],".dct") && \
385 				strcmp(&orig[strlen(orig)-4], ".exe") && \
386 				strcmp(&orig[strlen(orig)-4], ".bin") && \
387 				strcmp(&orig[strlen(orig)-4], ".bz2") && \
388 				strcmp(&orig[strlen(orig)-5], ".tbz2") && \
389 				strcmp(&orig[strlen(orig)-4], ".tgz") && \
390 				strcmp(&orig[strlen(orig)-3], ".gz")) {
391 				return(NULL);
392 			}
393 /* XXX: I wonder if this breaks easily... */
394 			ret=strdup(orig);
395 			(*strrchr(ret, '.'))='\0';
396 			break;
397 		case DACT_MODE_STAT:
398 			return(NULL);
399 			break;
400 	}
401 	return(ret);
402 }
403 
main(int argc,char ** argv)404 int main(int argc, char **argv) {
405 	unsigned char options[20]={0};
406 	signed char opt;
407 	struct stat stat_buf;
408 	char **in_files, *in_file=NULL, *out_file=NULL;
409 	char dact_binfilebuf[256], *dact_binfile;
410 	char *ext=".dct";
411 	int filecnt=0;
412 	int in_fd, out_fd;
413 	int mode=DACT_MODE_COMPR, ciphernum=-1;
414 	uint32_t dact_blk_size=0;
415 	uint32_t crcs[6]={0};
416 	uint32_t i,x;
417 
418 	dact_ui_init();
419 	dact_init();
420 
421 /* hack, to make upgrade work even if DACT_OPT_BINCHK is enabled, we must
422  *      get the new version before executing it.
423  */
424 	if (argv[1]!=NULL) {
425 		if (!strcmp(argv[1],"-N")) return(dact_upgrade(options));
426 		if (!strcmp(argv[1],"-a")) options[DACT_OPT_UPGRADE]=1;
427 	}
428 
429 	dact_config_loadfile(DACT_CONFIG_FILE, options, &dact_blk_size);
430 #ifndef NO_BINCHECK
431 	dact_binfilebuf[0]='\0';
432 	if (getenv("HOME")) {
433 		strncpy(dact_binfilebuf,getenv("HOME"),sizeof(dact_binfilebuf)-1);
434 	}
435 	strncat(dact_binfilebuf,"/.dact/dact.conf",sizeof(dact_binfilebuf)-strlen(dact_binfilebuf)-1);
436 	dact_config_loadfile(dact_binfilebuf, options, &dact_blk_size);
437 #endif
438 
439 	if (options[DACT_OPT_BINCHK]) {
440 		dact_binfile=parse_url_subst(DACT_BIN, "");
441 		if (strcmp(argv[0],dact_binfile)) {
442 			if (!access(dact_binfile,X_OK)) {
443 				argv[0]=dact_binfile;
444 				/* This fixes a strange warning..*/
445 #ifndef __MINGW32__
446 				execv(dact_binfile, argv);
447 #else
448 				execv(dact_binfile, (const char **) argv);
449 #endif
450 			}
451 		}
452 	}
453 
454 	while ((opt=getopt(argc,argv,"adfsvcnhixNVHCM:E:p:I:m:e:lb:u:U:TPOD:o:"))!=-1) {
455 		switch (opt) {
456 			case 'a':
457 				options[DACT_OPT_UPGRADE]=1;
458 				break;
459 			case 'd':
460 				mode=DACT_MODE_DECMP;
461 				break;
462 			case 'f':
463 				options[DACT_OPT_FORCE]++;
464 				break;
465 			case 's':
466 				mode=DACT_MODE_STAT;
467 				break;
468 			case 'i':
469 				dact_ui_setopt(DACT_UI_OPT_PASSSTDIN, 1);
470 				break;
471 			case 'x':
472 				if (strcmp(EXEEXT, "")==0) {
473 					ext=".bin";
474 				} else {
475 					ext=EXEEXT;
476 				}
477 				options[DACT_OPT_SFX]=!options[DACT_OPT_SFX];
478 				break;
479 			case 'c':
480 				options[DACT_OPT_STDOUT]=!options[DACT_OPT_STDOUT];
481 				break;
482 			case 'b':
483 				i=atoi2(optarg);
484 				if (i<DACT_BLK_SIZE_ABSMAX) dact_blk_size=i;
485 				break;
486 			case 'v':
487 				options[DACT_OPT_VERB]++;
488 				dact_ui_setopt(DACT_UI_OPT_LEVEL,dact_ui_getopt(DACT_UI_OPT_LEVEL)+1);
489 				break;
490 			case 'n':
491 				options[DACT_OPT_NOCRC]=!options[DACT_OPT_NOCRC];
492 				break;
493 			case 'p':
494 				PRINT_LINE; fprintf(stderr, "dact: %s\n",parse_url_subst(optarg,"@@file@@"));
495 				mode=DACT_MODE_RET;
496 				break;
497 			case 'C':
498 				options[DACT_OPT_COMPLN]++;
499 				break;
500 			case 'm':
501 				dact_config_loadfile(optarg, options, &dact_blk_size);
502 				break;
503 			case 'e':
504 				i=(atoi(optarg)&0xff);
505 				algorithms[i]=DACT_FAILED_ALGO;
506 				break;
507 			case 'H':
508 				options[DACT_OPT_HDONLY]=!options[DACT_OPT_HDONLY];
509 				break;
510 			case 'o':
511 				out_file=parse_url_subst(optarg, "");
512 				break;
513 			case 'M':
514 				dact_config_execute(optarg, options, &dact_blk_size);
515 				break;
516 			case 'N':
517 				PRINTERR("The `-N\' option must be the first and only argument passed to dact.");
518 				return(0);
519 				break;
520 			case 'E':
521 				strtolower(optarg);
522 				x=hash_fourbyte((unsigned char *) optarg, ' ');
523 				if (x==hash_fourbyte((unsigned char *) "list", ' ')) {
524 					PRINT_LINE; fprintf(stderr, "dact: Num | Name\n");
525 					for (i=0;i<CIPHER_COUNT;i++) {
526 						if (ciphers_name[i]!=NULL && ciphers[i]!=DACT_FAILED_ALGO) {
527 							PRINT_LINE; fprintf(stderr, "dact: %3i | %s\n",i,ciphers_name[i]);
528 						}
529 					}
530 					return(0);
531 				}
532 				for (i=0;i<CIPHER_COUNT;i++) {
533 					if (ciphers_name[i]!=NULL && ciphers[i]!=DACT_FAILED_ALGO) {
534 						if (x==hash_fourbyte((unsigned char *) ciphers_name[i], ' ')) {
535 							break;
536 						}
537 					}
538 				}
539 				if (i==CIPHER_COUNT) i=-1;
540 				ciphernum=i;
541 				if (ciphernum==-1) {
542 					PRINTERR("No such cipher.");
543 					return(-1);
544 				}
545 				break;
546 			case 'l':
547 				PRINT_LINE; fprintf(stderr, "dact: Num | Name\n");
548 				for (i=0;i<255;i++) {
549 					if (algorithms[i]==NULL || algorithms[i]==DACT_FAILED_ALGO) continue;
550 					PRINT_LINE; fprintf(stderr, "dact: %3i | %s\n",i,algorithm_names[i]);
551 
552 				}
553 				mode=DACT_MODE_RET;
554 				break;
555 			case 'I':
556 				x=atoi(optarg);
557 				for (i=1;i<255;i++) {
558 					if (i!=x) algorithms[i]=NULL;
559 				}
560 				break;
561 			case 'V':
562 				printf("DACT %i.%i.%i-%s", DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION, DACT_VER_SUB);
563 #if defined(__DATE__) && defined(__TIME__)
564 				printf("  built on %s at %s",__DATE__,__TIME__);
565 #endif
566 #ifdef DACT_CONTACT
567 				printf(" %s",DACT_CONTACT);
568 #endif
569 				printf("\n");
570 				return(0);
571 				break;
572 			case 'u':
573 				dact_hdr_ext_regs(DACT_HDR_URL, optarg, strlen(optarg));
574 				break;
575 			case 'U':
576 				dact_hdr_ext_regs(DACT_HDR_URLFILE, optarg, strlen(optarg));
577 				break;
578 			case 'D':
579 				dact_hdr_ext_regs(DACT_HDR_DESC, optarg, strlen(optarg));
580 				break;
581 			case 'T':
582 				options[DACT_OPT_TIME]=!options[DACT_OPT_TIME];
583 				break;
584 			case 'P':
585 				options[DACT_OPT_PERM]=!options[DACT_OPT_PERM];
586 				break;
587 			case 'O':
588 				options[DACT_OPT_ORIG]=!options[DACT_OPT_ORIG];
589 				break;
590 			case 'S':
591 				options[DACT_OPT_SZSPD]=!options[DACT_OPT_SZSPD];
592 				break;
593 			case '?':
594 			case ':':
595 			case 'h':
596 				return(print_help(argc,argv));
597 		}
598 
599 	}
600 
601 /*
602  * Check for a new version of DACT
603  */
604 	if ((i=dact_upgrade_file_checkver("dact", DACT_BIN_URL_VER, options))>DACT_BIN_VER) {
605 		PRINTERR("**+");
606 		PRINTERR("**> There is a new version of DACT available.");
607 		PRINTERR("**>");
608 		PRINT_LINE; fprintf(stderr, "dact: **> [CURR: DACT %i.%i.%i]\n",DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION);
609 		PRINT_LINE; fprintf(stderr, "dact: **> [NEW:  DACT %i.%i.%i]\n",i>>16,(i>>8)&0xff,i&0xff);
610 		PRINTERR("**>");
611 		PRINTERR("**> Run `dact -N' to get it.");
612 		PRINTERR("**> or get the source at: http://www.rkeene.org/devel/dact.tar.gz");
613 		PRINTERR("**>");
614 		PRINTERR("**-");
615 	}
616 
617 	if (mode==DACT_MODE_RET) return(0);
618 
619 	in_files=&argv[optind];
620 
621 /* Loop through extra parameters (files ...) and setup FDs for them */
622 	do {
623 		in_fd=-1;
624 		out_fd=-1;
625 
626 		in_file=in_files[filecnt];
627 		if (in_file!=NULL) {
628 /* Determine resulting file name */
629 			if (out_file==NULL) out_file=dact_getoutfilename(in_file, mode, ext);
630 			if (strcmp("-",in_file)==0) {
631 				in_fd=STDIN_FILENO;
632 			} else {
633 				if (stat(in_file, &stat_buf)>=0) {
634 					if (S_ISDIR(stat_buf.st_mode)) {
635 						fprintf(stderr, "dact: %s is a directory.\n",in_file);
636 						continue;
637 					}
638 				}
639 				if ((in_fd=open_net(in_file, O_RDONLY, 0))<0) {
640 					fprintf(stderr, "dact: Can't open %s.\n",in_file);
641 					PERROR_L(in_fd, "open");
642 					continue;
643 				}
644 			}
645 			if (out_file!=NULL) {
646 				if (!strcmp("-",out_file)) options[DACT_OPT_STDOUT]=1;
647 /*
648  *
649  * This is a bad thing if this program is SUID root, which it NEVER EVER
650  * should be.
651  *
652  *  DO NOT MAKE DACT SUID ROOT OR YOU WILL BE HACKED
653  *
654  * that should be a suffcient warning.
655  * (this is a mere race condition, but a severe warning should prevent
656  *  people from complaining about it to me.)
657  *
658  */
659 				if (access(out_file,F_OK)!=-1 && options[DACT_OPT_FORCE]==0 && options[DACT_OPT_STDOUT]==0) {
660 					fprintf(stderr, "dact: %s exists.\n",out_file);
661 					close(in_fd);
662 					continue;
663 				}
664 				if (!options[DACT_OPT_STDOUT]) {
665 					if ((out_fd=open_net(out_file,O_WRONLY|O_CREAT|O_TRUNC,0644))<0) {
666 						fprintf(stderr, "dact: Can't open %s for writing.\n",out_file);
667 						PERROR_L(out_fd, "open");
668 						continue;
669 					}
670 				}
671 			}
672 			if (options[DACT_OPT_STDOUT]) out_fd=STDOUT_FILENO;
673 		}
674 
675 /* Use STDIN/STDOUT if no files specified ... unless an outfile was specified... */
676 		if (in_file==NULL && filecnt==0) {
677 /* ... But only if STDOUT isn't a terminal */
678 			if (isatty(STDOUT_FILENO) && options[DACT_OPT_FORCE]==0) {
679 				fprintf(stderr, "dact: Refusing to write compressed output to a terminal.\n");
680 			} else {
681 				out_fd=STDOUT_FILENO;
682 				in_fd=STDIN_FILENO;
683 			}
684 		}
685 
686 /* Okay, we're all done, now pass these to something to do the real stuff */
687 		if (in_fd!=-1 && (out_fd!=-1 || mode==DACT_MODE_STAT)) {
688 			crcs[1]=crcs[0]=0;
689 			if (dact_process_file(in_fd, out_fd, mode, options, in_file, crcs, dact_blk_size, ciphernum)==0) {
690 				close(in_fd);
691 				close(out_fd);
692 				if (out_fd!=STDOUT_FILENO) {
693 					unlink(out_file);
694 				}
695 				return(dact_shutdown(-1));
696 			}
697 		}
698 /* Cleanup */
699 		if (out_fd!=-1) close(out_fd);
700 		if (in_fd!=-1) close(in_fd);
701 	} while (in_files[filecnt++]!=NULL);
702 
703 	return(dact_shutdown(0));
704 }
705