util  Check-in [011cb3726d]

Overview
Comment:add bgrd
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 011cb3726d7358bc63d1d8c98d536fcf064ce27fb31e91209c531d0e1396aea5
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>