home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
prgramer
/
rcs
/
sources
/
set_lock.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-23
|
6KB
|
233 lines
#ifndef lint
static char rcsid[] = "$Id: set_lock.c,v 1.8 89/11/19 23:20:26 berliner Exp $";
#endif
/*
* Copyright (c) 1989, Brian Berliner
*
* You may distribute under the terms of the GNU General Public License
* as specified in the README file that comes with the CVS 1.0 kit.
*
* Set Lock
*
* Lock file support for CVS. Currently, only "update" and "commit"
* (and by extension, "checkout") adhere to this locking protocol.
* Maybe some day, others will too.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include "dir.h"
#include "cvs.h"
static char lckdir[MAXPATHLEN], lckrfl[MAXPATHLEN], lckwfl[MAXPATHLEN];
/*
* Remove the lock files (without complaining if they are not there),
* and do a quick check to see if the Entries file is missing, but
* the Entries.Backup file is there.
*/
void
Lock_Cleanup(sig)
int sig;
{
struct stat sb;
if (lckrfl[0] != '\0')
(void) unlink(lckrfl);
if (lckwfl[0] != '\0')
(void) unlink(lckwfl);
if (lckdir[0] != '\0') {
/*
* Only remove the lock directory if it is ours, note that this does
* lead to the limitation that one user ID should not be committing
* files into the same Repository directory at the same time.
* Oh well.
*/
if (stat(lckdir, &sb) != -1 && sb.st_uid == geteuid())
(void) rmdir(lckdir);
}
if (!isfile(CVSADM_ENT) && isfile(CVSADM_ENTBAK)) {
warn(0, "warning: restoring %s to %s", CVSADM_ENTBAK, CVSADM_ENT);
rename_file(CVSADM_ENTBAK, CVSADM_ENT);
}
if (sig != 0)
exit(1);
}
/*
* Create a lock file for readers (like "update" is)
*/
Reader_Lock()
{
extern char *ctime();
extern time_t time();
char *cp;
time_t now;
FILE *fp;
(void) sprintf(lckdir, "%s%c%s", Repository, DIRSEP, CVSLCK);
(void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSTFL, getpid());
(void) signal(SIGINT, Lock_Cleanup);
(void) signal(SIGTERM, Lock_Cleanup);
(void) signal(SIGBREAK, Lock_Cleanup);
if ((fp = fopen(lckrfl, "w+")) != NULL) {
(void) fclose(fp);
(void) unlink(lckrfl);
set_lock(lckdir);
(void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSRFL, getpid());
if ((fp = fopen(lckrfl, "w+")) == NULL)
warn(1, "cannot create read lock file %s", lckrfl);
else
(void) fclose(fp);
if (rmdir(lckdir) < 0)
warn(1, "failed to remove lock dir %s", lckdir);
} else {
while (isfile(lckdir)) {
struct stat sb;
(void) time(&now);
/*
* If the create time of the directory is more than CVSLCKAGE
* seconds ago, try to clean-up the lock directory, and if
* successful, we are (somewhat) free and clear.
*/
if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
if (rmdir(lckdir) != -1)
break;
}
cp = ctime(&now);
warn(0, "%s: waiting for the lock directory to go away", cp);
sleep(CVSLCKSLEEP);
}
}
}
/*
* Create a lock file for writers (like "commit" is)
*/
Writer_Lock()
{
FILE *fp;
(void) sprintf(lckdir, "%s%c%s", Repository, DIRSEP, CVSLCK);
(void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSTFL, getpid());
(void) sprintf(lckwfl, "%s%c%s%04x", Repository, DIRSEP, CVSWFL, getpid());
(void) signal(SIGINT, Lock_Cleanup);
(void) signal(SIGTERM, Lock_Cleanup);
(void) signal(SIGBREAK, Lock_Cleanup);
if ((fp = fopen(lckrfl, "w+")) == NULL)
error(1, "you have no write permission in %s", Repository);
(void) fclose(fp);
(void) unlink(lckrfl);
(void) sprintf(lckrfl, "%s%c%s%04x", Repository, DIRSEP, CVSRFL, getpid());
set_lock(lckdir);
if ((fp = fopen(lckwfl, "w+")) == NULL)
warn(1, "cannot create write lock file %s", lckwfl);
else
(void) fclose(fp);
while (readers_exist()) {
extern char *ctime();
extern time_t time();
char *cp;
time_t now;
(void) time(&now);
cp = ctime(&now);
cp[24] = ' ';
warn(0, "%s: waiting for readers to go away", cp);
sleep(CVSLCKSLEEP);
}
}
/*
* readers_exist() returns 0 if there are no reader lock files
* remaining in the repository; else 1 is returned, to indicate that the
* caller should sleep a while and try again.
*/
static
readers_exist()
{
char line[MAXLINELEN];
DIR *dirp;
struct dirent *dp;
char *cp;
int ret = 0;
again:
if ((dirp = opendir(Repository)) == NULL)
error(0, "cannot open directory %s", Repository);
(void) sprintf(line, "^%s.*", CVSRFL);
if ((cp = re_comp(line)) != NULL)
error(0, "%s", cp);
while ((dp = readdir(dirp)) != NULL) {
if (re_exec(dp->d_name)) {
struct stat sb;
long now;
(void) time(&now);
/*
* If the create time of the file is more than CVSLCKAGE
* seconds ago, try to clean-up the lock file, and if
* successful, re-open the directory and try again.
*/
(void) sprintf(line, "%s%c%s", Repository, DIRSEP, dp->d_name);
if (stat(line, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
if (unlink(line) != -1) {
(void) closedir(dirp);
goto again;
}
}
ret = 1;
break;
}
}
(void) closedir(dirp);
return (ret);
}
/*
* Persistently tries to make the directory "lckdir",, which serves as a lock.
* If the create time on the directory is greater than CVSLCKAGE seconds
* old, just try to remove the directory.
*/
static
set_lock(lckdir)
char *lckdir;
{
extern char *ctime();
extern time_t time();
struct stat sb;
char *cp;
time_t now;
/*
* Note that it is up to the callers of Set_Lock() to
* arrange for signal handlers that do the appropriate things,
* like remove the lock directory before they exit.
*/
for (;;) {
if (mkdir(lckdir, 0777) < 0) {
(void) time(&now);
/*
* If the create time of the directory is more than CVSLCKAGE
* seconds ago, try to clean-up the lock directory, and if
* successful, just quietly retry to make it.
*/
if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
if (rmdir(lckdir) != -1)
continue;
}
cp = ctime(&now);
cp[24] = ' ';
warn(0, "%s: waiting for the lock to go away", cp);
sleep(CVSLCKSLEEP);
} else {
break;
}
}
}