util  Check-in [6a14de1811]

Overview
Comment:udpate xpriv to use sysv shmem by default; give iaia an option to generate its own types, and allow selecting between 7-bit and 8-bit encodings for ascii (defaulting to 8-bit); update mkpw to work with new iaia; update ord to add flag controlling byte length (7 or 8) for iaia's ascii mode
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 6a14de18116c33e773d7050066650a2c56ba3bee6a9c0b6c29519f097523a0bf
User & Date: lexi on 2019-07-20 23:37:03
Other Links: manifest | tags
Context
2019-07-21
06:15
add clipserv check-in: 5e680bdd13 user: lexi tags: trunk
2019-07-20
23:37
udpate xpriv to use sysv shmem by default; give iaia an option to generate its own types, and allow selecting between 7-bit and 8-bit encodings for ascii (defaulting to 8-bit); update mkpw to work with new iaia; update ord to add flag controlling byte length (7 or 8) for iaia's ascii mode check-in: 6a14de1811 user: lexi tags: trunk
18:12
fixes check-in: 00358989c7 user: lexi tags: trunk
Changes

Modified clib/iaia.c from [f7f2775d1b] to [1d0d9f385e].

     1      1   /* [ʞ] iaia.c
     2      2    *  ~ lexi hale <lexi@hale.su>
     3      3    *  # include "iaia.c"
     4      4    *  # define _IAIA_FN_{ATOI,ITOA,ASCTOI,ITOASC}
            5  + *           _IAIA_EXP_ASCFORM
     5      6    *  : typedef iaia_word_type,
     6      7    *            iaia_error_type
     7      8    *  : enum iaia_e_domain,
     8      9    *         iaia_e_base,
     9     10    *         iaia_e_overflow
    10     11    *  ? arbitrary-base integer conversion functions
    11     12    */
................................................................................
    18     19   #endif
    19     20   #ifndef _IAIA_FN_ASCTOI
    20     21   #	define _IAIA_FN_ASCTOI asctoi
    21     22   #endif
    22     23   #ifndef _IAIA_FN_ITOASC
    23     24   #	define _IAIA_FN_ITOASC itoasc
    24     25   #endif
           26  +#ifndef _IAIA_EXP_ASCFORM
           27  +/* this is an expression that will be evaluated to
           28  + * determine whether to compress ascii to a 7-bit
           29  + * representation or to store it in 8-bit space.
           30  + *  1 = 7-bit (compressed)
           31  + *  0 = 8-bit (uncompressed) */
           32  +#	define _IAIA_EXP_ASCFORM (0)
           33  +#endif
    25     34   
    26     35   enum /* constants */ {
           36  +	base7bit = 128,
    27     37   
    28     38   	/* ascii address space */
    29     39   	numspace        = (0x39 - 0x30) + 1, /* 10 */
    30     40   	alphaspace      = (0x5a - 0x41) + 1, /* 26 */
    31     41   	smallalphaspace = (0x7a - 0x61) + 1, /* 26 */
    32     42   
    33     43   	/* base representations */
    34     44   	imaxbase = numspace + alphaspace,    /* 36 */
    35     45   	maxbase = imaxbase + smallalphaspace /* 62 */
    36     46   };
           47  +#ifndef _IAIA_EXTERNAL_TYPES
           48  +	typedef enum iaia_error_type {
           49  +		iaia_e_ok,
           50  +		iaia_e_domain,
           51  +		iaia_e_base,
           52  +		iaia_e_overflow,
           53  +	} iaia_error_type;
           54  +	typedef unsigned long long iaia_word_type;
           55  +#endif
    37     56   
    38     57   /* -- string to integer converters -- */
    39     58   
    40     59   iaia_error_type _IAIA_FN_ASCTOI(const char* s, iaia_word_type* ret) {
    41     60   	iaia_word_type val = 0;
    42         -	enum { base = 128 };
    43     61   
    44     62   	for (;*s!=null;++s) {
    45     63   		uint8_t v = *s;
    46         -		if (v > base) return iaia_e_domain;
           64  +		if (v > base7bit) return iaia_e_domain;
    47     65   
    48         -		val *= base;
           66  +		if (_IAIA_EXP_ASCFORM)
           67  +			val *= base7bit;
           68  +			else val <<= 8;
           69  +
    49     70   		val += v;
    50     71   	}
    51     72   
    52     73   	*ret = val;
    53     74   	return ok;
    54     75   }
    55     76   
................................................................................
   106    127   iaia_error_type _IAIA_FN_ITOASC(iaia_word_type val, const char* buf_start, char* buf_end, char** newbuf) {
   107    128   	char* ptr = buf_end;
   108    129   
   109    130   	*ptr-- = 0;
   110    131   	while(val > 0) {
   111    132   		if (ptr < buf_start) return iaia_e_overflow;
   112    133   		iaia_word_type rem = val % 128;
   113         -		val /= 128;
          134  +		if (_IAIA_EXP_ASCFORM)
          135  +			val /= base7bit;
          136  +			else val >>= 8;
   114    137   		*ptr-- = (char)rem;
   115    138   	}
   116    139   
   117    140   	if (newbuf != null) *newbuf = ptr + 1;
   118    141   	return ok;
   119    142   }
   120    143   

Modified mkpw.c from [2857320b30] to [4060441d9a].

    56     56   enum /* iaia errors */ {
    57     57   	iaia_e_ok = ok,
    58     58   	iaia_e_base = fail,
    59     59   	iaia_e_domain = fail,
    60     60   	iaia_e_overflow = fail,
    61     61   };
    62     62   #define _IAIA_FN_ATOI katoi
           63  +#define _IAIA_EXTERNAL_TYPES
    63     64   #include "clib/iaia.c"
    64     65   
    65     66   typedef enum {
    66     67   	tbl_ok = ok, tbl_error = fail
    67     68   } tbl_error_type;
    68     69   typedef unsigned char tbl_word_type;
    69     70   #include "clib/tbl.c"

Modified ord.c from [8e7c9355c5] to [9504e2c85c].

    81     81   	arg_asc,
    82     82   
    83     83   	arg_bin, arg_trn, arg_oct, arg_dec,
    84     84   	arg_duo, arg_hex, arg_b32, arg_b64,
    85     85   
    86     86   	switch_prefix, param_prefix,
    87     87   	switch_lowercase,
           88  +	switch_7bit,
    88     89   
    89     90   	arg_ebcdic,
    90     91   };
    91     92   
    92     93   word bases[] = {
    93     94   	[arg_asc] =  0,
    94     95   	[arg_bin] =  2,
................................................................................
   124    125   	{arg_duo, "duo"}, {arg_duo, "duodecimal"},
   125    126   	{arg_hex, "hex"}, {arg_hex, "hexadecimal"},
   126    127   
   127    128   	{arg_hex, "b32"}, {arg_hex, "base32"}, /* not padded! */
   128    129   
   129    130   	{switch_prefix, "-p"}, {switch_prefix, "--prefix"},
   130    131   	{switch_lowercase, "-l"}, {switch_lowercase, "--lowercase"},
          132  +	{switch_7bit, "-7"}, {switch_7bit, "--7bit"},
   131    133   	{param_prefix, "-m"}, {param_prefix, "--manual-prefix"},
   132    134   
   133    135   	{arg_ebcdic, "ebcdic"},
   134    136   };
   135    137   
   136    138   /* import the conversion utilities */
   137    139   typedef bad iaia_error_type;
................................................................................
   138    140   typedef word iaia_word_type;
   139    141   enum /* iaia synonyms */ {
   140    142   	iaia_e_ok = ok,
   141    143   	iaia_e_domain = bad_domain,
   142    144   	iaia_e_base = bad_base,
   143    145   	iaia_e_overflow = bad_overflow,
   144    146   };
          147  +bool ascii_7bit = false;
          148  +#define _IAIA_EXP_ASCFORM ascii_7bit
          149  +#define _IAIA_EXTERNAL_TYPES
   145    150   #include "clib/iaia.c"
   146    151   
   147    152   bad run(const int argc, const char** argv) {
   148    153   #	ifndef _POSIX_IO
   149    154   		/* fuck your buffering, it only ever makes
   150    155   		 * things worse */
   151    156   		setvbuf(stdout,null,_IONBF);
................................................................................
   161    166   	
   162    167   	bool raw = false;
   163    168   	bool prefix = false;
   164    169   	bool lowercase = false;
   165    170   
   166    171   	for (const char** arg = argv + 1; *arg != null; ++arg) {
   167    172   		uint8_t tblval;
   168         -		if (*arg[0] == '%') { ++ *arg; goto number; } else
          173  +		if (*arg[0] == '`') { ++ *arg; goto number; } else
   169    174   		if (!raw && (tblget(sz(argtbl),argtbl, *arg, &tblval) == ok)) {
   170    175   			enum argument symbol = (enum argument) tblval;
   171    176   			switch (symbol) {
   172    177   				case arg_to: {
   173    178   					if (curset == set_out) return bad_syntax;
   174    179   					else curset = set_out;
   175    180   				} break;
................................................................................
   197    202   					forposix(pfxstrlen = strlen(pfxstr));
   198    203   					++arg;
   199    204   				} break;
   200    205   
   201    206   				/* specify an automatic output prefix */
   202    207   				case switch_prefix: { prefix = true; pfxstr = null; } break;
   203    208   				case switch_lowercase: { lowercase = true; } break;
          209  +				case switch_7bit: { ascii_7bit = true; } break;
   204    210   
   205    211   				default: {
   206    212   					/* assume base shorthand */
   207    213   					base[curset] = bases[symbol];
   208    214   				}
   209    215   			}
   210    216   		} else /* bad_find */ number: {
................................................................................
   286    292   					lit("base") " " box("0-9") plus OR "asc")),
   287    293   		}, ints[] = {
   288    294   			p("default base: \x1b[94m.+\x1b[m"),
   289    295   			p("binary literal: "lit("0b") box("01") plus),
   290    296   			p("ternary literal: "lit("0t") box("012") plus),
   291    297   			p("hex literal: "lit("0x") box("0-9A-Fa-f") plus),
   292    298   			p("ascii literal: "lit("@") "\x1b[94m.+\x1b[m"),
   293         -			p("interpret any string (e.g. a keyword) as integer: " lit("%") box("0-9A-Za-z") plus),
          299  +			p("interpret any string (e.g. a keyword) as integer: " lit("`") box("0-9A-Za-z") plus),
   294    300   		}, opts[] = {
   295    301   			p("-p --prefix       : print known prefix codes on output strings"),
   296    302   			p("-m --manual-prefix: specify a manual prefix to print before each number"),
   297    303   			p("-l --lowercase    : prefer lowercase for case-insensitive bases"),
          304  +			p("-7 --7bit         : encode ascii in 7-bit space instead of keeping the"),
          305  +			p("                    eighth empty bit. if this option is used, ascii"),
          306  +			p("                    strings will be maximally compact, but will not match"),
          307  +			p("                    the way they are stored in computer memory!"),
          308  +			/* p("-u --utf           : allow non-ascii input"), */
   298    309   		};
   299    310   #	undef p
   300    311   #	undef OR
   301    312   #	undef plus
   302    313   
   303    314   #	define hl_on  "\x1b[;1m" 
   304    315   #	define hl_off "\x1b[m"

Modified xpriv.c from [6369b6f0d6] to [48a3d17a7c].

    68     68   
    69     69    TODO add a randomizer call that works on BSD
    70     70    
    71     71    TODO document flags
    72     72    
    73     73    TODO implement/remove lock flag
    74     74   
    75         - TODO add flag to bring window to current desktop */
           75  + TODO add flag to bring window to current desktop
           76  +
           77  + TODO rewrite using sysv shmem */
    76     78    
    77     79   
    78     80   #include <pwd.h>
    79     81   #include <pty.h>
    80     82   #include <fcntl.h>
    81     83   #include <unistd.h>
    82     84   #include <stdint.h>
................................................................................
    83     85   #include <stdlib.h>
    84     86   #include <string.h>
    85     87   #include <signal.h>
    86     88   #include <sys/mman.h>
    87     89   #include <sys/stat.h>
    88     90   #include <sys/wait.h>
    89     91   #include <sys/types.h>
           92  +#include <sys/shm.h>
    90     93   #include <X11/Xlib.h>
    91     94   #include <errno.h>
    92         -#include <sys/random.h> //TODO bsd compat
           95  +#include <sys/random.h>
    93     96   
    94         -#define shmem_prefix "/k.xpriv:"
           97  +#ifdef _RAND_SYSCALL
           98  +#	include <sys/syscall.h>
           99  +#	define getrandom(a,b,c) syscall(SYS_getrandom,a,b,c)
          100  +	/* this is necessary on certain platforms due to
          101  +	 * certainly ungodly libc issues, i think. */
          102  +#endif
    95    103   
    96         -typedef enum { false, true } bool;
          104  +#ifdef _SHM_LINUX
          105  +	/* xpriv was originally written with linux shared
          106  +	 * memory in mind, because i'm an idiot. i've since
          107  +	 * redesigned it to use the superior old sysv shm
          108  +	 * api that works on every other unix, not just
          109  +	 * linux, but if for some ungodly reason you want
          110  +	 * to use the linux one, then just pass -D_SHM_LINUX */
          111  +#	define shmem_prefix "/k.xpriv:"
          112  +#	define shmlinux(...) __VA_ARGS__
          113  +#	define shmsysv(...)
          114  +#else
          115  +#	define shmlinux(...) 
          116  +#	define shmsysv(...) __VA_ARGS__
          117  +#endif
          118  +
          119  +enum /* constants */ {
          120  +	false = 0, true = 1,
          121  +	shmsysv(shmem_key = 0x53373EC3,) /* ye olde magique numbre */
          122  +};
          123  +
          124  +typedef _Bool bool;
    97    125   enum mode { mode_usage, mode_go, mode_register,
    98    126   	mode_kill, mode_lock };
    99    127   
   100    128   enum res { ok, fail_parse, fail_arg, fail_opt, fail_shm,
   101    129                  fail_mem, fail_pty, fail_nop, fail_win,
   102    130                  fail_wid, fail_x11};
   103    131   enum res bad(enum res code) {
................................................................................
   146    174   void sigusr(int a) { if (global -> op == mode_kill) run = false; }
   147    175   void sigterm(int a) { run = false; }
   148    176   
   149    177   void spawn(pid_t ssha, const char* const sockn) {
   150    178   	if (ssha = fork()) {
   151    179   		char pid_s_buf[16];
   152    180   		char* pid_s = itoa(ssha, pid_s_buf, sizeof(pid_s_buf));
   153         -		while (access(sockn, F_OK));
   154         -			// avoid nasty race condition
          181  +		while (access(sockn, F_OK)); // avoid nasty race condition
   155    182   		setenv("SSH_AGENT_PID", pid_s, true);
   156    183   		setenv("SSH_AUTH_SOCK", sockn, true);
   157    184   		global -> agent = ssha;
   158    185   	} else {
   159    186   		close(1); close(0);
   160         -		execlp("ssh-agent","ssh-agent","-D", "-a",sockn,0);
          187  +		execlp("ssh-agent","ssh-agent","-D","-a",sockn,0);
   161    188   	}
   162    189   }
   163    190   
   164         -enum res register_window(const char* const id, bool weak, const char* const name) {
          191  +enum res register_window(shmlinux(const char* const id,) bool weak, const char* name) {
   165    192   	// the id field denotes the path to the shared memory
   166    193   	// in use, and allows the user to have multiple
   167    194   	// contexts by creating aliases to the binary
   168         -	int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600);
   169         -	ftruncate(fd, sizeof(struct signal));
   170         -	if (fd == -1) return fail_shm;
   171         -	
   172         -	struct signal* s = mmap(0, sizeof(struct signal),
   173         -			PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   174         -	if(s == MAP_FAILED) return fail_mem;
   175         -	else global = s;
          195  +	struct signal* s;
          196  +	shmlinux ({
          197  +		int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600);
          198  +		ftruncate(fd, sizeof(struct signal));
          199  +		if (fd == -1) return fail_shm;
          200  +		
          201  +		s = mmap(0, sizeof(struct signal),
          202  +				PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
          203  +		if(s == MAP_FAILED) return fail_mem;
          204  +		else global = s;
          205  +	}) shmsysv (int shmem;
          206  +		shmem = shmget(shmem_key, sizeof (struct signal), IPC_CREAT | 0777);
          207  +		if (shmem == -1) return fail_shm;
          208  +
          209  +		s = shmat(shmem, 0,0);
          210  +
          211  +		if (s == (void*)-1) return fail_mem;
          212  +		else global = s;
          213  +	)
   176    214   
   177    215   	Display* xdpy = XOpenDisplay(NULL);
   178    216   	Atom xvital;
   179    217   
   180    218   	/* x11 */ {
   181    219   		if (xdpy == NULL) return fail_win;
   182    220   		Window win;
................................................................................
   206    244   		}
   207    245   
   208    246   		if(s -> op == mode_kill) {
   209    247   			kill(s -> pid, SIGTERM);
   210    248   		}
   211    249   		kill(s -> agent, SIGTERM);
   212    250   		sigprocmask(SIG_BLOCK, &mask, NULL);
   213         -		shm_unlink(id);
          251  +
          252  +		shmlinux(shm_unlink(id));
          253  +		shmsysv({
          254  +			struct shmid_ds bleh; /* ?? */
          255  +			shmctl(shmem, IPC_RMID, &bleh);
          256  +		})
          257  +
   214    258   		if (!weak) {
   215    259   			XDeleteProperty(xdpy,s -> wid,xvital);
   216    260   			XSync(xdpy,false);
   217    261   		}
   218    262   		XCloseDisplay(xdpy);
   219    263   	} else {
   220    264   		// now we start ssh-agent and set the proper environment
   221    265   		// variables
   222    266   		pid_t ssha;
   223    267   
   224    268   		if (name == NULL) {
   225    269   			/* messy part */ 
   226    270   			const char* tmp; //tmpdir defined?
   227         -			if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp";
          271  +			if (!(tmp = getenv("XDG_RUNTIME_DIR")))
          272  +				if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp";
          273  +
   228    274   			size_t tmpsz = strlen(tmp);
   229    275   			
   230    276   			char sockn[tmpsz + 1 + sizeof "ssh."
   231    277   				+ 11];
   232    278   			strcpy(sockn, tmp);
   233    279   			sockn[tmpsz] = '/';
   234    280   			strcpy(sockn+tmpsz+1,"ssh.");
................................................................................
   241    287   			// assuming ascii…
   242    288   			for(uint8_t*i=rndid;i<rndid+11;++i) {
   243    289   				*i = '0' + (*i % (25 * 2 + 10));
   244    290   				if (*i > '9') *i += 7;
   245    291   				if (*i > 'Z') *i += ('a' - 'Z');
   246    292   			}
   247    293   
   248         -			spawn(ssha, sockn);
   249         -		} else spawn(ssha, name);
          294  +			name = sockn;
          295  +		}
          296  +		spawn(ssha, name);
   250    297   	
   251    298   		pid_t sad;
   252    299   		int p;
   253    300   		if (sad = fork()) {
   254    301   			int added;
   255    302   			waitpid(sad, &added, 0);
   256    303   			if (added == 0) {
   257    304   				if (weak == false) {
   258    305   					XChangeProperty(xdpy,s -> wid,xvital,xvital,8,PropModeReplace,"\01", 1);
   259    306   					XSync(xdpy,false);
   260    307   				}
   261    308   				write(1,"\033c",3);
   262    309   				execlp("fish","fish",NULL);
   263         -			} else { return ok; }
          310  +			}
   264    311   		} else {
   265    312   			execlp("ssh-add","ssh-add",NULL);
   266    313   		}
   267    314   	}
   268    315   
   269         -	return ok; // this is kind of pointless but w/e
          316  +	return ok;
   270    317   }
   271         -enum res kill_window(const char* id) {
   272         -	int fd = shm_open(id, O_RDWR, 0600);
   273         -	if (fd == -1) return fail_nop;
          318  +enum res kill_window(shmlinux(const char* id)) {
          319  +	struct signal* s;
          320  +	shmlinux({
          321  +		int fd = shm_open(id, O_RDWR, 0600);
          322  +		if (fd == -1) return fail_nop;
   274    323   
   275         -	struct signal* s = mmap(0, sizeof(struct signal),
   276         -			PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   277         -	if(s == MAP_FAILED) return fail_mem;
          324  +		s = mmap(0, sizeof(struct signal),
          325  +				PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
          326  +		if(s == MAP_FAILED) return fail_mem;
          327  +	}) shmsysv (int shmem; {
          328  +		shmem = shmget(shmem_key, sizeof(struct signal), 0);
          329  +		if (shmem == -1) return fail_nop;
          330  +		s = shmat(shmem,0,0);
          331  +		if (s == (void*)-1) return fail_mem;
          332  +	})
          333  +
          334  +	shmsysv({
          335  +		struct shmid_ds bleh; /* ?? */
          336  +		shmctl(shmem, IPC_RMID, &bleh);
          337  +	})
   278    338   
   279    339   	s -> op = mode_kill;
   280    340   	kill(s -> pid, SIGUSR1);
   281    341   
   282    342   	return ok;
   283    343   }
   284    344   enum res activate_window(Window w) {
................................................................................
   299    359   	if(!XSendEvent(dpy, DefaultRootWindow(dpy), False, mask, &ev)) return fail_x11;
   300    360   
   301    361   	XSync(dpy,false);
   302    362   	return ok;
   303    363   }
   304    364   
   305    365   int main(int sz, char** argv) {
          366  +	char* binname = "xpriv";
          367  +	if(sz > 0) binname = argv[0];
          368  +
   306    369   	enum mode op = mode_go;
   307    370   	bool init_weak = false;
   308    371   	const char* init_named = NULL;
   309    372   
   310    373   	for(int i = 1; i<sz; ++i) {
   311    374   		char* v = argv[i];
   312    375   		if (*v != '-') return bad(fail_arg);
................................................................................
   325    388   					  seen_string_arg = true;
   326    389   					  ++ i; break;
   327    390   			default: return bad(fail_opt);
   328    391   		}
   329    392   		if(opt[1] != 0) { ++opt; goto read_opt; }
   330    393   	}
   331    394   
   332         -	size_t nsz;
   333         -	const char* basename = argv[0], *p;
   334         -	for (p = argv[0]; *p!=0; ++p) {
   335         -		if(*p == '/') basename = p + 1;
   336         -	}
   337         -	nsz = p - basename;
   338         -	char shid[nsz + sizeof shmem_prefix];
   339         -	strncpy(shid,shmem_prefix,sizeof shmem_prefix);
   340         -	strncpy(shid + sizeof shmem_prefix - 1, basename, nsz);
   341         -	shid[nsz + sizeof shmem_prefix - 1] = 0;
          395  +	shmlinux(
          396  +		size_t nsz;
          397  +		const char* basename = argv[0], *p;
          398  +		for (p = binname; *p!=0; ++p) {
          399  +			if(*p == '/') basename = p + 1;
          400  +		}
          401  +		nsz = p - basename;
          402  +		char shid[nsz + sizeof shmem_prefix];
          403  +		strncpy(shid,shmem_prefix,sizeof shmem_prefix);
          404  +		strncpy(shid + sizeof shmem_prefix - 1, basename, nsz);
          405  +		shid[nsz + sizeof shmem_prefix - 1] = 0;
          406  +	) shmsysv ({
          407  +		/* TODO: implement ability to have multiple
          408  +		 * keys based on the name of the binary */
          409  +	})
   342    410   
   343         -	if (op == mode_go) {
   344         -		int fd;
   345         -		if ((fd = shm_open(shid, O_RDWR, 0600)) == -1) {
          411  +	tryagain: if (op == mode_go) {
          412  +		int shm;
          413  +		if ((shm = shmlinux(
          414  +				shm_open(shid, O_RDWR, 0600)
          415  +			) shmsysv (
          416  +				shmget(shmem_key,sizeof (struct signal),0)
          417  +			)) == -1) {
   346    418   			const char* args[] = {
   347    419   				"urxvtc", "-bg", "[90]#4b0024",
   348    420   				          "-e",  argv[0],
   349    421   						  (init_weak?"-aw":"-a"), 0, 0, 0};
   350    422   
   351    423   			const uint8_t argsz = sizeof args/sizeof(const char*);
   352    424   			if (init_named != NULL) {
   353    425   				args[argsz - 3] = "-n"; // im sorry
   354    426   				args[argsz - 2] = init_named;
   355    427   			}
   356    428   
   357    429   			execvp("urxvtc", (char* const*)args);
   358    430   		} else {
   359         -			struct signal*s = mmap(0, sizeof(struct signal),
   360         -					PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
          431  +			struct signal*s = shmlinux(
          432  +				mmap(0, sizeof(struct signal), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0)
          433  +			) shmsysv (
          434  +				shmat(shm, 0, 0)
          435  +			);
          436  +
          437  +			struct shmid_ds stat;
          438  +			shmctl(shm, IPC_STAT, &stat);
          439  +			if (stat.shm_nattch == 0) {
          440  +				/* if the shm segment is not attached to any
          441  +				 * process, it's a relic that needs to be
          442  +				 * cleaned up before we do anything else. on
          443  +				 * a sane OS, there would be built-in non-
          444  +				 * persistence mechanisms for shared mem, but
          445  +				 * alas, as you already know, POSIX */
          446  +				shmctl(shm, IPC_RMID, &stat);
          447  +				goto tryagain;
          448  +			}
          449  +
          450  +			if (s == shmlinux(MAP_FAILED) shmsysv((void*)-1))
          451  +				return bad(fail_mem);
   361    452   			return bad(activate_window(s->wid));
   362    453   		}
   363    454   	} else if (op == mode_register)
   364         -		return bad(register_window(shid,init_weak,init_named));
          455  +		return bad(register_window(shmlinux(shid,) init_weak,init_named));
   365    456   	else if (op == mode_kill)
   366         -		return bad(kill_window(shid));
          457  +		return bad(kill_window(shmlinux(shid)));
   367    458   	else if (op == mode_usage) {
   368    459   		write(1,"\e[1musage:\e[0m ",15);
   369    460   		write(1, argv[0], strlen(argv[0]));
   370    461   		write(1, " [-aklw [arg]]\n",16);
   371    462   		return fail_parse;
   372    463   	}
   373    464   }
   374    465