Overview
Comment: | add bgrd |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
011cb3726d7358bc63d1d8c98d536fcf |
User & Date: | lexi on 2019-04-13 11:22:59 |
Other Links: | manifest | tags |
Context
2019-04-13
| ||
13:44 | fix typo check-in: ee4f58caef user: lexi tags: trunk | |
11:22 | add bgrd check-in: 011cb3726d user: lexi tags: trunk | |
2019-04-12
| ||
00:49 | make safekill use _NET_CLOSE_WINDOW extension where available instead of XDestroyWindow, which is super unfriendly and frequently crashes or hard-locks multi-window applications. XDestroyWindow is still available as a fallback if the extension fails; `export k_safekill_fallback=0` to stop this check-in: 12c34052e4 user: lexi tags: trunk | |
Changes
Added bgrd.c version [f9254ef448].
1 +/* [ʞ] bgrd.c 2 + * ~ lexi hale <lexi@hale.su> 3 + * $ cc -Ofast bgread.c -lutil -obgrd 4 + * © affero general public license 3.0 5 + 6 + * i am angry beyond words that this program had to 7 + * be written 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 13 + * saliently: buffered io. 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 18 + * scripts. so far so good. 19 + * 20 + * except unix has two distinctly different concepts 21 + * of IO. there's POSIX IO, and then there's libc IO. 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. 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 38 + * complicated, dangerous, slow, insecure mess that drags 39 + * a ridiculous amount of background bullshit into the 40 + * frame. such as BUFFERING. 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. 49 + * 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. 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 63 + * you create with pipe(2) - and the kind you create with 64 + * openpty(2). 65 + * 66 + * a pty is, essentially, a kind of pipe that carries 67 + * extra information around, the information you access 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 73 + * pty. 74 + * 75 + * libc, tragically, is among them. 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. 82 + * 83 + * this is a problem if you are, say, trying to output a 84 + * handle that scripts can use to control the running 85 + * program. 86 + * 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 93 + * thing to do. they could have explicitly flushed stdout 94 + * after printf(3)'ing to it, the dumb and error-pront 95 + * thing to do. 96 + * 97 + * instead, they did *nothing.* 98 + * 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 108 + * around the suckmore crowd's suckitude. 109 + * 110 + * so i figured i'd save you some time. 111 + * 112 + * i am probably going to submit a PR eventually because 113 + * holy hell this is just so monumentally bozotic. 114 + * 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 122 + * similarly broken software tho. 123 + * 124 + * in conclusion, read lenin. */ 125 + 126 +#include <stdio.h> 127 +#include <unistd.h> 128 +#include <fcntl.h> 129 +#include <stdint.h> 130 +#include <pty.h> 131 + 132 +int main(int argc, char** argv) { 133 + // pipe fd handles 134 + int wr, rd; 135 + 136 + // populate the pipe 137 + openpty(&wr, &rd, NULL, NULL, NULL); 138 + 139 + // note ptys and pipes use basically the same 140 + // interface; you can use one as a drop-in 141 + // replacement for the other, tho the creation 142 + // function syntax is a bit different. 143 + 144 + if(fork()) goto master; 145 + else goto child; 146 + 147 + master: { 148 + close(wr); 149 + char buf[256]; size_t sz; 150 + while(sz = read(rd, buf, 255)) { 151 + buf[sz]=0; 152 + for (size_t i=0;i<sz;++i) { 153 + if (buf[i] == '\n') { 154 + write(1,buf,i); 155 + // got what we came for, time to blow 156 + // this popsicle stand. 157 + goto leave; // bite me, dijkstra 158 + } 159 + } 160 + write(1,buf,sz); 161 + } 162 + } 163 + 164 + leave: { 165 + close(rd); 166 + return 0; 167 + } 168 + 169 + child: { 170 + close(rd); 171 + 172 + // redirect stdout and stderr to our pty master 173 + dup2(wr, 1); 174 + dup2(wr, 2); 175 + close(wr); 176 + 177 + execv(argv[1],argv+2); 178 + return 1; // THIS SHOULD NEVER HAPPEN 179 + } 180 +}
Modified readme.md from [2513df755d] to [2e8787ac9f].
1 1 # util 2 2 various odds and ends. all code in this repository is licensed under the AGPL unless otherwise noted. 3 3 4 4 * **safekill.c**: utility to help keep from accidentally killing important windows; compile with `cc -Ofast safekill.c -lX11 -lc -osafekill` 5 +* **bgrd.c**: it’s… a long story. just read the header.
Modified safekill.c from [54b90bee6d] to [95fcf40cb0].
1 1 /* [ʞ] safekill.c <c.hale.su/lexi/util> 2 2 * ~ lexi hale <lexi@hale.su> 3 3 * $ cc -Ofast safekill.c -lX11 -lc -osafekill 4 4 * © affero general public license 5 + 5 6 * a utility to make it harder to accidentally nuke 6 7 * important windows on i3wm or whatever. */ 7 8 8 9 #include <X11/Xlib.h> 9 10 #include <X11/Xutil.h> 10 11 #include <X11/Xatom.h> 11 12 #include <stdio.h>