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
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
/* [ʞ] bgrd.c
 *  ~ lexi hale <lexi@hale.su>
 *  $ cc -Ofast bgread.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>
#include <stdint.h>
#include <pty.h>

int main(int argc, char** argv) {
	// pipe fd handles
	int wr, rd;
	
	// populate the pipe
	openpty(&wr, &rd, NULL, NULL, NULL);

	// note ptys and pipes use basically the same
	// interface; you can use one as a drop-in
	// replacement for the other, tho the creation
	// function syntax is a bit different.

	if(fork()) goto master;
	      else goto child;

	master: {
		close(wr);
		char buf[256]; size_t sz;
		while(sz = read(rd, buf, 255)) {
			buf[sz]=0;
			for (size_t i=0;i<sz;++i) {
				if (buf[i] == '\n') {
					write(1,buf,i);
					// got what we came for, time to blow
					// this popsicle stand.
					goto leave; // bite me, dijkstra
				}
			}
			write(1,buf,sz);
		}
	}

	leave: {
		close(rd);
		return 0;
	}

	child: {
		close(rd);
		
		// redirect stdout and stderr to our pty master
		dup2(wr, 1);
		dup2(wr, 2);
		close(wr);

		execv(argv[1],argv+2);
		return 1; // THIS SHOULD NEVER HAPPEN
	}
}

Modified readme.md from [2513df755d] to [2e8787ac9f].

1
2
3
4

# util
various odds and ends. all code in this repository is licensed under the AGPL unless otherwise noted.

* **safekill.c**: utility to help keep from accidentally killing important windows; compile with `cc -Ofast safekill.c -lX11 -lc -osafekill`





>
1
2
3
4
5
# util
various odds and ends. all code in this repository is licensed under the AGPL unless otherwise noted.

* **safekill.c**: utility to help keep from accidentally killing important windows; compile with `cc -Ofast safekill.c -lX11 -lc -osafekill`
* **bgrd.c**: it’s… a long story. just read the header.

Modified safekill.c from [54b90bee6d] to [95fcf40cb0].

1
2
3
4

5
6
7
8
9
10
11
/* [ʞ] safekill.c <c.hale.su/lexi/util>
 *  ~ lexi hale <lexi@hale.su>
 *  $ cc -Ofast safekill.c -lX11 -lc -osafekill
 *  © affero general public license

 * a utility to make it harder to accidentally nuke
 * important windows on i3wm or whatever. */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>




>







1
2
3
4
5
6
7
8
9
10
11
12
/* [ʞ] safekill.c <c.hale.su/lexi/util>
 *  ~ lexi hale <lexi@hale.su>
 *  $ cc -Ofast safekill.c -lX11 -lc -osafekill
 *  © affero general public license
 
 * a utility to make it harder to accidentally nuke
 * important windows on i3wm or whatever. */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>