/* * File: lock.c * * Author: Ulli Horlacher (framstag@belwue.de) * * History: * * 1995-11-02 Framstag initial version * 1998-09-29 Framstag print also PID on testing * * This program sets or tests advisory locks conforming to POSIX fcntl() call. * You may specify optionaly a program to start it within the lock context. * * Copyright © 1997 Ulli Horlacher * This file is covered by the GNU General Public License */ #include #include #include #include #include #include #include #include #include #include /* some systems are missing the getopt declarations */ int getopt(int, char * const *, const char *); extern int opterr; extern int optind; extern int optopt; extern char *optarg; /* write-lock a file (POSIX conform) */ int wlock_file(int,int,int); /* test if a file is write-lock blocked (POSIX conform) */ int tlock_file(int,int,int); /* print short usage message */ void usage(); char *prg; /* name of the game */ int main(int argc, char *argv[]) { int i, /* simple loop counter */ status, /* return status */ lockf, /* lock file descriptor */ opt, /* getopt return value */ verbose, /* flag for verbose mode */ begin, /* begin of locking area */ length, /* length of locking area */ seconds, /* seconds to sleep */ pid; /* process ID */ char type; /* locl-type: testing or seting */ char cmd[32768]; /* program and arguments to start */ char *cp, /* simple string pointer */ *file, /* file to lock */ *nprg; /* next program to start */ verbose=0; begin=0; length=0; seconds=86400; strcpy(cmd,""); type='t'; /* default: test lock */ /* what's my name? */ prg=argv[0]; if ((cp=strrchr(prg,'/'))) prg=cp+1; while ((opt=getopt(argc, argv, "vtsb:l:a:")) > 0) { switch (opt) { case ':': case 'h': case '?': usage(); case 't': type='t'; break; case 's': type='s'; break; case 'v': verbose=1; break; case 'b': begin=atoi(optarg); break; case 'l': length=atoi(optarg); break; case 'a': seconds=atoi(optarg); break; } } if (argc-optind==0) usage(); file=argv[optind]; nprg=argv[optind+1]; /* try to open file */ if ((lockf=open(file,O_WRONLY|O_APPEND,S_IRUSR|S_IWUSR))<0) { fprintf(stderr,"%s: cannot open %s : %s\n",prg,file,strerror(errno)); exit(1); } /* set lock mode? */ if (type=='s') { /* try to lock it */ status=wlock_file(lockf,begin,length); /* lock failed */ if (status<0) { if (verbose) fprintf(stderr,"%s: lock failed for %s\n",prg,file); exit(2); } /* next program specified? */ if (nprg) { /* build command string */ for (i=optind+1;argv[i];i++) { strcat(cmd," "); strcat(cmd,argv[i]); } /* create subprocess */ pid=fork(); if (pid<0) { fprintf(stderr,"%s: cannot create subprocess : %s\n",prg,strerror(errno)); exit(2); } /* in subprocess start next program */ if (pid==0) { if (verbose) fprintf(stderr,"%s: executing %s\n",prg,cmd); execvp(nprg,&argv[optind+1]); fprintf(stderr,"%s: cannot execute %s : %s\n",prg,nprg,strerror(errno)); exit(2); } /* that's it */ wait(NULL); exit(0); } /* sleep for some time to keep lock alive */ if (verbose) fprintf(stderr,"%s: lock ok for %s, " "going into sleep for %d seconds\n", prg,file,seconds); sleep(seconds); exit(0); /* only test the file for locks */ } else { status=tlock_file(lockf,begin,length); if (status<0) { if (verbose) fprintf(stderr,"%s: testing lock for %s failed!\n",prg,file); exit(2); } if (status==0) { if (verbose) fprintf(stderr,"%s: no lock for %s\n",prg,file); exit(1); } if (status>0) { if (verbose) fprintf(stderr,"%s: %s is locked by PID %d\n", prg,file,status); exit(0); } } exit(0); } /* * wlock_file - write-lock a file (POSIX conform) * * INPUT: file descriptor * * RETURN: >= 0 if ok, -1 if error */ int wlock_file(int fd, int begin, int length) { struct flock lock; /* file locking structure */ /* fill out the file locking structure */ lock.l_type=F_WRLCK; lock.l_start=begin; lock.l_whence=SEEK_SET; lock.l_len=length; /* try to lock the file and return the status */ return(fcntl(fd,F_SETLK,&lock)); } /* * tlock_file - test if a file is write-lock blocked (POSIX conform) * * INPUT: fd - file descriptor * * RETURN: 0 if no lock, lock-PID if locked, -1 on error */ int tlock_file(int fd, int begin, int length) { int status; struct flock lock; /* file locking structure */ /* fill out the file locking structure */ lock.l_type=F_WRLCK; lock.l_start=begin; lock.l_whence=SEEK_SET; lock.l_len=length; /* test the lock status */ status=fcntl(fd,F_GETLK,&lock); if (status>=0) status=(lock.l_type!=F_UNLCK); if (status>0) status=lock.l_pid; return(status); } void usage() { printf("purpose: \"%s\" tests or sets a file with POSIX-fcntl() write-locks\n",prg); printf("usage: %s [-s [-a seconds]] [-t] [-v] [-b begin] [-l length] file\n",prg); printf(" or: %s -s [-v] [-b begin] [-l length] file program [arguments]\n",prg); printf("options: -t test lock (default)\n"); printf(" -s set lock\n"); printf(" -v verbose output\n"); printf(" -b lock starts at byte #begin\n"); printf(" -l lock is #length byte long\n"); printf(" -a lock is #seconds active (default=86400)\n"); printf(" program ... start this program within the lock context\n"); printf("Exit status: test: 0 = locked, 1 = not locked, 2 = error\n"); printf(" set: 0 = lock was successful, 2 = error\n"); printf("Examples: %s -s -v log_file\n",prg); printf(" %s -s -b 10 log_file vi log_file\n",prg); printf(" %s -vt log_file\n",prg); exit(0); }