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