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