home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / RESCUE / TCX-LINU.TAR / tcx / tcx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-26  |  7.9 KB  |  334 lines

  1. /* tcx.c, Version 1.0.2, 25/3/1993 by Stewart Forster */
  2.  
  3. /************************************************************************/
  4. /*   Copyright (C) 1993 Stewart Forster                    */
  5. /*  This program is free software; you can redistribute it and/or modify*/
  6. /*  it under the terms of the GNU General Public License as published by*/
  7. /*  the Free Software Foundation; either version 2, or (at your option) */
  8. /*  any later version.                            */
  9. /*                                    */
  10. /*  This program is distributed in the hope that it will be useful,    */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  13. /*  GNU General Public License for more details.            */
  14. /*                                    */
  15. /*  You should have received a copy of the GNU General Public License    */
  16. /*  along with this program; if not, write to the Free Software        */
  17. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  18. /************************************************************************/
  19.  
  20.  
  21. #include    "config.h"
  22.  
  23. extern    int    errno;
  24.  
  25. int    main(int, char *[]);
  26. int    is_tcx(int);
  27. int    doencode(int, int);
  28.  
  29. #ifdef ULTRIX
  30. int    is_file_local(char *);
  31. #endif
  32.  
  33. int
  34. main(int argc, char *argv[])
  35. {
  36. struct    stat    dostat;
  37. char    *s;
  38. int    perms;
  39. int    infd, outfd;
  40. char    tofile[MAXPATHLEN];
  41. char    header[MAXHEADERSIZE];
  42. struct    flock    lck;
  43. unsigned char c;
  44. #ifdef ULTRIX
  45. int    islocal;
  46. #endif
  47.  
  48.     /* Check to make sure we have an argument */
  49.  
  50.     if(argc < 2)
  51.     {
  52.         (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  53.         exit(-1);
  54.     }
  55.  
  56.     /* Try to lstat first argument. If cannot, quit */
  57.  
  58.     if(lstat(argv[1], &dostat) < 0)
  59.     {
  60.         perror(argv[1]);
  61.         exit(-1);
  62.     }
  63.  
  64.     /* Make sure it's a regular file. If not, quit! */
  65.  
  66.     if(!(dostat.st_mode & S_IFREG)||((dostat.st_mode & S_IFMT) == S_IFLNK))
  67.     {
  68.         (void)fprintf(stderr, "Error: %s is not a regular file\n", argv[1]);
  69.         exit(-1);
  70.     }
  71.  
  72.     /* Check permissions on file, must not be setuid or setgid */
  73.     /* Then check to see if it's an executable */
  74.  
  75.     if(dostat.st_mode & (S_ISUID | S_ISGID))
  76.     {
  77.         (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
  78.         exit(-1);
  79.     }
  80.  
  81.     if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  82.     {
  83.         (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
  84.         exit(-1);
  85.     }
  86.  
  87. #ifdef ULTRIX
  88.     /* Test to see if file we are compressing is local or not */
  89.  
  90.     if((islocal = is_file_local(argv[1])) < 0)
  91.     {
  92.         perror("statfs");
  93.         exit(-1);
  94.     }
  95. #endif
  96.  
  97.     /* Now open file we are compressing for reading. Quit if can't. */
  98.  
  99.     if((infd = open(argv[1], O_RDONLY)) < 0)
  100.     {
  101.         perror(argv[1]);
  102.         exit(-1);
  103.     }
  104.  
  105.     /* Check to make sure file is not already tcx'ed */
  106.  
  107.     if(is_tcx(infd))
  108.     {
  109.         (void)fprintf(stderr, "%s is already in tcx format!\n", argv[1]);
  110.         exit(0);
  111.     }
  112.  
  113.     if(lseek(infd, 0, SEEK_SET) < 0)
  114.     {
  115.         perror("lseek");
  116.         exit(-1);
  117.     }
  118.  
  119.     /* Open generation file, and try to mimic permissions */
  120.     /* If cannot, warn user and quit */
  121.  
  122.     if(strrchr(argv[1], '/') == NULL)
  123.         (void)sprintf(tofile, ".tcx.%s", argv[1]);
  124.     else
  125.     {
  126.         (void)strcpy(tofile, argv[1]);
  127.         s = strrchr(tofile, '/');
  128.         *s = '\0';
  129.         (void)strcat(tofile, "/.tcx.");
  130.         s = strrchr(argv[1], '/');
  131.         s++;
  132.         (void)strcat(tofile, s);
  133.     }
  134.  
  135.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  136.  
  137.     perms = (dostat.st_mode & 0777);
  138.     if(perms & S_IXUSR) perms |= S_IRUSR;
  139.     if(perms & S_IXGRP) perms |= S_IRGRP;
  140.     if(perms & S_IXOTH) perms |= S_IROTH;
  141.     perms |= S_IWUSR;
  142.  
  143.     /* Attempt to create scratch file */
  144.     /* Ultrix barfs on F_SETLK if file is on an NFS mount. */
  145.  
  146.     if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  147.     {
  148. #ifdef ULTRIX
  149.         if(islocal == 0 || errno != EEXIST)
  150. #else
  151.         if(errno != EEXIST)
  152. #endif
  153.         {
  154.             perror(tofile);
  155.             exit(-1);
  156.         }
  157.  
  158.         /* Attempt to open and lock file that's there.  If we can't */
  159.         /* lock the file, someone else must be packing it, so quit. */
  160.         /* If we can, it must be bogus and left lying around after a*/
  161.         /* crash, interrupt or something. Delete file and try again.*/
  162.  
  163.         if((outfd = open(tofile, O_WRONLY)) < 0)
  164.         {
  165.             perror(tofile);
  166.             exit(-1);
  167.         }
  168.  
  169.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  170.             exit(-1);
  171.  
  172.         (void)unlink(tofile);    /* Unlink. Don't care if fails yet */
  173.         (void)close(outfd);
  174.         if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  175.         {
  176.             perror(tofile);
  177.             exit(-1);
  178.         }
  179.     }
  180.  
  181.     /* Attempt to lock tofile.  If can't then assume someone else */
  182.     /* is in the process of packing this file, so quit. */
  183.     /* Only try to lock on ULTRIX if file is local.  If not, risk */
  184.     /* the race condition, we have no choice!. */
  185.  
  186. #ifdef ULTRIX
  187.     if(islocal == 1)
  188. #endif
  189.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  190.             exit(-1);
  191.  
  192.     /* Do a chmod (Just to be sure - in case of user umask affecting open) */
  193.  
  194.     if(chmod(tofile, perms) < 0)
  195.     {
  196.         (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
  197.         (void)close(infd);
  198.         (void)close(outfd);
  199.         if(unlink(tofile) < 0)
  200.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  201.         exit(-1);
  202.     }
  203.  
  204.     if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
  205.     {
  206.         (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
  207.         (void)close(infd);
  208.         (void)close(outfd);
  209.         if(unlink(tofile) < 0)
  210.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  211.         exit(-1);
  212.     }
  213.  
  214.     /* Spit out header and start encoding executable */
  215.  
  216.     (void)sprintf(header, "#!%s\n", PATHUNTCX);
  217.     if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
  218.  
  219.     c = 0;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  220.     c = 76;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  221.     c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  222.     c = 13;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  223.     c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  224.  
  225.     if(doencode(infd, outfd) != 0)
  226.     {
  227.         (void)fprintf(stderr, "Compression failed\n");
  228.         if(unlink(tofile) < 0)
  229.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  230.         exit(-1);
  231.     }
  232.  
  233.     (void)close(infd);
  234.  
  235.     if((infd = open(argv[1], O_WRONLY)) <= 0)
  236.     {
  237.         perror(argv[1]);
  238.         if(unlink(tofile) < 0)
  239.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  240.         exit(-1);
  241.     }
  242.  
  243. #ifdef ULTRIX
  244.     if(islocal == 1)
  245. #endif
  246.         if(fcntl(infd, F_SETLK, &lck) < 0)
  247.         {
  248.             if(unlink(tofile) < 0)
  249.                 (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  250.             exit(-1);
  251.         }
  252.  
  253.     /* Rename() compressed version to original */
  254.  
  255.     if(rename(tofile, argv[1]) < 0)
  256.     {
  257.         perror(argv[1]);
  258.         if(unlink(tofile) < 0)
  259.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  260.         exit(-1);
  261.     }
  262.  
  263.     /* Close files and hence locks */
  264.  
  265.     (void)close(infd);
  266.     (void)close(outfd);
  267.  
  268.     /* All done! Bye, bye. */
  269.  
  270.     return(0);
  271. }
  272.  
  273.  
  274. int
  275. is_tcx(int fd)
  276. {
  277. int     i;
  278. unsigned char   c;
  279.  
  280.         for(i = 0; i < MAXHEADERSIZE; i++)
  281.                 if(read(fd, &c, 1) < 1 || c == 0)
  282.                         break;
  283.         if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  284.             || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  285.                 return 0;
  286.         return 1;
  287. } /* is_tcx */
  288.  
  289.  
  290. int
  291. doencode(int infd, int outfd)
  292. {
  293. int    pid;
  294. union    wait    status;
  295.  
  296.     pid = fork();
  297.     if(pid < 0) return -1;
  298.     if(pid == 0)
  299.     {
  300.         if(dup2(infd, 0) < 0)    exit(-1);    /* Attach infd to stdin */
  301.         (void)close(infd);
  302.         if(dup2(outfd, 1) < 0)    exit(-1);    /* Attach outfd to stdout */
  303.         (void)close(outfd);
  304. #ifdef PACKEROPTS
  305.         (void)execl(PATHPACKER, "packer", PACKEROPTS, (char *)0);
  306. #else
  307.         (void)execl(PATHPACKER, "packer", (char *)0);
  308. #endif
  309.         exit(-1);
  310.     }
  311.     else
  312.         pid = wait(&status);
  313.     return WEXITSTATUS(status);
  314. } /* doencode */
  315.  
  316.  
  317. #ifdef ULTRIX
  318. int
  319. is_file_local(char *path)
  320. {
  321. struct  fs_data fsbuf;
  322.  
  323.         if(statfs(path, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  324.                 return -1;
  325.  
  326.         /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  327.         /* to a client, so return false on this condition. */
  328.  
  329.         if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  330.                 return 0;
  331.     return 1;
  332. } /* is_file_local */
  333. #endif
  334.