summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorethan <ethan@vx32vardo>2013-07-05 21:51:35 +0100
committerethan <ethan@vx32vardo>2013-07-05 21:51:35 +0100
commit0e9a80d129306202e31e9ed253b75b9b06703a86 (patch)
tree0141d8ed52f9c78e33f8ebbf281d0d2125c55108
parent6fd3e90d85b43e4d7d97d11d282946d11d22183a (diff)
parent252b0ff3c9b17628e641f2e9eb84468fb8975a6e (diff)
merge
-rw-r--r--lib/bullshit1
-rw-r--r--lib/face/48x48x8/n/nixie.1bin17954 -> 1109 bytes
-rw-r--r--lib/font/bit/germgoth/unicode.12.font146
-rw-r--r--lib/font/bit/germgoth/unicode.14.font153
-rw-r--r--lib/font/bit/germgoth/unicode.16.font153
-rw-r--r--lib/font/bit/germgoth/unicode.18.font153
-rw-r--r--lib/rob1
-rwxr-xr-xrc/bin/sysinfo49
-rw-r--r--sys/games/lib/fortunes13
-rw-r--r--sys/include/ape/draw.h1
-rw-r--r--sys/include/draw.h1
-rw-r--r--sys/man/1/jpg29
-rw-r--r--sys/man/1/sysinfo24
-rw-r--r--sys/man/1/vnc35
-rw-r--r--sys/man/8/hjfs12
-rw-r--r--sys/man/8/plan9.ini17
-rw-r--r--sys/src/9/ip/ethermedium.c14
-rw-r--r--sys/src/9/pc/apic.c100
-rw-r--r--sys/src/9/pc/archacpi.c12
-rw-r--r--sys/src/9/pc/archmp.c2
-rw-r--r--sys/src/9/pc/dat.h1
-rw-r--r--sys/src/9/pc/etheriwl.c96
-rw-r--r--sys/src/9/pc/mtrr.c4
-rw-r--r--sys/src/9/pc/wifi.c347
-rw-r--r--sys/src/9/pc/wifi.h21
-rw-r--r--sys/src/9/port/alarm.c2
-rw-r--r--sys/src/9/port/devcons.c3
-rw-r--r--sys/src/9/port/devmnt.c8
-rw-r--r--sys/src/9/port/devshr.c73
-rw-r--r--sys/src/9/port/devsrv.c118
-rw-r--r--sys/src/9/port/portclock.c3
-rw-r--r--sys/src/cmd/9nfs/9p.c2
-rw-r--r--sys/src/cmd/abaco/util.c12
-rw-r--r--sys/src/cmd/acme/fsys.c3
-rw-r--r--sys/src/cmd/auth/asn12dsa.c13
-rw-r--r--sys/src/cmd/aux/consolefs.c5
-rw-r--r--sys/src/cmd/aux/depend.c5
-rw-r--r--sys/src/cmd/aux/timesync.c4
-rw-r--r--sys/src/cmd/aux/wpa.c301
-rw-r--r--sys/src/cmd/cfs/cfs.c5
-rw-r--r--sys/src/cmd/cpu.c4
-rw-r--r--sys/src/cmd/disk/9660/dump9660.c10
-rw-r--r--sys/src/cmd/exportfs/exportfs.c5
-rw-r--r--sys/src/cmd/hjfs/auth.c1
-rw-r--r--sys/src/cmd/hjfs/cons.c8
-rw-r--r--sys/src/cmd/hjfs/fns.h1
-rw-r--r--sys/src/cmd/hjfs/fs1.c2
-rw-r--r--sys/src/cmd/iostats/iostats.c3
-rw-r--r--sys/src/cmd/ip/ftpfs/ftpfs.c4
-rw-r--r--sys/src/cmd/jpg/imagefile.h6
-rw-r--r--sys/src/cmd/jpg/mkfile2
-rw-r--r--sys/src/cmd/jpg/readtif.c1793
-rw-r--r--sys/src/cmd/jpg/tif.c251
-rw-r--r--sys/src/cmd/ndb/cs.c10
-rw-r--r--sys/src/cmd/ndb/dn.c17
-rw-r--r--sys/src/cmd/ndb/dns.c14
-rw-r--r--sys/src/cmd/nusb/ether/asix.c8
-rw-r--r--sys/src/cmd/nusb/ether/ether.c5
-rw-r--r--sys/src/cmd/page.c16
-rw-r--r--sys/src/cmd/paint.c76
-rw-r--r--sys/src/cmd/paqfs/paqfs.c2
-rw-r--r--sys/src/cmd/plumb/fsys.c8
-rw-r--r--sys/src/cmd/rio/dat.h1
-rw-r--r--sys/src/cmd/rio/fsys.c5
-rw-r--r--sys/src/cmd/rio/wind.c103
-rw-r--r--sys/src/cmd/samterm/main.c3
-rw-r--r--sys/src/cmd/scram.c14
-rw-r--r--sys/src/cmd/tcs/cyrillic.h8
-rw-r--r--sys/src/cmd/uhtml.c2
-rw-r--r--sys/src/cmd/upas/smtp/smtp.c2
-rw-r--r--sys/src/cmd/vac/vacfs.c4
-rw-r--r--sys/src/cmd/vnc/exportfs.c5
-rw-r--r--sys/src/lib9p/srv.c4
-rw-r--r--sys/src/libaml/aml.c682
-rw-r--r--sys/src/libc/mips/lock.c6
-rw-r--r--sys/src/libc/port/pool.c236
-rw-r--r--sys/src/libdraw/alloc.c4
-rw-r--r--sys/src/libdraw/badrect.c22
-rw-r--r--sys/src/libdraw/emenuhit.c3
-rw-r--r--sys/src/libdraw/menuhit.c3
-rw-r--r--sys/src/libdraw/mkfile1
-rw-r--r--sys/src/libdraw/window.c13
-rw-r--r--sys/src/libmemdraw/alloc.c13
-rw-r--r--sys/src/libmemdraw/cload.c2
-rw-r--r--sys/src/libmemdraw/draw.c24
-rw-r--r--sys/src/libmemdraw/load.c2
-rw-r--r--sys/src/libmemdraw/unload.c2
87 files changed, 4447 insertions, 905 deletions
diff --git a/lib/bullshit b/lib/bullshit
index 2e2ac6ee8..01a633f8d 100644
--- a/lib/bullshit
+++ b/lib/bullshit
@@ -20,6 +20,7 @@ template
realtime |
realtime-java |
just-in-time |
+full-stack |
API
service
event
diff --git a/lib/face/48x48x8/n/nixie.1 b/lib/face/48x48x8/n/nixie.1
index 064755f19..82ff860b0 100644
--- a/lib/face/48x48x8/n/nixie.1
+++ b/lib/face/48x48x8/n/nixie.1
Binary files differ
diff --git a/lib/font/bit/germgoth/unicode.12.font b/lib/font/bit/germgoth/unicode.12.font
new file mode 100644
index 000000000..34b1d4db3
--- /dev/null
+++ b/lib/font/bit/germgoth/unicode.12.font
@@ -0,0 +1,146 @@
+15 11
+0xff00 0xfff8 ../fixed/6x12.FF00
+0xfe00 0xfeff ../fixed/6x12.FE00
+0xfb00 0xfbff ../fixed/6x12.FB00
+0xf101 0xf201 germgoth.12.f101
+0x4d00 0x4dff ../fixed/10x20.4D00
+0x3000 0x30ff ../fixed/10x20.3000
+0x2b00 0x2bff ../fixed/10x20.2B00
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x2800 0x28ff ../fixed/10x20.2800
+0x2700 0x27ff ../fixed/10x20.2700
+0x2600 0x26ff ../fixed/10x20.2600
+0x2500 0x25ff ../fixed/10x20.2500
+0x2400 0x24ff ../fixed/10x20.2400
+0x2320 0x23ff ../fixed/10x20.2300
+0x2219 0x2319 germgoth.12.2219
+0x2190 0x21ea ../misc/arrows
+0x2119 0x2189 ../fixed/10x20.2100
+0x2018 0x2118 germgoth.12.2018
+0x2000 0x2017 ../fixed/10x20.2000
+0x1f00 0x1fff ../fixed/10x20.1F00
+0x1e00 0x1eff ../fixed/10x20.1E00
+0x1d00 0x1dff ../fixed/10x20.1D00
+0x1600 0x16ff ../fixed/10x20.1600
+0x1300 0x13ff ../fixed/10x20.1300
+0x1200 0x12ff ../fixed/10x20.1200
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x0600 0x06ff ../fixed/10x20.0600
+0x0500 0x05ff ../fixed/10x20.0500
+0x0400 0x04ff ../fixed/10x20.0400
+0x03c7 0x03ff ../fixed/10x20.0300
+0x02c6 0x03c6 germgoth.12.02c6
+0x0232 0x02c5 ../fixed/10x20.0200
+0x0131 0x0231 germgoth.12.0131
+0x007f 0x007f ../palatino/R.6.1
+0x0000 0x0130 germgoth.12.0000
+0x2100 0x21ff ../fixed/7x14.2100
+0x2200 0x22ff ../fixed/7x14.2200
+0x2300 0x23ff ../fixed/7x14.2300
+0x4e00 0x4ffe ../shinonome/k12.4e00
+0x5005 0x51fe ../shinonome/k12.5005
+0x5200 0x53fa ../shinonome/k12.5200
+0x5401 0x55fe ../shinonome/k12.5401
+0x5606 0x57fc ../shinonome/k12.5606
+0x5800 0x59ff ../shinonome/k12.5800
+0x5a01 0x5bff ../shinonome/k12.5a01
+0x5c01 0x5dfe ../shinonome/k12.5c01
+0x5e02 0x5fff ../shinonome/k12.5e02
+0x600e 0x61ff ../shinonome/k12.600e
+0x6200 0x63fa ../shinonome/k12.6200
+0x6406 0x65fb ../shinonome/k12.6406
+0x6602 0x67ff ../shinonome/k12.6602
+0x6802 0x69ff ../shinonome/k12.6802
+0x6a02 0x6bf3 ../shinonome/k12.6a02
+0x6c08 0x6dfb ../shinonome/k12.6c08
+0x6e05 0x6ffe ../shinonome/k12.6e05
+0x7001 0x71ff ../shinonome/k12.7001
+0x7206 0x73fe ../shinonome/k12.7206
+0x7403 0x75ff ../shinonome/k12.7403
+0x7601 0x77fc ../shinonome/k12.7601
+0x7802 0x79fb ../shinonome/k12.7802
+0x7a00 0x7bf7 ../shinonome/k12.7a00
+0x7c00 0x7dfb ../shinonome/k12.7c00
+0x7e01 0x7ffc ../shinonome/k12.7e01
+0x8000 0x81fe ../shinonome/k12.8000
+0x8201 0x83fd ../shinonome/k12.8201
+0x8403 0x85fe ../shinonome/k12.8403
+0x8602 0x87fe ../shinonome/k12.8602
+0x8805 0x89f8 ../shinonome/k12.8805
+0x8a00 0x8b9a ../shinonome/k12.8a00
+0x8c37 0x8dff ../shinonome/k12.8c37
+0x8e08 0x8ffd ../shinonome/k12.8e08
+0x9000 0x91ff ../shinonome/k12.9000
+0x920d 0x93e8 ../shinonome/k12.920d
+0x9403 0x95e5 ../shinonome/k12.9403
+0x961c 0x97ff ../shinonome/k12.961c
+0x9801 0x99ff ../shinonome/k12.9801
+0x9a01 0x9bf5 ../shinonome/k12.9a01
+0x9c04 0x9dfd ../shinonome/k12.9c04
+0x9e1a 0x9fa0 ../shinonome/k12.9e1a
+0xff00 0xffff ../fixed/7x14.FF00
+0x1000 0x10ff ../fixed/9x15.1000
+0x2900 0x29ff ../fixed/9x15.2900
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0xfc00 0xfcff ../vga/vgafc
+0xfd00 0xfdff ../vga/vgafd
+0x1100 0x11ff ../fixed/6x13.1100
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0xf6c5 0xf7c5 ../dejavusans/dejavusans.12.f6c5
+0xf001 0xf101 ../dejavusans/dejavusans.12.f001
+0xef00 0xf000 ../dejavusans/dejavusans.12.ef00
+0xa746 0xa846 ../dejavusans/dejavusans.12.a746
+0xa644 0xa744 ../dejavusans/dejavusans.12.a644
+0x2d61 0x2e61 ../dejavusans/dejavusans.12.2d61
+0x2c60 0x2d60 ../dejavusans/dejavusans.12.2c60
+0x0f00 0x0f3f ../dejavusans/dejavusans.12.0e3f
+0x07c0 0x08c0 ../dejavusans/dejavusans.12.07c0
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xf400 0xf500 ../dejavu/dejavu.12.f400
+0x2e18 0x2f18 ../dejavu/dejavu.12.2e18
+0x2b00 0x2c00 ../dejavu/dejavu.12.2b00
+0x4e00 0x4fff ../jis/jis4e00.24
+0x5000 0x51ff ../jis/jis5000.24
+0x5200 0x53ff ../jis/jis5200.24
+0x5400 0x55ff ../jis/jis5400.24
+0x5600 0x57ff ../jis/jis5600.24
+0x5a00 0x5bff ../jis/jis5a00.24
+0x5c00 0x5dff ../jis/jis5c00.24
+0x5e00 0x5fff ../jis/jis5e00.24
+0x6000 0x61ff ../jis/jis6000.24
+0x6200 0x63ff ../jis/jis6200.24
+0x6400 0x65ff ../jis/jis6400.24
+0x6600 0x67ff ../jis/jis6600.24
+0x6800 0x69ff ../jis/jis6800.24
+0x6a00 0x6bff ../jis/jis6a00.24
+0x6c00 0x6dff ../jis/jis6c00.24
+0x6e00 0x6fff ../jis/jis6e00.24
+0x7000 0x71ff ../jis/jis7000.24
+0x7200 0x73ff ../jis/jis7200.24
+0x7400 0x75ff ../jis/jis7400.24
+0x7600 0x77ff ../jis/jis7600.24
+0x7800 0x79ff ../jis/jis7800.24
+0x7a00 0x7bff ../jis/jis7a00.24
+0x7c00 0x7dff ../jis/jis7c00.24
+0x7e00 0x7fff ../jis/jis7e00.24
+0x8000 0x81ff ../jis/jis8000.24
+0x8200 0x83ff ../jis/jis8200.24
+0x8400 0x85ff ../jis/jis8400.24
+0x8600 0x87ff ../jis/jis8600.24
+0x8800 0x89ff ../jis/jis8800.24
+0x8a00 0x8bff ../jis/jis8a00.24
+0x8c00 0x8dff ../jis/jis8c00.24
+0x8e00 0x8fff ../jis/jis8e00.24
+0x9200 0x93ff ../jis/jis9200.24
+0x9400 0x95ff ../jis/jis9400.24
+0x9600 0x97ff ../jis/jis9600.24
+0x9800 0x99ff ../jis/jis9800.24
+0x9a00 0x9bff ../jis/jis9a00.24
+0x9c00 0x9dff ../jis/jis9c00.24
+0x9e00 0x9fff ../jis/jis9e00.24
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.12.f6c4
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.12.f5c5
+0x1700 0x1746 ../dejavusansit/dejavusansit.12.1646
+0x2010 0x21d4 ../shinonome/k12.2010
diff --git a/lib/font/bit/germgoth/unicode.14.font b/lib/font/bit/germgoth/unicode.14.font
new file mode 100644
index 000000000..b2487cdf3
--- /dev/null
+++ b/lib/font/bit/germgoth/unicode.14.font
@@ -0,0 +1,153 @@
+17 12
+0xff00 0xfff8 ../fixed/6x12.FF00
+0xfe00 0xfeff ../fixed/6x12.FE00
+0xfb00 0xfbff ../fixed/6x12.FB00
+0xf101 0xf201 germgoth.14.f101
+0x4d00 0x4dff ../fixed/10x20.4D00
+0x3000 0x30ff ../fixed/10x20.3000
+0x2b00 0x2bff ../fixed/10x20.2B00
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x2800 0x28ff ../fixed/10x20.2800
+0x2700 0x27ff ../fixed/10x20.2700
+0x2600 0x26ff ../fixed/10x20.2600
+0x2500 0x25ff ../fixed/10x20.2500
+0x2400 0x24ff ../fixed/10x20.2400
+0x2320 0x23ff ../fixed/10x20.2300
+0x2219 0x2319 germgoth.14.2219
+0x2190 0x21ea ../misc/arrows
+0x2119 0x2189 ../fixed/10x20.2100
+0x2018 0x2118 germgoth.14.2018
+0x2000 0x2017 ../fixed/10x20.2000
+0x1f00 0x1fff ../fixed/10x20.1F00
+0x1e00 0x1eff ../fixed/10x20.1E00
+0x1d00 0x1dff ../fixed/10x20.1D00
+0x1600 0x16ff ../fixed/10x20.1600
+0x1300 0x13ff ../fixed/10x20.1300
+0x1200 0x12ff ../fixed/10x20.1200
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x0600 0x06ff ../fixed/10x20.0600
+0x0500 0x05ff ../fixed/10x20.0500
+0x0400 0x04ff ../fixed/10x20.0400
+0x03c7 0x03ff ../fixed/10x20.0300
+0x02c6 0x03c6 germgoth.14.02c6
+0x0232 0x02c5 ../fixed/10x20.0200
+0x0131 0x0231 germgoth.14.0131
+0x007f 0x007f ../palatino/R.6.1
+0x0000 0x0130 germgoth.14.0000
+0xfff9 0xffff ../dejavu/dejavu.12.fff9
+0xfb00 0xfc00 ../dejavu/dejavu.12.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.12.f6c5
+0xf400 0xf500 ../dejavu/dejavu.12.f400
+0xa746 0xa846 ../dejavu/dejavu.12.a746
+0xa644 0xa744 ../dejavu/dejavu.12.a644
+0x2e18 0x2f18 ../dejavu/dejavu.12.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.12.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.12.2b00
+0x29eb 0x2aeb ../dejavu/dejavu.12.29eb
+0x28a2 0x29a2 ../dejavu/dejavu.12.28a2
+0x2310 0x2410 ../dejavu/dejavu.12.2310
+0x220b 0x230b ../dejavu/dejavu.12.220b
+0x2109 0x2209 ../dejavu/dejavu.12.2109
+0x10a0 0x11a0 ../dejavu/dejavu.12.10a0
+0xf001 0xf101 ../dejavusans/dejavusans.12.f001
+0xef00 0xf000 ../dejavusans/dejavusans.12.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.12.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.12.2d61
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x21fc 0x22f7 ../dejavusans/dejavusans.12.21fc
+0x1502 0x15ff ../dejavusans/dejavusans.12.1502
+0x1401 0x1501 ../dejavusans/dejavusans.12.1401
+0x0f00 0x0f3f ../dejavusans/dejavusans.12.0e3f
+0x07c0 0x08c0 ../dejavusans/dejavusans.12.07c0
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0x4e00 0x4ffe ../shinonome/k12.4e00
+0x5005 0x51fe ../shinonome/k12.5005
+0x5200 0x53fa ../shinonome/k12.5200
+0x5401 0x55fe ../shinonome/k12.5401
+0x5606 0x57fc ../shinonome/k12.5606
+0x5800 0x59ff ../shinonome/k12.5800
+0x5a01 0x5bff ../shinonome/k12.5a01
+0x5c01 0x5dfe ../shinonome/k12.5c01
+0x5e02 0x5fff ../shinonome/k12.5e02
+0x600e 0x61ff ../shinonome/k12.600e
+0x6200 0x63fa ../shinonome/k12.6200
+0x6406 0x65fb ../shinonome/k12.6406
+0x6602 0x67ff ../shinonome/k12.6602
+0x6802 0x69ff ../shinonome/k12.6802
+0x6a02 0x6bf3 ../shinonome/k12.6a02
+0x6c08 0x6dfb ../shinonome/k12.6c08
+0x6e05 0x6ffe ../shinonome/k12.6e05
+0x7001 0x71ff ../shinonome/k12.7001
+0x7206 0x73fe ../shinonome/k12.7206
+0x7403 0x75ff ../shinonome/k12.7403
+0x7601 0x77fc ../shinonome/k12.7601
+0x7802 0x79fb ../shinonome/k12.7802
+0x7a00 0x7bf7 ../shinonome/k12.7a00
+0x7c00 0x7dfb ../shinonome/k12.7c00
+0x7e01 0x7ffc ../shinonome/k12.7e01
+0x8000 0x81fe ../shinonome/k12.8000
+0x8201 0x83fd ../shinonome/k12.8201
+0x8403 0x85fe ../shinonome/k12.8403
+0x8602 0x87fe ../shinonome/k12.8602
+0x8805 0x89f8 ../shinonome/k12.8805
+0x8a00 0x8b9a ../shinonome/k12.8a00
+0x8c37 0x8dff ../shinonome/k12.8c37
+0x8e08 0x8ffd ../shinonome/k12.8e08
+0x9000 0x91ff ../shinonome/k12.9000
+0x920d 0x93e8 ../shinonome/k12.920d
+0x9403 0x95e5 ../shinonome/k12.9403
+0x961c 0x97ff ../shinonome/k12.961c
+0x9801 0x99ff ../shinonome/k12.9801
+0x9a01 0x9bf5 ../shinonome/k12.9a01
+0x9c04 0x9dfd ../shinonome/k12.9c04
+0x9e1a 0x9fa0 ../shinonome/k12.9e1a
+0x1000 0x10ff ../fixed/9x15.1000
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0x1400 0x14ff ../fixed/9x18.1400
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0x4e00 0x4fff ../jis/jis4e00.24
+0x5000 0x51ff ../jis/jis5000.24
+0x5200 0x53ff ../jis/jis5200.24
+0x5400 0x55ff ../jis/jis5400.24
+0x5600 0x57ff ../jis/jis5600.24
+0x5a00 0x5bff ../jis/jis5a00.24
+0x5c00 0x5dff ../jis/jis5c00.24
+0x5e00 0x5fff ../jis/jis5e00.24
+0x6000 0x61ff ../jis/jis6000.24
+0x6200 0x63ff ../jis/jis6200.24
+0x6400 0x65ff ../jis/jis6400.24
+0x6600 0x67ff ../jis/jis6600.24
+0x6800 0x69ff ../jis/jis6800.24
+0x6a00 0x6bff ../jis/jis6a00.24
+0x6c00 0x6dff ../jis/jis6c00.24
+0x6e00 0x6fff ../jis/jis6e00.24
+0x7000 0x71ff ../jis/jis7000.24
+0x7200 0x73ff ../jis/jis7200.24
+0x7400 0x75ff ../jis/jis7400.24
+0x7600 0x77ff ../jis/jis7600.24
+0x7800 0x79ff ../jis/jis7800.24
+0x7a00 0x7bff ../jis/jis7a00.24
+0x7c00 0x7dff ../jis/jis7c00.24
+0x7e00 0x7fff ../jis/jis7e00.24
+0x8000 0x81ff ../jis/jis8000.24
+0x8200 0x83ff ../jis/jis8200.24
+0x8400 0x85ff ../jis/jis8400.24
+0x8600 0x87ff ../jis/jis8600.24
+0x8800 0x89ff ../jis/jis8800.24
+0x8a00 0x8bff ../jis/jis8a00.24
+0x8c00 0x8dff ../jis/jis8c00.24
+0x8e00 0x8fff ../jis/jis8e00.24
+0x9200 0x93ff ../jis/jis9200.24
+0x9400 0x95ff ../jis/jis9400.24
+0x9600 0x97ff ../jis/jis9600.24
+0x9800 0x99ff ../jis/jis9800.24
+0x9a00 0x9bff ../jis/jis9a00.24
+0x9c00 0x9dff ../jis/jis9c00.24
+0x9e00 0x9fff ../jis/jis9e00.24
+0x1100 0x11ff ../fixed/6x13.1100
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.12.f6c4
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.12.f5c5
+0x1700 0x1746 ../dejavusansit/dejavusansit.12.1646
+0x2010 0x21d4 ../shinonome/k14.2010
diff --git a/lib/font/bit/germgoth/unicode.16.font b/lib/font/bit/germgoth/unicode.16.font
new file mode 100644
index 000000000..4d7dcdae3
--- /dev/null
+++ b/lib/font/bit/germgoth/unicode.16.font
@@ -0,0 +1,153 @@
+20 14
+0xff00 0xfff8 ../fixed/6x12.FF00
+0xfe00 0xfeff ../fixed/6x12.FE00
+0xfb00 0xfbff ../fixed/6x12.FB00
+0xf101 0xf201 germgoth.16.f101
+0x4d00 0x4dff ../fixed/10x20.4D00
+0x3000 0x30ff ../fixed/10x20.3000
+0x2b00 0x2bff ../fixed/10x20.2B00
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x2800 0x28ff ../fixed/10x20.2800
+0x2700 0x27ff ../fixed/10x20.2700
+0x2600 0x26ff ../fixed/10x20.2600
+0x2500 0x25ff ../fixed/10x20.2500
+0x2400 0x24ff ../fixed/10x20.2400
+0x2320 0x23ff ../fixed/10x20.2300
+0x2219 0x2319 germgoth.16.2219
+0x2190 0x21ea ../misc/arrows
+0x2119 0x2189 ../fixed/10x20.2100
+0x2018 0x2118 germgoth.16.2018
+0x2000 0x2017 ../fixed/10x20.2000
+0x1f00 0x1fff ../fixed/10x20.1F00
+0x1e00 0x1eff ../fixed/10x20.1E00
+0x1d00 0x1dff ../fixed/10x20.1D00
+0x1600 0x16ff ../fixed/10x20.1600
+0x1300 0x13ff ../fixed/10x20.1300
+0x1200 0x12ff ../fixed/10x20.1200
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x0600 0x06ff ../fixed/10x20.0600
+0x0500 0x05ff ../fixed/10x20.0500
+0x0400 0x04ff ../fixed/10x20.0400
+0x03c7 0x03ff ../fixed/10x20.0300
+0x02c6 0x03c6 germgoth.16.02c6
+0x0232 0x02c5 ../fixed/10x20.0200
+0x0131 0x0231 germgoth.16.0131
+0x007f 0x007f ../palatino/R.6.1
+0x0000 0x0130 germgoth.16.0000
+0xfff9 0xffff ../dejavu/dejavu.14.fff9
+0xfb00 0xfc00 ../dejavu/dejavu.14.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.14.f6c5
+0xf400 0xf500 ../dejavu/dejavu.14.f400
+0xa746 0xa846 ../dejavu/dejavu.14.a746
+0xa644 0xa744 ../dejavu/dejavu.14.a644
+0x2e18 0x2f18 ../dejavu/dejavu.14.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.14.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.14.2b00
+0x29eb 0x2aeb ../dejavu/dejavu.14.29eb
+0x28a2 0x29a2 ../dejavu/dejavu.14.28a2
+0x10a0 0x11a0 ../dejavu/dejavu.14.10a0
+0xf001 0xf101 ../dejavusans/dejavusans.14.f001
+0xef00 0xf000 ../dejavusans/dejavusans.14.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.14.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.14.2d61
+0x2104 0x21fb ../dejavusans/dejavusans.14.2104
+0x1401 0x1501 ../dejavusans/dejavusans.14.1401
+0x0f00 0x0f3f ../dejavusans/dejavusans.14.0e3f
+0x4e00 0x4ffe ../shinonome/k14.4e00
+0x5005 0x51fe ../shinonome/k14.5005
+0x5200 0x53fa ../shinonome/k14.5200
+0x5401 0x55fe ../shinonome/k14.5401
+0x5606 0x57fc ../shinonome/k14.5606
+0x5800 0x59ff ../shinonome/k14.5800
+0x5a01 0x5bff ../shinonome/k14.5a01
+0x5c01 0x5dfe ../shinonome/k14.5c01
+0x5e02 0x5fff ../shinonome/k14.5e02
+0x600e 0x61ff ../shinonome/k14.600e
+0x6200 0x63fa ../shinonome/k14.6200
+0x6406 0x65fb ../shinonome/k14.6406
+0x6602 0x67ff ../shinonome/k14.6602
+0x6802 0x69ff ../shinonome/k14.6802
+0x6a02 0x6bf3 ../shinonome/k14.6a02
+0x6c08 0x6dfb ../shinonome/k14.6c08
+0x6e05 0x6ffe ../shinonome/k14.6e05
+0x7001 0x71ff ../shinonome/k14.7001
+0x7206 0x73fe ../shinonome/k14.7206
+0x7403 0x75ff ../shinonome/k14.7403
+0x7601 0x77fc ../shinonome/k14.7601
+0x7802 0x79fb ../shinonome/k14.7802
+0x7a00 0x7bf7 ../shinonome/k14.7a00
+0x7c00 0x7dfb ../shinonome/k14.7c00
+0x7e01 0x7ffc ../shinonome/k14.7e01
+0x8000 0x81fe ../shinonome/k14.8000
+0x8201 0x83fd ../shinonome/k14.8201
+0x8403 0x85fe ../shinonome/k14.8403
+0x8602 0x87fe ../shinonome/k14.8602
+0x8805 0x89f8 ../shinonome/k14.8805
+0x8a00 0x8b9a ../shinonome/k14.8a00
+0x8c37 0x8dff ../shinonome/k14.8c37
+0x8e08 0x8ffd ../shinonome/k14.8e08
+0x9000 0x91ff ../shinonome/k14.9000
+0x920d 0x93e8 ../shinonome/k14.920d
+0x9403 0x95e5 ../shinonome/k14.9403
+0x961c 0x97ff ../shinonome/k14.961c
+0x9801 0x99ff ../shinonome/k14.9801
+0x9a01 0x9bf5 ../shinonome/k14.9a01
+0x9c04 0x9dfd ../shinonome/k14.9c04
+0x9e1a 0x9fa0 ../shinonome/k14.9e1a
+0x1000 0x10ff ../fixed/10x20.1000
+0x2200 0x227f ../misc/math1
+0x2300 0x232c ../misc/tech
+0x4e00 0x4fff ../jis/jis4e00.16
+0x5000 0x51ff ../jis/jis5000.16
+0x5200 0x53ff ../jis/jis5200.16
+0x5400 0x55ff ../jis/jis5400.16
+0x5600 0x57ff ../jis/jis5600.16
+0x5a00 0x5bff ../jis/jis5a00.16
+0x5c00 0x5dff ../jis/jis5c00.16
+0x5e00 0x5fff ../jis/jis5e00.16
+0x6000 0x61ff ../jis/jis6000.16
+0x6200 0x63ff ../jis/jis6200.16
+0x6400 0x65ff ../jis/jis6400.16
+0x6600 0x67ff ../jis/jis6600.16
+0x6800 0x69ff ../jis/jis6800.16
+0x6a00 0x6bff ../jis/jis6a00.16
+0x6c00 0x6dff ../jis/jis6c00.16
+0x6e00 0x6fff ../jis/jis6e00.16
+0x7000 0x71ff ../jis/jis7000.16
+0x7200 0x73ff ../jis/jis7200.16
+0x7400 0x75ff ../jis/jis7400.16
+0x7600 0x77ff ../jis/jis7600.16
+0x7800 0x79ff ../jis/jis7800.16
+0x7a00 0x7bff ../jis/jis7a00.16
+0x7c00 0x7dff ../jis/jis7c00.16
+0x7e00 0x7fff ../jis/jis7e00.16
+0x8000 0x81ff ../jis/jis8000.16
+0x8200 0x83ff ../jis/jis8200.16
+0x8400 0x85ff ../jis/jis8400.16
+0x8600 0x87ff ../jis/jis8600.16
+0x8800 0x89ff ../jis/jis8800.16
+0x8a00 0x8bff ../jis/jis8a00.16
+0x8c00 0x8dff ../jis/jis8c00.16
+0x8e00 0x8fff ../jis/jis8e00.16
+0x9200 0x93ff ../jis/jis9200.16
+0x9400 0x95ff ../jis/jis9400.16
+0x9600 0x97ff ../jis/jis9600.16
+0x9800 0x99ff ../jis/jis9800.16
+0x9a00 0x9bff ../jis/jis9a00.16
+0x9c00 0x9dff ../jis/jis9c00.16
+0x9e00 0x9fff ../jis/jis9e00.16
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0x2100 0x21ff ../fixed/10x20.2100
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x07c0 0x08c0 ../dejavusans/dejavusans.12.07c0
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0x1100 0x11ff ../fixed/6x13.1100
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.14.f6c4
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.14.f5c5
+0x2010 0x21d4 ../shinonome/k16.2010
+0x1700 0x1746 ../dejavusansit/dejavusansit.12.1646
diff --git a/lib/font/bit/germgoth/unicode.18.font b/lib/font/bit/germgoth/unicode.18.font
new file mode 100644
index 000000000..eae1b1076
--- /dev/null
+++ b/lib/font/bit/germgoth/unicode.18.font
@@ -0,0 +1,153 @@
+23 16
+0xff00 0xfff8 ../fixed/6x12.FF00
+0xfe00 0xfeff ../fixed/6x12.FE00
+0xfb00 0xfbff ../fixed/6x12.FB00
+0xf101 0xf201 germgoth.18.f101
+0x4d00 0x4dff ../fixed/10x20.4D00
+0x3000 0x30ff ../fixed/10x20.3000
+0x2b00 0x2bff ../fixed/10x20.2B00
+0x2a00 0x2aff ../fixed/10x20.2A00
+0x2800 0x28ff ../fixed/10x20.2800
+0x2700 0x27ff ../fixed/10x20.2700
+0x2600 0x26ff ../fixed/10x20.2600
+0x2500 0x25ff ../fixed/10x20.2500
+0x2400 0x24ff ../fixed/10x20.2400
+0x2320 0x23ff ../fixed/10x20.2300
+0x2219 0x2319 germgoth.18.2219
+0x2190 0x21ea ../misc/arrows
+0x2119 0x2189 ../fixed/10x20.2100
+0x2018 0x2118 germgoth.18.2018
+0x2000 0x2017 ../fixed/10x20.2000
+0x1f00 0x1fff ../fixed/10x20.1F00
+0x1e00 0x1eff ../fixed/10x20.1E00
+0x1d00 0x1dff ../fixed/10x20.1D00
+0x1600 0x16ff ../fixed/10x20.1600
+0x1300 0x13ff ../fixed/10x20.1300
+0x1200 0x12ff ../fixed/10x20.1200
+0x0e00 0x0eff ../fixed/10x20.0E00
+0x0600 0x06ff ../fixed/10x20.0600
+0x0500 0x05ff ../fixed/10x20.0500
+0x0400 0x04ff ../fixed/10x20.0400
+0x03c7 0x03ff ../fixed/10x20.0300
+0x02c6 0x03c6 germgoth.18.02c6
+0x0232 0x02c5 ../fixed/10x20.0200
+0x0131 0x0231 germgoth.18.0131
+0x007f 0x007f ../palatino/R.6.1
+0x0000 0x0130 germgoth.18.0000
+0xfff9 0xffff ../dejavu/dejavu.16.fff9
+0xfb00 0xfc00 ../dejavu/dejavu.16.fb00
+0xf6c5 0xf7c5 ../dejavu/dejavu.16.f6c5
+0xf400 0xf500 ../dejavu/dejavu.16.f400
+0xa746 0xa846 ../dejavu/dejavu.16.a746
+0xa644 0xa744 ../dejavu/dejavu.16.a644
+0x2e18 0x2f18 ../dejavu/dejavu.16.2e18
+0x2c60 0x2d60 ../dejavu/dejavu.16.2c60
+0x2b00 0x2c00 ../dejavu/dejavu.16.2b00
+0x28a2 0x29a2 ../dejavu/dejavu.16.28a2
+0x10a0 0x11a0 ../dejavu/dejavu.16.10a0
+0xf001 0xf101 ../dejavusans/dejavusans.16.f001
+0xef00 0xf000 ../dejavusans/dejavusans.16.ef00
+0x4dc0 0x4ec0 ../dejavusans/dejavusans.16.4dc0
+0x2d61 0x2e61 ../dejavusans/dejavusans.16.2d61
+0x1401 0x1501 ../dejavusans/dejavusans.16.1401
+0x0f00 0x0f3f ../dejavusans/dejavusans.16.0e3f
+0x07c0 0x08c0 ../dejavusans/dejavusans.16.07c0
+0x4e00 0x4ffe ../shinonome/k16.4e00
+0x5005 0x51fe ../shinonome/k16.5005
+0x5200 0x53fa ../shinonome/k16.5200
+0x5401 0x55fe ../shinonome/k16.5401
+0x5606 0x57fc ../shinonome/k16.5606
+0x5800 0x59ff ../shinonome/k16.5800
+0x5a01 0x5bff ../shinonome/k16.5a01
+0x5c01 0x5dfe ../shinonome/k16.5c01
+0x5e02 0x5fff ../shinonome/k16.5e02
+0x600e 0x61ff ../shinonome/k16.600e
+0x6200 0x63fa ../shinonome/k16.6200
+0x6406 0x65fb ../shinonome/k16.6406
+0x6602 0x67ff ../shinonome/k16.6602
+0x6802 0x69ff ../shinonome/k16.6802
+0x6a02 0x6bf3 ../shinonome/k16.6a02
+0x6c08 0x6dfb ../shinonome/k16.6c08
+0x6e05 0x6ffe ../shinonome/k16.6e05
+0x7001 0x71ff ../shinonome/k16.7001
+0x7206 0x73fe ../shinonome/k16.7206
+0x7403 0x75ff ../shinonome/k16.7403
+0x7601 0x77fc ../shinonome/k16.7601
+0x7802 0x79fb ../shinonome/k16.7802
+0x7a00 0x7bf7 ../shinonome/k16.7a00
+0x7c00 0x7dfb ../shinonome/k16.7c00
+0x7e01 0x7ffc ../shinonome/k16.7e01
+0x8000 0x81fe ../shinonome/k16.8000
+0x8201 0x83fd ../shinonome/k16.8201
+0x8403 0x85fe ../shinonome/k16.8403
+0x8602 0x87fe ../shinonome/k16.8602
+0x8805 0x89f8 ../shinonome/k16.8805
+0x8a00 0x8b9a ../shinonome/k16.8a00
+0x8c37 0x8dff ../shinonome/k16.8c37
+0x8e08 0x8ffd ../shinonome/k16.8e08
+0x9000 0x91ff ../shinonome/k16.9000
+0x920d 0x93e8 ../shinonome/k16.920d
+0x9403 0x95e5 ../shinonome/k16.9403
+0x961c 0x97ff ../shinonome/k16.961c
+0x9801 0x99ff ../shinonome/k16.9801
+0x9a01 0x9bf5 ../shinonome/k16.9a01
+0x9c04 0x9dfd ../shinonome/k16.9c04
+0x9e1a 0x9fa0 ../shinonome/k16.9e1a
+0x2100 0x21ea ../lucida/Letterlike.9.0
+0x2200 0x22f1 ../lucida/MathOps1.9.0
+0x1000 0x10ff ../fixed/10x20.1000
+0x2100 0x21ff ../fixed/10x20.2100
+0x2300 0x23ff ../fixed/10x20.2300
+0xfc00 0xfcff ../fixed/10x20.FC00
+0xfd00 0xfdff ../fixed/10x20.FD00
+0x4e00 0x4fff ../jis/jis4e00.24
+0x5000 0x51ff ../jis/jis5000.24
+0x5200 0x53ff ../jis/jis5200.24
+0x5400 0x55ff ../jis/jis5400.24
+0x5600 0x57ff ../jis/jis5600.24
+0x5a00 0x5bff ../jis/jis5a00.24
+0x5c00 0x5dff ../jis/jis5c00.24
+0x5e00 0x5fff ../jis/jis5e00.24
+0x6000 0x61ff ../jis/jis6000.24
+0x6200 0x63ff ../jis/jis6200.24
+0x6400 0x65ff ../jis/jis6400.24
+0x6600 0x67ff ../jis/jis6600.24
+0x6800 0x69ff ../jis/jis6800.24
+0x6a00 0x6bff ../jis/jis6a00.24
+0x6c00 0x6dff ../jis/jis6c00.24
+0x6e00 0x6fff ../jis/jis6e00.24
+0x7000 0x71ff ../jis/jis7000.24
+0x7200 0x73ff ../jis/jis7200.24
+0x7400 0x75ff ../jis/jis7400.24
+0x7600 0x77ff ../jis/jis7600.24
+0x7800 0x79ff ../jis/jis7800.24
+0x7a00 0x7bff ../jis/jis7a00.24
+0x7c00 0x7dff ../jis/jis7c00.24
+0x7e00 0x7fff ../jis/jis7e00.24
+0x8000 0x81ff ../jis/jis8000.24
+0x8200 0x83ff ../jis/jis8200.24
+0x8400 0x85ff ../jis/jis8400.24
+0x8600 0x87ff ../jis/jis8600.24
+0x8800 0x89ff ../jis/jis8800.24
+0x8a00 0x8bff ../jis/jis8a00.24
+0x8c00 0x8dff ../jis/jis8c00.24
+0x8e00 0x8fff ../jis/jis8e00.24
+0x9200 0x93ff ../jis/jis9200.24
+0x9400 0x95ff ../jis/jis9400.24
+0x9600 0x97ff ../jis/jis9600.24
+0x9800 0x99ff ../jis/jis9800.24
+0x9a00 0x9bff ../jis/jis9a00.24
+0x9c00 0x9dff ../jis/jis9c00.24
+0x9e00 0x9fff ../jis/jis9e00.24
+0x29eb 0x2aeb ../dejavu/dejavu.14.29eb
+0x1400 0x14ff ../fixed/9x18.1400
+0x1500 0x15ff ../fixed/9x18.1500
+0x2940 0x2a40 ../dejavusans/dejavusans.12.2940
+0x0606 0x0706 ../dejavusans/dejavusans.12.0606
+0xe000 0xe0ff ../fixed/9x15.E000
+0xe700 0xe7ff ../fixed/9x15.E700
+0x1100 0x11ff ../fixed/6x13.1100
+0xf6c4 0xf7c4 ../dejavubi/dejavubi.16.f6c4
+0x1700 0x1746 ../dejavusansbd/dejavusansbd.16.1646
+0xf5c5 0xf6c5 ../dejavusansbi/dejavusansbi.16.f5c5
+0x2010 0x21d4 ../shinonome/k16.2010
diff --git a/lib/rob b/lib/rob
index ca92dade9..facefc329 100644
--- a/lib/rob
+++ b/lib/rob
@@ -138,3 +138,4 @@ This statement demonstrates a profound misunderstanding.
I guess that wasn't very helpful.
The proposed fix is perhaps not the best one.
It's only an issue on mailing lists and discussion groups.
+Let me put in a word about the Apple wireless trackpad.
diff --git a/rc/bin/sysinfo b/rc/bin/sysinfo
index a071458c3..8905368f8 100755
--- a/rc/bin/sysinfo
+++ b/rc/bin/sysinfo
@@ -1,13 +1,11 @@
#!/bin/rc
rfork e
-
fn logprog{
echo % `{echo $"* | sed 's/#/''#''/g'}
$*
echo
}
-
-fn work{
+fn print{
echo '% cd ''#ec''; for(i in *){echo $i ''='' `{cat $i}}'
cd '#ec'; for(i in *){echo $i '=' `{cat $i}}
echo
@@ -42,11 +40,42 @@ fn work{
logprog cat '#A/volume'
logprog cat /mnt/apm/ctl
}
-
-switch($1){
-case -m
- {echo Subject: `{cat '#P/cputype'}; work} >[2=1] |
- user=/dev/null upas/smtp 9front.org $user hardware@9front.org
-case *
- work
+fn post{
+ file=/tmp/sysinfo.$user.$pid
+ if(! ~ $#e 0)
+ echo $e >$file
+ print >>$file >[2=1]
+ @{
+ rfork n
+ webfs
+ hpost -u http://sysinfo.9front.org -p / a_body@$file submit:submit fake:fake a_func:add_post url: |
+ grep -e '\/body\"' |
+ sed 1q | sed 's/^.*href=\"//g; s/body\".*$/body/g; s/^/http:\/\/sysinfo.9front.org/g'
+ rm -f $file
+ }
+}
+argv0=$0
+fn usage {
+ echo usage: $argv0 '[ -e e-mail ] [ -p ]' >[1=2]
+ exit usage
+}
+e=()
+p=()
+while(~ $1 -*){
+ switch($1){
+ case -e
+ e=$2
+ shift
+ case -p
+ p=1
+ shift
+ case *
+ usage
+ }
+ shift
}
+if(~ $p 1)
+ post
+
+if not
+ print
diff --git a/sys/games/lib/fortunes b/sys/games/lib/fortunes
index 7933c5ee9..d3c6de57f 100644
--- a/sys/games/lib/fortunes
+++ b/sys/games/lib/fortunes
@@ -4876,3 +4876,16 @@ PART (flamingnoms) #cat-v "compiling clang"
While many are concerned about the reach of PRISM overseas, the Finnish Foreign Minister says he plans to continue using Outlook for email.
As The Web Improves, Apple's Platforms Look Increasingly Broken
(#go-nuts) cronos → damn, how many apis are there?
+What does German soldiers during World War II have in common with the UNIX philosophy of “worse is better”? 
+Introducing WOW! AT&T World of Women: our newest website
+Bringing Israelis And Palestinians Together With Mobile Apps
+18:10 < mischief> is there a way to execute plan 9 programs in linuxemu?
+For example, whilst he was playing to me, a favourite cat came in, upon which he immediately left his harpsichord, nor could we bring him back for a considerable time.
+Subject: [dev] daemon for DWM
+Subject: [inferno-list] Goth - Inferno in Go
+/* die */
+Subject: [dev] lisp
+As always, do not blindly enter commands you do not understand into your computer. -- OpenBSD FAQ
+When Will Architects Speak Up for Women’s Rights?
+So much for capitalism being the great "driver" of the economy.
+For each droplet of ink the printer creates a fairly strong spike of electrical energy, and these spikes provide a signature specific to each printer model.
diff --git a/sys/include/ape/draw.h b/sys/include/ape/draw.h
index 8b621636c..6b0e130d1 100644
--- a/sys/include/ape/draw.h
+++ b/sys/include/ape/draw.h
@@ -408,6 +408,7 @@ extern int cmap2rgb(int);
extern int cmap2rgba(int);
extern void icossin(int, int*, int*);
extern void icossin2(int, int, int*, int*);
+extern int badrect(Rectangle);
/*
* Graphics
diff --git a/sys/include/draw.h b/sys/include/draw.h
index 20c5c3eb3..a6ec71230 100644
--- a/sys/include/draw.h
+++ b/sys/include/draw.h
@@ -401,6 +401,7 @@ extern int cmap2rgb(int);
extern int cmap2rgba(int);
extern void icossin(int, int*, int*);
extern void icossin2(int, int, int*, int*);
+extern int badrect(Rectangle);
/*
* Graphics
diff --git a/sys/man/1/jpg b/sys/man/1/jpg
index 9ec0153fc..e242fa6e8 100644
--- a/sys/man/1/jpg
+++ b/sys/man/1/jpg
@@ -1,6 +1,6 @@
.TH JPG 1
.SH NAME
-jpg, gif, png, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm, topng, toico \- view and convert pictures
+jpg, gif, png, tif, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm, topng, toico \- view and convert pictures
.SH SYNOPSIS
.B jpg
[
@@ -23,6 +23,13 @@ jpg, gif, png, ppm, bmp, v210, yuv, ico, tga, tojpg, togeordi, togif, toppm, top
.I file ...
]
.br
+.B tif
+[
+.B -39cdektv
+] [
+.I file ...
+]
+.br
.B ppm
[
.B -39cdektv
@@ -137,6 +144,7 @@ These programs read, display, and write image files in public formats.
.IR Jpg ,
.IR gif ,
.IR png ,
+.IR tif ,
.IR ppm ,
.IR bmp ,
.IR tga ,
@@ -156,8 +164,14 @@ read Plan 9 images files, convert them to JPEG, GIF, PPM, or PNG, and write them
The default behavior of
.IR jpg ,
.IR gif ,
+.IR png ,
+.IR tif ,
+.IR ppm ,
+.IR bmp ,
+.IR tga ,
+.IR v210 ,
and
-.IR ppm
+.IR yuv
is to display the
.IR file ,
or standard input if no file is named.
@@ -227,11 +241,12 @@ The input is a motion JPEG file, with multiple images representing frames of the
.PP
The
.IR tojpg ,
-.IR togif
-and
+.IR togif ,
.IR toppm
-programs go the other way: they convert from Plan 9 images to JPEG, GIF and PPM,
-and have no display capability.
+and
+.IR topng
+programs go the other way: they convert from Plan 9 images to JPEG, GIF,
+PPM and PNG and have no display capability.
They all accept an option
.B -c
to set the comment field of the resulting file.
@@ -323,6 +338,8 @@ space in the image. The icon file is written to standard output.
.br
.B http://www.w3.org/TR/2003/REC-PNG-20031110
.br
+.B http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
+.br
.B http://netpbm.sourceforge.net/doc/ppm.html
.br
.B http://en.wikipedia.org/wiki/Windows_bitmap
diff --git a/sys/man/1/sysinfo b/sys/man/1/sysinfo
index 1ecef1d74..01f96517f 100644
--- a/sys/man/1/sysinfo
+++ b/sys/man/1/sysinfo
@@ -4,7 +4,10 @@ sysinfo, sysupdate \- report information about, update the system
.SH SYNOPSIS
.B sysinfo
[
-.B -m
+.B -e e-mail
+]
+[
+.B -p
]
.br
.B sysupdate
@@ -19,11 +22,20 @@ the running system, concatenating the output to
stdout.
.PP
The
-.B -m
-flag causes the output to be piped to a mail command,
-whose recipient is
-.B hardware@9front.org.
-This flag is useful for reporting new installs to the
+.B -p
+flag causes the output to be posted at a website
+archive,
+.B http://sysinfo.9front.org,
+which in turn forwards the message to a
+mailing list,
+.B 9front-sysinfo@9front.org.
+A URL pointing to the archived output is returned.
+The
+.B -e
+flag causes a reply-to e-mail address to be included
+in the message (the e-mail address is not divulged
+to the mailing list).
+These flags are useful for reporting new installs to the
development team.
.PP
.I Sysupdate
diff --git a/sys/man/1/vnc b/sys/man/1/vnc
index 49cbe0eb5..fbf1f5373 100644
--- a/sys/man/1/vnc
+++ b/sys/man/1/vnc
@@ -194,41 +194,6 @@ start TLS on the connection.
.B -v
print verbose output to standard error.
.PD
-.PP
-The VNC protocol represents keyboard input as
-key up/down events.
-Plan 9 does not expose the state of the
-Ctl and Shift keys except as it can be inferred
-from receipt of control or shifted characters.
-It does not expose the state of the Alt key at all,
-since the Alt key is used to compose Unicode characters
-(see
-.IR keyboard (6)).
-.I Vncv
-correctly handles the sending of control and shifted
-characters.
-To support systems that use key sequences like Alt-X
-(or worse, Alt-mouse-click), typing the Plan 9 compose
-sequences
-.B Alt
-.B Z
-.B A
-(for Alt),
-.B Alt
-.B Z
-.B C
-(for Ctrl),
-and
-.B Alt
-.B Z
-.B S
-(for Shift)
-will send a ``key down'' message for
-the given key.
-A corresponding ``key up'' message
-will be sent after the next key is pressed,
-or when the sequence is retyped,
-whichever happens first.
.SH SOURCE
.B /sys/src/cmd/vnc
.SH "SEE ALSO
diff --git a/sys/man/8/hjfs b/sys/man/8/hjfs
index e7f84740c..49573fbb4 100644
--- a/sys/man/8/hjfs
+++ b/sys/man/8/hjfs
@@ -27,6 +27,8 @@ hjfs \- file server maintenance
.I name
.RI [ options ]
.PP
+.B users
+.PP
.B sync
.PP
.B debug-chdeind
@@ -113,10 +115,6 @@ owned by user and group
The options are
.TF =leaderxx
.TP
-.B ?
-Print the entry for
-.IR name .
-.TP
.B :
Add a group: add the name to
.B /adm/users
@@ -157,6 +155,12 @@ command the file server overwrites
.B /adm/users
to reflect the internal state of the user table.
.PP
+.I Users
+reads the contents of file
+.B /adm/users
+to initialize the file server's internal representation of the
+users structure.
+.PP
.I Sync
writes dirty blocks in memory to the magnetic disk cache.
.PP
diff --git a/sys/man/8/plan9.ini b/sys/man/8/plan9.ini
index 61115f7fd..bbd6f317a 100644
--- a/sys/man/8/plan9.ini
+++ b/sys/man/8/plan9.ini
@@ -392,18 +392,28 @@ or
.B /boot.
To select the access point, the
.B essid=
-parameter can be specified at boot or set during runtime
+and
+.B bssid=
+parameters can be specified at boot or set during runtime
like:
.EX
echo essid left-armpit >/net/ether1/clone
.EE
+If both
+.B essid=
+and
+.B bssid=
+are specified, both must match.
Scan results appear in the
.B ifstats
file and can be read out like:
.EX
cat /net/ether1/ifstats
.EE
-Ad-hoc mode or encryption is currently not supported.
+Ad-hoc mode or WEP encryption is currently not supported.
+To enable WPA/WPA2 encryption, see
+.IR wpa (8)
+for details.
.SS DISKS, TAPES
(S)ATA controllers are autodetected.
.SS \fL*nodma=\fP
@@ -720,6 +730,9 @@ processors.
Prints a summary of the multiprocessor APIC interrupt configuration.
.SS \fL*nomsi=\fP
Disables message signaled interrupts.
+.SS \fL*notsc=\fP
+Disables the use of the per processor timestamp counter registers
+as high resolution clock.
.SS \fL*pcimaxbno=value\fP
This puts a limit on the maximum bus number probed
on a PCI bus (default 7).
diff --git a/sys/src/9/ip/ethermedium.c b/sys/src/9/ip/ethermedium.c
index 1aab2b9ec..f5b4e855d 100644
--- a/sys/src/9/ip/ethermedium.c
+++ b/sys/src/9/ip/ethermedium.c
@@ -354,11 +354,12 @@ etherread4(void *a)
nexterror();
}
ifc->in++;
- bp->rp += ifc->m->hsize;
- if(ifc->lifc == nil)
+ if(ifc->lifc == nil || BLEN(bp) <= ifc->m->hsize)
freeb(bp);
- else
+ else {
+ bp->rp += ifc->m->hsize;
ipiput4(er->f, ifc, bp);
+ }
runlock(ifc);
poperror();
}
@@ -393,11 +394,12 @@ etherread6(void *a)
nexterror();
}
ifc->in++;
- bp->rp += ifc->m->hsize;
- if(ifc->lifc == nil)
+ if(ifc->lifc == nil || BLEN(bp) <= ifc->m->hsize)
freeb(bp);
- else
+ else {
+ bp->rp += ifc->m->hsize;
ipiput6(er->f, ifc, bp);
+ }
runlock(ifc);
poperror();
}
diff --git a/sys/src/9/pc/apic.c b/sys/src/9/pc/apic.c
index eada39531..f27adb81e 100644
--- a/sys/src/9/pc/apic.c
+++ b/sys/src/9/pc/apic.c
@@ -89,14 +89,17 @@ static uchar lapictdxtab[] = { /* LapicTDCR */
static ulong* lapicbase;
-struct
+typedef struct Apictimer Apictimer;
+struct Apictimer
{
uvlong hz;
ulong max;
ulong min;
ulong div;
int tdx;
-} lapictimer;
+};
+
+static Apictimer lapictimer[MAXMACH];
static ulong
lapicr(int r)
@@ -115,15 +118,25 @@ lapicw(int r, ulong data)
void
lapiconline(void)
{
+ Apictimer *a;
+
+ a = &lapictimer[m->machno];
+
/*
* Reload the timer to de-synchronise the processors,
* then lower the task priority to allow interrupts to be
* accepted by the APIC.
*/
microdelay((TK2MS(1)*1000/conf.nmach) * m->machno);
- lapicw(LapicTICR, lapictimer.max);
+ lapicw(LapicTICR, a->max);
lapicw(LapicTIMER, LapicCLKIN|LapicPERIODIC|(VectorPIC+IrqTIMER));
+ /*
+ * not strickly neccesary, but reported (osdev.org) to be
+ * required for some machines.
+ */
+ lapicw(LapicTDCR, lapictdxtab[a->tdx]);
+
lapicw(LapicTPR, 0);
}
@@ -133,35 +146,44 @@ lapiconline(void)
static void
lapictimerinit(void)
{
+ uvlong x, v, hz;
+ Apictimer *a;
+ int s;
+
+ s = splhi();
+ a = &lapictimer[m->machno];
+ a->tdx = 0;
Retry:
- lapicw(LapicTDCR, lapictdxtab[lapictimer.tdx]);
lapicw(LapicTIMER, ApicIMASK|LapicCLKIN|LapicONESHOT|(VectorPIC+IrqTIMER));
-
- if(lapictimer.hz == 0ULL){
- uvlong x, v, hz;
-
- x = fastticks(&hz);
- x += hz/10;
- lapicw(LapicTICR, 0xffffffff);
- do{
- v = fastticks(nil);
- }while(v < x);
-
- v = (0xffffffffUL-lapicr(LapicTCCR))*10;
- if(v > hz-(hz/10)){
- if(v > hz+(hz/10) && lapictimer.tdx < nelem(lapictdxtab)-1){
- lapictimer.tdx++;
- goto Retry;
- }
- v = hz;
+ lapicw(LapicTDCR, lapictdxtab[a->tdx]);
+
+ x = fastticks(&hz);
+ x += hz/10;
+ lapicw(LapicTICR, 0xffffffff);
+ do{
+ v = fastticks(nil);
+ }while(v < x);
+
+ v = (0xffffffffUL-lapicr(LapicTCCR))*10;
+ if(v > hz-(hz/10)){
+ if(v > hz+(hz/10) && a->tdx < nelem(lapictdxtab)-1){
+ a->tdx++;
+ goto Retry;
}
- assert(v != 0);
-
- lapictimer.hz = v;
- lapictimer.div = hz/lapictimer.hz;
- lapictimer.max = lapictimer.hz/HZ;
- lapictimer.min = lapictimer.hz/(100*HZ);
+ v = hz;
}
+
+ assert(v >= (100*HZ));
+
+ a->hz = v;
+ a->div = hz/a->hz;
+ a->max = a->hz/HZ;
+ a->min = a->hz/(100*HZ);
+
+ splx(s);
+
+ v = (v+500000LL)/1000000LL;
+ print("cpu%d: lapic clock at %lludMHz\n", m->machno, v);
}
void
@@ -371,25 +393,19 @@ void
lapictimerset(uvlong next)
{
vlong period;
- int x;
-
- x = splhi();
- lock(&m->apictimerlock);
+ Apictimer *a;
- period = lapictimer.max;
+ a = &lapictimer[m->machno];
+ period = a->max;
if(next != 0){
period = next - fastticks(nil);
- period /= lapictimer.div;
-
- if(period < lapictimer.min)
- period = lapictimer.min;
- else if(period > lapictimer.max - lapictimer.min)
- period = lapictimer.max;
+ period /= a->div;
+ if(period < a->min)
+ period = a->min;
+ else if(period > a->max - a->min)
+ period = a->max;
}
lapicw(LapicTICR, period);
-
- unlock(&m->apictimerlock);
- splx(x);
}
void
diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c
index 243b8996c..45e3b938d 100644
--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -37,6 +37,10 @@ struct Tbl {
uchar data[];
};
+enum {
+ Tblsz = 4+4+1+1+6+8+4+4+4,
+};
+
static Rsd *rsd;
/* physical addresses visited by maptable() */
@@ -82,7 +86,7 @@ get64(uchar *p){
static uint
tbldlen(Tbl *t){
- return get32(t->len) - sizeof(Tbl);
+ return get32(t->len) - Tblsz;
}
static void
@@ -109,7 +113,7 @@ maptable(uvlong xpa)
if((t = vmap(pa, 8)) == nil)
return;
l = get32(t->len);
- if(l < sizeof(Tbl)){
+ if(l < Tblsz){
vunmap(t, 8);
return;
}
@@ -396,7 +400,7 @@ Foundapic:
a->addr = va;
a->lintr[0] = ApicIMASK;
a->lintr[1] = ApicIMASK;
- a->flags = (p[4] & PcmpEN);
+ a->flags = p[4] & PcmpEN;
if(a->flags & PcmpEN){
a->machno = machno++;
@@ -515,7 +519,7 @@ identify(void)
return 1;
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
return 1;
- if(cpuserver && m->havetsc)
+ if(m->havetsc && getconf("*notsc") == nil)
archacpi.fastclock = tscticks;
return 0;
}
diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c
index bbde765a0..b5eb89805 100644
--- a/sys/src/9/pc/archmp.c
+++ b/sys/src/9/pc/archmp.c
@@ -395,7 +395,7 @@ identify(void)
return 1;
}
- if(cpuserver && m->havetsc)
+ if(m->havetsc && getconf("*notsc") == nil)
archmp.fastclock = tscticks;
return 0;
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h
index 862dc344a..8ba2d018e 100644
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -242,7 +242,6 @@ struct Mach
int loopconst;
- Lock apictimerlock;
int cpumhz;
uvlong cyclefreq; /* Frequency of user readable cycle counter */
uvlong cpuhz;
diff --git a/sys/src/9/pc/etheriwl.c b/sys/src/9/pc/etheriwl.c
index 6c192a6b7..9bf90ef07 100644
--- a/sys/src/9/pc/etheriwl.c
+++ b/sys/src/9/pc/etheriwl.c
@@ -1723,6 +1723,8 @@ rxon(Ether *edev, Wnode *bss)
filter = FilterNoDecrypt | FilterMulticast | FilterBeacon;
if(ctlr->prom){
filter |= FilterPromisc;
+ if(bss != nil)
+ ctlr->channel = bss->channel;
bss = nil;
}
if(bss != nil){
@@ -1743,8 +1745,16 @@ rxon(Ether *edev, Wnode *bss)
}
flags = RFlagTSF | RFlagCTSToSelf | RFlag24Ghz | RFlagAuto;
- if(0) print("rxon: bssid %E, aid %x, channel %d, filter %x, flags %x\n",
- ctlr->bssid, ctlr->aid, ctlr->channel, filter, flags);
+ if(ctlr->aid != 0)
+ setled(ctlr, 2, 0, 1); /* on when associated */
+ else if(memcmp(ctlr->bssid, edev->bcast, Eaddrlen) != 0)
+ setled(ctlr, 2, 10, 10); /* slow blink when connecting */
+ else
+ setled(ctlr, 2, 5, 5); /* fast blink when scanning */
+
+ if(ctlr->wifi->debug)
+ print("#l%d: rxon: bssid %E, aid %x, channel %d, filter %x, flags %x\n",
+ edev->ctlrno, ctlr->bssid, ctlr->aid, ctlr->channel, filter, flags);
memset(p = c, 0, sizeof(c));
memmove(p, edev->ea, 6); p += 8; /* myaddr */
@@ -1833,7 +1843,6 @@ transmit(Wifi *wifi, Wnode *wn, Block *b)
Wifipkt *w;
char *err;
- w = (Wifipkt*)b->rp;
edev = wifi->ether;
ctlr = edev->ctlr;
@@ -1844,15 +1853,20 @@ transmit(Wifi *wifi, Wnode *wn, Block *b)
return;
}
- if(ctlr->prom == 0)
- if(wn->aid != ctlr->aid
- || wn->channel != ctlr->channel
- || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)
+ if((wn->channel != ctlr->channel)
+ || (!ctlr->prom && (wn->aid != ctlr->aid || memcmp(wn->bssid, ctlr->bssid, Eaddrlen) != 0)))
rxon(edev, wn);
+ if(b == nil){
+ /* association note has no data to transmit */
+ qunlock(ctlr);
+ return;
+ }
+
rate = 0;
flags = 0;
nodeid = ctlr->bcastnodeid;
+ w = (Wifipkt*)b->rp;
if((w->a1[0] & 1) == 0){
flags |= TFlagNeedACK;
@@ -1943,14 +1957,21 @@ iwlifstat(Ether *edev, void *buf, long n, ulong off)
static void
setoptions(Ether *edev)
{
+ char buf[64], *p;
Ctlr *ctlr;
- char buf[64];
int i;
ctlr = edev->ctlr;
for(i = 0; i < edev->nopt; i++){
- if(strncmp(edev->opt[i], "essid=", 6) == 0){
- snprint(buf, sizeof(buf), "essid %s", edev->opt[i]+6);
+ snprint(buf, sizeof(buf), "%s", edev->opt[i]);
+ p = strchr(buf, '=');
+ if(p != nil)
+ *p = 0;
+ if(strcmp(buf, "debug") == 0
+ || strcmp(buf, "essid") == 0
+ || strcmp(buf, "bssid") == 0){
+ if(p != nil)
+ *p = ' ';
if(!waserror()){
wifictl(ctlr->wifi, buf, strlen(buf));
poperror();
@@ -1974,60 +1995,8 @@ iwlpromiscuous(void *arg, int on)
}
static void
-iwlproc(void *arg)
-{
- Ether *edev;
- Ctlr *ctlr;
- Wifi *wifi;
- Wnode *bss;
-
- edev = arg;
- ctlr = edev->ctlr;
- wifi = ctlr->wifi;
-
- for(;;){
- /* hop channels for catching beacons */
- setled(ctlr, 2, 5, 5);
- while(wifi->bss == nil){
- qlock(ctlr);
- if(wifi->bss != nil){
- qunlock(ctlr);
- break;
- }
- ctlr->channel = 1 + ctlr->channel % 11;
- ctlr->aid = 0;
- rxon(edev, nil);
- qunlock(ctlr);
- tsleep(&up->sleep, return0, 0, 1000);
- }
-
- /* wait for association */
- setled(ctlr, 2, 10, 10);
- while((bss = wifi->bss) != nil){
- if(bss->aid != 0)
- break;
- tsleep(&up->sleep, return0, 0, 1000);
- }
-
- if(bss == nil)
- continue;
-
- /* wait for disassociation */
- edev->link = 1;
- setled(ctlr, 2, 0, 1);
- while((bss = wifi->bss) != nil){
- if(bss->aid == 0)
- break;
- tsleep(&up->sleep, return0, 0, 1000);
- }
- edev->link = 0;
- }
-}
-
-static void
iwlattach(Ether *edev)
{
- char name[32];
FWImage *fw;
Ctlr *ctlr;
char *err;
@@ -2072,9 +2041,6 @@ iwlattach(Ether *edev)
setoptions(edev);
- snprint(name, sizeof(name), "#l%diwl", edev->ctlrno);
- kproc(name, iwlproc, edev);
-
ctlr->attached = 1;
}
qunlock(ctlr);
diff --git a/sys/src/9/pc/mtrr.c b/sys/src/9/pc/mtrr.c
index dc8e52baa..b40bf0de6 100644
--- a/sys/src/9/pc/mtrr.c
+++ b/sys/src/9/pc/mtrr.c
@@ -290,6 +290,8 @@ mtrr(uvlong base, uvlong size, char *tstr)
qlock(&mtrrlk);
slot = -1;
vcnt = cap & Capvcnt;
+ if(vcnt > Nmtrr)
+ vcnt = Nmtrr;
for(i = 0; i < vcnt; i++){
mtrrget(&mtrr, i);
mok = mtrrdec(&mtrr, &mp, &msize, &mtype);
@@ -330,6 +332,8 @@ mtrrprint(char *buf, long bufsize)
n += snprint(buf+n, bufsize-n, "cache default %s\n",
type2str(def & Deftype));
vcnt = cap & Capvcnt;
+ if(vcnt > Nmtrr)
+ vcnt = Nmtrr;
for(i = 0; i < vcnt; i++){
mtrrget(&mtrr, i);
if (mtrrdec(&mtrr, &base, &size, &type))
diff --git a/sys/src/9/pc/wifi.c b/sys/src/9/pc/wifi.c
index 1f0bd73b2..0e6ae0c3a 100644
--- a/sys/src/9/pc/wifi.c
+++ b/sys/src/9/pc/wifi.c
@@ -29,10 +29,11 @@ enum {
SNAPHDRSIZE = 8,
};
-static char Snone[] = "new";
static char Sconn[] = "connecting";
static char Sauth[] = "authenticated";
-static char Sunauth[] = "unauthentictaed";
+static char Sneedauth[] = "need authentication";
+static char Sunauth[] = "unauthenticated";
+
static char Sassoc[] = "associated";
static char Sunassoc[] = "unassociated";
static char Sblocked[] = "blocked"; /* no keys negotiated. only pass EAPOL frames */
@@ -132,6 +133,8 @@ wifitx(Wifi *wifi, Wnode *wn, Block *b)
Wifipkt *w;
uint seq;
+ wn->lastsend = MACHP(0)->ticks;
+
seq = incref(&wifi->txseq);
seq <<= 4;
@@ -170,7 +173,7 @@ nodelookup(Wifi *wifi, uchar *bssid, int new)
wn->lastseen = MACHP(0)->ticks;
return wn;
}
- if(wn->lastseen < nn->lastseen)
+ if((long)(wn->lastseen - nn->lastseen) < 0)
nn = wn;
}
if(!new)
@@ -182,6 +185,51 @@ nodelookup(Wifi *wifi, uchar *bssid, int new)
}
static void
+wifiprobe(Wifi *wifi, Wnode *wn)
+{
+ Wifipkt *w;
+ Block *b;
+ uchar *p;
+ int n;
+
+ n = strlen(wifi->essid);
+ if(n == 0){
+ /* no specific essid, just tell driver to tune channel */
+ (*wifi->transmit)(wifi, wn, nil);
+ return;
+ }
+
+ b = allocb(WIFIHDRSIZE + 512);
+ w = (Wifipkt*)b->wp;
+ w->fc[0] = 0x40; /* probe request */
+ w->fc[1] = 0x00; /* STA->STA */
+ memmove(w->a1, wifi->ether->bcast, Eaddrlen); /* ??? */
+ memmove(w->a2, wifi->ether->ea, Eaddrlen);
+ memmove(w->a3, wifi->ether->bcast, Eaddrlen);
+ b->wp += WIFIHDRSIZE;
+ p = b->wp;
+
+ *p++ = 0x00; /* set */
+ *p++ = n;
+ memmove(p, wifi->essid, n);
+ p += n;
+
+ *p++ = 1; /* RATES (BUG: these are all lies!) */
+ *p++ = 4;
+ *p++ = 0x82;
+ *p++ = 0x84;
+ *p++ = 0x8b;
+ *p++ = 0x96;
+
+ *p++ = 0x03; /* ds parameter set */
+ *p++ = 1;
+ *p++ = wn->channel;
+
+ b->wp = p;
+ wifitx(wifi, wn, b);
+}
+
+static void
sendauth(Wifi *wifi, Wnode *bss)
{
Wifipkt *w;
@@ -204,6 +252,9 @@ sendauth(Wifi *wifi, Wnode *bss)
*p++ = 0; /* status */
*p++ = 0;
b->wp = p;
+
+ bss->aid = 0;
+
wifitx(wifi, bss, b);
}
@@ -252,6 +303,21 @@ sendassoc(Wifi *wifi, Wnode *bss)
}
static void
+setstatus(Wifi *wifi, Wnode *wn, char *new)
+{
+ char *old;
+
+ old = wn->status;
+ wn->status = new;
+ if(wifi->debug && new != old)
+ print("#l%d: status %E: %s -> %s (from pc=%#p)\n",
+ wifi->ether->ctlrno,
+ wn->bssid,
+ old, new,
+ getcallerpc(&wifi));
+}
+
+static void
recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
{
uint s;
@@ -266,20 +332,20 @@ recvassoc(Wifi *wifi, Wnode *wn, uchar *d, int len)
case 0x00:
wn->aid = d[0] | d[1]<<8;
if(wn->rsnelen > 0)
- wifi->status = Sblocked;
+ setstatus(wifi, wn, Sblocked);
else
- wifi->status = Sassoc;
+ setstatus(wifi, wn, Sassoc);
break;
default:
wn->aid = 0;
- wifi->status = Sunassoc;
- return;
+ setstatus(wifi, wn, Sunassoc);
}
}
static void
recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
{
+ static uchar wpa1oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
uchar *e, *x;
uchar t, m[256/8];
@@ -304,7 +370,7 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
m[t/8] |= 1<<(t%8);
switch(t){
- case 0: /* SSID */
+ case 0x00: /* SSID */
len = 0;
while(len < Essidlen && d+len < x && d[len] != 0)
len++;
@@ -315,15 +381,67 @@ recvbeacon(Wifi *, Wnode *wn, uchar *d, int len)
wn->ssid[len] = 0;
}
break;
- case 3: /* DSPARAMS */
+ case 0x03: /* DSPARAMS */
if(d != x)
wn->channel = d[0];
break;
+ case 0xdd: /* vendor specific */
+ len = x - d;
+ if(len < sizeof(wpa1oui) || memcmp(d, wpa1oui, sizeof(wpa1oui)) != 0)
+ break;
+ /* no break */
+ case 0x30: /* RSN information */
+ len = x - &d[-2];
+ memmove(wn->brsne, &d[-2], len);
+ wn->brsnelen = len;
+ break;
}
}
}
static void
+wifideauth(Wifi *wifi, Wnode *wn)
+{
+ Ether *ether;
+ Netfile *f;
+ int i;
+
+ /* deassociate node, clear keys */
+ setstatus(wifi, wn, Sunauth);
+ memset(wn->rxkey, 0, sizeof(wn->rxkey));
+ memset(wn->txkey, 0, sizeof(wn->txkey));
+ wn->aid = 0;
+
+ if(wn == wifi->bss){
+ /* notify driver about node aid association */
+ (*wifi->transmit)(wifi, wn, nil);
+
+ /* notify aux/wpa with a zero length write that we got deassociated from the ap */
+ ether = wifi->ether;
+ for(i=0; i<ether->nfile; i++){
+ f = ether->f[i];
+ if(f == nil || f->in == nil || f->inuse == 0 || f->type != 0x888e)
+ continue;
+ qwrite(f->in, 0, 0);
+ }
+ }
+}
+
+/* check if a node qualifies as our bss matching bssid and essid */
+static int
+goodbss(Wifi *wifi, Wnode *wn)
+{
+ if(memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) != 0){
+ if(memcmp(wifi->bssid, wn->bssid, Eaddrlen) != 0)
+ return 0; /* bssid doesnt match */
+ } else if(wifi->essid[0] == 0)
+ return 0; /* both bssid and essid unspecified */
+ if(wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) != 0)
+ return 0; /* essid doesnt match */
+ return 1;
+}
+
+static void
wifiproc(void *arg)
{
Wifi *wifi;
@@ -341,7 +459,7 @@ wifiproc(void *arg)
w = (Wifipkt*)b->rp;
if(w->fc[1] & 0x40){
/* encrypted */
- if((wn = nodelookup(wifi, w->a2, 1)) == nil)
+ if((wn = nodelookup(wifi, w->a2, 0)) == nil)
continue;
if((b = wifidecrypt(wifi, wn, b)) != nil){
w = (Wifipkt*)b->rp;
@@ -355,42 +473,57 @@ wifiproc(void *arg)
/* management */
if((w->fc[0] & 0x0c) != 0x00)
continue;
+
switch(w->fc[0] & 0xf0){
case 0x50: /* probe response */
+ if(wifi->debug)
+ print("#l%d: got probe from %E\n", wifi->ether->ctlrno, w->a3);
+ /* no break */
case 0x80: /* beacon */
if((wn = nodelookup(wifi, w->a3, 1)) == nil)
continue;
b->rp += wifihdrlen(w);
recvbeacon(wifi, wn, b->rp, BLEN(b));
- if(wifi->bss == nil && wifi->essid[0] != 0 && strcmp(wifi->essid, wn->ssid) == 0){
- wifi->bss = wn;
- wifi->status = Sconn;
+
+ if(wifi->bss == nil
+ && TK2MS(MACHP(0)->ticks - wn->lastsend) > 1000
+ && goodbss(wifi, wn)){
+ setstatus(wifi, wn, Sconn);
sendauth(wifi, wn);
}
continue;
}
+
if(memcmp(w->a1, wifi->ether->ea, Eaddrlen))
continue;
if((wn = nodelookup(wifi, w->a3, 0)) == nil)
continue;
- if(wn != wifi->bss)
- continue;
switch(w->fc[0] & 0xf0){
case 0x10: /* assoc response */
case 0x30: /* reassoc response */
b->rp += wifihdrlen(w);
recvassoc(wifi, wn, b->rp, BLEN(b));
+ /* notify driver about node aid association */
+ if(wn == wifi->bss)
+ (*wifi->transmit)(wifi, wn, nil);
break;
case 0xb0: /* auth */
- wifi->status = Sauth;
- sendassoc(wifi, wn);
+ if(wifi->debug)
+ print("#l%d: got auth from %E\n", wifi->ether->ctlrno, wn->bssid);
+ if(wn->brsnelen > 0 && wn->rsnelen == 0)
+ setstatus(wifi, wn, Sneedauth);
+ else
+ setstatus(wifi, wn, Sauth);
+ if(wifi->bss == nil && goodbss(wifi, wn)){
+ wifi->bss = wn;
+ if(wn->status == Sauth)
+ sendassoc(wifi, wn);
+ }
break;
case 0xc0: /* deauth */
- wifi->status = Sunauth;
- memset(wn->rxkey, 0, sizeof(wn->rxkey));
- memset(wn->txkey, 0, sizeof(wn->txkey));
- wn->aid = 0;
- sendauth(wifi, wn);
+ if(wifi->debug)
+ print("#l%d: got deauth from %E\n", wifi->ether->ctlrno, wn->bssid);
+ wifideauth(wifi, wn);
break;
}
}
@@ -413,11 +546,11 @@ wifietheroq(Wifi *wifi, Block *b)
memmove(&e, b->rp, ETHERHDRSIZE);
b->rp += ETHERHDRSIZE;
- if(wifi->status == Sblocked){
+ if(wn->status == Sblocked){
/* only pass EAPOL frames when port is blocked */
if((e.type[0]<<8 | e.type[1]) != 0x888e)
goto drop;
- } else if(wifi->status != Sassoc)
+ } else if(wn->status != Sassoc)
goto drop;
b = padblock(b, WIFIHDRSIZE + SNAPHDRSIZE);
@@ -457,6 +590,56 @@ wifoproc(void *arg)
pexit("ether out queue closed", 0);
}
+static void
+wifsproc(void *arg)
+{
+ Ether *ether;
+ Wifi *wifi;
+ Wnode wnscan;
+ Wnode *wn;
+ ulong now, tmout;
+
+ wifi = arg;
+ ether = wifi->ether;
+
+ wn = &wnscan;
+ memset(wn, 0, sizeof(*wn));
+ memmove(wn->bssid, ether->bcast, Eaddrlen);
+
+ while(waserror())
+ ;
+Scan:
+ /* scan for access point */
+ while(wifi->bss == nil){
+ ether->link = 0;
+ wnscan.channel = 1 + wnscan.channel % 11;
+ wifiprobe(wifi, &wnscan);
+ tsleep(&up->sleep, return0, 0, 1000);
+ }
+
+ /* maintain access point */
+ tmout = 0;
+ while((wn = wifi->bss) != nil){
+ ether->link = (wn->status == Sassoc) || (wn->status == Sblocked);
+ now = MACHP(0)->ticks;
+ if(wn->status != Sneedauth && TK2SEC(now - wn->lastseen) > 60 || goodbss(wifi, wn) == 0){
+ wifideauth(wifi, wn);
+ wifi->bss = nil;
+ break;
+ }
+ if(TK2MS(now - wn->lastsend) > 1000){
+ if(wn->status == Sauth && (++tmout & 7) == 0)
+ wifideauth(wifi, wn); /* stuck in auth, start over */
+ if(wn->status == Sconn || wn->status == Sunauth)
+ sendauth(wifi, wn);
+ if(wn->status == Sauth)
+ sendassoc(wifi, wn);
+ }
+ tsleep(&up->sleep, return0, 0, 500);
+ }
+ goto Scan;
+}
+
Wifi*
wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
{
@@ -473,12 +656,16 @@ wifiattach(Ether *ether, void (*transmit)(Wifi*, Wnode*, Block*))
}
wifi->ether = ether;
wifi->transmit = transmit;
- wifi->status = Snone;
+
+ wifi->essid[0] = 0;
+ memmove(wifi->bssid, ether->bcast, Eaddrlen);
snprint(name, sizeof(name), "#l%dwifi", ether->ctlrno);
kproc(name, wifiproc, wifi);
snprint(name, sizeof(name), "#l%dwifo", ether->ctlrno);
kproc(name, wifoproc, wifi);
+ snprint(name, sizeof(name), "#l%dwifs", ether->ctlrno);
+ kproc(name, wifsproc, wifi);
return wifi;
}
@@ -541,10 +728,10 @@ parsekey(Wkey *k, char *s)
}
enum {
+ CMdebug,
CMessid,
CMauth,
- CMunblock,
-
+ CMbssid,
CMrxkey0,
CMrxkey1,
CMrxkey2,
@@ -555,8 +742,10 @@ enum {
static Cmdtab wifictlmsg[] =
{
+ CMdebug, "debug", 0,
CMessid, "essid", 0,
CMauth, "auth", 0,
+ CMbssid, "bssid", 0,
CMrxkey0, "rxkey0", 0, /* group keys */
CMrxkey1, "rxkey1", 0,
@@ -572,58 +761,91 @@ static Cmdtab wifictlmsg[] =
long
wifictl(Wifi *wifi, void *buf, long n)
{
+ uchar addr[Eaddrlen];
Cmdbuf *cb;
Cmdtab *ct;
Wnode *wn;
Wkey *k;
+ int i;
cb = nil;
if(waserror()){
free(cb);
nexterror();
}
+ if(wifi->debug)
+ print("#l%d: wifictl: %.*s\n", wifi->ether->ctlrno, (int)n, buf);
+ memmove(addr, wifi->ether->bcast, Eaddrlen);
wn = wifi->bss;
cb = parsecmd(buf, n);
ct = lookupcmd(cb, wifictlmsg, nelem(wifictlmsg));
- if(ct->index != CMessid){
- if(ct->index >= CMrxkey0 && cb->nf > 1){
- uchar addr[Eaddrlen];
-
+ if(ct->index >= CMauth){
+ if(cb->nf > 1 && (ct->index == CMbssid || ct->index >= CMrxkey0)){
if(parseether(addr, cb->f[1]) == 0){
cb->f++;
cb->nf--;
wn = nodelookup(wifi, addr, 0);
}
}
- if(wn == nil)
+ if(wn == nil && ct->index != CMbssid)
error("missing node");
}
switch(ct->index){
+ case CMdebug:
+ if(cb->f[1] != nil)
+ wifi->debug = atoi(cb->f[1]);
+ else
+ wifi->debug ^= 1;
+ print("#l%d: debug: %d\n", wifi->ether->ctlrno, wifi->debug);
+ break;
case CMessid:
- if(cb->f[1] == nil){
- wifi->essid[0] = 0;
- wifi->bss = nil;
- wifi->status = Snone;
- } else {
+ if(cb->f[1] != nil)
strncpy(wifi->essid, cb->f[1], Essidlen);
- for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
- if(strcmp(wifi->essid, wn->ssid) == 0){
- wifi->bss = wn;
- wifi->status = Sconn;
- sendauth(wifi, wn);
- break;
- }
+ else
+ wifi->essid[0] = 0;
+ Findbss:
+ wn = wifi->bss;
+ if(wn != nil){
+ if(goodbss(wifi, wn))
+ break;
+ wifideauth(wifi, wn);
}
+ wifi->bss = nil;
+ if(wifi->essid[0] == 0 && memcmp(wifi->bssid, wifi->ether->bcast, Eaddrlen) == 0)
+ break;
+ for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++)
+ if(goodbss(wifi, wn)){
+ setstatus(wifi, wn, Sconn);
+ sendauth(wifi, wn);
+ }
+ /* wait 3 seconds for authentication response */
+ for(i=0; i < 30; i++){
+ if(wifi->bss != nil)
+ goto done;
+ if(!waserror()){
+ tsleep(&up->sleep, return0, 0, 100);
+ poperror();
+ }
+ }
+ error("connect timeout");
break;
+ case CMbssid:
+ memmove(wifi->bssid, addr, Eaddrlen);
+ goto Findbss;
case CMauth:
- wifi->status = Sauth;
memset(wn->rxkey, 0, sizeof(wn->rxkey));
memset(wn->txkey, 0, sizeof(wn->txkey));
if(cb->f[1] == nil)
wn->rsnelen = 0;
else
wn->rsnelen = hextob(cb->f[1], nil, wn->rsne, sizeof(wn->rsne));
- sendassoc(wifi, wn);
+ if(wn->aid == 0){
+ setstatus(wifi, wn, Sconn);
+ sendauth(wifi, wn);
+ } else {
+ setstatus(wifi, wn, Sauth);
+ sendassoc(wifi, wn);
+ }
break;
case CMrxkey0: case CMrxkey1: case CMrxkey2: case CMrxkey3: case CMrxkey4:
case CMtxkey0:
@@ -633,10 +855,11 @@ wifictl(Wifi *wifi, void *buf, long n)
k = &wn->txkey[ct->index - CMtxkey0];
if(cb->f[1] == nil || parsekey(k, cb->f[1]) != 0)
error("bad key");
- if(ct->index >= CMtxkey0 && wifi->status == Sblocked && wifi->bss == wn)
- wifi->status = Sassoc;
+ if(ct->index >= CMtxkey0 && wn->status == Sblocked)
+ setstatus(wifi, wn, Sassoc);
break;
}
+done:
poperror();
free(cb);
return n;
@@ -649,14 +872,36 @@ wifistat(Wifi *wifi, void *buf, long n, ulong off)
char *s, *p, *e;
Wnode *wn;
long now;
+ int i;
p = s = smalloc(4096);
e = s + 4096;
- p = seprint(p, e, "status: %s\n", wifi->status);
- p = seprint(p, e, "essid: %s\n", wifi->essid);
wn = wifi->bss;
- p = seprint(p, e, "bssid: %E\n", wn != nil ? wn->bssid : zeros);
+ if(wn != nil){
+ p = seprint(p, e, "essid: %s\n", wn->ssid);
+ p = seprint(p, e, "bssid: %E\n", wn->bssid);
+ p = seprint(p, e, "status: %s\n", wn->status);
+ p = seprint(p, e, "channel: %.2d\n", wn->channel);
+
+ /* only print key ciphers and key length */
+ for(i = 0; i<nelem(wn->rxkey); i++)
+ p = seprint(p, e, "rxkey%d: %s:[%d]\n", i,
+ ciphers[wn->rxkey[i].cipher], wn->rxkey[i].len);
+ for(i = 0; i<nelem(wn->txkey); i++)
+ p = seprint(p, e, "txkey%d: %s:[%d]\n", i,
+ ciphers[wn->txkey[i].cipher], wn->txkey[i].len);
+
+ if(wn->brsnelen > 0){
+ p = seprint(p, e, "brsne: ");
+ for(i=0; i<wn->brsnelen; i++)
+ p = seprint(p, e, "%.2X", wn->brsne[i]);
+ p = seprint(p, e, "\n");
+ }
+ } else {
+ p = seprint(p, e, "essid: %s\n", wifi->essid);
+ p = seprint(p, e, "bssid: %E\n", wifi->bssid);
+ }
now = MACHP(0)->ticks;
for(wn = wifi->node; wn != &wifi->node[nelem(wifi->node)]; wn++){
diff --git a/sys/src/9/pc/wifi.h b/sys/src/9/pc/wifi.h
index 718e1038d..d338f1f04 100644
--- a/sys/src/9/pc/wifi.h
+++ b/sys/src/9/pc/wifi.h
@@ -26,28 +26,41 @@ struct Wnode
uchar bssid[Eaddrlen];
char ssid[Essidlen+2];
+ char *status;
+
int rsnelen;
- uchar rsne[256];
+ uchar rsne[258];
Wkey txkey[1];
Wkey rxkey[5];
+ int aid; /* association id */
+ ulong lastsend;
+ ulong lastseen;
+
+ /* stuff from beacon */
int ival;
int cap;
- int aid;
int channel;
- long lastseen;
+ int brsnelen;
+ uchar brsne[258];
};
struct Wifi
{
Ether *ether;
+ int debug;
+
Queue *iq;
- char *status;
+ ulong watchdog;
Ref txseq;
void (*transmit)(Wifi*, Wnode*, Block*);
+ /* for searching */
+ uchar bssid[Eaddrlen];
char essid[Essidlen+2];
+
+ /* effective base station */
Wnode *bss;
Wnode node[32];
diff --git a/sys/src/9/port/alarm.c b/sys/src/9/port/alarm.c
index fb607523b..d500a68e4 100644
--- a/sys/src/9/port/alarm.c
+++ b/sys/src/9/port/alarm.c
@@ -37,7 +37,7 @@ alarmkproc(void*)
}
/*
- * called every clock tick
+ * called every clock tick on cpu0
*/
void
checkalarms(void)
diff --git a/sys/src/9/port/devcons.c b/sys/src/9/port/devcons.c
index 53025dd5b..aacc64d3f 100644
--- a/sys/src/9/port/devcons.c
+++ b/sys/src/9/port/devcons.c
@@ -73,8 +73,7 @@ prflush(void)
*/
struct {
Lock lk;
-// char buf[16384]; /* normal */
- char buf[256*1024]; /* for acpi debugging */
+ char buf[16384];
uint n;
} kmesg;
diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c
index da51d0366..926b6ee61 100644
--- a/sys/src/9/port/devmnt.c
+++ b/sys/src/9/port/devmnt.c
@@ -794,8 +794,12 @@ mountio(Mnt *m, Mntrpc *r)
if(m->msize == 0)
panic("msize");
n = convS2M(&r->request, r->rpc, m->msize);
- if(n < 0)
- panic("bad message type in mountio");
+ if(n <= 0){
+ print("mountio: proc %s %lud: convS2M returned %d for tag %d fid %d T%d\n",
+ up->text, up->pid, n, r->request.tag, r->request.fid, r->request.type);
+ error(Emountrpc);
+ }
+
if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n)
error(Emountrpc);
r->stime = fastticks(nil);
diff --git a/sys/src/9/port/devshr.c b/sys/src/9/port/devshr.c
index 35e73629b..faac78574 100644
--- a/sys/src/9/port/devshr.c
+++ b/sys/src/9/port/devshr.c
@@ -89,7 +89,7 @@ putmpt(Mpt *mpt)
{
if(decref(mpt))
return;
- if(mpt->m.to)
+ if(mpt->m.to != nil)
cclose(mpt->m.to);
free(mpt->name);
free(mpt->owner);
@@ -148,9 +148,9 @@ shrclone(Chan *c)
nc = devclone(c);
sch = smalloc(sizeof(*sch));
memmove(sch, och, sizeof(*sch));
- if(sch->shr)
+ if(sch->shr != nil)
incref(sch->shr);
- if(sch->mpt)
+ if(sch->mpt != nil)
incref(sch->mpt);
sch->chan = nc;
nc->aux = sch;
@@ -165,9 +165,9 @@ shrclunk(Chan *c)
sch = tosch(c);
c->aux = nil;
sch->chan = nil;
- if(sch->mpt)
+ if(sch->mpt != nil)
putmpt(sch->mpt);
- if(sch->shr)
+ if(sch->shr != nil)
putshr(sch->shr);
free(sch);
}
@@ -226,7 +226,7 @@ shrwalk(Chan *c, Chan *nc, char **name, int nname)
sch->shr = nil;
} else if(sch->level == Qcroot || sch->level == Qroot) {
qlock(&shrslk);
- for(shr = shrs; shr; shr = shr->next)
+ for(shr = shrs; shr != nil; shr = shr->next)
if(strcmp(nam, shr->name) == 0){
incref(shr);
break;
@@ -242,7 +242,7 @@ shrwalk(Chan *c, Chan *nc, char **name, int nname)
shr = sch->shr;
h = &shr->umh;
rlock(&h->lock);
- for(m = h->mount; m; m = m->next){
+ for(m = h->mount; m != nil; m = m->next){
mpt = tompt(m);
if(strcmp(nam, mpt->name) == 0){
incref(mpt);
@@ -259,7 +259,7 @@ shrwalk(Chan *c, Chan *nc, char **name, int nname)
h = &shr->umh;
wq2 = nil;
rlock(&h->lock);
- for(m = h->mount; m && wq2 == nil; m = m->next){
+ for(m = h->mount; m != nil && wq2 == nil; m = m->next){
if(m->to == nil)
continue;
if(waserror())
@@ -302,7 +302,7 @@ shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
case Qroot:
case Qcroot:
qlock(&shrslk);
- for(shr = shrs; shr && s; shr = shr->next)
+ for(shr = shrs; shr != nil && s > 0; shr = shr->next)
s--;
if(shr == nil){
qunlock(&shrslk);
@@ -321,7 +321,7 @@ shrgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
shr = sch->shr;
h = &shr->umh;
rlock(&h->lock);
- for(m = h->mount; m && s; m = m->next)
+ for(m = h->mount; m != nil && s > 0; m = m->next)
s--;
if(m == nil){
runlock(&h->lock);
@@ -469,7 +469,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
qunlock(&shrslk);
nexterror();
}
- for(shr = shrs; shr; shr = shr->next)
+ for(shr = shrs; shr != nil; shr = shr->next)
if(strcmp(name, shr->name) == 0)
error(Eexist);
@@ -494,7 +494,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
case Qcshr:
if(up->pgrp->noattach)
error(Enoattach);
- if((perm & DMDIR) || openmode(omode) != OWRITE)
+ if((perm & DMDIR) != 0 || openmode(omode) != OWRITE)
error(Eperm);
shr = sch->shr;
@@ -511,7 +511,7 @@ shrcreate(Chan *c, char *name, int omode, ulong perm)
wunlock(&h->lock);
nexterror();
}
- for(m = h->mount; m; m = m->next){
+ for(m = h->mount; m != nil; m = m->next){
mpt = tompt(m);
if(strcmp(name, mpt->name) == 0)
error(Eexist);
@@ -574,13 +574,13 @@ shrremove(Chan *c)
h = &shr->umh;
qlock(&shrslk);
rlock(&h->lock);
- if(h->mount){
+ if(h->mount != nil){
runlock(&h->lock);
qunlock(&shrslk);
error("directory not empty");
}
runlock(&h->lock);
- for(sl = &shrs; *sl; sl = &((*sl)->next))
+ for(sl = &shrs; *sl != nil; sl = &((*sl)->next))
if(*sl == shr){
*sl = shr->next;
shr->next = nil;
@@ -594,7 +594,7 @@ shrremove(Chan *c)
m = &mpt->m;
h = &shr->umh;
wlock(&h->lock);
- for(ml = &h->mount; *ml; ml = &((*ml)->next))
+ for(ml = &h->mount; *ml != nil; ml = &((*ml)->next))
if(*ml == m){
*ml = m->next;
m->next = nil;
@@ -618,6 +618,15 @@ shrwstat(Chan *c, uchar *dp, int n)
Ent *ent;
Dir d;
+ strs = smalloc(n);
+ if(waserror()){
+ free(strs);
+ nexterror();
+ }
+ n = convM2D(dp, n, &d, strs);
+ if(n == 0)
+ error(Eshortstat);
+
h = nil;
sch = tosch(c);
switch(sch->level){
@@ -645,27 +654,17 @@ shrwstat(Chan *c, uchar *dp, int n)
if(strcmp(ent->owner, up->user) && !iseve())
error(Eperm);
- strs = smalloc(n);
- if(waserror()){
- free(strs);
- nexterror();
- }
- n = convM2D(dp, n, &d, strs);
- if(n == 0)
- error(Eshortstat);
- if(d.mode != ~0UL)
- ent->perm = d.mode & 0777;
- if(d.uid && *d.uid)
- kstrdup(&ent->owner, d.uid);
- if(d.name && *d.name && strcmp(ent->name, d.name) != 0) {
+ if(d.name != nil && *d.name && strcmp(ent->name, d.name) != 0) {
if(strchr(d.name, '/') != nil)
error(Ebadchar);
if(strlen(d.name) >= sizeof(up->genbuf))
error(Etoolong);
kstrdup(&ent->name, d.name);
}
- poperror();
- free(strs);
+ if(d.uid != nil && *d.uid)
+ kstrdup(&ent->owner, d.uid);
+ if(d.mode != ~0UL)
+ ent->perm = d.mode & 0777;
switch(sch->level){
case Qcshr:
@@ -677,6 +676,10 @@ shrwstat(Chan *c, uchar *dp, int n)
wunlock(&h->lock);
break;
}
+
+ poperror();
+ free(strs);
+
return n;
}
@@ -771,7 +774,7 @@ shrwrite(Chan *c, void *va, long n, vlong)
m->to = c0;
wunlock(&h->lock);
- if(bc)
+ if(bc != nil)
cclose(bc);
return n;
@@ -810,7 +813,7 @@ Dev shrdevtab = {
static void
chowner(Ent *ent, char *old, char *new)
{
- if(ent->owner!=nil && strcmp(old, ent->owner)==0)
+ if(ent->owner != nil && strcmp(old, ent->owner) == 0)
kstrdup(&ent->owner, new);
}
@@ -821,9 +824,9 @@ shrrenameuser(char *old, char *new)
Mount *m;
qlock(&shrslk);
- for(shr = shrs; shr; shr = shr->next){
+ for(shr = shrs; shr != nil; shr = shr->next){
wlock(&shr->umh.lock);
- for(m = shr->umh.mount; m; m = m->next)
+ for(m = shr->umh.mount; m != nil; m = m->next)
chowner(tompt(m), old, new);
wunlock(&shr->umh.lock);
chowner(shr, old, new);
diff --git a/sys/src/9/port/devsrv.c b/sys/src/9/port/devsrv.c
index 982e96cb3..193fa6c8b 100644
--- a/sys/src/9/port/devsrv.c
+++ b/sys/src/9/port/devsrv.c
@@ -25,9 +25,11 @@ static Srv*
srvlookup(char *name, ulong qidpath)
{
Srv *sp;
- for(sp = srv; sp; sp = sp->link)
- if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
+
+ for(sp = srv; sp != nil; sp = sp->link) {
+ if(sp->path == qidpath || (name != nil && strcmp(sp->name, name) == 0))
return sp;
+ }
return nil;
}
@@ -43,13 +45,13 @@ srvgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
}
qlock(&srvlk);
- if(name)
+ if(name != nil)
sp = srvlookup(name, -1);
else {
- for(sp = srv; sp && s; sp = sp->link)
+ for(sp = srv; sp != nil && s > 0; sp = sp->link)
s--;
}
- if(sp == 0 || name && (strlen(sp->name) >= sizeof(up->genbuf))) {
+ if(sp == nil || (name != nil && (strlen(sp->name) >= sizeof(up->genbuf)))) {
qunlock(&srvlk);
return -1;
}
@@ -91,19 +93,25 @@ srvname(Chan *c)
Srv *sp;
char *s;
- for(sp = srv; sp; sp = sp->link)
+ s = nil;
+ qlock(&srvlk);
+ for(sp = srv; sp != nil; sp = sp->link) {
if(sp->chan == c){
- s = smalloc(3+strlen(sp->name)+1);
- sprint(s, "#s/%s", sp->name);
- return s;
+ s = malloc(3+strlen(sp->name)+1);
+ if(s != nil)
+ sprint(s, "#s/%s", sp->name);
+ break;
}
- return nil;
+ }
+ qunlock(&srvlk);
+ return s;
}
static Chan*
srvopen(Chan *c, int omode)
{
Srv *sp;
+ Chan *nc;
if(c->qid.type == QTDIR){
if(omode & ORCLOSE)
@@ -122,7 +130,7 @@ srvopen(Chan *c, int omode)
}
sp = srvlookup(nil, c->qid.path);
- if(sp == 0 || sp->chan == 0)
+ if(sp == nil || sp->chan == nil)
error(Eshutdown);
if(omode&OTRUNC)
@@ -131,17 +139,19 @@ srvopen(Chan *c, int omode)
error(Eperm);
devpermcheck(sp->owner, sp->perm, omode);
- cclose(c);
- incref(sp->chan);
+ nc = sp->chan;
+ incref(nc);
+
qunlock(&srvlk);
poperror();
- return sp->chan;
+
+ cclose(c);
+ return nc;
}
static Chan*
srvcreate(Chan *c, char *name, int omode, ulong perm)
{
- char *sname;
Srv *sp;
if(openmode(omode) != OWRITE)
@@ -151,35 +161,35 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
error(Etoolong);
sp = smalloc(sizeof *sp);
- sname = smalloc(strlen(name)+1);
+ kstrdup(&sp->name, name);
+ kstrdup(&sp->owner, up->user);
qlock(&srvlk);
if(waserror()){
- free(sp);
- free(sname);
qunlock(&srvlk);
+ free(sp->owner);
+ free(sp->name);
+ free(sp);
nexterror();
}
- if(sp == nil || sname == nil)
- error(Enomem);
- if(srvlookup(name, -1))
+ if(srvlookup(name, -1) != nil)
error(Eexist);
+ sp->perm = perm&0777;
sp->path = qidpath++;
- sp->link = srv;
- strcpy(sname, name);
- sp->name = sname;
- c->qid.type = QTFILE;
+
c->qid.path = sp->path;
+ c->qid.type = QTFILE;
+
+ sp->link = srv;
srv = sp;
+
qunlock(&srvlk);
poperror();
- kstrdup(&sp->owner, up->user);
- sp->perm = perm&0777;
-
c->flag |= COPEN;
c->mode = OWRITE;
+
return c;
}
@@ -197,13 +207,12 @@ srvremove(Chan *c)
nexterror();
}
l = &srv;
- for(sp = *l; sp; sp = sp->link) {
+ for(sp = *l; sp != nil; sp = *l) {
if(sp->path == c->qid.path)
break;
-
l = &sp->link;
}
- if(sp == 0)
+ if(sp == nil)
error(Enonexist);
/*
@@ -219,10 +228,12 @@ srvremove(Chan *c)
error(Eperm);
*l = sp->link;
+ sp->link = nil;
+
qunlock(&srvlk);
poperror();
- if(sp->chan)
+ if(sp->chan != nil)
cclose(sp->chan);
free(sp->owner);
free(sp->name);
@@ -233,45 +244,52 @@ static int
srvwstat(Chan *c, uchar *dp, int n)
{
char *strs;
- Dir d;
Srv *sp;
+ Dir d;
if(c->qid.type & QTDIR)
error(Eperm);
- strs = nil;
+ strs = smalloc(n);
+ if(waserror()){
+ free(strs);
+ nexterror();
+ }
+ n = convM2D(dp, n, &d, strs);
+ if(n == 0)
+ error(Eshortstat);
+
qlock(&srvlk);
if(waserror()){
qunlock(&srvlk);
- free(strs);
nexterror();
}
sp = srvlookup(nil, c->qid.path);
- if(sp == 0)
+ if(sp == nil)
error(Enonexist);
if(strcmp(sp->owner, up->user) != 0 && !iseve())
error(Eperm);
- strs = smalloc(n);
- n = convM2D(dp, n, &d, strs);
- if(n == 0)
- error(Eshortstat);
- if(d.mode != ~0UL)
- sp->perm = d.mode & 0777;
- if(d.uid && *d.uid)
- kstrdup(&sp->owner, d.uid);
- if(d.name && *d.name && strcmp(sp->name, d.name) != 0) {
+ if(d.name != nil && *d.name && strcmp(sp->name, d.name) != 0) {
if(strchr(d.name, '/') != nil)
error(Ebadchar);
if(strlen(d.name) >= sizeof(up->genbuf))
error(Etoolong);
kstrdup(&sp->name, d.name);
}
+ if(d.uid != nil && *d.uid)
+ kstrdup(&sp->owner, d.uid);
+ if(d.mode != ~0UL)
+ sp->perm = d.mode & 0777;
+
qunlock(&srvlk);
+ poperror();
+
free(strs);
poperror();
+
return n;
}
@@ -325,13 +343,14 @@ srvwrite(Chan *c, void *va, long n, vlong)
if(c1->qid.type & QTAUTH)
error("cannot post auth file in srv");
sp = srvlookup(nil, c->qid.path);
- if(sp == 0)
+ if(sp == nil)
error(Enonexist);
- if(sp->chan)
+ if(sp->chan != nil)
error(Ebadusefd);
sp->chan = c1;
+
qunlock(&srvlk);
poperror();
return n;
@@ -364,8 +383,9 @@ srvrenameuser(char *old, char *new)
Srv *sp;
qlock(&srvlk);
- for(sp = srv; sp; sp = sp->link)
- if(sp->owner!=nil && strcmp(old, sp->owner)==0)
+ for(sp = srv; sp != nil; sp = sp->link) {
+ if(sp->owner != nil && strcmp(old, sp->owner) == 0)
kstrdup(&sp->owner, new);
+ }
qunlock(&srvlk);
}
diff --git a/sys/src/9/port/portclock.c b/sys/src/9/port/portclock.c
index 3f7d4be7c..8f56b50c1 100644
--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -153,7 +153,8 @@ hzclock(Ureg *ur)
exit(0);
}
- checkalarms();
+ if(m->machno == 0)
+ checkalarms();
if(up && up->state == Running)
hzsched(); /* in proc.c */
diff --git a/sys/src/cmd/9nfs/9p.c b/sys/src/cmd/9nfs/9p.c
index 27fc2b5a8..55575c384 100644
--- a/sys/src/cmd/9nfs/9p.c
+++ b/sys/src/cmd/9nfs/9p.c
@@ -44,6 +44,8 @@ again:
clog("xmesg read error: %r\n");
return -1;
}
+ if(n == 0)
+ goto again;
if(convM2S(s->data, n, &s->f) <= 0){
clog("xmesg bad convM2S %d %.2x %.2x %.2x %.2x\n",
n, ((uchar*)s->data)[0], ((uchar*)s->data)[1],
diff --git a/sys/src/cmd/abaco/util.c b/sys/src/cmd/abaco/util.c
index cd7e7b3da..2a704793e 100644
--- a/sys/src/cmd/abaco/util.c
+++ b/sys/src/cmd/abaco/util.c
@@ -866,7 +866,7 @@ static
int
findctype(char *b, int l, char *keyword, char *s)
{
- char *p, *e;
+ char *p, *e, c;
int i;
p = cistrstr(s, keyword);
@@ -882,14 +882,18 @@ findctype(char *b, int l, char *keyword, char *s)
p++;
if(!*p)
return -1;
- if(*p == '"'){
+ switch (c = *p){
+ case '"':
+ case '\'':
p++;
- e = strchr(p, '"');
+ e = strchr(p, c);
if(!e)
return -1;
- }else
+ break;
+ default:
for(e = p; *e < 127 && *e > ' ' ; e++)
;
+ }
i = e-p;
if(i < 1)
return -1;
diff --git a/sys/src/cmd/acme/fsys.c b/sys/src/cmd/acme/fsys.c
index 7235bbe22..edc65537d 100644
--- a/sys/src/cmd/acme/fsys.c
+++ b/sys/src/cmd/acme/fsys.c
@@ -148,7 +148,8 @@ fsysproc(void *)
x = nil;
for(;;){
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
- n = read9pmsg(sfd, buf, messagesize);
+ while((n = read9pmsg(sfd, buf, messagesize)) == 0 && !closing)
+ ;
if(n <= 0){
if(closing)
break;
diff --git a/sys/src/cmd/auth/asn12dsa.c b/sys/src/cmd/auth/asn12dsa.c
index 7df5dd781..b7e770ed4 100644
--- a/sys/src/cmd/auth/asn12dsa.c
+++ b/sys/src/cmd/auth/asn12dsa.c
@@ -18,7 +18,7 @@ main(int argc, char **argv)
uchar *buf;
int fd;
long n, tot;
- char *tag, *file;
+ char *tag;
DSApriv *key;
fmtinstall('B', mpfmt);
@@ -35,13 +35,12 @@ main(int argc, char **argv)
if(argc != 0 && argc != 1)
usage();
- if(argc == 1)
- file = argv[0];
- else
- file = "/dev/stdin";
+ fd = 0;
+ if(argc == 1){
+ if((fd = open(*argv, OREAD)) < 0)
+ sysfatal("open %s: %r", *argv);
+ }
- if((fd = open(file, OREAD)) < 0)
- sysfatal("open %s: %r", file);
buf = nil;
tot = 0;
for(;;){
diff --git a/sys/src/cmd/aux/consolefs.c b/sys/src/cmd/aux/consolefs.c
index 180431bd4..ebc5e1230 100644
--- a/sys/src/cmd/aux/consolefs.c
+++ b/sys/src/cmd/aux/consolefs.c
@@ -681,8 +681,9 @@ fsrun(void *v)
}
free(d);
r = allocreq(fs, messagesize);
- n = read9pmsg(fs->fd, r->buf, messagesize);
- if(n <= 0)
+ while((n = read9pmsg(fs->fd, r->buf, messagesize)) == 0)
+ ;
+ if(n < 0)
fatal("unmounted");
if(convM2S(r->buf, n, &r->f) == 0){
diff --git a/sys/src/cmd/aux/depend.c b/sys/src/cmd/aux/depend.c
index a7e031d38..6132b2d22 100644
--- a/sys/src/cmd/aux/depend.c
+++ b/sys/src/cmd/aux/depend.c
@@ -365,9 +365,10 @@ fsrun(void *a)
for(;;){
r = allocreq(messagesize);
qlock(&iolock);
- n = read9pmsg(fs->fd, r->buf, messagesize);
+ while((n = read9pmsg(fs->fd, r->buf, messagesize)) == 0)
+ ;
qunlock(&iolock);
- if(n <= 0)
+ if(n < 0)
fatal("read9pmsg error: %r");
if(convM2S(r->buf, n, &r->f) == 0){
diff --git a/sys/src/cmd/aux/timesync.c b/sys/src/cmd/aux/timesync.c
index 11253efa9..e69281722 100644
--- a/sys/src/cmd/aux/timesync.c
+++ b/sys/src/cmd/aux/timesync.c
@@ -288,8 +288,8 @@ main(int argc, char **argv)
/* figure out our time interface and initial frequency */
inittime();
gettime(0, 0, &hz);
- minhz = hz/10;
- maxhz = hz*10;
+ minhz = hz / 2;
+ maxhz = hz * 2;
myprec = getclockprecision(hz);
/* convert the accuracy from nanoseconds to ticks */
diff --git a/sys/src/cmd/aux/wpa.c b/sys/src/cmd/aux/wpa.c
index f97116296..85cd9577c 100644
--- a/sys/src/cmd/aux/wpa.c
+++ b/sys/src/cmd/aux/wpa.c
@@ -66,32 +66,63 @@ uchar ptk[PTKlen];
char essid[32+1];
uvlong lastrepc;
+uchar rsntkipoui[4] = {0x00, 0x0F, 0xAC, 0x02};
+uchar rsnccmpoui[4] = {0x00, 0x0F, 0xAC, 0x04};
+uchar rsnapskoui[4] = {0x00, 0x0F, 0xAC, 0x02};
+
uchar rsnie[] = {
0x30, /* RSN */
0x14, /* length */
0x01, 0x00, /* version 1 */
0x00, 0x0F, 0xAC, 0x04, /* group cipher suite CCMP */
- 0x01, 0x00, /* peerwise cipher suite count 1 */
- 0x00, 0x0F, 0xAC, 0x04, /* peerwise cipher suite CCMP */
+ 0x01, 0x00, /* pairwise cipher suite count 1 */
+ 0x00, 0x0F, 0xAC, 0x04, /* pairwise cipher suite CCMP */
0x01, 0x00, /* authentication suite count 1 */
0x00, 0x0F, 0xAC, 0x02, /* authentication suite PSK */
0x00, 0x00, /* capabilities */
};
+uchar wpa1oui[4] = {0x00, 0x50, 0xF2, 0x01};
+uchar wpatkipoui[4] = {0x00, 0x50, 0xF2, 0x02};
+uchar wpaapskoui[4] = {0x00, 0x50, 0xF2, 0x02};
+
uchar wpaie[] = {
0xdd, /* vendor specific */
0x16, /* length */
0x00, 0x50, 0xf2, 0x01, /* WPAIE type 1 */
0x01, 0x00, /* version 1 */
0x00, 0x50, 0xf2, 0x02, /* group cipher suite TKIP */
- 0x01, 0x00, /* peerwise cipher suite count 1 */
- 0x00, 0x50, 0xf2, 0x02, /* peerwise cipher suite TKIP */
+ 0x01, 0x00, /* pairwise cipher suite count 1 */
+ 0x00, 0x50, 0xf2, 0x02, /* pairwise cipher suite TKIP */
0x01, 0x00, /* authentication suite count 1 */
0x00, 0x50, 0xf2, 0x02, /* authentication suite PSK */
};
+int
+hextob(char *s, char **sp, uchar *b, int n)
+{
+ int r;
+
+ n <<= 1;
+ for(r = 0; r < n && *s; s++){
+ *b <<= 4;
+ if(*s >= '0' && *s <= '9')
+ *b |= (*s - '0');
+ else if(*s >= 'a' && *s <= 'f')
+ *b |= 10+(*s - 'a');
+ else if(*s >= 'A' && *s <= 'F')
+ *b |= 10+(*s - 'A');
+ else break;
+ if((++r & 1) == 0)
+ b++;
+ }
+ if(sp != nil)
+ *sp = s;
+ return r >> 1;
+}
+
char*
-getessid(void)
+getifstats(char *key, char *val, int nval)
{
char buf[8*1024], *f[2], *p, *e;
int fd, n;
@@ -99,23 +130,174 @@ getessid(void)
snprint(buf, sizeof(buf), "%s/ifstats", devdir);
if((fd = open(buf, OREAD)) < 0)
return nil;
- n = read(fd, buf, sizeof(buf)-1);
+ n = readn(fd, buf, sizeof(buf)-1);
close(fd);
- if(n > 0){
- buf[n] = 0;
- for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
- *e++ = 0;
- if(tokenize(p, f, 2) != 2)
- continue;
- if(strcmp(f[0], "essid:") != 0)
- continue;
- strncpy(essid, f[1], 32);
- return essid;
- }
+ if(n <= 0)
+ return nil;
+ buf[n] = 0;
+ for(p = buf; (e = strchr(p, '\n')) != nil; p = e){
+ *e++ = 0;
+ if(tokenize(p, f, 2) != 2)
+ continue;
+ if(strcmp(f[0], key) != 0)
+ continue;
+ strncpy(val, f[1], nval);
+ val[nval-1] = 0;
+ return val;
}
return nil;
}
+char*
+getessid(void)
+{
+ return getifstats("essid:", essid, sizeof(essid));
+}
+
+int
+buildrsne(uchar rsne[258])
+{
+ char buf[1024];
+ uchar brsne[258];
+ int brsnelen;
+ uchar *p, *w, *e;
+ int i, n;
+
+ if(getifstats("brsne:", buf, sizeof(buf)) == nil)
+ return 0; /* not an error, might be old kernel */
+
+ brsnelen = hextob(buf, nil, brsne, sizeof(brsne));
+ if(brsnelen <= 4){
+trunc: sysfatal("invalid or truncated RSNE; brsne: %s", buf);
+ return 0;
+ }
+
+ w = rsne;
+ p = brsne;
+ e = p + brsnelen;
+ if(p[0] == 0x30){
+ p += 2;
+
+ /* RSN */
+ *w++ = 0x30;
+ *w++ = 0; /* length */
+ } else if(p[0] == 0xDD){
+ p += 2;
+ if((e - p) < 4 || memcmp(p, wpa1oui, 4) != 0){
+ sysfatal("unrecognized WPAIE type; brsne: %s", buf);
+ return 0;
+ }
+
+ /* WPA */
+ *w++ = 0xDD;
+ *w++ = 0; /* length */
+
+ memmove(w, wpa1oui, 4);
+ w += 4;
+ p += 4;
+ } else {
+ sysfatal("unrecognized RSNE type; brsne: %s", buf);
+ return 0;
+ }
+
+ if((e - p) < 6)
+ goto trunc;
+
+ *w++ = *p++; /* version */
+ *w++ = *p++;
+
+ if(rsne[0] == 0x30){
+ if(memcmp(p, rsnccmpoui, 4) == 0)
+ groupcipher = &ccmp;
+ else if(memcmp(p, rsntkipoui, 4) == 0)
+ groupcipher = &tkip;
+ else {
+ sysfatal("unrecognized RSN group cipher; brsne: %s", buf);
+ return 0;
+ }
+ } else {
+ if(memcmp(p, wpatkipoui, 4) != 0){
+ sysfatal("unrecognized WPA group cipher; brsne: %s", buf);
+ return 0;
+ }
+ groupcipher = &tkip;
+ }
+
+ memmove(w, p, 4); /* group cipher */
+ w += 4;
+ p += 4;
+
+ if((e - p) < 6)
+ goto trunc;
+
+ *w++ = 0x01; /* # of peer ciphers */
+ *w++ = 0x00;
+ n = *p++;
+ n |= *p++ << 8;
+
+ if(n <= 0)
+ goto trunc;
+
+ peercipher = &tkip;
+ for(i=0; i<n; i++){
+ if((e - p) < 4)
+ goto trunc;
+
+ if(rsne[0] == 0x30 && memcmp(p, rsnccmpoui, 4) == 0 && peercipher == &tkip)
+ peercipher = &ccmp;
+ p += 4;
+ }
+ if(peercipher == &ccmp)
+ memmove(w, rsnccmpoui, 4);
+ else if(rsne[0] == 0x30)
+ memmove(w, rsntkipoui, 4);
+ else
+ memmove(w, wpatkipoui, 4);
+ w += 4;
+
+ if((e - p) < 6)
+ goto trunc;
+
+ *w++ = 0x01; /* # of auth suites */
+ *w++ = 0x00;
+ n = *p++;
+ n |= *p++ << 8;
+
+ if(n <= 0)
+ goto trunc;
+
+ for(i=0; i<n; i++){
+ if((e - p) < 4)
+ goto trunc;
+
+ /* look for PSK oui */
+ if(rsne[0] == 0x30){
+ if(memcmp(p, rsnapskoui, 4) == 0)
+ break;
+ } else {
+ if(memcmp(p, wpaapskoui, 4) == 0)
+ break;
+ }
+ p += 4;
+ }
+ if(i >= n){
+ sysfatal("auth suite is not PSK; brsne: %s", buf);
+ return 0;
+ }
+
+ memmove(w, p, 4);
+ w += 4;
+
+ if(rsne[0] == 0x30){
+ /* RSN caps */
+ *w++ = 0x00;
+ *w++ = 0x00;
+ }
+
+ rsne[1] = (w - rsne) - 2;
+ return w - rsne;
+}
+
int
getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
uchar snonce[Noncelen], uchar anonce[Noncelen],
@@ -148,8 +330,10 @@ getptk( uchar smac[Eaddrlen], uchar amac[Eaddrlen],
goto out;
if((ret = auth_rpc(rpc, "read", nil, 0)) != ARok)
goto out;
- if(rpc->narg != PTKlen)
+ if(rpc->narg != PTKlen){
+ ret = -1;
goto out;
+ }
memmove(ptk, rpc->arg, PTKlen);
ret = 0;
out:
@@ -294,7 +478,7 @@ checkmic(Keydescr *kd, uchar *msg, int msglen)
}
void
-reply(uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar *data, int datalen)
+reply(int eapver, uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar *data, int datalen)
{
uchar buf[4096], *m, *p = buf;
@@ -304,7 +488,7 @@ reply(uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar
*p++ = 0x8e;
m = p;
- *p++ = 0x01;
+ *p++ = eapver;
*p++ = 0x03;
datalen += Keydescrlen;
*p++ = datalen >> 8;
@@ -325,7 +509,7 @@ reply(uchar smac[Eaddrlen], uchar amac[Eaddrlen], int flags, Keydescr *kd, uchar
if(flags & Fmic)
calcmic(kd, m, p - m);
if(debug != 0){
- fprint(2, "\nreply %E -> %E: ", smac, amac);
+ fprint(2, "\nreply(v%d) %E -> %E: ", eapver, smac, amac);
dumpkeydescr(kd);
}
datalen = p - buf;
@@ -353,11 +537,10 @@ main(int argc, char *argv[])
fmtinstall('H', Hfmt);
fmtinstall('E', eipfmt);
- /* default is WPA */
- rsne = wpaie;
- rsnelen = sizeof(wpaie);
- peercipher = &tkip;
- groupcipher = &tkip;
+ rsne = nil;
+ rsnelen = -1;
+ peercipher = nil;
+ groupcipher = nil;
ARGBEGIN {
case 'd':
@@ -415,6 +598,24 @@ main(int argc, char *argv[])
free(s);
}
+ if(rsnelen <= 0){
+ static uchar brsne[258];
+
+ rsne = brsne;
+ rsnelen = buildrsne(rsne);
+ }
+
+ if(rsnelen <= 0){
+ /* default is WPA */
+ rsne = wpaie;
+ rsnelen = sizeof(wpaie);
+ peercipher = &tkip;
+ groupcipher = &tkip;
+ }
+
+ if(debug)
+ fprint(2, "rsne: %.*H\n", rsnelen, rsne);
+
/*
* we use write() instead of fprint so message gets written
* at once and not chunked up on fprint buffer.
@@ -437,12 +638,20 @@ main(int argc, char *argv[])
for(;;){
uchar smac[Eaddrlen], amac[Eaddrlen], snonce[Noncelen], anonce[Noncelen], *p, *e, *m;
- int proto, flags, vers, datalen;
+ int proto, eapver, flags, vers, datalen;
uvlong repc, rsc, tsc;
Keydescr *kd;
if((n = read(fd, buf, sizeof(buf))) < 0)
sysfatal("read: %r");
+
+ if(n == 0){
+ if(debug != 0)
+ fprint(2, "got deassociation\n");
+ lastrepc = 0ULL;
+ continue;
+ }
+
p = buf;
e = buf+n;
if(n < 2*Eaddrlen + 2)
@@ -455,18 +664,26 @@ main(int argc, char *argv[])
m = p;
n = e - p;
- if(n < 4 || p[0] != 0x01 || p[1] != 0x03)
+ if(n < 4)
continue;
+ eapver = p[0];
+ if((eapver != 0x01 && eapver != 0x02) || p[1] != 0x03)
+ continue;
+
+ if(debug != 0)
+ fprint(2, "\nrecv(v%d) %E <- %E: ", eapver, smac, amac);
+
n = p[2]<<8 | p[3];
p += 4;
- if(n < Keydescrlen || p + n > e)
+ if(n < Keydescrlen || p + n > e){
+ if(debug != 0)
+ fprint(2, "bad kd size\n");
continue;
+ }
e = p + n;
kd = (Keydescr*)p;
- if(debug){
- fprint(2, "\nrecv %E <- %E: ", smac, amac);
+ if(debug != 0)
dumpkeydescr(kd);
- }
if(kd->type[0] != 0xFE && kd->type[0] != 0x02)
continue;
@@ -483,14 +700,17 @@ main(int argc, char *argv[])
memmove(anonce, kd->nonce, sizeof(anonce));
genrandom(snonce, sizeof(snonce));
- if(getptk(smac, amac, snonce, anonce, ptk) < 0)
+ if(getptk(smac, amac, snonce, anonce, ptk) != 0){
+ if(debug != 0)
+ fprint(2, "getptk: %r\n");
continue;
+ }
/* ack key exchange with mic */
memset(kd->rsc, 0, sizeof(kd->rsc));
memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
memmove(kd->nonce, snonce, sizeof(kd->nonce));
- reply(smac, amac, (flags & ~(Fack|Fins)) | Fmic, kd, rsne, rsnelen);
+ reply(eapver, smac, amac, (flags & ~(Fack|Fins)) | Fmic, kd, rsne, rsnelen);
} else {
uchar gtk[GTKlen];
int gtklen, gtkkid;
@@ -577,22 +797,19 @@ main(int argc, char *argv[])
tsc = rsc;
rsc = 0LL;
}
- /* install peerwise receive key */
+ /* install pairwise receive key */
if(fprint(cfd, "rxkey %.*H %s:%.*H@%llux", Eaddrlen, amac,
peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
sysfatal("write rxkey: %r");
- /* pick random 16bit tsc value for transmit */
- tsc = 1 + (truerand() & 0x7fff);
+ tsc = 0LL;
memset(kd->rsc, 0, sizeof(kd->rsc));
- kd->rsc[0] = tsc;
- kd->rsc[1] = tsc>>8;
memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
memset(kd->nonce, 0, sizeof(kd->nonce));
- reply(smac, amac, flags & ~(Fack|Fenc|Fsec), kd, nil, 0);
+ reply(eapver, smac, amac, flags & ~(Fack|Fenc|Fins), kd, nil, 0);
sleep(100);
- /* install peerwise transmit key */
+ /* install pairwise transmit key */
if(fprint(cfd, "txkey %.*H %s:%.*H@%llux", Eaddrlen, amac,
peercipher->name, peercipher->keylen, ptk+32, tsc) < 0)
sysfatal("write txkey: %r");
@@ -612,7 +829,7 @@ main(int argc, char *argv[])
memset(kd->rsc, 0, sizeof(kd->rsc));
memset(kd->eapoliv, 0, sizeof(kd->eapoliv));
memset(kd->nonce, 0, sizeof(kd->nonce));
- reply(smac, amac, flags & ~(Fenc|Fack), kd, nil, 0);
+ reply(eapver, smac, amac, flags & ~(Fenc|Fack), kd, nil, 0);
} else
continue;
diff --git a/sys/src/cmd/cfs/cfs.c b/sys/src/cmd/cfs/cfs.c
index 2fbf3f421..d49e32a98 100644
--- a/sys/src/cmd/cfs/cfs.c
+++ b/sys/src/cmd/cfs/cfs.c
@@ -808,8 +808,9 @@ rcvmsg(P9fs *p, Fcall *f)
char buf[128];
olen = p->len;
- p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv));
- if(p->len <= 0){
+ while((p->len = read9pmsg(p->fd[0], datarcv, sizeof(datarcv))) == 0)
+ ;
+ if(p->len < 0){
snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
p->fd[0], p->len);
error(buf);
diff --git a/sys/src/cmd/cpu.c b/sys/src/cmd/cpu.c
index 16d73e814..16c0f6186 100644
--- a/sys/src/cmd/cpu.c
+++ b/sys/src/cmd/cpu.c
@@ -1090,11 +1090,13 @@ notefs(int fd)
ncpunote = 0;
for(;;){
n = read9pmsg(fd, buf, sizeof(buf));
- if(n <= 0){
+ if(n < 0){
if(dbg)
fprint(2, "read9pmsg(%d) returns %d: %r\n", fd, n);
break;
}
+ if(n == 0)
+ continue;
if(convM2S(buf, n, &f) <= BIT16SZ)
break;
if(dbg)
diff --git a/sys/src/cmd/disk/9660/dump9660.c b/sys/src/cmd/disk/9660/dump9660.c
index 83ae9807a..5585c4d49 100644
--- a/sys/src/cmd/disk/9660/dump9660.c
+++ b/sys/src/cmd/disk/9660/dump9660.c
@@ -307,11 +307,10 @@ Dofix:
* Patch in root directories.
*/
setroot(cd, cd->iso9660pvd, iroot.block, iroot.length);
- setvolsize(cd, cd->iso9660pvd, (vlong)cd->nextblock * Blocksize);
+ setvolsize(cd, cd->iso9660pvd, cd->nextblock);
if(cd->flags & CDjoliet){
setroot(cd, cd->jolietsvd, jroot.block, jroot.length);
- setvolsize(cd, cd->jolietsvd,
- (vlong)cd->nextblock * Blocksize);
+ setvolsize(cd, cd->jolietsvd, cd->nextblock);
}
}else{
/*
@@ -341,11 +340,10 @@ Dofix:
* Patch in new root directory entry.
*/
setroot(cd, cd->iso9660pvd, idumproot.block, idumproot.length);
- setvolsize(cd, cd->iso9660pvd, (vlong)cd->nextblock * Blocksize);
+ setvolsize(cd, cd->iso9660pvd, cd->nextblock);
if(cd->flags & CDjoliet){
setroot(cd, cd->jolietsvd, jdumproot.block, jdumproot.length);
- setvolsize(cd, cd->jolietsvd,
- (vlong)cd->nextblock * Blocksize);
+ setvolsize(cd, cd->jolietsvd, cd->nextblock);
}
}
writepathtables(cd);
diff --git a/sys/src/cmd/exportfs/exportfs.c b/sys/src/cmd/exportfs/exportfs.c
index ae9ad20d4..b618369b4 100644
--- a/sys/src/cmd/exportfs/exportfs.c
+++ b/sys/src/cmd/exportfs/exportfs.c
@@ -388,8 +388,9 @@ main(int argc, char **argv)
if(r == 0)
fatal("Out of service buffers");
- n = localread9pmsg(netfd, r->buf, messagesize, ini);
- if(n <= 0)
+ while((n = localread9pmsg(netfd, r->buf, messagesize, ini)) == 0)
+ ;
+ if(n < 0)
fatal(nil);
if(convM2S(r->buf, n, &r->work) == 0)
fatal("convM2S format error");
diff --git a/sys/src/cmd/hjfs/auth.c b/sys/src/cmd/hjfs/auth.c
index 1e032de25..ede0286e5 100644
--- a/sys/src/cmd/hjfs/auth.c
+++ b/sys/src/cmd/hjfs/auth.c
@@ -465,3 +465,4 @@ found:
createuserdir(fs, argv[1], uid);
return 1;
}
+
diff --git a/sys/src/cmd/hjfs/cons.c b/sys/src/cmd/hjfs/cons.c
index 688f31378..bfe6bf938 100644
--- a/sys/src/cmd/hjfs/cons.c
+++ b/sys/src/cmd/hjfs/cons.c
@@ -322,6 +322,13 @@ error:
return -1;
}
+int
+cmdusers(int, char**)
+{
+ readusers(fsmain);
+ return 0;
+}
+
extern int cmdnewuser(int, char **);
Cmd cmds[] = {
@@ -334,6 +341,7 @@ Cmd cmds[] = {
{"sync", 1, cmdsync},
{"halt", 1, cmdhalt},
{"newuser", 0, cmdnewuser},
+ {"users", 1, cmdusers},
{"echo", 2, cmdecho},
{"df", 1, cmddf},
{"debug-deind", 2, cmddebugdeind},
diff --git a/sys/src/cmd/hjfs/fns.h b/sys/src/cmd/hjfs/fns.h
index 24c48dffc..0a2cb8667 100644
--- a/sys/src/cmd/hjfs/fns.h
+++ b/sys/src/cmd/hjfs/fns.h
@@ -53,3 +53,4 @@ int userssave(Fs *, Chan *);
int ingroup(Fs *, short, short, int);
void workerinit(void);
void writeusers(Fs *);
+void readusers(Fs *);
diff --git a/sys/src/cmd/hjfs/fs1.c b/sys/src/cmd/hjfs/fs1.c
index ac37eefb0..b59d1e7f4 100644
--- a/sys/src/cmd/hjfs/fs1.c
+++ b/sys/src/cmd/hjfs/fs1.c
@@ -214,7 +214,7 @@ error:
dprint("writeusers: %r\n");
}
-static void
+void
readusers(Fs *fs)
{
Chan *ch;
diff --git a/sys/src/cmd/iostats/iostats.c b/sys/src/cmd/iostats/iostats.c
index 8b1356d0a..61b16ea4b 100644
--- a/sys/src/cmd/iostats/iostats.c
+++ b/sys/src/cmd/iostats/iostats.c
@@ -164,7 +164,8 @@ main(int argc, char **argv)
if(r == 0)
fatal("Out of service buffers");
- n = read9pmsg(p[1], r->buf, sizeof(r->buf));
+ while((n = read9pmsg(p[1], r->buf, sizeof(r->buf))) == 0 && !done)
+ ;
if(done)
break;
if(n < 0)
diff --git a/sys/src/cmd/ip/ftpfs/ftpfs.c b/sys/src/cmd/ip/ftpfs/ftpfs.c
index 5d6f35b2e..540ce853b 100644
--- a/sys/src/cmd/ip/ftpfs/ftpfs.c
+++ b/sys/src/cmd/ip/ftpfs/ftpfs.c
@@ -262,12 +262,14 @@ io(void)
while(!dying){
n = read9pmsg(mfd, mdata, messagesize);
- if(n <= 0){
+ if(n < 0){
errstr(buf, sizeof buf);
if(buf[0]=='\0' || strstr(buf, "hungup"))
exits("");
fatal("mount read: %s\n", buf);
}
+ if(n == 0)
+ continue;
if(convM2S(mdata, n, &thdr) == 0)
continue;
diff --git a/sys/src/cmd/jpg/imagefile.h b/sys/src/cmd/jpg/imagefile.h
index bab62e84e..04600e364 100644
--- a/sys/src/cmd/jpg/imagefile.h
+++ b/sys/src/cmd/jpg/imagefile.h
@@ -50,9 +50,11 @@ typedef struct ImageInfo {
Rawimage** readjpg(int, int);
-Rawimage** Breadjpg(Biobuf *b, int);
+Rawimage** Breadjpg(Biobuf*, int);
Rawimage** readpng(int, int);
-Rawimage** Breadpng(Biobuf *b, int);
+Rawimage** Breadpng(Biobuf*, int);
+Rawimage** readtif(int);
+Rawimage** Breadtif(Biobuf*);
Rawimage** readgif(int, int);
Rawimage** readpixmap(int, int);
Rawimage* torgbv(Rawimage*, int);
diff --git a/sys/src/cmd/jpg/mkfile b/sys/src/cmd/jpg/mkfile
index 3671856e9..0455f2cc9 100644
--- a/sys/src/cmd/jpg/mkfile
+++ b/sys/src/cmd/jpg/mkfile
@@ -9,6 +9,7 @@ TARG=\
toppm\
png\
topng\
+ tif\
yuv\
ico\
toico\
@@ -55,6 +56,7 @@ $O.ppm: $IMFILES readppm.$O ppm.$O
$O.toppm: writeppm.$O multichan.$O toppm.$O
$O.png: $IMFILES readpng.$O png.$O
$O.topng: writepng.$O topng.$O
+$O.tif: $IMFILES readtif.$O tif.$O
$O.yuv: $IMFILES readyuv.$O yuv.$O
$O.bmp: $IMFILES readbmp.$O bmp.$O
$O.v210: $IMFILES readv210.$O v210.$O
diff --git a/sys/src/cmd/jpg/readtif.c b/sys/src/cmd/jpg/readtif.c
new file mode 100644
index 000000000..51b15424d
--- /dev/null
+++ b/sys/src/cmd/jpg/readtif.c
@@ -0,0 +1,1793 @@
+/*
+* code/documentation:
+* http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
+* http://paulbourke.net/dataformats/tiff/
+* http://www.fileformat.info/format/tiff/egff.htm
+* http://www.fileformat.info/mirror/egff/ch09_05.htm
+* http://www.itu.int/rec/T-REC-T.4-199904-S/en
+* http://www.itu.int/rec/T-REC-T.6-198811-I/en
+*
+* fax codes and lzw:
+* http://www.remotesensing.org/libtiff/
+*/
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include "imagefile.h"
+
+enum {
+ II = 0x4949, /* little-endian */
+ MM = 0x4d4d, /* big-endian */
+ TIF = 0x002a /* tiff magic number */
+};
+
+enum {
+ Byte = 1,
+ Short = 3,
+ Long = 4
+};
+
+enum {
+ Width = 0x0100,
+ Length = 0x0101,
+ Bits = 0x0102,
+
+ Compression = 0x0103,
+ Nocomp = 0x0001,
+ Huffman = 0x0002,
+ T4enc = 0x0003,
+ T6enc = 0x0004,
+ Lzwenc = 0x0005,
+ Packbits = 0x8005,
+
+ Photometric = 0x0106,
+ Whitezero = 0x0000,
+ Blackzero = 0x0001,
+ Rgb = 0x0002,
+ Palette = 0x0003,
+
+ Fill = 0x010a,
+ Strips = 0x0111,
+ Orientation = 0x0112,
+ Samples = 0x0115,
+ Rows = 0x0116,
+ Counts = 0x0117,
+ Planar = 0x011c,
+ T4opts = 0x0124,
+ T6opts = 0x0125,
+ Predictor = 0x13d,
+ Color = 0x0140
+};
+
+enum {
+ Nfaxcodes = 10,
+ Nfaxtab = 105
+};
+
+enum {
+ Clrcode = 256,
+ Eoicode = 257,
+ Tabsz = 1<<12
+};
+
+typedef struct Tab Tab;
+typedef struct Fax Fax;
+typedef struct Code Code;
+typedef struct Lzw Lzw;
+typedef struct Fld Fld;
+typedef struct Tif Tif;
+
+struct Tab {
+ int len;
+ int code;
+ int run; /* run length */
+};
+
+struct Fax {
+ ulong n;
+ int m;
+ int st; /* state */
+ Tab *tab[2];
+ int ntab; /* position in tab */
+ Tab *eol;
+ int (*getbit)(Fax *);
+ int *l1;
+ int *l2;
+ ulong nl;
+ uchar *data;
+ ulong next; /* next strip offset in data */
+};
+
+struct Code {
+ uchar val;
+ Code *next;
+};
+
+struct Lzw {
+ Code tab[Tabsz];
+ int ntab;
+ int len; /* code length */
+ ulong n;
+ int m;
+ uchar *data;
+ ulong next; /* next strip offset in data */
+ /* remaining allocated codes */
+ Code *first;
+ Code *last;
+};
+
+struct Fld {
+ uint tag;
+ uint typ;
+ ulong cnt;
+ ulong off; /* value offset */
+ ulong *val;
+ ulong nval;
+};
+
+struct Tif {
+ Biobuf *fd;
+ uint end; /* endianness */
+ uchar tmp[4];
+ uchar *buf;
+ ulong nbuf;
+ int eof; /* reached end of image */
+ ulong n; /* offset in buf array */
+ ulong off;
+ uint nfld;
+ Fld *fld;
+ ulong (*byte2)(uchar *);
+ ulong (*byte4)(uchar *);
+
+ /* field data */
+ ulong dx;
+ ulong dy;
+ ulong depth;
+ ulong comp;
+ uchar *(*uncompress)(Tif *);
+ ulong orientation;
+ ulong photo;
+ int (*decode)(Tif *, Rawimage *, uchar *);
+ ulong fill;
+ ulong *strips;
+ ulong nstrips;
+ ulong samples;
+ ulong rows;
+ ulong *counts;
+ ulong ncounts;
+ ulong planar;
+ ulong *color; /* color map */
+ ulong ncolor;
+ ulong t4;
+ ulong t6;
+ ulong predictor;
+
+ /* image data */
+ uchar *data;
+ ulong ndata;
+};
+
+/*
+* imported from libdraw/arith.c to permit
+* extern log2 function
+*/
+static int log2[] = {
+ -1, 0, 1, -1, 2, -1, -1, -1, 3,
+ -1, -1, -1, -1, -1, -1, -1, 4,
+ -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */,
+ -1, -1, -1, -1, -1, -1, -1, 5
+};
+
+static Tab faxwhite[Nfaxtab] = {
+ {4, 0x7, 2}, /* 0111 */
+ {4, 0x8, 3}, /* 1000 */
+ {4, 0xb, 4}, /* 1011 */
+ {4, 0xc, 5}, /* 1100 */
+ {4, 0xe, 6}, /* 1110 */
+ {4, 0xf, 7}, /* 1111 */
+ {5, 0x12, 128}, /* 1001 0 */
+ {5, 0x13, 8}, /* 1001 1 */
+ {5, 0x14, 9}, /* 1010 0 */
+ {5, 0x1b, 64}, /* 1101 1 */
+ {5, 0x7, 10}, /* 0011 1 */
+ {5, 0x8, 11}, /* 0100 0 */
+ {6, 0x17, 192}, /* 0101 11 */
+ {6, 0x18, 1664}, /* 0110 00 */
+ {6, 0x2a, 16}, /* 1010 10 */
+ {6, 0x2b, 17}, /* 1010 11 */
+ {6, 0x3, 13}, /* 0000 11 */
+ {6, 0x34, 14}, /* 1101 00 */
+ {6, 0x35, 15}, /* 1101 01 */
+ {6, 0x7, 1}, /* 0001 11 */
+ {6, 0x8, 12}, /* 0010 00 */
+ {7, 0x13, 26}, /* 0010 011 */
+ {7, 0x17, 21}, /* 0010 111 */
+ {7, 0x18, 28}, /* 0011 000 */
+ {7, 0x24, 27}, /* 0100 100 */
+ {7, 0x27, 18}, /* 0100 111 */
+ {7, 0x28, 24}, /* 0101 000 */
+ {7, 0x2b, 25}, /* 0101 011 */
+ {7, 0x3, 22}, /* 0000 011 */
+ {7, 0x37, 256}, /* 0110 111 */
+ {7, 0x4, 23}, /* 0000 100 */
+ {7, 0x8, 20}, /* 0001 000 */
+ {7, 0xc, 19}, /* 0001 100 */
+ {8, 0x12, 33}, /* 0001 0010 */
+ {8, 0x13, 34}, /* 0001 0011 */
+ {8, 0x14, 35}, /* 0001 0100 */
+ {8, 0x15, 36}, /* 0001 0101 */
+ {8, 0x16, 37}, /* 0001 0110 */
+ {8, 0x17, 38}, /* 0001 0111 */
+ {8, 0x1a, 31}, /* 0001 1010 */
+ {8, 0x1b, 32}, /* 0001 1011 */
+ {8, 0x2, 29}, /* 0000 0010 */
+ {8, 0x24, 53}, /* 0010 0100 */
+ {8, 0x25, 54}, /* 0010 0101 */
+ {8, 0x28, 39}, /* 0010 1000 */
+ {8, 0x29, 40}, /* 0010 1001 */
+ {8, 0x2a, 41}, /* 0010 1010 */
+ {8, 0x2b, 42}, /* 0010 1011 */
+ {8, 0x2c, 43}, /* 0010 1100 */
+ {8, 0x2d, 44}, /* 0010 1101 */
+ {8, 0x3, 30}, /* 0000 0011 */
+ {8, 0x32, 61}, /* 0011 0010 */
+ {8, 0x33, 62}, /* 0011 0011 */
+ {8, 0x34, 63}, /* 0011 0100 */
+ {8, 0x35, 0}, /* 0011 0101 */
+ {8, 0x36, 320}, /* 0011 0110 */
+ {8, 0x37, 384}, /* 0011 0111 */
+ {8, 0x4, 45}, /* 0000 0100 */
+ {8, 0x4a, 59}, /* 0100 1010 */
+ {8, 0x4b, 60}, /* 0100 1011 */
+ {8, 0x5, 46}, /* 0000 0101 */
+ {8, 0x52, 49}, /* 0101 0010 */
+ {8, 0x53, 50}, /* 0101 0011 */
+ {8, 0x54, 51}, /* 0101 0100 */
+ {8, 0x55, 52}, /* 0101 0101 */
+ {8, 0x58, 55}, /* 0101 1000 */
+ {8, 0x59, 56}, /* 0101 1001 */
+ {8, 0x5a, 57}, /* 0101 1010 */
+ {8, 0x5b, 58}, /* 0101 1011 */
+ {8, 0x64, 448}, /* 0110 0100 */
+ {8, 0x65, 512}, /* 0110 0101 */
+ {8, 0x67, 640}, /* 0110 0111 */
+ {8, 0x68, 576}, /* 0110 1000 */
+ {8, 0xa, 47}, /* 0000 1010 */
+ {8, 0xb, 48}, /* 0000 1011 */
+ {9, 0x98, 1472}, /* 0100 1100 0 */
+ {9, 0x99, 1536}, /* 0100 1100 1 */
+ {9, 0x9a, 1600}, /* 0100 1101 0 */
+ {9, 0x9b, 1728}, /* 0100 1101 1 */
+ {9, 0xcc, 704}, /* 0110 0110 0 */
+ {9, 0xcd, 768}, /* 0110 0110 1 */
+ {9, 0xd2, 832}, /* 0110 1001 0 */
+ {9, 0xd3, 896}, /* 0110 1001 1 */
+ {9, 0xd4, 960}, /* 0110 1010 0 */
+ {9, 0xd5, 1024}, /* 0110 1010 1 */
+ {9, 0xd6, 1088}, /* 0110 1011 0 */
+ {9, 0xd7, 1152}, /* 0110 1011 1 */
+ {9, 0xd8, 1216}, /* 0110 1100 0 */
+ {9, 0xd9, 1280}, /* 0110 1100 1 */
+ {9, 0xda, 1344}, /* 0110 1101 0 */
+ {9, 0xdb, 1408}, /* 0110 1101 1 */
+ {11, 0x8, 1792}, /* 0000 0001 000 */
+ {11, 0xc, 1856}, /* 0000 0001 100 */
+ {11, 0xd, 1920}, /* 0000 0001 101 */
+ {12, 0x1, -1}, /* 0000 0000 0001 */
+ {12, 0x12, 1984}, /* 0000 0001 0010 */
+ {12, 0x13, 2048}, /* 0000 0001 0011 */
+ {12, 0x14, 2112}, /* 0000 0001 0100 */
+ {12, 0x15, 2176}, /* 0000 0001 0101 */
+ {12, 0x16, 2240}, /* 0000 0001 0110 */
+ {12, 0x17, 2304}, /* 0000 0001 0111 */
+ {12, 0x1c, 2368}, /* 0000 0001 1100 */
+ {12, 0x1d, 2432}, /* 0000 0001 1101 */
+ {12, 0x1e, 2496}, /* 0000 0001 1110 */
+ {12, 0x1f, 2560} /* 0000 0001 1111 */
+};
+
+static Tab faxblack[Nfaxtab] = {
+ {2, 0x2, 3}, /* 10 */
+ {2, 0x3, 2}, /* 11 */
+ {3, 0x2, 1}, /* 010 */
+ {3, 0x3, 4}, /* 011 */
+ {4, 0x2, 6}, /* 0010 */
+ {4, 0x3, 5}, /* 0011 */
+ {5, 0x3, 7}, /* 0001 1 */
+ {6, 0x4, 9}, /* 0001 00 */
+ {6, 0x5, 8}, /* 0001 01 */
+ {7, 0x4, 10}, /* 0000 100 */
+ {7, 0x5, 11}, /* 0000 101 */
+ {7, 0x7, 12}, /* 0000 111 */
+ {8, 0x4, 13}, /* 0000 0100 */
+ {8, 0x7, 14}, /* 0000 0111 */
+ {9, 0x18, 15}, /* 0000 1100 0 */
+ {10, 0x17, 16}, /* 0000 0101 11 */
+ {10, 0x18, 17}, /* 0000 0110 00 */
+ {10, 0x37, 0}, /* 0000 1101 11 */
+ {10, 0x8, 18}, /* 0000 0010 00 */
+ {10, 0xf, 64}, /* 0000 0011 11 */
+ {11, 0x17, 24}, /* 0000 0010 111 */
+ {11, 0x18, 25}, /* 0000 0011 000 */
+ {11, 0x28, 23}, /* 0000 0101 000 */
+ {11, 0x37, 22}, /* 0000 0110 111 */
+ {11, 0x67, 19}, /* 0000 1100 111 */
+ {11, 0x68, 20}, /* 0000 1101 000 */
+ {11, 0x6c, 21}, /* 0000 1101 100 */
+ {11, 0x8, 1792}, /* 0000 0001 000 */
+ {11, 0xc, 1856}, /* 0000 0001 100 */
+ {11, 0xd, 1920}, /* 0000 0001 101 */
+ {12, 0x1, -1}, /* 0000 0000 0001 */
+ {12, 0x12, 1984}, /* 0000 0001 0010 */
+ {12, 0x13, 2048}, /* 0000 0001 0011 */
+ {12, 0x14, 2112}, /* 0000 0001 0100 */
+ {12, 0x15, 2176}, /* 0000 0001 0101 */
+ {12, 0x16, 2240}, /* 0000 0001 0110 */
+ {12, 0x17, 2304}, /* 0000 0001 0111 */
+ {12, 0x1c, 2368}, /* 0000 0001 1100 */
+ {12, 0x1d, 2432}, /* 0000 0001 1101 */
+ {12, 0x1e, 2496}, /* 0000 0001 1110 */
+ {12, 0x1f, 2560}, /* 0000 0001 1111 */
+ {12, 0x24, 52}, /* 0000 0010 0100 */
+ {12, 0x27, 55}, /* 0000 0010 0111 */
+ {12, 0x28, 56}, /* 0000 0010 1000 */
+ {12, 0x2b, 59}, /* 0000 0010 1011 */
+ {12, 0x2c, 60}, /* 0000 0010 1100 */
+ {12, 0x33, 320}, /* 0000 0011 0011 */
+ {12, 0x34, 384}, /* 0000 0011 0100 */
+ {12, 0x35, 448}, /* 0000 0011 0101 */
+ {12, 0x37, 53}, /* 0000 0011 0111 */
+ {12, 0x38, 54}, /* 0000 0011 1000 */
+ {12, 0x52, 50}, /* 0000 0101 0010 */
+ {12, 0x53, 51}, /* 0000 0101 0011 */
+ {12, 0x54, 44}, /* 0000 0101 0100 */
+ {12, 0x55, 45}, /* 0000 0101 0101 */
+ {12, 0x56, 46}, /* 0000 0101 0110 */
+ {12, 0x57, 47}, /* 0000 0101 0111 */
+ {12, 0x58, 57}, /* 0000 0101 1000 */
+ {12, 0x59, 58}, /* 0000 0101 1001 */
+ {12, 0x5a, 61}, /* 0000 0101 1010 */
+ {12, 0x5b, 256}, /* 0000 0101 1011 */
+ {12, 0x64, 48}, /* 0000 0110 0100 */
+ {12, 0x65, 49}, /* 0000 0110 0101 */
+ {12, 0x66, 62}, /* 0000 0110 0110 */
+ {12, 0x67, 63}, /* 0000 0110 0111 */
+ {12, 0x68, 30}, /* 0000 0110 1000 */
+ {12, 0x69, 31}, /* 0000 0110 1001 */
+ {12, 0x6a, 32}, /* 0000 0110 1010 */
+ {12, 0x6b, 33}, /* 0000 0110 1011 */
+ {12, 0x6c, 40}, /* 0000 0110 1100 */
+ {12, 0x6d, 41}, /* 0000 0110 1101 */
+ {12, 0xc8, 128}, /* 0000 1100 1000 */
+ {12, 0xc9, 192}, /* 0000 1100 1001 */
+ {12, 0xca, 26}, /* 0000 1100 1010 */
+ {12, 0xcb, 27}, /* 0000 1100 1011 */
+ {12, 0xcc, 28}, /* 0000 1100 1100 */
+ {12, 0xcd, 29}, /* 0000 1100 1101 */
+ {12, 0xd2, 34}, /* 0000 1101 0010 */
+ {12, 0xd3, 35}, /* 0000 1101 0011 */
+ {12, 0xd4, 36}, /* 0000 1101 0100 */
+ {12, 0xd5, 37}, /* 0000 1101 0101 */
+ {12, 0xd6, 38}, /* 0000 1101 0110 */
+ {12, 0xd7, 39}, /* 0000 1101 0111 */
+ {12, 0xda, 42}, /* 0000 1101 1010 */
+ {12, 0xdb, 43}, /* 0000 1101 1011 */
+ {13, 0x4a, 640}, /* 0000 0010 0101 0 */
+ {13, 0x4b, 704}, /* 0000 0010 0101 1 */
+ {13, 0x4c, 768}, /* 0000 0010 0110 0 */
+ {13, 0x4d, 832}, /* 0000 0010 0110 1 */
+ {13, 0x52, 1280}, /* 0000 0010 1001 0 */
+ {13, 0x53, 1344}, /* 0000 0010 1001 1 */
+ {13, 0x54, 1408}, /* 0000 0010 1010 0 */
+ {13, 0x55, 1472}, /* 0000 0010 1010 1 */
+ {13, 0x5a, 1536}, /* 0000 0010 1101 0 */
+ {13, 0x5b, 1600}, /* 0000 0010 1101 1 */
+ {13, 0x64, 1664}, /* 0000 0011 0010 0 */
+ {13, 0x65, 1728}, /* 0000 0011 0010 1 */
+ {13, 0x6c, 512}, /* 0000 0011 0110 0 */
+ {13, 0x6d, 576}, /* 0000 0011 0110 1 */
+ {13, 0x72, 896}, /* 0000 0011 1001 0 */
+ {13, 0x73, 960}, /* 0000 0011 1001 1 */
+ {13, 0x74, 1024}, /* 0000 0011 1010 0 */
+ {13, 0x75, 1088}, /* 0000 0011 1010 1 */
+ {13, 0x76, 1152}, /* 0000 0011 1011 0 */
+ {13, 0x77, 1216} /* 0000 0011 1011 1 */
+};
+
+static Tab faxcodes[Nfaxcodes] = {
+ {1, 0x1, 0}, /* 1 */
+ {3, 0x1, 0}, /* 001 */
+ {3, 0x2, 0}, /* 010 */
+ {3, 0x3, 0}, /* 011 */
+ {4, 0x1, 0}, /* 0001 */
+ {6, 0x2, 0}, /* 0000 10 */
+ {6, 0x3, 0}, /* 0000 11 */
+ {7, 0x2, 0}, /* 0000 010 */
+ {7, 0x3, 0}, /* 0000 011 */
+ {12, 0x1, -1} /* 0000 0000 0001 */
+};
+
+static int typesizes[] = {0, 1, 0, 2, 4};
+static int vcodeval[] = {0, 0, 0, 1, 0, 0, 2, 3};
+
+static ulong byte2le(uchar *);
+static ulong byte4le(uchar *);
+static ulong byte2be(uchar *);
+static ulong byte4be(uchar *);
+static void readdata(Tif *, ulong);
+static void readnbytes(Tif *, ulong);
+static ulong readbyte(Tif *);
+static ulong readshort(Tif *);
+static ulong readlong(Tif *);
+static int gototif(Tif *, ulong);
+static int readheader(Tif *);
+static uchar *nocomp(Tif *);
+static int getbit1(Fax *);
+static int getbit2(Fax *);
+static Tab *findtab(Fax *, int, int, Tab *, int);
+static Tab *gettab(Fax *, int);
+static Tab *geteol(Fax *);
+static int faxfill(Fax *, uchar *, ulong, ulong *, ulong *, ulong, int);
+static void fillbits(Fax *);
+static int faxalloclines(Fax *);
+static Tab *getfax1d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
+static Tab *getfax2d(Fax *, uchar *, ulong, ulong *, ulong *, ulong);
+static int faxstrip(Tif *, Fax *, uchar *, ulong, ulong *);
+static uchar *fax(Tif *);
+static void tabinit(Lzw *);
+static Code *newcode(Lzw *, Code *);
+static void listadd(Lzw *, Code *);
+static Code *tabadd(Lzw *, Code *, Code *);
+static int getcode(Lzw *);
+static int wstr(uchar *, ulong, ulong *, Code *, long *);
+static void predict(Tif *, uchar *);
+static int lzwstrip(Lzw *, uchar *, ulong, ulong *, long);
+static uchar *lzw(Tif *);
+static uchar *packbits(Tif *);
+static int faxdecode(Tif *, Rawimage *, uchar *);
+static int greydecode(Tif *, Rawimage *, uchar *);
+static int rgbdecode(Tif *, Rawimage *, uchar *);
+static int paldecode(Tif *, Rawimage *, uchar *);
+static int parsefield(Tif *, Fld *);
+static int readfield(Tif *, Fld *);
+static int checkfields(Tif *);
+static int readstrips(Tif *);
+static Rawimage *decode(Tif *);
+static void freefields(Tif *);
+static Rawimage *readslave(Tif *);
+
+static ulong
+byte2le(uchar *buf)
+{
+ return (buf[1] << 8) | buf[0];
+}
+
+static ulong
+byte4le(uchar *buf)
+{
+ return (byte2le(buf+2) << 16) | byte2le(buf);
+}
+
+static ulong
+byte2be(uchar *buf)
+{
+ return (buf[0] << 8) | buf[1];
+}
+
+static ulong
+byte4be(uchar *buf)
+{
+ return (byte2be(buf) << 16) | byte2be(buf+2);
+}
+
+static void
+readdata(Tif *t, ulong offset)
+{
+ long n, m;
+ ulong size;
+
+ if(offset < t->nbuf)
+ offset = t->nbuf;
+ m = offset + 4096 - t->nbuf;
+ size = (m + t->nbuf) * sizeof *t->buf;
+ if(t->buf == nil) {
+ if((t->buf = malloc(size)) == nil)
+ sysfatal("malloc: %r");
+ } else {
+ if((t->buf = realloc(t->buf, size)) == nil)
+ sysfatal("realloc: %r");
+ }
+ if((n = Bread(t->fd, t->buf+t->nbuf, m)) < 0)
+ sysfatal("Bread: %r");
+ if(n != m)
+ t->eof = 1;
+ t->nbuf += n;
+}
+
+static void
+readnbytes(Tif *t, ulong n)
+{
+ if(n <= 0 || n > 4)
+ sysfatal("cannot read %lud bytes", n);
+ if(t->n+n > t->nbuf) {
+ if(t->eof)
+ sysfatal("reached end of file");
+ readdata(t, 0);
+ }
+ memmove(t->tmp, t->buf+t->n, n);
+ t->n += n;
+}
+
+static ulong
+readbyte(Tif *t)
+{
+ readnbytes(t, 1);
+ return t->tmp[0];
+}
+
+static ulong
+readshort(Tif *t)
+{
+ readnbytes(t, 2);
+ return (*t->byte2)(t->tmp);
+}
+
+static ulong
+readlong(Tif *t)
+{
+ readnbytes(t, 4);
+ return (*t->byte4)(t->tmp);
+}
+
+static int
+gototif(Tif *t, ulong n)
+{
+ if(n < 8) {
+ werrstr("offset pointing to header");
+ return -1;
+ }
+ if(n > t->nbuf)
+ readdata(t, n);
+ t->n = n;
+ return 0;
+}
+
+static int
+readheader(Tif *t)
+{
+ uint n;
+
+ t->end = readshort(t);
+ switch(t->end) {
+ case II:
+ break;
+ case MM:
+ t->byte2 = byte2be;
+ t->byte4 = byte4be;
+ break;
+ default:
+ werrstr("illegal byte order: %#.4x", t->end);
+ return -1;
+ }
+ if((n = readshort(t)) != TIF) {
+ werrstr("illegal tiff magic: %#.4x", n);
+ return -1;
+ }
+ t->off = readlong(t);
+ return gototif(t, t->off);
+}
+
+static uchar *
+nocomp(Tif *t)
+{
+ return t->data;
+}
+
+static int
+getbit1(Fax *f)
+{
+ int bit;
+
+ if(f->n >= f->next)
+ return -1;
+ bit = (f->data[f->n] >> f->m) & 0x1;
+ f->m--;
+ if(f->m < 0) {
+ f->n++;
+ f->m = 7;
+ }
+ return bit;
+}
+
+static int
+getbit2(Fax *f)
+{
+ int bit;
+
+ if(f->n >= f->next)
+ return -1;
+ bit = (f->data[f->n] >> f->m) & 0x1;
+ f->m++;
+ if(f->m >= 8) {
+ f->n++;
+ f->m = 0;
+ }
+ return bit;
+}
+
+static Tab *
+findtab(Fax *f, int code, int len, Tab *tab, int max)
+{
+ Tab *p;
+
+ while(f->ntab < max) {
+ p = &tab[f->ntab];
+ if(p->len > len)
+ break;
+ if(p->code == code) {
+ f->ntab = 0;
+ return p;
+ }
+ f->ntab++;
+ }
+ return nil;
+}
+
+static Tab *
+gettab(Fax *f, int mode)
+{
+ int i, n, maxlen, bit, code;
+ Tab *p, *tab;
+
+ code = 0;
+ if(mode) {
+ n = Nfaxcodes;
+ tab = faxcodes;
+ } else {
+ n = Nfaxtab;
+ tab = f->tab[f->st];
+ }
+ maxlen = tab[n-1].len;
+ for(i = 1; i <= maxlen; i++) {
+ if((bit = (*f->getbit)(f)) < 0) {
+ f->st = -1;
+ return nil;
+ }
+ code = (code << 1) | bit;
+ if((p = findtab(f, code, i, tab, n)) != nil)
+ return p;
+ }
+ werrstr("code not found");
+ return nil;
+}
+
+static Tab *
+geteol(Fax *f)
+{
+ int i, bit;
+ Tab *p;
+
+ if(f->eol == nil) {
+ if((p = gettab(f, 0)) == nil || p->run >= 0) {
+ werrstr("first eol");
+ return nil;
+ }
+ f->eol = p;
+ return p;
+ }
+ for(i = 0; (bit = (*f->getbit)(f)) == 0; i++)
+ ;
+ if(bit < 0) {
+ f->st = -1;
+ return nil;
+ }
+ if(i < 11) {
+ werrstr("eol");
+ return nil;
+ }
+ return f->eol;
+}
+
+static int
+faxfill(Fax *f, uchar *data, ulong size, ulong *i, ulong *x, ulong dx,
+ int n)
+{
+ if((*x += n) > dx) {
+ werrstr("fax row overflow");
+ return -1;
+ }
+ if((*i += n) >= size) {
+ werrstr("fax data overflow");
+ return -1;
+ }
+ if(f->st != 0)
+ memset(data+*i-n, f->st, n);
+ return 0;
+}
+
+static void
+fillbits(Fax *f)
+{
+ if(f->getbit == getbit1) {
+ if(f->m != 7) {
+ f->n++;
+ f->m = 7;
+ }
+ } else {
+ if(f->m != 0) {
+ f->n++;
+ f->m = 0;
+ }
+ }
+}
+
+static int
+faxalloclines(Fax *f)
+{
+ f->nl *= 2;
+ f->l1 = realloc(f->l1, f->nl*sizeof *f->l1);
+ if(f->l1 == nil)
+ return -1;
+ f->l2 = realloc(f->l2, f->nl*sizeof *f->l2);
+ if(f->l2 == nil) {
+ free(f->l1);
+ return -1;
+ }
+ return 0;
+}
+
+static Tab *
+getfax1d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
+ ulong dx)
+{
+ int j, n;
+ Tab *p;
+
+ for(j = 0; *x < dx;) {
+ if((p = gettab(f, 0)) == nil)
+ return nil;
+ if((n = p->run) < 0) {
+ f->l1[j] = dx;
+ return f->eol;
+ }
+ if(faxfill(f, data, size, i, x, dx, n) < 0)
+ return nil;
+ if(n < 64) {
+ f->l1[j++] = *x;
+ f->st ^= 1;
+ }
+ if(j >= f->nl)
+ faxalloclines(f);
+ }
+ return nil;
+}
+
+static Tab *
+getfax2d(Fax *f, uchar *data, ulong size, ulong *i, ulong *x,
+ ulong dx)
+{
+ int j, k, n, code, len, a0, a1, b1, b2, v;
+ Tab *p;
+
+ a0 = -1;
+ for(j = 0; *x < dx;) {
+ for(k = 0;; k++) {
+ b1 = f->l1[k];
+ if(b1 > a0 && f->st == k%2)
+ break;
+ if(b1 >= dx)
+ break;
+ }
+ if((b2 = b1) < dx)
+ b2 = f->l1[k+1];
+ if((p = gettab(f, 1)) == nil)
+ return nil;
+ /* early eofb */
+ if(p->run < 0) {
+ f->st = -1;
+ return nil;
+ }
+ len = p->len;
+ code = p->code;
+ if(code == 1 && len == 3) {
+ /* horizontal */
+ for(k = 0; k < 2;) {
+ if((p = gettab(f, 0)) == nil)
+ return nil;
+ n = p->run;
+ if(faxfill(f, data, size, i, x,
+ dx, n) < 0)
+ return nil;
+ if(n < 64) {
+ f->l2[j++] = *x;
+ f->st ^= 1;
+ k++;
+ }
+ }
+ } else if(code == 1 && len == 4) {
+ /* pass */
+ n = b2 - *x;
+ if(faxfill(f, data, size, i, x, dx, n) < 0)
+ return nil;
+ if(*x == dx)
+ f->l2[j++] = *x;
+ } else {
+ /* vertical */
+ switch(code) {
+ case 1:
+ case 2:
+ v = -vcodeval[len];
+ break;
+ case 3:
+ v = vcodeval[len];
+ break;
+ default:
+ werrstr("mode");
+ return nil;
+ }
+ a1 = b1 + v;
+ n = a1 - *x;
+ if(faxfill(f, data, size, i, x, dx, n) < 0)
+ return nil;
+ f->l2[j++] = *x;
+ f->st ^= 1;
+ }
+ if(j >= f->nl)
+ faxalloclines(f);
+ a0 = *x;
+ }
+ memmove(f->l1, f->l2, j*sizeof *f->l1);
+ return nil;
+}
+
+static int
+faxstrip(Tif *t, Fax *f, uchar *data, ulong size, ulong *i)
+{
+ int d1;
+ ulong x, y;
+ Tab *p;
+
+ d1 = t->comp != T6enc;
+ p = nil;
+ for(x = y = 0; x < t->dx || y < t->rows;) {
+ f->st = 0;
+ if(t->comp == T4enc) {
+ if(p == nil && geteol(f) == nil) {
+ if(f->st >= 0)
+ return -1;
+ break;
+ }
+ if(y > 0)
+ *i += t->dx - x;
+ if(t->t4 & 1) {
+ d1 = (*f->getbit)(f);
+ if(d1 < 0)
+ break;
+ }
+ }
+ x = 0;
+ y++;
+ if(d1) {
+ p = getfax1d(f, data, size, i,
+ &x, t->dx);
+ } else {
+ p = getfax2d(f, data, size, i,
+ &x, t->dx);
+ }
+ if(t->comp == Huffman)
+ fillbits(f);
+ if(p == nil && x != t->dx) {
+ if(f->st >= 0 || x > t->dx)
+ return -1;
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+* the t4 fax test images i decoded did not follow the
+* spec. in particular, they did not have rtcs.
+*/
+static uchar *
+fax(Tif *t)
+{
+ int m;
+ ulong i, j, datasz, linesz;
+ uchar *data;
+ Fax f;
+
+ datasz = t->dx * t->dy * sizeof *data;
+ data = malloc(datasz);
+ f.nl = t->dx;
+ linesz = f.nl * sizeof *f.l1;
+ f.l1 = malloc(linesz);
+ f.l2 = malloc(linesz);
+ if(data == nil || f.l1 == nil || f.l2 == nil) {
+ free(t->data);
+ if(data != nil)
+ free(data);
+ if(f.l1 != nil)
+ free(f.l1);
+ if(f.l2 != nil)
+ free(f.l2);
+ return nil;
+ }
+ memset(data, 0, datasz);
+ memset(f.l1, 0, linesz);
+ memset(f.l2, 0, linesz);
+ if(t->fill == 1) {
+ f.getbit = getbit1;
+ m = 7;
+ } else {
+ f.getbit = getbit2;
+ m = 0;
+ }
+ f.tab[0] = faxwhite;
+ f.tab[1] = faxblack;
+ f.ntab = 0;
+ f.eol = nil;
+ f.data = t->data;
+ for(i = j = 0; i < t->nstrips; i++) {
+ f.l1[0] = t->dx;
+ f.n = t->strips[i];
+ f.m = m;
+ if(i < t->nstrips-1)
+ f.next = t->strips[i+1];
+ else
+ f.next = t->ndata;
+ if(faxstrip(t, &f, data, datasz, &j) < 0)
+ break;
+ }
+ if(i < t->nstrips) {
+ free(data);
+ data = nil;
+ }
+ free(t->data);
+ free(f.l1);
+ free(f.l2);
+ return data;
+}
+
+static void
+tabinit(Lzw *l)
+{
+ l->ntab = Eoicode + 1;
+ l->len = 9;
+}
+
+static Code *
+newcode(Lzw *l, Code *p)
+{
+ Code *q;
+
+ if(p == nil)
+ return nil;
+ if(l->first != nil) {
+ q = l->first;
+ if((l->first = l->first->next) == nil)
+ l->last = nil;
+ } else if((q = malloc(sizeof *q)) == nil)
+ return nil;
+ q->val = p->val;
+ q->next = nil;
+ return q;
+}
+
+static void
+listadd(Lzw *l, Code *p)
+{
+ if(p == nil)
+ return;
+ if(l->last != nil)
+ l->last->next = p;
+ else
+ l->first = l->last = p;
+ while(l->last->next != nil)
+ l->last = l->last->next;
+}
+
+static Code *
+tabadd(Lzw *l, Code *p, Code *q)
+{
+ Code *r, *s;
+
+ if(l->ntab >= Tabsz) {
+ werrstr("lzw table full");
+ return nil;
+ }
+ r = s = &l->tab[l->ntab++];
+ switch(l->ntab) {
+ case 511:
+ case 1023:
+ case 2047:
+ l->len++;
+ break;
+ default:
+ break;
+ }
+ s->val = p->val;
+ while((p = p->next) != nil) {
+ if(s->next != nil)
+ s->next->val = p->val;
+ else if((s->next = newcode(l, p)) == nil)
+ return nil;
+ s = s->next;
+ }
+ if(s->next != nil) {
+ s->next->val = q->val;
+ s = s->next;
+ if(s->next != nil) {
+ listadd(l, s->next);
+ s->next = nil;
+ }
+ } else if((s->next = newcode(l, q)) == nil)
+ return nil;
+ return r;
+}
+
+static int
+getcode(Lzw *l)
+{
+ int i, c, code;
+
+ if(l->n >= l->next) {
+ werrstr("lzw eof");
+ return -1;
+ }
+ code = 0;
+ for(i = l->len-1; i >= 0; i--) {
+ c = (l->data[l->n] >> l->m) & 0x1;
+ code |= c << i;
+ l->m--;
+ if(l->m < 0) {
+ l->n++;
+ l->m = 7;
+ }
+ }
+ return code;
+}
+
+static int
+wstr(uchar *data, ulong size, ulong *i, Code *p, long *striplen)
+{
+ for(; p != nil; p = p->next, ++*i, --*striplen) {
+ if(*i >= size || *striplen < 0) {
+ werrstr("lzw overflow");
+ return -1;
+ }
+ data[*i] = p->val;
+ }
+ return 0;
+}
+
+static void
+predict(Tif *t, uchar *data)
+{
+ char a, b;
+ ulong y, x, i, j, k, s;
+
+ s = t->samples;
+ for(y = 0; y < t->dy; y++) {
+ for(x = 1; x < t->dx; x++) {
+ i = y*t->dx + x;
+ for(j = 0; j < s; j++) {
+ k = i*s + j;
+ a = (char)data[k];
+ b = (char)data[k-s];
+ data[k] = (uchar)(a + b);
+ }
+ }
+ }
+}
+
+static int
+lzwstrip(Lzw *l, uchar *data, ulong size, ulong *i, long striplen)
+{
+ int c, oc;
+ Code *p, *q;
+
+ if((c = getcode(l)) != Clrcode) {
+ werrstr("clear code");
+ return -1;
+ }
+ for(oc = -1; c != Eoicode;) {
+ if(c < 0)
+ return -1;
+ if(c == Clrcode) {
+ if(oc >= 0)
+ tabinit(l);
+ if((c = getcode(l)) == Eoicode)
+ break;
+ if(c < 0)
+ return -1;
+ if(wstr(data, size, i, &l->tab[c],
+ &striplen) < 0)
+ return -1;
+ } else if(c < l->ntab) {
+ p = &l->tab[c];
+ if(wstr(data, size, i, p,
+ &striplen) < 0)
+ return -1;
+ q = &l->tab[oc];
+ if(tabadd(l, q, p) == nil)
+ return -1;
+ } else {
+ q = &l->tab[oc];
+ if((p = tabadd(l, q, q)) == nil)
+ return -1;
+ if(wstr(data, size, i, p,
+ &striplen) < 0)
+ return -1;
+ }
+ if(striplen <= 0)
+ break;
+ oc = c;
+ c = getcode(l);
+ }
+ return 0;
+}
+
+static uchar *
+lzw(Tif *t)
+{
+ ulong i, j, size;
+ long striplen;
+ uchar *data;
+ Lzw l;
+ Code *p, *q;
+
+ i = t->dx * t->rows * t->depth;
+ striplen = i%8 == 0? i/8: i/8+1;
+ size = t->nstrips * striplen * sizeof *data;
+ if((data = malloc(size)) == nil) {
+ free(t->data);
+ return nil;
+ }
+ for(i = 0; i < Tabsz; i++) {
+ l.tab[i].val = i;
+ l.tab[i].next = nil;
+ }
+ l.data = t->data;
+ l.first = l.last = nil;
+ for(i = j = 0; i < t->nstrips; i++) {
+ tabinit(&l);
+ l.n = t->strips[i];
+ l.m = 7;
+ if(i < t->nstrips-1)
+ l.next = t->strips[i+1];
+ else
+ l.next = t->ndata;
+ if(lzwstrip(&l, data, size, &j, striplen) < 0)
+ break;
+ }
+ if(i < t->nstrips) {
+ free(data);
+ data = nil;
+ }
+ for(i = 0; i < Tabsz; i++) {
+ for(p = l.tab[i].next; (q = p) != nil;) {
+ p = p->next;
+ free(q);
+ }
+ }
+ for(p = l.first; (q = p) != nil;) {
+ p = p->next;
+ free(q);
+ }
+ free(t->data);
+ if(data != nil && t->predictor == 2)
+ predict(t, data);
+ return data;
+}
+
+static uchar *
+packbits(Tif *t)
+{
+ char n;
+ ulong i, j, k, size;
+ uchar *data;
+
+ size = t->dx * t->dy * t->samples * sizeof *data;
+ if((data = malloc(size)) == nil) {
+ free(t->data);
+ return nil;
+ }
+ for(i = 0, j = 0; i < t->ndata;) {
+ n = (char)t->data[i++];
+ if(n >= 0) {
+ k = n + 1;
+ if(j+k >= size || i+k >= t->ndata)
+ break;
+ memmove(data+j, t->data+i, k);
+ i += k;
+ j += k;
+ } else if(n > -128 && n < 0) {
+ k = j - n + 1;
+ if(k > size || i >= t->ndata)
+ break;
+ for(; j < k; j++)
+ data[j] = t->data[i];
+ i++;
+ }
+ }
+ if(i < t->ndata) {
+ werrstr("packbits overflow");
+ free(data);
+ data = nil;
+ }
+ free(t->data);
+ return data;
+}
+
+static int
+faxdecode(Tif *t, Rawimage *im, uchar *data)
+{
+ ulong n;
+
+ for(n = 0; n < im->chanlen; n++) {
+ if(t->photo == Whitezero)
+ data[n] ^= 1;
+ im->chans[0][n] = data[n] * 0xff;
+ }
+ return 0;
+}
+
+static int
+greydecode(Tif *t, Rawimage *im, uchar *data)
+{
+ int pix, pmask, xmask;
+ ulong i, n, x, y;
+
+ pmask = (1 << t->depth) - 1;
+ xmask = 7 >> log2[t->depth];
+ for(y = 0, n = 0; y < t->dy; y++) {
+ i = y * bytesperline(im->r, t->depth);
+ for(x = 0; x < t->dx; x++, n++) {
+ if(n >= im->chanlen) {
+ werrstr("grey overflow");
+ return -1;
+ }
+ pix = (data[i] >> t->depth*((xmask -
+ x) & xmask)) & pmask;
+ if(((x + 1) & xmask) == 0)
+ i++;
+ if(t->photo == Whitezero)
+ pix ^= pmask;
+ pix = (pix * 0xff) / pmask;
+ im->chans[0][n] = pix;
+ }
+ }
+ return 0;
+}
+
+static int
+rgbdecode(Tif *t, Rawimage *im, uchar *data)
+{
+ ulong i, n, x, y;
+
+ for(y = 0, n = 0; y < t->dy; y++) {
+ for(x = 0; x < t->dx; x++, n += 3) {
+ if(n >= im->chanlen) {
+ werrstr("rgb overflow");
+ return -1;
+ }
+ i = (y*t->dx + x) * 3;
+ im->chans[0][n] = data[i+2];
+ im->chans[0][n+1] = data[i+1];
+ im->chans[0][n+2] = data[i];
+ }
+ }
+ return 0;
+}
+
+static int
+paldecode(Tif *t, Rawimage *im, uchar *data)
+{
+ int pix, pmask, xmask;
+ ulong i, n, x, y, *r, *g, *b, max;
+
+ pmask = (1 << t->depth) - 1;
+ xmask = 7 >> log2[t->depth];
+ for(i = 0, max = 1; i < t->ncolor; i++) {
+ if(t->color[i] > max)
+ max = t->color[i];
+ }
+ for(i = 0; i < t->ncolor; i++)
+ t->color[i] = (t->color[i] * 0xff) / max;
+ r = t->color;
+ g = r + pmask + 1;
+ b = g + pmask + 1;
+ for(y = 0, n = 0; y < t->dy; y++) {
+ i = y * bytesperline(im->r, t->depth);
+ for(x = 0; x < t->dx; x++, n += 3) {
+ if(n >= im->chanlen) {
+ werrstr("palette overflow");
+ return -1;
+ }
+ pix = (data[i] >> t->depth*((xmask -
+ x) & xmask)) & pmask;
+ if(((x + 1) & xmask) == 0)
+ i++;
+ im->chans[0][n] = b[pix];
+ im->chans[0][n+1] = g[pix];
+ im->chans[0][n+2] = r[pix];
+ }
+ }
+ return 0;
+}
+
+static int
+parsefield(Tif *t, Fld *f)
+{
+ ulong v;
+
+ v = f->val[0];
+ switch(f->tag) {
+ case Width:
+ t->dx = v;
+ break;
+ case Length:
+ t->dy = v;
+ break;
+ case Bits:
+ t->depth = v;
+ if(f->cnt == 3)
+ t->depth += f->val[1] + f->val[2];
+ break;
+ case Compression:
+ t->comp = v;
+ break;
+ case Photometric:
+ t->photo = v;
+ switch(t->photo) {
+ case Whitezero:
+ case Blackzero:
+ t->decode = greydecode;
+ break;
+ case Rgb:
+ t->decode = rgbdecode;
+ break;
+ case Palette:
+ t->decode = paldecode;
+ break;
+ default:
+ break;
+ }
+ break;
+ case Strips:
+ t->strips = f->val;
+ t->nstrips = f->cnt;
+ break;
+ case Fill:
+ t->fill = v;
+ break;
+ case Orientation:
+ t->orientation = v;
+ break;
+ case Samples:
+ t->samples = v;
+ break;
+ case Rows:
+ t->rows = v;
+ break;
+ case Counts:
+ t->counts = f->val;
+ t->ncounts = f->cnt;
+ break;
+ case Planar:
+ t->planar = v;
+ break;
+ case T4opts:
+ t->t4 = v;
+ break;
+ case T6opts:
+ t->t6 = v;
+ break;
+ case Predictor:
+ t->predictor = v;
+ break;
+ case Color:
+ t->color = f->val;
+ t->ncolor = f->cnt;
+ break;
+ default:
+ werrstr("shouldn't reach");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+readfield(Tif *t, Fld *f)
+{
+ int size;
+ ulong i, j, n, off;
+ ulong (*readval)(Tif *);
+
+ f->tag = readshort(t);
+ f->typ = readshort(t);
+ f->cnt = readlong(t);
+ f->val = nil;
+ switch(f->tag) {
+ case Width:
+ case Length:
+ case Compression:
+ case Photometric:
+ case Fill:
+ case Orientation:
+ case Samples:
+ case Rows:
+ case Planar:
+ case T4opts:
+ case T6opts:
+ case Predictor:
+ if(f->cnt != 1) {
+ werrstr("field count");
+ return -1;
+ }
+ break;
+ case Bits:
+ if(f->cnt != 1 && f->cnt != 3) {
+ werrstr("field count");
+ return -1;
+ }
+ break;
+ case Strips:
+ case Counts:
+ case Color:
+ break;
+ default:
+ readlong(t);
+ return 0;
+ }
+ switch(f->typ) {
+ case Byte:
+ readval = readbyte;
+ break;
+ case Short:
+ readval = readshort;
+ break;
+ case Long:
+ readval = readlong;
+ break;
+ default:
+ werrstr("unsupported type\n");
+ return -1;
+ }
+ if((f->val = malloc(f->cnt*sizeof *f->val)) == nil)
+ return -1;
+ size = typesizes[f->typ];
+ if((n = size*f->cnt) <= 4) {
+ for(i = 0; i < f->cnt; i++)
+ f->val[i] = readval(t);
+ f->off = 0x0;
+ f->nval = i;
+ for(j = n; j < 4; j += size)
+ readval(t);
+ } else {
+ f->off = readlong(t);
+ off = t->n;
+ if(gototif(t, f->off) < 0)
+ return -1;
+ for(i = 0; i < f->cnt; i++)
+ f->val[i] = readval(t);
+ f->nval = i;
+ if(gototif(t, off) < 0)
+ return -1;
+ }
+ return parsefield(t, f);
+}
+
+static int
+checkfields(Tif *t)
+{
+ double a, b;
+ ulong n, size;
+
+ if(t->dx == 0) {
+ werrstr("image width");
+ return -1;
+ }
+ if(t->dy == 0) {
+ werrstr("image length");
+ return -1;
+ }
+ switch(t->depth) {
+ case 1:
+ case 4:
+ case 8:
+ case 24:
+ break;
+ default:
+ werrstr("bits per sample");
+ return -1;
+ }
+ switch(t->comp) {
+ case Nocomp:
+ t->uncompress = nocomp;
+ break;
+ case Huffman:
+ case T4enc:
+ case T6enc:
+ t->uncompress = fax;
+ if(t->decode != nil)
+ t->decode = faxdecode;
+ if((t->comp == T4enc && t->t4 & (1<<1)) ||
+ (t->comp == T6enc &&
+ t->t6 & (1<<1))) {
+ werrstr("uncompressed mode");
+ return -1;
+ }
+ break;
+ case Lzwenc:
+ t->uncompress = lzw;
+ break;
+ case Packbits:
+ t->uncompress = packbits;
+ break;
+ default:
+ werrstr("compression");
+ return -1;
+ }
+ if(t->decode == nil) {
+ werrstr("photometric interpretation");
+ return -1;
+ }
+ if(t->depth > 1 && (t->comp == Huffman ||
+ t->comp == T4enc || t->comp == T6enc)) {
+ werrstr("compression");
+ return -1;
+ }
+ if(t->fill != 1 && t->fill != 2) {
+ werrstr("fill order");
+ return -1;
+ }
+ if(t->fill == 2 && t->depth != 1) {
+ werrstr("depth should be 1 with fill order 2");
+ return -1;
+ }
+ if(t->orientation != 1) {
+ werrstr("orientation");
+ return -1;
+ }
+ if(t->rows == 0) {
+ werrstr("rows per strip");
+ return -1;
+ }
+ a = (double)t->dy;
+ b = (double)t->rows;
+ n = (ulong)floor((a+b-1)/b);
+ if(t->strips == nil || t->nstrips != n) {
+ werrstr("strip offsets");
+ return -1;
+ }
+ if(t->samples == 1 && t->photo == Rgb) {
+ werrstr("not enough samples per pixel");
+ return -1;
+ }
+ if(t->samples == 3 && t->photo != Rgb) {
+ werrstr("too many samples per pixel");
+ return -1;
+ }
+ if(t->samples != 1 && t->samples != 3) {
+ werrstr("samples per pixel");
+ return -1;
+ }
+ /*
+ * strip byte counts should not be missing,
+ * but we can guess correctly in this case
+ */
+ size = sizeof *t->counts;
+ if(t->counts == nil && t->comp == Nocomp &&
+ t->nstrips == 1 &&
+ (t->counts = malloc(size)) != nil) {
+ n = t->dx * t->dy * t->depth;
+ t->counts[0] = n%8 == 0? n/8: n/8+1;
+ t->ncounts = t->nstrips;
+ }
+ if(t->counts == nil || t->ncounts != t->nstrips) {
+ werrstr("strip byte counts");
+ return -1;
+ }
+ if(t->planar != 1) {
+ werrstr("planar configuration");
+ return -1;
+ }
+ if(t->photo == Palette && (t->color == nil ||
+ t->ncolor != 3*(1<<t->depth))) {
+ werrstr("color map");
+ return -1;
+ }
+ if(t->predictor == 2 && t->depth == 1) {
+ werrstr("depth too low for predictor 2");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+readstrips(Tif *t)
+{
+ int i, j, n;
+ ulong off;
+
+ t->ndata = 0;
+ for(i = 0; i < t->nstrips; i++)
+ t->ndata += t->counts[i];
+ if((t->data = malloc(t->ndata*sizeof *t->data)) == nil)
+ return -1;
+ off = t->n;
+ for(i = n = 0; i < t->nstrips; i++) {
+ if(gototif(t, t->strips[i]) < 0)
+ return -1;
+ /*
+ * we store each strip's offset in t->data
+ * in order to skip the final rtc or eofb
+ * during fax decoding. t->strips is used
+ * to save on memory allocation. these
+ * offsets are also used in lzw as a
+ * preventive measure.
+ */
+ t->strips[i] = n;
+ for(j = 0; j < t->counts[i]; j++, n++)
+ t->data[n] = readbyte(t);
+ }
+ return gototif(t, off);
+}
+
+static Rawimage *
+decode(Tif *t)
+{
+ ulong size;
+ uchar *data;
+ Rawimage *im;
+
+ if((im = malloc(sizeof *im)) == nil)
+ return nil;
+ im->r = Rect(0, 0, t->dx, t->dy);
+ im->cmap = nil;
+ im->cmaplen = 0;
+ im->chanlen = t->dx * t->dy;
+ if(t->photo == Rgb || t->photo == Palette) {
+ im->chandesc = CRGB24;
+ im->chanlen *= 3;
+ } else
+ im->chandesc = CY;
+ im->nchans = 1;
+ size = im->chanlen * sizeof *im->chans[0];
+ if((im->chans[0] = malloc(size)) == nil)
+ return nil;
+ /* unused members */
+ im->fields = 0;
+ im->gifflags = 0;
+ im->gifdelay = 0;
+ im->giftrindex = 0;
+ im->gifloopcount = 1;
+ if((data = (*t->uncompress)(t)) == nil)
+ return nil;
+ if((*t->decode)(t, im, data) < 0) {
+ free(im->chans[0]);
+ free(im);
+ im = nil;
+ }
+ free(data);
+ return im;
+}
+
+static void
+freefields(Tif *t)
+{
+ uint i;
+
+ for(i = 0; i < t->nfld; i++) {
+ if(t->fld[i].val != nil)
+ free(t->fld[i].val);
+ }
+ free(t->fld);
+}
+
+static Rawimage *
+readslave(Tif *t)
+{
+ uint i, j;
+ Rawimage *r;
+
+ if(readheader(t) < 0)
+ return nil;
+ if((t->nfld = readshort(t)) <= 0) {
+ werrstr("illegal field number: %#.4x", t->nfld);
+ return nil;
+ }
+ if((t->fld = malloc(t->nfld*sizeof *t->fld)) == nil)
+ return nil;
+ for(i = 0; i < t->nfld; i++) {
+ if(readfield(t, &t->fld[i]) < 0) {
+ if(t->fld[i].val != nil)
+ free(t->fld[i].val);
+ break;
+ }
+ }
+ if(i < t->nfld) {
+ for(j = 0; j < i; j++) {
+ if(t->fld[j].val != nil)
+ free(t->fld[j].val);
+ }
+ free(t->fld);
+ return nil;
+ }
+ readlong(t);
+ if(checkfields(t) < 0) {
+ freefields(t);
+ return nil;
+ }
+ if(readstrips(t) < 0) {
+ freefields(t);
+ if(t->data != nil)
+ free(t->data);
+ return nil;
+ }
+ free(t->buf);
+ r = decode(t);
+ freefields(t);
+ return r;
+}
+
+Rawimage **
+Breadtif(Biobuf *b)
+{
+ Rawimage **array, *r;
+ Tif *t;
+
+ if((t = malloc(sizeof *t)) == nil)
+ return nil;
+ if((array = malloc(2*sizeof *array)) == nil)
+ return nil;
+ t->fd = b;
+ t->buf = nil;
+ t->nbuf = t->eof = t->n = 0;
+ /* order doesn't matter for the first two bytes */
+ t->byte2 = byte2le;
+ t->byte4 = byte4le;
+ /* defaults */
+ t->dx = 0;
+ t->dy = 0;
+ t->depth = 1;
+ t->comp = 1;
+ t->uncompress = nil;
+ t->photo = 0;
+ t->decode = nil;
+ t->fill = 1;
+ t->orientation = 1;
+ t->strips = nil;
+ t->nstrips = 0;
+ t->samples = 1;
+ t->rows = 0xffffffff; /* entire image is one strip */
+ t->counts = nil;
+ t->ncounts = 0;
+ t->planar = 1;
+ t->t4 = 0;
+ t->t6 = 0;
+ t->predictor = 1;
+ t->color = nil;
+ t->ncolor = 0;
+ r = readslave(t);
+ free(t);
+ array[0] = r;
+ array[1] = nil;
+ return array;
+}
+
+Rawimage **
+readtif(int fd)
+{
+ Rawimage **a;
+ Biobuf b;
+
+ if(Binit(&b, fd, OREAD) < 0)
+ return nil;
+ a = Breadtif(&b);
+ Bterm(&b);
+ return a;
+}
diff --git a/sys/src/cmd/jpg/tif.c b/sys/src/cmd/jpg/tif.c
new file mode 100644
index 000000000..6607efb93
--- /dev/null
+++ b/sys/src/cmd/jpg/tif.c
@@ -0,0 +1,251 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include "imagefile.h"
+
+int cflag = 0;
+int dflag = 0;
+int eflag = 0;
+int nineflag = 0;
+int threeflag = 0;
+int output = 0;
+Image *image;
+int defaultcolor = 1;
+
+enum {
+ Border = 2,
+ Edge = 5
+};
+
+int init(void);
+char *show(int, char *, int);
+
+void
+eresized(int new)
+{
+ Rectangle r;
+
+ if(new && getwindow(display, Refnone) < 0)
+ sysfatal("getwindow: %r");
+ if(image == nil)
+ return;
+ r = insetrect(screen->clipr, Edge+Border);
+ r.max.x = r.min.x + Dx(image->r);
+ r.max.y = r.min.y + Dy(image->r);
+ border(screen, r, -Border, nil, ZP);
+ drawop(screen, r, image, nil, image->r.min, S);
+ flushimage(display, 1);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-39cdektv] [file.tif ...]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int fd, i;
+ char *err;
+ ulong outchan;
+
+ outchan = CMAP8;
+ ARGBEGIN {
+ /*
+ * produce encoded, compressed, bitmap file;
+ * no display by default
+ */
+ case 'c':
+ cflag++;
+ dflag++;
+ output++;
+ if(defaultcolor)
+ outchan = CMAP8;
+ break;
+ /* suppress display of image */
+ case 'd':
+ dflag++;
+ break;
+ /* disable floyd-steinberg error diffusion */
+ case 'e':
+ eflag++;
+ break;
+ /* force black and white */
+ case 'k':
+ defaultcolor = 0;
+ outchan = GREY8;
+ break;
+ /*
+ * produce encoded, compressed, three-color
+ * bitmap file; no display by default
+ */
+ case '3':
+ threeflag++;
+ /* fall through */
+ /*
+ * produce encoded, compressed, true-color
+ * bitmap file; no display by default
+ */
+ case 't':
+ cflag++;
+ dflag++;
+ output++;
+ defaultcolor = 0;
+ outchan = RGB24;
+ break;
+ /* force RGBV */
+ case 'v':
+ defaultcolor = 0;
+ outchan = CMAP8;
+ break;
+ /*
+ * produce plan 9, uncompressed, bitmap file;
+ * no display by default
+ */
+ case '9':
+ nineflag++;
+ dflag++;
+ output++;
+ if(defaultcolor)
+ outchan = CMAP8;
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if(argc <= 0)
+ exits(show(0, "<stdin>", outchan));
+ err = nil;
+ for(i = 0; i < argc; i++) {
+ if((fd = open(argv[i], OREAD)) < 0) {
+ fprint(2, "%s: open %s: %r\n",
+ argv0, argv[i]);
+ err = "open";
+ } else {
+ err = show(fd, argv[i], outchan);
+ close(fd);
+ }
+ if((nineflag || cflag) && argc > 1 && err == nil) {
+ fprint(2, "%s: exiting after one file\n",
+ argv0);
+ break;
+ }
+ }
+ exits(err);
+}
+
+int
+init(void)
+{
+ static int inited = 0;
+
+ if(!inited) {
+ if(initdraw(0, 0, 0) < 0) {
+ fprint(2, "%s: initdraw: %r", argv0);
+ return -1;
+ }
+ einit(Ekeyboard|Emouse);
+ inited++;
+ }
+ return 0;
+}
+
+char *
+show(int fd, char *name, int outchan)
+{
+ Rawimage **array, *r, *c;
+ Image *i;
+ int j, ch;
+ Biobuf b;
+ char buf[32];
+
+ if(Binit(&b, fd, OREAD) < 0)
+ return nil;
+ array = Breadtif(&b);
+ if(array == nil || array[0] == nil) {
+ if(array != nil)
+ free(array);
+ fprint(2, "%s: decode %s failed: %r\n", argv0,
+ name);
+ return "decode";
+ }
+ Bterm(&b);
+ if(!dflag) {
+ if(init() < 0)
+ return "initdraw";
+/* fixme: ppm doesn't check for outchan==CMAP8 */
+ if(defaultcolor && screen->depth > 8 &&
+ outchan == CMAP8)
+ outchan = RGB24;
+ }
+ r = array[0];
+ if(outchan != CMAP8) {
+ switch(r->chandesc) {
+ case CY:
+ outchan = GREY8;
+ break;
+ case CRGB24:
+ outchan = RGB24;
+ break;
+ }
+ c = r;
+ } else if((c = torgbv(r, !eflag)) == nil) {
+ fprint(2, "%s: conversion of %s failed: %r\n",
+ argv0, name);
+ return "torgbv";
+ }
+ if(!dflag) {
+ i = allocimage(display, c->r, outchan, 0, 0);
+ if(i == nil) {
+ fprint(2, "%s: allocimage %s: %r\n",
+ argv0, name);
+ return "allocimage";
+ }
+ if(loadimage(i, i->r, c->chans[0],
+ c->chanlen) < 0) {
+ fprint(2, "%s: loadimage %s: %r\n",
+ argv0, name);
+ return "loadimage";
+ }
+ image = i;
+ eresized(0);
+ ch = ekbd();
+ if(ch == 'q' || ch == 0x7f || ch == 0x04)
+ exits(nil);
+ draw(screen, screen->clipr, display->white,
+ nil, ZP);
+ image = nil;
+ freeimage(i);
+ }
+ if(nineflag) {
+ chantostr(buf, outchan);
+ print("%11s %11d %11d %11d %11d ", buf,
+ c->r.min.x, c->r.min.y,
+ c->r.max.x, c->r.max.y);
+ if(write(1, c->chans[0], c->chanlen) !=
+ c->chanlen) {
+ fprint(2, "%s: %s: write error: %r\n",
+ argv0, name);
+ return "write";
+ }
+ } else if(cflag) {
+ if(writerawimage(1, c) < 0) {
+ fprint(2, "%s: %s: write error: %r\n",
+ argv0, name);
+ return "write";
+ }
+ }
+ if(c != nil && c != r) {
+ free(c->chans[0]);
+ free(c);
+ }
+ for(j = 0; j < r->nchans; j++)
+ free(r->chans[j]);
+ free(r);
+ free(array);
+ return nil;
+}
diff --git a/sys/src/cmd/ndb/cs.c b/sys/src/cmd/ndb/cs.c
index 4e0ed17d6..512f1706a 100644
--- a/sys/src/cmd/ndb/cs.c
+++ b/sys/src/cmd/ndb/cs.c
@@ -87,6 +87,7 @@ int *isslave; /* *isslave non-zero means this is a slave process */
long active; /* number of active slaves */
char *dbfile;
Ndb *db, *netdb;
+char *csuser;
void rversion(Job*);
void rflush(Job*);
@@ -266,6 +267,7 @@ main(int argc, char *argv[])
netinit(0);
if(!justsetname){
+ csuser = estrdup(getuser());
mountinit(servefile, mntpt);
io();
}
@@ -442,8 +444,10 @@ io(void)
for(;;){
n = read9pmsg(mfd[0], mdata, sizeof mdata);
- if(n<=0)
+ if(n < 0)
error("mount read");
+ if(n == 0)
+ continue;
job = newjob();
if(convM2S(mdata, n, &job->request) != n){
syslog(1, logfile, "format error %ux %ux %ux %ux %ux",
@@ -779,6 +783,9 @@ rwrite(Job *job, Mfile *mf)
}
job->request.data[cnt] = 0;
+ if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, csuser) != 0)
+ goto query; /* skip special commands if not owner */
+
/*
* toggle debugging
*/
@@ -825,6 +832,7 @@ rwrite(Job *job, Mfile *mf)
goto send;
}
+query:
if(mf->ref){
err = "query already in progress";
goto send;
diff --git a/sys/src/cmd/ndb/dn.c b/sys/src/cmd/ndb/dn.c
index e91183c37..ffc55ef8f 100644
--- a/sys/src/cmd/ndb/dn.c
+++ b/sys/src/cmd/ndb/dn.c
@@ -597,7 +597,7 @@ dnagedb(void)
/*
* mark all local db records about my area as authoritative,
- * time out any others
+ * delete timed out ones
*/
void
dnauthdb(void)
@@ -606,7 +606,7 @@ dnauthdb(void)
ulong minttl;
Area *area;
DN *dp;
- RR *rp;
+ RR *rp, **l;
lock(&dnlock);
@@ -614,19 +614,22 @@ dnauthdb(void)
for(i = 0; i < HTLEN; i++)
for(dp = ht[i]; dp; dp = dp->next){
area = inmyarea(dp->name);
- for(rp = dp->rr; rp; rp = rp->next)
+ l = &dp->rr;
+ for(rp = *l; rp; rp = *l){
if(rp->db){
+ if(rp->expire == 0){
+ rrdelhead(l);
+ continue;
+ }
if(area){
minttl = area->soarr->soa->minttl;
if(rp->ttl < minttl)
rp->ttl = minttl;
rp->auth = 1;
}
- if(rp->expire == 0){
- rp->db = 0;
- dp->referenced = now-Reserved-1;
- }
}
+ l = &rp->next;
+ }
}
unlock(&dnlock);
diff --git a/sys/src/cmd/ndb/dns.c b/sys/src/cmd/ndb/dns.c
index 8fc4f5167..5a8e25ce6 100644
--- a/sys/src/cmd/ndb/dns.c
+++ b/sys/src/cmd/ndb/dns.c
@@ -77,6 +77,7 @@ char *zonerefreshprogram;
char *logfile = "dns"; /* or "dns.test" */
char *dbfile;
+char *dnsuser;
char mntpt[Maxpath];
int addforwtarg(char *);
@@ -198,6 +199,7 @@ main(int argc, char *argv[])
opendatabase();
now = time(nil); /* open time files before we fork */
nowns = nsec();
+ dnsuser = estrdup(getuser());
snprint(servefile, sizeof servefile, "#s/dns%s", ext);
dir = dirstat(servefile);
@@ -428,8 +430,9 @@ io(void)
while(!stop){
procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms",
stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms);
- n = read9pmsg(mfd[0], mdata, sizeof mdata);
- if(n<=0){
+ while((n = read9pmsg(mfd[0], mdata, sizeof mdata)) == 0)
+ ;
+ if(n < 0){
dnslog("error reading 9P from %s: %r", mntpt);
sleep(2000); /* don't thrash after read error */
return;
@@ -717,10 +720,14 @@ rwrite(Job *job, Mfile *mf, Request *req)
if(cnt > 0 && job->request.data[cnt-1] == '\n')
job->request.data[cnt-1] = 0;
+ if(strcmp(mf->user, "none") == 0 || strcmp(mf->user, dnsuser) != 0)
+ goto query; /* skip special commands if not owner */
+
/*
* special commands
*/
-// dnslog("rwrite got: %s", job->request.data);
+ if(debug)
+ dnslog("rwrite got: %s", job->request.data);
send = 1;
if(strcmp(job->request.data, "debug")==0)
debug ^= 1;
@@ -744,6 +751,7 @@ rwrite(Job *job, Mfile *mf, Request *req)
if (send)
goto send;
+query:
/*
* kill previous reply
*/
diff --git a/sys/src/cmd/nusb/ether/asix.c b/sys/src/cmd/nusb/ether/asix.c
index 2b8f507ea..dc0158f42 100644
--- a/sys/src/cmd/nusb/ether/asix.c
+++ b/sys/src/cmd/nusb/ether/asix.c
@@ -225,7 +225,8 @@ asixread(Dev *ep, uchar *p, int plen)
hd = GET4(bin);
n = hd & 0xFFFF;
m = n+4;
- if((n != ~(hd>>16)) || (n < 6) || (m > nbin)){
+ hd = (hd>>16) ^ 0xFFFF;
+ if((n != hd) || (n < 6) || (m > nbin)){
nbin = 0;
return 0;
}
@@ -242,9 +243,12 @@ asixread(Dev *ep, uchar *p, int plen)
static void
asixwrite(Dev *ep, uchar *p, int n)
{
+ uint hd;
+
if(n > sizeof(bout)-8)
n = sizeof(bout)-8;
- PUT4(bout, n | ~(n<<16));
+ hd = n | (n<<16)^0xFFFF0000;
+ PUT4(bout, hd);
memmove(bout+4, p, n);
n += 4;
if((n % ep->maxpkt) == 0){
diff --git a/sys/src/cmd/nusb/ether/ether.c b/sys/src/cmd/nusb/ether/ether.c
index 90478faaf..143c4a9de 100644
--- a/sys/src/cmd/nusb/ether/ether.c
+++ b/sys/src/cmd/nusb/ether/ether.c
@@ -810,8 +810,9 @@ threadmain(int argc, char **argv)
if(argc != 1)
usage();
- d = getdev(atoi(*argv));
- if(findendpoints(d, &ei, &eo) < 0)
+ if((d = getdev(atoi(*argv))) == nil)
+ sysfatal("getdev: %r");
+ if(findendpoints(d, &ei, &eo) < 0)
sysfatal("no endpoints found");
werrstr("");
diff --git a/sys/src/cmd/page.c b/sys/src/cmd/page.c
index a44f74d4b..aea34facd 100644
--- a/sys/src/cmd/page.c
+++ b/sys/src/cmd/page.c
@@ -680,6 +680,7 @@ popenfile(Page *p)
"image/gif", popenimg, "gif",
"image/jpeg", popenimg, "jpg",
"image/png", popenimg, "png",
+ "image/tiff", popenimg, "tif",
"image/ppm", popenimg, "ppm",
"image/bmp", popenimg, "bmp",
"image/tga", popenimg, "tga",
@@ -1241,12 +1242,9 @@ showext(Page *p)
if(p->ext == nil)
return;
snprint(label, sizeof(label), "%s %s", p->ext, p->label);
- if(p->image){
- ps = subpt(p->image->r.max, p->image->r.min);
- ps.x += 24;
- ps.y += 24;
- } else
- ps = subpt(screen->r.max, screen->r.min);
+ ps = Pt(0, 0);
+ if(p->image)
+ ps = addpt(subpt(p->image->r.max, p->image->r.min), Pt(24, 24));
drawlock(0);
if((fd = p->fd) < 0){
if(p->open != popenfile)
@@ -1257,13 +1255,15 @@ showext(Page *p)
seek(fd, 0, 0);
}
if(rfork(RFPROC|RFMEM|RFFDG|RFNOTEG|RFNAMEG|RFNOWAIT) == 0){
- snprint(buf, sizeof(buf), "-pid %d -dx %d -dy %d", getpid(), ps.x, ps.y);
+ snprint(buf, sizeof(buf), "-pid %d", getpid());
if(newwindow(buf) != -1){
dupfds(fd, 1, 2, -1);
if((fd = open("/dev/label", OWRITE)) >= 0){
write(fd, label, strlen(label));
close(fd);
}
+ if(ps.x && ps.y)
+ resizewin(ps);
argv[0] = "rc";
argv[1] = "-c";
argv[2] = p->ext;
@@ -1360,7 +1360,7 @@ docmd(int i, Mouse *m)
break;
o = subpt(m->xy, screen->r.min);
if(i == Czoomin){
- if(zoom < 0x40000000){
+ if(zoom < 0x1000){
zoom *= 2;
pos = addpt(mulpt(subpt(pos, o), 2), o);
}
diff --git a/sys/src/cmd/paint.c b/sys/src/cmd/paint.c
index adac1afd6..cfc07b158 100644
--- a/sys/src/cmd/paint.c
+++ b/sys/src/cmd/paint.c
@@ -15,6 +15,7 @@ Image *back;
Image *pal[16]; /* palette */
Rectangle palr; /* palette rect on screen */
Rectangle penr; /* pen size rect on screen */
+
enum {
NBRUSH = 10+1,
};
@@ -42,6 +43,29 @@ int c64[] = { /* c64 color palette */
};
/*
+ * get bounding rectnagle for stroke from r.min to r.max with
+ * specified brush (size).
+ */
+static Rectangle
+strokerect(Rectangle r, int brush)
+{
+ r = canonrect(r);
+ return Rect(r.min.x-brush, r.min.y-brush, r.max.x+brush+1, r.max.y+brush+1);
+}
+
+/*
+ * draw stroke from r.min to r.max to dst with color ink and
+ * brush (size).
+ */
+static void
+strokedraw(Image *dst, Rectangle r, Image *ink, int brush)
+{
+ if(!eqpt(r.min, r.max))
+ line(dst, r.min, r.max, Enddisc, Enddisc, brush, ink, ZP);
+ fillellipse(dst, r.max, brush, brush, ink, ZP);
+}
+
+/*
* A draw operation that touches only the area contained in bot but not in top.
* mp and sp get aligned with bot.min.
*/
@@ -259,10 +283,16 @@ restore(int n)
if((tmp = undo[x]) == nil)
return;
undo[x] = nil;
- expand(tmp->r);
- draw(canvas, tmp->r, tmp, nil, tmp->r.min);
- update(&tmp->r);
- freeimage(tmp);
+ if(canvas == nil || canvas->chan != tmp->chan){
+ freeimage(canvas);
+ canvas = tmp;
+ update(nil);
+ } else {
+ expand(tmp->r);
+ draw(canvas, tmp->r, tmp, nil, tmp->r.min);
+ update(&tmp->r);
+ freeimage(tmp);
+ }
}
}
@@ -450,19 +480,21 @@ drawpal(void)
r = penr;
draw(screen, r, back, nil, ZP);
- for(i=0; i<10; i++){
+ for(i=0; i<NBRUSH; i++){
r.max.x = penr.min.x + (i+1)*Dx(penr) / NBRUSH;
rr = r;
if(i == brush)
rr.min.y += Dy(r)/3;
- fillellipse(screen, addpt(rr.min, divpt(subpt(rr.max, rr.min), 2)), i, i, ink, ZP);
+ if(i == NBRUSH-1){
+ /* last is special brush for fill draw */
+ draw(screen, rr, ink, nil, ZP);
+ } else {
+ rr.min = addpt(rr.min, divpt(subpt(rr.max, rr.min), 2));
+ rr.max = rr.min;
+ strokedraw(screen, rr, ink, i);
+ }
r.min.x = r.max.x;
}
- r.max.x = penr.min.x + (i+1)*Dx(penr) / NBRUSH;
- rr = r;
- if(i == brush)
- rr.min.y += Dy(r)/3;
- draw(screen, rr, ink, nil, ZP);
r = palr;
for(i=1; i<=nelem(pal); i++){
@@ -614,7 +646,7 @@ main(int argc, char *argv[])
/* no break */
case 1:
p = s2c(e.mouse.xy);
- if(brush >= 10){
+ if(brush == NBRUSH-1){
/* flood fill brush */
if(canvas == nil || !ptinrect(p, canvas->r)){
back = img;
@@ -632,10 +664,10 @@ main(int argc, char *argv[])
;
break;
}
- r = Rect(p.x-brush, p.y-brush, p.x+brush+1, p.y+brush+1);
+ r = strokerect(Rpt(p, p), brush);
expand(r);
save(r, 1);
- fillellipse(canvas, p, brush, brush, img, ZP);
+ strokedraw(canvas, Rpt(p, p), img, brush);
update(&r);
for(;;){
m = e.mouse;
@@ -646,14 +678,10 @@ main(int argc, char *argv[])
d = s2c(e.mouse.xy);
if(eqpt(d, p))
continue;
- r = canonrect(Rpt(p, d));
- r.min.x -= brush;
- r.min.y -= brush;
- r.max.x += brush+1;
- r.max.y += brush+1;
+ r = strokerect(Rpt(p, d), brush);
expand(r);
save(r, 0);
- line(canvas, p, d, Enddisc, Enddisc, brush, img, ZP);
+ strokedraw(canvas, Rpt(p, d), img, brush);
update(&r);
p = d;
}
@@ -677,10 +705,12 @@ main(int argc, char *argv[])
center();
break;
case '+':
- setzoom(e.mouse.xy, zoom*2);
+ if(zoom < 0x1000)
+ setzoom(e.mouse.xy, zoom*2);
break;
case '-':
- setzoom(e.mouse.xy, zoom/2);
+ if(zoom > 1)
+ setzoom(e.mouse.xy, zoom/2);
break;
case 'c':
if(canvas == nil)
@@ -694,7 +724,7 @@ main(int argc, char *argv[])
restore(16);
break;
case 'f':
- brush = 10;
+ brush = NBRUSH-1;
drawpal();
break;
case '0': case '1': case '2': case '3': case '4':
diff --git a/sys/src/cmd/paqfs/paqfs.c b/sys/src/cmd/paqfs/paqfs.c
index 6769326f9..8fe05cc05 100644
--- a/sys/src/cmd/paqfs/paqfs.c
+++ b/sys/src/cmd/paqfs/paqfs.c
@@ -817,7 +817,7 @@ io(int fd)
if(n < 0)
sysfatal("mount read");
if(n == 0)
- break;
+ continue;
if(convM2S(mdata, n, &rhdr) == 0)
continue;
diff --git a/sys/src/cmd/plumb/fsys.c b/sys/src/cmd/plumb/fsys.c
index ffedce259..0a5f6fbdd 100644
--- a/sys/src/cmd/plumb/fsys.c
+++ b/sys/src/cmd/plumb/fsys.c
@@ -237,12 +237,10 @@ fsysproc(void*)
if(buf == nil)
error("malloc failed: %r");
qlock(&readlock);
- n = read9pmsg(srvfd, buf, messagesize);
- if(n <= 0){
- if(n < 0)
- error("i/o error on server channel");
+ while((n = read9pmsg(srvfd, buf, messagesize)) == 0)
+ ;
+ if(n < 0)
threadexitsall("unmounted");
- }
if(readlock.head == nil) /* no other processes waiting to read; start one */
proccreate(fsysproc, nil, Stack);
qunlock(&readlock);
diff --git a/sys/src/cmd/rio/dat.h b/sys/src/cmd/rio/dat.h
index 1f12eef48..e1d617ac9 100644
--- a/sys/src/cmd/rio/dat.h
+++ b/sys/src/cmd/rio/dat.h
@@ -139,6 +139,7 @@ struct Window
Channel *mouseread; /* chan(Mousereadmesg) */
Channel *wctlread; /* chan(Consreadmesg) */
Channel *kbdread; /* chan(Kbdreadmesg) */
+ Channel *complete; /* chan(Completion*) */
uint nr; /* number of runes in window */
uint maxr; /* number of runes allocated in r */
Rune *r;
diff --git a/sys/src/cmd/rio/fsys.c b/sys/src/cmd/rio/fsys.c
index 1676ef1f9..fe4d186e4 100644
--- a/sys/src/cmd/rio/fsys.c
+++ b/sys/src/cmd/rio/fsys.c
@@ -194,8 +194,9 @@ filsysproc(void *arg)
x = nil;
for(;;){
buf = emalloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */
- n = read9pmsg(fs->sfd, buf, messagesize);
- if(n <= 0){
+ while((n = read9pmsg(fs->sfd, buf, messagesize)) == 0)
+ yield();
+ if(n < 0){
yield(); /* if threadexitsall'ing, will not return */
fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
errorshouldabort = 0;
diff --git a/sys/src/cmd/rio/wind.c b/sys/src/cmd/rio/wind.c
index 6fd67a559..d8c47d4cb 100644
--- a/sys/src/cmd/rio/wind.c
+++ b/sys/src/cmd/rio/wind.c
@@ -44,6 +44,7 @@ wmk(Image *i, Mousectl *mc, Channel *ck, Channel *cctl, int scrolling)
w->kbdread = chancreate(sizeof(Kbdreadmesg), 0);
w->mouseread = chancreate(sizeof(Mousereadmesg), 0);
w->wctlread = chancreate(sizeof(Consreadmesg), 0);
+ w->complete = chancreate(sizeof(Completion*), 0);
w->scrollr = r;
w->scrollr.max.x = r.min.x+Scrollwid;
w->lastsr = ZR;
@@ -157,17 +158,19 @@ wclose(Window *w)
return 1;
}
+void
+showcandidates(Window *, Completion *);
void
winctl(void *arg)
{
Rune *rp, *bp, *tp, *up;
- uint qh;
+ uint qh, q0;
int nr, nb, c, wid, i, npart, initial, lastb;
char *s, *t, part[3];
Window *w;
Mousestate *mp, m;
- enum { WKbd, WKbdread, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, NWALT };
+ enum { WKbd, WKbdread, WMouse, WMouseread, WCtl, WCwrite, WCread, WWread, WComplete, NWALT };
Alt alts[NWALT+1];
Mousereadmesg mrm;
Kbdreadmesg krm;
@@ -176,6 +179,7 @@ winctl(void *arg)
Consreadmesg cwrm;
Stringpair pair;
Wctlmesg wcm;
+ Completion *cr;
char buf[4*12+1], *kbdq[8], *kbds;
int kbdqr, kbdqw;
@@ -215,6 +219,9 @@ winctl(void *arg)
alts[WWread].c = w->wctlread;
alts[WWread].v = &cwrm;
alts[WWread].op = CHANSND;
+ alts[WComplete].c = w->complete;
+ alts[WComplete].v = &cr;
+ alts[WComplete].op = CHANRCV;
alts[NWALT].op = CHANEND;
memset(kbdq, 0, sizeof(kbdq));
@@ -418,6 +425,21 @@ winctl(void *arg)
}
send(cwrm.c2, &pair);
continue;
+ case WComplete:
+ if(!w->deleted){
+ if(!cr->advance)
+ showcandidates(w, cr);
+ if(cr->advance){
+ rp = runesmprint("%s", cr->string);
+ nr = runestrlen(rp);
+ q0 = w->q0;
+ q0 = winsert(w, rp, nr, q0);
+ wshow(w, q0+nr);
+ free(rp);
+ }
+ }
+ freecompletion(cr);
+ break;
}
if(!w->deleted)
flushimage(display, 1);
@@ -507,24 +529,53 @@ showcandidates(Window *w, Completion *c)
free(rp);
}
-Rune*
+typedef struct Completejob Completejob;
+struct Completejob
+{
+ char *dir;
+ char *str;
+ Window *win;
+};
+
+void
+completeproc(void *arg)
+{
+ Completejob *job;
+ Completion *c;
+ char buf[128];
+
+ job = arg;
+ snprint(buf, sizeof(buf), "namecomplete %s", job->dir);
+ threadsetname(buf);
+
+ c = complete(job->dir, job->str);
+ if(c != nil && sendp(job->win->complete, c) <= 0)
+ freecompletion(c);
+
+ wclose(job->win);
+
+ free(job->dir);
+ free(job->str);
+ free(job);
+}
+
+void
namecomplete(Window *w)
{
int nstr, npath;
- Rune *rp, *path, *str;
- Completion *c;
- char *s, *dir, *root;
+ Rune *path, *str;
+ char *dir, *root;
+ Completejob *job;
/* control-f: filename completion; works back to white space or / */
if(w->q0<w->nr && w->r[w->q0]>' ') /* must be at end of word */
- return nil;
+ return;
nstr = windfilewidth(w, w->q0, TRUE);
str = runemalloc(nstr);
runemove(str, w->r+(w->q0-nstr), nstr);
npath = windfilewidth(w, w->q0-nstr, FALSE);
path = runemalloc(npath);
runemove(path, w->r+(w->q0-nstr-npath), npath);
- rp = nil;
/* is path rooted? if not, we need to make it relative to window path */
if(npath>0 && path[0]=='/'){
@@ -538,34 +589,24 @@ namecomplete(Window *w)
dir = malloc(strlen(root)+1+UTFmax*npath+1);
sprint(dir, "%s/%.*S", root, npath, path);
}
- dir = cleanname(dir);
-
- s = smprint("%.*S", nstr, str);
- c = complete(dir, s);
- free(s);
- if(c == nil)
- goto Return;
- if(!c->advance)
- showcandidates(w, c);
+ /* run in background, winctl will collect the result on w->complete chan */
+ job = emalloc(sizeof *job);
+ job->str = smprint("%.*S", nstr, str);
+ job->dir = cleanname(dir);
+ job->win = w;
+ incref(w);
+ proccreate(completeproc, job, STACK);
- if(c->advance)
- rp = runesmprint("%s", c->string);
-
- Return:
- freecompletion(c);
- free(dir);
free(path);
free(str);
- return rp;
}
void
wkeyctl(Window *w, Rune r)
{
uint q0 ,q1;
- int n, nb, nr;
- Rune *rp;
+ int n, nb;
int *notefd;
switch(r){
@@ -679,14 +720,7 @@ wkeyctl(Window *w, Rune r)
return;
case Kack: /* ^F: file name completion */
case Kins: /* Insert: file name completion */
- rp = namecomplete(w);
- if(rp == nil)
- return;
- nr = runestrlen(rp);
- q0 = w->q0;
- q0 = winsert(w, rp, nr, q0);
- wshow(w, q0+nr);
- free(rp);
+ namecomplete(w);
return;
case Kbs: /* ^H: erase character */
case Knack: /* ^U: erase line */
@@ -1193,6 +1227,7 @@ wctlmesg(Window *w, int m, Rectangle r, void *p)
chanfree(w->mouseread);
chanfree(w->wctlread);
chanfree(w->kbdread);
+ chanfree(w->complete);
free(w->raw);
free(w->r);
free(w->dir);
diff --git a/sys/src/cmd/samterm/main.c b/sys/src/cmd/samterm/main.c
index 6ee72c94a..6f47e455c 100644
--- a/sys/src/cmd/samterm/main.c
+++ b/sys/src/cmd/samterm/main.c
@@ -310,6 +310,9 @@ scrorigin(Flayer *l, int but, long p0)
{
Text *t=(Text *)l->user1;
+ if(t->tag == Untagged)
+ return;
+
switch(but){
case 1:
outTsll(Torigin, t->tag, l->origin, p0);
diff --git a/sys/src/cmd/scram.c b/sys/src/cmd/scram.c
index cbbe8d90d..1ce3aa6e8 100644
--- a/sys/src/cmd/scram.c
+++ b/sys/src/cmd/scram.c
@@ -25,6 +25,10 @@ struct Tbl {
uchar data[];
};
+enum {
+ Tblsz = 4+4+1+1+6+8+4+4+4,
+};
+
void*
amlalloc(int n){
return mallocz(n, 1);
@@ -64,15 +68,15 @@ loadacpi(void)
amlinit();
for(;;){
t = malloc(sizeof(*t));
- if((n = readn(fd, t, sizeof(*t))) <= 0)
+ if((n = readn(fd, t, Tblsz)) <= 0)
break;
- if(n != sizeof(*t))
+ if(n != Tblsz)
return -1;
l = get32(t->len);
- if(l < sizeof(*t))
+ if(l < Tblsz)
return -1;
- t = realloc(t, l);
- l -= sizeof(*t);
+ l -= Tblsz;
+ t = realloc(t, sizeof(*t) + l);
if(readn(fd, t->data, l) != l)
return -1;
if(memcmp("DSDT", t->sig, 4) == 0)
diff --git a/sys/src/cmd/tcs/cyrillic.h b/sys/src/cmd/tcs/cyrillic.h
index 569b4907e..69797ec43 100644
--- a/sys/src/cmd/tcs/cyrillic.h
+++ b/sys/src/cmd/tcs/cyrillic.h
@@ -39,10 +39,10 @@ long tabkoi8[256] =
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1,0x0451,0x0454, -1,0x0456,0x0457,
+ -1, -1, -1, -1, -1,0x0491,0x045e, -1,
+ -1, -1, -1,0x0401,0x0404, -1,0x0406,0x0407,
+ -1, -1, -1, -1, -1,0x0490,0x040e, -1,
0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
diff --git a/sys/src/cmd/uhtml.c b/sys/src/cmd/uhtml.c
index 7c612de9e..08e512354 100644
--- a/sys/src/cmd/uhtml.c
+++ b/sys/src/cmd/uhtml.c
@@ -65,7 +65,7 @@ main(int argc, char *argv[])
if(*argv){
close(0);
- if(open(*argv, OREAD) != 1)
+ if(open(*argv, OREAD) != 0)
sysfatal("open: %r");
}
nbuf = 0;
diff --git a/sys/src/cmd/upas/smtp/smtp.c b/sys/src/cmd/upas/smtp/smtp.c
index 8c9e9d50b..9c8e89d6a 100644
--- a/sys/src/cmd/upas/smtp/smtp.c
+++ b/sys/src/cmd/upas/smtp/smtp.c
@@ -64,7 +64,7 @@ static int bustedmx;
void
usage(void)
{
- fprint(2, "usage: smtp [-aAdfips] [-b busted-mx] [-g gw] [-h host] "
+ fprint(2, "usage: smtp [-aAdfipst] [-b busted-mx] [-g gw] [-h host] "
"[-u user] [.domain] net!host[!service] sender rcpt-list\n");
exits(Giveup);
}
diff --git a/sys/src/cmd/vac/vacfs.c b/sys/src/cmd/vac/vacfs.c
index 164bf8060..cc1a5ca06 100644
--- a/sys/src/cmd/vac/vacfs.c
+++ b/sys/src/cmd/vac/vacfs.c
@@ -706,8 +706,10 @@ io(void)
for(;;){
n = read9pmsg(mfd[0], mdata, sizeof mdata);
- if(n <= 0)
+ if(n < 0)
break;
+ if(n == 0)
+ continue;
if(convM2Su(mdata, n, &rhdr, dotu) != n)
sysfatal("convM2S conversion error");
diff --git a/sys/src/cmd/vnc/exportfs.c b/sys/src/cmd/vnc/exportfs.c
index a2feb83ae..07e20e477 100644
--- a/sys/src/cmd/vnc/exportfs.c
+++ b/sys/src/cmd/vnc/exportfs.c
@@ -149,8 +149,9 @@ exportproc(Export *fs)
errdepth(ed);
q = smalloc(sizeof(Exq));
- n = read9pmsg(fs->io, q->buf, Maxrpc);
- if(n <= 0 || convM2S(q->buf, n, &q->rpc) != n)
+ while((n = read9pmsg(fs->io, q->buf, Maxrpc)) == 0)
+ ;
+ if(n < 0 || convM2S(q->buf, n, &q->rpc) != n)
goto bad;
if(exdebug)
diff --git a/sys/src/lib9p/srv.c b/sys/src/lib9p/srv.c
index 12b1d7fe5..5a2bd9e1c 100644
--- a/sys/src/lib9p/srv.c
+++ b/sys/src/lib9p/srv.c
@@ -59,7 +59,9 @@ getreq(Srv *s)
Req *r;
qlock(&s->rlock);
- if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
+ while((n = read9pmsg(s->infd, s->rbuf, s->msize)) == 0)
+ ;
+ if(n < 0){
qunlock(&s->rlock);
return nil;
}
diff --git a/sys/src/libaml/aml.c b/sys/src/libaml/aml.c
index 22201b4bd..a05e939a4 100644
--- a/sys/src/libaml/aml.c
+++ b/sys/src/libaml/aml.c
@@ -47,7 +47,8 @@ static char *spacename[] = {
"Smbus",
"Cmos",
"Pcibar",
- "Ipmi" };
+ "Ipmi",
+};
/* field flags */
enum {
@@ -85,7 +86,7 @@ struct Region {
int space;
uvlong off;
uvlong len;
- uchar *va;
+ uchar *va; /* non nil when mapped */
};
struct Field {
@@ -166,8 +167,8 @@ enum {
Oindex, Omutex, Oevent,
Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
Oif, Oelse, Owhile, Obreak, Oret, Ocall,
- Ostore, Oderef, Osize, Oref, Ocref,
- Oacq, Orel, Ostall, Osleep,
+ Ostore, Oderef, Osize, Oref, Ocref, Ocat,
+ Oacq, Orel, Ostall, Osleep, Oload, Ounload,
};
static Op optab[];
@@ -175,15 +176,22 @@ static uchar octab1[];
static uchar octab2[];
static Name*
-rootname(Name *dot){
+rootname(Name *dot)
+{
while(dot != dot->up)
dot = dot->up;
return dot;
}
static void
-gcmark(void *p){
+gcmark(void *p)
+{
+ int i;
+ Env *e;
+ Field *f;
Heap *h;
+ Name *n, *d;
+ Package *a;
if(p == nil)
return;
@@ -193,35 +201,29 @@ gcmark(void *p){
h->mark = 1;
switch(h->tag){
case 'E':
- {
- int i;
- Env *e = p;
- for(i=0; i<nelem(e->loc); i++)
- gcmark(e->loc[i]);
- for(i=0; i<nelem(e->arg); i++)
- gcmark(e->arg[i]);
- }
+ e = p;
+ for(i=0; i<nelem(e->loc); i++)
+ gcmark(e->loc[i]);
+ for(i=0; i<nelem(e->arg); i++)
+ gcmark(e->arg[i]);
break;
- case 'R': case 'A': case 'L':
+ case 'R':
+ case 'A':
+ case 'L':
gcmark(((Ref*)p)->ref);
break;
case 'N':
- {
- Name *d, *n = p;
- gcmark(n->v);
- for(d = n->down; d; d = d->next)
- gcmark(d);
- gcmark(n->fork);
- gcmark(n->up);
- }
+ n = p;
+ gcmark(n->v);
+ for(d = n->down; d; d = d->next)
+ gcmark(d);
+ gcmark(n->fork);
+ gcmark(n->up);
break;
case 'p':
- {
- int i;
- Package *a = p;
- for(i=0; i<a->n; i++)
- gcmark(a->a[i]);
- }
+ a = p;
+ for(i=0; i<a->n; i++)
+ gcmark(a->a[i]);
break;
case 'r':
gcmark(((Region*)p)->name);
@@ -231,21 +233,20 @@ gcmark(void *p){
break;
case 'f':
case 'u':
- {
- Field *f = p;
- gcmark(f->reg);
- gcmark(f->index);
- gcmark(f->indexv);
- }
+ f = p;
+ gcmark(f->reg);
+ gcmark(f->index);
+ gcmark(f->indexv);
break;
}
}
static int
-gc(void){
+gc(void)
+{
+ int i;
Heap *h, **hh;
Frame *f;
- int i;
for(h = hp; h; h = h->link)
h->mark = 0;
@@ -268,6 +269,12 @@ gc(void){
continue;
}
*hh = h->link;
+ if(h->tag == 'r'){
+ Region *r = (void*)H2D(h);
+
+ /* TODO: unmap region */
+ r->va = nil;
+ }
memset(h, ~0, sizeof(Heap)+h->size);
amlfree(h);
i++;
@@ -277,7 +284,8 @@ gc(void){
}
static void*
-mk(int tag, int size){
+mk(int tag, int size)
+{
Heap *h;
int a;
@@ -291,21 +299,26 @@ mk(int tag, int size){
}
static uvlong*
-mki(uvlong i){
- uvlong *v = mk('i', sizeof(uvlong));
+mki(uvlong i)
+{
+ uvlong *v;
+
+ v = mk('i', sizeof(uvlong));
*v = i;
return v;
}
static char*
-mks(char *s){
+mks(char *s)
+{
char *r = mk('s', strlen(s)+1);
strcpy(r, s);
return r;
}
static int
-pkglen(uchar *p, uchar *e, uchar **np){
+pkglen(uchar *p, uchar *e, uchar **np)
+{
ulong n;
uchar b;
@@ -336,7 +349,8 @@ pkglen(uchar *p, uchar *e, uchar **np){
}
static Name*
-forkname(Name *dot){
+forkname(Name *dot)
+{
Name *n;
n = mk('N', sizeof(Name));
@@ -355,7 +369,8 @@ forkname(Name *dot){
}
static Name*
-getseg(Name *dot, void *seg, int new){
+getseg(Name *dot, void *seg, int new)
+{
Name *n, *l;
for(n = l = nil; dot; dot = dot->fork){
@@ -425,17 +440,6 @@ getname(Name *dot, char *path, int new)
}
static uvlong
-ival(void *p){
- if(p) switch(TAG(p)){
- case 'i':
- return *((uvlong*)p);
- case 's':
- return strtoull((char*)p, 0, 0);
- }
- return 0;
-}
-
-static uvlong
rwreg(void *reg, int off, int len, uvlong v, int write)
{
Region *r;
@@ -447,6 +451,7 @@ rwreg(void *reg, int off, int len, uvlong v, int write)
p = reg;
if((off+len) > SIZE(p))
break;
+ RWMem:
if(write){
for(i=0; i<len; i++){
p[off+i] = v & 0xFF;
@@ -462,17 +467,46 @@ rwreg(void *reg, int off, int len, uvlong v, int write)
if((off+len) > r->len)
break;
if(amldebug){
- print("rwreg: %s %-8s [%llux+%x]/%d %llux\n",
+ print("\nrwreg: %s %-8s [%llux+%x]/%d %llux\n",
write ? "W" : "R",
spacename[r->space],
r->off, off, len, v);
}
+ /* TODO: map region */
+ if(r->va != nil){
+ p = r->va + off;
+ goto RWMem;
+ }
break;
}
return ~0;
}
+static uvlong
+ival(void *p)
+{
+ int n;
+
+ if(p != nil){
+ switch(TAG(p)){
+ case 'i':
+ return *((uvlong*)p);
+ case 's':
+ if(*((char*)p) == 0)
+ break;
+ return strtoull((char*)p, 0, 16);
+ case 'b':
+ n = SIZE(p);
+ if(n > 0){
+ if(n > 8) n = 8;
+ return rwreg(p, 0, n, 0, 0);
+ }
+ }
+ }
+ return 0;
+}
+
static void *deref(void *p);
static void *store(void *s, void *d);
@@ -495,7 +529,8 @@ fieldalign(int flags)
}
static void*
-rwfield(Field *f, void *v, int write){
+rwfield(Field *f, void *v, int write)
+{
int boff, blen, wo, ws, wl, wa, wd, i;
uvlong w, m;
void *reg;
@@ -552,6 +587,7 @@ rwfield(Field *f, void *v, int write){
return nil;
if(blen > 64)
return b;
+
w = 0;
for(i=0; i<SIZE(b); i++)
w |= ((uvlong)b[i]) << i*8;
@@ -559,7 +595,8 @@ rwfield(Field *f, void *v, int write){
}
static void*
-deref(void *p){
+deref(void *p)
+{
if(p) switch(TAG(p)){
case 'N':
return ((Name*)p)->v;
@@ -572,32 +609,73 @@ deref(void *p){
}
static void*
-copy(int tag, void *s){
+copy(int tag, void *s)
+{
+ static char hex[] = "0123456789ABCDEF";
+ uvlong v;
void *d;
- if(s){
- int n;
- if(tag == 0)
- tag = TAG(s);
+ int i, n;
+
+ if(tag == 0){
+ if(s == nil)
+ return nil;
+ tag = TAG(s);
+ }
+ if(s == nil || TAG(s) == 'i'){
+ n = 4;
+ v = ival(s);
+ if(v > 0xFFFFFFFFULL)
+ n <<= 1;
switch(tag){
case 'b':
+ d = mk(tag, n);
+ rwreg(d, 0, n, v, 1);
+ return d;
case 's':
- n = SIZE(s);
- if(tag == 's' && TAG(s) == 'b')
- n++;
+ n <<= 1;
+ d = mk(tag, n+1);
+ ((char*)d)[n] = 0;
+ while(n > 0){
+ ((char*)d)[--n] = hex[v & 0xF];
+ v >>= 4;
+ }
+ return d;
+ case 'i':
+ if(v == 0ULL)
+ return nil;
+ return mki(v);
+ }
+ } else {
+ n = SIZE(s);
+ switch(tag){
+ case 's':
+ if(TAG(s) == 'b'){
+ d = mk(tag, n*3 + 1);
+ for(i=0; i<n; i++){
+ ((char*)d)[i*3 + 0] = hex[((uchar*)s)[i] >> 4];
+ ((char*)d)[i*3 + 1] = hex[((uchar*)s)[i] & 0xF];
+ ((char*)d)[i*3 + 2] = ' ';
+ }
+ ((char*)d)[n*3] = 0;
+ return d;
+ }
+ /* no break */
+ case 'b':
+ if(TAG(s) == 's'){
+ n = strlen(s);
+ /* zero length string is converted to zero length buffer */ if(n > 0) n++;
+ }
d = mk(tag, n);
memmove(d, s, n);
- if(tag == 's')
- ((uchar*)d)[n-1] = 0;
return d;
- case 'i':
- return mki(ival(s));
}
}
return s;
}
static void*
-store(void *s, void *d){
+store(void *s, void *d)
+{
void *p, **pp;
if(d == nil)
@@ -610,41 +688,46 @@ store(void *s, void *d){
/* no break */
case 'R': case 'L':
pp = ((Ref*)d)->ptr;
- while(p = *pp){
+ while((p = *pp) != nil){
switch(TAG(p)){
case 'R': case 'A': case 'L':
pp = ((Ref*)p)->ptr;
- continue;
+ break;
case 'N':
pp = &((Name*)p)->v;
- if(*pp != p)
- continue;
+ break;
}
- break;
+ if(*pp == p)
+ break;
}
break;
case 'N':
pp = &((Name*)d)->v;
+ break;
}
p = *pp;
- if(p && TAG(p) != 'N'){
+ if(p != nil && TAG(p) != 'N'){
switch(TAG(p)){
case 'f':
case 'u':
rwfield(p, s, 1);
return d;
}
- *pp = copy(TAG(p), s);
- } else
- *pp = copy(0, s);
+ if(TAG(d) != 'A' && TAG(d) != 'L'){
+ *pp = copy(TAG(p), s);
+ return d;
+ }
+ }
+ *pp = copy(0, s);
return d;
}
static int
-Nfmt(Fmt *f){
+Nfmt(Fmt *f)
+{
char buf[5];
- Name *n;
int i;
+ Name *n;
n = va_arg(f->args, Name*);
if(n == nil)
@@ -664,9 +747,17 @@ Nfmt(Fmt *f){
}
static int
-Vfmt(Fmt *f){
+Vfmt(Fmt *f)
+{
void *p;
- int c;
+ int i, n, c;
+ Env *e;
+ Field *l;
+ Name *nm;
+ Method *m;
+ Package *a;
+ Region *g;
+ Ref *r;
p = va_arg(f->args, void*);
if(p == nil)
@@ -674,90 +765,74 @@ Vfmt(Fmt *f){
c = TAG(p);
switch(c){
case 'N':
- {
- Name *n = p;
-
- if(n->v != n)
- return fmtprint(f, "%N=%V", n, n->v);
- return fmtprint(f, "%N=*", n);
- }
- case 'A': case 'L':
- {
- Ref *r = p;
- Env *e = r->ref;
- if(c == 'A')
- return fmtprint(f, "Arg%ld=%V", r->ptr - e->arg, *r->ptr);
- if(c == 'L')
- return fmtprint(f, "Local%ld=%V", r->ptr - e->loc, *r->ptr);
- }
+ nm = p;
+ if(nm->v != nm)
+ return fmtprint(f, "%N=%V", nm, nm->v);
+ return fmtprint(f, "%N=*", nm);
+ case 'A':
+ case 'L':
+ r = p;
+ e = r->ref;
+ if(c == 'A')
+ return fmtprint(f, "Arg%ld=%V", r->ptr - e->arg, *r->ptr);
+ if(c == 'L')
+ return fmtprint(f, "Local%ld=%V", r->ptr - e->loc, *r->ptr);
case 's':
return fmtprint(f, "\"%s\"", (char*)p);
case 'i':
- return fmtprint(f, "0x%llux", *((uvlong*)p));
+ return fmtprint(f, "%#llux", *((uvlong*)p));
case 'p':
- {
- int i;
- Package *a = p;
- fmtprint(f, "Package(%d){", a->n);
- for(i=0; i<a->n; i++){
- if(i > 0)
- fmtprint(f, ", ");
- fmtprint(f, "%V", a->a[i]);
- }
- fmtprint(f, "}");
+ a = p;
+ fmtprint(f, "Package(%d){", a->n);
+ for(i=0; i<a->n; i++){
+ if(i > 0)
+ fmtprint(f, ", ");
+ fmtprint(f, "%V", a->a[i]);
}
+ fmtprint(f, "}");
return 0;
case 'b':
- {
- int i, n;
- n = SIZE(p);
- fmtprint(f, "Buffer(%d){", n);
- for(i=0; i<n; i++){
- if(i > 0)
- fmtprint(f, ", ");
- fmtprint(f, "%.2uX", ((uchar*)p)[i]);
- }
- fmtprint(f, "}");
+ n = SIZE(p);
+ fmtprint(f, "Buffer(%d){", n);
+ for(i=0; i<n; i++){
+ if(i > 0)
+ fmtprint(f, ", ");
+ fmtprint(f, "%.2uX", ((uchar*)p)[i]);
}
+ fmtprint(f, "}");
return 0;
case 'r':
- {
- Region *r = p;
- return fmtprint(f, "Region(%s, 0x%llux, 0x%llux)",
- spacename[r->space & 7], r->off, r->len);
- }
+ g = p;
+ return fmtprint(f, "Region(%s, %#llux, %#llux)",
+ spacename[g->space & 7], g->off, g->len);
case 'm':
- {
- int i;
- Method *m = p;
- fmtprint(f, "%N(", m->name);
- for(i=0; i < m->narg; i++){
- if(i > 0)
- fmtprint(f, ", ");
- fmtprint(f, "Arg%d", i);
- }
- fmtprint(f, ")");
- return 0;
+ m = p;
+ fmtprint(f, "%N(", m->name);
+ for(i=0; i < m->narg; i++){
+ if(i > 0)
+ fmtprint(f, ", ");
+ fmtprint(f, "Arg%d", i);
}
+ fmtprint(f, ")");
+ return 0;
case 'u':
fmtprint(f, "Buffer");
/* no break */
case 'f':
- {
- Field *l = p;
- if(l->index)
- return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
- l->flags, l->bitoff, l->bitlen, l->index, l->indexv);
- return fmtprint(f, "Field(%x, %x, %x) @ %V",
- l->flags, l->bitoff, l->bitlen, l->reg);
- }
+ l = p;
+ if(l->index)
+ return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
+ l->flags, l->bitoff, l->bitlen, l->index, l->indexv);
+ return fmtprint(f, "Field(%x, %x, %x) @ %V",
+ l->flags, l->bitoff, l->bitlen, l->reg);
default:
return fmtprint(f, "%c:%p", c, p);
}
}
static void
-dumpregs(void){
+dumpregs(void)
+{
Frame *f;
Env *e;
int i;
@@ -789,7 +864,8 @@ dumpregs(void){
}
static int
-xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret){
+xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret)
+{
static int loop;
int i, c;
void *r;
@@ -820,12 +896,12 @@ xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret){
default:
if(PC >= FP->end){
Overrun:
- print("PC overrun frame end");
+ print("aml: PC overrun frame end");
goto Out;
}
FP++;
if(FP >= FT){
- print("frame stack overflow");
+ print("aml: frame stack overflow");
goto Out;
}
*FP = FP[-1];
@@ -870,7 +946,10 @@ xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret){
((uchar*)r)[c] = 0;
PC = end;
break;
- case '1': case '2': case '4': case '8':
+ case '1':
+ case '2':
+ case '4':
+ case '8':
end = PC+(c-'0');
if(end > FP->end)
goto Overrun;
@@ -950,7 +1029,8 @@ Out:
}
static void*
-evalnamec(void){
+evalnamec(void)
+{
int s, c, new;
Name *x, *dot;
@@ -998,12 +1078,14 @@ evalnamec(void){
}
static void*
-evaliarg0(){
+evaliarg0(void)
+{
return FP->arg[0];
}
static void*
-evalconst(void){
+evalconst(void)
+{
switch(FP->start[0]){
case 0x01:
return mki(1);
@@ -1014,7 +1096,8 @@ evalconst(void){
}
static void*
-evalbuf(void){
+evalbuf(void)
+{
int n, m;
uchar *p;
@@ -1029,12 +1112,13 @@ evalbuf(void){
}
static void*
-evalpkg(void){
+evalpkg(void)
+{
Package *p;
void **x;
int n;
- if(p = FP->ref){
+ if((p = FP->ref) != nil){
x = FP->aux;
if(x >= &p->a[0] && x < &p->a[p->n]){
*x++ = FP->arg[0];
@@ -1052,7 +1136,8 @@ evalpkg(void){
}
static void*
-evalname(void){
+evalname(void)
+{
Name *n;
if(n = FP->arg[0])
@@ -1063,7 +1148,8 @@ evalname(void){
}
static void*
-evalscope(void){
+evalscope(void)
+{
Name *n;
if(n = FP->arg[0])
@@ -1075,7 +1161,8 @@ evalscope(void){
}
static void*
-evalalias(void){
+evalalias(void)
+{
Name *n;
if(n = FP->arg[1])
@@ -1084,10 +1171,12 @@ evalalias(void){
}
static void*
-evalmet(void){
+evalmet(void)
+{
Name *n;
+ Method *m;
+
if(n = FP->arg[0]){
- Method *m;
m = mk('m', sizeof(Method));
m->narg = ival(FP->arg[1]) & 7;
m->start = PC;
@@ -1100,22 +1189,26 @@ evalmet(void){
}
static void*
-evalreg(void){
+evalreg(void)
+{
Name *n;
- if(n = FP->arg[0]){
- Region *r;
+ Region *r;
+
+ if((n = FP->arg[0]) != nil){
r = mk('r', sizeof(Region));
r->space = ival(FP->arg[1]);
r->off = ival(FP->arg[2]);
r->len = ival(FP->arg[3]);
r->name = n;
+ r->va = nil;
n->v = r;
}
return nil;
}
static void*
-evalcfield(void){
+evalcfield(void)
+{
void *r;
Field *f;
Name *n;
@@ -1158,7 +1251,8 @@ evalcfield(void){
}
static void*
-evalfield(void){
+evalfield(void)
+{
int flags, bitoff, wa, n;
Field *f, *df;
Name *d;
@@ -1226,15 +1320,17 @@ Out:
}
static void*
-evalnop(void){
+evalnop(void)
+{
return nil;
}
static void*
-evalbad(void){
+evalbad(void)
+{
int i;
- print("bad opcode %p: ", PC);
+ print("aml: bad opcode %p: ", PC);
for(i=0; i < 8 && (FP->start+i) < FP->end; i++){
if(i > 0)
print(" ");
@@ -1248,7 +1344,8 @@ evalbad(void){
}
static void*
-evalcond(void){
+evalcond(void)
+{
switch(FP->op - optab){
case Oif:
if(FP <= FB)
@@ -1283,32 +1380,32 @@ evalcond(void){
}
static void*
-evalcmp(void){
+evalcmp(void)
+{
void *a, *b;
- int c;
+ int tag, c;
- if((a = FP->arg[0]) == nil)
- a = mki(0);
- if((b = FP->arg[1]) == nil)
- b = mki(0);
-
- switch(TAG(a)){
- default:
- return nil;
- case 'i':
+ a = FP->arg[0];
+ b = FP->arg[1];
+ if(a == nil || TAG(a) == 'i'){
c = ival(a) - ival(b);
- break;
- case 's':
- if(TAG(b) != 's')
- b = copy('s', b);
- c = strcmp((char*)a, (char*)b);
- break;
- case 'b':
- if(TAG(b) != 'b')
- b = copy('b', b);
- if((c = SIZE(a) - SIZE(b)) == 0)
- c = memcmp(a, b, SIZE(a));
- break;
+ } else {
+ tag = TAG(a);
+ if(b == nil || TAG(b) != tag)
+ b = copy(tag, b);
+ if(TAG(b) != tag)
+ return nil; /* botch */
+ switch(tag){
+ default:
+ return nil; /* botch */
+ case 's':
+ c = strcmp((char*)a, (char*)b);
+ break;
+ case 'b':
+ if((c = SIZE(a) - SIZE(b)) == 0)
+ c = memcmp(a, b, SIZE(a));
+ break;
+ }
}
switch(FP->op - optab){
@@ -1322,12 +1419,12 @@ evalcmp(void){
if(c < 0) return mki(1);
break;
}
-
return nil;
}
static void*
-evalcall(void){
+evalcall(void)
+{
Method *m;
Env *e;
int i;
@@ -1360,7 +1457,8 @@ evalcall(void){
}
static void*
-evalret(void){
+evalret(void)
+{
void *r = FP->arg[0];
int brk = (FP->op - optab) != Oret;
while(--FP >= FB){
@@ -1381,7 +1479,8 @@ evalret(void){
}
static void*
-evalenv(void){
+evalenv(void)
+{
Ref *r;
Env *e;
int c;
@@ -1402,12 +1501,52 @@ evalenv(void){
}
static void*
-evalstore(void){
+evalstore(void)
+{
return store(FP->arg[0], FP->arg[1]);
}
static void*
-evalindex(void){
+evalcat(void)
+{
+ void *r, *a, *b;
+ int tag, n, m;
+
+ a = FP->arg[0];
+ b = FP->arg[1];
+ if(a == nil || TAG(a) == 'i')
+ a = copy('b', a); /* Concat(Int, ???) -> Buf */
+ tag = TAG(a);
+ if(b == nil || TAG(b) != tag)
+ b = copy(tag, b);
+ if(TAG(b) != tag)
+ return nil; /* botch */
+ switch(tag){
+ default:
+ return nil; /* botch */
+ case 'b':
+ n = SIZE(a);
+ m = SIZE(b);
+ r = mk('b', n + m);
+ memmove(r, a, n);
+ memmove((uchar*)r + n, b, m);
+ break;
+ case 's':
+ n = strlen((char*)a);
+ m = strlen((char*)b);
+ r = mk('s', n + m + 1);
+ memmove(r, a, n);
+ memmove((char*)r + n, b, m);
+ ((char*)r)[n+m] = 0;
+ break;
+ }
+ store(r, FP->arg[2]);
+ return r;
+}
+
+static void*
+evalindex(void)
+{
Field *f;
void *p;
Ref *r;
@@ -1441,7 +1580,8 @@ evalindex(void){
}
static void*
-evalcondref(void){
+evalcondref(void)
+{
void *s;
if((s = FP->arg[0]) == nil)
return nil;
@@ -1450,12 +1590,14 @@ evalcondref(void){
}
static void*
-evalsize(void){
+evalsize(void)
+{
return mki(amllen(FP->arg[0]));
}
static void*
-evalderef(void){
+evalderef(void)
+{
void *p;
if(p = FP->arg[0]){
@@ -1467,8 +1609,12 @@ evalderef(void){
}
static void*
-evalarith(void){
- void *r = nil;
+evalarith(void)
+{
+ uvlong v, d;
+ void *r;
+
+ r = nil;
switch(FP->op - optab){
case Oadd:
r = mki(ival(FP->arg[0]) + ival(FP->arg[1]));
@@ -1476,27 +1622,24 @@ evalarith(void){
case Osub:
r = mki(ival(FP->arg[0]) - ival(FP->arg[1]));
break;
- case Omod:
- {
- uvlong d;
- d = ival(FP->arg[1]);
- r = mki(ival(FP->arg[0]) % d);
- }
- break;
case Omul:
r = mki(ival(FP->arg[0]) * ival(FP->arg[1]));
break;
+ case Omod:
case Odiv:
- {
- uvlong v, d;
- v = ival(FP->arg[0]);
- d = ival(FP->arg[1]);
- r = mki(v / d);
- if(FP->arg[2])
- store(mki(v % d), FP->arg[2]);
- store(r, FP->arg[3]);
- return r;
+ v = ival(FP->arg[0]);
+ d = ival(FP->arg[1]);
+ if(d == 0){
+ print("aml: division by zero: PC=%#p\n", PC);
+ return nil;
}
+ r = mki(v % d);
+ store(r, FP->arg[2]);
+ if((FP->op - optab) != Odiv)
+ return r;
+ r = mki(v / d);
+ store(r, FP->arg[3]);
+ return r;
case Oshl:
r = mki(ival(FP->arg[0]) << ival(FP->arg[1]));
break;
@@ -1543,6 +1686,59 @@ evalarith(void){
return r;
}
+static void*
+evalload(void)
+{
+ enum { LenOffset = 4, HdrLen = 36 };
+ uvlong *tid;
+ Region *r;
+ int l;
+
+ tid = nil;
+ if(FP->aux){
+ if(PC >= FP->end){
+ PC = FP->aux; /* restore */
+ FP->aux = nil;
+ FP->end = PC;
+ tid = mki(1); /* fake */
+ }
+ } else {
+ store(nil, FP->arg[1]);
+ if(FP->arg[0] == nil)
+ return nil;
+
+ l = rwreg(FP->arg[0], LenOffset, 32, 0, 0);
+ if(l <= HdrLen)
+ return nil;
+
+ FP->aux = PC; /* save */
+ FP->ref = FP->arg[0];
+ switch(TAG(FP->ref)){
+ case 'b':
+ if(SIZE(FP->ref) < l)
+ return nil;
+ PC = (uchar*)FP->ref + HdrLen;
+ break;
+ case 'r':
+ r = FP->ref;
+ if(r->len < l || r->va == nil)
+ return nil;
+ /* assuming rwreg() has mapped the region */
+ PC = (uchar*)r->va + HdrLen;
+ break;
+ default:
+ return nil;
+ }
+ FP->end = PC + (l - HdrLen);
+ FP->dot = amlroot;
+ FP->env = nil;
+
+ tid = mki(1); /* fake */
+ store(tid, FP->arg[1]);
+ }
+ return tid;
+}
+
static Op optab[] = {
[Obad] "", "", evalbad,
[Onop] "Noop", "", evalnop,
@@ -1623,11 +1819,14 @@ static Op optab[] = {
[Oref] "RefOf", "@", evaliarg0,
[Ocref] "CondRefOf", "@@", evalcondref,
[Oderef] "DerefOf", "@", evalderef,
+ [Ocat] "Concatenate", "**@", evalcat,
[Oacq] "Acquire", "@2", evalnop,
[Orel] "Release", "@", evalnop,
[Ostall] "Stall", "i", evalnop,
[Osleep] "Sleep", "i", evalnop,
+ [Oload] "Load", "*@}", evalload,
+ [Ounload] "Unload", "@", evalnop,
};
static uchar octab1[] = {
@@ -1645,7 +1844,7 @@ static uchar octab1[] = {
/* 58 */ Onamec, Onamec, Onamec, Obad, Onamec, Obad, Onamec, Onamec,
/* 60 */ Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv,
/* 68 */ Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Oenv, Obad,
-/* 70 */ Ostore, Oref, Oadd, Obad, Osub, Oinc, Odec, Omul,
+/* 70 */ Ostore, Oref, Oadd, Ocat, Osub, Oinc, Odec, Omul,
/* 78 */ Odiv, Oshl, Oshr, Oand, Onand, Oor, Onor, Oxor,
/* 80 */ Onot, Obad, Obad, Oderef, Obad, Omod, Obad, Osize,
/* 88 */ Oindex, Obad, Ocfld4, Ocfld2, Ocfld1, Ocfld0, Obad, Ocfld8,
@@ -1670,8 +1869,8 @@ static uchar octab2[] = {
/* 08 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 10 */ Obad, Obad, Ocref, Ocfld, Obad, Obad, Obad, Obad,
/* 18 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
-/* 20 */ Obad, Ostall, Osleep, Oacq, Obad, Obad, Obad, Orel,
-/* 28 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
+/* 20 */ Oload, Ostall, Osleep, Oacq, Obad, Obad, Obad, Orel,
+/* 28 */ Obad, Obad, Ounload,Obad, Obad, Obad, Obad, Obad,
/* 30 */ Obad, Odebug, Obad, Obad, Obad, Obad, Obad, Obad,
/* 38 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
/* 40 */ Obad, Obad, Obad, Obad, Obad, Obad, Obad, Obad,
@@ -1701,12 +1900,14 @@ static uchar octab2[] = {
};
int
-amltag(void *p){
+amltag(void *p)
+{
return p ? TAG(p) : 0;
}
void*
-amlval(void *p){
+amlval(void *p)
+{
p = deref(p);
if(p && TAG(p) == 'p')
p = ((Package*)p)->a;
@@ -1714,12 +1915,14 @@ amlval(void *p){
}
uvlong
-amlint(void *p){
+amlint(void *p)
+{
return ival(p);
}
int
-amllen(void *p){
+amllen(void *p)
+{
while(p){
switch(TAG(p)){
case 'R':
@@ -1737,7 +1940,8 @@ amllen(void *p){
}
void
-amlinit(void){
+amlinit(void)
+{
Name *n;
fmtinstall('V', Vfmt);
@@ -1771,24 +1975,28 @@ amlinit(void){
}
void
-amlexit(void){
+amlexit(void)
+{
amlroot = nil;
FP = FB-1;
gc();
}
int
-amlload(uchar *data, int len){
+amlload(uchar *data, int len)
+{
return xec(data, data+len, amlroot, nil, nil);
}
void*
-amlwalk(void *dot, char *name){
+amlwalk(void *dot, char *name)
+{
return getname(dot, name, 0);
}
void
-amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg){
+amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg)
+{
Name *n, *d;
int rec;
@@ -1806,7 +2014,8 @@ amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg){
}
int
-amleval(void *dot, char *fmt, ...){
+amleval(void *dot, char *fmt, ...)
+{
va_list a;
Method *m;
void **r;
@@ -1830,13 +2039,14 @@ amleval(void *dot, char *fmt, ...){
}
r = va_arg(a, void**);
va_end(a);
- if(dot = deref(dot)) switch(TAG(dot)){
- case 'm':
+ if(dot = deref(dot))
+ if(TAG(dot) == 'm'){
m = dot;
if(i != m->narg)
return -1;
return xec(m->start, m->end, forkname(m->name), e, r);
}
- if(r) *r = dot;
+ if(r != nil)
+ *r = dot;
return 0;
}
diff --git a/sys/src/libc/mips/lock.c b/sys/src/libc/mips/lock.c
index c42208822..9c9bd2208 100644
--- a/sys/src/libc/mips/lock.c
+++ b/sys/src/libc/mips/lock.c
@@ -124,8 +124,9 @@ retry:
return 1;
}
}
- return 0;
+ break;
}
+ return 0;
}
void
@@ -164,6 +165,7 @@ retry:
return 0;
}
}
- return 1;
+ break;
}
+ return 1;
}
diff --git a/sys/src/libc/port/pool.c b/sys/src/libc/port/pool.c
index 0bbe89a22..6944afc13 100644
--- a/sys/src/libc/port/pool.c
+++ b/sys/src/libc/port/pool.c
@@ -141,10 +141,7 @@ static ulong bsize2asize(Pool*, ulong);
static ulong dsize2bsize(Pool*, ulong);
static ulong getdsize(Alloc*);
static Alloc* trim(Pool*, Alloc*, ulong);
-static Free* listadd(Free*, Free*);
-static Free* listdelete(Free*, Free*);
static void logstack(Pool*);
-static Free** ltreewalk(Free**, ulong);
static void memmark(void*, int, ulong);
static Free* pooladd(Pool*, Alloc*);
static void* poolallocl(Pool*, ulong);
@@ -157,9 +154,8 @@ static void pooldumparena(Pool*, Arena*);
static void poolfreel(Pool*, void*);
static void poolnewarena(Pool*, ulong);
static void* poolreallocl(Pool*, void*, ulong);
-static Free* treedelete(Free*, Free*);
-static Free* treeinsert(Free*, Free*);
static Free* treelookupgt(Free*, ulong);
+static Free* treesplay(Free*, ulong);
/*
* Debugging
@@ -225,76 +221,6 @@ checktree(Free *t, int a, int b)
}
-/* ltreewalk: return address of pointer to node of size == size */
-static Free**
-ltreewalk(Free **t, ulong size)
-{
- Free *f;
-
- for(;;) {
- f = *t;
- if(f == nil || f->magic != FREE_MAGIC)
- return t;
- if(size == f->size)
- return t;
- if(size < f->size)
- t = &f->left;
- else
- t = &f->right;
- }
-}
-
-/* treeinsert: insert node into tree */
-static Free*
-treeinsert(Free *tree, Free *node)
-{
- Free **loc, *repl;
-
- assert(node != nil /* treeinsert */);
-
- loc = ltreewalk(&tree, node->size);
- repl = *loc;
- if(repl == nil || repl->magic != FREE_MAGIC) {
- node->left = nil;
- node->right = nil;
- } else { /* replace existing node */
- node->left = repl->left;
- node->right = repl->right;
- }
- *loc = node;
- return tree;
-}
-
-/* treedelete: remove node from tree */
-static Free*
-treedelete(Free *tree, Free *node)
-{
- Free **loc, **lsucc, *succ;
-
- assert(node != nil /* treedelete */);
-
- loc = ltreewalk(&tree, node->size);
- if(*loc != node || node->magic != FREE_MAGIC)
- return tree; /* free nodes corrupted */
-
- if(node->left == nil)
- *loc = node->right;
- else if(node->right == nil)
- *loc = node->left;
- else {
- /* have two children, use inorder successor as replacement */
- for(lsucc = &node->right; (*lsucc)->left; lsucc = &(*lsucc)->left)
- ;
- succ = *lsucc;
- *lsucc = succ->right;
- succ->left = node->left;
- succ->right = node->right;
- *loc = succ;
- }
- node->left = node->right = Poison;
- return tree;
-}
-
/* treelookupgt: find smallest node in tree with size >= size */
static Free*
treelookupgt(Free *t, ulong size)
@@ -303,8 +229,9 @@ treelookupgt(Free *t, ulong size)
lastgood = nil;
for(;;) {
- if(t == nil || t->magic != FREE_MAGIC)
+ if(t == nil)
return lastgood;
+ assert(t->magic == FREE_MAGIC);
if(size == t->size)
return t;
if(size < t->size) {
@@ -315,59 +242,64 @@ treelookupgt(Free *t, ulong size)
}
}
-/*
- * List maintenance
- */
-
-/* listadd: add a node to a doubly linked list */
+/* treesplay: splay node of size size to the root and return new root */
static Free*
-listadd(Free *list, Free *node)
+treesplay(Free *t, ulong size)
{
- if(list == nil) {
- node->next = node;
- node->prev = node;
- return node;
- }
-
- node->prev = list->prev;
- node->next = list;
+ Free N, *l, *r, *y;
- node->prev->next = node;
- node->next->prev = node;
+ N.left = N.right = nil;
+ l = r = &N;
- return list;
-}
-
-/* listdelete: remove node from a doubly linked list */
-static Free*
-listdelete(Free *list, Free *node)
-{
- if(node->next == node) { /* singular list */
- node->prev = node->next = Poison;
- return nil;
+ for(;;) {
+ assert(t->magic == FREE_MAGIC);
+ if(size < t->size) {
+ y = t->left;
+ if(y != nil) {
+ assert(y->magic == FREE_MAGIC);
+ if(size < y->size) {
+ t->left = y->right;
+ y->right = t;
+ t = y;
+ }
+ }
+ if(t->left == nil)
+ break;
+ r->left = t;
+ r = t;
+ t = t->left;
+ } else if(size > t->size) {
+ y = t->right;
+ if(y != nil) {
+ assert(y->magic == FREE_MAGIC);
+ if(size > y->size) {
+ t->right = y->left;
+ y->left = t;
+ t = y;
+ }
+ }
+ if(t->right == nil)
+ break;
+ l->right = t;
+ l = t;
+ t = t->right;
+ } else
+ break;
}
- node->next->prev = node->prev;
- node->prev->next = node->next;
+ l->right=t->left;
+ r->left=t->right;
+ t->left=N.right;
+ t->right=N.left;
- if(list == node)
- list = node->next;
-
- node->prev = node->next = Poison;
- return list;
+ return t;
}
-/*
- * Pool maintenance
- */
-
/* pooladd: add anode to the free pool */
static Free*
pooladd(Pool *p, Alloc *anode)
{
- Free *lst, *olst;
- Free *node;
- Free **parent;
+ Free *node, *root;
antagonism {
memmark(_B2D(anode), 0xF7, anode->size-sizeof(Bhdr)-sizeof(Btail));
@@ -375,17 +307,33 @@ pooladd(Pool *p, Alloc *anode)
node = (Free*)anode;
node->magic = FREE_MAGIC;
- parent = ltreewalk(&p->freeroot, node->size);
- olst = *parent;
- if(olst != nil && olst->magic != FREE_MAGIC){
- /* corruption of free nodes */
- poolcheckl(p);
- olst = *parent = nil;
+ node->left = node->right = nil;
+ node->next = node->prev = node;
+
+ if(p->freeroot != nil) {
+ root = treesplay(p->freeroot, node->size);
+ if(root->size > node->size) {
+ node->left = root->left;
+ node->right = root;
+ root->left = nil;
+ } else if(root->size < node->size) {
+ node->right = root->right;
+ node->left = root;
+ root->right = nil;
+ } else {
+ node->left = root->left;
+ node->right = root->right;
+ root->left = root->right = Poison;
+
+ node->prev = root->prev;
+ node->next = root;
+ node->prev->next = node;
+ node->next->prev = node;
+ }
}
- lst = listadd(olst, node);
- if(olst != lst) /* need to update tree */
- *parent = treeinsert(*parent, lst);
+ p->freeroot = node;
p->curfree += node->size;
+
return node;
}
@@ -393,30 +341,38 @@ pooladd(Pool *p, Alloc *anode)
static Alloc*
pooldel(Pool *p, Free *node)
{
- Free *lst, *olst;
- Free **parent;
-
- parent = ltreewalk(&p->freeroot, node->size);
- olst = *parent;
- if(olst == nil || olst->magic != FREE_MAGIC){
- /* corruption of free nodes */
- poolcheckl(p);
- *parent = nil;
+ Free *root;
+
+ root = treesplay(p->freeroot, node->size);
+ if(node == root && node->next == node) {
+ if(node->left == nil)
+ root = node->right;
+ else {
+ root = treesplay(node->left, node->size);
+ assert(root->right == nil);
+ root->right = node->right;
+ }
} else {
- lst = listdelete(olst, node);
- if(lst == nil)
- *parent = treedelete(*parent, olst);
- else if(lst != olst)
- *parent = treeinsert(*parent, lst);
+ if(node == root) {
+ root = node->next;
+ root->left = node->left;
+ root->right = node->right;
+ }
+ assert(root->magic == FREE_MAGIC && root->size == node->size);
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
}
- node->left = node->right = Poison;
+ p->freeroot = root;
p->curfree -= node->size;
+ node->left = node->right = node->next = node->prev = Poison;
+
antagonism {
memmark(_B2D(node), 0xF9, node->size-sizeof(Bhdr)-sizeof(Btail));
}
node->magic = UNALLOC_MAGIC;
+
return (Alloc*)node;
}
diff --git a/sys/src/libdraw/alloc.c b/sys/src/libdraw/alloc.c
index 7884321ac..256378f36 100644
--- a/sys/src/libdraw/alloc.c
+++ b/sys/src/libdraw/alloc.c
@@ -26,6 +26,10 @@ _allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val,
err = 0;
i = 0;
+ if(badrect(r)){
+ werrstr("bad rectangle");
+ return nil;
+ }
if(chan == 0){
werrstr("bad channel descriptor");
return nil;
diff --git a/sys/src/libdraw/badrect.c b/sys/src/libdraw/badrect.c
new file mode 100644
index 000000000..5ec53edb4
--- /dev/null
+++ b/sys/src/libdraw/badrect.c
@@ -0,0 +1,22 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+/*
+ * check for zero, negative size or insanely huge rectangle.
+ */
+int
+badrect(Rectangle r)
+{
+ int x, y;
+ uint z;
+
+ x = Dx(r);
+ y = Dy(r);
+ if(x > 0 && y > 0){
+ z = x*y;
+ if(z/x == y && z < 0x10000000)
+ return 0;
+ }
+ return 1;
+}
diff --git a/sys/src/libdraw/emenuhit.c b/sys/src/libdraw/emenuhit.c
index 8e34fe942..a8e01a358 100644
--- a/sys/src/libdraw/emenuhit.c
+++ b/sys/src/libdraw/emenuhit.c
@@ -230,7 +230,8 @@ emenuhit(int but, Mouse *m, Menu *menu)
border(screen, menur, Blackborder, bord, ZP);
save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1);
r = menurect(textr, lasti);
- emoveto(divpt(addpt(r.min, r.max), 2));
+ if(pt.x || pt.y)
+ emoveto(divpt(addpt(r.min, r.max), 2));
menupaint(menu, textr, off, nitemdrawn);
if(scrolling)
menuscrollpaint(scrollr, off, nitem, nitemdrawn);
diff --git a/sys/src/libdraw/menuhit.c b/sys/src/libdraw/menuhit.c
index cea8bb716..e911466ec 100644
--- a/sys/src/libdraw/menuhit.c
+++ b/sys/src/libdraw/menuhit.c
@@ -234,7 +234,8 @@ menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr)
border(b, menur, Blackborder, bord, ZP);
save = allocimage(display, menurect(textr, 0), screen->chan, 0, -1);
r = menurect(textr, lasti);
- moveto(mc, divpt(addpt(r.min, r.max), 2));
+ if(pt.x || pt.y)
+ moveto(mc, divpt(addpt(r.min, r.max), 2));
menupaint(b, menu, textr, off, nitemdrawn);
if(scrolling)
menuscrollpaint(b, scrollr, off, nitem, nitemdrawn);
diff --git a/sys/src/libdraw/mkfile b/sys/src/libdraw/mkfile
index 0a70c3a48..ef76b522b 100644
--- a/sys/src/libdraw/mkfile
+++ b/sys/src/libdraw/mkfile
@@ -6,6 +6,7 @@ OFILES=\
alloc.$O\
allocimagemix.$O\
arith.$O\
+ badrect.$O\
bezier.$O\
border.$O\
buildfont.$O\
diff --git a/sys/src/libdraw/window.c b/sys/src/libdraw/window.c
index 4c734208b..84ecb1fc9 100644
--- a/sys/src/libdraw/window.c
+++ b/sys/src/libdraw/window.c
@@ -22,14 +22,11 @@ allocscreen(Image *image, Image *fill, int public)
s = malloc(sizeof(Screen));
if(s == 0)
return 0;
- SET(id);
for(try=0; try<25; try++){
/* loop until find a free id */
a = bufimage(d, 1+4+4+4+1);
- if(a == 0){
- free(s);
- return 0;
- }
+ if(a == 0)
+ break;
id = ++screenid;
a[0] = 'A';
BPLONG(a+1, id);
@@ -37,8 +34,12 @@ allocscreen(Image *image, Image *fill, int public)
BPLONG(a+9, fill->id);
a[13] = public;
if(flushimage(d, 0) != -1)
- break;
+ goto Found;
}
+ free(s);
+ return 0;
+
+ Found:
s->display = d;
s->id = id;
s->image = image;
diff --git a/sys/src/libmemdraw/alloc.c b/sys/src/libmemdraw/alloc.c
index 14abdf53d..d2852c3c4 100644
--- a/sys/src/libmemdraw/alloc.c
+++ b/sys/src/libmemdraw/alloc.c
@@ -27,14 +27,14 @@ allocmemimaged(Rectangle r, ulong chan, Memdata *md)
ulong l;
Memimage *i;
- if(Dx(r) <= 0 || Dy(r) <= 0){
- werrstr("bad rectangle %R", r);
- return nil;
- }
if((d = chantodepth(chan)) == 0) {
werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
+ if(badrect(r)){
+ werrstr("bad rectangle %R", r);
+ return nil;
+ }
l = wordsperline(r, d);
@@ -76,8 +76,13 @@ allocmemimage(Rectangle r, ulong chan)
werrstr("bad channel descriptor %.8lux", chan);
return nil;
}
+ if(badrect(r)){
+ werrstr("bad rectangle %R", r);
+ return nil;
+ }
l = wordsperline(r, d);
+
nw = l*Dy(r);
md = malloc(sizeof(Memdata));
if(md == nil)
diff --git a/sys/src/libmemdraw/cload.c b/sys/src/libmemdraw/cload.c
index 5e068cba0..b70c23603 100644
--- a/sys/src/libmemdraw/cload.c
+++ b/sys/src/libmemdraw/cload.c
@@ -9,7 +9,7 @@ cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
int y, bpl, c, cnt, offs;
uchar mem[NMEM], *memp, *omemp, *emem, *linep, *elinep, *u, *eu;
- if(!rectinrect(r, i->r))
+ if(badrect(r) || !rectinrect(r, i->r))
return -1;
bpl = bytesperline(r, i->depth);
u = data;
diff --git a/sys/src/libmemdraw/draw.c b/sys/src/libmemdraw/draw.c
index 574d597db..5a15e4dae 100644
--- a/sys/src/libmemdraw/draw.c
+++ b/sys/src/libmemdraw/draw.c
@@ -228,7 +228,7 @@ drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask,
int splitcoords;
Rectangle omr;
- if(r->min.x>=r->max.x || r->min.y>=r->max.y)
+ if(badrect(*r))
return 0;
splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
/* clip to destination */
@@ -1541,8 +1541,8 @@ readcmap(Param *p, uchar *buf, int y)
static void
writecmap(Param *p, uchar *w, Buffer src)
{
- uchar *cmap, *red, *grn, *blu;
- int i, dx, delta;
+ uchar *cmap, *red, *grn, *blu, *alpha;
+ int i, dx, delta, a, m;
cmap = p->img->cmap->rgb2cmap;
@@ -1552,8 +1552,20 @@ writecmap(Param *p, uchar *w, Buffer src)
blu = src.blu;
dx = p->dx;
- for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
- *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
+ if(p->img->flags&Falpha){
+ alpha = src.alpha;
+ m = p->img->shift[CMap]/8;
+ a = p->img->shift[CAlpha]/8;
+ for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta, w+=2){
+ w[a] = *alpha;
+ if(alpha != &ones)
+ alpha+=delta;
+ w[m] = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
+ }
+ } else {
+ for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
+ *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
+ }
}
#define DBG if(0)
@@ -1752,7 +1764,7 @@ writefn(Memimage *img)
{
if(img->depth < 8)
return writenbit;
- if(img->chan == CMAP8)
+ if(img->nbits[CMap] == 8)
return writecmap;
return writebyte;
}
diff --git a/sys/src/libmemdraw/load.c b/sys/src/libmemdraw/load.c
index 984efa958..9c17eb01b 100644
--- a/sys/src/libmemdraw/load.c
+++ b/sys/src/libmemdraw/load.c
@@ -10,7 +10,7 @@ loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
Memdrawparam par;
uchar *q;
- if(!rectinrect(r, i->r))
+ if(badrect(r) || !rectinrect(r, i->r))
return -1;
memset(&par, 0, sizeof par);
diff --git a/sys/src/libmemdraw/unload.c b/sys/src/libmemdraw/unload.c
index b3f25c93a..9e638a93e 100644
--- a/sys/src/libmemdraw/unload.c
+++ b/sys/src/libmemdraw/unload.c
@@ -9,7 +9,7 @@ unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
int y, l;
uchar *q;
- if(!rectinrect(r, i->r))
+ if(badrect(r) || !rectinrect(r, i->r))
return -1;
l = bytesperline(r, i->depth);
if(ndata < l*Dy(r))