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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * inetadm - administer services controlled by inetd and print out inetd
29 * service related information.
30 */
31
32 #include <locale.h>
33 #include <libintl.h>
34 #include <libscf.h>
35 #include <libscf_priv.h>
36 #include <libuutil.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <inetsvc.h>
43 #include <errno.h>
44
45 #ifndef TEXT_DOMAIN
46 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
47 #endif /* TEXT_DOMAIN */
48
49 /* Strings for output to the user, and checking user's input */
50
51 #define INETADM_TRUE_STR "TRUE"
52 #define INETADM_FALSE_STR "FALSE"
53 #define INETADM_ENABLED_STR "enabled"
54 #define INETADM_DISABLED_STR "disabled"
55 #define INETADM_DEFAULT_STR "default"
56
57 /* String for checking if an instance is under inetd's control. */
58
59 #define INETADM_INETD_STR "network/inetd"
60
61 /*
62 * Used to hold a list of scf_value_t's whilst performing a transaction
63 * to write a proto list back.
64 */
65 typedef struct scf_val_el {
66 scf_value_t *val;
67 uu_list_node_t link;
68 } scf_val_el_t;
69
70 /*
71 * Structure used to encapsulate argc and argv so they can be passed using the
72 * single data argument supplied by scf_walk_fmri() for the consumption of
73 * modify_inst_props_cb().
74 */
75 typedef struct arglist {
76 int argc;
77 char **argv;
78 } arglist_t;
79
80 static scf_handle_t *h;
81
82 static void
scfdie()83 scfdie()
84 {
85 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
86 scf_strerror(scf_error()));
87 }
88
89 static void
usage(boolean_t detailed)90 usage(boolean_t detailed)
91 {
92
93 uu_warn(gettext(
94 "Usage:\n"
95 " inetadm\n"
96 " inetadm -?\n"
97 " inetadm -p\n"
98 " inetadm -l {FMRI | pattern}...\n"
99 " inetadm -e {FMRI | pattern}...\n"
100 " inetadm -d {FMRI | pattern}...\n"
101 " inetadm -m {FMRI | pattern}... {name=value}...\n"
102 " inetadm -M {name=value}...\n"));
103
104 if (!detailed)
105 exit(UU_EXIT_USAGE);
106
107 (void) fprintf(stdout, gettext(
108 "\n"
109 "Without any options inetadm lists all inetd managed services.\n"
110 "\n"
111 "Options:\n"
112 " -? Print help.\n"
113 " -p List all default inetd property values.\n"
114 " -l List all inetd property values for the inet "
115 "service(s).\n"
116 " -e Enable the inet service(s).\n"
117 " -d Disable the inet service(s).\n"
118 " -m Modify the inet service(s) inetd property values.\n"
119 " -M Modify default inetd property values.\n"));
120 }
121
122 /*
123 * Add the proto list contained in array 'plist' to entry 'entry', storing
124 * aside the scf_value_t's created and added to the entry in a list that the
125 * pointer referenced by sv_list is made to point at.
126 */
127 static void
add_proto_list(scf_transaction_entry_t * entry,scf_handle_t * hdl,char ** plist,uu_list_t ** sv_list)128 add_proto_list(scf_transaction_entry_t *entry, scf_handle_t *hdl,
129 char **plist, uu_list_t **sv_list)
130 {
131 scf_val_el_t *sv_el;
132 int i;
133
134 static uu_list_pool_t *sv_pool = NULL;
135
136 if ((sv_pool == NULL) &&
137 ((sv_pool = uu_list_pool_create("sv_pool",
138 sizeof (scf_val_el_t), offsetof(scf_val_el_t, link), NULL,
139 UU_LIST_POOL_DEBUG)) == NULL))
140 uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error()));
141
142 if ((*sv_list = uu_list_create(sv_pool, NULL, 0)) == NULL)
143 uu_die(gettext("Error: %s.\n"), uu_strerror(uu_error()));
144
145 for (i = 0; plist[i] != NULL; i++) {
146 if ((sv_el = malloc(sizeof (scf_val_el_t))) == NULL)
147 uu_die(gettext("Error:"));
148
149 if (((sv_el->val = scf_value_create(hdl)) == NULL) ||
150 (scf_value_set_astring(sv_el->val, plist[i]) != 0) ||
151 (scf_entry_add_value(entry, sv_el->val) != 0))
152 scfdie();
153
154 uu_list_node_init(sv_el, &sv_el->link, sv_pool);
155 (void) uu_list_insert_after(*sv_list, NULL, sv_el);
156 }
157 }
158
159 /*
160 * A counterpart to add_proto_list(), this function removes and frees the
161 * scf_value_t's it added to entry 'entry'.
162 */
163 static void
remove_proto_list(scf_transaction_entry_t * entry,uu_list_t * sv_list)164 remove_proto_list(scf_transaction_entry_t *entry, uu_list_t *sv_list)
165 {
166 scf_val_el_t *sv_el;
167 void *cookie = NULL;
168
169 scf_entry_reset(entry);
170
171 while ((sv_el = uu_list_teardown(sv_list, &cookie)) != NULL) {
172 scf_value_destroy(sv_el->val);
173 free(sv_el);
174 }
175
176 uu_list_destroy(sv_list);
177 }
178
179 /*
180 * modify_prop takes an instance, property group, property name, type, and
181 * value, and modifies the specified property in the repository to the
182 * submitted value.
183 */
184
185 static void
modify_prop(const scf_instance_t * inst,const char * pg,const char * prop,scf_type_t type,void * value)186 modify_prop(const scf_instance_t *inst, const char *pg, const char *prop,
187 scf_type_t type, void *value)
188 {
189 scf_transaction_t *tx;
190 scf_transaction_entry_t *ent;
191 scf_propertygroup_t *gpg;
192 scf_property_t *eprop;
193 scf_value_t *v;
194 int ret, create = 0;
195 char *fmri;
196 ssize_t max_fmri_len;
197
198 if ((gpg = scf_pg_create(h)) == NULL ||
199 (eprop = scf_property_create(h)) == NULL ||
200 (v = scf_value_create(h)) == NULL)
201 scfdie();
202
203 /* Get the property group or create it if it is missing. */
204 if (scf_instance_get_pg(inst, pg, gpg) == -1) {
205 if (scf_error() != SCF_ERROR_NOT_FOUND)
206 scfdie();
207
208 max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
209 if ((fmri = malloc(max_fmri_len + 1)) == NULL)
210 uu_die(gettext("Error: Out of memory.\n"));
211
212 if (scf_instance_to_fmri(inst, fmri, max_fmri_len + 1) < 0)
213 scfdie();
214
215 syslog(LOG_NOTICE, "inetadm: Property group \"%s\" missing "
216 "from \"%s\", attempting to add it.\n", pg, fmri);
217 free(fmri);
218
219 if (scf_instance_add_pg(inst, pg, SCF_GROUP_FRAMEWORK, 0,
220 gpg) == -1) {
221 switch (scf_error()) {
222 case SCF_ERROR_EXISTS:
223 break;
224 case SCF_ERROR_PERMISSION_DENIED:
225 uu_die(gettext("Error: Permission denied.\n"));
226 default:
227 scfdie();
228 }
229 }
230 }
231
232 if (scf_pg_get_property(gpg, prop, eprop) == -1) {
233 if (scf_error() != SCF_ERROR_NOT_FOUND)
234 scfdie();
235
236 create = 1;
237 }
238
239 if ((tx = scf_transaction_create(h)) == NULL ||
240 (ent = scf_entry_create(h)) == NULL)
241 scfdie();
242
243 do {
244 uu_list_t *sv_list;
245
246 if (scf_transaction_start(tx, gpg) == -1) {
247 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
248 scfdie();
249
250 uu_die(gettext("Error: Permission denied.\n"));
251 }
252
253 /* Modify the property or create it if it is missing */
254 if (create)
255 ret = scf_transaction_property_new(tx, ent, prop, type);
256 else
257 ret = scf_transaction_property_change_type(tx, ent,
258 prop, type);
259 if (ret == -1)
260 scfdie();
261
262 switch (type) {
263 case SCF_TYPE_BOOLEAN:
264 scf_value_set_boolean(v, *(uint8_t *)value);
265 break;
266 case SCF_TYPE_INTEGER:
267 scf_value_set_integer(v, *(int64_t *)value);
268 break;
269 case SCF_TYPE_ASTRING:
270 if (strcmp(prop, PR_PROTO_NAME) == 0) {
271 add_proto_list(ent, h, (char **)value,
272 &sv_list);
273 } else if (scf_value_set_astring(v, value) == -1) {
274 scfdie();
275 }
276 break;
277 default:
278 uu_die(gettext("Error: Internal inetadm error"));
279 }
280
281 if ((strcmp(prop, PR_PROTO_NAME) != 0) &&
282 (scf_entry_add_value(ent, v) == -1))
283 scfdie();
284
285 ret = scf_transaction_commit(tx);
286 if (ret == -1) {
287 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
288 scfdie();
289
290 uu_die(gettext("Error: Permission denied.\n"));
291 }
292
293 scf_transaction_reset(tx);
294
295 if (ret == 0) {
296 if (scf_pg_update(gpg) == -1)
297 scfdie();
298 }
299
300 if (strcmp(prop, PR_PROTO_NAME) == 0)
301 remove_proto_list(ent, sv_list);
302
303 } while (ret == 0);
304
305 scf_value_destroy(v);
306 scf_entry_destroy(ent);
307 scf_transaction_destroy(tx);
308 scf_property_destroy(eprop);
309 scf_pg_destroy(gpg);
310 }
311
312 /*
313 * delete_prop takes an instance, property group name and property, and
314 * deletes the specified property from the repository.
315 */
316
317 static void
delete_prop(const scf_instance_t * inst,const char * pg,const char * prop)318 delete_prop(const scf_instance_t *inst, const char *pg, const char *prop)
319 {
320 scf_transaction_t *tx;
321 scf_transaction_entry_t *ent;
322 scf_propertygroup_t *gpg;
323 scf_property_t *eprop;
324 int ret;
325
326 if ((gpg = scf_pg_create(h)) == NULL ||
327 (eprop = scf_property_create(h)) == NULL ||
328 (tx = scf_transaction_create(h)) == NULL ||
329 (ent = scf_entry_create(h)) == NULL)
330 scfdie();
331
332 if (scf_instance_get_pg(inst, pg, gpg) != SCF_SUCCESS) {
333 if (scf_error() != SCF_ERROR_NOT_FOUND)
334 scfdie();
335
336 uu_die(gettext("Error: \"%s\" property group missing.\n"), pg);
337 }
338
339 do {
340 if (scf_transaction_start(tx, gpg) != SCF_SUCCESS) {
341 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
342 scfdie();
343
344 uu_die(gettext("Error: Permission denied.\n"));
345 }
346
347 if (scf_transaction_property_delete(tx, ent,
348 prop) != SCF_SUCCESS) {
349 if (scf_error() != SCF_ERROR_NOT_FOUND)
350 scfdie();
351
352 uu_die(
353 gettext("Error: \"%s\" property does not exist.\n"),
354 prop);
355 }
356
357 ret = scf_transaction_commit(tx);
358 if (ret < 0) {
359 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
360 scfdie();
361
362 uu_die(gettext("Error: Permission denied.\n"));
363 }
364 if (ret == 0) {
365 scf_transaction_reset(tx);
366 if (scf_pg_update(gpg) == -1)
367 scfdie();
368 }
369 } while (ret == 0);
370
371 (void) scf_entry_destroy(ent);
372 scf_transaction_destroy(tx);
373 scf_property_destroy(eprop);
374 scf_pg_destroy(gpg);
375 }
376
377 /*
378 * commit_props evaluates an entire property list that has been created
379 * based on command line options, and either deletes or modifies properties
380 * as requested.
381 */
382
383 static void
commit_props(const scf_instance_t * inst,inetd_prop_t * mod,boolean_t defaults)384 commit_props(const scf_instance_t *inst, inetd_prop_t *mod, boolean_t defaults)
385 {
386 int i;
387 uint8_t new_bool;
388
389 for (i = 0; mod[i].ip_name != NULL; i++) {
390 switch (mod[i].ip_error) {
391 case IVE_UNSET:
392 break;
393 case IVE_INVALID:
394 delete_prop(inst, mod[i].ip_pg, mod[i].ip_name);
395 break;
396 case IVE_VALID:
397 switch (mod[i].ip_type) {
398 case INET_TYPE_STRING:
399 modify_prop(inst,
400 defaults ? PG_NAME_SERVICE_DEFAULTS :
401 mod[i].ip_pg, mod[i].ip_name,
402 SCF_TYPE_ASTRING,
403 mod[i].ip_value.iv_string);
404 break;
405 case INET_TYPE_STRING_LIST:
406 modify_prop(inst,
407 defaults ? PG_NAME_SERVICE_DEFAULTS :
408 mod[i].ip_pg, mod[i].ip_name,
409 SCF_TYPE_ASTRING,
410 mod[i].ip_value.iv_string_list);
411 break;
412 case INET_TYPE_INTEGER:
413 modify_prop(inst,
414 defaults ? PG_NAME_SERVICE_DEFAULTS :
415 mod[i].ip_pg, mod[i].ip_name,
416 SCF_TYPE_INTEGER, &mod[i].ip_value.iv_int);
417 break;
418 case INET_TYPE_BOOLEAN:
419 new_bool = (mod[i].ip_value.iv_boolean) ? 1 : 0;
420
421 modify_prop(inst,
422 defaults ? PG_NAME_SERVICE_DEFAULTS :
423 mod[i].ip_pg, mod[i].ip_name,
424 SCF_TYPE_BOOLEAN, &new_bool);
425 break;
426 }
427 }
428 }
429 }
430
431 /*
432 * list_callback is the callback function to be handed to simple_walk_instances
433 * in list_services. It is called once on every instance on a machine. If
434 * that instance is controlled by inetd, it prints enabled/disabled, state,
435 * and instance FMRI.
436 */
437
438 /*ARGSUSED*/
439 static int
list_callback(scf_handle_t * hin,scf_instance_t * inst,void * buf)440 list_callback(scf_handle_t *hin, scf_instance_t *inst, void *buf)
441 {
442 ssize_t max_name_length;
443 char *inst_name;
444 scf_simple_prop_t *prop = NULL, *prop2 = NULL;
445 const uint8_t *enabled;
446 const char *state, *restart_str;
447
448 max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
449 if ((inst_name = malloc(max_name_length + 1)) == NULL)
450 uu_die(gettext("Error: Out of memory.\n"));
451
452 /*
453 * Get the FMRI of the instance, and check if its delegated restarter
454 * is inetd.
455 */
456
457 if (scf_instance_to_fmri(inst, inst_name, max_name_length + 1) < 0)
458 return (SCF_FAILED);
459
460 if ((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL,
461 SCF_PROPERTY_RESTARTER)) == NULL)
462 goto out;
463
464 if ((restart_str = scf_simple_prop_next_ustring(prop)) == NULL)
465 goto out;
466
467 if (strstr(restart_str, INETADM_INETD_STR) == NULL)
468 goto out;
469
470 /* Free restarter prop so it can be reused below */
471 scf_simple_prop_free(prop);
472
473 /*
474 * We know that this instance is managed by inetd.
475 * Now get the enabled and state properties.
476 */
477
478 if (((prop = scf_simple_prop_get(hin, inst_name, SCF_PG_GENERAL,
479 SCF_PROPERTY_ENABLED)) == NULL) ||
480 ((enabled = scf_simple_prop_next_boolean(prop)) == NULL)) {
481 (void) uu_warn(gettext("Error: Instance %s is missing enabled "
482 "property.\n"), inst_name);
483 goto out;
484 }
485
486 if (((prop2 = scf_simple_prop_get(hin, inst_name, SCF_PG_RESTARTER,
487 SCF_PROPERTY_STATE)) == NULL) ||
488 ((state = scf_simple_prop_next_astring(prop2)) == NULL)) {
489 (void) uu_warn(gettext("Error: Instance %s is missing state "
490 "property.\n"), inst_name);
491 goto out;
492 }
493
494 /* Print enabled/disabled, state, and FMRI for the instance. */
495
496 if (*enabled)
497 (void) printf("%-10s%-15s%s\n", INETADM_ENABLED_STR, state,
498 inst_name);
499 else
500 (void) printf("%-10s%-15s%s\n", INETADM_DISABLED_STR, state,
501 inst_name);
502
503 out:
504 free(inst_name);
505 scf_simple_prop_free(prop);
506 scf_simple_prop_free(prop2);
507 return (SCF_SUCCESS);
508 }
509
510 /*
511 * list_services calls list_callback on every instance on the machine.
512 */
513
514 static void
list_services()515 list_services()
516 {
517 (void) printf("%-10s%-15s%s\n", "ENABLED", "STATE", "FMRI");
518
519 if (scf_simple_walk_instances(SCF_STATE_ALL, NULL, list_callback) ==
520 SCF_FAILED)
521 scfdie();
522 }
523
524 static void
print_prop_val(inetd_prop_t * prop)525 print_prop_val(inetd_prop_t *prop)
526 {
527 switch (prop->ip_type) {
528 case INET_TYPE_STRING:
529 (void) printf("\"%s\"\n", prop->ip_value.iv_string);
530 break;
531 case INET_TYPE_STRING_LIST:
532 {
533 int j = 0;
534 char **cpp = prop->ip_value.iv_string_list;
535
536 /*
537 * Print string list as comma separated list.
538 */
539
540 (void) printf("\"%s", cpp[j]);
541 while (cpp[++j] != NULL)
542 (void) printf(",%s", cpp[j]);
543 (void) printf("\"\n");
544 }
545 break;
546 case INET_TYPE_INTEGER:
547 (void) printf("%lld\n", prop->ip_value.iv_int);
548 break;
549 case INET_TYPE_BOOLEAN:
550 if (prop->ip_value.iv_boolean)
551 (void) printf("%s\n", INETADM_TRUE_STR);
552 else
553 (void) printf("%s\n", INETADM_FALSE_STR);
554 break;
555 }
556 }
557
558 /*
559 * list_props_cb is a callback function for scf_walk_fmri that lists all
560 * relevant inetd properties for an instance managed by inetd.
561 */
562
563 /* ARGSUSED0 */
564 static int
list_props_cb(void * data,scf_walkinfo_t * wip)565 list_props_cb(void *data, scf_walkinfo_t *wip)
566 {
567 int i;
568 const char *instname = wip->fmri;
569 scf_simple_prop_t *prop;
570 inetd_prop_t *proplist;
571 const char *restart_str;
572 boolean_t is_rpc = B_FALSE;
573 size_t numprops;
574 scf_handle_t *h;
575 scf_error_t err;
576
577 if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
578 (scf_handle_bind(h) == -1))
579 scfdie();
580
581 /*
582 * Get the property that holds the name of this instance's
583 * restarter, and make sure that it is inetd.
584 */
585 if ((prop = scf_simple_prop_get(h, instname, SCF_PG_GENERAL,
586 SCF_PROPERTY_RESTARTER)) == NULL) {
587 if (scf_error() == SCF_ERROR_NOT_FOUND)
588 uu_die(gettext("Error: Specified service instance "
589 "\"%s\" has no restarter property. inetd is not "
590 "the delegated restarter of this instance.\n"),
591 instname);
592 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT)
593 uu_die(gettext("Error: \"%s\" is not a valid service "
594 "instance.\n"), instname);
595
596 scfdie();
597 }
598
599 if (((restart_str = scf_simple_prop_next_ustring(prop)) == NULL) ||
600 (strstr(restart_str, INETADM_INETD_STR) == NULL)) {
601 uu_die(gettext("Error: inetd is not the delegated restarter of "
602 "specified service instance \"%s\".\n"), instname);
603 }
604
605 scf_simple_prop_free(prop);
606
607 /*
608 * This instance is controlled by inetd, so now we display all
609 * of its properties. First the mandatory properties, and then
610 * the properties that have default values, substituting the
611 * default values inherited from inetd as necessary (this is done
612 * for us by read_instance_props()).
613 */
614
615 if ((proplist = read_instance_props(h, instname, &numprops, &err)) ==
616 NULL) {
617 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
618 scf_strerror(err));
619 }
620 scf_handle_destroy(h);
621
622 (void) printf("%-9s%s\n", "SCOPE", "NAME=VALUE");
623
624 for (i = 0; i < numprops; i++) {
625 /* Skip rpc version properties if it's not an RPC service */
626 if ((strcmp(PR_RPC_LW_VER_NAME, proplist[i].ip_name) == 0) ||
627 (strcmp(PR_RPC_HI_VER_NAME, proplist[i].ip_name) == 0))
628 if (!is_rpc)
629 continue;
630
631 /* If it's not an unset property, print it out. */
632 if (proplist[i].ip_error != IVE_UNSET) {
633 if (strcmp(PR_ISRPC_NAME, proplist[i].ip_name) == 0)
634 is_rpc = proplist[i].ip_value.iv_boolean;
635
636 (void) printf("%-9s%s=",
637 proplist[i].from_inetd ? INETADM_DEFAULT_STR : "",
638 proplist[i].ip_name);
639 print_prop_val(&proplist[i]);
640 continue;
641 }
642
643 /* arg0 is non-default, but also doesn't have to be set. */
644
645 if (i == PT_ARG0_INDEX)
646 continue;
647
648 /* all other properties should have values. */
649 if (proplist[i].ip_default) {
650 (void) uu_warn(gettext("Error: Property %s is missing "
651 "and has no defined default value.\n"),
652 proplist[i].ip_name);
653 } else {
654 (void) uu_warn(gettext("Error: Required property %s is "
655 "missing.\n"), proplist[i].ip_name);
656 }
657 }
658
659 free_instance_props(proplist);
660 return (0);
661 }
662
663 /*
664 * set_svc_enable_cb is a callback function for scf_walk_fmri that sets the
665 * enabled property in the repository for an instance based on the value given
666 * by 'data'.
667 */
668
669 static int
set_svc_enable_cb(void * data,scf_walkinfo_t * wip)670 set_svc_enable_cb(void *data, scf_walkinfo_t *wip)
671 {
672 uint8_t desired = *(uint8_t *)data;
673 const char *instname = wip->fmri;
674
675 if (desired) {
676 if (smf_enable_instance(instname, 0) == 0)
677 return (0);
678 } else {
679 if (smf_disable_instance(instname, 0) == 0)
680 return (0);
681 }
682
683 switch (scf_error()) {
684 case SCF_ERROR_INVALID_ARGUMENT:
685 uu_die(gettext("Error: \"%s\" is not a valid service "
686 "instance.\n"), instname);
687 break;
688 case SCF_ERROR_NOT_FOUND:
689 uu_die(gettext("Error: Service instance \"%s\" not found.\n"),
690 instname);
691 break;
692 default:
693 scfdie();
694 }
695
696 return (0);
697 }
698
699 /*
700 * list_defaults lists all the default property values being provided by
701 * inetd.
702 */
703
704 static void
list_defaults()705 list_defaults()
706 {
707 scf_handle_t *h;
708 scf_error_t err;
709 int i;
710 inetd_prop_t *proptable;
711 size_t numprops;
712
713 if (((h = scf_handle_create(SCF_VERSION)) == NULL) ||
714 (scf_handle_bind(h) == -1))
715 scfdie();
716
717 if ((proptable = read_default_props(h, &numprops, &err)) == NULL) {
718 uu_die(gettext("Unexpected libscf error: %s. Exiting.\n"),
719 scf_strerror(err));
720 }
721
722 (void) printf("NAME=VALUE\n");
723
724 for (i = 0; i < numprops; i++) {
725 if (!proptable[i].ip_default)
726 continue;
727
728 if (proptable[i].ip_error == IVE_UNSET) {
729 (void) uu_warn(gettext("Error: Default property %s "
730 "missing.\n"), proptable[i].ip_name);
731 continue;
732 }
733
734 (void) printf("%s=", proptable[i].ip_name);
735 print_prop_val(&proptable[i]);
736 }
737
738 free_instance_props(proptable);
739 }
740
741 /*
742 * modify_inst_props_cb is a callback function for scf_walk_fmri that modifies
743 * the properties that are given as name=value pairs on the command line
744 * to the requested value.
745 */
746
747 static int
modify_inst_props_cb(void * data,scf_walkinfo_t * wip)748 modify_inst_props_cb(void *data, scf_walkinfo_t *wip)
749 {
750 int i, j;
751 char *value;
752 const char *fmri = wip->fmri;
753 scf_instance_t *inst = wip->inst;
754 inetd_prop_t *mod, *prop_table;
755 size_t numprops;
756 ssize_t max_val;
757 int64_t new_int;
758 int argc = ((arglist_t *)data)->argc;
759 char **argv = ((arglist_t *)data)->argv;
760
761 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
762 scfdie();
763
764 prop_table = get_prop_table(&numprops);
765
766 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
767 uu_die(gettext("Error: Out of memory.\n"));
768
769 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
770
771 /*
772 * For each property to be changed, look up the property name in the
773 * property table. Change each property in the mod array, and then
774 * write the entire thing back.
775 */
776 for (i = 0; i < argc; i++) {
777 /* Separate argument into name and value pair */
778 if ((value = strchr(argv[i], '=')) == NULL)
779 uu_die(gettext("Error: Malformed name=value pair "
780 "\"%s\"\n"), argv[i]);
781
782 *value = '\0';
783 value++;
784
785 /* Find property name in array of properties */
786 for (j = 0; mod[j].ip_name != NULL; j++) {
787 if (strcmp(mod[j].ip_name, argv[i]) == 0)
788 break;
789 }
790
791 if (mod[j].ip_name == NULL)
792 uu_die(gettext("Error: \"%s\" is not a valid "
793 "property.\n"), argv[i]);
794
795 if (*value == '\0') {
796 if ((mod[j].ip_default) || (j == PT_ARG0_INDEX)) {
797 /* mark property for deletion */
798 mod[j].ip_error = IVE_INVALID;
799
800 /* return the '=' taken out above */
801 *(--value) = '=';
802
803 continue;
804 } else {
805 uu_die(gettext("\"%s\" is a mandatory "
806 "property and can not be deleted.\n"),
807 argv[i]);
808 }
809 }
810
811 switch (mod[j].ip_type) {
812 case INET_TYPE_INTEGER:
813 if (uu_strtoint(value, &new_int, sizeof (new_int), 0,
814 0, 0) == -1)
815 uu_die(gettext("Error: \"%s\" is not a valid "
816 "integer value.\n"), value);
817
818 mod[j].ip_value.iv_int = new_int;
819 break;
820 case INET_TYPE_STRING:
821 if (strlen(value) >= max_val) {
822 uu_die(gettext("Error: String value is longer "
823 "than %l characters.\n"), max_val);
824 } else if ((mod[j].ip_value.iv_string = strdup(value))
825 == NULL) {
826 uu_die(gettext("Error: Out of memory.\n"));
827 }
828 break;
829 case INET_TYPE_STRING_LIST:
830 if ((mod[j].ip_value.iv_string_list =
831 get_protos(value)) == NULL) {
832 if (errno == ENOMEM) {
833 uu_die(gettext(
834 "Error: Out of memory.\n"));
835 } else if (errno == E2BIG) {
836 uu_die(gettext(
837 "Error: String value in "
838 "%s property longer than "
839 "%l characters.\n"),
840 PR_PROTO_NAME, max_val);
841 } else {
842 uu_die(gettext(
843 "Error: No values "
844 "specified for %s "
845 "property.\n"),
846 PR_PROTO_NAME);
847 }
848 }
849 break;
850 case INET_TYPE_BOOLEAN:
851 if (strcasecmp(value, INETADM_TRUE_STR) == 0)
852 mod[j].ip_value.iv_boolean = B_TRUE;
853 else if (strcasecmp(value, INETADM_FALSE_STR) == 0)
854 mod[j].ip_value.iv_boolean = B_FALSE;
855 else
856 uu_die(gettext("Error: \"%s\" is not a valid "
857 "boolean value. (TRUE or FALSE)\n"), value);
858 }
859 /* mark property for modification */
860 mod[j].ip_error = IVE_VALID;
861
862 /* return the '=' taken out above */
863 *(--value) = '=';
864 }
865
866 commit_props(inst, mod, B_FALSE);
867 free(mod);
868 if (smf_refresh_instance(fmri) != 0)
869 uu_die(gettext("Error: Unable to refresh instance %s.\n"),
870 fmri);
871
872 return (0);
873 }
874
875 /*
876 * modify_defaults takes n name=value pairs for inetd default property values,
877 * parses them, and then modifies the values in the repository.
878 */
879
880 static void
modify_defaults(int argc,char * argv[])881 modify_defaults(int argc, char *argv[])
882 {
883 int i, j;
884 char *value;
885 scf_instance_t *inst;
886 inetd_prop_t *mod, *prop_table;
887 size_t numprops;
888 ssize_t max_val;
889 int64_t new_int;
890
891 if ((inst = scf_instance_create(h)) == NULL)
892 scfdie();
893
894 if (scf_handle_decode_fmri(h, INETD_INSTANCE_FMRI, NULL, NULL,
895 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
896 if (scf_error() == SCF_ERROR_NOT_FOUND) {
897 uu_die(gettext("inetd instance missing in repository."
898 "\n"));
899 } else {
900 scfdie();
901 }
902 }
903
904 if ((max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
905 scfdie();
906
907 prop_table = get_prop_table(&numprops);
908
909 if ((mod = malloc(numprops * sizeof (inetd_prop_t))) == NULL)
910 uu_die(gettext("Error: Out of memory.\n"));
911
912 (void) memcpy(mod, prop_table, numprops * sizeof (inetd_prop_t));
913
914 for (i = 0; i < argc; i++) {
915 /* Separate argument into name and value pair */
916 if ((value = strchr(argv[i], '=')) == NULL)
917 uu_die(gettext("Error: Malformed name=value pair \"%s"
918 "\"\n"), argv[i]);
919
920 *value = '\0';
921 value++;
922
923 /* Find property name in array of defaults */
924 for (j = 0; mod[j].ip_name != NULL; j++) {
925 if (!mod[j].ip_default)
926 continue;
927 if (strcmp(mod[j].ip_name, argv[i]) == 0)
928 break;
929 }
930
931 if (mod[j].ip_name == NULL)
932 uu_die(gettext("Error: \"%s\" is not a default inetd "
933 "property.\n"), argv[i]);
934
935 if (*value == '\0')
936 uu_die(gettext("Cannot accept NULL values for default "
937 "properties.\n"));
938
939 switch (mod[j].ip_type) {
940 case INET_TYPE_INTEGER:
941 if (uu_strtoint(value, &new_int, sizeof (new_int), 0,
942 0, 0) == -1)
943 uu_die(gettext("Error: \"%s\" is not a valid "
944 "integer value.\n"), value);
945
946 mod[j].ip_value.iv_int = new_int;
947 break;
948 case INET_TYPE_STRING:
949 if (strlen(value) >= max_val)
950 uu_die(gettext("Error: String value is longer "
951 "than %l characters.\n"), max_val);
952 if ((mod[j].ip_value.iv_string = strdup(value))
953 == NULL)
954 uu_die(gettext("Error: Out of memory.\n"));
955 break;
956 case INET_TYPE_BOOLEAN:
957 if (strcasecmp(value, INETADM_TRUE_STR) == 0)
958 mod[j].ip_value.iv_boolean = B_TRUE;
959 else if (strcasecmp(value, INETADM_FALSE_STR) == 0)
960 mod[j].ip_value.iv_boolean = B_FALSE;
961 else
962 uu_die(gettext("Error: \"%s\" is not a valid "
963 "boolean value. (TRUE or FALSE)\n"), value);
964 }
965 /* mark property for modification */
966 mod[j].ip_error = IVE_VALID;
967 }
968
969 commit_props(inst, mod, B_TRUE);
970 free(mod);
971 scf_instance_destroy(inst);
972 if (refresh_inetd() != 0)
973 uu_warn(gettext("Warning: Unable to refresh inetd.\n"));
974 }
975
976 int
main(int argc,char * argv[])977 main(int argc, char *argv[])
978 {
979 int opt;
980 uint_t lflag, eflag, dflag, pflag, mflag, Mflag;
981 uint8_t enable;
982 scf_error_t serr;
983 int exit_status = 0;
984
985 (void) setlocale(LC_ALL, "");
986 (void) textdomain(TEXT_DOMAIN);
987
988 if ((h = scf_handle_create(SCF_VERSION)) == NULL)
989 scfdie();
990
991 if (scf_handle_bind(h) == -1)
992 uu_die(gettext("Error: Couldn't bind to svc.configd.\n"));
993
994 if (argc == 1) {
995 list_services();
996 goto out;
997 }
998
999 lflag = eflag = dflag = pflag = mflag = Mflag = 0;
1000 while ((opt = getopt(argc, argv, "ledpMm?")) != -1) {
1001 switch (opt) {
1002 case 'l':
1003 lflag = 1;
1004 break;
1005 case 'e':
1006 eflag = 1;
1007 break;
1008 case 'd':
1009 dflag = 1;
1010 break;
1011 case 'p':
1012 pflag = 1;
1013 break;
1014 case 'M':
1015 Mflag = 1;
1016 break;
1017 case 'm':
1018 mflag = 1;
1019 break;
1020 case '?':
1021 if (optopt == '?') {
1022 usage(B_TRUE);
1023 goto out;
1024 } else {
1025 usage(B_FALSE);
1026 }
1027 break;
1028 default:
1029 usage(B_FALSE);
1030 }
1031 }
1032
1033 /*
1034 * All options are mutually exclusive, and we must have an option
1035 * if we reached here.
1036 */
1037 if (lflag + eflag + dflag + pflag + mflag + Mflag != 1)
1038 usage(B_FALSE);
1039
1040 argv += optind;
1041 argc -= optind;
1042 if ((pflag == 0) && (argc == 0))
1043 usage(B_FALSE);
1044
1045 serr = 0;
1046 if (lflag) {
1047 serr = scf_walk_fmri(h, argc, argv, 0, list_props_cb, NULL,
1048 &exit_status, uu_warn);
1049 } else if (dflag) {
1050 enable = 0;
1051 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
1052 &enable, &exit_status, uu_warn);
1053 } else if (eflag) {
1054 enable = 1;
1055 serr = scf_walk_fmri(h, argc, argv, 0, set_svc_enable_cb,
1056 &enable, &exit_status, uu_warn);
1057 } else if (mflag) {
1058 arglist_t args;
1059 char **cpp = argv;
1060 uint_t fmri_args = 0;
1061
1062 /* count number of fmri arguments */
1063 while ((fmri_args < argc) && (strchr(*cpp, '=') == NULL)) {
1064 fmri_args++;
1065 cpp++;
1066 }
1067
1068 /* if no x=y args or no fmri, show usage */
1069 if ((fmri_args == argc) || (fmri_args == 0))
1070 usage(B_FALSE);
1071
1072 /* setup args for modify_inst_props_cb */
1073 args.argc = argc - fmri_args;
1074 args.argv = argv + fmri_args;
1075
1076 serr = scf_walk_fmri(h, fmri_args, argv, 0,
1077 modify_inst_props_cb, &args, &exit_status, uu_warn);
1078 } else if (Mflag) {
1079 modify_defaults(argc, argv);
1080 } else if (pflag) {
1081 /* ensure there's no trailing garbage */
1082 if (argc != 0)
1083 usage(B_FALSE);
1084 list_defaults();
1085 }
1086 if (serr != 0) {
1087 uu_warn(gettext("failed to iterate over instances: %s"),
1088 scf_strerror(serr));
1089 exit(UU_EXIT_FATAL);
1090 }
1091
1092 out:
1093 (void) scf_handle_unbind(h);
1094 scf_handle_destroy(h);
1095
1096 return (exit_status);
1097 }
1098