History

a

Russ Cox committed 21 years ago

Commit 934846f1 parent 0189e66382 files · +62610 −-4Browse files

Unified · Split

382 files
  1. Makefile +82 −0
  2. Notes +16 −0
  3. args.h +20 −0
  4. cpu.c +606 −0
  5. drawterm.h +10 −0
  6. drawterm.ico +0 −0
  7. drawterm.rc +72 −0
  8. drawterm.res +0 −0
  9. exportfs/Makefile +16 −0
  10. exportfs/exportfs.c +503 −0
  11. exportfs/exportfs.h +148 −0
  12. exportfs/exportsrv.c +679 −0
  13. exportfs/mkfile +11 −0
  14. gui-win32/alloc.c +23 −0
  15. gui-win32/cload.c +10 −0
  16. gui-win32/draw.c +22 −0
  17. gui-win32/load.c +10 −0
  18. gui-win32/mkfile +14 −0
  19. gui-win32/screen.c +642 −0
  20. gui-win32/wstrtoutf.c +35 −0
  21. gui-x11/Makefile +20 −0
  22. gui-x11/alloc.c +209 −0
  23. gui-x11/cload.c +16 −0
  24. gui-x11/draw.c +189 −0
  25. gui-x11/keysym2ucs-x11.c +857 −0
  26. gui-x11/keysym2ucs.h +9 −0
  27. gui-x11/ksym2utf.h +754 −0
  28. gui-x11/load.c +16 −0
  29. gui-x11/screen.c +1094 −0
  30. gui-x11/xmem.h +60 −0
  31. include/a.out +0 −0
  32. include/auth.h +144 −0
  33. include/authsrv.h +166 −0
  34. include/cursor.h +6 −0
  35. include/draw.h +519 −0
  36. include/dtos.h +10 −0
  37. include/fcall.h +110 −0
  38. include/keyboard.h +42 −0
  39. include/lib.h +246 −0
  40. include/libc.h +3 −0
  41. include/libsec.h +340 −0
  42. include/memdraw.h +200 −0
  43. include/memlayer.h +51 −0
  44. include/mp.h +134 −0
  45. include/u.h +26 −0
  46. include/unix.h +14 −0
  47. include/user.h +65 −0
  48. include/x +0 −0
  49. include/x.c +6 −0
  50. kern/Makefile +50 −0
  51. kern/allocb.c +165 −0
  52. kern/cache.c +46 −0
  53. kern/chan.c +1496 −0
  54. kern/dat.h +519 −0
  55. kern/data.c +31 −0
  56. kern/dev.c +468 −0
  57. kern/devcons.c +1238 −0
  58. kern/devdraw.c +2100 −0
  59. kern/devfs.c +638 −0
  60. kern/devip-posix.c +209 −0
  61. kern/devip-win.c +208 −0
  62. kern/devip.c +936 −0
  63. kern/devip.h +17 −0
  64. kern/devmnt.c +1214 −0
  65. kern/devmouse.c +237 −0
  66. kern/devntfs.c +704 −0
  67. kern/devpipe.c +398 −0
  68. kern/devroot.c +268 −0
  69. kern/devssl.c +1512 −0
  70. kern/devtab.c +27 −0
  71. kern/error.c +50 −0
  72. kern/error.h +50 −0
  73. kern/exportfs.c +821 −0
  74. kern/fns.h +377 −0
  75. kern/mkfile +47 −0
  76. kern/netif.h +133 −0
  77. kern/os-windows.c +184 −0
  78. kern/parse.c +113 −0
  79. kern/pgrp.c +272 −0
  80. kern/posix.c +190 −0
  81. kern/procinit.c +67 −0
  82. kern/qio.c +1524 −0
  83. kern/qlock.c +94 −0
  84. kern/rendez.c +90 −0
  85. kern/rwlock.c +39 −0
  86. kern/screen.h +59 −0
  87. kern/sleep.c +90 −0
  88. kern/smalloc.c +18 −0
  89. kern/stub.c +170 −0
  90. kern/syscall.c +837 −0
  91. kern/sysfile.c +1242 −0
  92. kern/sysproc.c +32 −0
  93. kern/term.c +204 −0
  94. kern/todo.c +0 −0
  95. kern/uart.c +14 −0
  96. kern/waserror.c +27 −0
  97. kern/winduhz.h +18 −0
  98. kern/x +601 −0
  99. latin1.c +177 −0
  100. libauthsrv/Makefile +28 −0
  101. libauthsrv/authdial.c +31 −0
  102. libauthsrv/convA2M.c +25 −0
  103. libauthsrv/convM2A.c +23 −0
  104. libauthsrv/convM2PR.c +28 −0
  105. libauthsrv/convM2T.c +28 −0
  106. libauthsrv/convM2TR.c +28 −0
  107. libauthsrv/convPR2M.c +28 −0
  108. libauthsrv/convT2M.c +27 −0
  109. libauthsrv/convTR2M.c +27 −0
  110. libauthsrv/mkfile +25 −0
  111. libauthsrv/nvcsum.c +16 −0
  112. libauthsrv/opasstokey.c +29 −0
  113. libauthsrv/passtokey.c +33 −0
  114. libauthsrv/readnvram.c +368 −0
  115. libc/Makefile +89 −0
  116. libc/charstod.c +81 −0
  117. libc/cleanname.c +52 −0
  118. libc/convD2M.c +95 −0
  119. libc/convM2D.c +94 −0
  120. libc/convM2S.c +315 −0
  121. libc/convS2M.c +386 −0
  122. libc/crypt.c +68 −0
  123. libc/dial.c +209 −0
  124. libc/dirfstat.c +37 −0
  125. libc/dirfwstat.c +19 −0
  126. libc/dirmodefmt.c +48 −0
  127. libc/dirstat.c +37 −0
  128. libc/dirwstat.c +19 −0
  129. libc/dofmt.c +520 −0
  130. libc/dorfmt.c +46 −0
  131. libc/errfmt.c +12 −0
  132. libc/fcallfmt.c +234 −0
  133. libc/fltfmt.c +312 −0
  134. libc/fmt.c +193 −0
  135. libc/fmt.h +99 −0
  136. libc/fmtdef.h +85 −0
  137. libc/fmtfd.c +31 −0
  138. libc/fmtlock.c +16 −0
  139. libc/fmtprint.c +32 −0
  140. libc/fmtquote.c +247 −0
  141. libc/fmtrune.c +25 −0
  142. libc/fmtstr.c +11 −0
  143. libc/fmtvprint.c +31 −0
  144. libc/fprint.c +14 −0
  145. libc/frand.c +17 −0
  146. libc/getfields.c +37 −0
  147. libc/getpid.c +17 −0
  148. libc/lnrand.c +18 −0
  149. libc/lock.c +64 −0
  150. libc/lrand.c +83 −0
  151. libc/mallocz.c +13 −0
  152. libc/mkfile +90 −0
  153. libc/nan.h +4 −0
  154. libc/nan64.c +55 −0
  155. libc/netmkaddr.c +52 −0
  156. libc/nrand.c +18 −0
  157. libc/nsec.c +66 −0
  158. libc/pow10.c +49 −0
  159. libc/print.c +14 −0
  160. libc/pushssl.c +44 −0
  161. libc/rand.c +8 −0
  162. libc/read9pmsg.c +31 −0
  163. libc/readn.c +22 −0
  164. libc/rune.c +162 −0
  165. libc/runefmtstr.c +11 −0
  166. libc/runeseprint.c +14 −0
  167. libc/runesmprint.c +14 −0
  168. libc/runesnprint.c +15 −0
  169. libc/runesprint.c +14 −0
  170. libc/runestrcat.c +10 −0
  171. libc/runestrchr.c +20 −0
  172. libc/runestrcmp.c +20 −0
  173. libc/runestrcpy.c +13 −0
  174. libc/runestrdup.c +14 −0
  175. libc/runestrecpy.c +17 −0
  176. libc/runestrlen.c +9 −0
  177. libc/runestrncat.c +17 −0
  178. libc/runestrncmp.c +22 −0
  179. libc/runestrncpy.c +18 −0
  180. libc/runestrrchr.c +15 −0
  181. libc/runestrstr.c +29 −0
  182. libc/runetype.c +1138 −0
  183. libc/runevseprint.c +23 −0
  184. libc/runevsmprint.c +70 −0
  185. libc/runevsnprint.c +22 −0
  186. libc/seprint.c +14 −0
  187. libc/smprint.c +14 −0
  188. libc/snprint.c +15 −0
  189. libc/sprint.c +14 −0
  190. libc/strecpy.c +17 −0
  191. libc/strtod.c +532 −0
  192. libc/strtod.h +4 −0
  193. libc/strtoll.c +93 −0
  194. libc/sysfatal.c +30 −0
  195. libc/time.c +51 −0
  196. libc/tokenize.c +107 −0
  197. libc/truerand.c +17 −0
  198. libc/u16.c +53 −0
  199. libc/u32.c +110 −0
  200. libc/u64.c +127 −0
  201. libc/utf.h +51 −0
  202. libc/utfdef.h +14 −0
  203. libc/utfecpy.c +21 −0
  204. libc/utflen.c +23 −0
  205. libc/utfnlen.c +26 −0
  206. libc/utfrrune.c +31 −0
  207. libc/utfrune.c +30 −0
  208. libc/utfutf.c +26 −0
  209. libc/vfprint.c +34 −0
  210. libc/vseprint.c +23 −0
  211. libc/vsmprint.c +70 −0
  212. libc/vsnprint.c +22 −0
  213. libdraw/Makefile +24 −0
  214. libdraw/alloc.c +237 −0
  215. libdraw/arith.c +206 −0
  216. libdraw/bytesperline.c +34 −0
  217. libdraw/chan.c +77 −0
  218. libdraw/defont.c +402 −0
  219. libdraw/drawrepl.c +23 −0
  220. libdraw/icossin.c +140 −0
  221. libdraw/icossin2.c +261 −0
  222. libdraw/mkfile +18 −0
  223. libdraw/rectclip.c +25 −0
  224. libdraw/rgb.c +99 −0
  225. libmemdraw/Makefile +33 −0
  226. libmemdraw/alloc.c +200 −0
  227. libmemdraw/alpha.hoc +9 −0
  228. libmemdraw/arc.c +117 −0
  229. libmemdraw/arctest.c +62 −0
  230. libmemdraw/cload.c +68 −0
  231. libmemdraw/cmap.c +320 −0
  232. libmemdraw/cread.c +96 −0
  233. libmemdraw/defont.c +68 −0
  234. libmemdraw/draw.c +2499 −0
  235. libmemdraw/drawtest.c +1004 −0
  236. libmemdraw/ellipse.c +248 −0
  237. libmemdraw/fillpoly.c +523 −0
  238. libmemdraw/hwdraw.c +12 −0
  239. libmemdraw/iprint.c +12 −0
  240. libmemdraw/line.c +485 −0
  241. libmemdraw/load.c +72 −0
  242. libmemdraw/mkcmap.c +79 −0
  243. libmemdraw/mkfile +27 −0
  244. libmemdraw/openmemsubfont.c +53 −0
  245. libmemdraw/poly.c +24 −0
  246. libmemdraw/read.c +111 −0
  247. libmemdraw/string.c +68 −0
  248. libmemdraw/subfont.c +34 −0
  249. libmemdraw/times +19 −0
  250. libmemdraw/unload.c +25 −0
  251. libmemdraw/write.c +183 −0
  252. libmemlayer/Makefile +26 −0
  253. libmemlayer/draw.c +192 −0
  254. libmemlayer/lalloc.c +79 −0
  255. libmemlayer/layerop.c +112 −0
  256. libmemlayer/ldelete.c +67 −0
  257. libmemlayer/lhide.c +67 −0
  258. libmemlayer/line.c +122 −0
  259. libmemlayer/load.c +55 −0
  260. libmemlayer/lorigin.c +107 −0
  261. libmemlayer/lsetrefresh.c +35 −0
  262. libmemlayer/ltofront.c +80 −0
  263. libmemlayer/ltorear.c +69 −0
  264. libmemlayer/mkfile +23 −0
  265. libmemlayer/unload.c +52 −0
  266. libmp/Makefile +46 −0
  267. libmp/betomp.c +40 −0
  268. libmp/crt.c +122 −0
  269. libmp/crttest.c +54 −0
  270. libmp/dat.h +15 −0
  271. libmp/letomp.c +29 −0
  272. libmp/mkfile +40 −0
  273. libmp/mpadd.c +54 −0
  274. libmp/mpaux.c +185 −0
  275. libmp/mpcmp.c +28 −0
  276. libmp/mpdigdiv.c +43 −0
  277. libmp/mpdiv.c +112 −0
  278. libmp/mpeuclid.c +82 −0
  279. libmp/mpexp.c +86 −0
  280. libmp/mpextendedgcd.c +97 −0
  281. libmp/mpfmt.c +193 −0
  282. libmp/mpinvert.c +21 −0
  283. libmp/mpleft.c +46 −0
  284. libmp/mpmod.c +15 −0
  285. libmp/mpmul.c +156 −0
  286. libmp/mprand.c +42 −0
  287. libmp/mpright.c +40 −0
  288. libmp/mpsub.c +52 −0
  289. libmp/mptobe.c +57 −0
  290. libmp/mptoi.c +44 −0
  291. libmp/mptole.c +54 −0
  292. libmp/mptoui.c +35 −0
  293. libmp/mptouv.c +49 −0
  294. libmp/mptov.c +69 −0
  295. libmp/mpvecadd.c +35 −0
  296. libmp/mpveccmp.c +28 −0
  297. libmp/mpvecdigmuladd.c +103 −0
  298. libmp/mpvecsub.c +34 −0
  299. libmp/os.h +3 −0
  300. libmp/reduce +16 −0
  301. libmp/strtomp.c +205 −0
  302. libsec/Makefile +60 −0
  303. libsec/aes.c +1544 −0
  304. libsec/blowfish.c +579 −0
  305. libsec/decodepem.c +59 −0
  306. libsec/des.c +480 −0
  307. libsec/des3CBC.c +59 −0
  308. libsec/des3ECB.c +48 −0
  309. libsec/desCBC.c +59 −0
  310. libsec/desECB.c +48 −0
  311. libsec/desmodes.c +31 −0
  312. libsec/dsaalloc.c +69 −0
  313. libsec/dsagen.c +61 −0
  314. libsec/dsaprimes.c +97 −0
  315. libsec/dsaprivtopub.c +16 −0
  316. libsec/dsasign.c +52 −0
  317. libsec/dsaverify.c +46 −0
  318. libsec/egalloc.c +67 −0
  319. libsec/egdecrypt.c +28 −0
  320. libsec/egencrypt.c +38 −0
  321. libsec/eggen.c +21 −0
  322. libsec/egprivtopub.c +17 −0
  323. libsec/egsign.c +43 −0
  324. libsec/egtest.c +34 −0
  325. libsec/egverify.c +29 −0
  326. libsec/fastrand.c +16 −0
  327. libsec/genprime.c +27 −0
  328. libsec/genrandom.c +62 −0
  329. libsec/gensafeprime.c +36 −0
  330. libsec/genstrongprime.c +57 −0
  331. libsec/hmac.c +56 −0
  332. libsec/hmactest.c +19 −0
  333. libsec/md4.c +271 −0
  334. libsec/md4test.c +31 −0
  335. libsec/md5.c +148 −0
  336. libsec/md5block.c +267 −0
  337. libsec/md5pickle.c +37 −0
  338. libsec/mkfile +55 −0
  339. libsec/nfastrand.c +23 −0
  340. libsec/os.h +2 −0
  341. libsec/primetest.c +41 −0
  342. libsec/prng.c +15 −0
  343. libsec/probably_prime.c +84 −0
  344. libsec/ranlib.core +0 −0
  345. libsec/rc4.c +104 −0
  346. libsec/readcert.c +50 −0
  347. libsec/rsaalloc.c +52 −0
  348. libsec/rsadecrypt.c +37 −0
  349. libsec/rsaencrypt.c +12 −0
  350. libsec/rsafill.c +61 −0
  351. libsec/rsagen.c +82 −0
  352. libsec/rsaprivtopub.c +16 −0
  353. libsec/rsatest.c +57 −0
  354. libsec/sha1.c +127 −0
  355. libsec/sha1block.c +187 −0
  356. libsec/sha1pickle.c +38 −0
  357. libsec/smallprimes.c +1004 −0
  358. libsec/smallprimetest.c +1039 −0
  359. libsec/thumb.c +97 −0
  360. libsec/tlshand.c +2291 −0
  361. libsec/x509.c +2520 −0
  362. main.c +126 −0
  363. mkfile +95 −0
  364. mkfile-Windows +54 −0
  365. mkfile-posix +9 −0
  366. mkone +50 −0
  367. posix-386/Makefile +16 −0
  368. posix-386/getcallerpc.c +8 −0
  369. posix-386/md5block.s +241 −0
  370. posix-386/sha1block.s +214 −0
  371. posix-386/tas.c +23 −0
  372. posix-power/Makefile +16 −0
  373. posix-power/getcallerpc.c +8 −0
  374. posix-power/tas.c +42 −0
  375. readcons.c +110 −0
  376. resource.h +16 −0
  377. secstore.c +667 −0
  378. win32-386/getcallerpc.c +8 −0
  379. win32-386/md5block.s +241 −0
  380. win32-386/mkfile +10 −0
  381. win32-386/sha1block.s +214 −0
  382. win32-386/tas.c +22 −0
Makefile+82−0
@@ -0,0 +1,82 @@
1TARG=drawterm
2CC=gcc
3CFLAGS=-Iinclude -c -ggdb -D_THREAD_SAFE -pthread # not ready for this yet: -Wall
4O=o
5#CC=cl
6#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -Iinclude -DWINDOWS
7#O=obj
8
9OFILES=\
10 main.$O\
11 cpu.$O\
12 readcons.$O\
13 secstore.$O\
14 latin1.$O\
15
16LIBS=\
17 kern/libkern.a\
18 exportfs/libexportfs.a\
19 libauthsrv/libauthsrv.a\
20 libsec/libsec.a\
21 libmp/libmp.a\
22 libmemdraw/libmemdraw.a\
23 libmemlayer/libmemlayer.a\
24 libdraw/libdraw.a\
25 libc/libc.a\
26 kern/libkern.a\
27 gui-x11/libx11.a\
28 libmemdraw/libmemdraw.a\
29 libdraw/libdraw.a\
30 kern/libkern.a\
31 libc/libc.a\
32 libmemdraw/libmemdraw.a\
33 libmemlayer/libmemlayer.a\
34 libdraw/libdraw.a\
35 libmachdep.a
36
37$(TARG): $(OFILES) $(LIBS)
38 $(CC) -pthread -o $(TARG) $(OFILES) $(LIBS) -L/usr/X11R6/lib -lX11 -ggdb
39
40%.$O: %.c
41 $(CC) $(CFLAGS) $*.c
42
43clean:
44 rm -f *.o */*.o */*.a drawterm *.a
45
46kern/libkern.a:
47 (cd kern; make)
48
49exportfs/libexportfs.a:
50 (cd exportfs; make)
51
52libauthsrv/libauthsrv.a:
53 (cd libauthsrv; make)
54
55libmp/libmp.a:
56 (cd libmp; make)
57
58libsec/libsec.a:
59 (cd libsec; make)
60
61libmemdraw/libmemdraw.a:
62 (cd libmemdraw; make)
63
64libmemlayer/libmemlayer.a:
65 (cd libmemlayer; make)
66
67libdraw/libdraw.a:
68 (cd libdraw; make)
69
70libc/libc.a:
71 (cd libc; make)
72
73gui-x11/libx11.a:
74 (cd gui-x11; make)
75
76#libmachdep.a:
77# arch=`uname -m|sed 's/i.86/386/;s/Power Macintosh/power/'`; \
78# (cd gcc$$arch && make)
79
80libmachdep.a:
81 (cd posix-386; make)
82
Notes+16−0
@@ -0,0 +1,16 @@
1
2Win32 port Notes:
3
4* Issues:
5
6 ** ownership questions on files are completely deferred by
7 marking them as unknown. It works for now, but probably
8 should be handled correctly.
9
10 ** No performance measurements have been done. The interactive
11 response seems faster than old drawterm, but the i/o seems
12 slower.
13
14 ** fs functions in devntfs.c need to handle conversions to/from
15 widechar and utf-8.
16
args.h+20−0
@@ -0,0 +1,20 @@
1extern char *argv0;
2#define ARGBEGIN for((argv0? 0: (argv0=*argv)),argv++,argc--;\
3 argv[0] && argv[0][0]=='-' && argv[0][1];\
4 argc--, argv++) {\
5 char *_args, *_argt;\
6 Rune _argc;\
7 _args = &argv[0][1];\
8 if(_args[0]=='-' && _args[1]==0){\
9 argc--; argv++; break;\
10 }\
11 _argc = 0;\
12 while(*_args && (_args += chartorune(&_argc, _args)))\
13 switch(_argc)
14#define ARGEND SET(_argt);USED(_argt); USED(_argc); USED(_args);}USED(argv); USED(argc);
15#define ARGF() (_argt=_args, _args="",\
16 (*_argt? _argt: argv[1]? (argc--, *++argv): 0))
17#define ARGC() _argc
18
19#define EARGF(x) (_argt=_args, _args="",\
20 (*_argt? _argt: argv[1]? (argc--, *++argv): (x, (char*)0)))
cpu.c+606−0
@@ -0,0 +1,606 @@
1/*
2 * cpu.c - Make a connection to a cpu server
3 *
4 * Invoked by listen as 'cpu -R | -N service net netdir'
5 * by users as 'cpu [-h system] [-c cmd args ...]'
6 */
7
8#include <u.h>
9#include <libc.h>
10#include <auth.h>
11#include <fcall.h>
12#include <authsrv.h>
13#include <libsec.h>
14#include "args.h"
15#include "drawterm.h"
16
17#define Maxfdata 8192
18#define MaxStr 128
19
20static char* getuser(void);
21static void fatal(int, char*, ...);
22static void catcher(void*, char*);
23static void usage(void);
24static void writestr(int, char*, char*, int);
25static int readstr(int, char*, int);
26static char *rexcall(int*, char*, char*);
27static int setamalg(char*);
28static char *keyspec = "";
29static AuthInfo *p9any(int);
30
31static int notechan;
32#define system csystem
33static char *system;
34static int cflag;
35int dbg;
36
37static char *srvname = "ncpu";
38static char *ealgs = "rc4_256 sha1";
39
40/* message size for exportfs; may be larger so we can do big graphics in CPU window */
41static int msgsize = Maxfdata+IOHDRSZ;
42
43/* authentication mechanisms */
44static int netkeyauth(int);
45static int netkeysrvauth(int, char*);
46static int p9auth(int);
47static int srvp9auth(int, char*);
48static int noauth(int);
49static int srvnoauth(int, char*);
50
51char *authserver;
52
53typedef struct AuthMethod AuthMethod;
54struct AuthMethod {
55 char *name; /* name of method */
56 int (*cf)(int); /* client side authentication */
57 int (*sf)(int, char*); /* server side authentication */
58} authmethod[] =
59{
60 { "p9", p9auth, srvp9auth,},
61 { "netkey", netkeyauth, netkeysrvauth,},
62// { "none", noauth, srvnoauth,},
63 { nil, nil}
64};
65AuthMethod *am = authmethod; /* default is p9 */
66
67char *p9authproto = "p9any";
68
69int setam(char*);
70
71void
72exits(char *s)
73{
74 print("\ngoodbye\n");
75 for(;;) osyield();
76}
77
78void
79usage(void)
80{
81 fprint(2, "usage: drawterm [-a authserver] [-c cpuserver] [-s secstore] [-u user]\n");
82 exits("usage");
83}
84int fdd;
85
86void
87cpumain(int argc, char **argv)
88{
89 char dat[MaxStr], buf[MaxStr], cmd[MaxStr], *p, *err, *secstoreserver, *s;
90 int fd, ms, data;
91
92 /* see if we should use a larger message size */
93 fd = open("/dev/draw", OREAD);
94 if(fd > 0){
95 ms = iounit(fd);
96 if(msgsize < ms+IOHDRSZ)
97 msgsize = ms+IOHDRSZ;
98 close(fd);
99 }
100
101 user = readcons("user", getenv("USER"), 0);
102 secstoreserver = nil;
103 ARGBEGIN{
104 case 'a':
105 authserver = EARGF(usage());
106 break;
107 case 'e':
108 ealgs = EARGF(usage());
109 if(*ealgs == 0 || strcmp(ealgs, "clear") == 0)
110 ealgs = nil;
111 break;
112 case 'd':
113 dbg++;
114 break;
115 case 'c':
116 system = EARGF(usage());
117 break;
118/*
119 case 'c':
120 cflag++;
121 cmd[0] = '!';
122 cmd[1] = '\0';
123 while(p = ARGF()) {
124 strcat(cmd, " ");
125 strcat(cmd, p);
126 }
127 break;
128*/
129 case 'u':
130 user = EARGF(usage());
131 break;
132 case 's':
133 secstoreserver = EARGF(usage());
134 break;
135 default:
136 usage();
137 }ARGEND;
138
139 if(secstoreserver == nil)
140 secstoreserver = authserver;
141
142 if(secstoreserver && havesecstore(secstoreserver, user)){
143 s = secstorefetch(secstoreserver, user, nil);
144 if(s){
145 if(strlen(s) >= sizeof secstorebuf)
146 panic("secstore data too big");
147 strcpy(secstorebuf, s);
148 }
149 }
150
151
152 if(argc != 0)
153 usage();
154
155 if(system == nil) {
156 p = getenv("cpu");
157 if(p == 0)
158 fatal(0, "set $cpu");
159 system = p;
160 }
161
162 if(err = rexcall(&data, system, srvname))
163 fatal(1, "%s: %s", err, system);
164
165 /* Tell the remote side the command to execute and where our working directory is */
166 if(cflag)
167 writestr(data, cmd, "command", 0);
168 if(getcwd(dat, sizeof(dat)) == 0)
169 writestr(data, "NO", "dir", 0);
170 else
171 writestr(data, dat, "dir", 0);
172
173 /*
174 * Wait for the other end to execute and start our file service
175 * of /mnt/term
176 */
177 if(readstr(data, buf, sizeof(buf)) < 0)
178 fatal(1, "waiting for FS: %r");
179 if(strncmp("FS", buf, 2) != 0) {
180 print("remote cpu: %s", buf);
181 exits(buf);
182 }
183
184 if(readstr(data, buf, sizeof buf) < 0)
185 fatal(1, "waiting for remote export: %r");
186 if(strcmp(buf, "/") != 0){
187 print("remote cpu: %s" , buf);
188 exits(buf);
189 }
190 write(data, "OK", 2);
191
192 /* Begin serving the gnot namespace */
193 exportfs(data, msgsize);
194 fatal(1, "starting exportfs");
195}
196
197void
198fatal(int syserr, char *fmt, ...)
199{
200 Fmt f;
201 char *str;
202 va_list arg;
203
204 fmtstrinit(&f);
205 fmtprint(&f, "cpu: ");
206 va_start(arg, fmt);
207 fmtvprint(&f, fmt, arg);
208 va_end(arg);
209 if(syserr)
210 fmtprint(&f, ": %r");
211 fmtprint(&f, "\n");
212 str = fmtstrflush(&f);
213 write(2, str, strlen(str));
214 exits(str);
215}
216
217char *negstr = "negotiating authentication method";
218
219char bug[256];
220
221char*
222rexcall(int *fd, char *host, char *service)
223{
224 char *na;
225 char dir[MaxStr];
226 char err[ERRMAX];
227 char msg[MaxStr];
228 int n;
229
230 na = netmkaddr(host, "tcp", "17010");
231 if((*fd = dial(na, 0, dir, 0)) < 0)
232 return "can't dial";
233
234 /* negotiate authentication mechanism */
235 if(ealgs != nil)
236 snprint(msg, sizeof(msg), "%s %s", am->name, ealgs);
237 else
238 snprint(msg, sizeof(msg), "%s", am->name);
239 writestr(*fd, msg, negstr, 0);
240 n = readstr(*fd, err, sizeof err);
241 if(n < 0)
242 return negstr;
243 if(*err){
244 werrstr(err);
245 return negstr;
246 }
247
248 /* authenticate */
249 *fd = (*am->cf)(*fd);
250 if(*fd < 0)
251 return "can't authenticate";
252 return 0;
253}
254
255void
256writestr(int fd, char *str, char *thing, int ignore)
257{
258 int l, n;
259
260 l = strlen(str);
261 n = write(fd, str, l+1);
262 if(!ignore && n < 0)
263 fatal(1, "writing network: %s", thing);
264}
265
266int
267readstr(int fd, char *str, int len)
268{
269 int n;
270
271 while(len) {
272 n = read(fd, str, 1);
273 if(n < 0)
274 return -1;
275 if(*str == '\0')
276 return 0;
277 str++;
278 len--;
279 }
280 return -1;
281}
282
283static int
284readln(char *buf, int n)
285{
286 int i;
287 char *p;
288
289 n--; /* room for \0 */
290 p = buf;
291 for(i=0; i<n; i++){
292 if(read(0, p, 1) != 1)
293 break;
294 if(*p == '\n' || *p == '\r')
295 break;
296 p++;
297 }
298 *p = '\0';
299 return p-buf;
300}
301
302/*
303 * user level challenge/response
304 */
305static int
306netkeyauth(int fd)
307{
308 char chall[32];
309 char resp[32];
310
311 strecpy(chall, chall+sizeof chall, getuser());
312 print("user[%s]: ", chall);
313 if(readln(resp, sizeof(resp)) < 0)
314 return -1;
315 if(*resp != 0)
316 strcpy(chall, resp);
317 writestr(fd, chall, "challenge/response", 1);
318
319 for(;;){
320 if(readstr(fd, chall, sizeof chall) < 0)
321 break;
322 if(*chall == 0)
323 return fd;
324 print("challenge: %s\nresponse: ", chall);
325 if(readln(resp, sizeof(resp)) < 0)
326 break;
327 writestr(fd, resp, "challenge/response", 1);
328 }
329 return -1;
330}
331
332static int
333netkeysrvauth(int fd, char *user)
334{
335 return -1;
336}
337
338static void
339mksecret(char *t, uchar *f)
340{
341 sprint(t, "%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
342 f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9]);
343}
344
345/*
346 * plan9 authentication followed by rc4 encryption
347 */
348static int
349p9auth(int fd)
350{
351 uchar key[16];
352 uchar digest[SHA1dlen];
353 char fromclientsecret[21];
354 char fromserversecret[21];
355 int i;
356 AuthInfo *ai;
357
358 ai = p9any(fd);
359 if(ai == nil)
360 return -1;
361 memmove(key+4, ai->secret, ai->nsecret);
362 if(ealgs == nil)
363 return fd;
364
365 /* exchange random numbers */
366 srand(truerand());
367 for(i = 0; i < 4; i++)
368 key[i] = rand();
369 if(write(fd, key, 4) != 4)
370 return -1;
371 if(readn(fd, key+12, 4) != 4)
372 return -1;
373
374 /* scramble into two secrets */
375 sha1(key, sizeof(key), digest, nil);
376 mksecret(fromclientsecret, digest);
377 mksecret(fromserversecret, digest+10);
378
379 /* set up encryption */
380 i = pushssl(fd, ealgs, fromclientsecret, fromserversecret, nil);
381 if(i < 0)
382 werrstr("can't establish ssl connection: %r");
383 return i;
384}
385
386int
387authdial(char *net, char *dom)
388{
389 int fd;
390 fd = dial(netmkaddr(authserver, "tcp", "567"), 0, 0, 0);
391 //print("authdial %d\n", fd);
392 return fd;
393}
394
395static int
396getastickets(Ticketreq *tr, char *trbuf, char *tbuf)
397{
398 int asfd, rv;
399 char *dom;
400
401 dom = tr->authdom;
402 asfd = authdial(nil, dom);
403 if(asfd < 0)
404 return -1;
405 rv = _asgetticket(asfd, trbuf, tbuf);
406 close(asfd);
407 return rv;
408}
409
410static int
411mkserverticket(Ticketreq *tr, char *authkey, char *tbuf)
412{
413 int i;
414 Ticket t;
415
416 if(strcmp(tr->authid, tr->hostid) != 0)
417 return -1;
418 memset(&t, 0, sizeof(t));
419 memmove(t.chal, tr->chal, CHALLEN);
420 strcpy(t.cuid, tr->uid);
421 strcpy(t.suid, tr->uid);
422 for(i=0; i<DESKEYLEN; i++)
423 t.key[i] = fastrand();
424 t.num = AuthTc;
425 convT2M(&t, tbuf, authkey);
426 t.num = AuthTs;
427 convT2M(&t, tbuf+TICKETLEN, authkey);
428 return 0;
429}
430
431static int
432gettickets(Ticketreq *tr, char *key, char *trbuf, char *tbuf)
433{
434 if(getastickets(tr, trbuf, tbuf) >= 0)
435 return 0;
436 return mkserverticket(tr, key, tbuf);
437}
438
439AuthInfo*
440p9any(int fd)
441{
442 char buf[1024], buf2[1024], cchal[CHALLEN], *bbuf, *p, *dom, *u;
443 char *pass;
444 char tbuf[TICKETLEN+TICKETLEN+AUTHENTLEN], trbuf[TICKREQLEN];
445 char authkey[DESKEYLEN];
446 Authenticator auth;
447 int i, v2, n;
448 Ticketreq tr;
449 Ticket t;
450 AuthInfo *ai;
451
452 if((n = readstr(fd, buf, sizeof buf)) < 0)
453 fatal(1, "cannot read p9any negotiation");
454 bbuf = buf;
455 v2 = 0;
456 if(strncmp(buf, "v.2 ", 4) == 0){
457 v2 = 1;
458 bbuf += 4;
459 }
460 if(p = strchr(bbuf, ' '))
461 *p = 0;
462 p = bbuf;
463 if((dom = strchr(p, '@')) == nil)
464 fatal(1, "bad p9any domain");
465 *dom++ = 0;
466 if(strcmp(p, "p9sk1") != 0)
467 fatal(1, "server did not offer p9sk1");
468
469 sprint(buf2, "%s %s", p, dom);
470 if(write(fd, buf2, strlen(buf2)+1) != strlen(buf2)+1)
471 fatal(1, "cannot write user/domain choice in p9any");
472 if(v2){
473 if((n = readstr(fd, buf, sizeof buf)) != 3)
474 fatal(1, "cannot read OK in p9any");
475 if(memcmp(buf, "OK\0", 3) != 0)
476 fatal(1, "did not get OK in p9any");
477 }
478 for(i=0; i<CHALLEN; i++)
479 cchal[i] = fastrand();
480 if(write(fd, cchal, 8) != 8)
481 fatal(1, "cannot write p9sk1 challenge");
482
483 if(readn(fd, trbuf, TICKREQLEN) != TICKREQLEN)
484 fatal(1, "cannot read ticket request in p9sk1");
485
486
487 convM2TR(trbuf, &tr);
488 u = user;
489 pass = findkey(&u, tr.authdom);
490 if(pass == nil)
491 again:
492 pass = getkey(u, tr.authdom);
493 if(pass == nil)
494 fatal(1, "no password");
495
496 passtokey(authkey, pass);
497 memset(pass, 0, strlen(pass));
498
499 tr.type = AuthTreq;
500 strecpy(tr.hostid, tr.hostid+sizeof tr.hostid, u);
501 strecpy(tr.uid, tr.uid+sizeof tr.uid, u);
502 convTR2M(&tr, trbuf);
503
504 if(gettickets(&tr, authkey, trbuf, tbuf) < 0)
505 fatal(1, "cannot get auth tickets in p9sk1");
506
507 convM2T(tbuf, &t, authkey);
508 if(t.num != AuthTc){
509 print("?password mismatch with auth server\n");
510 goto again;
511 }
512 memmove(tbuf, tbuf+TICKETLEN, TICKETLEN);
513
514 auth.num = AuthAc;
515 memmove(auth.chal, tr.chal, CHALLEN);
516 auth.id = 0;
517 convA2M(&auth, tbuf+TICKETLEN, t.key);
518
519 if(write(fd, tbuf, TICKETLEN+AUTHENTLEN) != TICKETLEN+AUTHENTLEN)
520 fatal(1, "cannot send ticket and authenticator back in p9sk1");
521
522 if(readn(fd, tbuf, AUTHENTLEN) != AUTHENTLEN)
523 fatal(1, "cannot read authenticator in p9sk1");
524
525 convM2A(tbuf, &auth, t.key);
526 if(auth.num != AuthAs
527 || memcmp(auth.chal, cchal, CHALLEN) != 0
528 || auth.id != 0){
529 print("?you and auth server agree about password.\n");
530 print("?server is confused.\n");
531 fatal(1, "server lies got %llux.%d want %llux.%d", *(vlong*)auth.chal, auth.id, *(vlong*)cchal, 0);
532 }
533 //print("i am %s there.\n", t.suid);
534 ai = mallocz(sizeof(AuthInfo), 1);
535 ai->secret = mallocz(8, 1);
536 des56to64((uchar*)t.key, ai->secret);
537 ai->nsecret = 8;
538 ai->suid = strdup(t.suid);
539 ai->cuid = strdup(t.cuid);
540 memset(authkey, 0, sizeof authkey);
541 return ai;
542}
543
544static int
545noauth(int fd)
546{
547 ealgs = nil;
548 return fd;
549}
550
551static int
552srvnoauth(int fd, char *user)
553{
554 strecpy(user, user+MaxStr, getuser());
555 ealgs = nil;
556 return fd;
557}
558
559void
560loghex(uchar *p, int n)
561{
562 char buf[100];
563 int i;
564
565 for(i = 0; i < n; i++)
566 sprint(buf+2*i, "%2.2ux", p[i]);
567// syslog(0, "cpu", buf);
568}
569
570static int
571srvp9auth(int fd, char *user)
572{
573 return -1;
574}
575
576/*
577 * set authentication mechanism
578 */
579int
580setam(char *name)
581{
582 for(am = authmethod; am->name != nil; am++)
583 if(strcmp(am->name, name) == 0)
584 return 0;
585 am = authmethod;
586 return -1;
587}
588
589/*
590 * set authentication mechanism and encryption/hash algs
591 */
592int
593setamalg(char *s)
594{
595 ealgs = strchr(s, ' ');
596 if(ealgs != nil)
597 *ealgs++ = 0;
598 return setam(s);
599}
600
601char*
602getuser(void)
603{
604 return getenv("USER");
605}
606
drawterm.h+10−0
@@ -0,0 +1,10 @@
1extern int havesecstore(char *addr, char *owner);
2extern char *secstore;
3extern char secstorebuf[65536];
4extern char *secstorefetch(char *addr, char *owner, char *passwd);
5extern char *authaddr;
6extern char *readcons(char *prompt, char *def, int secret);
7extern int exportfs(int, int);
8extern char *user;
9extern char *getkey(char*, char*);
10extern char *findkey(char**, char*);
drawterm.ico+0−0

Binary file not shown.

drawterm.rc+72−0
@@ -0,0 +1,72 @@
1//Microsoft Developer Studio generated resource script.
2//
3#include "resource.h"
4
5#define APSTUDIO_READONLY_SYMBOLS
6/////////////////////////////////////////////////////////////////////////////
7//
8// Generated from the TEXTINCLUDE 2 resource.
9//
10#include "afxres.h"
11
12/////////////////////////////////////////////////////////////////////////////
13#undef APSTUDIO_READONLY_SYMBOLS
14
15/////////////////////////////////////////////////////////////////////////////
16// English (U.S.) resources
17
18#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
19#ifdef _WIN32
20LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21#pragma code_page(1252)
22#endif //_WIN32
23
24/////////////////////////////////////////////////////////////////////////////
25//
26// Icon
27//
28
29// Icon with lowest ID value placed first to ensure application icon
30// remains consistent on all systems.
31IDI_ICON1 ICON DISCARDABLE "drawterm.ico"
32
33#ifdef APSTUDIO_INVOKED
34/////////////////////////////////////////////////////////////////////////////
35//
36// TEXTINCLUDE
37//
38
391 TEXTINCLUDE DISCARDABLE
40BEGIN
41 "resource.h\0"
42END
43
442 TEXTINCLUDE DISCARDABLE
45BEGIN
46 "#include ""afxres.h""\r\n"
47 "\0"
48END
49
503 TEXTINCLUDE DISCARDABLE
51BEGIN
52 "\r\n"
53 "\0"
54END
55
56#endif // APSTUDIO_INVOKED
57
58#endif // English (U.S.) resources
59/////////////////////////////////////////////////////////////////////////////
60
61
62
63#ifndef APSTUDIO_INVOKED
64/////////////////////////////////////////////////////////////////////////////
65//
66// Generated from the TEXTINCLUDE 3 resource.
67//
68
69
70/////////////////////////////////////////////////////////////////////////////
71#endif // not APSTUDIO_INVOKED
72
drawterm.res+0−0

Binary file not shown.

exportfs/Makefile+16−0
@@ -0,0 +1,16 @@
1LIB=libexportfs.a
2CC=gcc
3CFLAGS=-I../include -I. -I.. -c -ggdb -D_THREAD_SAFE -pthread
4O=o
5
6OFILES=\
7 exportfs.$O\
8 exportsrv.$O
9
10$(LIB): $(OFILES)
11 ar r $(LIB) $(OFILES)
12 ranlib $(LIB)
13
14%.$O: %.c
15 $(CC) $(CFLAGS) $*.c
16
exportfs/exportfs.c+503−0
@@ -0,0 +1,503 @@
1/*
2 * exportfs - Export a plan 9 name space across a network
3 */
4#include <u.h>
5#include <libc.h>
6#include <fcall.h>
7#include <libsec.h>
8#include "drawterm.h"
9#define Extern
10#include "exportfs.h"
11
12/* #define QIDPATH ((1LL<<48)-1) */
13#define QIDPATH ((((vlong)1)<<48)-1)
14vlong newqid = 0;
15
16void (*fcalls[256])(Fsrpc*);
17
18/* accounting and debugging counters */
19int filecnt;
20int freecnt;
21int qidcnt;
22int qfreecnt;
23int ncollision;
24int netfd;
25
26int
27exportfs(int fd, int msgsz)
28{
29 char buf[ERRMAX], ebuf[ERRMAX];
30 Fsrpc *r;
31 int n;
32 char *dbfile, *srv, *file;
33 ulong initial;
34
35 fcalls[Tversion] = Xversion;
36 fcalls[Tauth] = Xauth;
37 fcalls[Tflush] = Xflush;
38 fcalls[Tattach] = Xattach;
39 fcalls[Twalk] = Xwalk;
40 fcalls[Topen] = slave;
41 fcalls[Tcreate] = Xcreate;
42 fcalls[Tclunk] = Xclunk;
43 fcalls[Tread] = slave;
44 fcalls[Twrite] = slave;
45 fcalls[Tremove] = Xremove;
46 fcalls[Tstat] = Xstat;
47 fcalls[Twstat] = Xwstat;
48
49 srvfd = -1;
50 netfd = fd;
51 //dbg = 1;
52
53 strcpy(buf, "this is buf");
54 strcpy(ebuf, "this is ebuf");
55 DEBUG(DFD, "exportfs: started\n");
56
57// rfork(RFNOTEG);
58
59 messagesize = msgsz;
60 if(messagesize == 0){
61 messagesize = iounit(netfd);
62 if(messagesize == 0)
63 messagesize = 8192+IOHDRSZ;
64 }
65
66 Workq = emallocz(sizeof(Fsrpc)*Nr_workbufs);
67// for(i=0; i<Nr_workbufs; i++)
68// Workq[i].buf = emallocz(messagesize);
69 fhash = emallocz(sizeof(Fid*)*FHASHSIZE);
70
71 fmtinstall('F', fcallfmt);
72
73 initroot();
74
75 DEBUG(DFD, "exportfs: %s\n", buf);
76
77 /*
78 * Start serving file requests from the network
79 */
80 for(;;) {
81 r = getsbuf();
82 if(r == 0)
83 fatal("Out of service buffers");
84
85 DEBUG(DFD, "read9p...");
86 n = read9pmsg(netfd, r->buf, messagesize);
87 if(n <= 0)
88 fatal(nil);
89
90 if(convM2S(r->buf, n, &r->work) == 0)
91 fatal("convM2S format error");
92
93 DEBUG(DFD, "%F\n", &r->work);
94 (fcalls[r->work.type])(r);
95 }
96}
97
98void
99reply(Fcall *r, Fcall *t, char *err)
100{
101 uchar *data;
102 int m, n;
103
104 t->tag = r->tag;
105 t->fid = r->fid;
106 if(err) {
107 t->type = Rerror;
108 t->ename = err;
109 }
110 else
111 t->type = r->type + 1;
112
113 DEBUG(DFD, "\t%F\n", t);
114
115 data = malloc(messagesize); /* not mallocz; no need to clear */
116 if(data == nil)
117 fatal(Enomem);
118 n = convS2M(t, data, messagesize);
119 if((m=write(netfd, data, n))!=n){
120 fprint(2, "wrote %d got %d (%r)\n", n, m);
121 fatal("write");
122 }
123 free(data);
124}
125
126Fid *
127getfid(int nr)
128{
129 Fid *f;
130
131 for(f = fidhash(nr); f; f = f->next)
132 if(f->nr == nr)
133 return f;
134
135 return 0;
136}
137
138int
139freefid(int nr)
140{
141 Fid *f, **l;
142 char buf[128];
143
144 l = &fidhash(nr);
145 for(f = *l; f; f = f->next) {
146 if(f->nr == nr) {
147 if(f->mid) {
148 sprint(buf, "/mnt/exportfs/%d", f->mid);
149 unmount(0, buf);
150 psmap[f->mid] = 0;
151 }
152 if(f->f) {
153 freefile(f->f);
154 f->f = nil;
155 }
156 *l = f->next;
157 f->next = fidfree;
158 fidfree = f;
159 return 1;
160 }
161 l = &f->next;
162 }
163
164 return 0;
165}
166
167Fid *
168newfid(int nr)
169{
170 Fid *new, **l;
171 int i;
172
173 l = &fidhash(nr);
174 for(new = *l; new; new = new->next)
175 if(new->nr == nr)
176 return 0;
177
178 if(fidfree == 0) {
179 fidfree = emallocz(sizeof(Fid) * Fidchunk);
180
181 for(i = 0; i < Fidchunk-1; i++)
182 fidfree[i].next = &fidfree[i+1];
183
184 fidfree[Fidchunk-1].next = 0;
185 }
186
187 new = fidfree;
188 fidfree = new->next;
189
190 memset(new, 0, sizeof(Fid));
191 new->next = *l;
192 *l = new;
193 new->nr = nr;
194 new->fid = -1;
195 new->mid = 0;
196
197 return new;
198}
199
200Fsrpc *
201getsbuf(void)
202{
203 static int ap;
204 int look, rounds;
205 Fsrpc *wb;
206 int small_instead_of_fast = 1;
207
208 if(small_instead_of_fast)
209 ap = 0; /* so we always start looking at the beginning and reuse buffers */
210
211 for(rounds = 0; rounds < 10; rounds++) {
212 for(look = 0; look < Nr_workbufs; look++) {
213 if(++ap == Nr_workbufs)
214 ap = 0;
215 if(Workq[ap].busy == 0)
216 break;
217 }
218
219 if(look == Nr_workbufs){
220 sleep(10 * rounds);
221 continue;
222 }
223
224 wb = &Workq[ap];
225 wb->pid = 0;
226 wb->canint = 0;
227 wb->flushtag = NOTAG;
228 wb->busy = 1;
229 if(wb->buf == nil) /* allocate buffers dynamically to keep size down */
230 wb->buf = emallocz(messagesize);
231 return wb;
232 }
233 fatal("No more work buffers");
234 return nil;
235}
236
237void
238freefile(File *f)
239{
240 File *parent, *child;
241
242Loop:
243 f->ref--;
244 if(f->ref > 0)
245 return;
246 freecnt++;
247 if(f->ref < 0) abort();
248 DEBUG(DFD, "free %s\n", f->name);
249 /* delete from parent */
250 parent = f->parent;
251 if(parent->child == f)
252 parent->child = f->childlist;
253 else{
254 for(child=parent->child; child->childlist!=f; child=child->childlist)
255 if(child->childlist == nil)
256 fatal("bad child list");
257 child->childlist = f->childlist;
258 }
259 freeqid(f->qidt);
260 free(f->name);
261 f->name = nil;
262 free(f);
263 f = parent;
264 if(f != nil)
265 goto Loop;
266}
267
268File *
269file(File *parent, char *name)
270{
271 Dir *dir;
272 char *path;
273 File *f;
274
275 DEBUG(DFD, "\tfile: 0x%p %s name %s\n", parent, parent->name, name);
276
277 path = makepath(parent, name);
278 dir = dirstat(path);
279 free(path);
280 if(dir == nil)
281 return nil;
282
283 for(f = parent->child; f; f = f->childlist)
284 if(strcmp(name, f->name) == 0)
285 break;
286
287 if(f == nil){
288 f = emallocz(sizeof(File));
289 f->name = estrdup(name);
290
291 f->parent = parent;
292 f->childlist = parent->child;
293 parent->child = f;
294 parent->ref++;
295 f->ref = 0;
296 filecnt++;
297 }
298 f->ref++;
299 f->qid.type = dir->qid.type;
300 f->qid.vers = dir->qid.vers;
301 f->qidt = uniqueqid(dir);
302 f->qid.path = f->qidt->uniqpath;
303
304 f->inval = 0;
305
306 free(dir);
307
308 return f;
309}
310
311void
312initroot(void)
313{
314 Dir *dir;
315
316 root = emallocz(sizeof(File));
317 root->name = estrdup(".");
318
319 dir = dirstat(root->name);
320 if(dir == nil)
321 fatal("root stat");
322
323 root->ref = 1;
324 root->qid.vers = dir->qid.vers;
325 root->qidt = uniqueqid(dir);
326 root->qid.path = root->qidt->uniqpath;
327 root->qid.type = QTDIR;
328 free(dir);
329
330 psmpt = emallocz(sizeof(File));
331 psmpt->name = estrdup("/");
332
333 dir = dirstat(psmpt->name);
334 if(dir == nil)
335 return;
336
337 psmpt->ref = 1;
338 psmpt->qid.vers = dir->qid.vers;
339 psmpt->qidt = uniqueqid(dir);
340 psmpt->qid.path = psmpt->qidt->uniqpath;
341 free(dir);
342
343 psmpt = file(psmpt, "mnt");
344 if(psmpt == 0)
345 return;
346 psmpt = file(psmpt, "exportfs");
347}
348
349char*
350makepath(File *p, char *name)
351{
352 int i, n;
353 char *c, *s, *path, *seg[256];
354
355 seg[0] = name;
356 n = strlen(name)+2;
357 for(i = 1; i < 256 && p; i++, p = p->parent){
358 seg[i] = p->name;
359 n += strlen(p->name)+1;
360 }
361 path = malloc(n);
362 if(path == nil)
363 fatal("out of memory");
364 s = path;
365
366 while(i--) {
367 for(c = seg[i]; *c; c++)
368 *s++ = *c;
369 *s++ = '/';
370 }
371 while(s[-1] == '/')
372 s--;
373 *s = '\0';
374
375 return path;
376}
377
378int
379qidhash(vlong path)
380{
381 int h, n;
382
383 h = 0;
384 for(n=0; n<64; n+=Nqidbits){
385 h ^= path;
386 path >>= Nqidbits;
387 }
388 return h & (Nqidtab-1);
389}
390
391void
392freeqid(Qidtab *q)
393{
394 ulong h;
395 Qidtab *l;
396
397 q->ref--;
398 if(q->ref > 0)
399 return;
400 qfreecnt++;
401 h = qidhash(q->path);
402 if(qidtab[h] == q)
403 qidtab[h] = q->next;
404 else{
405 for(l=qidtab[h]; l->next!=q; l=l->next)
406 if(l->next == nil)
407 fatal("bad qid list");
408 l->next = q->next;
409 }
410 free(q);
411}
412
413Qidtab*
414qidlookup(Dir *d)
415{
416 ulong h;
417 Qidtab *q;
418
419 h = qidhash(d->qid.path);
420 for(q=qidtab[h]; q!=nil; q=q->next)
421 if(q->type==d->type && q->dev==d->dev && q->path==d->qid.path)
422 return q;
423 return nil;
424}
425
426int
427qidexists(vlong path)
428{
429 int h;
430 Qidtab *q;
431
432 for(h=0; h<Nqidtab; h++)
433 for(q=qidtab[h]; q!=nil; q=q->next)
434 if(q->uniqpath == path)
435 return 1;
436 return 0;
437}
438
439Qidtab*
440uniqueqid(Dir *d)
441{
442 ulong h;
443 vlong path;
444 Qidtab *q;
445
446 q = qidlookup(d);
447 if(q != nil){
448 q->ref++;
449 return q;
450 }
451 path = d->qid.path;
452 while(qidexists(path)){
453 DEBUG(DFD, "collision on %s\n", d->name);
454 /* collision: find a new one */
455 ncollision++;
456 path &= QIDPATH;
457 ++newqid;
458 if(newqid >= (1<<16)){
459 DEBUG(DFD, "collision wraparound\n");
460 newqid = 1;
461 }
462 path |= newqid<<48;
463 DEBUG(DFD, "assign qid %.16llux\n", path);
464 }
465 q = mallocz(sizeof(Qidtab), 1);
466 if(q == nil)
467 fatal("no memory for qid table");
468 qidcnt++;
469 q->ref = 1;
470 q->type = d->type;
471 q->dev = d->dev;
472 q->path = d->qid.path;
473 q->uniqpath = path;
474 h = qidhash(d->qid.path);
475 q->next = qidtab[h];
476 qidtab[h] = q;
477 return q;
478}
479
480void
481fatal(char *s, ...)
482{
483 char buf[ERRMAX];
484 va_list arg;
485 Proc *m;
486
487 if (s) {
488 va_start(arg, s);
489 vsnprint(buf, ERRMAX, s, arg);
490 va_end(arg);
491 }
492
493 /* Clear away the slave children */
494// for(m = Proclist; m; m = m->next)
495// postnote(PNPROC, m->pid, "kill");
496
497 DEBUG(DFD, "%s\n", buf);
498 if (s)
499 sysfatal(buf);
500 else
501 exits(nil);
502}
503
exportfs/exportfs.h+148−0
@@ -0,0 +1,148 @@
1/*
2 * exportfs.h - definitions for exporting file server
3 */
4
5#define DEBUG if(!dbg){}else fprint
6#define DFD 2
7#define fidhash(s) fhash[s%FHASHSIZE]
8
9#define Proc Exproc
10
11
12typedef struct Fsrpc Fsrpc;
13typedef struct Fid Fid;
14typedef struct File File;
15typedef struct Proc Proc;
16typedef struct Qidtab Qidtab;
17
18struct Fsrpc
19{
20 int busy; /* Work buffer has pending rpc to service */
21 int pid; /* Pid of slave process executing the rpc */
22 int canint; /* Interrupt gate */
23 int flushtag; /* Tag on which to reply to flush */
24 Fcall work; /* Plan 9 incoming Fcall */
25 uchar *buf; /* Data buffer */
26};
27
28struct Fid
29{
30 int fid; /* system fd for i/o */
31 File *f; /* File attached to this fid */
32 int mode;
33 int nr; /* fid number */
34 int mid; /* Mount id */
35 Fid *next; /* hash link */
36};
37
38struct File
39{
40 char *name;
41 int ref;
42 Qid qid;
43 Qidtab *qidt;
44 int inval;
45 File *parent;
46 File *child;
47 File *childlist;
48};
49
50struct Proc
51{
52 int pid;
53 int busy;
54 Proc *next;
55};
56
57struct Qidtab
58{
59 int ref;
60 int type;
61 int dev;
62 vlong path;
63 vlong uniqpath;
64 Qidtab *next;
65};
66
67enum
68{
69 MAXPROC = 50,
70 FHASHSIZE = 64,
71 Nr_workbufs = 50,
72 Fidchunk = 1000,
73 Npsmpt = 32,
74 Nqidbits = 5,
75 Nqidtab = (1<<Nqidbits),
76};
77
78#define Enomem Exenomem
79#define Ebadfix Exebadfid
80#define Enotdir Exenotdir
81#define Edupfid Exedupfid
82#define Eopen Exeopen
83#define Exmnt Exexmnt
84#define Emip Exemip
85#define Enopsmt Exenopsmt
86
87extern char Ebadfid[];
88extern char Enotdir[];
89extern char Edupfid[];
90extern char Eopen[];
91extern char Exmnt[];
92extern char Enomem[];
93extern char Emip[];
94extern char Enopsmt[];
95
96Extern Fsrpc *Workq;
97Extern int dbg;
98Extern File *root;
99Extern File *psmpt;
100Extern Fid **fhash;
101Extern Fid *fidfree;
102Extern Proc *Proclist;
103Extern char psmap[Npsmpt];
104Extern Qidtab *qidtab[Nqidtab];
105Extern ulong messagesize;
106Extern int srvfd;
107
108/* File system protocol service procedures */
109void Xattach(Fsrpc*);
110void Xauth(Fsrpc*);
111void Xclunk(Fsrpc*);
112void Xcreate(Fsrpc*);
113void Xflush(Fsrpc*);
114void Xnop(Fsrpc*);
115void Xremove(Fsrpc*);
116void Xstat(Fsrpc*);
117void Xversion(Fsrpc*);
118void Xwalk(Fsrpc*);
119void Xwstat(Fsrpc*);
120void slave(Fsrpc*);
121
122void reply(Fcall*, Fcall*, char*);
123Fid *getfid(int);
124int freefid(int);
125Fid *newfid(int);
126Fsrpc *getsbuf(void);
127void initroot(void);
128void fatal(char*, ...);
129char* makepath(File*, char*);
130File *file(File*, char*);
131void freefile(File*);
132void slaveopen(Fsrpc*);
133void slaveread(Fsrpc*);
134void slavewrite(Fsrpc*);
135void blockingslave(void*);
136void reopen(Fid *f);
137void noteproc(int, char*);
138void flushaction(void*, char*);
139void pushfcall(char*);
140Qidtab* uniqueqid(Dir*);
141void freeqid(Qidtab*);
142char* estrdup(char*);
143void* emallocz(uint);
144int readmessage(int, char*, int);
145
146#define notify
147#define noted
148#define exits
exportfs/exportsrv.c+679−0
@@ -0,0 +1,679 @@
1#include <u.h>
2#include <libc.h>
3#include <fcall.h>
4#define Extern extern
5#include "exportfs.h"
6
7char Ebadfid[] = "Bad fid";
8char Enotdir[] = "Not a directory";
9char Edupfid[] = "Fid already in use";
10char Eopen[] = "Fid already opened";
11char Exmnt[] = "Cannot .. past mount point";
12char Emip[] = "Mount in progress";
13char Enopsmt[] = "Out of pseudo mount points";
14char Enomem[] = "No memory";
15char Eversion[] = "Bad 9P2000 version";
16
17int iounit(int x)
18{
19 return 8192+IOHDRSZ;
20}
21
22void*
23emallocz(ulong n)
24{
25 void *v;
26
27 v = mallocz(n, 1);
28 if(v == nil)
29 panic("out of memory");
30 return v;
31}
32
33ulong messagesize;
34
35void
36Xversion(Fsrpc *t)
37{
38 Fcall rhdr;
39
40 if(t->work.msize > messagesize)
41 t->work.msize = messagesize;
42 messagesize = t->work.msize;
43 if(strncmp(t->work.version, "9P2000", 6) != 0){
44 reply(&t->work, &rhdr, Eversion);
45 return;
46 }
47 rhdr.version = "9P2000";
48 rhdr.msize = t->work.msize;
49 reply(&t->work, &rhdr, 0);
50 t->busy = 0;
51}
52
53void
54Xauth(Fsrpc *t)
55{
56 Fcall rhdr;
57
58 reply(&t->work, &rhdr, "exportfs: authentication not required");
59 t->busy = 0;
60}
61
62void
63Xflush(Fsrpc *t)
64{
65 Fsrpc *w, *e;
66 Fcall rhdr;
67
68 e = &Workq[Nr_workbufs];
69
70 for(w = Workq; w < e; w++) {
71 if(w->work.tag == t->work.oldtag) {
72 DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
73 if(w->busy && w->pid) {
74 w->flushtag = t->work.tag;
75 DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
76 // if(w->canint)
77 // postnote(PNPROC, w->pid, "flush");
78 t->busy = 0;
79 return;
80 }
81 }
82 }
83
84 reply(&t->work, &rhdr, 0);
85 DEBUG(DFD, "\tflush reply\n");
86 t->busy = 0;
87}
88
89void
90Xattach(Fsrpc *t)
91{
92 int i, nfd;
93 Fcall rhdr;
94 Fid *f;
95 char buf[128];
96
97 f = newfid(t->work.fid);
98 if(f == 0) {
99 reply(&t->work, &rhdr, Ebadfid);
100 t->busy = 0;
101 return;
102 }
103
104 if(srvfd >= 0){
105/*
106 if(psmpt == 0){
107 Nomount:
108 reply(&t->work, &rhdr, Enopsmt);
109 t->busy = 0;
110 freefid(t->work.fid);
111 return;
112 }
113 for(i=0; i<Npsmpt; i++)
114 if(psmap[i] == 0)
115 break;
116 if(i >= Npsmpt)
117 goto Nomount;
118 sprint(buf, "%d", i);
119 f->f = file(psmpt, buf);
120 if(f->f == nil)
121 goto Nomount;
122 sprint(buf, "/mnt/exportfs/%d", i);
123 nfd = dup(srvfd, -1);
124 if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
125 errstr(buf, sizeof buf);
126 reply(&t->work, &rhdr, buf);
127 t->busy = 0;
128 freefid(t->work.fid);
129 close(nfd);
130 return;
131 }
132 psmap[i] = 1;
133 f->mid = i;
134*/
135 }else{
136 f->f = root;
137 f->f->ref++;
138 }
139
140 rhdr.qid = f->f->qid;
141 reply(&t->work, &rhdr, 0);
142 t->busy = 0;
143}
144
145Fid*
146clonefid(Fid *f, int new)
147{
148 Fid *n;
149
150 n = newfid(new);
151 if(n == 0) {
152 n = getfid(new);
153 if(n == 0)
154 fatal("inconsistent fids");
155 if(n->fid >= 0)
156 close(n->fid);
157 freefid(new);
158 n = newfid(new);
159 if(n == 0)
160 fatal("inconsistent fids2");
161 }
162 n->f = f->f;
163 n->f->ref++;
164 return n;
165}
166
167void
168Xwalk(Fsrpc *t)
169{
170 char err[ERRMAX], *e;
171 Fcall rhdr;
172 Fid *f, *nf;
173 File *wf;
174 int i;
175
176 f = getfid(t->work.fid);
177 if(f == 0) {
178 reply(&t->work, &rhdr, Ebadfid);
179 t->busy = 0;
180 return;
181 }
182
183 nf = nil;
184 if(t->work.newfid != t->work.fid){
185 nf = clonefid(f, t->work.newfid);
186 f = nf;
187 }
188
189 rhdr.nwqid = 0;
190 e = nil;
191 for(i=0; i<t->work.nwname; i++){
192 if(i == MAXWELEM){
193 e = "Too many path elements";
194 break;
195 }
196
197 if(strcmp(t->work.wname[i], "..") == 0) {
198 if(f->f->parent == nil) {
199 e = Exmnt;
200 break;
201 }
202 wf = f->f->parent;
203 wf->ref++;
204 goto Accept;
205 }
206
207 wf = file(f->f, t->work.wname[i]);
208 if(wf == 0){
209 errstr(err, sizeof err);
210 e = err;
211 break;
212 }
213 Accept:
214 freefile(f->f);
215 rhdr.wqid[rhdr.nwqid++] = wf->qid;
216 f->f = wf;
217 continue;
218 }
219
220 if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
221 freefid(t->work.newfid);
222 if(rhdr.nwqid > 0)
223 e = nil;
224 reply(&t->work, &rhdr, e);
225 t->busy = 0;
226}
227
228void
229Xclunk(Fsrpc *t)
230{
231 Fcall rhdr;
232 Fid *f;
233
234 f = getfid(t->work.fid);
235 if(f == 0) {
236 reply(&t->work, &rhdr, Ebadfid);
237 t->busy = 0;
238 return;
239 }
240
241 if(f->fid >= 0)
242 close(f->fid);
243
244 freefid(t->work.fid);
245 reply(&t->work, &rhdr, 0);
246 t->busy = 0;
247}
248
249void
250Xstat(Fsrpc *t)
251{
252 char err[ERRMAX], *path;
253 Fcall rhdr;
254 Fid *f;
255 Dir *d;
256 int s;
257 uchar *statbuf;
258
259 f = getfid(t->work.fid);
260 if(f == 0) {
261 reply(&t->work, &rhdr, Ebadfid);
262 t->busy = 0;
263 return;
264 }
265 if(f->fid >= 0)
266 d = dirfstat(f->fid);
267 else {
268 path = makepath(f->f, "");
269 d = dirstat(path);
270 free(path);
271 }
272
273 if(d == nil) {
274 errstr(err, sizeof err);
275 reply(&t->work, &rhdr, err);
276 t->busy = 0;
277 return;
278 }
279
280 d->qid.path = f->f->qidt->uniqpath;
281 s = sizeD2M(d);
282 statbuf = emallocz(s);
283 s = convD2M(d, statbuf, s);
284 free(d);
285 rhdr.nstat = s;
286 rhdr.stat = statbuf;
287 reply(&t->work, &rhdr, 0);
288 free(statbuf);
289 t->busy = 0;
290}
291
292static int
293getiounit(int fd)
294{
295 int n;
296
297 n = iounit(fd);
298 if(n > messagesize-IOHDRSZ)
299 n = messagesize-IOHDRSZ;
300 return n;
301}
302
303void
304Xcreate(Fsrpc *t)
305{
306 char err[ERRMAX], *path;
307 Fcall rhdr;
308 Fid *f;
309 File *nf;
310
311 f = getfid(t->work.fid);
312 if(f == 0) {
313 reply(&t->work, &rhdr, Ebadfid);
314 t->busy = 0;
315 return;
316 }
317
318
319 path = makepath(f->f, t->work.name);
320 f->fid = create(path, t->work.mode, t->work.perm);
321 free(path);
322 if(f->fid < 0) {
323 errstr(err, sizeof err);
324 reply(&t->work, &rhdr, err);
325 t->busy = 0;
326 return;
327 }
328
329 nf = file(f->f, t->work.name);
330 if(nf == 0) {
331 errstr(err, sizeof err);
332 reply(&t->work, &rhdr, err);
333 t->busy = 0;
334 return;
335 }
336
337 f->mode = t->work.mode;
338 freefile(f->f);
339 f->f = nf;
340 rhdr.qid = f->f->qid;
341 rhdr.iounit = getiounit(f->fid);
342 reply(&t->work, &rhdr, 0);
343 t->busy = 0;
344}
345
346void
347Xremove(Fsrpc *t)
348{
349 char err[ERRMAX], *path;
350 Fcall rhdr;
351 Fid *f;
352
353 f = getfid(t->work.fid);
354 if(f == 0) {
355 reply(&t->work, &rhdr, Ebadfid);
356 t->busy = 0;
357 return;
358 }
359
360 path = makepath(f->f, "");
361 DEBUG(DFD, "\tremove: %s\n", path);
362 if(remove(path) < 0) {
363 free(path);
364 errstr(err, sizeof err);
365 reply(&t->work, &rhdr, err);
366 t->busy = 0;
367 return;
368 }
369 free(path);
370
371 f->f->inval = 1;
372 if(f->fid >= 0)
373 close(f->fid);
374 freefid(t->work.fid);
375
376 reply(&t->work, &rhdr, 0);
377 t->busy = 0;
378}
379
380void
381Xwstat(Fsrpc *t)
382{
383 char err[ERRMAX], *path;
384 Fcall rhdr;
385 Fid *f;
386 int s;
387 char *strings;
388 Dir d;
389
390 f = getfid(t->work.fid);
391 if(f == 0) {
392 reply(&t->work, &rhdr, Ebadfid);
393 t->busy = 0;
394 return;
395 }
396 strings = emallocz(t->work.nstat); /* ample */
397 if(convM2D(t->work.stat, t->work.nstat, &d, strings) < 0){
398 rerrstr(err, sizeof err);
399 reply(&t->work, &rhdr, err);
400 t->busy = 0;
401 free(strings);
402 return;
403 }
404
405 if(f->fid >= 0)
406 s = dirfwstat(f->fid, &d);
407 else {
408 path = makepath(f->f, "");
409 s = dirwstat(path, &d);
410 free(path);
411 }
412 if(s < 0) {
413 rerrstr(err, sizeof err);
414 reply(&t->work, &rhdr, err);
415 }
416 else {
417 /* wstat may really be rename */
418 if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
419 free(f->f->name);
420 f->f->name = estrdup(d.name);
421 }
422 reply(&t->work, &rhdr, 0);
423 }
424 free(strings);
425 t->busy = 0;
426}
427
428void
429slave(Fsrpc *f)
430{
431 Proc *p;
432 int pid;
433 static int nproc;
434
435 for(;;) {
436 for(p = Proclist; p; p = p->next) {
437 if(p->busy == 0) {
438 f->pid = p->pid;
439 p->busy = 1;
440 pid = rendezvous(p->pid, (ulong)f);
441 if(pid != p->pid)
442 fatal("rendezvous sync fail");
443 return;
444 }
445 }
446
447 if(++nproc > MAXPROC)
448 fatal("too many procs");
449
450 pid = kproc("slave", blockingslave, nil);
451 DEBUG(DFD, "slave pid %d\n", pid);
452 if(pid == -1)
453 fatal("kproc");
454
455 p = malloc(sizeof(Proc));
456 if(p == 0)
457 fatal("out of memory");
458
459 p->busy = 0;
460 p->pid = pid;
461 p->next = Proclist;
462 Proclist = p;
463
464DEBUG(DFD, "parent %d rendez\n", pid);
465 rendezvous(pid, (ulong)p);
466DEBUG(DFD, "parent %d went\n", pid);
467 }
468}
469
470void
471blockingslave(void *x)
472{
473 Fsrpc *p;
474 Fcall rhdr;
475 Proc *m;
476 int pid;
477
478 USED(x);
479
480 notify(flushaction);
481
482 pid = getpid();
483
484DEBUG(DFD, "blockingslave %d rendez\n", pid);
485 m = (Proc*)rendezvous(pid, 0);
486DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
487
488 for(;;) {
489 p = (Fsrpc*)rendezvous(pid, pid);
490 if((int)p == ~0) /* Interrupted */
491 continue;
492
493 DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
494 if(p->flushtag != NOTAG)
495 goto flushme;
496
497 switch(p->work.type) {
498 case Tread:
499 slaveread(p);
500 break;
501
502 case Twrite:
503 slavewrite(p);
504 break;
505
506 case Topen:
507 slaveopen(p);
508 break;
509
510 default:
511 reply(&p->work, &rhdr, "exportfs: slave type error");
512 }
513 if(p->flushtag != NOTAG) {
514flushme:
515 p->work.type = Tflush;
516 p->work.tag = p->flushtag;
517 reply(&p->work, &rhdr, 0);
518 }
519 p->busy = 0;
520 m->busy = 0;
521 }
522}
523
524int
525openmount(int sfd)
526{
527 werrstr("openmount not implemented");
528 return -1;
529}
530
531void
532slaveopen(Fsrpc *p)
533{
534 char err[ERRMAX], *path;
535 Fcall *work, rhdr;
536 Fid *f;
537 Dir *d;
538
539 work = &p->work;
540
541 f = getfid(work->fid);
542 if(f == 0) {
543 reply(work, &rhdr, Ebadfid);
544 return;
545 }
546 if(f->fid >= 0) {
547 close(f->fid);
548 f->fid = -1;
549 }
550
551 path = makepath(f->f, "");
552 DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
553
554 p->canint = 1;
555 if(p->flushtag != NOTAG){
556 free(path);
557 return;
558 }
559 /* There is a race here I ignore because there are no locks */
560 f->fid = open(path, work->mode);
561 free(path);
562 p->canint = 0;
563 if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
564 Error:
565 errstr(err, sizeof err);
566 reply(work, &rhdr, err);
567 return;
568 }
569 f->f->qid = d->qid;
570 free(d);
571 if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
572 f->fid = openmount(f->fid);
573 if(f->fid < 0)
574 goto Error;
575 }
576
577 DEBUG(DFD, "\topen: fd %d\n", f->fid);
578 f->mode = work->mode;
579 rhdr.iounit = getiounit(f->fid);
580 rhdr.qid = f->f->qid;
581 reply(work, &rhdr, 0);
582}
583
584void
585slaveread(Fsrpc *p)
586{
587 Fid *f;
588 int n, r;
589 Fcall *work, rhdr;
590 char *data, err[ERRMAX];
591
592 work = &p->work;
593
594 f = getfid(work->fid);
595 if(f == 0) {
596 reply(work, &rhdr, Ebadfid);
597 return;
598 }
599
600 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
601 p->canint = 1;
602 if(p->flushtag != NOTAG)
603 return;
604 data = malloc(n);
605 if(data == nil)
606 fatal(Enomem);
607
608 /* can't just call pread, since directories must update the offset */
609 r = pread(f->fid, data, n, work->offset);
610 p->canint = 0;
611 if(r < 0) {
612 free(data);
613 errstr(err, sizeof err);
614 reply(work, &rhdr, err);
615 return;
616 }
617
618 DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
619
620 rhdr.data = data;
621 rhdr.count = r;
622 reply(work, &rhdr, 0);
623 free(data);
624}
625
626void
627slavewrite(Fsrpc *p)
628{
629 char err[ERRMAX];
630 Fcall *work, rhdr;
631 Fid *f;
632 int n;
633
634 work = &p->work;
635
636 f = getfid(work->fid);
637 if(f == 0) {
638 reply(work, &rhdr, Ebadfid);
639 return;
640 }
641
642 n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
643 p->canint = 1;
644 if(p->flushtag != NOTAG)
645 return;
646 n = pwrite(f->fid, work->data, n, work->offset);
647 p->canint = 0;
648 if(n < 0) {
649 errstr(err, sizeof err);
650 reply(work, &rhdr, err);
651 return;
652 }
653
654 DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
655
656 rhdr.count = n;
657 reply(work, &rhdr, 0);
658}
659
660void
661reopen(Fid *f)
662{
663 USED(f);
664 fatal("reopen");
665}
666
667void
668flushaction(void *a, char *cause)
669{
670 USED(a);
671 if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
672 fprint(2, "exportsrv: note: %s\n", cause);
673 exits("noted");
674 }
675 if(strncmp(cause, "kill", 4) == 0)
676 noted(NDFLT);
677
678 noted(NCONT);
679}
exportfs/mkfile+11−0
@@ -0,0 +1,11 @@
1<$DSRC/mkfile-$CONF
2TARG=libexportfs.$L
3
4OFILES=\
5 exportfs.$O\
6 exportsrv.$O
7
8HFILES=\
9 exportfs.h
10
11<$DSRC/mklib-$CONF
gui-win32/alloc.c+23−0
@@ -0,0 +1,23 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5
6Memimage*
7allocmemimage(Rectangle r, ulong chan)
8{
9 return _allocmemimage(r, chan);
10}
11
12void
13freememimage(Memimage *i)
14{
15 _freememimage(i);
16}
17
18void
19memfillcolor(Memimage *i, ulong val)
20{
21 _memfillcolor(i, val);
22}
23
gui-win32/cload.c+10−0
@@ -0,0 +1,10 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5
6int
7cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
8{
9 return _cloadmemimage(i, r, data, ndata);
10}
gui-win32/draw.c+22−0
@@ -0,0 +1,22 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5
6void
7memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
8{
9 _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op));
10}
11
12ulong
13pixelbits(Memimage *m, Point p)
14{
15 return _pixelbits(m, p);
16}
17
18void
19memimageinit(void)
20{
21 _memimageinit();
22}
gui-win32/load.c+10−0
@@ -0,0 +1,10 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5
6int
7loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
8{
9 return _loadmemimage(i, r, data, ndata);
10}
gui-win32/mkfile+14−0
@@ -0,0 +1,14 @@
1<$DSRC/mkfile-$CONF
2TARG=libgui.$L
3
4OFILES=\
5 alloc.$O\
6 cload.$O\
7 draw.$O\
8 load.$O\
9 screen.$O\
10 wstrtoutf.$O
11
12HFILES=\
13
14<$DSRC/mklib-$CONF
gui-win32/screen.c+642−0
@@ -0,0 +1,642 @@
1#include <windows.h>
2// #include "winduhz.h"
3
4#undef Rectangle
5#define Rectangle _Rectangle
6
7#include <u.h>
8#include <libc.h>
9#include <dat.h>
10#include <draw.h>
11#include <memdraw.h>
12#include "error.h"
13#include "screen.h"
14#include "keyboard.h"
15#include "fns.h"
16
17Memimage *gscreen;
18Screeninfo screen;
19
20extern int mousequeue;
21static int depth;
22
23static HINSTANCE inst;
24static HWND window;
25static HPALETTE palette;
26static LOGPALETTE *logpal;
27static Lock gdilock;
28static BITMAPINFO *bmi;
29static HCURSOR hcursor;
30
31static void winproc(void *);
32static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
33static void paletteinit(void);
34static void bmiinit(void);
35static void screenload2(Rectangle r, int ldepth, uchar *p, Point pt, int step);
36
37static int readybit;
38static Rendez rend;
39
40Point ZP;
41
42static
43isready(void*a)
44{
45 return readybit;
46}
47
48void
49screeninit(void)
50{
51 int fmt;
52 int dx, dy;
53
54 memimageinit();
55 if(depth == 0)
56 depth = GetDeviceCaps(GetDC(NULL), BITSPIXEL);
57 switch(depth){
58 case 32:
59 screen.dibtype = DIB_RGB_COLORS;
60 screen.depth = 32;
61 fmt = XRGB32;
62 break;
63 case 24:
64 screen.dibtype = DIB_RGB_COLORS;
65 screen.depth = 24;
66 fmt = RGB24;
67 break;
68 case 16:
69 screen.dibtype = DIB_RGB_COLORS;
70 screen.depth = 16;
71 fmt = RGB15; /* [sic] */
72 break;
73 case 8:
74 default:
75 screen.dibtype = DIB_PAL_COLORS;
76 screen.depth = 8;
77 depth = 8;
78 fmt = CMAP8;
79 break;
80 }
81 dx = GetDeviceCaps(GetDC(NULL), HORZRES);
82 dy = GetDeviceCaps(GetDC(NULL), VERTRES);
83
84 gscreen = allocmemimage(Rect(0,0,dx,dy), fmt);
85 kproc("winscreen", winproc, 0);
86 sleep(&rend, isready, 0);
87}
88
89uchar*
90attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen, void **X)
91{
92 *r = gscreen->r;
93 *chan = gscreen->chan;
94 *depth = gscreen->depth;
95 *width = gscreen->width;
96 *softscreen = 1;
97
98 return gscreen->data->bdata;
99}
100
101void
102flushmemscreen(Rectangle r)
103{
104 screenload(r, gscreen->depth, byteaddr(gscreen, ZP), ZP,
105 gscreen->width*sizeof(ulong));
106// Sleep(100);
107}
108
109void
110screenload(Rectangle r, int depth, uchar *p, Point pt, int step)
111{
112 int dx, dy, delx;
113 HDC hdc;
114 RECT winr;
115
116 if(depth != gscreen->depth)
117 panic("screenload: bad ldepth");
118
119 /*
120 * Sometimes we do get rectangles that are off the
121 * screen to the negative axes, for example, when
122 * dragging around a window border in a Move operation.
123 */
124 if(rectclip(&r, gscreen->r) == 0)
125 return;
126
127 if(step&3 != 0 || ((pt.x*depth)%32) != 0 || (ulong)p&3 != 0)
128 panic("screenload: bad params %d %d %ux", step, pt.x, p);
129 dx = r.max.x - r.min.x;
130 dy = r.max.y - r.min.y;
131
132 if(dx <= 0 || dy <= 0)
133 return;
134
135 if(depth == 24)
136 delx = r.min.x % 4;
137 else
138 delx = r.min.x & (31/depth);
139
140 p += (r.min.y-pt.y)*step;
141 p += ((r.min.x-delx-pt.x)*depth)>>3;
142
143 if(GetWindowRect(window, &winr)==0)
144 return;
145 if(rectclip(&r, Rect(0, 0, winr.right-winr.left, winr.bottom-winr.top))==0)
146 return;
147
148 lock(&gdilock);
149
150 hdc = GetDC(window);
151 SelectPalette(hdc, palette, 0);
152 RealizePalette(hdc);
153
154//FillRect(hdc,(void*)&r, GetStockObject(BLACK_BRUSH));
155//GdiFlush();
156//Sleep(100);
157
158 bmi->bmiHeader.biWidth = (step*8)/depth;
159 bmi->bmiHeader.biHeight = -dy; /* - => origin upper left */
160
161 StretchDIBits(hdc, r.min.x, r.min.y, dx, dy,
162 delx, 0, dx, dy, p, bmi, screen.dibtype, SRCCOPY);
163
164 ReleaseDC(window, hdc);
165
166 GdiFlush();
167
168 unlock(&gdilock);
169}
170
171static void
172winproc(void *a)
173{
174 WNDCLASS wc;
175 MSG msg;
176
177 inst = GetModuleHandle(NULL);
178
179 paletteinit();
180 bmiinit();
181 terminit();
182
183 wc.style = 0;
184 wc.lpfnWndProc = WindowProc;
185 wc.cbClsExtra = 0;
186 wc.cbWndExtra = 0;
187 wc.hInstance = inst;
188 wc.hIcon = LoadIcon(inst, NULL);
189 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
190 wc.hbrBackground = GetStockObject(WHITE_BRUSH);
191 wc.lpszMenuName = 0;
192 wc.lpszClassName = "9pmgraphics";
193 RegisterClass(&wc);
194
195 window = CreateWindowEx(
196 0, /* extended style */
197 "9pmgraphics", /* class */
198 "drawterm screen", /* caption */
199 WS_OVERLAPPEDWINDOW, /* style */
200 CW_USEDEFAULT, /* init. x pos */
201 CW_USEDEFAULT, /* init. y pos */
202 CW_USEDEFAULT, /* init. x size */
203 CW_USEDEFAULT, /* init. y size */
204 NULL, /* parent window (actually owner window for overlapped)*/
205 NULL, /* menu handle */
206 inst, /* program handle */
207 NULL /* create parms */
208 );
209
210 if(window == nil)
211 panic("can't make window\n");
212
213 ShowWindow(window, SW_SHOWDEFAULT);
214 UpdateWindow(window);
215
216 readybit = 1;
217 wakeup(&rend);
218
219 screen.reshaped = 0;
220
221 while(GetMessage(&msg, NULL, 0, 0)) {
222 TranslateMessage(&msg);
223 DispatchMessage(&msg);
224 }
225// MessageBox(0, "winproc", "exits", MB_OK);
226 ExitProcess(0);
227}
228
229int
230col(int v, int n)
231{
232 int i, c;
233
234 c = 0;
235 for(i = 0; i < 8; i += n)
236 c |= v << (16-(n+i));
237 return c >> 8;
238}
239
240
241void
242paletteinit(void)
243{
244 PALETTEENTRY *pal;
245 int r, g, b, cr, cg, cb, v;
246 int num, den;
247 int i, j;
248
249 logpal = mallocz(sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY), 1);
250 if(logpal == nil)
251 panic("out of memory");
252 logpal->palVersion = 0x300;
253 logpal->palNumEntries = 256;
254 pal = logpal->palPalEntry;
255
256 for(r=0,i=0; r<4; r++) {
257 for(v=0; v<4; v++,i+=16){
258 for(g=0,j=v-r; g<4; g++) {
259 for(b=0; b<4; b++,j++){
260 den=r;
261 if(g>den)
262 den=g;
263 if(b>den)
264 den=b;
265 /* divide check -- pick grey shades */
266 if(den==0)
267 cr=cg=cb=v*17;
268 else{
269 num=17*(4*den+v);
270 cr=r*num/den;
271 cg=g*num/den;
272 cb=b*num/den;
273 }
274 pal[i+(j&15)].peRed = cr;
275 pal[i+(j&15)].peGreen = cg;
276 pal[i+(j&15)].peBlue = cb;
277 pal[i+(j&15)].peFlags = 0;
278 }
279 }
280 }
281 }
282 palette = CreatePalette(logpal);
283}
284
285
286void
287getcolor(ulong i, ulong *r, ulong *g, ulong *b)
288{
289 PALETTEENTRY *pal;
290
291 pal = logpal->palPalEntry;
292 *r = pal[i].peRed;
293 *g = pal[i].peGreen;
294 *b = pal[i].peBlue;
295}
296
297void
298bmiinit(void)
299{
300 ushort *p;
301 int i;
302
303 bmi = mallocz(sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), 1);
304 if(bmi == 0)
305 panic("out of memory");
306 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
307 bmi->bmiHeader.biWidth = 0;
308 bmi->bmiHeader.biHeight = 0; /* - => origin upper left */
309 bmi->bmiHeader.biPlanes = 1;
310 bmi->bmiHeader.biBitCount = depth;
311 bmi->bmiHeader.biCompression = BI_RGB;
312 bmi->bmiHeader.biSizeImage = 0;
313 bmi->bmiHeader.biXPelsPerMeter = 0;
314 bmi->bmiHeader.biYPelsPerMeter = 0;
315 bmi->bmiHeader.biClrUsed = 0;
316 bmi->bmiHeader.biClrImportant = 0; /* number of important colors: 0 means all */
317
318 p = (ushort*)bmi->bmiColors;
319 for(i = 0; i < 256; i++)
320 p[i] = i;
321}
322
323LRESULT CALLBACK
324WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
325{
326 PAINTSTRUCT paint;
327 HDC hdc;
328 LONG x, y, b;
329 int i;
330 Rectangle r;
331
332 switch(msg) {
333 case WM_CREATE:
334 break;
335 case WM_SETCURSOR:
336 /* User set */
337 if(hcursor != NULL) {
338 SetCursor(hcursor);
339 return 1;
340 }
341 return DefWindowProc(hwnd, msg, wparam, lparam);
342 case WM_MOUSEMOVE:
343 case WM_LBUTTONUP:
344 case WM_MBUTTONUP:
345 case WM_RBUTTONUP:
346 case WM_LBUTTONDOWN:
347 case WM_MBUTTONDOWN:
348 case WM_RBUTTONDOWN:
349 x = LOWORD(lparam);
350 y = HIWORD(lparam);
351 b = 0;
352 if(wparam & MK_LBUTTON)
353 b = 1;
354 if(wparam & MK_MBUTTON)
355 b |= 2;
356 if(wparam & MK_RBUTTON) {
357 if(wparam & MK_SHIFT)
358 b |= 2;
359 else
360 b |= 4;
361 }
362 lock(&mouse.lk);
363 i = mouse.wi;
364 if(mousequeue) {
365 if(i == mouse.ri || mouse.lastb != b || mouse.trans) {
366 mouse.wi = (i+1)%Mousequeue;
367 if(mouse.wi == mouse.ri)
368 mouse.ri = (mouse.ri+1)%Mousequeue;
369 mouse.trans = mouse.lastb != b;
370 } else {
371 i = (i-1+Mousequeue)%Mousequeue;
372 }
373 } else {
374 mouse.wi = (i+1)%Mousequeue;
375 mouse.ri = i;
376 }
377 mouse.queue[i].xy.x = x;
378 mouse.queue[i].xy.y = y;
379 mouse.queue[i].buttons = b;
380 mouse.queue[i].msec = ticks();
381 mouse.lastb = b;
382 unlock(&mouse.lk);
383 wakeup(&mouse.r);
384 break;
385
386 case WM_CHAR:
387 /* repeat count is lparam & 0xf */
388 switch(wparam){
389 case '\n':
390 wparam = '\r';
391 break;
392 case '\r':
393 wparam = '\n';
394 break;
395 }
396 kbdputc(kbdq, wparam);
397 break;
398
399 case WM_SYSKEYUP:
400 break;
401 case WM_SYSKEYDOWN:
402 case WM_KEYDOWN:
403 switch(wparam) {
404 case VK_MENU:
405 kbdputc(kbdq, Kalt);
406 break;
407 case VK_INSERT:
408 kbdputc(kbdq, Kins);
409 break;
410 case VK_DELETE:
411// kbdputc(kbdq, Kdel);
412 kbdputc(kbdq, 0x7f); // should have Kdel in keyboard.h
413 break;
414 case VK_UP:
415 kbdputc(kbdq, Kup);
416 break;
417 case VK_DOWN:
418 kbdputc(kbdq, Kdown);
419 break;
420 case VK_LEFT:
421 kbdputc(kbdq, Kleft);
422 break;
423 case VK_RIGHT:
424 kbdputc(kbdq, Kright);
425 break;
426 }
427 break;
428
429 case WM_CLOSE:
430 DestroyWindow(hwnd);
431 break;
432
433 case WM_DESTROY:
434 PostQuitMessage(0);
435 break;
436
437 case WM_PALETTECHANGED:
438 if((HWND)wparam == hwnd)
439 break;
440 /* fall through */
441 case WM_QUERYNEWPALETTE:
442 hdc = GetDC(hwnd);
443 SelectPalette(hdc, palette, 0);
444 if(RealizePalette(hdc) != 0)
445 InvalidateRect(hwnd, nil, 0);
446 ReleaseDC(hwnd, hdc);
447 break;
448
449 case WM_PAINT:
450 hdc = BeginPaint(hwnd, &paint);
451 r.min.x = paint.rcPaint.left;
452 r.min.y = paint.rcPaint.top;
453 r.max.x = paint.rcPaint.right;
454 r.max.y = paint.rcPaint.bottom;
455 flushmemscreen(r);
456 EndPaint(hwnd, &paint);
457 break;
458 case WM_COMMAND:
459 case WM_SETFOCUS:
460 case WM_DEVMODECHANGE:
461 case WM_WININICHANGE:
462 case WM_INITMENU:
463 default:
464 return DefWindowProc(hwnd, msg, wparam, lparam);
465 }
466 return 0;
467}
468
469void
470mouseset(Point xy)
471{
472 POINT pt;
473
474 pt.x = xy.x;
475 pt.y = xy.y;
476 MapWindowPoints(window, 0, &pt, 1);
477 SetCursorPos(pt.x, pt.y);
478}
479
480void
481setcursor(void)
482{
483 HCURSOR nh;
484 int x, y, h, w;
485 uchar *sp, *cp;
486 uchar *and, *xor;
487
488 h = GetSystemMetrics(SM_CYCURSOR);
489 w = (GetSystemMetrics(SM_CXCURSOR)+7)/8;
490
491 and = mallocz(h*w, 1);
492 memset(and, 0xff, h*w);
493 xor = mallocz(h*w, 1);
494
495 lock(&cursor.lk);
496 for(y=0,sp=cursor.set,cp=cursor.clr; y<16; y++) {
497 for(x=0; x<2; x++) {
498 and[y*w+x] = ~(*sp|*cp);
499 xor[y*w+x] = ~*sp & *cp;
500 cp++;
501 sp++;
502 }
503 }
504 nh = CreateCursor(inst, -cursor.offset.x, -cursor.offset.y,
505 GetSystemMetrics(SM_CXCURSOR), h,
506 and, xor);
507 if(nh != NULL) {
508 SetCursor(nh);
509 if(hcursor != NULL)
510 DestroyCursor(hcursor);
511 hcursor = nh;
512 }
513 unlock(&cursor.lk);
514
515 free(and);
516 free(xor);
517
518 PostMessage(window, WM_SETCURSOR, (int)window, 0);
519}
520
521void
522cursorarrow(void)
523{
524 if(hcursor != 0) {
525 DestroyCursor(hcursor);
526 hcursor = 0;
527 }
528 SetCursor(LoadCursor(0, IDC_ARROW));
529 PostMessage(window, WM_SETCURSOR, (int)window, 0);
530}
531
532
533void
534setcolor(ulong index, ulong red, ulong green, ulong blue)
535{
536}
537
538
539uchar*
540clipreadunicode(HANDLE h)
541{
542 Rune *p;
543 int n;
544 uchar *q;
545
546 p = GlobalLock(h);
547 n = wstrutflen(p)+1;
548 q = malloc(n);
549 wstrtoutf(q, p, n);
550 GlobalUnlock(h);
551
552 return q;
553}
554
555uchar *
556clipreadutf(HANDLE h)
557{
558 uchar *p;
559
560 p = GlobalLock(h);
561 p = strdup(p);
562 GlobalUnlock(h);
563
564 return p;
565}
566
567
568uchar*
569clipread()
570{
571 HANDLE h;
572 uchar *p;
573
574 if(!OpenClipboard(window)) {
575 oserror();
576 return strdup("");
577 }
578
579 if(h = GetClipboardData(CF_UNICODETEXT))
580 p = clipreadunicode(h);
581 else if(h = GetClipboardData(CF_TEXT))
582 p = clipreadutf(h);
583 else {
584 oserror();
585 p = strdup("");
586 }
587
588 CloseClipboard();
589 return p;
590}
591
592int
593clipwrite(char *buf)
594{
595 HANDLE h;
596 char *p, *e;
597 Rune *rp;
598 int n = strlen(buf);
599
600 if(!OpenClipboard(window)) {
601 oserror();
602 return -1;
603 }
604
605 if(!EmptyClipboard()) {
606 oserror();
607 CloseClipboard();
608 return -1;
609 }
610
611 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, (n+1)*sizeof(Rune));
612 if(h == NULL)
613 panic("out of memory");
614 rp = GlobalLock(h);
615 p = buf;
616 e = p+n;
617 while(p<e)
618 p += chartorune(rp++, p);
619 *rp = 0;
620 GlobalUnlock(h);
621
622 SetClipboardData(CF_UNICODETEXT, h);
623
624 h = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, n+1);
625 if(h == NULL)
626 panic("out of memory");
627 p = GlobalLock(h);
628 memcpy(p, buf, n);
629 p[n] = 0;
630 GlobalUnlock(h);
631
632 SetClipboardData(CF_TEXT, h);
633
634 CloseClipboard();
635 return n;
636}
637
638int
639atlocalconsole(void)
640{
641 return 1;
642}
gui-win32/wstrtoutf.c+35−0
@@ -0,0 +1,35 @@
1#include <u.h>
2#include <libc.h>
3
4int
5wstrutflen(Rune *s)
6{
7 int n;
8
9 for(n=0; *s; n+=runelen(*s),s++)
10 ;
11 return n;
12}
13
14int
15wstrtoutf(char *s, Rune *t, int n)
16{
17 int i;
18 char *s0;
19
20 s0 = s;
21 if(n <= 0)
22 return wstrutflen(t)+1;
23 while(*t) {
24 if(n < UTFmax+1 && n < runelen(*t)+1) {
25 *s = 0;
26 return i+wstrutflen(t)+1;
27 }
28 i = runetochar(s, t);
29 s += i;
30 n -= i;
31 t++;
32 }
33 *s = 0;
34 return s-s0;
35}
gui-x11/Makefile+20−0
@@ -0,0 +1,20 @@
1LIB=libx11.a
2CC=gcc
3CFLAGS=-I../include -I. -I/usr/X11R6/include -I../kern -c -ggdb -D_THREAD_SAFE -pthread
4O=o
5
6OFILES=\
7 alloc.$O\
8 cload.$O\
9 draw.$O\
10 load.$O\
11 screen.$O\
12 keysym2ucs-x11.$O
13
14$(LIB): $(OFILES)
15 ar r $(LIB) $(OFILES)
16 ranlib $(LIB)
17
18%.$O: %.c
19 $(CC) $(CFLAGS) $*.c
20
gui-x11/alloc.c+209−0
@@ -0,0 +1,209 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5#include "xmem.h"
6
7/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
8#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
9
10Memimage*
11xallocmemimage(Rectangle r, ulong chan, int pmid)
12{
13 Memimage *m;
14 Xmem *xm;
15 XImage *xi;
16 int offset;
17 int d;
18
19 m = _allocmemimage(r, chan);
20 if(chan != GREY1 && chan != xscreenchan)
21 return m;
22
23 d = m->depth;
24 xm = mallocz(sizeof(Xmem), 1);
25 if(pmid != PMundef)
26 xm->pmid = pmid;
27 else
28 xm->pmid = XCreatePixmap(xdisplay, xscreenid, Dx(r), Dy(r), (d==32) ? 24 : d);
29
30 if(m->depth == 24)
31 offset = r.min.x&(4-1);
32 else
33 offset = r.min.x&(31/m->depth);
34 r.min.x -= offset;
35
36 assert(wordsperline(r, m->depth) <= m->width);
37
38 xi = XCreateImage(xdisplay, xvis, m->depth==32?24:m->depth, ZPixmap, 0,
39 (char*)m->data->bdata, Dx(r), Dy(r), 32, m->width*sizeof(ulong));
40
41 if(xi == nil){
42 _freememimage(m);
43 return nil;
44 }
45
46 xm->xi = xi;
47 xm->pc = getcallerpc(&r);
48 xm->r = r;
49
50 /*
51 * Set the parameters of the XImage so its memory looks exactly like a
52 * Memimage, so we can call _memimagedraw on the same data. All frame
53 * buffers we've seen, and Plan 9's graphics code, require big-endian
54 * bits within bytes, but little endian byte order within pixels.
55 */
56 xi->bitmap_unit = m->depth < 8 || m->depth == 24 ? 8 : m->depth;
57 xi->byte_order = LSBFirst;
58 xi->bitmap_bit_order = MSBFirst;
59 xi->bitmap_pad = 32;
60 xm->r = Rect(0,0,0,0);
61 XInitImage(xi);
62 XFlush(xdisplay);
63
64 m->X = xm;
65 return m;
66}
67
68Memimage*
69allocmemimage(Rectangle r, ulong chan)
70{
71 return xallocmemimage(r, chan, PMundef);
72}
73
74void
75freememimage(Memimage *m)
76{
77 Xmem *xm;
78
79 if(m == nil)
80 return;
81
82 if(m->data->ref == 1){
83 if((xm = m->X) != nil){
84 if(xm->xi){
85 xm->xi->data = nil;
86 XFree(xm->xi);
87 }
88 XFreePixmap(xdisplay, xm->pmid);
89 free(xm);
90 m->X = nil;
91 }
92 }
93 _freememimage(m);
94}
95
96void
97memfillcolor(Memimage *m, ulong val)
98{
99 _memfillcolor(m, val);
100 if(m->X){
101 if((val & 0xFF) == 0xFF)
102 xfillcolor(m, m->r, _rgbatoimg(m, val));
103 else
104 putXdata(m, m->r);
105 }
106}
107
108static void
109addrect(Rectangle *rp, Rectangle r)
110{
111 if(rp->min.x >= rp->max.x)
112 *rp = r;
113 else
114 combinerect(rp, r);
115}
116
117XImage*
118getXdata(Memimage *m, Rectangle r)
119{
120 uchar *p;
121 int x, y;
122 Xmem *xm;
123 Point xdelta, delta;
124 Point tp;
125
126 xm = m->X;
127 if(xm == nil)
128 return;
129
130 assert(xm != nil && xm->xi != nil);
131
132 if(xm->dirty == 0)
133 return xm->xi;
134
135 r = xm->dirtyr;
136 if(Dx(r)==0 || Dy(r)==0)
137 return xm->xi;
138
139 delta = subpt(r.min, m->r.min);
140 tp = xm->r.min; /* avoid unaligned access on digital unix */
141 xdelta = subpt(r.min, tp);
142
143 XGetSubImage(xdisplay, xm->pmid, delta.x, delta.y, Dx(r), Dy(r),
144 AllPlanes, ZPixmap, xm->xi, xdelta.x, xdelta.y);
145
146 if(xtblbit && m->chan == CMAP8)
147 for(y=r.min.y; y<r.max.y; y++)
148 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
149 *p = x11toplan9[*p];
150
151 xm->dirty = 0;
152 xm->dirtyr = Rect(0,0,0,0);
153 return xm->xi;
154}
155
156void
157putXdata(Memimage *m, Rectangle r)
158{
159 Xmem *xm;
160 XImage *xi;
161 GC g;
162 int offset;
163 Point xdelta, delta;
164 Point tp;
165 int x, y;
166 uchar *p;
167
168 xm = m->X;
169 if(xm == nil)
170 return;
171
172 assert(xm != nil);
173 assert(xm->xi != nil);
174
175 xi = xm->xi;
176
177 g = (m->chan == GREY1) ? xgccopy0 : xgccopy;
178 if(m->depth == 24)
179 offset = r.min.x % 4;
180 else
181 offset = m->r.min.x & (31/m->depth);
182
183 delta = subpt(r.min, m->r.min);
184 tp = xm->r.min; /* avoid unaligned access on digital unix */
185 xdelta = subpt(r.min, tp);
186
187 if(xtblbit && m->chan == CMAP8)
188 for(y=r.min.y; y<r.max.y; y++)
189 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
190 *p = plan9tox11[*p];
191
192 XPutImage(xdisplay, xm->pmid, g, xi, xdelta.x, xdelta.y, delta.x, delta.y, Dx(r), Dy(r));
193
194 if(xtblbit && m->chan == CMAP8)
195 for(y=r.min.y; y<r.max.y; y++)
196 for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
197 *p = x11toplan9[*p];
198}
199
200void
201dirtyXdata(Memimage *m, Rectangle r)
202{
203 Xmem *xm;
204
205 if((xm = m->X) != nil){
206 xm->dirty = 1;
207 addrect(&xm->dirtyr, r);
208 }
209}
gui-x11/cload.c+16−0
@@ -0,0 +1,16 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5#include "xmem.h"
6
7int
8cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
9{
10 int n;
11
12 n = _cloadmemimage(i, r, data, ndata);
13 if(n > 0 && i->X)
14 putXdata(i, r);
15 return n;
16}
gui-x11/draw.c+189−0
@@ -0,0 +1,189 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5#include "xmem.h"
6
7void xfillcolor(Memimage*, Rectangle, ulong);
8static int xdraw(Memdrawparam*);
9
10int xgcfillcolor = 0;
11int xgcfillcolor0 = 0;
12int xgczeropm = 0;
13int xgczeropm0 = 0;
14int xgcsimplecolor = 0;
15int xgcsimplecolor0 = 0;
16int xgcsimplepm = 0;
17int xgcsimplepm0 = 0;
18int xgcreplsrctile = 0;
19int xgcreplsrctile0 = 0;
20
21void
22memimageinit(void)
23{
24 static int didinit = 0;
25
26 if(didinit)
27 return;
28
29 didinit = 1;
30 _memimageinit();
31
32 xfillcolor(memblack, memblack->r, 0);
33 xfillcolor(memwhite, memwhite->r, 1);
34}
35
36void
37memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
38{
39 int didx;
40 Rectangle dr, mr, sr;
41 Memdrawparam *par;
42
43 if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
44 return;
45 _memimagedraw(par);
46 if(!xdraw(par))
47 putXdata(dst, par->r);
48}
49
50void
51xfillcolor(Memimage *m, Rectangle r, ulong v)
52{
53 GC gc;
54 Xmem *dxm;
55
56 dxm = m->X;
57 assert(dxm != nil);
58 r = rectsubpt(r, m->r.min);
59
60 if(m->chan == GREY1){
61 gc = xgcfill0;
62 if(xgcfillcolor0 != v){
63 XSetForeground(xdisplay, gc, v);
64 xgcfillcolor0 = v;
65 }
66 }else{
67 if(m->chan == CMAP8 && xtblbit)
68 v = plan9tox11[v];
69
70 gc = xgcfill;
71 if(xgcfillcolor != v){
72 XSetForeground(xdisplay, gc, v);
73 xgcfillcolor = v;
74 }
75 }
76 XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, Dx(r), Dy(r));
77}
78
79static int
80xdraw(Memdrawparam *par)
81{
82 int dy, dx;
83 unsigned m;
84 Memimage *src, *dst, *mask;
85 Xmem *dxm, *sxm, *mxm;
86 GC gc;
87 Rectangle r, sr, mr;
88 ulong sdval;
89
90 dx = Dx(par->r);
91 dy = Dy(par->r);
92 src = par->src;
93 dst = par->dst;
94 mask = par->mask;
95 r = par->r;
96 sr = par->sr;
97 mr = par->mr;
98 sdval = par->sdval;
99
100return 0;
101 if((dxm = dst->X) == nil)
102 return 0;
103
104 /*
105 * If we have an opaque mask and source is one opaque pixel we can convert to the
106 * destination format and just XFillRectangle.
107 */
108 m = Simplesrc|Simplemask|Fullmask;
109 if((par->state&m)==m){
110 xfillcolor(dst, r, sdval);
111 dirtyXdata(dst, par->r);
112 return 1;
113 }
114
115 /*
116 * If no source alpha, an opaque mask, we can just copy the
117 * source onto the destination. If the channels are the same and
118 * the source is not replicated, XCopyArea suffices.
119 */
120 m = Simplemask|Fullmask;
121 if((par->state&(m|Replsrc))==m && src->chan == dst->chan && src->X){
122 sxm = src->X;
123 r = rectsubpt(r, dst->r.min);
124 sr = rectsubpt(sr, src->r.min);
125 if(dst->chan == GREY1)
126 gc = xgccopy0;
127 else
128 gc = xgccopy;
129 XCopyArea(xdisplay, sxm->pmid, dxm->pmid, gc,
130 sr.min.x, sr.min.y, dx, dy, r.min.x, r.min.y);
131 dirtyXdata(dst, par->r);
132 return 1;
133 }
134
135 /*
136 * If no source alpha, a 1-bit mask, and a simple source
137 * we can just copy through the mask onto the destination.
138 */
139 if(dst->X && mask->X && !(mask->flags&Frepl)
140 && mask->chan == GREY1 && (par->state&Simplesrc)){
141 Point p;
142
143 mxm = mask->X;
144 r = rectsubpt(r, dst->r.min);
145 mr = rectsubpt(mr, mask->r.min);
146 p = subpt(r.min, mr.min);
147 if(dst->chan == GREY1){
148 gc = xgcsimplesrc0;
149 if(xgcsimplecolor0 != sdval){
150 XSetForeground(xdisplay, gc, sdval);
151 xgcsimplecolor0 = sdval;
152 }
153 if(xgcsimplepm0 != mxm->pmid){
154 XSetStipple(xdisplay, gc, mxm->pmid);
155 xgcsimplepm0 = mxm->pmid;
156 }
157 }else{
158 /* somehow this doesn't work on rob's mac
159 gc = xgcsimplesrc;
160 if(dst->chan == CMAP8 && xtblbit)
161 sdval = plan9tox11[sdval];
162
163 if(xgcsimplecolor != sdval){
164 XSetForeground(xdisplay, gc, sdval);
165 xgcsimplecolor = sdval;
166 }
167 if(xgcsimplepm != mxm->pmid){
168 XSetStipple(xdisplay, gc, mxm->pmid);
169 xgcsimplepm = mxm->pmid;
170 }
171 */
172 return 0;
173 }
174 XSetTSOrigin(xdisplay, gc, p.x, p.y);
175 XFillRectangle(xdisplay, dxm->pmid, gc, r.min.x, r.min.y, dx, dy);
176 dirtyXdata(dst, par->r);
177 return 1;
178 }
179 return 0;
180}
181
182ulong
183pixelbits(Memimage *m, Point p)
184{
185 Xmem *xm;
186 if(m->X)
187 getXdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
188 return _pixelbits(m, p);
189}
gui-x11/keysym2ucs-x11.c+857−0
@@ -0,0 +1,857 @@
1/* $XFree86: xc/programs/xterm/keysym2ucs.c,v 1.5 2001/06/18 19:09:26 dickey Exp $
2 * This module converts keysym values into the corresponding ISO 10646
3 * (UCS, Unicode) values.
4 *
5 * The array keysymtab[] contains pairs of X11 keysym values for graphical
6 * characters and the corresponding Unicode value. The function
7 * keysym2ucs() maps a keysym onto a Unicode value using a binary search,
8 * therefore keysymtab[] must remain SORTED by keysym value.
9 *
10 * The keysym -> UTF-8 conversion will hopefully one day be provided
11 * by Xlib via XmbLookupString() and should ideally not have to be
12 * done in X applications. But we are not there yet.
13 *
14 * We allow to represent any UCS character in the range U-00000000 to
15 * U-00FFFFFF by a keysym value in the range 0x01000000 to 0x01ffffff.
16 * This admittedly does not cover the entire 31-bit space of UCS, but
17 * it does cover all of the characters up to U-10FFFF, which can be
18 * represented by UTF-16, and more, and it is very unlikely that higher
19 * UCS codes will ever be assigned by ISO. So to get Unicode character
20 * U+ABCD you can directly use keysym 0x0100abcd.
21 *
22 * NOTE: The comments in the table below contain the actual character
23 * encoded in UTF-8, so for viewing and editing best use an editor in
24 * UTF-8 mode.
25 *
26 * Author: Markus G. Kuhn <mkuhn@acm.org>, University of Cambridge, April 2001
27 *
28 * Special thanks to Richard Verhoeven <river@win.tue.nl> for preparing
29 * an initial draft of the mapping table.
30 *
31 * This software is in the public domain. Share and enjoy!
32 *
33 * AUTOMATICALLY GENERATED FILE, DO NOT EDIT !!! (unicode/convmap.pl)
34 */
35
36#ifndef KEYSYM2UCS_INCLUDED
37
38#include "keysym2ucs.h"
39#define VISIBLE /* */
40
41#else
42
43#define VISIBLE static
44
45#endif
46
47static struct codepair {
48 unsigned short keysym;
49 unsigned short ucs;
50} keysymtab[] = {
51 { 0x01a1, 0x0104 }, /* Aogonek Ą LATIN CAPITAL LETTER A WITH OGONEK */
52 { 0x01a2, 0x02d8 }, /* breve ˘ BREVE */
53 { 0x01a3, 0x0141 }, /* Lstroke Ł LATIN CAPITAL LETTER L WITH STROKE */
54 { 0x01a5, 0x013d }, /* Lcaron Ľ LATIN CAPITAL LETTER L WITH CARON */
55 { 0x01a6, 0x015a }, /* Sacute Ś LATIN CAPITAL LETTER S WITH ACUTE */
56 { 0x01a9, 0x0160 }, /* Scaron Š LATIN CAPITAL LETTER S WITH CARON */
57 { 0x01aa, 0x015e }, /* Scedilla Ş LATIN CAPITAL LETTER S WITH CEDILLA */
58 { 0x01ab, 0x0164 }, /* Tcaron Ť LATIN CAPITAL LETTER T WITH CARON */
59 { 0x01ac, 0x0179 }, /* Zacute Ź LATIN CAPITAL LETTER Z WITH ACUTE */
60 { 0x01ae, 0x017d }, /* Zcaron Ž LATIN CAPITAL LETTER Z WITH CARON */
61 { 0x01af, 0x017b }, /* Zabovedot Ż LATIN CAPITAL LETTER Z WITH DOT ABOVE */
62 { 0x01b1, 0x0105 }, /* aogonek ą LATIN SMALL LETTER A WITH OGONEK */
63 { 0x01b2, 0x02db }, /* ogonek ˛ OGONEK */
64 { 0x01b3, 0x0142 }, /* lstroke ł LATIN SMALL LETTER L WITH STROKE */
65 { 0x01b5, 0x013e }, /* lcaron ľ LATIN SMALL LETTER L WITH CARON */
66 { 0x01b6, 0x015b }, /* sacute ś LATIN SMALL LETTER S WITH ACUTE */
67 { 0x01b7, 0x02c7 }, /* caron ˇ CARON */
68 { 0x01b9, 0x0161 }, /* scaron š LATIN SMALL LETTER S WITH CARON */
69 { 0x01ba, 0x015f }, /* scedilla ş LATIN SMALL LETTER S WITH CEDILLA */
70 { 0x01bb, 0x0165 }, /* tcaron ť LATIN SMALL LETTER T WITH CARON */
71 { 0x01bc, 0x017a }, /* zacute ź LATIN SMALL LETTER Z WITH ACUTE */
72 { 0x01bd, 0x02dd }, /* doubleacute ˝ DOUBLE ACUTE ACCENT */
73 { 0x01be, 0x017e }, /* zcaron ž LATIN SMALL LETTER Z WITH CARON */
74 { 0x01bf, 0x017c }, /* zabovedot ż LATIN SMALL LETTER Z WITH DOT ABOVE */
75 { 0x01c0, 0x0154 }, /* Racute Ŕ LATIN CAPITAL LETTER R WITH ACUTE */
76 { 0x01c3, 0x0102 }, /* Abreve Ă LATIN CAPITAL LETTER A WITH BREVE */
77 { 0x01c5, 0x0139 }, /* Lacute Ĺ LATIN CAPITAL LETTER L WITH ACUTE */
78 { 0x01c6, 0x0106 }, /* Cacute Ć LATIN CAPITAL LETTER C WITH ACUTE */
79 { 0x01c8, 0x010c }, /* Ccaron Č LATIN CAPITAL LETTER C WITH CARON */
80 { 0x01ca, 0x0118 }, /* Eogonek Ę LATIN CAPITAL LETTER E WITH OGONEK */
81 { 0x01cc, 0x011a }, /* Ecaron Ě LATIN CAPITAL LETTER E WITH CARON */
82 { 0x01cf, 0x010e }, /* Dcaron Ď LATIN CAPITAL LETTER D WITH CARON */
83 { 0x01d0, 0x0110 }, /* Dstroke Đ LATIN CAPITAL LETTER D WITH STROKE */
84 { 0x01d1, 0x0143 }, /* Nacute Ń LATIN CAPITAL LETTER N WITH ACUTE */
85 { 0x01d2, 0x0147 }, /* Ncaron Ň LATIN CAPITAL LETTER N WITH CARON */
86 { 0x01d5, 0x0150 }, /* Odoubleacute Ő LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */
87 { 0x01d8, 0x0158 }, /* Rcaron Ř LATIN CAPITAL LETTER R WITH CARON */
88 { 0x01d9, 0x016e }, /* Uring Ů LATIN CAPITAL LETTER U WITH RING ABOVE */
89 { 0x01db, 0x0170 }, /* Udoubleacute Ű LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */
90 { 0x01de, 0x0162 }, /* Tcedilla Ţ LATIN CAPITAL LETTER T WITH CEDILLA */
91 { 0x01e0, 0x0155 }, /* racute ŕ LATIN SMALL LETTER R WITH ACUTE */
92 { 0x01e3, 0x0103 }, /* abreve ă LATIN SMALL LETTER A WITH BREVE */
93 { 0x01e5, 0x013a }, /* lacute ĺ LATIN SMALL LETTER L WITH ACUTE */
94 { 0x01e6, 0x0107 }, /* cacute ć LATIN SMALL LETTER C WITH ACUTE */
95 { 0x01e8, 0x010d }, /* ccaron č LATIN SMALL LETTER C WITH CARON */
96 { 0x01ea, 0x0119 }, /* eogonek ę LATIN SMALL LETTER E WITH OGONEK */
97 { 0x01ec, 0x011b }, /* ecaron ě LATIN SMALL LETTER E WITH CARON */
98 { 0x01ef, 0x010f }, /* dcaron ď LATIN SMALL LETTER D WITH CARON */
99 { 0x01f0, 0x0111 }, /* dstroke đ LATIN SMALL LETTER D WITH STROKE */
100 { 0x01f1, 0x0144 }, /* nacute ń LATIN SMALL LETTER N WITH ACUTE */
101 { 0x01f2, 0x0148 }, /* ncaron ň LATIN SMALL LETTER N WITH CARON */
102 { 0x01f5, 0x0151 }, /* odoubleacute ő LATIN SMALL LETTER O WITH DOUBLE ACUTE */
103 { 0x01f8, 0x0159 }, /* rcaron ř LATIN SMALL LETTER R WITH CARON */
104 { 0x01f9, 0x016f }, /* uring ů LATIN SMALL LETTER U WITH RING ABOVE */
105 { 0x01fb, 0x0171 }, /* udoubleacute ű LATIN SMALL LETTER U WITH DOUBLE ACUTE */
106 { 0x01fe, 0x0163 }, /* tcedilla ţ LATIN SMALL LETTER T WITH CEDILLA */
107 { 0x01ff, 0x02d9 }, /* abovedot ˙ DOT ABOVE */
108 { 0x02a1, 0x0126 }, /* Hstroke Ħ LATIN CAPITAL LETTER H WITH STROKE */
109 { 0x02a6, 0x0124 }, /* Hcircumflex Ĥ LATIN CAPITAL LETTER H WITH CIRCUMFLEX */
110 { 0x02a9, 0x0130 }, /* Iabovedot İ LATIN CAPITAL LETTER I WITH DOT ABOVE */
111 { 0x02ab, 0x011e }, /* Gbreve Ğ LATIN CAPITAL LETTER G WITH BREVE */
112 { 0x02ac, 0x0134 }, /* Jcircumflex Ĵ LATIN CAPITAL LETTER J WITH CIRCUMFLEX */
113 { 0x02b1, 0x0127 }, /* hstroke ħ LATIN SMALL LETTER H WITH STROKE */
114 { 0x02b6, 0x0125 }, /* hcircumflex ĥ LATIN SMALL LETTER H WITH CIRCUMFLEX */
115 { 0x02b9, 0x0131 }, /* idotless ı LATIN SMALL LETTER DOTLESS I */
116 { 0x02bb, 0x011f }, /* gbreve ğ LATIN SMALL LETTER G WITH BREVE */
117 { 0x02bc, 0x0135 }, /* jcircumflex ĵ LATIN SMALL LETTER J WITH CIRCUMFLEX */
118 { 0x02c5, 0x010a }, /* Cabovedot Ċ LATIN CAPITAL LETTER C WITH DOT ABOVE */
119 { 0x02c6, 0x0108 }, /* Ccircumflex Ĉ LATIN CAPITAL LETTER C WITH CIRCUMFLEX */
120 { 0x02d5, 0x0120 }, /* Gabovedot Ġ LATIN CAPITAL LETTER G WITH DOT ABOVE */
121 { 0x02d8, 0x011c }, /* Gcircumflex Ĝ LATIN CAPITAL LETTER G WITH CIRCUMFLEX */
122 { 0x02dd, 0x016c }, /* Ubreve Ŭ LATIN CAPITAL LETTER U WITH BREVE */
123 { 0x02de, 0x015c }, /* Scircumflex Ŝ LATIN CAPITAL LETTER S WITH CIRCUMFLEX */
124 { 0x02e5, 0x010b }, /* cabovedot ċ LATIN SMALL LETTER C WITH DOT ABOVE */
125 { 0x02e6, 0x0109 }, /* ccircumflex ĉ LATIN SMALL LETTER C WITH CIRCUMFLEX */
126 { 0x02f5, 0x0121 }, /* gabovedot ġ LATIN SMALL LETTER G WITH DOT ABOVE */
127 { 0x02f8, 0x011d }, /* gcircumflex ĝ LATIN SMALL LETTER G WITH CIRCUMFLEX */
128 { 0x02fd, 0x016d }, /* ubreve ŭ LATIN SMALL LETTER U WITH BREVE */
129 { 0x02fe, 0x015d }, /* scircumflex ŝ LATIN SMALL LETTER S WITH CIRCUMFLEX */
130 { 0x03a2, 0x0138 }, /* kra ĸ LATIN SMALL LETTER KRA */
131 { 0x03a3, 0x0156 }, /* Rcedilla Ŗ LATIN CAPITAL LETTER R WITH CEDILLA */
132 { 0x03a5, 0x0128 }, /* Itilde Ĩ LATIN CAPITAL LETTER I WITH TILDE */
133 { 0x03a6, 0x013b }, /* Lcedilla Ļ LATIN CAPITAL LETTER L WITH CEDILLA */
134 { 0x03aa, 0x0112 }, /* Emacron Ē LATIN CAPITAL LETTER E WITH MACRON */
135 { 0x03ab, 0x0122 }, /* Gcedilla Ģ LATIN CAPITAL LETTER G WITH CEDILLA */
136 { 0x03ac, 0x0166 }, /* Tslash Ŧ LATIN CAPITAL LETTER T WITH STROKE */
137 { 0x03b3, 0x0157 }, /* rcedilla ŗ LATIN SMALL LETTER R WITH CEDILLA */
138 { 0x03b5, 0x0129 }, /* itilde ĩ LATIN SMALL LETTER I WITH TILDE */
139 { 0x03b6, 0x013c }, /* lcedilla ļ LATIN SMALL LETTER L WITH CEDILLA */
140 { 0x03ba, 0x0113 }, /* emacron ē LATIN SMALL LETTER E WITH MACRON */
141 { 0x03bb, 0x0123 }, /* gcedilla ģ LATIN SMALL LETTER G WITH CEDILLA */
142 { 0x03bc, 0x0167 }, /* tslash ŧ LATIN SMALL LETTER T WITH STROKE */
143 { 0x03bd, 0x014a }, /* ENG Ŋ LATIN CAPITAL LETTER ENG */
144 { 0x03bf, 0x014b }, /* eng ŋ LATIN SMALL LETTER ENG */
145 { 0x03c0, 0x0100 }, /* Amacron Ā LATIN CAPITAL LETTER A WITH MACRON */
146 { 0x03c7, 0x012e }, /* Iogonek Į LATIN CAPITAL LETTER I WITH OGONEK */
147 { 0x03cc, 0x0116 }, /* Eabovedot Ė LATIN CAPITAL LETTER E WITH DOT ABOVE */
148 { 0x03cf, 0x012a }, /* Imacron Ī LATIN CAPITAL LETTER I WITH MACRON */
149 { 0x03d1, 0x0145 }, /* Ncedilla Ņ LATIN CAPITAL LETTER N WITH CEDILLA */
150 { 0x03d2, 0x014c }, /* Omacron Ō LATIN CAPITAL LETTER O WITH MACRON */
151 { 0x03d3, 0x0136 }, /* Kcedilla Ķ LATIN CAPITAL LETTER K WITH CEDILLA */
152 { 0x03d9, 0x0172 }, /* Uogonek Ų LATIN CAPITAL LETTER U WITH OGONEK */
153 { 0x03dd, 0x0168 }, /* Utilde Ũ LATIN CAPITAL LETTER U WITH TILDE */
154 { 0x03de, 0x016a }, /* Umacron Ū LATIN CAPITAL LETTER U WITH MACRON */
155 { 0x03e0, 0x0101 }, /* amacron ā LATIN SMALL LETTER A WITH MACRON */
156 { 0x03e7, 0x012f }, /* iogonek į LATIN SMALL LETTER I WITH OGONEK */
157 { 0x03ec, 0x0117 }, /* eabovedot ė LATIN SMALL LETTER E WITH DOT ABOVE */
158 { 0x03ef, 0x012b }, /* imacron ī LATIN SMALL LETTER I WITH MACRON */
159 { 0x03f1, 0x0146 }, /* ncedilla ņ LATIN SMALL LETTER N WITH CEDILLA */
160 { 0x03f2, 0x014d }, /* omacron ō LATIN SMALL LETTER O WITH MACRON */
161 { 0x03f3, 0x0137 }, /* kcedilla ķ LATIN SMALL LETTER K WITH CEDILLA */
162 { 0x03f9, 0x0173 }, /* uogonek ų LATIN SMALL LETTER U WITH OGONEK */
163 { 0x03fd, 0x0169 }, /* utilde ũ LATIN SMALL LETTER U WITH TILDE */
164 { 0x03fe, 0x016b }, /* umacron ū LATIN SMALL LETTER U WITH MACRON */
165 { 0x047e, 0x203e }, /* overline ‾ OVERLINE */
166 { 0x04a1, 0x3002 }, /* kana_fullstop 。 IDEOGRAPHIC FULL STOP */
167 { 0x04a2, 0x300c }, /* kana_openingbracket 「 LEFT CORNER BRACKET */
168 { 0x04a3, 0x300d }, /* kana_closingbracket 」 RIGHT CORNER BRACKET */
169 { 0x04a4, 0x3001 }, /* kana_comma 、 IDEOGRAPHIC COMMA */
170 { 0x04a5, 0x30fb }, /* kana_conjunctive ・ KATAKANA MIDDLE DOT */
171 { 0x04a6, 0x30f2 }, /* kana_WO ヲ KATAKANA LETTER WO */
172 { 0x04a7, 0x30a1 }, /* kana_a ァ KATAKANA LETTER SMALL A */
173 { 0x04a8, 0x30a3 }, /* kana_i ィ KATAKANA LETTER SMALL I */
174 { 0x04a9, 0x30a5 }, /* kana_u ゥ KATAKANA LETTER SMALL U */
175 { 0x04aa, 0x30a7 }, /* kana_e ェ KATAKANA LETTER SMALL E */
176 { 0x04ab, 0x30a9 }, /* kana_o ォ KATAKANA LETTER SMALL O */
177 { 0x04ac, 0x30e3 }, /* kana_ya ャ KATAKANA LETTER SMALL YA */
178 { 0x04ad, 0x30e5 }, /* kana_yu ュ KATAKANA LETTER SMALL YU */
179 { 0x04ae, 0x30e7 }, /* kana_yo ョ KATAKANA LETTER SMALL YO */
180 { 0x04af, 0x30c3 }, /* kana_tsu ッ KATAKANA LETTER SMALL TU */
181 { 0x04b0, 0x30fc }, /* prolongedsound ー KATAKANA-HIRAGANA PROLONGED SOUND MARK */
182 { 0x04b1, 0x30a2 }, /* kana_A ア KATAKANA LETTER A */
183 { 0x04b2, 0x30a4 }, /* kana_I イ KATAKANA LETTER I */
184 { 0x04b3, 0x30a6 }, /* kana_U ウ KATAKANA LETTER U */
185 { 0x04b4, 0x30a8 }, /* kana_E エ KATAKANA LETTER E */
186 { 0x04b5, 0x30aa }, /* kana_O オ KATAKANA LETTER O */
187 { 0x04b6, 0x30ab }, /* kana_KA カ KATAKANA LETTER KA */
188 { 0x04b7, 0x30ad }, /* kana_KI キ KATAKANA LETTER KI */
189 { 0x04b8, 0x30af }, /* kana_KU ク KATAKANA LETTER KU */
190 { 0x04b9, 0x30b1 }, /* kana_KE ケ KATAKANA LETTER KE */
191 { 0x04ba, 0x30b3 }, /* kana_KO コ KATAKANA LETTER KO */
192 { 0x04bb, 0x30b5 }, /* kana_SA サ KATAKANA LETTER SA */
193 { 0x04bc, 0x30b7 }, /* kana_SHI シ KATAKANA LETTER SI */
194 { 0x04bd, 0x30b9 }, /* kana_SU ス KATAKANA LETTER SU */
195 { 0x04be, 0x30bb }, /* kana_SE セ KATAKANA LETTER SE */
196 { 0x04bf, 0x30bd }, /* kana_SO ソ KATAKANA LETTER SO */
197 { 0x04c0, 0x30bf }, /* kana_TA タ KATAKANA LETTER TA */
198 { 0x04c1, 0x30c1 }, /* kana_CHI チ KATAKANA LETTER TI */
199 { 0x04c2, 0x30c4 }, /* kana_TSU ツ KATAKANA LETTER TU */
200 { 0x04c3, 0x30c6 }, /* kana_TE テ KATAKANA LETTER TE */
201 { 0x04c4, 0x30c8 }, /* kana_TO ト KATAKANA LETTER TO */
202 { 0x04c5, 0x30ca }, /* kana_NA ナ KATAKANA LETTER NA */
203 { 0x04c6, 0x30cb }, /* kana_NI ニ KATAKANA LETTER NI */
204 { 0x04c7, 0x30cc }, /* kana_NU ヌ KATAKANA LETTER NU */
205 { 0x04c8, 0x30cd }, /* kana_NE ネ KATAKANA LETTER NE */
206 { 0x04c9, 0x30ce }, /* kana_NO ノ KATAKANA LETTER NO */
207 { 0x04ca, 0x30cf }, /* kana_HA ハ KATAKANA LETTER HA */
208 { 0x04cb, 0x30d2 }, /* kana_HI ヒ KATAKANA LETTER HI */
209 { 0x04cc, 0x30d5 }, /* kana_FU フ KATAKANA LETTER HU */
210 { 0x04cd, 0x30d8 }, /* kana_HE ヘ KATAKANA LETTER HE */
211 { 0x04ce, 0x30db }, /* kana_HO ホ KATAKANA LETTER HO */
212 { 0x04cf, 0x30de }, /* kana_MA マ KATAKANA LETTER MA */
213 { 0x04d0, 0x30df }, /* kana_MI ミ KATAKANA LETTER MI */
214 { 0x04d1, 0x30e0 }, /* kana_MU ム KATAKANA LETTER MU */
215 { 0x04d2, 0x30e1 }, /* kana_ME メ KATAKANA LETTER ME */
216 { 0x04d3, 0x30e2 }, /* kana_MO モ KATAKANA LETTER MO */
217 { 0x04d4, 0x30e4 }, /* kana_YA ヤ KATAKANA LETTER YA */
218 { 0x04d5, 0x30e6 }, /* kana_YU ユ KATAKANA LETTER YU */
219 { 0x04d6, 0x30e8 }, /* kana_YO ヨ KATAKANA LETTER YO */
220 { 0x04d7, 0x30e9 }, /* kana_RA ラ KATAKANA LETTER RA */
221 { 0x04d8, 0x30ea }, /* kana_RI リ KATAKANA LETTER RI */
222 { 0x04d9, 0x30eb }, /* kana_RU ル KATAKANA LETTER RU */
223 { 0x04da, 0x30ec }, /* kana_RE レ KATAKANA LETTER RE */
224 { 0x04db, 0x30ed }, /* kana_RO ロ KATAKANA LETTER RO */
225 { 0x04dc, 0x30ef }, /* kana_WA ワ KATAKANA LETTER WA */
226 { 0x04dd, 0x30f3 }, /* kana_N ン KATAKANA LETTER N */
227 { 0x04de, 0x309b }, /* voicedsound ゛ KATAKANA-HIRAGANA VOICED SOUND MARK */
228 { 0x04df, 0x309c }, /* semivoicedsound ゜ KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
229 { 0x05ac, 0x060c }, /* Arabic_comma ، ARABIC COMMA */
230 { 0x05bb, 0x061b }, /* Arabic_semicolon ؛ ARABIC SEMICOLON */
231 { 0x05bf, 0x061f }, /* Arabic_question_mark ؟ ARABIC QUESTION MARK */
232 { 0x05c1, 0x0621 }, /* Arabic_hamza ء ARABIC LETTER HAMZA */
233 { 0x05c2, 0x0622 }, /* Arabic_maddaonalef آ ARABIC LETTER ALEF WITH MADDA ABOVE */
234 { 0x05c3, 0x0623 }, /* Arabic_hamzaonalef أ ARABIC LETTER ALEF WITH HAMZA ABOVE */
235 { 0x05c4, 0x0624 }, /* Arabic_hamzaonwaw ؤ ARABIC LETTER WAW WITH HAMZA ABOVE */
236 { 0x05c5, 0x0625 }, /* Arabic_hamzaunderalef إ ARABIC LETTER ALEF WITH HAMZA BELOW */
237 { 0x05c6, 0x0626 }, /* Arabic_hamzaonyeh ئ ARABIC LETTER YEH WITH HAMZA ABOVE */
238 { 0x05c7, 0x0627 }, /* Arabic_alef ا ARABIC LETTER ALEF */
239 { 0x05c8, 0x0628 }, /* Arabic_beh ب ARABIC LETTER BEH */
240 { 0x05c9, 0x0629 }, /* Arabic_tehmarbuta ة ARABIC LETTER TEH MARBUTA */
241 { 0x05ca, 0x062a }, /* Arabic_teh ت ARABIC LETTER TEH */
242 { 0x05cb, 0x062b }, /* Arabic_theh ث ARABIC LETTER THEH */
243 { 0x05cc, 0x062c }, /* Arabic_jeem ج ARABIC LETTER JEEM */
244 { 0x05cd, 0x062d }, /* Arabic_hah ح ARABIC LETTER HAH */
245 { 0x05ce, 0x062e }, /* Arabic_khah خ ARABIC LETTER KHAH */
246 { 0x05cf, 0x062f }, /* Arabic_dal د ARABIC LETTER DAL */
247 { 0x05d0, 0x0630 }, /* Arabic_thal ذ ARABIC LETTER THAL */
248 { 0x05d1, 0x0631 }, /* Arabic_ra ر ARABIC LETTER REH */
249 { 0x05d2, 0x0632 }, /* Arabic_zain ز ARABIC LETTER ZAIN */
250 { 0x05d3, 0x0633 }, /* Arabic_seen س ARABIC LETTER SEEN */
251 { 0x05d4, 0x0634 }, /* Arabic_sheen ش ARABIC LETTER SHEEN */
252 { 0x05d5, 0x0635 }, /* Arabic_sad ص ARABIC LETTER SAD */
253 { 0x05d6, 0x0636 }, /* Arabic_dad ض ARABIC LETTER DAD */
254 { 0x05d7, 0x0637 }, /* Arabic_tah ط ARABIC LETTER TAH */
255 { 0x05d8, 0x0638 }, /* Arabic_zah ظ ARABIC LETTER ZAH */
256 { 0x05d9, 0x0639 }, /* Arabic_ain ع ARABIC LETTER AIN */
257 { 0x05da, 0x063a }, /* Arabic_ghain غ ARABIC LETTER GHAIN */
258 { 0x05e0, 0x0640 }, /* Arabic_tatweel ـ ARABIC TATWEEL */
259 { 0x05e1, 0x0641 }, /* Arabic_feh ف ARABIC LETTER FEH */
260 { 0x05e2, 0x0642 }, /* Arabic_qaf ق ARABIC LETTER QAF */
261 { 0x05e3, 0x0643 }, /* Arabic_kaf ك ARABIC LETTER KAF */
262 { 0x05e4, 0x0644 }, /* Arabic_lam ل ARABIC LETTER LAM */
263 { 0x05e5, 0x0645 }, /* Arabic_meem م ARABIC LETTER MEEM */
264 { 0x05e6, 0x0646 }, /* Arabic_noon ن ARABIC LETTER NOON */
265 { 0x05e7, 0x0647 }, /* Arabic_ha ه ARABIC LETTER HEH */
266 { 0x05e8, 0x0648 }, /* Arabic_waw و ARABIC LETTER WAW */
267 { 0x05e9, 0x0649 }, /* Arabic_alefmaksura ى ARABIC LETTER ALEF MAKSURA */
268 { 0x05ea, 0x064a }, /* Arabic_yeh ي ARABIC LETTER YEH */
269 { 0x05eb, 0x064b }, /* Arabic_fathatan ً ARABIC FATHATAN */
270 { 0x05ec, 0x064c }, /* Arabic_dammatan ٌ ARABIC DAMMATAN */
271 { 0x05ed, 0x064d }, /* Arabic_kasratan ٍ ARABIC KASRATAN */
272 { 0x05ee, 0x064e }, /* Arabic_fatha َ ARABIC FATHA */
273 { 0x05ef, 0x064f }, /* Arabic_damma ُ ARABIC DAMMA */
274 { 0x05f0, 0x0650 }, /* Arabic_kasra ِ ARABIC KASRA */
275 { 0x05f1, 0x0651 }, /* Arabic_shadda ّ ARABIC SHADDA */
276 { 0x05f2, 0x0652 }, /* Arabic_sukun ْ ARABIC SUKUN */
277 { 0x06a1, 0x0452 }, /* Serbian_dje ђ CYRILLIC SMALL LETTER DJE */
278 { 0x06a2, 0x0453 }, /* Macedonia_gje ѓ CYRILLIC SMALL LETTER GJE */
279 { 0x06a3, 0x0451 }, /* Cyrillic_io ё CYRILLIC SMALL LETTER IO */
280 { 0x06a4, 0x0454 }, /* Ukrainian_ie є CYRILLIC SMALL LETTER UKRAINIAN IE */
281 { 0x06a5, 0x0455 }, /* Macedonia_dse ѕ CYRILLIC SMALL LETTER DZE */
282 { 0x06a6, 0x0456 }, /* Ukrainian_i і CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */
283 { 0x06a7, 0x0457 }, /* Ukrainian_yi ї CYRILLIC SMALL LETTER YI */
284 { 0x06a8, 0x0458 }, /* Cyrillic_je ј CYRILLIC SMALL LETTER JE */
285 { 0x06a9, 0x0459 }, /* Cyrillic_lje љ CYRILLIC SMALL LETTER LJE */
286 { 0x06aa, 0x045a }, /* Cyrillic_nje њ CYRILLIC SMALL LETTER NJE */
287 { 0x06ab, 0x045b }, /* Serbian_tshe ћ CYRILLIC SMALL LETTER TSHE */
288 { 0x06ac, 0x045c }, /* Macedonia_kje ќ CYRILLIC SMALL LETTER KJE */
289 { 0x06ae, 0x045e }, /* Byelorussian_shortu ў CYRILLIC SMALL LETTER SHORT U */
290 { 0x06af, 0x045f }, /* Cyrillic_dzhe џ CYRILLIC SMALL LETTER DZHE */
291 { 0x06b0, 0x2116 }, /* numerosign № NUMERO SIGN */
292 { 0x06b1, 0x0402 }, /* Serbian_DJE Ђ CYRILLIC CAPITAL LETTER DJE */
293 { 0x06b2, 0x0403 }, /* Macedonia_GJE Ѓ CYRILLIC CAPITAL LETTER GJE */
294 { 0x06b3, 0x0401 }, /* Cyrillic_IO Ё CYRILLIC CAPITAL LETTER IO */
295 { 0x06b4, 0x0404 }, /* Ukrainian_IE Є CYRILLIC CAPITAL LETTER UKRAINIAN IE */
296 { 0x06b5, 0x0405 }, /* Macedonia_DSE Ѕ CYRILLIC CAPITAL LETTER DZE */
297 { 0x06b6, 0x0406 }, /* Ukrainian_I І CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */
298 { 0x06b7, 0x0407 }, /* Ukrainian_YI Ї CYRILLIC CAPITAL LETTER YI */
299 { 0x06b8, 0x0408 }, /* Cyrillic_JE Ј CYRILLIC CAPITAL LETTER JE */
300 { 0x06b9, 0x0409 }, /* Cyrillic_LJE Љ CYRILLIC CAPITAL LETTER LJE */
301 { 0x06ba, 0x040a }, /* Cyrillic_NJE Њ CYRILLIC CAPITAL LETTER NJE */
302 { 0x06bb, 0x040b }, /* Serbian_TSHE Ћ CYRILLIC CAPITAL LETTER TSHE */
303 { 0x06bc, 0x040c }, /* Macedonia_KJE Ќ CYRILLIC CAPITAL LETTER KJE */
304 { 0x06be, 0x040e }, /* Byelorussian_SHORTU Ў CYRILLIC CAPITAL LETTER SHORT U */
305 { 0x06bf, 0x040f }, /* Cyrillic_DZHE Џ CYRILLIC CAPITAL LETTER DZHE */
306 { 0x06c0, 0x044e }, /* Cyrillic_yu ю CYRILLIC SMALL LETTER YU */
307 { 0x06c1, 0x0430 }, /* Cyrillic_a а CYRILLIC SMALL LETTER A */
308 { 0x06c2, 0x0431 }, /* Cyrillic_be б CYRILLIC SMALL LETTER BE */
309 { 0x06c3, 0x0446 }, /* Cyrillic_tse ц CYRILLIC SMALL LETTER TSE */
310 { 0x06c4, 0x0434 }, /* Cyrillic_de д CYRILLIC SMALL LETTER DE */
311 { 0x06c5, 0x0435 }, /* Cyrillic_ie е CYRILLIC SMALL LETTER IE */
312 { 0x06c6, 0x0444 }, /* Cyrillic_ef ф CYRILLIC SMALL LETTER EF */
313 { 0x06c7, 0x0433 }, /* Cyrillic_ghe г CYRILLIC SMALL LETTER GHE */
314 { 0x06c8, 0x0445 }, /* Cyrillic_ha х CYRILLIC SMALL LETTER HA */
315 { 0x06c9, 0x0438 }, /* Cyrillic_i и CYRILLIC SMALL LETTER I */
316 { 0x06ca, 0x0439 }, /* Cyrillic_shorti й CYRILLIC SMALL LETTER SHORT I */
317 { 0x06cb, 0x043a }, /* Cyrillic_ka к CYRILLIC SMALL LETTER KA */
318 { 0x06cc, 0x043b }, /* Cyrillic_el л CYRILLIC SMALL LETTER EL */
319 { 0x06cd, 0x043c }, /* Cyrillic_em м CYRILLIC SMALL LETTER EM */
320 { 0x06ce, 0x043d }, /* Cyrillic_en н CYRILLIC SMALL LETTER EN */
321 { 0x06cf, 0x043e }, /* Cyrillic_o о CYRILLIC SMALL LETTER O */
322 { 0x06d0, 0x043f }, /* Cyrillic_pe п CYRILLIC SMALL LETTER PE */
323 { 0x06d1, 0x044f }, /* Cyrillic_ya я CYRILLIC SMALL LETTER YA */
324 { 0x06d2, 0x0440 }, /* Cyrillic_er р CYRILLIC SMALL LETTER ER */
325 { 0x06d3, 0x0441 }, /* Cyrillic_es с CYRILLIC SMALL LETTER ES */
326 { 0x06d4, 0x0442 }, /* Cyrillic_te т CYRILLIC SMALL LETTER TE */
327 { 0x06d5, 0x0443 }, /* Cyrillic_u у CYRILLIC SMALL LETTER U */
328 { 0x06d6, 0x0436 }, /* Cyrillic_zhe ж CYRILLIC SMALL LETTER ZHE */
329 { 0x06d7, 0x0432 }, /* Cyrillic_ve в CYRILLIC SMALL LETTER VE */
330 { 0x06d8, 0x044c }, /* Cyrillic_softsign ь CYRILLIC SMALL LETTER SOFT SIGN */
331 { 0x06d9, 0x044b }, /* Cyrillic_yeru ы CYRILLIC SMALL LETTER YERU */
332 { 0x06da, 0x0437 }, /* Cyrillic_ze з CYRILLIC SMALL LETTER ZE */
333 { 0x06db, 0x0448 }, /* Cyrillic_sha ш CYRILLIC SMALL LETTER SHA */
334 { 0x06dc, 0x044d }, /* Cyrillic_e э CYRILLIC SMALL LETTER E */
335 { 0x06dd, 0x0449 }, /* Cyrillic_shcha щ CYRILLIC SMALL LETTER SHCHA */
336 { 0x06de, 0x0447 }, /* Cyrillic_che ч CYRILLIC SMALL LETTER CHE */
337 { 0x06df, 0x044a }, /* Cyrillic_hardsign ъ CYRILLIC SMALL LETTER HARD SIGN */
338 { 0x06e0, 0x042e }, /* Cyrillic_YU Ю CYRILLIC CAPITAL LETTER YU */
339 { 0x06e1, 0x0410 }, /* Cyrillic_A А CYRILLIC CAPITAL LETTER A */
340 { 0x06e2, 0x0411 }, /* Cyrillic_BE Б CYRILLIC CAPITAL LETTER BE */
341 { 0x06e3, 0x0426 }, /* Cyrillic_TSE Ц CYRILLIC CAPITAL LETTER TSE */
342 { 0x06e4, 0x0414 }, /* Cyrillic_DE Д CYRILLIC CAPITAL LETTER DE */
343 { 0x06e5, 0x0415 }, /* Cyrillic_IE Е CYRILLIC CAPITAL LETTER IE */
344 { 0x06e6, 0x0424 }, /* Cyrillic_EF Ф CYRILLIC CAPITAL LETTER EF */
345 { 0x06e7, 0x0413 }, /* Cyrillic_GHE Г CYRILLIC CAPITAL LETTER GHE */
346 { 0x06e8, 0x0425 }, /* Cyrillic_HA Х CYRILLIC CAPITAL LETTER HA */
347 { 0x06e9, 0x0418 }, /* Cyrillic_I И CYRILLIC CAPITAL LETTER I */
348 { 0x06ea, 0x0419 }, /* Cyrillic_SHORTI Й CYRILLIC CAPITAL LETTER SHORT I */
349 { 0x06eb, 0x041a }, /* Cyrillic_KA К CYRILLIC CAPITAL LETTER KA */
350 { 0x06ec, 0x041b }, /* Cyrillic_EL Л CYRILLIC CAPITAL LETTER EL */
351 { 0x06ed, 0x041c }, /* Cyrillic_EM М CYRILLIC CAPITAL LETTER EM */
352 { 0x06ee, 0x041d }, /* Cyrillic_EN Н CYRILLIC CAPITAL LETTER EN */
353 { 0x06ef, 0x041e }, /* Cyrillic_O О CYRILLIC CAPITAL LETTER O */
354 { 0x06f0, 0x041f }, /* Cyrillic_PE П CYRILLIC CAPITAL LETTER PE */
355 { 0x06f1, 0x042f }, /* Cyrillic_YA Я CYRILLIC CAPITAL LETTER YA */
356 { 0x06f2, 0x0420 }, /* Cyrillic_ER Р CYRILLIC CAPITAL LETTER ER */
357 { 0x06f3, 0x0421 }, /* Cyrillic_ES С CYRILLIC CAPITAL LETTER ES */
358 { 0x06f4, 0x0422 }, /* Cyrillic_TE Т CYRILLIC CAPITAL LETTER TE */
359 { 0x06f5, 0x0423 }, /* Cyrillic_U У CYRILLIC CAPITAL LETTER U */
360 { 0x06f6, 0x0416 }, /* Cyrillic_ZHE Ж CYRILLIC CAPITAL LETTER ZHE */
361 { 0x06f7, 0x0412 }, /* Cyrillic_VE В CYRILLIC CAPITAL LETTER VE */
362 { 0x06f8, 0x042c }, /* Cyrillic_SOFTSIGN Ь CYRILLIC CAPITAL LETTER SOFT SIGN */
363 { 0x06f9, 0x042b }, /* Cyrillic_YERU Ы CYRILLIC CAPITAL LETTER YERU */
364 { 0x06fa, 0x0417 }, /* Cyrillic_ZE З CYRILLIC CAPITAL LETTER ZE */
365 { 0x06fb, 0x0428 }, /* Cyrillic_SHA Ш CYRILLIC CAPITAL LETTER SHA */
366 { 0x06fc, 0x042d }, /* Cyrillic_E Э CYRILLIC CAPITAL LETTER E */
367 { 0x06fd, 0x0429 }, /* Cyrillic_SHCHA Щ CYRILLIC CAPITAL LETTER SHCHA */
368 { 0x06fe, 0x0427 }, /* Cyrillic_CHE Ч CYRILLIC CAPITAL LETTER CHE */
369 { 0x06ff, 0x042a }, /* Cyrillic_HARDSIGN Ъ CYRILLIC CAPITAL LETTER HARD SIGN */
370 { 0x07a1, 0x0386 }, /* Greek_ALPHAaccent Ά GREEK CAPITAL LETTER ALPHA WITH TONOS */
371 { 0x07a2, 0x0388 }, /* Greek_EPSILONaccent Έ GREEK CAPITAL LETTER EPSILON WITH TONOS */
372 { 0x07a3, 0x0389 }, /* Greek_ETAaccent Ή GREEK CAPITAL LETTER ETA WITH TONOS */
373 { 0x07a4, 0x038a }, /* Greek_IOTAaccent Ί GREEK CAPITAL LETTER IOTA WITH TONOS */
374 { 0x07a5, 0x03aa }, /* Greek_IOTAdiaeresis Ϊ GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */
375 { 0x07a7, 0x038c }, /* Greek_OMICRONaccent Ό GREEK CAPITAL LETTER OMICRON WITH TONOS */
376 { 0x07a8, 0x038e }, /* Greek_UPSILONaccent Ύ GREEK CAPITAL LETTER UPSILON WITH TONOS */
377 { 0x07a9, 0x03ab }, /* Greek_UPSILONdieresis Ϋ GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */
378 { 0x07ab, 0x038f }, /* Greek_OMEGAaccent Ώ GREEK CAPITAL LETTER OMEGA WITH TONOS */
379 { 0x07ae, 0x0385 }, /* Greek_accentdieresis ΅ GREEK DIALYTIKA TONOS */
380 { 0x07af, 0x2015 }, /* Greek_horizbar ― HORIZONTAL BAR */
381 { 0x07b1, 0x03ac }, /* Greek_alphaaccent ά GREEK SMALL LETTER ALPHA WITH TONOS */
382 { 0x07b2, 0x03ad }, /* Greek_epsilonaccent έ GREEK SMALL LETTER EPSILON WITH TONOS */
383 { 0x07b3, 0x03ae }, /* Greek_etaaccent ή GREEK SMALL LETTER ETA WITH TONOS */
384 { 0x07b4, 0x03af }, /* Greek_iotaaccent ί GREEK SMALL LETTER IOTA WITH TONOS */
385 { 0x07b5, 0x03ca }, /* Greek_iotadieresis ϊ GREEK SMALL LETTER IOTA WITH DIALYTIKA */
386 { 0x07b6, 0x0390 }, /* Greek_iotaaccentdieresis ΐ GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
387 { 0x07b7, 0x03cc }, /* Greek_omicronaccent ό GREEK SMALL LETTER OMICRON WITH TONOS */
388 { 0x07b8, 0x03cd }, /* Greek_upsilonaccent ύ GREEK SMALL LETTER UPSILON WITH TONOS */
389 { 0x07b9, 0x03cb }, /* Greek_upsilondieresis ϋ GREEK SMALL LETTER UPSILON WITH DIALYTIKA */
390 { 0x07ba, 0x03b0 }, /* Greek_upsilonaccentdieresis ΰ GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
391 { 0x07bb, 0x03ce }, /* Greek_omegaaccent ώ GREEK SMALL LETTER OMEGA WITH TONOS */
392 { 0x07c1, 0x0391 }, /* Greek_ALPHA Α GREEK CAPITAL LETTER ALPHA */
393 { 0x07c2, 0x0392 }, /* Greek_BETA Β GREEK CAPITAL LETTER BETA */
394 { 0x07c3, 0x0393 }, /* Greek_GAMMA Γ GREEK CAPITAL LETTER GAMMA */
395 { 0x07c4, 0x0394 }, /* Greek_DELTA Δ GREEK CAPITAL LETTER DELTA */
396 { 0x07c5, 0x0395 }, /* Greek_EPSILON Ε GREEK CAPITAL LETTER EPSILON */
397 { 0x07c6, 0x0396 }, /* Greek_ZETA Ζ GREEK CAPITAL LETTER ZETA */
398 { 0x07c7, 0x0397 }, /* Greek_ETA Η GREEK CAPITAL LETTER ETA */
399 { 0x07c8, 0x0398 }, /* Greek_THETA Θ GREEK CAPITAL LETTER THETA */
400 { 0x07c9, 0x0399 }, /* Greek_IOTA Ι GREEK CAPITAL LETTER IOTA */
401 { 0x07ca, 0x039a }, /* Greek_KAPPA Κ GREEK CAPITAL LETTER KAPPA */
402 { 0x07cb, 0x039b }, /* Greek_LAMBDA Λ GREEK CAPITAL LETTER LAMDA */
403 { 0x07cc, 0x039c }, /* Greek_MU Μ GREEK CAPITAL LETTER MU */
404 { 0x07cd, 0x039d }, /* Greek_NU Ν GREEK CAPITAL LETTER NU */
405 { 0x07ce, 0x039e }, /* Greek_XI Ξ GREEK CAPITAL LETTER XI */
406 { 0x07cf, 0x039f }, /* Greek_OMICRON Ο GREEK CAPITAL LETTER OMICRON */
407 { 0x07d0, 0x03a0 }, /* Greek_PI Π GREEK CAPITAL LETTER PI */
408 { 0x07d1, 0x03a1 }, /* Greek_RHO Ρ GREEK CAPITAL LETTER RHO */
409 { 0x07d2, 0x03a3 }, /* Greek_SIGMA Σ GREEK CAPITAL LETTER SIGMA */
410 { 0x07d4, 0x03a4 }, /* Greek_TAU Τ GREEK CAPITAL LETTER TAU */
411 { 0x07d5, 0x03a5 }, /* Greek_UPSILON Υ GREEK CAPITAL LETTER UPSILON */
412 { 0x07d6, 0x03a6 }, /* Greek_PHI Φ GREEK CAPITAL LETTER PHI */
413 { 0x07d7, 0x03a7 }, /* Greek_CHI Χ GREEK CAPITAL LETTER CHI */
414 { 0x07d8, 0x03a8 }, /* Greek_PSI Ψ GREEK CAPITAL LETTER PSI */
415 { 0x07d9, 0x03a9 }, /* Greek_OMEGA Ω GREEK CAPITAL LETTER OMEGA */
416 { 0x07e1, 0x03b1 }, /* Greek_alpha α GREEK SMALL LETTER ALPHA */
417 { 0x07e2, 0x03b2 }, /* Greek_beta β GREEK SMALL LETTER BETA */
418 { 0x07e3, 0x03b3 }, /* Greek_gamma γ GREEK SMALL LETTER GAMMA */
419 { 0x07e4, 0x03b4 }, /* Greek_delta δ GREEK SMALL LETTER DELTA */
420 { 0x07e5, 0x03b5 }, /* Greek_epsilon ε GREEK SMALL LETTER EPSILON */
421 { 0x07e6, 0x03b6 }, /* Greek_zeta ζ GREEK SMALL LETTER ZETA */
422 { 0x07e7, 0x03b7 }, /* Greek_eta η GREEK SMALL LETTER ETA */
423 { 0x07e8, 0x03b8 }, /* Greek_theta θ GREEK SMALL LETTER THETA */
424 { 0x07e9, 0x03b9 }, /* Greek_iota ι GREEK SMALL LETTER IOTA */
425 { 0x07ea, 0x03ba }, /* Greek_kappa κ GREEK SMALL LETTER KAPPA */
426 { 0x07eb, 0x03bb }, /* Greek_lambda λ GREEK SMALL LETTER LAMDA */
427 { 0x07ec, 0x03bc }, /* Greek_mu μ GREEK SMALL LETTER MU */
428 { 0x07ed, 0x03bd }, /* Greek_nu ν GREEK SMALL LETTER NU */
429 { 0x07ee, 0x03be }, /* Greek_xi ξ GREEK SMALL LETTER XI */
430 { 0x07ef, 0x03bf }, /* Greek_omicron ο GREEK SMALL LETTER OMICRON */
431 { 0x07f0, 0x03c0 }, /* Greek_pi π GREEK SMALL LETTER PI */
432 { 0x07f1, 0x03c1 }, /* Greek_rho ρ GREEK SMALL LETTER RHO */
433 { 0x07f2, 0x03c3 }, /* Greek_sigma σ GREEK SMALL LETTER SIGMA */
434 { 0x07f3, 0x03c2 }, /* Greek_finalsmallsigma ς GREEK SMALL LETTER FINAL SIGMA */
435 { 0x07f4, 0x03c4 }, /* Greek_tau τ GREEK SMALL LETTER TAU */
436 { 0x07f5, 0x03c5 }, /* Greek_upsilon υ GREEK SMALL LETTER UPSILON */
437 { 0x07f6, 0x03c6 }, /* Greek_phi φ GREEK SMALL LETTER PHI */
438 { 0x07f7, 0x03c7 }, /* Greek_chi χ GREEK SMALL LETTER CHI */
439 { 0x07f8, 0x03c8 }, /* Greek_psi ψ GREEK SMALL LETTER PSI */
440 { 0x07f9, 0x03c9 }, /* Greek_omega ω GREEK SMALL LETTER OMEGA */
441 { 0x08a1, 0x23b7 }, /* leftradical ⎷ ??? */
442 { 0x08a2, 0x250c }, /* topleftradical ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
443 { 0x08a3, 0x2500 }, /* horizconnector ─ BOX DRAWINGS LIGHT HORIZONTAL */
444 { 0x08a4, 0x2320 }, /* topintegral ⌠ TOP HALF INTEGRAL */
445 { 0x08a5, 0x2321 }, /* botintegral ⌡ BOTTOM HALF INTEGRAL */
446 { 0x08a6, 0x2502 }, /* vertconnector │ BOX DRAWINGS LIGHT VERTICAL */
447 { 0x08a7, 0x23a1 }, /* topleftsqbracket ⎡ ??? */
448 { 0x08a8, 0x23a3 }, /* botleftsqbracket ⎣ ??? */
449 { 0x08a9, 0x23a4 }, /* toprightsqbracket ⎤ ??? */
450 { 0x08aa, 0x23a6 }, /* botrightsqbracket ⎦ ??? */
451 { 0x08ab, 0x239b }, /* topleftparens ⎛ ??? */
452 { 0x08ac, 0x239d }, /* botleftparens ⎝ ??? */
453 { 0x08ad, 0x239e }, /* toprightparens ⎞ ??? */
454 { 0x08ae, 0x23a0 }, /* botrightparens ⎠ ??? */
455 { 0x08af, 0x23a8 }, /* leftmiddlecurlybrace ⎨ ??? */
456 { 0x08b0, 0x23ac }, /* rightmiddlecurlybrace ⎬ ??? */
457/* 0x08b1 topleftsummation ? ??? */
458/* 0x08b2 botleftsummation ? ??? */
459/* 0x08b3 topvertsummationconnector ? ??? */
460/* 0x08b4 botvertsummationconnector ? ??? */
461/* 0x08b5 toprightsummation ? ??? */
462/* 0x08b6 botrightsummation ? ??? */
463/* 0x08b7 rightmiddlesummation ? ??? */
464 { 0x08bc, 0x2264 }, /* lessthanequal ≤ LESS-THAN OR EQUAL TO */
465 { 0x08bd, 0x2260 }, /* notequal ≠ NOT EQUAL TO */
466 { 0x08be, 0x2265 }, /* greaterthanequal ≥ GREATER-THAN OR EQUAL TO */
467 { 0x08bf, 0x222b }, /* integral ∫ INTEGRAL */
468 { 0x08c0, 0x2234 }, /* therefore ∴ THEREFORE */
469 { 0x08c1, 0x221d }, /* variation ∝ PROPORTIONAL TO */
470 { 0x08c2, 0x221e }, /* infinity ∞ INFINITY */
471 { 0x08c5, 0x2207 }, /* nabla ∇ NABLA */
472 { 0x08c8, 0x223c }, /* approximate ∼ TILDE OPERATOR */
473 { 0x08c9, 0x2243 }, /* similarequal ≃ ASYMPTOTICALLY EQUAL TO */
474 { 0x08cd, 0x21d4 }, /* ifonlyif ⇔ LEFT RIGHT DOUBLE ARROW */
475 { 0x08ce, 0x21d2 }, /* implies ⇒ RIGHTWARDS DOUBLE ARROW */
476 { 0x08cf, 0x2261 }, /* identical ≡ IDENTICAL TO */
477 { 0x08d6, 0x221a }, /* radical √ SQUARE ROOT */
478 { 0x08da, 0x2282 }, /* includedin ⊂ SUBSET OF */
479 { 0x08db, 0x2283 }, /* includes ⊃ SUPERSET OF */
480 { 0x08dc, 0x2229 }, /* intersection ∩ INTERSECTION */
481 { 0x08dd, 0x222a }, /* union ∪ UNION */
482 { 0x08de, 0x2227 }, /* logicaland ∧ LOGICAL AND */
483 { 0x08df, 0x2228 }, /* logicalor ∨ LOGICAL OR */
484 { 0x08ef, 0x2202 }, /* partialderivative ∂ PARTIAL DIFFERENTIAL */
485 { 0x08f6, 0x0192 }, /* function ƒ LATIN SMALL LETTER F WITH HOOK */
486 { 0x08fb, 0x2190 }, /* leftarrow ← LEFTWARDS ARROW */
487 { 0x08fc, 0x2191 }, /* uparrow ↑ UPWARDS ARROW */
488 { 0x08fd, 0x2192 }, /* rightarrow → RIGHTWARDS ARROW */
489 { 0x08fe, 0x2193 }, /* downarrow ↓ DOWNWARDS ARROW */
490/* 0x09df blank ? ??? */
491 { 0x09e0, 0x25c6 }, /* soliddiamond ◆ BLACK DIAMOND */
492 { 0x09e1, 0x2592 }, /* checkerboard ▒ MEDIUM SHADE */
493 { 0x09e2, 0x2409 }, /* ht ␉ SYMBOL FOR HORIZONTAL TABULATION */
494 { 0x09e3, 0x240c }, /* ff ␌ SYMBOL FOR FORM FEED */
495 { 0x09e4, 0x240d }, /* cr ␍ SYMBOL FOR CARRIAGE RETURN */
496 { 0x09e5, 0x240a }, /* lf ␊ SYMBOL FOR LINE FEED */
497 { 0x09e8, 0x2424 }, /* nl ␤ SYMBOL FOR NEWLINE */
498 { 0x09e9, 0x240b }, /* vt ␋ SYMBOL FOR VERTICAL TABULATION */
499 { 0x09ea, 0x2518 }, /* lowrightcorner ┘ BOX DRAWINGS LIGHT UP AND LEFT */
500 { 0x09eb, 0x2510 }, /* uprightcorner ┐ BOX DRAWINGS LIGHT DOWN AND LEFT */
501 { 0x09ec, 0x250c }, /* upleftcorner ┌ BOX DRAWINGS LIGHT DOWN AND RIGHT */
502 { 0x09ed, 0x2514 }, /* lowleftcorner └ BOX DRAWINGS LIGHT UP AND RIGHT */
503 { 0x09ee, 0x253c }, /* crossinglines ┼ BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
504 { 0x09ef, 0x23ba }, /* horizlinescan1 ⎺ HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */
505 { 0x09f0, 0x23bb }, /* horizlinescan3 ⎻ HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */
506 { 0x09f1, 0x2500 }, /* horizlinescan5 ─ BOX DRAWINGS LIGHT HORIZONTAL */
507 { 0x09f2, 0x23bc }, /* horizlinescan7 ⎼ HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */
508 { 0x09f3, 0x23bd }, /* horizlinescan9 ⎽ HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */
509 { 0x09f4, 0x251c }, /* leftt ├ BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
510 { 0x09f5, 0x2524 }, /* rightt ┤ BOX DRAWINGS LIGHT VERTICAL AND LEFT */
511 { 0x09f6, 0x2534 }, /* bott ┴ BOX DRAWINGS LIGHT UP AND HORIZONTAL */
512 { 0x09f7, 0x252c }, /* topt ┬ BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
513 { 0x09f8, 0x2502 }, /* vertbar │ BOX DRAWINGS LIGHT VERTICAL */
514 { 0x0aa1, 0x2003 }, /* emspace   EM SPACE */
515 { 0x0aa2, 0x2002 }, /* enspace   EN SPACE */
516 { 0x0aa3, 0x2004 }, /* em3space   THREE-PER-EM SPACE */
517 { 0x0aa4, 0x2005 }, /* em4space   FOUR-PER-EM SPACE */
518 { 0x0aa5, 0x2007 }, /* digitspace   FIGURE SPACE */
519 { 0x0aa6, 0x2008 }, /* punctspace   PUNCTUATION SPACE */
520 { 0x0aa7, 0x2009 }, /* thinspace   THIN SPACE */
521 { 0x0aa8, 0x200a }, /* hairspace   HAIR SPACE */
522 { 0x0aa9, 0x2014 }, /* emdash — EM DASH */
523 { 0x0aaa, 0x2013 }, /* endash – EN DASH */
524/* 0x0aac signifblank ? ??? */
525 { 0x0aae, 0x2026 }, /* ellipsis … HORIZONTAL ELLIPSIS */
526 { 0x0aaf, 0x2025 }, /* doubbaselinedot ‥ TWO DOT LEADER */
527 { 0x0ab0, 0x2153 }, /* onethird ⅓ VULGAR FRACTION ONE THIRD */
528 { 0x0ab1, 0x2154 }, /* twothirds ⅔ VULGAR FRACTION TWO THIRDS */
529 { 0x0ab2, 0x2155 }, /* onefifth ⅕ VULGAR FRACTION ONE FIFTH */
530 { 0x0ab3, 0x2156 }, /* twofifths ⅖ VULGAR FRACTION TWO FIFTHS */
531 { 0x0ab4, 0x2157 }, /* threefifths ⅗ VULGAR FRACTION THREE FIFTHS */
532 { 0x0ab5, 0x2158 }, /* fourfifths ⅘ VULGAR FRACTION FOUR FIFTHS */
533 { 0x0ab6, 0x2159 }, /* onesixth ⅙ VULGAR FRACTION ONE SIXTH */
534 { 0x0ab7, 0x215a }, /* fivesixths ⅚ VULGAR FRACTION FIVE SIXTHS */
535 { 0x0ab8, 0x2105 }, /* careof ℅ CARE OF */
536 { 0x0abb, 0x2012 }, /* figdash ‒ FIGURE DASH */
537 { 0x0abc, 0x2329 }, /* leftanglebracket 〈 LEFT-POINTING ANGLE BRACKET */
538/* 0x0abd decimalpoint ? ??? */
539 { 0x0abe, 0x232a }, /* rightanglebracket 〉 RIGHT-POINTING ANGLE BRACKET */
540/* 0x0abf marker ? ??? */
541 { 0x0ac3, 0x215b }, /* oneeighth ⅛ VULGAR FRACTION ONE EIGHTH */
542 { 0x0ac4, 0x215c }, /* threeeighths ⅜ VULGAR FRACTION THREE EIGHTHS */
543 { 0x0ac5, 0x215d }, /* fiveeighths ⅝ VULGAR FRACTION FIVE EIGHTHS */
544 { 0x0ac6, 0x215e }, /* seveneighths ⅞ VULGAR FRACTION SEVEN EIGHTHS */
545 { 0x0ac9, 0x2122 }, /* trademark ™ TRADE MARK SIGN */
546 { 0x0aca, 0x2613 }, /* signaturemark ☓ SALTIRE */
547/* 0x0acb trademarkincircle ? ??? */
548 { 0x0acc, 0x25c1 }, /* leftopentriangle ◁ WHITE LEFT-POINTING TRIANGLE */
549 { 0x0acd, 0x25b7 }, /* rightopentriangle ▷ WHITE RIGHT-POINTING TRIANGLE */
550 { 0x0ace, 0x25cb }, /* emopencircle ○ WHITE CIRCLE */
551 { 0x0acf, 0x25af }, /* emopenrectangle ▯ WHITE VERTICAL RECTANGLE */
552 { 0x0ad0, 0x2018 }, /* leftsinglequotemark ‘ LEFT SINGLE QUOTATION MARK */
553 { 0x0ad1, 0x2019 }, /* rightsinglequotemark ’ RIGHT SINGLE QUOTATION MARK */
554 { 0x0ad2, 0x201c }, /* leftdoublequotemark “ LEFT DOUBLE QUOTATION MARK */
555 { 0x0ad3, 0x201d }, /* rightdoublequotemark ” RIGHT DOUBLE QUOTATION MARK */
556 { 0x0ad4, 0x211e }, /* prescription ℞ PRESCRIPTION TAKE */
557 { 0x0ad6, 0x2032 }, /* minutes ′ PRIME */
558 { 0x0ad7, 0x2033 }, /* seconds ″ DOUBLE PRIME */
559 { 0x0ad9, 0x271d }, /* latincross ✝ LATIN CROSS */
560/* 0x0ada hexagram ? ??? */
561 { 0x0adb, 0x25ac }, /* filledrectbullet ▬ BLACK RECTANGLE */
562 { 0x0adc, 0x25c0 }, /* filledlefttribullet ◀ BLACK LEFT-POINTING TRIANGLE */
563 { 0x0add, 0x25b6 }, /* filledrighttribullet ▶ BLACK RIGHT-POINTING TRIANGLE */
564 { 0x0ade, 0x25cf }, /* emfilledcircle ● BLACK CIRCLE */
565 { 0x0adf, 0x25ae }, /* emfilledrect ▮ BLACK VERTICAL RECTANGLE */
566 { 0x0ae0, 0x25e6 }, /* enopencircbullet ◦ WHITE BULLET */
567 { 0x0ae1, 0x25ab }, /* enopensquarebullet ▫ WHITE SMALL SQUARE */
568 { 0x0ae2, 0x25ad }, /* openrectbullet ▭ WHITE RECTANGLE */
569 { 0x0ae3, 0x25b3 }, /* opentribulletup △ WHITE UP-POINTING TRIANGLE */
570 { 0x0ae4, 0x25bd }, /* opentribulletdown ▽ WHITE DOWN-POINTING TRIANGLE */
571 { 0x0ae5, 0x2606 }, /* openstar ☆ WHITE STAR */
572 { 0x0ae6, 0x2022 }, /* enfilledcircbullet • BULLET */
573 { 0x0ae7, 0x25aa }, /* enfilledsqbullet ▪ BLACK SMALL SQUARE */
574 { 0x0ae8, 0x25b2 }, /* filledtribulletup ▲ BLACK UP-POINTING TRIANGLE */
575 { 0x0ae9, 0x25bc }, /* filledtribulletdown ▼ BLACK DOWN-POINTING TRIANGLE */
576 { 0x0aea, 0x261c }, /* leftpointer ☜ WHITE LEFT POINTING INDEX */
577 { 0x0aeb, 0x261e }, /* rightpointer ☞ WHITE RIGHT POINTING INDEX */
578 { 0x0aec, 0x2663 }, /* club ♣ BLACK CLUB SUIT */
579 { 0x0aed, 0x2666 }, /* diamond ♦ BLACK DIAMOND SUIT */
580 { 0x0aee, 0x2665 }, /* heart ♥ BLACK HEART SUIT */
581 { 0x0af0, 0x2720 }, /* maltesecross ✠ MALTESE CROSS */
582 { 0x0af1, 0x2020 }, /* dagger † DAGGER */
583 { 0x0af2, 0x2021 }, /* doubledagger ‡ DOUBLE DAGGER */
584 { 0x0af3, 0x2713 }, /* checkmark ✓ CHECK MARK */
585 { 0x0af4, 0x2717 }, /* ballotcross ✗ BALLOT X */
586 { 0x0af5, 0x266f }, /* musicalsharp ♯ MUSIC SHARP SIGN */
587 { 0x0af6, 0x266d }, /* musicalflat ♭ MUSIC FLAT SIGN */
588 { 0x0af7, 0x2642 }, /* malesymbol ♂ MALE SIGN */
589 { 0x0af8, 0x2640 }, /* femalesymbol ♀ FEMALE SIGN */
590 { 0x0af9, 0x260e }, /* telephone ☎ BLACK TELEPHONE */
591 { 0x0afa, 0x2315 }, /* telephonerecorder ⌕ TELEPHONE RECORDER */
592 { 0x0afb, 0x2117 }, /* phonographcopyright ℗ SOUND RECORDING COPYRIGHT */
593 { 0x0afc, 0x2038 }, /* caret ‸ CARET */
594 { 0x0afd, 0x201a }, /* singlelowquotemark ‚ SINGLE LOW-9 QUOTATION MARK */
595 { 0x0afe, 0x201e }, /* doublelowquotemark „ DOUBLE LOW-9 QUOTATION MARK */
596/* 0x0aff cursor ? ??? */
597 { 0x0ba3, 0x003c }, /* leftcaret < LESS-THAN SIGN */
598 { 0x0ba6, 0x003e }, /* rightcaret > GREATER-THAN SIGN */
599 { 0x0ba8, 0x2228 }, /* downcaret ∨ LOGICAL OR */
600 { 0x0ba9, 0x2227 }, /* upcaret ∧ LOGICAL AND */
601 { 0x0bc0, 0x00af }, /* overbar ¯ MACRON */
602 { 0x0bc2, 0x22a5 }, /* downtack ⊥ UP TACK */
603 { 0x0bc3, 0x2229 }, /* upshoe ∩ INTERSECTION */
604 { 0x0bc4, 0x230a }, /* downstile ⌊ LEFT FLOOR */
605 { 0x0bc6, 0x005f }, /* underbar _ LOW LINE */
606 { 0x0bca, 0x2218 }, /* jot ∘ RING OPERATOR */
607 { 0x0bcc, 0x2395 }, /* quad ⎕ APL FUNCTIONAL SYMBOL QUAD */
608 { 0x0bce, 0x22a4 }, /* uptack ⊤ DOWN TACK */
609 { 0x0bcf, 0x25cb }, /* circle ○ WHITE CIRCLE */
610 { 0x0bd3, 0x2308 }, /* upstile ⌈ LEFT CEILING */
611 { 0x0bd6, 0x222a }, /* downshoe ∪ UNION */
612 { 0x0bd8, 0x2283 }, /* rightshoe ⊃ SUPERSET OF */
613 { 0x0bda, 0x2282 }, /* leftshoe ⊂ SUBSET OF */
614 { 0x0bdc, 0x22a2 }, /* lefttack ⊢ RIGHT TACK */
615 { 0x0bfc, 0x22a3 }, /* righttack ⊣ LEFT TACK */
616 { 0x0cdf, 0x2017 }, /* hebrew_doublelowline ‗ DOUBLE LOW LINE */
617 { 0x0ce0, 0x05d0 }, /* hebrew_aleph א HEBREW LETTER ALEF */
618 { 0x0ce1, 0x05d1 }, /* hebrew_bet ב HEBREW LETTER BET */
619 { 0x0ce2, 0x05d2 }, /* hebrew_gimel ג HEBREW LETTER GIMEL */
620 { 0x0ce3, 0x05d3 }, /* hebrew_dalet ד HEBREW LETTER DALET */
621 { 0x0ce4, 0x05d4 }, /* hebrew_he ה HEBREW LETTER HE */
622 { 0x0ce5, 0x05d5 }, /* hebrew_waw ו HEBREW LETTER VAV */
623 { 0x0ce6, 0x05d6 }, /* hebrew_zain ז HEBREW LETTER ZAYIN */
624 { 0x0ce7, 0x05d7 }, /* hebrew_chet ח HEBREW LETTER HET */
625 { 0x0ce8, 0x05d8 }, /* hebrew_tet ט HEBREW LETTER TET */
626 { 0x0ce9, 0x05d9 }, /* hebrew_yod י HEBREW LETTER YOD */
627 { 0x0cea, 0x05da }, /* hebrew_finalkaph ך HEBREW LETTER FINAL KAF */
628 { 0x0ceb, 0x05db }, /* hebrew_kaph כ HEBREW LETTER KAF */
629 { 0x0cec, 0x05dc }, /* hebrew_lamed ל HEBREW LETTER LAMED */
630 { 0x0ced, 0x05dd }, /* hebrew_finalmem ם HEBREW LETTER FINAL MEM */
631 { 0x0cee, 0x05de }, /* hebrew_mem מ HEBREW LETTER MEM */
632 { 0x0cef, 0x05df }, /* hebrew_finalnun ן HEBREW LETTER FINAL NUN */
633 { 0x0cf0, 0x05e0 }, /* hebrew_nun נ HEBREW LETTER NUN */
634 { 0x0cf1, 0x05e1 }, /* hebrew_samech ס HEBREW LETTER SAMEKH */
635 { 0x0cf2, 0x05e2 }, /* hebrew_ayin ע HEBREW LETTER AYIN */
636 { 0x0cf3, 0x05e3 }, /* hebrew_finalpe ף HEBREW LETTER FINAL PE */
637 { 0x0cf4, 0x05e4 }, /* hebrew_pe פ HEBREW LETTER PE */
638 { 0x0cf5, 0x05e5 }, /* hebrew_finalzade ץ HEBREW LETTER FINAL TSADI */
639 { 0x0cf6, 0x05e6 }, /* hebrew_zade צ HEBREW LETTER TSADI */
640 { 0x0cf7, 0x05e7 }, /* hebrew_qoph ק HEBREW LETTER QOF */
641 { 0x0cf8, 0x05e8 }, /* hebrew_resh ר HEBREW LETTER RESH */
642 { 0x0cf9, 0x05e9 }, /* hebrew_shin ש HEBREW LETTER SHIN */
643 { 0x0cfa, 0x05ea }, /* hebrew_taw ת HEBREW LETTER TAV */
644 { 0x0da1, 0x0e01 }, /* Thai_kokai ก THAI CHARACTER KO KAI */
645 { 0x0da2, 0x0e02 }, /* Thai_khokhai ข THAI CHARACTER KHO KHAI */
646 { 0x0da3, 0x0e03 }, /* Thai_khokhuat ฃ THAI CHARACTER KHO KHUAT */
647 { 0x0da4, 0x0e04 }, /* Thai_khokhwai ค THAI CHARACTER KHO KHWAI */
648 { 0x0da5, 0x0e05 }, /* Thai_khokhon ฅ THAI CHARACTER KHO KHON */
649 { 0x0da6, 0x0e06 }, /* Thai_khorakhang ฆ THAI CHARACTER KHO RAKHANG */
650 { 0x0da7, 0x0e07 }, /* Thai_ngongu ง THAI CHARACTER NGO NGU */
651 { 0x0da8, 0x0e08 }, /* Thai_chochan จ THAI CHARACTER CHO CHAN */
652 { 0x0da9, 0x0e09 }, /* Thai_choching ฉ THAI CHARACTER CHO CHING */
653 { 0x0daa, 0x0e0a }, /* Thai_chochang ช THAI CHARACTER CHO CHANG */
654 { 0x0dab, 0x0e0b }, /* Thai_soso ซ THAI CHARACTER SO SO */
655 { 0x0dac, 0x0e0c }, /* Thai_chochoe ฌ THAI CHARACTER CHO CHOE */
656 { 0x0dad, 0x0e0d }, /* Thai_yoying ญ THAI CHARACTER YO YING */
657 { 0x0dae, 0x0e0e }, /* Thai_dochada ฎ THAI CHARACTER DO CHADA */
658 { 0x0daf, 0x0e0f }, /* Thai_topatak ฏ THAI CHARACTER TO PATAK */
659 { 0x0db0, 0x0e10 }, /* Thai_thothan ฐ THAI CHARACTER THO THAN */
660 { 0x0db1, 0x0e11 }, /* Thai_thonangmontho ฑ THAI CHARACTER THO NANGMONTHO */
661 { 0x0db2, 0x0e12 }, /* Thai_thophuthao ฒ THAI CHARACTER THO PHUTHAO */
662 { 0x0db3, 0x0e13 }, /* Thai_nonen ณ THAI CHARACTER NO NEN */
663 { 0x0db4, 0x0e14 }, /* Thai_dodek ด THAI CHARACTER DO DEK */
664 { 0x0db5, 0x0e15 }, /* Thai_totao ต THAI CHARACTER TO TAO */
665 { 0x0db6, 0x0e16 }, /* Thai_thothung ถ THAI CHARACTER THO THUNG */
666 { 0x0db7, 0x0e17 }, /* Thai_thothahan ท THAI CHARACTER THO THAHAN */
667 { 0x0db8, 0x0e18 }, /* Thai_thothong ธ THAI CHARACTER THO THONG */
668 { 0x0db9, 0x0e19 }, /* Thai_nonu น THAI CHARACTER NO NU */
669 { 0x0dba, 0x0e1a }, /* Thai_bobaimai บ THAI CHARACTER BO BAIMAI */
670 { 0x0dbb, 0x0e1b }, /* Thai_popla ป THAI CHARACTER PO PLA */
671 { 0x0dbc, 0x0e1c }, /* Thai_phophung ผ THAI CHARACTER PHO PHUNG */
672 { 0x0dbd, 0x0e1d }, /* Thai_fofa ฝ THAI CHARACTER FO FA */
673 { 0x0dbe, 0x0e1e }, /* Thai_phophan พ THAI CHARACTER PHO PHAN */
674 { 0x0dbf, 0x0e1f }, /* Thai_fofan ฟ THAI CHARACTER FO FAN */
675 { 0x0dc0, 0x0e20 }, /* Thai_phosamphao ภ THAI CHARACTER PHO SAMPHAO */
676 { 0x0dc1, 0x0e21 }, /* Thai_moma ม THAI CHARACTER MO MA */
677 { 0x0dc2, 0x0e22 }, /* Thai_yoyak ย THAI CHARACTER YO YAK */
678 { 0x0dc3, 0x0e23 }, /* Thai_rorua ร THAI CHARACTER RO RUA */
679 { 0x0dc4, 0x0e24 }, /* Thai_ru ฤ THAI CHARACTER RU */
680 { 0x0dc5, 0x0e25 }, /* Thai_loling ล THAI CHARACTER LO LING */
681 { 0x0dc6, 0x0e26 }, /* Thai_lu ฦ THAI CHARACTER LU */
682 { 0x0dc7, 0x0e27 }, /* Thai_wowaen ว THAI CHARACTER WO WAEN */
683 { 0x0dc8, 0x0e28 }, /* Thai_sosala ศ THAI CHARACTER SO SALA */
684 { 0x0dc9, 0x0e29 }, /* Thai_sorusi ษ THAI CHARACTER SO RUSI */
685 { 0x0dca, 0x0e2a }, /* Thai_sosua ส THAI CHARACTER SO SUA */
686 { 0x0dcb, 0x0e2b }, /* Thai_hohip ห THAI CHARACTER HO HIP */
687 { 0x0dcc, 0x0e2c }, /* Thai_lochula ฬ THAI CHARACTER LO CHULA */
688 { 0x0dcd, 0x0e2d }, /* Thai_oang อ THAI CHARACTER O ANG */
689 { 0x0dce, 0x0e2e }, /* Thai_honokhuk ฮ THAI CHARACTER HO NOKHUK */
690 { 0x0dcf, 0x0e2f }, /* Thai_paiyannoi ฯ THAI CHARACTER PAIYANNOI */
691 { 0x0dd0, 0x0e30 }, /* Thai_saraa ะ THAI CHARACTER SARA A */
692 { 0x0dd1, 0x0e31 }, /* Thai_maihanakat ั THAI CHARACTER MAI HAN-AKAT */
693 { 0x0dd2, 0x0e32 }, /* Thai_saraaa า THAI CHARACTER SARA AA */
694 { 0x0dd3, 0x0e33 }, /* Thai_saraam ำ THAI CHARACTER SARA AM */
695 { 0x0dd4, 0x0e34 }, /* Thai_sarai ิ THAI CHARACTER SARA I */
696 { 0x0dd5, 0x0e35 }, /* Thai_saraii ี THAI CHARACTER SARA II */
697 { 0x0dd6, 0x0e36 }, /* Thai_saraue ึ THAI CHARACTER SARA UE */
698 { 0x0dd7, 0x0e37 }, /* Thai_sarauee ื THAI CHARACTER SARA UEE */
699 { 0x0dd8, 0x0e38 }, /* Thai_sarau ุ THAI CHARACTER SARA U */
700 { 0x0dd9, 0x0e39 }, /* Thai_sarauu ู THAI CHARACTER SARA UU */
701 { 0x0dda, 0x0e3a }, /* Thai_phinthu ฺ THAI CHARACTER PHINTHU */
702/* 0x0dde Thai_maihanakat_maitho ? ??? */
703 { 0x0ddf, 0x0e3f }, /* Thai_baht ฿ THAI CURRENCY SYMBOL BAHT */
704 { 0x0de0, 0x0e40 }, /* Thai_sarae เ THAI CHARACTER SARA E */
705 { 0x0de1, 0x0e41 }, /* Thai_saraae แ THAI CHARACTER SARA AE */
706 { 0x0de2, 0x0e42 }, /* Thai_sarao โ THAI CHARACTER SARA O */
707 { 0x0de3, 0x0e43 }, /* Thai_saraaimaimuan ใ THAI CHARACTER SARA AI MAIMUAN */
708 { 0x0de4, 0x0e44 }, /* Thai_saraaimaimalai ไ THAI CHARACTER SARA AI MAIMALAI */
709 { 0x0de5, 0x0e45 }, /* Thai_lakkhangyao ๅ THAI CHARACTER LAKKHANGYAO */
710 { 0x0de6, 0x0e46 }, /* Thai_maiyamok ๆ THAI CHARACTER MAIYAMOK */
711 { 0x0de7, 0x0e47 }, /* Thai_maitaikhu ็ THAI CHARACTER MAITAIKHU */
712 { 0x0de8, 0x0e48 }, /* Thai_maiek ่ THAI CHARACTER MAI EK */
713 { 0x0de9, 0x0e49 }, /* Thai_maitho ้ THAI CHARACTER MAI THO */
714 { 0x0dea, 0x0e4a }, /* Thai_maitri ๊ THAI CHARACTER MAI TRI */
715 { 0x0deb, 0x0e4b }, /* Thai_maichattawa ๋ THAI CHARACTER MAI CHATTAWA */
716 { 0x0dec, 0x0e4c }, /* Thai_thanthakhat ์ THAI CHARACTER THANTHAKHAT */
717 { 0x0ded, 0x0e4d }, /* Thai_nikhahit ํ THAI CHARACTER NIKHAHIT */
718 { 0x0df0, 0x0e50 }, /* Thai_leksun ๐ THAI DIGIT ZERO */
719 { 0x0df1, 0x0e51 }, /* Thai_leknung ๑ THAI DIGIT ONE */
720 { 0x0df2, 0x0e52 }, /* Thai_leksong ๒ THAI DIGIT TWO */
721 { 0x0df3, 0x0e53 }, /* Thai_leksam ๓ THAI DIGIT THREE */
722 { 0x0df4, 0x0e54 }, /* Thai_leksi ๔ THAI DIGIT FOUR */
723 { 0x0df5, 0x0e55 }, /* Thai_lekha ๕ THAI DIGIT FIVE */
724 { 0x0df6, 0x0e56 }, /* Thai_lekhok ๖ THAI DIGIT SIX */
725 { 0x0df7, 0x0e57 }, /* Thai_lekchet ๗ THAI DIGIT SEVEN */
726 { 0x0df8, 0x0e58 }, /* Thai_lekpaet ๘ THAI DIGIT EIGHT */
727 { 0x0df9, 0x0e59 }, /* Thai_lekkao ๙ THAI DIGIT NINE */
728 { 0x0ea1, 0x3131 }, /* Hangul_Kiyeog ㄱ HANGUL LETTER KIYEOK */
729 { 0x0ea2, 0x3132 }, /* Hangul_SsangKiyeog ㄲ HANGUL LETTER SSANGKIYEOK */
730 { 0x0ea3, 0x3133 }, /* Hangul_KiyeogSios ㄳ HANGUL LETTER KIYEOK-SIOS */
731 { 0x0ea4, 0x3134 }, /* Hangul_Nieun ㄴ HANGUL LETTER NIEUN */
732 { 0x0ea5, 0x3135 }, /* Hangul_NieunJieuj ㄵ HANGUL LETTER NIEUN-CIEUC */
733 { 0x0ea6, 0x3136 }, /* Hangul_NieunHieuh ㄶ HANGUL LETTER NIEUN-HIEUH */
734 { 0x0ea7, 0x3137 }, /* Hangul_Dikeud ㄷ HANGUL LETTER TIKEUT */
735 { 0x0ea8, 0x3138 }, /* Hangul_SsangDikeud ㄸ HANGUL LETTER SSANGTIKEUT */
736 { 0x0ea9, 0x3139 }, /* Hangul_Rieul ㄹ HANGUL LETTER RIEUL */
737 { 0x0eaa, 0x313a }, /* Hangul_RieulKiyeog ㄺ HANGUL LETTER RIEUL-KIYEOK */
738 { 0x0eab, 0x313b }, /* Hangul_RieulMieum ㄻ HANGUL LETTER RIEUL-MIEUM */
739 { 0x0eac, 0x313c }, /* Hangul_RieulPieub ㄼ HANGUL LETTER RIEUL-PIEUP */
740 { 0x0ead, 0x313d }, /* Hangul_RieulSios ㄽ HANGUL LETTER RIEUL-SIOS */
741 { 0x0eae, 0x313e }, /* Hangul_RieulTieut ㄾ HANGUL LETTER RIEUL-THIEUTH */
742 { 0x0eaf, 0x313f }, /* Hangul_RieulPhieuf ㄿ HANGUL LETTER RIEUL-PHIEUPH */
743 { 0x0eb0, 0x3140 }, /* Hangul_RieulHieuh ㅀ HANGUL LETTER RIEUL-HIEUH */
744 { 0x0eb1, 0x3141 }, /* Hangul_Mieum ㅁ HANGUL LETTER MIEUM */
745 { 0x0eb2, 0x3142 }, /* Hangul_Pieub ㅂ HANGUL LETTER PIEUP */
746 { 0x0eb3, 0x3143 }, /* Hangul_SsangPieub ㅃ HANGUL LETTER SSANGPIEUP */
747 { 0x0eb4, 0x3144 }, /* Hangul_PieubSios ㅄ HANGUL LETTER PIEUP-SIOS */
748 { 0x0eb5, 0x3145 }, /* Hangul_Sios ㅅ HANGUL LETTER SIOS */
749 { 0x0eb6, 0x3146 }, /* Hangul_SsangSios ㅆ HANGUL LETTER SSANGSIOS */
750 { 0x0eb7, 0x3147 }, /* Hangul_Ieung ㅇ HANGUL LETTER IEUNG */
751 { 0x0eb8, 0x3148 }, /* Hangul_Jieuj ㅈ HANGUL LETTER CIEUC */
752 { 0x0eb9, 0x3149 }, /* Hangul_SsangJieuj ㅉ HANGUL LETTER SSANGCIEUC */
753 { 0x0eba, 0x314a }, /* Hangul_Cieuc ㅊ HANGUL LETTER CHIEUCH */
754 { 0x0ebb, 0x314b }, /* Hangul_Khieuq ㅋ HANGUL LETTER KHIEUKH */
755 { 0x0ebc, 0x314c }, /* Hangul_Tieut ㅌ HANGUL LETTER THIEUTH */
756 { 0x0ebd, 0x314d }, /* Hangul_Phieuf ㅍ HANGUL LETTER PHIEUPH */
757 { 0x0ebe, 0x314e }, /* Hangul_Hieuh ㅎ HANGUL LETTER HIEUH */
758 { 0x0ebf, 0x314f }, /* Hangul_A ㅏ HANGUL LETTER A */
759 { 0x0ec0, 0x3150 }, /* Hangul_AE ㅐ HANGUL LETTER AE */
760 { 0x0ec1, 0x3151 }, /* Hangul_YA ㅑ HANGUL LETTER YA */
761 { 0x0ec2, 0x3152 }, /* Hangul_YAE ㅒ HANGUL LETTER YAE */
762 { 0x0ec3, 0x3153 }, /* Hangul_EO ㅓ HANGUL LETTER EO */
763 { 0x0ec4, 0x3154 }, /* Hangul_E ㅔ HANGUL LETTER E */
764 { 0x0ec5, 0x3155 }, /* Hangul_YEO ㅕ HANGUL LETTER YEO */
765 { 0x0ec6, 0x3156 }, /* Hangul_YE ㅖ HANGUL LETTER YE */
766 { 0x0ec7, 0x3157 }, /* Hangul_O ㅗ HANGUL LETTER O */
767 { 0x0ec8, 0x3158 }, /* Hangul_WA ㅘ HANGUL LETTER WA */
768 { 0x0ec9, 0x3159 }, /* Hangul_WAE ㅙ HANGUL LETTER WAE */
769 { 0x0eca, 0x315a }, /* Hangul_OE ㅚ HANGUL LETTER OE */
770 { 0x0ecb, 0x315b }, /* Hangul_YO ㅛ HANGUL LETTER YO */
771 { 0x0ecc, 0x315c }, /* Hangul_U ㅜ HANGUL LETTER U */
772 { 0x0ecd, 0x315d }, /* Hangul_WEO ㅝ HANGUL LETTER WEO */
773 { 0x0ece, 0x315e }, /* Hangul_WE ㅞ HANGUL LETTER WE */
774 { 0x0ecf, 0x315f }, /* Hangul_WI ㅟ HANGUL LETTER WI */
775 { 0x0ed0, 0x3160 }, /* Hangul_YU ㅠ HANGUL LETTER YU */
776 { 0x0ed1, 0x3161 }, /* Hangul_EU ㅡ HANGUL LETTER EU */
777 { 0x0ed2, 0x3162 }, /* Hangul_YI ㅢ HANGUL LETTER YI */
778 { 0x0ed3, 0x3163 }, /* Hangul_I ㅣ HANGUL LETTER I */
779 { 0x0ed4, 0x11a8 }, /* Hangul_J_Kiyeog ᆨ HANGUL JONGSEONG KIYEOK */
780 { 0x0ed5, 0x11a9 }, /* Hangul_J_SsangKiyeog ᆩ HANGUL JONGSEONG SSANGKIYEOK */
781 { 0x0ed6, 0x11aa }, /* Hangul_J_KiyeogSios ᆪ HANGUL JONGSEONG KIYEOK-SIOS */
782 { 0x0ed7, 0x11ab }, /* Hangul_J_Nieun ᆫ HANGUL JONGSEONG NIEUN */
783 { 0x0ed8, 0x11ac }, /* Hangul_J_NieunJieuj ᆬ HANGUL JONGSEONG NIEUN-CIEUC */
784 { 0x0ed9, 0x11ad }, /* Hangul_J_NieunHieuh ᆭ HANGUL JONGSEONG NIEUN-HIEUH */
785 { 0x0eda, 0x11ae }, /* Hangul_J_Dikeud ᆮ HANGUL JONGSEONG TIKEUT */
786 { 0x0edb, 0x11af }, /* Hangul_J_Rieul ᆯ HANGUL JONGSEONG RIEUL */
787 { 0x0edc, 0x11b0 }, /* Hangul_J_RieulKiyeog ᆰ HANGUL JONGSEONG RIEUL-KIYEOK */
788 { 0x0edd, 0x11b1 }, /* Hangul_J_RieulMieum ᆱ HANGUL JONGSEONG RIEUL-MIEUM */
789 { 0x0ede, 0x11b2 }, /* Hangul_J_RieulPieub ᆲ HANGUL JONGSEONG RIEUL-PIEUP */
790 { 0x0edf, 0x11b3 }, /* Hangul_J_RieulSios ᆳ HANGUL JONGSEONG RIEUL-SIOS */
791 { 0x0ee0, 0x11b4 }, /* Hangul_J_RieulTieut ᆴ HANGUL JONGSEONG RIEUL-THIEUTH */
792 { 0x0ee1, 0x11b5 }, /* Hangul_J_RieulPhieuf ᆵ HANGUL JONGSEONG RIEUL-PHIEUPH */
793 { 0x0ee2, 0x11b6 }, /* Hangul_J_RieulHieuh ᆶ HANGUL JONGSEONG RIEUL-HIEUH */
794 { 0x0ee3, 0x11b7 }, /* Hangul_J_Mieum ᆷ HANGUL JONGSEONG MIEUM */
795 { 0x0ee4, 0x11b8 }, /* Hangul_J_Pieub ᆸ HANGUL JONGSEONG PIEUP */
796 { 0x0ee5, 0x11b9 }, /* Hangul_J_PieubSios ᆹ HANGUL JONGSEONG PIEUP-SIOS */
797 { 0x0ee6, 0x11ba }, /* Hangul_J_Sios ᆺ HANGUL JONGSEONG SIOS */
798 { 0x0ee7, 0x11bb }, /* Hangul_J_SsangSios ᆻ HANGUL JONGSEONG SSANGSIOS */
799 { 0x0ee8, 0x11bc }, /* Hangul_J_Ieung ᆼ HANGUL JONGSEONG IEUNG */
800 { 0x0ee9, 0x11bd }, /* Hangul_J_Jieuj ᆽ HANGUL JONGSEONG CIEUC */
801 { 0x0eea, 0x11be }, /* Hangul_J_Cieuc ᆾ HANGUL JONGSEONG CHIEUCH */
802 { 0x0eeb, 0x11bf }, /* Hangul_J_Khieuq ᆿ HANGUL JONGSEONG KHIEUKH */
803 { 0x0eec, 0x11c0 }, /* Hangul_J_Tieut ᇀ HANGUL JONGSEONG THIEUTH */
804 { 0x0eed, 0x11c1 }, /* Hangul_J_Phieuf ᇁ HANGUL JONGSEONG PHIEUPH */
805 { 0x0eee, 0x11c2 }, /* Hangul_J_Hieuh ᇂ HANGUL JONGSEONG HIEUH */
806 { 0x0eef, 0x316d }, /* Hangul_RieulYeorinHieuh ㅭ HANGUL LETTER RIEUL-YEORINHIEUH */
807 { 0x0ef0, 0x3171 }, /* Hangul_SunkyeongeumMieum ㅱ HANGUL LETTER KAPYEOUNMIEUM */
808 { 0x0ef1, 0x3178 }, /* Hangul_SunkyeongeumPieub ㅸ HANGUL LETTER KAPYEOUNPIEUP */
809 { 0x0ef2, 0x317f }, /* Hangul_PanSios ㅿ HANGUL LETTER PANSIOS */
810 { 0x0ef3, 0x3181 }, /* Hangul_KkogjiDalrinIeung ㆁ HANGUL LETTER YESIEUNG */
811 { 0x0ef4, 0x3184 }, /* Hangul_SunkyeongeumPhieuf ㆄ HANGUL LETTER KAPYEOUNPHIEUPH */
812 { 0x0ef5, 0x3186 }, /* Hangul_YeorinHieuh ㆆ HANGUL LETTER YEORINHIEUH */
813 { 0x0ef6, 0x318d }, /* Hangul_AraeA ㆍ HANGUL LETTER ARAEA */
814 { 0x0ef7, 0x318e }, /* Hangul_AraeAE ㆎ HANGUL LETTER ARAEAE */
815 { 0x0ef8, 0x11eb }, /* Hangul_J_PanSios ᇫ HANGUL JONGSEONG PANSIOS */
816 { 0x0ef9, 0x11f0 }, /* Hangul_J_KkogjiDalrinIeung ᇰ HANGUL JONGSEONG YESIEUNG */
817 { 0x0efa, 0x11f9 }, /* Hangul_J_YeorinHieuh ᇹ HANGUL JONGSEONG YEORINHIEUH */
818 { 0x0eff, 0x20a9 }, /* Korean_Won ₩ WON SIGN */
819 { 0x13a4, 0x20ac }, /* Euro € EURO SIGN */
820 { 0x13bc, 0x0152 }, /* OE Œ LATIN CAPITAL LIGATURE OE */
821 { 0x13bd, 0x0153 }, /* oe œ LATIN SMALL LIGATURE OE */
822 { 0x13be, 0x0178 }, /* Ydiaeresis Ÿ LATIN CAPITAL LETTER Y WITH DIAERESIS */
823 { 0x20ac, 0x20ac }, /* EuroSign € EURO SIGN */
824};
825
826VISIBLE
827long keysym2ucs(KeySym keysym)
828{
829 int min = 0;
830 int max = sizeof(keysymtab) / sizeof(struct codepair) - 1;
831 int mid;
832
833 /* first check for Latin-1 characters (1:1 mapping) */
834 if ((keysym >= 0x0020 && keysym <= 0x007e) ||
835 (keysym >= 0x00a0 && keysym <= 0x00ff))
836 return keysym;
837
838 /* also check for directly encoded 24-bit UCS characters */
839 if ((keysym & 0xff000000) == 0x01000000)
840 return keysym & 0x00ffffff;
841
842 /* binary search in table */
843 while (max >= min) {
844 mid = (min + max) / 2;
845 if (keysymtab[mid].keysym < keysym)
846 min = mid + 1;
847 else if (keysymtab[mid].keysym > keysym)
848 max = mid - 1;
849 else {
850 /* found it */
851 return keysymtab[mid].ucs;
852 }
853 }
854
855 /* no matching Unicode value found */
856 return -1;
857}
gui-x11/keysym2ucs.h+9−0
@@ -0,0 +1,9 @@
1/* $XFree86: xc/programs/xterm/keysym2ucs.h,v 1.1 1999/06/12 15:37:18 dawes Exp $ */
2/*
3 * This module converts keysym values into the corresponding ISO 10646-1
4 * (UCS, Unicode) values.
5 */
6
7#include <X11/X.h>
8
9long keysym2ucs(KeySym keysym);
gui-x11/ksym2utf.h+754−0
@@ -0,0 +1,754 @@
1static ulong
2ksym2utf[] = {
3 [0x01a1] 0x0104,
4 [0x01a2] 0x02d8,
5 [0x01a3] 0x0141,
6 [0x01a5] 0x013d,
7 [0x01a6] 0x015a,
8 [0x01a9] 0x0160,
9 [0x01aa] 0x015e,
10 [0x01ab] 0x0164,
11 [0x01ac] 0x0179,
12 [0x01ae] 0x017d,
13 [0x01af] 0x017b,
14 [0x01b1] 0x0105,
15 [0x01b2] 0x02db,
16 [0x01b3] 0x0142,
17 [0x01b5] 0x013e,
18 [0x01b6] 0x015b,
19 [0x01b7] 0x02c7,
20 [0x01b9] 0x0161,
21 [0x01ba] 0x015f,
22 [0x01bb] 0x0165,
23 [0x01bc] 0x017a,
24 [0x01bd] 0x02dd,
25 [0x01be] 0x017e,
26 [0x01bf] 0x017c,
27 [0x01c0] 0x0154,
28 [0x01c3] 0x0102,
29 [0x01c5] 0x0139,
30 [0x01c6] 0x0106,
31 [0x01c8] 0x010c,
32 [0x01ca] 0x0118,
33 [0x01cc] 0x011a,
34 [0x01cf] 0x010e,
35 [0x01d0] 0x0110,
36 [0x01d1] 0x0143,
37 [0x01d2] 0x0147,
38 [0x01d5] 0x0150,
39 [0x01d8] 0x0158,
40 [0x01d9] 0x016e,
41 [0x01db] 0x0170,
42 [0x01de] 0x0162,
43 [0x01e0] 0x0155,
44 [0x01e3] 0x0103,
45 [0x01e5] 0x013a,
46 [0x01e6] 0x0107,
47 [0x01e8] 0x010d,
48 [0x01ea] 0x0119,
49 [0x01ec] 0x011b,
50 [0x01ef] 0x010f,
51 [0x01f0] 0x0111,
52 [0x01f1] 0x0144,
53 [0x01f2] 0x0148,
54 [0x01f5] 0x0151,
55 [0x01f8] 0x0159,
56 [0x01f9] 0x016f,
57 [0x01fb] 0x0171,
58 [0x01fe] 0x0163,
59 [0x01ff] 0x02d9,
60 [0x02a1] 0x0126,
61 [0x02a6] 0x0124,
62 [0x02a9] 0x0130,
63 [0x02ab] 0x011e,
64 [0x02ac] 0x0134,
65 [0x02b1] 0x0127,
66 [0x02b6] 0x0125,
67 [0x02b9] 0x0131,
68 [0x02bb] 0x011f,
69 [0x02bc] 0x0135,
70 [0x02c5] 0x010a,
71 [0x02c6] 0x0108,
72 [0x02d5] 0x0120,
73 [0x02d8] 0x011c,
74 [0x02dd] 0x016c,
75 [0x02de] 0x015c,
76 [0x02e5] 0x010b,
77 [0x02e6] 0x0109,
78 [0x02f5] 0x0121,
79 [0x02f8] 0x011d,
80 [0x02fd] 0x016d,
81 [0x02fe] 0x015d,
82 [0x03a2] 0x0138,
83 [0x03a3] 0x0156,
84 [0x03a5] 0x0128,
85 [0x03a6] 0x013b,
86 [0x03aa] 0x0112,
87 [0x03ab] 0x0122,
88 [0x03ac] 0x0166,
89 [0x03b3] 0x0157,
90 [0x03b5] 0x0129,
91 [0x03b6] 0x013c,
92 [0x03ba] 0x0113,
93 [0x03bb] 0x0123,
94 [0x03bc] 0x0167,
95 [0x03bd] 0x014a,
96 [0x03bf] 0x014b,
97 [0x03c0] 0x0100,
98 [0x03c7] 0x012e,
99 [0x03cc] 0x0116,
100 [0x03cf] 0x012a,
101 [0x03d1] 0x0145,
102 [0x03d2] 0x014c,
103 [0x03d3] 0x0136,
104 [0x03d9] 0x0172,
105 [0x03dd] 0x0168,
106 [0x03de] 0x016a,
107 [0x03e0] 0x0101,
108 [0x03e7] 0x012f,
109 [0x03ec] 0x0117,
110 [0x03ef] 0x012b,
111 [0x03f1] 0x0146,
112 [0x03f2] 0x014d,
113 [0x03f3] 0x0137,
114 [0x03f9] 0x0173,
115 [0x03fd] 0x0169,
116 [0x03fe] 0x016b,
117 [0x047e] 0x203e,
118 [0x04a1] 0x3002,
119 [0x04a2] 0x300c,
120 [0x04a3] 0x300d,
121 [0x04a4] 0x3001,
122 [0x04a5] 0x30fb,
123 [0x04a6] 0x30f2,
124 [0x04a7] 0x30a1,
125 [0x04a8] 0x30a3,
126 [0x04a9] 0x30a5,
127 [0x04aa] 0x30a7,
128 [0x04ab] 0x30a9,
129 [0x04ac] 0x30e3,
130 [0x04ad] 0x30e5,
131 [0x04ae] 0x30e7,
132 [0x04af] 0x30c3,
133 [0x04b0] 0x30fc,
134 [0x04b1] 0x30a2,
135 [0x04b2] 0x30a4,
136 [0x04b3] 0x30a6,
137 [0x04b4] 0x30a8,
138 [0x04b5] 0x30aa,
139 [0x04b6] 0x30ab,
140 [0x04b7] 0x30ad,
141 [0x04b8] 0x30af,
142 [0x04b9] 0x30b1,
143 [0x04ba] 0x30b3,
144 [0x04bb] 0x30b5,
145 [0x04bc] 0x30b7,
146 [0x04bd] 0x30b9,
147 [0x04be] 0x30bb,
148 [0x04bf] 0x30bd,
149 [0x04c0] 0x30bf,
150 [0x04c1] 0x30c1,
151 [0x04c2] 0x30c4,
152 [0x04c3] 0x30c6,
153 [0x04c4] 0x30c8,
154 [0x04c5] 0x30ca,
155 [0x04c6] 0x30cb,
156 [0x04c7] 0x30cc,
157 [0x04c8] 0x30cd,
158 [0x04c9] 0x30ce,
159 [0x04ca] 0x30cf,
160 [0x04cb] 0x30d2,
161 [0x04cc] 0x30d5,
162 [0x04cd] 0x30d8,
163 [0x04ce] 0x30db,
164 [0x04cf] 0x30de,
165 [0x04d0] 0x30df,
166 [0x04d1] 0x30e0,
167 [0x04d2] 0x30e1,
168 [0x04d3] 0x30e2,
169 [0x04d4] 0x30e4,
170 [0x04d5] 0x30e6,
171 [0x04d6] 0x30e8,
172 [0x04d7] 0x30e9,
173 [0x04d8] 0x30ea,
174 [0x04d9] 0x30eb,
175 [0x04da] 0x30ec,
176 [0x04db] 0x30ed,
177 [0x04dc] 0x30ef,
178 [0x04dd] 0x30f3,
179 [0x04de] 0x309b,
180 [0x04df] 0x309c,
181 [0x05ac] 0x060c,
182 [0x05bb] 0x061b,
183 [0x05bf] 0x061f,
184 [0x05c1] 0x0621,
185 [0x05c2] 0x0622,
186 [0x05c3] 0x0623,
187 [0x05c4] 0x0624,
188 [0x05c5] 0x0625,
189 [0x05c6] 0x0626,
190 [0x05c7] 0x0627,
191 [0x05c8] 0x0628,
192 [0x05c9] 0x0629,
193 [0x05ca] 0x062a,
194 [0x05cb] 0x062b,
195 [0x05cc] 0x062c,
196 [0x05cd] 0x062d,
197 [0x05ce] 0x062e,
198 [0x05cf] 0x062f,
199 [0x05d0] 0x0630,
200 [0x05d1] 0x0631,
201 [0x05d2] 0x0632,
202 [0x05d3] 0x0633,
203 [0x05d4] 0x0634,
204 [0x05d5] 0x0635,
205 [0x05d6] 0x0636,
206 [0x05d7] 0x0637,
207 [0x05d8] 0x0638,
208 [0x05d9] 0x0639,
209 [0x05da] 0x063a,
210 [0x05e0] 0x0640,
211 [0x05e1] 0x0641,
212 [0x05e2] 0x0642,
213 [0x05e3] 0x0643,
214 [0x05e4] 0x0644,
215 [0x05e5] 0x0645,
216 [0x05e6] 0x0646,
217 [0x05e7] 0x0647,
218 [0x05e8] 0x0648,
219 [0x05e9] 0x0649,
220 [0x05ea] 0x064a,
221 [0x05eb] 0x064b,
222 [0x05ec] 0x064c,
223 [0x05ed] 0x064d,
224 [0x05ee] 0x064e,
225 [0x05ef] 0x064f,
226 [0x05f0] 0x0650,
227 [0x05f1] 0x0651,
228 [0x05f2] 0x0652,
229 [0x06a1] 0x0452,
230 [0x06a2] 0x0453,
231 [0x06a3] 0x0451,
232 [0x06a4] 0x0454,
233 [0x06a5] 0x0455,
234 [0x06a6] 0x0456,
235 [0x06a7] 0x0457,
236 [0x06a8] 0x0458,
237 [0x06a9] 0x0459,
238 [0x06aa] 0x045a,
239 [0x06ab] 0x045b,
240 [0x06ac] 0x045c,
241 [0x06ae] 0x045e,
242 [0x06af] 0x045f,
243 [0x06b0] 0x2116,
244 [0x06b1] 0x0402,
245 [0x06b2] 0x0403,
246 [0x06b3] 0x0401,
247 [0x06b4] 0x0404,
248 [0x06b5] 0x0405,
249 [0x06b6] 0x0406,
250 [0x06b7] 0x0407,
251 [0x06b8] 0x0408,
252 [0x06b9] 0x0409,
253 [0x06ba] 0x040a,
254 [0x06bb] 0x040b,
255 [0x06bc] 0x040c,
256 [0x06be] 0x040e,
257 [0x06bf] 0x040f,
258 [0x06c0] 0x044e,
259 [0x06c1] 0x0430,
260 [0x06c2] 0x0431,
261 [0x06c3] 0x0446,
262 [0x06c4] 0x0434,
263 [0x06c5] 0x0435,
264 [0x06c6] 0x0444,
265 [0x06c7] 0x0433,
266 [0x06c8] 0x0445,
267 [0x06c9] 0x0438,
268 [0x06ca] 0x0439,
269 [0x06cb] 0x043a,
270 [0x06cc] 0x043b,
271 [0x06cd] 0x043c,
272 [0x06ce] 0x043d,
273 [0x06cf] 0x043e,
274 [0x06d0] 0x043f,
275 [0x06d1] 0x044f,
276 [0x06d2] 0x0440,
277 [0x06d3] 0x0441,
278 [0x06d4] 0x0442,
279 [0x06d5] 0x0443,
280 [0x06d6] 0x0436,
281 [0x06d7] 0x0432,
282 [0x06d8] 0x044c,
283 [0x06d9] 0x044b,
284 [0x06da] 0x0437,
285 [0x06db] 0x0448,
286 [0x06dc] 0x044d,
287 [0x06dd] 0x0449,
288 [0x06de] 0x0447,
289 [0x06df] 0x044a,
290 [0x06e0] 0x042e,
291 [0x06e1] 0x0410,
292 [0x06e2] 0x0411,
293 [0x06e3] 0x0426,
294 [0x06e4] 0x0414,
295 [0x06e5] 0x0415,
296 [0x06e6] 0x0424,
297 [0x06e7] 0x0413,
298 [0x06e8] 0x0425,
299 [0x06e9] 0x0418,
300 [0x06ea] 0x0419,
301 [0x06eb] 0x041a,
302 [0x06ec] 0x041b,
303 [0x06ed] 0x041c,
304 [0x06ee] 0x041d,
305 [0x06ef] 0x041e,
306 [0x06f0] 0x041f,
307 [0x06f1] 0x042f,
308 [0x06f2] 0x0420,
309 [0x06f3] 0x0421,
310 [0x06f4] 0x0422,
311 [0x06f5] 0x0423,
312 [0x06f6] 0x0416,
313 [0x06f7] 0x0412,
314 [0x06f8] 0x042c,
315 [0x06f9] 0x042b,
316 [0x06fa] 0x0417,
317 [0x06fb] 0x0428,
318 [0x06fc] 0x042d,
319 [0x06fd] 0x0429,
320 [0x06fe] 0x0427,
321 [0x06ff] 0x042a,
322 [0x07a1] 0x0386,
323 [0x07a2] 0x0388,
324 [0x07a3] 0x0389,
325 [0x07a4] 0x038a,
326 [0x07a5] 0x03aa,
327 [0x07a7] 0x038c,
328 [0x07a8] 0x038e,
329 [0x07a9] 0x03ab,
330 [0x07ab] 0x038f,
331 [0x07ae] 0x0385,
332 [0x07af] 0x2015,
333 [0x07b1] 0x03ac,
334 [0x07b2] 0x03ad,
335 [0x07b3] 0x03ae,
336 [0x07b4] 0x03af,
337 [0x07b5] 0x03ca,
338 [0x07b6] 0x0390,
339 [0x07b7] 0x03cc,
340 [0x07b8] 0x03cd,
341 [0x07b9] 0x03cb,
342 [0x07ba] 0x03b0,
343 [0x07bb] 0x03ce,
344 [0x07c1] 0x0391,
345 [0x07c2] 0x0392,
346 [0x07c3] 0x0393,
347 [0x07c4] 0x0394,
348 [0x07c5] 0x0395,
349 [0x07c6] 0x0396,
350 [0x07c7] 0x0397,
351 [0x07c8] 0x0398,
352 [0x07c9] 0x0399,
353 [0x07ca] 0x039a,
354 [0x07cb] 0x039b,
355 [0x07cc] 0x039c,
356 [0x07cd] 0x039d,
357 [0x07ce] 0x039e,
358 [0x07cf] 0x039f,
359 [0x07d0] 0x03a0,
360 [0x07d1] 0x03a1,
361 [0x07d2] 0x03a3,
362 [0x07d4] 0x03a4,
363 [0x07d5] 0x03a5,
364 [0x07d6] 0x03a6,
365 [0x07d7] 0x03a7,
366 [0x07d8] 0x03a8,
367 [0x07d9] 0x03a9,
368 [0x07e1] 0x03b1,
369 [0x07e2] 0x03b2,
370 [0x07e3] 0x03b3,
371 [0x07e4] 0x03b4,
372 [0x07e5] 0x03b5,
373 [0x07e6] 0x03b6,
374 [0x07e7] 0x03b7,
375 [0x07e8] 0x03b8,
376 [0x07e9] 0x03b9,
377 [0x07ea] 0x03ba,
378 [0x07eb] 0x03bb,
379 [0x07ec] 0x03bc,
380 [0x07ed] 0x03bd,
381 [0x07ee] 0x03be,
382 [0x07ef] 0x03bf,
383 [0x07f0] 0x03c0,
384 [0x07f1] 0x03c1,
385 [0x07f2] 0x03c3,
386 [0x07f3] 0x03c2,
387 [0x07f4] 0x03c4,
388 [0x07f5] 0x03c5,
389 [0x07f6] 0x03c6,
390 [0x07f7] 0x03c7,
391 [0x07f8] 0x03c8,
392 [0x07f9] 0x03c9,
393 [0x08a4] 0x2320,
394 [0x08a5] 0x2321,
395 [0x08a6] 0x2502,
396 [0x08bc] 0x2264,
397 [0x08bd] 0x2260,
398 [0x08be] 0x2265,
399 [0x08bf] 0x222b,
400 [0x08c0] 0x2234,
401 [0x08c1] 0x221d,
402 [0x08c2] 0x221e,
403 [0x08c5] 0x2207,
404 [0x08c8] 0x2245,
405 [0x08cd] 0x21d4,
406 [0x08ce] 0x21d2,
407 [0x08cf] 0x2261,
408 [0x08d6] 0x221a,
409 [0x08da] 0x2282,
410 [0x08db] 0x2283,
411 [0x08dc] 0x2229,
412 [0x08dd] 0x222a,
413 [0x08de] 0x2227,
414 [0x08df] 0x2228,
415 [0x08ef] 0x2202,
416 [0x08f6] 0x0192,
417 [0x08fb] 0x2190,
418 [0x08fc] 0x2191,
419 [0x08fd] 0x2192,
420 [0x08fe] 0x2193,
421 [0x09df] 0x2422,
422 [0x09e0] 0x25c6,
423 [0x09e1] 0x2592,
424 [0x09e2] 0x2409,
425 [0x09e3] 0x240c,
426 [0x09e4] 0x240d,
427 [0x09e5] 0x240a,
428 [0x09e8] 0x2424,
429 [0x09e9] 0x240b,
430 [0x09ea] 0x2518,
431 [0x09eb] 0x2510,
432 [0x09ec] 0x250c,
433 [0x09ed] 0x2514,
434 [0x09ee] 0x253c,
435 [0x09f1] 0x2500,
436 [0x09f4] 0x251c,
437 [0x09f5] 0x2524,
438 [0x09f6] 0x2534,
439 [0x09f7] 0x252c,
440 [0x09f8] 0x2502,
441 [0x0aa1] 0x2003,
442 [0x0aa2] 0x2002,
443 [0x0aa3] 0x2004,
444 [0x0aa4] 0x2005,
445 [0x0aa5] 0x2007,
446 [0x0aa6] 0x2008,
447 [0x0aa7] 0x2009,
448 [0x0aa8] 0x200a,
449 [0x0aa9] 0x2014,
450 [0x0aaa] 0x2013,
451 [0x0aae] 0x2026,
452 [0x0ab0] 0x2153,
453 [0x0ab1] 0x2154,
454 [0x0ab2] 0x2155,
455 [0x0ab3] 0x2156,
456 [0x0ab4] 0x2157,
457 [0x0ab5] 0x2158,
458 [0x0ab6] 0x2159,
459 [0x0ab7] 0x215a,
460 [0x0ab8] 0x2105,
461 [0x0abb] 0x2012,
462 [0x0abc] 0x2329,
463 [0x0abd] 0x002e,
464 [0x0abe] 0x232a,
465 [0x0ac3] 0x215b,
466 [0x0ac4] 0x215c,
467 [0x0ac5] 0x215d,
468 [0x0ac6] 0x215e,
469 [0x0ac9] 0x2122,
470 [0x0aca] 0x2613,
471 [0x0acc] 0x25c1,
472 [0x0acd] 0x25b7,
473 [0x0ace] 0x25cb,
474 [0x0acf] 0x25a1,
475 [0x0ad0] 0x2018,
476 [0x0ad1] 0x2019,
477 [0x0ad2] 0x201c,
478 [0x0ad3] 0x201d,
479 [0x0ad4] 0x211e,
480 [0x0ad6] 0x2032,
481 [0x0ad7] 0x2033,
482 [0x0ad9] 0x271d,
483 [0x0adb] 0x25ac,
484 [0x0adc] 0x25c0,
485 [0x0add] 0x25b6,
486 [0x0ade] 0x25cf,
487 [0x0adf] 0x25a0,
488 [0x0ae0] 0x25e6,
489 [0x0ae1] 0x25ab,
490 [0x0ae2] 0x25ad,
491 [0x0ae3] 0x25b3,
492 [0x0ae4] 0x25bd,
493 [0x0ae5] 0x2606,
494 [0x0ae6] 0x2022,
495 [0x0ae7] 0x25aa,
496 [0x0ae8] 0x25b2,
497 [0x0ae9] 0x25bc,
498 [0x0aea] 0x261c,
499 [0x0aeb] 0x261e,
500 [0x0aec] 0x2663,
501 [0x0aed] 0x2666,
502 [0x0aee] 0x2665,
503 [0x0af0] 0x2720,
504 [0x0af1] 0x2020,
505 [0x0af2] 0x2021,
506 [0x0af3] 0x2713,
507 [0x0af4] 0x2717,
508 [0x0af5] 0x266f,
509 [0x0af6] 0x266d,
510 [0x0af7] 0x2642,
511 [0x0af8] 0x2640,
512 [0x0af9] 0x260e,
513 [0x0afa] 0x2315,
514 [0x0afb] 0x2117,
515 [0x0afc] 0x2038,
516 [0x0afd] 0x201a,
517 [0x0afe] 0x201e,
518 [0x0ba3] 0x003c,
519 [0x0ba6] 0x003e,
520 [0x0ba8] 0x2228,
521 [0x0ba9] 0x2227,
522 [0x0bc0] 0x00af,
523 [0x0bc2] 0x22a4,
524 [0x0bc3] 0x2229,
525 [0x0bc4] 0x230a,
526 [0x0bc6] 0x005f,
527 [0x0bca] 0x2218,
528 [0x0bcc] 0x2395,
529 [0x0bce] 0x22a5,
530 [0x0bcf] 0x25cb,
531 [0x0bd3] 0x2308,
532 [0x0bd6] 0x222a,
533 [0x0bd8] 0x2283,
534 [0x0bda] 0x2282,
535 [0x0bdc] 0x22a3,
536 [0x0bfc] 0x22a2,
537 [0x0cdf] 0x2017,
538 [0x0ce0] 0x05d0,
539 [0x0ce1] 0x05d1,
540 [0x0ce2] 0x05d2,
541 [0x0ce3] 0x05d3,
542 [0x0ce4] 0x05d4,
543 [0x0ce5] 0x05d5,
544 [0x0ce6] 0x05d6,
545 [0x0ce7] 0x05d7,
546 [0x0ce8] 0x05d8,
547 [0x0ce9] 0x05d9,
548 [0x0cea] 0x05da,
549 [0x0ceb] 0x05db,
550 [0x0cec] 0x05dc,
551 [0x0ced] 0x05dd,
552 [0x0cee] 0x05de,
553 [0x0cef] 0x05df,
554 [0x0cf0] 0x05e0,
555 [0x0cf1] 0x05e1,
556 [0x0cf2] 0x05e2,
557 [0x0cf3] 0x05e3,
558 [0x0cf4] 0x05e4,
559 [0x0cf5] 0x05e5,
560 [0x0cf6] 0x05e6,
561 [0x0cf7] 0x05e7,
562 [0x0cf8] 0x05e8,
563 [0x0cf9] 0x05e9,
564 [0x0cfa] 0x05ea,
565 [0x0da1] 0x0e01,
566 [0x0da2] 0x0e02,
567 [0x0da3] 0x0e03,
568 [0x0da4] 0x0e04,
569 [0x0da5] 0x0e05,
570 [0x0da6] 0x0e06,
571 [0x0da7] 0x0e07,
572 [0x0da8] 0x0e08,
573 [0x0da9] 0x0e09,
574 [0x0daa] 0x0e0a,
575 [0x0dab] 0x0e0b,
576 [0x0dac] 0x0e0c,
577 [0x0dad] 0x0e0d,
578 [0x0dae] 0x0e0e,
579 [0x0daf] 0x0e0f,
580 [0x0db0] 0x0e10,
581 [0x0db1] 0x0e11,
582 [0x0db2] 0x0e12,
583 [0x0db3] 0x0e13,
584 [0x0db4] 0x0e14,
585 [0x0db5] 0x0e15,
586 [0x0db6] 0x0e16,
587 [0x0db7] 0x0e17,
588 [0x0db8] 0x0e18,
589 [0x0db9] 0x0e19,
590 [0x0dba] 0x0e1a,
591 [0x0dbb] 0x0e1b,
592 [0x0dbc] 0x0e1c,
593 [0x0dbd] 0x0e1d,
594 [0x0dbe] 0x0e1e,
595 [0x0dbf] 0x0e1f,
596 [0x0dc0] 0x0e20,
597 [0x0dc1] 0x0e21,
598 [0x0dc2] 0x0e22,
599 [0x0dc3] 0x0e23,
600 [0x0dc4] 0x0e24,
601 [0x0dc5] 0x0e25,
602 [0x0dc6] 0x0e26,
603 [0x0dc7] 0x0e27,
604 [0x0dc8] 0x0e28,
605 [0x0dc9] 0x0e29,
606 [0x0dca] 0x0e2a,
607 [0x0dcb] 0x0e2b,
608 [0x0dcc] 0x0e2c,
609 [0x0dcd] 0x0e2d,
610 [0x0dce] 0x0e2e,
611 [0x0dcf] 0x0e2f,
612 [0x0dd0] 0x0e30,
613 [0x0dd1] 0x0e31,
614 [0x0dd2] 0x0e32,
615 [0x0dd3] 0x0e33,
616 [0x0dd4] 0x0e34,
617 [0x0dd5] 0x0e35,
618 [0x0dd6] 0x0e36,
619 [0x0dd7] 0x0e37,
620 [0x0dd8] 0x0e38,
621 [0x0dd9] 0x0e39,
622 [0x0dda] 0x0e3a,
623 [0x0dde] 0x0e3e,
624 [0x0ddf] 0x0e3f,
625 [0x0de0] 0x0e40,
626 [0x0de1] 0x0e41,
627 [0x0de2] 0x0e42,
628 [0x0de3] 0x0e43,
629 [0x0de4] 0x0e44,
630 [0x0de5] 0x0e45,
631 [0x0de6] 0x0e46,
632 [0x0de7] 0x0e47,
633 [0x0de8] 0x0e48,
634 [0x0de9] 0x0e49,
635 [0x0dea] 0x0e4a,
636 [0x0deb] 0x0e4b,
637 [0x0dec] 0x0e4c,
638 [0x0ded] 0x0e4d,
639 [0x0df0] 0x0e50,
640 [0x0df1] 0x0e51,
641 [0x0df2] 0x0e52,
642 [0x0df3] 0x0e53,
643 [0x0df4] 0x0e54,
644 [0x0df5] 0x0e55,
645 [0x0df6] 0x0e56,
646 [0x0df7] 0x0e57,
647 [0x0df8] 0x0e58,
648 [0x0df9] 0x0e59,
649 [0x0ea1] 0x3131,
650 [0x0ea2] 0x3132,
651 [0x0ea3] 0x3133,
652 [0x0ea4] 0x3134,
653 [0x0ea5] 0x3135,
654 [0x0ea6] 0x3136,
655 [0x0ea7] 0x3137,
656 [0x0ea8] 0x3138,
657 [0x0ea9] 0x3139,
658 [0x0eaa] 0x313a,
659 [0x0eab] 0x313b,
660 [0x0eac] 0x313c,
661 [0x0ead] 0x313d,
662 [0x0eae] 0x313e,
663 [0x0eaf] 0x313f,
664 [0x0eb0] 0x3140,
665 [0x0eb1] 0x3141,
666 [0x0eb2] 0x3142,
667 [0x0eb3] 0x3143,
668 [0x0eb4] 0x3144,
669 [0x0eb5] 0x3145,
670 [0x0eb6] 0x3146,
671 [0x0eb7] 0x3147,
672 [0x0eb8] 0x3148,
673 [0x0eb9] 0x3149,
674 [0x0eba] 0x314a,
675 [0x0ebb] 0x314b,
676 [0x0ebc] 0x314c,
677 [0x0ebd] 0x314d,
678 [0x0ebe] 0x314e,
679 [0x0ebf] 0x314f,
680 [0x0ec0] 0x3150,
681 [0x0ec1] 0x3151,
682 [0x0ec2] 0x3152,
683 [0x0ec3] 0x3153,
684 [0x0ec4] 0x3154,
685 [0x0ec5] 0x3155,
686 [0x0ec6] 0x3156,
687 [0x0ec7] 0x3157,
688 [0x0ec8] 0x3158,
689 [0x0ec9] 0x3159,
690 [0x0eca] 0x315a,
691 [0x0ecb] 0x315b,
692 [0x0ecc] 0x315c,
693 [0x0ecd] 0x315d,
694 [0x0ece] 0x315e,
695 [0x0ecf] 0x315f,
696 [0x0ed0] 0x3160,
697 [0x0ed1] 0x3161,
698 [0x0ed2] 0x3162,
699 [0x0ed3] 0x3163,
700 [0x0ed4] 0x11a8,
701 [0x0ed5] 0x11a9,
702 [0x0ed6] 0x11aa,
703 [0x0ed7] 0x11ab,
704 [0x0ed8] 0x11ac,
705 [0x0ed9] 0x11ad,
706 [0x0eda] 0x11ae,
707 [0x0edb] 0x11af,
708 [0x0edc] 0x11b0,
709 [0x0edd] 0x11b1,
710 [0x0ede] 0x11b2,
711 [0x0edf] 0x11b3,
712 [0x0ee0] 0x11b4,
713 [0x0ee1] 0x11b5,
714 [0x0ee2] 0x11b6,
715 [0x0ee3] 0x11b7,
716 [0x0ee4] 0x11b8,
717 [0x0ee5] 0x11b9,
718 [0x0ee6] 0x11ba,
719 [0x0ee7] 0x11bb,
720 [0x0ee8] 0x11bc,
721 [0x0ee9] 0x11bd,
722 [0x0eea] 0x11be,
723 [0x0eeb] 0x11bf,
724 [0x0eec] 0x11c0,
725 [0x0eed] 0x11c1,
726 [0x0eee] 0x11c2,
727 [0x0eef] 0x316d,
728 [0x0ef0] 0x3171,
729 [0x0ef1] 0x3178,
730 [0x0ef2] 0x317f,
731 [0x0ef4] 0x3184,
732 [0x0ef5] 0x3186,
733 [0x0ef6] 0x318d,
734 [0x0ef7] 0x318e,
735 [0x0ef8] 0x11eb,
736 [0x0efa] 0x11f9,
737 [0x0eff] 0x20a9,
738 [0x13bc] 0x0152,
739 [0x13bd] 0x0153,
740 [0x13be] 0x0178,
741 [0x20a0] 0x20a0,
742 [0x20a1] 0x20a1,
743 [0x20a2] 0x20a2,
744 [0x20a3] 0x20a3,
745 [0x20a4] 0x20a4,
746 [0x20a5] 0x20a5,
747 [0x20a6] 0x20a6,
748 [0x20a7] 0x20a7,
749 [0x20a8] 0x20a8,
750 [0x20a9] 0x20a9,
751 [0x20aa] 0x20aa,
752 [0x20ab] 0x20ab,
753 [0x20ac] 0x20ac,
754};
gui-x11/load.c+16−0
@@ -0,0 +1,16 @@
1#include <u.h>
2#include <libc.h>
3#include <draw.h>
4#include <memdraw.h>
5#include "xmem.h"
6
7int
8loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
9{
10 int n;
11
12 n = _loadmemimage(i, r, data, ndata);
13 if(n > 0 && i->X)
14 putXdata(i, r);
15 return n;
16}
gui-x11/screen.c+1094−0
@@ -0,0 +1,1094 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <fcntl.h>
4#include <termios.h>
5#include <stdio.h>
6
7#include <X11/Xlib.h>
8#include <X11/Xatom.h>
9#include <X11/Xutil.h>
10#include <X11/keysym.h>
11
12#include "keysym2ucs.h"
13
14/*
15 * alias defs for image types to overcome name conflicts
16 */
17#define Point IPoint
18#define Rectangle IRectangle
19#define Display IDisplay
20#define Font IFont
21#define Screen IScreen
22
23#include <u.h>
24#include <libc.h>
25#include <draw.h>
26#include <memdraw.h>
27#include <keyboard.h>
28#include "dat.h"
29#include "fns.h"
30#include "screen.h"
31
32#undef time
33#undef Point
34#undef Rectangle
35#undef Display
36#undef Font
37#undef Screen
38
39typedef struct ICursor ICursor;
40struct ICursor
41{
42 int w;
43 int h;
44 int hotx;
45 int hoty;
46 char *src;
47 char *mask;
48};
49
50
51#define ABS(x) ((x) < 0 ? -(x) : (x))
52
53enum
54{
55 DblTime = 300 /* double click time in msec */
56};
57
58XColor map[256]; /* Plan 9 colormap array */
59XColor map7[128]; /* Plan 9 colormap array */
60uchar map7to8[128][2];
61Colormap xcmap; /* Default shared colormap */
62int plan9tox11[256]; /* Values for mapping between */
63int x11toplan9[256]; /* X11 and Plan 9 */
64int x24bitswap = 0; /* swap endian for 24bit RGB */
65int xtblbit;
66extern int mousequeue;
67
68/* for copy/paste, lifted from plan9ports */
69Atom clipboard;
70Atom utf8string;
71Atom targets;
72Atom text;
73Atom compoundtext;
74
75static XModifierKeymap *modmap;
76static int keypermod;
77static Drawable xdrawable;
78/* static Atom wm_take_focus; */
79static void xexpose(XEvent*);
80static void xmouse(XEvent*);
81static void xkeyboard(XEvent*);
82static void xmapping(XEvent*);
83static void xdestroy(XEvent*);
84static void xselect(XEvent*);
85static void xproc(void*);
86static Memimage* xinitscreen(void);
87static void initmap(Window);
88static GC creategc(Drawable);
89static void graphicscmap(XColor*);
90 int xscreendepth;
91 Drawable xscreenid;
92 Display* xdisplay;
93 Display* xkmcon;
94 Display* xsnarfcon;
95 Visual *xvis;
96 GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
97 GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
98 ulong xblack;
99 ulong xwhite;
100 ulong xscreenchan;
101
102extern Memimage* xallocmemimage(IRectangle, ulong, int);
103Memimage *gscreen;
104Screeninfo screen;
105XImage *ximage;
106
107void
108screeninit(void)
109{
110 _memmkcmap();
111
112 gscreen = xinitscreen();
113 kproc("xscreen", xproc, nil);
114
115 memimageinit();
116 terminit();
117 flushmemscreen(gscreen->r);
118}
119
120uchar*
121attachscreen(IRectangle *r, ulong *chan, int *depth,
122 int *width, int *softscreen, void **X)
123{
124 *r = gscreen->r;
125 *chan = gscreen->chan;
126 *depth = gscreen->depth;
127 *width = gscreen->width;
128 *X = gscreen->X;
129 *softscreen = 1;
130
131 return gscreen->data->bdata;
132}
133
134void
135flushmemscreen(IRectangle r)
136{
137 if(r.min.x >= r.max.x || r.min.y >= r.max.y)
138 return;
139 XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y);
140 XFlush(xdisplay);
141}
142
143static int
144revbyte(int b)
145{
146 int r;
147
148 r = 0;
149 r |= (b&0x01) << 7;
150 r |= (b&0x02) << 5;
151 r |= (b&0x04) << 3;
152 r |= (b&0x08) << 1;
153 r |= (b&0x10) >> 1;
154 r |= (b&0x20) >> 3;
155 r |= (b&0x40) >> 5;
156 r |= (b&0x80) >> 7;
157 return r;
158}
159
160void
161mouseset(IPoint xy)
162{
163 XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y);
164 XFlush(xdisplay);
165}
166
167static Cursor xcursor;
168
169void
170setcursor(void)
171{
172 Cursor xc;
173 XColor fg, bg;
174 Pixmap xsrc, xmask;
175 int i;
176 uchar src[2*16], mask[2*16];
177
178 for(i=0; i<2*16; i++){
179 src[i] = revbyte(cursor.set[i]);
180 mask[i] = revbyte(cursor.set[i] | cursor.clr[i]);
181 }
182
183 fg = map[0];
184 bg = map[255];
185 xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16);
186 xmask = XCreateBitmapFromData(xdisplay, xdrawable, mask, 16, 16);
187 xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -cursor.offset.x, -cursor.offset.y);
188 if(xc != 0) {
189 XDefineCursor(xdisplay, xdrawable, xc);
190 if(xcursor != 0)
191 XFreeCursor(xdisplay, xcursor);
192 xcursor = xc;
193 }
194 XFreePixmap(xdisplay, xsrc);
195 XFreePixmap(xdisplay, xmask);
196 XFlush(xdisplay);
197}
198
199void
200cursorarrow(void)
201{
202 if(xcursor != 0){
203 XFreeCursor(xdisplay, xcursor);
204 xcursor = 0;
205 }
206 XUndefineCursor(xdisplay, xdrawable);
207 XFlush(xdisplay);
208}
209
210static void
211xproc(void *arg)
212{
213 ulong mask;
214 XEvent event;
215
216 mask = KeyPressMask|
217 ButtonPressMask|
218 ButtonReleaseMask|
219 PointerMotionMask|
220 Button1MotionMask|
221 Button2MotionMask|
222 Button3MotionMask|
223 Button4MotionMask|
224 Button5MotionMask|
225 ExposureMask|
226 StructureNotifyMask;
227
228 XSelectInput(xkmcon, xdrawable, mask);
229 for(;;) {
230 //XWindowEvent(xkmcon, xdrawable, mask, &event);
231 XNextEvent(xkmcon, &event);
232 xselect(&event);
233 xkeyboard(&event);
234 xmouse(&event);
235 xexpose(&event);
236 xmapping(&event);
237 xdestroy(&event);
238 }
239}
240
241static int
242shutup(Display *d, XErrorEvent *e)
243{
244 char buf[200];
245 iprint("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code);
246 XGetErrorText(d, e->error_code, buf, sizeof(buf));
247 iprint("%s\n", buf);
248 USED(d);
249 USED(e);
250 return 0;
251}
252
253static int
254panicshutup(Display *d)
255{
256 panic("x error");
257 return -1;
258}
259
260static Memimage*
261xinitscreen(void)
262{
263 Memimage *gscreen;
264 int i, xsize, ysize, pmid;
265 char *argv[2];
266 char *disp_val;
267 Window rootwin;
268 IRectangle r;
269 XWMHints hints;
270 Screen *screen;
271 XVisualInfo xvi;
272 int rootscreennum;
273 XTextProperty name;
274 XClassHint classhints;
275 XSizeHints normalhints;
276 XSetWindowAttributes attrs;
277 XPixmapFormatValues *pfmt;
278 int n;
279 Memdata *md;
280
281 xscreenid = 0;
282 xdrawable = 0;
283
284 xdisplay = XOpenDisplay(NULL);
285 if(xdisplay == 0){
286 disp_val = getenv("DISPLAY");
287 if(disp_val == 0)
288 disp_val = "not set";
289 iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
290 exit(0);
291 }
292
293 XSetErrorHandler(shutup);
294 XSetIOErrorHandler(panicshutup);
295 rootscreennum = DefaultScreen(xdisplay);
296 rootwin = DefaultRootWindow(xdisplay);
297
298 xscreendepth = DefaultDepth(xdisplay, rootscreennum);
299 if(XMatchVisualInfo(xdisplay, rootscreennum, 16, TrueColor, &xvi)
300 || XMatchVisualInfo(xdisplay, rootscreennum, 16, DirectColor, &xvi)){
301 xvis = xvi.visual;
302 xscreendepth = 16;
303 xtblbit = 1;
304 }
305 else if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi)
306 || XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){
307 xvis = xvi.visual;
308 xscreendepth = 24;
309 xtblbit = 1;
310 }
311 else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi)
312 || XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){
313 if(xscreendepth > 8)
314 panic("drawterm: can't deal with colormapped depth %d screens\n", xscreendepth);
315 xvis = xvi.visual;
316 xscreendepth = 8;
317 }
318 else{
319 if(xscreendepth != 8)
320 panic("drawterm: can't deal with depth %d screens\n", xscreendepth);
321 xvis = DefaultVisual(xdisplay, rootscreennum);
322 }
323
324 /*
325 * xscreendepth is only the number of significant pixel bits,
326 * not the total. We need to walk the display list to find
327 * how many actual bits are being used per pixel.
328 */
329 xscreenchan = 0; /* not a valid channel */
330 pfmt = XListPixmapFormats(xdisplay, &n);
331 for(i=0; i<n; i++){
332 if(pfmt[i].depth == xscreendepth){
333 switch(pfmt[i].bits_per_pixel){
334 case 1: /* untested */
335 xscreenchan = GREY1;
336 break;
337 case 2: /* untested */
338 xscreenchan = GREY2;
339 break;
340 case 4: /* untested */
341 xscreenchan = GREY4;
342 break;
343 case 8:
344 xscreenchan = CMAP8;
345 break;
346 case 16: /* uses 16 rather than 15, empirically. */
347 xscreenchan = RGB16;
348 break;
349 case 24: /* untested (impossible?) */
350 xscreenchan = RGB24;
351 break;
352 case 32:
353 xscreenchan = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8);
354 break;
355 }
356 }
357 }
358 if(xscreenchan == 0)
359 panic("drawterm: unknown screen pixel format\n");
360
361 screen = DefaultScreenOfDisplay(xdisplay);
362 xcmap = DefaultColormapOfScreen(screen);
363
364 if(xvis->class != StaticColor){
365 graphicscmap(map);
366 initmap(rootwin);
367 }
368
369 if((modmap = XGetModifierMapping(xdisplay)))
370 keypermod = modmap->max_keypermod;
371
372 r.min = ZP;
373 r.max.x = WidthOfScreen(screen);
374 r.max.y = HeightOfScreen(screen);
375
376 md = mallocz(sizeof(Memdata), 1);
377
378 xsize = Dx(r)*3/4;
379 ysize = Dy(r)*3/4;
380
381 attrs.colormap = xcmap;
382 attrs.background_pixel = 0;
383 attrs.border_pixel = 0;
384 /* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */
385 xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0,
386 xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs);
387
388 /*
389 * set up property as required by ICCCM
390 */
391 name.value = (uchar*)"drawterm";
392 name.encoding = XA_STRING;
393 name.format = 8;
394 name.nitems = strlen(name.value);
395 normalhints.flags = USSize|PMaxSize;
396 normalhints.max_width = Dx(r);
397 normalhints.max_height = Dy(r);
398 normalhints.width = xsize;
399 normalhints.height = ysize;
400 hints.flags = InputHint|StateHint;
401 hints.input = 1;
402 hints.initial_state = NormalState;
403 classhints.res_name = "drawterm";
404 classhints.res_class = "Drawterm";
405 argv[0] = "drawterm";
406 argv[1] = nil;
407 XSetWMProperties(xdisplay, xdrawable,
408 &name, /* XA_WM_NAME property for ICCCM */
409 &name, /* XA_WM_ICON_NAME */
410 argv, /* XA_WM_COMMAND */
411 1, /* argc */
412 &normalhints, /* XA_WM_NORMAL_HINTS */
413 &hints, /* XA_WM_HINTS */
414 &classhints); /* XA_WM_CLASS */
415 XFlush(xdisplay);
416
417 /*
418 * put the window on the screen
419 */
420 XMapWindow(xdisplay, xdrawable);
421 XFlush(xdisplay);
422
423 xscreenid = XCreatePixmap(xdisplay, xdrawable, Dx(r), Dy(r), xscreendepth);
424 gscreen = xallocmemimage(r, xscreenchan, xscreenid);
425
426 xgcfill = creategc(xscreenid);
427 XSetFillStyle(xdisplay, xgcfill, FillSolid);
428 xgccopy = creategc(xscreenid);
429 xgcsimplesrc = creategc(xscreenid);
430 XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled);
431 xgczero = creategc(xscreenid);
432 xgcreplsrc = creategc(xscreenid);
433 XSetFillStyle(xdisplay, xgcreplsrc, FillTiled);
434
435 pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1);
436 xgcfill0 = creategc(pmid);
437 XSetForeground(xdisplay, xgcfill0, 0);
438 XSetFillStyle(xdisplay, xgcfill0, FillSolid);
439 xgccopy0 = creategc(pmid);
440 xgcsimplesrc0 = creategc(pmid);
441 XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled);
442 xgczero0 = creategc(pmid);
443 xgcreplsrc0 = creategc(pmid);
444 XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled);
445 XFreePixmap(xdisplay, pmid);
446
447 XSetForeground(xdisplay, xgccopy, plan9tox11[0]);
448 XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize);
449
450 xkmcon = XOpenDisplay(NULL);
451 if(xkmcon == 0){
452 disp_val = getenv("DISPLAY");
453 if(disp_val == 0)
454 disp_val = "not set";
455 iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
456 exit(0);
457 }
458 xsnarfcon = XOpenDisplay(NULL);
459 if(xsnarfcon == 0){
460 disp_val = getenv("DISPLAY");
461 if(disp_val == 0)
462 disp_val = "not set";
463 iprint("drawterm: open %r, DISPLAY is %s\n", disp_val);
464 exit(0);
465 }
466
467 clipboard = XInternAtom(xkmcon, "CLIPBOARD", False);
468 utf8string = XInternAtom(xkmcon, "UTF8_STRING", False);
469 targets = XInternAtom(xkmcon, "TARGETS", False);
470 text = XInternAtom(xkmcon, "TEXT", False);
471 compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False);
472
473 xblack = screen->black_pixel;
474 xwhite = screen->white_pixel;
475 return gscreen;
476}
477
478static void
479graphicscmap(XColor *map)
480{
481 int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
482
483 for(r=0; r!=4; r++) {
484 for(g = 0; g != 4; g++) {
485 for(b = 0; b!=4; b++) {
486 for(v = 0; v!=4; v++) {
487 den=r;
488 if(g > den)
489 den=g;
490 if(b > den)
491 den=b;
492 /* divide check -- pick grey shades */
493 if(den==0)
494 cr=cg=cb=v*17;
495 else {
496 num=17*(4*den+v);
497 cr=r*num/den;
498 cg=g*num/den;
499 cb=b*num/den;
500 }
501 idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
502 map[idx].red = cr*0x0101;
503 map[idx].green = cg*0x0101;
504 map[idx].blue = cb*0x0101;
505 map[idx].pixel = idx;
506 map[idx].flags = DoRed|DoGreen|DoBlue;
507
508 v7 = v >> 1;
509 idx7 = r*32 + v7*16 + g*4 + b;
510 if((v & 1) == v7){
511 map7to8[idx7][0] = idx;
512 if(den == 0) { /* divide check -- pick grey shades */
513 cr = ((255.0/7.0)*v7)+0.5;
514 cg = cr;
515 cb = cr;
516 }
517 else {
518 num=17*15*(4*den+v7*2)/14;
519 cr=r*num/den;
520 cg=g*num/den;
521 cb=b*num/den;
522 }
523 map7[idx7].red = cr*0x0101;
524 map7[idx7].green = cg*0x0101;
525 map7[idx7].blue = cb*0x0101;
526 map7[idx7].pixel = idx7;
527 map7[idx7].flags = DoRed|DoGreen|DoBlue;
528 }
529 else
530 map7to8[idx7][1] = idx;
531 }
532 }
533 }
534 }
535}
536
537/*
538 * Initialize and install the drawterm colormap as a private colormap for this
539 * application. Drawterm gets the best colors here when it has the cursor focus.
540 */
541static void
542initmap(Window w)
543{
544 XColor c;
545 int i;
546 ulong p, pp;
547 char buf[30];
548
549 if(xscreendepth <= 1)
550 return;
551
552 if(xscreendepth >= 24) {
553 /* The pixel value returned from XGetPixel needs to
554 * be converted to RGB so we can call rgb2cmap()
555 * to translate between 24 bit X and our color. Unfortunately,
556 * the return value appears to be display server endian
557 * dependant. Therefore, we run some heuristics to later
558 * determine how to mask the int value correctly.
559 * Yeah, I know we can look at xvis->byte_order but
560 * some displays say MSB even though they run on LSB.
561 * Besides, this is more anal.
562 */
563
564 c = map[19];
565 /* find out index into colormap for our RGB */
566 if(!XAllocColor(xdisplay, xcmap, &c))
567 panic("drawterm: screen-x11 can't alloc color");
568
569 p = c.pixel;
570 pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
571 if(pp!=map[19].pixel) {
572 /* check if endian is other way */
573 pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
574 if(pp!=map[19].pixel)
575 panic("cannot detect x server byte order");
576 switch(xscreenchan){
577 case RGB24:
578 xscreenchan = BGR24;
579 break;
580 case XRGB32:
581 xscreenchan = XBGR32;
582 break;
583 default:
584 panic("don't know how to byteswap channel %s",
585 chantostr(buf, xscreenchan));
586 break;
587 }
588 }
589 } else if(xvis->class == TrueColor || xvis->class == DirectColor) {
590 } else if(xvis->class == PseudoColor) {
591 if(xtblbit == 0){
592 xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll);
593 XStoreColors(xdisplay, xcmap, map, 256);
594 for(i = 0; i < 256; i++) {
595 plan9tox11[i] = i;
596 x11toplan9[i] = i;
597 }
598 }
599 else {
600 for(i = 0; i < 128; i++) {
601 c = map7[i];
602 if(!XAllocColor(xdisplay, xcmap, &c)) {
603 iprint("drawterm: can't alloc colors in default map, don't use -7\n");
604 exit(0);
605 }
606 plan9tox11[map7to8[i][0]] = c.pixel;
607 plan9tox11[map7to8[i][1]] = c.pixel;
608 x11toplan9[c.pixel] = map7to8[i][0];
609 }
610 }
611 }
612 else
613 panic("drawterm: unsupported visual class %d\n", xvis->class);
614}
615
616static void
617xdestroy(XEvent *e)
618{
619 XDestroyWindowEvent *xe;
620 if(e->type != DestroyNotify)
621 return;
622 xe = (XDestroyWindowEvent*)e;
623 if(xe->window == xdrawable)
624 exit(0);
625}
626
627static void
628xselection(XEvent *e)
629{
630 XSelectionRequestEvent *xre;
631 XSelectionEvent *xe;
632}
633
634static void
635xmapping(XEvent *e)
636{
637 XMappingEvent *xe;
638
639 if(e->type != MappingNotify)
640 return;
641 xe = (XMappingEvent*)e;
642 if(modmap)
643 XFreeModifiermap(modmap);
644 modmap = XGetModifierMapping(xe->display);
645 if(modmap)
646 keypermod = modmap->max_keypermod;
647}
648
649
650/*
651 * Disable generation of GraphicsExpose/NoExpose events in the GC.
652 */
653static GC
654creategc(Drawable d)
655{
656 XGCValues gcv;
657
658 gcv.function = GXcopy;
659 gcv.graphics_exposures = False;
660 return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv);
661}
662
663static void
664xexpose(XEvent *e)
665{
666 IRectangle r;
667 XExposeEvent *xe;
668
669 if(e->type != Expose)
670 return;
671 xe = (XExposeEvent*)e;
672 r.min.x = xe->x;
673 r.min.y = xe->y;
674 r.max.x = xe->x + xe->width;
675 r.max.y = xe->y + xe->height;
676 drawflushr(r);
677}
678
679static void
680xkeyboard(XEvent *e)
681{
682 KeySym k;
683 unsigned int md;
684
685 /*
686 * I tried using XtGetActionKeysym, but it didn't seem to
687 * do case conversion properly
688 * (at least, with Xterminal servers and R4 intrinsics)
689 */
690 if(e->xany.type != KeyPress)
691 return;
692
693
694 XLookupString(e,NULL,0,&k,NULL);
695
696 if(k == XK_Multi_key || k == NoSymbol)
697 return;
698 if(k&0xFF00){
699 switch(k){
700 case XK_BackSpace:
701 case XK_Tab:
702 case XK_Escape:
703 case XK_Delete:
704 case XK_KP_0:
705 case XK_KP_1:
706 case XK_KP_2:
707 case XK_KP_3:
708 case XK_KP_4:
709 case XK_KP_5:
710 case XK_KP_6:
711 case XK_KP_7:
712 case XK_KP_8:
713 case XK_KP_9:
714 case XK_KP_Divide:
715 case XK_KP_Multiply:
716 case XK_KP_Subtract:
717 case XK_KP_Add:
718 case XK_KP_Decimal:
719 k &= 0x7F;
720 break;
721 case XK_Linefeed:
722 k = '\r';
723 break;
724 case XK_KP_Space:
725 k = ' ';
726 break;
727 case XK_Home:
728 case XK_KP_Home:
729 k = Khome;
730 break;
731 case XK_Left:
732 case XK_KP_Left:
733 k = Kleft;
734 break;
735 case XK_Up:
736 case XK_KP_Up:
737 k = Kup;
738 break;
739 case XK_Down:
740 case XK_KP_Down:
741 k = Kdown;
742 break;
743 case XK_Right:
744 case XK_KP_Right:
745 k = Kright;
746 break;
747 case XK_Page_Down:
748 case XK_KP_Page_Down:
749 k = Kpgdown;
750 break;
751 case XK_End:
752 case XK_KP_End:
753 k = Kend;
754 break;
755 case XK_Page_Up:
756 case XK_KP_Page_Up:
757 k = Kpgup;
758 break;
759 case XK_Insert:
760 case XK_KP_Insert:
761 k = Kins;
762 break;
763 case XK_KP_Enter:
764 case XK_Return:
765 k = '\n';
766 break;
767 case XK_Alt_L:
768 case XK_Alt_R:
769 k = Kalt;
770 break;
771 case XK_Shift_L:
772 case XK_Shift_R:
773 case XK_Control_L:
774 case XK_Control_R:
775 case XK_Caps_Lock:
776 case XK_Shift_Lock:
777
778 case XK_Meta_L:
779 case XK_Meta_R:
780 case XK_Super_L:
781 case XK_Super_R:
782 case XK_Hyper_L:
783 case XK_Hyper_R:
784 return;
785 default: /* not ISO-1 or tty control */
786 if(k>0xff) {
787 k = keysym2ucs(k); /* supplied by X */
788 if(k == -1) return;
789 }
790 }
791 }
792
793 /* Compensate for servers that call a minus a hyphen */
794 if(k == XK_hyphen)
795 k = XK_minus;
796 /* Do control mapping ourselves if translator doesn't */
797 if(e->xkey.state&ControlMask)
798 k &= 0x9f;
799 if(k == NoSymbol) {
800 return;
801 }
802
803 kbdputc(kbdq, k);
804}
805
806static void
807xmouse(XEvent *e)
808{
809 Mousestate ms;
810 int i, s;
811 XButtonEvent *be;
812 XMotionEvent *me;
813
814 switch(e->type){
815 case ButtonPress:
816 be = (XButtonEvent *)e;
817 ms.xy.x = be->x;
818 ms.xy.y = be->y;
819 s = be->state;
820 ms.msec = be->time;
821 switch(be->button){
822 case 1:
823 s |= Button1Mask;
824 break;
825 case 2:
826 s |= Button2Mask;
827 break;
828 case 3:
829 s |= Button3Mask;
830 break;
831 case 4:
832 s |= Button4Mask;
833 break;
834 case 5:
835 s |= Button5Mask;
836 break;
837 }
838 break;
839 case ButtonRelease:
840 be = (XButtonEvent *)e;
841 ms.xy.x = be->x;
842 ms.xy.y = be->y;
843 ms.msec = be->time;
844 s = be->state;
845 switch(be->button){
846 case 1:
847 s &= ~Button1Mask;
848 break;
849 case 2:
850 s &= ~Button2Mask;
851 break;
852 case 3:
853 s &= ~Button3Mask;
854 break;
855 case 4:
856 s &= ~Button4Mask;
857 break;
858 case 5:
859 s &= ~Button5Mask;
860 break;
861 }
862 break;
863 case MotionNotify:
864 me = (XMotionEvent *)e;
865 s = me->state;
866 ms.xy.x = me->x;
867 ms.xy.y = me->y;
868 ms.msec = me->time;
869 break;
870 default:
871 return;
872 }
873
874 ms.buttons = 0;
875 if(s & Button1Mask)
876 ms.buttons |= 1;
877 if(s & Button2Mask)
878 ms.buttons |= 2;
879 if(s & Button3Mask)
880 ms.buttons |= 4;
881 if(s & Button4Mask)
882 ms.buttons |= 8;
883 if(s & Button5Mask)
884 ms.buttons |= 16;
885
886 lock(&mouse.lk);
887 i = mouse.wi;
888 if(mousequeue) {
889 if(i == mouse.ri || mouse.lastb != ms.buttons || mouse.trans) {
890 mouse.wi = (i+1)%Mousequeue;
891 if(mouse.wi == mouse.ri)
892 mouse.ri = (mouse.ri+1)%Mousequeue;
893 mouse.trans = mouse.lastb != ms.buttons;
894 } else {
895 i = (i-1+Mousequeue)%Mousequeue;
896 }
897 } else {
898 mouse.wi = (i+1)%Mousequeue;
899 mouse.ri = i;
900 }
901 mouse.queue[i] = ms;
902 mouse.lastb = ms.buttons;
903 unlock(&mouse.lk);
904 wakeup(&mouse.r);
905}
906
907void
908getcolor(ulong i, ulong *r, ulong *g, ulong *b)
909{
910 ulong v;
911
912 v = cmap2rgb(i);
913 *r = (v>>16)&0xFF;
914 *g = (v>>8)&0xFF;
915 *b = v&0xFF;
916}
917
918void
919setcolor(ulong i, ulong r, ulong g, ulong b)
920{
921 /* no-op */
922}
923
924typedef struct Clip Clip;
925struct Clip
926{
927 char buf[SnarfSize];
928 ulong n;
929 int want, have;
930 QLock lk;
931 Rendez vous;
932};
933
934Clip clip;
935
936enum {
937 Chunk = 2048
938};
939
940static void
941xselect(XEvent *e)
942{
943 XSelectionRequestEvent *q;
944 XEvent r;
945 Atom a[4];
946 char *name;
947
948
949 if(e->type != SelectionRequest)
950 return;
951
952 /*
953 * The lock is around the whole routine because we use the
954 * lock to make sure two people aren't sending on xkmcon
955 * at once.
956 */
957 q = (XSelectionRequestEvent*)e;
958
959 r.xselection.property = q->property;
960 if(q->target == targets) {
961 a[0] = XA_STRING;
962 a[1] = utf8string;
963 a[2] = text;
964 a[3] = compoundtext;
965
966 XChangeProperty(xkmcon, q->requestor, q->property, q->target,
967 8, PropModeReplace, (uchar*)a, sizeof a);
968 }else if(q->target == XA_STRING || q->target == utf8string || q->target == text || q->target == compoundtext){
969 qlock(&clip.lk);
970 XChangeProperty(xkmcon, q->requestor, q->property, q->target, 8,
971 PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
972 qunlock(&clip.lk);
973 }else {
974 name = XGetAtomName(xkmcon, q->target);
975 if(strcmp(name, "TIMESTAMP") != 0)
976 fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)q->target);
977 r.xselection.property = None;
978 }
979
980 r.xselection.type = SelectionNotify;
981 r.xselection.display = q->display;
982 r.xselection.requestor = q->requestor;
983 r.xselection.selection = q->selection;
984 r.xselection.target = q->target;
985 r.xselection.time = q->time;
986 XSendEvent(xkmcon, q->requestor, False, 0, &r);
987 XFlush(xkmcon);
988}
989
990int
991haveclip(void *a)
992{
993 return clip.want == clip.have;
994}
995
996#undef long /* sic */
997char*
998clipread(void)
999{
1000 Window w;
1001 XEvent e;
1002 Atom type;
1003 unsigned long len, lleft, left, dummy;
1004 int i, fmt, res;
1005 uchar *data;
1006
1007 qlock(&clip.lk);
1008 w = XGetSelectionOwner(xsnarfcon, XA_PRIMARY);
1009 if(w == xdrawable)
1010 data = (uchar*)strdup(clip.buf);
1011 else if(w == None)
1012 data = nil;
1013 else {
1014 /*
1015 * we're supposed to get a notification, but we seem not to,
1016 * so let's just watch and see when the buffer stabilizes.
1017 * if you know how to fix this, mail rsc@plan9.bell-labs.com.
1018 */
1019 XChangeProperty(xsnarfcon, xdrawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace,
1020 (uchar*)"", 0);
1021 XConvertSelection(xsnarfcon, XA_PRIMARY, XA_STRING, None, xdrawable, CurrentTime);
1022 XFlush(xsnarfcon);
1023 for(i=0; i<30; i++){
1024 osmsleep(100);
1025 XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, 0, 0, AnyPropertyType,
1026 &type, &fmt, &len, &left, &data);
1027 if(lleft == left && left > 0)
1028 break;
1029 lleft = left;
1030 }
1031 if(left > 0){
1032 res = XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, left, 0,
1033 AnyPropertyType, &type, &fmt, &len, &dummy, &data);
1034 data = (uchar*)strdup(data);
1035 }else
1036 data = nil;
1037 }
1038 qunlock(&clip.lk);
1039 return (char*)data;
1040}
1041
1042int
1043clipwrite(char *buf)
1044{
1045 int n;
1046
1047 n = strlen(buf);
1048 qlock(&clip.lk);
1049 if(n >= SnarfSize)
1050 n = SnarfSize - 1;
1051 memmove(clip.buf, buf, n);
1052 clip.buf[n] = 0;
1053 clip.n = n;
1054 /*
1055 * xkmcon so that we get the event in the select loop.
1056 * It seems to be okay to send a message and read an event
1057 * from a Display* at the same time. Let's hope so.
1058 */
1059 XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
1060 XFlush(xkmcon);
1061 qunlock(&clip.lk);
1062 return n;
1063}
1064#define long int /* sic */
1065
1066int
1067atlocalconsole(void)
1068{
1069 char *p, *q;
1070 char buf[128];
1071
1072 p = getenv("DISPLAY");
1073 if(p == nil)
1074 return 0;
1075
1076 /* extract host part */
1077 q = strchr(p, ':');
1078 if(q == nil)
1079 return 0;
1080 *q = 0;
1081
1082 if(strcmp(p, "") == 0)
1083 return 1;
1084
1085 /* try to match against system name (i.e. for ssh) */
1086 if(gethostname(buf, sizeof buf) == 0){
1087 if(strcmp(p, buf) == 0)
1088 return 1;
1089 if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.')
1090 return 1;
1091 }
1092
1093 return 0;
1094}
gui-x11/xmem.h+60−0
@@ -0,0 +1,60 @@
1#define Font XXFont
2#define Screen XXScreen
3#define Display XXDisplay
4
5#include <X11/Xlib.h>
6/* #include <X11/Xlibint.h> */
7#include <X11/Xatom.h>
8#include <X11/Xutil.h>
9#include <X11/IntrinsicP.h>
10#include <X11/StringDefs.h>
11
12#undef Font
13#undef Screen
14#undef Display
15
16/*
17 * Structure pointed to by X field of Memimage
18 */
19typedef struct Xmem Xmem;
20
21enum
22{
23 PMundef = ~0 /* undefined pixmap id */
24};
25
26
27struct Xmem
28{
29 int pmid; /* pixmap id for screen ldepth instance */
30 XImage *xi; /* local image if we currenty have the data */
31 int dirty;
32 Rectangle dirtyr;
33 Rectangle r;
34 ulong pc; /* who wrote into xi */
35};
36
37extern int xtblbit;
38extern int x24bitswap;
39extern int plan9tox11[];
40extern int x11toplan9[];
41extern int xscreendepth;
42extern XXDisplay *xdisplay;
43extern Drawable xscreenid;
44extern Visual *xvis;
45extern GC xgcfill, xgcfill0;
46extern int xgcfillcolor, xgcfillcolor0;
47extern GC xgccopy, xgccopy0;
48extern GC xgczero, xgczero0;
49extern int xgczeropm, xgczeropm0;
50extern GC xgcsimplesrc, xgcsimplesrc0;
51extern int xgcsimplecolor, xgcsimplecolor0, xgcsimplepm, xgcsimplepm0;
52extern GC xgcreplsrc, xgcreplsrc0;
53extern int xgcreplsrcpm, xgcreplsrcpm0, xgcreplsrctile, xgcreplsrctile0;
54extern XImage* allocXdata(Memimage*, Rectangle);
55extern void putXdata(Memimage*, Rectangle);
56extern XImage* getXdata(Memimage*, Rectangle);
57extern void freeXdata(Memimage*);
58extern void dirtyXdata(Memimage*, Rectangle);
59extern ulong xscreenchan;
60extern void xfillcolor(Memimage*, Rectangle, ulong);
include/a.out+0−0

Binary file not shown.

include/auth.h+144−0
@@ -0,0 +1,144 @@
1#pragma src "/sys/src/libauth"
2#pragma lib "libauth.a"
3
4/*
5 * Interface for typical callers.
6 */
7
8typedef struct AuthInfo AuthInfo;
9typedef struct Chalstate Chalstate;
10typedef struct Chapreply Chapreply;
11typedef struct MSchapreply MSchapreply;
12typedef struct UserPasswd UserPasswd;
13typedef struct AuthRpc AuthRpc;
14
15enum
16{
17 MAXCHLEN= 256, /* max challenge length */
18 MAXNAMELEN= 256, /* maximum name length */
19 MD5LEN= 16,
20
21 ARok = 0, /* rpc return values */
22 ARdone,
23 ARerror,
24 ARneedkey,
25 ARbadkey,
26 ARwritenext,
27 ARtoosmall,
28 ARtoobig,
29 ARrpcfailure,
30 ARphase,
31
32 AuthRpcMax = 4096,
33};
34
35struct AuthRpc
36{
37 int afd;
38 char ibuf[AuthRpcMax];
39 char obuf[AuthRpcMax];
40 char *arg;
41 uint narg;
42};
43
44struct AuthInfo
45{
46 char *cuid; /* caller id */
47 char *suid; /* server id */
48 char *cap; /* capability (only valid on server side) */
49 int nsecret; /* length of secret */
50 uchar *secret; /* secret */
51};
52
53struct Chalstate
54{
55 char *user;
56 char chal[MAXCHLEN];
57 int nchal;
58 void *resp;
59 int nresp;
60
61/* for implementation only */
62 int afd; /* to factotum */
63 AuthRpc *rpc; /* to factotum */
64 char userbuf[MAXNAMELEN]; /* temp space if needed */
65 int userinchal; /* user was sent to obtain challenge */
66};
67
68struct Chapreply /* for protocol "chap" */
69{
70 uchar id;
71 char resp[MD5LEN];
72};
73
74struct MSchapreply /* for protocol "mschap" */
75{
76 char LMresp[24]; /* Lan Manager response */
77 char NTresp[24]; /* NT response */
78};
79
80struct UserPasswd
81{
82 char *user;
83 char *passwd;
84};
85
86extern int newns(char*, char*);
87extern int addns(char*, char*);
88
89extern int noworld(char*);
90extern int amount(int, char*, int, char*);
91
92/* these two may get generalized away -rsc */
93extern int login(char*, char*, char*);
94extern int httpauth(char*, char*);
95
96typedef struct Attr Attr;
97typedef struct String String;
98enum {
99 AttrNameval, /* name=val -- when matching, must have name=val */
100 AttrQuery, /* name? -- when matching, must be present */
101 AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */
102};
103struct Attr
104{
105 int type;
106 Attr *next;
107 char *name;
108 char *val;
109};
110
111typedef int AuthGetkey(char*);
112
113int _attrfmt(Fmt*);
114Attr *_copyattr(Attr*);
115Attr *_delattr(Attr*, char*);
116Attr *_findattr(Attr*, char*);
117void _freeattr(Attr*);
118Attr *_mkattr(int, char*, char*, Attr*);
119Attr *_parseattr(char*);
120char *_strfindattr(Attr*, char*);
121#pragma varargck type "A" Attr*
122
123extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params);
124extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...);
125extern int auth_getkey(char*);
126extern int (*amount_getkey)(char*);
127extern void auth_freeAI(AuthInfo *ai);
128extern int auth_chuid(AuthInfo *ai, char *ns);
129extern Chalstate *auth_challenge(char*, ...);
130extern AuthInfo* auth_response(Chalstate*);
131extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...);
132extern void auth_freechal(Chalstate*);
133extern AuthInfo* auth_userpasswd(char *user, char *passwd);
134extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...);
135extern AuthInfo* auth_getinfo(AuthRpc *rpc);
136extern AuthRpc* auth_allocrpc(int afd);
137extern Attr* auth_attr(AuthRpc *rpc);
138extern void auth_freerpc(AuthRpc *rpc);
139extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n);
140extern int auth_wep(char*, char*, ...);
141#pragma varargck argpos auth_proxy 3
142#pragma varargck argpos auth_challenge 1
143#pragma varargck argpos auth_respond 3
144#pragma varargck argpos auth_getuserpasswd 2
include/authsrv.h+166−0
@@ -0,0 +1,166 @@
1#pragma src "/sys/src/libauthsrv"
2#pragma lib "libauthsrv.a"
3
4/*
5 * Interface for talking to authentication server.
6 */
7typedef struct Ticket Ticket;
8typedef struct Ticketreq Ticketreq;
9typedef struct Authenticator Authenticator;
10typedef struct Nvrsafe Nvrsafe;
11typedef struct Passwordreq Passwordreq;
12typedef struct OChapreply OChapreply;
13typedef struct OMSchapreply OMSchapreply;
14
15enum
16{
17 ANAMELEN= 28, /* maximum size of name in previous proto */
18 AERRLEN= 64, /* maximum size of errstr in previous proto */
19 DOMLEN= 48, /* length of an authentication domain name */
20 DESKEYLEN= 7, /* length of a des key for encrypt/decrypt */
21 CHALLEN= 8, /* length of a plan9 sk1 challenge */
22 NETCHLEN= 16, /* max network challenge length (used in AS protocol) */
23 CONFIGLEN= 14,
24 SECRETLEN= 32, /* max length of a secret */
25
26 KEYDBOFF= 8, /* length of random data at the start of key file */
27 OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* length of an entry in old key file */
28 KEYDBLEN= OKEYDBLEN+SECRETLEN, /* length of an entry in key file */
29 OMD5LEN= 16,
30};
31
32/* encryption numberings (anti-replay) */
33enum
34{
35 AuthTreq=1, /* ticket request */
36 AuthChal=2, /* challenge box request */
37 AuthPass=3, /* change password */
38 AuthOK=4, /* fixed length reply follows */
39 AuthErr=5, /* error follows */
40 AuthMod=6, /* modify user */
41 AuthApop=7, /* apop authentication for pop3 */
42 AuthOKvar=9, /* variable length reply follows */
43 AuthChap=10, /* chap authentication for ppp */
44 AuthMSchap=11, /* MS chap authentication for ppp */
45 AuthCram=12, /* CRAM verification for IMAP (RFC2195 & rfc2104) */
46 AuthHttp=13, /* http domain login */
47 AuthVNC=14, /* VNC server login (deprecated) */
48
49
50 AuthTs=64, /* ticket encrypted with server's key */
51 AuthTc, /* ticket encrypted with client's key */
52 AuthAs, /* server generated authenticator */
53 AuthAc, /* client generated authenticator */
54 AuthTp, /* ticket encrypted with client's key for password change */
55 AuthHr, /* http reply */
56};
57
58struct Ticketreq
59{
60 char type;
61 char authid[ANAMELEN]; /* server's encryption id */
62 char authdom[DOMLEN]; /* server's authentication domain */
63 char chal[CHALLEN]; /* challenge from server */
64 char hostid[ANAMELEN]; /* host's encryption id */
65 char uid[ANAMELEN]; /* uid of requesting user on host */
66};
67#define TICKREQLEN (3*ANAMELEN+CHALLEN+DOMLEN+1)
68
69struct Ticket
70{
71 char num; /* replay protection */
72 char chal[CHALLEN]; /* server challenge */
73 char cuid[ANAMELEN]; /* uid on client */
74 char suid[ANAMELEN]; /* uid on server */
75 char key[DESKEYLEN]; /* nonce DES key */
76};
77#define TICKETLEN (CHALLEN+2*ANAMELEN+DESKEYLEN+1)
78
79struct Authenticator
80{
81 char num; /* replay protection */
82 char chal[CHALLEN];
83 ulong id; /* authenticator id, ++'d with each auth */
84};
85#define AUTHENTLEN (CHALLEN+4+1)
86
87struct Passwordreq
88{
89 char num;
90 char old[ANAMELEN];
91 char new[ANAMELEN];
92 char changesecret;
93 char secret[SECRETLEN]; /* new secret */
94};
95#define PASSREQLEN (2*ANAMELEN+1+1+SECRETLEN)
96
97struct OChapreply
98{
99 uchar id;
100 char uid[ANAMELEN];
101 char resp[OMD5LEN];
102};
103
104struct OMSchapreply
105{
106 char uid[ANAMELEN];
107 char LMresp[24]; /* Lan Manager response */
108 char NTresp[24]; /* NT response */
109};
110
111/*
112 * convert to/from wire format
113 */
114extern int convT2M(Ticket*, char*, char*);
115extern void convM2T(char*, Ticket*, char*);
116extern void convM2Tnoenc(char*, Ticket*);
117extern int convA2M(Authenticator*, char*, char*);
118extern void convM2A(char*, Authenticator*, char*);
119extern int convTR2M(Ticketreq*, char*);
120extern void convM2TR(char*, Ticketreq*);
121extern int convPR2M(Passwordreq*, char*, char*);
122extern void convM2PR(char*, Passwordreq*, char*);
123
124/*
125 * convert ascii password to DES key
126 */
127extern int opasstokey(char*, char*);
128extern int passtokey(char*, char*);
129
130/*
131 * Nvram interface
132 */
133enum {
134 NVwrite = 1<<0, /* always prompt and rewrite nvram */
135 NVwriteonerr = 1<<1, /* prompt and rewrite nvram when corrupt */
136};
137
138struct Nvrsafe
139{
140 char machkey[DESKEYLEN];
141 uchar machsum;
142 char authkey[DESKEYLEN];
143 uchar authsum;
144 char config[CONFIGLEN];
145 uchar configsum;
146 char authid[ANAMELEN];
147 uchar authidsum;
148 char authdom[DOMLEN];
149 uchar authdomsum;
150};
151
152extern uchar nvcsum(void*, int);
153extern int readnvram(Nvrsafe*, int);
154
155/*
156 * call up auth server
157 */
158extern int authdial(char *netroot, char *authdom);
159
160/*
161 * exchange messages with auth server
162 */
163extern int _asgetticket(int, char*, char*);
164extern int _asrdresp(int, char*, int);
165extern int sslnegotiate(int, Ticket*, char**, char**);
166extern int srvsslnegotiate(int, Ticket*, char**, char**);
include/cursor.h+6−0
@@ -0,0 +1,6 @@
1struct Cursor
2{
3 Point offset;
4 uchar clr[2*16];
5 uchar set[2*16];
6};
include/draw.h+519−0
@@ -0,0 +1,519 @@
1#pragma src "/sys/src/libdraw"
2#pragma lib "libdraw.a"
3
4typedef struct Cachefont Cachefont;
5typedef struct Cacheinfo Cacheinfo;
6typedef struct Cachesubf Cachesubf;
7typedef struct Display Display;
8typedef struct Font Font;
9typedef struct Fontchar Fontchar;
10typedef struct Image Image;
11typedef struct Mouse Mouse;
12typedef struct Point Point;
13typedef struct Rectangle Rectangle;
14typedef struct RGB RGB;
15typedef struct Screen Screen;
16typedef struct Subfont Subfont;
17
18#pragma varargck type "R" Rectangle
19#pragma varargck type "P" Point
20extern int Rfmt(Fmt*);
21extern int Pfmt(Fmt*);
22
23enum
24{
25 DOpaque = 0xFFFFFFFF,
26 DTransparent = 0x00000000, /* only useful for allocimage, memfillcolor */
27 DBlack = 0x000000FF,
28 DWhite = 0xFFFFFFFF,
29 DRed = 0xFF0000FF,
30 DGreen = 0x00FF00FF,
31 DBlue = 0x0000FFFF,
32 DCyan = 0x00FFFFFF,
33 DMagenta = 0xFF00FFFF,
34 DYellow = 0xFFFF00FF,
35 DPaleyellow = 0xFFFFAAFF,
36 DDarkyellow = 0xEEEE9EFF,
37 DDarkgreen = 0x448844FF,
38 DPalegreen = 0xAAFFAAFF,
39 DMedgreen = 0x88CC88FF,
40 DDarkblue = 0x000055FF,
41 DPalebluegreen= 0xAAFFFFFF,
42 DPaleblue = 0x0000BBFF,
43 DBluegreen = 0x008888FF,
44 DGreygreen = 0x55AAAAFF,
45 DPalegreygreen = 0x9EEEEEFF,
46 DYellowgreen = 0x99994CFF,
47 DMedblue = 0x000099FF,
48 DGreyblue = 0x005DBBFF,
49 DPalegreyblue = 0x4993DDFF,
50 DPurpleblue = 0x8888CCFF,
51
52 DNotacolor = 0xFFFFFF00,
53 DNofill = DNotacolor,
54
55};
56
57enum
58{
59 Displaybufsize = 8000,
60 ICOSSCALE = 1024,
61 Borderwidth = 4,
62};
63
64enum
65{
66 /* refresh methods */
67 Refbackup = 0,
68 Refnone = 1,
69 Refmesg = 2
70};
71#define NOREFRESH ((void*)-1)
72
73enum
74{
75 /* line ends */
76 Endsquare = 0,
77 Enddisc = 1,
78 Endarrow = 2,
79 Endmask = 0x1F
80};
81
82#define ARROW(a, b, c) (Endarrow|((a)<<5)|((b)<<14)|((c)<<23))
83
84typedef enum
85{
86 /* Porter-Duff compositing operators */
87 Clear = 0,
88
89 SinD = 8,
90 DinS = 4,
91 SoutD = 2,
92 DoutS = 1,
93
94 S = SinD|SoutD,
95 SoverD = SinD|SoutD|DoutS,
96 SatopD = SinD|DoutS,
97 SxorD = SoutD|DoutS,
98
99 D = DinS|DoutS,
100 DoverS = DinS|DoutS|SoutD,
101 DatopS = DinS|SoutD,
102 DxorS = DoutS|SoutD, /* == SxorD */
103
104 Ncomp = 12,
105} Drawop;
106
107/*
108 * image channel descriptors
109 */
110enum {
111 CRed = 0,
112 CGreen,
113 CBlue,
114 CGrey,
115 CAlpha,
116 CMap,
117 CIgnore,
118 NChan,
119};
120
121#define __DC(type, nbits) ((((type)&15)<<4)|((nbits)&15))
122#define CHAN1(a,b) __DC(a,b)
123#define CHAN2(a,b,c,d) (CHAN1((a),(b))<<8|__DC((c),(d)))
124#define CHAN3(a,b,c,d,e,f) (CHAN2((a),(b),(c),(d))<<8|__DC((e),(f)))
125#define CHAN4(a,b,c,d,e,f,g,h) (CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h)))
126
127#define NBITS(c) ((c)&15)
128#define TYPE(c) (((c)>>4)&15)
129
130enum {
131 GREY1 = CHAN1(CGrey, 1),
132 GREY2 = CHAN1(CGrey, 2),
133 GREY4 = CHAN1(CGrey, 4),
134 GREY8 = CHAN1(CGrey, 8),
135 CMAP8 = CHAN1(CMap, 8),
136 RGB15 = CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5),
137 RGB16 = CHAN3(CRed, 5, CGreen, 6, CBlue, 5),
138 RGB24 = CHAN3(CRed, 8, CGreen, 8, CBlue, 8),
139 BGR24 = CHAN3(CBlue, 8, CGreen, 8, CRed, 8),
140 RGBA32 = CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8),
141 ARGB32 = CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8), /* stupid VGAs */
142 XRGB32 = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8),
143 XBGR32 = CHAN4(CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8),
144};
145
146extern char* chantostr(char*, ulong);
147extern ulong strtochan(char*);
148extern int chantodepth(ulong);
149
150struct Point
151{
152 int x;
153 int y;
154};
155
156struct Rectangle
157{
158 Point min;
159 Point max;
160};
161
162typedef void (*Reffn)(Image*, Rectangle, void*);
163
164struct Screen
165{
166 Display *display; /* display holding data */
167 int id; /* id of system-held Screen */
168 Image *image; /* unused; for reference only */
169 Image *fill; /* color to paint behind windows */
170};
171
172struct Display
173{
174 QLock qlock;
175 int locking; /*program is using lockdisplay */
176 int dirno;
177 int fd;
178 int reffd;
179 int ctlfd;
180 int imageid;
181 int local;
182 void (*error)(Display*, char*);
183 char *devdir;
184 char *windir;
185 char oldlabel[64];
186 ulong dataqid;
187 Image *white;
188 Image *black;
189 Image *opaque;
190 Image *transparent;
191 Image *image;
192 uchar *buf;
193 int bufsize;
194 uchar *bufp;
195 Font *defaultfont;
196 Subfont *defaultsubfont;
197 Image *windows;
198 Image *screenimage;
199 int _isnewdisplay;
200};
201
202struct Image
203{
204 Display *display; /* display holding data */
205 int id; /* id of system-held Image */
206 Rectangle r; /* rectangle in data area, local coords */
207 Rectangle clipr; /* clipping region */
208 int depth; /* number of bits per pixel */
209 ulong chan;
210 int repl; /* flag: data replicates to tile clipr */
211 Screen *screen; /* 0 if not a window */
212 Image *next; /* next in list of windows */
213};
214
215struct RGB
216{
217 ulong red;
218 ulong green;
219 ulong blue;
220};
221
222/*
223 * Subfonts
224 *
225 * given char c, Subfont *f, Fontchar *i, and Point p, one says
226 * i = f->info+c;
227 * draw(b, Rect(p.x+i->left, p.y+i->top,
228 * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
229 * color, f->bits, Pt(i->x, i->top));
230 * p.x += i->width;
231 * to draw characters in the specified color (itself an Image) in Image b.
232 */
233
234struct Fontchar
235{
236 int x; /* left edge of bits */
237 uchar top; /* first non-zero scan-line */
238 uchar bottom; /* last non-zero scan-line + 1 */
239 char left; /* offset of baseline */
240 uchar width; /* width of baseline */
241};
242
243struct Subfont
244{
245 char *name;
246 short n; /* number of chars in font */
247 uchar height; /* height of image */
248 char ascent; /* top of image to baseline */
249 Fontchar *info; /* n+1 character descriptors */
250 Image *bits; /* of font */
251 int ref;
252};
253
254enum
255{
256 /* starting values */
257 LOG2NFCACHE = 6,
258 NFCACHE = (1<<LOG2NFCACHE), /* #chars cached */
259 NFLOOK = 5, /* #chars to scan in cache */
260 NFSUBF = 2, /* #subfonts to cache */
261 /* max value */
262 MAXFCACHE = 1024+NFLOOK, /* upper limit */
263 MAXSUBF = 50, /* generous upper limit */
264 /* deltas */
265 DSUBF = 4,
266 /* expiry ages */
267 SUBFAGE = 10000,
268 CACHEAGE = 10000
269};
270
271struct Cachefont
272{
273 Rune min; /* lowest rune value to be taken from subfont */
274 Rune max; /* highest rune value+1 to be taken from subfont */
275 int offset; /* position in subfont of character at min */
276 char *name; /* stored in font */
277 char *subfontname; /* to access subfont */
278};
279
280struct Cacheinfo
281{
282 ushort x; /* left edge of bits */
283 uchar width; /* width of baseline */
284 schar left; /* offset of baseline */
285 Rune value; /* value of character at this slot in cache */
286 ushort age;
287};
288
289struct Cachesubf
290{
291 ulong age; /* for replacement */
292 Cachefont *cf; /* font info that owns us */
293 Subfont *f; /* attached subfont */
294};
295
296struct Font
297{
298 char *name;
299 Display *display;
300 short height; /* max height of image, interline spacing */
301 short ascent; /* top of image to baseline */
302 short width; /* widest so far; used in caching only */
303 short nsub; /* number of subfonts */
304 ulong age; /* increasing counter; used for LRU */
305 int maxdepth; /* maximum depth of all loaded subfonts */
306 int ncache; /* size of cache */
307 int nsubf; /* size of subfont list */
308 Cacheinfo *cache;
309 Cachesubf *subf;
310 Cachefont **sub; /* as read from file */
311 Image *cacheimage;
312};
313
314#define Dx(r) ((r).max.x-(r).min.x)
315#define Dy(r) ((r).max.y-(r).min.y)
316
317/*
318 * Image management
319 */
320extern Image* _allocimage(Image*, Display*, Rectangle, ulong, int, ulong, int, int);
321extern Image* allocimage(Display*, Rectangle, ulong, int, ulong);
322extern uchar* bufimage(Display*, int);
323extern int bytesperline(Rectangle, int);
324extern void closedisplay(Display*);
325extern void drawerror(Display*, char*);
326extern int flushimage(Display*, int);
327extern int freeimage(Image*);
328extern int _freeimage1(Image*);
329extern int geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
330extern int initdraw(void(*)(Display*, char*), char*, char*);
331extern int newwindow(char*);
332extern Display* initdisplay(char*, char*, void(*)(Display*, char*));
333extern int loadimage(Image*, Rectangle, uchar*, int);
334extern int cloadimage(Image*, Rectangle, uchar*, int);
335extern int getwindow(Display*, int);
336extern int gengetwindow(Display*, char*, Image**, Screen**, int);
337extern Image* readimage(Display*, int, int);
338extern Image* creadimage(Display*, int, int);
339extern int unloadimage(Image*, Rectangle, uchar*, int);
340extern int wordsperline(Rectangle, int);
341extern int writeimage(int, Image*, int);
342extern Image* namedimage(Display*, char*);
343extern int nameimage(Image*, char*, int);
344extern Image* allocimagemix(Display*, ulong, ulong);
345
346/*
347 * Colors
348 */
349extern void readcolmap(Display*, RGB*);
350extern void writecolmap(Display*, RGB*);
351extern ulong setalpha(ulong, uchar);
352
353/*
354 * Windows
355 */
356extern Screen* allocscreen(Image*, Image*, int);
357extern Image* _allocwindow(Image*, Screen*, Rectangle, int, ulong);
358extern Image* allocwindow(Screen*, Rectangle, int, ulong);
359extern void bottomnwindows(Image**, int);
360extern void bottomwindow(Image*);
361extern int freescreen(Screen*);
362extern Screen* publicscreen(Display*, int, ulong);
363extern void topnwindows(Image**, int);
364extern void topwindow(Image*);
365extern int originwindow(Image*, Point, Point);
366
367/*
368 * Geometry
369 */
370extern Point Pt(int, int);
371extern Rectangle Rect(int, int, int, int);
372extern Rectangle Rpt(Point, Point);
373extern Point addpt(Point, Point);
374extern Point subpt(Point, Point);
375extern Point divpt(Point, int);
376extern Point mulpt(Point, int);
377extern int eqpt(Point, Point);
378extern int eqrect(Rectangle, Rectangle);
379extern Rectangle insetrect(Rectangle, int);
380extern Rectangle rectaddpt(Rectangle, Point);
381extern Rectangle rectsubpt(Rectangle, Point);
382extern Rectangle canonrect(Rectangle);
383extern int rectXrect(Rectangle, Rectangle);
384extern int rectinrect(Rectangle, Rectangle);
385extern void combinerect(Rectangle*, Rectangle);
386extern int rectclip(Rectangle*, Rectangle);
387extern int ptinrect(Point, Rectangle);
388extern void replclipr(Image*, int, Rectangle);
389extern int drawreplxy(int, int, int); /* used to be drawsetxy */
390extern Point drawrepl(Rectangle, Point);
391extern int rgb2cmap(int, int, int);
392extern int cmap2rgb(int);
393extern int cmap2rgba(int);
394extern void icossin(int, int*, int*);
395extern void icossin2(int, int, int*, int*);
396
397/*
398 * Graphics
399 */
400extern void draw(Image*, Rectangle, Image*, Image*, Point);
401extern void drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
402extern void gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
403extern void gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
404extern void line(Image*, Point, Point, int, int, int, Image*, Point);
405extern void lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
406extern void poly(Image*, Point*, int, int, int, int, Image*, Point);
407extern void polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
408extern void fillpoly(Image*, Point*, int, int, Image*, Point);
409extern void fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
410extern Point string(Image*, Point, Image*, Point, Font*, char*);
411extern Point stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
412extern Point stringn(Image*, Point, Image*, Point, Font*, char*, int);
413extern Point stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
414extern Point runestring(Image*, Point, Image*, Point, Font*, Rune*);
415extern Point runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
416extern Point runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
417extern Point runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
418extern Point stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
419extern Point stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
420extern Point stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
421extern Point stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
422extern Point runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
423extern Point runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
424extern Point runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
425extern Point runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
426extern Point _string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
427extern Point stringsubfont(Image*, Point, Image*, Subfont*, char*);
428extern int bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
429extern int bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
430extern int bezspline(Image*, Point*, int, int, int, int, Image*, Point);
431extern int bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
432extern int bezsplinepts(Point*, int, Point**);
433extern int fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
434extern int fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
435extern int fillbezspline(Image*, Point*, int, int, Image*, Point);
436extern int fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
437extern void ellipse(Image*, Point, int, int, int, Image*, Point);
438extern void ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
439extern void fillellipse(Image*, Point, int, int, Image*, Point);
440extern void fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
441extern void arc(Image*, Point, int, int, int, Image*, Point, int, int);
442extern void arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
443extern void fillarc(Image*, Point, int, int, Image*, Point, int, int);
444extern void fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
445extern void border(Image*, Rectangle, int, Image*, Point);
446extern void borderop(Image*, Rectangle, int, Image*, Point, Drawop);
447
448/*
449 * Font management
450 */
451extern Font* openfont(Display*, char*);
452extern Font* buildfont(Display*, char*, char*);
453extern void freefont(Font*);
454extern Font* mkfont(Subfont*, Rune);
455extern int cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
456extern void agefont(Font*);
457extern Subfont* allocsubfont(char*, int, int, int, Fontchar*, Image*);
458extern Subfont* lookupsubfont(Display*, char*);
459extern void installsubfont(char*, Subfont*);
460extern void uninstallsubfont(Subfont*);
461extern void freesubfont(Subfont*);
462extern Subfont* readsubfont(Display*, char*, int, int);
463extern Subfont* readsubfonti(Display*, char*, int, Image*, int);
464extern int writesubfont(int, Subfont*);
465extern void _unpackinfo(Fontchar*, uchar*, int);
466extern Point stringsize(Font*, char*);
467extern int stringwidth(Font*, char*);
468extern int stringnwidth(Font*, char*, int);
469extern Point runestringsize(Font*, Rune*);
470extern int runestringwidth(Font*, Rune*);
471extern int runestringnwidth(Font*, Rune*, int);
472extern Point strsubfontwidth(Subfont*, char*);
473extern int loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
474extern char* subfontname(char*, char*, int);
475extern Subfont* _getsubfont(Display*, char*);
476extern Subfont* getdefont(Display*);
477extern void lockdisplay(Display*);
478extern void unlockdisplay(Display*);
479extern int drawlsetrefresh(ulong, int, void*, void*);
480
481/*
482 * Predefined
483 */
484extern uchar defontdata[];
485extern int sizeofdefont;
486extern Point ZP;
487extern Rectangle ZR;
488
489/*
490 * Set up by initdraw()
491 */
492extern Display *display;
493extern Font *font;
494/* extern Image *screen; */
495extern Screen *_screen;
496extern int _cursorfd;
497extern int _drawdebug; /* set to 1 to see errors from flushimage */
498extern void _setdrawop(Display*, Drawop);
499
500#define BGSHORT(p) (((p)[0]<<0) | ((p)[1]<<8))
501#define BGLONG(p) ((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16))
502#define BPSHORT(p, v) ((p)[0]=(v), (p)[1]=((v)>>8))
503#define BPLONG(p, v) (BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16))
504
505/*
506 * Compressed image file parameters and helper routines
507 */
508#define NMATCH 3 /* shortest match possible */
509#define NRUN (NMATCH+31) /* longest match possible */
510#define NMEM 1024 /* window size */
511#define NDUMP 128 /* maximum length of dump */
512#define NCBLOCK 6000 /* size of compressed blocks */
513extern void _twiddlecompressed(uchar*, int);
514extern int _compblocksize(Rectangle, int);
515
516/* XXX backwards helps; should go */
517extern int log2[];
518extern ulong drawld2chan[];
519extern void drawsetdebug(int);
include/dtos.h+10−0
@@ -0,0 +1,10 @@
1#if defined(linux) || defined(IRIX) || defined(SOLARIS) || defined(OSF1) || defined(__FreeBSD__) || defined(__APPLE__)
2# include "unix.h"
3# ifdef __APPLE__
4# define panic dt_panic
5# endif
6#elif defined(WINDOWS)
7# include "winduhz.h"
8#else
9# error "Define an OS"
10#endif
include/fcall.h+110−0
@@ -0,0 +1,110 @@
1#define VERSION9P "9P2000"
2
3#define MAXWELEM 16
4
5typedef
6struct Fcall
7{
8 uchar type;
9 u32int fid;
10 ushort tag;
11 u32int msize; /* Tversion, Rversion */
12 char *version; /* Tversion, Rversion */
13 ushort oldtag; /* Tflush */
14 char *ename; /* Rerror */
15 Qid qid; /* Rattach, Ropen, Rcreate */
16 u32int iounit; /* Ropen, Rcreate */
17 Qid aqid; /* Rauth */
18 u32int afid; /* Tauth, Tattach */
19 char *uname; /* Tauth, Tattach */
20 char *aname; /* Tauth, Tattach */
21 u32int perm; /* Tcreate */
22 char *name; /* Tcreate */
23 uchar mode; /* Tcreate, Topen */
24 u32int newfid; /* Twalk */
25 ushort nwname; /* Twalk */
26 char *wname[MAXWELEM]; /* Twalk */
27 ushort nwqid; /* Rwalk */
28 Qid wqid[MAXWELEM]; /* Rwalk */
29 vlong offset; /* Tread, Twrite */
30 u32int count; /* Tread, Twrite, Rread */
31 char *data; /* Twrite, Rread */
32 ushort nstat; /* Twstat, Rstat */
33 uchar *stat; /* Twstat, Rstat */
34} Fcall;
35
36
37#define GBIT8(p) ((p)[0])
38#define GBIT16(p) ((p)[0]|((p)[1]<<8))
39#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24))
40#define GBIT64(p) ((vlong)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\
41 ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32))
42
43#define PBIT8(p,v) (p)[0]=(v)
44#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
45#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24
46#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\
47 (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56
48
49#define BIT8SZ 1
50#define BIT16SZ 2
51#define BIT32SZ 4
52#define BIT64SZ 8
53#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ)
54
55/* STATFIXLEN includes leading 16-bit count */
56/* The count, however, excludes itself; total size is BIT16SZ+count */
57#define STATFIXLEN (BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ) /* amount of fixed length data in a stat buffer */
58
59#define NOTAG (ushort)~0U /* Dummy tag */
60#define NOFID (u32int)~0U /* Dummy fid */
61#define IOHDRSZ 24 /* ample room for Twrite/Rread header (iounit) */
62
63enum
64{
65 Tversion = 100,
66 Rversion,
67 Tauth = 102,
68 Rauth,
69 Tattach = 104,
70 Rattach,
71 Terror = 106, /* illegal */
72 Rerror,
73 Tflush = 108,
74 Rflush,
75 Twalk = 110,
76 Rwalk,
77 Topen = 112,
78 Ropen,
79 Tcreate = 114,
80 Rcreate,
81 Tread = 116,
82 Rread,
83 Twrite = 118,
84 Rwrite,
85 Tclunk = 120,
86 Rclunk,
87 Tremove = 122,
88 Rremove,
89 Tstat = 124,
90 Rstat,
91 Twstat = 126,
92 Rwstat,
93 Tmax,
94};
95
96uint convM2S(uchar*, uint, Fcall*);
97uint convS2M(Fcall*, uchar*, uint);
98uint sizeS2M(Fcall*);
99
100int statcheck(uchar *abuf, uint nbuf);
101uint convM2D(uchar*, uint, Dir*, char*);
102uint convD2M(Dir*, uchar*, uint);
103uint sizeD2M(Dir*);
104
105int fcallfmt(Fmt*);
106int dirfmt(Fmt*);
107int dirmodefmt(Fmt*);
108
109int read9pmsg(int, void*, uint);
110
include/keyboard.h+42−0
@@ -0,0 +1,42 @@
1#pragma src "/sys/src/libdraw"
2#pragma lib "libdraw.a"
3
4typedef struct Keyboardctl Keyboardctl;
5typedef struct Channel Channel;
6
7struct Keyboardctl
8{
9 Channel *c; /* chan(Rune)[20] */
10
11 char *file;
12 int consfd; /* to cons file */
13 int ctlfd; /* to ctl file */
14 int pid; /* of slave proc */
15};
16
17
18extern Keyboardctl* initkeyboard(char*);
19extern int ctlkeyboard(Keyboardctl*, char*);
20extern void closekeyboard(Keyboardctl*);
21
22enum {
23 KF= 0xF000, /* Rune: beginning of private Unicode space */
24 Spec= 0xF800,
25 /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
26 Khome= KF|0x0D,
27 Kup= KF|0x0E,
28 Kpgup= KF|0x0F,
29 Kprint= KF|0x10,
30 Kleft= KF|0x11,
31 Kright= KF|0x12,
32 Kdown= Spec|0x00,
33 Kview= Spec|0x00,
34 Kpgdown= KF|0x13,
35 Kins= KF|0x14,
36 Kend= KF|0x18,
37
38 Kalt= KF|0x15,
39 Kshift= KF|0x16,
40 Kctl= KF|0x17,
41};
42
include/lib.h+246−0
@@ -0,0 +1,246 @@
1/* avoid name conflicts */
2#define accept pm_accept
3#define listen pm_listen
4#define sleep ksleep
5#define wakeup kwakeup
6#define strtod libstrtod
7#define pow10 libpow10
8
9/* conflicts on some os's */
10#define encrypt libencrypt
11#define decrypt libdecrypt
12#define oserror liboserror
13#define clone libclone
14#define atexit libatexit
15#define log2 liblog2
16#define log liblog
17#define reboot libreboot
18#define srand dtsrand
19#define rand dtrand
20#define nrand dtnrand
21#define lrand dtlrand
22#define lnrand dtlnrand
23#undef timeradd
24#define timeradd xtimeradd
25
26
27#define nil ((void*)0)
28
29typedef unsigned char p9_uchar;
30typedef unsigned int p9_uint;
31typedef unsigned int p9_ulong;
32typedef int p9_long;
33typedef signed char p9_schar;
34typedef unsigned short p9_ushort;
35typedef unsigned short Rune;
36typedef unsigned int p9_u32int;
37typedef p9_u32int mpdigit;
38
39/* make sure we don't conflict with predefined types */
40#define schar p9_schar
41#define uchar p9_uchar
42#define ushort p9_ushort
43#define uint p9_uint
44#define u32int p9_u32int
45
46/* #define long int rather than p9_long so that "unsigned long" is valid */
47#define long int
48#define ulong p9_ulong
49#define vlong p9_vlong
50#define uvlong p9_uvlong
51
52#define nelem(x) (sizeof(x)/sizeof((x)[0]))
53#define USED(x) if(x);else
54#define SET(x)
55
56enum
57{
58 UTFmax = 3, /* maximum bytes per rune */
59 Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
60 Runeself = 0x80, /* rune and UTF sequences are the same (<) */
61 Runeerror = 0x80 /* decoding error in UTF */
62};
63
64/*
65 * new rune routines
66 */
67extern int runetochar(char*, Rune*);
68extern int chartorune(Rune*, char*);
69extern int runelen(long);
70extern int fullrune(char*, int);
71
72extern int wstrtoutf(char*, Rune*, int);
73extern int wstrutflen(Rune*);
74
75/*
76 * rune routines from converted str routines
77 */
78extern long utflen(char*);
79extern char* utfrune(char*, long);
80extern char* utfrrune(char*, long);
81
82/*
83 * Syscall data structures
84 */
85#define MORDER 0x0003 /* mask for bits defining order of mounting */
86#define MREPL 0x0000 /* mount replaces object */
87#define MBEFORE 0x0001 /* mount goes before others in union directory */
88#define MAFTER 0x0002 /* mount goes after others in union directory */
89#define MCREATE 0x0004 /* permit creation in mounted directory */
90#define MCACHE 0x0010 /* cache some data */
91#define MMASK 0x0017 /* all bits on */
92
93#define OREAD 0 /* open for read */
94#define OWRITE 1 /* write */
95#define ORDWR 2 /* read and write */
96#define OEXEC 3 /* execute, == read but check execute permission */
97#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
98#define OCEXEC 32 /* or'ed in, close on exec */
99#define ORCLOSE 64 /* or'ed in, remove on close */
100#define OEXCL 0x1000 /* or'ed in, exclusive create */
101
102#define NCONT 0 /* continue after note */
103#define NDFLT 1 /* terminate after note */
104#define NSAVE 2 /* clear note but hold state */
105#define NRSTR 3 /* restore saved state */
106
107#define ERRMAX 128 /* max length of error string */
108#define KNAMELEN 28 /* max length of name held in kernel */
109
110/* bits in Qid.type */
111#define QTDIR 0x80 /* type bit for directories */
112#define QTAPPEND 0x40 /* type bit for append only files */
113#define QTEXCL 0x20 /* type bit for exclusive use files */
114#define QTMOUNT 0x10 /* type bit for mounted channel */
115#define QTAUTH 0x08 /* type bit for authentication file */
116#define QTFILE 0x00 /* plain file */
117
118/* bits in Dir.mode */
119#define DMDIR 0x80000000 /* mode bit for directories */
120#define DMAPPEND 0x40000000 /* mode bit for append only files */
121#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
122#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
123#define DMAUTH 0x08000000 /* mode bit for authentication files */
124#define DMREAD 0x4 /* mode bit for read permission */
125#define DMWRITE 0x2 /* mode bit for write permission */
126#define DMEXEC 0x1 /* mode bit for execute permission */
127
128typedef struct Lock
129{
130 long key;
131} Lock;
132
133typedef struct QLock
134{
135 Lock lk;
136 struct Proc *hold;
137 struct Proc *first;
138 struct Proc *last;
139} QLock;
140
141typedef
142struct Qid
143{
144 uvlong path;
145 ulong vers;
146 uchar type;
147} Qid;
148
149typedef
150struct Dir {
151 /* system-modified data */
152 ushort type; /* server type */
153 uint dev; /* server subtype */
154 /* file data */
155 Qid qid; /* unique id from server */
156 ulong mode; /* permissions */
157 ulong atime; /* last read time */
158 ulong mtime; /* last write time */
159 vlong length; /* file length */
160 char *name; /* last element of path */
161 char *uid; /* owner name */
162 char *gid; /* group name */
163 char *muid; /* last modifier name */
164} Dir;
165
166typedef
167struct Waitmsg
168{
169 int pid; /* of loved one */
170 ulong time[3]; /* of loved one & descendants */
171 char *msg;
172} Waitmsg;
173
174/*
175 * print routines
176 */
177typedef struct Fmt Fmt;
178struct Fmt{
179 uchar runes; /* output buffer is runes or chars? */
180 void *start; /* of buffer */
181 void *to; /* current place in the buffer */
182 void *stop; /* end of the buffer; overwritten if flush fails */
183 int (*flush)(Fmt *); /* called when to == stop */
184 void *farg; /* to make flush a closure */
185 int nfmt; /* num chars formatted so far */
186 va_list args; /* args passed to dofmt */
187 int r; /* % format Rune */
188 int width;
189 int prec;
190 ulong flags;
191};
192
193enum{
194 FmtWidth = 1,
195 FmtLeft = FmtWidth << 1,
196 FmtPrec = FmtLeft << 1,
197 FmtSharp = FmtPrec << 1,
198 FmtSpace = FmtSharp << 1,
199 FmtSign = FmtSpace << 1,
200 FmtZero = FmtSign << 1,
201 FmtUnsigned = FmtZero << 1,
202 FmtShort = FmtUnsigned << 1,
203 FmtLong = FmtShort << 1,
204 FmtVLong = FmtLong << 1,
205 FmtComma = FmtVLong << 1,
206 FmtByte = FmtComma << 1,
207
208 FmtFlag = FmtByte << 1
209};
210
211extern int print(char*, ...);
212extern char* seprint(char*, char*, char*, ...);
213extern char* vseprint(char*, char*, char*, va_list);
214extern int snprint(char*, int, char*, ...);
215extern int vsnprint(char*, int, char*, va_list);
216extern char* smprint(char*, ...);
217extern char* vsmprint(char*, va_list);
218extern int sprint(char*, char*, ...);
219extern int fprint(int, char*, ...);
220extern int vfprint(int, char*, va_list);
221
222extern int (*doquote)(int);
223extern int runesprint(Rune*, char*, ...);
224extern int runesnprint(Rune*, int, char*, ...);
225extern int runevsnprint(Rune*, int, char*, va_list);
226extern Rune* runeseprint(Rune*, Rune*, char*, ...);
227extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
228extern Rune* runesmprint(char*, ...);
229extern Rune* runevsmprint(char*, va_list);
230
231extern int fmtfdinit(Fmt*, int, char*, int);
232extern int fmtfdflush(Fmt*);
233extern int fmtstrinit(Fmt*);
234extern int fmtinstall(int, int (*)(Fmt*));
235extern char* fmtstrflush(Fmt*);
236extern int runefmtstrinit(Fmt*);
237extern Rune* runefmtstrflush(Fmt*);
238
239extern void* mallocz(ulong, int);
240
241extern void srand(long);
242extern int rand(void);
243extern int nrand(int);
244extern long lrand(void);
245extern long lnrand(long);
246extern double frand(void);
include/libc.h+3−0
@@ -0,0 +1,3 @@
1#include "lib.h"
2#include "user.h"
3
include/libsec.h+340−0
@@ -0,0 +1,340 @@
1
2#ifndef _MPINT
3typedef struct mpint mpint;
4#endif
5
6/////////////////////////////////////////////////////////
7// AES definitions
8/////////////////////////////////////////////////////////
9
10enum
11{
12 AESbsize= 16,
13 AESmaxkey= 32,
14 AESmaxrounds= 14
15};
16
17typedef struct AESstate AESstate;
18struct AESstate
19{
20 ulong setup;
21 int rounds;
22 int keybytes;
23 uchar key[AESmaxkey]; /* unexpanded key */
24 u32int ekey[4*(AESmaxrounds + 1)]; /* encryption key */
25 u32int dkey[4*(AESmaxrounds + 1)]; /* decryption key */
26 uchar ivec[AESbsize]; /* initialization vector */
27};
28
29void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec);
30void aesCBCencrypt(uchar *p, int len, AESstate *s);
31void aesCBCdecrypt(uchar *p, int len, AESstate *s);
32
33/////////////////////////////////////////////////////////
34// Blowfish Definitions
35/////////////////////////////////////////////////////////
36
37enum
38{
39 BFbsize = 8,
40 BFrounds = 16
41};
42
43// 16-round Blowfish
44typedef struct BFstate BFstate;
45struct BFstate
46{
47 ulong setup;
48
49 uchar key[56];
50 uchar ivec[8];
51
52 u32int pbox[BFrounds+2];
53 u32int sbox[1024];
54};
55
56void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec);
57void bfCBCencrypt(uchar*, int, BFstate*);
58void bfCBCdecrypt(uchar*, int, BFstate*);
59void bfECBencrypt(uchar*, int, BFstate*);
60void bfECBdecrypt(uchar*, int, BFstate*);
61
62/////////////////////////////////////////////////////////
63// DES definitions
64/////////////////////////////////////////////////////////
65
66enum
67{
68 DESbsize= 8
69};
70
71// single des
72typedef struct DESstate DESstate;
73struct DESstate
74{
75 ulong setup;
76 uchar key[8]; /* unexpanded key */
77 ulong expanded[32]; /* expanded key */
78 uchar ivec[8]; /* initialization vector */
79};
80
81void setupDESstate(DESstate *s, uchar key[8], uchar *ivec);
82void des_key_setup(uchar[8], ulong[32]);
83void block_cipher(ulong*, uchar*, int);
84void desCBCencrypt(uchar*, int, DESstate*);
85void desCBCdecrypt(uchar*, int, DESstate*);
86void desECBencrypt(uchar*, int, DESstate*);
87void desECBdecrypt(uchar*, int, DESstate*);
88
89// for backward compatibility with 7 byte DES key format
90void des56to64(uchar *k56, uchar *k64);
91void des64to56(uchar *k64, uchar *k56);
92void key_setup(uchar[7], ulong[32]);
93
94// triple des encrypt/decrypt orderings
95enum {
96 DES3E= 0,
97 DES3D= 1,
98 DES3EEE= 0,
99 DES3EDE= 2,
100 DES3DED= 5,
101 DES3DDD= 7
102};
103
104typedef struct DES3state DES3state;
105struct DES3state
106{
107 ulong setup;
108 uchar key[3][8]; /* unexpanded key */
109 ulong expanded[3][32]; /* expanded key */
110 uchar ivec[8]; /* initialization vector */
111};
112
113void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec);
114void triple_block_cipher(ulong keys[3][32], uchar*, int);
115void des3CBCencrypt(uchar*, int, DES3state*);
116void des3CBCdecrypt(uchar*, int, DES3state*);
117void des3ECBencrypt(uchar*, int, DES3state*);
118void des3ECBdecrypt(uchar*, int, DES3state*);
119
120/////////////////////////////////////////////////////////
121// digests
122/////////////////////////////////////////////////////////
123
124enum
125{
126 SHA1dlen= 20, /* SHA digest length */
127 MD4dlen= 16, /* MD4 digest length */
128 MD5dlen= 16 /* MD5 digest length */
129};
130
131typedef struct DigestState DigestState;
132struct DigestState
133{
134 ulong len;
135 u32int state[5];
136 uchar buf[128];
137 int blen;
138 char malloced;
139 char seeded;
140};
141typedef struct DigestState SHAstate; /* obsolete name */
142typedef struct DigestState SHA1state;
143typedef struct DigestState MD5state;
144typedef struct DigestState MD4state;
145
146DigestState* md4(uchar*, ulong, uchar*, DigestState*);
147DigestState* md5(uchar*, ulong, uchar*, DigestState*);
148DigestState* sha1(uchar*, ulong, uchar*, DigestState*);
149DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
150DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
151char* sha1pickle(SHA1state*);
152SHA1state* sha1unpickle(char*);
153
154/////////////////////////////////////////////////////////
155// random number generation
156/////////////////////////////////////////////////////////
157void genrandom(uchar *buf, int nbytes);
158void prng(uchar *buf, int nbytes);
159ulong fastrand(void);
160ulong nfastrand(ulong);
161
162/////////////////////////////////////////////////////////
163// primes
164/////////////////////////////////////////////////////////
165void genprime(mpint *p, int n, int accuracy); // generate an n bit probable prime
166void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); // prime and generator
167void genstrongprime(mpint *p, int n, int accuracy); // generate an n bit strong prime
168void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]);
169int probably_prime(mpint *n, int nrep); // miller-rabin test
170int smallprimetest(mpint *p); // returns -1 if not prime, 0 otherwise
171
172/////////////////////////////////////////////////////////
173// rc4
174/////////////////////////////////////////////////////////
175typedef struct RC4state RC4state;
176struct RC4state
177{
178 uchar state[256];
179 uchar x;
180 uchar y;
181};
182
183void setupRC4state(RC4state*, uchar*, int);
184void rc4(RC4state*, uchar*, int);
185void rc4skip(RC4state*, int);
186void rc4back(RC4state*, int);
187
188/////////////////////////////////////////////////////////
189// rsa
190/////////////////////////////////////////////////////////
191typedef struct RSApub RSApub;
192typedef struct RSApriv RSApriv;
193
194// public/encryption key
195struct RSApub
196{
197 mpint *n; // modulus
198 mpint *ek; // exp (encryption key)
199};
200
201// private/decryption key
202struct RSApriv
203{
204 RSApub pub;
205
206 mpint *dk; // exp (decryption key)
207
208 // precomputed values to help with chinese remainder theorem calc
209 mpint *p;
210 mpint *q;
211 mpint *kp; // dk mod p-1
212 mpint *kq; // dk mod q-1
213 mpint *c2; // (inv p) mod q
214};
215
216RSApriv* rsagen(int nlen, int elen, int rounds);
217RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q);
218mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out);
219mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out);
220RSApub* rsapuballoc(void);
221void rsapubfree(RSApub*);
222RSApriv* rsaprivalloc(void);
223void rsaprivfree(RSApriv*);
224RSApub* rsaprivtopub(RSApriv*);
225RSApub* X509toRSApub(uchar*, int, char*, int);
226RSApriv* asn1toRSApriv(uchar*, int);
227void asn1dump(uchar *der, int len);
228uchar* decodepem(char *s, char *type, int *len);
229uchar* X509gen(RSApriv *priv, char *subj, ulong valid[2], int *certlen);
230uchar* X509req(RSApriv *priv, char *subj, int *certlen);
231char* X509verify(uchar *cert, int ncert, RSApub *pk);
232void X509dump(uchar *cert, int ncert);
233/////////////////////////////////////////////////////////
234// elgamal
235/////////////////////////////////////////////////////////
236typedef struct EGpub EGpub;
237typedef struct EGpriv EGpriv;
238typedef struct EGsig EGsig;
239
240// public/encryption key
241struct EGpub
242{
243 mpint *p; // modulus
244 mpint *alpha; // generator
245 mpint *key; // (encryption key) alpha**secret mod p
246};
247
248// private/decryption key
249struct EGpriv
250{
251 EGpub pub;
252 mpint *secret; // (decryption key)
253};
254
255// signature
256struct EGsig
257{
258 mpint *r, *s;
259};
260
261EGpriv* eggen(int nlen, int rounds);
262mpint* egencrypt(EGpub *k, mpint *in, mpint *out);
263mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out);
264EGsig* egsign(EGpriv *k, mpint *m);
265int egverify(EGpub *k, EGsig *sig, mpint *m);
266EGpub* egpuballoc(void);
267void egpubfree(EGpub*);
268EGpriv* egprivalloc(void);
269void egprivfree(EGpriv*);
270EGsig* egsigalloc(void);
271void egsigfree(EGsig*);
272EGpub* egprivtopub(EGpriv*);
273
274/////////////////////////////////////////////////////////
275// dsa
276/////////////////////////////////////////////////////////
277typedef struct DSApub DSApub;
278typedef struct DSApriv DSApriv;
279typedef struct DSAsig DSAsig;
280
281// public/encryption key
282struct DSApub
283{
284 mpint *p; // modulus
285 mpint *q; // group order, q divides p-1
286 mpint *alpha; // group generator
287 mpint *key; // (encryption key) alpha**secret mod p
288};
289
290// private/decryption key
291struct DSApriv
292{
293 DSApub pub;
294 mpint *secret; // (decryption key)
295};
296
297// signature
298struct DSAsig
299{
300 mpint *r, *s;
301};
302
303DSApriv* dsagen(DSApub *opub);
304DSAsig* dsasign(DSApriv *k, mpint *m);
305int dsaverify(DSApub *k, DSAsig *sig, mpint *m);
306DSApub* dsapuballoc(void);
307void dsapubfree(DSApub*);
308DSApriv* dsaprivalloc(void);
309void dsaprivfree(DSApriv*);
310DSAsig* dsasigalloc(void);
311void dsasigfree(DSAsig*);
312DSApub* dsaprivtopub(DSApriv*);
313
314/////////////////////////////////////////////////////////
315// TLS
316/////////////////////////////////////////////////////////
317typedef struct Thumbprint{
318 struct Thumbprint *next;
319 uchar sha1[SHA1dlen];
320} Thumbprint;
321
322typedef struct TLSconn{
323 char dir[40]; // connection directory
324 uchar *cert; // certificate (local on input, remote on output)
325 uchar *sessionID;
326 int certlen, sessionIDlen;
327 int (*trace)(char*fmt, ...);
328} TLSconn;
329
330// tlshand.c
331extern int tlsClient(int fd, TLSconn *c);
332extern int tlsServer(int fd, TLSconn *c);
333
334// thumb.c
335extern Thumbprint* initThumbprints(char *ok, char *crl);
336extern void freeThumbprints(Thumbprint *ok);
337extern int okThumbprint(uchar *sha1, Thumbprint *ok);
338
339// readcert.c
340extern uchar *readcert(char *filename, int *pcertlen);
include/memdraw.h+200−0
@@ -0,0 +1,200 @@
1#pragma src "/sys/src/libmemdraw"
2#pragma lib "libmemdraw.a"
3
4typedef struct Memimage Memimage;
5typedef struct Memdata Memdata;
6typedef struct Memsubfont Memsubfont;
7typedef struct Memlayer Memlayer;
8typedef struct Memcmap Memcmap;
9typedef struct Memdrawparam Memdrawparam;
10
11/*
12 * Memdata is allocated from main pool, but .data from the image pool.
13 * Memdata is allocated separately to permit patching its pointer after
14 * compaction when windows share the image data.
15 * The first word of data is a back pointer to the Memdata, to find
16 * The word to patch.
17 */
18
19struct Memdata
20{
21 ulong *base; /* allocated data pointer */
22 uchar *bdata; /* pointer to first byte of actual data; word-aligned */
23 int ref; /* number of Memimages using this data */
24 void* imref;
25 int allocd; /* is this malloc'd? */
26};
27
28enum {
29 Frepl = 1<<0, /* is replicated */
30 Fsimple = 1<<1, /* is 1x1 */
31 Fgrey = 1<<2, /* is grey */
32 Falpha = 1<<3, /* has explicit alpha */
33 Fcmap = 1<<4, /* has cmap channel */
34 Fbytes = 1<<5, /* has only 8-bit channels */
35};
36
37struct Memimage
38{
39 Rectangle r; /* rectangle in data area, local coords */
40 Rectangle clipr; /* clipping region */
41 int depth; /* number of bits of storage per pixel */
42 int nchan; /* number of channels */
43 ulong chan; /* channel descriptions */
44 Memcmap *cmap;
45
46 Memdata *data; /* pointer to data; shared by windows in this image */
47 int zero; /* data->bdata+zero==&byte containing (0,0) */
48 ulong width; /* width in words of a single scan line */
49 Memlayer *layer; /* nil if not a layer*/
50 ulong flags;
51
52 int shift[NChan];
53 int mask[NChan];
54 int nbits[NChan];
55
56 void *X;
57};
58
59struct Memcmap
60{
61 uchar cmap2rgb[3*256];
62 uchar rgb2cmap[16*16*16];
63};
64
65/*
66 * Subfonts
67 *
68 * given char c, Subfont *f, Fontchar *i, and Point p, one says
69 * i = f->info+c;
70 * draw(b, Rect(p.x+i->left, p.y+i->top,
71 * p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
72 * color, f->bits, Pt(i->x, i->top));
73 * p.x += i->width;
74 * to draw characters in the specified color (itself a Memimage) in Memimage b.
75 */
76
77struct Memsubfont
78{
79 char *name;
80 short n; /* number of chars in font */
81 uchar height; /* height of bitmap */
82 char ascent; /* top of bitmap to baseline */
83 Fontchar *info; /* n+1 character descriptors */
84 Memimage *bits; /* of font */
85};
86
87/*
88 * Encapsulated parameters and information for sub-draw routines.
89 */
90enum {
91 Simplesrc=1<<0,
92 Simplemask=1<<1,
93 Replsrc=1<<2,
94 Replmask=1<<3,
95 Fullmask=1<<4,
96};
97struct Memdrawparam
98{
99 Memimage *dst;
100 Rectangle r;
101 Memimage *src;
102 Rectangle sr;
103 Memimage *mask;
104 Rectangle mr;
105 int op;
106
107 ulong state;
108 ulong mval; /* if Simplemask, the mask pixel in mask format */
109 ulong mrgba; /* mval in rgba */
110 ulong sval; /* if Simplesrc, the source pixel in src format */
111 ulong srgba; /* sval in rgba */
112 ulong sdval; /* sval in dst format */
113};
114
115/*
116 * Memimage management
117 */
118
119extern Memimage* allocmemimage(Rectangle, ulong);
120extern Memimage* _allocmemimage(Rectangle, ulong);
121extern Memimage* allocmemimaged(Rectangle, ulong, Memdata*, void*);
122extern Memimage* readmemimage(int);
123extern Memimage* creadmemimage(int);
124extern int writememimage(int, Memimage*);
125extern void freememimage(Memimage*);
126extern int _loadmemimage(Memimage*, Rectangle, uchar*, int);
127extern int _cloadmemimage(Memimage*, Rectangle, uchar*, int);
128extern int _unloadmemimage(Memimage*, Rectangle, uchar*, int);
129extern int loadmemimage(Memimage*, Rectangle, uchar*, int);
130extern int cloadmemimage(Memimage*, Rectangle, uchar*, int);
131extern int unloadmemimage(Memimage*, Rectangle, uchar*, int);
132extern ulong* wordaddr(Memimage*, Point);
133extern uchar* byteaddr(Memimage*, Point);
134extern int drawclip(Memimage*, Rectangle*, Memimage*, Point*, Memimage*, Point*, Rectangle*, Rectangle*);
135extern void memfillcolor(Memimage*, ulong);
136extern int memsetchan(Memimage*, ulong);
137
138/*
139 * Graphics
140 */
141extern void memdraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
142extern void memline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int);
143extern void mempoly(Memimage*, Point*, int, int, int, int, Memimage*, Point, int);
144extern void memfillpoly(Memimage*, Point*, int, int, Memimage*, Point, int);
145extern void _memfillpolysc(Memimage*, Point*, int, int, Memimage*, Point, int, int, int, int);
146extern Memdrawparam* _memimagedrawsetup(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
147extern void _memimagedraw(Memdrawparam*);
148extern void memimagedraw(Memimage*, Rectangle, Memimage*, Point, Memimage*, Point, int);
149extern int hwdraw(Memdrawparam*);
150extern void memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, int);
151extern void _memimageline(Memimage*, Point, Point, int, int, int, Memimage*, Point, Rectangle, int);
152extern Point memimagestring(Memimage*, Point, Memimage*, Point, Memsubfont*, char*);
153extern void memellipse(Memimage*, Point, int, int, int, Memimage*, Point, int);
154extern void memarc(Memimage*, Point, int, int, int, Memimage*, Point, int, int, int);
155extern Rectangle memlinebbox(Point, Point, int, int, int);
156extern int memlineendsize(int);
157extern void _memmkcmap(void);
158extern void memimageinit(void);
159
160/*
161 * Subfont management
162 */
163extern Memsubfont* allocmemsubfont(char*, int, int, int, Fontchar*, Memimage*);
164extern Memsubfont* openmemsubfont(char*);
165extern void freememsubfont(Memsubfont*);
166extern Point memsubfontwidth(Memsubfont*, char*);
167extern Memsubfont* getmemdefont(void);
168
169/*
170 * Predefined
171 */
172extern Memimage* memwhite;
173extern Memimage* memblack;
174extern Memimage* memopaque;
175extern Memimage* memtransparent;
176extern Memcmap *memdefcmap;
177
178/*
179 * Kernel interface
180 */
181void memimagemove(void*, void*);
182
183/*
184 * Kernel cruft
185 */
186extern void rdb(void);
187extern int iprint(char*, ...);
188#pragma varargck argpos iprint 1
189extern int drawdebug;
190
191/*
192 * doprint interface: numbconv bit strings
193 */
194#pragma varargck type "llb" vlong
195#pragma varargck type "llb" uvlong
196#pragma varargck type "lb" long
197#pragma varargck type "lb" ulong
198#pragma varargck type "b" int
199#pragma varargck type "b" uint
200
include/memlayer.h+51−0
@@ -0,0 +1,51 @@
1#pragma src "/sys/src/libmemlayer"
2#pragma lib "libmemlayer.a"
3
4typedef struct Memscreen Memscreen;
5typedef void (*Refreshfn)(Memimage*, Rectangle, void*);
6
7struct Memscreen
8{
9 Memimage *frontmost; /* frontmost layer on screen */
10 Memimage *rearmost; /* rearmost layer on screen */
11 Memimage *image; /* upon which all layers are drawn */
12 Memimage *fill; /* if non-zero, picture to use when repainting */
13};
14
15struct Memlayer
16{
17 Rectangle screenr; /* true position of layer on screen */
18 Point delta; /* add delta to go from image coords to screen */
19 Memscreen *screen; /* screen this layer belongs to */
20 Memimage *front; /* window in front of this one */
21 Memimage *rear; /* window behind this one*/
22 int clear; /* layer is fully visible */
23 Memimage *save; /* save area for obscured parts */
24 Refreshfn refreshfn; /* function to call to refresh obscured parts if save==nil */
25 void *refreshptr; /* argument to refreshfn */
26};
27
28/*
29 * These functions accept local coordinates
30 */
31int memload(Memimage*, Rectangle, uchar*, int, int);
32int memunload(Memimage*, Rectangle, uchar*, int);
33
34/*
35 * All these functions accept screen coordinates, not local ones.
36 */
37void _memlayerop(void (*fn)(Memimage*, Rectangle, Rectangle, void*, int), Memimage*, Rectangle, Rectangle, void*);
38Memimage* memlalloc(Memscreen*, Rectangle, Refreshfn, void*, ulong);
39void memldelete(Memimage*);
40void memlfree(Memimage*);
41void memltofront(Memimage*);
42void memltofrontn(Memimage**, int);
43void _memltofrontfill(Memimage*, int);
44void memltorear(Memimage*);
45void memltorearn(Memimage**, int);
46int memlsetrefresh(Memimage*, Refreshfn, void*);
47void memlhide(Memimage*, Rectangle);
48void memlexpose(Memimage*, Rectangle);
49void _memlsetclear(Memscreen*);
50int memlorigin(Memimage*, Point, Point);
51void memlnorefresh(Memimage*, Rectangle, void*);
include/mp.h+134−0
@@ -0,0 +1,134 @@
1#define _MPINT 1
2
3// the code assumes mpdigit to be at least an int
4// mpdigit must be an atomic type. mpdigit is defined
5// in the architecture specific u.h
6
7typedef struct mpint mpint;
8
9struct mpint
10{
11 int sign; // +1 or -1
12 int size; // allocated digits
13 int top; // significant digits
14 mpdigit *p;
15 char flags;
16};
17
18enum
19{
20 MPstatic= 0x01,
21 Dbytes= sizeof(mpdigit), // bytes per digit
22 Dbits= Dbytes*8 // bits per digit
23};
24
25// allocation
26void mpsetminbits(int n); // newly created mpint's get at least n bits
27mpint* mpnew(int n); // create a new mpint with at least n bits
28void mpfree(mpint *b);
29void mpbits(mpint *b, int n); // ensure that b has at least n bits
30void mpnorm(mpint *b); // dump leading zeros
31mpint* mpcopy(mpint *b);
32void mpassign(mpint *old, mpint *new);
33
34// random bits
35mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b);
36
37// conversion
38mpint* strtomp(char*, char**, int, mpint*); // ascii
39int mpfmt(Fmt*);
40char* mptoa(mpint*, int, char*, int);
41mpint* letomp(uchar*, uint, mpint*); // byte array, little-endian
42int mptole(mpint*, uchar*, uint, uchar**);
43mpint* betomp(uchar*, uint, mpint*); // byte array, little-endian
44int mptobe(mpint*, uchar*, uint, uchar**);
45uint mptoui(mpint*); // unsigned int
46mpint* uitomp(uint, mpint*);
47int mptoi(mpint*); // int
48mpint* itomp(int, mpint*);
49uvlong mptouv(mpint*); // unsigned vlong
50mpint* uvtomp(uvlong, mpint*);
51vlong mptov(mpint*); // vlong
52mpint* vtomp(vlong, mpint*);
53
54// divide 2 digits by one
55void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
56
57// in the following, the result mpint may be
58// the same as one of the inputs.
59void mpadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
60void mpsub(mpint *b1, mpint *b2, mpint *diff); // diff = b1-b2
61void mpleft(mpint *b, int shift, mpint *res); // res = b<<shift
62void mpright(mpint *b, int shift, mpint *res); // res = b>>shift
63void mpmul(mpint *b1, mpint *b2, mpint *prod); // prod = b1*b2
64void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); // res = b**e mod m
65void mpmod(mpint *b, mpint *m, mpint *remainder); // remainder = b mod m
66
67// quotient = dividend/divisor, remainder = dividend % divisor
68void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder);
69
70// return neg, 0, pos as b1-b2 is neg, 0, pos
71int mpcmp(mpint *b1, mpint *b2);
72
73// extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d
74void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y);
75
76// res = b**-1 mod m
77void mpinvert(mpint *b, mpint *m, mpint *res);
78
79// bit counting
80int mpsignif(mpint*); // number of sigificant bits in mantissa
81int mplowbits0(mpint*); // k, where n = 2**k * q for odd q
82
83// well known constants
84extern mpint *mpzero, *mpone, *mptwo;
85
86// sum[0:alen] = a[0:alen-1] + b[0:blen-1]
87// prereq: alen >= blen, sum has room for alen+1 digits
88void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum);
89
90// diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
91// prereq: alen >= blen, diff has room for alen digits
92void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff);
93
94// p[0:n] += m * b[0:n-1]
95// prereq: p has room for n+1 digits
96void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p);
97
98// p[0:n] -= m * b[0:n-1]
99// prereq: p has room for n+1 digits
100int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p);
101
102// p[0:alen*blen-1] = a[0:alen-1] * b[0:blen-1]
103// prereq: alen >= blen, p has room for m*n digits
104void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p);
105
106// sign of a - b or zero if the same
107int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen);
108
109// divide the 2 digit dividend by the one digit divisor and stick in quotient
110// we assume that the result is one digit - overflow is all 1's
111void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient);
112
113// playing with magnitudes
114int mpmagcmp(mpint *b1, mpint *b2);
115void mpmagadd(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
116void mpmagsub(mpint *b1, mpint *b2, mpint *sum); // sum = b1+b2
117
118// chinese remainder theorem
119typedef struct CRTpre CRTpre; // precomputed values for converting
120 // twixt residues and mpint
121typedef struct CRTres CRTres; // residue form of an mpint
122
123struct CRTres
124{
125 int n; // number of residues
126 mpint *r[1]; // residues
127};
128
129CRTpre* crtpre(int, mpint**); // precompute conversion values
130CRTres* crtin(CRTpre*, mpint*); // convert mpint to residues
131void crtout(CRTpre*, CRTres*, mpint*); // convert residues to mpint
132void crtprefree(CRTpre*);
133void crtresfree(CRTres*);
134
include/u.h+26−0
@@ -0,0 +1,26 @@
1#include "dtos.h"
2
3/* avoid name conflicts */
4#undef accept
5#undef listen
6
7/* sys calls */
8#undef bind
9#undef chdir
10#undef close
11#undef create
12#undef dup
13#undef export
14#undef fstat
15#undef fwstat
16#undef mount
17#undef open
18#undef start
19#undef read
20#undef remove
21#undef seek
22#undef stat
23#undef write
24#undef wstat
25#undef unmount
26#undef pipe
include/unix.h+14−0
@@ -0,0 +1,14 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <math.h>
5#include <fcntl.h>
6#include <setjmp.h>
7#include <time.h>
8#include <assert.h>
9#include <unistd.h>
10#include <stdarg.h>
11
12
13typedef long long p9_vlong;
14typedef unsigned long long p9_uvlong;
include/user.h+65−0
@@ -0,0 +1,65 @@
1/* sys calls */
2#define bind sysbind
3#define chdir syschdir
4#define close sysclose
5#define create syscreate
6#define dup sysdup
7#define export sysexport
8#define fstat sysfstat
9#define fwstat sysfwstat
10#define mount sysmount
11#define open sysopen
12#define read sysread
13#define remove sysremove
14#define seek sysseek
15#define stat sysstat
16#define write syswrite
17#define wstat syswstat
18#define unmount sysunmount
19#define pipe syspipe
20#define rendezvous sysrendezvous
21#define getpid sysgetpid
22#define time systime
23#define nsec sysnsec
24#define pread syspread
25#define pwrite syspwrite
26
27extern int bind(char*, char*, int);
28extern int chdir(char*);
29extern int close(int);
30extern int create(char*, int, ulong);
31extern int dup(int, int);
32extern int export(int);
33extern int fstat(int, uchar*, int);
34extern int fwstat(int, uchar*, int);
35extern int mount(int, int, char*, int, char*);
36extern int unmount(char*, char*);
37extern int open(char*, int);
38extern int pipe(int*);
39extern long read(int, void*, long);
40extern long readn(int, void*, long);
41extern int remove(char*);
42extern vlong seek(int, vlong, int);
43extern int stat(char*, uchar*, int);
44extern long write(int, void*, long);
45extern int wstat(char*, uchar*, int);
46
47extern Dir *dirstat(char*);
48extern Dir *dirfstat(int);
49extern int dirwstat(char*, Dir*);
50extern int dirfwstat(int, Dir*);
51extern long dirread(int, Dir*, long);
52
53/*
54 * network dialing and authentication
55 */
56#define NETPATHLEN 40
57extern int accept(int, char*);
58extern int announce(char*, char*);
59extern int dial(char*, char*, char*, int*);
60extern int hangup(int);
61extern int listen(char*, char*);
62extern char *netmkaddr(char*, char*, char*);
63extern int reject(int, char*, char*);
64
65extern char* argv0;
include/x+0−0

Empty file added.

include/x.c+6−0
@@ -0,0 +1,6 @@
1#include <stdio.h>
2
3void
4main(void)
5{
6}
kern/Makefile+50−0
@@ -0,0 +1,50 @@
1LIB=libkern.a
2CC=gcc
3CFLAGS=-I../include -I. -c -ggdb -D_THREAD_SAFE -pthread
4O=o
5#CC=cl
6#CFLAGS=-c -nologo -W3 -YX -Zi -MT -Zl -I../include -DWINDOWS
7#O=obj
8
9OFILES=\
10 allocb.$O\
11 cache.$O\
12 chan.$O\
13 data.$O\
14 dev.$O\
15 devcons.$O\
16 devdraw.$O\
17 devfs.$O\
18 devip.$O\
19 devip-posix.$O\
20 devmnt.$O\
21 devmouse.$O\
22 devpipe.$O\
23 devroot.$O\
24 devssl.$O\
25 devtab.$O\
26 error.$O\
27 parse.$O\
28 pgrp.$O\
29 posix.$O\
30 procinit.$O\
31 rwlock.$O\
32 sleep.$O\
33 smalloc.$O\
34 stub.$O\
35 sysfile.$O\
36 sysproc.$O\
37 qio.$O\
38 qlock.$O\
39 term.$O\
40 todo.$O\
41 uart.$O\
42 waserror.$O
43
44$(LIB): $(OFILES)
45 ar r $(LIB) $(OFILES)
46 ranlib $(LIB)
47
48%.$O: %.c
49 $(CC) $(CFLAGS) $*.c
50
kern/allocb.c+165−0
@@ -0,0 +1,165 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7enum
8{
9 Hdrspc = 64, /* leave room for high-level headers */
10 Bdead = 0x51494F42, /* "QIOB" */
11};
12
13struct
14{
15 Lock lk;
16 ulong bytes;
17} ialloc;
18
19static Block*
20_allocb(int size)
21{
22 Block *b;
23 ulong addr;
24
25 if((b = mallocz(sizeof(Block)+size+Hdrspc, 0)) == nil)
26 return nil;
27
28 b->next = nil;
29 b->list = nil;
30 b->free = 0;
31 b->flag = 0;
32
33 /* align start of data portion by rounding up */
34 addr = (ulong)b;
35 addr = ROUND(addr + sizeof(Block), BLOCKALIGN);
36 b->base = (uchar*)addr;
37
38 /* align end of data portion by rounding down */
39 b->lim = ((uchar*)b) + sizeof(Block)+size+Hdrspc;
40 addr = (ulong)(b->lim);
41 addr = addr & ~(BLOCKALIGN-1);
42 b->lim = (uchar*)addr;
43
44 /* leave sluff at beginning for added headers */
45 b->rp = b->lim - ROUND(size, BLOCKALIGN);
46 if(b->rp < b->base)
47 panic("_allocb");
48 b->wp = b->rp;
49
50 return b;
51}
52
53Block*
54allocb(int size)
55{
56 Block *b;
57
58 /*
59 * Check in a process and wait until successful.
60 * Can still error out of here, though.
61 */
62 if(up == nil)
63 panic("allocb without up: %luX\n", getcallerpc(&size));
64 if((b = _allocb(size)) == nil){
65 panic("allocb: no memory for %d bytes\n", size);
66 }
67 setmalloctag(b, getcallerpc(&size));
68
69 return b;
70}
71
72Block*
73iallocb(int size)
74{
75 Block *b;
76 static int m1, m2;
77
78 if(ialloc.bytes > conf.ialloc){
79 if((m1++%10000)==0)
80 print("iallocb: limited %lud/%lud\n",
81 ialloc.bytes, conf.ialloc);
82 return 0;
83 }
84
85 if((b = _allocb(size)) == nil){
86 if((m2++%10000)==0)
87 print("iallocb: no memory %lud/%lud\n",
88 ialloc.bytes, conf.ialloc);
89 return nil;
90 }
91 setmalloctag(b, getcallerpc(&size));
92 b->flag = BINTR;
93
94 ilock(&ialloc.lk);
95 ialloc.bytes += b->lim - b->base;
96 iunlock(&ialloc.lk);
97
98 return b;
99}
100
101void
102freeb(Block *b)
103{
104 void *dead = (void*)Bdead;
105
106 if(b == nil)
107 return;
108
109 /*
110 * drivers which perform non cache coherent DMA manage their own buffer
111 * pool of uncached buffers and provide their own free routine.
112 */
113 if(b->free) {
114 b->free(b);
115 return;
116 }
117 if(b->flag & BINTR) {
118 ilock(&ialloc.lk);
119 ialloc.bytes -= b->lim - b->base;
120 iunlock(&ialloc.lk);
121 }
122
123 /* poison the block in case someone is still holding onto it */
124 b->next = dead;
125 b->rp = dead;
126 b->wp = dead;
127 b->lim = dead;
128 b->base = dead;
129
130 free(b);
131}
132
133void
134checkb(Block *b, char *msg)
135{
136 void *dead = (void*)Bdead;
137
138 if(b == dead)
139 panic("checkb b %s %lux", msg, b);
140 if(b->base == dead || b->lim == dead || b->next == dead
141 || b->rp == dead || b->wp == dead){
142 print("checkb: base 0x%8.8luX lim 0x%8.8luX next 0x%8.8luX\n",
143 b->base, b->lim, b->next);
144 print("checkb: rp 0x%8.8luX wp 0x%8.8luX\n", b->rp, b->wp);
145 panic("checkb dead: %s\n", msg);
146 }
147
148 if(b->base > b->lim)
149 panic("checkb 0 %s %lux %lux", msg, b->base, b->lim);
150 if(b->rp < b->base)
151 panic("checkb 1 %s %lux %lux", msg, b->base, b->rp);
152 if(b->wp < b->base)
153 panic("checkb 2 %s %lux %lux", msg, b->base, b->wp);
154 if(b->rp > b->lim)
155 panic("checkb 3 %s %lux %lux", msg, b->rp, b->lim);
156 if(b->wp > b->lim)
157 panic("checkb 4 %s %lux %lux", msg, b->wp, b->lim);
158
159}
160
161void
162iallocsummary(void)
163{
164 print("ialloc %lud/%lud\n", ialloc.bytes, conf.ialloc);
165}
kern/cache.c+46−0
@@ -0,0 +1,46 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7
8void
9cinit(void)
10{
11}
12
13void
14copen(Chan *c)
15{
16 USED(c);
17}
18
19int
20cread(Chan *c, uchar *buf, int len, vlong off)
21{
22 USED(c);
23 USED(buf);
24 USED(len);
25 USED(off);
26
27 return 0;
28}
29
30void
31cupdate(Chan *c, uchar *buf, int len, vlong off)
32{
33 USED(c);
34 USED(buf);
35 USED(len);
36 USED(off);
37}
38
39void
40cwrite(Chan* c, uchar *buf, int len, vlong off)
41{
42 USED(c);
43 USED(buf);
44 USED(len);
45 USED(off);
46}
kern/chan.c+1496−0
@@ -0,0 +1,1496 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7int chandebug=0; /* toggled by sysr1 */
8QLock chanprint; /* probably asking for trouble (deadlocks) -rsc */
9
10int domount(Chan**, Mhead**);
11
12void
13dumpmount(void) /* DEBUGGING */
14{
15 Pgrp *pg;
16 Mount *t;
17 Mhead **h, **he, *f;
18
19 if(up == nil){
20 print("no process for dumpmount\n");
21 return;
22 }
23 pg = up->pgrp;
24 if(pg == nil){
25 print("no pgrp for dumpmount\n");
26 return;
27 }
28 rlock(&pg->ns);
29 if(waserror()) {
30 runlock(&pg->ns);
31 nexterror();
32 }
33
34 he = &pg->mnthash[MNTHASH];
35 for(h = pg->mnthash; h < he; h++) {
36 for(f = *h; f; f = f->hash) {
37 print("head: %p: %s 0x%llux.%lud %C %lud -> \n", f,
38 f->from->name->s, f->from->qid.path,
39 f->from->qid.vers, devtab[f->from->type]->dc,
40 f->from->dev);
41 for(t = f->mount; t; t = t->next)
42 print("\t%p: %s (umh %p) (path %.8llux dev %C %lud)\n", t, t->to->name->s, t->to->umh, t->to->qid.path, devtab[t->to->type]->dc, t->to->dev);
43 }
44 }
45 poperror();
46 runlock(&pg->ns);
47}
48
49
50char*
51c2name(Chan *c) /* DEBUGGING */
52{
53 if(c == nil)
54 return "<nil chan>";
55 if(c->name == nil)
56 return "<nil name>";
57 if(c->name->s == nil)
58 return "<nil name.s>";
59 return c->name->s;
60}
61
62enum
63{
64 CNAMESLOP = 20
65};
66
67struct
68{
69 Lock lk;
70 int fid;
71 Chan *free;
72 Chan *list;
73}chanalloc;
74
75typedef struct Elemlist Elemlist;
76
77struct Elemlist
78{
79 char *name; /* copy of name, so '/' can be overwritten */
80 int nelems;
81 char **elems;
82 int *off;
83 int mustbedir;
84};
85
86#define SEP(c) ((c) == 0 || (c) == '/')
87void cleancname(Cname*);
88
89int
90isdotdot(char *p)
91{
92 return p[0]=='.' && p[1]=='.' && p[2]=='\0';
93}
94
95int
96incref(Ref *r)
97{
98 int x;
99
100 lock(&r->lk);
101 x = ++r->ref;
102 unlock(&r->lk);
103 return x;
104}
105
106int
107decref(Ref *r)
108{
109 int x;
110
111 lock(&r->lk);
112 x = --r->ref;
113 unlock(&r->lk);
114 if(x < 0)
115 panic("decref, pc=0x%lux", getcallerpc(&r));
116
117 return x;
118}
119
120/*
121 * Rather than strncpy, which zeros the rest of the buffer, kstrcpy
122 * truncates if necessary, always zero terminates, does not zero fill,
123 * and puts ... at the end of the string if it's too long. Usually used to
124 * save a string in up->genbuf;
125 */
126void
127kstrcpy(char *s, char *t, int ns)
128{
129 int nt;
130
131 nt = strlen(t);
132 if(nt+1 <= ns){
133 memmove(s, t, nt+1);
134 return;
135 }
136 /* too long */
137 if(ns < 4){
138 /* but very short! */
139 strncpy(s, t, ns);
140 return;
141 }
142 /* truncate with ... at character boundary (very rare case) */
143 memmove(s, t, ns-4);
144 ns -= 4;
145 s[ns] = '\0';
146 /* look for first byte of UTF-8 sequence by skipping continuation bytes */
147 while(ns>0 && (s[--ns]&0xC0)==0x80)
148 ;
149 strcpy(s+ns, "...");
150}
151
152int
153emptystr(char *s)
154{
155 if(s == nil)
156 return 1;
157 if(s[0] == '\0')
158 return 1;
159 return 0;
160}
161
162/*
163 * Atomically replace *p with copy of s
164 */
165void
166kstrdup(char **p, char *s)
167{
168 int n;
169 char *t, *prev;
170 static Lock l;
171
172 n = strlen(s)+1;
173 /* if it's a user, we can wait for memory; if not, something's very wrong */
174 if(up){
175 t = smalloc(n);
176 setmalloctag(t, getcallerpc(&p));
177 }else{
178 t = malloc(n);
179 if(t == nil)
180 panic("kstrdup: no memory");
181 }
182 memmove(t, s, n);
183 prev = *p;
184 *p = t;
185 free(prev);
186}
187
188void
189chandevreset(void)
190{
191 int i;
192
193 for(i=0; devtab[i] != nil; i++)
194 devtab[i]->reset();
195}
196
197void
198chandevinit(void)
199{
200 int i;
201
202 for(i=0; devtab[i] != nil; i++)
203 devtab[i]->init();
204}
205
206void
207chandevshutdown(void)
208{
209 int i;
210
211 /* shutdown in reverse order */
212 for(i=0; devtab[i] != nil; i++)
213 ;
214 for(i--; i >= 0; i--)
215 devtab[i]->shutdown();
216}
217
218Chan*
219newchan(void)
220{
221 Chan *c;
222
223 lock(&chanalloc.lk);
224 c = chanalloc.free;
225 if(c != 0)
226 chanalloc.free = c->next;
227 unlock(&chanalloc.lk);
228
229 if(c == nil) {
230 c = smalloc(sizeof(Chan));
231 lock(&chanalloc.lk);
232 c->fid = ++chanalloc.fid;
233 c->link = chanalloc.list;
234 chanalloc.list = c;
235 unlock(&chanalloc.lk);
236 }
237
238 /* if you get an error before associating with a dev,
239 close calls rootclose, a nop */
240 c->type = 0;
241 c->flag = 0;
242 c->ref.ref = 1;
243 c->dev = 0;
244 c->offset = 0;
245 c->iounit = 0;
246 c->umh = 0;
247 c->uri = 0;
248 c->dri = 0;
249 c->aux = 0;
250 c->mchan = 0;
251 c->mcp = 0;
252 c->mux = 0;
253 memset(&c->mqid, 0, sizeof(c->mqid));
254 c->name = 0;
255 return c;
256}
257
258static Ref ncname;
259
260Cname*
261newcname(char *s)
262{
263 Cname *n;
264 int i;
265
266 n = smalloc(sizeof(Cname));
267 i = strlen(s);
268 n->len = i;
269 n->alen = i+CNAMESLOP;
270 n->s = smalloc(n->alen);
271 memmove(n->s, s, i+1);
272 n->ref.ref = 1;
273 incref(&ncname);
274 return n;
275}
276
277void
278cnameclose(Cname *n)
279{
280 if(n == nil)
281 return;
282 if(decref(&n->ref))
283 return;
284 decref(&ncname);
285 free(n->s);
286 free(n);
287}
288
289Cname*
290addelem(Cname *n, char *s)
291{
292 int i, a;
293 char *t;
294 Cname *new;
295
296 if(s[0]=='.' && s[1]=='\0')
297 return n;
298
299 if(n->ref.ref > 1){
300 /* copy on write */
301 new = newcname(n->s);
302 cnameclose(n);
303 n = new;
304 }
305
306 i = strlen(s);
307 if(n->len+1+i+1 > n->alen){
308 a = n->len+1+i+1 + CNAMESLOP;
309 t = smalloc(a);
310 memmove(t, n->s, n->len+1);
311 free(n->s);
312 n->s = t;
313 n->alen = a;
314 }
315 if(n->len>0 && n->s[n->len-1]!='/' && s[0]!='/') /* don't insert extra slash if one is present */
316 n->s[n->len++] = '/';
317 memmove(n->s+n->len, s, i+1);
318 n->len += i;
319 if(isdotdot(s))
320 cleancname(n);
321 return n;
322}
323
324void
325chanfree(Chan *c)
326{
327 c->flag = CFREE;
328
329 if(c->umh != nil){
330 putmhead(c->umh);
331 c->umh = nil;
332 }
333 if(c->umc != nil){
334 cclose(c->umc);
335 c->umc = nil;
336 }
337 if(c->mux != nil){
338 muxclose(c->mux);
339 c->mux = nil;
340 }
341 if(c->mchan != nil){
342 cclose(c->mchan);
343 c->mchan = nil;
344 }
345
346 cnameclose(c->name);
347
348 lock(&chanalloc.lk);
349 c->next = chanalloc.free;
350 chanalloc.free = c;
351 unlock(&chanalloc.lk);
352}
353
354void
355cclose(Chan *c)
356{
357 if(c->flag&CFREE)
358 panic("cclose %lux", getcallerpc(&c));
359
360 if(decref(&c->ref))
361 return;
362
363 if(!waserror()){
364 devtab[c->type]->close(c);
365 poperror();
366 }
367 chanfree(c);
368}
369
370/*
371 * Make sure we have the only copy of c. (Copy on write.)
372 */
373Chan*
374cunique(Chan *c)
375{
376 Chan *nc;
377
378 if(c->ref.ref != 1) {
379 nc = cclone(c);
380 cclose(c);
381 c = nc;
382 }
383
384 return c;
385}
386
387int
388eqqid(Qid a, Qid b)
389{
390 return a.path==b.path && a.vers==b.vers;
391}
392
393int
394eqchan(Chan *a, Chan *b, int pathonly)
395{
396 if(a->qid.path != b->qid.path)
397 return 0;
398 if(!pathonly && a->qid.vers!=b->qid.vers)
399 return 0;
400 if(a->type != b->type)
401 return 0;
402 if(a->dev != b->dev)
403 return 0;
404 return 1;
405}
406
407int
408eqchantdqid(Chan *a, int type, int dev, Qid qid, int pathonly)
409{
410 if(a->qid.path != qid.path)
411 return 0;
412 if(!pathonly && a->qid.vers!=qid.vers)
413 return 0;
414 if(a->type != type)
415 return 0;
416 if(a->dev != dev)
417 return 0;
418 return 1;
419}
420
421Mhead*
422newmhead(Chan *from)
423{
424 Mhead *mh;
425
426 mh = smalloc(sizeof(Mhead));
427 mh->ref.ref = 1;
428 mh->from = from;
429 incref(&from->ref);
430
431/*
432 n = from->name->len;
433 if(n >= sizeof(mh->fromname))
434 n = sizeof(mh->fromname)-1;
435 memmove(mh->fromname, from->name->s, n);
436 mh->fromname[n] = 0;
437*/
438 return mh;
439}
440
441int
442cmount(Chan **newp, Chan *old, int flag, char *spec)
443{
444 Pgrp *pg;
445 int order, flg;
446 Mhead *m, **l, *mh;
447 Mount *nm, *f, *um, **h;
448 Chan *new;
449
450 if(QTDIR & (old->qid.type^(*newp)->qid.type))
451 error(Emount);
452
453if(old->umh)print("cmount old extra umh\n");
454
455 order = flag&MORDER;
456
457 if((old->qid.type&QTDIR)==0 && order != MREPL)
458 error(Emount);
459
460 new = *newp;
461 mh = new->umh;
462
463 /*
464 * Not allowed to bind when the old directory
465 * is itself a union. (Maybe it should be allowed, but I don't see
466 * what the semantics would be.)
467 *
468 * We need to check mh->mount->next to tell unions apart from
469 * simple mount points, so that things like
470 * mount -c fd /root
471 * bind -c /root /
472 * work. The check of mount->mflag catches things like
473 * mount fd /root
474 * bind -c /root /
475 *
476 * This is far more complicated than it should be, but I don't
477 * see an easier way at the moment. -rsc
478 */
479 if((flag&MCREATE) && mh && mh->mount
480 && (mh->mount->next || !(mh->mount->mflag&MCREATE)))
481 error(Emount);
482
483 pg = up->pgrp;
484 wlock(&pg->ns);
485
486 l = &MOUNTH(pg, old->qid);
487 for(m = *l; m; m = m->hash) {
488 if(eqchan(m->from, old, 1))
489 break;
490 l = &m->hash;
491 }
492
493 if(m == nil) {
494 /*
495 * nothing mounted here yet. create a mount
496 * head and add to the hash table.
497 */
498 m = newmhead(old);
499 *l = m;
500
501 /*
502 * if this is a union mount, add the old
503 * node to the mount chain.
504 */
505 if(order != MREPL)
506 m->mount = newmount(m, old, 0, 0);
507 }
508 wlock(&m->lock);
509 if(waserror()){
510 wunlock(&m->lock);
511 nexterror();
512 }
513 wunlock(&pg->ns);
514
515 nm = newmount(m, new, flag, spec);
516 if(mh != nil && mh->mount != nil) {
517 /*
518 * copy a union when binding it onto a directory
519 */
520 flg = order;
521 if(order == MREPL)
522 flg = MAFTER;
523 h = &nm->next;
524 um = mh->mount;
525 for(um = um->next; um; um = um->next) {
526 f = newmount(m, um->to, flg, um->spec);
527 *h = f;
528 h = &f->next;
529 }
530 }
531
532 if(m->mount && order == MREPL) {
533 mountfree(m->mount);
534 m->mount = 0;
535 }
536
537 if(flag & MCREATE)
538 nm->mflag |= MCREATE;
539
540 if(m->mount && order == MAFTER) {
541 for(f = m->mount; f->next; f = f->next)
542 ;
543 f->next = nm;
544 }
545 else {
546 for(f = nm; f->next; f = f->next)
547 ;
548 f->next = m->mount;
549 m->mount = nm;
550 }
551
552 wunlock(&m->lock);
553 poperror();
554 return nm->mountid;
555}
556
557void
558cunmount(Chan *mnt, Chan *mounted)
559{
560 Pgrp *pg;
561 Mhead *m, **l;
562 Mount *f, **p;
563
564 if(mnt->umh) /* should not happen */
565 print("cunmount newp extra umh %p has %p\n", mnt, mnt->umh);
566
567 /*
568 * It _can_ happen that mounted->umh is non-nil,
569 * because mounted is the result of namec(Aopen)
570 * (see sysfile.c:/^sysunmount).
571 * If we open a union directory, it will have a umh.
572 * Although surprising, this is okay, since the
573 * cclose will take care of freeing the umh.
574 */
575
576 pg = up->pgrp;
577 wlock(&pg->ns);
578
579 l = &MOUNTH(pg, mnt->qid);
580 for(m = *l; m; m = m->hash) {
581 if(eqchan(m->from, mnt, 1))
582 break;
583 l = &m->hash;
584 }
585
586 if(m == 0) {
587 wunlock(&pg->ns);
588 error(Eunmount);
589 }
590
591 wlock(&m->lock);
592 if(mounted == 0) {
593 *l = m->hash;
594 wunlock(&pg->ns);
595 mountfree(m->mount);
596 m->mount = nil;
597 cclose(m->from);
598 wunlock(&m->lock);
599 putmhead(m);
600 return;
601 }
602
603 p = &m->mount;
604 for(f = *p; f; f = f->next) {
605 /* BUG: Needs to be 2 pass */
606 if(eqchan(f->to, mounted, 1) ||
607 (f->to->mchan && eqchan(f->to->mchan, mounted, 1))) {
608 *p = f->next;
609 f->next = 0;
610 mountfree(f);
611 if(m->mount == nil) {
612 *l = m->hash;
613 cclose(m->from);
614 wunlock(&m->lock);
615 wunlock(&pg->ns);
616 putmhead(m);
617 return;
618 }
619 wunlock(&m->lock);
620 wunlock(&pg->ns);
621 return;
622 }
623 p = &f->next;
624 }
625 wunlock(&m->lock);
626 wunlock(&pg->ns);
627 error(Eunion);
628}
629
630Chan*
631cclone(Chan *c)
632{
633 Chan *nc;
634 Walkqid *wq;
635
636 wq = devtab[c->type]->walk(c, nil, nil, 0);
637 if(wq == nil)
638 error("clone failed");
639 nc = wq->clone;
640 free(wq);
641 nc->name = c->name;
642 if(c->name)
643 incref(&c->name->ref);
644 return nc;
645}
646
647int
648findmount(Chan **cp, Mhead **mp, int type, int dev, Qid qid)
649{
650 Pgrp *pg;
651 Mhead *m;
652
653 pg = up->pgrp;
654 rlock(&pg->ns);
655 for(m = MOUNTH(pg, qid); m; m = m->hash){
656 rlock(&m->lock);
657if(m->from == nil){
658 print("m %p m->from 0\n", m);
659 runlock(&m->lock);
660 continue;
661}
662 if(eqchantdqid(m->from, type, dev, qid, 1)) {
663 runlock(&pg->ns);
664 if(mp != nil){
665 incref(&m->ref);
666 if(*mp != nil)
667 putmhead(*mp);
668 *mp = m;
669 }
670 if(*cp != nil)
671 cclose(*cp);
672 incref(&m->mount->to->ref);
673 *cp = m->mount->to;
674 runlock(&m->lock);
675 return 1;
676 }
677 runlock(&m->lock);
678 }
679
680 runlock(&pg->ns);
681 return 0;
682}
683
684int
685domount(Chan **cp, Mhead **mp)
686{
687 return findmount(cp, mp, (*cp)->type, (*cp)->dev, (*cp)->qid);
688}
689
690Chan*
691undomount(Chan *c, Cname *name)
692{
693 Chan *nc;
694 Pgrp *pg;
695 Mount *t;
696 Mhead **h, **he, *f;
697
698 pg = up->pgrp;
699 rlock(&pg->ns);
700 if(waserror()) {
701 runlock(&pg->ns);
702 nexterror();
703 }
704
705 he = &pg->mnthash[MNTHASH];
706 for(h = pg->mnthash; h < he; h++) {
707 for(f = *h; f; f = f->hash) {
708 if(strcmp(f->from->name->s, name->s) != 0)
709 continue;
710 for(t = f->mount; t; t = t->next) {
711 if(eqchan(c, t->to, 1)) {
712 /*
713 * We want to come out on the left hand side of the mount
714 * point using the element of the union that we entered on.
715 * To do this, find the element that has a from name of
716 * c->name->s.
717 */
718 if(strcmp(t->head->from->name->s, name->s) != 0)
719 continue;
720 nc = t->head->from;
721 incref(&nc->ref);
722 cclose(c);
723 c = nc;
724 break;
725 }
726 }
727 }
728 }
729 poperror();
730 runlock(&pg->ns);
731 return c;
732}
733
734/*
735 * Either walks all the way or not at all. No partial results in *cp.
736 * *nerror is the number of names to display in an error message.
737 */
738static char Edoesnotexist[] = "does not exist";
739int
740walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
741{
742 int dev, dotdot, i, n, nhave, ntry, type;
743 Chan *c, *nc;
744 Cname *cname;
745 Mount *f;
746 Mhead *mh, *nmh;
747 Walkqid *wq;
748
749 c = *cp;
750 incref(&c->ref);
751 cname = c->name;
752 incref(&cname->ref);
753 mh = nil;
754
755 /*
756 * While we haven't gotten all the way down the path:
757 * 1. step through a mount point, if any
758 * 2. send a walk request for initial dotdot or initial prefix without dotdot
759 * 3. move to the first mountpoint along the way.
760 * 4. repeat.
761 *
762 * An invariant is that each time through the loop, c is on the undomount
763 * side of the mount point, and c's name is cname.
764 */
765 for(nhave=0; nhave<nnames; nhave+=n){
766 if((c->qid.type&QTDIR)==0){
767 if(nerror)
768 *nerror = nhave;
769 cnameclose(cname);
770 cclose(c);
771 strcpy(up->errstr, Enotdir);
772 if(mh != nil)
773{print("walk 1\n");
774 putmhead(mh);
775}
776 return -1;
777 }
778 ntry = nnames - nhave;
779 if(ntry > MAXWELEM)
780 ntry = MAXWELEM;
781 dotdot = 0;
782 for(i=0; i<ntry; i++){
783 if(isdotdot(names[nhave+i])){
784 if(i==0) {
785 dotdot = 1;
786 ntry = 1;
787 } else
788 ntry = i;
789 break;
790 }
791 }
792
793 if(!dotdot && !nomount)
794 domount(&c, &mh);
795
796 type = c->type;
797 dev = c->dev;
798
799 if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){
800 /* try a union mount, if any */
801 if(mh && !nomount){
802 /*
803 * mh->mount == c, so start at mh->mount->next
804 */
805 rlock(&mh->lock);
806 for(f = mh->mount->next; f; f = f->next)
807 if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil)
808 break;
809 runlock(&mh->lock);
810 if(f != nil){
811 type = f->to->type;
812 dev = f->to->dev;
813 }
814 }
815 if(wq == nil){
816 cclose(c);
817 cnameclose(cname);
818 if(nerror)
819 *nerror = nhave+1;
820 if(mh != nil)
821 putmhead(mh);
822 return -1;
823 }
824 }
825
826 nmh = nil;
827 if(dotdot) {
828 assert(wq->nqid == 1);
829 assert(wq->clone != nil);
830
831 cname = addelem(cname, "..");
832 nc = undomount(wq->clone, cname);
833 n = 1;
834 } else {
835 nc = nil;
836 if(!nomount)
837 for(i=0; i<wq->nqid && i<ntry-1; i++)
838 if(findmount(&nc, &nmh, type, dev, wq->qid[i]))
839 break;
840 if(nc == nil){ /* no mount points along path */
841 if(wq->clone == nil){
842 cclose(c);
843 cnameclose(cname);
844 if(wq->nqid==0 || (wq->qid[wq->nqid-1].type&QTDIR)){
845 if(nerror)
846 *nerror = nhave+wq->nqid+1;
847 strcpy(up->errstr, Edoesnotexist);
848 }else{
849 if(nerror)
850 *nerror = nhave+wq->nqid;
851 strcpy(up->errstr, Enotdir);
852 }
853 free(wq);
854 if(mh != nil)
855 putmhead(mh);
856 return -1;
857 }
858 n = wq->nqid;
859 nc = wq->clone;
860 }else{ /* stopped early, at a mount point */
861 if(wq->clone != nil){
862 cclose(wq->clone);
863 wq->clone = nil;
864 }
865 n = i+1;
866 }
867 for(i=0; i<n; i++)
868 cname = addelem(cname, names[nhave+i]);
869 }
870 cclose(c);
871 c = nc;
872 putmhead(mh);
873 mh = nmh;
874 free(wq);
875 }
876
877 putmhead(mh);
878
879 c = cunique(c);
880
881 if(c->umh != nil){ //BUG
882 print("walk umh\n");
883 putmhead(c->umh);
884 c->umh = nil;
885 }
886
887 cnameclose(c->name);
888 c->name = cname;
889
890 cclose(*cp);
891 *cp = c;
892 if(nerror)
893 *nerror = 0;
894 return 0;
895}
896
897/*
898 * c is a mounted non-creatable directory. find a creatable one.
899 */
900Chan*
901createdir(Chan *c, Mhead *m)
902{
903 Chan *nc;
904 Mount *f;
905
906 rlock(&m->lock);
907 if(waserror()) {
908 runlock(&m->lock);
909 nexterror();
910 }
911 for(f = m->mount; f; f = f->next) {
912 if(f->mflag&MCREATE) {
913 nc = cclone(f->to);
914 runlock(&m->lock);
915 poperror();
916 cclose(c);
917 return nc;
918 }
919 }
920 error(Enocreate);
921 return 0;
922}
923
924void
925saveregisters(void)
926{
927}
928
929/*
930 * In place, rewrite name to compress multiple /, eliminate ., and process ..
931 */
932void
933cleancname(Cname *n)
934{
935 char *p;
936
937 if(n->s[0] == '#'){
938 p = strchr(n->s, '/');
939 if(p == nil)
940 return;
941 cleanname(p);
942
943 /*
944 * The correct name is #i rather than #i/,
945 * but the correct name of #/ is #/.
946 */
947 if(strcmp(p, "/")==0 && n->s[1] != '/')
948 *p = '\0';
949 }else
950 cleanname(n->s);
951 n->len = strlen(n->s);
952}
953
954static void
955growparse(Elemlist *e)
956{
957 char **new;
958 int *inew;
959 enum { Delta = 8 };
960
961 if(e->nelems % Delta == 0){
962 new = smalloc((e->nelems+Delta) * sizeof(char*));
963 memmove(new, e->elems, e->nelems*sizeof(char*));
964 free(e->elems);
965 e->elems = new;
966 inew = smalloc((e->nelems+Delta+1) * sizeof(int));
967 memmove(inew, e->off, e->nelems*sizeof(int));
968 free(e->off);
969 e->off = inew;
970 }
971}
972
973/*
974 * The name is known to be valid.
975 * Copy the name so slashes can be overwritten.
976 * An empty string will set nelem=0.
977 * A path ending in / or /. or /.//./ etc. will have
978 * e.mustbedir = 1, so that we correctly
979 * reject, e.g., "/adm/users/." when /adm/users is a file
980 * rather than a directory.
981 */
982static void
983parsename(char *name, Elemlist *e)
984{
985 char *slash;
986
987 kstrdup(&e->name, name);
988 name = e->name;
989 e->nelems = 0;
990 e->elems = nil;
991 e->off = smalloc(sizeof(int));
992 e->off[0] = skipslash(name) - name;
993 for(;;){
994 name = skipslash(name);
995 if(*name=='\0'){
996 e->mustbedir = 1;
997 break;
998 }
999 growparse(e);
1000 e->elems[e->nelems++] = name;
1001 slash = utfrune(name, '/');
1002 if(slash == nil){
1003 e->off[e->nelems] = name+strlen(name) - e->name;
1004 e->mustbedir = 0;
1005 break;
1006 }
1007 e->off[e->nelems] = slash - e->name;
1008 *slash++ = '\0';
1009 name = slash;
1010 }
1011}
1012
1013void*
1014memrchr(void *va, int c, long n)
1015{
1016 uchar *a, *e;
1017
1018 a = va;
1019 for(e=a+n-1; e>a; e--)
1020 if(*e == c)
1021 return e;
1022 return nil;
1023}
1024
1025/*
1026 * Turn a name into a channel.
1027 * &name[0] is known to be a valid address. It may be a kernel address.
1028 *
1029 * Opening with amode Aopen, Acreate, or Aremove guarantees
1030 * that the result will be the only reference to that particular fid.
1031 * This is necessary since we might pass the result to
1032 * devtab[]->remove().
1033 *
1034 * Opening Atodir, Amount, or Aaccess does not guarantee this.
1035 *
1036 * Opening Aaccess can, under certain conditions, return a
1037 * correct Chan* but with an incorrect Cname attached.
1038 * Since the functions that open Aaccess (sysstat, syswstat, sys_stat)
1039 * do not use the Cname*, this avoids an unnecessary clone.
1040 */
1041Chan*
1042namec(char *aname, int amode, int omode, ulong perm)
1043{
1044 int n, prefix, len, t, nomount, npath;
1045 Chan *c, *cnew;
1046 Cname *cname;
1047 Elemlist e;
1048 Rune r;
1049 Mhead *m;
1050 char *createerr, tmperrbuf[ERRMAX];
1051 char *name;
1052
1053 name = aname;
1054 if(name[0] == '\0')
1055 error("empty file name");
1056 validname(name, 1);
1057
1058 /*
1059 * Find the starting off point (the current slash, the root of
1060 * a device tree, or the current dot) as well as the name to
1061 * evaluate starting there.
1062 */
1063 nomount = 0;
1064 switch(name[0]){
1065 case '/':
1066 c = up->slash;
1067 incref(&c->ref);
1068 break;
1069
1070 case '#':
1071 nomount = 1;
1072 up->genbuf[0] = '\0';
1073 n = 0;
1074 while(*name!='\0' && (*name != '/' || n < 2)){
1075 if(n >= sizeof(up->genbuf)-1)
1076 error(Efilename);
1077 up->genbuf[n++] = *name++;
1078 }
1079 up->genbuf[n] = '\0';
1080 /*
1081 * noattach is sandboxing.
1082 *
1083 * the OK exceptions are:
1084 * | it only gives access to pipes you create
1085 * d this process's file descriptors
1086 * e this process's environment
1087 * the iffy exceptions are:
1088 * c time and pid, but also cons and consctl
1089 * p control of your own processes (and unfortunately
1090 * any others left unprotected)
1091 */
1092 n = chartorune(&r, up->genbuf+1)+1;
1093 /* actually / is caught by parsing earlier */
1094 if(utfrune("M", r))
1095 error(Enoattach);
1096 if(up->pgrp->noattach && utfrune("|decp", r)==nil)
1097 error(Enoattach);
1098 t = devno(r, 1);
1099 if(t == -1)
1100 error(Ebadsharp);
1101 c = devtab[t]->attach(up->genbuf+n);
1102 break;
1103
1104 default:
1105 c = up->dot;
1106 incref(&c->ref);
1107 break;
1108 }
1109 prefix = name - aname;
1110
1111 e.name = nil;
1112 e.elems = nil;
1113 e.off = nil;
1114 e.nelems = 0;
1115 if(waserror()){
1116 cclose(c);
1117 free(e.name);
1118 free(e.elems);
1119 free(e.off);
1120//dumpmount();
1121 nexterror();
1122 }
1123
1124 /*
1125 * Build a list of elements in the path.
1126 */
1127 parsename(name, &e);
1128
1129 /*
1130 * On create, ....
1131 */
1132 if(amode == Acreate){
1133 /* perm must have DMDIR if last element is / or /. */
1134 if(e.mustbedir && !(perm&DMDIR)){
1135 npath = e.nelems;
1136 strcpy(tmperrbuf, "create without DMDIR");
1137 goto NameError;
1138 }
1139
1140 /* don't try to walk the last path element just yet. */
1141 if(e.nelems == 0)
1142 error(Eexist);
1143 e.nelems--;
1144 }
1145
1146 if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){
1147 if(npath < 0 || npath > e.nelems){
1148 print("namec %s walk error npath=%d\n", aname, npath);
1149 nexterror();
1150 }
1151 strcpy(tmperrbuf, up->errstr);
1152 NameError:
1153 len = prefix+e.off[npath];
1154 if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname)
1155 snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
1156 else
1157 snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
1158 snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperrbuf);
1159 nexterror();
1160 }
1161
1162 if(e.mustbedir && !(c->qid.type&QTDIR)){
1163 npath = e.nelems;
1164 strcpy(tmperrbuf, "not a directory");
1165 goto NameError;
1166 }
1167
1168 if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){
1169 npath = e.nelems;
1170 error("cannot exec directory");
1171 }
1172
1173 switch(amode){
1174 case Aaccess:
1175 if(!nomount)
1176 domount(&c, nil);
1177 break;
1178
1179 case Abind:
1180 m = nil;
1181 if(!nomount)
1182 domount(&c, &m);
1183 if(c->umh != nil)
1184 putmhead(c->umh);
1185 c->umh = m;
1186 break;
1187
1188 case Aremove:
1189 case Aopen:
1190 Open:
1191 /* save the name; domount might change c */
1192 cname = c->name;
1193 incref(&cname->ref);
1194 m = nil;
1195 if(!nomount)
1196 domount(&c, &m);
1197
1198 /* our own copy to open or remove */
1199 c = cunique(c);
1200
1201 /* now it's our copy anyway, we can put the name back */
1202 cnameclose(c->name);
1203 c->name = cname;
1204
1205 switch(amode){
1206 case Aremove:
1207 putmhead(m);
1208 break;
1209
1210 case Aopen:
1211 case Acreate:
1212if(c->umh != nil){
1213 print("cunique umh Open\n");
1214 putmhead(c->umh);
1215 c->umh = nil;
1216}
1217
1218 /* only save the mount head if it's a multiple element union */
1219 if(m && m->mount && m->mount->next)
1220 c->umh = m;
1221 else
1222 putmhead(m);
1223
1224 /* save registers else error() in open has wrong value of c saved */
1225 saveregisters();
1226
1227 if(omode == OEXEC)
1228 c->flag &= ~CCACHE;
1229
1230 c = devtab[c->type]->open(c, omode&~OCEXEC);
1231
1232 if(omode & OCEXEC)
1233 c->flag |= CCEXEC;
1234 if(omode & ORCLOSE)
1235 c->flag |= CRCLOSE;
1236 break;
1237 }
1238 break;
1239
1240 case Atodir:
1241 /*
1242 * Directories (e.g. for cd) are left before the mount point,
1243 * so one may mount on / or . and see the effect.
1244 */
1245 if(!(c->qid.type & QTDIR))
1246 error(Enotdir);
1247 break;
1248
1249 case Amount:
1250 /*
1251 * When mounting on an already mounted upon directory,
1252 * one wants subsequent mounts to be attached to the
1253 * original directory, not the replacement. Don't domount.
1254 */
1255 break;
1256
1257 case Acreate:
1258 /*
1259 * We've already walked all but the last element.
1260 * If the last exists, try to open it OTRUNC.
1261 * If omode&OEXCL is set, just give up.
1262 */
1263 e.nelems++;
1264 if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
1265 if(omode&OEXCL)
1266 error(Eexist);
1267 omode |= OTRUNC;
1268 goto Open;
1269 }
1270
1271 /*
1272 * The semantics of the create(2) system call are that if the
1273 * file exists and can be written, it is to be opened with truncation.
1274 * On the other hand, the create(5) message fails if the file exists.
1275 * If we get two create(2) calls happening simultaneously,
1276 * they might both get here and send create(5) messages, but only
1277 * one of the messages will succeed. To provide the expected create(2)
1278 * semantics, the call with the failed message needs to try the above
1279 * walk again, opening for truncation. This correctly solves the
1280 * create/create race, in the sense that any observable outcome can
1281 * be explained as one happening before the other.
1282 * The create/create race is quite common. For example, it happens
1283 * when two rc subshells simultaneously update the same
1284 * environment variable.
1285 *
1286 * The implementation still admits a create/create/remove race:
1287 * (A) walk to file, fails
1288 * (B) walk to file, fails
1289 * (A) create file, succeeds, returns
1290 * (B) create file, fails
1291 * (A) remove file, succeeds, returns
1292 * (B) walk to file, return failure.
1293 *
1294 * This is hardly as common as the create/create race, and is really
1295 * not too much worse than what might happen if (B) got a hold of a
1296 * file descriptor and then the file was removed -- either way (B) can't do
1297 * anything with the result of the create call. So we don't care about this race.
1298 *
1299 * Applications that care about more fine-grained decision of the races
1300 * can use the OEXCL flag to get at the underlying create(5) semantics;
1301 * by default we provide the common case.
1302 *
1303 * We need to stay behind the mount point in case we
1304 * need to do the first walk again (should the create fail).
1305 *
1306 * We also need to cross the mount point and find the directory
1307 * in the union in which we should be creating.
1308 *
1309 * The channel staying behind is c, the one moving forward is cnew.
1310 */
1311 m = nil;
1312 cnew = nil; /* is this assignment necessary? */
1313 if(!waserror()){ /* try create */
1314 if(!nomount && findmount(&cnew, &m, c->type, c->dev, c->qid))
1315 cnew = createdir(cnew, m);
1316 else{
1317 cnew = c;
1318 incref(&cnew->ref);
1319 }
1320
1321 /*
1322 * We need our own copy of the Chan because we're
1323 * about to send a create, which will move it. Once we have
1324 * our own copy, we can fix the name, which might be wrong
1325 * if findmount gave us a new Chan.
1326 */
1327 cnew = cunique(cnew);
1328 cnameclose(cnew->name);
1329 cnew->name = c->name;
1330 incref(&cnew->name->ref);
1331
1332 devtab[cnew->type]->create(cnew, e.elems[e.nelems-1], omode&~(OEXCL|OCEXEC), perm);
1333 poperror();
1334 if(omode & OCEXEC)
1335 cnew->flag |= CCEXEC;
1336 if(omode & ORCLOSE)
1337 cnew->flag |= CRCLOSE;
1338 if(m)
1339 putmhead(m);
1340 cclose(c);
1341 c = cnew;
1342 c->name = addelem(c->name, e.elems[e.nelems-1]);
1343 break;
1344 }else{ /* create failed */
1345 cclose(cnew);
1346 if(m)
1347 putmhead(m);
1348 if(omode & OEXCL)
1349 nexterror();
1350 /* save error */
1351 createerr = up->errstr;
1352 up->errstr = tmperrbuf;
1353 /* note: we depend that walk does not error */
1354 if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) < 0){
1355 up->errstr = createerr;
1356 error(createerr); /* report true error */
1357 }
1358 up->errstr = createerr;
1359 omode |= OTRUNC;
1360 goto Open;
1361 }
1362 panic("namec: not reached");
1363
1364 default:
1365 panic("unknown namec access %d\n", amode);
1366 }
1367
1368 poperror();
1369
1370 /* place final element in genbuf for e.g. exec */
1371 if(e.nelems > 0)
1372 kstrcpy(up->genbuf, e.elems[e.nelems-1], sizeof up->genbuf);
1373 else
1374 kstrcpy(up->genbuf, ".", sizeof up->genbuf);
1375 free(e.name);
1376 free(e.elems);
1377 free(e.off);
1378
1379 return c;
1380}
1381
1382/*
1383 * name is valid. skip leading / and ./ as much as possible
1384 */
1385char*
1386skipslash(char *name)
1387{
1388 while(name[0]=='/' || (name[0]=='.' && (name[1]==0 || name[1]=='/')))
1389 name++;
1390 return name;
1391}
1392
1393char isfrog[256]={
1394 /*NUL*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
1395 /*BKS*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x08 */
1396 /*DLE*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x10 */
1397 /*CAN*/ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x18 */
1398 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 */
1399 0, 0, 0, 0, 0, 0, 0, 1, /* 0x28 (1 is '/', 0x2F) */
1400 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 */
1401 0, 0, 0, 0, 0, 0, 0, 0, /* 0x38 */
1402 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */
1403 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48 */
1404 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 */
1405 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */
1406 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */
1407 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */
1408 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */
1409 0, 0, 0, 0, 0, 0, 0, 1, /* 0x78 (1 is DEL, 0x7F) */
1410};
1411
1412/*
1413 * Check that the name
1414 * a) is in valid memory.
1415 * b) is shorter than 2^16 bytes, so it can fit in a 9P string field.
1416 * c) contains no frogs.
1417 * The first byte is known to be addressible by the requester, so the
1418 * routine works for kernel and user memory both.
1419 * The parameter slashok flags whether a slash character is an error
1420 * or a valid character.
1421 */
1422void
1423validname(char *aname, int slashok)
1424{
1425 char *p, *ename, *name;
1426 uint t;
1427 int c;
1428 Rune r;
1429
1430 name = aname;
1431/*
1432 if(((ulong)name & KZERO) != KZERO) {
1433 p = name;
1434 t = BY2PG-((ulong)p&(BY2PG-1));
1435 while((ename=vmemchr(p, 0, t)) == nil) {
1436 p += t;
1437 t = BY2PG;
1438 }
1439 }else
1440*/
1441 ename = memchr(name, 0, (1<<16));
1442
1443 if(ename==nil || ename-name>=(1<<16))
1444 error("name too long");
1445
1446 while(*name){
1447 /* all characters above '~' are ok */
1448 c = *(uchar*)name;
1449 if(c >= Runeself)
1450 name += chartorune(&r, name);
1451 else{
1452 if(isfrog[c])
1453 if(!slashok || c!='/'){
1454 snprint(up->genbuf, sizeof(up->genbuf), "%s: %q", Ebadchar, aname);
1455 error(up->genbuf);
1456 }
1457 name++;
1458 }
1459 }
1460}
1461
1462void
1463isdir(Chan *c)
1464{
1465 if(c->qid.type & QTDIR)
1466 return;
1467 error(Enotdir);
1468}
1469
1470/*
1471 * This is necessary because there are many
1472 * pointers to the top of a given mount list:
1473 *
1474 * - the mhead in the namespace hash table
1475 * - the mhead in chans returned from findmount:
1476 * used in namec and then by unionread.
1477 * - the mhead in chans returned from createdir:
1478 * used in the open/create race protect, which is gone.
1479 *
1480 * The RWlock in the Mhead protects the mount list it contains.
1481 * The mount list is deleted when we cunmount.
1482 * The RWlock ensures that nothing is using the mount list at that time.
1483 *
1484 * It is okay to replace c->mh with whatever you want as
1485 * long as you are sure you have a unique reference to it.
1486 *
1487 * This comment might belong somewhere else.
1488 */
1489void
1490putmhead(Mhead *m)
1491{
1492 if(m && decref(&m->ref) == 0){
1493 m->mount = (Mount*)0xCafeBeef;
1494 free(m);
1495 }
1496}
kern/dat.h+519−0
@@ -0,0 +1,519 @@
1#define KNAMELEN 28 /* max length of name held in kernel */
2#define DOMLEN 64
3
4#define BLOCKALIGN 8
5
6typedef struct Alarms Alarms;
7typedef struct Block Block;
8typedef struct CSN CSN;
9typedef struct Chan Chan;
10typedef struct Cmdbuf Cmdbuf;
11typedef struct Cmdtab Cmdtab;
12typedef struct Cname Cname;
13typedef struct Conf Conf;
14typedef struct Dev Dev;
15typedef struct Dirtab Dirtab;
16typedef struct Edfinterface Edfinterface;
17typedef struct Egrp Egrp;
18typedef struct Evalue Evalue;
19typedef struct Fgrp Fgrp;
20typedef struct FPsave FPsave;
21typedef struct DevConf DevConf;
22typedef struct Label Label;
23typedef struct List List;
24typedef struct Log Log;
25typedef struct Logflag Logflag;
26typedef struct Mntcache Mntcache;
27typedef struct Mount Mount;
28typedef struct Mntrpc Mntrpc;
29typedef struct Mntwalk Mntwalk;
30typedef struct Mnt Mnt;
31typedef struct Mhead Mhead;
32typedef struct Note Note;
33typedef struct Page Page;
34typedef struct Palloc Palloc;
35typedef struct Perf Perf;
36typedef struct Pgrps Pgrps;
37typedef struct PhysUart PhysUart;
38typedef struct Pgrp Pgrp;
39typedef struct Physseg Physseg;
40typedef struct Proc Proc;
41typedef struct Pte Pte;
42typedef struct Pthash Pthash;
43typedef struct Queue Queue;
44typedef struct Ref Ref;
45typedef struct Rendez Rendez;
46typedef struct Rgrp Rgrp;
47typedef struct RWlock RWlock;
48typedef struct Schedq Schedq;
49typedef struct Segment Segment;
50typedef struct Session Session;
51typedef struct Task Task;
52typedef struct Talarm Talarm;
53typedef struct Timer Timer;
54typedef struct Uart Uart;
55typedef struct Ureg Ureg;
56typedef struct Waitq Waitq;
57typedef struct Walkqid Walkqid;
58typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*);
59
60#include "fcall.h"
61
62enum
63{
64 SnarfSize = 64*1024,
65};
66
67struct Conf
68{
69 ulong nmach; /* processors */
70 ulong nproc; /* processes */
71 ulong monitor; /* has monitor? */
72 ulong npage0; /* total physical pages of memory */
73 ulong npage1; /* total physical pages of memory */
74 ulong npage; /* total physical pages of memory */
75 ulong upages; /* user page pool */
76 ulong nimage; /* number of page cache image headers */
77 ulong nswap; /* number of swap pages */
78 int nswppo; /* max # of pageouts per segment pass */
79 ulong base0; /* base of bank 0 */
80 ulong base1; /* base of bank 1 */
81 ulong copymode; /* 0 is copy on write, 1 is copy on reference */
82 ulong ialloc; /* max interrupt time allocation in bytes */
83 ulong pipeqsize; /* size in bytes of pipe queues */
84 int nuart; /* number of uart devices */
85};
86
87struct Label
88{
89 jmp_buf buf;
90};
91
92struct Ref
93{
94 Lock lk;
95 long ref;
96};
97
98struct Rendez
99{
100 Lock lk;
101 Proc *p;
102};
103
104struct RWlock /* changed from kernel */
105{
106 int readers;
107 Lock lk;
108 QLock x;
109 QLock k;
110};
111
112struct Talarm
113{
114 Lock lk;
115 Proc *list;
116};
117
118struct Alarms
119{
120 QLock lk;
121 Proc *head;
122};
123
124/*
125 * Access types in namec & channel flags
126 */
127enum
128{
129 Aaccess, /* as in stat, wstat */
130 Abind, /* for left-hand-side of bind */
131 Atodir, /* as in chdir */
132 Aopen, /* for i/o */
133 Amount, /* to be mounted or mounted upon */
134 Acreate, /* is to be created */
135 Aremove, /* will be removed by caller */
136
137 COPEN = 0x0001, /* for i/o */
138 CMSG = 0x0002, /* the message channel for a mount */
139/*rsc CCREATE = 0x0004, /* permits creation if c->mnt */
140 CCEXEC = 0x0008, /* close on exec */
141 CFREE = 0x0010, /* not in use */
142 CRCLOSE = 0x0020, /* remove on close */
143 CCACHE = 0x0080, /* client cache */
144};
145
146/* flag values */
147enum
148{
149 BINTR = (1<<0),
150 BFREE = (1<<1),
151 Bipck = (1<<2), /* ip checksum */
152 Budpck = (1<<3), /* udp checksum */
153 Btcpck = (1<<4), /* tcp checksum */
154 Bpktck = (1<<5), /* packet checksum */
155};
156
157struct Block
158{
159 Block* next;
160 Block* list;
161 uchar* rp; /* first unconsumed byte */
162 uchar* wp; /* first empty byte */
163 uchar* lim; /* 1 past the end of the buffer */
164 uchar* base; /* start of the buffer */
165 void (*free)(Block*);
166 ushort flag;
167 ushort checksum; /* IP checksum of complete packet (minus media header) */
168};
169#define BLEN(s) ((s)->wp - (s)->rp)
170#define BALLOC(s) ((s)->lim - (s)->base)
171
172struct Chan
173{
174 Ref ref;
175 Chan* next; /* allocation */
176 Chan* link;
177 vlong offset; /* in file */
178 ushort type;
179 ulong dev;
180 ushort mode; /* read/write */
181 ushort flag;
182 Qid qid;
183 int fid; /* for devmnt */
184 ulong iounit; /* chunk size for i/o; 0==default */
185 Mhead* umh; /* mount point that derived Chan; used in unionread */
186 Chan* umc; /* channel in union; held for union read */
187 QLock umqlock; /* serialize unionreads */
188 int uri; /* union read index */
189 int dri; /* devdirread index */
190 ulong mountid;
191 Mntcache *mcp; /* Mount cache pointer */
192 Mnt *mux; /* Mnt for clients using me for messages */
193 void* aux;
194 Qid pgrpid; /* for #p/notepg */
195 ulong mid; /* for ns in devproc */
196 Chan* mchan; /* channel to mounted server */
197 Qid mqid; /* qid of root of mount point */
198 Session*session;
199 Cname *name;
200};
201
202struct Cname
203{
204 Ref ref;
205 int alen; /* allocated length */
206 int len; /* strlen(s) */
207 char *s;
208};
209
210struct Dev
211{
212 int dc;
213 char* name;
214
215 void (*reset)(void);
216 void (*init)(void);
217 void (*shutdown)(void);
218 Chan* (*attach)(char*);
219 Walkqid* (*walk)(Chan*, Chan*, char**, int);
220 int (*stat)(Chan*, uchar*, int);
221 Chan* (*open)(Chan*, int);
222 void (*create)(Chan*, char*, int, ulong);
223 void (*close)(Chan*);
224 long (*read)(Chan*, void*, long, vlong);
225 Block* (*bread)(Chan*, long, ulong);
226 long (*write)(Chan*, void*, long, vlong);
227 long (*bwrite)(Chan*, Block*, ulong);
228 void (*remove)(Chan*);
229 int (*wstat)(Chan*, uchar*, int);
230 void (*power)(int); /* power mgt: power(1) => on, power (0) => off */
231 int (*config)(int, char*, DevConf*); // returns nil on error
232};
233
234struct Dirtab
235{
236 char name[KNAMELEN];
237 Qid qid;
238 vlong length;
239 long perm;
240};
241
242struct Walkqid
243{
244 Chan *clone;
245 int nqid;
246 Qid qid[1];
247};
248
249enum
250{
251 NSMAX = 1000,
252 NSLOG = 7,
253 NSCACHE = (1<<NSLOG),
254};
255
256struct Mntwalk /* state for /proc/#/ns */
257{
258 int cddone;
259 ulong id;
260 Mhead* mh;
261 Mount* cm;
262};
263
264struct Mount
265{
266 ulong mountid;
267 Mount* next;
268 Mhead* head;
269 Mount* copy;
270 Mount* order;
271 Chan* to; /* channel replacing channel */
272 int mflag;
273 char *spec;
274};
275
276struct Mhead
277{
278 Ref ref;
279 RWlock lock;
280 Chan* from; /* channel mounted upon */
281 Mount* mount; /* what's mounted upon it */
282 Mhead* hash; /* Hash chain */
283};
284
285struct Mnt
286{
287 Lock lk;
288 /* references are counted using c->ref; channels on this mount point incref(c->mchan) == Mnt.c */
289 Chan *c; /* Channel to file service */
290 Proc *rip; /* Reader in progress */
291 Mntrpc *queue; /* Queue of pending requests on this channel */
292 ulong id; /* Multiplexer id for channel check */
293 Mnt *list; /* Free list */
294 int flags; /* cache */
295 int msize; /* data + IOHDRSZ */
296 char *version; /* 9P version */
297 Queue *q; /* input queue */
298};
299
300enum
301{
302 NUser, /* note provided externally */
303 NExit, /* deliver note quietly */
304 NDebug, /* print debug message */
305};
306
307struct Note
308{
309 char msg[ERRMAX];
310 int flag; /* whether system posted it */
311};
312
313enum
314{
315 RENDLOG = 5,
316 RENDHASH = 1<<RENDLOG, /* Hash to lookup rendezvous tags */
317 MNTLOG = 5,
318 MNTHASH = 1<<MNTLOG, /* Hash to walk mount table */
319 NFD = 100, /* per process file descriptors */
320 PGHLOG = 9,
321 PGHSIZE = 1<<PGHLOG, /* Page hash for image lookup */
322};
323#define REND(p,s) ((p)->rendhash[(s)&((1<<RENDLOG)-1)])
324#define MOUNTH(p,qid) ((p)->mnthash[(qid).path&((1<<MNTLOG)-1)])
325
326struct Pgrp
327{
328 Ref ref; /* also used as a lock when mounting */
329 int noattach;
330 ulong pgrpid;
331 QLock debug; /* single access via devproc.c */
332 RWlock ns; /* Namespace n read/one write lock */
333 Mhead *mnthash[MNTHASH];
334};
335
336struct Rgrp
337{
338 Ref ref;
339 Proc *rendhash[RENDHASH]; /* Rendezvous tag hash */
340};
341
342struct Egrp
343{
344 Ref ref;
345 RWlock lk;
346 Evalue **ent;
347 int nent;
348 int ment;
349 ulong path; /* qid.path of next Evalue to be allocated */
350 ulong vers; /* of Egrp */
351};
352
353struct Evalue
354{
355 char *name;
356 char *value;
357 int len;
358 Evalue *link;
359 Qid qid;
360};
361
362struct Fgrp
363{
364 Ref ref;
365 Chan **fd;
366 int nfd; /* number allocated */
367 int maxfd; /* highest fd in use */
368 int exceed; /* debugging */
369};
370
371enum
372{
373 DELTAFD = 20, /* incremental increase in Fgrp.fd's */
374 NERR = 20
375};
376
377typedef uvlong Ticks;
378
379enum
380{
381 Running,
382 Rendezvous,
383 Wakeme,
384};
385
386struct Proc
387{
388 uint state;
389 uint mach;
390
391 ulong pid;
392 ulong parentpid;
393
394 Pgrp *pgrp; /* Process group for namespace */
395 Fgrp *fgrp; /* File descriptor group */
396 Rgrp *rgrp;
397
398 Lock rlock; /* sync sleep/wakeup with postnote */
399 Rendez *r; /* rendezvous point slept on */
400 Rendez sleep; /* place for syssleep/debug */
401 int notepending; /* note issued but not acted on */
402 int kp; /* true if a kernel process */
403
404 ulong rendtag; /* Tag for rendezvous */
405 ulong rendval; /* Value for rendezvous */
406 Proc *rendhash; /* Hash list for tag values */
407
408 int nerrlab;
409 Label errlab[NERR];
410 char user[KNAMELEN];
411 char *syserrstr; /* last error from a system call, errbuf0 or 1 */
412 char *errstr; /* reason we're unwinding the error stack, errbuf1 or 0 */
413 char errbuf0[ERRMAX];
414 char errbuf1[ERRMAX];
415 char genbuf[128]; /* buffer used e.g. for last name element from namec */
416 char text[KNAMELEN];
417
418 Chan *slash;
419 Chan *dot;
420
421 Proc *qnext;
422
423 void (*fn)(void*);
424 void *arg;
425
426 char oproc[1024]; /* reserved for os */
427
428};
429
430enum
431{
432 PRINTSIZE = 256,
433 MAXCRYPT = 127,
434 NUMSIZE = 12, /* size of formatted number */
435 MB = (1024*1024),
436 READSTR = 1000, /* temporary buffer size for device reads */
437};
438
439extern char* conffile;
440extern int cpuserver;
441extern Dev* devtab[];
442extern char *eve;
443extern char hostdomain[];
444extern uchar initcode[];
445extern Queue* kbdq;
446extern Queue* kprintoq;
447extern Ref noteidalloc;
448extern Palloc palloc;
449extern Queue *serialoq;
450extern char* statename[];
451extern int nsyscall;
452extern char *sysname;
453extern uint qiomaxatomic;
454extern Conf conf;
455enum
456{
457 LRESPROF = 3,
458};
459
460/*
461 * action log
462 */
463struct Log {
464 Lock lk;
465 int opens;
466 char* buf;
467 char *end;
468 char *rptr;
469 int len;
470 int nlog;
471 int minread;
472
473 int logmask; /* mask of things to debug */
474
475 QLock readq;
476 Rendez readr;
477};
478
479struct Logflag {
480 char* name;
481 int mask;
482};
483
484enum
485{
486 NCMDFIELD = 128
487};
488
489struct Cmdbuf
490{
491 char *buf;
492 char **f;
493 int nf;
494};
495
496struct Cmdtab
497{
498 int index; /* used by client to switch on result */
499 char *cmd; /* command name */
500 int narg; /* expected #args; 0 ==> variadic */
501};
502
503/* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */
504enum
505{
506 /* Queue.state */
507 Qstarve = (1<<0), /* consumer starved */
508 Qmsg = (1<<1), /* message stream */
509 Qclosed = (1<<2), /* queue has been closed/hungup */
510 Qflow = (1<<3), /* producer flow controlled */
511 Qcoalesce = (1<<4), /* coallesce packets on read */
512 Qkick = (1<<5), /* always call the kick routine after qwrite */
513};
514
515#define DEVDOTDOT -1
516
517extern Proc *_getproc(void);
518extern void _setproc(Proc*);
519#define up (_getproc())
kern/data.c+31−0
@@ -0,0 +1,31 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7Proc *up;
8Conf conf =
9{
10 1,
11 100,
12 0,
13 1024*1024*1024,
14 1024*1024*1024,
15 1024*1024*1024,
16 1024*1024*1024,
17 1024*1024*1024,
18 1024*1024*1024,
19 1024*1024*1024,
20 1024*1024*1024,
21 1024*1024*1024,
22 1024*1024*1024,
23 1024*1024*1024,
24 1024*1024*1024,
25 0,
26};
27
28char *eve = "eve";
29ulong kerndate;
30int cpuserver;
31char hostdomain[] = "drawterm.net";
kern/dev.c+468−0
@@ -0,0 +1,468 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7extern ulong kerndate;
8
9void
10mkqid(Qid *q, vlong path, ulong vers, int type)
11{
12 q->type = type;
13 q->vers = vers;
14 q->path = path;
15}
16
17int
18devno(int c, int user)
19{
20 int i;
21
22 for(i = 0; devtab[i] != nil; i++) {
23 if(devtab[i]->dc == c)
24 return i;
25 }
26 if(user == 0)
27 panic("devno %C 0x%ux", c, c);
28
29 return -1;
30}
31
32void
33devdir(Chan *c, Qid qid, char *n, vlong length, char *user, long perm, Dir *db)
34{
35 db->name = n;
36 if(c->flag&CMSG)
37 qid.type |= QTMOUNT;
38 db->qid = qid;
39 db->type = devtab[c->type]->dc;
40 db->dev = c->dev;
41 db->mode = perm;
42 db->mode |= qid.type << 24;
43 db->atime = seconds();
44 db->mtime = kerndate;
45 db->length = length;
46 db->uid = user;
47 db->gid = eve;
48 db->muid = user;
49}
50
51/*
52 * (here, Devgen is the prototype; devgen is the function in dev.c.)
53 *
54 * a Devgen is expected to return the directory entry for ".."
55 * if you pass it s==DEVDOTDOT (-1). otherwise...
56 *
57 * there are two contradictory rules.
58 *
59 * (i) if c is a directory, a Devgen is expected to list its children
60 * as you iterate s.
61 *
62 * (ii) whether or not c is a directory, a Devgen is expected to list
63 * its siblings as you iterate s.
64 *
65 * devgen always returns the list of children in the root
66 * directory. thus it follows (i) when c is the root and (ii) otherwise.
67 * many other Devgens follow (i) when c is a directory and (ii) otherwise.
68 *
69 * devwalk assumes (i). it knows that devgen breaks (i)
70 * for children that are themselves directories, and explicitly catches them.
71 *
72 * devstat assumes (ii). if the Devgen in question follows (i)
73 * for this particular c, devstat will not find the necessary info.
74 * with our particular Devgen functions, this happens only for
75 * directories, so devstat makes something up, assuming
76 * c->name, c->qid, eve, DMDIR|0555.
77 *
78 * devdirread assumes (i). the callers have to make sure
79 * that the Devgen satisfies (i) for the chan being read.
80 */
81/*
82 * the zeroth element of the table MUST be the directory itself for ..
83*/
84int
85devgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
86{
87 if(tab == 0)
88 return -1;
89 if(i == DEVDOTDOT){
90 /* nothing */
91 }else if(name){
92 for(i=1; i<ntab; i++)
93 if(strcmp(tab[i].name, name) == 0)
94 break;
95 if(i==ntab)
96 return -1;
97 tab += i;
98 }else{
99 /* skip over the first element, that for . itself */
100 i++;
101 if(i >= ntab)
102 return -1;
103 tab += i;
104 }
105 devdir(c, tab->qid, tab->name, tab->length, eve, tab->perm, dp);
106 return 1;
107}
108
109void
110devreset(void)
111{
112}
113
114void
115devinit(void)
116{
117}
118
119void
120devshutdown(void)
121{
122}
123
124Chan*
125devattach(int tc, char *spec)
126{
127 Chan *c;
128 char *buf;
129
130 c = newchan();
131 mkqid(&c->qid, 0, 0, QTDIR);
132 c->type = devno(tc, 0);
133 if(spec == nil)
134 spec = "";
135 buf = smalloc(4+strlen(spec)+1);
136 sprint(buf, "#%C%s", tc, spec);
137 c->name = newcname(buf);
138 free(buf);
139 return c;
140}
141
142
143Chan*
144devclone(Chan *c)
145{
146 Chan *nc;
147
148 if(c->flag & COPEN)
149 panic("clone of open file type %C\n", devtab[c->type]->dc);
150
151 nc = newchan();
152
153 nc->type = c->type;
154 nc->dev = c->dev;
155 nc->mode = c->mode;
156 nc->qid = c->qid;
157 nc->offset = c->offset;
158 nc->umh = nil;
159 nc->mountid = c->mountid;
160 nc->aux = c->aux;
161 nc->pgrpid = c->pgrpid;
162 nc->mid = c->mid;
163 nc->mqid = c->mqid;
164 nc->mcp = c->mcp;
165 return nc;
166}
167
168Walkqid*
169devwalk(Chan *c, Chan *nc, char **name, int nname, Dirtab *tab, int ntab, Devgen *gen)
170{
171 int i, j, alloc;
172 Walkqid *wq;
173 char *n;
174 Dir dir;
175
176 if(nname > 0)
177 isdir(c);
178
179 alloc = 0;
180 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
181 if(waserror()){
182 if(alloc && wq->clone!=nil)
183 cclose(wq->clone);
184 free(wq);
185 return nil;
186 }
187 if(nc == nil){
188 nc = devclone(c);
189 nc->type = 0; /* device doesn't know about this channel yet */
190 alloc = 1;
191 }
192 wq->clone = nc;
193
194 for(j=0; j<nname; j++){
195 if(!(nc->qid.type&QTDIR)){
196 if(j==0)
197 error(Enotdir);
198 goto Done;
199 }
200 n = name[j];
201 if(strcmp(n, ".") == 0){
202 Accept:
203 wq->qid[wq->nqid++] = nc->qid;
204 continue;
205 }
206 if(strcmp(n, "..") == 0){
207 if((*gen)(nc, nil, tab, ntab, DEVDOTDOT, &dir) != 1){
208 print("devgen walk .. in dev%s %llux broken\n",
209 devtab[nc->type]->name, nc->qid.path);
210 error("broken devgen");
211 }
212 nc->qid = dir.qid;
213 goto Accept;
214 }
215 /*
216 * Ugly problem: If we're using devgen, make sure we're
217 * walking the directory itself, represented by the first
218 * entry in the table, and not trying to step into a sub-
219 * directory of the table, e.g. /net/net. Devgen itself
220 * should take care of the problem, but it doesn't have
221 * the necessary information (that we're doing a walk).
222 */
223 if(gen==devgen && nc->qid.path!=tab[0].qid.path)
224 goto Notfound;
225 for(i=0;; i++) {
226 switch((*gen)(nc, n, tab, ntab, i, &dir)){
227 case -1:
228 Notfound:
229 if(j == 0)
230 error(Enonexist);
231 kstrcpy(up->errstr, Enonexist, ERRMAX);
232 goto Done;
233 case 0:
234 continue;
235 case 1:
236 if(strcmp(n, dir.name) == 0){
237 nc->qid = dir.qid;
238 goto Accept;
239 }
240 continue;
241 }
242 }
243 }
244 /*
245 * We processed at least one name, so will return some data.
246 * If we didn't process all nname entries succesfully, we drop
247 * the cloned channel and return just the Qids of the walks.
248 */
249Done:
250 poperror();
251 if(wq->nqid < nname){
252 if(alloc)
253 cclose(wq->clone);
254 wq->clone = nil;
255 }else if(wq->clone){
256 /* attach cloned channel to same device */
257 wq->clone->type = c->type;
258 }
259 return wq;
260}
261
262int
263devstat(Chan *c, uchar *db, int n, Dirtab *tab, int ntab, Devgen *gen)
264{
265 int i;
266 Dir dir;
267 char *p, *elem;
268
269 for(i=0;; i++)
270 switch((*gen)(c, nil, tab, ntab, i, &dir)){
271 case -1:
272 if(c->qid.type & QTDIR){
273 if(c->name == nil)
274 elem = "???";
275 else if(strcmp(c->name->s, "/") == 0)
276 elem = "/";
277 else
278 for(elem=p=c->name->s; *p; p++)
279 if(*p == '/')
280 elem = p+1;
281 devdir(c, c->qid, elem, 0, eve, DMDIR|0555, &dir);
282 n = convD2M(&dir, db, n);
283 if(n == 0)
284 error(Ebadarg);
285 return n;
286 }
287 print("devstat %C %llux\n", devtab[c->type]->dc, c->qid.path);
288
289 error(Enonexist);
290 case 0:
291 break;
292 case 1:
293 if(c->qid.path == dir.qid.path) {
294 if(c->flag&CMSG)
295 dir.mode |= DMMOUNT;
296 n = convD2M(&dir, db, n);
297 if(n == 0)
298 error(Ebadarg);
299 return n;
300 }
301 break;
302 }
303 error(Egreg); /* not reached? */
304 return -1;
305}
306
307long
308devdirread(Chan *c, char *d, long n, Dirtab *tab, int ntab, Devgen *gen)
309{
310 long m, dsz;
311 struct{
312 Dir d;
313 char slop[100];
314 }dir;
315
316 for(m=0; m<n; c->dri++) {
317 switch((*gen)(c, nil, tab, ntab, c->dri, &dir.d)){
318 case -1:
319 return m;
320
321 case 0:
322 break;
323
324 case 1:
325 dsz = convD2M(&dir.d, (uchar*)d, n-m);
326 if(dsz <= BIT16SZ){ /* <= not < because this isn't stat; read is stuck */
327 if(m == 0)
328 error(Eshort);
329 return m;
330 }
331 m += dsz;
332 d += dsz;
333 break;
334 }
335 }
336
337 return m;
338}
339
340/*
341 * error(Eperm) if open permission not granted for up->user.
342 */
343void
344devpermcheck(char *fileuid, ulong perm, int omode)
345{
346 ulong t;
347 static int access[] = { 0400, 0200, 0600, 0100 };
348
349 if(strcmp(up->user, fileuid) == 0)
350 perm <<= 0;
351 else
352 if(strcmp(up->user, eve) == 0)
353 perm <<= 3;
354 else
355 perm <<= 6;
356
357 t = access[omode&3];
358 if((t&perm) != t)
359 error(Eperm);
360}
361
362Chan*
363devopen(Chan *c, int omode, Dirtab *tab, int ntab, Devgen *gen)
364{
365 int i;
366 Dir dir;
367
368 for(i=0;; i++) {
369 switch((*gen)(c, nil, tab, ntab, i, &dir)){
370 case -1:
371 goto Return;
372 case 0:
373 break;
374 case 1:
375 if(c->qid.path == dir.qid.path) {
376 devpermcheck(dir.uid, dir.mode, omode);
377 goto Return;
378 }
379 break;
380 }
381 }
382Return:
383 c->offset = 0;
384 if((c->qid.type&QTDIR) && omode!=OREAD)
385 error(Eperm);
386 c->mode = openmode(omode);
387 c->flag |= COPEN;
388 return c;
389}
390
391void
392devcreate(Chan *c, char *name, int mode, ulong perm)
393{
394 USED(c);
395 USED(name);
396 USED(mode);
397 USED(perm);
398
399 error(Eperm);
400}
401
402Block*
403devbread(Chan *c, long n, ulong offset)
404{
405 Block *bp;
406
407 bp = allocb(n);
408 if(bp == 0)
409 error(Enomem);
410 if(waserror()) {
411 freeb(bp);
412 nexterror();
413 }
414 bp->wp += devtab[c->type]->read(c, bp->wp, n, offset);
415 poperror();
416 return bp;
417}
418
419long
420devbwrite(Chan *c, Block *bp, ulong offset)
421{
422 long n;
423
424 if(waserror()) {
425 freeb(bp);
426 nexterror();
427 }
428 n = devtab[c->type]->write(c, bp->rp, BLEN(bp), offset);
429 poperror();
430 freeb(bp);
431
432 return n;
433}
434
435void
436devremove(Chan *c)
437{
438 USED(c);
439 error(Eperm);
440}
441
442int
443devwstat(Chan *c, uchar *a, int n)
444{
445 USED(c);
446 USED(a);
447 USED(n);
448
449 error(Eperm);
450 return 0;
451}
452
453void
454devpower(int a)
455{
456 USED(a);
457 error(Eperm);
458}
459
460int
461devconfig(int a, char *b, DevConf *c)
462{
463 USED(a);
464 USED(b);
465 USED(c);
466 error(Eperm);
467 return 0;
468}
kern/devcons.c+1238−0
@@ -0,0 +1,1238 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7#include "keyboard.h"
8
9void (*consdebug)(void) = nil;
10void (*screenputs)(char*, int) = nil;
11
12Queue* kbdq; /* unprocessed console input */
13Queue* lineq; /* processed console input */
14Queue* serialoq; /* serial console output */
15Queue* kprintoq; /* console output, for /dev/kprint */
16ulong kprintinuse; /* test and set whether /dev/kprint is open */
17int iprintscreenputs = 0;
18
19int panicking;
20
21struct
22{
23 int exiting;
24 int machs;
25} active;
26
27static struct
28{
29 QLock lk;
30
31 int raw; /* true if we shouldn't process input */
32 int ctl; /* number of opens to the control file */
33 int x; /* index into line */
34 char line[1024]; /* current input line */
35
36 int count;
37 int ctlpoff;
38
39 /* a place to save up characters at interrupt time before dumping them in the queue */
40 Lock lockputc;
41 char istage[1024];
42 char *iw;
43 char *ir;
44 char *ie;
45} kbd = {
46 { 0 },
47 0,
48 0,
49 0,
50 { 0 },
51 0,
52 0,
53 { 0 },
54 { 0 },
55 kbd.istage,
56 kbd.istage,
57 kbd.istage + sizeof(kbd.istage),
58};
59
60char *sysname;
61vlong fasthz;
62
63static void seedrand(void);
64static int readtime(ulong, char*, int);
65static int readbintime(char*, int);
66static int writetime(char*, int);
67static int writebintime(char*, int);
68
69enum
70{
71 CMreboot,
72 CMpanic,
73};
74
75Cmdtab rebootmsg[] =
76{
77 CMreboot, "reboot", 0,
78 CMpanic, "panic", 0,
79};
80
81int
82return0(void *v)
83{
84 return 0;
85}
86
87void
88printinit(void)
89{
90 lineq = qopen(2*1024, 0, nil, nil);
91 if(lineq == nil)
92 panic("printinit");
93 qnoblock(lineq, 1);
94
95 kbdq = qopen(4*1024, 0, 0, 0);
96 if(kbdq == nil)
97 panic("kbdinit");
98 qnoblock(kbdq, 1);
99}
100
101int
102consactive(void)
103{
104 if(serialoq)
105 return qlen(serialoq) > 0;
106 return 0;
107}
108
109void
110prflush(void)
111{
112/*
113 ulong now;
114
115 now = m->ticks;
116 while(consactive())
117 if(m->ticks - now >= HZ)
118 break;
119*/
120}
121
122/*
123 * Print a string on the console. Convert \n to \r\n for serial
124 * line consoles. Locking of the queues is left up to the screen
125 * or uart code. Multi-line messages to serial consoles may get
126 * interspersed with other messages.
127 */
128static void
129putstrn0(char *str, int n, int usewrite)
130{
131 int m;
132 char *t;
133
134 /*
135 * if someone is reading /dev/kprint,
136 * put the message there.
137 * if not and there's an attached bit mapped display,
138 * put the message there.
139 *
140 * if there's a serial line being used as a console,
141 * put the message there.
142 */
143 if(kprintoq != nil && !qisclosed(kprintoq)){
144 if(usewrite)
145 qwrite(kprintoq, str, n);
146 else
147 qiwrite(kprintoq, str, n);
148 }else if(screenputs != nil)
149 screenputs(str, n);
150
151 if(serialoq == nil){
152 uartputs(str, n);
153 return;
154 }
155
156 while(n > 0) {
157 t = memchr(str, '\n', n);
158 if(t && !kbd.raw) {
159 m = t-str;
160 if(usewrite){
161 qwrite(serialoq, str, m);
162 qwrite(serialoq, "\r\n", 2);
163 } else {
164 qiwrite(serialoq, str, m);
165 qiwrite(serialoq, "\r\n", 2);
166 }
167 n -= m+1;
168 str = t+1;
169 } else {
170 if(usewrite)
171 qwrite(serialoq, str, n);
172 else
173 qiwrite(serialoq, str, n);
174 break;
175 }
176 }
177}
178
179void
180putstrn(char *str, int n)
181{
182 putstrn0(str, n, 0);
183}
184
185int noprint;
186
187int
188print(char *fmt, ...)
189{
190 int n;
191 va_list arg;
192 char buf[PRINTSIZE];
193
194 if(noprint)
195 return -1;
196
197 va_start(arg, fmt);
198 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
199 va_end(arg);
200 putstrn(buf, n);
201
202 return n;
203}
204
205int
206iprint(char *fmt, ...)
207{
208 int n, s;
209 va_list arg;
210 char buf[PRINTSIZE];
211
212 s = splhi();
213 va_start(arg, fmt);
214 n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
215 va_end(arg);
216 if(screenputs != nil && iprintscreenputs)
217 screenputs(buf, n);
218 uartputs(buf, n);
219 splx(s);
220
221 return n;
222}
223
224void
225panic(char *fmt, ...)
226{
227 int n;
228 va_list arg;
229 char buf[PRINTSIZE];
230
231 kprintoq = nil; /* don't try to write to /dev/kprint */
232
233 if(panicking)
234 for(;;);
235 panicking = 1;
236
237 splhi();
238 strcpy(buf, "panic: ");
239 va_start(arg, fmt);
240 n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
241 va_end(arg);
242 buf[n] = '\n';
243 uartputs(buf, n+1);
244 if(consdebug)
245 (*consdebug)();
246 spllo();
247 prflush();
248 putstrn(buf, n+1);
249 dumpstack();
250
251 exit(1);
252}
253
254int
255pprint(char *fmt, ...)
256{
257 int n;
258 Chan *c;
259 va_list arg;
260 char buf[2*PRINTSIZE];
261
262 if(up == nil || up->fgrp == nil)
263 return 0;
264
265 c = up->fgrp->fd[2];
266 if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
267 return 0;
268 n = sprint(buf, "%s %lud: ", up->text, up->pid);
269 va_start(arg, fmt);
270 n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
271 va_end(arg);
272
273 if(waserror())
274 return 0;
275 devtab[c->type]->write(c, buf, n, c->offset);
276 poperror();
277
278 lock(&c->ref.lk);
279 c->offset += n;
280 unlock(&c->ref.lk);
281
282 return n;
283}
284
285static void
286echoscreen(char *buf, int n)
287{
288 char *e, *p;
289 char ebuf[128];
290 int x;
291
292 p = ebuf;
293 e = ebuf + sizeof(ebuf) - 4;
294 while(n-- > 0){
295 if(p >= e){
296 screenputs(ebuf, p - ebuf);
297 p = ebuf;
298 }
299 x = *buf++;
300 if(x == 0x15){
301 *p++ = '^';
302 *p++ = 'U';
303 *p++ = '\n';
304 } else
305 *p++ = x;
306 }
307 if(p != ebuf)
308 screenputs(ebuf, p - ebuf);
309}
310
311static void
312echoserialoq(char *buf, int n)
313{
314 char *e, *p;
315 char ebuf[128];
316 int x;
317
318 p = ebuf;
319 e = ebuf + sizeof(ebuf) - 4;
320 while(n-- > 0){
321 if(p >= e){
322 qiwrite(serialoq, ebuf, p - ebuf);
323 p = ebuf;
324 }
325 x = *buf++;
326 if(x == '\n'){
327 *p++ = '\r';
328 *p++ = '\n';
329 } else if(x == 0x15){
330 *p++ = '^';
331 *p++ = 'U';
332 *p++ = '\n';
333 } else
334 *p++ = x;
335 }
336 if(p != ebuf)
337 qiwrite(serialoq, ebuf, p - ebuf);
338}
339
340static void
341echo(char *buf, int n)
342{
343 static int ctrlt, pid;
344 extern ulong etext;
345 int x;
346 char *e, *p;
347
348 e = buf+n;
349 for(p = buf; p < e; p++){
350 switch(*p){
351 case 0x10: /* ^P */
352 if(cpuserver && !kbd.ctlpoff){
353 active.exiting = 1;
354 return;
355 }
356 break;
357 case 0x14: /* ^T */
358 ctrlt++;
359 if(ctrlt > 2)
360 ctrlt = 2;
361 continue;
362 }
363
364 if(ctrlt != 2)
365 continue;
366
367 /* ^T escapes */
368 ctrlt = 0;
369 switch(*p){
370 case 'S':
371 x = splhi();
372 dumpstack();
373 procdump();
374 splx(x);
375 return;
376 case 's':
377 dumpstack();
378 return;
379 case 'x':
380 xsummary();
381 ixsummary();
382 mallocsummary();
383 pagersummary();
384 return;
385 case 'd':
386 if(consdebug == nil)
387 consdebug = rdb;
388 else
389 consdebug = nil;
390 print("consdebug now 0x%p\n", consdebug);
391 return;
392 case 'D':
393 if(consdebug == nil)
394 consdebug = rdb;
395 consdebug();
396 return;
397 case 'p':
398 x = spllo();
399 procdump();
400 splx(x);
401 return;
402 case 'q':
403 scheddump();
404 return;
405 case 'k':
406 killbig();
407 return;
408 case 'r':
409 exit(0);
410 return;
411 }
412 }
413
414 qproduce(kbdq, buf, n);
415 if(kbd.raw)
416 return;
417 if(screenputs != nil)
418 echoscreen(buf, n);
419 if(serialoq)
420 echoserialoq(buf, n);
421}
422
423/*
424 * Called by a uart interrupt for console input.
425 *
426 * turn '\r' into '\n' before putting it into the queue.
427 */
428int
429kbdcr2nl(Queue *q, int ch)
430{
431 char *next;
432
433 USED(q);
434 ilock(&kbd.lockputc); /* just a mutex */
435 if(ch == '\r' && !kbd.raw)
436 ch = '\n';
437 next = kbd.iw+1;
438 if(next >= kbd.ie)
439 next = kbd.istage;
440 if(next != kbd.ir){
441 *kbd.iw = ch;
442 kbd.iw = next;
443 }
444 iunlock(&kbd.lockputc);
445 return 0;
446}
447static
448void
449_kbdputc(int c)
450{
451 Rune r;
452 char buf[UTFmax];
453 int n;
454
455 r = c;
456 n = runetochar(buf, &r);
457 if(n == 0)
458 return;
459 echo(buf, n);
460// kbd.c = r;
461// qproduce(kbdq, buf, n);
462}
463
464/* _kbdputc, but with compose translation */
465int
466kbdputc(Queue *q, int c)
467{
468 int i;
469 static int collecting, nk;
470 static Rune kc[5];
471
472 if(c == Kalt){
473 collecting = 1;
474 nk = 0;
475 return;
476 }
477
478 if(!collecting){
479 _kbdputc(c);
480 return;
481 }
482
483 kc[nk++] = c;
484 c = latin1(kc, nk);
485 if(c < -1) /* need more keystrokes */
486 return;
487 if(c != -1) /* valid sequence */
488 _kbdputc(c);
489 else
490 for(i=0; i<nk; i++)
491 _kbdputc(kc[i]);
492 nk = 0;
493 collecting = 0;
494
495 return 0;
496}
497
498
499enum{
500 Qdir,
501 Qbintime,
502 Qcons,
503 Qconsctl,
504 Qcpunote,
505 Qcputime,
506 Qdrivers,
507 Qkprint,
508 Qhostdomain,
509 Qhostowner,
510 Qnull,
511 Qosversion,
512 Qpgrpid,
513 Qpid,
514 Qppid,
515 Qrandom,
516 Qreboot,
517 Qsecstore,
518 Qsnarf,
519 Qswap,
520 Qsysname,
521 Qsysstat,
522 Qtime,
523 Quser,
524 Qzero,
525};
526
527enum
528{
529 VLNUMSIZE= 22,
530};
531
532static Dirtab consdir[]={
533 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
534 "bintime", {Qbintime}, 24, 0664,
535 "cons", {Qcons}, 0, 0660,
536 "consctl", {Qconsctl}, 0, 0220,
537 "cpunote", {Qcpunote}, 0, 0444,
538 "cputime", {Qcputime}, 6*NUMSIZE, 0444,
539 "drivers", {Qdrivers}, 0, 0444,
540 "hostdomain", {Qhostdomain}, DOMLEN, 0664,
541 "hostowner", {Qhostowner}, 0, 0664,
542 "kprint", {Qkprint, 0, QTEXCL}, 0, DMEXCL|0440,
543 "null", {Qnull}, 0, 0666,
544 "osversion", {Qosversion}, 0, 0444,
545 "pgrpid", {Qpgrpid}, NUMSIZE, 0444,
546 "pid", {Qpid}, NUMSIZE, 0444,
547 "ppid", {Qppid}, NUMSIZE, 0444,
548 "random", {Qrandom}, 0, 0444,
549 "reboot", {Qreboot}, 0, 0664,
550 "secstore", {Qsecstore}, 0, 0666,
551 "snarf", {Qsnarf}, 0, 0666,
552 "swap", {Qswap}, 0, 0664,
553 "sysname", {Qsysname}, 0, 0664,
554 "sysstat", {Qsysstat}, 0, 0666,
555 "time", {Qtime}, NUMSIZE+3*VLNUMSIZE, 0664,
556 "user", {Quser}, 0, 0666,
557 "zero", {Qzero}, 0, 0444,
558};
559
560char secstorebuf[65536];
561Dirtab *secstoretab = &consdir[Qsecstore];
562Dirtab *snarftab = &consdir[Qsnarf];
563
564int
565readnum(ulong off, char *buf, ulong n, ulong val, int size)
566{
567 char tmp[64];
568
569 snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val);
570 tmp[size-1] = ' ';
571 if(off >= size)
572 return 0;
573 if(off+n > size)
574 n = size-off;
575 memmove(buf, tmp+off, n);
576 return n;
577}
578
579int
580readstr(ulong off, char *buf, ulong n, char *str)
581{
582 int size;
583
584 size = strlen(str);
585 if(off >= size)
586 return 0;
587 if(off+n > size)
588 n = size-off;
589 memmove(buf, str+off, n);
590 return n;
591}
592
593static void
594consinit(void)
595{
596 todinit();
597 randominit();
598 /*
599 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
600 * processing it every 22 ms should be fine
601 */
602/* addclock0link(kbdputcclock, 22); */
603}
604
605static Chan*
606consattach(char *spec)
607{
608 return devattach('c', spec);
609}
610
611static Walkqid*
612conswalk(Chan *c, Chan *nc, char **name, int nname)
613{
614 return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
615}
616
617static int
618consstat(Chan *c, uchar *dp, int n)
619{
620 return devstat(c, dp, n, consdir, nelem(consdir), devgen);
621}
622
623static Chan*
624consopen(Chan *c, int omode)
625{
626 c->aux = nil;
627 c = devopen(c, omode, consdir, nelem(consdir), devgen);
628 switch((ulong)c->qid.path){
629 case Qconsctl:
630 qlock(&kbd.lk);
631 kbd.ctl++;
632 qunlock(&kbd.lk);
633 break;
634
635 case Qkprint:
636 if(tas(&kprintinuse) != 0){
637 c->flag &= ~COPEN;
638 error(Einuse);
639 }
640 if(kprintoq == nil){
641 kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
642 if(kprintoq == nil){
643 c->flag &= ~COPEN;
644 error(Enomem);
645 }
646 qnoblock(kprintoq, 1);
647 }else
648 qreopen(kprintoq);
649 c->iounit = qiomaxatomic;
650 break;
651
652 case Qsecstore:
653 if(omode == ORDWR)
654 error(Eperm);
655 if(omode != OREAD)
656 memset(secstorebuf, 0, sizeof secstorebuf);
657 break;
658
659 case Qsnarf:
660 if(omode == ORDWR)
661 error(Eperm);
662 if(omode == OREAD)
663 c->aux = strdup("");
664 else
665 c->aux = mallocz(SnarfSize, 1);
666 break;
667 }
668 return c;
669}
670
671static void
672consclose(Chan *c)
673{
674 switch((ulong)c->qid.path){
675 /* last close of control file turns off raw */
676 case Qconsctl:
677 if(c->flag&COPEN){
678 qlock(&kbd.lk);
679 if(--kbd.ctl == 0)
680 kbd.raw = 0;
681 qunlock(&kbd.lk);
682 }
683 break;
684
685 /* close of kprint allows other opens */
686 case Qkprint:
687 if(c->flag & COPEN){
688 kprintinuse = 0;
689 qhangup(kprintoq, nil);
690 }
691 break;
692
693 case Qsnarf:
694 if(c->mode == OWRITE)
695 clipwrite(c->aux);
696 free(c->aux);
697 break;
698 }
699}
700
701static long
702consread(Chan *c, void *buf, long n, vlong off)
703{
704 ulong l;
705 char *b, *bp;
706 char tmp[128]; /* must be >= 6*NUMSIZE */
707 char *cbuf = buf;
708 int ch, i, k, id, eol;
709 vlong offset = off;
710
711 if(n <= 0)
712 return n;
713 switch((ulong)c->qid.path){
714 case Qdir:
715 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
716
717 case Qcons:
718 qlock(&kbd.lk);
719 if(waserror()) {
720 qunlock(&kbd.lk);
721 nexterror();
722 }
723 if(kbd.raw) {
724 if(qcanread(lineq))
725 n = qread(lineq, buf, n);
726 else {
727 /* read as much as possible */
728 do {
729 i = qread(kbdq, cbuf, n);
730 cbuf += i;
731 n -= i;
732 } while (n>0 && qcanread(kbdq));
733 n = cbuf - (char*)buf;
734 }
735 } else {
736 while(!qcanread(lineq)) {
737 qread(kbdq, &kbd.line[kbd.x], 1);
738 ch = kbd.line[kbd.x];
739 eol = 0;
740 switch(ch){
741 case '\b':
742 if(kbd.x)
743 kbd.x--;
744 break;
745 case 0x15:
746 kbd.x = 0;
747 break;
748 case '\n':
749 case 0x04:
750 eol = 1;
751 default:
752 kbd.line[kbd.x++] = ch;
753 break;
754 }
755 if(kbd.x == sizeof(kbd.line) || eol){
756 if(ch == 0x04)
757 kbd.x--;
758 qwrite(lineq, kbd.line, kbd.x);
759 kbd.x = 0;
760 }
761 }
762 n = qread(lineq, buf, n);
763 }
764 qunlock(&kbd.lk);
765 poperror();
766 return n;
767
768 case Qcpunote:
769 sleep(&up->sleep, return0, nil);
770
771 case Qcputime:
772 return 0;
773
774 case Qkprint:
775 return qread(kprintoq, buf, n);
776
777 case Qpgrpid:
778 return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
779
780 case Qpid:
781 return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
782
783 case Qppid:
784 return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
785
786 case Qtime:
787 return readtime((ulong)offset, buf, n);
788
789 case Qbintime:
790 return readbintime(buf, n);
791
792 case Qhostowner:
793 return readstr((ulong)offset, buf, n, eve);
794
795 case Qhostdomain:
796 return readstr((ulong)offset, buf, n, hostdomain);
797
798 case Quser:
799 return readstr((ulong)offset, buf, n, up->user);
800
801 case Qnull:
802 return 0;
803
804 case Qsnarf:
805 if(offset == 0){
806 free(c->aux);
807 c->aux = clipread();
808 }
809 if(c->aux == nil)
810 return 0;
811 return readstr(offset, buf, n, c->aux);
812
813 case Qsecstore:
814 return readstr(offset, buf, n, secstorebuf);
815
816 case Qsysstat:
817 return 0;
818
819 case Qswap:
820 return 0;
821
822 case Qsysname:
823 if(sysname == nil)
824 return 0;
825 return readstr((ulong)offset, buf, n, sysname);
826
827 case Qrandom:
828 return randomread(buf, n);
829
830 case Qdrivers:
831 b = malloc(READSTR);
832 if(b == nil)
833 error(Enomem);
834 n = 0;
835 for(i = 0; devtab[i] != nil; i++)
836 n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc, devtab[i]->name);
837 if(waserror()){
838 free(b);
839 nexterror();
840 }
841 n = readstr((ulong)offset, buf, n, b);
842 free(b);
843 poperror();
844 return n;
845
846 case Qzero:
847 memset(buf, 0, n);
848 return n;
849
850 case Qosversion:
851 snprint(tmp, sizeof tmp, "2000");
852 n = readstr((ulong)offset, buf, n, tmp);
853 return n;
854
855 default:
856 print("consread 0x%llux\n", c->qid.path);
857 error(Egreg);
858 }
859 return -1; /* never reached */
860}
861
862static long
863conswrite(Chan *c, void *va, long n, vlong off)
864{
865 char buf[256];
866 long l, bp;
867 char *a = va;
868 int id, fd;
869 Chan *swc;
870 ulong offset = off;
871 Cmdbuf *cb;
872 Cmdtab *ct;
873
874 switch((ulong)c->qid.path){
875 case Qcons:
876 /*
877 * Can't page fault in putstrn, so copy the data locally.
878 */
879 l = n;
880 while(l > 0){
881 bp = l;
882 if(bp > sizeof buf)
883 bp = sizeof buf;
884 memmove(buf, a, bp);
885 putstrn0(buf, bp, 1);
886 a += bp;
887 l -= bp;
888 }
889 break;
890
891 case Qconsctl:
892 if(n >= sizeof(buf))
893 n = sizeof(buf)-1;
894 strncpy(buf, a, n);
895 buf[n] = 0;
896 for(a = buf; a;){
897 if(strncmp(a, "rawon", 5) == 0){
898 qlock(&kbd.lk);
899 if(kbd.x){
900 qwrite(kbdq, kbd.line, kbd.x);
901 kbd.x = 0;
902 }
903 kbd.raw = 1;
904 qunlock(&kbd.lk);
905 } else if(strncmp(a, "rawoff", 6) == 0){
906 qlock(&kbd.lk);
907 kbd.raw = 0;
908 kbd.x = 0;
909 qunlock(&kbd.lk);
910 } else if(strncmp(a, "ctlpon", 6) == 0){
911 kbd.ctlpoff = 0;
912 } else if(strncmp(a, "ctlpoff", 7) == 0){
913 kbd.ctlpoff = 1;
914 }
915 if(a = strchr(a, ' '))
916 a++;
917 }
918 break;
919
920 case Qtime:
921 if(!iseve())
922 error(Eperm);
923 return writetime(a, n);
924
925 case Qbintime:
926 if(!iseve())
927 error(Eperm);
928 return writebintime(a, n);
929
930 case Qhostowner:
931 return hostownerwrite(a, n);
932
933 case Qhostdomain:
934 return hostdomainwrite(a, n);
935
936 case Quser:
937 return userwrite(a, n);
938
939 case Qnull:
940 break;
941
942 case Qreboot:
943 if(!iseve())
944 error(Eperm);
945 cb = parsecmd(a, n);
946
947 if(waserror()) {
948 free(cb);
949 nexterror();
950 }
951 ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
952 switch(ct->index) {
953 case CMreboot:
954 rebootcmd(cb->nf-1, cb->f+1);
955 break;
956 case CMpanic:
957 panic("/dev/reboot");
958 }
959 poperror();
960 free(cb);
961 break;
962
963 case Qsecstore:
964 if(offset >= sizeof secstorebuf || offset+n+1 >= sizeof secstorebuf)
965 error(Etoobig);
966 secstoretab->qid.vers++;
967 memmove(secstorebuf+offset, va, n);
968 return n;
969
970 case Qsnarf:
971 if(offset >= SnarfSize || offset+n >= SnarfSize)
972 error(Etoobig);
973 snarftab->qid.vers++;
974 memmove((uchar*)c->aux+offset, va, n);
975 return n;
976
977 case Qsysstat:
978 n = 0;
979 break;
980
981 case Qswap:
982 if(n >= sizeof buf)
983 error(Egreg);
984 memmove(buf, va, n); /* so we can NUL-terminate */
985 buf[n] = 0;
986 /* start a pager if not already started */
987 if(strncmp(buf, "start", 5) == 0){
988 kickpager();
989 break;
990 }
991 if(cpuserver && !iseve())
992 error(Eperm);
993 if(buf[0]<'0' || '9'<buf[0])
994 error(Ebadarg);
995 fd = strtoul(buf, 0, 0);
996 swc = fdtochan(fd, -1, 1, 1);
997 setswapchan(swc);
998 break;
999
1000 case Qsysname:
1001 if(offset != 0)
1002 error(Ebadarg);
1003 if(n <= 0 || n >= sizeof buf)
1004 error(Ebadarg);
1005 strncpy(buf, a, n);
1006 buf[n] = 0;
1007 if(buf[n-1] == '\n')
1008 buf[n-1] = 0;
1009 kstrdup(&sysname, buf);
1010 break;
1011
1012 default:
1013 print("conswrite: 0x%llux\n", c->qid.path);
1014 error(Egreg);
1015 }
1016 return n;
1017}
1018
1019Dev consdevtab = {
1020 'c',
1021 "cons",
1022
1023 devreset,
1024 consinit,
1025 devshutdown,
1026 consattach,
1027 conswalk,
1028 consstat,
1029 consopen,
1030 devcreate,
1031 consclose,
1032 consread,
1033 devbread,
1034 conswrite,
1035 devbwrite,
1036 devremove,
1037 devwstat,
1038};
1039
1040static ulong randn;
1041
1042static void
1043seedrand(void)
1044{
1045 randomread((void*)&randn, sizeof(randn));
1046}
1047
1048// int
1049// nrand(int n)
1050// {
1051// if(randn == 0)
1052// seedrand();
1053// randn = randn*1103515245 + 12345 + fastticks(0);
1054// return (randn>>16) % n;
1055// }
1056
1057int
1058rand(void)
1059{
1060 nrand(1);
1061 return randn;
1062}
1063
1064/* static uvlong uvorder = 0x0001020304050607ULL; */
1065static uvlong uvorder = (uvlong)0x0001020304050607;
1066
1067static uchar*
1068le2vlong(vlong *to, uchar *f)
1069{
1070 uchar *t, *o;
1071 int i;
1072
1073 t = (uchar*)to;
1074 o = (uchar*)&uvorder;
1075 for(i = 0; i < sizeof(vlong); i++)
1076 t[o[i]] = f[i];
1077 return f+sizeof(vlong);
1078}
1079
1080static uchar*
1081vlong2le(uchar *t, vlong from)
1082{
1083 uchar *f, *o;
1084 int i;
1085
1086 f = (uchar*)&from;
1087 o = (uchar*)&uvorder;
1088 for(i = 0; i < sizeof(vlong); i++)
1089 t[i] = f[o[i]];
1090 return t+sizeof(vlong);
1091}
1092
1093static long order = 0x00010203;
1094
1095static uchar*
1096le2long(long *to, uchar *f)
1097{
1098 uchar *t, *o;
1099 int i;
1100
1101 t = (uchar*)to;
1102 o = (uchar*)&order;
1103 for(i = 0; i < sizeof(long); i++)
1104 t[o[i]] = f[i];
1105 return f+sizeof(long);
1106}
1107
1108static uchar*
1109long2le(uchar *t, long from)
1110{
1111 uchar *f, *o;
1112 int i;
1113
1114 f = (uchar*)&from;
1115 o = (uchar*)&order;
1116 for(i = 0; i < sizeof(long); i++)
1117 t[i] = f[o[i]];
1118 return t+sizeof(long);
1119}
1120
1121char *Ebadtimectl = "bad time control";
1122
1123/*
1124 * like the old #c/time but with added info. Return
1125 *
1126 * secs nanosecs fastticks fasthz
1127 */
1128static int
1129readtime(ulong off, char *buf, int n)
1130{
1131 vlong nsec, ticks;
1132 long sec;
1133 char str[7*NUMSIZE];
1134
1135 nsec = todget(&ticks);
1136 if(fasthz == (vlong)0)
1137 fastticks((uvlong*)&fasthz);
1138 sec = nsec/((uvlong) 1000000000);
1139 snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ",
1140 NUMSIZE-1, sec,
1141 VLNUMSIZE-1, nsec,
1142 VLNUMSIZE-1, ticks,
1143 VLNUMSIZE-1, fasthz);
1144 return readstr(off, buf, n, str);
1145}
1146
1147/*
1148 * set the time in seconds
1149 */
1150static int
1151writetime(char *buf, int n)
1152{
1153 char b[13];
1154 long i;
1155 vlong now;
1156
1157 if(n >= sizeof(b))
1158 error(Ebadtimectl);
1159 strncpy(b, buf, n);
1160 b[n] = 0;
1161 i = strtol(b, 0, 0);
1162 if(i <= 0)
1163 error(Ebadtimectl);
1164 now = i*((vlong) 1000000000);
1165 todset(now, 0, 0);
1166 return n;
1167}
1168
1169/*
1170 * read binary time info. all numbers are little endian.
1171 * ticks and nsec are syncronized.
1172 */
1173static int
1174readbintime(char *buf, int n)
1175{
1176 int i;
1177 vlong nsec, ticks;
1178 uchar *b = (uchar*)buf;
1179
1180 i = 0;
1181 if(fasthz == (vlong)0)
1182 fastticks((uvlong*)&fasthz);
1183 nsec = todget(&ticks);
1184 if(n >= 3*sizeof(uvlong)){
1185 vlong2le(b+2*sizeof(uvlong), fasthz);
1186 i += sizeof(uvlong);
1187 }
1188 if(n >= 2*sizeof(uvlong)){
1189 vlong2le(b+sizeof(uvlong), ticks);
1190 i += sizeof(uvlong);
1191 }
1192 if(n >= 8){
1193 vlong2le(b, nsec);
1194 i += sizeof(vlong);
1195 }
1196 return i;
1197}
1198
1199/*
1200 * set any of the following
1201 * - time in nsec
1202 * - nsec trim applied over some seconds
1203 * - clock frequency
1204 */
1205static int
1206writebintime(char *buf, int n)
1207{
1208 uchar *p;
1209 vlong delta;
1210 long period;
1211
1212 n--;
1213 p = (uchar*)buf + 1;
1214 switch(*buf){
1215 case 'n':
1216 if(n < sizeof(vlong))
1217 error(Ebadtimectl);
1218 le2vlong(&delta, p);
1219 todset(delta, 0, 0);
1220 break;
1221 case 'd':
1222 if(n < sizeof(vlong)+sizeof(long))
1223 error(Ebadtimectl);
1224 p = le2vlong(&delta, p);
1225 le2long(&period, p);
1226 todset(-1, delta, period);
1227 break;
1228 case 'f':
1229 if(n < sizeof(uvlong))
1230 error(Ebadtimectl);
1231 le2vlong(&fasthz, p);
1232 todsetfreq(fasthz);
1233 break;
1234 }
1235 return n;
1236}
1237
1238
kern/devdraw.c+2100−0
@@ -0,0 +1,2100 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7#define Image IMAGE
8#include <draw.h>
9#include <memdraw.h>
10#include <memlayer.h>
11#include <cursor.h>
12#include "screen.h"
13
14enum
15{
16 Qtopdir = 0,
17 Qnew,
18 Q3rd,
19 Q2nd,
20 Qcolormap,
21 Qctl,
22 Qdata,
23 Qrefresh,
24};
25
26/*
27 * Qid path is:
28 * 4 bits of file type (qids above)
29 * 24 bits of mux slot number +1; 0 means not attached to client
30 */
31#define QSHIFT 4 /* location in qid of client # */
32
33#define QID(q) ((((ulong)(q).path)&0x0000000F)>>0)
34#define CLIENTPATH(q) ((((ulong)q)&0x7FFFFFF0)>>QSHIFT)
35#define CLIENT(q) CLIENTPATH((q).path)
36
37#define NHASH (1<<5)
38#define HASHMASK (NHASH-1)
39#define IOUNIT (64*1024)
40
41typedef struct Client Client;
42typedef struct Draw Draw;
43typedef struct DImage DImage;
44typedef struct DScreen DScreen;
45typedef struct CScreen CScreen;
46typedef struct FChar FChar;
47typedef struct Refresh Refresh;
48typedef struct Refx Refx;
49typedef struct DName DName;
50
51ulong blanktime = 30; /* in minutes; a half hour */
52
53struct Draw
54{
55 QLock lk;
56 int clientid;
57 int nclient;
58 Client** client;
59 int nname;
60 DName* name;
61 int vers;
62 int softscreen;
63 int blanked; /* screen turned off */
64 ulong blanktime; /* time of last operation */
65 ulong savemap[3*256];
66};
67
68struct Client
69{
70 Ref r;
71 DImage* dimage[NHASH];
72 CScreen* cscreen;
73 Refresh* refresh;
74 Rendez refrend;
75 uchar* readdata;
76 int nreaddata;
77 int busy;
78 int clientid;
79 int slot;
80 int refreshme;
81 int infoid;
82 int op;
83};
84
85struct Refresh
86{
87 DImage* dimage;
88 Rectangle r;
89 Refresh* next;
90};
91
92struct Refx
93{
94 Client* client;
95 DImage* dimage;
96};
97
98struct DName
99{
100 char *name;
101 Client *client;
102 DImage* dimage;
103 int vers;
104};
105
106struct FChar
107{
108 int minx; /* left edge of bits */
109 int maxx; /* right edge of bits */
110 uchar miny; /* first non-zero scan-line */
111 uchar maxy; /* last non-zero scan-line + 1 */
112 schar left; /* offset of baseline */
113 uchar width; /* width of baseline */
114};
115
116/*
117 * Reference counts in DImages:
118 * one per open by original client
119 * one per screen image or fill
120 * one per image derived from this one by name
121 */
122struct DImage
123{
124 int id;
125 int ref;
126 char *name;
127 int vers;
128 Memimage* image;
129 int ascent;
130 int nfchar;
131 FChar* fchar;
132 DScreen* dscreen; /* 0 if not a window */
133 DImage* fromname; /* image this one is derived from, by name */
134 DImage* next;
135};
136
137struct CScreen
138{
139 DScreen* dscreen;
140 CScreen* next;
141};
142
143struct DScreen
144{
145 int id;
146 int public;
147 int ref;
148 DImage *dimage;
149 DImage *dfill;
150 Memscreen* screen;
151 Client* owner;
152 DScreen* next;
153};
154
155static Draw sdraw;
156static Memimage *screenimage;
157static Memdata screendata;
158static Rectangle flushrect;
159static int waste;
160static DScreen* dscreen;
161extern void flushmemscreen(Rectangle);
162 void drawmesg(Client*, void*, int);
163 void drawuninstall(Client*, int);
164 void drawfreedimage(DImage*);
165 Client* drawclientofpath(ulong);
166
167static char Enodrawimage[] = "unknown id for draw image";
168static char Enodrawscreen[] = "unknown id for draw screen";
169static char Eshortdraw[] = "short draw message";
170static char Eshortread[] = "draw read too short";
171static char Eimageexists[] = "image id in use";
172static char Escreenexists[] = "screen id in use";
173static char Edrawmem[] = "image memory allocation failed";
174static char Ereadoutside[] = "readimage outside image";
175static char Ewriteoutside[] = "writeimage outside image";
176static char Enotfont[] = "image not a font";
177static char Eindex[] = "character index out of range";
178static char Enoclient[] = "no such draw client";
179static char Edepth[] = "image has bad depth";
180static char Enameused[] = "image name in use";
181static char Enoname[] = "no image with that name";
182static char Eoldname[] = "named image no longer valid";
183static char Enamed[] = "image already has name";
184static char Ewrongname[] = "wrong name for image";
185
186static int
187drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
188{
189 int t;
190 Qid q;
191 ulong path;
192 Client *cl;
193
194 USED(name);
195 USED(dt);
196 USED(ndt);
197
198 q.vers = 0;
199
200 if(s == DEVDOTDOT){
201 switch(QID(c->qid)){
202 case Qtopdir:
203 case Q2nd:
204 mkqid(&q, Qtopdir, 0, QTDIR);
205 devdir(c, q, "#i", 0, eve, 0500, dp);
206 break;
207 case Q3rd:
208 cl = drawclientofpath(c->qid.path);
209 if(cl == nil)
210 strcpy(up->genbuf, "??");
211 else
212 sprint(up->genbuf, "%d", cl->clientid);
213 mkqid(&q, Q2nd, 0, QTDIR);
214 devdir(c, q, up->genbuf, 0, eve, 0500, dp);
215 break;
216 default:
217 panic("drawwalk %llux", c->qid.path);
218 }
219 return 1;
220 }
221
222 /*
223 * Top level directory contains the name of the device.
224 */
225 t = QID(c->qid);
226 if(t == Qtopdir){
227 switch(s){
228 case 0:
229 mkqid(&q, Q2nd, 0, QTDIR);
230 devdir(c, q, "draw", 0, eve, 0555, dp);
231 break;
232 default:
233 return -1;
234 }
235 return 1;
236 }
237
238 /*
239 * Second level contains "new" plus all the clients.
240 */
241 if(t == Q2nd || t == Qnew){
242 if(s == 0){
243 mkqid(&q, Qnew, 0, QTFILE);
244 devdir(c, q, "new", 0, eve, 0666, dp);
245 }
246 else if(s <= sdraw.nclient){
247 cl = sdraw.client[s-1];
248 if(cl == 0)
249 return 0;
250 sprint(up->genbuf, "%d", cl->clientid);
251 mkqid(&q, (s<<QSHIFT)|Q3rd, 0, QTDIR);
252 devdir(c, q, up->genbuf, 0, eve, 0555, dp);
253 return 1;
254 }
255 else
256 return -1;
257 return 1;
258 }
259
260 /*
261 * Third level.
262 */
263 path = c->qid.path&~((1<<QSHIFT)-1); /* slot component */
264 q.vers = c->qid.vers;
265 q.type = QTFILE;
266 switch(s){
267 case 0:
268 q.path = path|Qcolormap;
269 devdir(c, q, "colormap", 0, eve, 0600, dp);
270 break;
271 case 1:
272 q.path = path|Qctl;
273 devdir(c, q, "ctl", 0, eve, 0600, dp);
274 break;
275 case 2:
276 q.path = path|Qdata;
277 devdir(c, q, "data", 0, eve, 0600, dp);
278 break;
279 case 3:
280 q.path = path|Qrefresh;
281 devdir(c, q, "refresh", 0, eve, 0400, dp);
282 break;
283 default:
284 return -1;
285 }
286 return 1;
287}
288
289static
290int
291drawrefactive(void *a)
292{
293 Client *c;
294
295 c = a;
296 return c->refreshme || c->refresh!=0;
297}
298
299static
300void
301drawrefreshscreen(DImage *l, Client *client)
302{
303 while(l != nil && l->dscreen == nil)
304 l = l->fromname;
305 if(l != nil && l->dscreen->owner != client)
306 l->dscreen->owner->refreshme = 1;
307}
308
309static
310void
311drawrefresh(Memimage *m, Rectangle r, void *v)
312{
313 Refx *x;
314 DImage *d;
315 Client *c;
316 Refresh *ref;
317
318 USED(m);
319
320 if(v == 0)
321 return;
322 x = v;
323 c = x->client;
324 d = x->dimage;
325 for(ref=c->refresh; ref; ref=ref->next)
326 if(ref->dimage == d){
327 combinerect(&ref->r, r);
328 return;
329 }
330 ref = malloc(sizeof(Refresh));
331 if(ref){
332 ref->dimage = d;
333 ref->r = r;
334 ref->next = c->refresh;
335 c->refresh = ref;
336 }
337}
338
339static void
340addflush(Rectangle r)
341{
342 int abb, ar, anbb;
343 Rectangle nbb;
344
345 if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
346 return;
347
348 if(flushrect.min.x >= flushrect.max.x){
349 flushrect = r;
350 waste = 0;
351 return;
352 }
353 nbb = flushrect;
354 combinerect(&nbb, r);
355 ar = Dx(r)*Dy(r);
356 abb = Dx(flushrect)*Dy(flushrect);
357 anbb = Dx(nbb)*Dy(nbb);
358 /*
359 * Area of new waste is area of new bb minus area of old bb,
360 * less the area of the new segment, which we assume is not waste.
361 * This could be negative, but that's OK.
362 */
363 waste += anbb-abb - ar;
364 if(waste < 0)
365 waste = 0;
366 /*
367 * absorb if:
368 * total area is small
369 * waste is less than half total area
370 * rectangles touch
371 */
372 if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
373 flushrect = nbb;
374 return;
375 }
376 /* emit current state */
377 if(flushrect.min.x < flushrect.max.x)
378 flushmemscreen(flushrect);
379 flushrect = r;
380 waste = 0;
381}
382
383static
384void
385dstflush(int dstid, Memimage *dst, Rectangle r)
386{
387 Memlayer *l;
388
389 if(dstid == 0){
390 combinerect(&flushrect, r);
391 return;
392 }
393 /* how can this happen? -rsc, dec 12 2002 */
394 if(dst == 0){
395 print("nil dstflush\n");
396 return;
397 }
398 l = dst->layer;
399 if(l == nil)
400 return;
401 do{
402 if(l->screen->image->data != screenimage->data)
403 return;
404 r = rectaddpt(r, l->delta);
405 l = l->screen->image->layer;
406 }while(l);
407 addflush(r);
408}
409
410void
411drawflush(void)
412{
413 if(flushrect.min.x < flushrect.max.x)
414 flushmemscreen(flushrect);
415 flushrect = Rect(10000, 10000, -10000, -10000);
416}
417
418void
419drawflushr(Rectangle r)
420{
421 qlock(&sdraw.lk);
422 flushmemscreen(r);
423 qunlock(&sdraw.lk);
424}
425
426static
427int
428drawcmp(char *a, char *b, int n)
429{
430 if(strlen(a) != n)
431 return 1;
432 return memcmp(a, b, n);
433}
434
435DName*
436drawlookupname(int n, char *str)
437{
438 DName *name, *ename;
439
440 name = sdraw.name;
441 ename = &name[sdraw.nname];
442 for(; name<ename; name++)
443 if(drawcmp(name->name, str, n) == 0)
444 return name;
445 return 0;
446}
447
448int
449drawgoodname(DImage *d)
450{
451 DName *n;
452
453 /* if window, validate the screen's own images */
454 if(d->dscreen)
455 if(drawgoodname(d->dscreen->dimage) == 0
456 || drawgoodname(d->dscreen->dfill) == 0)
457 return 0;
458 if(d->name == nil)
459 return 1;
460 n = drawlookupname(strlen(d->name), d->name);
461 if(n==nil || n->vers!=d->vers)
462 return 0;
463 return 1;
464}
465
466DImage*
467drawlookup(Client *client, int id, int checkname)
468{
469 DImage *d;
470
471 d = client->dimage[id&HASHMASK];
472 while(d){
473 if(d->id == id){
474 if(checkname && !drawgoodname(d))
475 error(Eoldname);
476 return d;
477 }
478 d = d->next;
479 }
480 return 0;
481}
482
483DScreen*
484drawlookupdscreen(int id)
485{
486 DScreen *s;
487
488 s = dscreen;
489 while(s){
490 if(s->id == id)
491 return s;
492 s = s->next;
493 }
494 return 0;
495}
496
497DScreen*
498drawlookupscreen(Client *client, int id, CScreen **cs)
499{
500 CScreen *s;
501
502 s = client->cscreen;
503 while(s){
504 if(s->dscreen->id == id){
505 *cs = s;
506 return s->dscreen;
507 }
508 s = s->next;
509 }
510 error(Enodrawscreen);
511 return 0;
512}
513
514Memimage*
515drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
516{
517 DImage *d;
518
519 d = malloc(sizeof(DImage));
520 if(d == 0)
521 return 0;
522 d->id = id;
523 d->ref = 1;
524 d->name = 0;
525 d->vers = 0;
526 d->image = i;
527 d->nfchar = 0;
528 d->fchar = 0;
529 d->fromname = 0;
530 d->dscreen = dscreen;
531 d->next = client->dimage[id&HASHMASK];
532 client->dimage[id&HASHMASK] = d;
533 return i;
534}
535
536Memscreen*
537drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
538{
539 Memscreen *s;
540 CScreen *c;
541
542 c = malloc(sizeof(CScreen));
543 if(dimage && dimage->image && dimage->image->chan == 0)
544 panic("bad image %p in drawinstallscreen", dimage->image);
545
546 if(c == 0)
547 return 0;
548 if(d == 0){
549 d = malloc(sizeof(DScreen));
550 if(d == 0){
551 free(c);
552 return 0;
553 }
554 s = malloc(sizeof(Memscreen));
555 if(s == 0){
556 free(c);
557 free(d);
558 return 0;
559 }
560 s->frontmost = 0;
561 s->rearmost = 0;
562 d->dimage = dimage;
563 if(dimage){
564 s->image = dimage->image;
565 dimage->ref++;
566 }
567 d->dfill = dfill;
568 if(dfill){
569 s->fill = dfill->image;
570 dfill->ref++;
571 }
572 d->ref = 0;
573 d->id = id;
574 d->screen = s;
575 d->public = public;
576 d->next = dscreen;
577 d->owner = client;
578 dscreen = d;
579 }
580 c->dscreen = d;
581 d->ref++;
582 c->next = client->cscreen;
583 client->cscreen = c;
584 return d->screen;
585}
586
587void
588drawdelname(DName *name)
589{
590 int i;
591
592 i = name-sdraw.name;
593 memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
594 sdraw.nname--;
595}
596
597void
598drawfreedscreen(DScreen *this)
599{
600 DScreen *ds, *next;
601
602 this->ref--;
603 if(this->ref < 0)
604 print("negative ref in drawfreedscreen\n");
605 if(this->ref > 0)
606 return;
607 ds = dscreen;
608 if(ds == this){
609 dscreen = this->next;
610 goto Found;
611 }
612 while(next = ds->next){ /* assign = */
613 if(next == this){
614 ds->next = this->next;
615 goto Found;
616 }
617 ds = next;
618 }
619 error(Enodrawimage);
620
621 Found:
622 if(this->dimage)
623 drawfreedimage(this->dimage);
624 if(this->dfill)
625 drawfreedimage(this->dfill);
626 free(this->screen);
627 free(this);
628}
629
630void
631drawfreedimage(DImage *dimage)
632{
633 int i;
634 Memimage *l;
635 DScreen *ds;
636
637 dimage->ref--;
638 if(dimage->ref < 0)
639 print("negative ref in drawfreedimage\n");
640 if(dimage->ref > 0)
641 return;
642
643 /* any names? */
644 for(i=0; i<sdraw.nname; )
645 if(sdraw.name[i].dimage == dimage)
646 drawdelname(sdraw.name+i);
647 else
648 i++;
649 if(dimage->fromname){ /* acquired by name; owned by someone else*/
650 drawfreedimage(dimage->fromname);
651 goto Return;
652 }
653 if(dimage->image == screenimage) /* don't free the display */
654 goto Return;
655 ds = dimage->dscreen;
656 if(ds){
657 l = dimage->image;
658 if(l->data == screenimage->data)
659 addflush(l->layer->screenr);
660 if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
661 free(l->layer->refreshptr);
662 l->layer->refreshptr = nil;
663 if(drawgoodname(dimage))
664 memldelete(l);
665 else
666 memlfree(l);
667 drawfreedscreen(ds);
668 }else
669 freememimage(dimage->image);
670 Return:
671 free(dimage->fchar);
672 free(dimage);
673}
674
675void
676drawuninstallscreen(Client *client, CScreen *this)
677{
678 CScreen *cs, *next;
679
680 cs = client->cscreen;
681 if(cs == this){
682 client->cscreen = this->next;
683 drawfreedscreen(this->dscreen);
684 free(this);
685 return;
686 }
687 while(next = cs->next){ /* assign = */
688 if(next == this){
689 cs->next = this->next;
690 drawfreedscreen(this->dscreen);
691 free(this);
692 return;
693 }
694 cs = next;
695 }
696}
697
698void
699drawuninstall(Client *client, int id)
700{
701 DImage *d, *next;
702
703 d = client->dimage[id&HASHMASK];
704 if(d == 0)
705 error(Enodrawimage);
706 if(d->id == id){
707 client->dimage[id&HASHMASK] = d->next;
708 drawfreedimage(d);
709 return;
710 }
711 while(next = d->next){ /* assign = */
712 if(next->id == id){
713 d->next = next->next;
714 drawfreedimage(next);
715 return;
716 }
717 d = next;
718 }
719 error(Enodrawimage);
720}
721
722void
723drawaddname(Client *client, DImage *di, int n, char *str)
724{
725 DName *name, *ename, *new, *t;
726
727 name = sdraw.name;
728 ename = &name[sdraw.nname];
729 for(; name<ename; name++)
730 if(drawcmp(name->name, str, n) == 0)
731 error(Enameused);
732 t = smalloc((sdraw.nname+1)*sizeof(DName));
733 memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
734 free(sdraw.name);
735 sdraw.name = t;
736 new = &sdraw.name[sdraw.nname++];
737 new->name = smalloc(n+1);
738 memmove(new->name, str, n);
739 new->name[n] = 0;
740 new->dimage = di;
741 new->client = client;
742 new->vers = ++sdraw.vers;
743}
744
745Client*
746drawnewclient(void)
747{
748 Client *cl, **cp;
749 int i;
750
751 for(i=0; i<sdraw.nclient; i++){
752 cl = sdraw.client[i];
753 if(cl == 0)
754 break;
755 }
756 if(i == sdraw.nclient){
757 cp = malloc((sdraw.nclient+1)*sizeof(Client*));
758 if(cp == 0)
759 return 0;
760 memmove(cp, sdraw.client, sdraw.nclient*sizeof(Client*));
761 free(sdraw.client);
762 sdraw.client = cp;
763 sdraw.nclient++;
764 cp[i] = 0;
765 }
766 cl = malloc(sizeof(Client));
767 if(cl == 0)
768 return 0;
769 memset(cl, 0, sizeof(Client));
770 cl->slot = i;
771 cl->clientid = ++sdraw.clientid;
772 cl->op = SoverD;
773 sdraw.client[i] = cl;
774 return cl;
775}
776
777static int
778drawclientop(Client *cl)
779{
780 int op;
781
782 op = cl->op;
783 cl->op = SoverD;
784 return op;
785}
786
787int
788drawhasclients(void)
789{
790 /*
791 * if draw has ever been used, we can't resize the frame buffer,
792 * even if all clients have exited (nclients is cumulative); it's too
793 * hard to make work.
794 */
795 return sdraw.nclient != 0;
796}
797
798Client*
799drawclientofpath(ulong path)
800{
801 Client *cl;
802 int slot;
803
804 slot = CLIENTPATH(path);
805 if(slot == 0)
806 return nil;
807 cl = sdraw.client[slot-1];
808 if(cl==0 || cl->clientid==0)
809 return nil;
810 return cl;
811}
812
813
814Client*
815drawclient(Chan *c)
816{
817 Client *client;
818
819 client = drawclientofpath(c->qid.path);
820 if(client == nil)
821 error(Enoclient);
822 return client;
823}
824
825Memimage*
826drawimage(Client *client, uchar *a)
827{
828 DImage *d;
829
830 d = drawlookup(client, BGLONG(a), 1);
831 if(d == nil)
832 error(Enodrawimage);
833 return d->image;
834}
835
836void
837drawrectangle(Rectangle *r, uchar *a)
838{
839 r->min.x = BGLONG(a+0*4);
840 r->min.y = BGLONG(a+1*4);
841 r->max.x = BGLONG(a+2*4);
842 r->max.y = BGLONG(a+3*4);
843}
844
845void
846drawpoint(Point *p, uchar *a)
847{
848 p->x = BGLONG(a+0*4);
849 p->y = BGLONG(a+1*4);
850}
851
852Point
853drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
854{
855 FChar *fc;
856 Rectangle r;
857 Point sp1;
858
859 fc = &font->fchar[index];
860 r.min.x = p.x+fc->left;
861 r.min.y = p.y-(font->ascent-fc->miny);
862 r.max.x = r.min.x+(fc->maxx-fc->minx);
863 r.max.y = r.min.y+(fc->maxy-fc->miny);
864 sp1.x = sp->x+fc->left;
865 sp1.y = sp->y+fc->miny;
866 memdraw(dst, r, src, sp1, font->image, Pt(fc->minx, fc->miny), op);
867 p.x += fc->width;
868 sp->x += fc->width;
869 return p;
870}
871
872static int
873initscreenimage(void)
874{
875 int width, depth;
876 ulong chan;
877 void *X;
878 Rectangle r;
879
880 if(screenimage != nil)
881 return 1;
882
883 screendata.base = nil;
884 screendata.bdata = attachscreen(&r, &chan, &depth, &width, &sdraw.softscreen, &X);
885 if(screendata.bdata == nil && X == nil)
886 return 0;
887 screendata.ref = 1;
888
889 screenimage = allocmemimaged(r, chan, &screendata, X);
890 if(screenimage == nil){
891 /* RSC: BUG: detach screen */
892 return 0;
893 }
894
895 screenimage->width = width;
896 screenimage->clipr = r;
897 return 1;
898}
899
900void
901deletescreenimage(void)
902{
903 qlock(&sdraw.lk);
904 /* RSC: BUG: detach screen */
905 if(screenimage)
906 freememimage(screenimage);
907 screenimage = nil;
908 qunlock(&sdraw.lk);
909}
910
911static Chan*
912drawattach(char *spec)
913{
914 qlock(&sdraw.lk);
915 if(!initscreenimage()){
916 qunlock(&sdraw.lk);
917 error("no frame buffer");
918 }
919 qunlock(&sdraw.lk);
920 return devattach('i', spec);
921}
922
923static Walkqid*
924drawwalk(Chan *c, Chan *nc, char **name, int nname)
925{
926 if(screendata.bdata == nil)
927 error("no frame buffer");
928 return devwalk(c, nc, name, nname, 0, 0, drawgen);
929}
930
931static int
932drawstat(Chan *c, uchar *db, int n)
933{
934 return devstat(c, db, n, 0, 0, drawgen);
935}
936
937static Chan*
938drawopen(Chan *c, int omode)
939{
940 Client *cl;
941
942 if(c->qid.type & QTDIR){
943 c = devopen(c, omode, 0, 0, drawgen);
944 c->iounit = IOUNIT;
945 }
946
947 qlock(&sdraw.lk);
948 if(waserror()){
949 qunlock(&sdraw.lk);
950 nexterror();
951 }
952
953 if(QID(c->qid) == Qnew){
954 cl = drawnewclient();
955 if(cl == 0)
956 error(Enodev);
957 c->qid.path = Qctl|((cl->slot+1)<<QSHIFT);
958 }
959
960 switch(QID(c->qid)){
961 case Qnew:
962 break;
963
964 case Qctl:
965 cl = drawclient(c);
966 if(cl->busy)
967 error(Einuse);
968 cl->busy = 1;
969 flushrect = Rect(10000, 10000, -10000, -10000);
970 drawinstall(cl, 0, screenimage, 0);
971 incref(&cl->r);
972 break;
973 case Qcolormap:
974 case Qdata:
975 case Qrefresh:
976 cl = drawclient(c);
977 incref(&cl->r);
978 break;
979 }
980 qunlock(&sdraw.lk);
981 poperror();
982 c->mode = openmode(omode);
983 c->flag |= COPEN;
984 c->offset = 0;
985 c->iounit = IOUNIT;
986 return c;
987}
988
989static void
990drawclose(Chan *c)
991{
992 int i;
993 DImage *d, **dp;
994 Client *cl;
995 Refresh *r;
996
997 if(QID(c->qid) < Qcolormap) /* Qtopdir, Qnew, Q3rd, Q2nd have no client */
998 return;
999 qlock(&sdraw.lk);
1000 if(waserror()){
1001 qunlock(&sdraw.lk);
1002 nexterror();
1003 }
1004
1005 cl = drawclient(c);
1006 if(QID(c->qid) == Qctl)
1007 cl->busy = 0;
1008 if((c->flag&COPEN) && (decref(&cl->r)==0)){
1009 while(r = cl->refresh){ /* assign = */
1010 cl->refresh = r->next;
1011 free(r);
1012 }
1013 /* free names */
1014 for(i=0; i<sdraw.nname; )
1015 if(sdraw.name[i].client == cl)
1016 drawdelname(sdraw.name+i);
1017 else
1018 i++;
1019 while(cl->cscreen)
1020 drawuninstallscreen(cl, cl->cscreen);
1021 /* all screens are freed, so now we can free images */
1022 dp = cl->dimage;
1023 for(i=0; i<NHASH; i++){
1024 while((d = *dp) != nil){
1025 *dp = d->next;
1026 drawfreedimage(d);
1027 }
1028 dp++;
1029 }
1030 sdraw.client[cl->slot] = 0;
1031 drawflush(); /* to erase visible, now dead windows */
1032 free(cl);
1033 }
1034 qunlock(&sdraw.lk);
1035 poperror();
1036}
1037
1038long
1039drawread(Chan *c, void *a, long n, vlong off)
1040{
1041 int index, m;
1042 ulong red, green, blue;
1043 Client *cl;
1044 uchar *p;
1045 Refresh *r;
1046 DImage *di;
1047 Memimage *i;
1048 ulong offset = off;
1049 char buf[16];
1050
1051 if(c->qid.type & QTDIR)
1052 return devdirread(c, a, n, 0, 0, drawgen);
1053 cl = drawclient(c);
1054 qlock(&sdraw.lk);
1055 if(waserror()){
1056 qunlock(&sdraw.lk);
1057 nexterror();
1058 }
1059 switch(QID(c->qid)){
1060 case Qctl:
1061 if(n < 12*12)
1062 error(Eshortread);
1063 if(cl->infoid < 0)
1064 error(Enodrawimage);
1065 if(cl->infoid == 0){
1066 i = screenimage;
1067 if(i == nil)
1068 error(Enodrawimage);
1069 }else{
1070 di = drawlookup(cl, cl->infoid, 1);
1071 if(di == nil)
1072 error(Enodrawimage);
1073 i = di->image;
1074 }
1075 n = sprint(a, "%11d %11d %11s %11d %11d %11d %11d %11d %11d %11d %11d %11d ",
1076 cl->clientid, cl->infoid, chantostr(buf, i->chan), (i->flags&Frepl)==Frepl,
1077 i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
1078 i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
1079 cl->infoid = -1;
1080 break;
1081
1082 case Qcolormap:
1083 drawactive(1); /* to restore map from backup */
1084 p = malloc(4*12*256+1);
1085 if(p == 0)
1086 error(Enomem);
1087 m = 0;
1088 for(index = 0; index < 256; index++){
1089 getcolor(index, &red, &green, &blue);
1090 m += sprint((char*)p+m, "%11d %11lud %11lud %11lud\n", index, red>>24, green>>24, blue>>24);
1091 }
1092 n = readstr(offset, a, n, (char*)p);
1093 free(p);
1094 break;
1095
1096 case Qdata:
1097 if(cl->readdata == nil)
1098 error("no draw data");
1099 if(n < cl->nreaddata)
1100 error(Eshortread);
1101 n = cl->nreaddata;
1102 memmove(a, cl->readdata, cl->nreaddata);
1103 free(cl->readdata);
1104 cl->readdata = nil;
1105 break;
1106
1107 case Qrefresh:
1108 if(n < 5*4)
1109 error(Ebadarg);
1110 for(;;){
1111 if(cl->refreshme || cl->refresh)
1112 break;
1113 qunlock(&sdraw.lk);
1114 if(waserror()){
1115 qlock(&sdraw.lk); /* restore lock for waserror() above */
1116 nexterror();
1117 }
1118 sleep(&cl->refrend, drawrefactive, cl);
1119 poperror();
1120 qlock(&sdraw.lk);
1121 }
1122 p = a;
1123 while(cl->refresh && n>=5*4){
1124 r = cl->refresh;
1125 BPLONG(p+0*4, r->dimage->id);
1126 BPLONG(p+1*4, r->r.min.x);
1127 BPLONG(p+2*4, r->r.min.y);
1128 BPLONG(p+3*4, r->r.max.x);
1129 BPLONG(p+4*4, r->r.max.y);
1130 cl->refresh = r->next;
1131 free(r);
1132 p += 5*4;
1133 n -= 5*4;
1134 }
1135 cl->refreshme = 0;
1136 n = p-(uchar*)a;
1137 }
1138 qunlock(&sdraw.lk);
1139 poperror();
1140 return n;
1141}
1142
1143void
1144drawwakeall(void)
1145{
1146 Client *cl;
1147 int i;
1148
1149 for(i=0; i<sdraw.nclient; i++){
1150 cl = sdraw.client[i];
1151 if(cl && (cl->refreshme || cl->refresh))
1152 wakeup(&cl->refrend);
1153 }
1154}
1155
1156static long
1157drawwrite(Chan *c, void *a, long n, vlong offset)
1158{
1159 char buf[128], *fields[4], *q;
1160 Client *cl;
1161 int i, m, red, green, blue, x;
1162
1163 USED(offset);
1164
1165 if(c->qid.type & QTDIR)
1166 error(Eisdir);
1167 cl = drawclient(c);
1168 qlock(&sdraw.lk);
1169 if(waserror()){
1170 drawwakeall();
1171 qunlock(&sdraw.lk);
1172 nexterror();
1173 }
1174 switch(QID(c->qid)){
1175 case Qctl:
1176 if(n != 4)
1177 error("unknown draw control request");
1178 cl->infoid = BGLONG((uchar*)a);
1179 break;
1180
1181 case Qcolormap:
1182 drawactive(1); /* to restore map from backup */
1183 m = n;
1184 n = 0;
1185 while(m > 0){
1186 x = m;
1187 if(x > sizeof(buf)-1)
1188 x = sizeof(buf)-1;
1189 q = memccpy(buf, a, '\n', x);
1190 if(q == 0)
1191 break;
1192 i = q-buf;
1193 n += i;
1194 a = (char*)a + i;
1195 m -= i;
1196 *q = 0;
1197 if(tokenize(buf, fields, nelem(fields)) != 4)
1198 error(Ebadarg);
1199 i = strtoul(fields[0], 0, 0);
1200 red = strtoul(fields[1], 0, 0);
1201 green = strtoul(fields[2], 0, 0);
1202 blue = strtoul(fields[3], &q, 0);
1203 if(fields[3] == q)
1204 error(Ebadarg);
1205 if(red>255 || green>255 || blue>255 || i<0 || i>255)
1206 error(Ebadarg);
1207 red |= red<<8;
1208 red |= red<<16;
1209 green |= green<<8;
1210 green |= green<<16;
1211 blue |= blue<<8;
1212 blue |= blue<<16;
1213 setcolor(i, red, green, blue);
1214 }
1215 break;
1216
1217 case Qdata:
1218 drawmesg(cl, a, n);
1219 drawwakeall();
1220 break;
1221
1222 default:
1223 error(Ebadusefd);
1224 }
1225 qunlock(&sdraw.lk);
1226 poperror();
1227 return n;
1228}
1229
1230uchar*
1231drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
1232{
1233 int b, x;
1234
1235 if(p >= maxp)
1236 error(Eshortdraw);
1237 b = *p++;
1238 x = b & 0x7F;
1239 if(b & 0x80){
1240 if(p+1 >= maxp)
1241 error(Eshortdraw);
1242 x |= *p++ << 7;
1243 x |= *p++ << 15;
1244 if(x & (1<<22))
1245 x |= ~0<<23;
1246 }else{
1247 if(b & 0x40)
1248 x |= ~0<<7;
1249 x += oldx;
1250 }
1251 *newx = x;
1252 return p;
1253}
1254
1255static void
1256printmesg(char *fmt, uchar *a, int plsprnt)
1257{
1258 char buf[256];
1259 char *p, *q;
1260 int s;
1261
1262 if(1|| plsprnt==0){
1263 SET(s);
1264 SET(q);
1265 SET(p);
1266 USED(fmt);
1267 USED(a);
1268 USED(buf);
1269 USED(p);
1270 USED(q);
1271 USED(s);
1272 return;
1273 }
1274 q = buf;
1275 *q++ = *a++;
1276 for(p=fmt; *p; p++){
1277 switch(*p){
1278 case 'l':
1279 q += sprint(q, " %ld", (long)BGLONG(a));
1280 a += 4;
1281 break;
1282 case 'L':
1283 q += sprint(q, " %.8lux", (ulong)BGLONG(a));
1284 a += 4;
1285 break;
1286 case 'R':
1287 q += sprint(q, " [%d %d %d %d]", BGLONG(a), BGLONG(a+4), BGLONG(a+8), BGLONG(a+12));
1288 a += 16;
1289 break;
1290 case 'P':
1291 q += sprint(q, " [%d %d]", BGLONG(a), BGLONG(a+4));
1292 a += 8;
1293 break;
1294 case 'b':
1295 q += sprint(q, " %d", *a++);
1296 break;
1297 case 's':
1298 q += sprint(q, " %d", BGSHORT(a));
1299 a += 2;
1300 break;
1301 case 'S':
1302 q += sprint(q, " %.4ux", BGSHORT(a));
1303 a += 2;
1304 break;
1305 }
1306 }
1307 *q++ = '\n';
1308 *q = 0;
1309 iprint("%.*s", (int)(q-buf), buf);
1310}
1311
1312void
1313drawmesg(Client *client, void *av, int n)
1314{
1315 int c, repl, m, y, dstid, scrnid, ni, ci, j, nw, e0, e1, op, ox, oy, oesize, esize, doflush;
1316 uchar *u, *a, refresh;
1317 char *fmt;
1318 ulong value, chan;
1319 Rectangle r, clipr;
1320 Point p, q, *pp, sp;
1321 Memimage *i, *dst, *src, *mask;
1322 Memimage *l, **lp;
1323 Memscreen *scrn;
1324 DImage *font, *ll, *di, *ddst, *dsrc;
1325 DName *dn;
1326 DScreen *dscrn;
1327 FChar *fc;
1328 Refx *refx;
1329 CScreen *cs;
1330 Refreshfn reffn;
1331
1332 a = av;
1333 m = 0;
1334 fmt = nil;
1335 if(waserror()){
1336 if(fmt) printmesg(fmt, a, 1);
1337 /* iprint("error: %s\n", up->errstr); */
1338 nexterror();
1339 }
1340 while((n-=m) > 0){
1341 USED(fmt);
1342 a += m;
1343 switch(*a){
1344 default:
1345 error("bad draw command");
1346 /* new allocate: 'b' id[4] screenid[4] refresh[1] chan[4] repl[1] R[4*4] clipR[4*4] rrggbbaa[4] */
1347 case 'b':
1348 printmesg(fmt="LLbLbRRL", a, 0);
1349 m = 1+4+4+1+4+1+4*4+4*4+4;
1350 if(n < m)
1351 error(Eshortdraw);
1352 dstid = BGLONG(a+1);
1353 scrnid = BGSHORT(a+5);
1354 refresh = a[9];
1355 chan = BGLONG(a+10);
1356 repl = a[14];
1357 drawrectangle(&r, a+15);
1358 drawrectangle(&clipr, a+31);
1359 value = BGLONG(a+47);
1360 if(drawlookup(client, dstid, 0))
1361 error(Eimageexists);
1362 if(scrnid){
1363 dscrn = drawlookupscreen(client, scrnid, &cs);
1364 scrn = dscrn->screen;
1365 if(repl || chan!=scrn->image->chan)
1366 error("image parameters incompatible with screen");
1367 reffn = nil;
1368 switch(refresh){
1369 case Refbackup:
1370 break;
1371 case Refnone:
1372 reffn = memlnorefresh;
1373 break;
1374 case Refmesg:
1375 reffn = drawrefresh;
1376 break;
1377 default:
1378 error("unknown refresh method");
1379 }
1380 l = memlalloc(scrn, r, reffn, 0, value);
1381 if(l == 0)
1382 error(Edrawmem);
1383 addflush(l->layer->screenr);
1384 l->clipr = clipr;
1385 rectclip(&l->clipr, r);
1386 if(drawinstall(client, dstid, l, dscrn) == 0){
1387 memldelete(l);
1388 error(Edrawmem);
1389 }
1390 dscrn->ref++;
1391 if(reffn){
1392 refx = nil;
1393 if(reffn == drawrefresh){
1394 refx = malloc(sizeof(Refx));
1395 if(refx == 0){
1396 drawuninstall(client, dstid);
1397 error(Edrawmem);
1398 }
1399 refx->client = client;
1400 refx->dimage = drawlookup(client, dstid, 1);
1401 }
1402 memlsetrefresh(l, reffn, refx);
1403 }
1404 continue;
1405 }
1406 i = allocmemimage(r, chan);
1407 if(i == 0)
1408 error(Edrawmem);
1409 if(repl)
1410 i->flags |= Frepl;
1411 i->clipr = clipr;
1412 if(!repl)
1413 rectclip(&i->clipr, r);
1414 if(drawinstall(client, dstid, i, 0) == 0){
1415 freememimage(i);
1416 error(Edrawmem);
1417 }
1418 memfillcolor(i, value);
1419 continue;
1420
1421 /* allocate screen: 'A' id[4] imageid[4] fillid[4] public[1] */
1422 case 'A':
1423 printmesg(fmt="LLLb", a, 1);
1424 m = 1+4+4+4+1;
1425 if(n < m)
1426 error(Eshortdraw);
1427 dstid = BGLONG(a+1);
1428 if(dstid == 0)
1429 error(Ebadarg);
1430 if(drawlookupdscreen(dstid))
1431 error(Escreenexists);
1432 ddst = drawlookup(client, BGLONG(a+5), 1);
1433 dsrc = drawlookup(client, BGLONG(a+9), 1);
1434 if(ddst==0 || dsrc==0)
1435 error(Enodrawimage);
1436 if(drawinstallscreen(client, 0, dstid, ddst, dsrc, a[13]) == 0)
1437 error(Edrawmem);
1438 continue;
1439
1440 /* set repl and clip: 'c' dstid[4] repl[1] clipR[4*4] */
1441 case 'c':
1442 printmesg(fmt="LbR", a, 0);
1443 m = 1+4+1+4*4;
1444 if(n < m)
1445 error(Eshortdraw);
1446 ddst = drawlookup(client, BGLONG(a+1), 1);
1447 if(ddst == nil)
1448 error(Enodrawimage);
1449 if(ddst->name)
1450 error("can't change repl/clipr of shared image");
1451 dst = ddst->image;
1452 if(a[5])
1453 dst->flags |= Frepl;
1454 drawrectangle(&dst->clipr, a+6);
1455 continue;
1456
1457 /* draw: 'd' dstid[4] srcid[4] maskid[4] R[4*4] P[2*4] P[2*4] */
1458 case 'd':
1459 printmesg(fmt="LLLRPP", a, 0);
1460 m = 1+4+4+4+4*4+2*4+2*4;
1461 if(n < m)
1462 error(Eshortdraw);
1463 dst = drawimage(client, a+1);
1464 dstid = BGLONG(a+1);
1465 src = drawimage(client, a+5);
1466 mask = drawimage(client, a+9);
1467 drawrectangle(&r, a+13);
1468 drawpoint(&p, a+29);
1469 drawpoint(&q, a+37);
1470 op = drawclientop(client);
1471 memdraw(dst, r, src, p, mask, q, op);
1472 dstflush(dstid, dst, r);
1473 continue;
1474
1475 /* toggle debugging: 'D' val[1] */
1476 case 'D':
1477 printmesg(fmt="b", a, 0);
1478 m = 1+1;
1479 if(n < m)
1480 error(Eshortdraw);
1481 drawdebug = a[1];
1482 continue;
1483
1484 /* ellipse: 'e' dstid[4] srcid[4] center[2*4] a[4] b[4] thick[4] sp[2*4] alpha[4] phi[4]*/
1485 case 'e':
1486 case 'E':
1487 printmesg(fmt="LLPlllPll", a, 0);
1488 m = 1+4+4+2*4+4+4+4+2*4+2*4;
1489 if(n < m)
1490 error(Eshortdraw);
1491 dst = drawimage(client, a+1);
1492 dstid = BGLONG(a+1);
1493 src = drawimage(client, a+5);
1494 drawpoint(&p, a+9);
1495 e0 = BGLONG(a+17);
1496 e1 = BGLONG(a+21);
1497 if(e0<0 || e1<0)
1498 error("invalid ellipse semidiameter");
1499 j = BGLONG(a+25);
1500 if(j < 0)
1501 error("negative ellipse thickness");
1502 drawpoint(&sp, a+29);
1503 c = j;
1504 if(*a == 'E')
1505 c = -1;
1506 ox = BGLONG(a+37);
1507 oy = BGLONG(a+41);
1508 op = drawclientop(client);
1509 /* high bit indicates arc angles are present */
1510 if(ox & (1<<31)){
1511 if((ox & (1<<30)) == 0)
1512 ox &= ~(1<<31);
1513 memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
1514 }else
1515 memellipse(dst, p, e0, e1, c, src, sp, op);
1516 dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
1517 continue;
1518
1519 /* free: 'f' id[4] */
1520 case 'f':
1521 printmesg(fmt="L", a, 1);
1522 m = 1+4;
1523 if(n < m)
1524 error(Eshortdraw);
1525 ll = drawlookup(client, BGLONG(a+1), 0);
1526 if(ll && ll->dscreen && ll->dscreen->owner != client)
1527 ll->dscreen->owner->refreshme = 1;
1528 drawuninstall(client, BGLONG(a+1));
1529 continue;
1530
1531 /* free screen: 'F' id[4] */
1532 case 'F':
1533 printmesg(fmt="L", a, 1);
1534 m = 1+4;
1535 if(n < m)
1536 error(Eshortdraw);
1537 drawlookupscreen(client, BGLONG(a+1), &cs);
1538 drawuninstallscreen(client, cs);
1539 continue;
1540
1541 /* initialize font: 'i' fontid[4] nchars[4] ascent[1] */
1542 case 'i':
1543 printmesg(fmt="Llb", a, 1);
1544 m = 1+4+4+1;
1545 if(n < m)
1546 error(Eshortdraw);
1547 dstid = BGLONG(a+1);
1548 if(dstid == 0)
1549 error("can't use display as font");
1550 font = drawlookup(client, dstid, 1);
1551 if(font == 0)
1552 error(Enodrawimage);
1553 if(font->image->layer)
1554 error("can't use window as font");
1555 ni = BGLONG(a+5);
1556 if(ni<=0 || ni>4096)
1557 error("bad font size (4096 chars max)");
1558 free(font->fchar); /* should we complain if non-zero? */
1559 font->fchar = malloc(ni*sizeof(FChar));
1560 if(font->fchar == 0)
1561 error("no memory for font");
1562 memset(font->fchar, 0, ni*sizeof(FChar));
1563 font->nfchar = ni;
1564 font->ascent = a[9];
1565 continue;
1566
1567 /* load character: 'l' fontid[4] srcid[4] index[2] R[4*4] P[2*4] left[1] width[1] */
1568 case 'l':
1569 printmesg(fmt="LLSRPbb", a, 0);
1570 m = 1+4+4+2+4*4+2*4+1+1;
1571 if(n < m)
1572 error(Eshortdraw);
1573 font = drawlookup(client, BGLONG(a+1), 1);
1574 if(font == 0)
1575 error(Enodrawimage);
1576 if(font->nfchar == 0)
1577 error(Enotfont);
1578 src = drawimage(client, a+5);
1579 ci = BGSHORT(a+9);
1580 if(ci >= font->nfchar)
1581 error(Eindex);
1582 drawrectangle(&r, a+11);
1583 drawpoint(&p, a+27);
1584 memdraw(font->image, r, src, p, memopaque, p, S);
1585 fc = &font->fchar[ci];
1586 fc->minx = r.min.x;
1587 fc->maxx = r.max.x;
1588 fc->miny = r.min.y;
1589 fc->maxy = r.max.y;
1590 fc->left = a[35];
1591 fc->width = a[36];
1592 continue;
1593
1594 /* draw line: 'L' dstid[4] p0[2*4] p1[2*4] end0[4] end1[4] radius[4] srcid[4] sp[2*4] */
1595 case 'L':
1596 printmesg(fmt="LPPlllLP", a, 0);
1597 m = 1+4+2*4+2*4+4+4+4+4+2*4;
1598 if(n < m)
1599 error(Eshortdraw);
1600 dst = drawimage(client, a+1);
1601 dstid = BGLONG(a+1);
1602 drawpoint(&p, a+5);
1603 drawpoint(&q, a+13);
1604 e0 = BGLONG(a+21);
1605 e1 = BGLONG(a+25);
1606 j = BGLONG(a+29);
1607 if(j < 0)
1608 error("negative line width");
1609 src = drawimage(client, a+33);
1610 drawpoint(&sp, a+37);
1611 op = drawclientop(client);
1612 memline(dst, p, q, e0, e1, j, src, sp, op);
1613 /* avoid memlinebbox if possible */
1614 if(dstid==0 || dst->layer!=nil){
1615 /* BUG: this is terribly inefficient: update maximal containing rect*/
1616 r = memlinebbox(p, q, e0, e1, j);
1617 dstflush(dstid, dst, insetrect(r, -(1+1+j)));
1618 }
1619 continue;
1620
1621 /* create image mask: 'm' newid[4] id[4] */
1622/*
1623 *
1624 case 'm':
1625 printmesg("LL", a, 0);
1626 m = 4+4;
1627 if(n < m)
1628 error(Eshortdraw);
1629 break;
1630 *
1631 */
1632
1633 /* attach to a named image: 'n' dstid[4] j[1] name[j] */
1634 case 'n':
1635 printmesg(fmt="Lz", a, 0);
1636 m = 1+4+1;
1637 if(n < m)
1638 error(Eshortdraw);
1639 j = a[5];
1640 if(j == 0) /* give me a non-empty name please */
1641 error(Eshortdraw);
1642 m += j;
1643 if(n < m)
1644 error(Eshortdraw);
1645 dstid = BGLONG(a+1);
1646 if(drawlookup(client, dstid, 0))
1647 error(Eimageexists);
1648 dn = drawlookupname(j, (char*)a+6);
1649 if(dn == nil)
1650 error(Enoname);
1651 if(drawinstall(client, dstid, dn->dimage->image, 0) == 0)
1652 error(Edrawmem);
1653 di = drawlookup(client, dstid, 0);
1654 if(di == 0)
1655 error("draw: can't happen");
1656 di->vers = dn->vers;
1657 di->name = smalloc(j+1);
1658 di->fromname = dn->dimage;
1659 di->fromname->ref++;
1660 memmove(di->name, a+6, j);
1661 di->name[j] = 0;
1662 client->infoid = dstid;
1663 continue;
1664
1665 /* name an image: 'N' dstid[4] in[1] j[1] name[j] */
1666 case 'N':
1667 printmesg(fmt="Lbz", a, 0);
1668 m = 1+4+1+1;
1669 if(n < m)
1670 error(Eshortdraw);
1671 c = a[5];
1672 j = a[6];
1673 if(j == 0) /* give me a non-empty name please */
1674 error(Eshortdraw);
1675 m += j;
1676 if(n < m)
1677 error(Eshortdraw);
1678 di = drawlookup(client, BGLONG(a+1), 0);
1679 if(di == 0)
1680 error(Enodrawimage);
1681 if(di->name)
1682 error(Enamed);
1683 if(c)
1684 drawaddname(client, di, j, (char*)a+7);
1685 else{
1686 dn = drawlookupname(j, (char*)a+7);
1687 if(dn == nil)
1688 error(Enoname);
1689 if(dn->dimage != di)
1690 error(Ewrongname);
1691 drawdelname(dn);
1692 }
1693 continue;
1694
1695 /* position window: 'o' id[4] r.min [2*4] screenr.min [2*4] */
1696 case 'o':
1697 printmesg(fmt="LPP", a, 0);
1698 m = 1+4+2*4+2*4;
1699 if(n < m)
1700 error(Eshortdraw);
1701 dst = drawimage(client, a+1);
1702 if(dst->layer){
1703 drawpoint(&p, a+5);
1704 drawpoint(&q, a+13);
1705 r = dst->layer->screenr;
1706 ni = memlorigin(dst, p, q);
1707 if(ni < 0)
1708 error("image origin failed");
1709 if(ni > 0){
1710 addflush(r);
1711 addflush(dst->layer->screenr);
1712 ll = drawlookup(client, BGLONG(a+1), 1);
1713 drawrefreshscreen(ll, client);
1714 }
1715 }
1716 continue;
1717
1718 /* set compositing operator for next draw operation: 'O' op */
1719 case 'O':
1720 printmesg(fmt="b", a, 0);
1721 m = 1+1;
1722 if(n < m)
1723 error(Eshortdraw);
1724 client->op = a[1];
1725 continue;
1726
1727 /* filled polygon: 'P' dstid[4] n[2] wind[4] ignore[2*4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
1728 /* polygon: 'p' dstid[4] n[2] end0[4] end1[4] radius[4] srcid[4] sp[2*4] p0[2*4] dp[2*2*n] */
1729 case 'p':
1730 case 'P':
1731 printmesg(fmt="LslllLPP", a, 0);
1732 m = 1+4+2+4+4+4+4+2*4;
1733 if(n < m)
1734 error(Eshortdraw);
1735 dstid = BGLONG(a+1);
1736 dst = drawimage(client, a+1);
1737 ni = BGSHORT(a+5);
1738 if(ni < 0)
1739 error("negative count in polygon");
1740 e0 = BGLONG(a+7);
1741 e1 = BGLONG(a+11);
1742 j = 0;
1743 if(*a == 'p'){
1744 j = BGLONG(a+15);
1745 if(j < 0)
1746 error("negative polygon line width");
1747 }
1748 src = drawimage(client, a+19);
1749 drawpoint(&sp, a+23);
1750 drawpoint(&p, a+31);
1751 ni++;
1752 pp = malloc(ni*sizeof(Point));
1753 if(pp == nil)
1754 error(Enomem);
1755 doflush = 0;
1756 if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
1757 doflush = 1; /* simplify test in loop */
1758 ox = oy = 0;
1759 esize = 0;
1760 u = a+m;
1761 for(y=0; y<ni; y++){
1762 q = p;
1763 oesize = esize;
1764 u = drawcoord(u, a+n, ox, &p.x);
1765 u = drawcoord(u, a+n, oy, &p.y);
1766 ox = p.x;
1767 oy = p.y;
1768 if(doflush){
1769 esize = j;
1770 if(*a == 'p'){
1771 if(y == 0){
1772 c = memlineendsize(e0);
1773 if(c > esize)
1774 esize = c;
1775 }
1776 if(y == ni-1){
1777 c = memlineendsize(e1);
1778 if(c > esize)
1779 esize = c;
1780 }
1781 }
1782 if(*a=='P' && e0!=1 && e0 !=~0)
1783 r = dst->clipr;
1784 else if(y > 0){
1785 r = Rect(q.x-oesize, q.y-oesize, q.x+oesize+1, q.y+oesize+1);
1786 combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
1787 }
1788 if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */
1789 dstflush(dstid, dst, r);
1790 }
1791 pp[y] = p;
1792 }
1793 if(y == 1)
1794 dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
1795 op = drawclientop(client);
1796 if(*a == 'p')
1797 mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
1798 else
1799 memfillpoly(dst, pp, ni, e0, src, sp, op);
1800 free(pp);
1801 m = u-a;
1802 continue;
1803
1804 /* read: 'r' id[4] R[4*4] */
1805 case 'r':
1806 printmesg(fmt="LR", a, 0);
1807 m = 1+4+4*4;
1808 if(n < m)
1809 error(Eshortdraw);
1810 i = drawimage(client, a+1);
1811 drawrectangle(&r, a+5);
1812 if(!rectinrect(r, i->r))
1813 error(Ereadoutside);
1814 c = bytesperline(r, i->depth);
1815 c *= Dy(r);
1816 free(client->readdata);
1817 client->readdata = mallocz(c, 0);
1818 if(client->readdata == nil)
1819 error("readimage malloc failed");
1820 client->nreaddata = memunload(i, r, client->readdata, c);
1821 if(client->nreaddata < 0){
1822 free(client->readdata);
1823 client->readdata = nil;
1824 error("bad readimage call");
1825 }
1826 continue;
1827
1828 /* string: 's' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] ni*(index[2]) */
1829 /* stringbg: 'x' dstid[4] srcid[4] fontid[4] P[2*4] clipr[4*4] sp[2*4] ni[2] bgid[4] bgpt[2*4] ni*(index[2]) */
1830 case 's':
1831 case 'x':
1832 printmesg(fmt="LLLPRPs", a, 0);
1833 m = 1+4+4+4+2*4+4*4+2*4+2;
1834 if(*a == 'x')
1835 m += 4+2*4;
1836 if(n < m)
1837 error(Eshortdraw);
1838
1839 dst = drawimage(client, a+1);
1840 dstid = BGLONG(a+1);
1841 src = drawimage(client, a+5);
1842 font = drawlookup(client, BGLONG(a+9), 1);
1843 if(font == 0)
1844 error(Enodrawimage);
1845 if(font->nfchar == 0)
1846 error(Enotfont);
1847 drawpoint(&p, a+13);
1848 drawrectangle(&r, a+21);
1849 drawpoint(&sp, a+37);
1850 ni = BGSHORT(a+45);
1851 u = a+m;
1852 m += ni*2;
1853 if(n < m)
1854 error(Eshortdraw);
1855 clipr = dst->clipr;
1856 dst->clipr = r;
1857 op = drawclientop(client);
1858 if(*a == 'x'){
1859 /* paint background */
1860 l = drawimage(client, a+47);
1861 drawpoint(&q, a+51);
1862 r.min.x = p.x;
1863 r.min.y = p.y-font->ascent;
1864 r.max.x = p.x;
1865 r.max.y = r.min.y+Dy(font->image->r);
1866 j = ni;
1867 while(--j >= 0){
1868 ci = BGSHORT(u);
1869 if(ci<0 || ci>=font->nfchar){
1870 dst->clipr = clipr;
1871 error(Eindex);
1872 }
1873 r.max.x += font->fchar[ci].width;
1874 u += 2;
1875 }
1876 memdraw(dst, r, l, q, memopaque, ZP, op);
1877 u -= 2*ni;
1878 }
1879 q = p;
1880 while(--ni >= 0){
1881 ci = BGSHORT(u);
1882 if(ci<0 || ci>=font->nfchar){
1883 dst->clipr = clipr;
1884 error(Eindex);
1885 }
1886 q = drawchar(dst, q, src, &sp, font, ci, op);
1887 u += 2;
1888 }
1889 dst->clipr = clipr;
1890 p.y -= font->ascent;
1891 dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
1892 continue;
1893
1894 /* use public screen: 'S' id[4] chan[4] */
1895 case 'S':
1896 printmesg(fmt="Ll", a, 0);
1897 m = 1+4+4;
1898 if(n < m)
1899 error(Eshortdraw);
1900 dstid = BGLONG(a+1);
1901 if(dstid == 0)
1902 error(Ebadarg);
1903 dscrn = drawlookupdscreen(dstid);
1904 if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
1905 error(Enodrawscreen);
1906 if(dscrn->screen->image->chan != BGLONG(a+5))
1907 error("inconsistent chan");
1908 if(drawinstallscreen(client, dscrn, 0, 0, 0, 0) == 0)
1909 error(Edrawmem);
1910 continue;
1911
1912 /* top or bottom windows: 't' top[1] nw[2] n*id[4] */
1913 case 't':
1914 printmesg(fmt="bsL", a, 0);
1915 m = 1+1+2;
1916 if(n < m)
1917 error(Eshortdraw);
1918 nw = BGSHORT(a+2);
1919 if(nw < 0)
1920 error(Ebadarg);
1921 if(nw == 0)
1922 continue;
1923 m += nw*4;
1924 if(n < m)
1925 error(Eshortdraw);
1926 lp = malloc(nw*sizeof(Memimage*));
1927 if(lp == 0)
1928 error(Enomem);
1929 if(waserror()){
1930 free(lp);
1931 nexterror();
1932 }
1933 for(j=0; j<nw; j++)
1934 lp[j] = drawimage(client, a+1+1+2+j*4);
1935 if(lp[0]->layer == 0)
1936 error("images are not windows");
1937 for(j=1; j<nw; j++)
1938 if(lp[j]->layer->screen != lp[0]->layer->screen)
1939 error("images not on same screen");
1940 if(a[1])
1941 memltofrontn(lp, nw);
1942 else
1943 memltorearn(lp, nw);
1944 if(lp[0]->layer->screen->image->data == screenimage->data)
1945 for(j=0; j<nw; j++)
1946 addflush(lp[j]->layer->screenr);
1947 ll = drawlookup(client, BGLONG(a+1+1+2), 1);
1948 drawrefreshscreen(ll, client);
1949 poperror();
1950 free(lp);
1951 continue;
1952
1953 /* visible: 'v' */
1954 case 'v':
1955 printmesg(fmt="", a, 0);
1956 m = 1;
1957 drawflush();
1958 continue;
1959
1960 /* write: 'y' id[4] R[4*4] data[x*1] */
1961 /* write from compressed data: 'Y' id[4] R[4*4] data[x*1] */
1962 case 'y':
1963 case 'Y':
1964 printmesg(fmt="LR", a, 0);
1965 // iprint("load %c\n", *a);
1966 m = 1+4+4*4;
1967 if(n < m)
1968 error(Eshortdraw);
1969 dstid = BGLONG(a+1);
1970 dst = drawimage(client, a+1);
1971 drawrectangle(&r, a+5);
1972 if(!rectinrect(r, dst->r))
1973 error(Ewriteoutside);
1974 y = memload(dst, r, a+m, n-m, *a=='Y');
1975 if(y < 0)
1976 error("bad writeimage call");
1977 dstflush(dstid, dst, r);
1978 m += y;
1979 continue;
1980 }
1981 }
1982 poperror();
1983}
1984
1985Dev drawdevtab = {
1986 'i',
1987 "draw",
1988
1989 devreset,
1990 devinit,
1991 devshutdown,
1992 drawattach,
1993 drawwalk,
1994 drawstat,
1995 drawopen,
1996 devcreate,
1997 drawclose,
1998 drawread,
1999 devbread,
2000 drawwrite,
2001 devbwrite,
2002 devremove,
2003 devwstat,
2004};
2005
2006/*
2007 * On 8 bit displays, load the default color map
2008 */
2009void
2010drawcmap(void)
2011{
2012 int r, g, b, cr, cg, cb, v;
2013 int num, den;
2014 int i, j;
2015
2016 drawactive(1); /* to restore map from backup */
2017 for(r=0,i=0; r!=4; r++)
2018 for(v=0; v!=4; v++,i+=16){
2019 for(g=0,j=v-r; g!=4; g++)
2020 for(b=0;b!=4;b++,j++){
2021 den = r;
2022 if(g > den)
2023 den = g;
2024 if(b > den)
2025 den = b;
2026 if(den == 0) /* divide check -- pick grey shades */
2027 cr = cg = cb = v*17;
2028 else{
2029 num = 17*(4*den+v);
2030 cr = r*num/den;
2031 cg = g*num/den;
2032 cb = b*num/den;
2033 }
2034 setcolor(i+(j&15),
2035 cr*0x01010101, cg*0x01010101, cb*0x01010101);
2036 }
2037 }
2038}
2039
2040void
2041drawblankscreen(int blank)
2042{
2043 int i, nc;
2044 ulong *p;
2045
2046 if(blank == sdraw.blanked)
2047 return;
2048 if(!canqlock(&sdraw.lk))
2049 return;
2050 if(!initscreenimage()){
2051 qunlock(&sdraw.lk);
2052 return;
2053 }
2054 p = sdraw.savemap;
2055 nc = screenimage->depth > 8 ? 256 : 1<<screenimage->depth;
2056
2057 /*
2058 * blankscreen uses the hardware to blank the screen
2059 * when possible. to help in cases when it is not possible,
2060 * we set the color map to be all black.
2061 */
2062 if(blank == 0){ /* turn screen on */
2063 for(i=0; i<nc; i++, p+=3)
2064 setcolor(i, p[0], p[1], p[2]);
2065 // blankscreen(0);
2066 }else{ /* turn screen off */
2067 // blankscreen(1);
2068 for(i=0; i<nc; i++, p+=3){
2069 getcolor(i, &p[0], &p[1], &p[2]);
2070 setcolor(i, 0, 0, 0);
2071 }
2072 }
2073 sdraw.blanked = blank;
2074 qunlock(&sdraw.lk);
2075}
2076
2077/*
2078 * record activity on screen, changing blanking as appropriate
2079 */
2080void
2081drawactive(int active)
2082{
2083/*
2084 if(active){
2085 drawblankscreen(0);
2086 sdraw.blanktime = MACHP(0)->ticks;
2087 }else{
2088 if(blanktime && sdraw.blanktime && TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60 >= blanktime)
2089 drawblankscreen(1);
2090 }
2091*/
2092}
2093
2094int
2095drawidletime(void)
2096{
2097 return 0;
2098/* return TK2SEC(MACHP(0)->ticks - sdraw.blanktime)/60; */
2099}
2100
kern/devfs.c+638−0
@@ -0,0 +1,638 @@
1#include <sys/types.h>
2#include <sys/stat.h>
3#include <dirent.h>
4#include <fcntl.h>
5#include <errno.h>
6#include <stdio.h> /* for remove, rename */
7#include <limits.h>
8
9#ifndef NAME_MAX
10# define NAME_MAX 256
11#endif
12#include "u.h"
13#include "lib.h"
14#include "dat.h"
15#include "fns.h"
16#include "error.h"
17
18
19typedef struct Ufsinfo Ufsinfo;
20
21enum
22{
23 NUID = 256,
24 NGID = 256,
25 MAXPATH = 1024,
26 MAXCOMP = 128
27};
28
29struct Ufsinfo
30{
31 int mode;
32 int fd;
33 int uid;
34 int gid;
35 DIR* dir;
36 ulong offset;
37 QLock oq;
38 char nextname[NAME_MAX];
39};
40
41char *base = "/";
42
43static Qid fsqid(char*, struct stat *);
44static void fspath(Chan*, char*, char*);
45static ulong fsdirread(Chan*, uchar*, int, ulong);
46static int fsomode(int);
47
48/* clumsy hack, but not worse than the Path stuff in the last one */
49static char*
50uc2name(Chan *c)
51{
52 char *s;
53
54 if(c->name == nil)
55 return "/";
56 s = c2name(c);
57 if(s[0]=='#' && s[1]=='U')
58 return s+2;
59 return s;
60}
61
62static char*
63lastelem(Chan *c)
64{
65 char *s, *t;
66
67 s = uc2name(c);
68 if((t = strrchr(s, '/')) == nil)
69 return s;
70 if(t[1] == 0)
71 return t;
72 return t+1;
73}
74
75static Chan*
76fsattach(char *spec)
77{
78 Chan *c;
79 struct stat stbuf;
80 static int devno;
81 Ufsinfo *uif;
82
83 if(stat(base, &stbuf) < 0)
84 error(strerror(errno));
85
86 c = devattach('U', spec);
87
88 uif = mallocz(sizeof(Ufsinfo), 1);
89 uif->mode = stbuf.st_mode;
90 uif->uid = stbuf.st_uid;
91 uif->gid = stbuf.st_gid;
92
93 c->aux = uif;
94 c->dev = devno++;
95 c->qid.type = QTDIR;
96/*print("fsattach %s\n", c2name(c));*/
97
98 return c;
99}
100
101static Chan*
102fsclone(Chan *c, Chan *nc)
103{
104 Ufsinfo *uif;
105
106 uif = mallocz(sizeof(Ufsinfo), 1);
107 *uif = *(Ufsinfo*)c->aux;
108 nc->aux = uif;
109
110 return nc;
111}
112
113static int
114fswalk1(Chan *c, char *name)
115{
116 struct stat stbuf;
117 char path[MAXPATH];
118 Ufsinfo *uif;
119
120 fspath(c, name, path);
121
122 /*print("** fs walk '%s' -> %s\n", path, name); */
123
124 if(stat(path, &stbuf) < 0)
125 return 0;
126
127 uif = c->aux;
128
129 uif->mode = stbuf.st_mode;
130 uif->uid = stbuf.st_uid;
131 uif->gid = stbuf.st_gid;
132
133 c->qid = fsqid(path, &stbuf);
134
135 return 1;
136}
137
138extern Cname* addelem(Cname*, char*);
139
140static Walkqid*
141fswalk(Chan *c, Chan *nc, char **name, int nname)
142{
143 int i;
144 Cname *cname;
145 Walkqid *wq;
146
147 if(nc != nil)
148 panic("fswalk: nc != nil");
149 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
150 nc = devclone(c);
151 cname = c->name;
152 incref(&cname->ref);
153
154 fsclone(c, nc);
155 wq->clone = nc;
156 for(i=0; i<nname; i++){
157 nc->name = cname;
158 if(fswalk1(nc, name[i]) == 0)
159 break;
160 cname = addelem(cname, name[i]);
161 wq->qid[i] = nc->qid;
162 }
163 nc->name = nil;
164 cnameclose(cname);
165 if(i != nname){
166 cclose(nc);
167 wq->clone = nil;
168 }
169 wq->nqid = i;
170 return wq;
171}
172
173static int
174fsstat(Chan *c, uchar *buf, int n)
175{
176 Dir d;
177 struct stat stbuf;
178 char path[MAXPATH];
179
180 if(n < BIT16SZ)
181 error(Eshortstat);
182
183 fspath(c, 0, path);
184 if(stat(path, &stbuf) < 0)
185 error(strerror(errno));
186
187 d.name = lastelem(c);
188 d.uid = "unknown";
189 d.gid = "unknown";
190 d.muid = "unknown";
191 d.qid = c->qid;
192 d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
193 d.atime = stbuf.st_atime;
194 d.mtime = stbuf.st_mtime;
195 d.length = stbuf.st_size;
196 d.type = 'U';
197 d.dev = c->dev;
198 return convD2M(&d, buf, n);
199}
200
201static Chan*
202fsopen(Chan *c, int mode)
203{
204 char path[MAXPATH];
205 int m, isdir;
206 Ufsinfo *uif;
207
208/*print("fsopen %s\n", c2name(c));*/
209 m = mode & (OTRUNC|3);
210 switch(m) {
211 case 0:
212 break;
213 case 1:
214 case 1|16:
215 break;
216 case 2:
217 case 0|16:
218 case 2|16:
219 break;
220 case 3:
221 break;
222 default:
223 error(Ebadarg);
224 }
225
226 isdir = c->qid.type & QTDIR;
227
228 if(isdir && mode != OREAD)
229 error(Eperm);
230
231 m = fsomode(m & 3);
232 c->mode = openmode(mode);
233
234 uif = c->aux;
235
236 fspath(c, 0, path);
237 if(isdir) {
238 uif->dir = opendir(path);
239 if(uif->dir == 0)
240 error(strerror(errno));
241 }
242 else {
243 if(mode & OTRUNC)
244 m |= O_TRUNC;
245 uif->fd = open(path, m, 0666);
246
247 if(uif->fd < 0)
248 error(strerror(errno));
249 }
250 uif->offset = 0;
251
252 c->offset = 0;
253 c->flag |= COPEN;
254 return c;
255}
256
257static void
258fscreate(Chan *c, char *name, int mode, ulong perm)
259{
260 int fd, m;
261 char path[MAXPATH];
262 struct stat stbuf;
263 Ufsinfo *uif;
264
265 m = fsomode(mode&3);
266
267 fspath(c, name, path);
268
269 uif = c->aux;
270
271 if(perm & DMDIR) {
272 if(m)
273 error(Eperm);
274
275 if(mkdir(path, perm & 0777) < 0)
276 error(strerror(errno));
277
278 fd = open(path, 0);
279 if(fd >= 0) {
280 chmod(path, perm & 0777);
281 chown(path, uif->uid, uif->uid);
282 }
283 close(fd);
284
285 uif->dir = opendir(path);
286 if(uif->dir == 0)
287 error(strerror(errno));
288 }
289 else {
290 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
291 if(fd >= 0) {
292 if(m != 1) {
293 close(fd);
294 fd = open(path, m);
295 }
296 chmod(path, perm & 0777);
297 chown(path, uif->uid, uif->gid);
298 }
299 if(fd < 0)
300 error(strerror(errno));
301 uif->fd = fd;
302 }
303
304 if(stat(path, &stbuf) < 0)
305 error(strerror(errno));
306 c->qid = fsqid(path, &stbuf);
307 c->offset = 0;
308 c->flag |= COPEN;
309 c->mode = openmode(mode);
310}
311
312static void
313fsclose(Chan *c)
314{
315 Ufsinfo *uif;
316
317 uif = c->aux;
318
319 if(c->flag & COPEN) {
320 if(c->qid.type & QTDIR)
321 closedir(uif->dir);
322 else
323 close(uif->fd);
324 }
325
326 free(uif);
327}
328
329static long
330fsread(Chan *c, void *va, long n, vlong offset)
331{
332 int fd, r;
333 Ufsinfo *uif;
334
335/*print("fsread %s\n", c2name(c));*/
336 if(c->qid.type & QTDIR)
337 return fsdirread(c, va, n, offset);
338
339 uif = c->aux;
340 qlock(&uif->oq);
341 if(waserror()) {
342 qunlock(&uif->oq);
343 nexterror();
344 }
345 fd = uif->fd;
346 if(uif->offset != offset) {
347 r = lseek(fd, offset, 0);
348 if(r < 0)
349 error(strerror(errno));
350 uif->offset = offset;
351 }
352
353 n = read(fd, va, n);
354 if(n < 0)
355 error(strerror(errno));
356
357 uif->offset += n;
358 qunlock(&uif->oq);
359 poperror();
360
361 return n;
362}
363
364static long
365fswrite(Chan *c, void *va, long n, vlong offset)
366{
367 int fd, r;
368 Ufsinfo *uif;
369
370 uif = c->aux;
371
372 qlock(&uif->oq);
373 if(waserror()) {
374 qunlock(&uif->oq);
375 nexterror();
376 }
377 fd = uif->fd;
378 if(uif->offset != offset) {
379 r = lseek(fd, offset, 0);
380 if(r < 0)
381 error(strerror(errno));
382 uif->offset = offset;
383 }
384
385 n = write(fd, va, n);
386 if(n < 0)
387 error(strerror(errno));
388
389 uif->offset += n;
390 qunlock(&uif->oq);
391 poperror();
392
393 return n;
394}
395
396static void
397fsremove(Chan *c)
398{
399 int n;
400 char path[MAXPATH];
401
402 fspath(c, 0, path);
403 if(c->qid.type & QTDIR)
404 n = rmdir(path);
405 else
406 n = remove(path);
407 if(n < 0)
408 error(strerror(errno));
409}
410
411int
412fswstat(Chan *c, uchar *buf, int n)
413{
414 Dir d;
415 struct stat stbuf;
416 char old[MAXPATH], new[MAXPATH], dir[MAXPATH];
417 char strs[MAXPATH*3], *p;
418 Ufsinfo *uif;
419
420 if(convM2D(buf, n, &d, strs) != n)
421 error(Ebadstat);
422
423 fspath(c, 0, old);
424 if(stat(old, &stbuf) < 0)
425 error(strerror(errno));
426
427 uif = c->aux;
428
429 if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
430 fspath(c, 0, old);
431 strcpy(new, old);
432 p = strrchr(new, '/');
433 strcpy(p+1, d.name);
434 if(rename(old, new) < 0)
435 error(strerror(errno));
436 }
437
438 fspath(c, 0, old);
439 if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
440 if(chmod(old, d.mode&0777) < 0)
441 error(strerror(errno));
442 uif->mode &= ~0777;
443 uif->mode |= d.mode&0777;
444 }
445/*
446 p = name2pass(gid, d.gid);
447 if(p == 0)
448 error(Eunknown);
449
450 if(p->id != stbuf.st_gid) {
451 if(chown(old, stbuf.st_uid, p->id) < 0)
452 error(strerror(errno));
453
454 uif->gid = p->id;
455 }
456*/
457 return n;
458}
459
460static Qid
461fsqid(char *p, struct stat *st)
462{
463 Qid q;
464 int dev;
465 ulong h;
466 static int nqdev;
467 static uchar *qdev;
468
469 if(qdev == 0)
470 qdev = mallocz(65536U, 1);
471
472 q.type = 0;
473 if((st->st_mode&S_IFMT) == S_IFDIR)
474 q.type = QTDIR;
475
476 dev = st->st_dev & 0xFFFFUL;
477 if(qdev[dev] == 0)
478 qdev[dev] = ++nqdev;
479
480 h = 0;
481 while(*p != '\0')
482 h += *p++ * 13;
483
484 q.path = (vlong)qdev[dev]<<32;
485 q.path |= h;
486 q.vers = st->st_mtime;
487
488 return q;
489}
490
491static void
492fspath(Chan *c, char *ext, char *path)
493{
494 int i, n;
495 char *comp[MAXCOMP];
496
497 strcpy(path, base);
498 strcat(path, "/");
499 strcat(path, uc2name(c));
500 if(ext){
501 strcat(path, "/");
502 strcat(path, ext);
503 }
504 cleanname(path);
505}
506
507static int
508isdots(char *name)
509{
510 if(name[0] != '.')
511 return 0;
512 if(name[1] == '\0')
513 return 1;
514 if(name[1] != '.')
515 return 0;
516 if(name[2] == '\0')
517 return 1;
518 return 0;
519}
520
521static int
522p9readdir(char *name, Ufsinfo *uif)
523{
524 struct dirent *de;
525
526 if(uif->nextname[0]){
527 strcpy(name, uif->nextname);
528 uif->nextname[0] = 0;
529 return 1;
530 }
531
532 de = readdir(uif->dir);
533 if(de == NULL)
534 return 0;
535
536 strcpy(name, de->d_name);
537 return 1;
538}
539
540static ulong
541fsdirread(Chan *c, uchar *va, int count, ulong offset)
542{
543 int i;
544 Dir d;
545 long n;
546 char de[NAME_MAX];
547 struct stat stbuf;
548 char path[MAXPATH], dirpath[MAXPATH];
549 Ufsinfo *uif;
550
551/*print("fsdirread %s\n", c2name(c));*/
552 i = 0;
553 uif = c->aux;
554
555 errno = 0;
556 if(uif->offset != offset) {
557 if(offset != 0)
558 error("bad offset in fsdirread");
559 uif->offset = offset; /* sync offset */
560 uif->nextname[0] = 0;
561 rewinddir(uif->dir);
562 }
563
564 fspath(c, 0, dirpath);
565
566 while(i+BIT16SZ < count) {
567 if(!p9readdir(de, uif))
568 break;
569
570 if(de[0]==0 || isdots(de))
571 continue;
572
573 d.name = de;
574 sprint(path, "%s/%s", dirpath, de);
575 memset(&stbuf, 0, sizeof stbuf);
576
577 if(stat(path, &stbuf) < 0) {
578 print("dir: bad path %s\n", path);
579 /* but continue... probably a bad symlink */
580 }
581
582 d.uid = "unknown";
583 d.gid = "unknown";
584 d.qid = fsqid(path, &stbuf);
585 d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
586 d.atime = stbuf.st_atime;
587 d.mtime = stbuf.st_mtime;
588 d.length = stbuf.st_size;
589 d.type = 'U';
590 d.dev = c->dev;
591 n = convD2M(&d, (char*)va+i, count-i);
592 if(n == BIT16SZ){
593 strcpy(uif->nextname, de);
594 break;
595 }
596 i += n;
597 }
598/*print("got %d\n", i);*/
599 uif->offset += i;
600 return i;
601}
602
603static int
604fsomode(int m)
605{
606 switch(m) {
607 case 0: /* OREAD */
608 case 3: /* OEXEC */
609 return 0;
610 case 1: /* OWRITE */
611 return 1;
612 case 2: /* ORDWR */
613 return 2;
614 }
615 error(Ebadarg);
616 return 0;
617}
618
619Dev fsdevtab = {
620 'U',
621 "fs",
622
623 devreset,
624 devinit,
625 devshutdown,
626 fsattach,
627 fswalk,
628 fsstat,
629 fsopen,
630 fscreate,
631 fsclose,
632 fsread,
633 devbread,
634 fswrite,
635 devbwrite,
636 fsremove,
637 fswstat,
638};
kern/devip-posix.c+209−0
@@ -0,0 +1,209 @@
1#include <sys/types.h>
2#include <sys/socket.h>
3#include <netinet/in.h>
4#include <netinet/tcp.h>
5#include <netdb.h>
6
7#include "u.h"
8#include "lib.h"
9#include "dat.h"
10#include "fns.h"
11#include "error.h"
12
13#include "devip.h"
14
15#undef listen
16#undef accept
17#undef bind
18
19void
20osipinit(void)
21{
22 char buf[1024];
23 gethostname(buf, sizeof(buf));
24 kstrdup(&sysname, buf);
25
26}
27
28int
29so_socket(int type)
30{
31 int fd, one;
32
33 switch(type) {
34 default:
35 error("bad protocol type");
36 case S_TCP:
37 type = SOCK_STREAM;
38 break;
39 case S_UDP:
40 type = SOCK_DGRAM;
41 break;
42 }
43
44 fd = socket(AF_INET, type, 0);
45 if(fd < 0)
46 oserror();
47
48 one = 1;
49 if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0){
50 oserrstr();
51 print("setsockopt: %r");
52 }
53
54 return fd;
55}
56
57
58void
59so_connect(int fd, unsigned long raddr, unsigned short rport)
60{
61 struct sockaddr_in sin;
62
63 memset(&sin, 0, sizeof(sin));
64 sin.sin_family = AF_INET;
65 hnputs(&sin.sin_port, rport);
66 hnputl(&sin.sin_addr.s_addr, raddr);
67
68 if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
69 oserror();
70}
71
72void
73so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
74{
75 int len;
76 struct sockaddr_in sin;
77
78 len = sizeof(sin);
79 if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
80 oserror();
81
82 if(sin.sin_family != AF_INET || len != sizeof(sin))
83 error("not AF_INET");
84
85 *laddr = nhgetl(&sin.sin_addr.s_addr);
86 *lport = nhgets(&sin.sin_port);
87}
88
89void
90so_listen(int fd)
91{
92 if(listen(fd, 5) < 0)
93 oserror();
94}
95
96int
97so_accept(int fd, unsigned long *raddr, unsigned short *rport)
98{
99 int nfd, len;
100 struct sockaddr_in sin;
101
102 len = sizeof(sin);
103 nfd = accept(fd, (struct sockaddr*)&sin, &len);
104 if(nfd < 0)
105 oserror();
106
107 if(sin.sin_family != AF_INET || len != sizeof(sin))
108 error("not AF_INET");
109
110 *raddr = nhgetl(&sin.sin_addr.s_addr);
111 *rport = nhgets(&sin.sin_port);
112 return nfd;
113}
114
115void
116so_bind(int fd, int su, unsigned short port)
117{
118 int i, one;
119 struct sockaddr_in sin;
120
121 one = 1;
122 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0){
123 oserrstr();
124 print("setsockopt: %r");
125 }
126
127 if(su) {
128 for(i = 600; i < 1024; i++) {
129 memset(&sin, 0, sizeof(sin));
130 sin.sin_family = AF_INET;
131 sin.sin_port = i;
132
133 if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
134 return;
135 }
136 oserror();
137 }
138
139 memset(&sin, 0, sizeof(sin));
140 sin.sin_family = AF_INET;
141 hnputs(&sin.sin_port, port);
142
143 if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
144 oserror();
145}
146
147int
148so_gethostbyname(char *host, char**hostv, int n)
149{
150 int i;
151 char buf[32];
152 unsigned char *p;
153 struct hostent *hp;
154
155 hp = gethostbyname(host);
156 if(hp == 0)
157 return 0;
158
159 for(i = 0; hp->h_addr_list[i] && i < n; i++) {
160 p = (unsigned char*)hp->h_addr_list[i];
161 sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
162 hostv[i] = strdup(buf);
163 if(hostv[i] == 0)
164 break;
165 }
166 return i;
167}
168
169char*
170hostlookup(char *host)
171{
172 char buf[100];
173 uchar *p;
174 struct hostent *he;
175
176 he = gethostbyname(host);
177 if(he != 0 && he->h_addr_list[0]) {
178 p = (uchar*)he->h_addr_list[0];
179 sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
180 } else
181 strcpy(buf, host);
182
183 return strdup(buf);
184}
185
186int
187so_getservbyname(char *service, char *net, char *port)
188{
189 struct servent *s;
190
191 s = getservbyname(service, net);
192 if(s == 0)
193 return -1;
194
195 sprint(port, "%d", nhgets(&s->s_port));
196 return 0;
197}
198
199int
200so_send(int fd, void *d, int n, int f)
201{
202 send(fd, d, n, f);
203}
204
205int
206so_recv(int fd, void *d, int n, int f)
207{
208 return recv(fd, d, n, f);
209}
kern/devip-win.c+208−0
@@ -0,0 +1,208 @@
1#include <windows.h>
2#include "winduhz.h"
3#include "u.h"
4#include "lib.h"
5#include "dat.h"
6#include "fns.h"
7#include "error.h"
8
9#include "devip.h"
10
11#pragma comment(lib, "wsock32.lib")
12
13#undef listen
14#undef accept
15#undef bind
16
17void
18osipinit(void)
19{
20 WSADATA wasdat;
21 char buf[1024];
22
23 if(WSAStartup(MAKEWORD(1, 1), &wasdat) != 0)
24 panic("no winsock.dll");
25
26 gethostname(buf, sizeof(buf));
27 kstrdup(&sysname, buf);
28}
29
30int
31so_socket(int type)
32{
33 int fd, one;
34
35 switch(type) {
36 default:
37 error("bad protocol type");
38 case S_TCP:
39 type = SOCK_STREAM;
40 break;
41 case S_UDP:
42 type = SOCK_DGRAM;
43 break;
44 }
45
46 fd = socket(AF_INET, type, 0);
47 if(fd < 0)
48 error(sys_errlist[errno]);
49
50 one = 1;
51 if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) > 0)
52 print("setsockopt: %s", sys_errlist[errno]);
53
54
55 return fd;
56}
57
58
59void
60so_connect(int fd, unsigned long raddr, unsigned short rport)
61{
62 struct sockaddr_in sin;
63
64 memset(&sin, 0, sizeof(sin));
65 sin.sin_family = AF_INET;
66 hnputs(&sin.sin_port, rport);
67 hnputl(&sin.sin_addr.s_addr, raddr);
68
69 if(connect(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
70 error(sys_errlist[errno]);
71}
72
73void
74so_getsockname(int fd, unsigned long *laddr, unsigned short *lport)
75{
76 int len;
77 struct sockaddr_in sin;
78
79 len = sizeof(sin);
80 if(getsockname(fd, (struct sockaddr*)&sin, &len) < 0)
81 error(sys_errlist[errno]);
82
83 if(sin.sin_family != AF_INET || len != sizeof(sin))
84 error("not AF_INET");
85
86 *laddr = nhgetl(&sin.sin_addr.s_addr);
87 *lport = nhgets(&sin.sin_port);
88}
89
90void
91so_listen(int fd)
92{
93 if(listen(fd, 5) < 0)
94 error(sys_errlist[errno]);
95}
96
97int
98so_accept(int fd, unsigned long *raddr, unsigned short *rport)
99{
100 int nfd, len;
101 struct sockaddr_in sin;
102
103 len = sizeof(sin);
104 nfd = accept(fd, (struct sockaddr*)&sin, &len);
105 if(nfd < 0)
106 error(sys_errlist[errno]);
107
108 if(sin.sin_family != AF_INET || len != sizeof(sin))
109 error("not AF_INET");
110
111 *raddr = nhgetl(&sin.sin_addr.s_addr);
112 *rport = nhgets(&sin.sin_port);
113 return nfd;
114}
115
116void
117so_bind(int fd, int su, unsigned short port)
118{
119 int i, one;
120 struct sockaddr_in sin;
121
122 one = 1;
123 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one)) < 0)
124 print("setsockopt: %s", sys_errlist[errno]);
125
126 if(su) {
127 for(i = 600; i < 1024; i++) {
128 memset(&sin, 0, sizeof(sin));
129 sin.sin_family = AF_INET;
130 sin.sin_port = i;
131
132 if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) >= 0)
133 return;
134 }
135 error(sys_errlist[errno]);
136 }
137
138 memset(&sin, 0, sizeof(sin));
139 sin.sin_family = AF_INET;
140 hnputs(&sin.sin_port, port);
141
142 if(bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
143 error(sys_errlist[errno]);
144}
145
146int
147so_gethostbyname(char *host, char**hostv, int n)
148{
149 int i;
150 char buf[32];
151 unsigned char *p;
152 struct hostent *hp;
153
154 hp = gethostbyname(host);
155 if(hp == 0)
156 return 0;
157
158 for(i = 0; hp->h_addr_list[i] && i < n; i++) {
159 p = (unsigned char*)hp->h_addr_list[i];
160 sprint(buf, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
161 hostv[i] = strdup(buf);
162 if(hostv[i] == 0)
163 break;
164 }
165 return i;
166}
167
168char*
169hostlookup(char *host)
170{
171 char buf[100];
172 uchar *p;
173 HOSTENT *he;
174
175 he = gethostbyname(host);
176 if(he != 0 && he->h_addr_list[0]) {
177 p = he->h_addr_list[0];
178 sprint(buf, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]);
179 } else
180 strcpy(buf, host);
181
182 return strdup(buf);
183}
184
185int
186so_getservbyname(char *service, char *net, char *port)
187{
188 struct servent *s;
189
190 s = getservbyname(service, net);
191 if(s == 0)
192 return -1;
193
194 sprint(port, "%d", nhgets(&s->s_port));
195 return 0;
196}
197
198int
199so_send(int fd, void *d, int n, int f)
200{
201 return send(fd, d, n, f);
202}
203
204int
205so_recv(int fd, void *d, int n, int f)
206{
207 return recv(fd, d, n, f);
208}
kern/devip.c+936−0
@@ -0,0 +1,936 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7#include "devip.h"
8
9void hnputl(void *p, unsigned long v);
10void hnputs(void *p, unsigned short v);
11unsigned long nhgetl(void *p);
12unsigned short nhgets(void *p);
13unsigned long parseip(char *to, char *from);
14void csclose(Chan*);
15long csread(Chan*, void*, long, vlong);
16long cswrite(Chan*, void*, long, vlong);
17
18void osipinit(void);
19
20enum
21{
22 Qtopdir = 1, /* top level directory */
23 Qcs,
24 Qprotodir, /* directory for a protocol */
25 Qclonus,
26 Qconvdir, /* directory for a conversation */
27 Qdata,
28 Qctl,
29 Qstatus,
30 Qremote,
31 Qlocal,
32 Qlisten,
33
34 MAXPROTO = 4
35};
36#define TYPE(x) ((int)((x).path & 0xf))
37#define CONV(x) ((int)(((x).path >> 4)&0xfff))
38#define PROTO(x) ((int)(((x).path >> 16)&0xff))
39#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
40
41typedef struct Proto Proto;
42typedef struct Conv Conv;
43struct Conv
44{
45 int x;
46 Ref r;
47 int sfd;
48 int perm;
49 char owner[KNAMELEN];
50 char* state;
51 ulong laddr;
52 ushort lport;
53 ulong raddr;
54 ushort rport;
55 int restricted;
56 char cerr[KNAMELEN];
57 Proto* p;
58};
59
60struct Proto
61{
62 Lock l;
63 int x;
64 int stype;
65 char name[KNAMELEN];
66 int nc;
67 int maxconv;
68 Conv** conv;
69 Qid qid;
70};
71
72static int np;
73static Proto proto[MAXPROTO];
74int eipfmt(Fmt*);
75
76static Conv* protoclone(Proto*, char*, int);
77static void setladdr(Conv*);
78
79int
80ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
81{
82 Qid q;
83 Conv *cv;
84 char *p;
85
86 USED(nname);
87 q.vers = 0;
88 q.type = 0;
89 switch(TYPE(c->qid)) {
90 case Qtopdir:
91 if(s >= 1+np)
92 return -1;
93
94 if(s == 0){
95 q.path = QID(s, 0, Qcs);
96 devdir(c, q, "cs", 0, "network", 0666, dp);
97 }else{
98 s--;
99 q.path = QID(s, 0, Qprotodir);
100 q.type = QTDIR;
101 devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
102 }
103 return 1;
104 case Qprotodir:
105 if(s < proto[PROTO(c->qid)].nc) {
106 cv = proto[PROTO(c->qid)].conv[s];
107 sprint(up->genbuf, "%d", s);
108 q.path = QID(PROTO(c->qid), s, Qconvdir);
109 q.type = QTDIR;
110 devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
111 return 1;
112 }
113 s -= proto[PROTO(c->qid)].nc;
114 switch(s) {
115 default:
116 return -1;
117 case 0:
118 p = "clone";
119 q.path = QID(PROTO(c->qid), 0, Qclonus);
120 break;
121 }
122 devdir(c, q, p, 0, "network", 0555, dp);
123 return 1;
124 case Qconvdir:
125 cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
126 switch(s) {
127 default:
128 return -1;
129 case 0:
130 q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
131 devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
132 return 1;
133 case 1:
134 q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
135 devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
136 return 1;
137 case 2:
138 p = "status";
139 q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
140 break;
141 case 3:
142 p = "remote";
143 q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
144 break;
145 case 4:
146 p = "local";
147 q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
148 break;
149 case 5:
150 p = "listen";
151 q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
152 break;
153 }
154 devdir(c, q, p, 0, cv->owner, 0444, dp);
155 return 1;
156 }
157 return -1;
158}
159
160static void
161newproto(char *name, int type, int maxconv)
162{
163 int l;
164 Proto *p;
165
166 if(np >= MAXPROTO) {
167 print("no %s: increase MAXPROTO", name);
168 return;
169 }
170
171 p = &proto[np];
172 strcpy(p->name, name);
173 p->stype = type;
174 p->qid.path = QID(np, 0, Qprotodir);
175 p->qid.type = QTDIR;
176 p->x = np++;
177 p->maxconv = maxconv;
178 l = sizeof(Conv*)*(p->maxconv+1);
179 p->conv = mallocz(l, 1);
180 if(p->conv == 0)
181 panic("no memory");
182}
183
184void
185ipinit(void)
186{
187 osipinit();
188
189 newproto("udp", S_UDP, 10);
190 newproto("tcp", S_TCP, 30);
191
192 fmtinstall('I', eipfmt);
193 fmtinstall('E', eipfmt);
194
195}
196
197Chan *
198ipattach(char *spec)
199{
200 Chan *c;
201
202 c = devattach('I', spec);
203 c->qid.path = QID(0, 0, Qtopdir);
204 c->qid.type = QTDIR;
205 c->qid.vers = 0;
206 return c;
207}
208
209static Walkqid*
210ipwalk(Chan *c, Chan *nc, char **name, int nname)
211{
212 return devwalk(c, nc, name, nname, 0, 0, ipgen);
213}
214
215int
216ipstat(Chan *c, uchar *dp, int n)
217{
218 return devstat(c, dp, n, 0, 0, ipgen);
219}
220
221Chan *
222ipopen(Chan *c, int omode)
223{
224 Proto *p;
225 ulong raddr;
226 ushort rport;
227 int perm, sfd;
228 Conv *cv, *lcv;
229
230 omode &= 3;
231 switch(omode) {
232 case OREAD:
233 perm = 4;
234 break;
235 case OWRITE:
236 perm = 2;
237 break;
238 case ORDWR:
239 perm = 6;
240 break;
241 }
242
243 switch(TYPE(c->qid)) {
244 default:
245 break;
246 case Qtopdir:
247 case Qprotodir:
248 case Qconvdir:
249 case Qstatus:
250 case Qremote:
251 case Qlocal:
252 if(omode != OREAD)
253 error(Eperm);
254 break;
255 case Qclonus:
256 p = &proto[PROTO(c->qid)];
257 cv = protoclone(p, up->user, -1);
258 if(cv == 0)
259 error(Enodev);
260 c->qid.path = QID(p->x, cv->x, Qctl);
261 c->qid.vers = 0;
262 break;
263 case Qdata:
264 case Qctl:
265 p = &proto[PROTO(c->qid)];
266 lock(&p->l);
267 cv = p->conv[CONV(c->qid)];
268 lock(&cv->r.lk);
269 if((perm & (cv->perm>>6)) != perm) {
270 if(strcmp(up->user, cv->owner) != 0 ||
271 (perm & cv->perm) != perm) {
272 unlock(&cv->r.lk);
273 unlock(&p->l);
274 error(Eperm);
275 }
276 }
277 cv->r.ref++;
278 if(cv->r.ref == 1) {
279 memmove(cv->owner, up->user, KNAMELEN);
280 cv->perm = 0660;
281 }
282 unlock(&cv->r.lk);
283 unlock(&p->l);
284 break;
285 case Qlisten:
286 p = &proto[PROTO(c->qid)];
287 lcv = p->conv[CONV(c->qid)];
288 sfd = so_accept(lcv->sfd, &raddr, &rport);
289 cv = protoclone(p, up->user, sfd);
290 if(cv == 0) {
291 close(sfd);
292 error(Enodev);
293 }
294 cv->raddr = raddr;
295 cv->rport = rport;
296 setladdr(cv);
297 cv->state = "Established";
298 c->qid.path = QID(p->x, cv->x, Qctl);
299 break;
300 }
301 c->mode = openmode(omode);
302 c->flag |= COPEN;
303 c->offset = 0;
304 return c;
305}
306
307void
308ipclose(Chan *c)
309{
310 Conv *cc;
311
312 switch(TYPE(c->qid)) {
313 case Qcs:
314 csclose(c);
315 break;
316 case Qdata:
317 case Qctl:
318 if((c->flag & COPEN) == 0)
319 break;
320 cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
321 if(decref(&cc->r) != 0)
322 break;
323 strcpy(cc->owner, "network");
324 cc->perm = 0666;
325 cc->state = "Closed";
326 cc->laddr = 0;
327 cc->raddr = 0;
328 cc->lport = 0;
329 cc->rport = 0;
330 close(cc->sfd);
331 break;
332 }
333}
334
335long
336ipread(Chan *ch, void *a, long n, vlong offset)
337{
338 int r;
339 Conv *c;
340 Proto *x;
341 uchar ip[4];
342 char buf[128], *p;
343
344/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
345 p = a;
346 switch(TYPE(ch->qid)) {
347 default:
348 error(Eperm);
349 case Qcs:
350 return csread(ch, a, n, offset);
351 case Qprotodir:
352 case Qtopdir:
353 case Qconvdir:
354 return devdirread(ch, a, n, 0, 0, ipgen);
355 case Qctl:
356 sprint(buf, "%d", CONV(ch->qid));
357 return readstr(offset, p, n, buf);
358 case Qremote:
359 c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
360 hnputl(ip, c->raddr);
361 sprint(buf, "%I!%d\n", ip, c->rport);
362 return readstr(offset, p, n, buf);
363 case Qlocal:
364 c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
365 hnputl(ip, c->laddr);
366 sprint(buf, "%I!%d\n", ip, c->lport);
367 return readstr(offset, p, n, buf);
368 case Qstatus:
369 x = &proto[PROTO(ch->qid)];
370 c = x->conv[CONV(ch->qid)];
371 sprint(buf, "%s/%d %d %s \n",
372 c->p->name, c->x, c->r.ref, c->state);
373 return readstr(offset, p, n, buf);
374 case Qdata:
375 c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
376 r = so_recv(c->sfd, a, n, 0);
377 if(r < 0){
378 oserrstr();
379 nexterror();
380 }
381 return r;
382 }
383}
384
385static void
386setladdr(Conv *c)
387{
388 so_getsockname(c->sfd, &c->laddr, &c->lport);
389}
390
391static void
392setlport(Conv *c)
393{
394 if(c->restricted == 0 && c->lport == 0)
395 return;
396
397 so_bind(c->sfd, c->restricted, c->lport);
398}
399
400static void
401setladdrport(Conv *c, char *str)
402{
403 char *p, addr[4];
404
405 p = strchr(str, '!');
406 if(p == 0) {
407 p = str;
408 c->laddr = 0;
409 }
410 else {
411 *p++ = 0;
412 parseip(addr, str);
413 c->laddr = nhgetl((uchar*)addr);
414 }
415 if(*p == '*')
416 c->lport = 0;
417 else
418 c->lport = atoi(p);
419
420 setlport(c);
421}
422
423static char*
424setraddrport(Conv *c, char *str)
425{
426 char *p, addr[4];
427
428 p = strchr(str, '!');
429 if(p == 0)
430 return "malformed address";
431 *p++ = 0;
432 parseip(addr, str);
433 c->raddr = nhgetl((uchar*)addr);
434 c->rport = atoi(p);
435 p = strchr(p, '!');
436 if(p) {
437 if(strcmp(p, "!r") == 0)
438 c->restricted = 1;
439 }
440 return 0;
441}
442
443long
444ipwrite(Chan *ch, void *a, long n, vlong offset)
445{
446 Conv *c;
447 Proto *x;
448 int r, nf;
449 char *p, *fields[3], buf[128];
450
451 switch(TYPE(ch->qid)) {
452 default:
453 error(Eperm);
454 case Qcs:
455 return cswrite(ch, a, n, offset);
456 case Qctl:
457 x = &proto[PROTO(ch->qid)];
458 c = x->conv[CONV(ch->qid)];
459 if(n > sizeof(buf)-1)
460 n = sizeof(buf)-1;
461 memmove(buf, a, n);
462 buf[n] = '\0';
463
464 nf = tokenize(buf, fields, 3);
465 if(strcmp(fields[0], "connect") == 0){
466 switch(nf) {
467 default:
468 error("bad args to connect");
469 case 2:
470 p = setraddrport(c, fields[1]);
471 if(p != 0)
472 error(p);
473 break;
474 case 3:
475 p = setraddrport(c, fields[1]);
476 if(p != 0)
477 error(p);
478 c->lport = atoi(fields[2]);
479 setlport(c);
480 break;
481 }
482 so_connect(c->sfd, c->raddr, c->rport);
483 setladdr(c);
484 c->state = "Established";
485 return n;
486 }
487 if(strcmp(fields[0], "announce") == 0) {
488 switch(nf){
489 default:
490 error("bad args to announce");
491 case 2:
492 setladdrport(c, fields[1]);
493 break;
494 }
495 so_listen(c->sfd);
496 c->state = "Announced";
497 return n;
498 }
499 if(strcmp(fields[0], "bind") == 0){
500 switch(nf){
501 default:
502 error("bad args to bind");
503 case 2:
504 c->lport = atoi(fields[1]);
505 break;
506 }
507 setlport(c);
508 return n;
509 }
510 error("bad control message");
511 case Qdata:
512 x = &proto[PROTO(ch->qid)];
513 c = x->conv[CONV(ch->qid)];
514 r = so_send(c->sfd, a, n, 0);
515 if(r < 0){
516 oserrstr();
517 nexterror();
518 }
519 return r;
520 }
521 return n;
522}
523
524static Conv*
525protoclone(Proto *p, char *user, int nfd)
526{
527 Conv *c, **pp, **ep;
528
529 c = 0;
530 lock(&p->l);
531 if(waserror()) {
532 unlock(&p->l);
533 nexterror();
534 }
535 ep = &p->conv[p->maxconv];
536 for(pp = p->conv; pp < ep; pp++) {
537 c = *pp;
538 if(c == 0) {
539 c = mallocz(sizeof(Conv), 1);
540 if(c == 0)
541 error(Enomem);
542 lock(&c->r.lk);
543 c->r.ref = 1;
544 c->p = p;
545 c->x = pp - p->conv;
546 p->nc++;
547 *pp = c;
548 break;
549 }
550 lock(&c->r.lk);
551 if(c->r.ref == 0) {
552 c->r.ref++;
553 break;
554 }
555 unlock(&c->r.lk);
556 }
557 if(pp >= ep) {
558 unlock(&p->l);
559 poperror();
560 return 0;
561 }
562
563 strcpy(c->owner, user);
564 c->perm = 0660;
565 c->state = "Closed";
566 c->restricted = 0;
567 c->laddr = 0;
568 c->raddr = 0;
569 c->lport = 0;
570 c->rport = 0;
571 c->sfd = nfd;
572 if(nfd == -1)
573 c->sfd = so_socket(p->stype);
574
575 unlock(&c->r.lk);
576 unlock(&p->l);
577 poperror();
578 return c;
579}
580
581enum
582{
583 Isprefix= 16,
584};
585
586uchar prefixvals[256] =
587{
588/*0x00*/ 0 | Isprefix,
589 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
590/*0x10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
591/*0x20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
592/*0x30*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
593/*0x40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
594/*0x50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
595/*0x60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
596/*0x70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
597/*0x80*/ 1 | Isprefix,
598 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
599/*0x90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
600/*0xA0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
601/*0xB0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
602/*0xC0*/ 2 | Isprefix,
603 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
604/*0xD0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
605/*0xE0*/ 3 | Isprefix,
606 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
607/*0xF0*/ 4 | Isprefix,
608 0, 0, 0, 0, 0, 0, 0,
609/*0xF8*/ 5 | Isprefix,
610 0, 0, 0,
611/*0xFC*/ 6 | Isprefix,
612 0,
613/*0xFE*/ 7 | Isprefix,
614/*0xFF*/ 8 | Isprefix,
615};
616
617int
618eipfmt(Fmt *f)
619{
620 char buf[5*8];
621 static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
622 static char *ifmt = "%d.%d.%d.%d";
623 uchar *p, ip[16];
624 ulong *lp;
625 ushort s;
626 int i, j, n, eln, eli;
627 ulong ul;
628
629 switch(f->r) {
630 case 'E': /* Ethernet address */
631 p = va_arg(f->args, uchar*);
632 snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
633 return fmtstrcpy(f, buf);
634
635 case 'I':
636 ul = va_arg(f->args, ulong);
637 hnputl(ip, ul);
638 snprint(buf, sizeof buf, ifmt, ip[0], ip[1], ip[2], ip[3]);
639 return fmtstrcpy(f, buf);
640 }
641 return fmtstrcpy(f, "(eipfmt)");
642}
643
644void
645hnputl(void *p, unsigned long v)
646{
647 unsigned char *a;
648
649 a = p;
650 a[0] = v>>24;
651 a[1] = v>>16;
652 a[2] = v>>8;
653 a[3] = v;
654}
655
656void
657hnputs(void *p, unsigned short v)
658{
659 unsigned char *a;
660
661 a = p;
662 a[0] = v>>8;
663 a[1] = v;
664}
665
666unsigned long
667nhgetl(void *p)
668{
669 unsigned char *a;
670 a = p;
671 return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
672}
673
674unsigned short
675nhgets(void *p)
676{
677 unsigned char *a;
678 a = p;
679 return (a[0]<<8)|(a[1]<<0);
680}
681
682#define CLASS(p) ((*(unsigned char*)(p))>>6)
683
684unsigned long
685parseip(char *to, char *from)
686{
687 int i;
688 char *p;
689
690 p = from;
691 memset(to, 0, 4);
692 for(i = 0; i < 4 && *p; i++){
693 to[i] = strtoul(p, &p, 0);
694 if(*p == '.')
695 p++;
696 }
697 switch(CLASS(to)){
698 case 0: /* class A - 1 byte net */
699 case 1:
700 if(i == 3){
701 to[3] = to[2];
702 to[2] = to[1];
703 to[1] = 0;
704 } else if (i == 2){
705 to[3] = to[1];
706 to[1] = 0;
707 }
708 break;
709 case 2: /* class B - 2 byte net */
710 if(i == 3){
711 to[3] = to[2];
712 to[2] = 0;
713 }
714 break;
715 }
716 return nhgetl(to);
717}
718
719void
720csclose(Chan *c)
721{
722 free(c->aux);
723}
724
725long
726csread(Chan *c, void *a, long n, vlong offset)
727{
728 if(c->aux == nil)
729 return 0;
730 return readstr(offset, a, n, c->aux);
731}
732
733static struct
734{
735 char *name;
736 uint num;
737} tab[] = {
738 "cs", 1,
739 "echo", 7,
740 "discard", 9,
741 "systat", 11,
742 "daytime", 13,
743 "netstat", 15,
744 "chargen", 19,
745 "ftp-data", 20,
746 "ftp", 21,
747 "ssh", 22,
748 "telnet", 23,
749 "smtp", 25,
750 "time", 37,
751 "whois", 43,
752 "dns", 53,
753 "domain", 53,
754 "uucp", 64,
755 "gopher", 70,
756 "rje", 77,
757 "finger", 79,
758 "http", 80,
759 "link", 87,
760 "supdup", 95,
761 "hostnames", 101,
762 "iso-tsap", 102,
763 "x400", 103,
764 "x400-snd", 104,
765 "csnet-ns", 105,
766 "pop-2", 109,
767 "pop3", 110,
768 "portmap", 111,
769 "uucp-path", 117,
770 "nntp", 119,
771 "netbios", 139,
772 "imap4", 143,
773 "NeWS", 144,
774 "print-srv", 170,
775 "z39.50", 210,
776 "fsb", 400,
777 "sysmon", 401,
778 "proxy", 402,
779 "proxyd", 404,
780 "https", 443,
781 "cifs", 445,
782 "ssmtp", 465,
783 "rexec", 512,
784 "login", 513,
785 "shell", 514,
786 "printer", 515,
787 "courier", 530,
788 "cscan", 531,
789 "uucp", 540,
790 "snntp", 563,
791 "9fs", 564,
792 "whoami", 565,
793 "guard", 566,
794 "ticket", 567,
795 "dlsftp", 666,
796 "fmclient", 729,
797 "imaps", 993,
798 "pop3s", 995,
799 "ingreslock", 1524,
800 "pptp", 1723,
801 "nfs", 2049,
802 "webster", 2627,
803 "weather", 3000,
804 "secstore", 5356,
805 "Xdisplay", 6000,
806 "styx", 6666,
807 "mpeg", 6667,
808 "rstyx", 6668,
809 "infdb", 6669,
810 "infsigner", 6671,
811 "infcsigner", 6672,
812 "inflogin", 6673,
813 "bandt", 7330,
814 "face", 32000,
815 "dhashgate", 11978,
816 "exportfs", 17007,
817 "rexexec", 17009,
818 "ncpu", 17010,
819 "cpu", 17013,
820 "glenglenda1", 17020,
821 "glenglenda2", 17021,
822 "glenglenda3", 17022,
823 "glenglenda4", 17023,
824 "glenglenda5", 17024,
825 "glenglenda6", 17025,
826 "glenglenda7", 17026,
827 "glenglenda8", 17027,
828 "glenglenda9", 17028,
829 "glenglenda10", 17029,
830 "flyboy", 17032,
831 "dlsftp", 17033,
832 "venti", 17034,
833 "wiki", 17035,
834 "vica", 17036,
835 0
836};
837
838static int
839lookupport(char *s)
840{
841 int i;
842 char buf[10], *p;
843
844 i = strtol(s, &p, 0);
845 if(*s && *p == 0)
846 return i;
847
848 i = so_getservbyname(s, "tcp", buf);
849 if(i != -1)
850 return atoi(buf);
851 for(i=0; tab[i].name; i++)
852 if(strcmp(s, tab[i].name) == 0)
853 return tab[i].num;
854 return 0;
855}
856
857static ulong
858lookuphost(char *s)
859{
860 char to[4];
861 ulong ip;
862
863 memset(to, 0, sizeof to);
864 parseip(to, s);
865 ip = nhgetl(to);
866 if(ip != 0)
867 return ip;
868 if((s = hostlookup(s)) == nil)
869 return 0;
870 parseip(to, s);
871 ip = nhgetl(to);
872 free(s);
873 return ip;
874}
875
876long
877cswrite(Chan *c, void *a, long n, vlong offset)
878{
879 char *f[4];
880 char *s, *ns;
881 ulong ip;
882 int nf, port;
883
884 s = malloc(n+1);
885 if(s == nil)
886 error(Enomem);
887 if(waserror()){
888 free(s);
889 nexterror();
890 }
891 memmove(s, a, n);
892 s[n] = 0;
893 nf = getfields(s, f, nelem(f), 0, "!");
894 if(nf != 3)
895 error("can't translate");
896
897 port = lookupport(f[2]);
898 if(port <= 0)
899 error("no translation for port found");
900
901 ip = lookuphost(f[1]);
902 if(ip == 0)
903 error("no translation for host found");
904
905 ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
906 if(ns == nil)
907 error(Enomem);
908 free(c->aux);
909 c->aux = ns;
910 poperror();
911 free(s);
912 return n;
913}
914
915Dev ipdevtab =
916{
917 'I',
918 "ip",
919
920 devreset,
921 ipinit,
922 devshutdown,
923 ipattach,
924 ipwalk,
925 ipstat,
926 ipopen,
927 devcreate,
928 ipclose,
929 ipread,
930 devbread,
931 ipwrite,
932 devbwrite,
933 devremove,
934 devwstat,
935};
936
kern/devip.h+17−0
@@ -0,0 +1,17 @@
1enum
2{
3 S_TCP,
4 S_UDP
5};
6
7int so_socket(int type);
8void so_connect(int, unsigned long, unsigned short);
9void so_getsockname(int, unsigned long*, unsigned short*);
10void so_bind(int, int, unsigned short);
11void so_listen(int);
12int so_accept(int, unsigned long*, unsigned short*);
13int so_getservbyname(char*, char*, char*);
14int so_gethostbyname(char*, char**, int);
15
16char* hostlookup(char*);
17
kern/devmnt.c+1214−0
@@ -0,0 +1,1214 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7/*
8 * References are managed as follows:
9 * The channel to the server - a network connection or pipe - has one
10 * reference for every Chan open on the server. The server channel has
11 * c->mux set to the Mnt used for muxing control to that server. Mnts
12 * have no reference count; they go away when c goes away.
13 * Each channel derived from the mount point has mchan set to c,
14 * and increfs/decrefs mchan to manage references on the server
15 * connection.
16 */
17
18#define MAXRPC (IOHDRSZ+8192)
19
20struct Mntrpc
21{
22 Chan* c; /* Channel for whom we are working */
23 Mntrpc* list; /* Free/pending list */
24 Fcall request; /* Outgoing file system protocol message */
25 Fcall reply; /* Incoming reply */
26 Mnt* m; /* Mount device during rpc */
27 Rendez r; /* Place to hang out */
28 uchar* rpc; /* I/O Data buffer */
29 uint rpclen; /* len of buffer */
30 Block *b; /* reply blocks */
31 char done; /* Rpc completed */
32 uvlong stime; /* start time for mnt statistics */
33 ulong reqlen; /* request length for mnt statistics */
34 ulong replen; /* reply length for mnt statistics */
35 Mntrpc* flushed; /* message this one flushes */
36};
37
38enum
39{
40 TAGSHIFT = 5, /* ulong has to be 32 bits */
41 TAGMASK = (1<<TAGSHIFT)-1,
42 NMASK = (64*1024)>>TAGSHIFT,
43};
44
45struct Mntalloc
46{
47 Lock lk;
48 Mnt* list; /* Mount devices in use */
49 Mnt* mntfree; /* Free list */
50 Mntrpc* rpcfree;
51 int nrpcfree;
52 int nrpcused;
53 ulong id;
54 ulong tagmask[NMASK];
55}mntalloc;
56
57void mattach(Mnt*, Chan*, char*);
58Mnt* mntchk(Chan*);
59void mntdirfix(uchar*, Chan*);
60Mntrpc* mntflushalloc(Mntrpc*, ulong);
61void mntflushfree(Mnt*, Mntrpc*);
62void mntfree(Mntrpc*);
63void mntgate(Mnt*);
64void mntpntfree(Mnt*);
65void mntqrm(Mnt*, Mntrpc*);
66Mntrpc* mntralloc(Chan*, ulong);
67long mntrdwr(int, Chan*, void*, long, vlong);
68int mntrpcread(Mnt*, Mntrpc*);
69void mountio(Mnt*, Mntrpc*);
70void mountmux(Mnt*, Mntrpc*);
71void mountrpc(Mnt*, Mntrpc*);
72int rpcattn(void*);
73Chan* mntchan(void);
74
75char Esbadstat[] = "invalid directory entry received from server";
76char Enoversion[] = "version not established for mount channel";
77
78
79void (*mntstats)(int, Chan*, uvlong, ulong);
80
81static void
82mntreset(void)
83{
84 mntalloc.id = 1;
85 mntalloc.tagmask[0] = 1; /* don't allow 0 as a tag */
86 mntalloc.tagmask[NMASK-1] = 0x80000000UL; /* don't allow NOTAG */
87 fmtinstall('F', fcallfmt);
88 fmtinstall('D', dirfmt);
89/* We can't install %M since eipfmt does and is used in the kernel [sape] */
90
91 cinit();
92}
93
94/*
95 * Version is not multiplexed: message sent only once per connection.
96 */
97long
98mntversion(Chan *c, char *version, int msize, int returnlen)
99{
100 Fcall f;
101 uchar *msg;
102 Mnt *m;
103 char *v;
104 long k, l;
105 uvlong oo;
106 char buf[128];
107
108 qlock(&c->umqlock); /* make sure no one else does this until we've established ourselves */
109 if(waserror()){
110 qunlock(&c->umqlock);
111 nexterror();
112 }
113
114 /* defaults */
115 if(msize == 0)
116 msize = MAXRPC;
117 if(msize > c->iounit && c->iounit != 0)
118 msize = c->iounit;
119 v = version;
120 if(v == nil || v[0] == '\0')
121 v = VERSION9P;
122
123 /* validity */
124 if(msize < 0)
125 error("bad iounit in version call");
126 if(strncmp(v, VERSION9P, strlen(VERSION9P)) != 0)
127 error("bad 9P version specification");
128
129 m = c->mux;
130
131 if(m != nil){
132 qunlock(&c->umqlock);
133 poperror();
134
135 strecpy(buf, buf+sizeof buf, m->version);
136 k = strlen(buf);
137 if(strncmp(buf, v, k) != 0){
138 snprint(buf, sizeof buf, "incompatible 9P versions %s %s", m->version, v);
139 error(buf);
140 }
141 if(returnlen > 0){
142 if(returnlen < k)
143 error(Eshort);
144 memmove(version, buf, k);
145 }
146 return k;
147 }
148
149 f.type = Tversion;
150 f.tag = NOTAG;
151 f.msize = msize;
152 f.version = v;
153 msg = malloc(8192+IOHDRSZ);
154 if(msg == nil)
155 exhausted("version memory");
156 if(waserror()){
157 free(msg);
158 nexterror();
159 }
160 k = convS2M(&f, msg, 8192+IOHDRSZ);
161 if(k == 0)
162 error("bad fversion conversion on send");
163
164 lock(&c->ref.lk);
165 oo = c->offset;
166 c->offset += k;
167 unlock(&c->ref.lk);
168
169 l = devtab[c->type]->write(c, msg, k, oo);
170
171 if(l < k){
172 lock(&c->ref.lk);
173 c->offset -= k - l;
174 unlock(&c->ref.lk);
175 error("short write in fversion");
176 }
177
178 /* message sent; receive and decode reply */
179 k = devtab[c->type]->read(c, msg, 8192+IOHDRSZ, c->offset);
180 if(k <= 0)
181 error("EOF receiving fversion reply");
182
183 lock(&c->ref.lk);
184 c->offset += k;
185 unlock(&c->ref.lk);
186
187 l = convM2S(msg, k, &f);
188 if(l != k)
189 error("bad fversion conversion on reply");
190 if(f.type != Rversion){
191 if(f.type == Rerror)
192 error(f.ename);
193 error("unexpected reply type in fversion");
194 }
195 if(f.msize > msize)
196 error("server tries to increase msize in fversion");
197 if(f.msize<256 || f.msize>1024*1024)
198 error("nonsense value of msize in fversion");
199 if(strncmp(f.version, v, strlen(f.version)) != 0)
200 error("bad 9P version returned from server");
201
202 /* now build Mnt associated with this connection */
203 lock(&mntalloc.lk);
204 m = mntalloc.mntfree;
205 if(m != 0)
206 mntalloc.mntfree = m->list;
207 else {
208 m = malloc(sizeof(Mnt));
209 if(m == 0) {
210 unlock(&mntalloc.lk);
211 exhausted("mount devices");
212 }
213 }
214 m->list = mntalloc.list;
215 mntalloc.list = m;
216 m->version = nil;
217 kstrdup(&m->version, f.version);
218 m->id = mntalloc.id++;
219 m->q = qopen(10*MAXRPC, 0, nil, nil);
220 m->msize = f.msize;
221 unlock(&mntalloc.lk);
222
223 poperror(); /* msg */
224 free(msg);
225
226 lock(&m->lk);
227 m->queue = 0;
228 m->rip = 0;
229
230 c->flag |= CMSG;
231 c->mux = m;
232 m->c = c;
233 unlock(&m->lk);
234
235 poperror(); /* c */
236 qunlock(&c->umqlock);
237
238 k = strlen(f.version);
239 if(returnlen > 0){
240 if(returnlen < k)
241 error(Eshort);
242 memmove(version, f.version, k);
243 }
244
245 return k;
246}
247
248Chan*
249mntauth(Chan *c, char *spec)
250{
251 Mnt *m;
252 Mntrpc *r;
253
254 m = c->mux;
255
256 if(m == nil){
257 mntversion(c, VERSION9P, MAXRPC, 0);
258 m = c->mux;
259 if(m == nil)
260 error(Enoversion);
261 }
262
263 c = mntchan();
264 if(waserror()) {
265 /* Close must not be called since it will
266 * call mnt recursively
267 */
268 chanfree(c);
269 nexterror();
270 }
271
272 r = mntralloc(0, m->msize);
273
274 if(waserror()) {
275 mntfree(r);
276 nexterror();
277 }
278
279 r->request.type = Tauth;
280 r->request.afid = c->fid;
281 r->request.uname = up->user;
282 r->request.aname = spec;
283 mountrpc(m, r);
284
285 c->qid = r->reply.aqid;
286 c->mchan = m->c;
287 incref(&m->c->ref);
288 c->mqid = c->qid;
289 c->mode = ORDWR;
290
291 poperror(); /* r */
292 mntfree(r);
293
294 poperror(); /* c */
295
296 return c;
297
298}
299
300static Chan*
301mntattach(char *muxattach)
302{
303 Mnt *m;
304 Chan *c;
305 Mntrpc *r;
306 struct bogus{
307 Chan *chan;
308 Chan *authchan;
309 char *spec;
310 int flags;
311 }bogus;
312
313 bogus = *((struct bogus *)muxattach);
314 c = bogus.chan;
315
316 m = c->mux;
317
318 if(m == nil){
319 mntversion(c, nil, 0, 0);
320 m = c->mux;
321 if(m == nil)
322 error(Enoversion);
323 }
324
325 c = mntchan();
326 if(waserror()) {
327 /* Close must not be called since it will
328 * call mnt recursively
329 */
330 chanfree(c);
331 nexterror();
332 }
333
334 r = mntralloc(0, m->msize);
335
336 if(waserror()) {
337 mntfree(r);
338 nexterror();
339 }
340
341 r->request.type = Tattach;
342 r->request.fid = c->fid;
343 if(bogus.authchan == nil)
344 r->request.afid = NOFID;
345 else
346 r->request.afid = bogus.authchan->fid;
347 r->request.uname = up->user;
348 r->request.aname = bogus.spec;
349 mountrpc(m, r);
350
351 c->qid = r->reply.qid;
352 c->mchan = m->c;
353 incref(&m->c->ref);
354 c->mqid = c->qid;
355
356 poperror(); /* r */
357 mntfree(r);
358
359 poperror(); /* c */
360
361 if(bogus.flags&MCACHE)
362 c->flag |= CCACHE;
363 return c;
364}
365
366Chan*
367mntchan(void)
368{
369 Chan *c;
370
371 c = devattach('M', 0);
372 lock(&mntalloc.lk);
373 c->dev = mntalloc.id++;
374 unlock(&mntalloc.lk);
375
376 if(c->mchan)
377 panic("mntchan non-zero %p", c->mchan);
378 return c;
379}
380
381static Walkqid*
382mntwalk(Chan *c, Chan *nc, char **name, int nname)
383{
384 int i, alloc;
385 Mnt *m;
386 Mntrpc *r;
387 Walkqid *wq;
388
389 if(nc != nil)
390 print("mntwalk: nc != nil\n");
391 if(nname > MAXWELEM)
392 error("devmnt: too many name elements");
393 alloc = 0;
394 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
395 if(waserror()){
396 if(alloc && wq->clone!=nil)
397 cclose(wq->clone);
398 free(wq);
399 return nil;
400 }
401
402 alloc = 0;
403 m = mntchk(c);
404 r = mntralloc(c, m->msize);
405 if(nc == nil){
406 nc = devclone(c);
407 /*
408 * Until the other side accepts this fid, we can't mntclose it.
409 * Therefore set type to 0 for now; rootclose is known to be safe.
410 */
411 nc->type = 0;
412 alloc = 1;
413 }
414 wq->clone = nc;
415
416 if(waserror()) {
417 mntfree(r);
418 nexterror();
419 }
420 r->request.type = Twalk;
421 r->request.fid = c->fid;
422 r->request.newfid = nc->fid;
423 r->request.nwname = nname;
424 memmove(r->request.wname, name, nname*sizeof(char*));
425
426 mountrpc(m, r);
427
428 if(r->reply.nwqid > nname)
429 error("too many QIDs returned by walk");
430 if(r->reply.nwqid < nname){
431 if(alloc)
432 cclose(nc);
433 wq->clone = nil;
434 if(r->reply.nwqid == 0){
435 free(wq);
436 wq = nil;
437 goto Return;
438 }
439 }
440
441 /* move new fid onto mnt device and update its qid */
442 if(wq->clone != nil){
443 if(wq->clone != c){
444 wq->clone->type = c->type;
445 wq->clone->mchan = c->mchan;
446 incref(&c->mchan->ref);
447 }
448 if(r->reply.nwqid > 0)
449 wq->clone->qid = r->reply.wqid[r->reply.nwqid-1];
450 }
451 wq->nqid = r->reply.nwqid;
452 for(i=0; i<wq->nqid; i++)
453 wq->qid[i] = r->reply.wqid[i];
454
455 Return:
456 poperror();
457 mntfree(r);
458 poperror();
459 return wq;
460}
461
462static int
463mntstat(Chan *c, uchar *dp, int n)
464{
465 Mnt *m;
466 Mntrpc *r;
467
468 if(n < BIT16SZ)
469 error(Eshortstat);
470 m = mntchk(c);
471 r = mntralloc(c, m->msize);
472 if(waserror()) {
473 mntfree(r);
474 nexterror();
475 }
476 r->request.type = Tstat;
477 r->request.fid = c->fid;
478 mountrpc(m, r);
479
480 if(r->reply.nstat >= 1<<(8*BIT16SZ))
481 error("returned stat buffer count too large");
482
483 if(r->reply.nstat > n){
484 /*
485 * 12/31/2002 RSC
486 *
487 * This should be nstat-2, which is the first two
488 * bytes of the stat buffer. But dirstat and dirfstat
489 * depended on getting the full nstat (they didn't
490 * add BIT16SZ themselves). I fixed dirstat and dirfstat
491 * but am leaving this unchanged for now. After a
492 * few months, once enough of the relevant binaries
493 * have been recompiled for other reasons, we can
494 * change this to nstat-2. Devstat gets this right
495 * (via convD2M).
496 */
497 /* doesn't fit; just patch the count and return */
498 PBIT16((uchar*)dp, r->reply.nstat);
499 n = BIT16SZ;
500 }else{
501 n = r->reply.nstat;
502 memmove(dp, r->reply.stat, n);
503 validstat(dp, n);
504 mntdirfix(dp, c);
505 }
506 poperror();
507 mntfree(r);
508 return n;
509}
510
511static Chan*
512mntopencreate(int type, Chan *c, char *name, int omode, ulong perm)
513{
514 Mnt *m;
515 Mntrpc *r;
516
517 m = mntchk(c);
518 r = mntralloc(c, m->msize);
519 if(waserror()) {
520 mntfree(r);
521 nexterror();
522 }
523 r->request.type = type;
524 r->request.fid = c->fid;
525 r->request.mode = omode;
526 if(type == Tcreate){
527 r->request.perm = perm;
528 r->request.name = name;
529 }
530 mountrpc(m, r);
531
532 c->qid = r->reply.qid;
533 c->offset = 0;
534 c->mode = openmode(omode);
535 c->iounit = r->reply.iounit;
536 if(c->iounit == 0 || c->iounit > m->msize-IOHDRSZ)
537 c->iounit = m->msize-IOHDRSZ;
538 c->flag |= COPEN;
539 poperror();
540 mntfree(r);
541
542 if(c->flag & CCACHE)
543 copen(c);
544
545 return c;
546}
547
548static Chan*
549mntopen(Chan *c, int omode)
550{
551 return mntopencreate(Topen, c, nil, omode, 0);
552}
553
554static void
555mntcreate(Chan *c, char *name, int omode, ulong perm)
556{
557 mntopencreate(Tcreate, c, name, omode, perm);
558}
559
560static void
561mntclunk(Chan *c, int t)
562{
563 Mnt *m;
564 Mntrpc *r;
565
566 m = mntchk(c);
567 r = mntralloc(c, m->msize);
568 if(waserror()){
569 mntfree(r);
570 nexterror();
571 }
572
573 r->request.type = t;
574 r->request.fid = c->fid;
575 mountrpc(m, r);
576 mntfree(r);
577 poperror();
578}
579
580void
581muxclose(Mnt *m)
582{
583 Mntrpc *q, *r;
584
585 for(q = m->queue; q; q = r) {
586 r = q->list;
587 mntfree(q);
588 }
589 m->id = 0;
590 free(m->version);
591 m->version = nil;
592 mntpntfree(m);
593}
594
595void
596mntpntfree(Mnt *m)
597{
598 Mnt *f, **l;
599 Queue *q;
600
601 lock(&mntalloc.lk);
602 l = &mntalloc.list;
603 for(f = *l; f; f = f->list) {
604 if(f == m) {
605 *l = m->list;
606 break;
607 }
608 l = &f->list;
609 }
610 m->list = mntalloc.mntfree;
611 mntalloc.mntfree = m;
612 q = m->q;
613 unlock(&mntalloc.lk);
614
615 qfree(q);
616}
617
618static void
619mntclose(Chan *c)
620{
621 mntclunk(c, Tclunk);
622}
623
624static void
625mntremove(Chan *c)
626{
627 mntclunk(c, Tremove);
628}
629
630static int
631mntwstat(Chan *c, uchar *dp, int n)
632{
633 Mnt *m;
634 Mntrpc *r;
635
636 m = mntchk(c);
637 r = mntralloc(c, m->msize);
638 if(waserror()) {
639 mntfree(r);
640 nexterror();
641 }
642 r->request.type = Twstat;
643 r->request.fid = c->fid;
644 r->request.nstat = n;
645 r->request.stat = dp;
646 mountrpc(m, r);
647 poperror();
648 mntfree(r);
649 return n;
650}
651
652static long
653mntread(Chan *c, void *buf, long n, vlong off)
654{
655 uchar *p, *e;
656 int nc, cache, isdir, dirlen;
657
658 isdir = 0;
659 cache = c->flag & CCACHE;
660 if(c->qid.type & QTDIR) {
661 cache = 0;
662 isdir = 1;
663 }
664
665 p = buf;
666 if(cache) {
667 nc = cread(c, buf, n, off);
668 if(nc > 0) {
669 n -= nc;
670 if(n == 0)
671 return nc;
672 p += nc;
673 off += nc;
674 }
675 n = mntrdwr(Tread, c, p, n, off);
676 cupdate(c, p, n, off);
677 return n + nc;
678 }
679
680 n = mntrdwr(Tread, c, buf, n, off);
681 if(isdir) {
682 for(e = &p[n]; p+BIT16SZ < e; p += dirlen){
683 dirlen = BIT16SZ+GBIT16(p);
684 if(p+dirlen > e)
685 break;
686 validstat(p, dirlen);
687 mntdirfix(p, c);
688 }
689 if(p != e)
690 error(Esbadstat);
691 }
692 return n;
693}
694
695static long
696mntwrite(Chan *c, void *buf, long n, vlong off)
697{
698 return mntrdwr(Twrite, c, buf, n, off);
699}
700
701long
702mntrdwr(int type, Chan *c, void *buf, long n, vlong off)
703{
704 Mnt *m;
705 Mntrpc *r;
706 char *uba;
707 int cache;
708 ulong cnt, nr, nreq;
709
710 m = mntchk(c);
711 uba = buf;
712 cnt = 0;
713 cache = c->flag & CCACHE;
714 if(c->qid.type & QTDIR)
715 cache = 0;
716 for(;;) {
717 r = mntralloc(c, m->msize);
718 if(waserror()) {
719 mntfree(r);
720 nexterror();
721 }
722 r->request.type = type;
723 r->request.fid = c->fid;
724 r->request.offset = off;
725 r->request.data = uba;
726 nr = n;
727 if(nr > m->msize-IOHDRSZ)
728 nr = m->msize-IOHDRSZ;
729 r->request.count = nr;
730 mountrpc(m, r);
731 nreq = r->request.count;
732 nr = r->reply.count;
733 if(nr > nreq)
734 nr = nreq;
735
736 if(type == Tread)
737 r->b = bl2mem((uchar*)uba, r->b, nr);
738 else if(cache)
739 cwrite(c, (uchar*)uba, nr, off);
740
741 poperror();
742 mntfree(r);
743 off += nr;
744 uba += nr;
745 cnt += nr;
746 n -= nr;
747 if(nr != nreq || n == 0)
748 break;
749 }
750 return cnt;
751}
752
753void
754mountrpc(Mnt *m, Mntrpc *r)
755{
756 char *sn, *cn;
757 int t;
758
759 r->reply.tag = 0;
760 r->reply.type = Tmax; /* can't ever be a valid message type */
761
762 mountio(m, r);
763
764 t = r->reply.type;
765 switch(t) {
766 case Rerror:
767 error(r->reply.ename);
768 case Rflush:
769 error(Eintr);
770 default:
771 if(t == r->request.type+1)
772 break;
773 sn = "?";
774 if(m->c->name != nil)
775 sn = m->c->name->s;
776 cn = "?";
777 if(r->c != nil && r->c->name != nil)
778 cn = r->c->name->s;
779 print("mnt: proc %lud: mismatch from %s %s rep 0x%lux tag %d fid %d T%d R%d rp %d\n",
780 up->pid, sn, cn,
781 r, r->request.tag, r->request.fid, r->request.type,
782 r->reply.type, r->reply.tag);
783 error(Emountrpc);
784 }
785}
786
787void
788mountio(Mnt *m, Mntrpc *r)
789{
790 int n;
791
792 while(waserror()) {
793 if(m->rip == up)
794 mntgate(m);
795 if(strcmp(up->errstr, Eintr) != 0){
796 mntflushfree(m, r);
797 nexterror();
798 }
799 r = mntflushalloc(r, m->msize);
800 }
801
802 lock(&m->lk);
803 r->m = m;
804 r->list = m->queue;
805 m->queue = r;
806 unlock(&m->lk);
807
808 /* Transmit a file system rpc */
809 if(m->msize == 0)
810 panic("msize");
811 n = convS2M(&r->request, r->rpc, m->msize);
812 if(n < 0)
813 panic("bad message type in mountio");
814 if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
815 error(Emountrpc);
816 r->stime = fastticks(nil);
817 r->reqlen = n;
818
819 /* Gate readers onto the mount point one at a time */
820 for(;;) {
821 lock(&m->lk);
822 if(m->rip == 0)
823 break;
824 unlock(&m->lk);
825 sleep(&r->r, rpcattn, r);
826 if(r->done){
827 poperror();
828 mntflushfree(m, r);
829 return;
830 }
831 }
832 m->rip = up;
833 unlock(&m->lk);
834 while(r->done == 0) {
835 if(mntrpcread(m, r) < 0)
836 error(Emountrpc);
837 mountmux(m, r);
838 }
839 mntgate(m);
840 poperror();
841 mntflushfree(m, r);
842}
843
844static int
845doread(Mnt *m, int len)
846{
847 Block *b;
848
849 while(qlen(m->q) < len){
850 b = devtab[m->c->type]->bread(m->c, m->msize, 0);
851 if(b == nil)
852 return -1;
853 if(BLEN(b) == 0){
854 freeblist(b);
855 return -1;
856 }
857 qaddlist(m->q, b);
858 }
859 return 0;
860}
861
862int
863mntrpcread(Mnt *m, Mntrpc *r)
864{
865 int i, t, len, hlen;
866 Block *b, **l, *nb;
867
868 r->reply.type = 0;
869 r->reply.tag = 0;
870
871 /* read at least length, type, and tag and pullup to a single block */
872 if(doread(m, BIT32SZ+BIT8SZ+BIT16SZ) < 0)
873 return -1;
874 nb = pullupqueue(m->q, BIT32SZ+BIT8SZ+BIT16SZ);
875
876 /* read in the rest of the message, avoid rediculous (for now) message sizes */
877 len = GBIT32(nb->rp);
878 if(len > m->msize){
879 qdiscard(m->q, qlen(m->q));
880 return -1;
881 }
882 if(doread(m, len) < 0)
883 return -1;
884
885 /* pullup the header (i.e. everything except data) */
886 t = nb->rp[BIT32SZ];
887 switch(t){
888 case Rread:
889 hlen = BIT32SZ+BIT8SZ+BIT16SZ+BIT32SZ;
890 break;
891 default:
892 hlen = len;
893 break;
894 }
895 nb = pullupqueue(m->q, hlen);
896
897 if(convM2S(nb->rp, len, &r->reply) <= 0){
898 /* bad message, dump it */
899 print("mntrpcread: convM2S failed\n");
900 qdiscard(m->q, len);
901 return -1;
902 }
903
904 /* hang the data off of the fcall struct */
905 l = &r->b;
906 *l = nil;
907 do {
908 b = qremove(m->q);
909 if(hlen > 0){
910 b->rp += hlen;
911 len -= hlen;
912 hlen = 0;
913 }
914 i = BLEN(b);
915 if(i <= len){
916 len -= i;
917 *l = b;
918 l = &(b->next);
919 } else {
920 /* split block and put unused bit back */
921 nb = allocb(i-len);
922 memmove(nb->wp, b->rp+len, i-len);
923 b->wp = b->rp+len;
924 nb->wp += i-len;
925 qputback(m->q, nb);
926 *l = b;
927 return 0;
928 }
929 }while(len > 0);
930
931 return 0;
932}
933
934void
935mntgate(Mnt *m)
936{
937 Mntrpc *q;
938
939 lock(&m->lk);
940 m->rip = 0;
941 for(q = m->queue; q; q = q->list) {
942 if(q->done == 0)
943 if(wakeup(&q->r))
944 break;
945 }
946 unlock(&m->lk);
947}
948
949void
950mountmux(Mnt *m, Mntrpc *r)
951{
952 Mntrpc **l, *q;
953
954 lock(&m->lk);
955 l = &m->queue;
956 for(q = *l; q; q = q->list) {
957 /* look for a reply to a message */
958 if(q->request.tag == r->reply.tag) {
959 *l = q->list;
960 if(q != r) {
961 /*
962 * Completed someone else.
963 * Trade pointers to receive buffer.
964 */
965 q->reply = r->reply;
966 q->b = r->b;
967 r->b = nil;
968 }
969 q->done = 1;
970 unlock(&m->lk);
971 if(mntstats != nil)
972 (*mntstats)(q->request.type,
973 m->c, q->stime,
974 q->reqlen + r->replen);
975 if(q != r)
976 wakeup(&q->r);
977 return;
978 }
979 l = &q->list;
980 }
981 unlock(&m->lk);
982 print("unexpected reply tag %ud; type %d\n", r->reply.tag, r->reply.type);
983}
984
985/*
986 * Create a new flush request and chain the previous
987 * requests from it
988 */
989Mntrpc*
990mntflushalloc(Mntrpc *r, ulong iounit)
991{
992 Mntrpc *fr;
993
994 fr = mntralloc(0, iounit);
995
996 fr->request.type = Tflush;
997 if(r->request.type == Tflush)
998 fr->request.oldtag = r->request.oldtag;
999 else
1000 fr->request.oldtag = r->request.tag;
1001 fr->flushed = r;
1002
1003 return fr;
1004}
1005
1006/*
1007 * Free a chain of flushes. Remove each unanswered
1008 * flush and the original message from the unanswered
1009 * request queue. Mark the original message as done
1010 * and if it hasn't been answered set the reply to to
1011 * Rflush.
1012 */
1013void
1014mntflushfree(Mnt *m, Mntrpc *r)
1015{
1016 Mntrpc *fr;
1017
1018 while(r){
1019 fr = r->flushed;
1020 if(!r->done){
1021 r->reply.type = Rflush;
1022 mntqrm(m, r);
1023 }
1024 if(fr)
1025 mntfree(r);
1026 r = fr;
1027 }
1028}
1029
1030int
1031alloctag(void)
1032{
1033 int i, j;
1034 ulong v;
1035
1036 for(i = 0; i < NMASK; i++){
1037 v = mntalloc.tagmask[i];
1038 if(v == ~0UL)
1039 continue;
1040 for(j = 0; j < 1<<TAGSHIFT; j++)
1041 if((v & (1<<j)) == 0){
1042 mntalloc.tagmask[i] |= 1<<j;
1043 return (i<<TAGSHIFT) + j;
1044 }
1045 }
1046 panic("no friggin tags left");
1047 return NOTAG;
1048}
1049
1050void
1051freetag(int t)
1052{
1053 mntalloc.tagmask[t>>TAGSHIFT] &= ~(1<<(t&TAGMASK));
1054}
1055
1056Mntrpc*
1057mntralloc(Chan *c, ulong msize)
1058{
1059 Mntrpc *new;
1060
1061 lock(&mntalloc.lk);
1062 new = mntalloc.rpcfree;
1063 if(new == nil){
1064 new = malloc(sizeof(Mntrpc));
1065 if(new == nil) {
1066 unlock(&mntalloc.lk);
1067 exhausted("mount rpc header");
1068 }
1069 /*
1070 * The header is split from the data buffer as
1071 * mountmux may swap the buffer with another header.
1072 */
1073 new->rpc = mallocz(msize, 0);
1074 if(new->rpc == nil){
1075 free(new);
1076 unlock(&mntalloc.lk);
1077 exhausted("mount rpc buffer");
1078 }
1079 new->rpclen = msize;
1080 new->request.tag = alloctag();
1081 }
1082 else {
1083 mntalloc.rpcfree = new->list;
1084 mntalloc.nrpcfree--;
1085 if(new->rpclen < msize){
1086 free(new->rpc);
1087 new->rpc = mallocz(msize, 0);
1088 if(new->rpc == nil){
1089 free(new);
1090 mntalloc.nrpcused--;
1091 unlock(&mntalloc.lk);
1092 exhausted("mount rpc buffer");
1093 }
1094 new->rpclen = msize;
1095 }
1096 }
1097 mntalloc.nrpcused++;
1098 unlock(&mntalloc.lk);
1099 new->c = c;
1100 new->done = 0;
1101 new->flushed = nil;
1102 new->b = nil;
1103 return new;
1104}
1105
1106void
1107mntfree(Mntrpc *r)
1108{
1109 if(r->b != nil)
1110 freeblist(r->b);
1111 lock(&mntalloc.lk);
1112 if(mntalloc.nrpcfree >= 10){
1113 free(r->rpc);
1114 free(r);
1115 freetag(r->request.tag);
1116 }
1117 else{
1118 r->list = mntalloc.rpcfree;
1119 mntalloc.rpcfree = r;
1120 mntalloc.nrpcfree++;
1121 }
1122 mntalloc.nrpcused--;
1123 unlock(&mntalloc.lk);
1124}
1125
1126void
1127mntqrm(Mnt *m, Mntrpc *r)
1128{
1129 Mntrpc **l, *f;
1130
1131 lock(&m->lk);
1132 r->done = 1;
1133
1134 l = &m->queue;
1135 for(f = *l; f; f = f->list) {
1136 if(f == r) {
1137 *l = r->list;
1138 break;
1139 }
1140 l = &f->list;
1141 }
1142 unlock(&m->lk);
1143}
1144
1145Mnt*
1146mntchk(Chan *c)
1147{
1148 Mnt *m;
1149
1150 /* This routine is mostly vestiges of prior lives; now it's just sanity checking */
1151
1152 if(c->mchan == nil)
1153 panic("mntchk 1: nil mchan c %s\n", c2name(c));
1154
1155 m = c->mchan->mux;
1156
1157 if(m == nil)
1158 print("mntchk 2: nil mux c %s c->mchan %s \n", c2name(c), c2name(c->mchan));
1159
1160 /*
1161 * Was it closed and reused (was error(Eshutdown); now, it can't happen)
1162 */
1163 if(m->id == 0 || m->id >= c->dev)
1164 panic("mntchk 3: can't happen");
1165
1166 return m;
1167}
1168
1169/*
1170 * Rewrite channel type and dev for in-flight data to
1171 * reflect local values. These entries are known to be
1172 * the first two in the Dir encoding after the count.
1173 */
1174void
1175mntdirfix(uchar *dirbuf, Chan *c)
1176{
1177 uint r;
1178
1179 r = devtab[c->type]->dc;
1180 dirbuf += BIT16SZ; /* skip count */
1181 PBIT16(dirbuf, r);
1182 dirbuf += BIT16SZ;
1183 PBIT32(dirbuf, c->dev);
1184}
1185
1186int
1187rpcattn(void *v)
1188{
1189 Mntrpc *r;
1190
1191 r = v;
1192 return r->done || r->m->rip == 0;
1193}
1194
1195Dev mntdevtab = {
1196 'M',
1197 "mnt",
1198
1199 mntreset,
1200 devinit,
1201 devshutdown,
1202 mntattach,
1203 mntwalk,
1204 mntstat,
1205 mntopen,
1206 mntcreate,
1207 mntclose,
1208 mntread,
1209 devbread,
1210 mntwrite,
1211 devbwrite,
1212 mntremove,
1213 mntwstat,
1214};
kern/devmouse.c+237−0
@@ -0,0 +1,237 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7#include "draw.h"
8#include "memdraw.h"
9#include "screen.h"
10
11int mousequeue;
12
13Mouseinfo mouse;
14Cursorinfo cursor;
15
16static int mousechanged(void*);
17
18enum{
19 Qdir,
20 Qcursor,
21 Qmouse
22};
23
24Dirtab mousedir[]={
25 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
26 "cursor", {Qcursor}, 0, 0666,
27 "mouse", {Qmouse}, 0, 0666,
28};
29
30#define NMOUSE (sizeof(mousedir)/sizeof(Dirtab))
31
32static Chan*
33mouseattach(char *spec)
34{
35 return devattach('m', spec);
36}
37
38static Walkqid*
39mousewalk(Chan *c, Chan *nc, char **name, int nname)
40{
41 return devwalk(c, nc, name, nname, mousedir, NMOUSE, devgen);
42}
43
44static int
45mousestat(Chan *c, uchar *db, int n)
46{
47 return devstat(c, db, n, mousedir, NMOUSE, devgen);
48}
49
50static Chan*
51mouseopen(Chan *c, int omode)
52{
53 switch((long)c->qid.path){
54 case Qdir:
55 if(omode != OREAD)
56 error(Eperm);
57 break;
58 case Qmouse:
59 lock(&mouse.lk);
60 if(mouse.open){
61 unlock(&mouse.lk);
62 error(Einuse);
63 }
64 mouse.open = 1;
65 unlock(&mouse.lk);
66 break;
67 }
68 c->mode = openmode(omode);
69 c->flag |= COPEN;
70 c->offset = 0;
71 return c;
72}
73
74void
75mouseclose(Chan *c)
76{
77 if(!(c->flag&COPEN))
78 return;
79
80 switch((long)c->qid.path) {
81 case Qmouse:
82 lock(&mouse.lk);
83 mouse.open = 0;
84 unlock(&mouse.lk);
85 cursorarrow();
86 }
87}
88
89
90long
91mouseread(Chan *c, void *va, long n, vlong offset)
92{
93 char buf[4*12+1];
94 uchar *p;
95 int i, nn;
96 ulong msec;
97/* static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; */
98
99 p = va;
100 switch((long)c->qid.path){
101 case Qdir:
102 return devdirread(c, va, n, mousedir, NMOUSE, devgen);
103
104 case Qcursor:
105 if(offset != 0)
106 return 0;
107 if(n < 2*4+2*2*16)
108 error(Eshort);
109 n = 2*4+2*2*16;
110 lock(&cursor.lk);
111 BPLONG(p+0, cursor.offset.x);
112 BPLONG(p+4, cursor.offset.y);
113 memmove(p+8, cursor.clr, 2*16);
114 memmove(p+40, cursor.set, 2*16);
115 unlock(&cursor.lk);
116 return n;
117
118 case Qmouse:
119 while(mousechanged(0) == 0)
120 sleep(&mouse.r, mousechanged, 0);
121
122 lock(&screen.lk);
123 if(screen.reshaped) {
124 screen.reshaped = 0;
125 sprint(buf, "t%11d %11d", 0, ticks());
126 if(n > 1+2*12)
127 n = 1+2*12;
128 memmove(va, buf, n);
129 unlock(&screen.lk);
130 return n;
131 }
132 unlock(&screen.lk);
133
134 lock(&mouse.lk);
135 i = mouse.ri;
136 nn = (mouse.wi + Mousequeue - i) % Mousequeue;
137 if(nn < 1)
138 panic("empty mouse queue");
139 msec = ticks();
140 while(nn > 1) {
141 if(mouse.queue[i].msec + Mousewindow > msec)
142 break;
143 i = (i+1)%Mousequeue;
144 nn--;
145 }
146 sprint(buf, "m%11d %11d %11d %11d",
147 mouse.queue[i].xy.x,
148 mouse.queue[i].xy.y,
149 mouse.queue[i].buttons,
150 mouse.queue[i].msec);
151 mouse.ri = (i+1)%Mousequeue;
152 unlock(&mouse.lk);
153 if(n > 1+4*12)
154 n = 1+4*12;
155 memmove(va, buf, n);
156 return n;
157 }
158 return 0;
159}
160
161long
162mousewrite(Chan *c, void *va, long n, vlong offset)
163{
164 char *p;
165 Point pt;
166 char buf[64];
167
168 USED(offset);
169
170 p = va;
171 switch((long)c->qid.path){
172 case Qdir:
173 error(Eisdir);
174
175 case Qcursor:
176 if(n < 2*4+2*2*16){
177 cursorarrow();
178 }else{
179 n = 2*4+2*2*16;
180 lock(&cursor.lk);
181 cursor.offset.x = BGLONG(p+0);
182 cursor.offset.y = BGLONG(p+4);
183 memmove(cursor.clr, p+8, 2*16);
184 memmove(cursor.set, p+40, 2*16);
185 unlock(&cursor.lk);
186 setcursor();
187 }
188 return n;
189
190 case Qmouse:
191 if(n > sizeof buf-1)
192 n = sizeof buf -1;
193 memmove(buf, va, n);
194 buf[n] = 0;
195 p = 0;
196 pt.x = strtoul(buf+1, &p, 0);
197 if(p == 0)
198 error(Eshort);
199 pt.y = strtoul(p, 0, 0);
200 if(ptinrect(pt, gscreen->r))
201 mouseset(pt);
202 return n;
203 }
204
205 error(Egreg);
206 return -1;
207}
208
209int
210mousechanged(void *a)
211{
212 USED(a);
213
214 return mouse.ri != mouse.wi || screen.reshaped;
215}
216
217Dev mousedevtab = {
218 'm',
219 "mouse",
220
221 devreset,
222 devinit,
223 devshutdown,
224 mouseattach,
225 mousewalk,
226 mousestat,
227 mouseopen,
228 devcreate,
229 mouseclose,
230 mouseread,
231 devbread,
232 mousewrite,
233 devbwrite,
234 devremove,
235 devwstat,
236};
237
kern/devntfs.c+704−0
@@ -0,0 +1,704 @@
1#include <windows.h>
2#include <sys/types.h>
3#include <sys/stat.h>
4#include <fcntl.h>
5
6#ifndef NAME_MAX
7# define NAME_MAX 256
8#endif
9#include "u.h"
10#include "lib.h"
11#include "dat.h"
12#include "fns.h"
13#include "error.h"
14
15typedef struct DIR DIR;
16typedef struct Ufsinfo Ufsinfo;
17
18enum
19{
20 NUID = 256,
21 NGID = 256,
22 MAXPATH = 1024,
23 MAXCOMP = 128
24};
25
26struct DIR
27{
28 HANDLE handle;
29 char* path;
30 int index;
31 WIN32_FIND_DATA wfd;
32};
33
34struct Ufsinfo
35{
36 int mode;
37 int fd;
38 int uid;
39 int gid;
40 DIR* dir;
41 ulong offset;
42 QLock oq;
43 char nextname[NAME_MAX];
44};
45
46DIR* opendir(char*);
47int readdir(char*, DIR*);
48void closedir(DIR*);
49void rewinddir(DIR*);
50
51char *base = "c:/.";
52
53static Qid fsqid(char*, struct stat *);
54static void fspath(Chan*, char*, char*);
55// static void fsperm(Chan*, int);
56static ulong fsdirread(Chan*, uchar*, int, ulong);
57static int fsomode(int);
58static int chown(char *path, int uid, int);
59static int link(char *path, char *next);
60
61/* clumsy hack, but not worse than the Path stuff in the last one */
62static char*
63uc2name(Chan *c)
64{
65 char *s;
66
67 if(c->name == nil)
68 return "/";
69 s = c2name(c);
70 if(s[0]=='#' && s[1]=='U')
71 return s+2;
72 return s;
73}
74
75static char*
76lastelem(Chan *c)
77{
78 char *s, *t;
79
80 s = uc2name(c);
81 if((t = strrchr(s, '/')) == nil)
82 return s;
83 if(t[1] == 0)
84 return t;
85 return t+1;
86}
87
88static Chan*
89fsattach(void *spec)
90{
91 Chan *c;
92 struct stat stbuf;
93 static int devno;
94 Ufsinfo *uif;
95
96 if(stat(base, &stbuf) < 0)
97 error(strerror(errno));
98
99 c = devattach('U', spec);
100
101 uif = mallocz(sizeof(Ufsinfo), 1);
102 uif->gid = stbuf.st_gid;
103 uif->uid = stbuf.st_uid;
104 uif->mode = stbuf.st_mode;
105
106 c->aux = uif;
107 c->dev = devno++;
108 c->qid.type = QTDIR;
109/*print("fsattach %s\n", c2name(c));*/
110
111 return c;
112}
113
114static Chan*
115fsclone(Chan *c, Chan *nc)
116{
117 Ufsinfo *uif;
118
119 uif = mallocz(sizeof(Ufsinfo), 1);
120 *uif = *(Ufsinfo*)c->aux;
121 nc->aux = uif;
122
123 return nc;
124}
125
126static int
127fswalk1(Chan *c, char *name)
128{
129 struct stat stbuf;
130 char path[MAXPATH];
131 Ufsinfo *uif;
132
133 fspath(c, name, path);
134
135 /* print("** fs walk '%s' -> %s\n", path, name); /**/
136
137 if(stat(path, &stbuf) < 0)
138 return 0;
139
140 uif = c->aux;
141
142 uif->gid = stbuf.st_gid;
143 uif->uid = stbuf.st_uid;
144 uif->mode = stbuf.st_mode;
145
146 c->qid = fsqid(path, &stbuf);
147
148 return 1;
149}
150
151extern Cname* addelem(Cname*, char*);
152
153static Walkqid*
154fswalk(Chan *c, Chan *nc, char **name, int nname)
155{
156 int i;
157 Cname *cname;
158 Walkqid *wq;
159
160 if(nc != nil)
161 panic("fswalk: nc != nil");
162 wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
163 nc = devclone(c);
164 cname = c->name;
165 incref(&cname->ref);
166
167 fsclone(c, nc);
168 wq->clone = nc;
169 for(i=0; i<nname; i++){
170 nc->name = cname;
171 if(fswalk1(nc, name[i]) == 0)
172 break;
173 cname = addelem(cname, name[i]);
174 wq->qid[i] = nc->qid;
175 }
176 nc->name = nil;
177 cnameclose(cname);
178 if(i != nname){
179 cclose(nc);
180 wq->clone = nil;
181 }
182 wq->nqid = i;
183 return wq;
184}
185
186static int
187fsstat(Chan *c, uchar *buf, int n)
188{
189 Dir d;
190 struct stat stbuf;
191 char path[MAXPATH];
192
193 if(n < BIT16SZ)
194 error(Eshortstat);
195
196 fspath(c, 0, path);
197 if(stat(path, &stbuf) < 0)
198 error(strerror(errno));
199
200 d.name = lastelem(c);
201 d.uid = "unknown";
202 d.gid = "unknown";
203 d.muid = "unknown";
204 d.qid = c->qid;
205 d.mode = (c->qid.type<<24)|(stbuf.st_mode&0777);
206 d.atime = stbuf.st_atime;
207 d.mtime = stbuf.st_mtime;
208 d.length = stbuf.st_size;
209 d.type = 'U';
210 d.dev = c->dev;
211 return convD2M(&d, buf, n);
212}
213
214static Chan*
215fsopen(Chan *c, int mode)
216{
217 char path[MAXPATH];
218 int m, isdir;
219 Ufsinfo *uif;
220
221/*print("fsopen %s\n", c2name(c));*/
222 m = mode & (OTRUNC|3);
223 switch(m) {
224 case 0:
225 break;
226 case 1:
227 case 1|16:
228 break;
229 case 2:
230 case 0|16:
231 case 2|16:
232 break;
233 case 3:
234 break;
235 default:
236 error(Ebadarg);
237 }
238
239 isdir = c->qid.type & QTDIR;
240
241 if(isdir && mode != OREAD)
242 error(Eperm);
243
244 m = fsomode(m & 3);
245 c->mode = openmode(mode);
246
247 uif = c->aux;
248
249 fspath(c, 0, path);
250 if(isdir) {
251 uif->dir = opendir(path);
252 if(uif->dir == 0)
253 error(strerror(errno));
254 }
255 else {
256 if(mode & OTRUNC)
257 m |= O_TRUNC;
258 uif->fd = open(path, m|_O_BINARY, 0666);
259
260 if(uif->fd < 0)
261 error(strerror(errno));
262 }
263 uif->offset = 0;
264
265 c->offset = 0;
266 c->flag |= COPEN;
267 return c;
268}
269
270static void
271fscreate(Chan *c, char *name, int mode, ulong perm)
272{
273 int fd, m;
274 char path[MAXPATH];
275 struct stat stbuf;
276 Ufsinfo *uif;
277
278 m = fsomode(mode&3);
279
280 fspath(c, name, path);
281
282 uif = c->aux;
283
284 if(perm & DMDIR) {
285 if(m)
286 error(Eperm);
287
288 if(mkdir(path) < 0)
289 error(strerror(errno));
290
291 fd = open(path, 0);
292 if(fd >= 0) {
293 chmod(path, perm & 0777);
294 chown(path, uif->uid, uif->uid);
295 }
296 close(fd);
297
298 uif->dir = opendir(path);
299 if(uif->dir == 0)
300 error(strerror(errno));
301 }
302 else {
303 fd = open(path, _O_WRONLY|_O_BINARY|_O_CREAT|_O_TRUNC, 0666);
304 if(fd >= 0) {
305 if(m != 1) {
306 close(fd);
307 fd = open(path, m|_O_BINARY);
308 }
309 chmod(path, perm & 0777);
310 chown(path, uif->uid, uif->gid);
311 }
312 if(fd < 0)
313 error(strerror(errno));
314 uif->fd = fd;
315 }
316
317 if(stat(path, &stbuf) < 0)
318 error(strerror(errno));
319 c->qid = fsqid(path, &stbuf);
320 c->offset = 0;
321 c->flag |= COPEN;
322 c->mode = openmode(mode);
323}
324
325static void
326fsclose(Chan *c)
327{
328 Ufsinfo *uif;
329
330 uif = c->aux;
331
332 if(c->flag & COPEN) {
333 if(c->qid.type & QTDIR)
334 closedir(uif->dir);
335 else
336 close(uif->fd);
337 }
338
339 free(uif);
340}
341
342static long
343fsread(Chan *c, void *va, long n, ulong offset)
344{
345 int fd, r;
346 Ufsinfo *uif;
347
348/*print("fsread %s\n", c2name(c));*/
349 if(c->qid.type & QTDIR)
350 return fsdirread(c, va, n, offset);
351
352 uif = c->aux;
353 qlock(&uif->oq);
354 if(waserror()) {
355 qunlock(&uif->oq);
356 nexterror();
357 }
358 fd = uif->fd;
359 if(uif->offset != offset) {
360 r = lseek(fd, offset, 0);
361 if(r < 0)
362 error(strerror(errno));
363 uif->offset = offset;
364 }
365
366 n = read(fd, va, n);
367 if(n < 0)
368 error(strerror(errno));
369
370 uif->offset += n;
371 qunlock(&uif->oq);
372 poperror();
373
374 return n;
375}
376
377static long
378fswrite(Chan *c, void *va, long n, ulong offset)
379{
380 int fd, r;
381 Ufsinfo *uif;
382
383 uif = c->aux;
384
385 qlock(&uif->oq);
386 if(waserror()) {
387 qunlock(&uif->oq);
388 nexterror();
389 }
390 fd = uif->fd;
391 if(uif->offset != offset) {
392 r = lseek(fd, offset, 0);
393 if(r < 0)
394 error(strerror(errno));
395 uif->offset = offset;
396 }
397
398 n = write(fd, va, n);
399 if(n < 0)
400 error(strerror(errno));
401
402 uif->offset += n;
403 qunlock(&uif->oq);
404 poperror();
405
406 return n;
407}
408
409static void
410fsremove(Chan *c)
411{
412 int n;
413 char path[MAXPATH];
414
415 fspath(c, 0, path);
416 if(c->qid.type & QTDIR)
417 n = rmdir(path);
418 else
419 n = remove(path);
420 if(n < 0)
421 error(strerror(errno));
422}
423
424static int
425fswstat(Chan *c, uchar *buf, int n)
426{
427 Dir d;
428 struct stat stbuf;
429 char old[MAXPATH], new[MAXPATH];
430 char strs[MAXPATH*3], *p;
431 Ufsinfo *uif;
432
433 if (convM2D(buf, n, &d, strs) != n)
434 error(Ebadstat);
435
436 fspath(c, 0, old);
437 if(stat(old, &stbuf) < 0)
438 error(strerror(errno));
439
440 uif = c->aux;
441
442// if(uif->uid != stbuf.st_uid)
443// error(Eowner);
444
445 if(d.name[0] && strcmp(d.name, lastelem(c)) != 0) {
446 fspath(c, 0, old);
447 strcpy(new, old);
448 p = strrchr(new, '/');
449 strcpy(p+1, d.name);
450 if(rename(old, new) < 0)
451 error(strerror(errno));
452 }
453
454 fspath(c, 0, old);
455 if(~d.mode != 0 && (int)(d.mode&0777) != (int)(stbuf.st_mode&0777)) {
456 if(chmod(old, d.mode&0777) < 0)
457 error(strerror(errno));
458 uif->mode &= ~0777;
459 uif->mode |= d.mode&0777;
460 }
461/*
462 p = name2pass(gid, d.gid);
463 if(p == 0)
464 error(Eunknown);
465
466 if(p->id != stbuf.st_gid) {
467 if(chown(old, stbuf.st_uid, p->id) < 0)
468 error(sys_errlist[errno]);
469
470 uif->gid = p->id;
471 }
472*/
473 return n;
474}
475
476static Qid
477fsqid(char *p, struct stat *st)
478{
479 Qid q;
480 int dev;
481 ulong h;
482 static int nqdev;
483 static uchar *qdev;
484
485 if(qdev == 0)
486 qdev = mallocz(65536U, 1);
487
488 q.type = 0;
489 if((st->st_mode&S_IFMT) == S_IFDIR)
490 q.type = QTDIR;
491
492 dev = st->st_dev & 0xFFFFUL;
493 if(qdev[dev] == 0)
494 qdev[dev] = ++nqdev;
495
496 h = 0;
497 while(*p != '\0')
498 h += *p++ * 13;
499
500 q.path = (vlong)qdev[dev]<<32;
501 q.path |= h;
502 q.vers = st->st_mtime;
503
504 return q;
505}
506
507static void
508fspath(Chan *c, char *ext, char *path)
509{
510 strcpy(path, base);
511 strcat(path, "/");
512 strcat(path, uc2name(c));
513 if(ext) {
514 strcat(path, "/");
515 strcat(path, ext);
516 }
517 cleanname(path);
518}
519
520static int
521isdots(char *name)
522{
523 if(name[0] != '.')
524 return 0;
525 if(name[1] == '\0')
526 return 1;
527 if(name[1] != '.')
528 return 0;
529 if(name[2] == '\0')
530 return 1;
531 return 0;
532}
533
534static int
535p9readdir(char *name, Ufsinfo *uif)
536{
537 if(uif->nextname[0]){
538 strcpy(name, uif->nextname);
539 uif->nextname[0] = 0;
540 return 1;
541 }
542
543 return readdir(name, uif->dir);
544}
545
546static ulong
547fsdirread(Chan *c, uchar *va, int count, ulong offset)
548{
549 int i;
550 Dir d;
551 long n;
552 char de[NAME_MAX];
553 struct stat stbuf;
554 char path[MAXPATH], dirpath[MAXPATH];
555 Ufsinfo *uif;
556
557/*print("fsdirread %s\n", c2name(c));*/
558 i = 0;
559 uif = c->aux;
560
561 errno = 0;
562 if(uif->offset != offset) {
563 if(offset != 0)
564 error("bad offset in fsdirread");
565 uif->offset = offset; /* sync offset */
566 uif->nextname[0] = 0;
567 rewinddir(uif->dir);
568 }
569
570 fspath(c, 0, dirpath);
571
572 while(i+BIT16SZ < count) {
573 if(!p9readdir(de, uif))
574 break;
575
576 if(de[0]==0 || isdots(de))
577 continue;
578
579 d.name = de;
580 sprint(path, "%s/%s", dirpath, de);
581 memset(&stbuf, 0, sizeof stbuf);
582
583 if(stat(path, &stbuf) < 0) {
584 print("dir: bad path %s\n", path);
585 /* but continue... probably a bad symlink */
586 }
587
588 d.uid = "unknown";
589 d.gid = "unknown";
590 d.muid = "unknown";
591 d.qid = fsqid(path, &stbuf);
592 d.mode = (d.qid.type<<24)|(stbuf.st_mode&0777);
593 d.atime = stbuf.st_atime;
594 d.mtime = stbuf.st_mtime;
595 d.length = stbuf.st_size;
596 d.type = 'U';
597 d.dev = c->dev;
598 n = convD2M(&d, (char*)va+i, count-i);
599 if(n == BIT16SZ){
600 strcpy(uif->nextname, de);
601 break;
602 }
603 i += n;
604 }
605/*print("got %d\n", i);*/
606 uif->offset += i;
607 return i;
608}
609
610static int
611fsomode(int m)
612{
613 switch(m) {
614 case 0: /* OREAD */
615 case 3: /* OEXEC */
616 return 0;
617 case 1: /* OWRITE */
618 return 1;
619 case 2: /* ORDWR */
620 return 2;
621 }
622 error(Ebadarg);
623 return 0;
624}
625void
626closedir(DIR *d)
627{
628 FindClose(d->handle);
629 free(d->path);
630}
631
632int
633readdir(char *name, DIR *d)
634{
635 if(d->index != 0) {
636 if(FindNextFile(d->handle, &d->wfd) == FALSE)
637 return 0;
638 }
639 strcpy(name, d->wfd.cFileName);
640 d->index++;
641
642 return 1;
643}
644
645void
646rewinddir(DIR *d)
647{
648 FindClose(d->handle);
649 d->handle = FindFirstFile(d->path, &d->wfd);
650 d->index = 0;
651}
652
653static int
654chown(char *path, int uid, int perm)
655{
656/* panic("chown"); */
657 return 0;
658}
659
660DIR*
661opendir(char *p)
662{
663 DIR *d;
664 char path[MAX_PATH];
665
666
667 snprint(path, sizeof(path), "%s/*.*", p);
668
669 d = mallocz(sizeof(DIR), 1);
670 if(d == 0)
671 return 0;
672
673 d->index = 0;
674
675 d->handle = FindFirstFile(path, &d->wfd);
676 if(d->handle == INVALID_HANDLE_VALUE) {
677 free(d);
678 return 0;
679 }
680
681 d->path = strdup(path);
682 return d;
683}
684
685Dev fsdevtab = {
686 'U',
687 "fs",
688
689 devreset,
690 devinit,
691 devshutdown,
692 fsattach,
693 fswalk,
694 fsstat,
695 fsopen,
696 fscreate,
697 fsclose,
698 fsread,
699 devbread,
700 fswrite,
701 devbwrite,
702 fsremove,
703 fswstat,
704};
kern/devpipe.c+398−0
@@ -0,0 +1,398 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7#include "netif.h"
8
9typedef struct Pipe Pipe;
10struct Pipe
11{
12 QLock lk;
13 Pipe *next;
14 int ref;
15 ulong path;
16 Queue *q[2];
17 int qref[2];
18};
19
20struct
21{
22 Lock lk;
23 ulong path;
24} pipealloc;
25
26enum
27{
28 Qdir,
29 Qdata0,
30 Qdata1,
31};
32
33Dirtab pipedir[] =
34{
35 ".", {Qdir,0,QTDIR}, 0, DMDIR|0500,
36 "data", {Qdata0}, 0, 0600,
37 "data1", {Qdata1}, 0, 0600,
38};
39#define NPIPEDIR 3
40
41static void
42pipeinit(void)
43{
44 if(conf.pipeqsize == 0){
45 if(conf.nmach > 1)
46 conf.pipeqsize = 256*1024;
47 else
48 conf.pipeqsize = 32*1024;
49 }
50}
51
52/*
53 * create a pipe, no streams are created until an open
54 */
55static Chan*
56pipeattach(char *spec)
57{
58 Pipe *p;
59 Chan *c;
60
61 c = devattach('|', spec);
62 p = malloc(sizeof(Pipe));
63 if(p == 0)
64 exhausted("memory");
65 p->ref = 1;
66
67 p->q[0] = qopen(conf.pipeqsize, 0, 0, 0);
68 if(p->q[0] == 0){
69 free(p);
70 exhausted("memory");
71 }
72 p->q[1] = qopen(conf.pipeqsize, 0, 0, 0);
73 if(p->q[1] == 0){
74 free(p->q[0]);
75 free(p);
76 exhausted("memory");
77 }
78
79 lock(&pipealloc.lk);
80 p->path = ++pipealloc.path;
81 unlock(&pipealloc.lk);
82
83 mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
84 c->aux = p;
85 c->dev = 0;
86 return c;
87}
88
89static int
90pipegen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
91{
92 Qid q;
93 int len;
94 Pipe *p;
95
96 USED(name);
97
98 if(i == DEVDOTDOT){
99 devdir(c, c->qid, "#|", 0, eve, DMDIR|0555, dp);
100 return 1;
101 }
102 i++; /* skip . */
103 if(tab==0 || i>=ntab)
104 return -1;
105
106 tab += i;
107 p = c->aux;
108 switch((ulong)tab->qid.path){
109 case Qdata0:
110 len = qlen(p->q[0]);
111 break;
112 case Qdata1:
113 len = qlen(p->q[1]);
114 break;
115 default:
116 len = tab->length;
117 break;
118 }
119 mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
120 devdir(c, q, tab->name, len, eve, tab->perm, dp);
121 return 1;
122}
123
124
125static Walkqid*
126pipewalk(Chan *c, Chan *nc, char **name, int nname)
127{
128 Walkqid *wq;
129 Pipe *p;
130
131 wq = devwalk(c, nc, name, nname, pipedir, NPIPEDIR, pipegen);
132 if(wq != nil && wq->clone != nil && wq->clone != c){
133 p = c->aux;
134 qlock(&p->lk);
135 p->ref++;
136 if(c->flag & COPEN){
137 print("channel open in pipewalk\n");
138 switch(NETTYPE(c->qid.path)){
139 case Qdata0:
140 p->qref[0]++;
141 break;
142 case Qdata1:
143 p->qref[1]++;
144 break;
145 }
146 }
147 qunlock(&p->lk);
148 }
149 return wq;
150}
151
152static int
153pipestat(Chan *c, uchar *db, int n)
154{
155 Pipe *p;
156 Dir dir;
157
158 p = c->aux;
159
160 switch(NETTYPE(c->qid.path)){
161 case Qdir:
162 devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
163 break;
164 case Qdata0:
165 devdir(c, c->qid, "data", qlen(p->q[0]), eve, 0600, &dir);
166 break;
167 case Qdata1:
168 devdir(c, c->qid, "data1", qlen(p->q[1]), eve, 0600, &dir);
169 break;
170 default:
171 panic("pipestat");
172 }
173 n = convD2M(&dir, db, n);
174 if(n < BIT16SZ)
175 error(Eshortstat);
176 return n;
177}
178
179/*
180 * if the stream doesn't exist, create it
181 */
182static Chan*
183pipeopen(Chan *c, int omode)
184{
185 Pipe *p;
186
187 if(c->qid.type & QTDIR){
188 if(omode != OREAD)
189 error(Ebadarg);
190 c->mode = omode;
191 c->flag |= COPEN;
192 c->offset = 0;
193 return c;
194 }
195
196 p = c->aux;
197 qlock(&p->lk);
198 switch(NETTYPE(c->qid.path)){
199 case Qdata0:
200 p->qref[0]++;
201 break;
202 case Qdata1:
203 p->qref[1]++;
204 break;
205 }
206 qunlock(&p->lk);
207
208 c->mode = openmode(omode);
209 c->flag |= COPEN;
210 c->offset = 0;
211 c->iounit = qiomaxatomic;
212 return c;
213}
214
215static void
216pipeclose(Chan *c)
217{
218 Pipe *p;
219
220 p = c->aux;
221 qlock(&p->lk);
222
223 if(c->flag & COPEN){
224 /*
225 * closing either side hangs up the stream
226 */
227 switch(NETTYPE(c->qid.path)){
228 case Qdata0:
229 p->qref[0]--;
230 if(p->qref[0] == 0){
231 qhangup(p->q[1], 0);
232 qclose(p->q[0]);
233 }
234 break;
235 case Qdata1:
236 p->qref[1]--;
237 if(p->qref[1] == 0){
238 qhangup(p->q[0], 0);
239 qclose(p->q[1]);
240 }
241 break;
242 }
243 }
244
245
246 /*
247 * if both sides are closed, they are reusable
248 */
249 if(p->qref[0] == 0 && p->qref[1] == 0){
250 qreopen(p->q[0]);
251 qreopen(p->q[1]);
252 }
253
254 /*
255 * free the structure on last close
256 */
257 p->ref--;
258 if(p->ref == 0){
259 qunlock(&p->lk);
260 free(p->q[0]);
261 free(p->q[1]);
262 free(p);
263 } else
264 qunlock(&p->lk);
265}
266
267static long
268piperead(Chan *c, void *va, long n, vlong offset)
269{
270 Pipe *p;
271
272 USED(offset);
273
274 p = c->aux;
275
276 switch(NETTYPE(c->qid.path)){
277 case Qdir:
278 return devdirread(c, va, n, pipedir, NPIPEDIR, pipegen);
279 case Qdata0:
280 return qread(p->q[0], va, n);
281 case Qdata1:
282 return qread(p->q[1], va, n);
283 default:
284 panic("piperead");
285 }
286 return -1; /* not reached */
287}
288
289static Block*
290pipebread(Chan *c, long n, ulong offset)
291{
292 Pipe *p;
293
294 p = c->aux;
295
296 switch(NETTYPE(c->qid.path)){
297 case Qdata0:
298 return qbread(p->q[0], n);
299 case Qdata1:
300 return qbread(p->q[1], n);
301 }
302
303 return devbread(c, n, offset);
304}
305
306/*
307 * a write to a closed pipe causes a note to be sent to
308 * the process.
309 */
310static long
311pipewrite(Chan *c, void *va, long n, vlong offset)
312{
313 Pipe *p;
314
315 USED(offset);
316 if(!islo())
317 print("pipewrite hi %lux\n", getcallerpc(&c));
318
319 if(waserror()) {
320 /* avoid notes when pipe is a mounted queue */
321 if((c->flag & CMSG) == 0)
322 postnote(up, 1, "sys: write on closed pipe", NUser);
323 nexterror();
324 }
325
326 p = c->aux;
327
328 switch(NETTYPE(c->qid.path)){
329 case Qdata0:
330 n = qwrite(p->q[1], va, n);
331 break;
332
333 case Qdata1:
334 n = qwrite(p->q[0], va, n);
335 break;
336
337 default:
338 panic("pipewrite");
339 }
340
341 poperror();
342 return n;
343}
344
345static long
346pipebwrite(Chan *c, Block *bp, ulong offset)
347{
348 long n;
349 Pipe *p;
350
351 USED(offset);
352
353 if(waserror()) {
354 /* avoid notes when pipe is a mounted queue */
355 if((c->flag & CMSG) == 0)
356 postnote(up, 1, "sys: write on closed pipe", NUser);
357 nexterror();
358 }
359
360 p = c->aux;
361 switch(NETTYPE(c->qid.path)){
362 case Qdata0:
363 n = qbwrite(p->q[1], bp);
364 break;
365
366 case Qdata1:
367 n = qbwrite(p->q[0], bp);
368 break;
369
370 default:
371 n = 0;
372 panic("pipebwrite");
373 }
374
375 poperror();
376 return n;
377}
378
379Dev pipedevtab = {
380 '|',
381 "pipe",
382
383 devreset,
384 pipeinit,
385 devshutdown,
386 pipeattach,
387 pipewalk,
388 pipestat,
389 pipeopen,
390 devcreate,
391 pipeclose,
392 piperead,
393 pipebread,
394 pipewrite,
395 pipebwrite,
396 devremove,
397 devwstat,
398};
kern/devroot.c+268−0
@@ -0,0 +1,268 @@
1#include "u.h"
2#include "lib.h"
3#include "dat.h"
4#include "fns.h"
5#include "error.h"
6
7enum
8{
9 Qdir = 0,
10 Qboot = 0x1000,
11
12 Nrootfiles = 32,
13 Nbootfiles = 32,
14};
15
16typedef struct Dirlist Dirlist;
17struct Dirlist
18{
19 uint base;
20 Dirtab *dir;
21 uchar **data;
22 int ndir;
23 int mdir;
24};
25
26static Dirtab rootdir[Nrootfiles] = {
27 "#/", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
28 "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
29};
30static uchar *rootdata[Nrootfiles];
31static Dirlist rootlist =
32{
33 0,
34 rootdir,
35 rootdata,
36 2,
37 Nrootfiles
38};
39
40static Dirtab bootdir[Nbootfiles] = {
41 "boot", {Qboot, 0, QTDIR}, 0, DMDIR|0555,
42};
43static uchar *bootdata[Nbootfiles];
44static Dirlist bootlist =
45{
46 Qboot,
47 bootdir,
48 bootdata,
49 1,
50 Nbootfiles
51};
52
53/*
54 * add a file to the list
55 */
56static void
57addlist(Dirlist *l, char *name, uchar *contents, ulong len, int perm)
58{
59 Dirtab *d;
60
61 if(l->ndir >= l->mdir)
62 panic("too many root files");
63 l->data[l->ndir] = contents;
64 d = &l->dir[l->ndir];
65 strcpy(d->name, name);
66 d->length = len;
67 d->perm = perm;
68 d->qid.type = 0;
69 d->qid.vers = 0;
70 d->qid.path = ++l->ndir + l->base;
71 if(perm & DMDIR)
72 d->qid.type |= QTDIR;
73}
74
75/*
76 * add a root file
77 */
78void
79addbootfile(char *name, uchar *contents, ulong len)
80{
81 addlist(&bootlist, name, contents, len, 0555);
82}
83
84/*
85 * add a root directory
86 */
87static void
88addrootdir(char *name)
89{
90 addlist(&rootlist, name, nil, 0, DMDIR|0555);
91}
92
93static void
94rootreset(void)
95{
96 addrootdir("bin");
97 addrootdir("dev");
98 addrootdir("env");
99 addrootdir("fd");
100 addrootdir("mnt");
101 addrootdir("net");
102 addrootdir("net.alt");
103 addrootdir("proc");
104 addrootdir("root");
105 addrootdir("srv");
106}
107
108static Chan*
109rootattach(char *spec)
110{
111 return devattach('/', spec);
112}
113
114static int
115rootgen(Chan *c, char *name, Dirtab *dirt, int ndirt, int s, Dir *dp)
116{
117 int t;
118 Dirtab *d;
119 Dirlist *l;
120
121 USED(dirt);
122 USED(ndirt);
123
124 switch((int)c->qid.path){
125 case Qdir:
126 if(s == DEVDOTDOT){
127 Qid tqiddir = {Qdir, 0, QTDIR};
128 devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
129 return 1;
130 }
131 return devgen(c, name, rootlist.dir, rootlist.ndir, s, dp);
132 case Qboot:
133 if(s == DEVDOTDOT){
134 Qid tqiddir = {Qdir, 0, QTDIR};
135 devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
136 return 1;
137 }
138 return devgen(c, name, bootlist.dir, bootlist.ndir, s, dp);
139 default:
140 if(s == DEVDOTDOT){
141 Qid tqiddir = {Qdir, 0, QTDIR};
142 if((int)c->qid.path < Qboot)
143 devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
144 else {
145 tqiddir.path = Qboot;
146 devdir(c, tqiddir, "#/", 0, eve, 0555, dp);
147 }
148 return 1;
149 }
150 if(s != 0)
151 return -1;
152 if((int)c->qid.path < Qboot){
153 t = c->qid.path-1;
154 l = &rootlist;
155 }else{
156 t = c->qid.path - Qboot - 1;
157 l = &bootlist;
158 }
159 if(t >= l->ndir)
160 return -1;
161if(t < 0){
162print("rootgen %llud %d %d\n", c->qid.path, s, t);
163panic("whoops");
164}
165 d = &l->dir[t];
166 devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
167 return 1;
168 }
169 return -1;
170}
171
172static Walkqid*
173rootwalk(Chan *c, Chan *nc, char **name, int nname)
174{
175 return devwalk(c, nc, name, nname, nil, 0, rootgen);
176}
177
178static int
179rootstat(Chan *c, uchar *dp, int n)
180{
181 return devstat(c, dp, n, nil, 0, rootgen);
182}
183
184static Chan*
185rootopen(Chan *c, int omode)
186{
187 return devopen(c, omode, nil, 0, devgen);
188}
189
190/*
191 * sysremove() knows this is a nop
192 */
193static void
194rootclose(Chan *c)
195{
196 USED(c);
197}
198
199static long
200rootread(Chan *c, void *buf, long n, vlong off)
201{
202 ulong t;
203 Dirtab *d;
204 Dirlist *l;
205 uchar *data;
206 ulong offset = off;
207
208 t = c->qid.path;
209 switch(t){
210 case Qdir:
211 case Qboot:
212 return devdirread(c, buf, n, nil, 0, rootgen);
213 }
214
215 if(t<Qboot)
216 l = &rootlist;
217 else{
218 t -= Qboot;
219 l = &bootlist;
220 }
221
222 t--;
223 if(t >= l->ndir)
224 error(Egreg);
225
226 d = &l->dir[t];
227 data = l->data[t];
228 if(offset >= d->length)
229 return 0;
230 if(offset+n > d->length)
231 n = d->length - offset;
232 memmove(buf, data+offset, n);
233 return n;
234}
235
236static long
237rootwrite(Chan *c, void *v, long n, vlong o)
238{
239 USED(c);
240 USED(v);
241 USED(n);
242 USED(o);
243
244 error(Egreg);
245 return 0;
246}
247
248Dev rootdevtab = {
249 '/',
250 "root",
251
252 rootreset,
253 devinit,
254 devshutdown,
255 rootattach,
256 rootwalk,
257 rootstat,
258 rootopen,
259 devcreate,
260 rootclose,
261 rootread,
262 devbread,
263 rootwrite,
264 devbwrite,
265 devremove,
266 devwstat,
267};
268
kern/devssl.c+1512−0
@@ -0,0 +1,1512 @@
1/*
2 * devssl - secure sockets layer
3 */
4#include "u.h"
5#include "lib.h"
6#include "dat.h"
7#include "fns.h"
8#include "error.h"
9
10#include "libsec.h"
11
12#define NOSPOOKS 1
13
14typedef struct OneWay OneWay;
15struct OneWay
16{
17 QLock q;
18 QLock ctlq;
19
20 void *state; /* encryption state */
21 int slen; /* hash data length */
22 uchar *secret; /* secret */
23 ulong mid; /* message id */
24};
25
26enum
27{
28 /* connection states */
29 Sincomplete= 0,
30 Sclear= 1,
31 Sencrypting= 2,
32 Sdigesting= 4,
33 Sdigenc= Sencrypting|Sdigesting,
34
35 /* encryption algorithms */
36 Noencryption= 0,
37 DESCBC= 1,
38 DESECB= 2,
39 RC4= 3
40};
41
42typedef struct Dstate Dstate;
43struct Dstate
44{
45 Chan *c; /* io channel */
46 uchar state; /* state of connection */
47 int ref; /* serialized by dslock for atomic destroy */
48
49 uchar encryptalg; /* encryption algorithm */
50 ushort blocklen; /* blocking length */
51
52 ushort diglen; /* length of digest */
53 DigestState *(*hf)(uchar*, ulong, uchar*, DigestState*); /* hash func */
54
55 /* for SSL format */
56 int max; /* maximum unpadded data per msg */
57 int maxpad; /* maximum padded data per msg */
58
59 /* input side */
60 OneWay in;
61 Block *processed;
62 Block *unprocessed;
63
64 /* output side */
65 OneWay out;
66
67 /* protections */
68 char *user;
69 int perm;
70};
71
72enum
73{
74 Maxdmsg= 1<<16,
75 Maxdstate= 128, /* must be a power of 2 */
76};
77
78Lock dslock;
79int dshiwat;
80char *dsname[Maxdstate];
81Dstate *dstate[Maxdstate];
82char *encalgs;
83char *hashalgs;
84
85enum{
86 Qtopdir = 1, /* top level directory */
87 Qprotodir,
88 Qclonus,
89 Qconvdir, /* directory for a conversation */
90 Qdata,
91 Qctl,
92 Qsecretin,
93 Qsecretout,
94 Qencalgs,
95 Qhashalgs,
96};
97
98#define TYPE(x) ((x).path & 0xf)
99#define CONV(x) (((x).path >> 5)&(Maxdstate-1))
100#define QID(c, y) (((c)<<5) | (y))
101
102static void ensure(Dstate*, Block**, int);
103static void consume(Block**, uchar*, int);
104static void setsecret(OneWay*, uchar*, int);
105static Block* encryptb(Dstate*, Block*, int);
106static Block* decryptb(Dstate*, Block*);
107static Block* digestb(Dstate*, Block*, int);
108static void checkdigestb(Dstate*, Block*);
109static Chan* buftochan(char*);
110static void sslhangup(Dstate*);
111static Dstate* dsclone(Chan *c);
112static void dsnew(Chan *c, Dstate **);
113static long sslput(Dstate *s, Block * volatile b);
114
115char *sslnames[] = {
116 /* unused */ 0,
117 /* topdir */ 0,
118 /* protodir */ 0,
119 "clone",
120 /* convdir */ 0,
121 "data",
122 "ctl",
123 "secretin",
124 "secretout",
125 "encalgs",
126 "hashalgs",
127};
128
129static int
130sslgen(Chan *c, char *n, Dirtab *d, int nd, int s, Dir *dp)
131{
132 Qid q;
133 Dstate *ds;
134 char name[16], *p, *nm;
135 int ft;
136
137 USED(n);
138 USED(nd);
139 USED(d);
140
141 q.type = QTFILE;
142 q.vers = 0;
143
144 ft = TYPE(c->qid);
145 switch(ft) {
146 case Qtopdir:
147 if(s == DEVDOTDOT){
148 q.path = QID(0, Qtopdir);
149 q.type = QTDIR;
150 devdir(c, q, "#D", 0, eve, 0555, dp);
151 return 1;
152 }
153 if(s > 0)
154 return -1;
155 q.path = QID(0, Qprotodir);
156 q.type = QTDIR;
157 devdir(c, q, "ssl", 0, eve, 0555, dp);
158 return 1;
159 case Qprotodir:
160 if(s == DEVDOTDOT){
161 q.path = QID(0, Qtopdir);
162 q.type = QTDIR;
163 devdir(c, q, ".", 0, eve, 0555, dp);
164 return 1;
165 }
166 if(s < dshiwat) {
167 q.path = QID(s, Qconvdir);
168 q.type = QTDIR;
169 ds = dstate[s];
170 if(ds != 0)
171 nm = ds->user;
172 else
173 nm = eve;
174 if(dsname[s] == nil){
175 sprint(name, "%d", s);
176 kstrdup(&dsname[s], name);
177 }
178 devdir(c, q, dsname[s], 0, nm, 0555, dp);
179 return 1;
180 }
181 if(s > dshiwat)
182 return -1;
183 q.path = QID(0, Qclonus);
184 devdir(c, q, "clone", 0, eve, 0555, dp);
185 return 1;
186 case Qconvdir:
187 if(s == DEVDOTDOT){
188 q.path = QID(0, Qprotodir);
189 q.type = QTDIR;
190 devdir(c, q, "ssl", 0, eve, 0555, dp);
191 return 1;
192 }
193 ds = dstate[CONV(c->qid)];
194 if(ds != 0)
195 nm = ds->user;
196 else
197 nm = eve;
198 switch(s) {
199 default:
200 return -1;
201 case 0:
202 q.path = QID(CONV(c->qid), Qctl);
203 p = "ctl";
204 break;
205 case 1:
206 q.path = QID(CONV(c->qid), Qdata);
207 p = "data";
208 break;
209 case 2:
210 q.path = QID(CONV(c->qid), Qsecretin);
211 p = "secretin";
212 break;
213 case 3:
214 q.path = QID(CONV(c->qid), Qsecretout);
215 p = "secretout";
216 break;
217 case 4:
218 q.path = QID(CONV(c->qid), Qencalgs);
219 p = "encalgs";
220 break;
221 case 5:
222 q.path = QID(CONV(c->qid), Qhashalgs);
223 p = "hashalgs";
224 break;
225 }
226 devdir(c, q, p, 0, nm, 0660, dp);
227 return 1;
228 case Qclonus:
229 devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, eve, 0555, dp);
230 return 1;
231 default:
232 ds = dstate[CONV(c->qid)];
233 if(ds != 0)
234 nm = ds->user;
235 else
236 nm = eve;
237 devdir(c, c->qid, sslnames[TYPE(c->qid)], 0, nm, 0660, dp);
238 return 1;
239 }
240 return -1;
241}
242
243static Chan*
244sslattach(char *spec)
245{
246 Chan *c;
247
248 c = devattach('D', spec);
249 c->qid.path = QID(0, Qtopdir);
250 c->qid.vers = 0;
251 c->qid.type = QTDIR;
252 return c;
253}
254
255static Walkqid*
256sslwalk(Chan *c, Chan *nc, char **name, int nname)
257{
258 return devwalk(c, nc, name, nname, nil, 0, sslgen);
259}
260
261static int
262sslstat(Chan *c, uchar *db, int n)
263{
264 return devstat(c, db, n, nil, 0, sslgen);
265}
266
267static Chan*
268sslopen(Chan *c, int omode)
269{
270 Dstate *s, **pp;
271 int perm;
272 int ft;
273
274 perm = 0;
275 omode &= 3;
276 switch(omode) {
277 case OREAD:
278 perm = 4;
279 break;
280 case OWRITE:
281 perm = 2;
282 break;
283 case ORDWR:
284 perm = 6;
285 break;
286 }
287
288 ft = TYPE(c->qid);
289 switch(ft) {
290 default:
291 panic("sslopen");
292 case Qtopdir:
293 case Qprotodir:
294 case Qconvdir:
295 if(omode != OREAD)
296 error(Eperm);
297 break;
298 case Qclonus:
299 s = dsclone(c);
300 if(s == 0)
301 error(Enodev);
302 break;
303 case Qctl:
304 case Qdata:
305 case Qsecretin:
306 case Qsecretout:
307 if(waserror()) {
308 unlock(&dslock);
309 nexterror();
310 }
311 lock(&dslock);
312 pp = &dstate[CONV(c->qid)];
313 s = *pp;
314 if(s == 0)
315 dsnew(c, pp);
316 else {
317 if((perm & (s->perm>>6)) != perm
318 && (strcmp(up->user, s->user) != 0
319 || (perm & s->perm) != perm))
320 error(Eperm);
321
322 s->ref++;
323 }
324 unlock(&dslock);
325 poperror();
326 break;
327 case Qencalgs:
328 case Qhashalgs:
329 if(omode != OREAD)
330 error(Eperm);
331 break;
332 }
333 c->mode = openmode(omode);
334 c->flag |= COPEN;
335 c->offset = 0;
336 return c;
337}
338
339static int
340sslwstat(Chan *c, uchar *db, int n)
341{
342 Dir *dir;
343 Dstate *s;
344 int m;
345
346 s = dstate[CONV(c->qid)];
347 if(s == 0)
348 error(Ebadusefd);
349 if(strcmp(s->user, up->user) != 0)
350 error(Eperm);
351
352 dir = smalloc(sizeof(Dir)+n);
353 m = convM2D(db, n, &dir[0], (char*)&dir[1]);
354 if(m == 0){
355 free(dir);
356 error(Eshortstat);
357 }
358
359 if(!emptystr(dir->uid))
360 kstrdup(&s->user, dir->uid);
361 if(dir->mode != ~0UL)
362 s->perm = dir->mode;
363
364 free(dir);
365 return m;
366}
367
368static void
369sslclose(Chan *c)
370{
371 Dstate *s;
372 int ft;
373
374 ft = TYPE(c->qid);
375 switch(ft) {
376 case Qctl:
377 case Qdata:
378 case Qsecretin:
379 case Qsecretout:
380 if((c->flag & COPEN) == 0)
381 break;
382
383 s = dstate[CONV(c->qid)];
384 if(s == 0)
385 break;
386
387 lock(&dslock);
388 if(--s->ref > 0) {
389 unlock(&dslock);
390 break;
391 }
392 dstate[CONV(c->qid)] = 0;
393 unlock(&dslock);
394
395 if(s->user != nil)
396 free(s->user);
397 sslhangup(s);
398 if(s->c)
399 cclose(s->c);
400 if(s->in.secret)
401 free(s->in.secret);
402 if(s->out.secret)
403 free(s->out.secret);
404 if(s->in.state)
405 free(s->in.state);
406 if(s->out.state)
407 free(s->out.state);
408 free(s);
409
410 }
411}
412
413/*
414 * make sure we have at least 'n' bytes in list 'l'
415 */
416static void
417ensure(Dstate *s, Block **l, int n)
418{
419 int sofar, i;
420 Block *b, *bl;
421
422 sofar = 0;
423 for(b = *l; b; b = b->next){
424 sofar += BLEN(b);
425 if(sofar >= n)
426 return;
427 l = &b->next;
428 }
429
430 while(sofar < n){
431 bl = devtab[s->c->type]->bread(s->c, Maxdmsg, 0);
432 if(bl == 0)
433 nexterror();
434 *l = bl;
435 i = 0;
436 for(b = bl; b; b = b->next){
437 i += BLEN(b);
438 l = &b->next;
439 }
440 if(i == 0)
441 error(Ehungup);
442 sofar += i;
443 }
444}
445
446/*
447 * copy 'n' bytes from 'l' into 'p' and free
448 * the bytes in 'l'
449 */
450static void
451consume(Block **l, uchar *p, int n)
452{
453 Block *b;
454 int i;
455
456 for(; *l && n > 0; n -= i){
457 b = *l;
458 i = BLEN(b);
459 if(i > n)
460 i = n;
461 memmove(p, b->rp, i);
462 b->rp += i;
463 p += i;
464 if(BLEN(b) < 0)
465 panic("consume");
466 if(BLEN(b))
467 break;
468 *l = b->next;
469 freeb(b);
470 }
471}
472
473/*
474 * give back n bytes
475static void
476regurgitate(Dstate *s, uchar *p, int n)
477{
478 Block *b;
479
480 if(n <= 0)
481 return;
482 b = s->unprocessed;
483 if(s->unprocessed == nil || b->rp - b->base < n) {
484 b = allocb(n);
485 memmove(b->wp, p, n);
486 b->wp += n;
487 b->next = s->unprocessed;
488 s->unprocessed = b;
489 } else {
490 b->rp -= n;
491 memmove(b->rp, p, n);
492 }
493}
494 */
495
496/*
497 * remove at most n bytes from the queue, if discard is set
498 * dump the remainder
499 */
500static Block*
501qtake(Block **l, int n, int discard)
502{
503 Block *nb, *b, *first;
504 int i;
505
506 first = *l;
507 for(b = first; b; b = b->next){
508 i = BLEN(b);
509 if(i == n){
510 if(discard){
511 freeblist(b->next);
512 *l = 0;
513 } else
514 *l = b->next;
515 b->next = 0;
516 return first;
517 } else if(i > n){
518 i -= n;
519 if(discard){
520 freeblist(b->next);
521 b->wp -= i;
522 *l = 0;
523 } else {
524 nb = allocb(i);
525 memmove(nb->wp, b->rp+n, i);
526 nb->wp += i;
527 b->wp -= i;
528 nb->next = b->next;
529 *l = nb;
530 }
531 b->next = 0;
532 if(BLEN(b) < 0)
533 panic("qtake");
534 return first;
535 } else
536 n -= i;
537 if(BLEN(b) < 0)
538 panic("qtake");
539 }
540 *l = 0;
541 return first;
542}
543
544/*
545 * We can't let Eintr's lose data since the program
546 * doing the read may be able to handle it. The only
547 * places Eintr is possible is during the read's in consume.
548 * Therefore, we make sure we can always put back the bytes
549 * consumed before the last ensure.
550 */
551static Block*
552sslbread(Chan *c, long n, ulong o)
553{
554 Dstate * volatile s;
555 Block *b;
556 uchar consumed[3], *p;
557 int toconsume;
558 int len, pad;
559
560 USED(o);
561 s = dstate[CONV(c->qid)];
562 if(s == 0)
563 panic("sslbread");
564 if(s->state == Sincomplete)
565 error(Ebadusefd);
566
567 qlock(&s->in.q);
568 if(waserror()){
569 qunlock(&s->in.q);
570 nexterror();
571 }
572
573 if(s->processed == 0){
574 /*
575 * Read in the whole message. Until we've got it all,
576 * it stays on s->unprocessed, so that if we get Eintr,
577 * we'll pick up where we left off.
578 */
579 ensure(s, &s->unprocessed, 3);
580 s->unprocessed = pullupblock(s->unprocessed, 2);
581 p = s->unprocessed->rp;
582 if(p[0] & 0x80){
583 len = ((p[0] & 0x7f)<<8) | p[1];
584 ensure(s, &s->unprocessed, len);
585 pad = 0;
586 toconsume = 2;
587 } else {
588 s->unprocessed = pullupblock(s->unprocessed, 3);
589 len = ((p[0] & 0x3f)<<8) | p[1];
590 pad = p[2];
591 if(pad > len){
592 print("pad %d buf len %d\n", pad, len);
593 error("bad pad in ssl message");
594 }
595 toconsume = 3;
596 }
597 ensure(s, &s->unprocessed, toconsume+len);
598
599 /* skip header */
600 consume(&s->unprocessed, consumed, toconsume);
601
602 /* grab the next message and decode/decrypt it */
603 b = qtake(&s->unprocessed, len, 0);
604
605 if(blocklen(b) != len)
606 print("devssl: sslbread got wrong count %d != %d", blocklen(b), len);
607
608 if(waserror()){
609 qunlock(&s->in.ctlq);
610 if(b != nil)
611 freeb(b);
612 nexterror();
613 }
614 qlock(&s->in.ctlq);
615 switch(s->state){
616 case Sencrypting:
617 if(b == nil)
618 error("ssl message too short (encrypting)");
619 b = decryptb(s, b);
620 break;
621 case Sdigesting:
622 b = pullupblock(b, s->diglen);
623 if(b == nil)
624 error("ssl message too short (digesting)");
625 checkdigestb(s, b);
626 b->rp += s->diglen;
627 break;
628 case Sdigenc:
629 b = decryptb(s, b);
630 b = pullupblock(b, s->diglen);
631 if(b == nil)
632 error("ssl message too short (dig+enc)");
633 checkdigestb(s, b);
634 b->rp += s->diglen;
635 len -= s->diglen;
636 break;
637 }
638
639 /* remove pad */
640 if(pad)
641 s->processed = qtake(&b, len - pad, 1);
642 else
643 s->processed = b;
644 b = nil;
645 s->in.mid++;
646 qunlock(&s->in.ctlq);
647 poperror();
648 }
649
650 /* return at most what was asked for */
651 b = qtake(&s->processed, n, 0);
652
653 qunlock(&s->in.q);
654 poperror();
655
656 return b;
657}
658
659static long
660sslread(Chan *c, void *a, long n, vlong off)
661{
662 Block * volatile b;
663 Block *nb;
664 uchar *va;
665 int i;
666 char buf[128];
667 ulong offset = off;
668 int ft;
669
670 if(c->qid.type & QTDIR)
671 return devdirread(c, a, n, 0, 0, sslgen);
672
673 ft = TYPE(c->qid);
674 switch(ft) {
675 default:
676 error(Ebadusefd);
677 case Qctl:
678 ft = CONV(c->qid);
679 sprint(buf, "%d", ft);
680 return readstr(offset, a, n, buf);
681 case Qdata:
682 b = sslbread(c, n, offset);
683 break;
684 case Qencalgs:
685 return readstr(offset, a, n, encalgs);
686 break;
687 case Qhashalgs:
688 return readstr(offset, a, n, hashalgs);
689 break;
690 }
691
692 if(waserror()){
693 freeblist(b);
694 nexterror();
695 }
696
697 n = 0;
698 va = a;
699 for(nb = b; nb; nb = nb->next){
700 i = BLEN(nb);
701 memmove(va+n, nb->rp, i);
702 n += i;
703 }
704
705 freeblist(b);
706 poperror();
707
708 return n;
709}
710
711/*
712 * this algorithm doesn't have to be great since we're just
713 * trying to obscure the block fill
714 */
715static void
716randfill(uchar *buf, int len)
717{
718 while(len-- > 0)
719 *buf++ = nrand(256);
720}
721
722static long
723sslbwrite(Chan *c, Block *b, ulong o)
724{
725 Dstate * volatile s;
726 long rv;
727
728 USED(o);
729 s = dstate[CONV(c->qid)];
730 if(s == nil)
731 panic("sslbwrite");
732
733 if(s->state == Sincomplete){
734 freeb(b);
735 error(Ebadusefd);
736 }
737
738 /* lock so split writes won't interleave */
739 if(waserror()){
740 qunlock(&s->out.q);
741 nexterror();
742 }
743 qlock(&s->out.q);
744
745 rv = sslput(s, b);
746
747 poperror();
748 qunlock(&s->out.q);
749
750 return rv;
751}
752
753/*
754 * use SSL record format, add in count, digest and/or encrypt.
755 * the write is interruptable. if it is interrupted, we'll
756 * get out of sync with the far side. not much we can do about
757 * it since we don't know if any bytes have been written.
758 */
759static long
760sslput(Dstate *s, Block * volatile b)
761{
762 Block *nb;
763 int h, n, m, pad, rv;
764 uchar *p;
765 int offset;
766
767 if(waserror()){
768 if(b != nil)

744 more lines aren’t shown here.

kern/devtab.c+27−0

This diff is large: its 28 lines aren’t shown here.

kern/error.c+50−0

This diff is large: its 51 lines aren’t shown here.

kern/error.h+50−0

This diff is large: its 51 lines aren’t shown here.

kern/exportfs.c+821−0

This diff is large: its 822 lines aren’t shown here.

kern/fns.h+377−0

This diff is large: its 378 lines aren’t shown here.

kern/mkfile+47−0

This diff is large: its 48 lines aren’t shown here.

kern/netif.h+133−0

This diff is large: its 134 lines aren’t shown here.

kern/os-windows.c+184−0

This diff is large: its 185 lines aren’t shown here.

kern/parse.c+113−0

This diff is large: its 114 lines aren’t shown here.

kern/pgrp.c+272−0

This diff is large: its 273 lines aren’t shown here.

kern/posix.c+190−0

This diff is large: its 191 lines aren’t shown here.

kern/procinit.c+67−0

This diff is large: its 68 lines aren’t shown here.

kern/qio.c+1524−0

This diff is large: its 1525 lines aren’t shown here.

kern/qlock.c+94−0

This diff is large: its 95 lines aren’t shown here.

kern/rendez.c+90−0

This diff is large: its 91 lines aren’t shown here.

kern/rwlock.c+39−0

This diff is large: its 40 lines aren’t shown here.

kern/screen.h+59−0

This diff is large: its 60 lines aren’t shown here.

kern/sleep.c+90−0

This diff is large: its 91 lines aren’t shown here.

kern/smalloc.c+18−0

This diff is large: its 19 lines aren’t shown here.

kern/stub.c+170−0

This diff is large: its 171 lines aren’t shown here.

kern/syscall.c+837−0

This diff is large: its 838 lines aren’t shown here.

kern/sysfile.c+1242−0

This diff is large: its 1243 lines aren’t shown here.

kern/sysproc.c+32−0

This diff is large: its 33 lines aren’t shown here.

kern/term.c+204−0

This diff is large: its 205 lines aren’t shown here.

kern/todo.c+0−0

Empty file added.

kern/uart.c+14−0

This diff is large: its 15 lines aren’t shown here.

kern/waserror.c+27−0

This diff is large: its 28 lines aren’t shown here.

kern/winduhz.h+18−0

This diff is large: its 19 lines aren’t shown here.

kern/x+601−0

This diff is large: its 602 lines aren’t shown here.

latin1.c+177−0

This diff is large: its 178 lines aren’t shown here.

libauthsrv/Makefile+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/authdial.c+31−0

This diff is large: its 32 lines aren’t shown here.

libauthsrv/convA2M.c+25−0

This diff is large: its 26 lines aren’t shown here.

libauthsrv/convM2A.c+23−0

This diff is large: its 24 lines aren’t shown here.

libauthsrv/convM2PR.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convM2T.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convM2TR.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convPR2M.c+28−0

This diff is large: its 29 lines aren’t shown here.

libauthsrv/convT2M.c+27−0

This diff is large: its 28 lines aren’t shown here.

libauthsrv/convTR2M.c+27−0

This diff is large: its 28 lines aren’t shown here.

libauthsrv/mkfile+25−0

This diff is large: its 26 lines aren’t shown here.

libauthsrv/nvcsum.c+16−0

This diff is large: its 17 lines aren’t shown here.

libauthsrv/opasstokey.c+29−0

This diff is large: its 30 lines aren’t shown here.

libauthsrv/passtokey.c+33−0

This diff is large: its 34 lines aren’t shown here.

libauthsrv/readnvram.c+368−0

This diff is large: its 369 lines aren’t shown here.

libc/Makefile+89−0

This diff is large: its 90 lines aren’t shown here.

libc/charstod.c+81−0

This diff is large: its 82 lines aren’t shown here.

libc/cleanname.c+52−0

This diff is large: its 53 lines aren’t shown here.

libc/convD2M.c+95−0

This diff is large: its 96 lines aren’t shown here.

libc/convM2D.c+94−0

This diff is large: its 95 lines aren’t shown here.

libc/convM2S.c+315−0

This diff is large: its 316 lines aren’t shown here.

libc/convS2M.c+386−0

This diff is large: its 387 lines aren’t shown here.

libc/crypt.c+68−0

This diff is large: its 69 lines aren’t shown here.

libc/dial.c+209−0

This diff is large: its 210 lines aren’t shown here.

libc/dirfstat.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/dirfwstat.c+19−0

This diff is large: its 20 lines aren’t shown here.

libc/dirmodefmt.c+48−0

This diff is large: its 49 lines aren’t shown here.

libc/dirstat.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/dirwstat.c+19−0

This diff is large: its 20 lines aren’t shown here.

libc/dofmt.c+520−0

This diff is large: its 521 lines aren’t shown here.

libc/dorfmt.c+46−0

This diff is large: its 47 lines aren’t shown here.

libc/errfmt.c+12−0

This diff is large: its 13 lines aren’t shown here.

libc/fcallfmt.c+234−0

This diff is large: its 235 lines aren’t shown here.

libc/fltfmt.c+312−0

This diff is large: its 313 lines aren’t shown here.

libc/fmt.c+193−0

This diff is large: its 194 lines aren’t shown here.

libc/fmt.h+99−0

This diff is large: its 100 lines aren’t shown here.

libc/fmtdef.h+85−0

This diff is large: its 86 lines aren’t shown here.

libc/fmtfd.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/fmtlock.c+16−0

This diff is large: its 17 lines aren’t shown here.

libc/fmtprint.c+32−0

This diff is large: its 33 lines aren’t shown here.

libc/fmtquote.c+247−0

This diff is large: its 248 lines aren’t shown here.

libc/fmtrune.c+25−0

This diff is large: its 26 lines aren’t shown here.

libc/fmtstr.c+11−0

This diff is large: its 12 lines aren’t shown here.

libc/fmtvprint.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/fprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/frand.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/getfields.c+37−0

This diff is large: its 38 lines aren’t shown here.

libc/getpid.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/lnrand.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/lock.c+64−0

This diff is large: its 65 lines aren’t shown here.

libc/lrand.c+83−0

This diff is large: its 84 lines aren’t shown here.

libc/mallocz.c+13−0

This diff is large: its 14 lines aren’t shown here.

libc/mkfile+90−0

This diff is large: its 91 lines aren’t shown here.

libc/nan.h+4−0

This diff is large: its 5 lines aren’t shown here.

libc/nan64.c+55−0

This diff is large: its 56 lines aren’t shown here.

libc/netmkaddr.c+52−0

This diff is large: its 53 lines aren’t shown here.

libc/nrand.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/nsec.c+66−0

This diff is large: its 67 lines aren’t shown here.

libc/pow10.c+49−0

This diff is large: its 50 lines aren’t shown here.

libc/print.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/pushssl.c+44−0

This diff is large: its 45 lines aren’t shown here.

libc/rand.c+8−0

This diff is large: its 9 lines aren’t shown here.

libc/read9pmsg.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/readn.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/rune.c+162−0

This diff is large: its 163 lines aren’t shown here.

libc/runefmtstr.c+11−0

This diff is large: its 12 lines aren’t shown here.

libc/runeseprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runesmprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runesnprint.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/runesprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runestrcat.c+10−0

This diff is large: its 11 lines aren’t shown here.

libc/runestrchr.c+20−0

This diff is large: its 21 lines aren’t shown here.

libc/runestrcmp.c+20−0

This diff is large: its 21 lines aren’t shown here.

libc/runestrcpy.c+13−0

This diff is large: its 14 lines aren’t shown here.

libc/runestrdup.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/runestrecpy.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/runestrlen.c+9−0

This diff is large: its 10 lines aren’t shown here.

libc/runestrncat.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/runestrncmp.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/runestrncpy.c+18−0

This diff is large: its 19 lines aren’t shown here.

libc/runestrrchr.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/runestrstr.c+29−0

This diff is large: its 30 lines aren’t shown here.

libc/runetype.c+1138−0

This diff is large: its 1139 lines aren’t shown here.

libc/runevseprint.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/runevsmprint.c+70−0

This diff is large: its 71 lines aren’t shown here.

libc/runevsnprint.c+22−0

This diff is large: its 23 lines aren’t shown here.

libc/seprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/smprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/snprint.c+15−0

This diff is large: its 16 lines aren’t shown here.

libc/sprint.c+14−0

This diff is large: its 15 lines aren’t shown here.

libc/strecpy.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/strtod.c+532−0

This diff is large: its 533 lines aren’t shown here.

libc/strtod.h+4−0

This diff is large: its 5 lines aren’t shown here.

libc/strtoll.c+93−0

This diff is large: its 94 lines aren’t shown here.

libc/sysfatal.c+30−0

This diff is large: its 31 lines aren’t shown here.

libc/time.c+51−0

This diff is large: its 52 lines aren’t shown here.

libc/tokenize.c+107−0

This diff is large: its 108 lines aren’t shown here.

libc/truerand.c+17−0

This diff is large: its 18 lines aren’t shown here.

libc/u16.c+53−0

This diff is large: its 54 lines aren’t shown here.

libc/u32.c+110−0

This diff is large: its 111 lines aren’t shown here.

libc/u64.c+127−0

This diff is large: its 128 lines aren’t shown here.

libc/utf.h+51−0

This diff is large: its 52 lines aren’t shown here.

libc/utfdef.h+14−0

This diff is large: its 15 lines aren’t shown here.

libc/utfecpy.c+21−0

This diff is large: its 22 lines aren’t shown here.

libc/utflen.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/utfnlen.c+26−0

This diff is large: its 27 lines aren’t shown here.

libc/utfrrune.c+31−0

This diff is large: its 32 lines aren’t shown here.

libc/utfrune.c+30−0

This diff is large: its 31 lines aren’t shown here.

libc/utfutf.c+26−0

This diff is large: its 27 lines aren’t shown here.

libc/vfprint.c+34−0

This diff is large: its 35 lines aren’t shown here.

libc/vseprint.c+23−0

This diff is large: its 24 lines aren’t shown here.

libc/vsmprint.c+70−0

This diff is large: its 71 lines aren’t shown here.

libc/vsnprint.c+22−0

This diff is large: its 23 lines aren’t shown here.

libdraw/Makefile+24−0

This diff is large: its 25 lines aren’t shown here.

libdraw/alloc.c+237−0

This diff is large: its 238 lines aren’t shown here.

libdraw/arith.c+206−0

This diff is large: its 207 lines aren’t shown here.

libdraw/bytesperline.c+34−0

This diff is large: its 35 lines aren’t shown here.

libdraw/chan.c+77−0

This diff is large: its 78 lines aren’t shown here.

libdraw/defont.c+402−0

This diff is large: its 403 lines aren’t shown here.

libdraw/drawrepl.c+23−0

This diff is large: its 24 lines aren’t shown here.

libdraw/icossin.c+140−0

This diff is large: its 141 lines aren’t shown here.

libdraw/icossin2.c+261−0

This diff is large: its 262 lines aren’t shown here.

libdraw/mkfile+18−0

This diff is large: its 19 lines aren’t shown here.

libdraw/rectclip.c+25−0

This diff is large: its 26 lines aren’t shown here.

libdraw/rgb.c+99−0

This diff is large: its 100 lines aren’t shown here.

libmemdraw/Makefile+33−0

This diff is large: its 34 lines aren’t shown here.

libmemdraw/alloc.c+200−0

This diff is large: its 201 lines aren’t shown here.

libmemdraw/alpha.hoc+9−0

This diff is large: its 10 lines aren’t shown here.

libmemdraw/arc.c+117−0

This diff is large: its 118 lines aren’t shown here.

libmemdraw/arctest.c+62−0

This diff is large: its 63 lines aren’t shown here.

libmemdraw/cload.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/cmap.c+320−0

This diff is large: its 321 lines aren’t shown here.

libmemdraw/cread.c+96−0

This diff is large: its 97 lines aren’t shown here.

libmemdraw/defont.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/draw.c+2499−0

This diff is large: its 2500 lines aren’t shown here.

libmemdraw/drawtest.c+1004−0

This diff is large: its 1005 lines aren’t shown here.

libmemdraw/ellipse.c+248−0

This diff is large: its 249 lines aren’t shown here.

libmemdraw/fillpoly.c+523−0

This diff is large: its 524 lines aren’t shown here.

libmemdraw/hwdraw.c+12−0

This diff is large: its 13 lines aren’t shown here.

libmemdraw/iprint.c+12−0

This diff is large: its 13 lines aren’t shown here.

libmemdraw/line.c+485−0

This diff is large: its 486 lines aren’t shown here.

libmemdraw/load.c+72−0

This diff is large: its 73 lines aren’t shown here.

libmemdraw/mkcmap.c+79−0

This diff is large: its 80 lines aren’t shown here.

libmemdraw/mkfile+27−0

This diff is large: its 28 lines aren’t shown here.

libmemdraw/openmemsubfont.c+53−0

This diff is large: its 54 lines aren’t shown here.

libmemdraw/poly.c+24−0

This diff is large: its 25 lines aren’t shown here.

libmemdraw/read.c+111−0

This diff is large: its 112 lines aren’t shown here.

libmemdraw/string.c+68−0

This diff is large: its 69 lines aren’t shown here.

libmemdraw/subfont.c+34−0

This diff is large: its 35 lines aren’t shown here.

libmemdraw/times+19−0

This diff is large: its 20 lines aren’t shown here.

libmemdraw/unload.c+25−0

This diff is large: its 26 lines aren’t shown here.

libmemdraw/write.c+183−0

This diff is large: its 184 lines aren’t shown here.

libmemlayer/Makefile+26−0

This diff is large: its 27 lines aren’t shown here.

libmemlayer/draw.c+192−0

This diff is large: its 193 lines aren’t shown here.

libmemlayer/lalloc.c+79−0

This diff is large: its 80 lines aren’t shown here.

libmemlayer/layerop.c+112−0

This diff is large: its 113 lines aren’t shown here.

libmemlayer/ldelete.c+67−0

This diff is large: its 68 lines aren’t shown here.

libmemlayer/lhide.c+67−0

This diff is large: its 68 lines aren’t shown here.

libmemlayer/line.c+122−0

This diff is large: its 123 lines aren’t shown here.

libmemlayer/load.c+55−0

This diff is large: its 56 lines aren’t shown here.

libmemlayer/lorigin.c+107−0

This diff is large: its 108 lines aren’t shown here.

libmemlayer/lsetrefresh.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmemlayer/ltofront.c+80−0

This diff is large: its 81 lines aren’t shown here.

libmemlayer/ltorear.c+69−0

This diff is large: its 70 lines aren’t shown here.

libmemlayer/mkfile+23−0

This diff is large: its 24 lines aren’t shown here.

libmemlayer/unload.c+52−0

This diff is large: its 53 lines aren’t shown here.

libmp/Makefile+46−0

This diff is large: its 47 lines aren’t shown here.

libmp/betomp.c+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/crt.c+122−0

This diff is large: its 123 lines aren’t shown here.

libmp/crttest.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/dat.h+15−0

This diff is large: its 16 lines aren’t shown here.

libmp/letomp.c+29−0

This diff is large: its 30 lines aren’t shown here.

libmp/mkfile+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/mpadd.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/mpaux.c+185−0

This diff is large: its 186 lines aren’t shown here.

libmp/mpcmp.c+28−0

This diff is large: its 29 lines aren’t shown here.

libmp/mpdigdiv.c+43−0

This diff is large: its 44 lines aren’t shown here.

libmp/mpdiv.c+112−0

This diff is large: its 113 lines aren’t shown here.

libmp/mpeuclid.c+82−0

This diff is large: its 83 lines aren’t shown here.

libmp/mpexp.c+86−0

This diff is large: its 87 lines aren’t shown here.

libmp/mpextendedgcd.c+97−0

This diff is large: its 98 lines aren’t shown here.

libmp/mpfmt.c+193−0

This diff is large: its 194 lines aren’t shown here.

libmp/mpinvert.c+21−0

This diff is large: its 22 lines aren’t shown here.

libmp/mpleft.c+46−0

This diff is large: its 47 lines aren’t shown here.

libmp/mpmod.c+15−0

This diff is large: its 16 lines aren’t shown here.

libmp/mpmul.c+156−0

This diff is large: its 157 lines aren’t shown here.

libmp/mprand.c+42−0

This diff is large: its 43 lines aren’t shown here.

libmp/mpright.c+40−0

This diff is large: its 41 lines aren’t shown here.

libmp/mpsub.c+52−0

This diff is large: its 53 lines aren’t shown here.

libmp/mptobe.c+57−0

This diff is large: its 58 lines aren’t shown here.

libmp/mptoi.c+44−0

This diff is large: its 45 lines aren’t shown here.

libmp/mptole.c+54−0

This diff is large: its 55 lines aren’t shown here.

libmp/mptoui.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmp/mptouv.c+49−0

This diff is large: its 50 lines aren’t shown here.

libmp/mptov.c+69−0

This diff is large: its 70 lines aren’t shown here.

libmp/mpvecadd.c+35−0

This diff is large: its 36 lines aren’t shown here.

libmp/mpveccmp.c+28−0

This diff is large: its 29 lines aren’t shown here.

libmp/mpvecdigmuladd.c+103−0

This diff is large: its 104 lines aren’t shown here.

libmp/mpvecsub.c+34−0

This diff is large: its 35 lines aren’t shown here.

libmp/os.h+3−0

This diff is large: its 4 lines aren’t shown here.

libmp/reduce+16−0

This diff is large: its 17 lines aren’t shown here.

libmp/strtomp.c+205−0

This diff is large: its 206 lines aren’t shown here.

libsec/Makefile+60−0

This diff is large: its 61 lines aren’t shown here.

libsec/aes.c+1544−0

This diff is large: its 1545 lines aren’t shown here.

libsec/blowfish.c+579−0

This diff is large: its 580 lines aren’t shown here.

libsec/decodepem.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/des.c+480−0

This diff is large: its 481 lines aren’t shown here.

libsec/des3CBC.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/des3ECB.c+48−0

This diff is large: its 49 lines aren’t shown here.

libsec/desCBC.c+59−0

This diff is large: its 60 lines aren’t shown here.

libsec/desECB.c+48−0

This diff is large: its 49 lines aren’t shown here.

libsec/desmodes.c+31−0

This diff is large: its 32 lines aren’t shown here.

libsec/dsaalloc.c+69−0

This diff is large: its 70 lines aren’t shown here.

libsec/dsagen.c+61−0

This diff is large: its 62 lines aren’t shown here.

libsec/dsaprimes.c+97−0

This diff is large: its 98 lines aren’t shown here.

libsec/dsaprivtopub.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/dsasign.c+52−0

This diff is large: its 53 lines aren’t shown here.

libsec/dsaverify.c+46−0

This diff is large: its 47 lines aren’t shown here.

libsec/egalloc.c+67−0

This diff is large: its 68 lines aren’t shown here.

libsec/egdecrypt.c+28−0

This diff is large: its 29 lines aren’t shown here.

libsec/egencrypt.c+38−0

This diff is large: its 39 lines aren’t shown here.

libsec/eggen.c+21−0

This diff is large: its 22 lines aren’t shown here.

libsec/egprivtopub.c+17−0

This diff is large: its 18 lines aren’t shown here.

libsec/egsign.c+43−0

This diff is large: its 44 lines aren’t shown here.

libsec/egtest.c+34−0

This diff is large: its 35 lines aren’t shown here.

libsec/egverify.c+29−0

This diff is large: its 30 lines aren’t shown here.

libsec/fastrand.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/genprime.c+27−0

This diff is large: its 28 lines aren’t shown here.

libsec/genrandom.c+62−0

This diff is large: its 63 lines aren’t shown here.

libsec/gensafeprime.c+36−0

This diff is large: its 37 lines aren’t shown here.

libsec/genstrongprime.c+57−0

This diff is large: its 58 lines aren’t shown here.

libsec/hmac.c+56−0

This diff is large: its 57 lines aren’t shown here.

libsec/hmactest.c+19−0

This diff is large: its 20 lines aren’t shown here.

libsec/md4.c+271−0

This diff is large: its 272 lines aren’t shown here.

libsec/md4test.c+31−0

This diff is large: its 32 lines aren’t shown here.

libsec/md5.c+148−0

This diff is large: its 149 lines aren’t shown here.

libsec/md5block.c+267−0

This diff is large: its 268 lines aren’t shown here.

libsec/md5pickle.c+37−0

This diff is large: its 38 lines aren’t shown here.

libsec/mkfile+55−0

This diff is large: its 56 lines aren’t shown here.

libsec/nfastrand.c+23−0

This diff is large: its 24 lines aren’t shown here.

libsec/os.h+2−0

This diff is large: its 3 lines aren’t shown here.

libsec/primetest.c+41−0

This diff is large: its 42 lines aren’t shown here.

libsec/prng.c+15−0

This diff is large: its 16 lines aren’t shown here.

libsec/probably_prime.c+84−0

This diff is large: its 85 lines aren’t shown here.

libsec/ranlib.core+0−0

Binary file not shown.

libsec/rc4.c+104−0

This diff is large: its 105 lines aren’t shown here.

libsec/readcert.c+50−0

This diff is large: its 51 lines aren’t shown here.

libsec/rsaalloc.c+52−0

This diff is large: its 53 lines aren’t shown here.

libsec/rsadecrypt.c+37−0

This diff is large: its 38 lines aren’t shown here.

libsec/rsaencrypt.c+12−0

This diff is large: its 13 lines aren’t shown here.

libsec/rsafill.c+61−0

This diff is large: its 62 lines aren’t shown here.

libsec/rsagen.c+82−0

This diff is large: its 83 lines aren’t shown here.

libsec/rsaprivtopub.c+16−0

This diff is large: its 17 lines aren’t shown here.

libsec/rsatest.c+57−0

This diff is large: its 58 lines aren’t shown here.

libsec/sha1.c+127−0

This diff is large: its 128 lines aren’t shown here.

libsec/sha1block.c+187−0

This diff is large: its 188 lines aren’t shown here.

libsec/sha1pickle.c+38−0

This diff is large: its 39 lines aren’t shown here.

libsec/smallprimes.c+1004−0

This diff is large: its 1005 lines aren’t shown here.

libsec/smallprimetest.c+1039−0

This diff is large: its 1040 lines aren’t shown here.

libsec/thumb.c+97−0

This diff is large: its 98 lines aren’t shown here.

libsec/tlshand.c+2291−0

This diff is large: its 2292 lines aren’t shown here.

libsec/x509.c+2520−0

This diff is large: its 2521 lines aren’t shown here.

main.c+126−0

This diff is large: its 127 lines aren’t shown here.

mkfile+95−0

This diff is large: its 96 lines aren’t shown here.

mkfile-Windows+54−0

This diff is large: its 55 lines aren’t shown here.

mkfile-posix+9−0

This diff is large: its 10 lines aren’t shown here.

mkone+50−0

This diff is large: its 51 lines aren’t shown here.

posix-386/Makefile+16−0

This diff is large: its 17 lines aren’t shown here.

posix-386/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

posix-386/md5block.s+241−0

This diff is large: its 242 lines aren’t shown here.

posix-386/sha1block.s+214−0

This diff is large: its 215 lines aren’t shown here.

posix-386/tas.c+23−0

This diff is large: its 24 lines aren’t shown here.

posix-power/Makefile+16−0

This diff is large: its 17 lines aren’t shown here.

posix-power/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

posix-power/tas.c+42−0

This diff is large: its 43 lines aren’t shown here.

readcons.c+110−0

This diff is large: its 111 lines aren’t shown here.

resource.h+16−0

This diff is large: its 17 lines aren’t shown here.

secstore.c+667−0

This diff is large: its 668 lines aren’t shown here.

win32-386/getcallerpc.c+8−0

This diff is large: its 9 lines aren’t shown here.

win32-386/md5block.s+241−0

This diff is large: its 242 lines aren’t shown here.

win32-386/mkfile+10−0

This diff is large: its 11 lines aren’t shown here.

win32-386/sha1block.s+214−0

This diff is large: its 215 lines aren’t shown here.

win32-386/tas.c+22−0

This diff is large: its 23 lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t