home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / tcx-1.1 / part01 / tcx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-04  |  9.4 KB  |  401 lines

  1. /* tcx.c, Version 1.0.4, 1/4/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. #include    "config.h"
  21.  
  22. extern    int    errno;
  23.  
  24. int    main(int, char *[]);
  25. int    is_tcx(int);
  26. int    doencode(int, int);
  27.  
  28. #ifdef ULTRIX
  29. int    is_file_local(char *);
  30. #endif
  31.  
  32. char    execname[MAXPATHLEN];
  33. char    execpath[MAXPATHLEN];
  34. char    dofile[MAXPATHLEN];
  35. char    tofile[MAXPATHLEN];
  36. char    header[MAXHEADERSIZE];
  37.  
  38. int
  39. main(int argc, char *argv[])
  40. {
  41. struct    stat    dostat;
  42. char    *s;
  43. int    perms;
  44. int    infd, outfd;
  45. int    len;
  46. struct    flock    lck;
  47. unsigned char c;
  48. #ifdef ULTRIX
  49. int    islocal;
  50. #endif
  51.  
  52.     /* Check to make sure we have an argument */
  53.  
  54.     if(argc < 2)
  55.     {
  56.         (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  57.         exit(-1);
  58.     }
  59.  
  60.     if(getwd(dofile) == NULL)
  61.     {
  62.         (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
  63.         exit(-1);
  64.     }
  65.  
  66.     if(*argv[1] == '/')
  67.         (void)strcpy(dofile, argv[1]);
  68.     else
  69.     {
  70.         (void)strcat(dofile, "/");
  71.         (void)strcat(dofile, argv[1]);
  72.     }
  73.     for(;;)
  74.     {
  75.         if((s = strrchr(dofile, '/')) == NULL)
  76.         {
  77.             (void)fprintf(stderr, "Internal corruption of variables!\n");
  78.             exit(-1);
  79.         }
  80.         s++;
  81.         (void)strcpy(execname, s);
  82.         *s = '\0';
  83.  
  84.         if(chdir(dofile) < 0) { perror(dofile); exit(-1); }
  85.  
  86.         if(getwd(dofile) == NULL)
  87.         {
  88.             (void)fprintf(stderr, "Get Working Directory Error: %s\n", dofile);
  89.             exit(-1);
  90.         }
  91.  
  92.         if(lstat(execname, &dostat) < 0) { perror(execname); exit(-1); }
  93.  
  94.         if((dostat.st_mode & S_IFMT) == S_IFLNK)
  95.         {
  96.             if((len = readlink(execname, execpath, MAXPATHLEN)) < 0)
  97.             {
  98.                 perror(execname);    
  99.                 exit(-1);
  100.             }
  101.             execpath[len] = '\0';
  102.             if(execpath[0] == '/')
  103.                 (void)strcpy(dofile, execpath);
  104.             else
  105.             {
  106.                 (void)strcat(dofile, "/");
  107.                 (void)strcat(dofile, execpath);
  108.             }
  109.             continue;
  110.         }
  111.  
  112.         /* If we get here, dofile is no longer pointing at a symlink */
  113.  
  114.         (void)strcat(dofile, "/");
  115.         (void)strcat(dofile, execname);
  116.         break;
  117.     }
  118.  
  119.     /* dofile from now on is the FULL pathname to the executable we're tcx-ing */
  120.  
  121.     /* Just do a normal stat on dofile */
  122.  
  123.     if(stat(dofile, &dostat) < 0) { perror(dofile); exit(-1); }
  124.  
  125.     /* Make sure it's a regular file. If not, quit! */
  126.  
  127.     if(!(dostat.st_mode & S_IFREG))
  128.     {
  129.         (void)fprintf(stderr, "Error: %s is not a regular file\n", dofile);
  130.         exit(-1);
  131.     }
  132.  
  133.     /* Check permissions on file, must not be setuid or setgid */
  134.     /* Then check to see if it's an executable */
  135.  
  136.     if(dostat.st_mode & (S_ISUID | S_ISGID))
  137.     {
  138.         (void)fprintf(stderr, "Error: Cannot compress setuid or setgid programs.\n");
  139.         exit(-1);
  140.     }
  141.  
  142.     if(! (dostat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  143.     {
  144.         (void)fprintf(stderr, "File does have any execute bits set. Aborting.\n");
  145.         exit(-1);
  146.     }
  147.  
  148.     if(dostat.st_nlink > 1)
  149.     {
  150.         (void)fprintf(stderr, "File has multiple hard links to it!  These will be destroyed\n");
  151.         (void)fprintf(stderr, "by this operation.  Please turn the hard links into symlinks.\n");
  152.         exit(-1);
  153.     }
  154.  
  155. #ifdef ULTRIX
  156.     /* Test to see if file we are compressing is local or not */
  157.  
  158.     if((islocal = is_file_local(dofile)) < 0)
  159.     {
  160.         perror("statfs");
  161.         exit(-1);
  162.     }
  163. #endif
  164.  
  165.     /* Now open file we are compressing for reading. Quit if can't. */
  166.  
  167.     if((infd = open(dofile, O_RDONLY)) < 0)
  168.     {
  169.         perror(dofile);
  170.         exit(-1);
  171.     }
  172.  
  173.     /* Check to make sure file is not already tcx'ed */
  174.  
  175.     if(is_tcx(infd))
  176.     {
  177.         (void)fprintf(stderr, "%s is already in tcx format!\n", dofile);
  178.         exit(0);
  179.     }
  180.  
  181.     if(lseek(infd, 0, SEEK_SET) < 0)
  182.     {
  183.         perror("lseek");
  184.         exit(-1);
  185.     }
  186.  
  187.     /* Open generation file, and try to mimic permissions */
  188.     /* If cannot, warn user and quit */
  189.  
  190.     (void)strcpy(tofile, dofile);
  191.     s = strrchr(tofile, '/');
  192.     *s = '\0';
  193.     (void)strcat(tofile, "/.tcx.");
  194.     s = strrchr(dofile, '/');
  195.     s++;
  196.     (void)strcat(tofile, s);
  197.  
  198.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  199.  
  200.     perms = (dostat.st_mode & 0777);
  201.     if(perms & S_IXUSR) perms |= S_IRUSR;
  202.     if(perms & S_IXGRP) perms |= S_IRGRP;
  203.     if(perms & S_IXOTH) perms |= S_IROTH;
  204.     perms |= S_IWUSR;
  205.  
  206.     /* Attempt to create scratch file */
  207.     /* Ultrix barfs on F_SETLK if file is on an NFS mount. */
  208.  
  209.     if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  210.     {
  211. #ifdef ULTRIX
  212.         if(islocal == 0 || errno != EEXIST)
  213. #else
  214.         if(errno != EEXIST)
  215. #endif
  216.         {
  217.             perror(tofile);
  218.             exit(-1);
  219.         }
  220.  
  221.         /* Attempt to open and lock file that's there.  If we can't */
  222.         /* lock the file, someone else must be packing it, so quit. */
  223.         /* If we can, it must be bogus and left lying around after a*/
  224.         /* crash, interrupt or something. Delete file and try again.*/
  225.  
  226.         if((outfd = open(tofile, O_WRONLY)) < 0)
  227.         {
  228.             perror(tofile);
  229.             exit(-1);
  230.         }
  231.  
  232.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  233.             exit(-1);
  234.  
  235.         (void)unlink(tofile);    /* Unlink. Don't care if fails yet */
  236.         (void)close(outfd);
  237.         if((outfd = open(tofile, O_EXCL | O_CREAT | O_WRONLY, perms)) < 0)
  238.         {
  239.             perror(tofile);
  240.             exit(-1);
  241.         }
  242.     }
  243.  
  244.     /* Attempt to lock tofile.  If can't then assume someone else */
  245.     /* is in the process of packing this file, so quit. */
  246.     /* Only try to lock on ULTRIX if file is local.  If not, risk */
  247.     /* the race condition, we have no choice!. */
  248.  
  249. #ifdef ULTRIX
  250.     if(islocal == 1)
  251. #endif
  252.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  253.             exit(-1);
  254.  
  255.     /* Do a chmod (Just to be sure - in case of user umask affecting open) */
  256.  
  257.     if(chmod(tofile, perms) < 0)
  258.     {
  259.         (void)fprintf(stderr, "Cannot set proper permissions on scratch file %s\n", tofile);
  260.         (void)close(infd);
  261.         (void)close(outfd);
  262.         if(unlink(tofile) < 0)
  263.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  264.         exit(-1);
  265.     }
  266.  
  267.     if(chown(tofile, dostat.st_uid, dostat.st_gid) < 0)
  268.     {
  269.         (void)fprintf(stderr, "Cannot set proper ownership on scratch file\n");
  270.         (void)close(infd);
  271.         (void)close(outfd);
  272.         if(unlink(tofile) < 0)
  273.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  274.         exit(-1);
  275.     }
  276.  
  277.     /* Spit out header and start encoding executable */
  278.  
  279.     (void)sprintf(header, "#!%s\n", PATHUNTCX);
  280.     if(write(outfd, header, strlen(header)) < 0) { (void)perror("write"); exit(-1); }
  281.  
  282.     c = 0;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  283.     c = 76;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  284.     c = 193; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  285.     c = 13;    if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  286.     c = 138; if((write(outfd, &c, 1)) < 0) { (void)perror("write"); exit(-1); }
  287.  
  288.     if(doencode(infd, outfd) != 0)
  289.     {
  290.         (void)fprintf(stderr, "Compression failed\n");
  291.         if(unlink(tofile) < 0)
  292.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  293.         exit(-1);
  294.     }
  295.  
  296.     (void)close(infd);
  297.  
  298.     if((infd = open(dofile, O_WRONLY)) <= 0)
  299.     {
  300.         perror(dofile);
  301.         if(unlink(tofile) < 0)
  302.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  303.         exit(-1);
  304.     }
  305.  
  306. #ifdef ULTRIX
  307.     if(islocal == 1)
  308. #endif
  309.         if(fcntl(infd, F_SETLK, &lck) < 0)
  310.         {
  311.             if(unlink(tofile) < 0)
  312.                 (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  313.             exit(-1);
  314.         }
  315.  
  316.     /* Rename() compressed version to original */
  317.  
  318.     if(rename(tofile, dofile) < 0)
  319.     {
  320.         perror(dofile);
  321.         if(unlink(tofile) < 0)
  322.             (void)fprintf(stderr, "Warning: Unable to delete scratch file\n");
  323.         exit(-1);
  324.     }
  325.  
  326.     /* Close files and hence locks */
  327.  
  328.     (void)close(infd);
  329.     (void)close(outfd);
  330.  
  331.     /* All done! Bye, bye. */
  332.  
  333.     return(0);
  334. }
  335.  
  336.  
  337. int
  338. is_tcx(int fd)
  339. {
  340. int     i;
  341. unsigned char   c;
  342.  
  343.         for(i = 0; i < MAXHEADERSIZE; i++)
  344.                 if(read(fd, &c, 1) < 1 || c == 0)
  345.                         break;
  346.         if((i >= MAXHEADERSIZE) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  347.             || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  348.                 return 0;
  349.         return 1;
  350. } /* is_tcx */
  351.  
  352.  
  353. int
  354. doencode(int infd, int outfd)
  355. {
  356. int    pid;
  357. #if defined(AIX) || defined(IRIX)
  358. int    status;
  359. #else
  360. union wait status;
  361. #endif
  362.  
  363.     pid = fork();
  364.     if(pid < 0) return -1;
  365.     if(pid == 0)
  366.     {
  367.         if(dup2(infd, 0) < 0)    exit(-1);    /* Attach infd to stdin */
  368.         (void)close(infd);
  369.         if(dup2(outfd, 1) < 0)    exit(-1);    /* Attach outfd to stdout */
  370.         (void)close(outfd);
  371. #ifdef PACKEROPTS
  372.         (void)execl(PATHPACKER, PATHPACKER, PACKEROPTS, (char *)0);
  373. #else
  374.         (void)execl(PATHPACKER, PATHPACKER, (char *)0);
  375. #endif
  376.         exit(-1);
  377.     }
  378.     else
  379.         pid = wait(&status);
  380.     return WEXITSTATUS(status);
  381. } /* doencode */
  382.  
  383.  
  384. #ifdef ULTRIX
  385. int
  386. is_file_local(char *path)
  387. {
  388. struct  fs_data fsbuf;
  389.  
  390.         if(statfs(path, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  391.                 return -1;
  392.  
  393.         /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  394.         /* to a client, so return false on this condition. */
  395.  
  396.         if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  397.                 return 0;
  398.     return 1;
  399. } /* is_file_local */
  400. #endif
  401.