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