home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- *******************************************************************************
-
- Site: Western Michigan University Academic Computer Center
-
- System: Directory/File System Maintenance
-
- Program: maint
-
- Version=01 Level=00 01/24/92 Leonard J. Peirce
-
- Purpose: Execute the commands in a directory, informing the user of
- the result of each.
-
- Arguments: See individual routines
-
- External variables: See individual routines
-
- Maint external functions:
-
- Defined: xecute
-
- Called: free_comstr, mystrcpy
-
- Files accessed: Files with commands associated with them
-
- Return codes: See individual routines
-
- Compiling instructions: See Makefile
-
- Linking instructions: See Makefile
-
- Other information: (C) Copyright 1990, Leonard J. Peirce
-
- ********************************************************************************
- *******************************************************************************/
-
- /******************************************************************************/
- /* */
- /* # I N C L U D E F I L E S */
- /* */
- /******************************************************************************/
-
- #include <fcntl.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- #ifdef ultrix
- #include <cursesX.h>
- #else
- #include <curses.h>
- #endif
- #include "maint.h"
- #include <sys/stat.h>
-
- /******************************************************************************/
- /* */
- /* # D E F I N E S */
- /* */
- /******************************************************************************/
-
- #define XMESS_PAUSE 4 /* length of pause for error messages */
-
- /******************************************************************************/
- /* */
- /* S T R U C T U R E S , U N I O N S , T Y P E D E F S */
- /* */
- /******************************************************************************/
-
- /******************************************************************************/
- /* */
- /* 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 */
- /* */
- /******************************************************************************/
-
- extern char *mystrcpy();
-
- extern int unlink(),
- chmod(),
- rename(),
- read(),
- write(),
- open(),
- close(),
- errno;
-
- extern void free_comstr();
-
- void xecute();
-
- /******************************************************************************/
- /* */
- /* 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 */
- /* */
- /******************************************************************************/
-
- static char *make_err_msg();
-
- static int write_text(),
- copy_file(),
- rename_file();
-
- static void make_xmess();
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: xecute
-
- Purpose: Execute all of the file commands for the current directory.
- Display success and failure messages to the screen for each
- of the files.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- none
-
- Return Codes:
-
- Code Reason
- ---- ------
- none
-
- ********************************************************************************
- *******************************************************************************/
-
- void xecute(ent,dir_text,num_file)
- /******* FORMAL PARAMETERS *******/
- ENT_DEF *ent; /* file entry pointer */
- char *dir_text; /* pointer to directory text descrip. */
- short num_file; /* number of files in directory */
-
- { /*** xecute ***/
- /******** LOCAL VARIABLES ********/
- int status, /* return code status holder */
- prefix_len, /* length of message prefix string */
- text_write; /* set to FAILURE if write_text fails */
- register COM_DEF *comm_ptr; /* pointer to command structure */
- short i; /* loop and array index */
- char buf[SPEC_MAX*2+10]; /* for formatting messages */
-
-
- text_write = SUCCESS; /* assume it will work */
- i = 0;
-
- while(i < num_file)
- {
- if(ent->command != NULL) /* does this file have any commands? */
- {
- comm_ptr = ent->command; /* get a pointer to the comm struct */
-
- if(comm_ptr->comm_copy)
- {
- status = copy_file(ent->filename,comm_ptr->copy_name);
- make_xmess(buf,ent->filename,&prefix_len,status,COPY,ent->type);
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE); /* let user read error message */
- }
-
- errno = 0;
- }
-
- if(comm_ptr->comm_ren)
- {
- status = rename_file(ent->filename,comm_ptr->ren_name);
- make_xmess(buf,ent->filename,&prefix_len,status,RENAME,ent->type);
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE);
- }
-
- errno = 0;
- }
-
- if(comm_ptr->comm_prot)
- {
- if(chmod(ent->filename,(int) comm_ptr->prot) == 0)
- status = SUCCESS;
- else
- status = FAILURE;
-
- make_xmess(buf,ent->filename,&prefix_len,status,RENAME,ent->type);
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE);
- }
-
- errno = 0;
- }
-
- if(comm_ptr->comm_own)
- {
- if(chown(ent->filename,comm_ptr->owner,-1) == 0)
- status = SUCCESS;
- else
- status = FAILURE;
-
- make_xmess(buf,ent->filename,&prefix_len,status,OWNER,ent->type);
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE);
- }
-
- errno = 0;
- }
-
- if(comm_ptr->comm_grp)
- {
- if(chown(ent->filename,-1,comm_ptr->group) == 0)
- status = SUCCESS;
- else
- status = FAILURE;
-
- make_xmess(buf,ent->filename,&prefix_len,status,GROUP,ent->type);
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE);
- }
-
- errno = 0;
- }
-
- if(comm_ptr->comm_text != NULL && text_write == SUCCESS)
- {
- /* yes, write a text descriptor */
-
- text_write = write_text(ent->filename,comm_ptr->text,
- dir_text,FALSE);
-
- ent->text = NULL; /* no more text descriptor */
- }
-
- if(comm_ptr->comm_del)
- {
- if(ent->type != DIRECTORY)
- {
- /* nothing special, just use unlink */
-
- if(unlink(ent->filename) == 0)
- status = SUCCESS;
- else
- status = FAILURE;
-
- make_xmess(buf,ent->filename,&prefix_len,status,DELETE,
- ent->type);
- }
- else
- {
- if(rmdir(ent->filename) == 0)
- status = SUCCESS;
- else
- status = FAILURE;
-
- make_xmess(buf,ent->filename,&prefix_len,status,DELETE,
- ent->type);
- }
-
- xmess(buf,prefix_len);
-
- if(status != SUCCESS)
- {
- beep();
- sleep(XMESS_PAUSE);
- }
-
- ent->text = NULL; /* no more text descriptor */
- errno = 0;
- }
-
- free_comstr(ent->command); /* free the command structure */
- ent->command = NULL;
- }
-
- if(ent->text != NULL && text_write == SUCCESS)
- {
- /* yes, write a text descriptor */
-
- text_write = write_text(ent->filename,ent->text,dir_text,FALSE);
- }
-
- ++ent;
- ++i;
- }
-
- text_write = write_text(NULLPTR,NULLPTR,NULLPTR,TRUE);
- return;
-
- } /*** xecute ***/
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: copy_file
-
- Purpose: Copy the source file to the destination file.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- none
-
- Return Codes:
-
- Code Reason
- ---- ------
- SUCCESS
- CANT_STAT cannot stat source file
- CANT_OPEN cannot open source file
- CANT_OPEN_DEST cannot open destination file
- CANT_WRITE error writing to destination file
- CANT_CHMOD cannot do a chmod() on file
-
- ********************************************************************************
- *******************************************************************************/
-
- static int copy_file(source,dest)
- /******* FORMAL PARAMETERS *******/
- char *source, /* file to copy from */
- *dest; /* file to copy to */
-
- { /*** copy_file ***/
- /******** LOCAL VARIABLES ********/
- struct stat statbuf; /* for stat on source file */
- char buf[BUFSIZ+5]; /* read/write buffer */
- int numbyte, /* bytes read/written */
- badwrite, /* loop control variable */
- inputfd, /* input file descriptor */
- outputfd; /* output file descriptor */
-
-
- if(stat(source,&statbuf) < 0)
- return(CANT_STAT);
-
- if((inputfd = open(source,O_RDONLY,0)) < 0)
- return(CANT_OPEN);
-
- /* see if the destination is a directory; if it is, we have some work to
- * do to create the destination filename
- */
-
- if(stat(dest,&statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR))
- {
- /* it is a directory; cat the source name onto the destination name */
-
- strcat(dest,"/");
- strcat(dest,source);
- }
-
- if((outputfd = open(dest,O_WRONLY | O_TRUNC | O_CREAT,0)) < 0)
- {
- close(inputfd);
- return(CANT_OPEN_DEST);
- }
-
- numbyte = read(inputfd,buf,BUFSIZ);
- badwrite = FALSE;
-
- while(numbyte > 0 && !badwrite)
- {
- if((write(outputfd,buf,numbyte)) == -1)
- badwrite = TRUE;
- else
- numbyte = read(inputfd,buf,BUFSIZ);
- }
-
- close(inputfd);
- close(outputfd);
-
- if(badwrite) /* did it work? */
- {
- unlink(dest); /* nope, get rid of destination file */
- return(CANT_WRITE);
- }
-
- /* make sure the destination file has the same mode as the source */
-
- if(chmod(dest,(int) statbuf.st_mode) != 0)
- return(CANT_CHMOD);
-
- return(SUCCESS);
-
- } /*** copy_file ***/
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: rename_file
-
- Purpose: Rename the source file to the destination file.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- none
-
- Return Codes:
-
- Code Reason
- ---- ------
- SUCCESS
- FAILURE
- CANT_STAT cannot stat destination file
-
- ********************************************************************************
- *******************************************************************************/
-
- static int rename_file(source,dest)
- /******* FORMAL PARAMETERS *******/
- char *source, /* file to be renamed */
- *dest; /* file to rename to */
-
- { /*** rename_file ***/
- /******** LOCAL VARIABLES ********/
- struct stat statbuf; /* for stat on source file */
-
-
- /* see if the destination is a directory; if it is, we have some work to
- * do to create the destination filename
- */
-
- if(stat(dest,&statbuf) == 0 && ((statbuf.st_mode & S_IFMT) == S_IFDIR))
- {
- /* it is a directory; cat the source name onto the destination name */
-
- strcat(dest,"/");
- strcat(dest,source);
- }
-
- if(rename(source,dest) != 0)
- return(FAILURE);
-
- return(SUCCESS);
-
- } /*** rename_file ***/
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: make_xmess
-
- Purpose: Create a message for the xecute() routine by looking at
- what is being performed and the status code. First, the
- action is determined to get the correct string. Then, the
- correct result string is determined, based on the action
- type. If an error occurred, errno is examined to see if an
- intelligent error message can be constructed from it's value.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- COLS X
-
- Return Codes:
-
- Code Reason
- ---- ------
- none
-
- ********************************************************************************
- *******************************************************************************/
-
- static void make_xmess(buf,filename,prefix_len,status,action,type)
- /******* FORMAL PARAMETERS *******/
- char *buf, /* where to put the message */
- *filename; /* file being operated on */
- int *prefix_len, /* length of message prefix string */
- status; /* status code to check */
- u_char action, /* what is happening */
- type; /* type of file being acted upon */
-
- { /*** make_xmess ***/
- /******** LOCAL VARIABLES ********/
- char *msg_ptr, /* pointer to action type message */
- *error_ptr, /* pointer to errno message */
- *result_ptr; /* pointer to result message */
- int msg_len; /* length of action message part */
- static char delete_msg[] = {"Delete "},
- copy_msg[] = {"Copy "},
- rename_msg[] = {"Rename "},
- protect_msg[] = {"Protect "},
- text_msg[] = {"Text "},
- owner_msg[] = {"Change owner "},
- group_msg[] = {"Change group "},
- ok_msg[] = {"? [OK]"},
- error_msg[] = {"? *ERROR*"},
- null_msg[] = {""};
-
-
- error_ptr = null_msg; /* Suns don't like NULL too well.... */
-
- switch(action) /* what are we doing? */
- {
- case(DELETE):
- msg_ptr = delete_msg;
- msg_len = sizeof(delete_msg);
- break;
- case(COPY):
- msg_ptr = copy_msg;
- msg_len = sizeof(copy_msg);
- break;
- case(RENAME):
- msg_ptr = rename_msg;
- msg_len = sizeof(rename_msg);
- break;
- case(PROTECT):
- msg_ptr = protect_msg;
- msg_len = sizeof(protect_msg);
- break;
- case(GROUP):
- msg_ptr = group_msg;
- msg_len = sizeof(group_msg);
- break;
- case(OWNER):
- msg_ptr = owner_msg;
- msg_len = sizeof(owner_msg);
- break;
- case(TEXT):
- msg_ptr = text_msg;
- msg_len = sizeof(text_msg);
- break;
- default:
- break; /* should NEVER get here.... */
- }
-
- if(status == SUCCESS)
- {
- /* the action worked; creating the message will be easy here */
-
- result_ptr = ok_msg;
- }
- else if(status == FAILURE)
- {
- result_ptr = error_msg;
-
- /* make an explicit error message if possible */
-
- error_ptr = make_err_msg(status,action,type);
- }
- else
- {
- result_ptr = error_msg;
- }
-
- /* construct the message */
-
- sprintf(buf,"%s%s%s%s",msg_ptr,filename,result_ptr,error_ptr);
- *prefix_len = msg_len;
- return;
-
- } /*** make_xmess ***/
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: write_text
-
- Purpose: Inverted coroutine (to xecute()) to write text descriptor
- records to the text descriptor fioel. A record of length
- zero signifies that the entry is to be deleted.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- none
-
- Return Codes:
-
- Code Reason
- ---- ------
- SUCCESS
- FAILURE
-
- ********************************************************************************
- *******************************************************************************/
-
- static int write_text(filename,text,dir_text,eof_flag)
- /******* FORMAL PARAMETERS *******/
- char *filename, /* filename that has a text descrip */
- *text, /* text descriptor */
- *dir_text; /* directory text descriptor */
- u_char eof_flag; /* set if we're done */
-
- { /*** write_text ***/
- /******** LOCAL VARIABLES ********/
- static FILE *fptr; /* pointer to text descriptor file */
- static u_char state, /* state variable */
- file_open; /* set if file has been opened */
-
-
- /* special case where an attempt is made to close the file when nothing
- * had been written to it
- */
-
- if(eof_flag == TRUE && !file_open)
- {
- state = 0;
- return(SUCCESS);
- }
-
- if(state == 1)
- goto lab0;
-
- fptr = fopen(TEXT_FILE,"w");
-
- if(fptr == NULL)
- return(FALSE);
-
- /* write the directory text descriptor record */
-
- fprintf(fptr,">>>%s\n",dir_text);
- fputs(">\n",fptr);
-
- state = 1;
- file_open = 1;
-
- while(eof_flag == FALSE)
- {
- if(text != NULL) /* NULL descriptor means delete it */
- fprintf(fptr,"%s %s\n",filename,text);
-
- return(SUCCESS); /* coroutine "read" */
-
- lab0: ; /* this is where we return */
- }
-
- state = 0;
- file_open = 0;
- fclose(fptr);
-
- return(SUCCESS);
-
- } /*** write_text ***/
-
- /*******************************************************************************
- ********************************************************************************
-
- Function: make_err_msg
-
- Purpose: Try to make an intelligent error message based on an action
- and the value of errno.
-
- Global variables:
-
- Name Examine/Modify/Use/Read/Write
- ---- -----------------------------
- errno X
-
- Return Codes:
-
- Code Reason
- ---- ------
- retptr pointer to message
-
- ********************************************************************************
- *******************************************************************************/
-
- static char *make_err_msg(status,action,type)
- /******* FORMAL PARAMETERS *******/
- int status; /* status from attempted operation */
- u_char action, /* what command is being done */
- type; /* type of file being acted upon */
-
- { /*** make_err_msg ***/
- /******** LOCAL VARIABLES ********/
- char *retptr = NULL; /* message to return */
-
-
- /* first see if the status can be used to create an intelligent message */
-
- if(status != FAILURE && status != SUCCESS)
- {
- /* yep, use it */
-
- switch(status)
- {
- case(CANT_STAT):
- case(CANT_OPEN):
- retptr = " Cannot open source file";
- break;
- case(CANT_OPEN_DEST):
- retptr = " Cannot open destination file";
- break;
- case(CANT_WRITE):
- retptr = " Write to destination file failed";
- break;
- case(CANT_CHMOD):
- retptr = " Cannot set protection mode on destination file";
- break;
- default:
- break;
- }
-
- return(retptr);
- }
-
- /* nope, the status was no good to use; check the action and errno */
-
- switch(action)
- {
- case(RENAME):
-
- switch(errno)
- {
- case(ENOENT):
- retptr = " Invalid destination specificiation";
- break;
- case(EACCES):
- retptr = " Cannot open destination file";
- break;
- case(EPERM):
- retptr = " Destination file exists";
- break;
- case(EXDEV):
- retptr = " Destination file is on a different device";
- break;
- case(EROFS):
- retptr = " Destination directory is in a read-only filesystem";
- break;
- #if !defined(SYSV) || defined(sun)
- case(ELOOP):
- retptr = " Too many symbolic links in filename";
- break;
- case(EDQUOT):
- retptr = " Disk quota exhausted";
- break;
- #endif
- case(ENOSPC):
- retptr = " File system is full";
- break;
- default:
- break;
- }
-
- break;
-
- case(COPY):
-
- switch(errno)
- {
- case(EACCES):
- retptr = " Cannot open destination file";
- break;
- case(EIO):
- retptr = " I/O error";
- break;
- #if !defined(SYSV) || defined(sun)
- case(ELOOP):
- retptr = " Too many symbolic links in filename";
- break;
- case(EDQUOT):
- retptr = " Disk quota exhausted";
- break;
- #endif
- case(ENOENT):
- retptr = " Invalid destination specificiation";
- break;
- case(ENOSPC):
- retptr = " File system is full";
- break;
- default:
- break;
- }
-
- break;
-
- case(PROTECT):
-
- switch(errno)
- {
- case(EACCES):
- retptr = " Protection violation";
- break;
- case(EIO):
- retptr = " I/O error";
- break;
- case(ENOENT):
- retptr = " File does not exist";
- break;
- case(EPERM):
- retptr = " Not owner of file";
- break;
- case(EROFS):
- retptr = " File resides in a read-only filesystem";
- break;
- default:
- break;
- }
-
- break;
-
- case(DELETE):
-
- if(type != DIRECTORY)
- {
- switch(errno)
- {
- case(ENOENT):
- retptr = " File does not exist";
- break;
- case(EACCES):
- retptr = " Protection violation";
- break;
- case(EPERM):
- retptr = " Permission denied (mount point or not owner)";
- break;
- case(EIO):
- retptr = " I/O error";
- break;
- default:
- break;
- }
- }
- else
- {
- /* trying to delete a directory with rmdir */
-
- switch(errno)
- {
- #if !defined(SYSV) || defined(sun)
- case(ENOTEMPTY):
- retptr = " Directory is not empty";
- break;
- #endif
- case(EPERM):
- retptr = " Not owner";
- break;
- case(EBUSY):
- retptr = " Mount point for a mounted file system";
- break;
- case(EIO):
- retptr = " I/O error";
- break;
- default:
- break;
- }
- }
-
- break;
-
- case(OWNER):
- case(GROUP):
-
- switch(errno)
- {
- case(ENOENT):
- retptr = " File does not exist";
- break;
- case(EPERM):
- retptr = " Must be superuser";
- break;
- case(EROFS):
- retptr = " File resides in a read-only filesystem";
- break;
- default:
- break;
- }
-
- break;
-
- default:
-
- break;
- }
-
- return(retptr);
-
- } /*** make_err_msg ***/
-