home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume26 / maint / part03 / xecute.c < prev   
C/C++ Source or Header  |  1992-05-13  |  22KB  |  890 lines

  1. /******************************************************************************
  2. *******************************************************************************
  3.  
  4.    Site:    Western Michigan University Academic Computer Center
  5.  
  6.    System:    Directory/File System Maintenance
  7.   
  8.    Program:    maint
  9.  
  10.    Version=01    Level=00    01/24/92    Leonard J. Peirce
  11.  
  12.    Purpose:    Execute the commands in a directory, informing the user of
  13.         the result of each.
  14.  
  15.    Arguments:    See individual routines
  16.  
  17.    External variables:    See individual routines
  18.  
  19.    Maint external functions:
  20.  
  21.     Defined:    xecute
  22.  
  23.     Called:        free_comstr, mystrcpy
  24.  
  25.    Files accessed:    Files with commands associated with them
  26.  
  27.    Return codes:    See individual routines
  28.  
  29.    Compiling instructions:    See Makefile
  30.  
  31.    Linking instructions:    See Makefile
  32.  
  33.    Other information:    (C) Copyright 1990, Leonard J. Peirce
  34.  
  35. ********************************************************************************
  36. *******************************************************************************/
  37.  
  38. /******************************************************************************/
  39. /*                                                                            */
  40. /*                        # I N C L U D E   F I L E S                         */
  41. /*                                                                            */
  42. /******************************************************************************/
  43.  
  44. #include <fcntl.h>
  45. #include <errno.h>
  46. #include <stdio.h>
  47. #include <string.h>
  48. #ifdef ultrix
  49. #include <cursesX.h>
  50. #else
  51. #include <curses.h>
  52. #endif
  53. #include "maint.h"
  54. #include <sys/stat.h>
  55.  
  56. /******************************************************************************/
  57. /*                                                                            */
  58. /*                             # D E F I N E S                                */
  59. /*                                                                            */
  60. /******************************************************************************/
  61.  
  62. #define XMESS_PAUSE 4            /* length of pause for error messages */
  63.  
  64. /******************************************************************************/
  65. /*                                                                            */
  66. /*          S T R U C T U R E S ,   U N I O N S ,   T Y P E D E F S           */
  67. /*                                                                            */
  68. /******************************************************************************/
  69.  
  70. /******************************************************************************/
  71. /*                                                                            */
  72. /*   E X T E R N A L   D E F I N I T I O N S   &   D E C L A R A T I O N S    */
  73. /*                                                                            */
  74. /******************************************************************************/
  75.  
  76. extern     char      *mystrcpy();
  77.  
  78. extern     int      unlink(),
  79.           chmod(),
  80.           rename(),
  81.           read(),
  82.           write(),
  83.           open(),
  84.           close(),
  85.           errno;
  86.  
  87. extern     void      free_comstr();
  88.  
  89.      void      xecute();
  90.  
  91. /******************************************************************************/
  92. /*                                                                            */
  93. /*     S T A T I C   D E F I N I T I O N S   &   D E C L A R A T I O N S      */
  94. /*                                                                            */
  95. /******************************************************************************/
  96.  
  97. static     char      *make_err_msg();
  98.  
  99. static     int      write_text(),
  100.           copy_file(),
  101.           rename_file();
  102.  
  103. static     void      make_xmess();
  104.  
  105. /*******************************************************************************
  106. ********************************************************************************
  107.  
  108.   Function:    xecute
  109.  
  110.   Purpose:    Execute all of the file commands for the current directory.
  111.         Display success and failure messages to the screen for each
  112.         of the files.
  113.  
  114.   Global variables:
  115.  
  116.     Name            Examine/Modify/Use/Read/Write
  117.     ----            -----------------------------
  118.     none
  119.  
  120.   Return Codes:
  121.  
  122.     Code            Reason
  123.     ----            ------
  124.     none
  125.  
  126. ********************************************************************************
  127. *******************************************************************************/
  128.  
  129. void xecute(ent,dir_text,num_file)
  130.                     /*******   FORMAL  PARAMETERS   *******/
  131.      ENT_DEF  *ent;            /* file entry pointer              */
  132.      char      *dir_text;        /* pointer to directory text descrip. */
  133.      short      num_file;        /* number of files in directory          */
  134.  
  135. {    /*** xecute ***/
  136.                     /********   LOCAL  VARIABLES   ********/
  137.      int      status,        /* return code status holder          */
  138.           prefix_len,        /* length of message prefix string    */
  139.           text_write;        /* set to FAILURE if write_text fails */
  140. register COM_DEF  *comm_ptr;        /* pointer to command structure          */
  141.      short      i;            /* loop and array index              */
  142.      char      buf[SPEC_MAX*2+10];    /* for formatting messages          */
  143.  
  144.  
  145.    text_write = SUCCESS;        /* assume it will work              */
  146.    i = 0;
  147.  
  148.    while(i < num_file)
  149.    {
  150.       if(ent->command != NULL)        /* does this file have any commands?  */
  151.       {
  152.      comm_ptr = ent->command;    /* get a pointer to the comm struct   */
  153.  
  154.      if(comm_ptr->comm_copy)
  155.      {
  156.         status = copy_file(ent->filename,comm_ptr->copy_name);
  157.         make_xmess(buf,ent->filename,&prefix_len,status,COPY,ent->type);
  158.         xmess(buf,prefix_len);
  159.  
  160.         if(status != SUCCESS)
  161.         {
  162.            beep();
  163.            sleep(XMESS_PAUSE);    /* let user read error message          */
  164.         }
  165.  
  166.         errno = 0;
  167.      }
  168.  
  169.      if(comm_ptr->comm_ren)
  170.      {
  171.         status = rename_file(ent->filename,comm_ptr->ren_name);
  172.         make_xmess(buf,ent->filename,&prefix_len,status,RENAME,ent->type);
  173.         xmess(buf,prefix_len);
  174.  
  175.         if(status != SUCCESS)
  176.         {
  177.            beep();
  178.            sleep(XMESS_PAUSE);
  179.         }
  180.  
  181.         errno = 0;
  182.      }
  183.  
  184.      if(comm_ptr->comm_prot)
  185.      {
  186.         if(chmod(ent->filename,(int) comm_ptr->prot) == 0)
  187.            status = SUCCESS;
  188.         else
  189.            status = FAILURE;
  190.  
  191.         make_xmess(buf,ent->filename,&prefix_len,status,RENAME,ent->type);
  192.         xmess(buf,prefix_len);
  193.  
  194.         if(status != SUCCESS)
  195.         {
  196.            beep();
  197.            sleep(XMESS_PAUSE);
  198.         }
  199.  
  200.         errno = 0;
  201.      }
  202.  
  203.      if(comm_ptr->comm_own)
  204.      {
  205.         if(chown(ent->filename,comm_ptr->owner,-1) == 0)
  206.            status = SUCCESS;
  207.         else
  208.            status = FAILURE;
  209.  
  210.         make_xmess(buf,ent->filename,&prefix_len,status,OWNER,ent->type);
  211.         xmess(buf,prefix_len);
  212.  
  213.         if(status != SUCCESS)
  214.         {
  215.            beep();
  216.            sleep(XMESS_PAUSE);
  217.         }
  218.  
  219.         errno = 0;
  220.      }
  221.  
  222.      if(comm_ptr->comm_grp)
  223.      {
  224.         if(chown(ent->filename,-1,comm_ptr->group) == 0)
  225.            status = SUCCESS;
  226.         else
  227.            status = FAILURE;
  228.  
  229.         make_xmess(buf,ent->filename,&prefix_len,status,GROUP,ent->type);
  230.         xmess(buf,prefix_len);
  231.  
  232.         if(status != SUCCESS)
  233.         {
  234.            beep();
  235.            sleep(XMESS_PAUSE);
  236.         }
  237.  
  238.         errno = 0;
  239.      }
  240.  
  241.      if(comm_ptr->comm_text != NULL && text_write == SUCCESS)
  242.      {
  243.         /* yes, write a text descriptor */
  244.  
  245.         text_write = write_text(ent->filename,comm_ptr->text,
  246.                     dir_text,FALSE);
  247.  
  248.         ent->text = NULL;        /* no more text descriptor          */
  249.      }
  250.  
  251.      if(comm_ptr->comm_del)
  252.      {
  253.         if(ent->type != DIRECTORY)
  254.         {
  255.            /* nothing special, just use unlink */
  256.  
  257.            if(unlink(ent->filename) == 0)
  258.           status = SUCCESS;
  259.            else
  260.           status = FAILURE;
  261.  
  262.            make_xmess(buf,ent->filename,&prefix_len,status,DELETE,
  263.               ent->type);
  264.         }
  265.         else
  266.         {
  267.            if(rmdir(ent->filename) == 0)
  268.               status = SUCCESS;
  269.            else
  270.           status = FAILURE;
  271.  
  272.            make_xmess(buf,ent->filename,&prefix_len,status,DELETE,
  273.               ent->type);
  274.         }
  275.  
  276.         xmess(buf,prefix_len);
  277.  
  278.         if(status != SUCCESS)
  279.         {
  280.            beep();
  281.            sleep(XMESS_PAUSE);
  282.         }
  283.  
  284.         ent->text = NULL;        /* no more text descriptor          */
  285.         errno = 0;
  286.      }
  287.  
  288.      free_comstr(ent->command);    /* free the command structure          */
  289.      ent->command = NULL;
  290.       }
  291.  
  292.       if(ent->text != NULL && text_write == SUCCESS)
  293.       {
  294.      /* yes, write a text descriptor */
  295.  
  296.      text_write = write_text(ent->filename,ent->text,dir_text,FALSE);
  297.       }
  298.  
  299.       ++ent;
  300.       ++i;
  301.    }
  302.  
  303.    text_write = write_text(NULLPTR,NULLPTR,NULLPTR,TRUE);
  304.    return;
  305.  
  306. }    /*** xecute ***/     
  307.  
  308. /*******************************************************************************
  309. ********************************************************************************
  310.  
  311.   Function:    copy_file
  312.  
  313.   Purpose:    Copy the source file to the destination file.
  314.  
  315.   Global variables:
  316.  
  317.     Name            Examine/Modify/Use/Read/Write
  318.     ----            -----------------------------
  319.     none
  320.  
  321.   Return Codes:
  322.  
  323.     Code            Reason
  324.     ----            ------
  325.     SUCCESS
  326.     CANT_STAT        cannot stat source file
  327.     CANT_OPEN        cannot open source file
  328.     CANT_OPEN_DEST        cannot open destination file
  329.     CANT_WRITE        error writing to destination file
  330.     CANT_CHMOD        cannot do a chmod() on file
  331.  
  332. ********************************************************************************
  333. *******************************************************************************/
  334.  
  335. static int copy_file(source,dest)
  336.                     /*******   FORMAL  PARAMETERS   *******/
  337.      char      *source,        /* file to copy from              */
  338.           *dest;        /* file to copy to              */
  339.  
  340. {    /*** copy_file ***/
  341.                     /********   LOCAL  VARIABLES   ********/
  342. struct     stat      statbuf;        /* for stat on source file          */
  343.      char      buf[BUFSIZ+5];    /* read/write buffer              */
  344.      int      numbyte,        /* bytes read/written              */
  345.           badwrite,        /* loop control variable          */
  346.           inputfd,        /* input file descriptor          */
  347.           outputfd;        /* output file descriptor          */
  348.  
  349.  
  350.    if(stat(source,&statbuf) < 0)
  351.       return(CANT_STAT);
  352.  
  353.    if((inputfd = open(source,O_RDONLY,0)) < 0)
  354.       return(CANT_OPEN);
  355.  
  356.    /* see if the destination is a directory; if it is, we have some work to
  357.     * do to create the destination filename
  358.     */
  359.  
  360.    if(stat(dest,&statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR))
  361.    {
  362.       /* it is a directory; cat the source name onto the destination name */
  363.  
  364.       strcat(dest,"/");
  365.       strcat(dest,source);
  366.    }
  367.  
  368.    if((outputfd = open(dest,O_WRONLY | O_TRUNC | O_CREAT,0)) < 0)
  369.    {
  370.       close(inputfd);
  371.       return(CANT_OPEN_DEST);
  372.    }
  373.  
  374.    numbyte = read(inputfd,buf,BUFSIZ);
  375.    badwrite = FALSE;
  376.  
  377.    while(numbyte > 0 && !badwrite)
  378.    {
  379.       if((write(outputfd,buf,numbyte)) == -1)
  380.      badwrite = TRUE;
  381.       else
  382.      numbyte = read(inputfd,buf,BUFSIZ);
  383.    }
  384.  
  385.    close(inputfd);
  386.    close(outputfd);
  387.  
  388.    if(badwrite)                /* did it work?                  */
  389.    {
  390.       unlink(dest);            /* nope, get rid of destination file  */
  391.       return(CANT_WRITE);
  392.    }
  393.  
  394.    /* make sure the destination file has the same mode as the source */
  395.  
  396.    if(chmod(dest,(int) statbuf.st_mode) != 0)
  397.       return(CANT_CHMOD);
  398.  
  399.    return(SUCCESS);
  400.  
  401. }    /*** copy_file ***/
  402.  
  403. /*******************************************************************************
  404. ********************************************************************************
  405.  
  406.   Function:    rename_file
  407.  
  408.   Purpose:    Rename the source file to the destination file.
  409.  
  410.   Global variables:
  411.  
  412.     Name            Examine/Modify/Use/Read/Write
  413.     ----            -----------------------------
  414.     none
  415.  
  416.   Return Codes:
  417.  
  418.     Code            Reason
  419.     ----            ------
  420.     SUCCESS
  421.     FAILURE
  422.     CANT_STAT        cannot stat destination file
  423.  
  424. ********************************************************************************
  425. *******************************************************************************/
  426.  
  427. static int rename_file(source,dest)
  428.                     /*******   FORMAL  PARAMETERS   *******/
  429.      char      *source,        /* file to be renamed              */
  430.           *dest;        /* file to rename to              */
  431.  
  432. {    /*** rename_file ***/
  433.                     /********   LOCAL  VARIABLES   ********/
  434. struct     stat      statbuf;        /* for stat on source file          */
  435.  
  436.  
  437.    /* see if the destination is a directory; if it is, we have some work to
  438.     * do to create the destination filename
  439.     */
  440.  
  441.    if(stat(dest,&statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR))
  442.    {
  443.       /* it is a directory; cat the source name onto the destination name */
  444.  
  445.       strcat(dest,"/");
  446.       strcat(dest,source);
  447.    }
  448.  
  449.    if(rename(source,dest) != 0)
  450.       return(FAILURE);
  451.  
  452.    return(SUCCESS);
  453.  
  454. }    /*** rename_file ***/
  455.  
  456. /*******************************************************************************
  457. ********************************************************************************
  458.  
  459.   Function:    make_xmess
  460.  
  461.   Purpose:    Create a message for the xecute() routine by looking at
  462.         what is being performed and the status code.  First, the
  463.         action is determined to get the correct string.  Then, the
  464.         correct result string is determined, based on the action
  465.         type.  If an error occurred, errno is examined to see if an
  466.         intelligent error message can be constructed from it's value.
  467.  
  468.   Global variables:
  469.  
  470.     Name            Examine/Modify/Use/Read/Write
  471.     ----            -----------------------------
  472.     COLS               X
  473.  
  474.   Return Codes:
  475.  
  476.     Code            Reason
  477.     ----            ------
  478.     none
  479.  
  480. ********************************************************************************
  481. *******************************************************************************/
  482.  
  483. static void make_xmess(buf,filename,prefix_len,status,action,type)
  484.                     /*******   FORMAL  PARAMETERS   *******/
  485.      char      *buf,            /* where to put the message          */
  486.           *filename;        /* file being operated on          */
  487.      int      *prefix_len,        /* length of message prefix string    */
  488.           status;        /* status code to check              */
  489.      u_char      action,        /* what is happening              */
  490.           type;            /* type of file being acted upon      */
  491.  
  492. {    /*** make_xmess ***/
  493.                     /********   LOCAL  VARIABLES   ********/
  494.      char      *msg_ptr,        /* pointer to action type message     */
  495.           *error_ptr,        /* pointer to errno message          */
  496.           *result_ptr;        /* pointer to result message          */
  497.      int      msg_len;        /* length of action message part      */
  498. static     char      delete_msg[] = {"Delete "},
  499.           copy_msg[] = {"Copy "},
  500.           rename_msg[] = {"Rename "},
  501.           protect_msg[] = {"Protect "},
  502.           text_msg[] = {"Text "},
  503.           owner_msg[] = {"Change owner "},
  504.           group_msg[] = {"Change group "},
  505.           ok_msg[] = {"? [OK]"},
  506.           error_msg[] = {"? *ERROR*"},
  507.           null_msg[] = {""};
  508.  
  509.  
  510.    error_ptr = null_msg;        /* Suns don't like NULL too well....  */
  511.  
  512.    switch(action)            /* what are we doing?              */
  513.    {
  514.       case(DELETE):
  515.      msg_ptr = delete_msg;
  516.      msg_len = sizeof(delete_msg);
  517.      break;
  518.       case(COPY):
  519.      msg_ptr = copy_msg;
  520.      msg_len = sizeof(copy_msg);
  521.      break;
  522.       case(RENAME):
  523.      msg_ptr = rename_msg;
  524.      msg_len = sizeof(rename_msg);
  525.      break;
  526.       case(PROTECT):
  527.      msg_ptr = protect_msg;
  528.      msg_len = sizeof(protect_msg);
  529.      break;
  530.       case(GROUP):
  531.      msg_ptr = group_msg;
  532.      msg_len = sizeof(group_msg);
  533.      break;
  534.       case(OWNER):
  535.      msg_ptr = owner_msg;
  536.      msg_len = sizeof(owner_msg);
  537.      break;
  538.       case(TEXT):
  539.      msg_ptr = text_msg;
  540.      msg_len = sizeof(text_msg);
  541.      break;
  542.       default:
  543.      break;                /* should NEVER get here....          */
  544.    }
  545.  
  546.    if(status == SUCCESS)
  547.    {
  548.       /* the action worked; creating the message will be easy here */
  549.  
  550.       result_ptr = ok_msg;
  551.    }
  552.    else if(status == FAILURE)
  553.    {
  554.       result_ptr = error_msg;
  555.  
  556.       /* make an explicit error message if possible */
  557.  
  558.       error_ptr = make_err_msg(status,action,type);
  559.    }
  560.    else
  561.    {
  562.       result_ptr = error_msg;
  563.    }
  564.  
  565.    /* construct the message */
  566.  
  567.    sprintf(buf,"%s%s%s%s",msg_ptr,filename,result_ptr,error_ptr);
  568.    *prefix_len = msg_len;
  569.    return;
  570.  
  571. }    /*** make_xmess ***/
  572.  
  573. /*******************************************************************************
  574. ********************************************************************************
  575.  
  576.   Function:    write_text
  577.  
  578.   Purpose:    Inverted coroutine (to xecute()) to write text descriptor
  579.         records to the text descriptor fioel.  A record of length
  580.         zero signifies that the entry is to be deleted.
  581.  
  582.   Global variables:
  583.  
  584.     Name            Examine/Modify/Use/Read/Write
  585.     ----            -----------------------------
  586.     none
  587.  
  588.   Return Codes:
  589.  
  590.     Code            Reason
  591.     ----            ------
  592.     SUCCESS
  593.     FAILURE
  594.  
  595. ********************************************************************************
  596. *******************************************************************************/
  597.  
  598. static int write_text(filename,text,dir_text,eof_flag)
  599.                     /*******   FORMAL  PARAMETERS   *******/
  600.      char      *filename,        /* filename that has a text descrip   */
  601.           *text,        /* text descriptor              */
  602.           *dir_text;        /* directory text descriptor          */
  603.      u_char      eof_flag;        /* set if we're done              */
  604.  
  605. {    /*** write_text ***/
  606.                     /********   LOCAL  VARIABLES   ********/
  607. static     FILE      *fptr;        /* pointer to text descriptor file    */
  608. static     u_char      state,        /* state variable              */
  609.           file_open;        /* set if file has been opened          */
  610.  
  611.  
  612.    /* special case where an attempt is made to close the file when nothing
  613.     * had been written to it
  614.     */
  615.  
  616.    if(eof_flag == TRUE && !file_open)
  617.    {
  618.       state = 0;
  619.       return(SUCCESS);
  620.    }
  621.  
  622.    if(state == 1)
  623.       goto lab0;
  624.  
  625.    fptr = fopen(TEXT_FILE,"w");
  626.  
  627.    if(fptr == NULL)
  628.       return(FALSE);
  629.  
  630.    /* write the directory text descriptor record */
  631.  
  632.    fprintf(fptr,">>>%s\n",dir_text);
  633.    fputs(">\n",fptr);
  634.  
  635.    state = 1;
  636.    file_open = 1;
  637.  
  638.    while(eof_flag == FALSE)
  639.    {
  640.       if(text != NULL)            /* NULL descriptor means delete it    */
  641.          fprintf(fptr,"%s %s\n",filename,text);
  642.  
  643.       return(SUCCESS);            /* coroutine "read"              */
  644.  
  645. lab0: ;                    /* this is where we return          */
  646.    }
  647.  
  648.    state = 0;
  649.    file_open = 0;
  650.    fclose(fptr);
  651.  
  652.    return(SUCCESS);
  653.  
  654. }    /*** write_text ***/
  655.  
  656. /*******************************************************************************
  657. ********************************************************************************
  658.  
  659.   Function:    make_err_msg
  660.  
  661.   Purpose:    Try to make an intelligent error message based on an action
  662.         and the value of errno.
  663.  
  664.   Global variables:
  665.  
  666.     Name            Examine/Modify/Use/Read/Write
  667.     ----            -----------------------------
  668.     errno               X
  669.  
  670.   Return Codes:
  671.  
  672.     Code            Reason
  673.     ----            ------
  674.     retptr            pointer to message
  675.  
  676. ********************************************************************************
  677. *******************************************************************************/
  678.  
  679. static char *make_err_msg(status,action,type)
  680.                     /*******   FORMAL  PARAMETERS   *******/
  681.      int      status;        /* status from attempted operation    */
  682.      u_char      action,        /* what command is being done          */
  683.           type;            /* type of file being acted upon      */
  684.  
  685. {    /*** make_err_msg ***/
  686.                     /********   LOCAL  VARIABLES   ********/
  687.      char      *retptr = NULL;    /* message to return              */
  688.  
  689.  
  690.    /* first see if the status can be used to create an intelligent message */
  691.  
  692.    if(status != FAILURE && status != SUCCESS)
  693.    {
  694.       /* yep, use it */
  695.  
  696.       switch(status)
  697.       {
  698.      case(CANT_STAT):
  699.      case(CANT_OPEN):
  700.         retptr = " Cannot open source file";
  701.         break;
  702.      case(CANT_OPEN_DEST):
  703.         retptr = " Cannot open destination file";
  704.         break;
  705.      case(CANT_WRITE):
  706.         retptr = " Write to destination file failed";
  707.         break;
  708.      case(CANT_CHMOD):
  709.         retptr = " Cannot set protection mode on destination file";
  710.         break;
  711.      default:
  712.         break;
  713.       }
  714.  
  715.       return(retptr);
  716.    }
  717.  
  718.    /* nope, the status was no good to use; check the action and errno */
  719.  
  720.    switch(action)
  721.    {
  722.       case(RENAME):
  723.  
  724.      switch(errno)
  725.      {
  726.         case(ENOENT):
  727.            retptr = " Invalid destination specificiation";
  728.            break;
  729.         case(EACCES):
  730.            retptr = " Cannot open destination file";
  731.            break;
  732.         case(EPERM):
  733.            retptr = " Destination file exists";
  734.            break;
  735.         case(EXDEV):
  736.            retptr = " Destination file is on a different device";
  737.            break;
  738.           case(EROFS):
  739.            retptr = " Destination directory is in a read-only filesystem";
  740.            break;
  741. #if !defined(SYSV) || defined(sun)
  742.         case(ELOOP):
  743.            retptr = " Too many symbolic links in filename";
  744.            break;
  745.         case(EDQUOT):
  746.            retptr = " Disk quota exhausted";
  747.            break;
  748. #endif
  749.         case(ENOSPC):
  750.            retptr = " File system is full";
  751.            break;
  752.         default:
  753.            break; 
  754.      }
  755.  
  756.      break;
  757.  
  758.       case(COPY):
  759.  
  760.      switch(errno)
  761.      {
  762.         case(EACCES):
  763.            retptr = " Cannot open destination file";
  764.            break;
  765.         case(EIO):
  766.            retptr = " I/O error";
  767.            break;
  768. #if !defined(SYSV) || defined(sun)
  769.         case(ELOOP):
  770.            retptr = " Too many symbolic links in filename";
  771.            break;
  772.         case(EDQUOT):
  773.            retptr = " Disk quota exhausted";
  774.            break;
  775. #endif
  776.         case(ENOENT):
  777.            retptr = " Invalid destination specificiation";
  778.            break;
  779.         case(ENOSPC):
  780.            retptr = " File system is full";
  781.            break;
  782.         default:
  783.            break;
  784.      }
  785.  
  786.      break;
  787.  
  788.       case(PROTECT):
  789.  
  790.      switch(errno)
  791.      {
  792.         case(EACCES):
  793.            retptr = " Protection violation";
  794.            break;
  795.         case(EIO):
  796.            retptr = " I/O error";
  797.            break;
  798.         case(ENOENT):
  799.            retptr = " File does not exist";
  800.            break;
  801.         case(EPERM):
  802.            retptr = " Not owner of file";
  803.            break;
  804.         case(EROFS):
  805.            retptr = " File resides in a read-only filesystem";
  806.            break;
  807.         default:
  808.            break;
  809.      }
  810.  
  811.      break;
  812.  
  813.       case(DELETE):
  814.  
  815.      if(type != DIRECTORY)
  816.      {
  817.         switch(errno)
  818.         {
  819.            case(ENOENT):
  820.           retptr = " File does not exist";
  821.           break;
  822.            case(EACCES):
  823.           retptr = " Protection violation";
  824.           break;
  825.            case(EPERM):
  826.           retptr = " Permission denied (mount point or not owner)";
  827.           break;
  828.            case(EIO):
  829.           retptr = " I/O error";
  830.           break;
  831.            default:
  832.           break;
  833.         }
  834.      }
  835.      else
  836.      {
  837.         /* trying to delete a directory with rmdir */
  838.  
  839.         switch(errno)
  840.         {
  841. #if !defined(SYSV) || defined(sun)
  842.            case(ENOTEMPTY):
  843.           retptr = " Directory is not empty";
  844.           break;
  845. #endif
  846.            case(EPERM):
  847.           retptr = " Not owner";
  848.           break;
  849.            case(EBUSY):
  850.           retptr = " Mount point for a mounted file system";
  851.           break;
  852.            case(EIO):
  853.           retptr = " I/O error";
  854.           break;
  855.            default:
  856.           break;
  857.         }
  858.      }
  859.  
  860.      break;
  861.  
  862.       case(OWNER):
  863.       case(GROUP):
  864.  
  865.      switch(errno)
  866.      {
  867.         case(ENOENT):
  868.            retptr = " File does not exist";
  869.            break;
  870.         case(EPERM):
  871.            retptr = " Must be superuser";
  872.            break;
  873.         case(EROFS):
  874.            retptr = " File resides in a read-only filesystem";
  875.            break;
  876.         default:
  877.            break;
  878.      }
  879.  
  880.      break;
  881.  
  882.       default:
  883.  
  884.      break;
  885.    }
  886.  
  887.    return(retptr);
  888.  
  889. }    /*** make_err_msg ***/
  890.