Guest User

Untitled

a guest
Oct 21st, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.03 KB | None | 0 0
  1. /* gcc -O3 -ansi -Wall -Wextra -pedantic -static termwait.c -lrt -o termwait */
  2. #define _POSIX_C_SOURCE 200809L
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/mman.h>
  9. #include <sys/stat.h>
  10. #include <sys/wait.h>
  11. #include <termios.h>
  12. #include <time.h>
  13. #include <unistd.h>
  14.  
  15. /* Structure of shared object */
  16. struct msg {
  17. int error; /* error */
  18. struct timespec ts_main; /* executed */
  19. struct timespec ts_term; /* terminal prepared */
  20. struct timespec ts_ident; /* reply received */
  21. };
  22.  
  23. static struct timespec TS_INF = { -1, -1 };
  24.  
  25. /* Shared object name */
  26. #define SHM_PATH "/termwait.shm."
  27. #define SHM_PATH_SLEN 64
  28. #define SHM_ENV "TERMWAIT_SHM"
  29.  
  30. /* Prepare randomized name for shared object */
  31. static char *randpath(void *seed, size_t len) {
  32. static char hex[16] = "0123456789abcdef";
  33. static char path[SHM_PATH_SLEN] = SHM_PATH;
  34. unsigned k, i = sizeof(SHM_PATH)-1, h = getpid();
  35. #define MIX(h) { (h) ^= (h) << 13; (h) ^= (h) >> 17; (h) ^= (h) << 5; }
  36. for (k = 0; h >> k; k+=4)
  37. path[i++] = hex[(h>>k) & 0xf];
  38. path[i++] = '.';
  39. h ^= 2463534242;
  40. for (k = 0; k < len; k++) {
  41. MIX(h); h ^= ((char*)seed)[k];
  42. }
  43. for (; i < sizeof(path)-1; i++) {
  44. MIX(h); path[i] = hex[h & 0xf];
  45. }
  46. #undef MIX
  47. path[i] = '\0';
  48. return path;
  49. }
  50.  
  51. /* Prepare shared memory object and expose its name in environment */
  52. static struct msg *msg_create(char *path) {
  53. struct msg *shm;
  54. int md;
  55. if (setenv(SHM_ENV, path, 1)) {
  56. return NULL;
  57. }
  58. md = shm_open(path, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
  59. if (md < 0)
  60. return NULL;
  61. (void) ftruncate(md, sizeof *shm);
  62. shm = (struct msg*) mmap(NULL, sizeof *shm,
  63. PROT_READ|PROT_WRITE, MAP_SHARED, md, 0);
  64. (void) close(md);
  65. if (shm == MAP_FAILED) {
  66. (void) shm_unlink(SHM_PATH);
  67. return NULL;
  68. }
  69. return shm;
  70. }
  71.  
  72. /* Remove shared memory object */
  73. static int msg_remove(struct msg *shm) {
  74. (void) munmap(shm, sizeof *shm);
  75. return shm_unlink(getenv(SHM_ENV));
  76. }
  77.  
  78. /* Push data to shared object */
  79. static int msg_send(struct msg dat) {
  80. struct msg *shm;
  81. char *path = getenv(SHM_ENV);
  82. int md;
  83. if (!path)
  84. return -1;
  85. if ((md = shm_open(path, O_RDWR, 0)) < 0)
  86. return errno;
  87. shm = (struct msg*) mmap(NULL, sizeof *shm,
  88. PROT_READ|PROT_WRITE, MAP_SHARED, md, 0);
  89. (void) close(md);
  90. if (shm == MAP_FAILED)
  91. return errno;
  92. *shm = dat;
  93. (void) munmap(shm, sizeof *shm);
  94. return 0;
  95. }
  96.  
  97. /* Interrogate terminal: VT100 ident, ASCII ENQ, VT52 ident */
  98. #define TERM_ENQ "\033[c\005\033Z"
  99.  
  100. /* Wait for terminal's reply and record timing */
  101. static int termwait(struct msg *dat) {
  102. struct termios tp, rp;
  103. int td;
  104. char buf;
  105. if ((td = open("/dev/tty", O_RDWR | O_SYNC)) < 0)
  106. return dat->error = errno;
  107. if (tcgetattr(td, &rp))
  108. return dat->error = errno;
  109. (void) memset(&tp, 0, sizeof(tp));
  110. tp.c_cc[VTIME] = 30;
  111. tp.c_cc[VMIN] = 1;
  112. if (tcsetattr(td, TCSAFLUSH, &tp))
  113. return dat->error = errno;
  114. dat->ts_term = TS_INF;
  115. clock_gettime(CLOCK_REALTIME, &dat->ts_term);
  116. if (write(td, TERM_ENQ, sizeof(TERM_ENQ)) < 0)
  117. dat->error = errno;
  118. else
  119. if ((buf = read(td, &buf, 1)) < 0)
  120. dat->error = errno;
  121. clock_gettime(CLOCK_REALTIME, &dat->ts_ident);
  122. if (!buf)
  123. dat->ts_ident = TS_INF;
  124. (void) tcflush(td, TCIOFLUSH);
  125. (void) tcsetattr(td, TCSANOW, &rp);
  126. (void) tcdrain(td);
  127. (void) close(td);
  128. return 0;
  129. }
  130.  
  131. /* Subtract time specs */
  132. static struct timespec ts_sub(struct timespec a, struct timespec b) {
  133. if (a.tv_nsec == -1)
  134. return a; /* infty */
  135. if (b.tv_nsec > a.tv_nsec) {
  136. a.tv_nsec += 1000000000L;
  137. a.tv_sec--;
  138. }
  139. a.tv_nsec -= b.tv_nsec;
  140. a.tv_sec -= b.tv_sec;
  141. return a;
  142. }
  143.  
  144. /* Execute given command and read results */
  145. static int termexec(struct msg *shm, char *path, char **argv) {
  146. struct timespec base;
  147. pid_t child;
  148. int stat;
  149. shm->error = 0;
  150. shm->ts_main = TS_INF;
  151. clock_gettime(CLOCK_REALTIME, &base);
  152. if (!(child = fork())) {
  153. execv(path, argv);
  154. perror("execv");
  155. exit(errno);
  156. }
  157. (void) waitpid(child, &stat, 0);
  158. if (stat)
  159. shm->error = WEXITSTATUS(stat);
  160. shm->ts_main = ts_sub(shm->ts_main, base);
  161. shm->ts_term = ts_sub(shm->ts_term, base);
  162. shm->ts_ident = ts_sub(shm->ts_ident, base);
  163. return 0;
  164. }
  165.  
  166. /* Print results */
  167. static void ts_print(struct timespec ts) {
  168. if (ts.tv_nsec == -1)
  169. printf("inf\n");
  170. else
  171. printf("%lu.%09ld\n", ts.tv_sec, ts.tv_nsec);
  172. }
  173. static void msg_print(struct msg dat) {
  174. if (dat.error)
  175. fprintf(stderr, "Error: %s\n",
  176. strerror(dat.error));
  177. ts_print(dat.ts_main);
  178. /* ts_print(dat.ts_term); *//* term-main is negligible */
  179. ts_print(dat.ts_ident);
  180. }
  181.  
  182. int main(int argc, char **argv) {
  183. struct msg dat;
  184. clock_gettime(CLOCK_REALTIME, &dat.ts_main);
  185. if (argc < 2) {
  186. dat.error = 0;
  187. termwait(&dat);
  188. msg_send(dat);
  189. }
  190. else {
  191. struct msg *shm = msg_create(randpath(&dat, sizeof(dat)));
  192. if (!shm) {
  193. perror("Creating shared memory object");
  194. exit(1);
  195. }
  196. argv[argc] = NULL; /* sic */
  197. (void) termexec(shm, argv[1], argv+1);
  198. msg_print(*shm);
  199. (void) msg_remove(shm);
  200. }
  201. exit(0);
  202. }
Add Comment
Please, Sign In to add comment