home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / newsbreak / part01 / newsbreak.c
C/C++ Source or Header  |  1991-04-04  |  18KB  |  677 lines

  1. #define VERSION "newsbreak 1.12 by G. R. Walter"
  2.  
  3. /*
  4.  * newsbreak.c
  5.  *
  6.  * by G. R. Walter (Fred) December 30, 1988
  7.  *
  8.  * USAGE:
  9.  *     newsbreak [-a]
  10.  *        Default action is to only process files that contain the line
  11.  *        "Archive-name:" - this is used to create the subdirectory that
  12.  *        the shar files are unshared/etc into.
  13.  *
  14.  *        If -a is used then all files will be processed. This is needed
  15.  *        for postings to groups such as alt.sources, or when dealing with
  16.  *        entries at some archive sites (the program is stored as lots
  17.  *        of shar files).
  18.  *
  19.  * DESCRIPTION:
  20.  *     Takes a series of files which are shar files (strips any
  21.  *     garbage at the start of the shar file) that have been posted to
  22.  *     comp.{sources|binaries}.* and feeds them through sh.
  23.  *     After they have been fed through sh the original files are
  24.  *     deleted. Then any uuencoded files are uudecoded, after which
  25.  *     the uuencoded files are also deleted. Special care is taken
  26.  *     with files posted to comp.binaries.ibm.pc which use a non-standard
  27.  *     format.
  28.  *
  29.  * TO COMPILE:
  30.  *     Under BSD 4.3
  31.  *         cc newsbreak.c -o newsbreak
  32.  *     Under System V
  33.  *         cc -DSYSTEM_V newsbreak.c -lbsd -o newsbreak
  34.  *     Under Xenix
  35.  *         cc -DXENIX newsbreak.c -lx -o newsbreak
  36.  *
  37.  * NOTES:
  38.  *     1) This program assumes that all necessary shar files are in the
  39.  *        current directory. It attempts to not delete stuff if it can't
  40.  *        handle it (like when not all the parts of a multi-part uuencoded
  41.  *        file are available).
  42.  *     2) When there are multiple parts to a uuencoded file, a maximum
  43.  *        of 99 parts are currently handled.
  44.  *
  45.  * HISTORY:
  46.  * 1.00 - original version
  47.  * 1.01 - small enhancements/bug fixes
  48.  * 1.02 - now handle .zu's with > 9 parts correctly
  49.  * 1.03 - now check for ":\tshar\:Shell Archiver" when checking if a file
  50.  *        is a shar archive
  51.  *      - now handles files ending in .uu#
  52.  * 1.04 - now check for ": run sh on this file to unbundle" when checking
  53.  *        if a file is a shar archive
  54.  * 1.05 - now check for "# This is a shell archive." when checking
  55.  *        if a file is a shar archive
  56.  *      - now prints out the version (and author name) when run
  57.  * 1.06 - now check for "Archive-name:" to see what directory the
  58.  *        resulting files should be put in. NOTE: any parts after
  59.  *        a "part*" section in the path are not mkdir'ed
  60.  *      - now handles files ending in .zuu#
  61.  *      - now handles files ending in .uu# properly
  62.  *      - now doesn't attempt to process files starting in "."
  63.  *      - now prints some useful info (so you know what it is doing)
  64.  *      - now check for "# After you unpack everything" when checking
  65.  *        if a file is a shar archive
  66.  *      - make sure I don't try to uudecode directories
  67.  *      - recursively descend directories when uudecoding
  68.  * 1.07 - added ifdef's around code needed so this compiles under System V
  69.  *      - changes by ames!uts.amdahl.com!dwl10@mailrus (Dave Lowrey)
  70.  * 1.08 - now check for ": This is a shar archive." when checking
  71.  *        if a file is a shar archive
  72.  *      - now check for "# This is the first line of a \"shell archive\""
  73.  *        when checking if a file is a shar archive
  74.  *      - build up a list of files in the current directory before unshar'ing
  75.  *      - scan these files to see which ones should be unshar'ed and try
  76.  *        to determine the best ordering for unshar'ing (using the secondary
  77.  *        header "Archive-name:" if it exists, otherwise using file name)
  78.  *      - print what directory is being searched for uuencoded files
  79.  *      - print what is being uudecoded
  80.  * 1.09 - added code to force creation of all necessary subdirectories
  81.  *      - based on code supplied by michel@etl.go.jp (Michel Pasquier)
  82.  * 1.10 - now check for "# type    sh " when checking
  83.  *        if a file is a shar archive
  84.  *      - now check for "# To recover, type \"sh archive\"" when checking
  85.  *        if a file is a shar archive
  86.  *      - now handle .puu#
  87.  *      - effectively do a caseless strncmp() on "part" in unshar() so that
  88.  *        things like "Archive-name: nethack3p9/Part01" are properly handled
  89.  * 1.11 - added special case handling for postings to comp.binaries.ibm.pc
  90.  *        (these aren't shar files)
  91.  * 1.12 - ported to XENIX
  92.  */
  93.  
  94. #include <stdio.h>
  95. #include <ctype.h>
  96. #include <sys/types.h>
  97. #include <sys/file.h>
  98. #include <sys/stat.h>
  99. #ifdef XENIX
  100. # include <sys/ndir.h>
  101. # include <sys/dirent.h>
  102. # include <errno.h>
  103. char           *getcwd();
  104. #endif
  105. #ifdef SYSTEM_V
  106. # include <sys/dir.h>
  107. # include <dirent.h>
  108. char           *getcwd();
  109. #endif
  110. #ifndef XENIX
  111. # ifndef SYSTEM_V
  112. #  define OTHER
  113. #  include <sys/dir.h>
  114. char           *getwd();
  115. # endif
  116. #endif
  117.  
  118. #ifdef XENIX
  119. # define F_OK (0)
  120. #endif
  121.  
  122. char           *malloc();
  123. char           *strcpy();
  124. char           *sprintf();
  125.  
  126. typedef struct {
  127.     char           *filename;
  128.     char           *archivename;
  129. }               Name;
  130.  
  131. char            ArchiveName[200];
  132.  
  133. #define AN_ARCHIVE(BUF) \
  134. ( \
  135.    (!strncmp(BUF, "#!/bin/sh", 9)) \
  136. || (!strncmp(BUF, "#! /bin/sh", 10)) \
  137. || (!strncmp(BUF, "# This is a shell archive.", 26)) \
  138. || (!strncmp(BUF, ": This is a shar archive.", 25)) \
  139. || (!strncmp(BUF, ":\tshar:\tShell Archiver", 22)) \
  140. || (!strncmp(BUF, ": run sh on this file to unbundle", 33)) \
  141. || (!strncmp(BUF, "# After you unpack everything", 29)) \
  142. || (!strncmp(BUF, "# This is the first line of a \"shell archive\"", 45)) \
  143. || (!strncmp(BUF, "# type    sh ", 13)) \
  144. || (!strncmp(BUF, "# To recover, type \"sh archive\"", 30)) \
  145. )
  146.  
  147. #define COMBINE "~~"
  148.  
  149. main(argc, argv)
  150.     int             argc;
  151.     char          **argv;
  152. {
  153. #ifdef SYSTEM_V
  154.     struct dirent **dp;
  155. #else
  156.     struct direct **dp;
  157. #endif
  158.     struct stat     stat_buf;
  159.     int             size;
  160.     int             i;
  161.     int             j;
  162.     Name           *array;
  163.     int             all_flag = 0;
  164.  
  165.     int             Select();
  166.     int             alphasort();
  167.     int             scandir();
  168.     int             compare();
  169.     void            unshar();
  170.     void            uudecode();
  171.  
  172.     fprintf(stderr, "%s\n", VERSION);
  173.  
  174.     if (argc > 1)
  175.     if (!strcmp(argv[1], "-a"))
  176.         all_flag = -1;
  177.  
  178.     /*
  179.      * Count the sharfiles in the current directory. If there are any, put
  180.      * the filenames and archive-names (if any) into an array and sort it.
  181.      * Then unshar. (This code assumes that the current directory contents
  182.      * don't change underneath you.) 
  183.      */
  184.     size = scandir(".", &dp, Select, alphasort);
  185.     if (size > 0) {
  186.     array = (Name *) malloc((unsigned) (sizeof(Name) * size));
  187.     for (i = 0, j = 0; i < size; i++) {
  188.         if (stat(dp[i]->d_name, &stat_buf)) /* can't stat !?!?!? */
  189.         continue;
  190.  
  191.         if ((stat_buf.st_mode & S_IFDIR))   /* a directory */
  192.         continue;
  193.  
  194.         if (has_an_archive_name(dp[i]->d_name) || all_flag) {
  195.         array[j].filename =
  196.             malloc((unsigned) (strlen(dp[i]->d_name) + 1));
  197.         strcpy(array[j].filename, dp[i]->d_name);
  198.         array[j].archivename =
  199.             malloc((unsigned) (strlen(ArchiveName) + 1));
  200.         strcpy(array[j].archivename, ArchiveName);
  201.         j++;
  202.         }
  203.     }
  204.     size = j;
  205.     if (size > 0) {
  206.         fprintf(stderr, "\nNow performing the unshar pass.\n");
  207.  
  208.         qsort((char *) array, size, (int) sizeof(Name), compare);
  209.  
  210.         /* now unshar everything */
  211.         for (i = 0; i < size; i++)
  212.         unshar(array[i].filename, array[i].archivename);
  213.     }
  214.     fprintf(stderr, "\nNow performing the uudecode pass.\n");
  215.  
  216.     uudecode(".", 0);
  217.     }
  218.     /*
  219.      * In theory I should free all allocated memory, but it will be free'd
  220.      * upon exitting. 
  221.      */
  222.     exit(0);
  223. }
  224.  
  225. /*
  226.  * create_subpath - recursively create subpath
  227.  */
  228.  
  229. void
  230. create_subpath(dir, subpath)
  231.     char           *dir;
  232.     char           *subpath;
  233. {
  234.     char           *p;
  235.     char           *newdir;
  236.  
  237.     for (p = subpath; *p != '\0' && *p != '/'; p++);
  238.  
  239.     if (*p == '/') {            /* was a sub-directory and not a filename */
  240.     *p++ = '\0';
  241.     newdir = malloc((unsigned) (strlen(dir) + 1 + strlen(subpath) + 1));
  242.     sprintf(newdir, "%s/%s", dir, subpath);
  243.     /*
  244.      * If it doesn't exist then create it. 
  245.      */
  246.     if (access(newdir, F_OK) < 0) {
  247.         if (mkdir(newdir, 0777) < 0) {
  248.         fprintf(stderr, "Couldn't mkdir %s\n", newdir);
  249.         return;
  250.         }
  251.     }
  252.     create_subpath(newdir, p);
  253.     free(newdir);
  254.     }
  255. }
  256.  
  257. /*
  258.  * ensure_existance_of_subdirs - ensure existance of necessary sub-directories
  259.  *
  260.  * Search for destination file or path and extract its full name
  261.  * then create necessary sub-directories.
  262.  */
  263.  
  264. #define NOT_END(P) \
  265. (*P != ' ' && *P != '\'' && *P != '\"' && *P != '\n' && *P != '&' && *P != '\0')
  266.  
  267. void
  268. ensure_existance_of_subdirs(p, dir)
  269.     char           *p;
  270.     char           *dir;
  271. {
  272.     char           *subdirs;
  273.  
  274.     for (; *p != '>' && *p != '\0'; p++);       /* Get to start of path. */
  275.     if (*p == '\0')
  276.     return;
  277.     for (p++; (*p == ' ' || *p == '\'' || *p == '\"') && *p != '\0'; p++);
  278.     if (*p == '\0')
  279.     return;
  280.  
  281.     subdirs = p;                /* Get to end of path. */
  282.     for (; NOT_END(p); p++);
  283.     *p = '\0';
  284.  
  285.     create_subpath(dir, subdirs);
  286. }
  287.  
  288. void
  289. unshar(name, archivename)
  290.     char           *name;
  291.     char           *archivename;
  292. {
  293.     FILE           *fin;
  294.     FILE           *fout;
  295.     char            buf[200];
  296.     char            dir[200];
  297.     char           *part = NULL;
  298.     char           *p;
  299.     char            tmp[4];
  300.     int             i;
  301.  
  302.     fprintf(stderr, "Attempting to unshar %s\n", name);
  303.     fin = fopen(name, "r");
  304.     if (fin == (FILE *) NULL)            /* file doesn't exist !? */
  305.     return;
  306.  
  307.     strcpy(dir, ".");           /* setup directory to use */
  308.     if (archivename[0] != '\0') {
  309.     strcpy(dir, archivename);
  310.     for (p = dir; *p != '\0'; p++) {
  311.         if (*p == '/') {
  312.         *p = '\0';
  313.         for (i = 0; i < 4; i++) {
  314.             if (isascii(p[i + 1]) && isupper(p[i + 1]))
  315.             tmp[i] = tolower(p[i + 1]);
  316.             else
  317.             tmp[i] = p[i + 1];
  318.             if (tmp[i] == '\0')
  319.             break;
  320.         }
  321.         if (!strncmp(tmp, "part", 4)) {
  322.             part = p + 1;
  323.             break;
  324.         }
  325.         if (access(dir, F_OK) < 0)
  326.             if (mkdir(dir, 0777) < 0)
  327.             goto ABORT_ATTEMPT;
  328.         *p = '/';
  329.         }
  330.     }
  331.     if (access(dir, F_OK) < 0) {
  332.         if (mkdir(dir, 0777) < 0) {
  333.     ABORT_ATTEMPT:
  334.         fprintf(stderr, "Couldn't mkdir %s\n", dir);
  335.         fprintf(stderr, "Aborting this attempt\n");
  336.         fclose(fin);
  337.         return;
  338.         }
  339.     }
  340.     }
  341.     fprintf(stderr, "unsharing into directory \"%s\"\n", dir);
  342.  
  343.     for (;;) {
  344.     if (fgets(buf, 200, fin) == NULL) {     /* not a shar file !? */
  345.         fclose(fin);
  346.         return;
  347.     }
  348.     if (!strncmp(buf, "Newsgroups: comp.binaries.ibm.pc", 32)) {
  349.         if (part != NULL) {
  350.         fclose(fin);
  351.         sprintf(buf, "mv %s %s/%s%s", name, dir, part, COMBINE);
  352.         (void) system(buf);
  353.         return;
  354.         }
  355.     }
  356.     if (AN_ARCHIVE(buf))
  357.         break;
  358.     }
  359.  
  360.     sprintf(buf, "%s/.unshar.temp.file", dir);
  361.     fout = fopen(buf, "w");
  362.     while (fgets(buf, 200, fin) != NULL) {
  363.     fprintf(fout, "%s", buf);
  364.     /*
  365.      * For each source archived ensure existance of necessary
  366.      * sub-directories. 
  367.      */
  368.     if (!strncmp(buf, "sed", 3) || !strncmp(buf, "cat", 3))
  369.         ensure_existance_of_subdirs(buf, dir);
  370.     }
  371.     fclose(fout);
  372.     fclose(fin);
  373.  
  374.     sprintf(buf, "cd %s; sh .unshar.temp.file", dir);
  375.     if (system(buf) == 0) {
  376.     (void) unlink(name);
  377.     } else {
  378.     fprintf(stderr, "exit status non-zero, not deleting %s\n", name);
  379.     }
  380.  
  381.     sprintf(buf, "rm %s/.unshar.temp.file", dir);
  382.     (void) system(buf);
  383. }
  384.  
  385. void
  386. uudecode(name, level)
  387.     char           *name;
  388.     int             level;
  389. {
  390. #ifdef SYSTEM_V
  391.     struct dirent **dp;
  392. #else
  393.     struct direct **dp;
  394. #endif
  395.     FILE           *file;
  396.     char            buf[200];
  397.     char            name_buf[200];
  398.     char            path[200];
  399.     char           *p;
  400.     struct stat     stat_buf;
  401.     char            digit;
  402.     int             i;
  403.     int             size;
  404.  
  405.     int             scandir();
  406.     int             Select();
  407.     int             alphasort();
  408.  
  409.     if (stat(name, &stat_buf))  /* can't stat !?!?!?! */
  410.     return;
  411.  
  412.     if ((stat_buf.st_mode & S_IFDIR)) {
  413.     /* uudecode everything in this directory */
  414. #ifdef OTHER
  415.     if (!getwd(path))
  416.         return;
  417. #else
  418.     if (!getcwd(path, 200))
  419.         return;
  420. #endif
  421.     size = scandir(name, &dp, Select, alphasort);
  422.     if (size <= 0)
  423.         return;
  424.  
  425.     if (chdir(name))
  426.         return;
  427.  
  428.     level++;
  429.     if (level == 1)
  430.         fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
  431.     else
  432.         fprintf(stderr, "uudecoding in directory \"%s/%s\"\n", path, name);
  433.     for (i = 0; i < size; i++)
  434.         uudecode(dp[i]->d_name, level);
  435.     (void) chdir(path);
  436.     if (level > 1)
  437.         fprintf(stderr, "uudecoding in directory \"%s\"\n", path);
  438.     return;
  439.     }
  440.     /*
  441.      * First combine any files that end in COMBINE. 
  442.      */
  443.     p = name + strlen(name) - strlen(COMBINE);
  444.     if (p >= name) {
  445.     if (!strcmp(p, COMBINE)) {
  446.         sprintf(buf, "cat *%s | sed '/^END/,/^BEGIN/d'| uudecode", COMBINE);
  447.         if (system(buf) == 0) {
  448.         sprintf(buf, "rm *%s", COMBINE);
  449.         (void) system(buf);
  450.         }
  451.         return;
  452.     }
  453.     }
  454.     /*
  455.      * If the file ends in ".uue" or ".zuu" ".puu" or ".uu" just uudecode it.
  456.      * Handle ".zuu#", ".puu#", ".pu#", ".zu#" and ".uu#" where # is a
  457.      * number. 
  458.      */
  459.     p = name + strlen(name) - 4;
  460.     if (((strcmp(p, ".uue") && strcmp(p, ".zuu") &&
  461.       strcmp(p, ".puu") && strcmp(p + 1, ".uu")))) {
  462.     p += 3;
  463.     while (isdigit(*p))
  464.         p--;
  465.  
  466.     digit = p[1];
  467.     p[1] = '\0';
  468.     p -= 2;
  469.     if (!strcmp(p, ".uu") || !strcmp(p, ".zu") || !strcmp(p, ".pu")) {
  470.         if (digit == '0') {
  471.         sprintf(buf, "cat %s* | uudecode", name);
  472.         } else {
  473.         sprintf(name_buf, "%s10", name);
  474.         file = fopen(name_buf, "r");
  475.         if (file == (FILE *) NULL) {
  476.             sprintf(buf, "cat %s? | uudecode", name);
  477.         } else {
  478.             fclose(file);
  479.             sprintf(buf, "cat %s? %s?? | uudecode", name, name);
  480.         }
  481.         }
  482.     } else if (strcmp(p - 1, ".zuu") && strcmp(p - 1, ".puu")) {
  483.         return;
  484.     }
  485.     }
  486.     sprintf(buf, "cat %s* | uudecode", name);
  487.     fprintf(stderr, "%s\n", buf);
  488.     if (system(buf) == 0) {
  489.     sprintf(buf, "rm %s*", name);
  490.     (void) system(buf);
  491.     } else {
  492.     fprintf(stderr, "exit status non-zero, not deleting file(s)\n");
  493.     }
  494. }
  495.  
  496. int
  497. compare(element1, element2)
  498.     Name           *element1;
  499.     Name           *element2;
  500. {
  501.     int             result;
  502.  
  503.     result = strcmp(element1->archivename, element2->archivename);
  504.     if (result == 0)
  505.     result = strcmp(element1->filename, element2->filename);
  506.  
  507.     return (result);
  508. }
  509.  
  510. /*
  511.  * has_an_archive_name - return -1 if has an archive name, 0 otherwise.
  512.  *                     - as well, set the global variable ArchiveName
  513.  */
  514.  
  515. int
  516. has_an_archive_name(name)
  517.     char           *name;
  518. {
  519.     FILE           *fin;
  520.     char            buf[200];
  521.  
  522.     ArchiveName[0] = '\0';
  523.  
  524.     fin = fopen(name, "r");
  525.     if (fin == (FILE *) NULL)            /* file doesn't exist !? */
  526.     return (0);
  527.  
  528.     for (;;) {
  529.     if (fgets(buf, 200, fin) == NULL) {
  530.         break;
  531.     } else if (strncmp(buf, "Archive-name:", 13) == 0) {
  532.         sscanf(buf, "Archive-name: %s", ArchiveName);
  533.         fclose(fin);
  534.         return (-1);
  535.     }
  536.     }
  537.     fclose(fin);
  538.     return (0);
  539. }
  540.  
  541. int
  542. Select(dp)
  543. #ifdef SYSTEM_V
  544.     struct dirent  *dp;
  545. #else
  546.     struct direct  *dp;
  547. #endif
  548. {
  549.     if (dp->d_name[0] != '.')
  550.     return (-1);
  551.     else
  552.     return (0);
  553. }
  554.  
  555. #ifndef OTHER
  556. /*
  557.  * alphasort and scandir by rsalz.
  558.  */
  559.  
  560. /* Initial guess at directory size. */
  561. #define INITIAL_SIZE        30
  562.  
  563. /* A convenient shorthand. */
  564. typedef struct direct        ENTRY;
  565.  
  566. /* Linked in later. */
  567. extern char         *malloc();
  568. extern char         *realloc();
  569. extern char         *strcpy();
  570.  
  571. int
  572. alphasort(d1, d2)
  573.     ENTRY            **d1;
  574.     ENTRY            **d2;
  575. {
  576.     return(strcmp(d1[0]->d_name, d2[0]->d_name));
  577. }
  578.  
  579. int
  580. scandir(name, list, selector, sorter)
  581.     char              *name;
  582.     ENTRY           ***list;
  583.     int              (*selector)();
  584.     int              (*sorter)();
  585. {
  586.     ENTRY            **names;
  587.     ENTRY             *E;
  588.     DIR               *Dp;
  589.     int                i;
  590.     int                size;
  591.  
  592.     /* Get initial list space and open directory. */
  593.     size = INITIAL_SIZE;
  594.     names = (ENTRY **)malloc(size * sizeof names[0]);
  595.     if (names == (ENTRY **) NULL)
  596.         return(-1);
  597.     Dp = opendir(name);
  598.     if (Dp == (DIR *) NULL)
  599.         return(-1);
  600.  
  601.     /* Read entries in the directory. */
  602.     for (i = 0; E = readdir(Dp); )
  603.     if (selector == 0 || (*selector)(E)) {
  604.         /* User wants them all, or he wants this one. */
  605.         if (++i >= size) {
  606.             size <<= 1;
  607.             names = (ENTRY **)realloc((char *)names, size * sizeof names[0]);
  608.             if (names == (ENTRY **) NULL) {
  609.                 closedir(Dp);
  610.                 return(-1);
  611.             }
  612.         }
  613.  
  614.         /* Copy the entry. */
  615.         names[i - 1] = (ENTRY *)malloc(DIRSIZ(E));
  616.         if (names[i - 1] == (ENTRY *) NULL) {
  617.             closedir(Dp);
  618.             return(-1);
  619.         }
  620.         names[i - 1]->d_ino = E->d_ino;
  621.         names[i - 1]->d_reclen = E->d_reclen;
  622.         names[i - 1]->d_namlen = E->d_namlen;
  623.         (void)strcpy(names[i - 1]->d_name, E->d_name);
  624.     }
  625.  
  626.     /* Close things off. */
  627.     names[i] = (ENTRY *)NULL;
  628.     *list = names;
  629.     closedir(Dp);
  630.  
  631.     /* Sort? */
  632.     if (i && sorter)
  633.         qsort((char *)names, i, sizeof names[0], sorter);
  634.  
  635.     return(i);
  636. }
  637. #endif
  638.  
  639. #ifdef XENIX
  640. /*
  641.  * 4.2BSD mkdir simulation from cnews
  642.  */
  643.  
  644. /* system call returns */
  645. #define SYS_OK 0
  646. #define SYS_ERR (-1)
  647.  
  648. #define UMASK_MASK 0777
  649.  
  650. #define STRLEN(s) (sizeof (s) - 1)        /* s must be a char array */
  651.  
  652. int
  653. mkdir(dir, mode)
  654. char *dir;
  655. int mode;
  656. {
  657.     char *cbuf = malloc((unsigned)STRLEN("mkdir ") + strlen(dir) + 1);
  658.     register int oldmask, ret;
  659.  
  660.     if (cbuf == NULL) {
  661.         errno = ENOMEM;            /* kludge */
  662.         return SYS_ERR;
  663.     }
  664.     oldmask = umask(0);
  665.     (void) umask(~(mode & ~oldmask) & UMASK_MASK);
  666.  
  667.     (void) sprintf(cbuf, "mkdir %s", dir);
  668.     ret = (system(cbuf) != 0? SYS_ERR: SYS_OK);
  669.     if (ret == SYS_ERR)
  670.         errno = EINVAL;            /* kludge */
  671.  
  672.     (void) umask(oldmask);
  673.     free(cbuf);
  674.     return ret;
  675. }
  676. #endif
  677.