Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* gcc -O3 -ansi -Wall -Wextra -pedantic -static termwait.c -lrt -o termwait */
- #define _POSIX_C_SOURCE 200809L
- #include <errno.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <termios.h>
- #include <time.h>
- #include <unistd.h>
- /* Structure of shared object */
- struct msg {
- int error; /* error */
- struct timespec ts_main; /* executed */
- struct timespec ts_term; /* terminal prepared */
- struct timespec ts_ident; /* reply received */
- };
- static struct timespec TS_INF = { -1, -1 };
- /* Shared object name */
- #define SHM_PATH "/termwait.shm."
- #define SHM_PATH_SLEN 64
- #define SHM_ENV "TERMWAIT_SHM"
- /* Prepare randomized name for shared object */
- static char *randpath(void *seed, size_t len) {
- static char hex[16] = "0123456789abcdef";
- static char path[SHM_PATH_SLEN] = SHM_PATH;
- unsigned k, i = sizeof(SHM_PATH)-1, h = getpid();
- #define MIX(h) { (h) ^= (h) << 13; (h) ^= (h) >> 17; (h) ^= (h) << 5; }
- for (k = 0; h >> k; k+=4)
- path[i++] = hex[(h>>k) & 0xf];
- path[i++] = '.';
- h ^= 2463534242;
- for (k = 0; k < len; k++) {
- MIX(h); h ^= ((char*)seed)[k];
- }
- for (; i < sizeof(path)-1; i++) {
- MIX(h); path[i] = hex[h & 0xf];
- }
- #undef MIX
- path[i] = '\0';
- return path;
- }
- /* Prepare shared memory object and expose its name in environment */
- static struct msg *msg_create(char *path) {
- struct msg *shm;
- int md;
- if (setenv(SHM_ENV, path, 1)) {
- return NULL;
- }
- md = shm_open(path, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
- if (md < 0)
- return NULL;
- (void) ftruncate(md, sizeof *shm);
- shm = (struct msg*) mmap(NULL, sizeof *shm,
- PROT_READ|PROT_WRITE, MAP_SHARED, md, 0);
- (void) close(md);
- if (shm == MAP_FAILED) {
- (void) shm_unlink(SHM_PATH);
- return NULL;
- }
- return shm;
- }
- /* Remove shared memory object */
- static int msg_remove(struct msg *shm) {
- (void) munmap(shm, sizeof *shm);
- return shm_unlink(getenv(SHM_ENV));
- }
- /* Push data to shared object */
- static int msg_send(struct msg dat) {
- struct msg *shm;
- char *path = getenv(SHM_ENV);
- int md;
- if (!path)
- return -1;
- if ((md = shm_open(path, O_RDWR, 0)) < 0)
- return errno;
- shm = (struct msg*) mmap(NULL, sizeof *shm,
- PROT_READ|PROT_WRITE, MAP_SHARED, md, 0);
- (void) close(md);
- if (shm == MAP_FAILED)
- return errno;
- *shm = dat;
- (void) munmap(shm, sizeof *shm);
- return 0;
- }
- /* Interrogate terminal: VT100 ident, ASCII ENQ, VT52 ident */
- #define TERM_ENQ "\033[c\005\033Z"
- /* Wait for terminal's reply and record timing */
- static int termwait(struct msg *dat) {
- struct termios tp, rp;
- int td;
- char buf;
- if ((td = open("/dev/tty", O_RDWR | O_SYNC)) < 0)
- return dat->error = errno;
- if (tcgetattr(td, &rp))
- return dat->error = errno;
- (void) memset(&tp, 0, sizeof(tp));
- tp.c_cc[VTIME] = 30;
- tp.c_cc[VMIN] = 1;
- if (tcsetattr(td, TCSAFLUSH, &tp))
- return dat->error = errno;
- dat->ts_term = TS_INF;
- clock_gettime(CLOCK_REALTIME, &dat->ts_term);
- if (write(td, TERM_ENQ, sizeof(TERM_ENQ)) < 0)
- dat->error = errno;
- else
- if ((buf = read(td, &buf, 1)) < 0)
- dat->error = errno;
- clock_gettime(CLOCK_REALTIME, &dat->ts_ident);
- if (!buf)
- dat->ts_ident = TS_INF;
- (void) tcflush(td, TCIOFLUSH);
- (void) tcsetattr(td, TCSANOW, &rp);
- (void) tcdrain(td);
- (void) close(td);
- return 0;
- }
- /* Subtract time specs */
- static struct timespec ts_sub(struct timespec a, struct timespec b) {
- if (a.tv_nsec == -1)
- return a; /* infty */
- if (b.tv_nsec > a.tv_nsec) {
- a.tv_nsec += 1000000000L;
- a.tv_sec--;
- }
- a.tv_nsec -= b.tv_nsec;
- a.tv_sec -= b.tv_sec;
- return a;
- }
- /* Execute given command and read results */
- static int termexec(struct msg *shm, char *path, char **argv) {
- struct timespec base;
- pid_t child;
- int stat;
- shm->error = 0;
- shm->ts_main = TS_INF;
- clock_gettime(CLOCK_REALTIME, &base);
- if (!(child = fork())) {
- execv(path, argv);
- perror("execv");
- exit(errno);
- }
- (void) waitpid(child, &stat, 0);
- if (stat)
- shm->error = WEXITSTATUS(stat);
- shm->ts_main = ts_sub(shm->ts_main, base);
- shm->ts_term = ts_sub(shm->ts_term, base);
- shm->ts_ident = ts_sub(shm->ts_ident, base);
- return 0;
- }
- /* Print results */
- static void ts_print(struct timespec ts) {
- if (ts.tv_nsec == -1)
- printf("inf\n");
- else
- printf("%lu.%09ld\n", ts.tv_sec, ts.tv_nsec);
- }
- static void msg_print(struct msg dat) {
- if (dat.error)
- fprintf(stderr, "Error: %s\n",
- strerror(dat.error));
- ts_print(dat.ts_main);
- /* ts_print(dat.ts_term); *//* term-main is negligible */
- ts_print(dat.ts_ident);
- }
- int main(int argc, char **argv) {
- struct msg dat;
- clock_gettime(CLOCK_REALTIME, &dat.ts_main);
- if (argc < 2) {
- dat.error = 0;
- termwait(&dat);
- msg_send(dat);
- }
- else {
- struct msg *shm = msg_create(randpath(&dat, sizeof(dat)));
- if (!shm) {
- perror("Creating shared memory object");
- exit(1);
- }
- argv[argc] = NULL; /* sic */
- (void) termexec(shm, argv[1], argv+1);
- msg_print(*shm);
- (void) msg_remove(shm);
- }
- exit(0);
- }
Add Comment
Please, Sign In to add comment