Annotation of coherent/b/conf/patch/patch.c, revision 1.1.1.1

1.1       root        1: static char Copyright[] =      "$Copyright: (c) 1985, INETCO Systems, Ltd.$";
                      2: static char version[] =        "patch version 2.6 for COHERENT v.4.0";
                      3: 
                      4: /* (lgl-
                      5:  *     The information contained herein is a trade secret of Mark Williams
                      6:  *     Company, and  is confidential information.  It is provided  under a
                      7:  *     license agreement,  and may be  copied or disclosed  only under the
                      8:  *     terms of  that agreement.  Any  reproduction or disclosure  of this
                      9:  *     material without the express written authorization of Mark Williams
                     10:  *     Company or persuant to the license agreement is unlawful.
                     11:  *
                     12:  *     COHERENT Version 2.3.35
                     13:  *     Copyright (c) 1982, 1983, 1984.
                     14:  *     An unpublished work by Mark Williams Company, Chicago.
                     15:  *     All rights reserved.
                     16:  -lgl) */
                     17: /*
                     18:  * Patch binary system images
                     19:  * and possibly the running system.
                     20:  * This program is not expected to work other than on PC Coherent.
                     21:  * Certain hot patches may not be effective, since some values are only
                     22:  * referenced once at system initialization.
                     23:  *
                     24:  * $Log:       patch.c,v $
                     25:  * Revision 1.6  92/11/25  15:32:04  bin
                     26:  * hal: update to read fom /dev/imem
                     27:  * 
                     28:  * Revision 1.5  92/07/06  15:41:09  bin
                     29:  * piggy: all hex numbers have leading zeroes to indicate their length
                     30:  * 
                     31:  * Revision 1.1        91/04/24  14:20:20      bin
                     32:  * Initial revision
                     33:  * 
                     34:  * 87/02/01    Allan Cornish           /usr/src/cmd/conf/patch.c
                     35:  * myatol() routine added which recognizes numeric base specifications.
                     36:  * All references to atol() modified to use myatol().
                     37:  * main() now enables buffering on standard output.
                     38:  *
                     39:  */
                     40: char short_helpmessage[] = "\
                     41: patch -- alter COFF binary image\n\
                     42: Usage: patch [ -v ][ -p ][ -k ] imagename symbol=value [ ... ]\n\
                     43: ";
                     44: 
                     45: char helpmessage[] = "\
                     46: Options:\n\
                     47:        -v      Verbose mode--print what's being done.\n\
                     48:        -p      Peek only--do not write.\n\
                     49:        -k      Patch running system via /dev/kmem, /dev/kmemhi.\n\
                     50:        -K      Like -k but do not alter imagename.\n\
                     51: Patch alters the value of 'symbol' to 'value' in the binary 'imagename'.\n\
                     52: Both 'symbol' and 'value' may be composed of a decimal numeric constant\n\
                     53: or of a symbol in the image's symbol table, trailing '_' is significant,\n\
                     54: optionally offset by + or - a decimal numeric constant.\n\
                     55: The 'value' field may be optionally composed of 'makedev(d1, d2)' where 'd1'\n\
                     56: and 'd2' are decimal numbers and the result is a dev_t value.\n\
                     57: The size of the altered field is by default sizeof(int), but the 'value'\n\
                     58: specification may be followed by a ':' and a 'c', 's', 'i', or 'l' to\n\
                     59: explicitly specify a char, short, int, or long sized patch.\n\
                     60: \
                     61: ";
                     62: 
                     63: #include <stdio.h>
                     64: #include <coff.h>
                     65: #include <canon.h>
                     66: #include <ctype.h>
                     67: #include <fcntl.h>
                     68: #include <sys/types.h>
                     69: #include <sys/stat.h>
                     70: #include "patch.h"
                     71: 
                     72: /*
                     73:  * Nlist tables and patch records.
                     74:  */
                     75: #define NNLS   512
                     76: int    nnls;   /* Number of nlist elements used */
                     77: SYMENT nl[NNLS*2];
                     78: int    sym_len = 0;    /* Number of bytes allocated for symbols.  */
                     79: char   *symbols=NULL;
                     80: 
                     81: PLIST pl[NNLS];
                     82: 
                     83: char *namep;           /* Name of object file to patch.  */
                     84: int nobin = 0;         /* Should we not patch the image?  */
                     85: int hotpatch = 0;      /* Are we patching /dev/kmem,/dev/kmemhi?  */
                     86: int verbose = 0;       /* Are we printing feedback?  */
                     87: int peek = 0;          /* Just peek--don't actually do the patch.  */
                     88: 
                     89: void main();
                     90: int getnames();
                     91: void badsym();
                     92: void getone();
                     93: void setfile();
                     94: void setkmem();
                     95: int patch();
                     96: long myatol();
                     97: void usage();
                     98: char *index();
                     99: char *realloc();
                    100: 
                    101: 
                    102: void
                    103: main(argc, argv)
                    104:        int argc;
                    105:        char *argv[];
                    106: {
                    107:        static char obuf[BUFSIZ];
                    108:        int c;                  /* For reading options from getopt().  */
                    109:        int num_patches;        /* Number of patches to make on this file.  */
                    110: 
                    111:        extern int optind;
                    112:        extern char *optarg;
                    113: 
                    114:        /*
                    115:         * Enable output buffering.
                    116:         */
                    117:        setbuf( stdout, obuf );
                    118: 
                    119:        while ((c = getopt(argc, argv, "Kkpv?")) != EOF) {
                    120:                switch (c) {
                    121:                case 'K':
                    122:                        hotpatch++;
                    123:                        nobin++;
                    124:                case 'k':
                    125:                        hotpatch++;
                    126:                        break;
                    127:                case 'p':
                    128:                        peek++;
                    129:                        break;
                    130:                case 'v':
                    131:                        verbose++;
                    132:                        break;
                    133:                case '?':
                    134:                        fprintf(stderr, "%s\n", version);
                    135:                        usage(TRUE);    /* Does not return.  */
                    136:                default:
                    137:                        usage(FALSE);   /* Does not return.  */
                    138:                }
                    139:        }
                    140: 
                    141:        /*
                    142:         * There must be at least 2 arguments left.
                    143:         */
                    144:        if (argc - optind < 2) {
                    145:                fprintf(stderr, "Missing arguments.\n");
                    146:                usage(FALSE);   /* Does not return */
                    147:        }
                    148:        
                    149:        namep = argv[optind++]; /* Fetch the name of the file to patch.  */
                    150: 
                    151:        num_patches = (argc - optind);
                    152:        if (getnames(num_patches, &(argv[optind])) == 0) {
                    153:                if (!nobin) {
                    154:                        setfile(namep, num_patches, pl);
                    155:                }
                    156:                if (hotpatch) {
                    157:                        setkmem(num_patches);
                    158:                }
                    159:                exit(0);
                    160:        }
                    161:        exit(1);
                    162: }
                    163: 
                    164: /*
                    165:  * Fill in the array of patch structures 'pl[]' based on the command line.
                    166:  * 'nn' is the number of symbol assignments; 'npp' is an argv of symbol
                    167:  * assignments.
                    168:  * Returns the number of invalid assignments.
                    169:  */
                    170: int
                    171: getnames(nn, npp)
                    172:        int nn;
                    173:        char **npp;
                    174: {
                    175:        register int i;
                    176:        register PLIST *p;
                    177:        register SYMENT *np;
                    178:        int nbad;
                    179: 
                    180:        nbad = 0;
                    181:        for (i = 0; i < nn; i += 1)
                    182:                if (i < NNLS-1)
                    183:                        getone(i, npp[i]);
                    184: 
                    185:        /* Now we can look up all the symbols in the symbol table.  */
                    186:        coffnlist(namep, nl, symbols, nnls);
                    187: 
                    188:        for (i = 0; i < nn; i += 1)
                    189:                if (i >= NNLS)
                    190:                        fprintf(stderr,
                    191:                                "Too many patches: %s ignored\n", npp[i]);
                    192:                else {
                    193:                        /* 'p' is the struct we fill in this time around.  */
                    194:                        p = &pl[i];
                    195:                        
                    196:                        /* If the LHS was (part) symbolic, add in the value
                    197:                         * of the symbol.
                    198:                         */
                    199:                        if ((np = p->p_lvnp) != NULL) {
                    200:                                if (0xffff != np->n_type) {
                    201:                                        p->p_lval += np->n_value;
                    202:                                } else {
                    203:                                        nbad += 1;
                    204:                                        badsym(np->n_offset);
                    205:                                }
                    206:                        }
                    207:                        /* If the RHS was (part) symbolic, add in the value
                    208:                         * of the symbol.
                    209:                         */
                    210:                        if ((np = p->p_rvnp) != NULL) {
                    211:                                if (0xffff != np->n_type) {
                    212:                                        p->p_rval += np->n_value;
                    213:                                } else {
                    214:                                        nbad += 1;
                    215:                                        badsym(np->n_offset);
                    216:                                }
                    217:                        }
                    218: 
                    219:                        /* Fill in the value to be assigned.  */
                    220:                        switch (p->p_type) {
                    221:                        case 'c': p->p_val.p_char       = p->p_rval; break;
                    222:                        case 's': p->p_val.p_short      = p->p_rval; break;
                    223:                        case 'i': p->p_val.p_int        = p->p_rval; break;
                    224:                        case 'l': p->p_val.p_long       = p->p_rval; break;
                    225:                        default:
                    226:                                nbad += 1;
                    227:                                fprintf(stderr, "Bad data type %c in %s.\n",
                    228:                                        p->p_type, npp[i]);
                    229:                                break;
                    230:                        }
                    231:                }
                    232:        return (nbad);
                    233: }
                    234: 
                    235: void
                    236: badsym(offset)
                    237:        long offset;
                    238: {
                    239:        fprintf(stderr, "%s not found in %s\n",
                    240:                &(symbols[offset - sizeof(long)]), namep);
                    241: }
                    242: 
                    243: /*
                    244:  * Parse a symbolic assignment, filling in pl[i].
                    245:  */
                    246: void
                    247: getone(i, np)
                    248:        int i;                  /* Which'th symbol assigment is this?  */
                    249:        register char *np;      /* The symbol assignment itself.  */
                    250: {
                    251:        register int n;
                    252:        register char *cp;
                    253:        char *nsym;             /* Temporary holder for 'symbols' realloc().  */
                    254:        long myatol();
                    255: 
                    256:        pl[i].p_lvnp = NULL;
                    257:        pl[i].p_lval = 0;
                    258:        pl[i].p_rvnp = NULL;
                    259:        pl[i].p_rval = 0;
                    260:        pl[i].p_type = 'i';
                    261: 
                    262:        /*
                    263:         * If there is a type indicator, get it now.
                    264:         */
                    265:        if (NULL != (cp = index(np, ':'))) {
                    266:                pl[i].p_type = cp[1];
                    267:        }
                    268: 
                    269:        /* Pull apart LHS of assignment.  */
                    270:        if (isalpha(*np) || *np == '_') {
                    271:                pl[i].p_lvnp = nl + nnls;       /* Allocate another SYMENT.  */
                    272:                /* Mark as not yet found.  */
                    273:                nl[nnls].n_type = 0xffff;
                    274:                /* Point at offset into 'symbols' for new name.  */
                    275:                nl[nnls].n_zeroes = 0;
                    276:                nl[nnls].n_offset = sizeof(long) + sym_len;
                    277: 
                    278:                /* Figure out how big the symbol is by looking for
                    279:                 * a non-alphanumeric or _ character.
                    280:                 */
                    281:                cp = np;
                    282:                for (n = 0; isalnum(*cp) || *cp == '_'; n += 1) {
                    283:                        cp += 1;
                    284:                }
                    285:                /* Now allocate more space for symbol names.  */
                    286:                sym_len += n + sizeof('\0');
                    287:                if (NULL == (nsym = realloc(symbols, sym_len))) {
                    288:                        /* This assignment is too long; skip it.  */
                    289:                        sym_len -= n;
                    290:                        fprintf(stderr,
                    291:                                "Assignment too long; skipping:  %s\n", np);
                    292:                        return;
                    293:                }
                    294:                symbols = nsym; /* The realloc() worked.  */
                    295:                /* Copy the new symbol in place.  */
                    296:                cp = symbols + sym_len - (n + sizeof('\0'));
                    297:                strncpy(cp, np, n);
                    298:                cp[n] = '\0';
                    299: 
                    300:                nnls += 1;      /* Move up to next empty SYMENT.  */
                    301:                np += n;        /* Move on to next token.  */
                    302:        }
                    303:        /*
                    304:         * If there is a '+' it has served its purpose by dropping us
                    305:         * out of the for loop above.  Ignore it now.
                    306:         */
                    307:        if (*np == '+')
                    308:                np += 1;
                    309: 
                    310:        /* Fetch a possible literal number.  */
                    311:        pl[i].p_lval = myatol(np);
                    312: 
                    313:        /* Pull apart RHS of assignment.  */
                    314:        np = index(np, '=');
                    315:        if (np != NULL) {
                    316:                np += 1;
                    317:                if (strncmp(np, "makedev(", 8) == 0) {
                    318:                        /* RHS is a makedev() expression.  */
                    319:                        int d1, d2;
                    320: 
                    321:                        np = index(np, '(') + 1;
                    322:                        d1 = myatol(np);
                    323:                        np = index(np, ',');
                    324:                        if (np != NULL) {
                    325:                                d2 = myatol(np + 1);
                    326:                                np = index(np, ')');
                    327:                        } else
                    328:                                d2 = 0;
                    329:                        pl[i].p_rval = makedev(d1, d2);
                    330:                        pl[i].p_type = 's';
                    331:                        if (np == NULL)
                    332:                                np = "";
                    333:                        else
                    334:                                np += 1;
                    335:                        goto tail;
                    336:        } else if (isalpha(*np) || *np == '_') {
                    337:                        /* The RHS must be a object symbol.  */
                    338:        
                    339:                        pl[i].p_rvnp = nl + nnls;  /* Allocate another SYMENT.  */
                    340:                        nl[nnls].n_type = 0xffff;  /* Mark as not yet found.  */
                    341: 
                    342:                        /* Point at offset into 'symbols' for new name.  */
                    343:                        nl[nnls].n_zeroes = 0;
                    344:                        nl[nnls].n_offset = sizeof(long) + sym_len;
                    345:        
                    346:                        /* Figure out how big the symbol is by looking for
                    347:                         * a non-alphanumeric or _ character.
                    348:                         */
                    349:                        cp = np;
                    350:                        for (n = 0; isalnum(*cp) || *cp == '_'; n += 1) {
                    351:                                cp += 1;
                    352:                        }
                    353:                        /* Now allocate more space for symbol names.  */
                    354:                        sym_len += n + sizeof('\0');
                    355:                        if (NULL == (nsym = realloc(symbols, sym_len))) {
                    356:                                /* This assignment is too long; skip it.  */
                    357:                                sym_len -= n;
                    358:                                fprintf(stderr,
                    359:                                  "Assignment too long; skipping:  %s\n", np);
                    360:                                return;
                    361:                        }
                    362:                        symbols = nsym; /* The realloc() worked.  */
                    363:                        /* Copy the new symbol in place.  */
                    364:                        cp = &(symbols[sym_len - (n + sizeof('\0'))]);
                    365:                        strncpy(cp, np, n);
                    366:                        cp[n] = '\0';
                    367: 
                    368:                        nnls += 1;      /* Move up to next empty SYMENT.  */
                    369:                        np += n;        /* Move on to next token.  */
                    370:                }
                    371: 
                    372: 
                    373:                /*
                    374:                 * If there is a '+' is has served its purpose by dropping us
                    375:                 * out of the for loop above.  Ignore it now.
                    376:                 */
                    377:                if (*np == '+')
                    378:                        np += 1;
                    379:                /* Fetch a possible literal number.  */
                    380:                pl[i].p_rval = myatol(np);
                    381:        }
                    382: tail:
                    383:        return;
                    384: }
                    385: 
                    386: /*
                    387:  * Modify the contents of /dev/kmem to match the array of patch
                    388:  * structures pl[].  The argument 'n' is the number of entries in pl[]
                    389:  * that should be processed.
                    390:  */
                    391: void
                    392: setkmem(n)
                    393:        int n;
                    394: {
                    395:        int fdlo, fdhi;
                    396:        register int i;
                    397:        char *symname;  /* Name of symbol in LHS being patched.  */
                    398: 
                    399:        /* Open up live memory for patching.  */
                    400:        if (peek) {
                    401:                if ((fdlo=open("/dev/kmem", O_RDONLY)) < 0) {
                    402:                        fprintf(stderr, "Cannot open /dev/kmem for reading.\n");
                    403:                        return;
                    404:                }
                    405:                if ((fdhi=open("/dev/kmemhi", O_RDONLY)) < 0) {
                    406:                        fprintf(stderr, "Cannot open /dev/kmemhi for reading.\n");
                    407:                        return;
                    408:                }
                    409:        } else {
                    410:                if ((fdlo=open("/dev/kmem", O_RDWR)) < 0) {
                    411:                        fprintf(stderr, "Cannot open /dev/kmem.\n");
                    412:                        return;
                    413:                }
                    414:                if ((fdhi=open("/dev/kmemhi", O_RDWR)) < 0) {
                    415:                        fprintf(stderr, "Cannot open /dev/kmemhi.\n");
                    416:                        return;
                    417:                }
                    418:        }
                    419: 
                    420:        /* Walk through pl[] blasting the new values into live memory.  */
                    421:        for (i = 0; i < n; i += 1) {
                    422:                int seekOffset = pl[i].p_lval;
                    423:                symname = &(symbols[pl[i].p_lvnp->n_offset - sizeof(long)]);
                    424: 
                    425:                if ((seekOffset & 0x80000000) == 0) {
                    426:                        if(lseek(fdlo, seekOffset, 0) != -1L) {
                    427:                                if (patch(fdlo, &pl[i], "/dev/kmem",
                    428:                                  symname) < 0)
                    429:                                        fprintf(stderr,
                    430:                                          "Write error in /dev/kmem\n");
                    431:                        } else
                    432:                                fprintf(stderr, "Seek error in /dev/kmem\n");
                    433:                } else {
                    434:                        if(lseek(fdhi, seekOffset-0x80000000, 0) != -1L) {
                    435:                                if (patch(fdhi, &pl[i], "/dev/kmemhi",
                    436:                                  symname) < 0)
                    437:                                        fprintf(stderr,
                    438:                                          "Write error in /dev/kmemhi\n");
                    439:                        } else
                    440:                                fprintf(stderr, "Seek error in /dev/kmemhi\n");
                    441:                }
                    442:        }
                    443:        close(fdlo);
                    444:        close(fdhi);
                    445: }
                    446: 
                    447: 
                    448: /*
                    449:  * Modify the file attached to descriptor 'fd' to match the single patch
                    450:  * structure 'p'.  The file descriptor should already be lseek()'d to
                    451:  * the correct place.
                    452:  * Returns 0 on success, -1 otherwise.  errno will be set on error.
                    453:  */
                    454: int
                    455: patch(fd, p, file, sym)
                    456:        int fd;
                    457:        PLIST *p;
                    458:        /* These two args are only for information.  */
                    459:        char *file;     /* Name of the file being patched.  */
                    460:        char *sym;      /* Name of the LHS symbol being patched.  */
                    461: {
                    462:        register char *bp;
                    463:        register int nc;
                    464:        union {
                    465:                char    p_char;
                    466:                short   p_short;
                    467:                int     p_int;
                    468:                long    p_long;
                    469:        } old_val;
                    470: 
                    471:        bp = &p->p_val;
                    472:        switch (p->p_type) {
                    473:        case 'c':       nc = sizeof(char);      break;
                    474:        case 's':       nc = sizeof(short);     break;
                    475:        case 'i':       nc = sizeof(int);       break;
                    476:        case 'l':       nc = sizeof(long);      break;
                    477:        }
                    478: 
                    479:        if (verbose || peek) {
                    480:            old_val.p_long = 0; /* Zero the whole buffer.  */
                    481: 
                    482:            if (read(fd, &old_val, nc) != nc) {
                    483:                fprintf(stderr, "Can't read old value.\n");
                    484:            } else {
                    485: 
                    486:                printf("%s: ", file);
                    487: 
                    488:                if (verbose) printf("old value of ");
                    489: 
                    490:                printf("%s: ", sym);
                    491:                switch (p->p_type) {
                    492:                case 'c':       printf("0x%02x", old_val.p_char);       break;
                    493:                case 's':       printf("0x%04x", old_val.p_short);      break;
                    494:                case 'i':       printf("0x%08x", old_val.p_int);        break;
                    495:                case 'l':       printf("0x%08x", old_val.p_long);       break;
                    496:                } /* switch */
                    497: 
                    498:                printf("\n");
                    499: 
                    500:                if (!peek) {    /* If only peeking, there is no new value.  */
                    501:                        printf("%s: new value: ", file);
                    502:                        switch (p->p_type) {
                    503:                        case 'c':       printf("0x%02x", p->p_val.p_char);
                    504:                                        break;
                    505:                        case 's':       printf("0x%04x", p->p_val.p_short);
                    506:                                        break;
                    507:                        case 'i':       printf("0x%08x", p->p_val.p_int);
                    508:                                        break;
                    509:                        case 'l':       printf("0x%08x", p->p_val.p_long);
                    510:                                        break;
                    511:                        } /* switch */
                    512: 
                    513:                        printf("\n");
                    514:                } /* if (verbose) */
                    515: 
                    516:                /* Go back for the write.  */
                    517:                lseek(fd, (long) (-nc), 1);
                    518:            } /* if (read...) */
                    519: 
                    520:        } /* if (verbose || peek) */
                    521: 
                    522:        if (peek) {
                    523:                if (verbose) {
                    524:                        printf("Just peeking, no write.\n");
                    525:                }
                    526:        } else if (write(fd, bp, nc) != nc) {
                    527:                return (-1);
                    528:        }
                    529:        return (0);
                    530: }
                    531: 
                    532: /**
                    533:  *
                    534:  * long
                    535:  * myatol( s )         -- Ascii to Long integer conversion.
                    536:  * char * s;
                    537:  *
                    538:  *     Input:  s = pointer to string containing a numeric prefix.
                    539:  *
                    540:  *     Action: Parse input string.
                    541:  *             Parse optional leading sign character '-'.
                    542:  *             Parse optional numeric base specification '0', '0o', and '0x'.
                    543:  *             Parse following numeric digits.
                    544:  *
                    545:  *     Return: Long integer value.
                    546:  *
                    547:  *     Notes:  Numeric parsing terminates on first non-digit.
                    548:  */
                    549: long
                    550: myatol( s )
                    551:        register char * s;
                    552: {
                    553:        register int base;
                    554:        register int sign;
                    555:        auto    long valu;
                    556: 
                    557:        /*
                    558:         * Check for leading negative sign.
                    559:         */
                    560:        sign = 1;
                    561:        if ( *s == '-' ) {
                    562:                sign = -1;
                    563:                s++;
                    564:        }
                    565: 
                    566:        /*
                    567:         * Check for base specification.
                    568:         */
                    569:        base = 10;
                    570:        if ( *s == '0' ) {
                    571:                switch ( *++s ) {
                    572:                case 'x':       base = 16;      ++s;    break;
                    573:                case 'o':       base =  8;      ++s;    break;
                    574:                default:        base =  8;
                    575:                }
                    576:        }
                    577: 
                    578:        for ( valu = 0L; *s != '\0'; s++ ) {
                    579: 
                    580:                /*
                    581:                 * Decimal digit.
                    582:                 */
                    583:                if ( ('0' <= *s) && (*s <= '9') ) {
                    584:                        valu *= base;
                    585:                        valu += *s - '0';
                    586:                }
                    587: 
                    588:                /*
                    589:                 * Upper case hex digit.
                    590:                 */
                    591:                else if ( (base == 16) && ('A' <= *s) && (*s <= 'F') ) {
                    592:                        valu *= base;
                    593:                        valu += *s - ('A' - 10);
                    594:                }
                    595: 
                    596:                /*
                    597:                 * Lower case Hex digit.
                    598:                 */
                    599:                else if ( (base == 16) && ('a' <= *s) && (*s <= 'f') ) {
                    600:                        valu *= base;
                    601:                        valu += *s - ('a' - 10);
                    602:                }
                    603: 
                    604:                /*
                    605:                 * Not a digit.
                    606:                 */
                    607:                else
                    608:                        break;
                    609:        }
                    610: 
                    611:        if ( sign < 0 )
                    612:                valu = -valu;
                    613: 
                    614:        return valu;
                    615: }
                    616: 
                    617: /*
                    618:  * Print out an usage message.
                    619:  */
                    620: void
                    621: usage(verbose)
                    622:        int verbose;
                    623: {
                    624:        fprintf(stderr, short_helpmessage);
                    625:        if (verbose) {
                    626:                fprintf(stderr, helpmessage);
                    627:        }
                    628:        exit(1);
                    629: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.