1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <librestart.h> 30*0Sstevel@tonic-gate #include <librestart_priv.h> 31*0Sstevel@tonic-gate #include <libscf.h> 32*0Sstevel@tonic-gate #include <libscf_priv.h> 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <assert.h> 35*0Sstevel@tonic-gate #include <ctype.h> 36*0Sstevel@tonic-gate #include <dlfcn.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate #include <exec_attr.h> 39*0Sstevel@tonic-gate #include <grp.h> 40*0Sstevel@tonic-gate #include <libsysevent.h> 41*0Sstevel@tonic-gate #include <libuutil.h> 42*0Sstevel@tonic-gate #include <limits.h> 43*0Sstevel@tonic-gate #include <link.h> 44*0Sstevel@tonic-gate #include <malloc.h> 45*0Sstevel@tonic-gate #include <pool.h> 46*0Sstevel@tonic-gate #include <priv.h> 47*0Sstevel@tonic-gate #include <project.h> 48*0Sstevel@tonic-gate #include <pthread.h> 49*0Sstevel@tonic-gate #include <pwd.h> 50*0Sstevel@tonic-gate #include <secdb.h> 51*0Sstevel@tonic-gate #include <signal.h> 52*0Sstevel@tonic-gate #include <stdlib.h> 53*0Sstevel@tonic-gate #include <string.h> 54*0Sstevel@tonic-gate #include <syslog.h> 55*0Sstevel@tonic-gate #include <sys/corectl.h> 56*0Sstevel@tonic-gate #include <sys/machelf.h> 57*0Sstevel@tonic-gate #include <sys/task.h> 58*0Sstevel@tonic-gate #include <sys/types.h> 59*0Sstevel@tonic-gate #include <time.h> 60*0Sstevel@tonic-gate #include <unistd.h> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #define walkcontext _walkcontext 63*0Sstevel@tonic-gate #include <ucontext.h> 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate #define min(a, b) ((a) > (b) ? (b) : (a)) 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate #define MKW_TRUE ":true" 68*0Sstevel@tonic-gate #define MKW_KILL ":kill" 69*0Sstevel@tonic-gate #define MKW_KILL_PROC ":kill_process" 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate #define ALLOCFAIL ((char *)"Allocation failure.") 72*0Sstevel@tonic-gate #define RCBROKEN ((char *)"Repository connection broken.") 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate #define MAX_COMMIT_RETRIES 20 75*0Sstevel@tonic-gate #define MAX_COMMIT_RETRY_INT (5 * 1000000) /* 5 seconds */ 76*0Sstevel@tonic-gate #define INITIAL_COMMIT_RETRY_INT (10000) /* 1/100th second */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate /* 79*0Sstevel@tonic-gate * bad_fail() catches bugs in this and lower layers by reporting supposedly 80*0Sstevel@tonic-gate * impossible function failures. The NDEBUG case keeps the strings out of the 81*0Sstevel@tonic-gate * library but still calls abort() so we can root-cause from the coredump. 82*0Sstevel@tonic-gate */ 83*0Sstevel@tonic-gate #ifndef NDEBUG 84*0Sstevel@tonic-gate #define bad_fail(func, err) { \ 85*0Sstevel@tonic-gate (void) fprintf(stderr, \ 86*0Sstevel@tonic-gate "At %s:%d, %s() failed with unexpected error %d. Aborting.\n", \ 87*0Sstevel@tonic-gate __FILE__, __LINE__, (func), (err)); \ 88*0Sstevel@tonic-gate abort(); \ 89*0Sstevel@tonic-gate } 90*0Sstevel@tonic-gate #else 91*0Sstevel@tonic-gate #define bad_fail(func, err) abort() 92*0Sstevel@tonic-gate #endif 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate struct restarter_event_handle { 95*0Sstevel@tonic-gate char *reh_restarter_name; 96*0Sstevel@tonic-gate char *reh_delegate_channel_name; 97*0Sstevel@tonic-gate evchan_t *reh_delegate_channel; 98*0Sstevel@tonic-gate char *reh_delegate_subscriber_id; 99*0Sstevel@tonic-gate char *reh_master_channel_name; 100*0Sstevel@tonic-gate evchan_t *reh_master_channel; 101*0Sstevel@tonic-gate char *reh_master_subscriber_id; 102*0Sstevel@tonic-gate int (*reh_handler)(restarter_event_t *); 103*0Sstevel@tonic-gate }; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate struct restarter_event { 106*0Sstevel@tonic-gate sysevent_t *re_sysevent; 107*0Sstevel@tonic-gate restarter_event_type_t re_type; 108*0Sstevel@tonic-gate char *re_instance_name; 109*0Sstevel@tonic-gate restarter_event_handle_t *re_event_handle; 110*0Sstevel@tonic-gate restarter_instance_state_t re_state; 111*0Sstevel@tonic-gate restarter_instance_state_t re_next_state; 112*0Sstevel@tonic-gate }; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate static const char * const allocfail = "Allocation failure.\n"; 115*0Sstevel@tonic-gate static const char * const rcbroken = "Repository connection broken.\n"; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate static int method_context_safety = 0; /* Can safely call pools/projects. */ 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate int ndebug = 1; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate static void 122*0Sstevel@tonic-gate free_restarter_event_handle(struct restarter_event_handle *h) 123*0Sstevel@tonic-gate { 124*0Sstevel@tonic-gate if (h == NULL) 125*0Sstevel@tonic-gate return; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate /* 128*0Sstevel@tonic-gate * Just free the memory -- don't unbind the sysevent handle, 129*0Sstevel@tonic-gate * as otherwise events may be lost if this is just a restarter 130*0Sstevel@tonic-gate * restart. 131*0Sstevel@tonic-gate */ 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate if (h->reh_restarter_name != NULL) 134*0Sstevel@tonic-gate free(h->reh_restarter_name); 135*0Sstevel@tonic-gate if (h->reh_delegate_channel_name != NULL) 136*0Sstevel@tonic-gate free(h->reh_delegate_channel_name); 137*0Sstevel@tonic-gate if (h->reh_delegate_subscriber_id != NULL) 138*0Sstevel@tonic-gate free(h->reh_delegate_subscriber_id); 139*0Sstevel@tonic-gate if (h->reh_master_channel_name != NULL) 140*0Sstevel@tonic-gate free(h->reh_master_channel_name); 141*0Sstevel@tonic-gate if (h->reh_master_subscriber_id != NULL) 142*0Sstevel@tonic-gate free(h->reh_master_subscriber_id); 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate free(h); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate static const char * 148*0Sstevel@tonic-gate last_part(const char *fmri) 149*0Sstevel@tonic-gate { 150*0Sstevel@tonic-gate char *last_part; 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gate last_part = strrchr(fmri, '/'); 153*0Sstevel@tonic-gate last_part++; 154*0Sstevel@tonic-gate assert(last_part != NULL); 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate return (last_part); 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate char * 160*0Sstevel@tonic-gate _restarter_get_channel_name(const char *fmri, int type) 161*0Sstevel@tonic-gate { 162*0Sstevel@tonic-gate const char *name; 163*0Sstevel@tonic-gate char *chan_name = malloc(MAX_CHNAME_LEN); 164*0Sstevel@tonic-gate char prefix_name[3]; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if (chan_name == NULL) 167*0Sstevel@tonic-gate return (NULL); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate if (type == RESTARTER_CHANNEL_DELEGATE) 170*0Sstevel@tonic-gate (void) strcpy(prefix_name, "d_"); 171*0Sstevel@tonic-gate else if (type == RESTARTER_CHANNEL_MASTER) 172*0Sstevel@tonic-gate (void) strcpy(prefix_name, "m_"); 173*0Sstevel@tonic-gate else { 174*0Sstevel@tonic-gate free(chan_name); 175*0Sstevel@tonic-gate return (NULL); 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate name = last_part(fmri); 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Should check for [a-z],[A-Z],[0-9],.,_,-,: 182*0Sstevel@tonic-gate */ 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate if (snprintf(chan_name, MAX_CHNAME_LEN, "com.sun:scf:%s%s", 185*0Sstevel@tonic-gate prefix_name, name) > MAX_CHNAME_LEN) { 186*0Sstevel@tonic-gate free(chan_name); 187*0Sstevel@tonic-gate return (NULL); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate return (chan_name); 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate int 194*0Sstevel@tonic-gate cb(sysevent_t *syse, void *cookie) 195*0Sstevel@tonic-gate { 196*0Sstevel@tonic-gate restarter_event_handle_t *h = (restarter_event_handle_t *)cookie; 197*0Sstevel@tonic-gate restarter_event_t *e; 198*0Sstevel@tonic-gate nvlist_t *attr_list = NULL; 199*0Sstevel@tonic-gate int ret = 0; 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate e = uu_zalloc(sizeof (restarter_event_t)); 202*0Sstevel@tonic-gate if (e == NULL) 203*0Sstevel@tonic-gate uu_die(allocfail); 204*0Sstevel@tonic-gate e->re_event_handle = h; 205*0Sstevel@tonic-gate e->re_sysevent = syse; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate if (sysevent_get_attr_list(syse, &attr_list) != 0) 208*0Sstevel@tonic-gate uu_die(allocfail); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate if ((nvlist_lookup_uint32(attr_list, RESTARTER_NAME_TYPE, 211*0Sstevel@tonic-gate &(e->re_type)) != 0) || 212*0Sstevel@tonic-gate (nvlist_lookup_string(attr_list, 213*0Sstevel@tonic-gate RESTARTER_NAME_INSTANCE, &(e->re_instance_name)) != 0)) { 214*0Sstevel@tonic-gate uu_warn("%s: Can't decode nvlist for event %p\n", 215*0Sstevel@tonic-gate h->reh_restarter_name, (void *)syse); 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate ret = 0; 218*0Sstevel@tonic-gate } else { 219*0Sstevel@tonic-gate ret = h->reh_handler(e); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate uu_free(e); 223*0Sstevel@tonic-gate nvlist_free(attr_list); 224*0Sstevel@tonic-gate return (ret); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate /* 228*0Sstevel@tonic-gate * restarter_bind_handle(uint32_t, char *, int (*)(restarter_event_t *), int, 229*0Sstevel@tonic-gate * restarter_event_handle_t **) 230*0Sstevel@tonic-gate * 231*0Sstevel@tonic-gate * Bind to a delegated restarter event channel. 232*0Sstevel@tonic-gate * Each delegated restarter gets its own channel for resource management. 233*0Sstevel@tonic-gate * 234*0Sstevel@tonic-gate * Returns 0 on success or 235*0Sstevel@tonic-gate * ENOTSUP version mismatch 236*0Sstevel@tonic-gate * EINVAL restarter_name or event_handle is NULL 237*0Sstevel@tonic-gate * ENOMEM out of memory, too many channels, or too many subscriptions 238*0Sstevel@tonic-gate * EBUSY sysevent_evc_bind() could not establish binding 239*0Sstevel@tonic-gate * EFAULT internal sysevent_evc_bind()/sysevent_evc_subscribe() error 240*0Sstevel@tonic-gate * EMFILE out of file descriptors 241*0Sstevel@tonic-gate * EPERM insufficient privilege for sysevent_evc_bind() 242*0Sstevel@tonic-gate * EEXIST already subscribed 243*0Sstevel@tonic-gate */ 244*0Sstevel@tonic-gate int 245*0Sstevel@tonic-gate restarter_bind_handle(uint32_t version, const char *restarter_name, 246*0Sstevel@tonic-gate int (*event_handler)(restarter_event_t *), int flags, 247*0Sstevel@tonic-gate restarter_event_handle_t **rehp) 248*0Sstevel@tonic-gate { 249*0Sstevel@tonic-gate restarter_event_handle_t *h; 250*0Sstevel@tonic-gate size_t sz; 251*0Sstevel@tonic-gate int err; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate if (version != RESTARTER_EVENT_VERSION) 254*0Sstevel@tonic-gate return (ENOTSUP); 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if (restarter_name == NULL || event_handler == NULL) 257*0Sstevel@tonic-gate return (EINVAL); 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate if (flags & RESTARTER_FLAG_DEBUG) 260*0Sstevel@tonic-gate ndebug++; 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate if ((h = uu_zalloc(sizeof (restarter_event_handle_t))) == NULL) 263*0Sstevel@tonic-gate return (ENOMEM); 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate h->reh_delegate_subscriber_id = malloc(MAX_SUBID_LEN); 266*0Sstevel@tonic-gate h->reh_master_subscriber_id = malloc(MAX_SUBID_LEN); 267*0Sstevel@tonic-gate h->reh_restarter_name = strdup(restarter_name); 268*0Sstevel@tonic-gate if (h->reh_delegate_subscriber_id == NULL || 269*0Sstevel@tonic-gate h->reh_master_subscriber_id == NULL || 270*0Sstevel@tonic-gate h->reh_restarter_name == NULL) { 271*0Sstevel@tonic-gate free_restarter_event_handle(h); 272*0Sstevel@tonic-gate return (ENOMEM); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate sz = strlcpy(h->reh_delegate_subscriber_id, "del", MAX_SUBID_LEN); 276*0Sstevel@tonic-gate assert(sz < MAX_SUBID_LEN); 277*0Sstevel@tonic-gate sz = strlcpy(h->reh_master_subscriber_id, "master", MAX_SUBID_LEN); 278*0Sstevel@tonic-gate assert(sz < MAX_SUBID_LEN); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate h->reh_delegate_channel_name = 281*0Sstevel@tonic-gate _restarter_get_channel_name(restarter_name, 282*0Sstevel@tonic-gate RESTARTER_CHANNEL_DELEGATE); 283*0Sstevel@tonic-gate h->reh_master_channel_name = 284*0Sstevel@tonic-gate _restarter_get_channel_name(restarter_name, 285*0Sstevel@tonic-gate RESTARTER_CHANNEL_MASTER); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if (h->reh_delegate_channel_name == NULL || 288*0Sstevel@tonic-gate h->reh_master_channel_name == NULL) { 289*0Sstevel@tonic-gate free_restarter_event_handle(h); 290*0Sstevel@tonic-gate return (ENOMEM); 291*0Sstevel@tonic-gate } 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate if (sysevent_evc_bind(h->reh_delegate_channel_name, 294*0Sstevel@tonic-gate &h->reh_delegate_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) { 295*0Sstevel@tonic-gate err = errno; 296*0Sstevel@tonic-gate assert(err != EINVAL); 297*0Sstevel@tonic-gate assert(err != ENOENT); 298*0Sstevel@tonic-gate free_restarter_event_handle(h); 299*0Sstevel@tonic-gate return (err); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate if (sysevent_evc_bind(h->reh_master_channel_name, 303*0Sstevel@tonic-gate &h->reh_master_channel, EVCH_CREAT|EVCH_HOLD_PEND) != 0) { 304*0Sstevel@tonic-gate err = errno; 305*0Sstevel@tonic-gate assert(err != EINVAL); 306*0Sstevel@tonic-gate assert(err != ENOENT); 307*0Sstevel@tonic-gate free_restarter_event_handle(h); 308*0Sstevel@tonic-gate return (err); 309*0Sstevel@tonic-gate } 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate h->reh_handler = event_handler; 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate assert(strlen(restarter_name) <= MAX_CLASS_LEN - 1); 314*0Sstevel@tonic-gate assert(strlen(h->reh_delegate_subscriber_id) <= MAX_SUBID_LEN - 1); 315*0Sstevel@tonic-gate assert(strlen(h->reh_master_subscriber_id) <= MAX_SUBID_LEN - 1); 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate if (sysevent_evc_subscribe(h->reh_delegate_channel, 318*0Sstevel@tonic-gate h->reh_delegate_subscriber_id, EC_ALL, cb, h, EVCH_SUB_KEEP) != 0) { 319*0Sstevel@tonic-gate err = errno; 320*0Sstevel@tonic-gate assert(err != EINVAL); 321*0Sstevel@tonic-gate free_restarter_event_handle(h); 322*0Sstevel@tonic-gate return (err); 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate *rehp = h; 326*0Sstevel@tonic-gate return (0); 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate void 330*0Sstevel@tonic-gate restarter_unbind_handle(restarter_event_handle_t *h) 331*0Sstevel@tonic-gate { 332*0Sstevel@tonic-gate free_restarter_event_handle(h); 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate restarter_event_handle_t * 336*0Sstevel@tonic-gate restarter_event_get_handle(restarter_event_t *e) 337*0Sstevel@tonic-gate { 338*0Sstevel@tonic-gate assert(e != NULL && e->re_event_handle != NULL); 339*0Sstevel@tonic-gate return (e->re_event_handle); 340*0Sstevel@tonic-gate } 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate restarter_event_type_t 343*0Sstevel@tonic-gate restarter_event_get_type(restarter_event_t *e) 344*0Sstevel@tonic-gate { 345*0Sstevel@tonic-gate assert(e != NULL); 346*0Sstevel@tonic-gate return (e->re_type); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate ssize_t 350*0Sstevel@tonic-gate restarter_event_get_instance(restarter_event_t *e, char *inst, size_t sz) 351*0Sstevel@tonic-gate { 352*0Sstevel@tonic-gate assert(e != NULL && inst != NULL); 353*0Sstevel@tonic-gate return ((ssize_t)strlcpy(inst, e->re_instance_name, sz)); 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate int 357*0Sstevel@tonic-gate restarter_event_get_current_states(restarter_event_t *e, 358*0Sstevel@tonic-gate restarter_instance_state_t *state, restarter_instance_state_t *next_state) 359*0Sstevel@tonic-gate { 360*0Sstevel@tonic-gate if (e == NULL) 361*0Sstevel@tonic-gate return (-1); 362*0Sstevel@tonic-gate *state = e->re_state; 363*0Sstevel@tonic-gate *next_state = e->re_next_state; 364*0Sstevel@tonic-gate return (0); 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /* 368*0Sstevel@tonic-gate * Commit the state, next state, and auxiliary state into the repository. 369*0Sstevel@tonic-gate * Let the graph engine know about the state change and error. On success, 370*0Sstevel@tonic-gate * return 0. On error, return 371*0Sstevel@tonic-gate * EINVAL - aux has spaces 372*0Sstevel@tonic-gate * - inst is invalid or not an instance FMRI 373*0Sstevel@tonic-gate * EPROTO - librestart compiled against different libscf 374*0Sstevel@tonic-gate * ENOMEM - out of memory 375*0Sstevel@tonic-gate * - repository server out of resources 376*0Sstevel@tonic-gate * ENOTACTIVE - repository server not running 377*0Sstevel@tonic-gate * ECONNABORTED - repository connection established, but then broken 378*0Sstevel@tonic-gate * - unknown libscf error 379*0Sstevel@tonic-gate * ENOENT - inst does not exist in the repository 380*0Sstevel@tonic-gate * EPERM - insufficient permissions 381*0Sstevel@tonic-gate * EACCESS - backend access denied 382*0Sstevel@tonic-gate * EROFS - backend is readonly 383*0Sstevel@tonic-gate * EFAULT - internal sysevent_evc_publish() error 384*0Sstevel@tonic-gate * EBADF - h is invalid (sysevent_evc_publish() returned EINVAL) 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate int 387*0Sstevel@tonic-gate restarter_set_states(restarter_event_handle_t *h, const char *inst, 388*0Sstevel@tonic-gate restarter_instance_state_t cur_state, 389*0Sstevel@tonic-gate restarter_instance_state_t new_cur_state, 390*0Sstevel@tonic-gate restarter_instance_state_t next_state, 391*0Sstevel@tonic-gate restarter_instance_state_t new_next_state, restarter_error_t e, 392*0Sstevel@tonic-gate const char *aux) 393*0Sstevel@tonic-gate { 394*0Sstevel@tonic-gate nvlist_t *attr; 395*0Sstevel@tonic-gate scf_handle_t *scf_h; 396*0Sstevel@tonic-gate instance_data_t id; 397*0Sstevel@tonic-gate useconds_t retry_int = INITIAL_COMMIT_RETRY_INT; 398*0Sstevel@tonic-gate int retries; 399*0Sstevel@tonic-gate int ret = 0; 400*0Sstevel@tonic-gate char *p = (char *)aux; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate assert(h->reh_master_channel != NULL); 403*0Sstevel@tonic-gate assert(h->reh_master_channel_name != NULL); 404*0Sstevel@tonic-gate assert(h->reh_master_subscriber_id != NULL); 405*0Sstevel@tonic-gate 406*0Sstevel@tonic-gate /* Validate format of auxiliary state: no spaces allowed */ 407*0Sstevel@tonic-gate while (p != NULL) { 408*0Sstevel@tonic-gate if (isspace(*p)) 409*0Sstevel@tonic-gate return (EINVAL); 410*0Sstevel@tonic-gate p++; 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if ((scf_h = scf_handle_create(SCF_VERSION)) == NULL) { 414*0Sstevel@tonic-gate switch (scf_error()) { 415*0Sstevel@tonic-gate case SCF_ERROR_VERSION_MISMATCH: 416*0Sstevel@tonic-gate return (EPROTO); 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate case SCF_ERROR_NO_MEMORY: 419*0Sstevel@tonic-gate return (ENOMEM); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate default: 422*0Sstevel@tonic-gate bad_fail("scf_handle_create", scf_error()); 423*0Sstevel@tonic-gate } 424*0Sstevel@tonic-gate } 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate if (scf_handle_bind(scf_h) == -1) { 427*0Sstevel@tonic-gate scf_handle_destroy(scf_h); 428*0Sstevel@tonic-gate switch (scf_error()) { 429*0Sstevel@tonic-gate case SCF_ERROR_NO_SERVER: 430*0Sstevel@tonic-gate return (ENOTACTIVE); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate case SCF_ERROR_NO_RESOURCES: 433*0Sstevel@tonic-gate return (ENOMEM); 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 436*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 437*0Sstevel@tonic-gate default: 438*0Sstevel@tonic-gate bad_fail("scf_handle_bind", scf_error()); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate if (nvlist_alloc(&attr, NV_UNIQUE_NAME, 0) != 0 || 443*0Sstevel@tonic-gate nvlist_add_int32(attr, RESTARTER_NAME_STATE, new_cur_state) != 0 || 444*0Sstevel@tonic-gate nvlist_add_int32(attr, RESTARTER_NAME_NEXT_STATE, new_next_state) 445*0Sstevel@tonic-gate != 0 || 446*0Sstevel@tonic-gate nvlist_add_int32(attr, RESTARTER_NAME_ERROR, e) != 0 || 447*0Sstevel@tonic-gate nvlist_add_string(attr, RESTARTER_NAME_INSTANCE, inst) != 0) { 448*0Sstevel@tonic-gate ret = ENOMEM; 449*0Sstevel@tonic-gate goto errout; 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate id.i_fmri = inst; 453*0Sstevel@tonic-gate id.i_state = cur_state; 454*0Sstevel@tonic-gate id.i_next_state = next_state; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate ret = _restarter_commit_states(scf_h, &id, new_cur_state, 457*0Sstevel@tonic-gate new_next_state, aux); 458*0Sstevel@tonic-gate if (ret != 0) 459*0Sstevel@tonic-gate goto errout; 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate for (retries = 0; retries < MAX_COMMIT_RETRIES; retries++) { 462*0Sstevel@tonic-gate ret = sysevent_evc_publish(h->reh_master_channel, "master", 463*0Sstevel@tonic-gate "state_change", "com.sun", "librestart", attr, 464*0Sstevel@tonic-gate EVCH_NOSLEEP); 465*0Sstevel@tonic-gate if (ret == 0) 466*0Sstevel@tonic-gate break; 467*0Sstevel@tonic-gate 468*0Sstevel@tonic-gate switch (ret) { 469*0Sstevel@tonic-gate case EAGAIN: 470*0Sstevel@tonic-gate /* Queue is full */ 471*0Sstevel@tonic-gate (void) usleep(retry_int); 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate retry_int = min(retry_int * 2, MAX_COMMIT_RETRY_INT); 474*0Sstevel@tonic-gate break; 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate case EFAULT: 477*0Sstevel@tonic-gate case ENOMEM: 478*0Sstevel@tonic-gate goto errout; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate case EINVAL: 481*0Sstevel@tonic-gate ret = EBADF; 482*0Sstevel@tonic-gate goto errout; 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate case EOVERFLOW: 485*0Sstevel@tonic-gate default: 486*0Sstevel@tonic-gate bad_fail("sysevent_evc_publish", ret); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate errout: 491*0Sstevel@tonic-gate nvlist_free(attr); 492*0Sstevel@tonic-gate (void) scf_handle_unbind(scf_h); 493*0Sstevel@tonic-gate scf_handle_destroy(scf_h); 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate return (ret); 496*0Sstevel@tonic-gate } 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate restarter_instance_state_t 499*0Sstevel@tonic-gate restarter_string_to_state(char *string) 500*0Sstevel@tonic-gate { 501*0Sstevel@tonic-gate assert(string != NULL); 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate if (strcmp(string, SCF_STATE_STRING_NONE) == 0) 504*0Sstevel@tonic-gate return (RESTARTER_STATE_NONE); 505*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_UNINIT) == 0) 506*0Sstevel@tonic-gate return (RESTARTER_STATE_UNINIT); 507*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_MAINT) == 0) 508*0Sstevel@tonic-gate return (RESTARTER_STATE_MAINT); 509*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_OFFLINE) == 0) 510*0Sstevel@tonic-gate return (RESTARTER_STATE_OFFLINE); 511*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_DISABLED) == 0) 512*0Sstevel@tonic-gate return (RESTARTER_STATE_DISABLED); 513*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_ONLINE) == 0) 514*0Sstevel@tonic-gate return (RESTARTER_STATE_ONLINE); 515*0Sstevel@tonic-gate else if (strcmp(string, SCF_STATE_STRING_DEGRADED) == 0) 516*0Sstevel@tonic-gate return (RESTARTER_STATE_DEGRADED); 517*0Sstevel@tonic-gate else { 518*0Sstevel@tonic-gate return (RESTARTER_STATE_NONE); 519*0Sstevel@tonic-gate } 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate 522*0Sstevel@tonic-gate ssize_t 523*0Sstevel@tonic-gate restarter_state_to_string(restarter_instance_state_t state, char *string, 524*0Sstevel@tonic-gate size_t len) 525*0Sstevel@tonic-gate { 526*0Sstevel@tonic-gate assert(string != NULL); 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate if (state == RESTARTER_STATE_NONE) 529*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_NONE, len)); 530*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_UNINIT) 531*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_UNINIT, len)); 532*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_MAINT) 533*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_MAINT, len)); 534*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_OFFLINE) 535*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_OFFLINE, 536*0Sstevel@tonic-gate len)); 537*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_DISABLED) 538*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DISABLED, 539*0Sstevel@tonic-gate len)); 540*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_ONLINE) 541*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_ONLINE, len)); 542*0Sstevel@tonic-gate else if (state == RESTARTER_STATE_DEGRADED) 543*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, SCF_STATE_STRING_DEGRADED, 544*0Sstevel@tonic-gate len)); 545*0Sstevel@tonic-gate else 546*0Sstevel@tonic-gate return ((ssize_t)strlcpy(string, "unknown", len)); 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * Sets pg to the name property group of s_inst. If it doesn't exist, it is 551*0Sstevel@tonic-gate * added. 552*0Sstevel@tonic-gate * 553*0Sstevel@tonic-gate * Fails with 554*0Sstevel@tonic-gate * ECONNABORTED - repository disconnection or unknown libscf error 555*0Sstevel@tonic-gate * EBADF - inst is not set 556*0Sstevel@tonic-gate * ECANCELED - inst is deleted 557*0Sstevel@tonic-gate * EPERM - permission is denied 558*0Sstevel@tonic-gate * EACCES - backend denied access 559*0Sstevel@tonic-gate * EROFS - backend readonly 560*0Sstevel@tonic-gate */ 561*0Sstevel@tonic-gate static int 562*0Sstevel@tonic-gate instance_get_or_add_pg(scf_instance_t *inst, const char *name, 563*0Sstevel@tonic-gate const char *type, uint32_t flags, scf_propertygroup_t *pg) 564*0Sstevel@tonic-gate { 565*0Sstevel@tonic-gate again: 566*0Sstevel@tonic-gate if (scf_instance_get_pg(inst, name, pg) == 0) 567*0Sstevel@tonic-gate return (0); 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate switch (scf_error()) { 570*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 571*0Sstevel@tonic-gate default: 572*0Sstevel@tonic-gate return (ECONNABORTED); 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 575*0Sstevel@tonic-gate return (EBADF); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 578*0Sstevel@tonic-gate return (ECANCELED); 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 581*0Sstevel@tonic-gate break; 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 584*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 585*0Sstevel@tonic-gate bad_fail("scf_instance_get_pg", scf_error()); 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate if (scf_instance_add_pg(inst, name, type, flags, pg) == 0) 589*0Sstevel@tonic-gate return (0); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate switch (scf_error()) { 592*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 593*0Sstevel@tonic-gate default: 594*0Sstevel@tonic-gate return (ECONNABORTED); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 597*0Sstevel@tonic-gate return (ECANCELED); 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate case SCF_ERROR_EXISTS: 600*0Sstevel@tonic-gate goto again; 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 603*0Sstevel@tonic-gate return (EPERM); 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 606*0Sstevel@tonic-gate return (EACCES); 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 609*0Sstevel@tonic-gate return (EROFS); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 612*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 613*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: /* should be caught above */ 614*0Sstevel@tonic-gate bad_fail("scf_instance_add_pg", scf_error()); 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate return (0); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * Fails with 622*0Sstevel@tonic-gate * ECONNABORTED 623*0Sstevel@tonic-gate * ECANCELED - pg was deleted 624*0Sstevel@tonic-gate */ 625*0Sstevel@tonic-gate static int 626*0Sstevel@tonic-gate tx_set_value(scf_transaction_t *tx, scf_transaction_entry_t *ent, 627*0Sstevel@tonic-gate const char *pname, scf_type_t ty, scf_value_t *val) 628*0Sstevel@tonic-gate { 629*0Sstevel@tonic-gate int r; 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate for (;;) { 632*0Sstevel@tonic-gate if (scf_transaction_property_change_type(tx, ent, pname, 633*0Sstevel@tonic-gate ty) == 0) 634*0Sstevel@tonic-gate break; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate switch (scf_error()) { 637*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 638*0Sstevel@tonic-gate default: 639*0Sstevel@tonic-gate return (ECONNABORTED); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 642*0Sstevel@tonic-gate return (ECANCELED); 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 645*0Sstevel@tonic-gate break; 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 648*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 649*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 650*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 651*0Sstevel@tonic-gate bad_fail("scf_transaction_property_change_type", 652*0Sstevel@tonic-gate scf_error()); 653*0Sstevel@tonic-gate } 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate if (scf_transaction_property_new(tx, ent, pname, ty) == 0) 656*0Sstevel@tonic-gate break; 657*0Sstevel@tonic-gate 658*0Sstevel@tonic-gate switch (scf_error()) { 659*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 660*0Sstevel@tonic-gate default: 661*0Sstevel@tonic-gate return (ECONNABORTED); 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 664*0Sstevel@tonic-gate return (ECANCELED); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate case SCF_ERROR_EXISTS: 667*0Sstevel@tonic-gate break; 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 670*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 671*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 672*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 673*0Sstevel@tonic-gate bad_fail("scf_transaction_property_new", scf_error()); 674*0Sstevel@tonic-gate } 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate r = scf_entry_add_value(ent, val); 678*0Sstevel@tonic-gate assert(r == 0); 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate return (0); 681*0Sstevel@tonic-gate } 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate /* 684*0Sstevel@tonic-gate * Commit new_state, new_next_state, and aux to the repository for id. If 685*0Sstevel@tonic-gate * successful, also set id's state and next-state as given, and return 0. 686*0Sstevel@tonic-gate * Fails with 687*0Sstevel@tonic-gate * ENOMEM - out of memory 688*0Sstevel@tonic-gate * ECONNABORTED - repository connection broken 689*0Sstevel@tonic-gate * - unknown libscf error 690*0Sstevel@tonic-gate * EINVAL - id->i_fmri is invalid or not an instance FMRI 691*0Sstevel@tonic-gate * ENOENT - id->i_fmri does not exist 692*0Sstevel@tonic-gate * EPERM - insufficient permissions 693*0Sstevel@tonic-gate * EACCES - backend access denied 694*0Sstevel@tonic-gate * EROFS - backend is readonly 695*0Sstevel@tonic-gate */ 696*0Sstevel@tonic-gate int 697*0Sstevel@tonic-gate _restarter_commit_states(scf_handle_t *h, instance_data_t *id, 698*0Sstevel@tonic-gate restarter_instance_state_t new_state, 699*0Sstevel@tonic-gate restarter_instance_state_t new_state_next, const char *aux) 700*0Sstevel@tonic-gate { 701*0Sstevel@tonic-gate char str_state[MAX_SCF_STATE_STRING_SZ]; 702*0Sstevel@tonic-gate char str_new_state[MAX_SCF_STATE_STRING_SZ]; 703*0Sstevel@tonic-gate char str_state_next[MAX_SCF_STATE_STRING_SZ]; 704*0Sstevel@tonic-gate char str_new_state_next[MAX_SCF_STATE_STRING_SZ]; 705*0Sstevel@tonic-gate int ret = 0, r; 706*0Sstevel@tonic-gate struct timeval now; 707*0Sstevel@tonic-gate ssize_t sz; 708*0Sstevel@tonic-gate char *default_aux = "none"; 709*0Sstevel@tonic-gate 710*0Sstevel@tonic-gate scf_transaction_t *t = NULL; 711*0Sstevel@tonic-gate scf_transaction_entry_t *t_state = NULL, *t_state_next = NULL; 712*0Sstevel@tonic-gate scf_transaction_entry_t *t_stime = NULL, *t_aux = NULL; 713*0Sstevel@tonic-gate scf_value_t *v_state = NULL, *v_state_next = NULL, *v_stime = NULL; 714*0Sstevel@tonic-gate scf_value_t *v_aux = NULL; 715*0Sstevel@tonic-gate scf_instance_t *s_inst = NULL; 716*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate assert(new_state != RESTARTER_STATE_NONE); 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate /* If aux state is unset, set aux to a default string. */ 721*0Sstevel@tonic-gate if (aux == NULL) 722*0Sstevel@tonic-gate aux = default_aux; 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate if ((s_inst = scf_instance_create(h)) == NULL || 725*0Sstevel@tonic-gate (pg = scf_pg_create(h)) == NULL || 726*0Sstevel@tonic-gate (t = scf_transaction_create(h)) == NULL || 727*0Sstevel@tonic-gate (t_state = scf_entry_create(h)) == NULL || 728*0Sstevel@tonic-gate (t_state_next = scf_entry_create(h)) == NULL || 729*0Sstevel@tonic-gate (t_stime = scf_entry_create(h)) == NULL || 730*0Sstevel@tonic-gate (t_aux = scf_entry_create(h)) == NULL || 731*0Sstevel@tonic-gate (v_state = scf_value_create(h)) == NULL || 732*0Sstevel@tonic-gate (v_state_next = scf_value_create(h)) == NULL || 733*0Sstevel@tonic-gate (v_stime = scf_value_create(h)) == NULL || 734*0Sstevel@tonic-gate (v_aux = scf_value_create(h)) == NULL) { 735*0Sstevel@tonic-gate ret = ENOMEM; 736*0Sstevel@tonic-gate goto out; 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate sz = restarter_state_to_string(new_state, str_new_state, 740*0Sstevel@tonic-gate sizeof (str_new_state)); 741*0Sstevel@tonic-gate assert(sz < sizeof (str_new_state)); 742*0Sstevel@tonic-gate sz = restarter_state_to_string(new_state_next, str_new_state_next, 743*0Sstevel@tonic-gate sizeof (str_new_state_next)); 744*0Sstevel@tonic-gate assert(sz < sizeof (str_new_state_next)); 745*0Sstevel@tonic-gate sz = restarter_state_to_string(id->i_state, str_state, 746*0Sstevel@tonic-gate sizeof (str_state)); 747*0Sstevel@tonic-gate assert(sz < sizeof (str_state)); 748*0Sstevel@tonic-gate sz = restarter_state_to_string(id->i_next_state, str_state_next, 749*0Sstevel@tonic-gate sizeof (str_state_next)); 750*0Sstevel@tonic-gate assert(sz < sizeof (str_state_next)); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate ret = gettimeofday(&now, NULL); 753*0Sstevel@tonic-gate assert(ret != -1); 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate if (scf_handle_decode_fmri(h, id->i_fmri, NULL, NULL, s_inst, 756*0Sstevel@tonic-gate NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) { 757*0Sstevel@tonic-gate switch (scf_error()) { 758*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 759*0Sstevel@tonic-gate default: 760*0Sstevel@tonic-gate ret = ECONNABORTED; 761*0Sstevel@tonic-gate break; 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 764*0Sstevel@tonic-gate case SCF_ERROR_CONSTRAINT_VIOLATED: 765*0Sstevel@tonic-gate ret = EINVAL; 766*0Sstevel@tonic-gate break; 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 769*0Sstevel@tonic-gate ret = ENOENT; 770*0Sstevel@tonic-gate break; 771*0Sstevel@tonic-gate 772*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 773*0Sstevel@tonic-gate bad_fail("scf_handle_decode_fmri", scf_error()); 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate goto out; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate if (scf_value_set_astring(v_state, str_new_state) != 0 || 780*0Sstevel@tonic-gate scf_value_set_astring(v_state_next, str_new_state_next) != 0 || 781*0Sstevel@tonic-gate scf_value_set_astring(v_aux, aux) != 0) 782*0Sstevel@tonic-gate bad_fail("scf_value_set_astring", scf_error()); 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate if (scf_value_set_time(v_stime, now.tv_sec, now.tv_usec * 1000) != 0) 785*0Sstevel@tonic-gate bad_fail("scf_value_set_time", scf_error()); 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate add_pg: 788*0Sstevel@tonic-gate switch (r = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 789*0Sstevel@tonic-gate SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg)) { 790*0Sstevel@tonic-gate case 0: 791*0Sstevel@tonic-gate break; 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate case ECONNABORTED: 794*0Sstevel@tonic-gate case EPERM: 795*0Sstevel@tonic-gate case EACCES: 796*0Sstevel@tonic-gate case EROFS: 797*0Sstevel@tonic-gate ret = r; 798*0Sstevel@tonic-gate goto out; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate case ECANCELED: 801*0Sstevel@tonic-gate ret = ENOENT; 802*0Sstevel@tonic-gate goto out; 803*0Sstevel@tonic-gate 804*0Sstevel@tonic-gate case EBADF: 805*0Sstevel@tonic-gate default: 806*0Sstevel@tonic-gate bad_fail("instance_get_or_add_pg", r); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate for (;;) { 810*0Sstevel@tonic-gate if (scf_transaction_start(t, pg) != 0) { 811*0Sstevel@tonic-gate switch (scf_error()) { 812*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 813*0Sstevel@tonic-gate default: 814*0Sstevel@tonic-gate ret = ECONNABORTED; 815*0Sstevel@tonic-gate goto out; 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 818*0Sstevel@tonic-gate goto add_pg; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 821*0Sstevel@tonic-gate ret = EPERM; 822*0Sstevel@tonic-gate goto out; 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 825*0Sstevel@tonic-gate ret = EACCES; 826*0Sstevel@tonic-gate goto out; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 829*0Sstevel@tonic-gate ret = EROFS; 830*0Sstevel@tonic-gate goto out; 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 833*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 834*0Sstevel@tonic-gate bad_fail("scf_transaction_start", scf_error()); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate if ((r = tx_set_value(t, t_state, SCF_PROPERTY_STATE, 839*0Sstevel@tonic-gate SCF_TYPE_ASTRING, v_state)) != 0 || 840*0Sstevel@tonic-gate (r = tx_set_value(t, t_state_next, SCF_PROPERTY_NEXT_STATE, 841*0Sstevel@tonic-gate SCF_TYPE_ASTRING, v_state_next)) != 0 || 842*0Sstevel@tonic-gate (r = tx_set_value(t, t_aux, SCF_PROPERTY_AUX_STATE, 843*0Sstevel@tonic-gate SCF_TYPE_ASTRING, v_aux)) != 0 || 844*0Sstevel@tonic-gate (r = tx_set_value(t, t_stime, SCF_PROPERTY_STATE_TIMESTAMP, 845*0Sstevel@tonic-gate SCF_TYPE_TIME, v_stime)) != 0) { 846*0Sstevel@tonic-gate switch (r) { 847*0Sstevel@tonic-gate case ECONNABORTED: 848*0Sstevel@tonic-gate ret = ECONNABORTED; 849*0Sstevel@tonic-gate goto out; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate case ECANCELED: 852*0Sstevel@tonic-gate scf_transaction_reset(t); 853*0Sstevel@tonic-gate goto add_pg; 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate default: 856*0Sstevel@tonic-gate bad_fail("tx_set_value", r); 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate ret = scf_transaction_commit(t); 861*0Sstevel@tonic-gate if (ret == 1) 862*0Sstevel@tonic-gate break; 863*0Sstevel@tonic-gate if (ret == -1) { 864*0Sstevel@tonic-gate switch (scf_error()) { 865*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 866*0Sstevel@tonic-gate default: 867*0Sstevel@tonic-gate ret = ECONNABORTED; 868*0Sstevel@tonic-gate goto out; 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 871*0Sstevel@tonic-gate ret = EPERM; 872*0Sstevel@tonic-gate goto out; 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 875*0Sstevel@tonic-gate ret = EACCES; 876*0Sstevel@tonic-gate goto out; 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 879*0Sstevel@tonic-gate ret = EROFS; 880*0Sstevel@tonic-gate goto out; 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 883*0Sstevel@tonic-gate bad_fail("scf_transaction_commit", scf_error()); 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate scf_transaction_reset(t); 888*0Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 889*0Sstevel@tonic-gate switch (scf_error()) { 890*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 891*0Sstevel@tonic-gate default: 892*0Sstevel@tonic-gate ret = ECONNABORTED; 893*0Sstevel@tonic-gate goto out; 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 896*0Sstevel@tonic-gate goto add_pg; 897*0Sstevel@tonic-gate } 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate id->i_state = new_state; 902*0Sstevel@tonic-gate id->i_next_state = new_state_next; 903*0Sstevel@tonic-gate ret = 0; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate out: 906*0Sstevel@tonic-gate scf_transaction_destroy(t); 907*0Sstevel@tonic-gate scf_entry_destroy(t_state); 908*0Sstevel@tonic-gate scf_entry_destroy(t_state_next); 909*0Sstevel@tonic-gate scf_entry_destroy(t_stime); 910*0Sstevel@tonic-gate scf_entry_destroy(t_aux); 911*0Sstevel@tonic-gate scf_value_destroy(v_state); 912*0Sstevel@tonic-gate scf_value_destroy(v_state_next); 913*0Sstevel@tonic-gate scf_value_destroy(v_stime); 914*0Sstevel@tonic-gate scf_value_destroy(v_aux); 915*0Sstevel@tonic-gate scf_pg_destroy(pg); 916*0Sstevel@tonic-gate scf_instance_destroy(s_inst); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate return (ret); 919*0Sstevel@tonic-gate } 920*0Sstevel@tonic-gate 921*0Sstevel@tonic-gate /* 922*0Sstevel@tonic-gate * Fails with 923*0Sstevel@tonic-gate * EINVAL - type is invalid 924*0Sstevel@tonic-gate * ENOMEM 925*0Sstevel@tonic-gate * ECONNABORTED - repository connection broken 926*0Sstevel@tonic-gate * EBADF - s_inst is not set 927*0Sstevel@tonic-gate * ECANCELED - s_inst is deleted 928*0Sstevel@tonic-gate * EPERM - permission denied 929*0Sstevel@tonic-gate * EACCES - backend access denied 930*0Sstevel@tonic-gate * EROFS - backend readonly 931*0Sstevel@tonic-gate */ 932*0Sstevel@tonic-gate int 933*0Sstevel@tonic-gate restarter_remove_contract(scf_instance_t *s_inst, ctid_t contract_id, 934*0Sstevel@tonic-gate restarter_contract_type_t type) 935*0Sstevel@tonic-gate { 936*0Sstevel@tonic-gate scf_handle_t *h; 937*0Sstevel@tonic-gate scf_transaction_t *t = NULL; 938*0Sstevel@tonic-gate scf_transaction_entry_t *t_cid = NULL; 939*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 940*0Sstevel@tonic-gate scf_property_t *prop = NULL; 941*0Sstevel@tonic-gate scf_value_t *val; 942*0Sstevel@tonic-gate scf_iter_t *iter = NULL; 943*0Sstevel@tonic-gate const char *pname; 944*0Sstevel@tonic-gate int ret = 0, primary; 945*0Sstevel@tonic-gate uint64_t c; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate switch (type) { 948*0Sstevel@tonic-gate case RESTARTER_CONTRACT_PRIMARY: 949*0Sstevel@tonic-gate primary = 1; 950*0Sstevel@tonic-gate break; 951*0Sstevel@tonic-gate case RESTARTER_CONTRACT_TRANSIENT: 952*0Sstevel@tonic-gate primary = 0; 953*0Sstevel@tonic-gate break; 954*0Sstevel@tonic-gate default: 955*0Sstevel@tonic-gate return (EINVAL); 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate 958*0Sstevel@tonic-gate h = scf_instance_handle(s_inst); 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate pg = scf_pg_create(h); 961*0Sstevel@tonic-gate prop = scf_property_create(h); 962*0Sstevel@tonic-gate iter = scf_iter_create(h); 963*0Sstevel@tonic-gate t = scf_transaction_create(h); 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate if (pg == NULL || prop == NULL || iter == NULL || t == NULL) { 966*0Sstevel@tonic-gate ret = ENOMEM; 967*0Sstevel@tonic-gate goto remove_contract_cleanup; 968*0Sstevel@tonic-gate } 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate add: 971*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 972*0Sstevel@tonic-gate ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 973*0Sstevel@tonic-gate SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 974*0Sstevel@tonic-gate if (ret != 0) 975*0Sstevel@tonic-gate goto remove_contract_cleanup; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate pname = primary? SCF_PROPERTY_CONTRACT : 978*0Sstevel@tonic-gate SCF_PROPERTY_TRANSIENT_CONTRACT; 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate for (;;) { 981*0Sstevel@tonic-gate if (scf_transaction_start(t, pg) != 0) { 982*0Sstevel@tonic-gate switch (scf_error()) { 983*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 984*0Sstevel@tonic-gate default: 985*0Sstevel@tonic-gate ret = ECONNABORTED; 986*0Sstevel@tonic-gate goto remove_contract_cleanup; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 989*0Sstevel@tonic-gate goto add; 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 992*0Sstevel@tonic-gate ret = EPERM; 993*0Sstevel@tonic-gate goto remove_contract_cleanup; 994*0Sstevel@tonic-gate 995*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 996*0Sstevel@tonic-gate ret = EACCES; 997*0Sstevel@tonic-gate goto remove_contract_cleanup; 998*0Sstevel@tonic-gate 999*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 1000*0Sstevel@tonic-gate ret = EROFS; 1001*0Sstevel@tonic-gate goto remove_contract_cleanup; 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1004*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 1005*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1006*0Sstevel@tonic-gate bad_fail("scf_transaction_start", scf_error()); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate } 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate t_cid = scf_entry_create(h); 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate if (scf_pg_get_property(pg, pname, prop) == 0) { 1013*0Sstevel@tonic-gate replace: 1014*0Sstevel@tonic-gate if (scf_transaction_property_change_type(t, t_cid, 1015*0Sstevel@tonic-gate pname, SCF_TYPE_COUNT) != 0) { 1016*0Sstevel@tonic-gate switch (scf_error()) { 1017*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1018*0Sstevel@tonic-gate default: 1019*0Sstevel@tonic-gate ret = ECONNABORTED; 1020*0Sstevel@tonic-gate goto remove_contract_cleanup; 1021*0Sstevel@tonic-gate 1022*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1023*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1024*0Sstevel@tonic-gate goto add; 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 1027*0Sstevel@tonic-gate goto new; 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1030*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1031*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 1032*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1033*0Sstevel@tonic-gate bad_fail( 1034*0Sstevel@tonic-gate "scf_transaction_property_changetype", 1035*0Sstevel@tonic-gate scf_error()); 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) { 1040*0Sstevel@tonic-gate if (scf_iter_property_values(iter, prop) != 0) { 1041*0Sstevel@tonic-gate switch (scf_error()) { 1042*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1043*0Sstevel@tonic-gate default: 1044*0Sstevel@tonic-gate ret = ECONNABORTED; 1045*0Sstevel@tonic-gate goto remove_contract_cleanup; 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1048*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1049*0Sstevel@tonic-gate bad_fail( 1050*0Sstevel@tonic-gate "scf_iter_property_values", 1051*0Sstevel@tonic-gate scf_error()); 1052*0Sstevel@tonic-gate } 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate next_val: 1056*0Sstevel@tonic-gate val = scf_value_create(h); 1057*0Sstevel@tonic-gate if (val == NULL) { 1058*0Sstevel@tonic-gate assert(scf_error() == 1059*0Sstevel@tonic-gate SCF_ERROR_NO_MEMORY); 1060*0Sstevel@tonic-gate ret = ENOMEM; 1061*0Sstevel@tonic-gate goto remove_contract_cleanup; 1062*0Sstevel@tonic-gate } 1063*0Sstevel@tonic-gate 1064*0Sstevel@tonic-gate ret = scf_iter_next_value(iter, val); 1065*0Sstevel@tonic-gate if (ret == -1) { 1066*0Sstevel@tonic-gate switch (scf_error()) { 1067*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1068*0Sstevel@tonic-gate ret = ECONNABORTED; 1069*0Sstevel@tonic-gate goto remove_contract_cleanup; 1070*0Sstevel@tonic-gate 1071*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1072*0Sstevel@tonic-gate scf_value_destroy(val); 1073*0Sstevel@tonic-gate goto add; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1076*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1077*0Sstevel@tonic-gate default: 1078*0Sstevel@tonic-gate bad_fail("scf_iter_next_value", 1079*0Sstevel@tonic-gate scf_error()); 1080*0Sstevel@tonic-gate } 1081*0Sstevel@tonic-gate } 1082*0Sstevel@tonic-gate 1083*0Sstevel@tonic-gate if (ret == 1) { 1084*0Sstevel@tonic-gate ret = scf_value_get_count(val, &c); 1085*0Sstevel@tonic-gate assert(ret == 0); 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate if (c != contract_id) { 1088*0Sstevel@tonic-gate ret = scf_entry_add_value(t_cid, 1089*0Sstevel@tonic-gate val); 1090*0Sstevel@tonic-gate assert(ret == 0); 1091*0Sstevel@tonic-gate } else { 1092*0Sstevel@tonic-gate scf_value_destroy(val); 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate goto next_val; 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate scf_value_destroy(val); 1099*0Sstevel@tonic-gate } else { 1100*0Sstevel@tonic-gate switch (scf_error()) { 1101*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1102*0Sstevel@tonic-gate default: 1103*0Sstevel@tonic-gate ret = ECONNABORTED; 1104*0Sstevel@tonic-gate goto remove_contract_cleanup; 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate case SCF_ERROR_TYPE_MISMATCH: 1107*0Sstevel@tonic-gate break; 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1110*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1111*0Sstevel@tonic-gate bad_fail("scf_property_is_type", 1112*0Sstevel@tonic-gate scf_error()); 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate } 1115*0Sstevel@tonic-gate } else { 1116*0Sstevel@tonic-gate switch (scf_error()) { 1117*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1118*0Sstevel@tonic-gate default: 1119*0Sstevel@tonic-gate ret = ECONNABORTED; 1120*0Sstevel@tonic-gate goto remove_contract_cleanup; 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1123*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1124*0Sstevel@tonic-gate goto add; 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 1127*0Sstevel@tonic-gate break; 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1130*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1131*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1132*0Sstevel@tonic-gate bad_fail("scf_pg_get_property", scf_error()); 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate new: 1136*0Sstevel@tonic-gate if (scf_transaction_property_new(t, t_cid, pname, 1137*0Sstevel@tonic-gate SCF_TYPE_COUNT) != 0) { 1138*0Sstevel@tonic-gate switch (scf_error()) { 1139*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1140*0Sstevel@tonic-gate default: 1141*0Sstevel@tonic-gate ret = ECONNABORTED; 1142*0Sstevel@tonic-gate goto remove_contract_cleanup; 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1145*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1146*0Sstevel@tonic-gate goto add; 1147*0Sstevel@tonic-gate 1148*0Sstevel@tonic-gate case SCF_ERROR_EXISTS: 1149*0Sstevel@tonic-gate goto replace; 1150*0Sstevel@tonic-gate 1151*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1152*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1153*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1154*0Sstevel@tonic-gate bad_fail("scf_transaction_property_new", 1155*0Sstevel@tonic-gate scf_error()); 1156*0Sstevel@tonic-gate } 1157*0Sstevel@tonic-gate } 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate ret = scf_transaction_commit(t); 1161*0Sstevel@tonic-gate if (ret == -1) { 1162*0Sstevel@tonic-gate switch (scf_error()) { 1163*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1164*0Sstevel@tonic-gate default: 1165*0Sstevel@tonic-gate ret = ECONNABORTED; 1166*0Sstevel@tonic-gate goto remove_contract_cleanup; 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1169*0Sstevel@tonic-gate goto add; 1170*0Sstevel@tonic-gate 1171*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 1172*0Sstevel@tonic-gate ret = EPERM; 1173*0Sstevel@tonic-gate goto remove_contract_cleanup; 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 1176*0Sstevel@tonic-gate ret = EACCES; 1177*0Sstevel@tonic-gate goto remove_contract_cleanup; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 1180*0Sstevel@tonic-gate ret = EROFS; 1181*0Sstevel@tonic-gate goto remove_contract_cleanup; 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1184*0Sstevel@tonic-gate bad_fail("scf_transaction_commit", scf_error()); 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate } 1187*0Sstevel@tonic-gate if (ret == 1) { 1188*0Sstevel@tonic-gate ret = 0; 1189*0Sstevel@tonic-gate break; 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 1193*0Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 1194*0Sstevel@tonic-gate switch (scf_error()) { 1195*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1196*0Sstevel@tonic-gate default: 1197*0Sstevel@tonic-gate ret = ECONNABORTED; 1198*0Sstevel@tonic-gate goto remove_contract_cleanup; 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1201*0Sstevel@tonic-gate goto add; 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1204*0Sstevel@tonic-gate bad_fail("scf_pg_update", scf_error()); 1205*0Sstevel@tonic-gate } 1206*0Sstevel@tonic-gate } 1207*0Sstevel@tonic-gate } 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate remove_contract_cleanup: 1210*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 1211*0Sstevel@tonic-gate scf_transaction_destroy(t); 1212*0Sstevel@tonic-gate scf_iter_destroy(iter); 1213*0Sstevel@tonic-gate scf_property_destroy(prop); 1214*0Sstevel@tonic-gate scf_pg_destroy(pg); 1215*0Sstevel@tonic-gate 1216*0Sstevel@tonic-gate return (ret); 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate /* 1220*0Sstevel@tonic-gate * Fails with 1221*0Sstevel@tonic-gate * EINVAL - type is invalid 1222*0Sstevel@tonic-gate * ENOMEM 1223*0Sstevel@tonic-gate * ECONNABORTED - repository disconnection 1224*0Sstevel@tonic-gate * EBADF - s_inst is not set 1225*0Sstevel@tonic-gate * ECANCELED - s_inst is deleted 1226*0Sstevel@tonic-gate * EPERM 1227*0Sstevel@tonic-gate * EACCES 1228*0Sstevel@tonic-gate * EROFS 1229*0Sstevel@tonic-gate */ 1230*0Sstevel@tonic-gate int 1231*0Sstevel@tonic-gate restarter_store_contract(scf_instance_t *s_inst, ctid_t contract_id, 1232*0Sstevel@tonic-gate restarter_contract_type_t type) 1233*0Sstevel@tonic-gate { 1234*0Sstevel@tonic-gate scf_handle_t *h; 1235*0Sstevel@tonic-gate scf_transaction_t *t = NULL; 1236*0Sstevel@tonic-gate scf_transaction_entry_t *t_cid = NULL; 1237*0Sstevel@tonic-gate scf_value_t *val; 1238*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 1239*0Sstevel@tonic-gate scf_property_t *prop = NULL; 1240*0Sstevel@tonic-gate scf_iter_t *iter = NULL; 1241*0Sstevel@tonic-gate const char *pname; 1242*0Sstevel@tonic-gate int ret = 0, primary; 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate if (type == RESTARTER_CONTRACT_PRIMARY) 1245*0Sstevel@tonic-gate primary = 1; 1246*0Sstevel@tonic-gate else if (type == RESTARTER_CONTRACT_TRANSIENT) 1247*0Sstevel@tonic-gate primary = 0; 1248*0Sstevel@tonic-gate else 1249*0Sstevel@tonic-gate return (EINVAL); 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate h = scf_instance_handle(s_inst); 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate pg = scf_pg_create(h); 1254*0Sstevel@tonic-gate prop = scf_property_create(h); 1255*0Sstevel@tonic-gate iter = scf_iter_create(h); 1256*0Sstevel@tonic-gate t = scf_transaction_create(h); 1257*0Sstevel@tonic-gate 1258*0Sstevel@tonic-gate if (pg == NULL || prop == NULL || iter == NULL || t == NULL) { 1259*0Sstevel@tonic-gate ret = ENOMEM; 1260*0Sstevel@tonic-gate goto out; 1261*0Sstevel@tonic-gate } 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate add: 1264*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 1265*0Sstevel@tonic-gate ret = instance_get_or_add_pg(s_inst, SCF_PG_RESTARTER, 1266*0Sstevel@tonic-gate SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg); 1267*0Sstevel@tonic-gate if (ret != 0) 1268*0Sstevel@tonic-gate goto out; 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate pname = primary ? SCF_PROPERTY_CONTRACT : 1271*0Sstevel@tonic-gate SCF_PROPERTY_TRANSIENT_CONTRACT; 1272*0Sstevel@tonic-gate 1273*0Sstevel@tonic-gate for (;;) { 1274*0Sstevel@tonic-gate if (scf_transaction_start(t, pg) != 0) { 1275*0Sstevel@tonic-gate switch (scf_error()) { 1276*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1277*0Sstevel@tonic-gate default: 1278*0Sstevel@tonic-gate ret = ECONNABORTED; 1279*0Sstevel@tonic-gate goto out; 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1282*0Sstevel@tonic-gate goto add; 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 1285*0Sstevel@tonic-gate ret = EPERM; 1286*0Sstevel@tonic-gate goto out; 1287*0Sstevel@tonic-gate 1288*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 1289*0Sstevel@tonic-gate ret = EACCES; 1290*0Sstevel@tonic-gate goto out; 1291*0Sstevel@tonic-gate 1292*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 1293*0Sstevel@tonic-gate ret = EROFS; 1294*0Sstevel@tonic-gate goto out; 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1297*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 1298*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1299*0Sstevel@tonic-gate bad_fail("scf_transaction_start", scf_error()); 1300*0Sstevel@tonic-gate } 1301*0Sstevel@tonic-gate } 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate t_cid = scf_entry_create(h); 1304*0Sstevel@tonic-gate if (t_cid == NULL) { 1305*0Sstevel@tonic-gate ret = ENOMEM; 1306*0Sstevel@tonic-gate goto out; 1307*0Sstevel@tonic-gate } 1308*0Sstevel@tonic-gate 1309*0Sstevel@tonic-gate if (scf_pg_get_property(pg, pname, prop) == 0) { 1310*0Sstevel@tonic-gate replace: 1311*0Sstevel@tonic-gate if (scf_transaction_property_change_type(t, t_cid, 1312*0Sstevel@tonic-gate pname, SCF_TYPE_COUNT) != 0) { 1313*0Sstevel@tonic-gate switch (scf_error()) { 1314*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1315*0Sstevel@tonic-gate default: 1316*0Sstevel@tonic-gate ret = ECONNABORTED; 1317*0Sstevel@tonic-gate goto out; 1318*0Sstevel@tonic-gate 1319*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1320*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1321*0Sstevel@tonic-gate goto add; 1322*0Sstevel@tonic-gate 1323*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 1324*0Sstevel@tonic-gate goto new; 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1327*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1328*0Sstevel@tonic-gate case SCF_ERROR_IN_USE: 1329*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1330*0Sstevel@tonic-gate bad_fail( 1331*0Sstevel@tonic-gate "scf_transaction_propert_change_type", 1332*0Sstevel@tonic-gate scf_error()); 1333*0Sstevel@tonic-gate } 1334*0Sstevel@tonic-gate } 1335*0Sstevel@tonic-gate 1336*0Sstevel@tonic-gate if (scf_property_is_type(prop, SCF_TYPE_COUNT) == 0) { 1337*0Sstevel@tonic-gate if (scf_iter_property_values(iter, prop) != 0) { 1338*0Sstevel@tonic-gate switch (scf_error()) { 1339*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1340*0Sstevel@tonic-gate default: 1341*0Sstevel@tonic-gate ret = ECONNABORTED; 1342*0Sstevel@tonic-gate goto out; 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1345*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1346*0Sstevel@tonic-gate bad_fail( 1347*0Sstevel@tonic-gate "scf_iter_property_values", 1348*0Sstevel@tonic-gate scf_error()); 1349*0Sstevel@tonic-gate } 1350*0Sstevel@tonic-gate } 1351*0Sstevel@tonic-gate 1352*0Sstevel@tonic-gate next_val: 1353*0Sstevel@tonic-gate val = scf_value_create(h); 1354*0Sstevel@tonic-gate if (val == NULL) { 1355*0Sstevel@tonic-gate assert(scf_error() == 1356*0Sstevel@tonic-gate SCF_ERROR_NO_MEMORY); 1357*0Sstevel@tonic-gate ret = ENOMEM; 1358*0Sstevel@tonic-gate goto out; 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate ret = scf_iter_next_value(iter, val); 1362*0Sstevel@tonic-gate if (ret == -1) { 1363*0Sstevel@tonic-gate switch (scf_error()) { 1364*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1365*0Sstevel@tonic-gate default: 1366*0Sstevel@tonic-gate ret = ECONNABORTED; 1367*0Sstevel@tonic-gate goto out; 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1370*0Sstevel@tonic-gate scf_value_destroy(val); 1371*0Sstevel@tonic-gate goto add; 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1374*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1375*0Sstevel@tonic-gate bad_fail( 1376*0Sstevel@tonic-gate "scf_iter_next_value", 1377*0Sstevel@tonic-gate scf_error()); 1378*0Sstevel@tonic-gate } 1379*0Sstevel@tonic-gate } 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate if (ret == 1) { 1382*0Sstevel@tonic-gate ret = scf_entry_add_value(t_cid, val); 1383*0Sstevel@tonic-gate assert(ret == 0); 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate goto next_val; 1386*0Sstevel@tonic-gate } 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate scf_value_destroy(val); 1389*0Sstevel@tonic-gate } else { 1390*0Sstevel@tonic-gate switch (scf_error()) { 1391*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1392*0Sstevel@tonic-gate default: 1393*0Sstevel@tonic-gate ret = ECONNABORTED; 1394*0Sstevel@tonic-gate goto out; 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate case SCF_ERROR_TYPE_MISMATCH: 1397*0Sstevel@tonic-gate break; 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1400*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1401*0Sstevel@tonic-gate bad_fail("scf_property_is_type", 1402*0Sstevel@tonic-gate scf_error()); 1403*0Sstevel@tonic-gate } 1404*0Sstevel@tonic-gate } 1405*0Sstevel@tonic-gate } else { 1406*0Sstevel@tonic-gate switch (scf_error()) { 1407*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1408*0Sstevel@tonic-gate default: 1409*0Sstevel@tonic-gate ret = ECONNABORTED; 1410*0Sstevel@tonic-gate goto out; 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1413*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1414*0Sstevel@tonic-gate goto add; 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 1417*0Sstevel@tonic-gate break; 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1420*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1421*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1422*0Sstevel@tonic-gate bad_fail("scf_pg_get_property", scf_error()); 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate new: 1426*0Sstevel@tonic-gate if (scf_transaction_property_new(t, t_cid, pname, 1427*0Sstevel@tonic-gate SCF_TYPE_COUNT) != 0) { 1428*0Sstevel@tonic-gate switch (scf_error()) { 1429*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1430*0Sstevel@tonic-gate default: 1431*0Sstevel@tonic-gate ret = ECONNABORTED; 1432*0Sstevel@tonic-gate goto out; 1433*0Sstevel@tonic-gate 1434*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1435*0Sstevel@tonic-gate scf_entry_destroy(t_cid); 1436*0Sstevel@tonic-gate goto add; 1437*0Sstevel@tonic-gate 1438*0Sstevel@tonic-gate case SCF_ERROR_EXISTS: 1439*0Sstevel@tonic-gate goto replace; 1440*0Sstevel@tonic-gate 1441*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 1442*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 1443*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1444*0Sstevel@tonic-gate bad_fail("scf_transaction_property_new", 1445*0Sstevel@tonic-gate scf_error()); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate } 1449*0Sstevel@tonic-gate 1450*0Sstevel@tonic-gate val = scf_value_create(h); 1451*0Sstevel@tonic-gate if (val == NULL) { 1452*0Sstevel@tonic-gate assert(scf_error() == SCF_ERROR_NO_MEMORY); 1453*0Sstevel@tonic-gate ret = ENOMEM; 1454*0Sstevel@tonic-gate goto out; 1455*0Sstevel@tonic-gate } 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate scf_value_set_count(val, contract_id); 1458*0Sstevel@tonic-gate ret = scf_entry_add_value(t_cid, val); 1459*0Sstevel@tonic-gate assert(ret == 0); 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate ret = scf_transaction_commit(t); 1462*0Sstevel@tonic-gate if (ret == -1) { 1463*0Sstevel@tonic-gate switch (scf_error()) { 1464*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1465*0Sstevel@tonic-gate default: 1466*0Sstevel@tonic-gate ret = ECONNABORTED; 1467*0Sstevel@tonic-gate goto out; 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1470*0Sstevel@tonic-gate goto add; 1471*0Sstevel@tonic-gate 1472*0Sstevel@tonic-gate case SCF_ERROR_PERMISSION_DENIED: 1473*0Sstevel@tonic-gate ret = EPERM; 1474*0Sstevel@tonic-gate goto out; 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_ACCESS: 1477*0Sstevel@tonic-gate ret = EACCES; 1478*0Sstevel@tonic-gate goto out; 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate case SCF_ERROR_BACKEND_READONLY: 1481*0Sstevel@tonic-gate ret = EROFS; 1482*0Sstevel@tonic-gate goto out; 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1485*0Sstevel@tonic-gate bad_fail("scf_transaction_commit", scf_error()); 1486*0Sstevel@tonic-gate } 1487*0Sstevel@tonic-gate } 1488*0Sstevel@tonic-gate if (ret == 1) { 1489*0Sstevel@tonic-gate ret = 0; 1490*0Sstevel@tonic-gate break; 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 1494*0Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 1495*0Sstevel@tonic-gate switch (scf_error()) { 1496*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 1497*0Sstevel@tonic-gate default: 1498*0Sstevel@tonic-gate ret = ECONNABORTED; 1499*0Sstevel@tonic-gate goto out; 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 1502*0Sstevel@tonic-gate goto add; 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 1505*0Sstevel@tonic-gate bad_fail("scf_pg_update", scf_error()); 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate } 1509*0Sstevel@tonic-gate 1510*0Sstevel@tonic-gate out: 1511*0Sstevel@tonic-gate scf_transaction_destroy_children(t); 1512*0Sstevel@tonic-gate scf_transaction_destroy(t); 1513*0Sstevel@tonic-gate scf_iter_destroy(iter); 1514*0Sstevel@tonic-gate scf_property_destroy(prop); 1515*0Sstevel@tonic-gate scf_pg_destroy(pg); 1516*0Sstevel@tonic-gate 1517*0Sstevel@tonic-gate return (ret); 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate int 1521*0Sstevel@tonic-gate restarter_rm_libs_loadable() 1522*0Sstevel@tonic-gate { 1523*0Sstevel@tonic-gate void *libhndl; 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate if (method_context_safety) 1526*0Sstevel@tonic-gate return (1); 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate if ((libhndl = dlopen("libpool.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) 1529*0Sstevel@tonic-gate return (0); 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate (void) dlclose(libhndl); 1532*0Sstevel@tonic-gate 1533*0Sstevel@tonic-gate if ((libhndl = dlopen("libproject.so", RTLD_LAZY | RTLD_LOCAL)) == NULL) 1534*0Sstevel@tonic-gate return (0); 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate (void) dlclose(libhndl); 1537*0Sstevel@tonic-gate 1538*0Sstevel@tonic-gate method_context_safety = 1; 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate return (1); 1541*0Sstevel@tonic-gate } 1542*0Sstevel@tonic-gate 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate static int 1545*0Sstevel@tonic-gate get_astring_val(scf_propertygroup_t *pg, const char *name, char *buf, 1546*0Sstevel@tonic-gate size_t bufsz, scf_property_t *prop, scf_value_t *val) 1547*0Sstevel@tonic-gate { 1548*0Sstevel@tonic-gate ssize_t szret; 1549*0Sstevel@tonic-gate 1550*0Sstevel@tonic-gate if (scf_pg_get_property(pg, name, prop) != SCF_SUCCESS) { 1551*0Sstevel@tonic-gate if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) 1552*0Sstevel@tonic-gate uu_die(rcbroken); 1553*0Sstevel@tonic-gate return (-1); 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 1557*0Sstevel@tonic-gate if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) 1558*0Sstevel@tonic-gate uu_die(rcbroken); 1559*0Sstevel@tonic-gate return (-1); 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate szret = scf_value_get_astring(val, buf, bufsz); 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate return (szret >= 0 ? 0 : -1); 1565*0Sstevel@tonic-gate } 1566*0Sstevel@tonic-gate 1567*0Sstevel@tonic-gate /* 1568*0Sstevel@tonic-gate * Try to load mcp->pwd, if it isn't already. 1569*0Sstevel@tonic-gate * Fails with 1570*0Sstevel@tonic-gate * ENOMEM - malloc() failed 1571*0Sstevel@tonic-gate * ENOENT - no entry found 1572*0Sstevel@tonic-gate * EIO - I/O error 1573*0Sstevel@tonic-gate * EMFILE - process out of file descriptors 1574*0Sstevel@tonic-gate * ENFILE - system out of file handles 1575*0Sstevel@tonic-gate */ 1576*0Sstevel@tonic-gate static int 1577*0Sstevel@tonic-gate lookup_pwd(struct method_context *mcp) 1578*0Sstevel@tonic-gate { 1579*0Sstevel@tonic-gate struct passwd *pwdp; 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate if (mcp->pwbuf != NULL && mcp->pwd.pw_uid == mcp->uid) 1582*0Sstevel@tonic-gate return (0); 1583*0Sstevel@tonic-gate 1584*0Sstevel@tonic-gate if (mcp->pwbuf == NULL) { 1585*0Sstevel@tonic-gate mcp->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX); 1586*0Sstevel@tonic-gate assert(mcp->pwbufsz >= 0); 1587*0Sstevel@tonic-gate mcp->pwbuf = malloc(mcp->pwbufsz); 1588*0Sstevel@tonic-gate if (mcp->pwbuf == NULL) 1589*0Sstevel@tonic-gate return (ENOMEM); 1590*0Sstevel@tonic-gate } 1591*0Sstevel@tonic-gate 1592*0Sstevel@tonic-gate do { 1593*0Sstevel@tonic-gate errno = 0; 1594*0Sstevel@tonic-gate pwdp = getpwuid_r(mcp->uid, &mcp->pwd, mcp->pwbuf, 1595*0Sstevel@tonic-gate mcp->pwbufsz); 1596*0Sstevel@tonic-gate } while (pwdp == NULL && errno == EINTR); 1597*0Sstevel@tonic-gate if (pwdp != NULL) 1598*0Sstevel@tonic-gate return (0); 1599*0Sstevel@tonic-gate 1600*0Sstevel@tonic-gate free(mcp->pwbuf); 1601*0Sstevel@tonic-gate mcp->pwbuf = NULL; 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate switch (errno) { 1604*0Sstevel@tonic-gate case 0: 1605*0Sstevel@tonic-gate default: 1606*0Sstevel@tonic-gate /* 1607*0Sstevel@tonic-gate * Until bug 5065780 is fixed, getpwuid_r() can fail with 1608*0Sstevel@tonic-gate * ENOENT, particularly on the miniroot. Since the 1609*0Sstevel@tonic-gate * documentation is inaccurate, we'll return ENOENT for unknown 1610*0Sstevel@tonic-gate * errors. 1611*0Sstevel@tonic-gate */ 1612*0Sstevel@tonic-gate return (ENOENT); 1613*0Sstevel@tonic-gate 1614*0Sstevel@tonic-gate case EIO: 1615*0Sstevel@tonic-gate case EMFILE: 1616*0Sstevel@tonic-gate case ENFILE: 1617*0Sstevel@tonic-gate return (errno); 1618*0Sstevel@tonic-gate 1619*0Sstevel@tonic-gate case ERANGE: 1620*0Sstevel@tonic-gate bad_fail("getpwuid_r", errno); 1621*0Sstevel@tonic-gate /* NOTREACHED */ 1622*0Sstevel@tonic-gate } 1623*0Sstevel@tonic-gate } 1624*0Sstevel@tonic-gate 1625*0Sstevel@tonic-gate /* 1626*0Sstevel@tonic-gate * Get the user id for str. Returns 0 on success or 1627*0Sstevel@tonic-gate * ERANGE the uid is too big 1628*0Sstevel@tonic-gate * EINVAL the string starts with a digit, but is not a valid uid 1629*0Sstevel@tonic-gate * ENOMEM out of memory 1630*0Sstevel@tonic-gate * ENOENT no passwd entry for str 1631*0Sstevel@tonic-gate * EIO an I/O error has occurred 1632*0Sstevel@tonic-gate * EMFILE/ENFILE out of file descriptors 1633*0Sstevel@tonic-gate */ 1634*0Sstevel@tonic-gate int 1635*0Sstevel@tonic-gate get_uid(const char *str, struct method_context *ci, uid_t *uidp) 1636*0Sstevel@tonic-gate { 1637*0Sstevel@tonic-gate if (isdigit(str[0])) { 1638*0Sstevel@tonic-gate uid_t uid; 1639*0Sstevel@tonic-gate char *cp; 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate errno = 0; 1642*0Sstevel@tonic-gate uid = strtol(str, &cp, 10); 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate if (uid == 0 && errno != 0) { 1645*0Sstevel@tonic-gate assert(errno != EINVAL); 1646*0Sstevel@tonic-gate return (errno); 1647*0Sstevel@tonic-gate } 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate for (; *cp != '\0'; ++cp) 1650*0Sstevel@tonic-gate if (*cp != ' ' || *cp != '\t') 1651*0Sstevel@tonic-gate return (EINVAL); 1652*0Sstevel@tonic-gate 1653*0Sstevel@tonic-gate if (uid > UID_MAX) 1654*0Sstevel@tonic-gate return (EINVAL); 1655*0Sstevel@tonic-gate 1656*0Sstevel@tonic-gate *uidp = uid; 1657*0Sstevel@tonic-gate return (0); 1658*0Sstevel@tonic-gate } else { 1659*0Sstevel@tonic-gate struct passwd *pwdp; 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate if (ci->pwbuf == NULL) { 1662*0Sstevel@tonic-gate ci->pwbufsz = sysconf(_SC_GETPW_R_SIZE_MAX); 1663*0Sstevel@tonic-gate ci->pwbuf = malloc(ci->pwbufsz); 1664*0Sstevel@tonic-gate if (ci->pwbuf == NULL) 1665*0Sstevel@tonic-gate return (ENOMEM); 1666*0Sstevel@tonic-gate } 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gate do { 1669*0Sstevel@tonic-gate errno = 0; 1670*0Sstevel@tonic-gate pwdp = 1671*0Sstevel@tonic-gate getpwnam_r(str, &ci->pwd, ci->pwbuf, ci->pwbufsz); 1672*0Sstevel@tonic-gate } while (pwdp == NULL && errno == EINTR); 1673*0Sstevel@tonic-gate 1674*0Sstevel@tonic-gate if (pwdp != NULL) { 1675*0Sstevel@tonic-gate *uidp = ci->pwd.pw_uid; 1676*0Sstevel@tonic-gate return (0); 1677*0Sstevel@tonic-gate } else { 1678*0Sstevel@tonic-gate free(ci->pwbuf); 1679*0Sstevel@tonic-gate ci->pwbuf = NULL; 1680*0Sstevel@tonic-gate switch (errno) { 1681*0Sstevel@tonic-gate case 0: 1682*0Sstevel@tonic-gate return (ENOENT); 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate case ENOENT: 1685*0Sstevel@tonic-gate case EIO: 1686*0Sstevel@tonic-gate case EMFILE: 1687*0Sstevel@tonic-gate case ENFILE: 1688*0Sstevel@tonic-gate return (errno); 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate case ERANGE: 1691*0Sstevel@tonic-gate default: 1692*0Sstevel@tonic-gate bad_fail("getpwnam_r", errno); 1693*0Sstevel@tonic-gate /* NOTREACHED */ 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate } 1698*0Sstevel@tonic-gate 1699*0Sstevel@tonic-gate gid_t 1700*0Sstevel@tonic-gate get_gid(const char *str) 1701*0Sstevel@tonic-gate { 1702*0Sstevel@tonic-gate if (isdigit(str[0])) { 1703*0Sstevel@tonic-gate gid_t gid; 1704*0Sstevel@tonic-gate char *cp; 1705*0Sstevel@tonic-gate 1706*0Sstevel@tonic-gate errno = 0; 1707*0Sstevel@tonic-gate gid = strtol(str, &cp, 10); 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate if (gid == 0 && errno != 0) 1710*0Sstevel@tonic-gate return (-1); 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gate for (; *cp != '\0'; ++cp) 1713*0Sstevel@tonic-gate if (*cp != ' ' || *cp != '\t') 1714*0Sstevel@tonic-gate return (-1); 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate return (gid); 1717*0Sstevel@tonic-gate } else { 1718*0Sstevel@tonic-gate struct group grp, *ret; 1719*0Sstevel@tonic-gate char *buffer; 1720*0Sstevel@tonic-gate size_t buflen; 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate buflen = sysconf(_SC_GETGR_R_SIZE_MAX); 1723*0Sstevel@tonic-gate buffer = malloc(buflen); 1724*0Sstevel@tonic-gate if (buffer == NULL) 1725*0Sstevel@tonic-gate uu_die(allocfail); 1726*0Sstevel@tonic-gate 1727*0Sstevel@tonic-gate errno = 0; 1728*0Sstevel@tonic-gate ret = getgrnam_r(str, &grp, buffer, buflen); 1729*0Sstevel@tonic-gate free(buffer); 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate return (ret == NULL ? -1 : grp.gr_gid); 1732*0Sstevel@tonic-gate } 1733*0Sstevel@tonic-gate } 1734*0Sstevel@tonic-gate 1735*0Sstevel@tonic-gate /* 1736*0Sstevel@tonic-gate * Fails with 1737*0Sstevel@tonic-gate * ENOMEM - out of memory 1738*0Sstevel@tonic-gate * ENOENT - no passwd entry 1739*0Sstevel@tonic-gate * no project entry 1740*0Sstevel@tonic-gate * EIO - an I/O error occurred 1741*0Sstevel@tonic-gate * EMFILE - the process is out of file descriptors 1742*0Sstevel@tonic-gate * ENFILE - the system is out of file handles 1743*0Sstevel@tonic-gate * ERANGE - the project id is out of range 1744*0Sstevel@tonic-gate * EINVAL - str is invalid 1745*0Sstevel@tonic-gate * E2BIG - the project entry was too big 1746*0Sstevel@tonic-gate * -1 - the name service switch is misconfigured 1747*0Sstevel@tonic-gate */ 1748*0Sstevel@tonic-gate int 1749*0Sstevel@tonic-gate get_projid(const char *str, struct method_context *cip) 1750*0Sstevel@tonic-gate { 1751*0Sstevel@tonic-gate int ret; 1752*0Sstevel@tonic-gate void *buf; 1753*0Sstevel@tonic-gate const size_t bufsz = PROJECT_BUFSZ; 1754*0Sstevel@tonic-gate struct project proj, *pp; 1755*0Sstevel@tonic-gate 1756*0Sstevel@tonic-gate if (strcmp(str, ":default") == 0) { 1757*0Sstevel@tonic-gate if (cip->uid == 0) { 1758*0Sstevel@tonic-gate /* Don't change project for root services */ 1759*0Sstevel@tonic-gate cip->project = NULL; 1760*0Sstevel@tonic-gate return (0); 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate switch (ret = lookup_pwd(cip)) { 1764*0Sstevel@tonic-gate case 0: 1765*0Sstevel@tonic-gate break; 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate case ENOMEM: 1768*0Sstevel@tonic-gate case ENOENT: 1769*0Sstevel@tonic-gate case EIO: 1770*0Sstevel@tonic-gate case EMFILE: 1771*0Sstevel@tonic-gate case ENFILE: 1772*0Sstevel@tonic-gate return (ret); 1773*0Sstevel@tonic-gate 1774*0Sstevel@tonic-gate default: 1775*0Sstevel@tonic-gate bad_fail("lookup_pwd", ret); 1776*0Sstevel@tonic-gate } 1777*0Sstevel@tonic-gate 1778*0Sstevel@tonic-gate buf = malloc(bufsz); 1779*0Sstevel@tonic-gate if (buf == NULL) 1780*0Sstevel@tonic-gate return (ENOMEM); 1781*0Sstevel@tonic-gate 1782*0Sstevel@tonic-gate do { 1783*0Sstevel@tonic-gate errno = 0; 1784*0Sstevel@tonic-gate pp = getdefaultproj(cip->pwd.pw_name, &proj, buf, 1785*0Sstevel@tonic-gate bufsz); 1786*0Sstevel@tonic-gate } while (pp == NULL && errno == EINTR); 1787*0Sstevel@tonic-gate 1788*0Sstevel@tonic-gate /* to be continued ... */ 1789*0Sstevel@tonic-gate } else { 1790*0Sstevel@tonic-gate projid_t projid; 1791*0Sstevel@tonic-gate char *cp; 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate if (!isdigit(str[0])) { 1794*0Sstevel@tonic-gate cip->project = strdup(str); 1795*0Sstevel@tonic-gate return (cip->project != NULL ? 0 : ENOMEM); 1796*0Sstevel@tonic-gate } 1797*0Sstevel@tonic-gate 1798*0Sstevel@tonic-gate errno = 0; 1799*0Sstevel@tonic-gate projid = strtol(str, &cp, 10); 1800*0Sstevel@tonic-gate 1801*0Sstevel@tonic-gate if (projid == 0 && errno != 0) { 1802*0Sstevel@tonic-gate assert(errno == ERANGE); 1803*0Sstevel@tonic-gate return (errno); 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate for (; *cp != '\0'; ++cp) 1807*0Sstevel@tonic-gate if (*cp != ' ' || *cp != '\t') 1808*0Sstevel@tonic-gate return (EINVAL); 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate if (projid > MAXPROJID) 1811*0Sstevel@tonic-gate return (ERANGE); 1812*0Sstevel@tonic-gate 1813*0Sstevel@tonic-gate buf = malloc(bufsz); 1814*0Sstevel@tonic-gate if (buf == NULL) 1815*0Sstevel@tonic-gate return (ENOMEM); 1816*0Sstevel@tonic-gate 1817*0Sstevel@tonic-gate do { 1818*0Sstevel@tonic-gate errno = 0; 1819*0Sstevel@tonic-gate pp = getprojbyid(projid, &proj, buf, bufsz); 1820*0Sstevel@tonic-gate } while (pp == NULL && errno == EINTR); 1821*0Sstevel@tonic-gate } 1822*0Sstevel@tonic-gate 1823*0Sstevel@tonic-gate if (pp) { 1824*0Sstevel@tonic-gate cip->project = strdup(pp->pj_name); 1825*0Sstevel@tonic-gate free(buf); 1826*0Sstevel@tonic-gate return (cip->project != NULL ? 0 : ENOMEM); 1827*0Sstevel@tonic-gate } 1828*0Sstevel@tonic-gate 1829*0Sstevel@tonic-gate free(buf); 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate switch (errno) { 1832*0Sstevel@tonic-gate case 0: 1833*0Sstevel@tonic-gate return (ENOENT); 1834*0Sstevel@tonic-gate 1835*0Sstevel@tonic-gate case EIO: 1836*0Sstevel@tonic-gate case EMFILE: 1837*0Sstevel@tonic-gate case ENFILE: 1838*0Sstevel@tonic-gate return (errno); 1839*0Sstevel@tonic-gate 1840*0Sstevel@tonic-gate case ERANGE: 1841*0Sstevel@tonic-gate return (E2BIG); 1842*0Sstevel@tonic-gate 1843*0Sstevel@tonic-gate default: 1844*0Sstevel@tonic-gate return (-1); 1845*0Sstevel@tonic-gate } 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate /* 1849*0Sstevel@tonic-gate * Parse the supp_groups property value and populate ci->groups. Returns 1850*0Sstevel@tonic-gate * EINVAL (get_gid() failed for one of the components), E2BIG (the property has 1851*0Sstevel@tonic-gate * more than NGROUPS_MAX-1 groups), or 0 on success. 1852*0Sstevel@tonic-gate */ 1853*0Sstevel@tonic-gate int 1854*0Sstevel@tonic-gate get_groups(char *str, struct method_context *ci) 1855*0Sstevel@tonic-gate { 1856*0Sstevel@tonic-gate char *cp, *end, *next; 1857*0Sstevel@tonic-gate uint_t i; 1858*0Sstevel@tonic-gate 1859*0Sstevel@tonic-gate const char * const whitespace = " \t"; 1860*0Sstevel@tonic-gate const char * const illegal = ", \t"; 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate if (str[0] == '\0') { 1863*0Sstevel@tonic-gate ci->ngroups = 0; 1864*0Sstevel@tonic-gate return (0); 1865*0Sstevel@tonic-gate } 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate for (cp = str, i = 0; *cp != '\0'; ) { 1868*0Sstevel@tonic-gate /* skip whitespace */ 1869*0Sstevel@tonic-gate cp += strspn(cp, whitespace); 1870*0Sstevel@tonic-gate 1871*0Sstevel@tonic-gate /* find the end */ 1872*0Sstevel@tonic-gate end = cp + strcspn(cp, illegal); 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate /* skip whitespace after end */ 1875*0Sstevel@tonic-gate next = end + strspn(end, whitespace); 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate /* if there's a comma, it separates the fields */ 1878*0Sstevel@tonic-gate if (*next == ',') 1879*0Sstevel@tonic-gate ++next; 1880*0Sstevel@tonic-gate 1881*0Sstevel@tonic-gate *end = '\0'; 1882*0Sstevel@tonic-gate 1883*0Sstevel@tonic-gate if ((ci->groups[i] = get_gid(cp)) == -1) { 1884*0Sstevel@tonic-gate ci->ngroups = 0; 1885*0Sstevel@tonic-gate return (EINVAL); 1886*0Sstevel@tonic-gate } 1887*0Sstevel@tonic-gate 1888*0Sstevel@tonic-gate ++i; 1889*0Sstevel@tonic-gate if (i > NGROUPS_MAX - 1) { 1890*0Sstevel@tonic-gate ci->ngroups = 0; 1891*0Sstevel@tonic-gate return (E2BIG); 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate cp = next; 1895*0Sstevel@tonic-gate } 1896*0Sstevel@tonic-gate 1897*0Sstevel@tonic-gate ci->ngroups = i; 1898*0Sstevel@tonic-gate return (0); 1899*0Sstevel@tonic-gate } 1900*0Sstevel@tonic-gate 1901*0Sstevel@tonic-gate /* 1902*0Sstevel@tonic-gate * Eventually, we will return a structured error in the case of 1903*0Sstevel@tonic-gate * retryable or abortable failures such as memory allocation errors and 1904*0Sstevel@tonic-gate * repository connection failures. For now, these failures are just 1905*0Sstevel@tonic-gate * encoded in the failure string. 1906*0Sstevel@tonic-gate */ 1907*0Sstevel@tonic-gate static const char * 1908*0Sstevel@tonic-gate get_profile(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val, 1909*0Sstevel@tonic-gate const char *cmdline, struct method_context *ci) 1910*0Sstevel@tonic-gate { 1911*0Sstevel@tonic-gate char *buf = ci->vbuf; 1912*0Sstevel@tonic-gate ssize_t buf_sz = ci->vbuf_sz; 1913*0Sstevel@tonic-gate char cmd[PATH_MAX]; 1914*0Sstevel@tonic-gate char *cp, *value; 1915*0Sstevel@tonic-gate const char *cmdp; 1916*0Sstevel@tonic-gate execattr_t *eap; 1917*0Sstevel@tonic-gate char *errstr = NULL; 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_PROFILE, buf, buf_sz, prop, val) != 1920*0Sstevel@tonic-gate 0) 1921*0Sstevel@tonic-gate return ("Could not get profile property."); 1922*0Sstevel@tonic-gate 1923*0Sstevel@tonic-gate /* Extract the command from the command line. */ 1924*0Sstevel@tonic-gate cp = strpbrk(cmdline, " \t"); 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate if (cp == NULL) { 1927*0Sstevel@tonic-gate cmdp = cmdline; 1928*0Sstevel@tonic-gate } else { 1929*0Sstevel@tonic-gate (void) strncpy(cmd, cmdline, cp - cmdline); 1930*0Sstevel@tonic-gate cmd[cp - cmdline] = '\0'; 1931*0Sstevel@tonic-gate cmdp = cmd; 1932*0Sstevel@tonic-gate } 1933*0Sstevel@tonic-gate 1934*0Sstevel@tonic-gate /* Require that cmdp[0] == '/'? */ 1935*0Sstevel@tonic-gate 1936*0Sstevel@tonic-gate eap = getexecprof(buf, KV_COMMAND, cmdp, GET_ONE); 1937*0Sstevel@tonic-gate if (eap == NULL) 1938*0Sstevel@tonic-gate return ("Could not find profile."); 1939*0Sstevel@tonic-gate 1940*0Sstevel@tonic-gate /* Based on pfexec.c */ 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate /* Get the euid first so we don't override ci->pwd for the uid. */ 1943*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_EUID_KW)) != NULL) { 1944*0Sstevel@tonic-gate if (get_uid(value, ci, &ci->euid) != 0) { 1945*0Sstevel@tonic-gate ci->euid = -1; 1946*0Sstevel@tonic-gate errstr = "Could not interpret profile euid."; 1947*0Sstevel@tonic-gate goto out; 1948*0Sstevel@tonic-gate } 1949*0Sstevel@tonic-gate } 1950*0Sstevel@tonic-gate 1951*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_UID_KW)) != NULL) { 1952*0Sstevel@tonic-gate if (get_uid(value, ci, &ci->uid) != 0) { 1953*0Sstevel@tonic-gate ci->euid = ci->uid = -1; 1954*0Sstevel@tonic-gate errstr = "Could not interpret profile uid."; 1955*0Sstevel@tonic-gate goto out; 1956*0Sstevel@tonic-gate } 1957*0Sstevel@tonic-gate ci->euid = ci->uid; 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate 1960*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_GID_KW)) != NULL) { 1961*0Sstevel@tonic-gate ci->egid = ci->gid = get_gid(value); 1962*0Sstevel@tonic-gate if (ci->gid == -1) { 1963*0Sstevel@tonic-gate errstr = "Could not interpret profile gid."; 1964*0Sstevel@tonic-gate goto out; 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate } 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_EGID_KW)) != NULL) { 1969*0Sstevel@tonic-gate ci->egid = get_gid(value); 1970*0Sstevel@tonic-gate if (ci->egid == -1) { 1971*0Sstevel@tonic-gate errstr = "Could not interpret profile egid."; 1972*0Sstevel@tonic-gate goto out; 1973*0Sstevel@tonic-gate } 1974*0Sstevel@tonic-gate } 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_LPRIV_KW)) != NULL) { 1977*0Sstevel@tonic-gate ci->lpriv_set = priv_str_to_set(value, ",", NULL); 1978*0Sstevel@tonic-gate if (ci->lpriv_set == NULL) { 1979*0Sstevel@tonic-gate if (errno != EINVAL) 1980*0Sstevel@tonic-gate errstr = ALLOCFAIL; 1981*0Sstevel@tonic-gate else 1982*0Sstevel@tonic-gate errstr = "Could not interpret profile " 1983*0Sstevel@tonic-gate "limitprivs."; 1984*0Sstevel@tonic-gate goto out; 1985*0Sstevel@tonic-gate } 1986*0Sstevel@tonic-gate } 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate if ((value = kva_match(eap->attr, EXECATTR_IPRIV_KW)) != NULL) { 1989*0Sstevel@tonic-gate ci->priv_set = priv_str_to_set(value, ",", NULL); 1990*0Sstevel@tonic-gate if (ci->priv_set == NULL) { 1991*0Sstevel@tonic-gate if (errno != EINVAL) 1992*0Sstevel@tonic-gate errstr = ALLOCFAIL; 1993*0Sstevel@tonic-gate else 1994*0Sstevel@tonic-gate errstr = "Could not interpret profile privs."; 1995*0Sstevel@tonic-gate goto out; 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate } 1998*0Sstevel@tonic-gate 1999*0Sstevel@tonic-gate out: 2000*0Sstevel@tonic-gate free_execattr(eap); 2001*0Sstevel@tonic-gate 2002*0Sstevel@tonic-gate return (errstr); 2003*0Sstevel@tonic-gate } 2004*0Sstevel@tonic-gate 2005*0Sstevel@tonic-gate /* 2006*0Sstevel@tonic-gate * Eventually, we will return a structured error in the case of 2007*0Sstevel@tonic-gate * retryable or abortable failures such as memory allocation errors and 2008*0Sstevel@tonic-gate * repository connection failures. For now, these failures are just 2009*0Sstevel@tonic-gate * encoded in the failure string. 2010*0Sstevel@tonic-gate */ 2011*0Sstevel@tonic-gate static const char * 2012*0Sstevel@tonic-gate get_ids(scf_propertygroup_t *pg, scf_property_t *prop, scf_value_t *val, 2013*0Sstevel@tonic-gate struct method_context *ci) 2014*0Sstevel@tonic-gate { 2015*0Sstevel@tonic-gate const char *errstr = NULL; 2016*0Sstevel@tonic-gate char *vbuf = ci->vbuf; 2017*0Sstevel@tonic-gate ssize_t vbuf_sz = ci->vbuf_sz; 2018*0Sstevel@tonic-gate int r; 2019*0Sstevel@tonic-gate 2020*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_USER, vbuf, vbuf_sz, prop, val) != 2021*0Sstevel@tonic-gate 0) { 2022*0Sstevel@tonic-gate errstr = "Could not get user property."; 2023*0Sstevel@tonic-gate goto out; 2024*0Sstevel@tonic-gate } 2025*0Sstevel@tonic-gate 2026*0Sstevel@tonic-gate if (get_uid(vbuf, ci, &ci->uid) != 0) { 2027*0Sstevel@tonic-gate ci->uid = -1; 2028*0Sstevel@tonic-gate errstr = "Could not interpret user property."; 2029*0Sstevel@tonic-gate goto out; 2030*0Sstevel@tonic-gate } 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_GROUP, vbuf, vbuf_sz, prop, val) != 2033*0Sstevel@tonic-gate 0) { 2034*0Sstevel@tonic-gate errstr = "Could not get group property."; 2035*0Sstevel@tonic-gate goto out; 2036*0Sstevel@tonic-gate } 2037*0Sstevel@tonic-gate 2038*0Sstevel@tonic-gate if (strcmp(vbuf, ":default") != 0) { 2039*0Sstevel@tonic-gate ci->gid = get_gid(vbuf); 2040*0Sstevel@tonic-gate if (ci->gid == -1) { 2041*0Sstevel@tonic-gate errstr = "Could not interpret group property."; 2042*0Sstevel@tonic-gate goto out; 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate } else { 2045*0Sstevel@tonic-gate switch (r = lookup_pwd(ci)) { 2046*0Sstevel@tonic-gate case 0: 2047*0Sstevel@tonic-gate ci->gid = ci->pwd.pw_gid; 2048*0Sstevel@tonic-gate break; 2049*0Sstevel@tonic-gate 2050*0Sstevel@tonic-gate case ENOENT: 2051*0Sstevel@tonic-gate ci->gid = -1; 2052*0Sstevel@tonic-gate errstr = "No passwd entry."; 2053*0Sstevel@tonic-gate goto out; 2054*0Sstevel@tonic-gate 2055*0Sstevel@tonic-gate case ENOMEM: 2056*0Sstevel@tonic-gate errstr = "Out of memory."; 2057*0Sstevel@tonic-gate goto out; 2058*0Sstevel@tonic-gate 2059*0Sstevel@tonic-gate case EIO: 2060*0Sstevel@tonic-gate case EMFILE: 2061*0Sstevel@tonic-gate case ENFILE: 2062*0Sstevel@tonic-gate errstr = "getpwuid_r() failed."; 2063*0Sstevel@tonic-gate goto out; 2064*0Sstevel@tonic-gate 2065*0Sstevel@tonic-gate default: 2066*0Sstevel@tonic-gate bad_fail("lookup_pwd", r); 2067*0Sstevel@tonic-gate } 2068*0Sstevel@tonic-gate } 2069*0Sstevel@tonic-gate 2070*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_SUPP_GROUPS, vbuf, vbuf_sz, prop, 2071*0Sstevel@tonic-gate val) != 0) { 2072*0Sstevel@tonic-gate errstr = "Could not get supplemental groups property."; 2073*0Sstevel@tonic-gate goto out; 2074*0Sstevel@tonic-gate } 2075*0Sstevel@tonic-gate 2076*0Sstevel@tonic-gate if (strcmp(vbuf, ":default") != 0) { 2077*0Sstevel@tonic-gate switch (r = get_groups(vbuf, ci)) { 2078*0Sstevel@tonic-gate case 0: 2079*0Sstevel@tonic-gate break; 2080*0Sstevel@tonic-gate 2081*0Sstevel@tonic-gate case EINVAL: 2082*0Sstevel@tonic-gate errstr = 2083*0Sstevel@tonic-gate "Could not interpret supplemental groups property."; 2084*0Sstevel@tonic-gate goto out; 2085*0Sstevel@tonic-gate 2086*0Sstevel@tonic-gate case E2BIG: 2087*0Sstevel@tonic-gate errstr = "Too many supplemental groups."; 2088*0Sstevel@tonic-gate goto out; 2089*0Sstevel@tonic-gate 2090*0Sstevel@tonic-gate default: 2091*0Sstevel@tonic-gate bad_fail("get_groups", r); 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate } else { 2094*0Sstevel@tonic-gate ci->ngroups = -1; 2095*0Sstevel@tonic-gate } 2096*0Sstevel@tonic-gate 2097*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_PRIVILEGES, vbuf, vbuf_sz, prop, 2098*0Sstevel@tonic-gate val) != 0) { 2099*0Sstevel@tonic-gate errstr = "Could not get privileges property."; 2100*0Sstevel@tonic-gate goto out; 2101*0Sstevel@tonic-gate } 2102*0Sstevel@tonic-gate 2103*0Sstevel@tonic-gate /* 2104*0Sstevel@tonic-gate * For default privs, we need to keep priv_set == NULL, as 2105*0Sstevel@tonic-gate * we use this test elsewhere. 2106*0Sstevel@tonic-gate */ 2107*0Sstevel@tonic-gate if (strcmp(vbuf, ":default") != 0) { 2108*0Sstevel@tonic-gate ci->priv_set = priv_str_to_set(vbuf, ",", NULL); 2109*0Sstevel@tonic-gate if (ci->priv_set == NULL) { 2110*0Sstevel@tonic-gate if (errno != EINVAL) { 2111*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2112*0Sstevel@tonic-gate } else { 2113*0Sstevel@tonic-gate errstr = "Could not interpret privileges " 2114*0Sstevel@tonic-gate "property."; 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate goto out; 2117*0Sstevel@tonic-gate } 2118*0Sstevel@tonic-gate } 2119*0Sstevel@tonic-gate 2120*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_LIMIT_PRIVILEGES, vbuf, vbuf_sz, 2121*0Sstevel@tonic-gate prop, val) != 0) { 2122*0Sstevel@tonic-gate errstr = "Could not get limit_privileges property."; 2123*0Sstevel@tonic-gate goto out; 2124*0Sstevel@tonic-gate } 2125*0Sstevel@tonic-gate 2126*0Sstevel@tonic-gate if (strcmp(vbuf, ":default") == 0) 2127*0Sstevel@tonic-gate /* 2128*0Sstevel@tonic-gate * L must default to all privileges so root NPA services see 2129*0Sstevel@tonic-gate * iE = all. "zone" is all privileges available in the current 2130*0Sstevel@tonic-gate * zone, equivalent to "all" in the global zone. 2131*0Sstevel@tonic-gate */ 2132*0Sstevel@tonic-gate (void) strcpy(vbuf, "zone"); 2133*0Sstevel@tonic-gate 2134*0Sstevel@tonic-gate ci->lpriv_set = priv_str_to_set(vbuf, ",", NULL); 2135*0Sstevel@tonic-gate if (ci->lpriv_set == NULL) { 2136*0Sstevel@tonic-gate if (errno != EINVAL) 2137*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2138*0Sstevel@tonic-gate else { 2139*0Sstevel@tonic-gate errstr = "Could not interpret limit_privileges " 2140*0Sstevel@tonic-gate "property."; 2141*0Sstevel@tonic-gate } 2142*0Sstevel@tonic-gate goto out; 2143*0Sstevel@tonic-gate } 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate out: 2146*0Sstevel@tonic-gate return (errstr); 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate static int 2150*0Sstevel@tonic-gate get_environment(scf_handle_t *h, scf_propertygroup_t *pg, 2151*0Sstevel@tonic-gate struct method_context *mcp, scf_property_t *prop, scf_value_t *val) 2152*0Sstevel@tonic-gate { 2153*0Sstevel@tonic-gate scf_iter_t *iter; 2154*0Sstevel@tonic-gate scf_type_t type; 2155*0Sstevel@tonic-gate size_t i = 0; 2156*0Sstevel@tonic-gate int ret; 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, prop) != 0) { 2159*0Sstevel@tonic-gate if (scf_error() == SCF_ERROR_NOT_FOUND) 2160*0Sstevel@tonic-gate return (ENOENT); 2161*0Sstevel@tonic-gate return (scf_error()); 2162*0Sstevel@tonic-gate } 2163*0Sstevel@tonic-gate if (scf_property_type(prop, &type) != 0) 2164*0Sstevel@tonic-gate return (scf_error()); 2165*0Sstevel@tonic-gate if (type != SCF_TYPE_ASTRING) 2166*0Sstevel@tonic-gate return (EINVAL); 2167*0Sstevel@tonic-gate if ((iter = scf_iter_create(h)) == NULL) 2168*0Sstevel@tonic-gate return (scf_error()); 2169*0Sstevel@tonic-gate 2170*0Sstevel@tonic-gate if (scf_iter_property_values(iter, prop) != 0) { 2171*0Sstevel@tonic-gate ret = scf_error(); 2172*0Sstevel@tonic-gate scf_iter_destroy(iter); 2173*0Sstevel@tonic-gate return (ret); 2174*0Sstevel@tonic-gate } 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate mcp->env_sz = 10; 2177*0Sstevel@tonic-gate 2178*0Sstevel@tonic-gate if ((mcp->env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz)) == NULL) { 2179*0Sstevel@tonic-gate ret = ENOMEM; 2180*0Sstevel@tonic-gate goto out; 2181*0Sstevel@tonic-gate } 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate while ((ret = scf_iter_next_value(iter, val)) == 1) { 2184*0Sstevel@tonic-gate ret = scf_value_get_as_string(val, mcp->vbuf, mcp->vbuf_sz); 2185*0Sstevel@tonic-gate if (ret == -1) { 2186*0Sstevel@tonic-gate ret = scf_error(); 2187*0Sstevel@tonic-gate goto out; 2188*0Sstevel@tonic-gate } 2189*0Sstevel@tonic-gate 2190*0Sstevel@tonic-gate if ((mcp->env[i] = strdup(mcp->vbuf)) == NULL) { 2191*0Sstevel@tonic-gate ret = ENOMEM; 2192*0Sstevel@tonic-gate goto out; 2193*0Sstevel@tonic-gate } 2194*0Sstevel@tonic-gate 2195*0Sstevel@tonic-gate if (++i == mcp->env_sz) { 2196*0Sstevel@tonic-gate char **env; 2197*0Sstevel@tonic-gate mcp->env_sz *= 2; 2198*0Sstevel@tonic-gate env = uu_zalloc(sizeof (*mcp->env) * mcp->env_sz); 2199*0Sstevel@tonic-gate if (env == NULL) { 2200*0Sstevel@tonic-gate ret = ENOMEM; 2201*0Sstevel@tonic-gate goto out; 2202*0Sstevel@tonic-gate } 2203*0Sstevel@tonic-gate (void) memcpy(env, mcp->env, 2204*0Sstevel@tonic-gate sizeof (*mcp->env) * (mcp->env_sz / 2)); 2205*0Sstevel@tonic-gate free(mcp->env); 2206*0Sstevel@tonic-gate mcp->env = env; 2207*0Sstevel@tonic-gate } 2208*0Sstevel@tonic-gate } 2209*0Sstevel@tonic-gate 2210*0Sstevel@tonic-gate if (ret == -1) 2211*0Sstevel@tonic-gate ret = scf_error(); 2212*0Sstevel@tonic-gate 2213*0Sstevel@tonic-gate out: 2214*0Sstevel@tonic-gate scf_iter_destroy(iter); 2215*0Sstevel@tonic-gate return (ret); 2216*0Sstevel@tonic-gate } 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate /* 2219*0Sstevel@tonic-gate * Fetch method context information from the repository, allocate and fill 2220*0Sstevel@tonic-gate * a method_context structure, return it in *mcpp, and return NULL. On error, 2221*0Sstevel@tonic-gate * return a human-readable string which indicates the error. 2222*0Sstevel@tonic-gate * 2223*0Sstevel@tonic-gate * Eventually, we will return a structured error in the case of 2224*0Sstevel@tonic-gate * retryable or abortable failures such as memory allocation errors and 2225*0Sstevel@tonic-gate * repository connection failures. For now, these failures are just 2226*0Sstevel@tonic-gate * encoded in the failure string. 2227*0Sstevel@tonic-gate */ 2228*0Sstevel@tonic-gate const char * 2229*0Sstevel@tonic-gate restarter_get_method_context(uint_t version, scf_instance_t *inst, 2230*0Sstevel@tonic-gate scf_snapshot_t *snap, const char *mname, const char *cmdline, 2231*0Sstevel@tonic-gate struct method_context **mcpp) 2232*0Sstevel@tonic-gate { 2233*0Sstevel@tonic-gate scf_handle_t *h; 2234*0Sstevel@tonic-gate scf_propertygroup_t *methpg = NULL; 2235*0Sstevel@tonic-gate scf_propertygroup_t *instpg = NULL; 2236*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 2237*0Sstevel@tonic-gate scf_property_t *prop = NULL; 2238*0Sstevel@tonic-gate scf_value_t *val = NULL; 2239*0Sstevel@tonic-gate scf_type_t ty; 2240*0Sstevel@tonic-gate uint8_t use_profile; 2241*0Sstevel@tonic-gate int ret; 2242*0Sstevel@tonic-gate const char *errstr = NULL; 2243*0Sstevel@tonic-gate struct method_context *cip; 2244*0Sstevel@tonic-gate 2245*0Sstevel@tonic-gate 2246*0Sstevel@tonic-gate if (version != RESTARTER_METHOD_CONTEXT_VERSION) 2247*0Sstevel@tonic-gate return ("Unknown method_context version."); 2248*0Sstevel@tonic-gate 2249*0Sstevel@tonic-gate /* Get the handle before we allocate anything. */ 2250*0Sstevel@tonic-gate h = scf_instance_handle(inst); 2251*0Sstevel@tonic-gate if (h == NULL) 2252*0Sstevel@tonic-gate return (scf_strerror(scf_error())); 2253*0Sstevel@tonic-gate 2254*0Sstevel@tonic-gate cip = malloc(sizeof (*cip)); 2255*0Sstevel@tonic-gate if (cip == NULL) 2256*0Sstevel@tonic-gate return (ALLOCFAIL); 2257*0Sstevel@tonic-gate 2258*0Sstevel@tonic-gate (void) memset(cip, 0, sizeof (*cip)); 2259*0Sstevel@tonic-gate cip->uid = -1; 2260*0Sstevel@tonic-gate cip->euid = -1; 2261*0Sstevel@tonic-gate cip->gid = -1; 2262*0Sstevel@tonic-gate cip->egid = -1; 2263*0Sstevel@tonic-gate 2264*0Sstevel@tonic-gate cip->vbuf_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 2265*0Sstevel@tonic-gate assert(cip->vbuf_sz >= 0); 2266*0Sstevel@tonic-gate cip->vbuf = malloc(cip->vbuf_sz); 2267*0Sstevel@tonic-gate if (cip->vbuf == NULL) { 2268*0Sstevel@tonic-gate free(cip); 2269*0Sstevel@tonic-gate return (ALLOCFAIL); 2270*0Sstevel@tonic-gate } 2271*0Sstevel@tonic-gate 2272*0Sstevel@tonic-gate if ((instpg = scf_pg_create(h)) == NULL || 2273*0Sstevel@tonic-gate (methpg = scf_pg_create(h)) == NULL || 2274*0Sstevel@tonic-gate (prop = scf_property_create(h)) == NULL || 2275*0Sstevel@tonic-gate (val = scf_value_create(h)) == NULL) { 2276*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2277*0Sstevel@tonic-gate goto out; 2278*0Sstevel@tonic-gate } 2279*0Sstevel@tonic-gate 2280*0Sstevel@tonic-gate /* 2281*0Sstevel@tonic-gate * The method environment, and the credentials/profile data, 2282*0Sstevel@tonic-gate * may be found either in the pg for the method (methpg), 2283*0Sstevel@tonic-gate * or in the instance/service SCF_PG_METHOD_CONTEXT pg (named 2284*0Sstevel@tonic-gate * instpg below). 2285*0Sstevel@tonic-gate */ 2286*0Sstevel@tonic-gate 2287*0Sstevel@tonic-gate if (scf_instance_get_pg_composed(inst, snap, mname, methpg) != 2288*0Sstevel@tonic-gate SCF_SUCCESS) { 2289*0Sstevel@tonic-gate errstr = scf_strerror(scf_error()); 2290*0Sstevel@tonic-gate goto out; 2291*0Sstevel@tonic-gate } 2292*0Sstevel@tonic-gate 2293*0Sstevel@tonic-gate if (scf_instance_get_pg_composed(inst, snap, SCF_PG_METHOD_CONTEXT, 2294*0Sstevel@tonic-gate instpg) != SCF_SUCCESS) { 2295*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 2296*0Sstevel@tonic-gate errstr = scf_strerror(scf_error()); 2297*0Sstevel@tonic-gate goto out; 2298*0Sstevel@tonic-gate } 2299*0Sstevel@tonic-gate scf_pg_destroy(instpg); 2300*0Sstevel@tonic-gate instpg = NULL; 2301*0Sstevel@tonic-gate } 2302*0Sstevel@tonic-gate 2303*0Sstevel@tonic-gate ret = get_environment(h, methpg, cip, prop, val); 2304*0Sstevel@tonic-gate if (ret == ENOENT && instpg != NULL) { 2305*0Sstevel@tonic-gate ret = get_environment(h, instpg, cip, prop, val); 2306*0Sstevel@tonic-gate } 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate switch (ret) { 2309*0Sstevel@tonic-gate case 0: 2310*0Sstevel@tonic-gate case ENOENT: 2311*0Sstevel@tonic-gate break; 2312*0Sstevel@tonic-gate case ENOMEM: 2313*0Sstevel@tonic-gate errstr = "Out of memory."; 2314*0Sstevel@tonic-gate goto out; 2315*0Sstevel@tonic-gate case EINVAL: 2316*0Sstevel@tonic-gate errstr = "Invalid method environment."; 2317*0Sstevel@tonic-gate goto out; 2318*0Sstevel@tonic-gate default: 2319*0Sstevel@tonic-gate errstr = scf_strerror(ret); 2320*0Sstevel@tonic-gate goto out; 2321*0Sstevel@tonic-gate } 2322*0Sstevel@tonic-gate 2323*0Sstevel@tonic-gate pg = methpg; 2324*0Sstevel@tonic-gate 2325*0Sstevel@tonic-gate ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop); 2326*0Sstevel@tonic-gate if (ret && scf_error() == SCF_ERROR_NOT_FOUND && instpg != NULL) { 2327*0Sstevel@tonic-gate pg = instpg; 2328*0Sstevel@tonic-gate ret = scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, prop); 2329*0Sstevel@tonic-gate } 2330*0Sstevel@tonic-gate 2331*0Sstevel@tonic-gate if (ret) { 2332*0Sstevel@tonic-gate switch (scf_error()) { 2333*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 2334*0Sstevel@tonic-gate /* No context: use defaults */ 2335*0Sstevel@tonic-gate cip->uid = 0; 2336*0Sstevel@tonic-gate cip->gid = 0; 2337*0Sstevel@tonic-gate *mcpp = cip; 2338*0Sstevel@tonic-gate goto out; 2339*0Sstevel@tonic-gate 2340*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 2341*0Sstevel@tonic-gate errstr = RCBROKEN; 2342*0Sstevel@tonic-gate goto out; 2343*0Sstevel@tonic-gate 2344*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 2345*0Sstevel@tonic-gate errstr = "\"use_profile\" property deleted."; 2346*0Sstevel@tonic-gate goto out; 2347*0Sstevel@tonic-gate 2348*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 2349*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 2350*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 2351*0Sstevel@tonic-gate default: 2352*0Sstevel@tonic-gate bad_fail("scf_pg_get_property", scf_error()); 2353*0Sstevel@tonic-gate } 2354*0Sstevel@tonic-gate } 2355*0Sstevel@tonic-gate 2356*0Sstevel@tonic-gate if (scf_property_type(prop, &ty) != SCF_SUCCESS) { 2357*0Sstevel@tonic-gate switch (scf_error()) { 2358*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 2359*0Sstevel@tonic-gate errstr = RCBROKEN; 2360*0Sstevel@tonic-gate break; 2361*0Sstevel@tonic-gate 2362*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 2363*0Sstevel@tonic-gate errstr = "\"use profile\" property deleted."; 2364*0Sstevel@tonic-gate break; 2365*0Sstevel@tonic-gate 2366*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 2367*0Sstevel@tonic-gate default: 2368*0Sstevel@tonic-gate bad_fail("scf_property_type", scf_error()); 2369*0Sstevel@tonic-gate } 2370*0Sstevel@tonic-gate 2371*0Sstevel@tonic-gate goto out; 2372*0Sstevel@tonic-gate } 2373*0Sstevel@tonic-gate 2374*0Sstevel@tonic-gate if (ty != SCF_TYPE_BOOLEAN) { 2375*0Sstevel@tonic-gate errstr = "\"use profile\" property is not boolean."; 2376*0Sstevel@tonic-gate goto out; 2377*0Sstevel@tonic-gate } 2378*0Sstevel@tonic-gate 2379*0Sstevel@tonic-gate if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 2380*0Sstevel@tonic-gate switch (scf_error()) { 2381*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 2382*0Sstevel@tonic-gate errstr = RCBROKEN; 2383*0Sstevel@tonic-gate break; 2384*0Sstevel@tonic-gate 2385*0Sstevel@tonic-gate case SCF_ERROR_CONSTRAINT_VIOLATED: 2386*0Sstevel@tonic-gate errstr = 2387*0Sstevel@tonic-gate "\"use profile\" property has multiple values."; 2388*0Sstevel@tonic-gate break; 2389*0Sstevel@tonic-gate 2390*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 2391*0Sstevel@tonic-gate errstr = "\"use profile\" property has no values."; 2392*0Sstevel@tonic-gate break; 2393*0Sstevel@tonic-gate 2394*0Sstevel@tonic-gate default: 2395*0Sstevel@tonic-gate bad_fail("scf_property_get_value", scf_error()); 2396*0Sstevel@tonic-gate } 2397*0Sstevel@tonic-gate 2398*0Sstevel@tonic-gate goto out; 2399*0Sstevel@tonic-gate } 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate ret = scf_value_get_boolean(val, &use_profile); 2402*0Sstevel@tonic-gate assert(ret == SCF_SUCCESS); 2403*0Sstevel@tonic-gate 2404*0Sstevel@tonic-gate /* get ids & privileges */ 2405*0Sstevel@tonic-gate if (use_profile) 2406*0Sstevel@tonic-gate errstr = get_profile(pg, prop, val, cmdline, cip); 2407*0Sstevel@tonic-gate else 2408*0Sstevel@tonic-gate errstr = get_ids(pg, prop, val, cip); 2409*0Sstevel@tonic-gate if (errstr != NULL) 2410*0Sstevel@tonic-gate goto out; 2411*0Sstevel@tonic-gate 2412*0Sstevel@tonic-gate /* get working directory */ 2413*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_WORKING_DIRECTORY, cip->vbuf, 2414*0Sstevel@tonic-gate cip->vbuf_sz, prop, val) != 0) { 2415*0Sstevel@tonic-gate errstr = "Could not get value for working directory."; 2416*0Sstevel@tonic-gate goto out; 2417*0Sstevel@tonic-gate } 2418*0Sstevel@tonic-gate 2419*0Sstevel@tonic-gate if (strcmp(cip->vbuf, ":default") == 0 || 2420*0Sstevel@tonic-gate strcmp(cip->vbuf, ":home") == 0) { 2421*0Sstevel@tonic-gate switch (ret = lookup_pwd(cip)) { 2422*0Sstevel@tonic-gate case 0: 2423*0Sstevel@tonic-gate break; 2424*0Sstevel@tonic-gate 2425*0Sstevel@tonic-gate case ENOMEM: 2426*0Sstevel@tonic-gate errstr = "Out of memory."; 2427*0Sstevel@tonic-gate goto out; 2428*0Sstevel@tonic-gate 2429*0Sstevel@tonic-gate case ENOENT: 2430*0Sstevel@tonic-gate case EIO: 2431*0Sstevel@tonic-gate case EMFILE: 2432*0Sstevel@tonic-gate case ENFILE: 2433*0Sstevel@tonic-gate errstr = "Could not get passwd entry."; 2434*0Sstevel@tonic-gate goto out; 2435*0Sstevel@tonic-gate 2436*0Sstevel@tonic-gate default: 2437*0Sstevel@tonic-gate bad_fail("lookup_pwd", ret); 2438*0Sstevel@tonic-gate } 2439*0Sstevel@tonic-gate 2440*0Sstevel@tonic-gate cip->working_dir = strdup(cip->pwd.pw_dir); 2441*0Sstevel@tonic-gate if (cip->working_dir == NULL) { 2442*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2443*0Sstevel@tonic-gate goto out; 2444*0Sstevel@tonic-gate } 2445*0Sstevel@tonic-gate } else { 2446*0Sstevel@tonic-gate cip->working_dir = strdup(cip->vbuf); 2447*0Sstevel@tonic-gate if (cip->working_dir == NULL) { 2448*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2449*0Sstevel@tonic-gate goto out; 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate } 2452*0Sstevel@tonic-gate 2453*0Sstevel@tonic-gate /* get (optional) corefile pattern */ 2454*0Sstevel@tonic-gate if (scf_pg_get_property(pg, SCF_PROPERTY_COREFILE_PATTERN, prop) == 2455*0Sstevel@tonic-gate SCF_SUCCESS) { 2456*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_COREFILE_PATTERN, 2457*0Sstevel@tonic-gate cip->vbuf, cip->vbuf_sz, prop, val) != 0) { 2458*0Sstevel@tonic-gate errstr = "Could not get value for corefile pattern."; 2459*0Sstevel@tonic-gate goto out; 2460*0Sstevel@tonic-gate } 2461*0Sstevel@tonic-gate 2462*0Sstevel@tonic-gate cip->corefile_pattern = strdup(cip->vbuf); 2463*0Sstevel@tonic-gate if (cip->corefile_pattern == NULL) { 2464*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2465*0Sstevel@tonic-gate goto out; 2466*0Sstevel@tonic-gate } 2467*0Sstevel@tonic-gate } else { 2468*0Sstevel@tonic-gate switch (scf_error()) { 2469*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 2470*0Sstevel@tonic-gate /* okay if missing. */ 2471*0Sstevel@tonic-gate break; 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 2474*0Sstevel@tonic-gate errstr = RCBROKEN; 2475*0Sstevel@tonic-gate goto out; 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate case SCF_ERROR_DELETED: 2478*0Sstevel@tonic-gate errstr = "\"corefile_pattern\" property deleted."; 2479*0Sstevel@tonic-gate goto out; 2480*0Sstevel@tonic-gate 2481*0Sstevel@tonic-gate case SCF_ERROR_HANDLE_MISMATCH: 2482*0Sstevel@tonic-gate case SCF_ERROR_INVALID_ARGUMENT: 2483*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 2484*0Sstevel@tonic-gate default: 2485*0Sstevel@tonic-gate bad_fail("scf_pg_get_property", scf_error()); 2486*0Sstevel@tonic-gate } 2487*0Sstevel@tonic-gate } 2488*0Sstevel@tonic-gate 2489*0Sstevel@tonic-gate if (restarter_rm_libs_loadable()) { 2490*0Sstevel@tonic-gate /* get project */ 2491*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_PROJECT, cip->vbuf, 2492*0Sstevel@tonic-gate cip->vbuf_sz, prop, val) != 0) { 2493*0Sstevel@tonic-gate errstr = "Could not get project."; 2494*0Sstevel@tonic-gate goto out; 2495*0Sstevel@tonic-gate } 2496*0Sstevel@tonic-gate 2497*0Sstevel@tonic-gate switch (ret = get_projid(cip->vbuf, cip)) { 2498*0Sstevel@tonic-gate case 0: 2499*0Sstevel@tonic-gate break; 2500*0Sstevel@tonic-gate 2501*0Sstevel@tonic-gate case ENOMEM: 2502*0Sstevel@tonic-gate errstr = "Out of memory."; 2503*0Sstevel@tonic-gate goto out; 2504*0Sstevel@tonic-gate 2505*0Sstevel@tonic-gate case ENOENT: 2506*0Sstevel@tonic-gate errstr = "Missing passwd or project entry."; 2507*0Sstevel@tonic-gate goto out; 2508*0Sstevel@tonic-gate 2509*0Sstevel@tonic-gate case EIO: 2510*0Sstevel@tonic-gate errstr = "I/O error."; 2511*0Sstevel@tonic-gate goto out; 2512*0Sstevel@tonic-gate 2513*0Sstevel@tonic-gate case EMFILE: 2514*0Sstevel@tonic-gate case ENFILE: 2515*0Sstevel@tonic-gate errstr = "Out of file descriptors."; 2516*0Sstevel@tonic-gate goto out; 2517*0Sstevel@tonic-gate 2518*0Sstevel@tonic-gate case -1: 2519*0Sstevel@tonic-gate errstr = "Name service switch is misconfigured."; 2520*0Sstevel@tonic-gate goto out; 2521*0Sstevel@tonic-gate 2522*0Sstevel@tonic-gate case ERANGE: 2523*0Sstevel@tonic-gate errstr = "Project ID too big."; 2524*0Sstevel@tonic-gate goto out; 2525*0Sstevel@tonic-gate 2526*0Sstevel@tonic-gate case EINVAL: 2527*0Sstevel@tonic-gate errstr = "Project ID is invalid."; 2528*0Sstevel@tonic-gate goto out; 2529*0Sstevel@tonic-gate 2530*0Sstevel@tonic-gate case E2BIG: 2531*0Sstevel@tonic-gate errstr = "Project entry is too big."; 2532*0Sstevel@tonic-gate goto out; 2533*0Sstevel@tonic-gate 2534*0Sstevel@tonic-gate default: 2535*0Sstevel@tonic-gate bad_fail("get_projid", ret); 2536*0Sstevel@tonic-gate } 2537*0Sstevel@tonic-gate 2538*0Sstevel@tonic-gate /* get resource pool */ 2539*0Sstevel@tonic-gate if (get_astring_val(pg, SCF_PROPERTY_RESOURCE_POOL, cip->vbuf, 2540*0Sstevel@tonic-gate cip->vbuf_sz, prop, val) != 0) { 2541*0Sstevel@tonic-gate errstr = "Could not get value of resource pool."; 2542*0Sstevel@tonic-gate goto out; 2543*0Sstevel@tonic-gate } 2544*0Sstevel@tonic-gate 2545*0Sstevel@tonic-gate if (strcmp(cip->vbuf, ":default") != 0) { 2546*0Sstevel@tonic-gate cip->resource_pool = strdup(cip->vbuf); 2547*0Sstevel@tonic-gate if (cip->resource_pool == NULL) { 2548*0Sstevel@tonic-gate errstr = ALLOCFAIL; 2549*0Sstevel@tonic-gate goto out; 2550*0Sstevel@tonic-gate } 2551*0Sstevel@tonic-gate } 2552*0Sstevel@tonic-gate } 2553*0Sstevel@tonic-gate 2554*0Sstevel@tonic-gate *mcpp = cip; 2555*0Sstevel@tonic-gate 2556*0Sstevel@tonic-gate out: 2557*0Sstevel@tonic-gate (void) scf_value_destroy(val); 2558*0Sstevel@tonic-gate scf_property_destroy(prop); 2559*0Sstevel@tonic-gate scf_pg_destroy(instpg); 2560*0Sstevel@tonic-gate scf_pg_destroy(methpg); 2561*0Sstevel@tonic-gate 2562*0Sstevel@tonic-gate if (cip->pwbuf != NULL) 2563*0Sstevel@tonic-gate free(cip->pwbuf); 2564*0Sstevel@tonic-gate free(cip->vbuf); 2565*0Sstevel@tonic-gate 2566*0Sstevel@tonic-gate if (errstr != NULL) 2567*0Sstevel@tonic-gate restarter_free_method_context(cip); 2568*0Sstevel@tonic-gate 2569*0Sstevel@tonic-gate return (errstr); 2570*0Sstevel@tonic-gate } 2571*0Sstevel@tonic-gate 2572*0Sstevel@tonic-gate /* 2573*0Sstevel@tonic-gate * Modify the current process per the given method_context. On success, returns 2574*0Sstevel@tonic-gate * 0. Note that the environment is not modified by this function to include the 2575*0Sstevel@tonic-gate * environment variables in cip->env. 2576*0Sstevel@tonic-gate * 2577*0Sstevel@tonic-gate * On failure, sets *fp to NULL or the name of the function which failed, 2578*0Sstevel@tonic-gate * and returns one of the following error codes. The words in parentheses are 2579*0Sstevel@tonic-gate * the values to which *fp may be set for the error case. 2580*0Sstevel@tonic-gate * ENOMEM - malloc() failed 2581*0Sstevel@tonic-gate * EIO - an I/O error occurred (getpwuid_r, chdir) 2582*0Sstevel@tonic-gate * EMFILE - process is out of file descriptors (getpwuid_r) 2583*0Sstevel@tonic-gate * ENFILE - system is out of file handles (getpwuid_r) 2584*0Sstevel@tonic-gate * EINVAL - gid or egid is out of range (setregid) 2585*0Sstevel@tonic-gate * ngroups is too big (setgroups) 2586*0Sstevel@tonic-gate * project's project id is bad (setproject) 2587*0Sstevel@tonic-gate * uid or euid is out of range (setreuid) 2588*0Sstevel@tonic-gate * EPERM - insufficient privilege (setregid, initgroups, setgroups, setppriv, 2589*0Sstevel@tonic-gate * setproject, setreuid, settaskid) 2590*0Sstevel@tonic-gate * ENOENT - uid has a passwd entry but no shadow entry 2591*0Sstevel@tonic-gate * working_dir does not exist (chdir) 2592*0Sstevel@tonic-gate * uid has no passwd entry 2593*0Sstevel@tonic-gate * the pool could not be found (pool_set_binding) 2594*0Sstevel@tonic-gate * EFAULT - lpriv_set or priv_set has a bad address (setppriv) 2595*0Sstevel@tonic-gate * working_dir has a bad address (chdir) 2596*0Sstevel@tonic-gate * EACCES - could not access working_dir (chdir) 2597*0Sstevel@tonic-gate * in a TASK_FINAL task (setproject, settaskid) 2598*0Sstevel@tonic-gate * no resource pool accepting default binding exists (setproject) 2599*0Sstevel@tonic-gate * ELOOP - too many symbolic links in working_dir (chdir) 2600*0Sstevel@tonic-gate * ENAMETOOLONG - working_dir is too long (chdir) 2601*0Sstevel@tonic-gate * ENOLINK - working_dir is on an inaccessible remote machine (chdir) 2602*0Sstevel@tonic-gate * ENOTDIR - working_dir is not a directory (chdir) 2603*0Sstevel@tonic-gate * ESRCH - uid is not a user of project (setproject) 2604*0Sstevel@tonic-gate * project is invalid (setproject) 2605*0Sstevel@tonic-gate * the resource pool specified for project is unknown (setproject) 2606*0Sstevel@tonic-gate * EBADF - the configuration for the pool is invalid (pool_set_binding) 2607*0Sstevel@tonic-gate * -1 - core_set_process_path() failed (core_set_process_path) 2608*0Sstevel@tonic-gate * a resource control assignment failed (setproject) 2609*0Sstevel@tonic-gate * a system error occurred during pool_set_binding (pool_set_binding) 2610*0Sstevel@tonic-gate */ 2611*0Sstevel@tonic-gate int 2612*0Sstevel@tonic-gate restarter_set_method_context(struct method_context *cip, const char **fp) 2613*0Sstevel@tonic-gate { 2614*0Sstevel@tonic-gate pid_t mypid = -1; 2615*0Sstevel@tonic-gate int r, ret; 2616*0Sstevel@tonic-gate 2617*0Sstevel@tonic-gate cip->pwbuf = NULL; 2618*0Sstevel@tonic-gate *fp = NULL; 2619*0Sstevel@tonic-gate 2620*0Sstevel@tonic-gate if (cip->gid != -1) { 2621*0Sstevel@tonic-gate if (setregid(cip->gid, 2622*0Sstevel@tonic-gate cip->egid != -1 ? cip->egid : cip->gid) != 0) { 2623*0Sstevel@tonic-gate *fp = "setregid"; 2624*0Sstevel@tonic-gate 2625*0Sstevel@tonic-gate ret = errno; 2626*0Sstevel@tonic-gate assert(ret == EINVAL || ret == EPERM); 2627*0Sstevel@tonic-gate goto out; 2628*0Sstevel@tonic-gate } 2629*0Sstevel@tonic-gate } else { 2630*0Sstevel@tonic-gate if (cip->pwbuf == NULL) { 2631*0Sstevel@tonic-gate switch (ret = lookup_pwd(cip)) { 2632*0Sstevel@tonic-gate case 0: 2633*0Sstevel@tonic-gate break; 2634*0Sstevel@tonic-gate 2635*0Sstevel@tonic-gate case ENOMEM: 2636*0Sstevel@tonic-gate case ENOENT: 2637*0Sstevel@tonic-gate *fp = NULL; 2638*0Sstevel@tonic-gate goto out; 2639*0Sstevel@tonic-gate 2640*0Sstevel@tonic-gate case EIO: 2641*0Sstevel@tonic-gate case EMFILE: 2642*0Sstevel@tonic-gate case ENFILE: 2643*0Sstevel@tonic-gate *fp = "getpwuid_r"; 2644*0Sstevel@tonic-gate goto out; 2645*0Sstevel@tonic-gate 2646*0Sstevel@tonic-gate default: 2647*0Sstevel@tonic-gate bad_fail("lookup_pwd", ret); 2648*0Sstevel@tonic-gate } 2649*0Sstevel@tonic-gate } 2650*0Sstevel@tonic-gate 2651*0Sstevel@tonic-gate if (setregid(cip->pwd.pw_gid, 2652*0Sstevel@tonic-gate cip->egid != -1 ? cip->egid : cip->pwd.pw_gid) != 0) { 2653*0Sstevel@tonic-gate *fp = "setregid"; 2654*0Sstevel@tonic-gate 2655*0Sstevel@tonic-gate ret = errno; 2656*0Sstevel@tonic-gate assert(ret == EINVAL || ret == EPERM); 2657*0Sstevel@tonic-gate goto out; 2658*0Sstevel@tonic-gate } 2659*0Sstevel@tonic-gate } 2660*0Sstevel@tonic-gate 2661*0Sstevel@tonic-gate if (cip->ngroups == -1) { 2662*0Sstevel@tonic-gate if (cip->pwbuf == NULL) { 2663*0Sstevel@tonic-gate switch (ret = lookup_pwd(cip)) { 2664*0Sstevel@tonic-gate case 0: 2665*0Sstevel@tonic-gate break; 2666*0Sstevel@tonic-gate 2667*0Sstevel@tonic-gate case ENOMEM: 2668*0Sstevel@tonic-gate case ENOENT: 2669*0Sstevel@tonic-gate *fp = NULL; 2670*0Sstevel@tonic-gate goto out; 2671*0Sstevel@tonic-gate 2672*0Sstevel@tonic-gate case EIO: 2673*0Sstevel@tonic-gate case EMFILE: 2674*0Sstevel@tonic-gate case ENFILE: 2675*0Sstevel@tonic-gate *fp = "getpwuid_r"; 2676*0Sstevel@tonic-gate goto out; 2677*0Sstevel@tonic-gate 2678*0Sstevel@tonic-gate default: 2679*0Sstevel@tonic-gate bad_fail("lookup_pwd", ret); 2680*0Sstevel@tonic-gate } 2681*0Sstevel@tonic-gate } 2682*0Sstevel@tonic-gate 2683*0Sstevel@tonic-gate /* Ok if cip->gid == -1 */ 2684*0Sstevel@tonic-gate if (initgroups(cip->pwd.pw_name, cip->gid) != 0) { 2685*0Sstevel@tonic-gate *fp = "initgroups"; 2686*0Sstevel@tonic-gate ret = errno; 2687*0Sstevel@tonic-gate assert(ret == EPERM); 2688*0Sstevel@tonic-gate goto out; 2689*0Sstevel@tonic-gate } 2690*0Sstevel@tonic-gate } else if (cip->ngroups > 0 && 2691*0Sstevel@tonic-gate setgroups(cip->ngroups, cip->groups) != 0) { 2692*0Sstevel@tonic-gate *fp = "setgroups"; 2693*0Sstevel@tonic-gate 2694*0Sstevel@tonic-gate ret = errno; 2695*0Sstevel@tonic-gate assert(ret == EINVAL || ret == EPERM); 2696*0Sstevel@tonic-gate goto out; 2697*0Sstevel@tonic-gate } 2698*0Sstevel@tonic-gate 2699*0Sstevel@tonic-gate *fp = "setppriv"; 2700*0Sstevel@tonic-gate 2701*0Sstevel@tonic-gate if (cip->lpriv_set != NULL) { 2702*0Sstevel@tonic-gate if (setppriv(PRIV_SET, PRIV_LIMIT, cip->lpriv_set) != 0) { 2703*0Sstevel@tonic-gate ret = errno; 2704*0Sstevel@tonic-gate assert(ret == EFAULT || ret == EPERM); 2705*0Sstevel@tonic-gate goto out; 2706*0Sstevel@tonic-gate } 2707*0Sstevel@tonic-gate } 2708*0Sstevel@tonic-gate if (cip->priv_set != NULL) { 2709*0Sstevel@tonic-gate if (setppriv(PRIV_SET, PRIV_INHERITABLE, cip->priv_set) != 0) { 2710*0Sstevel@tonic-gate ret = errno; 2711*0Sstevel@tonic-gate assert(ret == EFAULT || ret == EPERM); 2712*0Sstevel@tonic-gate goto out; 2713*0Sstevel@tonic-gate } 2714*0Sstevel@tonic-gate } 2715*0Sstevel@tonic-gate 2716*0Sstevel@tonic-gate if (cip->working_dir != NULL) { 2717*0Sstevel@tonic-gate do 2718*0Sstevel@tonic-gate r = chdir(cip->working_dir); 2719*0Sstevel@tonic-gate while (r != 0 && errno == EINTR); 2720*0Sstevel@tonic-gate if (r != 0) { 2721*0Sstevel@tonic-gate *fp = "chdir"; 2722*0Sstevel@tonic-gate ret = errno; 2723*0Sstevel@tonic-gate goto out; 2724*0Sstevel@tonic-gate } 2725*0Sstevel@tonic-gate } 2726*0Sstevel@tonic-gate 2727*0Sstevel@tonic-gate if (cip->corefile_pattern != NULL) { 2728*0Sstevel@tonic-gate mypid = getpid(); 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate if (core_set_process_path(cip->corefile_pattern, 2731*0Sstevel@tonic-gate strlen(cip->corefile_pattern) + 1, mypid) != 0) { 2732*0Sstevel@tonic-gate *fp = "core_set_process_path"; 2733*0Sstevel@tonic-gate ret = -1; 2734*0Sstevel@tonic-gate goto out; 2735*0Sstevel@tonic-gate } 2736*0Sstevel@tonic-gate } 2737*0Sstevel@tonic-gate 2738*0Sstevel@tonic-gate if (restarter_rm_libs_loadable()) { 2739*0Sstevel@tonic-gate if (cip->project == NULL) { 2740*0Sstevel@tonic-gate if (settaskid(getprojid(), TASK_NORMAL) == -1) { 2741*0Sstevel@tonic-gate switch (errno) { 2742*0Sstevel@tonic-gate case EACCES: 2743*0Sstevel@tonic-gate case EPERM: 2744*0Sstevel@tonic-gate *fp = "settaskid"; 2745*0Sstevel@tonic-gate ret = errno; 2746*0Sstevel@tonic-gate goto out; 2747*0Sstevel@tonic-gate 2748*0Sstevel@tonic-gate case EINVAL: 2749*0Sstevel@tonic-gate default: 2750*0Sstevel@tonic-gate bad_fail("settaskid", errno); 2751*0Sstevel@tonic-gate } 2752*0Sstevel@tonic-gate } 2753*0Sstevel@tonic-gate } else { 2754*0Sstevel@tonic-gate switch (ret = lookup_pwd(cip)) { 2755*0Sstevel@tonic-gate case 0: 2756*0Sstevel@tonic-gate break; 2757*0Sstevel@tonic-gate 2758*0Sstevel@tonic-gate case ENOMEM: 2759*0Sstevel@tonic-gate case ENOENT: 2760*0Sstevel@tonic-gate *fp = NULL; 2761*0Sstevel@tonic-gate goto out; 2762*0Sstevel@tonic-gate 2763*0Sstevel@tonic-gate case EIO: 2764*0Sstevel@tonic-gate case EMFILE: 2765*0Sstevel@tonic-gate case ENFILE: 2766*0Sstevel@tonic-gate *fp = "getpwuid_r"; 2767*0Sstevel@tonic-gate goto out; 2768*0Sstevel@tonic-gate 2769*0Sstevel@tonic-gate default: 2770*0Sstevel@tonic-gate bad_fail("lookup_pwd", ret); 2771*0Sstevel@tonic-gate } 2772*0Sstevel@tonic-gate 2773*0Sstevel@tonic-gate *fp = "setproject"; 2774*0Sstevel@tonic-gate 2775*0Sstevel@tonic-gate switch (setproject(cip->project, cip->pwd.pw_name, 2776*0Sstevel@tonic-gate TASK_NORMAL)) { 2777*0Sstevel@tonic-gate case 0: 2778*0Sstevel@tonic-gate break; 2779*0Sstevel@tonic-gate 2780*0Sstevel@tonic-gate case SETPROJ_ERR_TASK: 2781*0Sstevel@tonic-gate case SETPROJ_ERR_POOL: 2782*0Sstevel@tonic-gate ret = errno; 2783*0Sstevel@tonic-gate goto out; 2784*0Sstevel@tonic-gate 2785*0Sstevel@tonic-gate default: 2786*0Sstevel@tonic-gate ret = -1; 2787*0Sstevel@tonic-gate goto out; 2788*0Sstevel@tonic-gate } 2789*0Sstevel@tonic-gate } 2790*0Sstevel@tonic-gate 2791*0Sstevel@tonic-gate if (cip->resource_pool != NULL) { 2792*0Sstevel@tonic-gate if (mypid == -1) 2793*0Sstevel@tonic-gate mypid = getpid(); 2794*0Sstevel@tonic-gate 2795*0Sstevel@tonic-gate *fp = "pool_set_binding"; 2796*0Sstevel@tonic-gate 2797*0Sstevel@tonic-gate if (pool_set_binding(cip->resource_pool, P_PID, 2798*0Sstevel@tonic-gate mypid) != PO_SUCCESS) { 2799*0Sstevel@tonic-gate switch (pool_error()) { 2800*0Sstevel@tonic-gate case POE_BADPARAM: 2801*0Sstevel@tonic-gate ret = ENOENT; 2802*0Sstevel@tonic-gate break; 2803*0Sstevel@tonic-gate 2804*0Sstevel@tonic-gate case POE_INVALID_CONF: 2805*0Sstevel@tonic-gate ret = EBADF; 2806*0Sstevel@tonic-gate break; 2807*0Sstevel@tonic-gate 2808*0Sstevel@tonic-gate case POE_SYSTEM: 2809*0Sstevel@tonic-gate ret = -1; 2810*0Sstevel@tonic-gate break; 2811*0Sstevel@tonic-gate 2812*0Sstevel@tonic-gate default: 2813*0Sstevel@tonic-gate bad_fail("pool_set_binding", 2814*0Sstevel@tonic-gate pool_error()); 2815*0Sstevel@tonic-gate } 2816*0Sstevel@tonic-gate 2817*0Sstevel@tonic-gate goto out; 2818*0Sstevel@tonic-gate } 2819*0Sstevel@tonic-gate } 2820*0Sstevel@tonic-gate } 2821*0Sstevel@tonic-gate 2822*0Sstevel@tonic-gate /* 2823*0Sstevel@tonic-gate * The last thing we must do is assume our ID. 2824*0Sstevel@tonic-gate * If the UID is 0, we want it to be privilege-aware, 2825*0Sstevel@tonic-gate * otherwise the limit set gets used instead of E/P. 2826*0Sstevel@tonic-gate * We can do this by setting P as well, which keeps 2827*0Sstevel@tonic-gate * PA status (see priv_can_clear_PA()). 2828*0Sstevel@tonic-gate */ 2829*0Sstevel@tonic-gate 2830*0Sstevel@tonic-gate *fp = "setreuid"; 2831*0Sstevel@tonic-gate if (setreuid(cip->uid, cip->euid != -1 ? cip->euid : cip->uid) != 0) { 2832*0Sstevel@tonic-gate ret = errno; 2833*0Sstevel@tonic-gate assert(ret == EINVAL || ret == EPERM); 2834*0Sstevel@tonic-gate goto out; 2835*0Sstevel@tonic-gate } 2836*0Sstevel@tonic-gate 2837*0Sstevel@tonic-gate *fp = "setppriv"; 2838*0Sstevel@tonic-gate if (cip->priv_set != NULL) { 2839*0Sstevel@tonic-gate if (setppriv(PRIV_SET, PRIV_PERMITTED, cip->priv_set) != 0) { 2840*0Sstevel@tonic-gate ret = errno; 2841*0Sstevel@tonic-gate assert(ret == EFAULT || ret == EPERM); 2842*0Sstevel@tonic-gate goto out; 2843*0Sstevel@tonic-gate } 2844*0Sstevel@tonic-gate } 2845*0Sstevel@tonic-gate 2846*0Sstevel@tonic-gate ret = 0; 2847*0Sstevel@tonic-gate out: 2848*0Sstevel@tonic-gate free(cip->pwbuf); 2849*0Sstevel@tonic-gate cip->pwbuf = NULL; 2850*0Sstevel@tonic-gate return (ret); 2851*0Sstevel@tonic-gate } 2852*0Sstevel@tonic-gate 2853*0Sstevel@tonic-gate void 2854*0Sstevel@tonic-gate restarter_free_method_context(struct method_context *mcp) 2855*0Sstevel@tonic-gate { 2856*0Sstevel@tonic-gate size_t i; 2857*0Sstevel@tonic-gate 2858*0Sstevel@tonic-gate if (mcp->lpriv_set != NULL) 2859*0Sstevel@tonic-gate priv_freeset(mcp->lpriv_set); 2860*0Sstevel@tonic-gate if (mcp->priv_set != NULL) 2861*0Sstevel@tonic-gate priv_freeset(mcp->priv_set); 2862*0Sstevel@tonic-gate 2863*0Sstevel@tonic-gate if (mcp->env != NULL) { 2864*0Sstevel@tonic-gate for (i = 0; i < mcp->env_sz; i++) 2865*0Sstevel@tonic-gate free(mcp->env[i]); 2866*0Sstevel@tonic-gate free(mcp->env); 2867*0Sstevel@tonic-gate } 2868*0Sstevel@tonic-gate 2869*0Sstevel@tonic-gate free(mcp->working_dir); 2870*0Sstevel@tonic-gate free(mcp->corefile_pattern); 2871*0Sstevel@tonic-gate free(mcp->project); 2872*0Sstevel@tonic-gate free(mcp->resource_pool); 2873*0Sstevel@tonic-gate free(mcp); 2874*0Sstevel@tonic-gate } 2875*0Sstevel@tonic-gate 2876*0Sstevel@tonic-gate /* 2877*0Sstevel@tonic-gate * Method keyword functions 2878*0Sstevel@tonic-gate */ 2879*0Sstevel@tonic-gate 2880*0Sstevel@tonic-gate int 2881*0Sstevel@tonic-gate restarter_is_null_method(const char *meth) 2882*0Sstevel@tonic-gate { 2883*0Sstevel@tonic-gate return (strcmp(meth, MKW_TRUE) == 0); 2884*0Sstevel@tonic-gate } 2885*0Sstevel@tonic-gate 2886*0Sstevel@tonic-gate static int 2887*0Sstevel@tonic-gate is_kill_method(const char *method, const char *kill_str, 2888*0Sstevel@tonic-gate size_t kill_str_len) 2889*0Sstevel@tonic-gate { 2890*0Sstevel@tonic-gate const char *cp; 2891*0Sstevel@tonic-gate int sig; 2892*0Sstevel@tonic-gate 2893*0Sstevel@tonic-gate if (strncmp(method, kill_str, kill_str_len) != 0 || 2894*0Sstevel@tonic-gate (method[kill_str_len] != '\0' && 2895*0Sstevel@tonic-gate !isspace(method[kill_str_len]))) 2896*0Sstevel@tonic-gate return (-1); 2897*0Sstevel@tonic-gate 2898*0Sstevel@tonic-gate cp = method + kill_str_len; 2899*0Sstevel@tonic-gate while (*cp != '\0' && isspace(*cp)) 2900*0Sstevel@tonic-gate ++cp; 2901*0Sstevel@tonic-gate 2902*0Sstevel@tonic-gate if (*cp == '\0') 2903*0Sstevel@tonic-gate return (SIGTERM); 2904*0Sstevel@tonic-gate 2905*0Sstevel@tonic-gate if (*cp != '-') 2906*0Sstevel@tonic-gate return (-1); 2907*0Sstevel@tonic-gate 2908*0Sstevel@tonic-gate return (str2sig(cp + 1, &sig) == 0 ? sig : -1); 2909*0Sstevel@tonic-gate } 2910*0Sstevel@tonic-gate 2911*0Sstevel@tonic-gate int 2912*0Sstevel@tonic-gate restarter_is_kill_proc_method(const char *method) 2913*0Sstevel@tonic-gate { 2914*0Sstevel@tonic-gate return (is_kill_method(method, MKW_KILL_PROC, 2915*0Sstevel@tonic-gate sizeof (MKW_KILL_PROC) - 1)); 2916*0Sstevel@tonic-gate } 2917*0Sstevel@tonic-gate 2918*0Sstevel@tonic-gate int 2919*0Sstevel@tonic-gate restarter_is_kill_method(const char *method) 2920*0Sstevel@tonic-gate { 2921*0Sstevel@tonic-gate return (is_kill_method(method, MKW_KILL, sizeof (MKW_KILL) - 1)); 2922*0Sstevel@tonic-gate } 2923*0Sstevel@tonic-gate 2924*0Sstevel@tonic-gate /* 2925*0Sstevel@tonic-gate * Stubs for now. 2926*0Sstevel@tonic-gate */ 2927*0Sstevel@tonic-gate 2928*0Sstevel@tonic-gate /* ARGSUSED */ 2929*0Sstevel@tonic-gate int 2930*0Sstevel@tonic-gate restarter_event_get_enabled(restarter_event_t *e) 2931*0Sstevel@tonic-gate { 2932*0Sstevel@tonic-gate return (-1); 2933*0Sstevel@tonic-gate } 2934*0Sstevel@tonic-gate 2935*0Sstevel@tonic-gate /* ARGSUSED */ 2936*0Sstevel@tonic-gate uint64_t 2937*0Sstevel@tonic-gate restarter_event_get_seq(restarter_event_t *e) 2938*0Sstevel@tonic-gate { 2939*0Sstevel@tonic-gate return (-1); 2940*0Sstevel@tonic-gate } 2941*0Sstevel@tonic-gate 2942*0Sstevel@tonic-gate /* ARGSUSED */ 2943*0Sstevel@tonic-gate void 2944*0Sstevel@tonic-gate restarter_event_get_time(restarter_event_t *e, hrtime_t *time) 2945*0Sstevel@tonic-gate { 2946*0Sstevel@tonic-gate } 2947