Annotation of 43BSD/contrib/mh/zotnet/bboards/getbbent.c, revision 1.1.1.1

1.1       root        1: /* getbbent.c - subroutines for accessing the BBoards file */
                      2: 
                      3: /* LINTLIBRARY */
                      4: 
                      5: #include "bboards.h"
                      6: #ifndef        MMDFONLY
                      7: #include "../h/strings.h"
                      8: #else  MMDFONLY
                      9: #include "strings.h"
                     10: #endif MMDFONLY
                     11: #include <ctype.h>
                     12: #include <pwd.h>
                     13: #include <grp.h>
                     14: #include <stdio.h>
                     15: #include <sys/types.h>
                     16: #include <sys/stat.h>
                     17: 
                     18: 
                     19: #define        NOTOK   (-1)
                     20: #define        OK      0
                     21: 
                     22: 
                     23: #define        MaxBBAka        100
                     24: #define        MaxBBLdr        100
                     25: #define        MaxBBDist       100
                     26: 
                     27: #define        COLON   ':'
                     28: #define        COMMA   ','
                     29: #define        NEWLINE '\n'
                     30: 
                     31: 
                     32: #define        ARCHIVE "archive"
                     33: #define        CNTFILE ".cnt"
                     34: #define        DSTFILE ".dist"
                     35: #define        MAPFILE ".map"
                     36: 
                     37: /*  */
                     38: 
                     39: static int  BBuid = -1;
                     40: 
                     41: static unsigned int  BBflags = SB_NULL;
                     42: 
                     43: static char BBName[BUFSIZ] = BBOARDS;
                     44: static char BBDir[BUFSIZ] = "";
                     45: static char BBData[BUFSIZ] = "";
                     46: 
                     47: static  FILE *BBfile = NULL;
                     48: 
                     49: 
                     50: static struct bboard    BB;
                     51: static struct bboard   *bb = &BB;
                     52: 
                     53: static int  BBload = 1;
                     54: 
                     55: static char BBFile[BUFSIZ];
                     56: static char BBArchive[BUFSIZ];
                     57: static char BBInfo[BUFSIZ];
                     58: static char BBMap[BUFSIZ];
                     59: static char *BBAkas[MaxBBAka];
                     60: static char *BBLeaders[MaxBBLdr];
                     61: static char *BBDists[MaxBBDist];
                     62: static char BBAddr[BUFSIZ];
                     63: static char BBRequest[BUFSIZ];
                     64: static char BBDate[BUFSIZ];
                     65: static char BBErrors[BUFSIZ];
                     66: 
                     67: 
                     68: char   *bbskip (), *getcpy ();
                     69: 
                     70: char   *crypt (), *getpass ();
                     71: struct group  *getgrnam ();
                     72: struct passwd *getpwnam (), *getpwuid ();
                     73: 
                     74: /*  */
                     75: 
                     76: int     setbbfile (file, f)
                     77: register char  *file;
                     78: register int    f;
                     79: {
                     80:     if (BBuid == -1)
                     81:        return setbbinfo (BBOARDS, file, f);
                     82: 
                     83:     (void) strcpy (BBData, file);
                     84: 
                     85:     BBflags = SB_NULL;
                     86:     (void) endbbent ();
                     87: 
                     88:     return setbbent (f);
                     89: }
                     90: 
                     91: /*  */
                     92: 
                     93: int    setbbinfo (user, file, f)
                     94: register char  *user,
                     95:                *file;
                     96: register int   f;
                     97: {
                     98:     register struct passwd *pw;
                     99: 
                    100:     if ((pw = getpwnam (user)) == NULL) {
                    101:        (void) sprintf (BBErrors, "unknown user: %s", user);
                    102:        return 0;
                    103:     }
                    104: 
                    105:     return setpwinfo (pw, file, f);
                    106: }
                    107: 
                    108: 
                    109: int    setpwinfo (pw, file, f)
                    110: register struct passwd *pw;
                    111: register char  *file;
                    112: register int   f;
                    113: {
                    114:     if (!setpwaux (pw, file))
                    115:        return 0;
                    116: 
                    117:     BBflags = SB_NULL;
                    118:     (void) endbbent ();
                    119: 
                    120:     return setbbent (f);
                    121: }
                    122: 
                    123: /*  */
                    124: 
                    125: static int  setbbaux (name, file)
                    126: register char  *name,
                    127:               *file;
                    128: {
                    129:     register struct passwd *pw;
                    130: 
                    131:     if ((pw = getpwnam (name)) == NULL) {
                    132:        (void) sprintf (BBErrors, "unknown user: %s", name);
                    133:        return 0;
                    134:     }
                    135: 
                    136:     return setpwaux (pw, file);
                    137: }
                    138: 
                    139: 
                    140: static int  setpwaux (pw, file)
                    141: register struct passwd *pw;
                    142: register char  *file;
                    143: {
                    144:     (void) strcpy (BBName, pw -> pw_name);
                    145:     BBuid = pw -> pw_uid;
                    146:     (void) strcpy (BBDir, pw -> pw_dir);
                    147:     (void) sprintf (BBData, "%s/%s",
                    148:            *file != '/' ? BBDir : "",
                    149:            *file != '/' ? file : file + 1);
                    150: 
                    151:     BBflags = SB_NULL;
                    152: 
                    153:     return 1;
                    154: }
                    155: 
                    156: /*  */
                    157: 
                    158: int     setbbent (f)
                    159: register int     f;
                    160: {
                    161:     if (BBfile == NULL) {
                    162:        if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
                    163:            return 0;
                    164: 
                    165:        if ((BBfile = fopen (BBData, "r")) == NULL) {
                    166:            (void) sprintf (BBErrors, "unable to open: %s", BBData);
                    167:            return 0;
                    168:        }
                    169:     }
                    170:     else
                    171:        rewind (BBfile);
                    172: 
                    173:     BBflags |= f;
                    174:     return (BBfile != NULL);
                    175: }
                    176: 
                    177: 
                    178: int     endbbent () {
                    179:     if (BBfile != NULL && !(BBflags & SB_STAY)) {
                    180:        (void) fclose (BBfile);
                    181:        BBfile = NULL;
                    182:     }
                    183: 
                    184:     return 1;
                    185: }
                    186: 
                    187: 
                    188: long    getbbtime () {
                    189:     struct stat st;
                    190: 
                    191:     if (BBfile == NULL) {
                    192:        if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
                    193:            return 0;
                    194: 
                    195:        if (stat (BBData, &st) == NOTOK) {
                    196:            (void) sprintf (BBErrors, "unable to stat: %s", BBData);
                    197:            return 0;
                    198:        }
                    199:     }
                    200:     else
                    201:        if (fstat (fileno (BBfile), &st) == NOTOK) {
                    202:            (void) sprintf (BBErrors, "unable to fstat: %s", BBData);
                    203:            return 0;
                    204:        }
                    205: 
                    206:     return ((long) st.st_mtime);
                    207: }
                    208: 
                    209: /*  */
                    210: 
                    211: struct bboard  *getbbent () {
                    212:     register char  *p,
                    213:                    *q,
                    214:                    *r,
                    215:                    *d,
                    216:                    *f,
                    217:                   **s;
                    218:     static char line[BUFSIZ];
                    219: 
                    220:     if (BBfile == NULL && !setbbent (SB_NULL))
                    221:        return NULL;
                    222: 
                    223:     if ((p = fgets (line, sizeof line, BBfile)) == NULL)
                    224:        return NULL;
                    225: 
                    226:     bb -> bb_name = p;
                    227:     p = q = bbskip (p, COLON);
                    228:     p = bb -> bb_file = bbskip (p, COLON);
                    229:     bb -> bb_archive = bb -> bb_info = bb -> bb_map = "";
                    230:     p = bb -> bb_passwd = bbskip (p, COLON);
                    231:     p = r = bbskip (p, COLON);
                    232:     p = bb -> bb_addr = bbskip (p, COLON);
                    233:     p = bb -> bb_request = bbskip (p, COLON);
                    234:     p = bb -> bb_relay = bbskip (p, COLON);
                    235:     p = d = bbskip (p, COLON);
                    236:     p = f = bbskip (p, COLON);
                    237:     (void) bbskip (p, NEWLINE);
                    238: 
                    239:     s = bb -> bb_aka = BBAkas;
                    240:     while (*q) {
                    241:        *s++ = q;
                    242:        q = bbskip (q, COMMA);
                    243:     }
                    244:     *s = NULL;
                    245: 
                    246:     s = bb -> bb_leader = BBLeaders;
                    247:     if (*r == NULL) {
                    248:        if (!(BBflags & SB_FAST))
                    249:            *s++ = BBName;
                    250:     }
                    251:     else
                    252:        while (*r) {
                    253:            *s++ = r;
                    254:            r = bbskip (r, COMMA);
                    255:        }
                    256:     *s = NULL;
                    257: 
                    258:     s = bb -> bb_dist = BBDists;
                    259:     while (*d) {
                    260:        *s++ = d;
                    261:        d = bbskip (d, COMMA);
                    262:     }
                    263:     *s = NULL;
                    264: 
                    265:     if (*f)
                    266:        (void) sscanf (f, "%o", &bb -> bb_flags);
                    267:     else
                    268:        bb -> bb_flags = BB_NULL;
                    269:     bb -> bb_count = bb -> bb_maxima = 0;
                    270:     bb -> bb_date = NULL;
                    271:     bb -> bb_next = bb -> bb_link = bb -> bb_chain = NULL;
                    272: 
                    273:     if (BBload)
                    274:        BBread ();
                    275: 
                    276:     return bb;
                    277: }
                    278: 
                    279: /*  */
                    280: 
                    281: struct bboard  *getbbnam (name)
                    282: register char   *name;
                    283: {
                    284:     register struct bboard *b = NULL;
                    285: 
                    286:     if (!setbbent (SB_NULL))
                    287:        return NULL;
                    288:     BBload = 0;
                    289:     while ((b = getbbent ()) && strcmp (name, b -> bb_name))
                    290:        continue;
                    291:     BBload = 1;
                    292:     (void) endbbent ();
                    293: 
                    294:     if (b != NULL)
                    295:        BBread ();
                    296: 
                    297:     return b;
                    298: }
                    299: 
                    300: 
                    301: struct bboard  *getbbaka (aka)
                    302: register char   *aka;
                    303: {
                    304:     register char **ap;
                    305:     register struct bboard *b = NULL;
                    306: 
                    307:     if (!setbbent (SB_NULL))
                    308:        return NULL;
                    309:     BBload = 0;
                    310:     while ((b = getbbent ()) != NULL)
                    311:        for (ap = b -> bb_aka; *ap; ap++)
                    312:            if (strcmp (aka, *ap) == 0)
                    313:                goto hit;
                    314: hit: ;
                    315:     BBload = 1;
                    316:     (void) endbbent ();
                    317: 
                    318:     if (b != NULL)
                    319:        BBread ();
                    320: 
                    321:     return b;
                    322: }
                    323: 
                    324: /*  */
                    325: 
                    326: static int  BBread () {
                    327:     register int    i;
                    328:     register char  *cp,
                    329:                    *dp,
                    330:                   *p,
                    331:                   *r;
                    332:     char    prf[BUFSIZ];
                    333:     static char line[BUFSIZ];
                    334:     register    FILE * info;
                    335: 
                    336:     if (BBflags & SB_FAST)
                    337:        return;
                    338: 
                    339:     p = index (bb -> bb_request, '@');
                    340:     r = index (bb -> bb_addr, '@');
                    341:     BBRequest[0] = NULL;
                    342: 
                    343:     if (*bb -> bb_request == '-')
                    344:        if (p == NULL && r && *r == '@')
                    345:            (void) sprintf (BBRequest, "%s%s%s",
                    346:                    bb -> bb_name, bb -> bb_request, r);
                    347:        else
                    348:            (void) sprintf (BBRequest, "%s%s",
                    349:                    bb -> bb_name, bb -> bb_request);
                    350:     else
                    351:        if (p == NULL && r && *r == '@' && *bb -> bb_request)
                    352:            (void) sprintf (BBRequest, "%s%s", bb -> bb_request, r);
                    353: 
                    354:     if (BBRequest[0])
                    355:        bb -> bb_request = BBRequest;
                    356:     else
                    357:        if (*bb -> bb_request == NULL)
                    358:            bb -> bb_request = *bb -> bb_addr ? bb -> bb_addr
                    359:                : bb -> bb_leader[0];
                    360: 
                    361:     if (*bb -> bb_addr == '@') {
                    362:        (void) sprintf (BBAddr, "%s%s", bb -> bb_name, bb -> bb_addr);
                    363:        bb -> bb_addr = BBAddr;
                    364:     }
                    365:     else
                    366:        if (*bb -> bb_addr == NULL)
                    367:            bb -> bb_addr = bb -> bb_name;
                    368: 
                    369:     if (*bb -> bb_file == NULL)
                    370:        return;
                    371:     if (*bb -> bb_file != '/') {
                    372:        (void) sprintf (BBFile, "%s/%s", BBDir, bb -> bb_file);
                    373:        bb -> bb_file = BBFile;
                    374:     }
                    375: 
                    376:     if ((cp = rindex (bb -> bb_file, '/')) == NULL || *++cp == NULL)
                    377:        (void) strcpy (prf, ""), cp = bb -> bb_file;
                    378:     else
                    379:        (void) sprintf (prf, "%.*s", cp - bb -> bb_file, bb -> bb_file);
                    380:     if ((dp = index (cp, '.')) == NULL)
                    381:        dp = cp + strlen (cp);
                    382: 
                    383:     (void) sprintf (BBArchive, "%s%s/%s", prf, ARCHIVE, cp);
                    384:     bb -> bb_archive = BBArchive;
                    385:     (void) sprintf (BBInfo, "%s.%.*s%s", prf, dp - cp, cp, CNTFILE);
                    386:     bb -> bb_info = BBInfo;
                    387:     (void) sprintf (BBMap, "%s.%.*s%s", prf, dp - cp, cp, MAPFILE);
                    388:     bb -> bb_map = BBMap;
                    389: 
                    390:     if ((info = fopen (bb -> bb_info, "r")) == NULL)
                    391:        return;
                    392: 
                    393:     if (fgets (line, sizeof line, info) && (i = atoi (line)) > 0)
                    394:        bb -> bb_maxima = (unsigned) i;
                    395:     if (!feof (info) && fgets (line, sizeof line, info)) {
                    396:        (void) strcpy (BBDate, line);
                    397:        if (cp = index (BBDate, NEWLINE))
                    398:            *cp = NULL;
                    399:        bb -> bb_date = BBDate;
                    400:     }
                    401: 
                    402:     (void) fclose (info);
                    403: }
                    404: 
                    405: /*  */
                    406: 
                    407: int     ldrbb (b)
                    408: register struct bboard  *b;
                    409: {
                    410:     register char  *p,
                    411:                   **q,
                    412:                   **r;
                    413:     static int  uid = 0,
                    414:                 gid = 0;
                    415:     static char username[10] = "";
                    416:     register struct passwd *pw;
                    417:     register struct group  *gr;
                    418: 
                    419:     if (b == NULL)
                    420:        return 0;
                    421:     if (BBuid == -1 && !setbbaux (BBOARDS, BBDB))
                    422:        return 0;
                    423: 
                    424:     if (username[0] == NULL) {
                    425:        if ((pw = getpwuid (uid = getuid ())) == NULL)
                    426:            return 0;
                    427:        gid = getgid ();
                    428:        (void) strcpy (username, pw -> pw_name);
                    429:     }
                    430: 
                    431:     if (uid == BBuid)
                    432:        return 1;
                    433: 
                    434:     q = b -> bb_leader;
                    435:     while (p = *q++)
                    436:        if (*p == '=') {
                    437:            if ((gr = getgrnam (++p)) == NULL)
                    438:                continue;
                    439:            if (gid == gr -> gr_gid)
                    440:                return 1;
                    441:            r = gr -> gr_mem;
                    442:            while (p = *r++)
                    443:                if (strcmp (username, p) == 0)
                    444:                    return 1;
                    445:        }
                    446:        else
                    447:            if (strcmp (username, p) == 0)
                    448:                return 1;
                    449: 
                    450:     return 0;
                    451: }
                    452: 
                    453: /*  */
                    454: 
                    455: int     ldrchk (b)
                    456: register struct bboard  *b;
                    457: {
                    458:     if (b == NULL)
                    459:        return 0;
                    460: 
                    461:     if (*b -> bb_passwd == NULL)
                    462:        return 1;
                    463: 
                    464:     if (strcmp (b -> bb_passwd,
                    465:                crypt (getpass ("Password: "), b -> bb_passwd)) == 0)
                    466:        return 1;
                    467: 
                    468:     fprintf (stderr, "Sorry\n");
                    469:     return 0;
                    470: }
                    471: 
                    472: /*  */
                    473: 
                    474: struct bboard  *getbbcpy (bp)
                    475: register struct bboard  *bp;
                    476: {
                    477:     register char **p,
                    478:                   **q;
                    479:     register struct bboard *b;
                    480: 
                    481:     if (bp == NULL)
                    482:        return NULL;
                    483: 
                    484:     b = (struct bboard *) malloc ((unsigned) sizeof *b);
                    485:     if (b == NULL)
                    486:        return NULL;
                    487: 
                    488:     b -> bb_name = getcpy (bp -> bb_name);
                    489:     b -> bb_file = getcpy (bp -> bb_file);
                    490:     b -> bb_archive = getcpy (bp -> bb_archive);
                    491:     b -> bb_info = getcpy (bp -> bb_info);
                    492:     b -> bb_map = getcpy (bp -> bb_map);
                    493:     b -> bb_passwd = getcpy (bp -> bb_passwd);
                    494:     b -> bb_flags = bp -> bb_flags;
                    495:     b -> bb_count = bp -> bb_count;
                    496:     b -> bb_maxima = bp -> bb_maxima;
                    497:     b -> bb_date = getcpy (bp -> bb_date);
                    498:     b -> bb_addr = getcpy (bp -> bb_addr);
                    499:     b -> bb_request = getcpy (bp -> bb_request);
                    500:     b -> bb_relay = getcpy (bp -> bb_relay);
                    501: 
                    502:     for (p = bp -> bb_aka; *p; p++)
                    503:        continue;
                    504:     b -> bb_aka =
                    505:        q = (char **) calloc ((unsigned) (p - bp -> bb_aka + 1), sizeof *q);
                    506:     if (q == NULL)
                    507:        return NULL;
                    508:     for (p = bp -> bb_aka; *p; *q++ = getcpy (*p++))
                    509:        continue;
                    510:     *q = NULL;
                    511: 
                    512:     for (p = bp -> bb_leader; *p; p++)
                    513:        continue;
                    514:     b -> bb_leader =
                    515:        q = (char **) calloc ((unsigned) (p - bp -> bb_leader + 1), sizeof *q);
                    516:     if (q == NULL)
                    517:        return NULL;
                    518:     for (p = bp -> bb_leader; *p; *q++ = getcpy (*p++))
                    519:        continue;
                    520:     *q = NULL;
                    521: 
                    522:     for (p = bp -> bb_dist; *p; p++)
                    523:        continue;
                    524:     b -> bb_dist = 
                    525:        q = (char **) calloc ((unsigned) (p - bp -> bb_dist + 1), sizeof *q);
                    526:     if (q == NULL)
                    527:        return NULL;
                    528:     for (p = bp -> bb_dist; *p; *q++ = getcpy (*p++))
                    529:        continue;
                    530:     *q = NULL;
                    531: 
                    532:     b -> bb_next = bp -> bb_next;
                    533:     b -> bb_link = bp -> bb_link;
                    534:     b -> bb_chain = bp -> bb_chain;
                    535: 
                    536:     return b;
                    537: }
                    538: 
                    539: /*  */
                    540: 
                    541: int     getbbdist (bb, action)
                    542: register struct bboard  *bb;
                    543: register int     (*action) ();
                    544: {
                    545:     register int    result;
                    546:     register char **dp;
                    547: 
                    548:     BBErrors[0] = NULL;
                    549:     for (dp = bb -> bb_dist; *dp; dp++)
                    550:        if (result = getbbitem (bb, *dp, action))
                    551:            return result;
                    552: 
                    553:     return result;
                    554: }
                    555: 
                    556: char    *getbberr () {
                    557:     return (BBErrors[0] ? BBErrors : NULL);
                    558: };
                    559: 
                    560: /*  */
                    561: 
                    562: static int  getbbitem (bb, item, action)
                    563: register struct bboard  *bb;
                    564: register char   *item;
                    565: register int     (*action) ();
                    566: {
                    567:     register int    result;
                    568:     register char  *cp,
                    569:                    *dp,
                    570:                    *hp,
                    571:                    *np;
                    572:     char    mbox[BUFSIZ],
                    573:             buffer[BUFSIZ],
                    574:             file[BUFSIZ],
                    575:             host[BUFSIZ],
                    576:             prf[BUFSIZ];
                    577:     register FILE *fp;
                    578: 
                    579:     switch (*item) {
                    580:        case '*': 
                    581:            switch (*++item) {
                    582:                case '/': 
                    583:                    hp = item;
                    584:                    break;
                    585: 
                    586:                case NULL: 
                    587:                    if ((cp = rindex (bb -> bb_file, '/')) == NULL || *++cp == NULL)
                    588:                        (void) strcpy (prf, ""), cp = bb -> bb_file;
                    589:                    else
                    590:                        (void) sprintf (prf, "%.*s", cp - bb -> bb_file, bb -> bb_file);
                    591:                    if ((dp = index (cp, '.')) == NULL)
                    592:                        dp = cp + strlen (cp);
                    593:                    (void) sprintf (file, "%s.%.*s%s", prf, dp - cp, cp, DSTFILE);
                    594:                    hp = file;
                    595:                    break;
                    596: 
                    597:                default: 
                    598:                    (void) sprintf (file, "%s/%s", BBDir, item);
                    599:                    hp = file;
                    600:                    break;
                    601:            }
                    602: 
                    603:            if ((fp = fopen (hp, "r")) == NULL)
                    604:                return bblose ("unable to read file %s", hp);
                    605:            while (fgets (buffer, sizeof buffer, fp)) {
                    606:                if (np = index (buffer, '\n'))
                    607:                    *np = NULL;
                    608:                if (result = getbbitem (bb, buffer, action)) {
                    609:                    (void) fclose (fp);
                    610:                    (void) bblose ("error with file %s, item %s", hp, buffer);
                    611:                    return result;
                    612:                }
                    613:            }
                    614:            (void) fclose (fp);
                    615:            return OK;
                    616: 
                    617:        default: 
                    618:            if (hp = rindex (item, '@')) {
                    619:                *hp++ = NULL;
                    620:                (void) strcpy (mbox, item);
                    621:                (void) strcpy (host, hp);
                    622:                *--hp = '@';
                    623:            }
                    624:            else {
                    625:                (void) sprintf (mbox, "%s%s", DISTADR, bb -> bb_name);
                    626:                (void) strcpy (host, item);
                    627:            }
                    628:            if (result = (*action) (mbox, host))
                    629:                (void) bblose ("action (%s, %s) returned 0%o", mbox, host, result);
                    630:            return result;
                    631:     }
                    632: }
                    633: 
                    634: /*  */
                    635: 
                    636: /* VARARGS1 */
                    637: 
                    638: static int  bblose (fmt, a, b, c)
                    639: char   *fmt,
                    640:        *a,
                    641:        *b,
                    642:        *c;
                    643: {
                    644:     if (BBErrors[0] == NULL)
                    645:        (void) sprintf (BBErrors, fmt, a, b, c);
                    646: 
                    647:     return NOTOK;
                    648: }
                    649: 
                    650: /*  */
                    651: 
                    652: void   make_lower (s1, s2)
                    653: register char   *s1,
                    654:                *s2;
                    655: {
                    656:     if (s1 == NULL || s2 == NULL)
                    657:        return;
                    658: 
                    659:     for (; *s2; s2++)
                    660:        *s1++ = isupper (*s2) ? tolower (*s2) : *s2;
                    661:     *s1 = NULL;
                    662: }
                    663: 
                    664: /*  */
                    665: 
                    666: static char *bbskip (p, c)
                    667: register char  *p,
                    668:                c;      
                    669: {
                    670:     if (p == NULL)
                    671:        return NULL;
                    672: 
                    673:     while (*p && *p != c)
                    674:        p++;
                    675:     if (*p)
                    676:        *p++ = NULL;
                    677: 
                    678:     return p;
                    679: }
                    680: 
                    681: 
                    682: static char   *getcpy (s)
                    683: register char   *s;
                    684: {
                    685:     register char  *p;
                    686: 
                    687:     if (s == NULL)
                    688:        return NULL;
                    689: 
                    690:     if (p = malloc ((unsigned) (strlen (s) + 1)))
                    691:        (void) strcpy (p, s);
                    692:     return p;
                    693: }

unix.superglobalmegacorp.com

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