Ignore:
Timestamp:
May 6, 2011, 4:25:19 AM (14 years ago)
Author:
Ben Rietbroek
Message:

AiR-BOOT v1.07 -- As released with eCS v2.1. [2011-05-06]
Signature-date: 2006-03-13. (incorrect)
Trunk contains buildable v1.07 version as distributed with eCS v2.1.
Directory 'tags' contains v1.06 & v1.07 reference versions
built for all languages. Note that language ID for 'Dutch' changed
from 'DT' to 'NL' in v1.07 and that the v1.06 reference version also
uses 'NL' for 'Dutch'.
Also note that helper programs like the installer and setaboot are
are only modified for the OS/2 versions in v1.07.
The signature-date for v1.07 incorrectly states the same
date as for v1.06. The signature-version is correct.
Removed other binaries. (cd-rom images, old releases, etc.)
The tags serve as reference versions:

  • v1.06: rebuilt from source. (tags/v1.06r)
  • v1.07: built as released with eCS v2.1. (tags/v1.07r)
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/TOOLS/OS2/SETABOOT/SETABOOT.C

    r29 r30  
    1717//
    1818
     19/*
     20// Rousseau: 2011-02-05
     21// - Made volumes compare case insensitive so fs-label matches volume-name on command-line.  (around line 510)
     22//   This means bootable volumes cannot not have the same and only differ in case.
     23*/
     24
     25
    1926#define INCL_BASE
    2027#define INCL_WINSHELLDATA
     
    6269
    6370typedef struct _AiRBOOTCONFIG {
    64    CHAR   Identifier[13];
     71   CHAR   Identifier[13];                                                        // Rousseau: INVISIBLE CHAR AT END !
    6572   UCHAR  MajorVersion;
    6673   UCHAR  MinorVersion;
     
    110117   UCHAR  AutomaticPartition;
    111118   UCHAR  ForceLBAUsage;
     119   UCHAR  IgnoreLVM;
     120   UCHAR  Reserved[82];
     121   CHAR   InstallVolume[12];
    112122 } AiRBOOTCONFIG;
    113123typedef AiRBOOTCONFIG *PAiRBOOTCONFIG;
     124
     125
    114126
    115127typedef struct _AiRBOOTIPENTRY {
     
    139151
    140152
     153/* Executables to search for */
     154PCHAR   classic_setboots[] = {
     155   "SETBM.EXE",
     156   NULL
     157};
     158
     159
     160/*
     161// ProtoTypes.
     162*/
     163BOOL Track0DetectAirBoot (BOOL* ab_bad);
     164BOOL Track0WriteAiRBOOTConfig (void);
     165
     166
     167
    141168   USHORT CountHarddrives (void) {
    142169      USHORT NumDrives = 0;
     
    149176   USHORT OS2_GetIOCTLHandle () {
    150177      USHORT IOCTLHandle = 0;
    151  
     178
    152179      if (DosPhysicalDisk(INFO_GETIOCTLHANDLE, &IOCTLHandle, sizeof(IOCTLHandle),"1:" , 3) != 0)
    153180         return 0;
     
    236263    }
    237264
     265
     266APIRET QueryBootDrive(char *bootdrv)
     267{
     268        ULONG   aulSysInfo[QSV_MAX]     = {0};                                             // System Information Data Buffer
     269        APIRET  rc                              = NO_ERROR;                                                                                                    // Return code
     270
     271        if(bootdrv==0) return 1;
     272
     273        rc = DosQuerySysInfo(1L,                                                                                                                            // Request all available system
     274                                                        QSV_MAX ,                                                                                                              // information
     275                                                        (PVOID)aulSysInfo,                                                                                          // Pointer to buffer
     276                                                        sizeof(ULONG)*QSV_MAX);                                                                             // Size of the buffer
     277
     278        if (rc != NO_ERROR) {
     279                return 1;
     280        }
     281        else {
     282                //printf("Bootable drive: %c:\n",
     283                //              aulSysInfo[QSV_BOOT_DRIVE-1]+'A'-1);  /* Max length of path name */
     284                bootdrv[0]=aulSysInfo[QSV_BOOT_DRIVE-1]+'A'-1;
     285
     286                /*
     287                printf("Total physical memory is %u bytes.\n",
     288                                aulSysInfo[QSV_TOTPHYSMEM-1]);
     289                */
     290
     291                return 0;
     292        }
     293
     294
     295}
     296
    238297USHORT GetChecksumOfSector (USHORT BaseCheck, USHORT SectorNo) {
    239298   PUSHORT CurPos     = (PUSHORT)((ULONG)&Track0+(SectorNo-1)*512);
     
    246305 }
    247306
    248 BOOL Track0DetectAirBoot (void) {
    249    USHORT ResultCheck;
    250    USHORT CurSectorNo = 0;
    251 
    252    AiRBOOT_CodeSig = (PAiRBOOTCODESIG)&Track0[2];
    253    AiRBOOT_Config  = (PAiRBOOTCONFIG)&Track0[(55-1)*512];
    254    AiRBOOT_IPT     = (PAiRBOOTIPENTRY)&Track0[(56-1)*512];
    255 
    256    if (strncmp(AiRBOOT_CodeSig->Identifier, "AiRBOOT", 7)!=0) {
    257       return FALSE;
    258     }
    259 
    260    if ((AiRBOOT_CodeSig->TotalCodeSectors)>53) {
    261       puts ("SETABOOT: AiR-BOOT Code damaged!");
    262       return FALSE;
    263     }
    264 
    265    ResultCheck = 0; CurSectorNo = 0;
    266    while (CurSectorNo<AiRBOOT_CodeSig->TotalCodeSectors) {
    267       ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo+2);
    268       CurSectorNo++;
    269     }
    270    if (ResultCheck!=AiRBOOT_CodeSig->CheckSumOfCode) {
    271       puts ("SETABOOT: AiR-BOOT Code damaged!");
    272       return FALSE;
    273     }
    274 
    275    if (strncmp(AiRBOOT_Config->Identifier, "AiRCFG-TABLE­", 13)!=0) {
    276       puts ("SETABOOT: AiR-BOOT Config damaged!");
    277       return FALSE;
    278     }
    279 
    280    // Set Config-CheckSum to 0
    281    AiRBOOT_ConfigCheckSum = AiRBOOT_Config->CheckSumOfConfig;
    282    AiRBOOT_Config->CheckSumOfConfig = 0;
    283 
    284    // Calculate CheckSum...
    285    ResultCheck = 0; CurSectorNo = 55;
    286    while (CurSectorNo<60) {
    287       ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo);
    288       CurSectorNo++;
    289     }
    290    if (ResultCheck!=AiRBOOT_ConfigCheckSum) {
    291       puts ("SETABOOT: AiR-BOOT Config damaged!");
    292       return FALSE;
    293     }
    294    return TRUE;
    295  }
    296 
    297 BOOL Track0WriteAiRBOOTConfig (void) {
    298    USHORT ResultCheck;
    299    USHORT CurSectorNo = 0;
    300 
    301    // Update Edit-Counter...
    302    AiRBOOT_Config->EditCounter++;
    303    AiRBOOT_Config->CheckSumOfConfig = 0;
    304 
    305    // Calculate CheckSum...
    306    ResultCheck = 0; CurSectorNo = 55;
    307    while (CurSectorNo<60) {
    308       ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo);
    309       CurSectorNo++;
    310     }
    311    AiRBOOT_Config->CheckSumOfConfig = ResultCheck;
    312 
    313    if (!Track0Write())
    314       return FALSE;
    315    return TRUE;
    316  }
    317 
    318 int main (int argc, char **argv) {
     307
     308
     309
     310/*
     311// If AiR-BOOT is not installed, the user probably meant to control OS/2 BM with this utility.
     312// Since the functionality of this utility is for AiR-BOOT only, we will pass the request to
     313// the OS/2 BM SETBOOT utility which is called SETBM.EXE as of eCS 2.01.
     314// Since the objective here is to supply OS/2 BM SETBOOT compatibility, if SETBM.EXE is not found,
     315// some other system locations are searched for the OS/2 version of SETBOOT.EXE.
     316// Any SETBOOT.EXE that is found and that does not have a module-name of "setaboot" is invoked,
     317// and passed along the command-line the user issued.
     318// In this case also the return-value of the OS/2 version of SETBOOT.EXE is returned.
     319*/
     320int   DoClassicActions(int argc, char **argv) {
     321   APIRET      rc             = -1;
     322   RESULTCODES  crc                        = {-1,-1};
     323   PTIB        ptib           = NULL;
     324   PPIB        ppib           = NULL;
     325   char        buffer[256]    = "\0";
     326   char        cmdline[256]   = "\0";
     327   PSZ         path           = NULL;
     328   char        sresult[256]   = "\0";
     329   char        bootdrive      = '?';
     330   char*       p              = NULL;
     331   int         i              = 0;
     332
     333   //printf("\nCLASSIC ACTIONS !! (%d)\n", argc);
     334
     335   rc = QueryBootDrive(&bootdrive);
     336
     337   rc = DosScanEnv("PATH", &path);
     338   rc = DosSearchPath(SEARCH_CUR_DIRECTORY | SEARCH_IGNORENETERRS,
     339                        path,
     340                        classic_setboots[0],
     341                        sresult,
     342                        sizeof(sresult));
     343
     344   //printf("SRESULT: rc=%d, %s\n", rc, sresult);
     345
     346   if (rc) {
     347      printf("\n");
     348      printf("ERROR: SETBOOT (AiR-BOOT version)\n");
     349      printf("Since the AiR-BOOT Boot Manager is not installed, this program (SETBOOT.EXE), funcions as a wrapper\n");
     350      printf("to %s that should be used to control IBM Boot Manager.\n", classic_setboots[0]);
     351      printf("However, %s could not be found in the PATH, the error-code is: %d\n", classic_setboots[0], rc);
     352      printf("You can resolve this situation by renaming a valid SETBOOT.EXE to %s\n", classic_setboots[0]);
     353      printf("and put it in your %c:\\OS2 directory.", bootdrive);
     354      printf("\n");
     355      exit(rc);
     356   }
     357
     358
     359
     360
     361   memset(cmdline, 0, sizeof(cmdline));                                          // Clear the command-line buffer.
     362   p = cmdline;                                                                  // Temporary pointer to insert arguments.
     363   strcpy(p, sresult);                                                           // Copy the program-name.
     364   p += strlen(sresult)+1;                                                       // Advance to point for space separated parameters.
     365
     366   /*
     367   // Process all the arguments,
     368   // inserting the separated by a space.
     369   */
     370   for (i=1; i<argc; i++) {
     371      strcpy(p, argv[i]);                                                        // Copy the argument.
     372      p += strlen(argv[i]);                                                      // Advance pointer past argument.
     373      *p++ = ' ';                                                                // Space separation.
     374   }
     375
     376   /*
     377   for (i=0; i<100; i++) {
     378      printf("%c", cmdline[i] ? cmdline[i] : '#');
     379   }
     380   printf("\n");
     381   */
     382
     383   //printf("CMDLINE: %s\n", cmdline);
     384   //printf("CMDLINE+: %s\n", cmdline+strlen(sresult)+1);
     385
     386   rc = DosExecPgm(buffer,
     387            sizeof(buffer),
     388            EXEC_SYNC,
     389            cmdline,
     390            NULL,
     391            &crc,
     392            sresult);
     393
     394   //rc = 3;
     395   if (rc) {
     396      printf("\n");
     397      printf("ERROR: SETBOOT (AiR-BOOT version)\n");
     398      printf("Since the AiR-BOOT Boot Manager is not installed, this program (SETBOOT.EXE), funcions as a wrapper\n");
     399      printf("to %s that should be used to control IBM Boot Manager.\n", classic_setboots[0]);
     400      printf("However, something went wrong when executing %s.\n", classic_setboots[0]);
     401      printf("The error-code is: %d and the termination-code is: %d\n", rc, crc.codeTerminate);
     402      printf("\n");
     403      exit(rc);
     404   }
     405
     406
     407   //printf("DosExecPgm: rc=%08X, codeterminate=%08X, coderesult=%08X\n", rc, crc.codeTerminate, crc.codeResult);
     408
     409   /*
     410   rc = DosGetInfoBlocks(&ptib, &ppib);
     411
     412   rc = DosQueryModuleName(ppib->pib_hmte, sizeof(buffer), buffer);
     413   printf("MODULE: %s\n", buffer);
     414   printf("CMDLINE: %s\n", ppib->pib_pchcmd);
     415   */
     416
     417   return crc.codeResult;
     418}
     419
     420
     421int   DoAirBootActions(int argc, char **argv, BOOL ab_detected, BOOL ab_bad) {
    319422   ULONG           CurArgument      = 0;
    320423   ULONG           ArgumentLen      = 0;
     
    347450   ULONG           XWPBootCount     = 0;
    348451   CHAR            XWPBootName[30][12];
    349    CHAR            XWPBootCommand[30][28]; // 'setaboot /IBA:""' (16 chars)
     452   CHAR            XWPBootCommand[30][28];                                       // 'setaboot /IBA:""' (16 chars)
    350453   BOOL            XWPEntryFound    = FALSE;
     454   BOOL            CDBoot           = FALSE;                                     // TRUE if booted from CD; New System will be added when using /4:"LABEL"
     455   BOOL            Track0Loaded     = FALSE;                                     // Assume track0 did not load correctly.
     456   BOOL            AiRBOOTBad       = FALSE;
     457
     458   //printf("\nAiR-BOOT ACTIONS !!\n");
     459
     460   AiRBOOTDetected = ab_detected;
     461   AiRBOOTBad = ab_bad;
     462
     463   if (AiRBOOTBad)
     464      return 1;
    351465
    352466   // Use OSO001.MSG, so we safe us the trouble of translating :)
     
    354468      return 1;
    355469
    356    puts ("SETABOOT - AiR-BOOT Configuration Utility (OS/2) - (c) 2004-2009 by M. Kiewitz");
     470   /*
     471   // Rousseau: changed version to be the same as the AiR-BOOT is accompanies.
     472   */
     473   //puts ("SETABOOT - AiR-BOOT Configuration Utility (OS/2) - (c) 2004-2009 by M. Kiewitz");
     474   puts ("SETABOOT v1.07 - AiR-BOOT Configuration Utility - (c) 2004-2011 by M. Kiewitz");
     475
     476
     477   //return 0;
     478
     479   /*
     480   // Rousseau:
     481   // Log some debug stuff to (virtual) flop.
     482   */
     483   /*
     484   {
     485      char        buf[512]="\0";
     486      FILE*       fp = NULL;
     487      int         i = 0;
     488
     489      fp = fopen("A:\\SETBOOT.TXT", "a");
     490      sprintf(buf, "Bliep");
     491      fprintf(fp,"Program: %s\n", argv[0]);
     492      fprintf(fp,"Arguments: %d\n", argc);
     493      for (i=0; i<argc-1; i++) {
     494         fprintf(fp, "Arg %d: %s\n", i+1, argv[i+1]);
     495      }
     496      fprintf(fp, "\n");
     497      fclose(fp);
     498   }
     499   */
     500
     501
     502
     503   /*
     504   // Rousseau: ## Enable boot-through when installing new system ##
     505   // In the install-environment, the MEMDRIVE env-var is defined.
     506   // This modifies the behavior after phase 1.
     507   */
     508   if (getenv("MEMDRIVE")) {
     509      printf("CDBoot Environment.\n");
     510      CDBoot = TRUE;
     511   }
     512
    357513
    358514   if (argc==1) {
     
    361517    }
    362518
     519
     520
     521
    363522   // Now we check for AiR-BOOT existance...
     523   /*
    364524   if (CountHarddrives()>0) {
    365525      if (Track0Load()) {
    366          if (Track0DetectAirBoot()) AiRBOOTDetected = TRUE;
    367        } else {
     526         // Rousseau: Track0DetectAirBoot() will init globals.
     527         if (Track0DetectAirBoot()) // REPLACE WITH BOOL
     528            AiRBOOTDetected = TRUE;
     529       }
     530       else {
    368531         MSG_Print (TXT_ERROR_DuringAccessHDD);
    369532       }
    370     } else {
     533    }
     534    else {
    371535      MSG_Print (TXT_ERROR_DuringAccessHDD);
    372     }
     536   }
     537   */
    373538
    374539   CurArgument = 1;
     
    460625
    461626            *StartPos = 0; StartPos++;
     627
    462628            // Search that partition in IPT of AiR-BOOT...
    463629            if ((CurChar=='4') && (ArgumentLen==0)) {
     
    475641             }
    476642
     643
     644            /*
     645            // Rousseau:
     646            // Insert label of newly installed system in AiR-BOOT configuration.
     647            // Note that it is changed to uppercase because AiR-BOOT uses the FS-label when
     648            // scanning partitions and LVM-info is not found. (Otherwise PART-label)
     649            // The auto-boot flag is not set in this case as this is handled by the AiR-BOOT loader.
     650            */
     651            if (CDBoot) {
     652               strncpy(AiRBOOT_Config->InstallVolume, _strupr(StartPos), ArgumentLen);
     653               AiRBOOT_Config->InstallVolume[ArgumentLen] = '\0';
     654               printf("Writing Install Volume: %s to AiR-BOOT configuration.\n", AiRBOOT_Config->InstallVolume);
     655               Track0WriteAiRBOOTConfig();
     656               return 0;
     657            }
     658
     659
     660
     661
    477662            BadValue = TRUE;
    478663            CurPartitionNo = 0; CurIPTEntry = AiRBOOT_IPT;
    479664            while (CurPartitionNo<AiRBOOT_Config->Partitions) {
    480                if (strncmp(CurIPTEntry->PartitionName, StartPos, ArgumentLen)==0) {
     665               /*
     666               // Rousseau: Changed below to case-insensitive compare.
     667               // This solves the part/vol-label (mixed-case) v.s. fs-label (upper-case) issue.
     668               */
     669               /*if (strncmp(CurIPTEntry->PartitionName, StartPos, ArgumentLen)==0) {*/
     670               if (strnicmp(CurIPTEntry->PartitionName, StartPos, ArgumentLen)==0) {
    481671                  if (ArgumentLen==11) {
    482672                     BadValue = FALSE;
     
    495685               CurPartitionNo++; CurIPTEntry++;
    496686             }
     687
    497688
    498689            if (BadValue) {
     
    602793      PrfWriteProfileData (HINI_USERPROFILE, "XWorkplace", "RebootTo", XWPOrgStringPtr, XWPStringSize);
    603794      free(XWPOrgStringPtr);
    604        
     795
    605796      puts ("SETABOOT: XWorkPlace updated.");
    606797      return 0;
     
    611802         return 1;
    612803       }
    613       printf ("SETABOOT: AiR-BOOT %X.%02X detected.\n\n", AiRBOOT_CodeSig->MajorVersion, AiRBOOT_CodeSig->MinorVersion);
     804      printf("SETABOOT: AiR-BOOT %X.%02X detected.\n\n", AiRBOOT_CodeSig->MajorVersion, AiRBOOT_CodeSig->MinorVersion);
     805      //printf("DEBUG: InstallVolume: %s\n", AiRBOOT_Config->InstallVolume);
    614806      if (AiRBOOT_Config->BootMenuActive) {
    615807         if (AiRBOOT_Config->TimedBoot) {
     
    697889    }
    698890   return 0;
     891
     892
     893
     894}
     895
     896
     897/*
     898// Rousseau:
     899// Global pointers will be initialized here !
     900*/
     901BOOL Track0DetectAirBoot (BOOL* ab_bad) {
     902   USHORT ResultCheck;
     903   USHORT CurSectorNo = 0;
     904
     905   /* Globals that get initialized */
     906   AiRBOOT_CodeSig = (PAiRBOOTCODESIG)&Track0[2];
     907   AiRBOOT_Config  = (PAiRBOOTCONFIG)&Track0[(55-1)*512];
     908   AiRBOOT_IPT     = (PAiRBOOTIPENTRY)&Track0[(56-1)*512];
     909
     910   if (strncmp(AiRBOOT_CodeSig->Identifier, "AiRBOOT", 7)!=0) {
     911      *ab_bad = FALSE;
     912      return FALSE;
     913    }
     914
     915   if ((AiRBOOT_CodeSig->TotalCodeSectors)>53) {
     916      puts ("SETABOOT: AiR-BOOT Code damaged!");
     917      *ab_bad = TRUE;
     918      return TRUE;
     919    }
     920
     921   ResultCheck = 0; CurSectorNo = 0;
     922   while (CurSectorNo<AiRBOOT_CodeSig->TotalCodeSectors) {
     923      ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo+2);
     924      CurSectorNo++;
     925    }
     926   if (ResultCheck!=AiRBOOT_CodeSig->CheckSumOfCode) {
     927      puts ("SETABOOT: AiR-BOOT Code damaged!");
     928      *ab_bad = TRUE;
     929      return TRUE;
     930    }
     931
     932   if (strncmp(AiRBOOT_Config->Identifier, "AiRCFG-TABLE­", 13)!=0) {            // Rousseau: INVISIBLE CHAR HERE !
     933      puts ("SETABOOT: AiR-BOOT Config damaged!");
     934      *ab_bad = TRUE;
     935      return TRUE;
     936    }
     937
     938   // Set Config-CheckSum to 0
     939   AiRBOOT_ConfigCheckSum = AiRBOOT_Config->CheckSumOfConfig;
     940   AiRBOOT_Config->CheckSumOfConfig = 0;
     941
     942   // Calculate CheckSum...
     943   ResultCheck = 0; CurSectorNo = 55;
     944   while (CurSectorNo<60) {
     945      ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo);
     946      CurSectorNo++;
     947    }
     948   if (ResultCheck!=AiRBOOT_ConfigCheckSum) {
     949      puts ("SETABOOT: AiR-BOOT Config damaged!");
     950      *ab_bad = TRUE;
     951      return TRUE;
     952    }
     953   *ab_bad = FALSE;
     954   return TRUE;
    699955 }
     956
     957BOOL Track0WriteAiRBOOTConfig (void) {
     958   USHORT ResultCheck;
     959   USHORT CurSectorNo = 0;
     960
     961   // Update Edit-Counter...
     962   AiRBOOT_Config->EditCounter++;
     963   AiRBOOT_Config->CheckSumOfConfig = 0;
     964
     965   // Calculate CheckSum...
     966   ResultCheck = 0; CurSectorNo = 55;
     967   while (CurSectorNo<60) {
     968      ResultCheck = GetChecksumOfSector(ResultCheck, CurSectorNo);
     969      CurSectorNo++;
     970    }
     971   AiRBOOT_Config->CheckSumOfConfig = ResultCheck;
     972
     973   if (!Track0Write())
     974      return FALSE;
     975   return TRUE;
     976 }
     977
     978
     979/*
     980// Rousseau: # This is the main entry-point #
     981// Special behavior if eCS is booted from CDROM and phase 1 called this program.
     982// In that case, the name of the newly installed system is put in the AiR-BOOT configuration.
     983// This will cause AiR-BOOT to boot through after phase 1.
     984*/
     985int main (int argc, char **argv) {
     986   BOOL  AiRBOOTDetected   = FALSE;
     987   BOOL  Track0Loaded      = FALSE;                                              // Assume track0 did not load correctly.
     988   BOOL  AiRBOOTBad        = FALSE;
     989   int   rc                = -1;
     990
     991
     992   /*
     993   // Rousseau: ## Changed order to first check for AiR-BOOT existance ##
     994   // If AiR-BOOT is not installed, all action is passed-thru to IBM SETBOOT (SETBM.EXE).
     995   */
     996
     997
     998   /*
     999   // Try to load track zero.
     1000   // We don't care if no harddisk is present, since we first want to know if AiR-BOOT is
     1001   // installed to adjust our behaviour.
     1002   // If it's not installed, or a loading error occurs, all actions will be deferred to
     1003   // IBM SETBOOT (SETBM.EXE).
     1004   // This means we also let IBM SETBOOT handle the situation in which no HD's are present.
     1005   */
     1006   Track0Loaded = Track0Load();
     1007
     1008   /*
     1009   // Now see if AiR-BOOT is present.
     1010   // If there was a loading error, no AiR-BOOT signature will be present, so
     1011   // we pass-thru to IBM SETBOOT.
     1012   */
     1013   AiRBOOTDetected = Track0DetectAirBoot(&AiRBOOTBad);
     1014
     1015   if (AiRBOOTDetected) {
     1016      rc = DoAirBootActions(argc, argv, AiRBOOTDetected, AiRBOOTBad);
     1017   }
     1018   else {
     1019      rc = DoClassicActions(argc, argv);
     1020   }
     1021
     1022
     1023   return rc;
     1024 }
Note: See TracChangeset for help on using the changeset viewer.