lock.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. if (lockwait)
  40. while ((lckfd = open(lock, ORDWR)) < 0)
  41. sleep(1000);
  42. else
  43. lckfd = open(lock, ORDWR);
  44. if (lckfd < 0)
  45. sysfatal("can't open %s read/write: %r", lock);
  46. dir = dirfstat(lckfd);
  47. if (dir == nil)
  48. sysfatal("can't fstat %s: %r", lock);
  49. if (!(dir->mode & DMEXCL)) {
  50. dir->mode |= DMEXCL;
  51. dir->qid.type |= QTEXCL;
  52. if (dirfwstat(lckfd, dir) < 0)
  53. sysfatal("can't make %s exclusive access: %r", lock);
  54. }
  55. free(dir);
  56. return lckfd;
  57. }
  58. void
  59. main(int argc, char *argv[])
  60. {
  61. int fd, lckfd, lckpid, cmdpid;
  62. char *cmd, *p, *lock;
  63. char **args;
  64. char *argarr[2];
  65. Waitmsg *w;
  66. ARGBEGIN {
  67. case 'd':
  68. ++debug;
  69. break;
  70. case 'w':
  71. ++lockwait;
  72. break;
  73. default:
  74. usage();
  75. break;
  76. } ARGEND
  77. if (argc < 1)
  78. usage();
  79. if (argc == 1) {
  80. args = argarr;
  81. args[0] = cmd = "rc";
  82. args[1] = nil;
  83. } else {
  84. cmd = argv[1];
  85. args = &argv[1];
  86. }
  87. /* set up lock and process to keep it alive */
  88. lock = argv[0];
  89. lckfd = openlock(lock);
  90. lckpid = fork();
  91. switch(lckpid){
  92. case -1:
  93. error("fork");
  94. case 0:
  95. /* keep lock alive until killed */
  96. for (;;) {
  97. sleep(60*1000);
  98. seek(lckfd, 0, 0);
  99. fprint(lckfd, "\n");
  100. }
  101. }
  102. /* spawn argument command */
  103. cmdpid = rfork(RFFDG|RFREND|RFPROC|RFENVG);
  104. switch(cmdpid){
  105. case -1:
  106. error("fork");
  107. case 0:
  108. fd = create("/env/prompt", OWRITE, 0666);
  109. if (fd >= 0) {
  110. fprint(fd, "%s%% ", lock);
  111. close(fd);
  112. }
  113. exec(cmd, args);
  114. if(cmd[0] != '/' && strncmp(cmd, "./", 2) != 0 &&
  115. strncmp(cmd, "../", 3) != 0)
  116. exec(smprint("/bin/%s", cmd), args);
  117. error(cmd);
  118. }
  119. notify(notifyf);
  120. w = waitfor(cmdpid);
  121. if (w == nil)
  122. error("wait");
  123. postnote(PNPROC, lckpid, "die");
  124. waitfor(lckpid);
  125. if(w->msg[0]){
  126. p = utfrune(w->msg, ':');
  127. if(p && p[1])
  128. p++;
  129. else
  130. p = w->msg;
  131. while (isspace(*p))
  132. p++;
  133. fprint(2, "%s: %s # status=%s\n", argv0, cmd, p);
  134. }
  135. exits(w->msg);
  136. }
  137. void
  138. error(char *s)
  139. {
  140. fprint(2, "%s: %s: %r\n", argv0, s);
  141. exits(s);
  142. }
  143. void
  144. notifyf(void *a, char *s)
  145. {
  146. USED(a);
  147. if(strcmp(s, "interrupt") == 0)
  148. noted(NCONT);
  149. noted(NDFLT);
  150. }