@@ -71,9 +71,11 @@ TODO document flags TODO implement/remove lock flag - TODO add flag to bring window to current desktop */ + TODO add flag to bring window to current desktop + + TODO rewrite using sysv shmem */ #include #include @@ -86,15 +88,41 @@ #include #include #include #include +#include #include #include -#include //TODO bsd compat +#include -#define shmem_prefix "/k.xpriv:" +#ifdef _RAND_SYSCALL +# include +# define getrandom(a,b,c) syscall(SYS_getrandom,a,b,c) + /* this is necessary on certain platforms due to + * certainly ungodly libc issues, i think. */ +#endif -typedef enum { false, true } bool; +#ifdef _SHM_LINUX + /* xpriv was originally written with linux shared + * memory in mind, because i'm an idiot. i've since + * redesigned it to use the superior old sysv shm + * api that works on every other unix, not just + * linux, but if for some ungodly reason you want + * to use the linux one, then just pass -D_SHM_LINUX */ +# define shmem_prefix "/k.xpriv:" +# define shmlinux(...) __VA_ARGS__ +# define shmsysv(...) +#else +# define shmlinux(...) +# define shmsysv(...) __VA_ARGS__ +#endif + +enum /* constants */ { + false = 0, true = 1, + shmsysv(shmem_key = 0x53373EC3,) /* ye olde magique numbre */ +}; + +typedef _Bool bool; enum mode { mode_usage, mode_go, mode_register, mode_kill, mode_lock }; enum res { ok, fail_parse, fail_arg, fail_opt, fail_shm, @@ -149,31 +177,41 @@ void spawn(pid_t ssha, const char* const sockn) { if (ssha = fork()) { char pid_s_buf[16]; char* pid_s = itoa(ssha, pid_s_buf, sizeof(pid_s_buf)); - while (access(sockn, F_OK)); - // avoid nasty race condition + while (access(sockn, F_OK)); // avoid nasty race condition setenv("SSH_AGENT_PID", pid_s, true); setenv("SSH_AUTH_SOCK", sockn, true); global -> agent = ssha; } else { close(1); close(0); - execlp("ssh-agent","ssh-agent","-D", "-a",sockn,0); + execlp("ssh-agent","ssh-agent","-D","-a",sockn,0); } } -enum res register_window(const char* const id, bool weak, const char* const name) { +enum res register_window(shmlinux(const char* const id,) bool weak, const char* name) { // the id field denotes the path to the shared memory // in use, and allows the user to have multiple // contexts by creating aliases to the binary - int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600); - ftruncate(fd, sizeof(struct signal)); - if (fd == -1) return fail_shm; - - struct signal* s = mmap(0, sizeof(struct signal), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if(s == MAP_FAILED) return fail_mem; - else global = s; + struct signal* s; + shmlinux ({ + int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600); + ftruncate(fd, sizeof(struct signal)); + if (fd == -1) return fail_shm; + + s = mmap(0, sizeof(struct signal), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(s == MAP_FAILED) return fail_mem; + else global = s; + }) shmsysv (int shmem; + shmem = shmget(shmem_key, sizeof (struct signal), IPC_CREAT | 0777); + if (shmem == -1) return fail_shm; + + s = shmat(shmem, 0,0); + + if (s == (void*)-1) return fail_mem; + else global = s; + ) Display* xdpy = XOpenDisplay(NULL); Atom xvital; @@ -209,9 +247,15 @@ kill(s -> pid, SIGTERM); } kill(s -> agent, SIGTERM); sigprocmask(SIG_BLOCK, &mask, NULL); - shm_unlink(id); + + shmlinux(shm_unlink(id)); + shmsysv({ + struct shmid_ds bleh; /* ?? */ + shmctl(shmem, IPC_RMID, &bleh); + }) + if (!weak) { XDeleteProperty(xdpy,s -> wid,xvital); XSync(xdpy,false); } @@ -223,9 +267,11 @@ if (name == NULL) { /* messy part */ const char* tmp; //tmpdir defined? - if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp"; + if (!(tmp = getenv("XDG_RUNTIME_DIR"))) + if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp"; + size_t tmpsz = strlen(tmp); char sockn[tmpsz + 1 + sizeof "ssh." + 11]; @@ -244,10 +290,11 @@ if (*i > '9') *i += 7; if (*i > 'Z') *i += ('a' - 'Z'); } - spawn(ssha, sockn); - } else spawn(ssha, name); + name = sockn; + } + spawn(ssha, name); pid_t sad; int p; if (sad = fork()) { @@ -259,23 +306,36 @@ XSync(xdpy,false); } write(1,"\033c",3); execlp("fish","fish",NULL); - } else { return ok; } + } } else { execlp("ssh-add","ssh-add",NULL); } } - return ok; // this is kind of pointless but w/e + return ok; } -enum res kill_window(const char* id) { - int fd = shm_open(id, O_RDWR, 0600); - if (fd == -1) return fail_nop; +enum res kill_window(shmlinux(const char* id)) { + struct signal* s; + shmlinux({ + int fd = shm_open(id, O_RDWR, 0600); + if (fd == -1) return fail_nop; - struct signal* s = mmap(0, sizeof(struct signal), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if(s == MAP_FAILED) return fail_mem; + s = mmap(0, sizeof(struct signal), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if(s == MAP_FAILED) return fail_mem; + }) shmsysv (int shmem; { + shmem = shmget(shmem_key, sizeof(struct signal), 0); + if (shmem == -1) return fail_nop; + s = shmat(shmem,0,0); + if (s == (void*)-1) return fail_mem; + }) + + shmsysv({ + struct shmid_ds bleh; /* ?? */ + shmctl(shmem, IPC_RMID, &bleh); + }) s -> op = mode_kill; kill(s -> pid, SIGUSR1); @@ -302,8 +362,11 @@ return ok; } int main(int sz, char** argv) { + char* binname = "xpriv"; + if(sz > 0) binname = argv[0]; + enum mode op = mode_go; bool init_weak = false; const char* init_named = NULL; @@ -328,22 +391,31 @@ } if(opt[1] != 0) { ++opt; goto read_opt; } } - size_t nsz; - const char* basename = argv[0], *p; - for (p = argv[0]; *p!=0; ++p) { - if(*p == '/') basename = p + 1; - } - nsz = p - basename; - char shid[nsz + sizeof shmem_prefix]; - strncpy(shid,shmem_prefix,sizeof shmem_prefix); - strncpy(shid + sizeof shmem_prefix - 1, basename, nsz); - shid[nsz + sizeof shmem_prefix - 1] = 0; + shmlinux( + size_t nsz; + const char* basename = argv[0], *p; + for (p = binname; *p!=0; ++p) { + if(*p == '/') basename = p + 1; + } + nsz = p - basename; + char shid[nsz + sizeof shmem_prefix]; + strncpy(shid,shmem_prefix,sizeof shmem_prefix); + strncpy(shid + sizeof shmem_prefix - 1, basename, nsz); + shid[nsz + sizeof shmem_prefix - 1] = 0; + ) shmsysv ({ + /* TODO: implement ability to have multiple + * keys based on the name of the binary */ + }) - if (op == mode_go) { - int fd; - if ((fd = shm_open(shid, O_RDWR, 0600)) == -1) { + tryagain: if (op == mode_go) { + int shm; + if ((shm = shmlinux( + shm_open(shid, O_RDWR, 0600) + ) shmsysv ( + shmget(shmem_key,sizeof (struct signal),0) + )) == -1) { const char* args[] = { "urxvtc", "-bg", "[90]#4b0024", "-e", argv[0], (init_weak?"-aw":"-a"), 0, 0, 0}; @@ -355,16 +427,35 @@ } execvp("urxvtc", (char* const*)args); } else { - struct signal*s = mmap(0, sizeof(struct signal), - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + struct signal*s = shmlinux( + mmap(0, sizeof(struct signal), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0) + ) shmsysv ( + shmat(shm, 0, 0) + ); + + struct shmid_ds stat; + shmctl(shm, IPC_STAT, &stat); + if (stat.shm_nattch == 0) { + /* if the shm segment is not attached to any + * process, it's a relic that needs to be + * cleaned up before we do anything else. on + * a sane OS, there would be built-in non- + * persistence mechanisms for shared mem, but + * alas, as you already know, POSIX */ + shmctl(shm, IPC_RMID, &stat); + goto tryagain; + } + + if (s == shmlinux(MAP_FAILED) shmsysv((void*)-1)) + return bad(fail_mem); return bad(activate_window(s->wid)); } } else if (op == mode_register) - return bad(register_window(shid,init_weak,init_named)); + return bad(register_window(shmlinux(shid,) init_weak,init_named)); else if (op == mode_kill) - return bad(kill_window(shid)); + return bad(kill_window(shmlinux(shid))); else if (op == mode_usage) { write(1,"\e[1musage:\e[0m ",15); write(1, argv[0], strlen(argv[0])); write(1, " [-aklw [arg]]\n",16);