1 /*
2 * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
13 */
14
15 #include <ctype.h>
16 #include "pmapi.h"
17 #include "impl.h"
18
19 /*
20 * PDU for id list (PDU_PMNS_IDS)
21 */
22 typedef struct {
23 __pmPDUHdr hdr;
24 int sts; /* to encode status of pmns op */
25 int numids;
26 pmID idlist[1];
27 } idlist_t;
28
29 #ifdef PCP_DEBUG
30 void
31 __pmDumpIDList(FILE *f, int numids, const pmID idlist[])
32 {
33 int i;
34
35 fprintf(f, "IDlist dump: numids = %d\n", numids);
36 for (i = 0; i < numids; i++)
37 fprintf(f, " PMID[%d]: 0x%08x %s\n", i, idlist[i], pmIDStr(idlist[i]));
38 }
39 #endif
40
41 /*
42 * Send a PDU_PMNS_IDS across socket.
43 */
44 int
45 __pmSendIDList(int fd, int from, int numids, const pmID idlist[], int sts)
46 {
47 idlist_t *ip;
48 int need;
49 int j;
50
51 #ifdef PCP_DEBUG
52 if (pmDebug & DBG_TRACE_PMNS) {
53 fprintf(stderr, "__pmSendIDList\n");
54 __pmDumpIDList(stderr, numids, idlist);
55 }
56 #endif
57
58 need = (int)(sizeof(idlist_t) + (numids-1) * sizeof(idlist[0]));
59
60 if ((ip = (idlist_t *)__pmFindPDUBuf(need)) == NULL)
61 return -oserror();
62 ip->hdr.len = need;
63 ip->hdr.type = PDU_PMNS_IDS;
64 ip->hdr.from = from;
65 ip->sts = htonl(sts);
66 ip->numids = htonl(numids);
67 for (j = 0; j < numids; j++) {
68 ip->idlist[j] = __htonpmID(idlist[j]);
69 }
70
71 return __pmXmitPDU(fd, (__pmPDU *)ip);
72 }
73
74 /*
75 * Decode a PDU_PMNS_IDS
76 * Assumes that we have preallocated idlist prior to this call
77 * (i.e. we know how many should definitely be coming over)
78 * Returns 0 on success.
79 */
80 int
81 __pmDecodeIDList(__pmPDU *pdubuf, int numids, pmID idlist[], int *sts)
82 {
83 idlist_t *idlist_pdu;
84 int j;
85
86 idlist_pdu = (idlist_t *)pdubuf;
87
88 *sts = ntohl(idlist_pdu->sts);
89 for (j = 0; j < numids; j++) {
90 idlist[j] = __ntohpmID(idlist_pdu->idlist[j]);
91 }
92
93 #ifdef PCP_DEBUG
94 if (pmDebug & DBG_TRACE_PMNS) {
95 fprintf(stderr, "__pmDecodeIDList\n");
96 __pmDumpIDList(stderr, numids, idlist);
97 }
98 #endif
99
100 return 0;
101 }
102
103 /*********************************************************************/
104
105 /*
106 * PDU for name list (PDU_PMNS_NAMES)
107 */
108
109 typedef struct {
110 int namelen;
111 char name[sizeof(__pmPDU)]; /* variable length */
112 } name_t;
113
114 typedef struct {
115 int status;
116 int namelen;
117 char name[sizeof(__pmPDU)]; /* variable length */
118 } name_status_t;
119
120 typedef struct {
121 __pmPDUHdr hdr;
122 int nstrbytes; /* number of str bytes including null terminators */
123 int numstatus; /* = 0 if there is no status to be encoded */
124 int numnames;
125 __pmPDU names[1]; /* list of variable length name_t or name_status_t */
126 } namelist_t;
127
128 /*
129 * NOTES:
130 *
131 * 1.
132 * name_t's are padded to a __pmPDU boundary (if needed)
133 * so that direct accesses of a following record
134 * can be made on a word boundary.
135 * i.e. the following "namelen" field will be accessible.
136 *
137 * 2.
138 * Names are sent length prefixed as opposed to null terminated.
139 * This can make copying at the decoding end simpler
140 * (and possibly more efficient using memcpy).
141 *
142 * 3.
143 * nstrbytes is used by the decoding function to know how many
144 * bytes to allocate.
145 *
146 * 4.
147 * name_status_t was added for pmGetChildrenStatus.
148 * It is a variant of the names pdu which encompasses status
149 * data as well.
150 */
151
152 #ifdef PCP_DEBUG
153 void
154 __pmDumpNameList(FILE *f, int numnames, char *namelist[])
155 {
156 int i;
157
158 fprintf(f, "namelist dump: numnames = %d\n", numnames);
159 for (i = 0; i < numnames; i++)
160 fprintf(f, " name[%d]: \"%s\"\n", i, namelist[i]);
161 }
162
163 void
164 __pmDumpStatusList(FILE *f, int numstatus, const int statuslist[])
165 {
166 int i;
167
168 fprintf(f, "statuslist dump: numstatus = %d\n", numstatus);
169 for (i = 0; i < numstatus; i++)
170 fprintf(f, " status[%d]: %d\n", i, statuslist[i]);
171 }
172
173 void
174 __pmDumpNameAndStatusList(FILE *f, int numnames, char *namelist[], int statuslist[])
175 {
176 int i;
177
178 fprintf(f, "namelist & statuslist dump: numnames = %d\n", numnames);
179 for (i = 0; i < numnames; i++)
180 fprintf(f, " name[%d]: \"%s\" (%s)\n", i, namelist[i],
181 statuslist[i] == PMNS_LEAF_STATUS ? "leaf" : "non-leaf");
182 }
183 #endif
184
185 /*
186 * Send a PDU_PMNS_NAMES across socket.
187 */
188 int
189 __pmSendNameList(int fd, int from, int numnames, char *namelist[],
190 const int statuslist[])
191 {
192 namelist_t *nlistp;
193 int need;
194 int nstrbytes=0;
195 int i;
196 name_t *nt;
197 name_status_t *nst;
198
199 #ifdef PCP_DEBUG
200 if (pmDebug & DBG_TRACE_PMNS) {
201 fprintf(stderr, "__pmSendNameList\n");
202 __pmDumpNameList(stderr, numnames, namelist);
203 if (statuslist != NULL)
204 __pmDumpStatusList(stderr, numnames, statuslist);
205 }
206 #endif
207
208 /* namelist_t + names rounded up to a __pmPDU boundary */
209 need = sizeof(*nlistp) - sizeof(nlistp->names);
210 for (i = 0; i < numnames; i++) {
211 int len = (int)strlen(namelist[i]);
212 nstrbytes += len+1;
213 if (namelist != NULL)
214 need += PM_PDU_SIZE_BYTES(len);
215 if (statuslist == NULL)
216 need += sizeof(*nt) - sizeof(nt->name);
217 else
218 need += sizeof(*nst) - sizeof(nst->name);
219 }
220
221 if ((nlistp = (namelist_t *)__pmFindPDUBuf(need)) == NULL)
222 return -oserror();
223 nlistp->hdr.len = need;
224 nlistp->hdr.type = PDU_PMNS_NAMES;
225 nlistp->hdr.from = from;
226 nlistp->nstrbytes = htonl(nstrbytes);
227 nlistp->numnames = htonl(numnames);
228
229 if (statuslist == NULL) {
230 int i, j = 0, namelen;
231 nlistp->numstatus = htonl(0);
232 for(i=0; i<numnames; i++) {
233 nt = (name_t*)&nlistp->names[j/sizeof(__pmPDU)];
234 namelen = (int)strlen(namelist[i]);
235 memcpy(nt->name, namelist[i], namelen);
236 #ifdef PCP_DEBUG
237 if ((namelen % sizeof(__pmPDU)) != 0) {
238 /* for Purify */
239 int pad;
240 char *padp = nt->name + namelen;
241 for (pad = sizeof(__pmPDU) - 1; pad >= (namelen % sizeof(__pmPDU)); pad--)
242 *padp++ = '~'; /* buffer end */
243 }
244 #endif
245 j += sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen);
246 nt->namelen = htonl(namelen);
247 }
248 }
249 else { /* include the status fields */
250 int i, j = 0, namelen;
251 nlistp->numstatus = htonl(numnames);
252 for(i=0; i<numnames; i++) {
253 nst = (name_status_t*)&nlistp->names[j/sizeof(__pmPDU)];
254 nst->status = htonl(statuslist[i]);
255 namelen = (int)strlen(namelist[i]);
256 memcpy(nst->name, namelist[i], namelen);
257 #ifdef PCP_DEBUG
258 if ((namelen % sizeof(__pmPDU)) != 0) {
259 /* for Purify */
260 int pad;
261 char *padp = nst->name + namelen;
262 for (pad = sizeof(__pmPDU) - 1; pad >= (namelen % sizeof(__pmPDU)); pad--)
263 *padp++ = '~'; /* buffer end */
264 }
265 #endif
266 j += sizeof(nst->status) + sizeof(namelen) +
267 PM_PDU_SIZE_BYTES(namelen);
268 nst->namelen = htonl(namelen);
269 }
270 }
271
272 return __pmXmitPDU(fd, (__pmPDU *)nlistp);
273 }
274
275 /*
276 * Decode a PDU_PMNS_NAMES
277 */
278 int
279 __pmDecodeNameList(__pmPDU *pdubuf, int *numnames,
280 char*** namelist, int** statuslist)
281 {
282 namelist_t *namelist_pdu;
283 char **names;
284 int *status = NULL;
285 int need;
286 int numstatus;
287
288 namelist_pdu = (namelist_t *)pdubuf;
289
290 *namelist = NULL;
|
Event var_compare_op: |
Comparing "statuslist" to null implies that "statuslist" might be null. |
| Also see events: |
[var_deref_op] |
|
At conditional (1): "statuslist": Taking false branch.
|
291 if (statuslist)
292 *statuslist = NULL;
293
294 *numnames = ntohl(namelist_pdu->numnames);
295 numstatus = ntohl(namelist_pdu->numstatus);
296
|
At conditional (2): "*numnames == 0": Taking false branch.
|
297 if (*numnames == 0)
298 return 0;
299
300 /* need space for name ptrs and the name characters */
301 need = *numnames * ((int)sizeof(char*)) + ntohl(namelist_pdu->nstrbytes);
|
At conditional (3): "(names = (char **)malloc(need)) == NULL": Taking false branch.
|
302 if ((names = (char**)malloc(need)) == NULL)
303 return -oserror();
304
305 /* need space for status values */
|
At conditional (4): "numstatus > 0": Taking true branch.
|
306 if (numstatus > 0) {
307 need = numstatus * (int)sizeof(int);
|
At conditional (5): "(status = (int *)malloc(need)) == NULL": Taking false branch.
|
308 if ((status = (int*)malloc(need)) == NULL) {
309 free(names);
310 return -oserror();
311 }
312 }
313
314 /* copy over ptrs and characters */
|
At conditional (6): "numstatus == 0": Taking false branch.
|
315 if (numstatus == 0) {
316 int i, j = 0;
317 char *dest = (char*)&names[*numnames];
318 name_t *np;
319 int namelen;
320
321 for (i = 0; i < *numnames; i++) {
322 np = (name_t*)&namelist_pdu->names[j/sizeof(__pmPDU)];
323 names[i] = dest;
324 namelen = ntohl(np->namelen);
325
326 memcpy(dest, np->name, namelen);
327 *(dest + namelen) = '\0';
328 dest += namelen + 1;
329
330 j += sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen);
331 }
332 }
333 else { /* include the status fields */
334 int i, j = 0;
335 char *dest = (char*)&names[*numnames];
336 name_status_t *np;
337 int namelen;
338
|
At conditional (7): "i < *numnames": Taking true branch.
|
|
At conditional (8): "i < *numnames": Taking false branch.
|
339 for (i = 0; i < *numnames; i++) {
340 np = (name_status_t*)&namelist_pdu->names[j/sizeof(__pmPDU)];
341 names[i] = dest;
342 namelen = ntohl(np->namelen);
343 status[i] = ntohl(np->status);
344
345 memcpy(dest, np->name, namelen);
346 *(dest + namelen) = '\0';
347 dest += namelen + 1;
348
349 j += sizeof(np->status) + sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen);
350 }
351 }
352
353 #ifdef PCP_DEBUG
|
At conditional (9): "pmDebug & 0x4000": Taking true branch.
|
354 if (pmDebug & DBG_TRACE_PMNS) {
355 fprintf(stderr, "__pmDecodeNameList\n");
356 __pmDumpNameList(stderr, *numnames, names);
|
At conditional (10): "status != NULL": Taking true branch.
|
357 if (status != NULL)
358 __pmDumpStatusList(stderr, numstatus, status);
359 }
360 #endif
361
362 *namelist = names;
|
At conditional (11): "status != NULL": Taking true branch.
|
363 if (status != NULL)
|
Event var_deref_op: |
Dereferencing null variable "statuslist". |
| Also see events: |
[var_compare_op] |
364 *statuslist = status;
365 return *numnames;
366 }
367
368
369 /*********************************************************************/
370
371 /*
372 * name request
373 */
374
375 typedef struct {
376 __pmPDUHdr hdr;
377 int subtype;
378 int namelen;
379 char name[sizeof(int)];
380 } namereq_t;
381
382 /*
383 * Send a PDU_PMNS_CHILD_REQ across socket.
384 */
385 static int
386 SendNameReq(int fd, int from, const char *name, int pdu_type, int subtype)
387 {
388 namereq_t *nreq;
389 int need;
390 int namelen;
391 int alloc_len; /* length allocated for name */
392
393 #ifdef PCP_DEBUG
394 if (pmDebug & DBG_TRACE_PMNS)
395 fprintf(stderr, "SendNameReq: from=%d name=\"%s\" pdu=%s subtype=%d\n",
396 from, name, __pmPDUTypeStr(pdu_type), subtype);
397 #endif
398
399 namelen = (int)strlen(name);
400 alloc_len = (int)(sizeof(int)*((namelen-1 + sizeof(int))/sizeof(int)));
401 need = (int)(sizeof(*nreq) - sizeof(nreq->name) + alloc_len);
402
403 if ((nreq = (namereq_t *)__pmFindPDUBuf(need)) == NULL)
404 return -oserror();
405 nreq->hdr.len = need;
406 nreq->hdr.type = pdu_type;
407 nreq->hdr.from = from;
408 nreq->subtype = htonl(subtype);
409 nreq->namelen = htonl(namelen);
410 memcpy(&nreq->name[0], name, namelen);
411
412 return __pmXmitPDU(fd, (__pmPDU *)nreq);
413 }
414
415 /*
416 * Decode a name request
417 */
418 static int
419 DecodeNameReq(__pmPDU *pdubuf, char **name_p, int *subtype)
420 {
421 namereq_t *namereq_pdu;
422 char *name;
423 int namelen;
424
425 namereq_pdu = (namereq_t *)pdubuf;
426
427 /* only set it if you want it */
428 if (subtype != NULL)
429 *subtype = ntohl(namereq_pdu->subtype);
430
431 namelen = ntohl(namereq_pdu->namelen);
432 name = malloc(namelen+1);
433 if (name == NULL)
434 return -oserror();
435 memcpy(name, namereq_pdu->name, namelen);
436 name[namelen] = '\0';
437
438 #ifdef PCP_DEBUG
439 if (pmDebug & DBG_TRACE_PMNS)
440 fprintf(stderr, "DecodeNameReq: name=\"%s\"\n", name);
441 #endif
442
443 *name_p = name;
444 return 0;
445 }
446
447 /*********************************************************************/
448
449 /*
450 * Send a PDU_PMNS_CHILD
451 */
452 int
453 __pmSendChildReq(int fd, int from, const char *name, int subtype)
454 {
455 return SendNameReq(fd, from, name, PDU_PMNS_CHILD, subtype);
456 }
457
458
459 /*
460 * Decode a PDU_PMNS_CHILD
461 */
462 int
463 __pmDecodeChildReq(__pmPDU *pdubuf, char **name_p, int *subtype)
464 {
465 return DecodeNameReq(pdubuf, name_p, subtype);
466 }
467
468 /*********************************************************************/
469
470 /*
471 * Send a PDU_PMNS_TRAVERSE
472 */
473 int
474 __pmSendTraversePMNSReq(int fd, int from, const char *name)
475 {
476 return SendNameReq(fd, from, name, PDU_PMNS_TRAVERSE, 0);
477 }
478
479
480 /*
481 * Decode a PDU_PMNS_TRAVERSE
482 */
483 int
484 __pmDecodeTraversePMNSReq(__pmPDU *pdubuf, char **name_p)
485 {
486 return DecodeNameReq(pdubuf, name_p, 0);
487 }
488
489 /*********************************************************************/