home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / Apps / DevTools / SmartPackage / Sources / SmartInstaller / SmartInstaller.m < prev   
Encoding:
Text File  |  1994-04-18  |  9.7 KB  |  410 lines

  1.  
  2. /*
  3.  * SmartInstaller.m: the heart of the Smart Installer application.
  4.  *
  5.  * Copyright (C) 1994, Yves Arrouye <Yves.Arrouye@imag.fr>
  6.  *
  7.  */
  8.  
  9. /*
  10.  * The Smart Installer application and the Smart Package utility suite may be
  11.  * copied and distributed freely, as long as an acknowledgement of the author's
  12.  * work, with its name and address, is kept. The code may not be distributed if
  13.  * it has been modified. Modified code propositions should be directed to the
  14.  * author who will made them if necessary and redistribute the packages.
  15.  *
  16.  */
  17.  
  18. #import <ctype.h>
  19. #import <stdio.h>
  20. #import <string.h>
  21.  
  22. #import <sys/file.h>
  23. #import <sys/param.h>
  24.  
  25. #import "SmartInstaller.h"
  26.  
  27. /*
  28.  * The DiskName string in the info file
  29.  *
  30.  */
  31.  
  32. #define DISK_NAME    "SmartDiskName"
  33. #define DISK_NAME_LEN    13
  34.  
  35. /*
  36.  * Exit codes
  37.  *
  38.  */
  39.  
  40. enum exit_codes {
  41.     EXIT_OK,            // No error
  42.     
  43.     EXIT_NO_INFO,        // No info file
  44.     EXIT_NO_DISK_NAME,        // No disk name in info file
  45.     EXIT_NO_MEDIA_LIST,        // Cannot get removeable media list
  46.     EXIT_NO_SUCH_DISK,        // Cancel when asking for a disk
  47.     EXIT_NO_EJECT,        // Cannot eject the disk
  48.     
  49.     EXIT_UNKNOWN        // Default exit code
  50. };
  51.  
  52. @implementation SmartInstaller
  53.  
  54. + (BOOL)isLocationRoot
  55. {
  56.     return NO;
  57. }
  58.  
  59. - setOnRoot:(BOOL)flag
  60. {
  61.     if (flag || (!flag && ![[self class] isLocationRoot])) {
  62.         isOnRoot = flag;
  63.     }
  64.     
  65.     return self;
  66. }
  67.  
  68. - (BOOL)isOnRoot
  69. {
  70.     return isOnRoot;
  71. }
  72.  
  73. - init
  74. {
  75.     [super init];
  76.     
  77.     isOnRoot = [[self class] isLocationRoot];
  78.     
  79.     return self;
  80. }
  81.  
  82. - initPackage:(const char*)from andDestination:(const char*)to
  83. {
  84.     return [[self init] setPackage:from andDestination:to];
  85. }
  86.  
  87. - setPackage:(const char*)from andDestination:(const char*)to
  88. {
  89.     char* cptr;            // Useful char pointer
  90.     const char* ccptr;        // Useful const char pointer
  91.     
  92.     // Remember these ones
  93.     
  94.     fromDir = from;
  95.     destDir = to;
  96.     
  97.     [self setOnRoot:!*destDir];
  98.     
  99.     // Now get the basename (we assume that the extension is .pkg)
  100.     
  101.     if (ccptr = strrchr(fromDir, '/')) {
  102.         ++ccptr;
  103.     } else {
  104.         ccptr = fromDir;
  105.     }
  106.     
  107.     cptr = rootName;
  108.     while (*ccptr && strcmp(ccptr, ".pkg")) {
  109.         *cptr++ = *ccptr++;
  110.     }
  111.     *cptr = '\0';
  112.  
  113.     return self;
  114. }
  115. - (int)obtainDisk:(char*)wantedDiskName number:(int)diskVolume
  116.       from:(const char*)diskName
  117. {
  118.     BOOL ret;
  119.     
  120.     sprintf(wantedDiskName, diskName, diskVolume);
  121.  
  122.     for (;;) {
  123.     char* medias;
  124.     
  125.     if ([[Application workspace]
  126.         getMountedRemovableMedia:&medias]) {
  127.         char* aMedia = strtok(medias, "\t");
  128.         char* dMedia = NULL;
  129.         int diskNumber = 0;
  130.         
  131.         while (aMedia &&
  132.         sscanf(aMedia, diskName, &diskNumber) > 0 &&
  133.         diskNumber != diskVolume) {
  134.         if (diskNumber && !dMedia) {
  135.             dMedia = aMedia;
  136.         }
  137.         aMedia = strtok(NULL, "\t");
  138.         }
  139.         
  140.         if (diskNumber == diskVolume) {
  141.         break;
  142.         } else {
  143.         active = [NXApp activeApp]; [NXApp activateSelf:YES];
  144.         
  145.             if (diskNumber == 0) {
  146.             ret = (NXRunLocalizedAlertPanel("Localizable",
  147.             "Disk Request",
  148.             "Please insert disk %s and click Continue (or click Cancel if the disk is unavailable).",
  149.             "Continue", "Cancel", NULL,
  150.             wantedDiskName + 1) != NX_ALERTDEFAULT);
  151.             
  152.             [NXApp activate:active];
  153.             
  154.             if (ret) {
  155.             return EXIT_NO_SUCH_DISK;
  156.             }
  157.         } else {
  158.             for (;;) {
  159.             if ([[Application workspace]
  160.                 unmountAndEjectDeviceAt:dMedia]) {
  161.                 break;
  162.             } else {
  163.                 active = [NXApp activeApp]; [NXApp activateSelf:YES];
  164.                 
  165.                 ret = (NXRunLocalizedAlertPanel("Localizable",
  166.                 "Disk Problem",
  167.                 "Cannot eject disk %s. Click Retry to have another try (or click Cancel to end the installation).",
  168.                 "Retry", "Cancel", NULL, dMedia + 1) !=
  169.                 NX_ALERTDEFAULT);
  170.                 
  171.                 [NXApp activate:active];
  172.                 
  173.                 if (ret) {
  174.                 return EXIT_NO_EJECT;
  175.                 }
  176.             }
  177.             }
  178.             
  179.             active = [NXApp activeApp]; [NXApp activateSelf:YES];
  180.             
  181.             ret = (NXRunLocalizedAlertPanel("Localizable",
  182.             "Disk Request",
  183.             "You have inserted disk %s. Please insert disk %s and click Continue (or click Cancel if the disk is unavailable).",
  184.             "Continue", "Cancel", NULL, dMedia + 1,
  185.             wantedDiskName + 1) != NX_ALERTDEFAULT);
  186.             
  187.             [NXApp activate:active];
  188.             
  189.             if (ret) {
  190.             return EXIT_NO_SUCH_DISK;
  191.             }
  192.         }
  193.         }
  194.     } else {
  195.         active = [NXApp activeApp]; [NXApp activateSelf:YES];
  196.         
  197.         NXRunLocalizedAlertPanel("Localizable",
  198.         "Disk Problem",
  199.         "Unable to find the name of the disks currently mounted. Please retry later...",
  200.         "Quit", NULL, NULL);
  201.         
  202.         [NXApp activate:active];
  203.         
  204.         return EXIT_NO_MEDIA_LIST;
  205.     }
  206.     
  207.     [[Application workspace] mountNewRemovableMedia:&medias];
  208.     }
  209.  
  210.     return EXIT_OK;
  211. }
  212.  
  213. - (int)installMultipleGzipped:(const char*)compName
  214. {
  215.     char infoName[MAXPATHLEN + 1];
  216.     FILE* info;                // Info file handle
  217.     
  218.     int exitCode = EXIT_OK;
  219.     
  220.     if (![NXBundle getPath:infoName forResource:rootName
  221.         ofType:(isOnRoot ? "info.smart" : "info")
  222.         inDirectory:fromDir withVersion:0] || !(info = fopen(infoName, "r"))) {
  223.         NXRunLocalizedAlertPanel("Localizable", "Package Problem",
  224.         "Cannot open package %s (There was an error reading the info file.)",
  225.         "Quit", NULL, NULL, fromDir);
  226.     exitCode = EXIT_NO_INFO;
  227.     } else {
  228.         char diskName[MAXPATHLEN + 1];
  229.  
  230.         char infoLine[512];
  231.     char* line;
  232.     
  233.     // Look for the line with the disk name.
  234.     
  235.     while (line = fgets(infoLine, sizeof(infoLine) / sizeof(char), info)) {
  236.         if (!strncmp(infoLine, DISK_NAME, DISK_NAME_LEN)) {
  237.             break;
  238.         }
  239.     }
  240.     
  241.     fclose(info);
  242.     
  243.     // Get this name.
  244.     
  245.     if (line != NULL) {
  246.         for (line += DISK_NAME_LEN; isspace(*line); ++line) {
  247.             ;
  248.         }
  249.         
  250.         if (*line) {
  251.             char* cptr = diskName;
  252.         
  253.         *cptr++ = '/';    // Assume the disk will be mounted there
  254.         
  255.         do {
  256.             *cptr++ = *line++;
  257.         } while (*line && *line != '\n');
  258.         
  259.         if (*line == '\n') {
  260.             *cptr = '\0';
  261.         }
  262.         } else {
  263.             line = NULL;
  264.         }
  265.     }
  266.     
  267.     if (line == NULL) {
  268.         NXRunLocalizedAlertPanel("Localizable", "Package Problem",
  269.         "Cannot open package %s (There was an error reading the info file.)",
  270.         "Quit", NULL, NULL, fromDir);
  271.         exitCode = EXIT_NO_DISK_NAME;
  272.     } else {
  273.         char wantedDiskName[MAXPATHLEN + 1];    // The current disk
  274.         char compTmpName[MAXPATHLEN + 1];    // Building there (without ext)
  275.         
  276.         BOOL again = YES;        // Do we have another volume?
  277.         
  278.         int origDiskVolume = 0;    // Our current disk volume
  279.         int diskVolume = 1;        // First volume to ask for
  280.         
  281.         char cmdLine[1024];
  282.         
  283.         sprintf(cmdLine, "%s/%s.pkg", diskName, rootName);
  284.         sscanf(fromDir, cmdLine, &origDiskVolume);
  285.  
  286.         sprintf(compTmpName, "/tmp/%s.tar", rootName);
  287.         
  288.         sprintf(cmdLine, "%s.Z", compTmpName);
  289.         unlink(cmdLine);
  290.         sprintf(cmdLine, "%s.gz", compTmpName);
  291.         unlink(cmdLine);
  292.                 
  293.         while (again) {
  294.         char cmdLine[1024];
  295.         
  296.         // We have the right to use sprintf here because NeXT's doc.
  297.         // says that the only % is for the %d in the volume name.
  298.         
  299.         if (exitCode = [self obtainDisk:wantedDiskName 
  300.             number:diskVolume from:diskName]) {
  301.             return exitCode;
  302.         }
  303.         
  304.         // Now! We shoud be in a situation where the correct disk is
  305.         // mounted under slash. Now please get the gzipped part.
  306.         
  307.         sprintf(cmdLine, "/bin/cat \"%s/%s.pkg/%s.tar.gz.%d\" >>%s.gz",
  308.             wantedDiskName, rootName, rootName, diskVolume,
  309.             compTmpName);
  310.             
  311.         if (exitCode = system(cmdLine)) {
  312.             break;
  313.         } else {
  314.             char lastName[MAXPATHLEN + 1];
  315.             
  316.             sprintf(lastName, "%s/%s.pkg/.last",
  317.                 wantedDiskName, rootName);
  318.             again = access(lastName, F_OK);
  319.             
  320.             if (!again && diskVolume == origDiskVolume) {
  321.                 break;
  322.             }
  323.  
  324.             // Eject the disk
  325.             
  326.             for (;;) {
  327.                 if ([[Application workspace]
  328.                    unmountAndEjectDeviceAt:wantedDiskName]) {
  329.                 break;
  330.             } else {
  331.                 BOOL ret;
  332.                 
  333.                 active = [NXApp activeApp]; [NXApp activateSelf:YES];
  334.                 
  335.                 ret = (NXRunLocalizedAlertPanel("Localizable",
  336.                     "Disk Problem",
  337.                 "Cannot eject disk %s. Click Retry to have another try (or click Cancel to end the installation).",
  338.                 "Retry", "Cancel", NULL, wantedDiskName + 1) !=
  339.                 NX_ALERTDEFAULT);
  340.             
  341.                 [NXApp activate:active];
  342.                 
  343.                 if (ret) {
  344.                 return EXIT_NO_EJECT;
  345.                 }
  346.             }
  347.             }
  348.             
  349.             // Next disk, please!
  350.             
  351.             ++diskVolume;
  352.         }
  353.         }
  354.         
  355.         // Now funzip the whole archive, and remove it after that
  356.         
  357.         sprintf(cmdLine,
  358.             "%s/funzip %s.gz | compress -c >%s.Z; /bin/rm -rf %s.gz; /bin/rm -f /tmp/%s.info; /bin/ln -s \"%s\" /tmp/%s.info",
  359.             [[NXBundle mainBundle] directory],
  360.         compTmpName, compTmpName, compTmpName, infoName,
  361.         rootName, rootName);
  362.         
  363.         if (!(exitCode = system(cmdLine))) {
  364.         
  365.             // Get the original disk back
  366.         
  367.             exitCode = [self obtainDisk:wantedDiskName 
  368.             number:origDiskVolume from:diskName];
  369.         
  370.         if (isOnRoot) {
  371.             active = [NXApp activeApp]; [NXApp activateSelf:YES];
  372.         
  373.             if (NXRunLocalizedAlertPanel("Localizable",
  374.             "Smart Installer",
  375.             "Smart installation done. Click Install to launch Installer and install the package (or click Quit if you want to quit now).",
  376.             "Install", "Quit", NULL) != NX_ALERTDEFAULT) {
  377.             return EXIT_OK;
  378.             }
  379.         }
  380.         
  381.         [[Application workspace] openFile:fromDir];
  382.         }
  383.     }
  384.     }
  385.     
  386.     return exitCode;    // Be careful: some return hide above!
  387. }
  388.  
  389. - (int)installPackage
  390. {
  391.     char compName[MAXPATHLEN + 1];
  392.     
  393.     int exitCode = EXIT_UNKNOWN;
  394.     
  395.     sprintf(compName, "%s/%s.gz", fromDir, rootName);
  396.     if (access(compName, R_OK) == 0) {
  397.         char cmdLine[1024];
  398.     
  399.     sprintf(cmdLine, "%s/funzip %s | /usr/ucb/compress -c >/tmp/%s.tar.Z",
  400.         [[NXBundle mainBundle] directory], compName, rootName);
  401.     exitCode = system(cmdLine);
  402.     } else {
  403.         exitCode = [self installMultipleGzipped:compName];
  404.     }
  405.  
  406.     return exitCode;
  407. }
  408.  
  409. @end
  410.