summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c12
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/inetd/inetd_impl.h14
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/inetd/repval.c601
-rw-r--r--usr/src/cmd/svc/svcs/svcs.c428
-rw-r--r--usr/src/lib/libscf/Makefile.com5
-rw-r--r--usr/src/lib/libscf/common/mapfile-vers1
-rw-r--r--usr/src/lib/libscf/common/midlevel.c61
-rw-r--r--usr/src/lib/libscf/inc/libscf_priv.h2
8 files changed, 779 insertions, 345 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c b/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c
index eefcc1d6b8..918b82e415 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd.c
@@ -1223,7 +1223,7 @@ add_method_ids(instance_t *ins, pid_t pid, ctid_t cid, instance_method_t mthd)
debug_msg("Entering add_method_ids");
if (cid != -1)
- (void) add_remove_contract(ins->fmri, B_TRUE, cid);
+ (void) add_remove_contract(ins, B_TRUE, cid);
if (mthd == IM_START) {
if (add_rep_val(ins->start_pids, (int64_t)pid) == 0) {
@@ -1249,7 +1249,7 @@ remove_method_ids(instance_t *inst, pid_t pid, ctid_t cid,
debug_msg("Entering remove_method_ids");
if (cid != -1)
- (void) add_remove_contract(inst->fmri, B_FALSE, cid);
+ (void) add_remove_contract(inst, B_FALSE, cid);
if (mthd == IM_START) {
remove_rep_val(inst->start_pids, (int64_t)pid);
@@ -1282,7 +1282,8 @@ create_instance(const char *fmri)
ret->bind_fail_count = 0;
if (((ret->non_start_pid = create_rep_val_list()) == NULL) ||
- ((ret->start_pids = create_rep_val_list()) == NULL))
+ ((ret->start_pids = create_rep_val_list()) == NULL) ||
+ ((ret->start_ctids = create_rep_val_list()) == NULL))
goto alloc_fail;
ret->cur_istate = IIS_NONE;
@@ -1329,6 +1330,7 @@ destroy_instance(instance_t *inst)
destroy_rep_val_list(inst->start_pids);
destroy_rep_val_list(inst->non_start_pid);
+ destroy_rep_val_list(inst->start_ctids);
free(inst->fmri);
@@ -2053,7 +2055,7 @@ process_restarter_event(void)
goto fail;
}
- if (((err = iterate_repository_contracts(instance->fmri, 0))
+ if (((err = iterate_repository_contracts(instance, 0))
!= 0) && (err != ENOENT)) {
error_msg(gettext(
"Failed to adopt contracts of instance %s: %s"),
@@ -2944,7 +2946,7 @@ run_method(instance_t *instance, instance_method_t method,
if ((sig = restarter_is_kill_method(mi->exec_path)) >= 0) {
/* Carry out contract assassination */
- ret = iterate_repository_contracts(instance->fmri, sig);
+ ret = iterate_repository_contracts(instance, sig);
/* ENOENT means we didn't find any contracts */
if (ret != 0 && ret != ENOENT) {
error_msg(gettext("Failed to send signal %d "
diff --git a/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd_impl.h b/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd_impl.h
index 423d7cdff5..47f80b90f1 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd_impl.h
+++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/inetd_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -178,6 +177,9 @@ typedef struct {
uu_list_t *non_start_pid;
uu_list_t *start_pids;
+ /* ctids of currently running start methods */
+ uu_list_t *start_ctids;
+
/* remote address, used for TCP tracing */
struct sockaddr_storage remote_addr;
@@ -319,8 +321,8 @@ extern int add_rep_val(uu_list_t *, int64_t);
extern void remove_rep_val(uu_list_t *, int64_t);
extern void empty_rep_val_list(uu_list_t *);
extern int make_handle_bound(scf_handle_t *);
-extern int add_remove_contract(const char *, boolean_t, ctid_t);
-extern int iterate_repository_contracts(const char *, int);
+extern int add_remove_contract(instance_t *, boolean_t, ctid_t);
+extern int iterate_repository_contracts(instance_t *, int);
/*
* contracts.c
diff --git a/usr/src/cmd/cmd-inet/usr.lib/inetd/repval.c b/usr/src/cmd/cmd-inet/usr.lib/inetd/repval.c
index e84582f3f8..95f79ad7d8 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/inetd/repval.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/inetd/repval.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
*/
/*
*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -41,9 +40,12 @@
#include <unistd.h>
#include <string.h>
#include <signal.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libscf_priv.h>
#include "inetd_impl.h"
-
/*
* Number of consecutive repository bind retries performed by bind_to_rep()
* before failing.
@@ -71,6 +73,13 @@ static scf_transaction_entry_t *entry = NULL;
static scf_property_t *prop = NULL;
/*
+ * Pathname storage for paths generated from the fmri.
+ * Used when updating the ctid and (start) pid files for an inetd service.
+ */
+static char genfmri_filename[MAXPATHLEN] = "";
+static char genfmri_temp_filename[MAXPATHLEN] = "";
+
+/*
* Try and make the given handle bind be bound to the repository. If
* it's already bound, or we succeed a new bind return 0; else return
* -1 on failure, with the SCF error set to one of the following:
@@ -468,39 +477,172 @@ _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name)
}
/*
- * A routine that loops trying to read/write repository values until
- * either success, an error other that a broken repository connection or
+ * Writes the repository values in the vals list to
+ * a file that is generated based on the passed in fmri and name.
+ * Returns 0 on success,
+ * ENAMETOOLONG if unable to generate filename from fmri (including
+ * the inability to create the directory for the generated filename) and
+ * ENOENT on all other failures.
+ */
+static int
+repvals_to_file(const char *fmri, const char *name, uu_list_t *vals)
+{
+ int tfd;
+ FILE *tfp; /* temp fp */
+ rep_val_t *spval; /* Contains a start_pid or ctid */
+ int ret = 0;
+
+ debug_msg("Entering repvals_to_file, fmri:%s, name=%s\n",
+ fmri, name);
+
+ if (gen_filenms_from_fmri(fmri, name, genfmri_filename,
+ genfmri_temp_filename) != 0) {
+ /* Failure either from fmri too long or mkdir failure */
+ return (ENAMETOOLONG);
+ }
+
+ if ((tfd = mkstemp(genfmri_temp_filename)) == -1) {
+ return (ENOENT);
+ }
+
+ if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
+ (void) close(tfd);
+ ret = ENOENT;
+ goto unlink_out;
+ }
+
+ if ((tfp = fdopen(tfd, "w")) == NULL) {
+ (void) close(tfd);
+ ret = ENOENT;
+ goto unlink_out;
+ }
+
+ for (spval = uu_list_first(vals); spval != NULL;
+ spval = uu_list_next(vals, spval)) {
+ if (fprintf(tfp, "%lld\n", spval->val) <= 0) {
+ (void) fclose(tfp);
+ ret = ENOENT;
+ goto unlink_out;
+ }
+ }
+ if (fclose(tfp) != 0) {
+ ret = ENOENT;
+ goto unlink_out;
+ }
+ if (rename(genfmri_temp_filename, genfmri_filename) != 0) {
+ ret = ENOENT;
+ goto unlink_out;
+ }
+ return (0);
+
+unlink_out:
+ if (unlink(genfmri_temp_filename) != 0) {
+ warn_msg(gettext("Removal of temp file "
+ "%s failed. Please remove manually."),
+ genfmri_temp_filename);
+ }
+ return (ret);
+}
+
+/*
+ * A routine that loops trying to read/write values until either success,
+ * an error other than a broken repository connection or
* the number of retries reaches REP_OP_RETRIES.
+ * This action is used to read/write the values:
+ * reads/writes to a file for the START_PIDS property due to scalability
+ * problems with libscf
+ * reads/writes to the repository for all other properties.
* Returns 0 on success, else the error value from either _store_rep_vals or
- * retrieve_rep_vals (based on whether 'store' was set or not), or one of the
- * following if a rebind failed:
- * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources.
+ * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the
+ * following:
+ * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources
+ * SCF_ERROR_NO_MEMORY if a memory allocation failure
* SCF_ERROR_NO_SERVER if the server isn't running.
+ * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files
*/
static scf_error_t
store_retrieve_rep_vals(uu_list_t *vals, const char *fmri,
const char *prop, boolean_t store)
{
- scf_error_t ret;
+ scf_error_t ret = 0;
uint_t retries;
+ FILE *tfp; /* temp fp */
+ int64_t tval; /* temp val holder */
+ int fscanf_ret;
+ int fopen_retry_cnt = 2;
debug_msg("Entering store_retrieve_rep_vals, store: %d", store);
-
- for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
- if (make_handle_bound(rep_handle) == -1) {
- ret = scf_error();
- break;
+ /* inetd specific action for START_PIDS property */
+ if (strcmp(prop, PR_NAME_START_PIDS) == 0) {
+ /*
+ * Storage performance of START_PIDS is important,
+ * so each instance has its own file and all start_pids
+ * in the list are written to a temp file and then
+ * moved (renamed).
+ */
+ if (store) {
+ /* Write all values in list to file */
+ if (repvals_to_file(fmri, "pid", vals)) {
+ return (SCF_ERROR_CONSTRAINT_VIOLATED);
+ }
+ } else {
+ /* no temp name needed */
+ if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename,
+ NULL) != 0)
+ return (SCF_ERROR_CONSTRAINT_VIOLATED);
+
+retry_fopen:
+ /* It's ok if no file, there are just no pids */
+ if ((tfp = fopen(genfmri_filename, "r")) == NULL) {
+ if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
+ fopen_retry_cnt--;
+ goto retry_fopen;
+ }
+ return (0);
+ }
+ /* fscanf may not set errno, so clear it first */
+ errno = 0;
+ while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) {
+ /* If tval isn't a valid pid, then fail. */
+ if ((tval > MAXPID) || (tval <= 0)) {
+ empty_rep_val_list(vals);
+ return (SCF_ERROR_CONSTRAINT_VIOLATED);
+ }
+ if (add_rep_val(vals, tval) == -1) {
+ empty_rep_val_list(vals);
+ return (SCF_ERROR_NO_MEMORY);
+ }
+ errno = 0;
+ }
+ /* EOF is ok when no errno */
+ if ((fscanf_ret != EOF) || (errno != 0)) {
+ empty_rep_val_list(vals);
+ return (SCF_ERROR_CONSTRAINT_VIOLATED);
+ }
+ if (fclose(tfp) != 0) {
+ /* for close failure just log a message */
+ warn_msg(gettext("Close of file %s failed."),
+ genfmri_filename);
+ }
}
+ } else {
+ for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
+ if (make_handle_bound(rep_handle) == -1) {
+ ret = scf_error();
+ break;
+ }
- if ((ret = (store ? _store_rep_vals(vals, fmri, prop) :
- _retrieve_rep_vals(vals, fmri, prop))) !=
- SCF_ERROR_CONNECTION_BROKEN)
- break;
+ if ((ret = (store ? _store_rep_vals(vals, fmri, prop) :
+ _retrieve_rep_vals(vals, fmri, prop))) !=
+ SCF_ERROR_CONNECTION_BROKEN)
+ break;
- (void) scf_handle_unbind(rep_handle);
+ (void) scf_handle_unbind(rep_handle);
+ }
}
+out:
return (ret);
}
@@ -517,304 +659,207 @@ retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop)
}
/*
- * Fails with ECONNABORTED, ENOENT, EACCES, EROFS, ENOMEM, or EPERM.
+ * Adds/removes a contract id to/from the cached list kept in the instance.
+ * Then the cached list is written to a file named "ctid" in a directory
+ * based on the fmri. Cached list is written to a file due to scalability
+ * problems in libscf. The file "ctid" is used when inetd is restarted
+ * so that inetd can adopt the contracts that it had previously.
+ * Returns:
+ * 0 on success
+ * ENAMETOOLONG if unable to generate filename from fmri (including
+ * the inability to create the directory for the generated filename)
+ * ENOENT - failure accessing file
+ * ENOMEM - memory allocation failure
*/
-static int
-add_remove_contract_norebind(const char *fmri, boolean_t add, ctid_t ctid)
+int
+add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid)
{
- int err;
-
- if (scf_handle_decode_fmri(rep_handle, fmri, NULL, NULL, inst, NULL,
- NULL, SCF_DECODE_FMRI_EXACT) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
- return (ECONNABORTED);
-
- case SCF_ERROR_NOT_FOUND:
- return (ENOENT);
-
- case SCF_ERROR_CONSTRAINT_VIOLATED:
- case SCF_ERROR_INVALID_ARGUMENT:
- case SCF_ERROR_HANDLE_MISMATCH:
- default:
- assert(0);
- abort();
- }
- }
+ FILE *tfp; /* temp fp */
+ int ret = 0;
+ int repval_ret = 0;
+ int fopen_retry_cnt = 2;
-redo:
- if (add)
- err = restarter_store_contract(inst, ctid,
- RESTARTER_CONTRACT_PRIMARY);
- else
- err = restarter_remove_contract(inst, ctid,
- RESTARTER_CONTRACT_PRIMARY);
- switch (err) {
- case 0:
- case ENOMEM:
- case ECONNABORTED:
- return (err);
-
- case ECANCELED:
- return (ENOENT);
+ debug_msg("Entering add_remove_contract, add: %d\n", add);
- case EPERM:
- assert(0);
- return (err);
-
- case EACCES:
- error_msg(add ? gettext("Failed to write contract id %ld for "
- "instance %s to repository: backend access denied.") :
- gettext("Failed to remove contract id %ld for instance %s "
- "from repository: backend access denied."), ctid, fmri);
- return (err);
-
- case EROFS:
- error_msg(add ? gettext("Failed to write contract id %ld for "
- "instance %s to repository: backend is read-only.") :
- gettext("Failed to remove contract id %ld for instance %s "
- "from repository: backend is read-only."), ctid, fmri);
- return (err);
-
- case EINVAL:
- case EBADF:
- default:
- assert(0);
- abort();
- /* NOTREACHED */
- }
-}
+ /*
+ * Storage performance of contract ids is important,
+ * so each instance has its own file. An add of a
+ * ctid will be appended to the ctid file.
+ * The removal of a ctid will result in the remaining
+ * ctids in the list being written to a temp file and then
+ * moved (renamed).
+ */
+ if (add) {
+ if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename,
+ NULL) != 0) {
+ /* Failure either from fmri too long or mkdir failure */
+ return (ENAMETOOLONG);
+ }
-/*
- * Tries to add/remove (dependent on the value of 'add') the specified
- * contract id to the specified instance until either success, an error
- * other that connection broken occurs, or the number of bind retries reaches
- * REP_OP_RETRIES.
- * Returns 0 on success else fails with one of ENOENT, EACCES, EROFS, EPERM,
- * ECONNABORTED or ENOMEM.
- */
-int
-add_remove_contract(const char *fmri, boolean_t add, ctid_t ctid)
-{
- uint_t retries;
- int err;
+retry_fopen:
+ if ((tfp = fopen(genfmri_filename, "a")) == NULL) {
+ if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
+ fopen_retry_cnt--;
+ goto retry_fopen;
+ }
+ ret = ENOENT;
+ goto out;
+ }
- for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
- if (make_handle_bound(rep_handle) == -1) {
- err = ECONNABORTED;
- break;
+ /* Always store ctids as long long */
+ if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) {
+ (void) fclose(tfp);
+ ret = ENOENT;
+ goto out;
}
- if ((err = add_remove_contract_norebind(fmri, add, ctid)) !=
- ECONNABORTED)
- break;
+ if (fclose(tfp) != 0) {
+ ret = ENOENT;
+ goto out;
+ }
- (void) scf_handle_unbind(rep_handle);
+ if (add_rep_val(inst->start_ctids, ctid) != 0) {
+ ret = ENOMEM;
+ goto out;
+ }
+ } else {
+ remove_rep_val(inst->start_ctids, ctid);
+
+ /* Write all values in list to file */
+ if ((repval_ret = repvals_to_file(inst->fmri, "ctid",
+ inst->start_ctids)) != 0) {
+ ret = repval_ret;
+ goto out;
+ }
}
- return (err);
+out:
+ return (ret);
}
/*
- * Iterate over all contracts associated with the instance specified by
- * fmri; if sig !=0, we send each contract the specified signal, otherwise
- * we call adopt_contract() to take ownership. This really ought to be
- * reworked to use a callback mechanism if more functionality is added.
+ * If sig !=0, iterate over all contracts in the cached list of contract
+ * ids kept in the instance. Send each contract the specified signal.
+ * If sig == 0, read in the contract ids that were last associated
+ * with this instance (reload the cache) and call adopt_contract()
+ * to take ownership.
*
- * Returns 0 on success or ENOENT if the instance, its restarter property
- * group, or its contract property don't exist, or EINVAL if the property
- * is not of the correct type, ENOMEM if there was a memory allocation
- * failure, EPERM if there were permission problems accessing the repository,
- * or ECONNABORTED if the connection with the repository was broken.
+ * Returns 0 on success;
+ * ENAMETOOLONG if unable to generate filename from fmri (including
+ * the inability to create the directory for the generated filename) and
+ * ENXIO if a failure accessing the file
+ * ENOMEM if there was a memory allocation failure
+ * ENOENT if the instance, its restarter property group, or its
+ * contract property don't exist
+ * EIO if invalid data read from the file
*/
int
-iterate_repository_contracts(const char *fmri, int sig)
+iterate_repository_contracts(instance_t *inst, int sig)
{
- scf_iter_t *iter;
- scf_value_t *val = NULL;
- uint64_t c;
- int err;
int ret = 0;
- uint_t retries = 0;
+ FILE *fp;
+ rep_val_t *spval = NULL; /* Contains a start_pid */
+ uint64_t tval; /* temp val holder */
+ uu_list_t *uup = NULL;
+ int fscanf_ret;
+ int fopen_retry_cnt = 2;
- debug_msg("Entering iterate_repository_contracts");
-
- if (make_handle_bound(rep_handle) == -1)
- return (ECONNABORTED);
-
- if (((iter = scf_iter_create(rep_handle)) == NULL) ||
- ((val = scf_value_create(rep_handle)) == NULL)) {
- ret = ENOMEM;
- goto out;
- }
+ debug_msg("Entering iterate_repository_contracts, sig: %d", sig);
-rep_retry:
- if (scf_handle_decode_fmri(rep_handle, fmri, NULL, NULL, inst, NULL,
- NULL, SCF_DECODE_FMRI_EXACT) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
-rebind:
- (void) scf_handle_unbind(rep_handle);
-
- if (retries++ == REP_OP_RETRIES) {
- ret = ECONNABORTED;
- goto out;
- }
-
- if (make_handle_bound(rep_handle) == -1) {
- ret = ECONNABORTED;
- goto out;
+ if (sig != 0) {
+ /*
+ * Send a signal to all in the contract; ESRCH just
+ * means they all exited before we could kill them
+ */
+ for (spval = uu_list_first(inst->start_ctids); spval != NULL;
+ spval = uu_list_next(inst->start_ctids, spval)) {
+ if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 &&
+ errno != ESRCH) {
+ warn_msg(gettext("Unable to signal all "
+ "contract members of instance %s: %s"),
+ inst->fmri, strerror(errno));
}
-
- goto rep_retry;
-
- case SCF_ERROR_NOT_FOUND:
- ret = ENOENT;
- goto out;
-
- case SCF_ERROR_CONSTRAINT_VIOLATED:
- case SCF_ERROR_INVALID_ARGUMENT:
- case SCF_ERROR_HANDLE_MISMATCH:
- default:
- assert(0);
- abort();
}
+ return (0);
}
- if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
- goto rebind;
-
- case SCF_ERROR_NOT_SET:
- ret = 0;
- goto out;
-
- case SCF_ERROR_NOT_FOUND:
- ret = ENOENT;
- goto out;
-
- case SCF_ERROR_INVALID_ARGUMENT:
- case SCF_ERROR_HANDLE_MISMATCH:
- default:
- assert(0);
- abort();
- }
+ /*
+ * sig == 0 case.
+ * Attempt to adopt the contract for each ctid.
+ */
+ if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename,
+ NULL) != 0) {
+ /* Failure either from fmri too long or mkdir failure */
+ return (ENAMETOOLONG);
}
- if (scf_pg_get_property(pg, SCF_PROPERTY_CONTRACT, prop) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
- goto rebind;
-
- case SCF_ERROR_NOT_SET:
- ret = 0;
- goto out;
-
- case SCF_ERROR_NOT_FOUND:
- ret = ENOENT;
- goto out;
-
- case SCF_ERROR_INVALID_ARGUMENT:
- case SCF_ERROR_HANDLE_MISMATCH:
- default:
- assert(0);
- abort();
+retry_fopen:
+ /* It's ok if no file, there are no ctids to adopt */
+ if ((fp = fopen(genfmri_filename, "r")) == NULL) {
+ if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
+ fopen_retry_cnt--;
+ goto retry_fopen;
}
+ return (0);
}
- if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
- goto rebind;
-
- case SCF_ERROR_NOT_SET:
- ret = ENOENT;
- goto out;
-
- case SCF_ERROR_TYPE_MISMATCH:
- ret = EINVAL;
+ /*
+ * Read ctids from file into 2 lists:
+ * - temporary list to be traversed (uup)
+ * - cached list that can be modified if adoption of
+ * contract fails (inst->start_ctids).
+ * Always treat ctids as long longs.
+ */
+ uup = create_rep_val_list();
+ /* fscanf may not set errno, so clear it first */
+ errno = 0;
+ while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) {
+ /* If tval isn't a valid ctid, then fail. */
+ if (tval == 0) {
+ (void) fclose(fp);
+ ret = EIO;
goto out;
-
- default:
- assert(0);
- abort();
}
- }
-
- if (scf_iter_property_values(iter, prop) != 0) {
- switch (scf_error()) {
- case SCF_ERROR_CONNECTION_BROKEN:
- goto rebind;
-
- case SCF_ERROR_NOT_SET:
- ret = ENOENT;
+ if ((add_rep_val(uup, tval) == -1) ||
+ (add_rep_val(inst->start_ctids, tval) == -1)) {
+ (void) fclose(fp);
+ ret = ENOMEM;
goto out;
-
- case SCF_ERROR_HANDLE_MISMATCH:
- default:
- assert(0);
- abort();
}
+ errno = 0;
+ }
+ /* EOF is not a failure when no errno */
+ if ((fscanf_ret != EOF) || (errno != 0)) {
+ ret = EIO;
+ goto out;
}
- for (;;) {
- err = scf_iter_next_value(iter, val);
- if (err == 0) {
- break;
- } else if (err != 1) {
- assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
- goto rebind;
- }
+ if (fclose(fp) != 0) {
+ ret = ENXIO;
+ goto out;
+ }
- err = scf_value_get_count(val, &c);
- assert(err == 0);
-
- if (sig == 0) {
- /* Try to adopt the contract */
- if (adopt_contract((ctid_t)c, fmri) != 0) {
- /*
- * Adoption failed. No reason to think it'll
- * work later, so remove the id from our list
- * in the repository.
- *
- * Beware: add_remove_contract_norebind() uses
- * the global scf_ handles. Fortunately we're
- * done with them. We need to be cognizant of
- * repository disconnection, though.
- */
- switch (add_remove_contract_norebind(fmri,
- B_FALSE, (ctid_t)c)) {
- case 0:
- case ENOENT:
- case EACCES:
- case EROFS:
- break;
-
- case ECONNABORTED:
- goto rebind;
-
- default:
- assert(0);
- abort();
- }
- }
- } else {
+ for (spval = uu_list_first(uup); spval != NULL;
+ spval = uu_list_next(uup, spval)) {
+ /* Try to adopt the contract */
+ if (adopt_contract((ctid_t)spval->val,
+ inst->fmri) != 0) {
/*
- * Send a signal to all in the contract; ESRCH just
- * means they all exited before we could kill them
+ * Adoption failed. No reason to think it'll
+ * work later, so remove the id from our list
+ * in the instance.
*/
- if (sigsend(P_CTID, (ctid_t)c, sig) == -1 &&
- errno != ESRCH) {
- warn_msg(gettext("Unable to signal all contract"
- "members of instance %s: %s"), fmri,
- strerror(errno));
- }
+ remove_rep_val(inst->start_ctids, spval->val);
}
}
-
out:
- scf_value_destroy(val);
- scf_iter_destroy(iter);
+ if (uup) {
+ empty_rep_val_list(uup);
+ destroy_rep_val_list(uup);
+ }
+
+ if (ret != 0)
+ empty_rep_val_list(inst->start_ctids);
+
return (ret);
}
diff --git a/usr/src/cmd/svc/svcs/svcs.c b/usr/src/cmd/svc/svcs/svcs.c
index a5d2d13f6c..f565f397e9 100644
--- a/usr/src/cmd/svc/svcs/svcs.c
+++ b/usr/src/cmd/svc/svcs/svcs.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,7 +18,7 @@
*
* CDDL HEADER END
*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,6 +132,12 @@ static int first_paragraph = 1; /* For -l mode. */
static char *common_name_buf; /* Sized for maximal length value. */
char *locale; /* Current locale. */
+/*
+ * Pathname storage for path generated from the fmri.
+ * Used for reading the ctid and (start) pid files for an inetd service.
+ */
+static char genfmri_filename[MAXPATHLEN] = "";
+
/* Options */
static int *opt_columns = NULL; /* Indices into columns to display. */
static int opt_cnum = 0;
@@ -533,16 +538,58 @@ get_restarter_count_prop(scf_instance_t *inst, const char *pname, uint64_t *cp,
* Generic functions
*/
+/*
+ * Return an array of pids associated with the given contract id.
+ * Returned pids are added to the end of the pidsp array.
+ */
+static void
+ctid_to_pids(uint64_t c, pid_t **pidsp, uint_t *np)
+{
+ ct_stathdl_t ctst;
+ uint_t m;
+ int fd;
+ int r, err;
+ pid_t *pids;
+
+ fd = contract_open(c, NULL, "status", O_RDONLY);
+ if (fd < 0)
+ return;
+
+ err = ct_status_read(fd, CTD_ALL, &ctst);
+ if (err != 0) {
+ uu_warn(gettext("Could not read status of contract "
+ "%ld: %s.\n"), c, strerror(err));
+ (void) close(fd);
+ return;
+ }
+
+ (void) close(fd);
+
+ r = ct_pr_status_get_members(ctst, &pids, &m);
+ assert(r == 0);
+
+ if (m == 0) {
+ ct_status_free(ctst);
+ return;
+ }
+
+ *pidsp = realloc(*pidsp, (*np + m) * sizeof (*pidsp));
+ if (*pidsp == NULL)
+ uu_die(gettext("Out of memory"));
+
+ bcopy(pids, *pidsp + *np, m * sizeof (*pids));
+ *np += m;
+
+ ct_status_free(ctst);
+}
+
static int
propvals_to_pids(scf_propertygroup_t *pg, const char *pname, pid_t **pidsp,
uint_t *np, scf_property_t *prop, scf_value_t *val, scf_iter_t *iter)
{
scf_type_t ty;
- int r, fd, err;
uint64_t c;
- ct_stathdl_t ctst;
- pid_t *pids;
- uint_t m;
+ int r;
if (scf_pg_get_property(pg, pname, prop) != 0) {
if (scf_error() != SCF_ERROR_NOT_FOUND)
@@ -570,46 +617,267 @@ propvals_to_pids(scf_propertygroup_t *pg, const char *pname, pid_t **pidsp,
if (scf_value_get_count(val, &c) != 0)
scfdie();
- fd = contract_open(c, NULL, "status", O_RDONLY);
- if (fd < 0)
- continue;
+ ctid_to_pids(c, pidsp, np);
+ }
- err = ct_status_read(fd, CTD_ALL, &ctst);
- if (err != 0) {
- uu_warn(gettext("Could not read status of contract "
- "%ld: %s.\n"), c, strerror(err));
- (void) close(fd);
- continue;
- }
+ return (0);
+}
- (void) close(fd);
+/*
+ * Check if instance has general/restarter property that matches
+ * given string. Restarter string must be in canonified form.
+ * Returns 0 for success; -1 otherwise.
+ */
+static int
+check_for_restarter(scf_instance_t *inst, const char *restarter)
+{
+ char *fmri_buf;
+ char *fmri_buf_canonified = NULL;
+ int ret = -1;
- r = ct_pr_status_get_members(ctst, &pids, &m);
- assert(r == 0);
+ if (inst == NULL)
+ return (-1);
- if (m == 0) {
- ct_status_free(ctst);
- continue;
+ /* Get restarter */
+ fmri_buf = safe_malloc(max_scf_fmri_length + 1);
+ if (inst_get_single_val(inst, SCF_PG_GENERAL,
+ SCF_PROPERTY_RESTARTER, SCF_TYPE_ASTRING, fmri_buf,
+ max_scf_fmri_length + 1, 0, 0, 1) != 0)
+ goto out;
+
+ fmri_buf_canonified = safe_malloc(max_scf_fmri_length + 1);
+ if (scf_canonify_fmri(fmri_buf, fmri_buf_canonified,
+ (max_scf_fmri_length + 1)) < 0)
+ goto out;
+
+ if (strcmp(fmri_buf, restarter) == 0)
+ ret = 0;
+
+out:
+ free(fmri_buf);
+ if (fmri_buf_canonified)
+ free(fmri_buf_canonified);
+ return (ret);
+}
+
+/*
+ * Common code that is used by ctids_by_restarter and pids_by_restarter.
+ * Checks for a common restarter and if one is available, it generates
+ * the appropriate filename using wip->fmri and stores that in the
+ * global genfmri_filename.
+ *
+ * Restarters currently supported are: svc:/network/inetd:default
+ * If a restarter specific action is available, then restarter_spec
+ * is set to 1. If a restarter specific action is not available, then
+ * restarter_spec is set to 0 and a -1 is returned.
+ *
+ * Returns:
+ * 0 if success: restarter specific action found and filename generated
+ * -1 if restarter specific action not found,
+ * if restarter specific action found but an error was encountered
+ * during the generation of the wip->fmri based filename
+ */
+static int
+common_by_restarter(scf_instance_t *inst, const char *fmri,
+ int *restarter_specp)
+{
+ int ret = -1;
+ int r;
+
+ /* Check for inetd specific restarter */
+ if (check_for_restarter(inst, "svc:/network/inetd:default") != 0) {
+ *restarter_specp = 0;
+ return (ret);
+ }
+
+ *restarter_specp = 1;
+
+ /* Get the ctid filename associated with this instance */
+ r = gen_filenms_from_fmri(fmri, "ctid", genfmri_filename, NULL);
+
+ switch (r) {
+ case 0:
+ break;
+
+ case -1:
+ /*
+ * Unable to get filename from fmri. Print warning
+ * and return failure with no ctids.
+ */
+ uu_warn(gettext("Unable to read contract ids for %s -- "
+ "FMRI is too long\n"), fmri);
+ return (ret);
+
+ case -2:
+ /*
+ * The directory didn't exist, so no contracts.
+ * Return failure with no ctids.
+ */
+ return (ret);
+
+ default:
+ uu_warn(gettext("%s:%d: gen_filenms_from_fmri() failed with "
+ "unknown error %d\n"), __FILE__, __LINE__, r);
+ abort();
+ }
+
+ return (0);
+
+}
+
+/*
+ * Get or print a contract id using a restarter specific action.
+ *
+ * If the print_flag is not set, this routine gets the single contract
+ * id associated with this instance.
+ * If the print flag is set, then print each contract id found.
+ *
+ * Returns:
+ * 0 if success: restarter specific action found and used with no error
+ * -1 if restarter specific action not found
+ * -1 if restarter specific action found, but there was a failure
+ * -1 if print flag is not set and no contract id is found or multiple
+ * contract ids were found
+ * E2BIG if print flag is not set, MULTI_OK bit in flag is set and multiple
+ * contract ids were found
+ */
+static int
+ctids_by_restarter(scf_walkinfo_t *wip, uint64_t *cp, int print_flag,
+ uint_t flags, int *restarter_specp, void (*callback_header)(),
+ void (*callback_ctid)(uint64_t))
+{
+ FILE *fp;
+ int ret = -1;
+ int fscanf_ret;
+ uint64_t cp2;
+ int rest_ret;
+
+ /* Check if callbacks are needed and were passed in */
+ if (print_flag) {
+ if ((callback_header == NULL) || (callback_ctid == NULL))
+ return (ret);
+ }
+
+ /* Check for restarter specific action and generation of filename */
+ rest_ret = common_by_restarter(wip->inst, wip->fmri, restarter_specp);
+ if (rest_ret != 0)
+ return (rest_ret);
+
+ /*
+ * If fopen fails, then ctid file hasn't been created yet.
+ * If print_flag is set, this is ok; otherwise fail.
+ */
+ if ((fp = fopen(genfmri_filename, "r")) == NULL) {
+ if (print_flag)
+ return (0);
+ goto out;
+ }
+
+ if (print_flag) {
+ /*
+ * Print all contract ids that are found.
+ * First callback to print ctid header.
+ */
+ callback_header();
+
+ /* fscanf may not set errno, so be sure to clear it first */
+ errno = 0;
+ while ((fscanf_ret = fscanf(fp, "%llu", cp)) == 1) {
+ /* Callback to print contract id */
+ callback_ctid(*cp);
+ errno = 0;
+ }
+ /* EOF is not a failure when no errno. */
+ if ((fscanf_ret != EOF) || (errno != 0)) {
+ uu_die(gettext("Unable to read ctid file for %s"),
+ wip->fmri);
+ }
+ (void) putchar('\n');
+ ret = 0;
+ } else {
+ /* Must find 1 ctid or fail */
+ if (fscanf(fp, "%llu", cp) == 1) {
+ /* If 2nd ctid found - fail */
+ if (fscanf(fp, "%llu", &cp2) == 1) {
+ if (flags & MULTI_OK)
+ ret = E2BIG;
+ } else {
+ /* Success - found only 1 ctid */
+ ret = 0;
+ }
}
+ }
+ (void) fclose(fp);
- *pidsp = realloc(*pidsp, (*np + m) * sizeof (*pidsp));
- if (*pidsp == NULL)
- uu_die(gettext("Out of memory"));
+out:
+ return (ret);
+}
+
+/*
+ * Get the process ids associated with an instance using a restarter
+ * specific action.
+ *
+ * Returns:
+ * 0 if success: restarter specific action found and used with no error
+ * -1 restarter specific action not found or if failure
+ */
+static int
+pids_by_restarter(scf_instance_t *inst, const char *fmri,
+ pid_t **pids, uint_t *np, int *restarter_specp)
+{
+ uint64_t c;
+ FILE *fp;
+ int fscanf_ret;
+ int rest_ret;
- bcopy(pids, *pidsp + *np, m * sizeof (*pids));
- *np += m;
+ /* Check for restarter specific action and generation of filename */
+ rest_ret = common_by_restarter(inst, fmri, restarter_specp);
+ if (rest_ret != 0)
+ return (rest_ret);
- ct_status_free(ctst);
+ /*
+ * If fopen fails with ENOENT then the ctid file hasn't been
+ * created yet so return success.
+ * For all other errors - fail with uu_die.
+ */
+ if ((fp = fopen(genfmri_filename, "r")) == NULL) {
+ if (errno == ENOENT)
+ return (0);
+ uu_die(gettext("Unable to open ctid file for %s"), fmri);
}
+ /* fscanf may not set errno, so be sure to clear it first */
+ errno = 0;
+ while ((fscanf_ret = fscanf(fp, "%llu", &c)) == 1) {
+ if (c == 0) {
+ (void) fclose(fp);
+ uu_die(gettext("ctid file for %s has corrupt data"),
+ fmri);
+ }
+ ctid_to_pids(c, pids, np);
+ errno = 0;
+ }
+ /* EOF is not a failure when no errno. */
+ if ((fscanf_ret != EOF) || (errno != 0)) {
+ uu_die(gettext("Unable to read ctid file for %s"), fmri);
+ }
+
+ (void) fclose(fp);
return (0);
}
static int
-instance_processes(scf_instance_t *inst, pid_t **pids, uint_t *np)
+instance_processes(scf_instance_t *inst, const char *fmri,
+ pid_t **pids, uint_t *np)
{
scf_iter_t *iter;
int ret;
+ int restarter_spec;
+
+ /* Use the restarter specific get pids routine, if available. */
+ ret = pids_by_restarter(inst, fmri, pids, np, &restarter_spec);
+ if (restarter_spec == 1)
+ return (ret);
if ((iter = scf_iter_create(h)) == NULL)
scfdie();
@@ -709,13 +977,24 @@ sprint_ctid(char **buf, scf_walkinfo_t *wip)
uint64_t c;
size_t newsize = (*buf ? strlen(*buf) : 0) + CTID_COLUMN_WIDTH + 2;
char *newbuf = safe_malloc(newsize);
+ int restarter_spec;
- if (wip->pg != NULL)
+ /*
+ * Use the restarter specific get pids routine, if available.
+ * Only check for non-legacy services (wip->pg == 0).
+ */
+ if (wip->pg != NULL) {
r = pg_get_single_val(wip->pg, scf_property_contract,
SCF_TYPE_COUNT, &c, 0, EMPTY_OK | MULTI_OK);
- else
- r = get_restarter_count_prop(wip->inst, scf_property_contract,
- &c, EMPTY_OK | MULTI_OK);
+ } else {
+ r = ctids_by_restarter(wip, &c, 0, MULTI_OK, &restarter_spec,
+ NULL, NULL);
+ if (restarter_spec == 0) {
+ /* No restarter specific routine */
+ r = get_restarter_count_prop(wip->inst,
+ scf_property_contract, &c, EMPTY_OK | MULTI_OK);
+ }
+ }
if (r == 0)
(void) snprintf(newbuf, newsize, "%s%*lu ",
@@ -738,13 +1017,24 @@ sortkey_ctid(char *buf, int reverse, scf_walkinfo_t *wip)
{
int r;
uint64_t c;
+ int restarter_spec;
- if (wip->pg != NULL)
+ /*
+ * Use the restarter specific get pids routine, if available.
+ * Only check for non-legacy services (wip->pg == 0).
+ */
+ if (wip->pg != NULL) {
r = pg_get_single_val(wip->pg, scf_property_contract,
SCF_TYPE_COUNT, &c, 0, EMPTY_OK);
- else
- r = get_restarter_count_prop(wip->inst, scf_property_contract,
- &c, EMPTY_OK);
+ } else {
+ r = ctids_by_restarter(wip, &c, 0, MULTI_OK, &restarter_spec,
+ NULL, NULL);
+ if (restarter_spec == 0) {
+ /* No restarter specific routine */
+ r = get_restarter_count_prop(wip->inst,
+ scf_property_contract, &c, EMPTY_OK);
+ }
+ }
if (r == 0) {
/*
@@ -1628,19 +1918,39 @@ pidcmp(const void *l, const void *r)
*/
#define DETAILED_WIDTH (11 + 2)
+/*
+ * Callback routine to print header for contract id.
+ * Called by ctids_by_restarter and print_detailed.
+ */
+static void
+print_ctid_header()
+{
+ (void) printf("%-*s", DETAILED_WIDTH, "contract_id");
+}
+
+/*
+ * Callback routine to print a contract id.
+ * Called by ctids_by_restarter and print_detailed.
+ */
+static void
+print_ctid_detailed(uint64_t c)
+{
+ (void) printf("%lu ", (ctid_t)c);
+}
+
static void
-detailed_list_processes(scf_instance_t *inst)
+detailed_list_processes(scf_walkinfo_t *wip)
{
uint64_t c;
pid_t *pids;
uint_t i, n;
psinfo_t psi;
- if (get_restarter_count_prop(inst, scf_property_contract, &c,
+ if (get_restarter_count_prop(wip->inst, scf_property_contract, &c,
EMPTY_OK) != 0)
return;
- if (instance_processes(inst, &pids, &n) != 0)
+ if (instance_processes(wip->inst, wip->fmri, &pids, &n) != 0)
return;
qsort(pids, n, sizeof (*pids), pidcmp);
@@ -1887,6 +2197,8 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
struct timeval tv;
time_t stime;
struct tm *tmp;
+ int restarter_spec;
+ int restarter_ret;
const char * const fmt = "%-*s%s\n";
@@ -2003,6 +2315,19 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
free(buf);
+ /*
+ * Use the restarter specific routine to print the ctids, if available.
+ * If restarter specific action is available and it fails, then die.
+ */
+ restarter_ret = ctids_by_restarter(wip, &c, 1, 0,
+ &restarter_spec, print_ctid_header, print_ctid_detailed);
+ if (restarter_spec == 1) {
+ if (restarter_ret != 0)
+ uu_die(gettext("Unable to get restarter for %s"),
+ wip->fmri);
+ goto restarter_common;
+ }
+
if (rpg) {
scf_iter_t *iter;
@@ -2012,8 +2337,9 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
if (scf_pg_get_property(rpg, scf_property_contract, g_prop) ==
0) {
if (scf_property_is_type(g_prop, SCF_TYPE_COUNT) == 0) {
- (void) printf("%-*s", DETAILED_WIDTH,
- "contract_id");
+
+ /* Callback to print ctid header */
+ print_ctid_header();
if (scf_iter_property_values(iter, g_prop) != 0)
scfdie();
@@ -2027,7 +2353,9 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
if (scf_value_get_count(g_val, &c) != 0)
scfdie();
- (void) printf("%lu ", (ctid_t)c);
+
+ /* Callback to print contract id. */
+ print_ctid_detailed(c);
}
(void) putchar('\n');
@@ -2046,6 +2374,7 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
scfdie();
}
+restarter_common:
scf_pg_destroy(rpg);
/* Dependencies. */
@@ -2067,7 +2396,7 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
scf_iter_destroy(pg_iter);
if (opt_processes)
- detailed_list_processes(wip->inst);
+ detailed_list_processes(wip);
return (0);
}
@@ -2077,15 +2406,16 @@ print_detailed(void *unused, scf_walkinfo_t *wip)
* return the augmented string.
*/
static char *
-add_processes(char *line, scf_instance_t *inst, scf_propertygroup_t *lpg)
+add_processes(scf_walkinfo_t *wip, char *line, scf_propertygroup_t *lpg)
{
pid_t *pids = NULL;
uint_t i, n = 0;
if (lpg == NULL) {
- if (instance_processes(inst, &pids, &n) != 0)
+ if (instance_processes(wip->inst, wip->fmri, &pids, &n) != 0)
return (line);
} else {
+ /* Legacy services */
scf_iter_t *iter;
if ((iter = scf_iter_create(h)) == NULL)
@@ -2211,7 +2541,7 @@ list_instance(void *unused, scf_walkinfo_t *wip)
/* If we're supposed to list the processes, too, do that now. */
if (opt_processes)
- lp->str = add_processes(lp->str, wip->inst, wip->pg);
+ lp->str = add_processes(wip, lp->str, wip->pg);
/* Create the sort key. */
cp = lp->key = safe_malloc(sortkey_sz);
diff --git a/usr/src/lib/libscf/Makefile.com b/usr/src/lib/libscf/Makefile.com
index 4bfbd1a811..230b768690 100644
--- a/usr/src/lib/libscf/Makefile.com
+++ b/usr/src/lib/libscf/Makefile.com
@@ -43,7 +43,7 @@ $(NOT_NATIVE)NATIVE_BUILD = $(POUND_SIGN)
$(NATIVE_BUILD)VERS =
$(NATIVE_BUILD)LIBS = $(DYNLIB)
-LDLIBS += -luutil -lc
+LDLIBS += -luutil -lc -lgen
SRCDIR = ../common
$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
@@ -61,7 +61,8 @@ LIBUUTIL = $(SRC)/lib/libuutil
MY_NATIVE_CPPFLAGS =\
-DNATIVE_BUILD $(DTEXTDOM) \
-I../inc -I$(COMDIR) -I$(LIBUUTIL)/common
-MY_NATIVE_LDLIBS = -L$(LIBUUTIL)/native -R$(LIBUUTIL)/native -luutil -ldoor -lc
+MY_NATIVE_LDLIBS = -L$(LIBUUTIL)/native -R$(LIBUUTIL)/native -luutil -ldoor -lc \
+ -lgen
.KEEP_STATE:
diff --git a/usr/src/lib/libscf/common/mapfile-vers b/usr/src/lib/libscf/common/mapfile-vers
index 9efd0293b7..9de9678dd5 100644
--- a/usr/src/lib/libscf/common/mapfile-vers
+++ b/usr/src/lib/libscf/common/mapfile-vers
@@ -225,6 +225,7 @@ SUNWprivate_1.1 {
scf_type_to_string;
scf_walk_fmri;
_smf_refresh_instance_i;
+ gen_filenms_from_fmri;
local:
*;
};
diff --git a/usr/src/lib/libscf/common/midlevel.c b/usr/src/lib/libscf/common/midlevel.c
index c4ca619f40..2629abfdd8 100644
--- a/usr/src/lib/libscf/common/midlevel.c
+++ b/usr/src/lib/libscf/common/midlevel.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,9 +32,11 @@
#include <strings.h>
#include <string.h>
#include <stdlib.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <libgen.h>
#include "midlevel_impl.h"
-
#ifndef NDEBUG
#define bad_error(func, err) { \
uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
@@ -46,6 +47,9 @@
#define bad_error(func, err) abort()
#endif
+/* Path to speedy files area must end with a slash */
+#define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/"
+
/*
* Internal private function that creates and binds a handle.
*/
@@ -2085,3 +2089,50 @@ scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
*length = ret->pv_opaque.o_size;
return (ret->pv_opaque.o_value);
}
+
+/*
+ * Generate a filename based on the fmri and the given name and return
+ * it in the buffer of MAXPATHLEN provided by the caller.
+ * If temp_filename is non-zero, also generate a temporary, unique filename
+ * and return it in the temp buffer of MAXPATHLEN provided by the caller.
+ * The path to the generated pathname is also created.
+ * Given fmri should begin with a scheme such as "svc:".
+ * Returns
+ * 0 on success
+ * -1 if filename would exceed MAXPATHLEN or
+ * -2 if unable to create directory to filename path
+ */
+int
+gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
+ char *temp_filename)
+{
+ int len;
+
+ len = strlen(SMF_SPEEDY_FILES_PATH);
+ len += strlen(fmri);
+ len += 2; /* for slash and null */
+ len += strlen(name);
+ len += 6; /* For X's needed for mkstemp */
+
+ if (len > MAXPATHLEN)
+ return (-1);
+
+ /* Construct directory name first - speedy path ends in slash */
+ (void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
+ (void) strcat(filename, fmri);
+ if (mkdirp(filename, 0755) == -1) {
+ /* errno is set */
+ if (errno != EEXIST)
+ return (-2);
+ }
+
+ (void) strcat(filename, "/");
+ (void) strcat(filename, name);
+
+ if (temp_filename) {
+ (void) strcpy(temp_filename, filename);
+ (void) strcat(temp_filename, "XXXXXX");
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libscf/inc/libscf_priv.h b/usr/src/lib/libscf/inc/libscf_priv.h
index 8af94d6d71..f4d01f0324 100644
--- a/usr/src/lib/libscf/inc/libscf_priv.h
+++ b/usr/src/lib/libscf/inc/libscf_priv.h
@@ -293,6 +293,8 @@ typedef struct scf_pattern {
int scf_cmp_pattern(char *, scf_pattern_t *);
+int gen_filenms_from_fmri(const char *, const char *, char *, char *);
+
#ifdef __cplusplus
}
#endif