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