Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <auth.h>
5 #include <fcall.h>
6 #include <draw.h>
7 #include <thread.h>
8 #include <mouse.h>
9 #include <keyboard.h>
11 typedef struct Graph Graph;
12 typedef struct Machine Machine;
14 enum
15 {
16 Ncolor = 6,
17 Ysqueeze = 2, /* vertical squeezing of label text */
18 Labspace = 2, /* room around label */
19 Dot = 2, /* height of dot */
20 Opwid = 5, /* strlen("add ") or strlen("drop ") */
21 Nlab = 3, /* max number of labels on y axis */
22 Lablen = 16, /* max length of label */
23 Lx = 4, /* label tick length */
25 STACK = 8192,
26 XSTACK = 32768,
27 };
29 enum
30 {
31 Vbattery,
32 Vcontext,
33 Vcpu,
34 Vether,
35 Vethererr,
36 Vetherin,
37 Vetherout,
38 Vfault,
39 Vfork,
40 Vidle,
41 Vintr,
42 Vload,
43 Vmem,
44 Vswap,
45 Vsys,
46 Vsyscall,
47 Vuser,
48 Nvalue,
49 };
51 char*
52 labels[Nvalue] =
53 {
54 "battery",
55 "context",
56 "cpu",
57 "ether",
58 "ethererr",
59 "etherin",
60 "etherout",
61 "fault",
62 "fork",
63 "idle",
64 "intr",
65 "load",
66 "mem",
67 "swap",
68 "sys",
69 "syscall",
70 "user",
71 };
73 struct Graph
74 {
75 int colindex;
76 Rectangle r;
77 int *data;
78 int ndata;
79 char *label;
80 int value;
81 void (*update)(Graph*, long, ulong);
82 Machine *mach;
83 int overflow;
84 Image *overtmp;
85 ulong vmax;
86 };
88 struct Machine
89 {
90 char *name;
91 int fd;
92 int pid;
93 int dead;
94 int absolute[Nvalue];
95 ulong last[Nvalue];
96 ulong val[Nvalue][2];
97 ulong load;
98 ulong nload;
99 };
101 char *menu2str[Nvalue+1];
102 char xmenu2str[Nvalue+1][40];
104 Menu menu2 = {menu2str, 0};
105 int present[Nvalue];
106 Image *cols[Ncolor][3];
107 Graph *graph;
108 Machine *mach;
109 Font *mediumfont;
110 char *mysysname;
111 char argchars[] = "bceEfiIlmnsw";
112 int pids[1024];
113 int parity; /* toggled to avoid patterns in textured background */
114 int nmach;
115 int ngraph; /* totaly number is ngraph*nmach */
116 double scale = 1.0;
117 int logscale = 0;
118 int ylabels = 0;
119 int oldsystem = 0;
120 int sleeptime = 1000;
121 int changedvmax;
123 Mousectl *mc;
124 Keyboardctl *kc;
126 void
127 killall(char *s)
129 int i;
131 for(i=0; i<nmach; i++)
132 if(mach[i].pid)
133 postnote(PNPROC, mach[i].pid, "kill");
134 threadexitsall(s);
137 void*
138 emalloc(ulong sz)
140 void *v;
141 v = malloc(sz);
142 if(v == nil) {
143 fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
144 killall("mem");
146 memset(v, 0, sz);
147 return v;
150 void*
151 erealloc(void *v, ulong sz)
153 v = realloc(v, sz);
154 if(v == nil) {
155 fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
156 killall("mem");
158 return v;
161 char*
162 estrdup(char *s)
164 char *t;
165 if((t = strdup(s)) == nil) {
166 fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
167 killall("mem");
169 return t;
172 void
173 mkcol(int i, int c0, int c1, int c2)
175 cols[i][0] = allocimagemix(display, c0, DWhite);
176 cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
177 cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
180 void
181 colinit(void)
183 mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
184 if(mediumfont == nil)
185 mediumfont = font;
187 /* Peach */
188 mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
189 /* Aqua */
190 mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
191 /* Yellow */
192 mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
193 /* Green */
194 mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
195 /* Blue */
196 mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
197 /* Grey */
198 cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
199 cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
200 cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
203 void
204 label(Point p, int dy, char *text)
206 char *s;
207 Rune r[2];
208 int w, maxw, maxy;
210 p.x += Labspace;
211 maxy = p.y+dy;
212 maxw = 0;
213 r[1] = '\0';
214 for(s=text; *s; ){
215 if(p.y+mediumfont->height-Ysqueeze > maxy)
216 break;
217 w = chartorune(r, s);
218 s += w;
219 w = runestringwidth(mediumfont, r);
220 if(w > maxw)
221 maxw = w;
222 runestring(screen, p, display->black, ZP, mediumfont, r);
223 p.y += mediumfont->height-Ysqueeze;
227 Point
228 paritypt(int x)
230 return Pt(x+parity, 0);
233 Point
234 datapoint(Graph *g, int x, ulong v, ulong vmax)
236 Point p;
237 double y;
239 p.x = x;
240 y = ((double)v)/(vmax*scale);
241 if(logscale){
242 /*
243 * Arrange scale to cover a factor of 1000.
244 * vmax corresponds to the 100 mark.
245 * 10*vmax is the top of the scale.
246 */
247 if(y <= 0.)
248 y = 0;
249 else{
250 y = log10(y);
251 /* 1 now corresponds to the top; -2 to the bottom; rescale */
252 y = (y+2.)/3.;
255 p.y = g->r.max.y - Dy(g->r)*y - Dot;
256 if(p.y < g->r.min.y)
257 p.y = g->r.min.y;
258 if(p.y > g->r.max.y-Dot)
259 p.y = g->r.max.y-Dot;
260 return p;
263 void
264 drawdatum(Graph *g, int x, ulong prev, ulong v, ulong vmax)
266 int c;
267 Point p, q;
269 c = g->colindex;
270 p = datapoint(g, x, v, vmax);
271 q = datapoint(g, x, prev, vmax);
272 if(p.y < q.y){
273 draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
274 draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
275 draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
276 }else{
277 draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
278 draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
279 draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
284 void
285 redraw(Graph *g, int vmax)
287 int i, c;
289 if(vmax != g->vmax){
290 g->vmax = vmax;
291 changedvmax = 1;
293 c = g->colindex;
294 draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
295 for(i=1; i<Dx(g->r); i++)
296 drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
297 drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
298 g->overflow = 0;
301 void
302 update1(Graph *g, long v, ulong vmax)
304 char buf[32];
305 int overflow;
307 if(v < 0)
308 v = 0;
309 if(vmax != g->vmax){
310 g->vmax = vmax;
311 changedvmax = 1;
313 if(g->overflow && g->overtmp!=nil)
314 draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
315 draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
316 drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
317 memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
318 g->data[0] = v;
319 g->overflow = 0;
320 if(logscale)
321 overflow = (v>10*vmax*scale);
322 else
323 overflow = (v>vmax*scale);
324 if(overflow && g->overtmp!=nil){
325 g->overflow = 1;
326 draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
327 sprint(buf, "%ld", v);
328 string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
332 void
333 usage(void)
335 fprint(2, "usage: stats [-O] [-S scale] [-LY] [-W winsize] [-%s] [machine...]\n", argchars);
336 threadexitsall("usage");
339 void
340 addgraph(int n)
342 Graph *g, *ograph;
343 int i, j;
344 static int nadd;
346 if(n > Nvalue)
347 abort();
348 /* avoid two adjacent graphs of same color */
349 if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
350 nadd++;
351 ograph = graph;
352 graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
353 for(i=0; i<nmach; i++)
354 for(j=0; j<ngraph; j++)
355 graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
356 free(ograph);
357 ngraph++;
358 for(i=0; i<nmach; i++){
359 g = &graph[i*ngraph+(ngraph-1)];
360 memset(g, 0, sizeof(Graph));
361 g->value = n;
362 g->label = menu2str[n]+Opwid;
363 g->update = update1; /* no other update functions yet */
364 g->mach = &mach[i];
365 g->colindex = nadd%Ncolor;
367 present[n] = 1;
368 nadd++;
371 void
372 dropgraph(int which)
374 Graph *ograph;
375 int i, j, n;
377 if(which > nelem(menu2str))
378 abort();
379 /* convert n to index in graph table */
380 n = -1;
381 for(i=0; i<ngraph; i++)
382 if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
383 n = i;
384 break;
386 if(n < 0){
387 fprint(2, "stats: internal error can't drop graph\n");
388 killall("error");
390 ograph = graph;
391 graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
392 for(i=0; i<nmach; i++){
393 for(j=0; j<n; j++)
394 graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
395 free(ograph[i*ngraph+j].data);
396 freeimage(ograph[i*ngraph+j].overtmp);
397 for(j++; j<ngraph; j++)
398 graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
400 free(ograph);
401 ngraph--;
402 present[which] = 0;
405 int initmach(Machine*, char*);
407 int
408 addmachine(char *name)
410 if(ngraph > 0){
411 fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
412 usage();
414 if(mach == nil)
415 nmach = 0; /* a little dance to get us started with local machine by default */
416 mach = erealloc(mach, (nmach+1)*sizeof(Machine));
417 memset(mach+nmach, 0, sizeof(Machine));
418 if (initmach(mach+nmach, name)){
419 nmach++;
420 return 1;
421 } else
422 return 0;
425 void
426 newvalue(Machine *m, int i, ulong *v, ulong *vmax)
428 ulong now;
430 if(m->last[i] == 0)
431 m->last[i] = m->val[i][0];
433 if(i == Vload){
434 /*
435 * Invert the ewma to obtain the 5s load statistics.
436 * Ewma is load' = (1884/2048)*load + (164/2048)*last5s, so we do
437 * last5s = (load' - (1884/2048)*load) / (164/2048).
438 */
439 if(++m->nload%5 == 0){
440 now = m->val[i][0];
441 m->load = (now - (((vlong)m->last[i]*1884)/2048)) * 2048 / 164;
442 m->last[i] = now;
444 *v = m->load;
445 *vmax = m->val[i][1];
446 }else if(m->absolute[i]){
447 *v = m->val[i][0];
448 *vmax = m->val[i][1];
449 }else{
450 now = m->val[i][0];
451 *v = (vlong)((now - m->last[i])*sleeptime)/1000;
452 m->last[i] = now;
453 *vmax = m->val[i][1];
455 if(*vmax == 0)
456 *vmax = 1;
459 void
460 labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
462 int j;
463 ulong vmax;
465 vmax = g->vmax;
466 if(logscale){
467 for(j=1; j<=2; j++)
468 sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
469 *np = 2;
470 }else{
471 for(j=1; j<=3; j++)
472 sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
473 *np = 3;
477 int
478 labelwidth(void)
480 int i, j, n, w, maxw;
481 char strs[Nlab][Lablen];
483 maxw = 0;
484 for(i=0; i<ngraph; i++){
485 /* choose value for rightmost graph */
486 labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
487 for(j=0; j<n; j++){
488 w = stringwidth(mediumfont, strs[j]);
489 if(w > maxw)
490 maxw = w;
493 return maxw;
496 void
497 resize(void)
499 int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
500 Graph *g;
501 Rectangle machr, r;
502 ulong v, vmax;
503 char buf[128], labs[Nlab][Lablen];
505 draw(screen, screen->r, display->white, nil, ZP);
507 /* label left edge */
508 x = screen->r.min.x;
509 y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
510 dy = (screen->r.max.y - y)/ngraph;
511 dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
512 startx = x+dx+1;
513 starty = y;
514 for(i=0; i<ngraph; i++,y+=dy){
515 draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
516 draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
517 label(Pt(x, y), dy, graph[i].label);
518 draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
521 /* label top edge */
522 dx = (screen->r.max.x - startx)/nmach;
523 for(x=startx, i=0; i<nmach; i++,x+=dx){
524 draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
525 j = dx/stringwidth(mediumfont, "0");
526 // n = mach[i].nproc;
527 n = 1;
528 if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */
529 j -= 3+(n>10)+(n>100);
530 if(j <= 0)
531 j = 1;
532 snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
533 }else
534 snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
535 string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
538 maxx = screen->r.max.x;
540 /* label right, if requested */
541 if(ylabels && dy>Nlab*(mediumfont->height+1)){
542 wid = labelwidth();
543 if(wid < (maxx-startx)-30){
544 /* else there's not enough room */
545 maxx -= 1+Lx+wid;
546 draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
547 y = starty;
548 for(j=0; j<ngraph; j++, y+=dy){
549 /* choose value for rightmost graph */
550 g = &graph[ngraph*(nmach-1)+j];
551 labelstrs(g, labs, &nlab);
552 r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
553 if(j == ngraph-1)
554 r.max.y = screen->r.max.y;
555 draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
556 for(k=0; k<nlab; k++){
557 ly = y + (dy*(nlab-k)/(nlab+1));
558 draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
559 ly -= mediumfont->height/2;
560 string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, mediumfont, labs[k]);
566 /* create graphs */
567 for(i=0; i<nmach; i++){
568 machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
569 if(i < nmach-1)
570 machr.max.x = startx+(i+1)*dx - 1;
571 y = starty;
572 for(j=0; j<ngraph; j++, y+=dy){
573 g = &graph[i*ngraph+j];
574 /* allocate data */
575 ondata = g->ndata;
576 g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */
577 g->data = erealloc(g->data, g->ndata*sizeof(ulong));
578 if(g->ndata > ondata)
579 memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(ulong));
580 /* set geometry */
581 g->r = machr;
582 g->r.min.y = y;
583 g->r.max.y = y+dy - 1;
584 if(j == ngraph-1)
585 g->r.max.y = screen->r.max.y;
586 draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
587 g->overflow = 0;
588 r = g->r;
589 r.max.y = r.min.y+mediumfont->height;
590 r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
591 freeimage(g->overtmp);
592 g->overtmp = nil;
593 if(r.max.x <= g->r.max.x)
594 g->overtmp = allocimage(display, r, screen->chan, 0, -1);
595 newvalue(g->mach, g->value, &v, &vmax);
596 redraw(g, vmax);
600 flushimage(display, 1);
603 void
604 eresized(int new)
606 lockdisplay(display);
607 if(new && getwindow(display, Refnone) < 0) {
608 fprint(2, "stats: can't reattach to window\n");
609 killall("reattach");
611 resize();
612 unlockdisplay(display);
615 void
616 mousethread(void *v)
618 Mouse m;
619 int i;
621 USED(v);
623 while(readmouse(mc) == 0){
624 m = mc->m;
625 if(m.buttons == 4){
626 for(i=0; i<Nvalue; i++)
627 if(present[i])
628 memmove(menu2str[i], "drop ", Opwid);
629 else
630 memmove(menu2str[i], "add ", Opwid);
631 lockdisplay(display);
632 i = menuhit(3, mc, &menu2, nil);
633 if(i >= 0){
634 if(!present[i])
635 addgraph(i);
636 else if(ngraph > 1)
637 dropgraph(i);
638 resize();
640 unlockdisplay(display);
645 void
646 resizethread(void *v)
648 USED(v);
650 while(recv(mc->resizec, 0) == 1){
651 lockdisplay(display);
652 if(getwindow(display, Refnone) < 0)
653 sysfatal("attach to window: %r");
654 resize();
655 unlockdisplay(display);
659 void
660 keyboardthread(void *v)
662 Rune r;
664 while(recv(kc->c, &r) == 1)
665 if(r == 0x7F || r == 'q')
666 killall("quit");
669 void machproc(void*);
670 void updateproc(void*);
672 void
673 threadmain(int argc, char *argv[])
675 int i, j;
676 char *s;
677 ulong nargs;
678 char args[100];
680 nmach = 1;
681 mysysname = sysname();
682 if(mysysname == nil){
683 fprint(2, "stats: can't find sysname: %r\n");
684 threadexitsall("sysname");
687 nargs = 0;
688 ARGBEGIN{
689 case 'T':
690 s = ARGF();
691 if(s == nil)
692 usage();
693 i = atoi(s);
694 if(i > 0)
695 sleeptime = 1000*i;
696 break;
697 case 'S':
698 s = ARGF();
699 if(s == nil)
700 usage();
701 scale = atof(s);
702 if(scale <= 0.)
703 usage();
704 break;
705 case 'L':
706 logscale++;
707 break;
708 case 'Y':
709 ylabels++;
710 break;
711 case 'O':
712 oldsystem = 1;
713 break;
714 case 'W':
715 winsize = EARGF(usage());
716 break;
717 default:
718 if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
719 usage();
720 args[nargs++] = ARGC();
721 }ARGEND
723 for(i=0; i<Nvalue; i++){
724 menu2str[i] = xmenu2str[i];
725 snprint(xmenu2str[i], sizeof xmenu2str[i], "add %s", labels[i]);
728 if(argc == 0){
729 mach = emalloc(nmach*sizeof(Machine));
730 initmach(&mach[0], mysysname);
731 }else{
732 for(i=j=0; i<argc; i++)
733 addmachine(argv[i]);
736 for(i=0; i<nmach; i++)
737 proccreate(machproc, &mach[i], STACK);
739 for(i=0; i<nargs; i++)
740 switch(args[i]){
741 default:
742 fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
743 usage();
744 case 'b':
745 addgraph(Vbattery);
746 break;
747 case 'c':
748 addgraph(Vcontext);
749 break;
750 case 'C':
751 addgraph(Vcpu);
752 break;
753 case 'e':
754 addgraph(Vether);
755 break;
756 case 'E':
757 addgraph(Vetherin);
758 addgraph(Vetherout);
759 break;
760 case 'f':
761 addgraph(Vfault);
762 break;
763 case 'i':
764 addgraph(Vintr);
765 break;
766 case 'I':
767 addgraph(Vload);
768 addgraph(Vidle);
769 break;
770 case 'l':
771 addgraph(Vload);
772 break;
773 case 'm':
774 addgraph(Vmem);
775 break;
776 case 'n':
777 addgraph(Vetherin);
778 addgraph(Vetherout);
779 addgraph(Vethererr);
780 break;
781 case 's':
782 addgraph(Vsyscall);
783 break;
784 case 'w':
785 addgraph(Vswap);
786 break;
789 if(ngraph == 0)
790 addgraph(Vload);
792 for(i=0; i<nmach; i++)
793 for(j=0; j<ngraph; j++)
794 graph[i*ngraph+j].mach = &mach[i];
796 if(initdraw(0, nil, "stats") < 0)
797 sysfatal("initdraw: %r");
798 colinit();
799 if((mc = initmouse(nil, screen)) == nil)
800 sysfatal("initmouse: %r");
801 if((kc = initkeyboard(nil)) == nil)
802 sysfatal("initkeyboard: %r");
804 display->locking = 1;
805 threadcreate(keyboardthread, nil, XSTACK);
806 threadcreate(mousethread, nil, XSTACK);
807 threadcreate(resizethread, nil, XSTACK);
808 proccreate(updateproc, nil, XSTACK);
809 resize();
810 unlockdisplay(display);
813 void
814 updateproc(void *z)
816 int i;
817 ulong v, vmax;
819 USED(z);
820 for(;;){
821 parity = 1-parity;
822 lockdisplay(display);
823 for(i=0; i<nmach*ngraph; i++){
824 newvalue(graph[i].mach, graph[i].value, &v, &vmax);
825 graph[i].update(&graph[i], v, vmax);
827 if(changedvmax){
828 changedvmax = 0;
829 resize();
831 flushimage(display, 1);
832 unlockdisplay(display);
833 sleep(sleeptime);
837 void
838 machproc(void *v)
840 char buf[256], *f[4], *p;
841 int i, n, t;
842 Machine *m;
844 m = v;
845 t = 0;
846 for(;;){
847 n = read(m->fd, buf+t, sizeof buf-t);
848 m->dead = 0;
849 if(n <= 0)
850 break;
851 t += n;
852 while((p = memchr(buf, '\n', t)) != nil){
853 *p++ = 0;
854 n = tokenize(buf, f, nelem(f));
855 if(n >= 3){
856 for(i=0; i<Nvalue; i++){
857 if(strcmp(labels[i], f[0]) == 0){
858 if(*f[1] == '='){
859 m->absolute[i] = 1;
860 f[1]++;
862 m->val[i][0] = strtoul(f[1], 0, 0);
863 m->val[i][1] = strtoul(f[2], 0, 0);
867 t -= (p-buf);
868 memmove(buf, p, t);
871 if(m->fd){
872 close(m->fd);
873 m->fd = -1;
875 if(m->pid){
876 postnote(PNPROC, m->pid, "kill");
877 m->pid = 0;
881 int
882 initmach(Machine *m, char *name)
884 char *args[5], *q;
885 int p[2], kfd[3], pid;
887 m->name = name;
888 if(strcmp(name, mysysname) == 0)
889 name = nil;
891 if(pipe(p) < 0)
892 sysfatal("pipe: %r");
894 memset(args, 0, sizeof args);
895 args[0] = "auxstats";
896 if(name){
897 args[1] = name;
898 if((q = strchr(name, ':')) != nil){
899 *q++ = 0;
900 args[2] = q;
903 kfd[0] = open("/dev/null", OREAD);
904 kfd[1] = p[1];
905 kfd[2] = dup(2, -1);
906 if((pid = threadspawn(kfd, "auxstats", args)) < 0){
907 fprint(2, "spawn: %r\n");
908 close(kfd[0]);
909 close(p[0]);
910 close(p[1]);
911 return 0;
913 m->fd = p[0];
914 m->pid = pid;
915 if((q = strchr(m->name, '.')) != nil)
916 *q = 0;
917 return 1;