Print this page
11691 ptree could show service FMRIs
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: Andy Fiddaman <andy@omniosce.org>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ptools/ptree/ptree.c
+++ new/usr/src/cmd/ptools/ptree/ptree.c
1 -/*
1 + /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + * Copyright 2019 Joyent, Inc.
24 25 */
25 26
26 27 /*
27 28 * ptree -- print family tree of processes
28 29 */
29 30
30 -#pragma ident "%Z%%M% %I% %E% SMI"
31 -
32 31 #include <assert.h>
33 32 #include <stdio.h>
34 33 #include <string.h>
35 34 #include <errno.h>
36 35 #include <fcntl.h>
37 36 #include <sys/types.h>
38 37 #include <sys/termios.h>
39 38 #include <unistd.h>
40 39 #include <stdlib.h>
41 40 #include <dirent.h>
42 41 #include <pwd.h>
43 42 #include <libproc.h>
44 43 #include <libzonecfg.h>
45 44 #include <limits.h>
46 45 #include <libcontract.h>
47 46 #include <sys/contract.h>
48 47 #include <sys/ctfs.h>
49 48 #include <libcontract_priv.h>
50 49 #include <sys/stat.h>
50 +#include <stdbool.h>
51 51
52 52 #define FAKEDPID0(p) (p->pid == 0 && p->psargs[0] == '\0')
53 53
54 54 typedef struct ps {
55 55 int done;
56 56 uid_t uid;
57 57 uid_t gid;
58 58 pid_t pid; /* pid == -1 indicates this is a contract */
59 59 pid_t ppid;
60 60 pid_t pgrp;
61 61 pid_t sid;
62 62 zoneid_t zoneid;
63 63 ctid_t ctid;
64 + char *svc_fmri;
64 65 timestruc_t start;
65 66 char psargs[PRARGSZ];
66 67 struct ps *pp; /* parent */
67 68 struct ps *sp; /* sibling */
68 69 struct ps *cp; /* child */
69 70 } ps_t;
70 71
71 72 static ps_t **ps; /* array of ps_t's */
72 73 static unsigned psize; /* size of array */
73 74 static int nps; /* number of ps_t's */
74 75 static ps_t **ctps; /* array of contract ps_t's */
75 76 static unsigned ctsize; /* size of contract array */
76 77 static int nctps; /* number of contract ps_t's */
77 78 static ps_t *proc0; /* process 0 */
78 79 static ps_t *proc1; /* process 1 */
79 80
80 81 static char *command;
81 82
82 83 static int aflag = 0;
83 84 static int cflag = 0;
85 +static int sflag = 0;
84 86 static int zflag = 0;
85 87 static zoneid_t zoneid;
88 +static char *match_svc;
89 +static char *match_inst;
86 90 static int columns = 80;
87 91
88 -static void markprocs(ps_t *p);
89 -static int printone(ps_t *p, int level);
92 +static bool match_proc(ps_t *);
93 +static void markprocs(ps_t *);
94 +static int printone(ps_t *, int);
90 95 static void insertchild(ps_t *, ps_t *);
91 -static void prsort(ps_t *p);
92 -static void printsubtree(ps_t *p, int level);
93 -static zoneid_t getzone(char *arg);
96 +static void prsort(ps_t *);
97 +static void printsubtree(ps_t *, int);
98 +static void p_get_svc_fmri(ps_t *, ct_stathdl_t);
99 +static char *parse_svc(const char *, char **);
100 +static zoneid_t getzone(const char *);
94 101 static ps_t *fakepid0(void);
95 102
96 103 int
97 104 main(int argc, char **argv)
98 105 {
99 106 psinfo_t info; /* process information structure from /proc */
100 107 int opt;
101 108 int errflg = 0;
102 109 struct winsize winsize;
103 110 char *s;
104 111 int n;
105 112 int retc = 0;
106 113
107 114 DIR *dirp;
108 115 struct dirent *dentp;
109 116 char pname[100];
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
110 117 int pdlen;
111 118
112 119 ps_t *p;
113 120
114 121 if ((command = strrchr(argv[0], '/')) == NULL)
115 122 command = argv[0];
116 123 else
117 124 command++;
118 125
119 126 /* options */
120 - while ((opt = getopt(argc, argv, "acz:")) != EOF) {
127 + while ((opt = getopt(argc, argv, "acs:z:")) != EOF) {
121 128 switch (opt) {
122 129 case 'a': /* include children of process 0 */
123 130 aflag = 1;
124 131 break;
125 132 case 'c': /* display contract ownership */
126 133 aflag = cflag = 1;
127 134 break;
135 + case 's':
136 + sflag = 1;
137 + match_svc = parse_svc(optarg, &match_inst);
138 + break;
128 139 case 'z': /* only processes in given zone */
129 140 zflag = 1;
130 141 zoneid = getzone(optarg);
131 142 break;
132 143 default:
133 144 errflg = 1;
134 145 break;
135 146 }
136 147 }
137 148
138 149 argc -= optind;
139 150 argv += optind;
140 151
141 152 if (errflg) {
142 153 (void) fprintf(stderr,
143 - "usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n",
154 + "usage:\t%s [-ac] [-s svc] [-z zone] [ {pid|user} ... ]\n",
144 155 command);
145 156 (void) fprintf(stderr,
146 157 " (show process trees)\n");
147 158 (void) fprintf(stderr,
148 159 " list can include process-ids and user names\n");
149 160 (void) fprintf(stderr,
150 161 " -a : include children of process 0\n");
151 162 (void) fprintf(stderr,
152 - " -c : show contract ownership\n");
163 + " -c : show contracts\n");
153 164 (void) fprintf(stderr,
165 + " -s : print only processes with given service FMRI\n");
166 + (void) fprintf(stderr,
154 167 " -z : print only processes in given zone\n");
155 168 return (2);
156 169 }
157 170
158 171 /*
159 172 * Kind of a hack to determine the width of the output...
160 173 */
161 174 if ((s = getenv("COLUMNS")) != NULL && (n = atoi(s)) > 0)
162 175 columns = n;
163 176 else if (isatty(fileno(stdout)) &&
164 177 ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0 &&
165 178 winsize.ws_col != 0)
166 179 columns = winsize.ws_col;
167 180
168 181 nps = 0;
169 182 psize = 0;
170 183 ps = NULL;
171 184
172 185 /*
173 186 * Search the /proc directory for all processes.
174 187 */
175 188 if ((dirp = opendir("/proc")) == NULL) {
176 189 (void) fprintf(stderr, "%s: cannot open /proc directory\n",
177 190 command);
178 191 return (1);
179 192 }
180 193
181 194 (void) strcpy(pname, "/proc");
182 195 pdlen = strlen(pname);
183 196 pname[pdlen++] = '/';
184 197
185 198 /* for each active process --- */
186 199 while (dentp = readdir(dirp)) {
187 200 int procfd; /* filedescriptor for /proc/nnnnn/psinfo */
188 201
189 202 if (dentp->d_name[0] == '.') /* skip . and .. */
190 203 continue;
191 204 (void) strcpy(pname + pdlen, dentp->d_name);
192 205 (void) strcpy(pname + strlen(pname), "/psinfo");
193 206 retry:
194 207 if ((procfd = open(pname, O_RDONLY)) == -1)
195 208 continue;
196 209
197 210 /*
198 211 * Get the info structure for the process and close quickly.
199 212 */
200 213 if (read(procfd, &info, sizeof (info)) != sizeof (info)) {
201 214 int saverr = errno;
202 215
203 216 (void) close(procfd);
204 217 if (saverr == EAGAIN)
205 218 goto retry;
206 219 if (saverr != ENOENT)
207 220 perror(pname);
208 221 continue;
209 222 }
210 223 (void) close(procfd);
211 224
212 225 /*
213 226 * We make sure there's always a free slot in the table
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
214 227 * in case we need to add a fake p0.
215 228 */
216 229 if (nps + 1 >= psize) {
217 230 if ((psize *= 2) == 0)
218 231 psize = 20;
219 232 if ((ps = realloc(ps, psize*sizeof (ps_t *))) == NULL) {
220 233 perror("realloc()");
221 234 return (1);
222 235 }
223 236 }
224 - if ((p = malloc(sizeof (ps_t))) == NULL) {
225 - perror("malloc()");
237 + if ((p = calloc(1, sizeof (ps_t))) == NULL) {
238 + perror("calloc()");
226 239 return (1);
227 240 }
228 241 ps[nps++] = p;
229 242 p->done = 0;
230 243 p->uid = info.pr_uid;
231 244 p->gid = info.pr_gid;
232 245 p->pid = info.pr_pid;
233 246 p->ppid = info.pr_ppid;
234 247 p->pgrp = info.pr_pgid;
235 248 p->sid = info.pr_sid;
236 249 p->zoneid = info.pr_zoneid;
237 250 p->ctid = info.pr_contract;
238 251 p->start = info.pr_start;
239 252 proc_unctrl_psinfo(&info);
240 253 if (info.pr_nlwp == 0)
241 254 (void) strcpy(p->psargs, "<defunct>");
↓ open down ↓ |
6 lines elided |
↑ open up ↑ |
242 255 else if (info.pr_psargs[0] == '\0')
243 256 (void) strncpy(p->psargs, info.pr_fname,
244 257 sizeof (p->psargs));
245 258 else
246 259 (void) strncpy(p->psargs, info.pr_psargs,
247 260 sizeof (p->psargs));
248 261 p->psargs[sizeof (p->psargs)-1] = '\0';
249 262 p->pp = NULL;
250 263 p->sp = NULL;
251 264 p->cp = NULL;
265 +
266 + if (sflag)
267 + p_get_svc_fmri(p, NULL);
268 +
252 269 if (p->pid == p->ppid)
253 270 proc0 = p;
254 271 if (p->pid == 1)
255 272 proc1 = p;
256 273 }
257 274
258 275 (void) closedir(dirp);
259 276 if (proc0 == NULL)
260 277 proc0 = fakepid0();
261 278 if (proc1 == NULL)
262 279 proc1 = proc0;
263 280
264 281 for (n = 0; n < nps; n++) {
265 282 p = ps[n];
266 283 if (p->pp == NULL)
267 284 prsort(p);
268 285 }
269 286
270 287 if (cflag)
271 288 /* Parent all orphan contracts to process 0. */
272 289 for (n = 0; n < nctps; n++) {
273 290 p = ctps[n];
274 291 if (p->pp == NULL)
275 292 insertchild(proc0, p);
276 293 }
277 294
278 295 if (argc == 0) {
279 296 for (p = aflag ? proc0->cp : proc1->cp; p != NULL; p = p->sp) {
280 297 markprocs(p);
281 298 printsubtree(p, 0);
282 299 }
283 300 return (0);
284 301 }
285 302
286 303 /*
287 304 * Initially, assume we're not going to find any processes. If we do
288 305 * mark any, then set this to 0 to indicate no error.
289 306 */
290 307 errflg = 1;
291 308
292 309 while (argc-- > 0) {
293 310 char *arg;
294 311 char *next;
295 312 pid_t pid;
296 313 uid_t uid;
297 314 int n;
298 315
299 316 /* in case some silly person said 'ptree /proc/[0-9]*' */
300 317 arg = strrchr(*argv, '/');
301 318 if (arg++ == NULL)
302 319 arg = *argv;
303 320 argv++;
304 321 uid = (uid_t)-1;
305 322 errno = 0;
306 323 pid = strtoul(arg, &next, 10);
307 324 if (errno != 0 || *next != '\0') {
308 325 struct passwd *pw = getpwnam(arg);
309 326 if (pw == NULL) {
310 327 (void) fprintf(stderr,
311 328 "%s: invalid username: %s\n",
312 329 command, arg);
313 330 retc = 1;
314 331 continue;
315 332 }
316 333 uid = pw->pw_uid;
317 334 pid = -1;
318 335 }
319 336
320 337 for (n = 0; n < nps; n++) {
321 338 ps_t *p = ps[n];
322 339
323 340 /*
324 341 * A match on pid causes the subtree starting at pid
325 342 * to be printed, regardless of the -a flag.
326 343 * For uid matches, we never include pid 0 and only
327 344 * include the children of pid 0 if -a was specified.
↓ open down ↓ |
66 lines elided |
↑ open up ↑ |
328 345 */
329 346 if (p->pid == pid || (p->uid == uid && p->pid != 0 &&
330 347 (p->ppid != 0 || aflag))) {
331 348 errflg = 0;
332 349 markprocs(p);
333 350 if (p->pid != 0)
334 351 for (p = p->pp; p != NULL &&
335 352 p->done != 1 && p->pid != 0;
336 353 p = p->pp)
337 354 if ((p->ppid != 0 || aflag) &&
338 - (!zflag ||
339 - p->zoneid == zoneid))
355 + match_proc(p))
340 356 p->done = 1;
341 357 if (uid == (uid_t)-1)
342 358 break;
343 359 }
344 360 }
345 361 }
346 362
347 363 printsubtree(proc0, 0);
348 364 /*
349 365 * retc = 1 if an invalid username was supplied.
350 366 * errflg = 1 if no matching processes were found.
351 367 */
352 368 return (retc || errflg);
353 369 }
354 370
355 371 #define PIDWIDTH 5
356 372
357 373 static int
358 374 printone(ps_t *p, int level)
359 375 {
360 376 int n, indent;
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
361 377
362 378 if (p->done && !FAKEDPID0(p)) {
363 379 indent = level * 2;
364 380 if ((n = columns - PIDWIDTH - indent - 2) < 0)
365 381 n = 0;
366 382 if (p->pid >= 0) {
367 383 (void) printf("%*.*s%-*d %.*s\n", indent, indent, " ",
368 384 PIDWIDTH, (int)p->pid, n, p->psargs);
369 385 } else {
370 386 assert(cflag != 0);
371 - (void) printf("%*.*s[process contract %d]\n",
372 - indent, indent, " ", (int)p->ctid);
387 + (void) printf("%*.*s[process contract %d: %s]\n",
388 + indent, indent, " ", (int)p->ctid,
389 + p->svc_fmri == NULL ? "?" : p->svc_fmri);
373 390 }
374 391 return (1);
375 392 }
376 393 return (0);
377 394 }
378 395
379 396 static void
380 397 insertchild(ps_t *pp, ps_t *cp)
381 398 {
382 399 /* insert as child process of p */
383 400 ps_t **here;
384 401 ps_t *sp;
385 402
386 403 /* sort by start time */
387 404 for (here = &pp->cp, sp = pp->cp;
388 405 sp != NULL;
389 406 here = &sp->sp, sp = sp->sp) {
390 407 if (cp->start.tv_sec < sp->start.tv_sec)
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
391 408 break;
392 409 if (cp->start.tv_sec == sp->start.tv_sec &&
393 410 cp->start.tv_nsec < sp->start.tv_nsec)
394 411 break;
395 412 }
396 413 cp->pp = pp;
397 414 cp->sp = sp;
398 415 *here = cp;
399 416 }
400 417
418 +static ct_stathdl_t
419 +ct_status_open(ctid_t ctid, struct stat64 *stp)
420 +{
421 + ct_stathdl_t hdl;
422 + int fd;
423 +
424 + if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1)
425 + return (NULL);
426 +
427 + if (fstat64(fd, stp) == -1 || ct_status_read(fd, CTD_FIXED, &hdl)) {
428 + (void) close(fd);
429 + return (NULL);
430 + }
431 +
432 + (void) close(fd);
433 +
434 + return (hdl);
435 +}
436 +
437 +/*
438 + * strdup() failure is OK - better to report something than fail totally.
439 + */
401 440 static void
441 +p_get_svc_fmri(ps_t *p, ct_stathdl_t inhdl)
442 +{
443 + ct_stathdl_t hdl = inhdl;
444 + struct stat64 st;
445 + char *fmri;
446 +
447 + if (hdl == NULL && (hdl = ct_status_open(p->ctid, &st)) == NULL)
448 + return;
449 +
450 + if (ct_pr_status_get_svc_fmri(hdl, &fmri) == 0)
451 + p->svc_fmri = strdup(fmri);
452 +
453 + if (inhdl == NULL)
454 + ct_status_free(hdl);
455 +}
456 +
457 +static void
402 458 ctsort(ctid_t ctid, ps_t *p)
403 459 {
404 460 ps_t *pp;
405 - int fd, n;
461 + int n;
406 462 ct_stathdl_t hdl;
407 463 struct stat64 st;
408 464
409 465 for (n = 0; n < nctps; n++)
410 466 if (ctps[n]->ctid == ctid) {
411 467 insertchild(ctps[n], p);
412 468 return;
413 469 }
414 470
415 - if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1)
471 + if ((hdl = ct_status_open(ctid, &st)) == NULL)
416 472 return;
417 - if (fstat64(fd, &st) == -1 || ct_status_read(fd, CTD_COMMON, &hdl)) {
418 - (void) close(fd);
419 - return;
420 - }
421 - (void) close(fd);
422 473
423 474 if (nctps >= ctsize) {
424 475 if ((ctsize *= 2) == 0)
425 476 ctsize = 20;
426 477 if ((ctps = realloc(ctps, ctsize * sizeof (ps_t *))) == NULL) {
427 478 perror("realloc()");
428 479 exit(1);
429 480 }
430 481 }
431 482 pp = calloc(sizeof (ps_t), 1);
432 483 if (pp == NULL) {
433 484 perror("calloc()");
434 485 exit(1);
435 486 }
436 487 ctps[nctps++] = pp;
437 488
438 489 pp->pid = -1;
439 490 pp->ctid = ctid;
491 +
492 + p_get_svc_fmri(pp, hdl);
493 +
440 494 pp->start.tv_sec = st.st_ctime;
441 495 insertchild(pp, p);
442 496
443 497 pp->zoneid = ct_status_get_zoneid(hdl);
498 +
444 499 /*
445 500 * In a zlogin <zonename>, the contract belongs to the
446 501 * global zone and the shell opened belongs to <zonename>.
447 502 * If the -c and -z zonename flags are used together, then
448 503 * we need to adjust the zoneid in the contract's ps_t as
449 504 * follows:
450 505 *
451 506 * ptree -c -z <zonename> --> zoneid == p->zoneid
452 507 * ptree -c -z global --> zoneid == pp->zoneid
453 508 *
454 509 * The approach assumes that no tool can create processes in
455 510 * different zones under the same contract. If this is
456 511 * possible, ptree will need to refactor how it builds
457 512 * its internal tree of ps_t's
458 513 */
459 514 if (zflag && p->zoneid != pp->zoneid &&
460 515 (zoneid == p->zoneid || zoneid == pp->zoneid))
461 516 pp->zoneid = p->zoneid;
462 517 if (ct_status_get_state(hdl) == CTS_OWNED) {
463 518 pp->ppid = ct_status_get_holder(hdl);
464 519 prsort(pp);
465 520 } else if (ct_status_get_state(hdl) == CTS_INHERITED) {
466 521 ctsort(ct_status_get_holder(hdl), pp);
467 522 }
468 523 ct_status_free(hdl);
469 524 }
470 525
471 526 static void
472 527 prsort(ps_t *p)
473 528 {
474 529 int n;
475 530 ps_t *pp;
476 531
477 532 /* If this node already has a parent, it's sorted */
478 533 if (p->pp != NULL)
479 534 return;
480 535
481 536 for (n = 0; n < nps; n++) {
482 537 pp = ps[n];
483 538
484 539 if (pp != NULL && p != pp && p->ppid == pp->pid) {
485 540 if (cflag && p->pid >= 0 &&
486 541 p->ctid != -1 && p->ctid != pp->ctid) {
487 542 ctsort(p->ctid, p);
488 543 } else {
489 544 insertchild(pp, p);
490 545 prsort(pp);
491 546 }
492 547 return;
493 548 }
494 549 }
495 550
496 551 /* File parentless processes under their contracts */
497 552 if (cflag && p->pid >= 0)
498 553 ctsort(p->ctid, p);
499 554 }
500 555
501 556 static void
502 557 printsubtree(ps_t *p, int level)
↓ open down ↓ |
49 lines elided |
↑ open up ↑ |
503 558 {
504 559 int printed;
505 560
506 561 printed = printone(p, level);
507 562 if (level != 0 || printed == 1)
508 563 level++;
509 564 for (p = p->cp; p != NULL; p = p->sp)
510 565 printsubtree(p, level);
511 566 }
512 567
568 +/*
569 + * Match against the service name (and just the final component), and any
570 + * specified instance name.
571 + */
572 +static bool
573 +match_proc(ps_t *p)
574 +{
575 + bool matched = false;
576 + const char *cp;
577 + char *p_inst;
578 + char *p_svc;
579 +
580 + if (zflag && p->zoneid != zoneid)
581 + return (false);
582 +
583 + if (!sflag)
584 + return (true);
585 +
586 + if (p->svc_fmri == NULL)
587 + return (false);
588 +
589 + p_svc = parse_svc(p->svc_fmri, &p_inst);
590 +
591 + if (strcmp(p_svc, match_svc) != 0 &&
592 + ((cp = strrchr(p_svc, '/')) == NULL ||
593 + strcmp(cp + 1, match_svc) != 0)) {
594 + goto out;
595 + }
596 +
597 + if (strlen(match_inst) == 0 ||
598 + strcmp(p_inst, match_inst) == 0)
599 + matched = true;
600 +
601 +out:
602 + free(p_svc);
603 + free(p_inst);
604 + return (matched);
605 +}
606 +
513 607 static void
514 608 markprocs(ps_t *p)
515 609 {
516 - if (!zflag || p->zoneid == zoneid)
610 + if (match_proc(p))
517 611 p->done = 1;
612 +
518 613 for (p = p->cp; p != NULL; p = p->sp)
519 614 markprocs(p);
520 615 }
521 616
522 617 /*
523 618 * If there's no "top" process, we fake one; it will be the parent of
524 619 * all orphans.
525 620 */
526 621 static ps_t *
527 622 fakepid0(void)
528 623 {
529 624 ps_t *p0, *p;
530 625 int n;
531 626
532 - if ((p0 = malloc(sizeof (ps_t))) == NULL) {
533 - perror("malloc()");
627 + if ((p0 = calloc(1, sizeof (ps_t))) == NULL) {
628 + perror("calloc()");
534 629 exit(1);
535 630 }
536 631 (void) memset(p0, '\0', sizeof (ps_t));
537 632
538 633 /* First build all partial process trees. */
539 634 for (n = 0; n < nps; n++) {
540 635 p = ps[n];
541 636 if (p->pp == NULL)
542 637 prsort(p);
543 638 }
544 639
545 640 /* Then adopt all orphans. */
546 641 for (n = 0; n < nps; n++) {
547 642 p = ps[n];
548 643 if (p->pp == NULL)
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
549 644 insertchild(p0, p);
550 645 }
551 646
552 647 /* We've made sure earlier there's room for this. */
553 648 ps[nps++] = p0;
554 649 return (p0);
555 650 }
556 651
557 652 /* convert string containing zone name or id to a numeric id */
558 653 static zoneid_t
559 -getzone(char *arg)
654 +getzone(const char *arg)
560 655 {
561 656 zoneid_t zoneid;
562 657
563 658 if (zone_get_id(arg, &zoneid) != 0) {
564 659 (void) fprintf(stderr, "%s: unknown zone: %s\n", command, arg);
565 660 exit(1);
566 661 }
567 662 return (zoneid);
663 +}
664 +
665 +/* svc:/mysvc:default -> mysvc, default */
666 +static char *
667 +parse_svc(const char *arg, char **instp)
668 +{
669 + const char *p = arg;
670 + char *ret;
671 + char *cp;
672 +
673 + if (strncmp(p, "svc:/", strlen("svc:/")) == 0)
674 + p += strlen("svc:/");
675 +
676 + if ((ret = strdup(p)) == NULL) {
677 + perror("strdup()");
678 + exit(1);
679 + }
680 +
681 + if ((cp = strrchr(ret, ':')) != NULL) {
682 + *cp = '\0';
683 + cp++;
684 + } else {
685 + cp = "";
686 + }
687 +
688 + if ((*instp = strdup(cp)) == NULL) {
689 + perror("strdup()");
690 + exit(1);
691 + }
692 +
693 + return (ret);
568 694 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX