| #include "a.h" | 
 |  | 
 | void | 
 | lbkick(Logbuf *lb) | 
 | { | 
 | 	char *s; | 
 | 	int n; | 
 | 	Req *r; | 
 |  | 
 | 	while(lb->wait && lb->rp != lb->wp){ | 
 | 		r = lb->wait; | 
 | 		lb->wait = r->aux; | 
 | 		if(lb->wait == nil) | 
 | 			lb->waitlast = &lb->wait; | 
 | 		r->aux = nil; | 
 | 		if(r->ifcall.count < 5){ | 
 | 			respond(r, "log read request count too short"); | 
 | 			continue; | 
 | 		} | 
 | 		s = lb->msg[lb->rp]; | 
 | 		lb->msg[lb->rp] = nil; | 
 | 		if(++lb->rp == nelem(lb->msg)) | 
 | 			lb->rp = 0; | 
 | 		n = r->ifcall.count; | 
 | 		if(n < strlen(s)+1+1){ | 
 | 			memmove(r->ofcall.data, s, n-5); | 
 | 			n -= 5; | 
 | 			r->ofcall.data[n] = '\0'; | 
 | 			/* look for first byte of UTF-8 sequence by skipping continuation bytes */ | 
 | 			while(n>0 && (r->ofcall.data[--n]&0xC0)==0x80) | 
 | 				; | 
 | 			strcpy(r->ofcall.data+n, "...\n"); | 
 | 		}else{ | 
 | 			strcpy(r->ofcall.data, s); | 
 | 			strcat(r->ofcall.data, "\n"); | 
 | 		} | 
 | 		r->ofcall.count = strlen(r->ofcall.data); | 
 | 		free(s); | 
 | 		respond(r, nil); | 
 | 	} | 
 | } | 
 |  | 
 | void | 
 | lbread(Logbuf *lb, Req *r) | 
 | { | 
 | 	if(lb->waitlast == nil) | 
 | 		lb->waitlast = &lb->wait; | 
 | 	*lb->waitlast = r; | 
 | 	lb->waitlast = (Req**)(void*)&r->aux; | 
 | 	r->aux = nil; | 
 | 	lbkick(lb); | 
 | } | 
 |  | 
 | void | 
 | lbflush(Logbuf *lb, Req *r) | 
 | { | 
 | 	Req **l; | 
 |  | 
 | 	for(l=&lb->wait; *l; l=(Req**)(void*)&(*l)->aux){ | 
 | 		if(*l == r){ | 
 | 			*l = r->aux; | 
 | 			r->aux = nil; | 
 | 			if(*l == nil) | 
 | 				lb->waitlast = l; | 
 | 			respond(r, "interrupted"); | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | void | 
 | lbappend(Logbuf *lb, char *fmt, ...) | 
 | { | 
 | 	va_list arg; | 
 |  | 
 | 	va_start(arg, fmt); | 
 | 	lbvappend(lb, fmt, arg); | 
 | 	va_end(arg); | 
 | } | 
 |  | 
 | void | 
 | lbvappend(Logbuf *lb, char *fmt, va_list arg) | 
 | { | 
 | 	char *s; | 
 |  | 
 | 	s = vsmprint(fmt, arg); | 
 | 	if(s == nil) | 
 | 		sysfatal("out of memory"); | 
 | 	if(lb->msg[lb->wp]) | 
 | 		free(lb->msg[lb->wp]); | 
 | 	lb->msg[lb->wp] = s; | 
 | 	if(++lb->wp == nelem(lb->msg)) | 
 | 		lb->wp = 0; | 
 | 	lbkick(lb); | 
 | } | 
 |  | 
 | Logbuf rpclogbuf; | 
 |  | 
 | void | 
 | rpclogread(Req *r) | 
 | { | 
 | 	lbread(&rpclogbuf, r); | 
 | } | 
 |  | 
 | void | 
 | rpclogflush(Req *r) | 
 | { | 
 | 	lbflush(&rpclogbuf, r); | 
 | } | 
 |  | 
 | void | 
 | rpclog(char *fmt, ...) | 
 | { | 
 | 	va_list arg; | 
 |  | 
 | 	va_start(arg, fmt); | 
 | 	lbvappend(&rpclogbuf, fmt, arg); | 
 | 	va_end(arg); | 
 | } | 
 |  |