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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 619 wr_string(char *str) 620 { 621 622 (void) fprintf(wstream, "%s", str); 623 (void) fflush(wstream); 624 return (0); 625 } 626 627 int 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 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 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 * 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 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 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 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 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 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