xref: /onnv-gate/usr/src/cmd/wbem/provider/tools/rds/rdprot.c (revision 6152:60a422e88ea9)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <search.h>
30 #include <stdlib.h>
31 
32 #include <sys/utsname.h>
33 #include "rdprot.h"
34 #include "rdutil.h"
35 /*
36  * This file works out the protocol layer of the bidirectional data interface
37  * between the rds and the client. In the server mode rds writes greetings and
38  * a protocol header to the output stream.
39  * pheader  == { "@RDS-MAG@"  PROTV }
40  * PROTV    == { protocol version }
41  * Then it sends a prompt and waits for command from client.
42  * PROMPT   == { "@RDS@>" }
43  * COMMAND  == { "command"  cmd }
44  * cmd	    == { "-pUuJjS" | "-p" | "-u" | "-U" |
45  *		 "-j" | "-J" | "-S" | "-i100" | "alive"| "exit" }
46  * The answer from rds is always a lists of data. The header of the answer data
47  * contains the number of lists in the package. Each list has a header and
48  * some elements, which have again a header and some fields of data:
49  * answer   == { lshead,  n * list }
50  * lshead   == { number of lists }
51  * list     == { lheader, n * element }
52  * lheader  == { LISTT, ELEMN }
53  * LISTT    == { type of the list }
54  * ELEMN    == { number of elements in the list }
55  * element  == { eheader, field }
56  * eheader  == { ELMID, FILDN }
57  * ELMID    == { element id, like pid, uid, project name }
58  * field    == { KEY, VALUE }
59  * All protocol elements have a key and a value separated by one space.
60  * The value begins after the first space and ends with the new line character.
61  * Protocol keys are: "@RDS-MAG@", PROTV, LISTN,  LISTT, ELEMN ELMID, FILDN,
62  * RDERR. The special key RDERR can occur in any line and indicates that an
63  * error condition occurred, where the VALUE is the error message.
64  */
65 
66 static char line[P_MAXLEN];
67 static char error[P_MAXLEN];
68 static char value[P_MAXVAL];
69 static char key[P_MAXKEY];
70 
71 static char *nullstr = "";
72 static FILE *wstream, *rstream;
73 
74 static int format_int64(int, char *, char *, int);
75 static int format_int32(int, char *, char *, int);
76 static int format_ulong(int, char *, char *, int);
77 static int format_float(int, char *, char *, int);
78 static int format_double(int, char *, char *, int);
79 static int format_string(int, char *, char *, int);
80 static int format_timestruc(int, char *, char *, int);
81 
82 /*
83  * The kv_pair_t represents an field in a  c-sturcture. An filed
84  * is defined by a key 'field name', format function and an offset
85  * in this structure
86  */
87 
88 /*
89  * Array of fields from id_info_t structure, that are sent/received
90  * in a process/user/project utilization list.
91  */
92 static kv_pair_t id_stub[] =
93 {
94 { "id_pid",	{ format_int32, offsetof(id_info_t, id_pid) }},
95 { "id_uid",	{ format_int32, offsetof(id_info_t, id_uid) }},
96 { "id_projid",	{ format_int32, offsetof(id_info_t, id_projid) }},
97 { "id_usr", 	{ format_double, offsetof(id_info_t, id_usr) }},
98 { "id_sys", 	{ format_double, offsetof(id_info_t, id_sys) }},
99 { "id_ttime", 	{ format_double, offsetof(id_info_t, id_ttime) }},
100 { "id_tpftime", { format_double, offsetof(id_info_t, id_tpftime) }},
101 { "id_dpftime", { format_double, offsetof(id_info_t, id_dpftime) }},
102 { "id_kpftime", { format_double, offsetof(id_info_t, id_kpftime) }},
103 { "id_lck", 	{ format_double, offsetof(id_info_t, id_lck) }},
104 { "id_slp", 	{ format_double, offsetof(id_info_t, id_slp) }},
105 { "id_lat", 	{ format_double, offsetof(id_info_t, id_lat) }},
106 { "id_stime", 	{ format_double, offsetof(id_info_t, id_stime) }},
107 { "id_minf", 	{ format_int64, offsetof(id_info_t, id_minf) }},
108 { "id_majf", 	{ format_int64, offsetof(id_info_t, id_majf) }},
109 { "id_nswap", 	{ format_int64, offsetof(id_info_t, id_nswap) }},
110 { "id_inblk", 	{ format_int64, offsetof(id_info_t, id_inblk) }},
111 { "id_oublk", 	{ format_int64, offsetof(id_info_t, id_oublk) }},
112 { "id_msnd", 	{ format_int64, offsetof(id_info_t, id_msnd) }},
113 { "id_mrcv", 	{ format_int64, offsetof(id_info_t, id_mrcv) }},
114 { "id_sigs", 	{ format_int64, offsetof(id_info_t, id_sigs) }},
115 { "id_vctx", 	{ format_int64, offsetof(id_info_t, id_vctx) }},
116 { "id_ictx", 	{ format_int64, offsetof(id_info_t, id_ictx) }},
117 { "id_scl", 	{ format_int64, offsetof(id_info_t, id_scl) }},
118 { "id_ioch", 	{ format_int64, offsetof(id_info_t, id_ioch) }},
119 { "id_hpsize", 	{ format_int64, offsetof(id_info_t, id_hpsize) }},
120 { "id_size", 	{ format_int64, offsetof(id_info_t, id_size) }},
121 { "id_rssize", 	{ format_int64, offsetof(id_info_t, id_rssize) }},
122 { "id_pctcpu", 	{ format_float, offsetof(id_info_t, id_pctcpu) }},
123 { "id_pctmem", 	{ format_float, offsetof(id_info_t, id_pctmem) }},
124 { "id_time", 	{ format_int64, offsetof(id_info_t, id_time) }},
125 { "id_nlwps", 	{ format_int32, offsetof(id_info_t, id_nlwps) }},
126 { "id_timestamp", { format_int64, offsetof(id_info_t, id_timestamp) }},
127 { "id_nproc", 	{ format_int32, offsetof(id_info_t, id_nproc) }},
128 { "id_inpkg", 	{ format_int64, offsetof(id_info_t, id_inpkg) }},
129 { "id_oupkg", 	{ format_int64, offsetof(id_info_t, id_oupkg) }},
130 { "id_name", 	{ format_string, offsetof(id_info_t, id_name) }}
131 };
132 
133 static kv_pair_t lwp_stub[] =
134 {
135 {"li_usage",	{ format_ulong, offsetof(lwp_info_t, li_usr) }},
136 {"li_usr",	{ format_ulong, offsetof(lwp_info_t, li_usr) }},
137 {"li_sys",	{ format_ulong, offsetof(lwp_info_t, li_sys) }},
138 {"li_ttime",	{ format_ulong, offsetof(lwp_info_t, li_ttime) }},
139 {"li_tpftime",	{ format_ulong, offsetof(lwp_info_t, li_tpftime) }},
140 {"li_dpftime",	{ format_ulong, offsetof(lwp_info_t, li_dpftime) }},
141 {"li_kpftime",	{ format_ulong, offsetof(lwp_info_t, li_kpftime) }},
142 {"li_lck",	{ format_ulong, offsetof(lwp_info_t, li_lck) }},
143 {"li_slp",	{ format_ulong, offsetof(lwp_info_t, li_slp) }},
144 {"li_lat",	{ format_ulong, offsetof(lwp_info_t, li_lat) }},
145 {"li_stime",	{ format_ulong, offsetof(lwp_info_t, li_stime) }},
146 {"li_minf",	{ format_ulong, offsetof(lwp_info_t, li_minf) }},
147 {"li_majf",	{ format_ulong, offsetof(lwp_info_t, li_majf) }},
148 {"li_nswap",	{ format_ulong, offsetof(lwp_info_t, li_nswap) }},
149 {"li_inblk",	{ format_ulong, offsetof(lwp_info_t, li_inblk) }},
150 {"li_oublk",	{ format_ulong, offsetof(lwp_info_t, li_oublk) }},
151 {"li_msnd",	{ format_ulong, offsetof(lwp_info_t, li_msnd) }},
152 {"li_mrcv",	{ format_ulong, offsetof(lwp_info_t, li_mrcv) }},
153 {"li_sigs",	{ format_ulong, offsetof(lwp_info_t, li_sigs) }},
154 {"li_vctx",	{ format_ulong, offsetof(lwp_info_t, li_vctx) }},
155 {"li_ictx",	{ format_ulong, offsetof(lwp_info_t, li_ictx) }},
156 {"li_scl",	{ format_ulong, offsetof(lwp_info_t, li_scl) }},
157 {"li_ioch",	{ format_ulong, offsetof(lwp_info_t, li_ioch) }},
158 {"li_hpsize",	{ format_ulong, offsetof(lwp_info_t, li_hpsize) }},
159 {"li_timestamp", { format_ulong, offsetof(lwp_info_t, li_timestamp) }},
160 };
161 
162 static kv_pair_t lwpinfo_stub[] =
163 {
164 {"lwpr_pid",	{ format_int32, offsetof(lwpinfo_t, pr_pid) }},
165 {"lwpr_lwpid",	{ format_int32, offsetof(lwpinfo_t, pr_lwpid) }},
166 };
167 
168 static kv_pair_t prusage_stub[] =
169 {
170 {"pr_tstamp",	{ format_timestruc, offsetof(prusage_t, pr_tstamp) }},
171 {"pr_create",	{ format_timestruc, offsetof(prusage_t, pr_create) }},
172 {"pr_term",	{ format_timestruc, offsetof(prusage_t, pr_term) }},
173 {"pr_rtime",	{ format_timestruc, offsetof(prusage_t, pr_rtime) }},
174 {"pr_utime",	{ format_timestruc, offsetof(prusage_t, pr_utime) }},
175 {"pr_stime",	{ format_timestruc, offsetof(prusage_t, pr_stime) }},
176 {"pr_ttime",	{ format_timestruc, offsetof(prusage_t, pr_ttime) }},
177 {"pr_tftime",	{ format_timestruc, offsetof(prusage_t, pr_tftime) }},
178 {"pr_dftime",	{ format_timestruc, offsetof(prusage_t, pr_dftime) }},
179 {"pr_kftime",	{ format_timestruc, offsetof(prusage_t, pr_kftime) }},
180 {"pr_ltime",	{ format_timestruc, offsetof(prusage_t, pr_ltime) }},
181 {"pr_slptime",	{ format_timestruc, offsetof(prusage_t, pr_slptime) }},
182 {"pr_wtime",	{ format_timestruc, offsetof(prusage_t, pr_wtime) }},
183 {"pr_stoptime", { format_timestruc, offsetof(prusage_t, pr_stoptime) }},
184 {"pr_minf",	{ format_ulong, offsetof(prusage_t, pr_minf) }},
185 {"pr_majf",	{ format_ulong, offsetof(prusage_t, pr_majf) }},
186 {"pr_nswap",	{ format_ulong, offsetof(prusage_t, pr_nswap) }},
187 {"pr_inblk",	{ format_ulong, offsetof(prusage_t, pr_inblk) }},
188 {"pr_oublk",	{ format_ulong, offsetof(prusage_t, pr_oublk) }},
189 {"pr_msnd",	{ format_ulong, offsetof(prusage_t, pr_msnd) }},
190 {"pr_mrcv",	{ format_ulong, offsetof(prusage_t, pr_mrcv) }},
191 {"pr_sigs",	{ format_ulong, offsetof(prusage_t, pr_sigs) }},
192 {"pr_vctx",	{ format_ulong, offsetof(prusage_t, pr_vctx) }},
193 {"pr_ictx",	{ format_ulong, offsetof(prusage_t, pr_ictx) }},
194 {"pr_sysc",	{ format_ulong, offsetof(prusage_t, pr_sysc) }},
195 {"pr_ioch",	{ format_ulong, offsetof(prusage_t, pr_ioch) }},
196 };
197 
198 /*
199  * Array of fields in id_info_t structure, that are sent/received
200  * in an active user list.
201  */
202 static kv_pair_t usr_stub[] =
203 {
204 { "usr_id", 	{ format_int32, offsetof(id_info_t, id_uid) }},
205 { "usr_name", 	{ format_string, offsetof(id_info_t, id_name) }}
206 };
207 
208 /*
209  * Array of fields in id_info_t structure, that are sent/received
210  * in an active project list.
211  */
212 static kv_pair_t prj_stub[] =
213 {
214 { "prj_id", 	{ format_int32, offsetof(id_info_t, id_projid) }},
215 { "prj_name", 	{ format_string, offsetof(id_info_t, id_name)   }}
216 };
217 
218 /*
219  * Array of fields in id_info_t structure, that are sent/received
220  * in a system list.
221  */
222 static kv_pair_t sys_stub[] =
223 {
224 { "sys_nodename", { format_string, offsetof(sys_info_t, nodename) }},
225 { "sys_name",	{ format_string, offsetof(sys_info_t, name) }}
226 };
227 
228 /*
229  * Array of fields in id_info_t structure, that are sent/received
230  * in command.
231  */
232 static kv_pair_t cmd_stub[] =
233 {
234 { "command",	{ format_int32, offsetof(cmd_t, command) }}
235 };
236 
237 #define	stubsize(stub) ((sizeof (stub))/(sizeof (kv_pair_t)))
238 
239 /*
240  * Each list type has its own fields description, the list type is
241  * the index into this table:
242  * L_PRC_SI - processes statistical information
243  * L_USR_SI - useres statistical information
244  * L_PRJ_SI - projects statistical information
245  * L_AC_USR - active users
246  * L_AC_PRJ - active projects
247  * L_SYSTEM - system
248  */
249 #define	NOF_STUBS   10
250 static stub_t stubs[NOF_STUBS + 1] = {
251 { 0, NULL},
252 { stubsize(id_stub), id_stub},
253 { stubsize(id_stub), id_stub},
254 { stubsize(id_stub), id_stub},
255 { stubsize(usr_stub), usr_stub},
256 { stubsize(prj_stub), prj_stub},
257 { stubsize(sys_stub), sys_stub},
258 { stubsize(cmd_stub), cmd_stub},
259 { stubsize(lwp_stub), lwp_stub},
260 { stubsize(lwpinfo_stub), lwpinfo_stub},
261 { stubsize(prusage_stub), prusage_stub},
262 };
263 
264 /*
265  * read a protocol line, do some checks and extract its key
266  * and value part.
267  */
268 static int
r_line()269 r_line() {
270 	size_t len;
271 
272 	if (fgets(line, P_MAXLEN, rstream) == NULL) {
273 		format_err("can't read line");
274 		return (-1);
275 	}
276 	len = strlen(line);
277 	if (len > P_MAXLEN) {
278 		format_err("%s: \"%s\"", "wrong line length", line);
279 		return (-1);
280 	}
281 	/* carriage return */
282 	if (len == 1) {
283 		value[0] = line[0];
284 		return (0);
285 	}
286 	/* see P_MAXKEY and P_MAXVAL for string sizes */
287 	if (sscanf(line, "%19s %58s", key, value) != 2) {
288 		format_err("%s: \"%s\"", "wrong line format", line);
289 		return (-1);
290 	}
291 	if (strcmp(key, RDERR) == 0) {
292 		(void) strcpy(error, line + strlen(RDERR) + 1);
293 		return (-1);
294 	}
295 	return (0);
296 }
297 
298 #define	STRUCT_TO_STR	1
299 #define	STR_TO_STRUCT	2
300 
301 /*
302  * if STR_TO_STRUCT read a 64 bit value from string buffer, format it and
303  * write it into the structure.
304  * if STRUCT_TO_STR read a 64 bit value from structure and write it as
305  * a string into buffer.
306  */
307 static int
format_int64(int set,char * buf,char * strct,int off)308 format_int64(int set, char *buf, char *strct, int off)
309 {
310 	int64_t v;
311 
312 	if (set == STR_TO_STRUCT) {
313 		if (sscanf(buf, "%" SCNd64, &v) != 1) {
314 			format_err("%s: \"%s\"", "wrong line format", line);
315 			return (-1);
316 		}
317 		*(int64_t *)(void *)(strct + off) = v;
318 
319 	} else {
320 		v = *((int64_t *)(void *)(strct + off));
321 		(void) sprintf(buf, "%" PRId64, v);
322 
323 	}
324 	return (0);
325 }
326 
327 /*
328  * if STR_TO_STRUCT read a 32 bit value from string buffer, format it and
329  * write it into the structure.
330  * if STRUCT_TO_STR read a 32 bit value from structure and write it as
331  * a string into buffer.
332  */
333 static int
format_int32(int set,char * buf,char * id,int off)334 format_int32(int set, char *buf, char *id, int off)
335 {
336 	int32_t v;
337 
338 	if (set == STR_TO_STRUCT) {
339 		if (sscanf(buf, "%d", &v) != 1) {
340 			format_err("%s: \"%s\"", "wrong line format", line);
341 			return (-1);
342 		}
343 		*(int32_t *)(void *)(id + off) = v;
344 
345 	} else {
346 		v = *((int32_t *)(void *)(id + off));
347 		(void) sprintf(buf, "%d", v);
348 
349 	}
350 	return (0);
351 }
352 
353 /*
354  */
355 static int
format_ulong(int set,char * buf,char * id,int off)356 format_ulong(int set, char *buf, char *id, int off)
357 {
358 	ulong_t v;
359 
360 	if (set == STR_TO_STRUCT) {
361 		if (sscanf(buf, "%lu", &v) != 1) {
362 			format_err("%s: \"%s\"", "wrong line format", line);
363 			return (-1);
364 		}
365 		*(ulong_t *)(void *)(id + off) = v;
366 
367 	} else {
368 		v = *((ulong_t *)(void *)(id + off));
369 		(void) sprintf(buf, "%ld", v);
370 
371 	}
372 	return (0);
373 }
374 
375 /*
376  * if STR_TO_STRUCT read a float value from string buffer, format it and
377  * write it into the structure.
378  * if STRUCT_TO_STR read a float value from structure and write it as
379  * a string into buffer.
380  */
381 static int
format_float(int set,char * buf,char * id,int off)382 format_float(int set, char *buf, char *id, int off)
383 {
384 	float v;
385 
386 	if (set == STR_TO_STRUCT) {
387 		if (sscanf(buf, "%f", &v) != 1) {
388 			format_err("%s: \"%s\"", "wrong line format", line);
389 			return (-1);
390 		}
391 		*(float *)(void *)(id + off) = v;
392 
393 	} else {
394 		v = *((float *)(void *)(id + off));
395 		(void) sprintf(buf, "%f", v);
396 
397 	}
398 	return (0);
399 }
400 
401 /*
402  * if STR_TO_STRUCT read a double value from string buffer, format it and
403  * write it into the structure.
404  * if STRUCT_TO_STR read a double value from structure and write it as
405  * a string into buffer.
406  */
407 static int
format_double(int set,char * buf,char * id,int off)408 format_double(int set, char *buf, char *id, int off)
409 {
410 	double v;
411 
412 	if (set == STR_TO_STRUCT) {
413 		if (sscanf(buf, "%lf", &v) != 1) {
414 			format_err("wrong line format: \"%s\"", line);
415 			return (-1);
416 		}
417 		*(double *)(void *)(id + off) = v;
418 
419 	} else {
420 		v = *((double *)(void *)(id + off));
421 		(void) sprintf(buf, "%f", v);
422 
423 	}
424 	return (0);
425 }
426 
427 /*
428  * if STR_TO_STRUCT read a string from string buffer, format it and
429  * write it into the structure.
430  * if STRUCT_TO_STR read a string from structure and write it as
431  * a string into buffer.
432  */
433 static int
format_string(int set,char * buf,char * id,int off)434 format_string(int set, char *buf, char *id, int off)
435 {
436 	char *v;
437 
438 	if (set == STR_TO_STRUCT) {
439 		if ((v = (char *)malloc(strlen(buf) + 1))  != 0) {
440 			(void) strcpy(v, buf);
441 		} else {
442 			v = nullstr;
443 			return (-1);
444 		}
445 		*(char **)(void *)(id + off) = v;
446 	} else {
447 		if ((*((char **)(void *)(id + off))) != NULL) {
448 			(void) snprintf(buf, P_MAXVAL, "%s",
449 			    *((char **)(void *)(id + off)));
450 		}
451 	}
452 	return (0);
453 }
454 
455 static int
format_timestruc(int set,char * buf,char * strct,int off)456 format_timestruc(int set, char *buf, char *strct, int off)
457 {
458 	int64_t v1;
459 	int64_t v2;
460 
461 	if (set == STR_TO_STRUCT) {
462 		if (sscanf(buf, "%" SCNd64 ",%" SCNd64, &v1, &v2) != 2) {
463 			format_err("%s: \"%s\"", "wrong line format", line);
464 			return (-1);
465 		}
466 		((timestruc_t *)(void *)(strct + off))->tv_sec = v1;
467 		((timestruc_t *)(void *)(strct + off))->tv_nsec = v2;
468 
469 	} else {
470 		v1 = ((timestruc_t *)(void *)(strct + off))->tv_sec;
471 		/*
472 		 * Since the times in prusage start with millisecond
473 		 * precision after the micro state accounting was enabled
474 		 * discard the nano/micro second fraction in the saved
475 		 * values otherwise we will get negative values in next run.
476 		 */
477 		v2 = ((((timestruc_t *)(void *)(strct + off))->tv_nsec) /
478 			MICROSEC) * MICROSEC;
479 		(void) sprintf(buf, "%" PRId64 ",%" PRId64, v1, v2);
480 
481 	}
482 	return (0);
483 }
484 
485 /*
486  * A hash table of keys == names and data == { formats and offsets }.
487  */
488 static int
init_hashtab()489 init_hashtab() {
490 	ENTRY item;
491 	int   i, j, size = 0;
492 
493 	for (i = 0; i < NOF_STUBS + 1; i++) {
494 		size += stubs[i].size;
495 	}
496 	if (hcreate(size) == 0) {
497 		format_err("can't create hash table");
498 		return (-1);
499 	}
500 	for (i = 0; i < NOF_STUBS + 1; i++) {
501 		for (j = 0; j < stubs[i].size; j++) {
502 			item.key = stubs[i].stub[j].key;
503 			item.data = (void *) &(stubs[i].stub[j].info);
504 			if (hsearch(item, ENTER) == NULL) {
505 				format_err("can't insert into hash table");
506 				return (-1);
507 			}
508 		}
509 	}
510 	return (0);
511 }
512 
513 int
open_prot(int fd,char * rw)514 open_prot(int fd, char *rw)
515 {
516 	if (strcmp(rw, "r") == 0) {
517 		if ((rstream = fdopen(fd, rw)) == NULL) {
518 			format_err("can't open read stream");
519 			return (-1);
520 		}
521 		if (init_hashtab() != 0) {
522 			format_err("can't initialize hashtab");
523 			return (-1);
524 		}
525 	} else if (strcmp(rw, "w") == 0) {
526 		if ((wstream = fdopen(fd, rw)) == NULL) {
527 			format_err("can't open write stream");
528 			return (-1);
529 		}
530 	} else {
531 		format_err("open_prot(), wrong argument  %s", rw);
532 			return (-1);
533 	}
534 	return (0);
535 }
536 
537 void
close_prot()538 close_prot()
539 {
540 
541 	(void) fclose(rstream);
542 	(void) fclose(wstream);
543 	hdestroy();
544 }
545 
546 /*
547  * @RDS-MAG@
548  * PROTV 100
549  */
550 int
wr_phead()551 wr_phead()
552 {
553 	(void) fprintf(wstream, "%s\n%s %d\n",
554 	    PROTM, PROTV, PROT_VERSION);
555 	(void) fflush(wstream);
556 	return (0);
557 }
558 /*
559  * @RDS@> [code]
560  */
561 int
wr_prompt(char * code)562 wr_prompt(char *code) {
563 
564 	(void) fprintf(wstream, "%s%s\n", PROMPT, code);
565 	(void) fflush(wstream);
566 	return (0);
567 }
568 
569 int
wr_lshead(int n)570 wr_lshead(int n)
571 {
572 	(void) fprintf(wstream, "%s %d\n", LISTN, n);
573 	(void) fflush(wstream);
574 	return (0);
575 }
576 
577 /*
578  * LISTT [type]
579  * ELEMN [n]
580  */
581 int
wr_lhead(int type,int n)582 wr_lhead(int type, int n)
583 {
584 	(void) fprintf(wstream, "%s %d\n%s %d\n", LISTT, type, ELEMN, n);
585 	(void) fflush(wstream);
586 	return (0);
587 }
588 /*
589  * ELMID [elemid]
590  * FILDN [number of elements]
591  * e.g.
592  * id_usr 11050000000
593  * id_sys 7850000000
594  * id_ttime 0
595  * id_tpftime 0
596  *
597  * Write all fields defined by stub[stubidx]. The src is the source pointer.
598  * For each element read the key, grab the format function and the offset.
599  * Read and format the element from the source and write it out as a string.
600  */
601 int
wr_element(int stubidx,char * src,char * elemid)602 wr_element(int stubidx, char *src, char *elemid)
603 {
604 	int i;
605 
606 	(void) fprintf(wstream, "%s %s\n%s %d\n",
607 	    ELMID, elemid, FILDN, stubs[stubidx].size);
608 	for (i = 0; i < stubs[stubidx].size; i++) {
609 		stubs[stubidx].stub[i].info.format(STRUCT_TO_STR,
610 		    value, src, stubs[stubidx].stub[i].info.off);
611 		(void) fprintf(wstream, "%s %s\n",
612 		    stubs[stubidx].stub[i].key, value);
613 	}
614 	(void) fflush(wstream);
615 	return (0);
616 }
617 
618 int
wr_string(char * str)619 wr_string(char *str)
620 {
621 
622 	(void) fprintf(wstream, "%s", str);
623 	(void) fflush(wstream);
624 	return (0);
625 }
626 
627 int
wr_value(char * key,int64_t v)628 wr_value(char *key, int64_t v)
629 {
630 
631 	(void) fprintf(wstream, "%s %" PRId64 "\n", key, v);
632 	(void) fflush(wstream);
633 	return (0);
634 }
635 /*
636  * RDERR [err]
637  */
638 void
wr_error(char * err)639 wr_error(char *err)
640 {
641 	size_t len = strlen(RDERR + 1);
642 	if (strlen(err) > P_MAXLEN - len) {
643 		*(err + P_MAXLEN - len - 4) = '.';
644 		*(err + P_MAXLEN - len - 3) = '.';
645 		*(err + P_MAXLEN - len - 2) = '.';
646 		*(err + P_MAXLEN - len - 1) = 0;
647 	}
648 	len = strlen(err) - 1;
649 	if (strlen(err) == 0) {
650 		return;
651 	}
652 	while (len-- > 0) {
653 		if (*(err + len) == '\n')
654 			*(err + len) = ' ';
655 	}
656 
657 	(void) fprintf(wstream, "%s %s\n", RDERR, err);
658 	(void) fflush(wstream);
659 }
660 
661 /*
662  * read a protocol line, check the key and return the value associated
663  * with it.
664  */
665 int64_t
r_value(char * check_key)666 r_value(char *check_key) {
667 	int64_t v = -1;
668 
669 	if ((r_line() == -1) ||
670 			(strcmp(check_key, key) != 0) ||
671 			(sscanf(value, "%" SCNd64, &v) != 1)) {
672 		return (-1);
673 	}
674 	return (v);
675 }
676 
677 char *
r_cmd()678 r_cmd()
679 {
680 
681 	if (r_line() == -1) {
682 		format_err("can't read command");
683 		return (NULL);
684 	}
685 	return (value);
686 }
687 
688 int
r_phead()689 r_phead()
690 {
691 	int protv;
692 	size_t len = strlen(PROTM);
693 	size_t errorlen = strlen(RDERR);
694 	int i = 0;
695 
696 	while (i++ < MAX_RETRIES) {
697 		if (fgets(line, P_MAXLEN, rstream) == NULL) {
698 			format_err("can't read prot. head");
699 			return (-1);
700 		}
701 		len = strlen(line);
702 		if (len > P_MAXLEN)
703 			continue;
704 		if (strcmp(line, PROTM) == 0)
705 			break;
706 		if (strncmp(line, RDERR, errorlen) == 0) {
707 			(void) strcpy(error, line + strlen(RDERR) + 1);
708 			return (-1);
709 		}
710 	}
711 	if ((protv = r_value(PROTV)) == -1) {
712 		format_err("can't read prot. version");
713 		return (-1);
714 	}
715 	if (protv != PROT_VERSION) {
716 		format_err("unsupported prot. version");
717 		return (-1);
718 	}
719 	return (0);
720 }
721 
722 int
r_lshead()723 r_lshead()
724 {
725 	int  ret;
726 
727 	if ((ret = r_value(LISTN)) == -1) {
728 		format_err("can't read number of lists");
729 		return (-1);
730 	}
731 	return (ret);
732 }
733 
734 int
r_lhead(int * type)735 r_lhead(int *type)
736 {
737 
738 	if ((*type = r_value(LISTT)) == -1) {
739 		format_err("can't read list type");
740 		return (-1);
741 	}
742 	return (r_value(ELEMN));
743 }
744 
745 int
r_element(char * src,char * elemid)746 r_element(char *src, char *elemid)
747 {
748 	int fn, i;
749 	ENTRY item, *fitem;
750 
751 	if (r_line() == -1) {
752 		format_err("can't read element id");
753 		return (-1);
754 	} else {
755 		(void) strcpy(elemid, value);
756 	}
757 	if ((fn = r_value(FILDN)) == -1) {
758 		format_err("can't read number of fields");
759 		return (-1);
760 	}
761 	for (i = 0; i < fn; i++) {
762 		if (r_line() == -1) {
763 			return (-1);
764 		} else {
765 			item.key = key;
766 			if ((fitem = hsearch(item, FIND)) == NULL) {
767 				format_err("%s: \"%s\" ",
768 						"unknown key ", line);
769 				return (-1);
770 			}
771 			((info_t *)(void *)fitem->data)->
772 				format(STR_TO_STRUCT, value, src,
773 					((info_t *)(void *)fitem->data)->off);
774 			}
775 	}
776 	return (0);
777 }
778 
779 int
skip_line()780 skip_line()
781 {
782 	if (r_line() == -1) {
783 		format_err("can't read element id");
784 		return (-1);
785 	} else {
786 		return (0);
787 	}
788 }
789