]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/kbdfs/kbdfs.c
aa7e72050f6d38e5ce64d6674f6cf385510c0c46
[plan9front.git] / sys / src / cmd / aux / kbdfs / kbdfs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 #include <keyboard.h>
7 #include <9p.h>
8
9 enum {
10         Nscan=  128,
11
12         Qroot=  0,
13         Qkbd,
14         Qkbdin,
15         Qkbin,
16         Qkbmap,
17         Qcons,
18         Qconsctl,
19         Nqid,
20
21         Rawon=  0,
22         Rawoff,
23
24         STACK = 8*1024,
25 };
26
27 typedef struct Key Key;
28 typedef struct Scan Scan;
29
30 struct Key {
31         int     down;
32         Rune    b;      /* button, unshifted key */
33         Rune    r;      /* rune, shifted key */
34 };
35
36 struct Scan {
37         int     esc1;
38         int     esc2;
39         int     caps;
40         int     num;
41         int     shift;
42         int     ctl;
43         int     alt;
44         int     altgr;
45         int     leds;
46 };
47
48 struct Qtab {
49         char *name;
50         int mode;
51         int type;
52 } qtab[Nqid] = {
53         "/",
54                 DMDIR|0500,
55                 QTDIR,
56
57         "kbd",
58                 0600,
59                 0,
60
61         "kbdin",
62                 0200,
63                 0,
64
65         "kbin",
66                 0200,   
67                 0,
68
69         "kbmap",
70                 0600,   
71                 0,
72
73         "cons",
74                 0600,   
75                 0,
76
77         "consctl",
78                 0600,
79                 0,
80 };
81
82 char Eshort[] = "read count too small";
83 char Ebadarg[] = "invalid argument";
84 char Eperm[] = "permission denied";
85 char Einuse[] = "file in use";
86 char Enonexist[] = "file does not exist";
87 char Ebadspec[] = "bad attach specifier";
88 char Ewalk[] = "walk in non directory";
89 char Ephase[] = "the front fell off";
90 char Eintr[] = "interrupted";
91
92 int kbdifd = -1;
93 int scanfd = -1;
94 int ledsfd = -1;
95 int consfd = -1;
96 int mctlfd = -1;
97 int msinfd = -1;
98 int notefd = -1;
99 int killfd = -1;
100
101 int kbdopen;
102 int consctlopen;
103 int quiet = 0;
104 char *sname = nil;
105 char *mntpt = "/dev";
106
107 int debug;
108
109 Channel *keychan;       /* chan(Key) */
110 Channel *mctlchan;      /* chan(Key) */
111
112 Channel *kbdreqchan;    /* chan(Req*) */
113 Channel *consreqchan;   /* chan(Req*) */
114
115 Channel *ctlchan;       /* chan(int) */
116
117 Channel *rawchan;       /* chan(Rune) */
118 Channel *runechan;      /* chan(Rune) */
119
120 Channel *conschan;      /* chan(char*) */
121 Channel *kbdchan;       /* chan(char*) */
122 Channel *intchan;       /* chan(int) */
123
124 /*
125  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
126  * A 'standard' keyboard doesn't produce anything above 0x58.
127  */
128 Rune kbtab[Nscan] = 
129 {
130 [0x00]  0,      0x1b,   '1',    '2',    '3',    '4',    '5',    '6',
131 [0x08]  '7',    '8',    '9',    '0',    '-',    '=',    '\b',   '\t',
132 [0x10]  'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
133 [0x18]  'o',    'p',    '[',    ']',    '\n',   Kctl,   'a',    's',
134 [0x20]  'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
135 [0x28]  '\'',   '`',    Kshift, '\\',   'z',    'x',    'c',    'v',
136 [0x30]  'b',    'n',    'm',    ',',    '.',    '/',    Kshift, '*',
137 [0x38]  Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
138 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,'7',
139 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
140 [0x50]  '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
141 [0x58]  KF|12,  0,      0,      0,      0,      0,      0,      0,
142 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
143 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
144 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
145 [0x78]  0,      Kdown,  0,      Kup,    0,      0,      0,      0,
146 };
147
148 Rune kbtabshift[Nscan] =
149 {
150 [0x00]  0,      0x1b,   '!',    '@',    '#',    '$',    '%',    '^',
151 [0x08]  '&',    '*',    '(',    ')',    '_',    '+',    '\b',   '\t',
152 [0x10]  'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
153 [0x18]  'O',    'P',    '{',    '}',    '\n',   Kctl,   'A',    'S',
154 [0x20]  'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
155 [0x28]  '"',    '~',    Kshift, '|',    'Z',    'X',    'C',    'V',
156 [0x30]  'B',    'N',    'M',    '<',    '>',    '?',    Kshift, '*',
157 [0x38]  Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
158 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,'7',
159 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
160 [0x50]  '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
161 [0x58]  KF|12,  0,      0,      0,      0,      0,      0,      0,
162 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
163 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
164 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
165 [0x78]  0,      Kdown,  0,      Kup,    0,      0,      0,      0,
166 };
167
168 Rune kbtabesc1[Nscan] =
169 {
170 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
171 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
172 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
173 [0x18]  0,      0,      0,      0,      '\n',   Kctl,   0,      0,
174 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
175 [0x28]  0,      0,      0,      0,      0,      0,      0,      0,
176 [0x30]  0,      0,      0,      0,      0,      '/',    0,      Kprint,
177 [0x38]  Kaltgr, 0,      0,      0,      0,      0,      0,      0,
178 [0x40]  0,      0,      0,      0,      0,      0,      Kbreak, Khome,
179 [0x48]  Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
180 [0x50]  Kdown,  Kpgdown,Kins,   Kdel,   0,      0,      0,      0,
181 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
182 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
183 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
184 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
185 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
186 };
187
188 Rune kbtabshiftesc1[Nscan] =
189 {
190 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
191 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
192 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
193 [0x18]  0,      0,      0,      0,      0,      0,      0,      0,
194 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
195 [0x28]  0,      0,      0,      0,      0,      0,      0,      0,
196 [0x30]  0,      0,      0,      0,      0,      0,      0,      0,
197 [0x38]  0,      0,      0,      0,      0,      0,      0,      0,
198 [0x40]  0,      0,      0,      0,      0,      0,      0,      0,
199 [0x48]  Kup,    0,      0,      0,      0,      0,      0,      0,
200 [0x50]  0,      0,      0,      0,      0,      0,      0,      0,
201 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
202 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
203 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
204 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
205 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
206 };
207
208 Rune kbtabctrlesc1[Nscan] =
209 {
210 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
211 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
212 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
213 [0x18]  0,      0,      0,      0,      0,      0,      0,      0,
214 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
215 [0x28]  0,      0,      0,      0,      0,      0,      0,      0,
216 [0x30]  0,      0,      0,      0,      0,      0,      0,      0,
217 [0x38]  0,      0,      0,      0,      0,      0,      0,      0,
218 [0x40]  0,      0,      0,      0,      0,      0,      0,      0,
219 [0x48]  Kup,    0,      0,      0,      0,      0,      0,      0,
220 [0x50]  0,      0,      0,      0,      0,      0,      0,      0,
221 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
222 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
223 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
224 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
225 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
226 };
227
228 Rune kbtabaltgr[Nscan] =
229 {
230 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
231 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
232 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
233 [0x18]  0,      0,      0,      0,      '\n',   Kctl,   0,      0,
234 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
235 [0x28]  0,      0,      Kshift, 0,      0,      0,      0,      0,
236 [0x30]  0,      0,      0,      0,      0,      '/',    0,      Kprint,
237 [0x38]  Kaltgr, 0,      0,      0,      0,      0,      0,      0,
238 [0x40]  0,      0,      0,      0,      0,      0,      Kbreak, Khome,
239 [0x48]  Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
240 [0x50]  Kdown,  Kpgdown,Kins,   Kdel,   0,      0,      0,      0,
241 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
242 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
243 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
244 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
245 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
246 };
247
248 Rune kbtabctl[Nscan] =
249 {
250 [0x00]  0,      '\e',    '\11',    '\12',    '\13',    '\14',    '\15',    '\16', 
251 [0x08]  '\17',    '\18',    '\19',    '\10',    '\r',    '\1d',    '\b',   '\t',
252 [0x10]  '\11',    '\17',    '\ 5',    '\12',    '\14',    '\19',    '\15',    '\t',
253 [0x18]  '\ f',    '\10',    '\e',    '\1d',    '\n',   Kctl,   '\ 1',    '\13', 
254 [0x20]  '\ 4',    '\ 6',    '\a',    '\b',   '\n',   '\v',    '\f',    '\e', 
255 [0x28]  '\a',    0,      Kshift, '\1c',    '\1a',    '\18',    '\ 3',    '\16', 
256 [0x30]  '\ 2',    '\ e',    '\r',    '\f',    '\ e',    '\ f',    Kshift, '\n',
257 [0x38]  Kalt,   0,      Kctl,   '\ 5',    '\ 6',    '\a',    '\ 4',    '\ 5', 
258 [0x40]  '\ 6',    '\a',    '\f',    '\r',    '\ e',    '\ 5',    '\ 6',    '\17', 
259 [0x48]  '\18',    '\19',    '\r',    '\14',    '\15',    '\16',    '\v',    '\11', 
260 [0x50]  '\12',    '\13',    '\10',    '\ e',    0,      0,      0,      '\ f', 
261 [0x58]  '\f',    0,      0,      0,      0,      0,      0,      0,
262 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
263 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
264 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
265 [0x78]  0,      '\a',    0,      '\b',   0,      0,      0,      0,
266 };
267
268 Rune kbtabshiftaltgr[Nscan] =
269 {
270 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
271 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
272 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
273 [0x18]  0,      0,      0,      0,      0,      0,      0,      0,
274 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
275 [0x28]  0,      0,      0,      0,      0,      0,      0,      0,
276 [0x30]  0,      0,      0,      0,      0,      0,      0,      0,
277 [0x38]  0,      0,      0,      0,      0,      0,      0,      0,
278 [0x40]  0,      0,      0,      0,      0,      0,      0,      0,
279 [0x48]  0,      0,      0,      0,      0,      0,      0,      0,
280 [0x50]  0,      0,      0,      0,      0,      0,      0,      0,
281 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
282 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
283 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
284 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
285 [0x78]  0,      0,      0,      0,      0,      0,      0,      0,
286 };
287
288 char*
289 dev(char *file)
290 {
291         static char *buf = nil;
292         free(buf);
293         buf = smprint("%s/%s", mntpt, file);
294         return buf;
295 }
296
297 int
298 eopen(char *name, int mode)
299 {
300         int fd;
301
302         fd = open(name, mode);
303         if(fd < 0 && !quiet)
304                 fprint(2, "%s: warning: can't open %s: %r\n", argv0, name);
305         return fd;
306 }
307
308 void
309 reboot(void)
310 {
311         int fd;
312
313         if(debug)
314                 return;
315
316         if((fd = eopen(dev("reboot"), OWRITE)) < 0)
317                 return;
318         fprint(fd, "reboot\n");
319         close(fd);
320 }
321
322 void
323 shutdown(void)
324 {
325         if(notefd >= 0)
326                 write(notefd, "hangup", 6);
327         if(killfd >= 0)
328                 write(killfd, "hangup", 6);
329         threadexitsall(nil);
330 }
331
332 /*
333  * Scan code processing
334  */
335 void
336 kbdputsc(Scan *scan, int c)
337 {
338         Key key;
339
340         /*
341          *  e0's is the first of a 2 character sequence, e1 and e2 the first
342          *  of a 3 character sequence (on the safari)
343          */
344         if(scan->esc2){
345                 scan->esc2--;
346                 return;
347         } else if(c == 0xe1 || c == 0xe2){
348                 scan->esc2 = 2;
349                 return;
350         } else if(c == 0xe0){
351                 scan->esc1 = 1;
352                 return;
353         }
354
355         key.down = (c & 0x80) == 0;
356         c &= 0x7f;
357
358         if(c >= Nscan)
359                 return;
360
361         /* qemu workarround: emulate e0 for numpad */
362         if(c != 0 && strchr("GHIKMOPQRS", c) != nil)
363                 scan->esc1 |= !scan->num;
364
365         if(scan->esc1 && scan->ctl && kbtabctrlesc1[c] != 0)
366                 key.r = kbtabctrlesc1[c];
367         else if(scan->esc1 && scan->shift && kbtabshiftesc1[c] != 0)
368                 key.r = kbtabshiftesc1[c];
369         else if(scan->esc1)
370                 key.r = kbtabesc1[c];
371         else if(scan->shift && scan->altgr && kbtabshiftaltgr[c] != 0)
372                 key.r = kbtabshiftaltgr[c];
373         else if(scan->shift)
374                 key.r = kbtabshift[c];
375         else if(scan->altgr)
376                 key.r = kbtabaltgr[c];
377         else if(scan->ctl)
378                 key.r = kbtabctl[c];
379         else
380                 key.r = kbtab[c];
381
382         if(scan->esc1 || kbtab[c] == 0)
383                 key.b = key.r;
384         else
385                 key.b = kbtab[c];
386
387         if(scan->caps && key.r<='z' && key.r>='a')
388                 key.r += 'A' - 'a';
389
390         if(scan->ctl && scan->alt && key.r == Kdel)
391                 reboot();
392
393         if(key.b)
394                 send(keychan, &key);
395
396         switch(key.r){
397         case Kshift:
398                 scan->shift = key.down;
399                 break;
400         case Kctl:
401                 scan->ctl = key.down;
402                 break;
403         case Kaltgr:
404                 scan->altgr = key.down;
405                 break;
406         case Kalt:
407                 scan->alt = key.down;
408                 break;
409         case Knum:
410                 scan->num ^= key.down;
411                 break;
412         case Kcaps:
413                 scan->caps ^= key.down;
414                 break;
415         }
416         scan->esc1 = 0;
417 }
418
419 static void
420 kbdin(Scan *a, char *p, int n)
421 {
422         char *s;
423         Key k;
424         int i;
425
426         if(n > 0 && p[n-1] != 0){
427                 /*
428                  * old format as used by bitsy keyboard:
429                  * just a string of characters, no keyup
430                  * information.
431                  */
432                 s = emalloc9p(n+1);
433                 memmove(s, p, n);
434                 s[n] = 0;
435                 p = s;
436                 while(*p){
437                         p += chartorune(&k.r, p);
438                         if(k.r)
439                                 send(rawchan, &k.r);
440                 }
441                 free(s);
442                 return;
443         }
444 Nextmsg:
445         if(n < 2)
446                 return;
447         switch(p[0]){
448         case 'R':
449         case 'r':
450                 /* rune up/down */
451                 chartorune(&k.r, p+1);
452                 if(k.r == 0)
453                         break;
454                 k.b = 0;
455                 k.down = (p[0] == 'r');
456                 for(i=0; i<Nscan; i++){
457                         if(kbtab[i] == k.r || kbtabshift[i] == k.r || (i >= 16 && kbtabctl[i] == k.r)){
458                                 /* assign button from kbtab */
459                                 k.b = kbtab[i];
460                                 /* handle ^X forms */
461                                 if(k.r == kbtab[i] && kbtabctl[i] && !a->shift && !a->altgr && a->ctl)
462                                         k.r = kbtabctl[i];
463                                 break;
464                         }
465                 }
466                 /* button unknown to kbtab, use rune if no modifier keys are active */
467                 if(k.b == 0 && !a->shift && !a->altgr && !a->ctl)
468                         k.b = k.r;
469                 if(k.r == Kshift)
470                         a->shift = k.down;
471                 else if(k.r == Kaltgr)
472                         a->altgr = k.down;
473                 else if(k.r == Kctl)
474                         a->ctl = k.down;
475                 send(keychan, &k);
476                 break;
477
478         case 'c':
479                 chartorune(&k.r, p+1);
480                 nbsend(runechan, &k.r);
481                 break;
482
483         default:
484                 if(!kbdopen)
485                         break;
486                 i = strlen(p)+1;
487                 s = emalloc9p(i);
488                 memmove(s, p, i);
489                 if(nbsendp(kbdchan, s) <= 0)
490                         free(s);
491         }
492         i = strlen(p)+1;
493         n -= i, p += i;
494         goto Nextmsg;
495 }
496
497 void
498 setleds(Scan *scan, int leds)
499 {
500         char buf[8];
501
502         if(ledsfd < 0 || scan->leds == leds)
503                 return;
504         leds &= 7;
505         snprint(buf, sizeof(buf), "%d", leds);
506         pwrite(ledsfd, buf, strlen(buf), 0);
507         scan->leds = leds;
508 }
509
510 /*
511  * Read scan codes from scanfd
512  */ 
513 void
514 scanproc(void *)
515 {
516         uchar buf[64];
517         Scan scan;
518         int i, n;
519
520         threadsetname("scanproc");
521
522         memset(&scan, 0, sizeof scan);
523         while((n = read(scanfd, buf, sizeof buf)) > 0){
524                 for(i=0; i<n; i++)
525                         kbdputsc(&scan, buf[i]);
526                 setleds(&scan, (scan.num<<1) | (scan.caps<<2));
527         }
528
529         shutdown();
530 }
531
532 void
533 kbdiproc(void *)
534 {
535         char buf[1024];
536         Scan a;
537         int n;
538
539         threadsetname("kbdiproc");
540
541         memset(&a, 0, sizeof(a));
542         while((n = read(kbdifd, buf, sizeof buf)) > 0)
543                 kbdin(&a, buf, n);
544
545         shutdown();
546 }
547
548 char*
549 utfconv(Rune *r, int n)
550 {
551         char *s, *p;
552         int l;
553
554         l = runenlen(r, n) + 1;
555         s = emalloc9p(l);
556         for(p = s; n > 0; r++, n--)
557                 p += runetochar(p, r);
558         *p = 0;
559         return s;
560 }
561
562 /*
563  * Read key events from keychan and produce characters to
564  * rawchan and keystate in kbdchan.
565  */
566 void
567 keyproc(void *)
568 {
569         Rune rb[Nscan+1];
570         Key key;
571         int i, nb;
572         char *s;
573
574         threadsetname("keyproc");
575
576         nb = 0;
577         while(recv(keychan, &key) > 0){
578                 if(key.r >= Kmouse+1 && key.r <= Kmouse+5){
579                         if(msinfd >= 0)
580                                 send(mctlchan, &key);
581                         continue;
582                 }
583                 rb[0] = 0;
584                 if(key.b){
585                         for(i=0; i<nb && rb[i+1] != key.b; i++)
586                                 ;
587                         if(!key.down){
588                                 while(i < nb && rb[i+1] == key.b){
589                                         memmove(rb+i+1, rb+i+2, (nb-i+1) * sizeof(rb[0]));
590                                         nb--;
591                                         rb[0] = 'K';
592                                 }
593                         } else if(i == nb && nb < nelem(rb)-1 && key.b){
594                                 rb[++nb] = key.b;
595                                 rb[0] = 'k';
596                         }
597                 }
598                 if(rb[0]){
599                         if(kbdopen){
600                                 s = utfconv(rb, nb+1);
601                                 if(nbsendp(kbdchan, s) <= 0)
602                                         free(s);
603                         }
604                         if(mctlfd >= 0)
605                                 send(mctlchan, &key);
606                 }
607                 if(key.down && key.r)
608                         send(rawchan, &key.r);
609         }
610 }
611
612 /*
613  * Read characters from consfd (serial console)
614  */ 
615 void
616 consproc(void *)
617 {
618         char *p, *e, *x, buf[64];
619         int n, cr;
620         Rune r;
621
622         threadsetname("consproc");
623
624         cr = 0;
625         p = buf;
626         e = buf + sizeof(buf);
627         while((n = read(consfd, p, e - p)) > 0){
628                 x = p + n;
629                 p = buf;
630                 while((n = x - p) > 0){
631                         if(!fullrune(p, n)){
632                                 memmove(buf, p, n);
633                                 break;
634                         }
635                         p += chartorune(&r, p);
636                         if(r == 021 || r == 023)        /* XON/XOFF */
637                                 continue;
638                         if(r == 0 || r == Runeerror){
639                                 cr = 0;
640                                 continue;
641                         }
642                         if(r == '\n' && cr){
643                                 cr = 0;
644                                 continue;
645                         }
646                         if(cr = (r == '\r'))
647                                 r = '\n';
648                         send(runechan, &r);
649                 }
650                 if(n < 0) n = 0;
651                 p = buf + n;
652         }
653
654         shutdown();
655 }
656
657 static int
658 nextrune(Channel *ch, Rune *r)
659 {
660         while(recv(ch, r) > 0){
661                 switch(*r){
662                 case 0:
663                 case Kcaps:
664                 case Knum:
665                 case Kshift:
666                 case Kaltgr:
667                         /* ignore modifiers */
668                         continue;
669
670                 case Kctl:
671                 case Kalt:
672                         /* composing escapes */
673                         return 1;
674                 }
675                 return 0;
676         }
677         return -1;
678 }
679
680 /*
681  * Read runes from rawchan, possibly compose special characters
682  * and output the new runes to runechan
683  */
684 void
685 runeproc(void *)
686 {
687         static struct {
688                 char    *ld;    /* must be seen before using this conversion */
689                 char    *si;    /* options for last input characters */
690                 Rune    *so;    /* the corresponding Rune for each si entry */
691         } tab[] = {
692 #include "latin1.h"
693         };
694         Rune r, rr;
695         int i, j;
696         int ctl;
697
698         threadsetname("runeproc");
699
700         ctl = 0;
701         while((i = nextrune(rawchan, &r)) >= 0){
702                 if(i == 0){
703                         ctl = 0;
704 Forward:
705                         send(runechan, &r);
706                         continue;
707                 }
708
709                 if(r == Kctl){
710                         ctl = 1;
711                         continue;
712                 }
713
714                 /*
715                  * emulators like qemu and vmware use Ctrl+Alt to lock
716                  * keyboard input so dont confuse them for a compose
717                  * sequence.
718                  */
719                 if(r != Kalt || ctl)
720                         continue;
721
722                 if(nextrune(rawchan, &r))
723                         continue;
724
725                 if(r == 'x' || r == 'X'){
726                         i = (r == 'X') ? 4 : 6;
727                         r = 0;
728                         do {
729                                 if(nextrune(rawchan, &rr))
730                                         break;
731                                 if(rr >= '0' && rr <= '9')
732                                         r = (r << 4) | (rr - '0');
733                                 else if(rr >= 'a' && rr <= 'f')
734                                         r = (r << 4) | (10 + (rr - 'a'));
735                                 else if(rr >= 'A' && rr <= 'F')
736                                         r = (r << 4) | (10 + (rr - 'A'));
737                                 else
738                                         break;
739                         } while(--i > 0);
740                         if((i == 0 || rr == ';') && r != 0 && r <= Runemax)
741                                 goto Forward;
742                 } else {
743                         if(nextrune(rawchan, &rr))
744                                 continue;
745                         for(i = 0; i<nelem(tab); i++){
746                                 if(tab[i].ld[0] != r)
747                                         continue;
748                                 if(tab[i].ld[1] == 0)
749                                         break;  
750                                 if(tab[i].ld[1] == rr){
751                                         nextrune(rawchan, &rr);
752                                         break;
753                                 }
754                         }
755                         if(i == nelem(tab) || rr == 0)
756                                 continue;
757                         for(j = 0; tab[i].si[j]; j++){
758                                 if(tab[i].si[j] != rr)
759                                         continue;
760                                 r = tab[i].so[j];
761                                 goto Forward;
762                         }
763                 }
764         }
765 }
766
767 /*
768  * Need to do this in a separate proc because if process we're interrupting
769  * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
770  */
771 void
772 intrproc(void *)
773 {
774         threadsetname("intrproc");
775
776         while(recv(intchan, nil) > 0)
777                 write(notefd, "interrupt", 9);
778 }
779
780 /*
781  * Process Kmouse keys and mouse button swap on shift,
782  * unblank screen by twiching.
783  */
784 void
785 mctlproc(void *)
786 {
787         Key key;
788         int i, mouseb = 0;
789
790         threadsetname("mctlproc");
791
792         for(;;){
793                 if(nbrecv(mctlchan, &key) <= 0){
794                         if(mctlfd >= 0)
795                                 fprint(mctlfd, "twitch");
796                         if(recv(mctlchan, &key) <= 0)
797                                 break;
798                 }
799
800                 if(mctlfd >= 0 && key.r == Kshift){
801                         if(key.down){
802                                 fprint(mctlfd, "buttonmap 132");
803                         } else {
804                                 fprint(mctlfd, "swap");
805                                 fprint(mctlfd, "swap");
806                         }
807                         continue;
808                 }
809
810                 if(msinfd >= 0 && key.r >= Kmouse+1 && key.r <= Kmouse+5){
811                         i = 1<<(key.r-(Kmouse+1));
812                         if(key.down)
813                                 mouseb |= i;
814                         else
815                                 mouseb &= ~i;
816                         fprint(msinfd, "m%11d %11d %11d", 0, 0, mouseb);
817                         continue;
818                 }
819         }
820 }
821
822 /*
823  * Cook lines for cons
824  */
825 void
826 lineproc(void *aux)
827 {
828         Rune rb[256], r;
829         Channel *cook;
830         int nr, done;
831         char *s;
832
833         cook = aux;
834
835         threadsetname("lineproc");
836
837         for(;;){
838                 nr = 0;
839                 done = 0;
840                 do {
841                         recv(cook, &r);
842                         switch(r){
843                         case Kdel:
844                                 if(nbsend(intchan, &notefd) <= 0)
845                                         continue;
846                                 /* no break */
847                         case '\0':      /* flush */
848                                 nr = 0;
849                                 continue;
850                         case Kbs:       /* ^H: erase character */
851                         case Knack:     /* ^U: erase line */
852                         case Ketb:      /* ^W: erase word */
853                                 while(nr > 0){
854                                         nr--;
855                                         fprint(1, "\b");
856                                         if(r == Kbs)
857                                                 break;
858                                         if(r == Ketb && utfrune(" \t", rb[nr]))
859                                                 break;
860                                 }
861                                 continue;
862                         case Keof:      /* ^D: eof */
863                                 done = 1;
864                                 break;
865                         case '\n':
866                                 done = 1;
867                                 /* no break */
868                         default:
869                                 rb[nr++] = r;
870                                 fprint(1, "%C", r);
871                         }
872                 } while(!done && nr < nelem(rb));
873                 s = utfconv(rb, nr);
874                 if(nbsendp(conschan, s) <= 0)
875                         free(s);
876         }
877 }
878
879 /*
880  * Reads Tread and Tflush requests from reqchan and responds
881  * to them with data received on the string channel.
882  */
883 void
884 reqproc(void *aux)
885 {
886         enum { AREQ, ASTR, AEND };
887         Alt a[AEND+1];
888         Channel **ac;
889         Req *r, *q, **qq;
890         char *s, *p, *e;
891         int n, m;
892
893         threadsetname("reqproc");
894
895         e = nil;
896         s = nil;
897         p = nil;
898
899         q = nil;
900         qq = &q;
901
902         ac = aux;
903         a[AREQ].op = CHANRCV;
904         a[AREQ].c = ac[0];      /* chan(Req*) */
905         a[AREQ].v = &r;
906
907         a[ASTR].c = ac[1];      /* chan(char*) */
908         a[ASTR].v = &s;
909
910         a[AEND].op = CHANEND;
911
912         for(;;){
913                 a[ASTR].op = s != nil ? CHANNOP : CHANRCV;
914
915                 switch(alt(a)){
916                 case AREQ:
917                         if(r->ifcall.type == Tflush){
918                                 Req **rr, **xx;
919
920                                 for(rr = &q; *rr; rr=xx){
921                                         xx = &((*rr)->aux);
922                                         if(*rr == r->oldreq){
923                                                 if((*rr = *xx) == nil)
924                                                         qq = rr;
925                                                 respond(r->oldreq, Eintr);
926                                                 break;
927                                         }
928                                 }
929                                 respond(r, nil);
930                                 continue;
931                         } else if(r->ifcall.type != Tread){
932                                 respond(r, Ephase);
933                                 continue;
934                         }
935                         r->aux = nil;
936                         *qq = r;
937                         qq = &r->aux;
938
939                         if(0){
940                 case ASTR:
941                                 p = s;
942                         }
943
944                         while(s != nil && q != nil){
945                                 r = q;
946                                 if((q = q->aux) == nil)
947                                         qq = &q;
948                                 r->ofcall.count = 0;
949                                 if(s == p){
950                                 More:
951                                         e = s + strlen(s);
952                                         if(r->fid->qid.path == Qkbd)
953                                                 e++; /* send terminating \0 if its kbd file */
954                                 }
955                                 n = e - p;
956                                 m = r->ifcall.count - r->ofcall.count;
957                                 if(n > m){
958                                         if(r->ofcall.count > 0){
959                                                 respond(r, nil);
960                                                 continue;
961                                         }
962                                         n = m;
963                                 }
964                                 memmove((char*)r->ofcall.data + r->ofcall.count, p, n);
965                                 r->ofcall.count += n;
966                                 p += n;
967                                 if(p >= e){
968                                         free(s);
969                                         s = nbrecvp(a[ASTR].c);
970                                         if(s != nil){
971                                                 p = s;
972                                                 goto More;
973                                         }
974                                 }
975                                 respond(r, nil);
976                         }
977                 }
978         }
979 }
980
981 /*
982  * Keep track of rawing state and distribute the runes from
983  * runechan to the right channels depending on the state.
984  */
985 void
986 ctlproc(void *)
987 {
988         Channel *cook, *aconsr[2], *akbdr[2];
989         enum { ACTL, ARUNE, AEND };
990         Alt a[AEND+1];
991         Rune r;
992         int c, raw;
993         char *s;
994
995         threadsetname("ctlproc");
996
997         if(kbdifd >= 0)
998                 proccreate(kbdiproc, nil, STACK);       /* kbdifd -> kbdin() */
999         if(mctlfd >= 0 || msinfd >= 0)
1000                 proccreate(mctlproc, nil, STACK);       /* mctlchan -> mctlfd, msinfd */
1001         if(scanfd >= 0)
1002                 proccreate(scanproc, nil, STACK);       /* scanfd -> keychan */
1003         if(consfd >= 0)
1004                 proccreate(consproc, nil, STACK);       /* consfd -> runechan */
1005         if(notefd >= 0)
1006                 proccreate(intrproc, nil, STACK);       /* intchan -> notefd */
1007
1008         threadcreate(keyproc, nil, STACK);              /* keychan -> mctlchan, rawchan, kbdchan */
1009         threadcreate(runeproc, nil, STACK);             /* rawchan -> runechan */
1010
1011         aconsr[0] = consreqchan;
1012         aconsr[1] = conschan;
1013         threadcreate(reqproc, aconsr, STACK);           /* consreqchan,conschan -> respond */
1014
1015         akbdr[0] = kbdreqchan;
1016         akbdr[1] = kbdchan;
1017         threadcreate(reqproc, akbdr, STACK);            /* kbdreqchan,kbdchan -> respond */
1018
1019         cook = chancreate(sizeof(Rune), 0);
1020         threadcreate(lineproc, cook, STACK);            /* cook -> conschan */
1021
1022         raw = 0;
1023
1024         a[ACTL].c = ctlchan;
1025         a[ACTL].v = &c;
1026         a[ACTL].op = CHANRCV;
1027
1028         a[ARUNE].c = runechan;
1029         a[ARUNE].v = &r;
1030         a[ARUNE].op = CHANRCV;
1031
1032         a[AEND].op = CHANEND;
1033
1034         for(;;){
1035                 switch(alt(a)){
1036                 case ACTL:
1037                         switch(c){
1038                         case Rawoff:
1039                         case Rawon:
1040                                 if(raw = (c == Rawon)){
1041                                         r = 0;
1042                                         nbsend(cook, &r);
1043                                 }
1044                         }
1045                         break;
1046                 case ARUNE:
1047                         if(kbdopen){
1048                                 s = emalloc9p(UTFmax+2);
1049                                 s[0] = 'c';
1050                                 s[1+runetochar(s+1, &r)] = 0;
1051                                 if(nbsendp(kbdchan, s) <= 0)
1052                                         free(s);
1053                                 break;
1054                         }
1055                         if(raw){
1056                                 s = emalloc9p(UTFmax+1);
1057                                 s[runetochar(s, &r)] = 0;
1058                                 if(nbsendp(conschan, s) <= 0)
1059                                         free(s);
1060                                 break;
1061                         }
1062                         nbsend(cook, &r);
1063                         break;
1064                 }
1065         }
1066 }
1067
1068 /*
1069  * Keyboard layout maps
1070  */
1071
1072 Rune*
1073 kbmapent(int t, int sc)
1074 {
1075         static Rune *tabs[] = { 
1076         /* 0 */ kbtab,
1077         /* 1 */ kbtabshift,
1078         /* 2 */ kbtabesc1,
1079         /* 3 */ kbtabaltgr,
1080         /* 4 */ kbtabctl,
1081         /* 5 */ kbtabctrlesc1,
1082         /* 6 */ kbtabshiftesc1,
1083         /* 7 */ kbtabshiftaltgr,
1084         };
1085         if(t >= 0 && t < nelem(tabs) && sc >= 0 && sc < Nscan)
1086                 return &tabs[t][sc];
1087         return nil;
1088 }
1089
1090 void
1091 kbmapread(Req *req)
1092 {
1093         char tmp[3*12+1];
1094         int t, sc, off, n;
1095         Rune *rp;
1096
1097         off = req->ifcall.offset/(sizeof(tmp)-1);
1098         t = off/Nscan;
1099         sc = off%Nscan;
1100         if(rp = kbmapent(t, sc))
1101                 sprint(tmp, "%11d %11d %11d\n", t, sc, *rp);
1102         else
1103                 *tmp = 0;
1104         n = strlen(tmp);
1105         if(req->ifcall.count < n)
1106                 n = req->ifcall.count;
1107         req->ofcall.count = n;
1108         memmove(req->ofcall.data, tmp, n);
1109         respond(req, nil);
1110 }
1111
1112 Rune
1113 kbcompat(Rune r)
1114 {
1115         static Rune o = Spec|0x60, tab[] = {
1116                 Kshift, Kbreak, Kctl, Kalt,
1117                 Kcaps, Knum, Kmiddle, Kaltgr,
1118         };
1119         if(r >= o && r < o+nelem(tab))
1120                 return tab[r - o];
1121         return r;
1122 }
1123
1124 void
1125 kbmapwrite(Req *req)
1126 {
1127         char line[100], *lp, *b;
1128         Rune r, *rp;
1129         int sc, t, l;
1130         Fid *f;
1131
1132         f = req->fid;
1133         b = req->ifcall.data;
1134         l = req->ifcall.count;
1135         lp = line;
1136         if(f->aux){
1137                 strcpy(line, f->aux);
1138                 lp = line+strlen(line);
1139                 free(f->aux);
1140                 f->aux = nil;
1141         }
1142         while(--l >= 0) {
1143                 *lp++  = *b++;
1144                 if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
1145                         *lp = 0;
1146                         if(*line == 0){
1147                         Badarg:
1148                                 respond(req, Ebadarg);
1149                                 return;
1150                         }
1151                         if(*line == '\n' || *line == '#'){
1152                                 lp = line;
1153                                 continue;
1154                         }
1155                         lp = line;
1156                         while(*lp == ' ' || *lp == '\t')
1157                                 lp++;
1158                         t = strtoul(line, &lp, 0);
1159                         sc = strtoul(lp, &lp, 0);
1160                         while(*lp == ' ' || *lp == '\t')
1161                                 lp++;
1162                         if((rp = kbmapent(t, sc)) == nil)
1163                                 goto Badarg;
1164                         r = 0;
1165                         if(*lp == '\'' && lp[1])
1166                                 chartorune(&r, lp+1);
1167                         else if(*lp == '^' && lp[1]){
1168                                 chartorune(&r, lp+1);
1169                                 if(0x40 <= r && r < 0x60)
1170                                         r -= 0x40;
1171                                 else
1172                                         goto Badarg;
1173                         }else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
1174                                 r = Kmouse+lp[1]-'0';
1175                         else if(*lp>='0' && *lp<='9') /* includes 0x... */
1176                                 r = strtoul(lp, &lp, 0);
1177                         else
1178                                 goto Badarg;
1179                         *rp = kbcompat(r);
1180                         lp = line;
1181                 }
1182         }
1183         if(lp != line){
1184                 l = lp-line;
1185                 f->aux = lp = emalloc9p(l+1);
1186                 memmove(lp, line, l);
1187                 lp[l] = 0;
1188         }
1189         req->ofcall.count = req->ifcall.count;
1190         respond(req, nil);
1191 }
1192
1193 /*
1194  * Filesystem
1195  */
1196
1197 static char*
1198 getauser(void)
1199 {
1200         static char user[64];
1201         int fd;
1202         int n;
1203
1204         if(*user)
1205                 return user;
1206         if((fd = open("/dev/user", OREAD)) < 0)
1207                 strcpy(user, "none");
1208         else {
1209                 n = read(fd, user, (sizeof user)-1);
1210                 close(fd);
1211                 if(n < 0)
1212                         strcpy(user, "none");
1213                 else
1214                         user[n] = 0;
1215         }
1216         return user;
1217 }
1218
1219 static int
1220 fillstat(ulong qid, Dir *d)
1221 {
1222         struct Qtab *t;
1223
1224         memset(d, 0, sizeof *d);
1225         d->uid = getauser();
1226         d->gid = getauser();
1227         d->muid = "";
1228         d->qid = (Qid){qid, 0, 0};
1229         d->atime = time(0);
1230         t = qtab + qid;
1231         d->name = t->name;
1232         d->qid.type = t->type;
1233         d->mode = t->mode;
1234         return 1;
1235 }
1236
1237 static void
1238 fsattach(Req *r)
1239 {
1240         char *spec;
1241
1242         spec = r->ifcall.aname;
1243         if(spec && spec[0]){
1244                 respond(r, Ebadspec);
1245                 return;
1246         }
1247         r->fid->qid = (Qid){Qroot, 0, QTDIR};
1248         r->ofcall.qid = r->fid->qid;
1249         respond(r, nil);
1250 }
1251
1252 static void
1253 fsstat(Req *r)
1254 {
1255         fillstat((ulong)r->fid->qid.path, &r->d);
1256         r->d.name = estrdup9p(r->d.name);
1257         r->d.uid = estrdup9p(r->d.uid);
1258         r->d.gid = estrdup9p(r->d.gid);
1259         r->d.muid = estrdup9p(r->d.muid);
1260         respond(r, nil);
1261 }
1262
1263 static char*
1264 fswalk1(Fid *fid, char *name, Qid *qid)
1265 {
1266         int i;
1267         ulong path;
1268
1269         path = fid->qid.path;
1270         switch(path){
1271         case Qroot:
1272                 if (strcmp(name, "..") == 0) {
1273                         *qid = (Qid){Qroot, 0, QTDIR};
1274                         fid->qid = *qid;
1275                         return nil;
1276                 }
1277                 for(i = fid->qid.path; i<Nqid; i++){
1278                         if(strcmp(name, qtab[i].name) != 0)
1279                                 continue;
1280                         *qid = (Qid){i, 0, 0};
1281                         fid->qid = *qid;
1282                         return nil;
1283                 }
1284                 return Enonexist;
1285                 
1286         default:
1287                 return Ewalk;
1288         }
1289 }
1290
1291 static void
1292 fsopen(Req *r)
1293 {
1294         Fid *f;
1295         static int need[4] = { 4, 2, 6, 1 };
1296         struct Qtab *t;
1297         int n;
1298
1299         f = r->fid;
1300         t = qtab + f->qid.path;
1301         n = need[r->ifcall.mode & 3]<<6;
1302         if((n & t->mode) != n)
1303                 respond(r, Eperm);
1304         else{
1305                 f->aux = nil;
1306                 switch((ulong)f->qid.path){
1307                 case Qkbd:
1308                         if(kbdopen){
1309                                 respond(r, Einuse);
1310                                 return;
1311                         }
1312                         kbdopen++;
1313                         break;
1314                 case Qconsctl:
1315                         consctlopen++;
1316                         break;
1317                 }
1318                 respond(r, nil);
1319         }
1320 }
1321
1322 static int
1323 readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
1324 {
1325         int i, m, n;
1326         long pos;
1327         Dir d;
1328
1329         n = 0;
1330         pos = 0;
1331         for (i = 1; i < Nqid; i++){
1332                 fillstat(i, &d);
1333                 m = convD2M(&d, &buf[n], blen-n);
1334                 if(off <= pos){
1335                         if(m <= BIT16SZ || m > cnt)
1336                                 break;
1337                         n += m;
1338                         cnt -= m;
1339                 }
1340                 pos += m;
1341         }
1342         return n;
1343 }
1344
1345 static void
1346 fsread(Req *r)
1347 {
1348         Fid *f;
1349
1350         f = r->fid;
1351         switch((ulong)f->qid.path){
1352         default:
1353                 respond(r, Ephase);
1354                 return;
1355         case Qroot:
1356                 r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
1357                         r->ifcall.count, r->ifcall.count);
1358                 break;
1359         case Qkbd:
1360                 sendp(kbdreqchan, r);
1361                 return;
1362         case Qcons:
1363                 sendp(consreqchan, r);
1364                 return;
1365         case Qkbmap:
1366                 kbmapread(r);
1367                 return;
1368         }
1369         respond(r, nil);
1370 }
1371
1372 static void
1373 fswrite(Req *r)
1374 {
1375         Fid *f;
1376         char *p;
1377         int n, i;
1378
1379         f = r->fid;
1380         p = r->ifcall.data;
1381         n = r->ifcall.count;
1382         switch((ulong)f->qid.path){
1383         default:
1384                 respond(r, Ephase);
1385                 return;
1386
1387         case Qcons:
1388                 if(write(1, p, n) != n){
1389                         responderror(r);
1390                         return;
1391                 }
1392                 break;
1393
1394         case Qconsctl:
1395                 if(n >= 5 && memcmp(p, "rawon", 5) == 0)
1396                         sendul(ctlchan, Rawon);
1397                 else if(n >= 6 && memcmp(p, "rawoff", 6) == 0)
1398                         sendul(ctlchan, Rawoff);
1399                 else {
1400                         respond(r, Ebadarg);
1401                         return;
1402                 }
1403                 break;
1404
1405         case Qkbdin:
1406         case Qkbin:
1407                 if(f->aux == nil){
1408                         f->aux = emalloc9p(sizeof(Scan));
1409                         memset(f->aux, 0, sizeof(Scan));
1410                 }
1411                 if(f->qid.path == Qkbin){
1412                         for(i=0; i<n; i++)
1413                                 kbdputsc((Scan*)f->aux, (uchar)p[i]);
1414                 } else {
1415                         kbdin((Scan*)f->aux, p, n);
1416                 }
1417                 break;
1418
1419         case Qkbmap:
1420                 kbmapwrite(r);
1421                 return;
1422
1423         }
1424         r->ofcall.count = n;
1425         respond(r, nil);
1426 }
1427
1428 static void
1429 fsflush(Req *r)
1430 {
1431         switch((ulong)r->oldreq->fid->qid.path) {
1432         case Qkbd:
1433                 sendp(kbdreqchan, r);
1434                 return;
1435         case Qcons:
1436                 sendp(consreqchan, r);
1437                 return;
1438         }
1439         respond(r, nil);
1440 }
1441
1442 static void
1443 fsdestroyfid(Fid *f)
1444 {
1445         void *p;
1446
1447         if(f->omode != -1)
1448                 switch((ulong)f->qid.path){
1449                 case Qkbdin:
1450                 case Qkbin:
1451                 case Qkbmap:
1452                         if(p = f->aux){
1453                                 f->aux = nil;
1454                                 free(p);
1455                         }
1456                         break;
1457                 case Qkbd:
1458                         kbdopen--;
1459                         break;
1460                 case Qconsctl:
1461                         if(--consctlopen == 0)
1462                                 sendul(ctlchan, Rawoff);
1463                         break;
1464                 }
1465 }
1466
1467 static int
1468 procopen(int pid, char *name, int mode)
1469 {
1470         char buf[128];
1471
1472         snprint(buf, sizeof(buf), "/proc/%d/%s", pid, name);
1473         return eopen(buf, mode);
1474 }
1475
1476 static void
1477 elevate(void)
1478 {
1479         Dir *d, nd;
1480         int fd;
1481
1482         if(debug)
1483                 return;
1484
1485         if((fd = procopen(getpid(), "ctl", OWRITE)) < 0)
1486                 return;
1487
1488         /* get higher than normal priority */
1489         fprint(fd, "pri 16\n");
1490
1491         /* always present in physical memory */
1492         fprint(fd, "noswap\n");
1493
1494         /* dont let anybody kill us */
1495         if(d = dirfstat(fd)){
1496                 nulldir(&nd);
1497                 nd.mode = d->mode & ~0222;
1498                 dirfwstat(fd, &nd);
1499                 free(d);
1500         }
1501
1502         close(fd);
1503 }
1504
1505 static void
1506 fsstart(Srv*)
1507 {
1508         killfd = procopen(getpid(), "notepg", OWRITE);
1509         elevate();
1510         proccreate(ctlproc, nil, STACK);
1511 }
1512
1513 static void
1514 fsend(Srv*)
1515 {
1516         shutdown();
1517 }
1518
1519 Srv fs = {
1520         .start=                 fsstart,
1521         .attach=                fsattach,
1522         .walk1=                 fswalk1,
1523         .open=                  fsopen,
1524         .read=                  fsread,
1525         .write=                 fswrite,
1526         .stat=                  fsstat,
1527         .flush=                 fsflush,
1528         .destroyfid=            fsdestroyfid,
1529         .end=                   fsend,
1530 };
1531
1532 void
1533 usage(void)
1534 {
1535         fprint(2, "usage: %s [ -qdD ] [ -s sname ] [ -m mntpnt ] [ file ]\n", argv0);
1536         exits("usage");
1537 }
1538
1539 void
1540 threadmain(int argc, char** argv)
1541 {
1542         ARGBEGIN{
1543         case 'd':
1544                 debug++;
1545                 break;
1546         case 'D':
1547                 chatty9p++;
1548                 break;
1549         case 's':
1550                 sname = EARGF(usage());
1551                 break;
1552         case 'm':
1553                 mntpt = EARGF(usage());
1554                 break;
1555         case 'q':
1556                 quiet++;
1557                 break;
1558         default:
1559                 usage();
1560         }ARGEND
1561
1562         if(*argv)
1563                 consfd = eopen(*argv, OREAD);
1564
1565         kbdifd = open(dev("kbd"), OREAD);
1566         if(kbdifd < 0){
1567                 scanfd = eopen(dev("scancode"), OREAD);
1568                 ledsfd = eopen(dev("leds"), OWRITE);
1569         }
1570         mctlfd = eopen(dev("mousectl"), OWRITE);
1571         msinfd = eopen(dev("mousein"), OWRITE);
1572
1573         notefd = procopen(getpid(), "notepg", OWRITE);
1574
1575         consreqchan = chancreate(sizeof(Req*), 0);
1576         kbdreqchan = chancreate(sizeof(Req*), 0);
1577
1578         keychan = chancreate(sizeof(Key), 64);
1579         mctlchan = chancreate(sizeof(Key), 64);
1580         ctlchan = chancreate(sizeof(int), 0);
1581         rawchan = chancreate(sizeof(Rune), 0);
1582         runechan = chancreate(sizeof(Rune), 256);
1583         conschan = chancreate(sizeof(char*), 128);
1584         kbdchan = chancreate(sizeof(char*), 128);
1585         intchan = chancreate(sizeof(int), 0);
1586
1587         threadpostmountsrv(&fs, sname, mntpt, MBEFORE);
1588         threadexits(0);
1589 }