lock.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * lock - keep a lock alive while a command runs
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <ctype.h>
  7. static int debug;
  8. static int lockwait;
  9. void error(char*);
  10. void notifyf(void*, char*);
  11. static void
  12. usage(void)
  13. {
  14. fprint(2, "usage: %s [-dw] lock [command [file]...]\n", argv0);
  15. exits("usage");
  16. }
  17. static Waitmsg *
  18. waitfor(int pid)
  19. {
  20. char err[ERRMAX];
  21. Waitmsg *w;
  22. for (;;) {
  23. w = wait();
  24. if (w == nil){
  25. errstr(err, sizeof err);
  26. if(strcmp(err, "interrupted") == 0)
  27. continue;
  28. return nil;
  29. }
  30. if (w->pid == pid)
  31. return w;
  32. }
  33. }
  34. static int
  35. openlock(char *lock)
  36. {
  37. int lckfd;
  38. Dir *dir;
  39. /* first ensure that the lock file has the lock bit set */
  40. dir = dirstat(lock);
  41. if (dir == nil)
  42. sysfatal("can't stat %s: %r", lock);
  43. if (!(dir->mode & DMEXCL)) {
  44. dir->mode |= DMEXCL;
  45. dir->qid.type |= QTEXCL;
  46. if (dirwstat(lock, dir) < 0)
  47. sysfatal("can't make %s exclusive access: %r", lock);
  48. }
  49. free(dir);
  50. if (lockwait)
  51. while ((lckfd = open(lock, ORDWR)) < 0)
  52. sleep(1000);
  53. else
  54. lckfd = open(lock, ORDWR);
  55. if (lckfd < 0)
  56. sysfatal("can't open %s read/write: %r", lock);
  57. return lckfd;
  58. }
  59. void
  60. main(int argc, char *argv[])
  61. {
  62. int fd, lckfd, lckpid, cmdpid;
  63. char *cmd, *p, *lock;
  64. char **args;
  65. char *argarr[2];
  66. Waitmsg *w;
  67. ARGBEGIN {
  68. case 'd':
  69. ++debug;
  70. break;
  71. case 'w':
  72. ++lockwait;
  73. break;
  74. default:
  75. usage();
  76. break;
  77. } ARGEND
  78. if (argc < 1)
  79. usage();
  80. if (argc == 1) {
  81. args = argarr;
  82. args[0] = cmd = "rc";
  83. args[1] = nil;
  84. } else {
  85. cmd = argv[1];
  86. args = &argv[1];
  87. }
  88. /* set up lock and process to keep it alive */
  89. lock = argv[0];
  90. lckfd = openlock(lock);
  91. lckpid = fork();
  92. switch(lckpid){
  93. case -1:
  94. error("fork");
  95. case 0:
  96. /* keep lock alive until killed */
  97. for (;;) {
  98. sleep(60*1000);
  99. seek(lckfd, 0, 0);
  100. fprint(lckfd, "\n");
  101. }
  102. }
  103. /* spawn argument command */
  104. cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG);
  105. switch(cmdpid){
  106. case -1:
  107. error("fork");
  108. case 0:
  109. fd = create("/env/prompt", OWRITE, 0666);
  110. if (fd >= 0) {
  111. fprint(fd, "%s%% ", lock);
  112. close(fd);
  113. }
  114. exec(cmd, args);
  115. if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 &&
  116. strncmp(cmd, "../", 3) != 0)
  117. exec(smprint("/bin/%s", cmd), args);
  118. error(cmd);
  119. }
  120. notify(notifyf);
  121. w = waitfor(cmdpid);
  122. if (w == nil)
  123. error("wait");
  124. postnote(PNPROC, lckpid, "die");
  125. waitfor(lckpid);
  126. if(w->msg[0]){
  127. p = utfrune(w->msg, ':');
  128. if(p && p[1])
  129. p++;
  130. else
  131. p = w->msg;
  132. while (isspace(*p))
  133. p++;
  134. fprint(2, "%s: %s # status=%s\n", argv0, cmd, p);
  135. }
  136. exits(w->msg);
  137. }
  138. void
  139. error(char *s)
  140. {
  141. fprint(2, "%s: %s: %r\n", argv0, s);
  142. exits(s);
  143. }
  144. void
  145. notifyf(void *a, char *s)
  146. {
  147. USED(a);
  148. if(strcmp(s, "interrupt") == 0)
  149. noted(NCONT);
  150. noted(NDFLT);
  151. }