home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume5 / flock < prev    next >
Internet Message Format  |  1989-02-03  |  11KB

  1. Path: xanth!nic.MR.NET!hal!ncoast!allbery
  2. From: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
  3. Newsgroups: comp.sources.misc
  4. Subject: v05i014: flock - shell level access to flock(2)
  5. Message-ID: <8810232013.AA06867@s.cc.purdue.edu>
  6. Date: 28 Oct 88 02:46:21 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
  9. Lines: 411
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 5, Issue 14
  13. Submitted-by: "Kevin Braunsdorf" <ksb@s.cc.purdue.edu>
  14. Archive-name: flock
  15.  
  16. [This was supposed to have been posted a few weeks ago but somehow found a
  17. crack to get lost in!  (oops!)  ++bsa]
  18.  
  19. #    This is a shell archive.
  20. #    Remove everything above and including the cut line.
  21. #    Then run the rest of the file through sh.
  22. #----cut here-----cut here-----cut here-----cut here----#
  23. #!/bin/sh
  24. # shar:    Shell Archiver
  25. #    Run the following text with /bin/sh to create:
  26. #    README        Makefile
  27. #    flock.1l     flock.c
  28. # This archive created: Sun Oct 23 15:09:58 1988
  29. # By:    Kevin Braunsdorf (Purdue UNIX Group)
  30. sed 's/^K//' << \SHAR_EOF > README
  31. KFlock applies or removes an advisory lock on the named file or file
  32. Kdescriptor.  Advisory locks allow cooperating processes to perform
  33. Kconsistent operations on files see flock(2).  This program is *very*
  34. Kuseful on a Sequent machine; almost as useful on fast uniprocessors.
  35. K
  36. KHere is a case where flock(1) is very useful: on a Sequent Balance
  37. Kseries machine parallel make can be used to compile many files at the
  38. Ksame time.  This doesn't work for programs that use xstr(1) because
  39. Kcompeting processes using xstrings fails.  In the Makefile for vi one
  40. Kmight use a flock on the Makefile to force (only) the xstr to be run
  41. Ksequentially:
  42. K
  43. K    .c.o:
  44. K        ${CC} -E ${CFLAGS} $*.c | \
  45. K        flock Makefile sh -c "${XSTR} -c -; mv x.c $*.p.x"; \
  46. K        sed '/rcsid\[\]/d' < $*.p.x > $*.p.c; \
  47. K        ${CC} ${CFLAGS} -c $*.p.c; \
  48. K        mv $*.p.o $*.o; \
  49. K        rm $*.p.x $*.p.c
  50. K      
  51. KWhich will start a few cpps in parallel and run only one xstr at a time,
  52. Kas soon as it can it will run the sed/cc/mv/rm allowing another process
  53. Kto begin using xstr.
  54. K
  55. K(I flock the Makefile by convention, because I know I always have one.
  56. K If more then one command set needs to work from the same Makefile I
  57. K flock `complie.lock', and `yacc.lock' or some such, not using Makefile
  58. K for either.  The clean target in the Makefile removes these files.)
  59. K
  60. Kkayessbee (Kevin S Braunsdorf) ksb@j.cc.purdue.edu, pur-ee!ksb
  61. SHAR_EOF
  62. sed 's/^K//' << \SHAR_EOF > flock.1l
  63. K.\" $Id: flock.1l,v 1.3 88/10/23 14:53:53 ksb Exp $
  64. K.\" by Kevin Braunsdorf and Matthew Bradburn
  65. K.TH FLOCK 1L LOCAL
  66. K.SH NAME
  67. Kflock - lock a file to synchronize command streams
  68. K.SH SYNOPSIS
  69. K\fBflock\fP [-\fBc\fP\fBh\fP\fBn\fP] [\-\fBEX\fP|\fBSH\fP|\fBUN\fP|\fBNB\fP] \fIfile\fP|\fIfd\fP [\fIcmd\fP]
  70. K.SH DESCRIPTION
  71. KFlock applies or removes an advisory lock on the named file or file descriptor.
  72. KAdvisory locks allow cooperating processes to perform consistent operations
  73. Kon files see \fIflock\fP(2).
  74. K.PP
  75. KThe exit status from the \fBflock\fP command is the exit status of
  76. Kits child.  The default \fIcmd\fP is ``/bin/true'' so that by default
  77. K\fBflock\fP will succeed.  \fBFlock\fP with exit nonzero if either
  78. K\-\fBNB\fP (nonblocking) is specified and flock fails, or
  79. Kthe specified \fIfile\fP (\fIfd\fP) cannot be (isn't) opened.
  80. K.PP
  81. KIt \fBflock\fP has to open the file to get the lock it will not pass
  82. Kthe created file descriptor to the child process.  (Said process might
  83. Kunlock the descriptor.)
  84. K.SH OPTIONS
  85. K.TP
  86. K.BI \-c
  87. KCreate the lock file if it doesn't exist.
  88. K.TP
  89. K.BI \-h
  90. KGive a brief help message.
  91. K.TP
  92. K.BI \-n
  93. KDo not create the lock file if it doesn't exist.  This is the default.
  94. K.TP
  95. K.BI \-EX
  96. KSet or reset the LOCK_EX bit in the arguments to \fIflock\fP(2).
  97. KThis is the default if no locking bits are given.
  98. K.TP
  99. K.BI \-NB
  100. KSet or reset the LOCK_NB bit in the arguments to \fIflock\fP(2).
  101. K.TP
  102. K.BI \-SH
  103. KSet or reset the LOCK_SH bit in the arguments to \fIflock\fP(2).
  104. K.TP
  105. K.BI \-UN
  106. KSet or reset the LOCK_UN bit in the arguments to \fIflock\fP(2).
  107. KThis option is only useful when a file descriptor is given as the
  108. K`file' on which to operate.
  109. K.PP
  110. KThe option \-\fBEX\fP may be spelled \-\fBLOCK_EX\fP, likewise the other
  111. Klocking bits may be spelled more verbosely.
  112. K.PP
  113. KThe locking bits may be inclusive or'ed together with a pipe (`|'), which
  114. Kmust be quoted from the shell.
  115. K.SH EXAMPLES
  116. K.PP
  117. KIf a given daemon flocks its log file before each group of writes
  118. Kone might use:
  119. K.sp 1
  120. K    flock -EX 1 echo \*(lqsomething important\*(rq >>daemon.log
  121. K.sp 1
  122. Kto avoid interlaminate writes to the log.
  123. K.PP
  124. KIn a shell script:
  125. K.sp 1
  126. K    # stdout is a (possibly) shared file so we wait for it
  127. K.br
  128. K    flock -EX 1
  129. K.br
  130. K    # these have to be run under one lock
  131. K.br
  132. K    doit1 ; doit2; doit3
  133. K.br
  134. K    # end critical code, unlock the descriptor
  135. K.br
  136. K    flock -UN 1
  137. K.sp 1
  138. KTo edit a shared file:
  139. K.sp 1
  140. K    flock share.c vi share.c
  141. K.sp 1
  142. K.SH BUGS
  143. KNone known.
  144. K.SH AUTHOR
  145. KKevin Braunsdorf
  146. K.br
  147. KPurdue University, West Laffayette IN
  148. K.br
  149. Kpur-ee!ksb, ksb@j.cc.purdue.edu
  150. K.SH "SEE ALSO"
  151. Ksh(1), true(1), flock(2), open(2)
  152. SHAR_EOF
  153. sed 's/^K//' << \SHAR_EOF > Makefile
  154. K# makefile for flock
  155. K#            by Kevin S Braunsdorf, PUCC
  156. K
  157. KBIN=    ${DESTDIR}$$HOME/bin
  158. K
  159. KI=/usr/include
  160. KS=/usr/include/sys
  161. K
  162. KINCLUDE=
  163. KDEBUG=    -O
  164. KCDEFS=    -Dbsd
  165. KCFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE}
  166. K
  167. KHDR=    
  168. KSRC=    flock.c
  169. KOBJ=    flock.o
  170. KSOURCE=    Makefile ${HDR} ${SRC}
  171. K
  172. Kall: flock
  173. K
  174. Kflock:
  175. K    ${CC} -o $@ ${CFLAGS} flock.c
  176. K
  177. Kclean: FRC
  178. K    rm -f Makefile.bak flock *.o a.out core errs tags
  179. K
  180. Kdepend: ${SRC} ${HDR} FRC
  181. K    maketd -a ${CDEFS} ${INCLUDE} -b flock.c
  182. K
  183. Kinstall: all FRC
  184. K    install -c -s flock ${BIN}
  185. K
  186. Klint: ${HDR} ${SRC} FRC
  187. K    lint -hnx ${CDEFS} ${INCLUDE} ${SRC}
  188. K
  189. Kprint: source FRC
  190. K    lpr -J'flock source' ${SOURCE}
  191. K
  192. Ksource: ${SOURCE}
  193. K
  194. Kspotless: clean
  195. K    rcsclean ${SOURCE}
  196. K
  197. Ktags: ${SRC} ${HDR}
  198. K    ctags -t ${SRC} ${HDR}
  199. K
  200. K${SOURCE}:
  201. K    co $@
  202. K
  203. KFRC:
  204. K
  205. K# DO NOT DELETE THIS LINE - maketd DEPENDS ON IT
  206. K
  207. Kflock: $I/fcntl.h $I/stdio.h $S/file.h $S/types.h $S/wait.h flock.c
  208. K
  209. K# *** Do not add anything here - It will go away. ***
  210. SHAR_EOF
  211. sed 's/^K//' << \SHAR_EOF > flock.c
  212. K/*
  213. K * flock a file and wait for a process to exit                (ksb)
  214. K *
  215. K * Copyright 1988, All Rights Reserved
  216. K *    Kevin S Braunsdorf
  217. K *    ksb@j.cc.purdue.edu, pur-ee!ksb
  218. K *    Math/Sci Building, Purdue Univ
  219. K *    West Lafayette, IN
  220. K *
  221. K *  `You may redistibute this code as long as you don't claim to have
  222. K *   written it. -- kayessbee'
  223. K *
  224. K * $Compile: ${cc-cc} ${DEBUG--C} ${SYS--Dbsd} %f -o %F
  225. K */
  226. K#include <sys/types.h>
  227. K#include <sys/file.h>
  228. K#include <sys/wait.h>
  229. K#include <fcntl.h>
  230. K#include <stdio.h>
  231. K
  232. K#if defined(bsd)
  233. K#define strchr    index
  234. K#define strrchr    rindex
  235. K#endif
  236. K
  237. Kstatic char *progname =
  238. K    "$Id: flock.c,v 2.0 88/10/23 15:06:21 ksb Exp $";
  239. K
  240. Kstatic char acUsage[] =        /* this is the usage line for the user    */
  241. K    "%s: usage [-chn] [-EX|SH|UN|NB] file|fd [cmd]\n";
  242. Kstatic char *apcHelp[] = {    /* help text                */
  243. K    "c    create file, if nonexistant",
  244. K    "h    print this help message",
  245. K    "n    do not create file",
  246. K    "EX    exclusive lock, default",
  247. K    "NB    do not block for lock",
  248. K    "SH    shared lock",
  249. K    "UN    unlock",
  250. K    (char *)0
  251. K};
  252. K
  253. Ktypedef struct LKnode {        /* a cmd line option implies a lock bit    */
  254. K    char *pcflag;
  255. K    int iflag;
  256. K} LOCKKEY;
  257. K
  258. Kstatic LOCKKEY aLKLocks[] = {    /* the list of the cmd lines we know    */
  259. K    {"LOCK_EX", LOCK_EX},
  260. K    {"LOCK_SH", LOCK_SH},
  261. K    {"LOCK_UN", LOCK_UN},
  262. K    {"LOCK_NB", LOCK_NB},
  263. K    {"EX", LOCK_EX},
  264. K    {"SH", LOCK_SH},
  265. K    {"UN", LOCK_UN},
  266. K    {"NB", LOCK_NB},
  267. K    {(char *)0, -1}
  268. K};
  269. K
  270. K/*
  271. K * determine which flag the use wants to set/clear            (ksb)
  272. K */
  273. Kint
  274. KFlag(pcCmd)
  275. Kchar *pcCmd;
  276. K{
  277. K    register char *pcTry;
  278. K    register LOCKKEY *pLK;
  279. K    extern char *strchr();
  280. K
  281. K    for (pLK = aLKLocks; (char *)0 != (pcTry = pLK->pcflag); ++pLK) {
  282. K        if (0 == strcmp(pcTry, pcCmd)) {
  283. K            return pLK->iflag;
  284. K        }
  285. K    }
  286. K    if ((char *)0 != (pcTry = strchr(pcCmd, '|'))) {
  287. K        *pcTry++ = '\000';
  288. K        return Flag(pcCmd)|Flag(pcTry);
  289. K    }
  290. K
  291. K    fprintf(stderr, "%s: `%s' is not a flock key\n", progname, pcCmd);
  292. K    exit(1);
  293. K    /*NOTREACHED*/
  294. K}
  295. K
  296. K/*
  297. K * is this character string all digits                    (ksb)
  298. K */
  299. Kint
  300. Kisnumber(pc)
  301. Kchar *pc;
  302. K{
  303. K    while (*pc) {
  304. K        if (*pc < '0' || *pc > '9')
  305. K            break;
  306. K        ++pc;
  307. K    }
  308. K    return *pc == '\000';
  309. K}
  310. K
  311. K/*
  312. K * Get a lock on the named file and execute the rest of our arguments    (ksb)
  313. K * while the lock is active, when this command exits exit with it's
  314. K * extit status.
  315. K */
  316. Kint
  317. Kmain(argc, argv)
  318. Kint argc;
  319. Kchar **argv;
  320. K{
  321. K    extern int atoi();
  322. K    extern char *strrchr();
  323. K    static char *apcTrue[] = {"true", (char *)0};
  324. K    auto union wait wait_buf;
  325. K    auto int fd, tClose, oFlags, fCreate = 0;
  326. K    auto int iLock = -1;
  327. K    auto char **ppcHelp;
  328. K
  329. K
  330. K    if ((char *)0 != (progname = strrchr(*argv, '/'))) {
  331. K        ++progname;
  332. K    } else {
  333. K        progname = *argv;
  334. K    }
  335. K    ++argv, --argc;
  336. K    while (argc > 0 && '-' == argv[0][0]) {
  337. K        switch (*++argv[0]) {
  338. K        case '\000':
  339. K            break;
  340. K        case 'n':
  341. K        case 'c':
  342. K            fCreate = argv[0][0] == 'c';
  343. K            argv[0][0] = '-';
  344. K            continue;
  345. K        case 'h':
  346. K            fprintf(stdout, acUsage, progname);
  347. K            for (ppcHelp = apcHelp; (char *)0 != *ppcHelp; ++ppcHelp) {
  348. K                fprintf(stdout, "%s\n", *ppcHelp);
  349. K            }
  350. K            exit(0);
  351. K        default:
  352. K            if (-1 == iLock)
  353. K                iLock = 0;
  354. K            iLock ^= Flag(argv[0]);
  355. K            break;
  356. K        }
  357. K        ++argv, --argc;
  358. K    }
  359. K
  360. K    if (-1 == iLock) {
  361. K        iLock = LOCK_EX;
  362. K    }
  363. K
  364. K    if (0 == argc) {
  365. K        fprintf(stderr, acUsage, progname);
  366. K        exit(1);
  367. K    }
  368. K
  369. K    tClose = 1;
  370. K    if (-1 == (fd = open(argv[0], O_RDONLY, 0600))) {
  371. K        oFlags = 0 != fCreate ? O_CREAT|O_WRONLY|O_APPEND : O_WRONLY|O_APPEND;
  372. K        if (-1 == (fd = open(argv[0], oFlags, 0666))) {
  373. K            if (!isnumber(argv[0])) {
  374. K                fprintf(stderr, "%s: open: ", progname);
  375. K                perror(argv[0]);
  376. K                exit(1);
  377. K            }
  378. K            fd = atoi(argv[0]);
  379. K            if (-1 == fcntl(fd, F_GETFD, 0)) {
  380. K                fprintf(stderr, "%s: %d: ", progname, fd);
  381. K                perror("fcntl");
  382. K                exit(1);
  383. K            }
  384. K            tClose = 0;
  385. K        }
  386. K    }
  387. K    if (-1 == flock(fd, iLock)) {
  388. K        fprintf(stderr, "%s: flock: ", progname);
  389. K        perror(argv[0]);
  390. K        exit(1);
  391. K    }
  392. K    ++argv, --argc;
  393. K
  394. K    if (0 == argc) {
  395. K        argv = apcTrue;
  396. K    }
  397. K    if (tClose != 0) {        /* save a fork */
  398. K        switch (fork()) {
  399. K        case 0:
  400. K            close(fd);
  401. K            break;
  402. K        case -1:
  403. K            fprintf(stderr, "%s: ", progname);
  404. K            perror("fork");
  405. K            exit(1);
  406. K            /*NOTREACHED*/
  407. K        default:
  408. K            wait(& wait_buf);
  409. K            /* exit will close fd for us */
  410. K            exit((int) wait_buf.w_retcode);
  411. K            /*NOTREACHED*/
  412. K        }
  413. K    }
  414. K    execvp(argv[0], argv);
  415. K    fprintf(stderr, "%s: ", progname);
  416. K    perror(argv[0]);
  417. K    exit(1);
  418. K    /*NOTREACHED*/
  419. K}
  420. SHAR_EOF
  421. #    End of shell archive
  422. exit 0
  423.