4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
37 #include <sys/corectl.h>
40 #include <libscf_priv.h>
43 #define E_SUCCESS 0 /* Exit status for success */
44 #define E_ERROR 1 /* Exit status for error */
45 #define E_USAGE 2 /* Exit status for usage error */
47 static const char PATH_CONFIG
[] = "/etc/coreadm.conf";
48 static const char PATH_CONFIG_OLD
[] = "/etc/coreadm.conf.old";
50 #define COREADM_INST_NAME "system/coreadm:default"
51 #define COREADM_INST_FMRI \
52 SCF_FMRI_SVC_PREFIX SCF_FMRI_SERVICE_PREFIX COREADM_INST_NAME
54 #define CONFIG_PARAMS "config_params"
55 #define GLOBAL_ENABLED "global_enabled"
56 #define PROCESS_ENABLED "process_enabled"
57 #define GLOBAL_SETID_ENABLED "global_setid_enabled"
58 #define PROCESS_SETID_ENABLED "process_setid_enabled"
59 #define GLOBAL_LOG_ENABLED "global_log_enabled"
60 #define GLOBAL_PATTERN "global_pattern"
61 #define GLOBAL_CONTENT "global_content"
62 #define INIT_PATTERN "init_pattern"
63 #define INIT_CONTENT "init_content"
66 static uint64_t options
;
67 static int alloptions
;
68 static char *glob_pattern
;
69 static char gpattern
[PATH_MAX
];
70 static core_content_t glob_content
= CC_CONTENT_INVALID
;
71 static char *init_pattern
;
72 static char ipattern
[PATH_MAX
];
73 static core_content_t init_content
= CC_CONTENT_INVALID
;
74 static char *proc_pattern
;
75 static size_t proc_size
;
76 static core_content_t proc_content
= CC_CONTENT_INVALID
;
78 static int report_settings(void);
79 static int do_processes(int, char **);
80 static int do_modify(boolean_t
);
81 static int do_update(void);
82 static int do_legacy(void);
84 static scf_propvec_t prop_gpattern
= { GLOBAL_PATTERN
, NULL
, SCF_TYPE_ASTRING
};
85 static scf_propvec_t prop_gcontent
= { GLOBAL_CONTENT
, NULL
, SCF_TYPE_ASTRING
};
86 static scf_propvec_t prop_ipattern
= { INIT_PATTERN
, NULL
, SCF_TYPE_ASTRING
};
87 static scf_propvec_t prop_icontent
= { INIT_CONTENT
, NULL
, SCF_TYPE_ASTRING
};
88 static scf_propvec_t prop_option
[] = {
89 { GLOBAL_ENABLED
, NULL
, SCF_TYPE_BOOLEAN
, NULL
, CC_GLOBAL_PATH
},
90 { PROCESS_ENABLED
, NULL
, SCF_TYPE_BOOLEAN
, NULL
, CC_PROCESS_PATH
},
91 { GLOBAL_SETID_ENABLED
, NULL
, SCF_TYPE_BOOLEAN
, NULL
, CC_GLOBAL_SETID
},
92 { PROCESS_SETID_ENABLED
, NULL
, SCF_TYPE_BOOLEAN
, NULL
, CC_PROCESS_SETID
},
93 { GLOBAL_LOG_ENABLED
, NULL
, SCF_TYPE_BOOLEAN
, NULL
, CC_GLOBAL_LOG
},
96 #define MAX_PROPS (4 + (sizeof (prop_option) / sizeof (scf_propvec_t)))
101 (void) fprintf(stderr
, gettext(
103 (void) fprintf(stderr
, gettext(
104 " %s [ -g pattern ] [ -i pattern ] [ -G content ] [ -I content ]\n"),
106 (void) fprintf(stderr
, gettext(
107 " [ -e {global | process | global-setid | proc-setid | log} ]\n"));
108 (void) fprintf(stderr
, gettext(
109 " [ -d {global | process | global-setid | proc-setid | log} ]\n"));
110 (void) fprintf(stderr
, gettext(
111 " %s [ -p pattern ] [ -P content ] [ pid ... ]\n"), command
);
118 (void) fprintf(stderr
, gettext("%s: insufficient privileges to "
119 "exercise the -[GIgied] options\n"), command
);
124 parse_content(char *arg
, core_content_t
*content
)
126 if (proc_str2content(arg
, content
) == 0)
128 (void) fprintf(stderr
, gettext("%s: invalid content string '%s'\n"),
134 main(int argc
, char **argv
)
140 int legacy_update
= 0;
146 char *curpid_ptr
= &curpid
[0];
148 (void) setlocale(LC_ALL
, "");
149 (void) textdomain(TEXT_DOMAIN
);
151 /* command name (e.g., "coreadm") */
152 if ((command
= strrchr(argv
[0], '/')) != NULL
)
157 while ((opt
= getopt(argc
, argv
, "g:G:i:I:p:P:e:d:uU?")) != EOF
) {
160 glob_pattern
= optarg
;
163 init_pattern
= optarg
;
166 proc_pattern
= optarg
;
167 proc_size
= strlen(proc_pattern
) + 1;
170 error
|= parse_content(optarg
, &glob_content
);
173 error
|= parse_content(optarg
, &init_content
);
176 error
|= parse_content(optarg
, &proc_content
);
180 if (strcmp(optarg
, "global") == 0)
181 flag
= CC_GLOBAL_PATH
;
182 else if (strcmp(optarg
, "process") == 0)
183 flag
= CC_PROCESS_PATH
;
184 else if (strcmp(optarg
, "global-setid") == 0)
185 flag
= CC_GLOBAL_SETID
;
186 else if (strcmp(optarg
, "proc-setid") == 0)
187 flag
= CC_PROCESS_SETID
;
188 else if (strcmp(optarg
, "log") == 0)
189 flag
= CC_GLOBAL_LOG
;
213 npids
= argc
- optind
;
214 pidlist
= argv
+ optind
;
220 * If 'modify' is true, we must modify the system settings
221 * and update the configuration file with the new parameters.
223 modify
= glob_pattern
!= NULL
|| glob_content
!= CC_CONTENT_INVALID
||
224 init_pattern
!= NULL
|| init_content
!= CC_CONTENT_INVALID
||
227 if ((update
|| legacy_update
) && (modify
|| proc_pattern
!= NULL
||
228 proc_content
!= CC_CONTENT_INVALID
|| npids
!= 0)) {
229 (void) fprintf(stderr
,
230 gettext("%s: the -u option must stand alone\n"), command
);
234 (proc_pattern
!= NULL
|| proc_content
!= CC_CONTENT_INVALID
)) {
235 (void) fprintf(stderr
, gettext(
236 "%s: -[GIgied] and -[Pp] options are mutually exclusive\n"),
240 if (modify
&& npids
!= 0) {
241 (void) fprintf(stderr
, gettext(
242 "%s: -[GIgied] options cannot have a process-id list\n"),
246 if ((proc_pattern
!= NULL
|| proc_content
!= CC_CONTENT_INVALID
) &&
248 (void) sprintf(curpid
, "%u", (uint_t
)getppid());
250 pidlist
= &curpid_ptr
;
254 return (do_legacy());
256 return (do_update());
258 return (do_modify(B_FALSE
));
260 return (do_processes(npids
, pidlist
));
262 return (report_settings());
266 report_settings(void)
268 char content_str
[PRCONTENTBUFSZ
];
270 if ((options
= core_get_options()) == -1) {
271 perror("core_get_options()");
274 if (core_get_global_path(gpattern
, sizeof (gpattern
)) != 0) {
275 perror("core_get_global_path()");
278 if (core_get_default_path(ipattern
, sizeof (ipattern
)) != 0) {
279 perror("core_get_default_path()");
282 if (core_get_global_content(&glob_content
) != 0) {
283 perror("core_get_global_content()");
286 if (core_get_default_content(&init_content
) != 0) {
287 perror("core_get_default_content()");
291 (void) printf(gettext(" global core file pattern: %s\n"),
293 (void) proc_content2str(glob_content
, content_str
,
294 sizeof (content_str
));
295 (void) printf(gettext(" global core file content: %s\n"),
297 (void) printf(gettext(" init core file pattern: %s\n"),
299 (void) proc_content2str(init_content
, content_str
,
300 sizeof (content_str
));
301 (void) printf(gettext(" init core file content: %s\n"),
303 (void) printf(gettext(" global core dumps: %s\n"),
304 (options
& CC_GLOBAL_PATH
)? "enabled" : "disabled");
305 (void) printf(gettext(" per-process core dumps: %s\n"),
306 (options
& CC_PROCESS_PATH
)? "enabled" : "disabled");
307 (void) printf(gettext(" global setid core dumps: %s\n"),
308 (options
& CC_GLOBAL_SETID
)? "enabled" : "disabled");
309 (void) printf(gettext(" per-process setid core dumps: %s\n"),
310 (options
& CC_PROCESS_SETID
)? "enabled" : "disabled");
311 (void) printf(gettext(" global core dump logging: %s\n"),
312 (options
& CC_GLOBAL_LOG
)? "enabled" : "disabled");
317 do_processes(int npids
, char **pidlist
)
319 char process_path
[PATH_MAX
];
320 core_content_t content
;
324 char content_str
[PRCONTENTBUFSZ
];
326 if (proc_pattern
== NULL
&& proc_content
== CC_CONTENT_INVALID
) {
327 while (npids
-- > 0) {
328 pid
= strtol(*pidlist
, &next
, 10);
329 if (*next
!= '\0' || !isdigit(**pidlist
)) {
330 (void) fprintf(stderr
,
331 gettext("%s: invalid process-id\n"),
334 } else if (core_get_process_path(process_path
,
335 sizeof (process_path
), pid
) != 0 ||
336 core_get_process_content(&content
, pid
) != 0) {
340 (void) proc_content2str(content
, content_str
,
341 sizeof (content_str
));
342 (void) printf(gettext("%s:\t%s\t%s\n"),
343 *pidlist
, process_path
, content_str
);
348 while (npids
-- > 0) {
349 pid
= strtol(*pidlist
, &next
, 10);
351 (void) fprintf(stderr
,
352 gettext("%s: invalid process-id\n"),
356 if (proc_pattern
!= NULL
&&
357 core_set_process_path(proc_pattern
,
358 proc_size
, pid
) != 0) {
363 if (proc_content
!= CC_CONTENT_INVALID
&&
364 core_set_process_content(
365 &proc_content
, pid
) != 0) {
378 addprop(scf_propvec_t
*props
, int size
, int count
, scf_propvec_t
*pv
, void *ptr
)
380 assert(count
+ 1 < size
);
382 props
[count
].pv_ptr
= ptr
;
386 is_online(const char *fmri
)
388 char *state
= smf_get_state(fmri
);
389 boolean_t result
= state
!= NULL
&&
390 strcmp(state
, SCF_STATE_STRING_ONLINE
) == 0;
397 * The user has specified the -g, -G, -i, -I, -d, or -e options to
398 * modify the given configuration parameter. Perform the modification
399 * in the smf repository and then perform a smf_refresh_instance which
400 * will cause a coreadm -u to occur which will transfer ALL coreadm
401 * configuration information from the repository to the kernel.
404 do_modify(boolean_t method
)
406 char gcontentstr
[PRCONTENTBUFSZ
];
407 char icontentstr
[PRCONTENTBUFSZ
];
409 scf_propvec_t properties
[MAX_PROPS
+ 1];
412 if (!method
&& !is_online(COREADM_INST_FMRI
)) {
413 (void) fprintf(stderr
,
414 gettext("%s: coreadm service not online\n"), command
);
418 if (glob_pattern
!= NULL
)
419 addprop(properties
, MAX_PROPS
, count
++, &prop_gpattern
,
422 if (glob_content
!= CC_CONTENT_INVALID
) {
423 (void) proc_content2str(glob_content
, gcontentstr
,
424 sizeof (gcontentstr
));
425 addprop(properties
, MAX_PROPS
, count
++, &prop_gcontent
,
429 if (init_pattern
!= NULL
)
430 addprop(properties
, MAX_PROPS
, count
++, &prop_ipattern
,
433 if (init_content
!= CC_CONTENT_INVALID
) {
434 (void) proc_content2str(init_content
, icontentstr
,
435 sizeof (icontentstr
));
436 addprop(properties
, MAX_PROPS
, count
++, &prop_icontent
,
440 for (prop
= prop_option
; prop
->pv_prop
!= NULL
; prop
++)
441 if ((alloptions
& prop
->pv_aux
) != 0)
442 addprop(properties
, MAX_PROPS
, count
++, prop
, &options
);
444 properties
[count
].pv_prop
= NULL
;
447 if (scf_write_propvec(COREADM_INST_FMRI
, CONFIG_PARAMS
, properties
,
448 &prop
) == SCF_FAILED
) {
450 (void) fprintf(stderr
, gettext(
451 "%s: Unable to write property '%s': %s"), command
,
452 prop
->pv_prop
, scf_strerror(scf_error()));
454 (void) fprintf(stderr
, gettext(
455 "%s: Unable to write configuration: %s\n"),
456 command
, scf_strerror(scf_error()));
461 if (smf_refresh_instance(COREADM_INST_FMRI
) != 0) {
462 (void) fprintf(stderr
,
463 gettext("%s: Unable to refresh %s: %s\n"
464 "Configuration stored but not made active.\n"),
465 command
, COREADM_INST_FMRI
, scf_strerror(scf_error()));
475 if (core_set_global_path(glob_pattern
, strlen(glob_pattern
) + 1) != 0)
476 return ("core_set_global_path()");
478 if (core_set_global_content(&glob_content
) != 0)
479 return ("core_set_global_content()");
481 if (core_set_default_path(init_pattern
, strlen(init_pattern
) + 1) != 0)
482 return ("core_set_default_path()");
484 if (core_set_default_content(&init_content
) != 0)
485 return ("core_set_init_content()");
487 if (core_set_options((int)options
) != 0)
488 return ("core_set_options()");
494 * BUFSIZE must be large enough to contain the longest path plus some more.
496 #define BUFSIZE (PATH_MAX + 80)
499 yes(char *name
, char *value
, int line
)
501 if (strcmp(value
, "yes") == 0)
503 if (strcmp(value
, "no") == 0)
505 (void) fprintf(stderr
, gettext(
506 "\"%s\", line %d: warning: value must be yes or no: %s=%s\n"),
507 PATH_CONFIG
, line
, name
, value
);
517 char name
[BUFSIZE
], value
[BUFSIZE
];
521 alloptions
= CC_OPTIONS
;
522 options
= CC_PROCESS_PATH
;
524 (void) strcpy(ipattern
, "core");
525 glob_content
= init_content
= CC_CONTENT_DEFAULT
;
527 glob_pattern
= gpattern
;
528 init_pattern
= ipattern
;
530 if ((fp
= fopen(PATH_CONFIG
, "r")) == NULL
)
533 for (line
= 1; fgets(buf
, sizeof (buf
), fp
) != NULL
; line
++) {
535 * Skip comment lines and empty lines.
537 if (buf
[0] == '#' || buf
[0] == '\n')
540 * Look for "name=value", with optional whitespace on either
541 * side, terminated by a newline, and consuming the whole line.
543 /* LINTED - unbounded string specifier */
544 n
= sscanf(buf
, " %[^=]=%s \n%n", name
, value
, &len
);
545 if (n
>= 1 && name
[0] != '\0' &&
546 (n
== 1 || len
== strlen(buf
))) {
549 if (strcmp(name
, "COREADM_GLOB_PATTERN") == 0) {
550 (void) strcpy(gpattern
, value
);
553 if (strcmp(name
, "COREADM_GLOB_CONTENT") == 0) {
554 (void) proc_str2content(value
, &glob_content
);
557 if (strcmp(name
, "COREADM_INIT_PATTERN") == 0) {
558 (void) strcpy(ipattern
, value
);
561 if (strcmp(name
, "COREADM_INIT_CONTENT") == 0) {
562 (void) proc_str2content(value
, &init_content
);
565 if (strcmp(name
, "COREADM_GLOB_ENABLED") == 0) {
566 if (yes(name
, value
, line
))
567 options
|= CC_GLOBAL_PATH
;
570 if (strcmp(name
, "COREADM_PROC_ENABLED") == 0) {
571 if (yes(name
, value
, line
))
572 options
|= CC_PROCESS_PATH
;
574 options
&= ~CC_PROCESS_PATH
;
577 if (strcmp(name
, "COREADM_GLOB_SETID_ENABLED") == 0) {
578 if (yes(name
, value
, line
))
579 options
|= CC_GLOBAL_SETID
;
582 if (strcmp(name
, "COREADM_PROC_SETID_ENABLED") == 0) {
583 if (yes(name
, value
, line
))
584 options
|= CC_PROCESS_SETID
;
587 if (strcmp(name
, "COREADM_GLOB_LOG_ENABLED") == 0) {
588 if (yes(name
, value
, line
))
589 options
|= CC_GLOBAL_LOG
;
592 (void) fprintf(stderr
, gettext(
593 "\"%s\", line %d: warning: invalid token: %s\n"),
594 PATH_CONFIG
, line
, name
);
596 (void) fprintf(stderr
,
597 gettext("\"%s\", line %d: syntax error\n"),
607 * Loads and applies the coreadm configuration stored in the default
608 * coreadm instance. As this option is (only) used from within an SMF
609 * service method, this function must return an SMF_EXIT_* exit status
616 scf_propvec_t properties
[MAX_PROPS
+ 1];
622 if ((errstr
= write_kernel()) != NULL
)
625 if (do_modify(B_TRUE
) != 0 ||
626 rename(PATH_CONFIG
, PATH_CONFIG_OLD
) != 0) {
627 (void) fprintf(stderr
, gettext(
628 "%s: failed to import legacy configuration.\n"),
630 return (SMF_EXIT_ERR_FATAL
);
632 return (SMF_EXIT_OK
);
635 addprop(properties
, MAX_PROPS
, count
++, &prop_gpattern
, &glob_pattern
);
636 addprop(properties
, MAX_PROPS
, count
++, &prop_gcontent
, &gcstr
);
637 addprop(properties
, MAX_PROPS
, count
++, &prop_ipattern
, &init_pattern
);
638 addprop(properties
, MAX_PROPS
, count
++, &prop_icontent
, &icstr
);
639 for (prop
= prop_option
; prop
->pv_prop
!= NULL
; prop
++)
640 addprop(properties
, MAX_PROPS
, count
++, prop
, &options
);
641 properties
[count
].pv_prop
= NULL
;
643 alloptions
= CC_OPTIONS
;
644 if (scf_read_propvec(COREADM_INST_FMRI
, CONFIG_PARAMS
, B_TRUE
,
645 properties
, &prop
) == SCF_FAILED
) {
647 (void) fprintf(stderr
, gettext(
648 "%s: configuration property '%s' not found.\n"),
649 command
, prop
->pv_prop
);
651 (void) fprintf(stderr
, gettext(
652 "%s: unable to read configuration: %s\n"),
653 command
, scf_strerror(scf_error()));
655 return (SMF_EXIT_ERR_FATAL
);
658 (void) proc_str2content(gcstr
, &glob_content
);
659 (void) proc_str2content(icstr
, &init_content
);
661 errstr
= write_kernel();
662 scf_clean_propvec(properties
);
664 return (SMF_EXIT_OK
);
667 if (errno
== EPERM
) {
669 return (SMF_EXIT_ERR_PERM
);
672 return (SMF_EXIT_ERR_FATAL
);
675 static int do_legacy()
679 if (read_legacy() && (errstr
= write_kernel()) != NULL
) {