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 "ciphers.h" 50 #include "module.h" 51 #include "header.h" 52 #include "parse.h" 53 #include "net.h" 54 #include "ui.h" 55 #ifdef HAVE_ZLIB_H 56 #include <zlib.h> 57 #endif 58 #ifdef HAVE_BZLIB_H 59 #include <bzlib.h> 60 #endif 61 62 63 int print_help(int argc, char **argv); 64 int dact_shutdown(int retval); 65 char *dact_getoutfilename(const char *orig, const int mode); 66 uint32_t dact_process_other(int src, const int dest, const uint32_t magic, const char *options); 67 int main(int argc, char **argv); 68 69 extern char *optarg; 70 extern int optind, opterr, optopt; 71 char dact_nonetwork=0; 72 73 int print_help(int argc, char **argv) { 74 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); 75 printf("usage: %s [options...] [file ...]\n",argv[0]); 76 printf("Options:\n"); 77 printf(" -d Decompress instead of compressing.\n"); 78 printf(" -s Give statistics rather than compress or decompress.\n"); 79 printf(" -f Force unsafe things to happen.\n"); 80 printf(" -c (De)compress to stdout.\n"); 81 printf(" -v Increase verbosity.\n"); 82 printf(" -l List available algorithms.\n"); 83 printf(" -n Toggle use of CRCs.\n"); 84 printf(" -i Use stdin to read information from instead of /dev/tty.\n"); 85 #ifndef DACT_UNSAFE 86 printf(" -C Complain when compression errors occur.\n"); 87 #endif 88 printf(" -H Write only header (no data).\n"); 89 printf(" -O Toggle writing original file name.\n"); 90 printf(" -S Use speed-size as a metric rather than size.\n"); 91 printf(" -h Give this help.\n"); 92 printf(" -V Display DACT version (%i.%i.%i-%s).\n", DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION, DACT_VER_SUB); 93 printf(" -N Upgrade DACT.\n"); 94 printf(" -a Upgrade DACT modules.\n"); 95 printf(" -b NN Use a block size of NN bytes for compression.\n"); 96 printf(" -e NN Exclude algorithm NN from being used.\n"); 97 printf(" -m CONF Load config file CONF.\n"); 98 printf(" -o FILE Send output to FILE.\n"); 99 printf(" -u URL Specify download location as URL.\n"); 100 printf(" -p URL Parse URL and print results, then exit.\n"); 101 printf(" -M COMMAND Execute COMMAND as if it had appeared in a config file.\n"); 102 printf(" -D DESC Specify a description of DESC.\n"); 103 printf(" -I NN Use ONLY 2 algorithms, NN and 0.\n"); 104 printf(" -U FILE Use FILE to select download location.\n"); 105 printf(" -E CIPHER Use CIPHER to encrypt data (LIST lists available ciphers.)\n"); 106 printf(" file... File(s) to (de)compress. (If none given, use standard input).\n"); 107 return(0); 108 } 109 110 int dact_blksize_calc(int fsize) { 111 if (fsize==0) return(DACT_BLK_SIZE_DEF); 112 if (fsize<(204800)) { 113 return(fsize+5); 114 } 115 return(((int) ((((float) fsize)/102400.0)-(0.9999999)))*65535); 116 } 117 118 int dact_upgrade_file(const char *name, const char *url_get, const char *url_ver, uint32_t version, const char *dest, const char *options) { 119 int newver, ifd=-1, ofd=-1, x=-1; 120 char *real_dest, *real_url_get, buf[4096]; 121 122 if (dest==NULL) { 123 real_dest=parse_url_subst(DACT_BIN_DIR "@@FILE@@.so", name); 124 } else { 125 real_dest=parse_url_subst(dest, name); 126 } 127 real_url_get=parse_url_subst(url_get, name); 128 129 newver=dact_upgrade_file_checkver(name, url_ver, options); 130 if (newver>version) { 131 if (options[DACT_OPT_UPGRADE]) { 132 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)); 133 if ((ifd=open_net(real_url_get, O_RDONLY, 0))>=0) { 134 if ((ofd=open_net(real_dest, O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU))>=0) { 135 while ((x=read(ifd, buf, sizeof(buf)))>0) { 136 write(ofd, buf, x); 137 } 138 close(ifd); 139 close(ofd); 140 if (x<0) PERROR("read"); 141 } else { 142 PERROR_L(ofd, "open"); 143 } 144 } else { 145 PERROR_L(ifd, "open"); 146 } 147 } else { 148 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)); 149 } 150 } 151 free(real_dest); 152 free(real_url_get); 153 return(x); 154 } 155 156 int dact_upgrade_file_checkver(const char *name, const char *url_ver, const char *options) { 157 #ifdef CHECK_VERSION 158 uint32_t rem_ver[4]={0, 0, 0, 0}; 159 int fd; 160 char rem_vers[3][4]={{0,0,0,0},{0,0,0,0},{0,0,0,0}}; 161 char *urlbuf, verbuf[9]; 162 163 if (options[DACT_OPT_VERCHK]==0 && options[DACT_OPT_UPGRADE]==0) return(0); 164 165 urlbuf=parse_url_subst(url_ver, name); 166 if ((fd=open_net(urlbuf, O_RDONLY, 0))>=0) { 167 read(fd, &verbuf, 9); 168 close(fd); 169 memcpy(rem_vers[0], verbuf, 3); 170 memcpy(rem_vers[1], verbuf+3, 3); 171 memcpy(rem_vers[2], verbuf+6, 3); 172 rem_ver[0]=atoi(rem_vers[0]); 173 rem_ver[1]=atoi(rem_vers[1]); 174 rem_ver[2]=atoi(rem_vers[2]); 175 rem_ver[3]=(rem_ver[0]<<16)|(rem_ver[1]<<8)|(rem_ver[2]); 176 } 177 free(urlbuf); 178 return(rem_ver[3]); 179 #else 180 return(0); 181 #endif 182 } 183 184 int dact_upgrade(char *options) { 185 #ifdef DACT_DEBIAN_UPGRADE_PROC 186 char *buf; 187 int status=0, i; 188 189 if (getuid()==0) { 190 buf=dact_ui_getuserinput("Executing `apt-get update' okay [y/N]? ", 5, 0); 191 if (toupper(buf[0])!='Y') { 192 PRINTERR("Failed to upgrade DACT."); 193 free(buf); 194 return(-1); 195 } 196 free(buf); 197 198 if (fork()==0) { 199 execl("/usr/bin/apt-get","apt-get","update",NULL); 200 return(-1); /* Couldn't run binary. */ 201 } else { 202 i=wait(&status); 203 if (WIFEXITED(status)) { 204 if (WEXITSTATUS(status)) { 205 PRINTERR("Failed to run `apt-get update'"); 206 return(-1); 207 } 208 } 209 } 210 211 if (fork()==0) { 212 execl("/usr/bin/apt-get","apt-get","install","dact",NULL); 213 return(-1); /* Couldn't run binary. */ 214 } else { 215 i=wait(&status); 216 if (WIFEXITED(status)) { 217 if (WEXITSTATUS(status)) { 218 PRINTERR("Failed to run `apt-get install dact'"); 219 return(-1); 220 } 221 } 222 } 223 224 return(1); 225 } 226 #else 227 options[DACT_OPT_UPGRADE]=1; 228 return(dact_upgrade_file("dact", DACT_BIN_URL, DACT_BIN_URL_VER, DACT_BIN_VER, DACT_BIN, options)); 229 #endif 230 } 231 232 #if 0 233 int dact_upgrade(const char *options, uint32_t *crcs) { 234 char *urlsubst, *buf, *dact_binfilebuf; 235 char dact_binfile[256]; 236 int inFd, outFd; 237 uint32_t i; 238 239 240 #ifdef DACT_DEBIAN_UPGRADE_PROC 241 int status=0; 242 243 if (getuid()==0) { 244 buf=dact_ui_getuserinput("Executing `apt-get update' okay [y/N]? ", 5, 0); 245 if (toupper(buf[0])!='Y') { 246 PRINTERR("Failed to upgrade DACT."); 247 free(buf); 248 return(-1); 249 } 250 free(buf); 251 252 if (fork()==0) { 253 execl("/usr/bin/apt-get","apt-get","update",NULL); 254 return(-1); /* Couldn't run binary. */ 255 } else { 256 i=wait(&status); 257 if (WIFEXITED(status)) { 258 if (WEXITSTATUS(status)) { 259 PRINTERR("Failed to run `apt-get update'"); 260 return(-1); 261 } 262 } 263 } 264 265 if (fork()==0) { 266 execl("/usr/bin/apt-get","apt-get","install","dact",NULL); 267 return(-1); /* Couldn't run binary. */ 268 } else { 269 i=wait(&status); 270 if (WIFEXITED(status)) { 271 if (WEXITSTATUS(status)) { 272 PRINTERR("Failed to run `apt-get install dact'"); 273 return(-1); 274 } 275 } 276 } 277 278 return(1); 279 } 280 #endif 281 282 if ((i=is_latest(options))) { 283 PRINTERR("**+"); 284 PRINT_LINE; fprintf(stderr, "dact: **> CURR: DACT %i.%i.%i\n",DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION); 285 PRINT_LINE; fprintf(stderr, "dact: **> NEW: DACT %i.%i.%i\n",i>>16,(i>>8)&0xff,i&0xff); 286 PRINTERR("**>"); 287 PRINTERR("**-"); 288 } 289 if ((inFd=open_net("http://www.rkeene.org/projects/rget/rget.cgi?project=dact&file=info", O_RDONLY))>=0) { 290 fprintf(stderr, "------------------------\n"); 291 buf=malloc(1024); 292 while (1) { 293 i=read_f(inFd, buf, 1024); 294 write(STDERR_FILENO, buf, i); 295 if (i!=1024) break; 296 } 297 fprintf(stderr, "------------------------\n"); 298 close(inFd); 299 free(buf); 300 } 301 302 #ifdef GO32 303 mkdir("c:/dact/", 0755); 304 strcpy(dact_binfile,"c:/dact/dact.exe"); 305 #else 306 strncpy(dact_binfile,getenv("HOME"),sizeof(dact_binfile)-1); 307 strncat(dact_binfile,"/.dact/",sizeof(dact_binfile)-strlen(dact_binfile)-1); 308 mkdir(dact_binfile, 0755); 309 dact_binfilebuf=parse_url_subst("@@OSNM@@-@@ARCH@@/", ""); 310 strncat(dact_binfile,dact_binfilebuf,sizeof(dact_binfile)-strlen(dact_binfile)-1); 311 free(dact_binfilebuf); 312 mkdir(dact_binfile, 0755); 313 314 strncat(dact_binfile,"dact.bin",sizeof(dact_binfile)-strlen(dact_binfile)-1); 315 #endif 316 urlsubst=parse_url_subst("http://www.rkeene.org/projects/rget/rget.cgi?os=@@OSNM@@&arch=@@ARCH@@&project=dact&file=bin& meth=gz",""); 317 if ((outFd=open_net(dact_binfile, O_WRONLY|O_TRUNC|O_CREAT, 0755))<0) { 318 PERROR_L(outFd, "open_net"); 319 return(-1); 320 } 321 if ((inFd=open_net(urlsubst, O_RDONLY, 0))<0) { 322 PERROR_L(inFd, "open_net"); 323 return(-1); 324 } 325 if (!dact_process_file(inFd, outFd, DACT_MODE_DECMP, options, "dact", crcs, DACT_BLK_SIZE_DEF, -1)) { 326 close(inFd); 327 close(outFd); 328 unlink(dact_binfile); 329 PRINTERR("Failed to upgrade DACT."); 330 return(-1); 331 } 332 close(inFd); 333 close(outFd); 334 if (!options[DACT_OPT_BINCHK]) { 335 PRINTERR("Note: You do not have binary_check set to `on' in your dact.conf."); 336 } 337 return(1); 338 } 339 340 uint32_t is_latest (const char *options) { 341 #if defined(CHECK_VERSION) 342 int fd; 343 char ver_maj[4]={0,0,0,0}, ver_min[4]={0,0,0,0}, ver_rev[4]={0,0,0,0}; 344 char bigbuf[1024]; 345 int vers[3]; 346 347 if (options[DACT_OPT_VERCHK]==0) return(0); 348 if (getuid()==0) return(0); 349 350 if ((fd=createconnection_tcp("www.rkeene.org", 80))<0) return(0); 351 352 write(fd, "GET http://www.rkeene.org/devel/dact/VERSION\n", 45); 353 read(fd, &bigbuf,1024); 354 355 memcpy(ver_maj,bigbuf,3); 356 memcpy(ver_min,bigbuf+3,3); 357 memcpy(ver_rev,bigbuf+6,3); 358 359 closeconnection(fd); 360 361 vers[0]=atoi(ver_maj); 362 vers[1]=atoi(ver_min); 363 vers[2]=atoi(ver_rev); 364 365 if ( ((vers[0]<<16)|(vers[1]<<8)|vers[2]) > ((DACT_VER_MAJOR<<16)|(DACT_VER_MINOR<<8)|DACT_VER_REVISION) ) { 366 return((vers[0]<<16)|(vers[1]<<8)|vers[2]); 367 } else { 368 return(0); 369 } 370 #else 371 return(0); 372 #endif 373 } 374 #endif 375 376 int dact_shutdown(int retval) { 377 unload_modules(); 378 dact_ui_deinit(); 379 return(retval); 380 } 381 382 char *dact_getoutfilename(const char *orig, const int mode) { 383 char *ret=NULL; 384 int x=0; 385 386 switch (mode) { 387 case DACT_MODE_COMPR: 388 ret=malloc(strlen(orig)+5); 389 #ifdef GO32 390 strncpy(ret,orig,8); 391 for (x=0;x<strlen(ret);x++) { 392 if (ret[x]=='.') ret[x]='_'; 393 } 394 strcat(ret,".dct"); 395 #else 396 strcpy(ret,orig); 397 strcat(ret,".dct"); 398 #endif 399 break; 400 case DACT_MODE_DECMP: 401 if (strcmp(&orig[strlen(orig)-4],".dct") && \ 402 strcmp(&orig[strlen(orig)-4], ".bz2") && \ 403 strcmp(&orig[strlen(orig)-5], ".tbz2") && \ 404 strcmp(&orig[strlen(orig)-4], ".tgz") && \ 405 strcmp(&orig[strlen(orig)-3], ".gz")) { 406 return(NULL); 407 } 408 /* XXX: I wonder if this breaks easily... */ 409 x=(strrchr(orig,'.')-orig); 410 ret=malloc(x+1); 411 strncpy(ret,orig,x); 412 ret[x]=0; 413 break; 414 case DACT_MODE_STAT: 415 return(NULL); 416 break; 417 } 418 return(ret); 419 } 420 421 uint32_t dact_process_other(int src, const int dest, const uint32_t magic, const char *options) { 422 char *buf, tmpbuf[128]="/tmp/dactXXXXXX"; 423 uint32_t filesize=0, x; 424 int tmpfd=0; 425 #if defined(HAVE_LIBBZ2) && (defined(HAVE_BZDOPEN) || defined(HAVE_NEW_BZDOPEN)) 426 BZFILE *bzfd; 427 #endif 428 #if defined(HAVE_LIBZ) && defined(HAVE_GZDOPEN) 429 gzFile gzfd; 430 #endif 431 432 filesize=0; /* Fix a warning, that is all. */ 433 434 /* 435 * bad and broke stuff XXX FIXME XXX FIXME XXX FIXME 436 * There has to be a better way to do this... I just want 437 * to rewind my socket/pipe 4 bytes... 4 bytes is all I ask 438 * Is that so much to ask for? Well?! Is it?! I don't 439 * think it is. 440 * I give up on this. 441 * 442 * Someone please fix it. 443 * -- Roy Keene <dact@rkeene.org> 444 */ 445 if (lseek_net(src, 0, SEEK_SET)<0) { 446 PRINTERR("This should not be happening."); 447 /* 448 * lseek_net() should make this obsolete. 449 * ... EXCEPT! when reading from stdin. 450 */ 451 tmpfd=mkstemp(tmpbuf); 452 write_de(tmpfd, magic, 4); 453 buf=malloc(1024); 454 while (1) { 455 x=read_f(src, buf, 1024); 456 write(tmpfd, buf, x); 457 if (x<1024) break; 458 } 459 close(src); 460 src=tmpfd; 461 lseek_net(src, 0, SEEK_SET); /* Now bitch. */ 462 free(buf); 463 } 464 #if defined(HAVE_LIBZ) && defined(HAVE_GZDOPEN) 465 466 467 if ((magic&0xffff0000)==0x1f8b0000) { /* gzip */ 468 dact_ui_status(DACT_UI_LVL_GEN, "Gunzipping..."); 469 buf=malloc(1024); 470 471 gzfd=gzdopen(src, "r"); 472 /*XXX: need to dact_ui_setup() */ 473 while (1) { 474 dact_ui_incrblkcnt(1); 475 x=gzread(gzfd,buf,1024); 476 filesize+=write(dest, buf, x); 477 if (x<1024) break; 478 } 479 free(buf); 480 if (tmpfd!=0) unlink(tmpbuf); 481 return(filesize); 482 } 483 #endif 484 485 #if defined(HAVE_LIBBZ2) && (defined(HAVE_BZDOPEN) || defined(HAVE_NEW_BZDOPEN)) 486 if ((magic&0xffffff00)==0x425a6800) { /* bzip2 */ 487 dact_ui_status(DACT_UI_LVL_GEN, "Bunzipping..."); 488 buf=malloc(1024); 489 490 #ifdef HAVE_NEW_BZDOPEN 491 bzfd=BZ2_bzdopen(src, "r"); 492 #else 493 bzfd=bzdopen(src, "r"); 494 #endif 495 /*XXX: need to dact_ui_setup() */ 496 while(1) { 497 dact_ui_incrblkcnt(1); 498 #ifdef HAVE_NEW_BZDOPEN 499 x=BZ2_bzread(bzfd, buf, 1024); 500 #else 501 x=bzread(bzfd, buf, 1024); 502 #endif 503 filesize+=write(dest, buf, x); 504 if (x<1024) break; 505 } 506 free(buf); 507 if (tmpfd!=0) unlink(tmpbuf); 508 return(filesize); 509 } 510 #endif 511 return(0); 512 } 513 514 int main(int argc, char **argv) { 515 unsigned char options[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 516 signed char opt; 517 struct stat stat_buf; 518 char **in_files, *in_file=NULL, *out_file=NULL; 519 char dact_binfilebuf[256], *dact_binfile; 520 int filecnt=0; 521 int in_fd, out_fd; 522 int mode=DACT_MODE_COMPR, ciphernum=-1; 523 uint32_t dact_blk_size=0; 524 uint32_t crcs[6]={0,0,0,0,0,0}; 525 uint32_t i,x; 526 527 528 dact_ui_init(); 529 530 531 /* hack, to make upgrade work even if DACT_OPT_BINCHK is enabled, we must 532 * get the new version before executing it. 533 */ 534 if (argv[1]!=NULL) { 535 if (!strcmp(argv[1],"-N")) return(dact_upgrade(options)); 536 if (!strcmp(argv[1],"-a")) options[DACT_OPT_UPGRADE]=1; 537 } 538 539 dact_config_loadfile(DACT_CONFIG_FILE, options, &dact_blk_size); 540 #ifndef NO_BINCHECK 541 dact_binfilebuf[0]='\0'; 542 if (getenv("HOME")) { 543 strncpy(dact_binfilebuf,getenv("HOME"),sizeof(dact_binfilebuf)-1); 544 } 545 strncat(dact_binfilebuf,"/.dact/dact.conf",sizeof(dact_binfilebuf)-strlen(dact_binfilebuf)-1); 546 dact_config_loadfile(dact_binfilebuf, options, &dact_blk_size); 547 #endif 548 549 if (options[DACT_OPT_BINCHK]) { 550 dact_binfile=parse_url_subst(DACT_BIN, ""); 551 if (strcmp(argv[0],dact_binfile)) { 552 if (!access(dact_binfile,X_OK)) { 553 argv[0]=dact_binfile; 554 /* This fixes a strange warning..*/ 555 #ifndef __MINGW32__ 556 execv(dact_binfile, argv); 557 #else 558 execv(dact_binfile, (const char **) argv); 559 #endif 560 } 561 } 562 } 563 564 while ((opt=getopt(argc,argv,"adfsvcnhiNVHCM:E:p:I:m:e:lb:u:U:TPOD:o:"))!=-1) { 565 switch (opt) { 566 case 'a': 567 options[DACT_OPT_UPGRADE]=1; 568 break; 569 case 'd': 570 mode=DACT_MODE_DECMP; 571 break; 572 case 'f': 573 options[DACT_OPT_FORCE]++; 574 break; 575 case 's': 576 mode=DACT_MODE_STAT; 577 break; 578 case 'i': 579 dact_ui_setopt(DACT_UI_OPT_PASSSTDIN, 1); 580 break; 581 case 'c': 582 options[DACT_OPT_STDOUT]=!options[DACT_OPT_STDOUT]; 583 break; 584 case 'b': 585 i=atoi2(optarg); 586 if (i<DACT_BLK_SIZE_MAX) dact_blk_size=i; 587 break; 588 case 'v': 589 options[DACT_OPT_VERB]++; 590 dact_ui_setopt(DACT_UI_OPT_LEVEL,dact_ui_getopt(DACT_UI_OPT_LEVEL)+1); 591 break; 592 case 'n': 593 options[DACT_OPT_NOCRC]=!options[DACT_OPT_NOCRC]; 594 break; 595 case 'p': 596 PRINT_LINE; fprintf(stderr, "dact: %s\n",parse_url_subst(optarg,"@@file@@")); 597 mode=DACT_MODE_RET; 598 break; 599 case 'C': 600 options[DACT_OPT_COMPLN]++; 601 break; 602 case 'm': 603 dact_config_loadfile(optarg, options, &dact_blk_size); 604 break; 605 case 'e': 606 i=(atoi(optarg)&0xff); 607 algorithms[i]=DACT_FAILED_ALGO; 608 break; 609 case 'H': 610 options[DACT_OPT_HDONLY]=!options[DACT_OPT_HDONLY]; 611 break; 612 case 'o': 613 out_file=parse_url_subst(optarg, ""); 614 break; 615 case 'M': 616 dact_config_execute(optarg, options, &dact_blk_size); 617 break; 618 case 'N': 619 PRINTERR("The `-N\' option must be the first and only argument passed to dact."); 620 return(0); 621 break; 622 case 'E': 623 strtolower(optarg); 624 x=hash_fourbyte(optarg, ' '); 625 if (x==hash_fourbyte("list", ' ')) { 626 PRINT_LINE; fprintf(stderr, "dact: Num | Name\n"); 627 for (i=0;i<CIPHER_COUNT;i++) { 628 if (ciphers_name[i]!=NULL && ciphers[i]!=DACT_FAILED_ALGO) { 629 PRINT_LINE; fprintf(stderr, "dact: %3i | %s\n",i,ciphers_name[i]); 630 } 631 } 632 return(0); 633 } 634 for (i=0;i<CIPHER_COUNT;i++) { 635 if (ciphers_name[i]!=NULL && ciphers[i]!=DACT_FAILED_ALGO) { 636 if (x==hash_fourbyte(ciphers_name[i], ' ')) { 637 break; 638 } 639 } 640 } 641 if (i==CIPHER_COUNT) i=-1; 642 ciphernum=i; 643 if (ciphernum==-1) { 644 PRINTERR("No such cipher."); 645 return(-1); 646 } 647 break; 648 case 'l': 649 PRINT_LINE; fprintf(stderr, "dact: Num | Name\n"); 650 for (i=0;i<255;i++) { 651 if (algorithms[i]==NULL || algorithms[i]==DACT_FAILED_ALGO) continue; 652 PRINT_LINE; fprintf(stderr, "dact: %3i | %s\n",i,algorithm_names[i]); 653 654 } 655 mode=DACT_MODE_RET; 656 break; 657 case 'I': 658 x=atoi(optarg); 659 for (i=1;i<255;i++) { 660 if (i!=x) algorithms[i]=NULL; 661 } 662 break; 663 case 'V': 664 printf("DACT %i.%i.%i-%s", DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION, DACT_VER_SUB); 665 #if defined(__DATE__) && defined(__TIME__) 666 printf(" built on %s at %s",__DATE__,__TIME__); 667 #endif 668 #ifdef DACT_CONTACT 669 printf(" %s",DACT_CONTACT); 670 #endif 671 printf("\n"); 672 return(0); 673 break; 674 case 'u': 675 dact_hdr_ext_regs(DACT_HDR_URL, optarg, strlen(optarg)); 676 break; 677 case 'U': 678 dact_hdr_ext_regs(DACT_HDR_URLFILE, optarg, strlen(optarg)); 679 break; 680 case 'D': 681 dact_hdr_ext_regs(DACT_HDR_DESC, optarg, strlen(optarg)); 682 break; 683 case 'T': 684 options[DACT_OPT_TIME]=!options[DACT_OPT_TIME]; 685 break; 686 case 'P': 687 options[DACT_OPT_PERM]=!options[DACT_OPT_PERM]; 688 break; 689 case 'O': 690 options[DACT_OPT_ORIG]=!options[DACT_OPT_ORIG]; 691 break; 692 case 'S': 693 options[DACT_OPT_SZSPD]=!options[DACT_OPT_SZSPD]; 694 break; 695 case '?': 696 case ':': 697 case 'h': 698 return(print_help(argc,argv)); 699 } 700 701 } 702 703 /* 704 * Check for a new version of DACT 705 */ 706 if ((i=dact_upgrade_file_checkver("dact", DACT_BIN_URL_VER, options))>DACT_BIN_VER) { 707 PRINTERR("**+"); 708 PRINTERR("**> There is a new version of DACT available."); 709 PRINTERR("**>"); 710 PRINT_LINE; fprintf(stderr, "dact: **> [CURR: DACT %i.%i.%i]\n",DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION); 711 PRINT_LINE; fprintf(stderr, "dact: **> [NEW: DACT %i.%i.%i]\n",i>>16,(i>>8)&0xff,i&0xff); 712 PRINTERR("**>"); 713 PRINTERR("**> Run `dact -N' to get it."); 714 PRINTERR("**> or get the source at: http://www.rkeene.org/devel/dact.tar.gz"); 715 PRINTERR("**>"); 716 PRINTERR("**-"); 717 } 718 719 if (mode==DACT_MODE_RET) return(0); 720 721 in_files=&argv[optind]; 722 723 /* Loop through extra parameters (files ...) and setup FDs for them */ 724 do { 725 in_fd=-1; 726 out_fd=-1; 727 728 in_file=in_files[filecnt]; 729 if (in_file!=NULL) { 730 /* Determine resulting file name */ 731 if (out_file==NULL) out_file=dact_getoutfilename(in_file,mode); 732 if (strcmp("-",in_file)==0) { 733 in_fd=STDIN_FILENO; 734 } else { 735 if (stat(in_file, &stat_buf)>=0) { 736 if (S_ISDIR(stat_buf.st_mode)) { 737 fprintf(stderr, "dact: %s is a directory.\n",in_file); 738 continue; 739 } 740 } 741 if ((in_fd=open_net(in_file, O_RDONLY, 0))<0) { 742 fprintf(stderr, "dact: Can't open %s.\n",in_file); 743 PERROR_L(in_fd, "open"); 744 continue; 745 } 746 } 747 if (out_file!=NULL) { 748 if (!strcmp("-",out_file)) options[DACT_OPT_STDOUT]=1; 749 /* 750 * 751 * This is a bad thing if this program is SUID root, which it NEVER EVER 752 * should be. 753 * 754 * DO NOT MAKE DACT SUID ROOT OR YOU WILL BE HACKED 755 * 756 * that should be a suffcient warning. 757 * (this is a mere race condition, but a severe warning should prevent 758 * people from complaining about it to me.) 759 * 760 */ 761 if (access(out_file,F_OK)!=-1 && options[DACT_OPT_FORCE]==0 && options[DACT_OPT_STDOUT]==0) { 762 fprintf(stderr, "dact: %s exists.\n",out_file); 763 close(in_fd); 764 continue; 765 } 766 if (!options[DACT_OPT_STDOUT]) { 767 if ((out_fd=open_net(out_file,O_WRONLY|O_CREAT|O_TRUNC,0644))<0) { 768 fprintf(stderr, "dact: Can't open %s for writing.\n",out_file); 769 PERROR_L(out_fd, "open"); 770 continue; 771 } 772 } 773 } 774 if (options[DACT_OPT_STDOUT]) out_fd=STDOUT_FILENO; 775 } 776 777 /* Use STDIN/STDOUT if no files specified ... unless an outfile was specified... */ 778 if (in_file==NULL && filecnt==0) { 779 /* ... But only if STDOUT isn't a terminal */ 780 if (isatty(STDOUT_FILENO) && options[DACT_OPT_FORCE]==0) { 781 fprintf(stderr, "dact: Refusing to write compressed output to a terminal.\n"); 782 } else { 783 out_fd=STDOUT_FILENO; 784 in_fd=STDIN_FILENO; 785 } 786 } 787 788 /* Okay, we're all done, now pass these to something to do the real stuff */ 789 if (in_fd!=-1 && (out_fd!=-1 || mode==DACT_MODE_STAT)) { 790 crcs[1]=crcs[0]=0; 791 if (dact_process_file(in_fd, out_fd, mode, options, in_file, crcs, dact_blk_size, ciphernum)==0) { 792 close(in_fd); 793 close(out_fd); 794 if (out_fd!=STDOUT_FILENO) { 795 unlink(out_file); 796 } 797 return(dact_shutdown(-1)); 798 } 799 } 800 /* Cleanup */ 801 if (out_fd!=-1) close(out_fd); 802 if (in_fd!=-1) close(in_fd); 803 } while (in_files[filecnt++]!=NULL); 804 805 return(dact_shutdown(0)); 806 } |