util  Check-in [196f94b613]

Overview
Comment:add shit, updates
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 196f94b613f23e130e98ecbce7965ed5baa3a9b15a6a05c8b5d997e966d28be1
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  +