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