Overview
Comment: | add shit, updates |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
196f94b613f23e130e98ecbce7965ed5 |
User & Date: | lexi on 2019-04-17 16:52:18 |
Other Links: | manifest | tags |
Context
2019-04-17
| ||
17:02 | added more comments check-in: 4b7174b913 user: lexi tags: trunk | |
16:52 | add shit, updates check-in: 196f94b613 user: lexi tags: trunk | |
2019-04-14
| ||
03:07 | rewrite safekill to use X properties instead of hacking a flag into the window class check-in: 795f87aa54 user: lexi tags: trunk | |
Changes
Modified bgrd.c from [1814ca81a5] to [d69c7e1283].
1 1 /* [ʞ] bgrd.c 2 2 * ~ lexi hale <lexi@hale.su> 3 3 * $ cc -Ofast bgrd.c -lutil -obgrd 4 4 * © affero general public license 3.0 5 5 6 - * i am angry beyond words that this program had to 7 - * be written 6 + * i am angry beyond words that this program had to be 7 + * written 8 8 * 9 - * bgrd "background read" is a tool for launching an 10 - * application and retrieving the first line of output. 11 - * this is a nontrivial task for a number of reasons, 12 - * all of which are incredibly stupid, however, most 9 + * bgrd "background read" is a tool for launching an 10 + * application and retrieving the first line of output. 11 + * this is a nontrivial task for a number of reasons, 12 + * all of which are incredibly stupid, however, most 13 13 * saliently: buffered io. 14 14 * 15 - * the suckmore web browser `surf` has an option '-x' 16 - * which is intended to print the X window id of the 17 - * window it opens, so it can be captured and used in 15 + * the suckmore web browser `surf` has an option '-x' 16 + * which is intended to print the X window id of the 17 + * window it opens, so it can be captured and used in 18 18 * scripts. so far so good. 19 19 * 20 - * except unix has two distinctly different concepts 21 - * of IO. there's POSIX IO, and then there's libc IO. 20 + * except unix has two distinctly different concepts of 21 + * IO. there's POSIX IO, and then there's libc IO. 22 22 * 23 - * POSIX IO uses the shit in <fcntl.h> and <unistd.h>; 24 - * syscalls like read(2), write(2), and pipe(2) - the 25 - * good, simple shit God made unix for. this is really 26 - * bare-metal; these are basically C wrappers over 27 - * kernel syscalls. POSIX IO uses plain old ints as 28 - * file descriptors, and it doesn't fuck around. when 29 - * you say "write," god dammit, it WRITES. 23 + * POSIX IO uses the shit in <fcntl.h> and <unistd.h>; 24 + * syscalls like read(2), write(2), and pipe(2) - the 25 + * good, simple shit God made unix for. this is really 26 + * bare-metal; these are basically C wrappers over kernel 27 + * syscalls. POSIX IO uses plain old ints as file 28 + * descriptors, and it doesn't fuck around. when you say 29 + * "write," god dammit, it WRITES. 30 30 * 31 - * libc is a very different beast. libc has opinions. 32 - * libc has abstractions. libc has its own entire 33 - * goddamn DSL by which to specify format strings, 34 - * because apparently someone felt called to reinvent 35 - * FORTRAN except worse. printf(), you know, the first 36 - * function they ever teach you in C 101? (more like CS 37 - * 403 these days, but aghhh) it's actually a heinously 31 + * libc is a very different beast. libc has opinions. 32 + * libc has abstractions. libc has its own entire goddamn 33 + * DSL by which to specify format strings, because 34 + * apparently someone felt called to reinvent FORTRAN 35 + * except worse. printf(), you know, the first function 36 + * they ever teach you in C 101? (more like CS 403 37 + * these days, but aghhh) it's actually a heinously 38 38 * complicated, dangerous, slow, insecure mess that drags 39 - * a ridiculous amount of background bullshit into the 39 + * a ridiculous amount of background bullshit into the 40 40 * frame. such as BUFFERING. 41 41 * 42 - * libc, you see, is too good to just wrap write() and 43 - * read(). no, it also has to decide when to SEND them. 44 - * this is responsible for that behavior every c coder 45 - * trips over eventually - you know the one, where if 46 - * you don't end your format string in '\n' it isn't 47 - * printed, sometimes even if the program exits. this 48 - * is not actually a POSIX thing; it's a libc thing. 42 + * libc, you see, is too good to just wrap write() and 43 + * read(). no, it also has to decide when to SEND them. 44 + * this is responsible for that behavior every c coder 45 + * trips over eventually - you know the one, where if you 46 + * don't end your format string in '\n' it isn't printed, 47 + * sometimes even if the program exits. this is not 48 + * actually a POSIX thing; it's a libc thing. 49 49 * 50 50 * libc has a couple different kinds of buffering tactics 51 - * (set with setvbuf(), a function nobody seems to know 52 - * exists) that it uses in different circumstances. 53 - * the printf \n gotcha behavior is what's known as 54 - * "line buffering." however, because libc thinks it's 55 - * fucking smart or something, it's not content to just 56 - * pick one predictable behavior and stick to it. oh no. 51 + * (set with setvbuf(), a function nobody seems to know 52 + * exists) that it uses in different circumstances. the 53 + * printf \n gotcha behavior is what's known as "line 54 + * buffering." however, because libc thinks it's fucking 55 + * smart or something, it's not content to just pick one 56 + * predictable behavior and stick to it. oh no. 57 57 * 58 - * ever noticed how programs can seem to tell whether 59 - * they're connected to a terminal (and thus can output 60 - * all those fancy ansi formatting codes), or whether 61 - * you're redirecting their stdout to a file? that's 62 - * because there's more than one kind of pipe. the kind 58 + * ever noticed how programs can seem to tell whether 59 + * they're connected to a terminal (and thus can output 60 + * all those fancy ansi formatting codes), or whether 61 + * you're redirecting their stdout to a file? that's 62 + * because there's more than one kind of pipe. the kind 63 63 * you create with pipe(2) - and the kind you create with 64 64 * openpty(2). 65 65 * 66 - * a pty is, essentially, a kind of pipe that carries 67 - * extra information around, the information you access 66 + * a pty is, essentially, a kind of pipe that carries 67 + * extra information around, the information you access 68 68 * via ioctl and termios. it's designed to imitate a TTY, 69 - * so that a shell can create one, aim a process at it, 70 - * and then that process can draw TUIs and shit on it. 71 - * and some programs are designed to behave differently 72 - * depending on whether they're hooked up to a pipe or a 69 + * so that a shell can create one, aim a process at it, 70 + * and then that process can draw TUIs and shit on it. 71 + * and some programs are designed to behave differently 72 + * depending on whether they're hooked up to a pipe or a 73 73 * pty. 74 74 * 75 75 * libc, tragically, is among them. 76 76 * 77 - * if libc notices it's hooked up to a pipe instead of a pty, 78 - * it will change its default buffering strategy. newlines 79 - * will suddenly cease flushing stdout, and libc will 80 - * only print its buffer in one of two circumstances: the 81 - * buffer is filled up, or the program exits. 77 + * if libc notices it's hooked up to a pipe instead of a 78 + * pty, it will change its default buffering strategy. 79 + * newlines will suddenly cease flushing stdout, and 80 + * libc will only print its buffer in one of two 81 + * circumstances: the buffer is filled up, or the program 82 + * exits. 82 83 * 83 - * this is a problem if you are, say, trying to output a 84 - * handle that scripts can use to control the running 84 + * this is a problem if you are, say, trying to output a 85 + * handle that scripts can use to control the running 85 86 * program. 86 87 * 87 - * the `surf` developers had a couple of options. they 88 - * could have simply broken out the POSIX headers and 89 - * sent the X id to stdout with a call to write(2), the 90 - * correct thing to do. they could have thrown in a call 91 - * to setvbuf(3) to explicitly pick a buffering strategy 92 - * compatible with their usecase, the sensibly wrong 88 + * the `surf` developers had a couple of options. they 89 + * could have simply broken out the POSIX headers and 90 + * sent the X id to stdout with a call to write(2), the 91 + * correct thing to do. they could have thrown in a call 92 + * to setvbuf(3) to explicitly pick a buffering strategy 93 + * compatible with their usecase, the sensibly wrong 93 94 * thing to do. they could have explicitly flushed stdout 94 - * after printf(3)'ing to it, the dumb and error-pront 95 + * after printf(3)'ing to it, the dumb and error-pront 95 96 * thing to do. 96 97 * 97 98 * instead, they did *nothing.* 98 99 * 99 - * so if you run `surf -x` from a terminal, great! 100 - * you'll see it print the x window id first thing. 101 - * you'll then try to capture it via any number of 102 - * increasing desperate means, all of which will fail 103 - * hilariously. finally, you'll spend four goddamn hours 104 - * after midnight reading source code and manpages and 105 - * frantically googling around and digging up unix lore 106 - * and finally, FINALLY figure out what the batshit FUCK 107 - * is going on, and write this goddamn utility to hack 100 + * so if you run `surf -x` from a terminal, great! 101 + * you'll see it print the x window id first thing. 102 + * you'll then try to capture it via any number of 103 + * increasing desperate means, all of which will fail 104 + * hilariously. finally, you'll spend four goddamn hours 105 + * after midnight reading source code and manpages and 106 + * frantically googling around and digging up unix lore 107 + * and finally, FINALLY figure out what the batshit FUCK 108 + * is going on, and write this goddamn utility to hack 108 109 * around the suckmore crowd's suckitude. 109 110 * 110 111 * so i figured i'd save you some time. 111 112 * 112 - * i am probably going to submit a PR eventually because 113 + * i am probably going to submit a PR eventually because 113 114 * holy hell this is just so monumentally bozotic. 114 115 * 115 - * in the mean time, you can use this extremely 116 - * no-bullshit wrapper by running `set surfwin (bgrd 117 - * (which surf) surf -x <params>` or whatever the bash 118 - * equivalent is and it will immediately launch surf in 119 - * the background, printing the X window and exiting 120 - * as soon as it hits a newline. it should be adaptable 121 - * to similar scenarios if you find yourself dealing with 116 + * in the mean time, you can use this extremely 117 + * no-bullshit wrapper by running `set surfwin (bgrd 118 + * (which surf) surf -x <params>` or whatever the bash 119 + * equivalent is and it will immediately launch surf in 120 + * the background, printing the X window and exiting as 121 + * soon as it hits a newline. it should be adaptable to 122 + * similar scenarios if you find yourself dealing with 122 123 * similarly broken software tho. 123 124 * 124 125 * in conclusion, read lenin. */ 125 126 126 127 #include <stdio.h> 127 128 #include <unistd.h> 128 129 #include <fcntl.h>
Added smake.c version [8f8960ef17].
1 +/* [ʞ] smake.c <c.hale.su/lexi/util> 2 + * ~ lexi hale <lexi@hale.su> 3 + * $ cc -Ofast smake.c -osmake 4 + * © affero general public license 5 + 6 + * I N C O M P L E T E * 7 + | basic functionality is still | 8 + | heavily under development | 9 + 10 + * a replacement for sassc --watch, smake maintains an 11 + * in-memory dependency graph for the specified files 12 + * and automatically re-compiles them when they or a 13 + * dependency of theirs changes 14 + 15 + TODO add switch to generate makefile from constructed 16 + graph and exit */ 17 + 18 +#include <stdio.h> 19 +#include <stdlib.h> 20 +#include <string.h> 21 +#include <unistd.h> 22 +#include <fcntl.h> 23 +#include <sys/mman.h> 24 + 25 +enum e { ok, badname, nofile }; 26 +enum kind { css, sass, scss, bad }; 27 +typedef enum { false, true } bool; 28 + 29 +#define corebufsz 1024 30 +char corebuf[corebufsz]; 31 +void* extbuf, * bufptr; 32 +size_t run = 0; 33 +#define max(a,b) (a > b ? a : b) 34 + 35 +void* alloc(size_t sz) { 36 + if((bufptr + sz) < ((void*)corebuf + corebufsz)) goto mkptr; 37 + else { 38 + if (run == 0) { 39 + run = corebufsz; 40 + extbuf = malloc(run); 41 + bufptr = extbuf + sz; 42 + return extbuf; 43 + } else { 44 + if ((bufptr + sz) < (extbuf + run)) goto mkptr; 45 + else { 46 + run += max(512, sz+128); 47 + size_t rsz = bufptr-extbuf; 48 + extbuf = realloc(extbuf, run); 49 + bufptr = extbuf + rsz + sz; 50 + return bufptr - sz; 51 + } 52 + } 53 + } 54 + // this point should never be reached 55 + mkptr: { 56 + void* ret = bufptr; 57 + bufptr += sz; 58 + return ret; 59 + } 60 +} 61 + 62 + 63 + 64 +struct file { 65 + char* src; 66 + char* out; 67 + enum kind kind; 68 + struct dep* deplink; 69 +}; 70 + 71 +struct dep { struct file* f; struct dep* nextdep; }; 72 + 73 +void readfile(struct file* f, char* src) { 74 + f->src = src; 75 + 76 + int fd = open(src, O_RDONLY); 77 + int sz = lseek(fd,0,SEEK_END); lseek(fd,0,SEEK_SET); 78 + char* file = mmap(0,sz,PROT_READ,MAP_PRIVATE,fd,0); 79 + close(fd); 80 + 81 + char namebuf[256]; 82 + char* namecur = namebuf; 83 + char* cur = file; 84 + 85 + char strqt = 0; 86 + 87 +read_start: 88 + if (*cur == 0) goto read_done; 89 + if (*cur == '"') { ++ cur; strqt = '"'; goto read_string; } 90 + if (*cur == '\'') { ++ cur; strqt = '\''; goto read_string; } 91 + if (*cur == '(') { ++ cur; strqt = ')'; goto read_string; } 92 + if (*cur == '[') { ++ cur; strqt = ']'; goto read_string; } 93 + if (*cur == '/') { 94 + switch(cur[1]) { 95 + case '/': goto skip_line; 96 + case '*': cur += 2; goto read_ml_comment; 97 + case 0: goto read_done; 98 + } 99 + ++cur; goto read_start; 100 + } 101 + if (*cur == '@') { 102 + if (strncmp(cur+1, "import", 6) == 0) { 103 + cur += 7; goto read_import; 104 + } 105 + } 106 + ++cur; goto read_start; 107 + 108 +read_import: 109 + if (*cur == ' ' || *cur == '\t' || *cur == '\n') { 110 + ++cur; goto read_import; 111 + } else if (*cur == 'u' && cur[1] == 'r' && cur[2] == 'l') { 112 + strqt=')'; goto read_string; 113 + } else if (*cur == '"' || *cur=='\'') { 114 + strqt=*cur; 115 + while(*++cur != strqt) { 116 + if (*cur == '\\' && cur[1] == strqt) { 117 + *namecur++=strqt; cur += 2; 118 + // FIXME support other escapes 119 + } else { 120 + *namecur++=*cur; 121 + } 122 + } 123 + *namecur = 0; 124 + printf("found import to %s;\n", namebuf); 125 + namecur = namebuf; 126 + } 127 + ++cur; goto read_start; 128 + 129 +read_string: 130 + if (*cur == 0) goto read_done; //unterminated string!? 131 + if (*cur++ == strqt) goto read_start; 132 + goto read_string; 133 + 134 +read_ml_comment: 135 + if (*cur == 0) goto read_done; //unterminated comment! 136 + if (*cur == '*' && cur[1] == '/') { 137 + cur += 2; 138 + goto read_start; 139 + } 140 + ++cur; goto read_ml_comment; 141 + 142 +skip_line: 143 + if (*cur == 0) goto read_done; 144 + if (*cur++ == '\n') goto read_start; 145 + goto skip_line; 146 + 147 +read_done: 148 + 149 + munmap(file,sz); 150 +} 151 + 152 +enum e parsename(struct file* f) { 153 + char* ext = NULL; 154 + char* path = f->src; 155 + 156 + while(*path++!=0) { 157 + if(*path == '.') ext = path + 1; 158 + } 159 + 160 + 161 + if(ext == NULL) return badname; 162 + 163 + // quickly determine file type 164 + if (ext[0] == 's' 165 + && ext[2] == 's' 166 + && ext[3] == 's') { 167 + if (ext[1] == 'c') f -> kind = scss; 168 + else if (ext[1] == 'a') f -> kind = sass; 169 + else f -> kind = bad; 170 + } else if (ext[0] == 'c' 171 + && ext[1] == 's' 172 + && ext[2] == 's' ) f -> kind = css; 173 + else f -> kind = bad; 174 + 175 + if(f -> kind == sass || f -> kind == scss) { 176 + size_t sz = (ext - f->src); 177 + f->out = alloc(sz + 4); 178 + strncpy(f->out, f->src, sz); 179 + f->out[sz+0] = 'c'; 180 + f->out[sz+1] = 's'; 181 + f->out[sz+2] = 's'; 182 + f->out[sz+3] = 0; 183 + } else f -> out = f -> src; 184 + 185 + printf("src %s; dst %s; ext %s;\n", f->src,f->out,ext); 186 +} 187 + 188 +int main(int argc, char** argv) { 189 + bufptr = corebuf; 190 + struct file top; 191 + readfile(&top, argv[1]); 192 + parsename(&top); 193 +}
Added xpriv.c version [c67b168cf4].
1 +/* [ʞ] xpriv.c <c.hale.su/lexi/util> 2 + * ~ lexi hale <lexi@hale.su> 3 + * $ cc -Ofast xpriv.c -lrt -lutil -lX11 -oxpriv 4 + * © affero general public license 5 + 6 + * xpriv.c is a tool for a very specific use case i have. 7 + * for security's sake, i don't tie my ssh keys to my 8 + * login session. when i intend to use them, i spawn a 9 + * special terminal and load the keys into memory, then 10 + * exit that terminal when i'm done using them. however, 11 + * i often lose track of or accidentally kill that win- 12 + * dow, despite adding a visual cue to its prompt. 13 + * safekill.c was one half of my attempt to address this 14 + * problem; this is the other. 15 + * 16 + * xpriv performs several different tasks to accomplish a 17 + * single purpose: i can hit a single keystroke that 18 + * will either conjure up a new privileged session, or 19 + * switch to one that's already active if it exists. it 20 + * does this by first checking for the existence of a 21 + * shared memory segment. if it doesn't find it, it 22 + * starts a new session; if it *does* find it, it 23 + * retrieves the X11 window ID from that shared memory 24 + * and sends a _NET_ACTIVE_WINDOW client message to the 25 + * root X window. the window manager interprets message, 26 + * activating the window. 27 + * 28 + * the flag -k can also be passed, in which case the 29 + * utility instructs the running process to liquidate its 30 + * subprocesses and exit itself. 31 + * 32 + * if the shared memory does not exist, xpriv creates a 33 + * new instance of urxvt. this instance is told to run 34 + * the command “xpriv -a” instead of the user’s normal 35 + * shell. the -a flag instructs xpriv to get the terminal 36 + * window’s ID from the $WINDOWID environment variable 37 + * which urxvt sets. after this, a ssh-agent process is 38 + * launched. spriv waits until it has opened a socket and 39 + * then runs ssh-add without parameters to add the user's 40 + * default keys to the session. 41 + * 42 + * xpriv does its best to clean up after itself, 43 + * killing all sensitive processes and their children and 44 + * removing the shmem segment when it is no longer in 45 + * use, even if exits somewhat abnormally. if you have to 46 + * kill -9 xpriv at any point tho, you can make it work 47 + * again (on linux) with 48 + * rm /dev/shm/k.xpriv:(xpriv binary basename) 49 + * 50 + * you can have multiple xpriv sessions by creating soft- 51 + * links to the binary with a different name for each. 52 + 53 + TODO send signal to urxvtd directly instead of launching 54 + urxvtc as a separate process 55 + 56 + TODO make shell & commands performed configurable, with 57 + flags to control or supplant ssh-agent 58 + 59 + TODO add a randomizer call that works on BSD 60 + 61 + TODO document flags 62 + 63 + TODO implement/remove lock flag 64 + 65 + TODO add flag to bring window to current desktop */ 66 + 67 + 68 +#include <pwd.h> 69 +#include <pty.h> 70 +#include <fcntl.h> 71 +#include <unistd.h> 72 +#include <stdint.h> 73 +#include <stdlib.h> 74 +#include <string.h> 75 +#include <signal.h> 76 +#include <sys/mman.h> 77 +#include <sys/stat.h> 78 +#include <sys/wait.h> 79 +#include <sys/types.h> 80 +#include <X11/Xlib.h> 81 +#include <errno.h> 82 +#include <sys/random.h> //TODO bsd compat 83 + 84 +#define shmem_prefix "/k.xpriv:" 85 + 86 +typedef enum { false, true } bool; 87 +enum mode { mode_usage, mode_go, mode_register, 88 + mode_kill, mode_lock }; 89 + 90 +enum res { ok, fail_parse, fail_arg, fail_opt, fail_shm, 91 + fail_mem, fail_pty, fail_nop, fail_win, 92 + fail_wid, fail_x11}; 93 +enum res bad(enum res code) { 94 + if (code == ok) return ok; 95 + 96 + write(1,"\e[1m|e|\e[0m ",12); 97 + const char* msg; uint8_t len; 98 + switch(code) { 99 + #define say(x) { msg = (x "\n"); len = (sizeof x) + 1; break; } 100 + case fail_parse: say("could not parse command-line options; pass -u for usage"); 101 + case fail_arg : say("invalid argument provided"); 102 + case fail_opt : say("no such option"); 103 + case fail_shm : say("instance already running"); 104 + case fail_mem : say("could not map memory"); 105 + case fail_pty : say("could not alloc pty"); 106 + case fail_nop : say("no instance running"); 107 + case fail_win : say("cannot open display"); 108 + case fail_wid : say("WINDOWID not defined"); 109 + case fail_x11 : say("X server refuses to handle request"); 110 + #undef say 111 + } 112 + write(1, msg, len); 113 + return code; 114 +} 115 + 116 +struct signal { 117 + Window wid; 118 + pid_t pid; 119 + pid_t agent; 120 + enum mode op; 121 +}*global; 122 + 123 +char* itoa(unsigned long i, char* buf, size_t bufsz) { 124 + char* cur = buf + bufsz; 125 + while (cur >= buf) { 126 + *--cur='0' + i % 10; 127 + if (i < 10) break; else i /= 10; 128 + } 129 + return cur; 130 +} 131 + 132 +bool run; 133 + 134 +struct termios initial_state; 135 + 136 +void sigusr(int a) { if (global -> op == mode_kill) run = false; } 137 +void sigterm(int a) { run = false; } 138 + 139 +enum res register_window(const char* id, bool weak) { 140 + // the id field denotes the path to the shared memory 141 + // in use, and allows the user to have multiple 142 + // contexts by creating aliases to the binary 143 + int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600); 144 + ftruncate(fd, sizeof(struct signal)); 145 + if (fd == -1) return fail_shm; 146 + 147 + struct signal* s = mmap(0, sizeof(struct signal), 148 + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 149 + if(s == MAP_FAILED) return fail_mem; 150 + else global = s; 151 + 152 + Display* xdpy = XOpenDisplay(NULL); 153 + Atom xvital; 154 + 155 + /* x11 */ { 156 + if (xdpy == NULL) return fail_win; 157 + Window win; 158 + const char* winid_s; 159 + if (!(winid_s = getenv("WINDOWID"))) return fail_wid; 160 + win=(Window)strtol(winid_s,NULL,10); 161 + if(weak == false) xvital = XInternAtom(xdpy,"_k_vital",false); 162 + s -> wid = win; 163 + } 164 + 165 + pid_t child; 166 + if(child = fork()) { 167 + s -> pid = child; 168 + sigset_t mask, oldmask; 169 + sigemptyset(&mask); 170 + sigaddset(&mask, SIGUSR1); 171 + sigprocmask(SIG_BLOCK, &mask, &oldmask); 172 + 173 + signal(SIGUSR1, sigusr); 174 + signal(SIGTERM, sigterm); 175 + signal(SIGCHLD, sigterm); 176 + signal(SIGHUP, sigterm); 177 + 178 + run = true; 179 + while(run == true) { 180 + sigsuspend(&oldmask); 181 + } 182 + 183 + if(s -> op == mode_kill) { 184 + kill(s -> pid, SIGTERM); 185 + } 186 + kill(s -> agent, SIGTERM); 187 + sigprocmask(SIG_BLOCK, &mask, NULL); 188 + shm_unlink(id); 189 + if (!weak) { 190 + XDeleteProperty(xdpy,s -> wid,xvital); 191 + XSync(xdpy,false); 192 + } 193 + XCloseDisplay(xdpy); 194 + } else { 195 + // now we start ssh-agent and set the proper environment 196 + // variables 197 + pid_t ssha; 198 + 199 + /* messy part */ { 200 + const char* tmp; //tmpdir defined? 201 + if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp"; 202 + size_t tmpsz = strlen(tmp); 203 + 204 + char sockn[tmpsz + 1 + sizeof "ssh." 205 + + 11]; 206 + strcpy(sockn, tmp); 207 + sockn[tmpsz] = '/'; 208 + strcpy(sockn+tmpsz+1,"ssh."); 209 + 210 + // first, gen a random identifier so we have the ability 211 + // to know where the socket winds up 212 + uint8_t* rndid = sockn+tmpsz+1+4; 213 + getrandom(rndid, 11, 0); 214 + 215 + // assuming ascii… 216 + for(uint8_t*i=rndid;i<rndid+11;++i) { 217 + *i = '0' + (*i % (25 * 2 + 10)); 218 + if (*i > '9') *i += 7; 219 + if (*i > 'Z') *i += ('a' - 'Z'); 220 + } 221 + 222 + if (ssha = fork()) { 223 + char pid_s_buf[16]; 224 + char* pid_s = itoa(ssha, pid_s_buf, sizeof(pid_s_buf)); 225 + while (access(sockn, F_OK)); 226 + // avoid nasty race condition 227 + setenv("SSH_AGENT_PID", pid_s, true); 228 + setenv("SSH_AUTH_SOCK", sockn, true); 229 + s -> agent = ssha; 230 + } else { 231 + close(1); close(0); 232 + execlp("ssh-agent","ssh-agent","-D", "-a",sockn,0); 233 + } 234 + } 235 + 236 + pid_t sad; 237 + int p; 238 + if (sad = fork()) { 239 + int added; 240 + waitpid(sad, &added, 0); 241 + if (added == 0) { 242 + if (weak == false) { 243 + XChangeProperty(xdpy,s -> wid,xvital,xvital,8,PropModeReplace,"\01", 1); 244 + XSync(xdpy,false); 245 + } 246 + write(1,"\033c",3); 247 + execlp("fish","fish",NULL); 248 + } else { return ok; } 249 + } else { 250 + execlp("ssh-add","ssh-add",NULL); 251 + } 252 + } 253 + 254 + return ok; // this is kind of pointless but w/e 255 +} 256 +enum res kill_window(const char* id) { 257 + int fd = shm_open(id, O_RDWR, 0600); 258 + if (fd == -1) return fail_nop; 259 + 260 + struct signal* s = mmap(0, sizeof(struct signal), 261 + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 262 + if(s == MAP_FAILED) return fail_mem; 263 + 264 + s -> op = mode_kill; 265 + kill(s -> pid, SIGUSR1); 266 + 267 + return ok; 268 +} 269 +enum res activate_window(Window w) { 270 + Display* dpy = XOpenDisplay(NULL); 271 + XEvent ev; 272 + long mask = SubstructureRedirectMask | SubstructureNotifyMask; 273 + ev.xclient.type = ClientMessage; 274 + ev.xclient.serial = 0; 275 + ev.xclient.send_event = True; 276 + ev.xclient.message_type = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 277 + ev.xclient.display = dpy; 278 + ev.xclient.window = w; 279 + ev.xclient.format = 32; 280 + ev.xclient.data.l[0] = 2; 281 + ev.xclient.data.l[1] = CurrentTime; 282 + ev.xclient.data.l[2] = 0; 283 + 284 + if(!XSendEvent(dpy, DefaultRootWindow(dpy), False, mask, &ev)) return fail_x11; 285 + 286 + XSync(dpy,false); 287 + return ok; 288 +} 289 + 290 +int main(int sz, char** argv) { 291 + enum mode op = mode_go; 292 + bool init_weak = false; 293 + 294 + for(int i = 1; i<sz; ++i) { 295 + char* v = argv[i]; 296 + if (*v != '-') return bad(fail_arg); 297 + char* opt = v + 1; 298 + read_opt: 299 + switch(*opt) { 300 + case 'a': op = mode_register; break; 301 + case 'k': op = mode_kill; break; 302 + case 'l': op = mode_lock; break; 303 + case 'h': op = mode_usage; break; 304 + case 'w': init_weak = true; break; 305 + default: return bad(fail_opt); 306 + } 307 + if(opt[1] != 0) { ++opt; goto read_opt; } 308 + } 309 + 310 + size_t nsz; 311 + const char* basename, *p; 312 + for (p = argv[0]; *p!=0; ++p) { 313 + if(*p == '/') basename = p + 1; 314 + } 315 + nsz = p - basename; 316 + char shid[nsz + sizeof shmem_prefix + 0]; 317 + strncpy(shid,shmem_prefix,sizeof shmem_prefix); 318 + strncpy(shid + sizeof shmem_prefix - 1, basename, nsz); 319 + 320 + if (op == mode_go) { 321 + int fd; 322 + if ((fd = shm_open(shid, O_RDWR, 0600)) == -1) { 323 + execlp("urxvtc", "urxvtc", "-bg", "[80]#4b0024", 324 + "-e", argv[0], (init_weak?"-aw":"-a"), 0); 325 + } else { 326 + struct signal*s = mmap(0, sizeof(struct signal), 327 + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 328 + return bad(activate_window(s->wid)); 329 + } 330 + } else if (op == mode_register) 331 + return bad(register_window(shid,init_weak)); 332 + else if (op == mode_kill) 333 + return bad(kill_window(shid)); 334 + else if (op == mode_usage) { 335 + write(1,"\e[1musage:\e[0m ",15); 336 + write(1, argv[0], strlen(argv[0])); 337 + write(1, " [-aklw [arg]]\n",16); 338 + return fail_parse; 339 + } 340 +} 341 +