8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / inetd / repval.c
blob0dd5dfeda2273136b20b4f38dc545b6b61508896
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains routines to manipulate lists of repository values that
31 * are used to store process ids and the internal state. There are routines
32 * to read/write the lists from/to the repository and routines to modify or
33 * inspect the lists. It also contains routines that deal with the
34 * repository side of contract ids.
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <libintl.h>
40 #include <unistd.h>
41 #include <string.h>
42 #include <signal.h>
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <libscf_priv.h>
47 #include "inetd_impl.h"
50 * Number of consecutive repository bind retries performed by bind_to_rep()
51 * before failing.
53 #define BIND_TO_REP_RETRIES 10
55 /* Name of property group where inetd's state for a service is stored. */
56 #define PG_NAME_INSTANCE_STATE (const char *) "inetd_state"
58 /* uu_list repval list pool */
59 static uu_list_pool_t *rep_val_pool = NULL;
62 * Repository object pointers that get set-up in repval_init() and closed down
63 * in repval_fini(). They're used in _retrieve_rep_vals(), _store_rep_vals(),
64 * add_remove_contract_norebind(), and adopt_repository_contracts(). They're
65 * global so they can be initialized once on inetd startup, and re-used
66 * there-after in the referenced functions.
68 static scf_handle_t *rep_handle = NULL;
69 static scf_propertygroup_t *pg = NULL;
70 static scf_instance_t *inst = NULL;
71 static scf_transaction_t *trans = NULL;
72 static scf_transaction_entry_t *entry = NULL;
73 static scf_property_t *prop = NULL;
76 * Pathname storage for paths generated from the fmri.
77 * Used when updating the ctid and (start) pid files for an inetd service.
79 static char genfmri_filename[MAXPATHLEN] = "";
80 static char genfmri_temp_filename[MAXPATHLEN] = "";
83 * Try and make the given handle bind be bound to the repository. If
84 * it's already bound, or we succeed a new bind return 0; else return
85 * -1 on failure, with the SCF error set to one of the following:
86 * SCF_ERROR_NO_SERVER
87 * SCF_ERROR_NO_RESOURCES
89 int
90 make_handle_bound(scf_handle_t *hdl)
92 uint_t retries;
94 for (retries = 0; retries <= BIND_TO_REP_RETRIES; retries++) {
95 if ((scf_handle_bind(hdl) == 0) ||
96 (scf_error() == SCF_ERROR_IN_USE))
97 return (0);
99 assert(scf_error() != SCF_ERROR_INVALID_ARGUMENT);
102 return (-1);
106 repval_init(void)
109 * Create the repval list pool.
111 rep_val_pool = uu_list_pool_create("rep_val_pool", sizeof (rep_val_t),
112 offsetof(rep_val_t, link), NULL, UU_LIST_POOL_DEBUG);
113 if (rep_val_pool == NULL) {
114 error_msg("%s: %s", gettext("Failed to create rep_val pool"),
115 uu_strerror(uu_error()));
116 return (-1);
120 * Create and bind a repository handle, and create all repository
121 * objects that we'll use later that are associated with it. On any
122 * errors we simply return -1 and let repval_fini() clean-up after
123 * us.
125 if ((rep_handle = scf_handle_create(SCF_VERSION)) == NULL) {
126 error_msg("%s: %s",
127 gettext("Failed to create repository handle"),
128 scf_strerror(scf_error()));
129 goto cleanup;
130 } else if (make_handle_bound(rep_handle) == -1) {
131 goto cleanup;
132 } else if (((pg = scf_pg_create(rep_handle)) == NULL) ||
133 ((inst = scf_instance_create(rep_handle)) == NULL) ||
134 ((trans = scf_transaction_create(rep_handle)) == NULL) ||
135 ((entry = scf_entry_create(rep_handle)) == NULL) ||
136 ((prop = scf_property_create(rep_handle)) == NULL)) {
137 error_msg("%s: %s",
138 gettext("Failed to create repository object"),
139 scf_strerror(scf_error()));
140 goto cleanup;
143 return (0);
144 cleanup:
145 repval_fini();
146 return (-1);
149 void
150 repval_fini(void)
152 if (rep_handle != NULL) {
154 * We unbind from the repository before we free the repository
155 * objects for efficiency reasons.
157 (void) scf_handle_unbind(rep_handle);
159 scf_pg_destroy(pg);
160 pg = NULL;
161 scf_instance_destroy(inst);
162 inst = NULL;
163 scf_transaction_destroy(trans);
164 trans = NULL;
165 scf_entry_destroy(entry);
166 entry = NULL;
167 scf_property_destroy(prop);
168 prop = NULL;
170 scf_handle_destroy(rep_handle);
171 rep_handle = NULL;
174 if (rep_val_pool != NULL) {
175 uu_list_pool_destroy(rep_val_pool);
176 rep_val_pool = NULL;
180 uu_list_t *
181 create_rep_val_list(void)
183 uu_list_t *ret;
185 if ((ret = uu_list_create(rep_val_pool, NULL, 0)) == NULL)
186 assert(uu_error() == UU_ERROR_NO_MEMORY);
188 return (ret);
191 void
192 destroy_rep_val_list(uu_list_t *list)
194 if (list != NULL) {
195 empty_rep_val_list(list);
196 uu_list_destroy(list);
200 rep_val_t *
201 find_rep_val(uu_list_t *list, int64_t val)
203 rep_val_t *rv;
205 for (rv = uu_list_first(list); rv != NULL;
206 rv = uu_list_next(list, rv)) {
207 if (rv->val == val)
208 break;
210 return (rv);
214 add_rep_val(uu_list_t *list, int64_t val)
216 rep_val_t *rv;
218 if ((rv = malloc(sizeof (rep_val_t))) == NULL)
219 return (-1);
221 uu_list_node_init(rv, &rv->link, rep_val_pool);
222 rv->val = val;
223 rv->scf_val = NULL;
224 (void) uu_list_insert_after(list, NULL, rv);
226 return (0);
229 void
230 remove_rep_val(uu_list_t *list, int64_t val)
232 rep_val_t *rv;
234 if ((rv = find_rep_val(list, val)) != NULL) {
235 uu_list_remove(list, rv);
236 assert(rv->scf_val == NULL);
237 free(rv);
241 void
242 empty_rep_val_list(uu_list_t *list)
244 void *cookie = NULL;
245 rep_val_t *rv;
247 while ((rv = uu_list_teardown(list, &cookie)) != NULL) {
248 if (rv->scf_val != NULL)
249 scf_value_destroy(rv->scf_val);
250 free(rv);
254 int64_t
255 get_single_rep_val(uu_list_t *list)
257 rep_val_t *rv = uu_list_first(list);
259 assert(rv != NULL);
260 return (rv->val);
264 set_single_rep_val(uu_list_t *list, int64_t val)
266 rep_val_t *rv = uu_list_first(list);
268 if (rv == NULL) {
269 if (add_rep_val(list, val) == -1)
270 return (-1);
271 } else {
272 rv->val = val;
275 return (0);
279 * Partner to add_tr_entry_values. This function frees the scf_values created
280 * in add_tr_entry_values() in the list 'vals'.
282 static void
283 remove_tr_entry_values(uu_list_t *vals)
285 rep_val_t *rval;
287 for (rval = uu_list_first(vals); rval != NULL;
288 rval = uu_list_next(vals, rval)) {
289 if (rval->scf_val != NULL) {
290 scf_value_destroy(rval->scf_val);
291 rval->scf_val = NULL;
297 * This function creates and associates with transaction entry 'entry' an
298 * scf value for each value in 'vals'. The pointers to the scf values
299 * are stored in the list for later cleanup by remove_tr_entry_values.
300 * Returns 0 on success, else -1 on error with scf_error() set to:
301 * SCF_ERROR_NO_MEMORY if memory allocation failed.
302 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
304 static int
305 add_tr_entry_values(scf_handle_t *hdl, scf_transaction_entry_t *entry,
306 uu_list_t *vals)
308 rep_val_t *rval;
310 for (rval = uu_list_first(vals); rval != NULL;
311 rval = uu_list_next(vals, rval)) {
313 assert(rval->scf_val == NULL);
314 if ((rval->scf_val = scf_value_create(hdl)) == NULL) {
315 remove_tr_entry_values(vals);
316 return (-1);
319 scf_value_set_integer(rval->scf_val, rval->val);
321 if (scf_entry_add_value(entry, rval->scf_val) < 0) {
322 remove_tr_entry_values(vals);
323 return (-1);
327 return (0);
331 * Stores the values contained in the list 'vals' into the property 'prop_name'
332 * of the instance with fmri 'inst_fmri', within the instance's instance
333 * state property group.
335 * Returns 0 on success, else one of the following on failure:
336 * SCF_ERROR_NO_MEMORY if memory allocation failed.
337 * SCF_ERROR_NO_RESOURCES if the server doesn't have required resources.
338 * SCF_ERROR_VERSION_MISMATCH if program compiled against a newer libscf
339 * than on system.
340 * SCF_ERROR_PERMISSION_DENIED if insufficient privileges to modify pg.
341 * SCF_ERROR_BACKEND_ACCESS if the repository back-end refused the pg modify.
342 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
344 static scf_error_t
345 _store_rep_vals(uu_list_t *vals, const char *inst_fmri, const char *prop_name)
347 int cret;
348 int ret;
350 if (scf_handle_decode_fmri(rep_handle, inst_fmri, NULL, NULL, inst,
351 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1)
352 return (scf_error());
355 * Fetch the instance state pg, and if it doesn't exist try and
356 * create it.
358 if (scf_instance_get_pg(inst, PG_NAME_INSTANCE_STATE, pg) < 0) {
359 if (scf_error() != SCF_ERROR_NOT_FOUND)
360 return (scf_error());
361 if (scf_instance_add_pg(inst, PG_NAME_INSTANCE_STATE,
362 SCF_GROUP_FRAMEWORK, SCF_PG_FLAG_NONPERSISTENT, pg) < 0)
363 return (scf_error());
367 * Perform a transaction to write the values to the requested property.
368 * If someone got there before us, loop and retry.
370 do {
371 if (scf_transaction_start(trans, pg) < 0)
372 return (scf_error());
374 if ((scf_transaction_property_new(trans, entry,
375 prop_name, SCF_TYPE_INTEGER) < 0) &&
376 (scf_transaction_property_change_type(trans, entry,
377 prop_name, SCF_TYPE_INTEGER) < 0)) {
378 ret = scf_error();
379 goto cleanup;
382 if (add_tr_entry_values(rep_handle, entry, vals) < 0) {
383 ret = scf_error();
384 goto cleanup;
387 if ((cret = scf_transaction_commit(trans)) < 0) {
388 ret = scf_error();
389 goto cleanup;
390 } else if (cret == 0) {
391 scf_transaction_reset(trans);
392 scf_entry_reset(entry);
393 remove_tr_entry_values(vals);
394 if (scf_pg_update(pg) < 0) {
395 ret = scf_error();
396 goto cleanup;
399 } while (cret == 0);
401 ret = 0;
402 cleanup:
403 scf_transaction_reset(trans);
404 scf_entry_reset(entry);
405 remove_tr_entry_values(vals);
406 return (ret);
410 * Retrieves the repository values of property 'prop_name', of the instance
411 * with fmri 'fmri', from within the instance's instance state property
412 * group and adds them to the value list 'list'.
414 * Returns 0 on success, else one of the following values on error:
415 * SCF_ERROR_NOT_FOUND if the property doesn't exist.
416 * SCF_ERROR_NO_MEMORY if memory allocation failed.
417 * SCF_ERROR_CONNECTION_BROKEN if the connection to the repository was broken.
418 * SCF_ERROR_TYPE_MISMATCH if the property was of an unexpected type.
421 static scf_error_t
422 _retrieve_rep_vals(uu_list_t *list, const char *fmri, const char *prop_name)
424 scf_simple_prop_t *sp;
425 int64_t *ip;
427 if ((sp = scf_simple_prop_get(rep_handle, fmri, PG_NAME_INSTANCE_STATE,
428 prop_name)) == NULL)
429 return (scf_error());
431 while ((ip = scf_simple_prop_next_integer(sp)) != NULL) {
432 if (add_rep_val(list, *ip) == -1) {
433 empty_rep_val_list(list);
434 scf_simple_prop_free(sp);
435 return (SCF_ERROR_NO_MEMORY);
438 if (scf_error() != SCF_ERROR_NONE) {
439 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
440 empty_rep_val_list(list);
441 scf_simple_prop_free(sp);
442 return (scf_error());
445 scf_simple_prop_free(sp);
446 return (0);
450 * Writes the repository values in the vals list to
451 * a file that is generated based on the passed in fmri and name.
452 * Returns 0 on success,
453 * ENAMETOOLONG if unable to generate filename from fmri (including
454 * the inability to create the directory for the generated filename) and
455 * ENOENT on all other failures.
457 static int
458 repvals_to_file(const char *fmri, const char *name, uu_list_t *vals)
460 int tfd;
461 FILE *tfp; /* temp fp */
462 rep_val_t *spval; /* Contains a start_pid or ctid */
463 int ret = 0;
465 if (gen_filenms_from_fmri(fmri, name, genfmri_filename,
466 genfmri_temp_filename) != 0) {
467 /* Failure either from fmri too long or mkdir failure */
468 return (ENAMETOOLONG);
471 if ((tfd = mkstemp(genfmri_temp_filename)) == -1) {
472 return (ENOENT);
475 if (fchmod(tfd, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) {
476 (void) close(tfd);
477 ret = ENOENT;
478 goto unlink_out;
481 if ((tfp = fdopen(tfd, "w")) == NULL) {
482 (void) close(tfd);
483 ret = ENOENT;
484 goto unlink_out;
487 for (spval = uu_list_first(vals); spval != NULL;
488 spval = uu_list_next(vals, spval)) {
489 if (fprintf(tfp, "%lld\n", spval->val) <= 0) {
490 (void) fclose(tfp);
491 ret = ENOENT;
492 goto unlink_out;
495 if (fclose(tfp) != 0) {
496 ret = ENOENT;
497 goto unlink_out;
499 if (rename(genfmri_temp_filename, genfmri_filename) != 0) {
500 ret = ENOENT;
501 goto unlink_out;
503 return (0);
505 unlink_out:
506 if (unlink(genfmri_temp_filename) != 0) {
507 warn_msg(gettext("Removal of temp file "
508 "%s failed. Please remove manually."),
509 genfmri_temp_filename);
511 return (ret);
515 * A routine that loops trying to read/write values until either success,
516 * an error other than a broken repository connection or
517 * the number of retries reaches REP_OP_RETRIES.
518 * This action is used to read/write the values:
519 * reads/writes to a file for the START_PIDS property due to scalability
520 * problems with libscf
521 * reads/writes to the repository for all other properties.
522 * Returns 0 on success, else the error value from either _store_rep_vals or
523 * _retrieve_rep_vals (based on whether 'store' was set or not), or one of the
524 * following:
525 * SCF_ERROR_NO_RESOURCES if the server doesn't have adequate resources
526 * SCF_ERROR_NO_MEMORY if a memory allocation failure
527 * SCF_ERROR_NO_SERVER if the server isn't running.
528 * SCF_ERROR_CONSTRAINT_VIOLATED if an error in dealing with the speedy files
530 static scf_error_t
531 store_retrieve_rep_vals(uu_list_t *vals, const char *fmri,
532 const char *prop, boolean_t store)
534 scf_error_t ret = 0;
535 uint_t retries;
536 FILE *tfp; /* temp fp */
537 int64_t tval; /* temp val holder */
538 int fscanf_ret;
539 int fopen_retry_cnt = 2;
541 /* inetd specific action for START_PIDS property */
542 if (strcmp(prop, PR_NAME_START_PIDS) == 0) {
544 * Storage performance of START_PIDS is important,
545 * so each instance has its own file and all start_pids
546 * in the list are written to a temp file and then
547 * moved (renamed).
549 if (store) {
550 /* Write all values in list to file */
551 if (repvals_to_file(fmri, "pid", vals)) {
552 return (SCF_ERROR_CONSTRAINT_VIOLATED);
554 } else {
555 /* no temp name needed */
556 if (gen_filenms_from_fmri(fmri, "pid", genfmri_filename,
557 NULL) != 0)
558 return (SCF_ERROR_CONSTRAINT_VIOLATED);
560 retry_fopen:
561 /* It's ok if no file, there are just no pids */
562 if ((tfp = fopen(genfmri_filename, "r")) == NULL) {
563 if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
564 fopen_retry_cnt--;
565 goto retry_fopen;
567 return (0);
569 /* fscanf may not set errno, so clear it first */
570 errno = 0;
571 while ((fscanf_ret = fscanf(tfp, "%lld", &tval)) == 1) {
572 /* If tval isn't a valid pid, then fail. */
573 if ((tval > MAXPID) || (tval <= 0)) {
574 empty_rep_val_list(vals);
575 return (SCF_ERROR_CONSTRAINT_VIOLATED);
577 if (add_rep_val(vals, tval) == -1) {
578 empty_rep_val_list(vals);
579 return (SCF_ERROR_NO_MEMORY);
581 errno = 0;
583 /* EOF is ok when no errno */
584 if ((fscanf_ret != EOF) || (errno != 0)) {
585 empty_rep_val_list(vals);
586 return (SCF_ERROR_CONSTRAINT_VIOLATED);
588 if (fclose(tfp) != 0) {
589 /* for close failure just log a message */
590 warn_msg(gettext("Close of file %s failed."),
591 genfmri_filename);
594 } else {
595 for (retries = 0; retries <= REP_OP_RETRIES; retries++) {
596 if (make_handle_bound(rep_handle) == -1) {
597 ret = scf_error();
598 break;
601 if ((ret = (store ? _store_rep_vals(vals, fmri, prop) :
602 _retrieve_rep_vals(vals, fmri, prop))) !=
603 SCF_ERROR_CONNECTION_BROKEN)
604 break;
606 (void) scf_handle_unbind(rep_handle);
610 out:
611 return (ret);
614 scf_error_t
615 store_rep_vals(uu_list_t *vals, const char *fmri, const char *prop)
617 return (store_retrieve_rep_vals(vals, fmri, prop, B_TRUE));
620 scf_error_t
621 retrieve_rep_vals(uu_list_t *vals, const char *fmri, const char *prop)
623 return (store_retrieve_rep_vals(vals, fmri, prop, B_FALSE));
627 * Adds/removes a contract id to/from the cached list kept in the instance.
628 * Then the cached list is written to a file named "ctid" in a directory
629 * based on the fmri. Cached list is written to a file due to scalability
630 * problems in libscf. The file "ctid" is used when inetd is restarted
631 * so that inetd can adopt the contracts that it had previously.
632 * Returns:
633 * 0 on success
634 * ENAMETOOLONG if unable to generate filename from fmri (including
635 * the inability to create the directory for the generated filename)
636 * ENOENT - failure accessing file
637 * ENOMEM - memory allocation failure
640 add_remove_contract(instance_t *inst, boolean_t add, ctid_t ctid)
642 FILE *tfp; /* temp fp */
643 int ret = 0;
644 int repval_ret = 0;
645 int fopen_retry_cnt = 2;
648 * Storage performance of contract ids is important,
649 * so each instance has its own file. An add of a
650 * ctid will be appended to the ctid file.
651 * The removal of a ctid will result in the remaining
652 * ctids in the list being written to a temp file and then
653 * moved (renamed).
655 if (add) {
656 if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename,
657 NULL) != 0) {
658 /* Failure either from fmri too long or mkdir failure */
659 return (ENAMETOOLONG);
662 retry_fopen:
663 if ((tfp = fopen(genfmri_filename, "a")) == NULL) {
664 if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
665 fopen_retry_cnt--;
666 goto retry_fopen;
668 ret = ENOENT;
669 goto out;
672 /* Always store ctids as long long */
673 if (fprintf(tfp, "%llu\n", (uint64_t)ctid) <= 0) {
674 (void) fclose(tfp);
675 ret = ENOENT;
676 goto out;
679 if (fclose(tfp) != 0) {
680 ret = ENOENT;
681 goto out;
684 if (add_rep_val(inst->start_ctids, ctid) != 0) {
685 ret = ENOMEM;
686 goto out;
688 } else {
689 remove_rep_val(inst->start_ctids, ctid);
691 /* Write all values in list to file */
692 if ((repval_ret = repvals_to_file(inst->fmri, "ctid",
693 inst->start_ctids)) != 0) {
694 ret = repval_ret;
695 goto out;
699 out:
700 return (ret);
704 * If sig !=0, iterate over all contracts in the cached list of contract
705 * ids kept in the instance. Send each contract the specified signal.
706 * If sig == 0, read in the contract ids that were last associated
707 * with this instance (reload the cache) and call adopt_contract()
708 * to take ownership.
710 * Returns 0 on success;
711 * ENAMETOOLONG if unable to generate filename from fmri (including
712 * the inability to create the directory for the generated filename) and
713 * ENXIO if a failure accessing the file
714 * ENOMEM if there was a memory allocation failure
715 * ENOENT if the instance, its restarter property group, or its
716 * contract property don't exist
717 * EIO if invalid data read from the file
720 iterate_repository_contracts(instance_t *inst, int sig)
722 int ret = 0;
723 FILE *fp;
724 rep_val_t *spval = NULL; /* Contains a start_pid */
725 uint64_t tval; /* temp val holder */
726 uu_list_t *uup = NULL;
727 int fscanf_ret;
728 int fopen_retry_cnt = 2;
730 if (sig != 0) {
732 * Send a signal to all in the contract; ESRCH just
733 * means they all exited before we could kill them
735 for (spval = uu_list_first(inst->start_ctids); spval != NULL;
736 spval = uu_list_next(inst->start_ctids, spval)) {
737 if (sigsend(P_CTID, (ctid_t)spval->val, sig) == -1 &&
738 errno != ESRCH) {
739 warn_msg(gettext("Unable to signal all "
740 "contract members of instance %s: %s"),
741 inst->fmri, strerror(errno));
744 return (0);
748 * sig == 0 case.
749 * Attempt to adopt the contract for each ctid.
751 if (gen_filenms_from_fmri(inst->fmri, "ctid", genfmri_filename,
752 NULL) != 0) {
753 /* Failure either from fmri too long or mkdir failure */
754 return (ENAMETOOLONG);
757 retry_fopen:
758 /* It's ok if no file, there are no ctids to adopt */
759 if ((fp = fopen(genfmri_filename, "r")) == NULL) {
760 if ((errno == EINTR) && (fopen_retry_cnt > 0)) {
761 fopen_retry_cnt--;
762 goto retry_fopen;
764 return (0);
768 * Read ctids from file into 2 lists:
769 * - temporary list to be traversed (uup)
770 * - cached list that can be modified if adoption of
771 * contract fails (inst->start_ctids).
772 * Always treat ctids as long longs.
774 uup = create_rep_val_list();
775 /* fscanf may not set errno, so clear it first */
776 errno = 0;
777 while ((fscanf_ret = fscanf(fp, "%llu", &tval)) == 1) {
778 /* If tval isn't a valid ctid, then fail. */
779 if (tval == 0) {
780 (void) fclose(fp);
781 ret = EIO;
782 goto out;
784 if ((add_rep_val(uup, tval) == -1) ||
785 (add_rep_val(inst->start_ctids, tval) == -1)) {
786 (void) fclose(fp);
787 ret = ENOMEM;
788 goto out;
790 errno = 0;
792 /* EOF is not a failure when no errno */
793 if ((fscanf_ret != EOF) || (errno != 0)) {
794 ret = EIO;
795 goto out;
798 if (fclose(fp) != 0) {
799 ret = ENXIO;
800 goto out;
803 for (spval = uu_list_first(uup); spval != NULL;
804 spval = uu_list_next(uup, spval)) {
805 /* Try to adopt the contract */
806 if (adopt_contract((ctid_t)spval->val,
807 inst->fmri) != 0) {
809 * Adoption failed. No reason to think it'll
810 * work later, so remove the id from our list
811 * in the instance.
813 remove_rep_val(inst->start_ctids, spval->val);
816 out:
817 if (uup) {
818 empty_rep_val_list(uup);
819 destroy_rep_val_list(uup);
822 if (ret != 0)
823 empty_rep_val_list(inst->start_ctids);
825 return (ret);