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