diff options
author | ethan <ethan@vx32vardo> | 2013-07-05 21:51:35 +0100 |
---|---|---|
committer | ethan <ethan@vx32vardo> | 2013-07-05 21:51:35 +0100 |
commit | 0e9a80d129306202e31e9ed253b75b9b06703a86 (patch) | |
tree | 0141d8ed52f9c78e33f8ebbf281d0d2125c55108 /sys | |
parent | 6fd3e90d85b43e4d7d97d11d282946d11d22183a (diff) | |
parent | 252b0ff3c9b17628e641f2e9eb84468fb8975a6e (diff) |
merge
Diffstat (limited to 'sys')
79 files changed, 3801 insertions, 895 deletions
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)) |