From 0751abb748fe12c6a2d306670c7fcd3948e675e9 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 23 Aug 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-08-23 --- pc/clock.c | 1 - pc/devfloppy.c | 35 +---- pc/devuart.c | 42 ++++-- pc/kbd.c | 1 + pc/main.c | 23 ++- pc/trap.c | 43 +++--- port/devwren.c | 396 +++++++++++++++++++++++++------------------------ 7 files changed, 271 insertions(+), 270 deletions(-) diff --git a/pc/clock.c b/pc/clock.c index 1e03c516f11752f3876d16bccf4dfa7e74181804..24a7ae386c6f1485f4de041133b896d932fc7e68 100644 --- a/pc/clock.c +++ b/pc/clock.c @@ -62,7 +62,6 @@ clock(Ureg *ur) m->ticks++; checkalarms(); - mouseclock(); /* * process time accounting diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 7f30b7e21a06b85f933206c8b166b5ee280cdf2a..7e8294b612c034d09214529fcd3ac98792b7578b 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -31,12 +31,6 @@ enum DMAchan= 2, /* floppy dma channel */ - /* sector size encodings */ - S128= 0, - S256= 1, - S512= 2, - S1024= 3, - /* status 0 byte */ Drivemask= 3<<0, Seekend= 1<<5, @@ -45,7 +39,6 @@ enum /* file types */ Qdir= 0, Qdata= (1<<2), - Qstruct= (2<<2), Qmask= (3<<2), }; @@ -163,14 +156,10 @@ static long floppyxfer(Drive*, int, void*, long, long); static void floppyintr(Ureg*); Dirtab floppydir[]={ - "fd0data", {Qdata + 0}, 0, 0600, - "fd0struct", {Qstruct + 0}, 8, 0600, - "fd1data", {Qdata + 1}, 0, 0600, - "fd1struct", {Qstruct + 1}, 8, 0600, - "fd2data", {Qdata + 2}, 0, 0600, - "fd2struct", {Qstruct + 2}, 8, 0600, - "fd3data", {Qdata + 3}, 0, 0600, - "fd3struct", {Qstruct + 3}, 8, 0600, + "fd0disk", {Qdata + 0}, 0, 0600, + "fd1disk", {Qdata + 1}, 0, 0600, + "fd2disk", {Qdata + 2}, 0, 0600, + "fd3disk", {Qdata + 3}, 0, 0600, }; #define NFDIR 2 /* directory entries/drive */ @@ -337,15 +326,6 @@ floppyread(Chan *c, void *a, long n) memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len); } break; - case Qstruct: - if (n < 2*sizeof(ulong)) - error(Ebadarg); - if (c->offset >= 2*sizeof(ulong)) - return 0; - rv = 2*sizeof(ulong); - ul2user((uchar*)a, dp->t->cap); - ul2user((uchar*)a+sizeof(ulong), dp->t->bytes); - break; default: panic("floppyread: bad qid"); } @@ -369,9 +349,6 @@ floppywrite(Chan *c, void *a, long n) break; } break; - case Qstruct: - error(Eperm); - break; default: panic("floppywrite: bad qid"); } @@ -733,7 +710,7 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) if(floppyseek(dp) < 0) errors("seeking floppy"); -print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", +/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ /* @@ -797,7 +774,7 @@ print("new offset %d instead of %d\n", offset, off+dp->len); static void floppyintr(Ureg *ur) { -print("floppy intr\n"); +/*print("floppy intr\n");/**/ floppy.intr = 1; wakeup(&floppy.r); } diff --git a/pc/devuart.c b/pc/devuart.c index e83e6f88e2481ea8377a502da7065143c276c57e..eb4c03c4fb18c479631f9fc0d8718a56cc01af54 100644 --- a/pc/devuart.c +++ b/pc/devuart.c @@ -1,4 +1,4 @@ - #include "u.h" +#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" @@ -18,6 +18,10 @@ enum */ Data= 0, /* xmit/rcv buffer */ Iena= 1, /* interrupt enable */ + Ircv= (1<<0), /* for char rcv'd */ + Ixmt= (1<<1), /* for xmit buffer empty */ + Irstat=(1<<2), /* for change in rcv'er status */ + Imstat=(1<<3), /* for change in modem status */ Istat= 2, /* interrupt flag (read) */ Tctl= 2, /* test control (write) */ Format= 3, /* byte format */ @@ -36,7 +40,9 @@ enum Loop= (1<<4), /* loop bask */ Lstat= 5, /* line status */ Inready=(1<<0), /* receive buffer full */ - Overrun=(1<<1), /* we lost an input char */ + Oerror=(1<<1), /* receiver overrun */ + Perror=(1<<2), /* receiver parity error */ + Ferror=(1<<3), /* rcv framing error */ Outready=(1<<5), /* output buffer full */ Mstat= 6, /* modem status */ Scratch=7, /* scratchpad */ @@ -67,6 +73,10 @@ struct Uart Alarm *a; /* alarm for waking the kernel process */ int kstarted; /* kproc started */ uchar delim[256/8]; /* characters that act as delimiters */ + + /* error statistics */ + ulong frame; + ulong overrun; }; Uart uart[2]; @@ -213,14 +223,15 @@ uartintr(Uart *up) IOQ *cq; int s, l; - /* - * the for loop takes care of multiple events per interrupt - */ for(;;){ s = uartrdreg(up, Istat); switch(s){ case 6: /* receiver line status */ l = uartrdreg(up, Lstat); + if(l & Ferror) + up->frame++; + if(l & Oerror) + up->overrun++; break; case 4: /* received data available */ @@ -233,9 +244,6 @@ uartintr(Uart *up) if(up->delim[ch/8] & (1<<(ch&7)) ) wakeup(&cq->r); } - l = uartrdreg(up, Lstat); - if(l & Overrun) - screenputc('!'); break; case 2: /* transmitter empty */ @@ -257,7 +265,7 @@ uartintr(Uart *up) default: if(s&1) return; - print("weird modem interrupt\n"); +/* print("weird modem interrupt\n");/**/ break; } } @@ -289,6 +297,11 @@ uartenable(Uart *up) print("can't turn on serial port power\n"); } + /* + * speed up the clock to poll the uart + fclockinit(); + */ + /* * set up i/o routines */ @@ -304,7 +317,7 @@ uartenable(Uart *up) /* * turn on interrupts */ - up->sticky[Iena] = 0x7; + up->sticky[Iena] = Ircv | Ixmt | Irstat; uartwrreg(up, Iena, 0); /* @@ -514,6 +527,7 @@ uartkproc(void *a) IOQ *cq = up->iq; Block *bp; int n; + ulong frame, overrun; if(waserror()) print("uartkproc got an error\n"); @@ -531,6 +545,14 @@ uartkproc(void *a) PUTNEXT(RD(up->wq), bp); } qunlock(up); + if(up->frame != frame){ + kprint("uart%d: %d framing\n", up-uart, up->frame); + frame = up->frame; + } + if(up->overrun != overrun){ + kprint("uart%d: %d overruns\n", up-uart, up->overrun); + overrun = up->overrun; + } } } diff --git a/pc/kbd.c b/pc/kbd.c index 964bf98083b7a9575ba2f47ea388cd59fb3aa5b5..cd253bca97616d1fcdc859cbfd571b948fa5c931 100644 --- a/pc/kbd.c +++ b/pc/kbd.c @@ -359,6 +359,7 @@ mymouseputc(int c) mouse.dx = msg[1]; mouse.dy = -msg[2]; mouse.track = 1; + spllo(); /* mouse tracking kills uart0 */ mouseclock(); } } diff --git a/pc/main.c b/pc/main.c index c2783ce126ff39ec521bb9d3011bb4305506afe5..5b0f87c3212ea7a9d1aaf87e5b50959936130759 100644 --- a/pc/main.c +++ b/pc/main.c @@ -18,6 +18,7 @@ main(void) confinit(); screeninit(); printinit(); + print("%lud K bytes of physical memory\n", 1024 + conf.npage1*BY2PG/1024); mmuinit(); trapinit(); kbdinit(); @@ -141,7 +142,15 @@ confinit(void) int mul; /* - * size memory + * the first 640k is the standard useful memory + * the next 128K is the display + * the last 256k belongs to the roms + */ + conf.npage0 = 640/4; + conf.base0 = 0; + + /* + * size the non-standard memory */ x = 0x12345678; for(i=1; i<16; i++){ @@ -165,17 +174,7 @@ confinit(void) break; x += 0x3141526; } - - /* - * the first 640k is the standard useful memory - */ - conf.npage0 = 640/4; - conf.base0 = 0; - - /* - * the last 128k belongs to the roms - */ - conf.npage1 = (i-1)*1024/4; + conf.npage1 = (i-2)*1024/4; conf.base1 = 1024*1024; conf.npage = conf.npage0 + conf.npage1; diff --git a/pc/trap.c b/pc/trap.c index 3344347bf421d09ed18818f0afbe308726dbaf22..6e0edc742f8f911dca7e5df684fee1f52ae2ab12 100644 --- a/pc/trap.c +++ b/pc/trap.c @@ -79,27 +79,27 @@ trapinit(void) * set all interrupts to panics */ for(i = 32; i < 256; i++) - sethvec(i, intrbad, SEGIG, 0); + sethvec(i, intrbad, SEGTG, 0); /* * set the standard traps */ - sethvec(0, intr0, SEGIG, 0); - sethvec(1, intr1, SEGIG, 0); - sethvec(2, intr2, SEGIG, 0); - sethvec(3, intr3, SEGIG, 0); - sethvec(4, intr4, SEGIG, 0); - sethvec(5, intr5, SEGIG, 0); - sethvec(6, intr6, SEGIG, 0); - sethvec(7, intr7, SEGIG, 0); - sethvec(8, intr8, SEGIG, 0); - sethvec(9, intr9, SEGIG, 0); - sethvec(10, intr10, SEGIG, 0); - sethvec(11, intr11, SEGIG, 0); - sethvec(12, intr12, SEGIG, 0); - sethvec(13, intr13, SEGIG, 0); - sethvec(14, intr14, SEGIG, 0); - sethvec(15, intr15, SEGIG, 0); + sethvec(0, intr0, SEGTG, 0); + sethvec(1, intr1, SEGTG, 0); + sethvec(2, intr2, SEGTG, 0); + sethvec(3, intr3, SEGTG, 0); + sethvec(4, intr4, SEGTG, 0); + sethvec(5, intr5, SEGTG, 0); + sethvec(6, intr6, SEGTG, 0); + sethvec(7, intr7, SEGTG, 0); + sethvec(8, intr8, SEGTG, 0); + sethvec(9, intr9, SEGTG, 0); + sethvec(10, intr10, SEGTG, 0); + sethvec(11, intr11, SEGTG, 0); + sethvec(12, intr12, SEGTG, 0); + sethvec(13, intr13, SEGTG, 0); + sethvec(14, intr14, SEGTG, 0); + sethvec(15, intr15, SEGTG, 0); /* * set the standard devices @@ -188,14 +188,10 @@ trap(Ureg *ur) if(c == Int1vec) outb(Int1ctl, EOI); outb(Int0ctl, EOI); + if(v != Uart0vec) + uartintr0(ur); } - /* - * check for a waiting character, the uart is at too low - * a priority level to work correctly at 9600 baud. - */ - uartintr0(ur); - /* * call the trap routine */ @@ -270,7 +266,6 @@ syscall(Ureg *ur) u->p->pc = ur->pc; if((ur->cs)&0xffff == KESEL) panic("recursive system call"); - spllo(); /* * do something about floating point!!! diff --git a/port/devwren.c b/port/devwren.c index c313cf352f4b6f912f93a3e761375758229804d0..5e79ef6e5c4899a1f7d95cf20ae5a8ff277e08ef 100644 --- a/port/devwren.c +++ b/port/devwren.c @@ -7,41 +7,41 @@ #include "devtab.h" #include "io.h" -typedef struct Part Part; -typedef struct Disk Disk; +typedef struct Partition Partition; +typedef struct Drive Drive; enum { - Npart= 2, /* maximum partitions per disk */ + Npart= 8+2, /* 8 sub partitions, disk, and partition */ Ndisk= 64, /* maximum disks */ + /* file types */ Qdir= 0, - Qdata= 16, - Qstruct= 32, - - Mask= 0x7, }; +#define PART(x) ((x)&0xF) +#define DRIVE(x) (((x)>>4)&0x7) +#define MKQID(d,p) (((d)<<4) | (p)) -static Dirtab *wrendir; -#define NWREN (2*(Npart+1)) - -struct Part +struct Partition { - ulong firstblock; - ulong maxblock; + ulong start; + ulong end; + char name[NAMELEN+1]; }; -struct Disk + +struct Drive { - ulong blocksize; - Part p[Npart]; + ulong bytes; /* bytes per block */ + int npart; /* actual number of partitions */ + int drive; + Partition p[Npart]; }; -static Disk wren[Ndisk]; - -void wrenint(uchar*, ulong); +static Drive wren[Ndisk]; #define DATASIZE (8*1024) /* BUG */ -#define BGLONG(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) +static void wrenpart(int); +static long wrenio(Drive *, Partition *, int, char *, ulong, ulong); /* * accepts [0-7].[0-7], or abbreviation @@ -50,21 +50,22 @@ static int wrendev(char *p) { int dev = 0; - if (p==0 || p[0]==0) + + if(p == 0 || p[0] == 0) goto out; - if (p[0]<'0' || p[0]>'7') + if(p[0] < '0' || p[0] > '7') goto cant; - dev = (p[0]-'0')<<3; - if (p[1]==0) + dev = (p[0] - '0') << 3; + if(p[1] == 0) goto out; - if (p[1]!='.') + if(p[1] != '.') goto cant; - if (p[2]==0) + if(p[2] == 0) goto out; - if (p[2]<'0' || p[2]>'7') + if(p[2] < '0' || p[2] > '7') goto cant; - dev |= p[2]-'0'; - if (p[3]!=0) + dev |= p[2] - '0'; + if(p[3] != 0) goto cant; out: if(dev >= Ndisk) @@ -75,58 +76,43 @@ cant: } static int -wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp) +wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp) { - long l; - Part *p; - Disk *d; - - if(s >= ntab) - return -1; - if(c->dev >= Ndisk) + Qid qid; + int drive; + char name[NAMELEN+4]; + Drive *dp; + Partition *pp; + ulong l; + + qid.vers = 0; + drive = s/Npart; + s = s % Npart; + if(drive >= Ndisk) return -1; + dp = &wren[drive]; - tab += s; - d = &wren[c->dev]; - p = &d->p[tab->qid.path&Mask]; - if((tab->qid.path&~Mask) == Qdata) - l = d->blocksize * (p->maxblock - p->firstblock); - else - l = 8; - devdir(c, tab->qid, tab->name, l, tab->perm, dp); + if(s >= dp->npart) + return 0; + + pp = &dp->p[s]; + sprint(name, "hd%d%s", drive, pp->name); + name[NAMELEN] = 0; + qid.path = MKQID(drive, s); + l = (pp->end - pp->start) * dp->bytes; + devdir(c, qid, name, l, 0600, dirp); return 1; } void wrenreset(void) { - Dirtab *p; - int i; - - p = wrendir = ialloc((Npart+1) * 2 * sizeof(Dirtab), 0); - for(i = 0; i < Npart; i++){ - sprint(p->name, "data%d", i); - p->qid.path = Qdata + i; - p->perm = 0600; - p++->length = 0; - sprint(p->name, "struct%d", i); - p->qid.path = Qstruct + i; - p->perm = 0600; - p++->length = 0; - } - strcpy(p->name, "data"); - p->qid.path = Qdata + Npart; - p->perm = 0600; - p++->length = 0; - strcpy(p->name, "struct"); - p->qid.path = Qstruct + Npart; - p->perm = 0600; - p->length = 0; } void wreninit(void) -{} +{ +} /* * param is #r. @@ -134,34 +120,17 @@ wreninit(void) Chan * wrenattach(char *param) { - uchar buf[32]; - int dev; Chan *c; - Disk *d; - ulong plen; - int i; + int drive; - dev = wrendev(param); - scsiready(dev); - scsisense(dev, buf); - scsicap(dev, buf); + drive = wrendev(param); + wrenpart(drive); c = devattach('r', param); - c->dev = dev; - d = &wren[dev]; - d->blocksize = BGLONG(&buf[4]); - - plen = BGLONG(&buf[0])+1; - d->p[Npart].firstblock = 0; - d->p[Npart].maxblock = plen; - plen = plen/Npart; - for(i = 0; i < Npart; i++){ - d->p[i].firstblock = i*plen; - d->p[i].maxblock = (i+1)*plen; - } + c->dev = drive; return c; } -Chan * +Chan* wrenclone(Chan *c, Chan *nc) { return devclone(c, nc); @@ -170,21 +139,19 @@ wrenclone(Chan *c, Chan *nc) int wrenwalk(Chan *c, char *name) { - return devwalk(c, name, wrendir, NWREN, wrengen); + return devwalk(c, name, 0, 0, wrengen); } void -wrenstat(Chan *c, char *db) +wrenstat(Chan *c, char *dp) { - devstat(c, db, wrendir, NWREN, wrengen); + devstat(c, dp, 0, 0, wrengen); } -Chan * +Chan* wrenopen(Chan *c, int omode) { - if (c->qid.path == Qdata && scsiready(c->dev) != 0) - error(Eio); - return devopen(c, omode, wrendir, NWREN, wrengen); + return devopen(c, omode, 0, 0, wrengen); } void @@ -195,123 +162,164 @@ wrencreate(Chan *c, char *name, int omode, ulong perm) void wrenclose(Chan *c) -{} +{ +} + +void +wrenremove(Chan *c) +{ + error(Eperm); +} + +void +wrenwstat(Chan *c, char *dp) +{ + error(Eperm); +} long wrenread(Chan *c, char *a, long n, ulong offset) { - Scsi *cmd; - ulong lbn; - Part *p; - Disk *d; + Drive *d; + Partition *p; - if (n == 0) - return 0; if(c->qid.path == CHDIR) - return devdirread(c, a, n, wrendir, NWREN, wrengen); - - d = &wren[c->dev]; - p = &(d->p[Mask&c->qid.path]); - switch ((int)(c->qid.path & ~Mask)) { - case Qdata: - if (n % d->blocksize || offset % d->blocksize) - error(Ebadarg); - lbn = (offset/d->blocksize) + p->firstblock; - if (lbn >= p->maxblock) - error(Ebadarg); - if (n > DATASIZE) - n = DATASIZE; - cmd = scsicmd(c->dev, 0x08, n); - if (waserror()) { - qunlock(cmd); - nexterror(); - } - cmd->cmdblk[1] = lbn>>16; - cmd->cmdblk[2] = lbn>>8; - cmd->cmdblk[3] = lbn; - cmd->cmdblk[4] = n/d->blocksize; - scsiexec(cmd, 1); - n = cmd->data.ptr - cmd->data.base; - memmove(a, cmd->data.base, n); - qunlock(cmd); - poperror(); - break; - case Qstruct: - if (n < 2*sizeof(ulong)) - error(Ebadarg); - if (offset >= 2*sizeof(ulong)) - return 0; - n = 2*sizeof(ulong); - wrenint((uchar*)a, p->maxblock - p->firstblock); - wrenint((uchar*)a+sizeof(ulong), d->blocksize); - break; - default: - panic("wrenread"); - } - return n; + return devdirread(c, a, n, 0, 0, wrengen); + + d = &wren[DRIVE(c->qid.path)]; + p = &d->p[PART(c->qid.path)]; + return wrenio(d, p, 0, a, n, offset); } long wrenwrite(Chan *c, char *a, long n, ulong offset) +{ + Drive *d; + Partition *p; + + d = &wren[DRIVE(c->qid.path)]; + p = &d->p[PART(c->qid.path)]; + return wrenio(d, p, 1, a, n, offset); +} + +static long +wrenio(Drive *d, Partition *p, int write, char *a, ulong n, ulong offset) { Scsi *cmd; - ulong lbn; - Part *p; - Disk *d; + void *b; + ulong block; - if (n == 0) + if(n % d->bytes || offset % d->bytes) + error(Ebadarg); + block = offset / d->bytes + p->start; + if(block >= p->end) return 0; - - d = &wren[c->dev]; - p = &(d->p[Mask&c->qid.path]); - switch ((int)(c->qid.path & ~Mask)) { - case Qdata: - if (n % d->blocksize || offset % d->blocksize) - error(Ebadarg); - lbn = offset/d->blocksize + p->firstblock; - if (lbn >= p->maxblock) - error(Ebadarg); - if (n > DATASIZE) - n = DATASIZE; - cmd = scsicmd(c->dev, 0x0a, n); - if (waserror()) { - qunlock(cmd); - nexterror(); - } - cmd->cmdblk[1] = lbn>>16; - cmd->cmdblk[2] = lbn>>8; - cmd->cmdblk[3] = lbn; - cmd->cmdblk[4] = n/d->blocksize; - memmove(cmd->data.base, a, n); - scsiexec(cmd, 0); - n = cmd->data.ptr - cmd->data.base; + if(n > DATASIZE) + n = DATASIZE; + n /= d->bytes; + if(block + n > p->end) + n = p->end - block; + if(n == 0) + return 0; + if(write) + cmd = scsicmd(d->drive, 0x0a, n*d->bytes); + else + cmd = scsicmd(d->drive, 0x08, n*d->bytes); + if(waserror()){ qunlock(cmd); - poperror(); - break; - default: - panic("wrenwrite"); + nexterror(); } + cmd->cmdblk[1] = block>>16; + cmd->cmdblk[2] = block>>8; + cmd->cmdblk[3] = block; + cmd->cmdblk[4] = n; + if(write) + memmove(cmd->data.base, a, n*d->bytes); + scsiexec(cmd, !write); + n = cmd->data.ptr - cmd->data.base; + if(!write) + memmove(a, cmd->data.base, n); + qunlock(cmd); + poperror(); return n; } -void -wrenremove(Chan *c) -{ - error(Eperm); -} - -void -wrenwstat(Chan *c, char *dp) +/* + * read partition table. The partition table is just ascii strings. + */ +#define MAGIC "plan9 partitions" +static void +wrenpart(int dev) { - error(Eperm); -} + Scsi *cmd; + Drive *dp; + Partition *pp; + uchar buf[32]; + char *b; + char *line[Npart+1]; + char *field[3]; + ulong n; + int i; -void -wrenint(uchar *a, ulong x) -{ - a[0] = x >> 24; - a[1] = x >> 16; - a[2] = x >> 8; - a[3] = x; + scsiready(dev); + scsisense(dev, buf); + scsicap(dev, buf); + dp = &wren[dev]; + dp->drive = dev; + if(dp->npart) + return; + /* + * we always have a partition for the whole disk + * and one for the partition table + */ + dp->bytes = (buf[4]<<24)+(buf[5]<<16)+(buf[6]<<8)+(buf[7]); + pp = &dp->p[0]; + strcpy(pp->name, "disk"); + pp->start = 0; + pp->end = (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]) + 1; + pp++; + strcpy(pp->name, "partition"); + pp->start = dp->p[0].end - 1; + pp->end = dp->p[0].end; + dp->npart = 2; + + /* + * read partition table from disk, null terminate + */ + cmd = scsicmd(dev, 0x08, dp->bytes); + if(waserror()){ + qunlock(cmd); + nexterror(); + } + n = dp->p[0].end-1; + cmd->cmdblk[1] = n>>16; + cmd->cmdblk[2] = n>>8; + cmd->cmdblk[3] = n; + cmd->cmdblk[4] = 1; + scsiexec(cmd, 1); + cmd->data.base[dp->bytes-1] = 0; + + /* + * parse partition table. + */ + n = getfields((char *)cmd->data.base, line, Npart+1, '\n'); + if(strncmp(line[0], MAGIC, sizeof(MAGIC)-1) != 0) + goto out; + for(i = 1; i < n; i++){ + pp++; + if(getfields(line[i], field, 3, ' ') != 3){ + break; + } + strncpy(pp->name, field[0], NAMELEN); + pp->start = strtoul(field[1], 0, 0); + pp->end = strtoul(field[2], 0, 0); + if(pp->start > pp->end || pp->start >= dp->p[0].end){ + break; + } + dp->npart++; + } +out: + qunlock(cmd); + poperror(); }