static void write_status(restarter_inst_t *inst, const char *mname, int stat) { int r; again: if (inst->ri_mi_deleted) return; r = libscf_write_method_status(inst->ri_m_inst, mname, stat); switch (r) { case 0: break; case ECONNABORTED: libscf_reget_instance(inst); goto again; case ECANCELED: inst->ri_mi_deleted = 1; break; case EPERM: case EACCES: case EROFS: log_framework(LOG_INFO, "Could not write exit status " "for %s method of %s: %s.\n", mname, inst->ri_i.i_fmri, strerror(r)); break; case ENAMETOOLONG: default: bad_error("libscf_write_method_status", r); } }
/* * void method_remove_contract() * Remove any non-permanent contracts from internal structures and * the repository, then abandon them. * Returns * 0 - success * ECANCELED - inst was deleted from the repository * * If the repository connection was broken, it is rebound. */ void method_remove_contract(restarter_inst_t *inst, boolean_t primary, boolean_t abandon) { ctid_t * const ctidp = primary ? &inst->ri_i.i_primary_ctid : &inst->ri_i.i_transient_ctid; int r; assert(*ctidp != 0); log_framework(LOG_DEBUG, "Removing %s contract %lu for %s.\n", primary ? "primary" : "transient", *ctidp, inst->ri_i.i_fmri); if (abandon) contract_abandon(*ctidp); again: if (inst->ri_mi_deleted) { r = ECANCELED; goto out; } r = restarter_remove_contract(inst->ri_m_inst, *ctidp, primary ? RESTARTER_CONTRACT_PRIMARY : RESTARTER_CONTRACT_TRANSIENT); switch (r) { case 0: break; case ECANCELED: inst->ri_mi_deleted = B_TRUE; break; case ECONNABORTED: libscf_handle_rebind(scf_instance_handle(inst->ri_m_inst)); /* FALLTHROUGH */ case EBADF: libscf_reget_instance(inst); goto again; case ENOMEM: case EPERM: case EACCES: case EROFS: log_error(LOG_INFO, "%s: Couldn't remove contract id %ld: " "%s.\n", inst->ri_i.i_fmri, *ctidp, strerror(r)); break; case EINVAL: default: bad_error("restarter_remove_contract", r); } out: if (primary) contract_hash_remove(*ctidp); *ctidp = 0; }
/* * Returns * 0 - success * ECANCELED - pg was deleted * ECONNABORTED - repository disconnected * ENOMEM - out of memory */ int load_pg_attrs(const scf_propertygroup_t *pg, pgroup_t **ipgp) { pgroup_t *ipg; ipg = internal_pgroup_new(); if (scf_pg_get_flags(pg, &ipg->sc_pgroup_flags) != 0) { switch (scf_error()) { case SCF_ERROR_DELETED: internal_pgroup_free(ipg); return (ECANCELED); case SCF_ERROR_CONNECTION_BROKEN: internal_pgroup_free(ipg); return (ECONNABORTED); case SCF_ERROR_NOT_SET: case SCF_ERROR_NOT_BOUND: default: bad_error("scf_pg_get_name", scf_error()); } } if (scf_pg_get_name(pg, loadbuf, loadbuf_sz) < 0) { switch (scf_error()) { case SCF_ERROR_DELETED: internal_pgroup_free(ipg); return (ECANCELED); case SCF_ERROR_CONNECTION_BROKEN: internal_pgroup_free(ipg); return (ECONNABORTED); case SCF_ERROR_NOT_SET: case SCF_ERROR_NOT_BOUND: default: bad_error("scf_pg_get_name", scf_error()); } } ipg->sc_pgroup_name = strdup(loadbuf); if (ipg->sc_pgroup_name == NULL) { internal_pgroup_free(ipg); return (ENOMEM); } if (scf_pg_get_type(pg, loadbuf, loadbuf_sz) < 0) { switch (scf_error()) { case SCF_ERROR_DELETED: free((char *)ipg->sc_pgroup_name); internal_pgroup_free(ipg); return (ECANCELED); case SCF_ERROR_CONNECTION_BROKEN: free((char *)ipg->sc_pgroup_name); internal_pgroup_free(ipg); return (ECONNABORTED); case SCF_ERROR_NOT_SET: case SCF_ERROR_NOT_BOUND: default: bad_error("scf_pg_get_name", scf_error()); } } ipg->sc_pgroup_type = strdup(loadbuf); if (ipg->sc_pgroup_type == NULL) { free((char *)ipg->sc_pgroup_name); internal_pgroup_free(ipg); return (ENOMEM); } *ipgp = ipg; return (0); }
/* * Create a property_t which represents an scf_property_t. Returns * 0 - success * ECANCELED - prop's pg was deleted * ECONNABORTED - repository disconnected * ENOMEM - out of memory * EACCES - permission denied when reading property */ static int load_property(scf_property_t *prop, property_t **ipp) { property_t *iprop; int r; ssize_t ssz; /* get name */ if (scf_property_get_name(prop, loadbuf, loadbuf_sz) < 0) { switch (scf_error()) { case SCF_ERROR_DELETED: return (ECANCELED); case SCF_ERROR_CONNECTION_BROKEN: return (ECONNABORTED); case SCF_ERROR_NOT_BOUND: case SCF_ERROR_NOT_SET: default: bad_error("scf_property_get_name", scf_error()); } } iprop = internal_property_new(); iprop->sc_property_name = strdup(loadbuf); if (iprop->sc_property_name == NULL) { internal_property_free(iprop); return (ENOMEM); } /* get type */ if (scf_property_type(prop, &iprop->sc_value_type) != 0) { switch (scf_error()) { case SCF_ERROR_DELETED: r = ECANCELED; goto out; case SCF_ERROR_CONNECTION_BROKEN: r = ECONNABORTED; goto out; case SCF_ERROR_NOT_BOUND: case SCF_ERROR_NOT_SET: default: bad_error("scf_property_type", scf_error()); } } /* get values */ if (scf_iter_property_values(load_valiter, prop) != 0) { switch (scf_error()) { case SCF_ERROR_DELETED: r = ECANCELED; goto out; case SCF_ERROR_CONNECTION_BROKEN: r = ECONNABORTED; goto out; case SCF_ERROR_HANDLE_MISMATCH: case SCF_ERROR_NOT_BOUND: case SCF_ERROR_NOT_SET: default: bad_error("scf_iter_property_values", scf_error()); } } for (;;) { value_t *ival; r = scf_iter_next_value(load_valiter, load_val); if (r == 0) break; if (r != 1) { switch (scf_error()) { case SCF_ERROR_DELETED: r = ECANCELED; goto out; case SCF_ERROR_CONNECTION_BROKEN: r = ECONNABORTED; goto out; case SCF_ERROR_PERMISSION_DENIED: r = EACCES; goto out; case SCF_ERROR_HANDLE_MISMATCH: case SCF_ERROR_NOT_BOUND: case SCF_ERROR_NOT_SET: case SCF_ERROR_INVALID_ARGUMENT: default: bad_error("scf_iter_next_value", scf_error()); } } ival = internal_value_new(); ival->sc_type = scf_value_type(load_val); assert(ival->sc_type != SCF_TYPE_INVALID); switch (ival->sc_type) { case SCF_TYPE_BOOLEAN: { uint8_t b; r = scf_value_get_boolean(load_val, &b); if (r != 0) bad_error("scf_value_get_boolean", scf_error()); ival->sc_u.sc_count = b; break; } case SCF_TYPE_COUNT: r = scf_value_get_count(load_val, &ival->sc_u.sc_count); if (r != 0) bad_error("scf_value_get_count", scf_error()); break; case SCF_TYPE_INTEGER: r = scf_value_get_integer(load_val, &ival->sc_u.sc_integer); if (r != 0) bad_error("scf_value_get_integer", scf_error()); break; default: ssz = scf_value_get_as_string(load_val, loadbuf, loadbuf_sz); if (ssz < 0) bad_error("scf_value_get_as_string", scf_error()); ival->sc_u.sc_string = strdup(loadbuf); if (ival->sc_u.sc_string == NULL) { r = ENOMEM; goto out; } ival->sc_free = internal_value_free_str; } internal_attach_value(iprop, ival); } *ipp = iprop; return (0); out: free(iprop->sc_property_name); internal_property_free(iprop); return (r); }
/* * Load the instance for fmri from the repository into memory. The * property groups that define the instances pg_patterns and prop_patterns * are also loaded. * * Returns 0 on success and non-zero on failure. */ int load_instance(const char *fmri, const char *name, entity_t **inst_ptr) { entity_t *e = NULL; scf_instance_t *inst; pgroup_t *ipg; int rc; char *type = NULL; ssize_t tsize; assert(inst_ptr != NULL); if ((inst = scf_instance_create(g_hndl)) == NULL) { switch (scf_error()) { case SCF_ERROR_NO_MEMORY: case SCF_ERROR_NO_RESOURCES: rc = EAGAIN; goto errout; default: bad_error("scf_instance_create", scf_error()); } } if (scf_handle_decode_fmri(g_hndl, fmri, NULL, NULL, inst, NULL, NULL, SCF_DECODE_FMRI_EXACT|SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) { switch (scf_error()) { case SCF_ERROR_CONNECTION_BROKEN: rc = ECONNABORTED; goto errout; case SCF_ERROR_DELETED: case SCF_ERROR_NOT_FOUND: rc = ENOENT; goto errout; case SCF_ERROR_INVALID_ARGUMENT: rc = EINVAL; goto errout; case SCF_ERROR_CONSTRAINT_VIOLATED: rc = ENOTSUP; goto errout; default: bad_error("scf_handle_decode_fmri", scf_error()); } } if (scf_iter_instance_pgs_composed(load_pgiter, inst, NULL) != 0) { switch (scf_error()) { case SCF_ERROR_DELETED: rc = ECANCELED; goto errout; case SCF_ERROR_CONNECTION_BROKEN: rc = ECONNABORTED; goto errout; default: bad_error("scf_iter_instance_pgs_composed", scf_error()); } } tsize = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH); type = uu_zalloc(tsize); if (type == NULL) { rc = ENOMEM; goto errout; } /* * Initialize our entity structure. */ e = internal_instance_new(name); if (e == NULL) { rc = ENOMEM; goto errout; } e->sc_fmri = uu_strdup(fmri); if (e->sc_fmri == NULL) { rc = ENOMEM; goto errout; } /* * Walk through the property group's of the instance and capture * the property groups that are of type * SCF_GROUP_TEMPLATE_PG_PATTERN and * SCF_GROUP_TEMPLATE_PROP_PATTERN. In other words grab the * pg_pattern and prop_pattern property groups. */ while ((rc = scf_iter_next_pg(load_pgiter, load_pgroup)) == 1) { if (scf_pg_get_type(load_pgroup, type, tsize) <= 0) { switch (scf_error()) { case SCF_ERROR_DELETED: rc = ENOENT; break; case SCF_ERROR_CONNECTION_BROKEN: rc = ECONNABORTED; break; default: bad_error("scf_pg_get_type", scf_error()); } goto errout; } if ((strcmp(type, SCF_GROUP_TEMPLATE_PG_PATTERN) != 0) && (strcmp(type, SCF_GROUP_TEMPLATE_PROP_PATTERN) != 0)) { continue; } if ((rc = load_pg(load_pgroup, &ipg, fmri, NULL)) != 0) { switch (rc) { case ECANCELED: case ECONNABORTED: case EACCES: case ENOMEM: break; default: bad_error("load_pg", rc); } goto errout; } if (internal_attach_pgroup(e, ipg) != 0) { rc = EBADF; goto errout; } } if (rc == -1) { /* Error in iteration. */ switch (scf_error()) { case SCF_ERROR_CONNECTION_BROKEN: rc = ECONNABORTED; break; case SCF_ERROR_DELETED: rc = ENOENT; break; case SCF_ERROR_NO_RESOURCES: rc = EAGAIN; break; default: bad_error("scf_iter_next_pg", scf_error()); } goto errout; } *inst_ptr = e; scf_instance_destroy(inst); return (0); errout: if (type != NULL) uu_free(type); if (inst != NULL) scf_instance_destroy(inst); if (e != NULL) internal_instance_free(e); return (rc); }
/* * Load a property group into a pgroup_t. Returns * 0 - success * ECANCELED - pg was deleted * ECONNABORTED - repository disconnected * EBADF - pg is corrupt (error printed if fmri is given) * ENOMEM - out of memory * EACCES - permission denied when reading property */ int load_pg(const scf_propertygroup_t *pg, pgroup_t **ipgp, const char *fmri, const char *snapname) { pgroup_t *ipg; int r; if (scf_iter_pg_properties(load_propiter, pg) != 0) { switch (scf_error()) { case SCF_ERROR_DELETED: return (ECANCELED); case SCF_ERROR_CONNECTION_BROKEN: return (ECONNABORTED); case SCF_ERROR_HANDLE_MISMATCH: case SCF_ERROR_NOT_SET: case SCF_ERROR_NOT_BOUND: default: bad_error("scf_iter_pg_properties", scf_error()); } } r = load_pg_attrs(pg, &ipg); switch (r) { case 0: break; case ECANCELED: case ECONNABORTED: case ENOMEM: return (r); default: bad_error("load_pg_attrs", r); } for (;;) { property_t *iprop; r = scf_iter_next_property(load_propiter, load_prop); if (r == 0) break; if (r != 1) { switch (scf_error()) { case SCF_ERROR_DELETED: r = ECANCELED; goto out; case SCF_ERROR_CONNECTION_BROKEN: r = ECONNABORTED; goto out; case SCF_ERROR_HANDLE_MISMATCH: case SCF_ERROR_NOT_BOUND: case SCF_ERROR_NOT_SET: case SCF_ERROR_INVALID_ARGUMENT: default: bad_error("scf_iter_next_property", scf_error()); } } r = load_property(load_prop, &iprop); switch (r) { case 0: break; case ECANCELED: case ECONNABORTED: case ENOMEM: case EACCES: goto out; default: bad_error("load_property", r); } r = internal_attach_property(ipg, iprop); if (r != 0) { if (fmri != NULL) { if (snapname == NULL) warn(gettext("Property group \"%s\" of " "%s has multiple definitions of " "property \"%s\".\n"), ipg->sc_pgroup_name, fmri, iprop->sc_property_name); else warn(gettext("Property group \"%s\" of " "the \"%s\" snapshot of %s has " "multiple definitions of property " "\"%s\".\n"), ipg->sc_pgroup_name, snapname, fmri, iprop->sc_property_name); } r = EBADF; goto out; } } *ipgp = ipg; return (0); out: internal_pgroup_free(ipg); return (r); }
word get_next_word(char* buffer, int* it, int bufSize, int* lineNum) { word w; // deal with END if (*it == bufSize) { w.type = END; return w; } // remove beginning whitespace while (buffer[*it] == ' ' || buffer[*it] == '\t') { (*it)++; if (*it == bufSize) { w.type = END; return w; } } // deal with single-char tokens, ; | ( ) < > # // don't need to update string component of the word bc we don't use it char c = buffer[*it]; switch (c) { case ';': w.type = SEMICOLON; w.string = ";"; (*it) = (*it) + 1; return w; case '|': w.type = PIPE; w.string = "|"; (*it) = (*it) + 1; return w; case '(': w.type = LPARENS; w.string = "("; (*it) = (*it) + 1; return w; case ')': w.type = RPARENS; w.string = ")"; (*it) = (*it) + 1; return w; case '<': w.type = INPUT; w.string = "<"; (*it) = (*it) + 1; return w; case '>': w.type = OUTPUT; w.string = ">"; (*it) = (*it) + 1; return w; case '\n': w.type = NEWLINE; w.string = "\n"; (*lineNum) = (*lineNum) + 1; (*it) = (*it) + 1; return w; case '#': w.type = COMMENT; w.string = "#"; while (*it < bufSize && buffer[*it] != '\n') (*it) = (*it) + 1; if (*it != bufSize) { (*it) = (*it) + 1; // move past new line, point to start of next word (*lineNum) = (*lineNum) + 1; } return w; default: break; } // deal with words int wordLen = 64; w.string = (char*)checked_malloc(sizeof(char)*wordLen); // create string int stringIndex = 0; while (buffer[*it] != ' ' && buffer[*it] != '\t' && buffer[*it] != '\n' && buffer[*it] != ';' && buffer[*it] != '|' && buffer[*it] != '(' && buffer[*it] != ')' && buffer[*it] != '<' && buffer[*it] != '>' && *it != bufSize) { if (stringIndex == wordLen) { wordLen = wordLen*2; size_t size_size = sizeof(char)*wordLen; w.string = (char*)checked_grow_alloc((void*)w.string, &(size_size)); } if (!(isalpha(buffer[*it]) || isdigit(buffer[*it]) || buffer[*it]=='!' || buffer[*it]=='%' || buffer[*it]=='+' || buffer[*it]==',' || buffer[*it]=='-' || buffer[*it]=='.' || buffer[*it]=='/' || buffer[*it]==':' || buffer[*it]=='@' || buffer[*it]=='^' || buffer[*it]=='_' )) bad_error(lineNum, __LINE__); w.string[stringIndex] = buffer[*it]; (*it) = (*it) + 1; stringIndex++; } w.string[stringIndex] = '\0'; // assign special words if (strcmp(w.string, "if") == 0) { w.type = IF; w.string = "IF"; return w; } else if (strcmp(w.string, "then") == 0) { w.type = THEN; w.string = "THEN"; return w; } else if (strcmp(w.string, "else") == 0) { w.type = ELSE; w.string = "ELSE"; return w; } else if (strcmp(w.string, "fi") == 0) { w.type = FI; w.string = "FI"; return w; } else if (strcmp(w.string, "while") == 0) { w.type = WHILE; w.string = "WHILE"; return w; } else if (strcmp(w.string, "until") == 0) { w.type = UNTIL; w.string = "UNTIL"; return w; } else if (strcmp(w.string, "do") == 0) { w.type = DO; w.string = "DO"; return w; } else if (strcmp(w.string, "done") == 0) { w.type = DONE; w.string = "DONE"; return w; } else { w.type = SIMPLE; return w; } }
int get_command(char* buffer, int* it, int bufSize, command_t com, int* lineNum) { word next_word = get_next_word(buffer, it, bufSize, lineNum); com->status = -1; command_t newCom = checked_malloc(sizeof(struct command)); switch (next_word.type) { case IF: com->type = IF_COMMAND; // IF com->u.command[0] = newCom; if (get_command(buffer, it, bufSize, newCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type == NEWLINE) { next_word = get_next_word(buffer, it, bufSize, lineNum); } // THEN if (next_word.type == THEN) { command_t thenCom = checked_malloc(sizeof(struct command)); com->u.command[1] = thenCom; if (get_command(buffer, it, bufSize, thenCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type == NEWLINE) { next_word = get_next_word(buffer, it, bufSize, lineNum); } // ELSE if (next_word.type == ELSE) { command_t elseCom = checked_malloc(sizeof(struct command)); com->u.command[2] = elseCom; if (get_command(buffer, it, bufSize, elseCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type == NEWLINE) { next_word = get_next_word(buffer, it, bufSize, lineNum); } // FI AFTER ELSE if (next_word.type == FI) return 1; else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } // NO ELSE - STRAIGHT TO FI else if (next_word.type == FI) return 1; else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); case WHILE: ; int w = 1; com->type = WHILE_COMMAND; // WHILE command_t whileCom = checked_malloc(sizeof(struct command)); whileCom->type = SEQUENCE_COMMAND; command_t whileWhileCom = whileCom; whileCom->u.command[0] = newCom; while (get_command(buffer, it, bufSize, newCom, lineNum)) { int s = *it; int* whileIt = &(s); next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type != DO) { whileCom->type = SEQUENCE_COMMAND; whileCom->u.command[1] = checked_malloc(sizeof(struct command)); newCom = whileCom->u.command[1]; whileCom = whileCom->u.command[1]; *it = *whileIt; w++; } else { if (w == 1) com->u.command[0] = whileWhileCom->u.command[0]; else com->u.command[0] = whileWhileCom; command_t doCom = checked_malloc(sizeof(struct command)); com->u.command[1] = doCom; if (get_command(buffer, it, bufSize, doCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type == NEWLINE) { next_word = get_next_word(buffer, it, bufSize, lineNum); } // DONE if (next_word.type == DONE) { // can't have another command after done int v = *it; int* doneIt = &(v); next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == SEMICOLON || next_word.type == INPUT || next_word.type == OUTPUT || next_word.type == END) { *it = *doneIt; return generate_from_simple(com, 0, buffer, it, bufSize, com, lineNum); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } } bad_error(lineNum, __LINE__); return 0; case UNTIL: ; int u = 1; com->type = UNTIL_COMMAND; // UNTIL command_t untilCom = checked_malloc(sizeof(struct command)); untilCom->type = SEQUENCE_COMMAND; command_t untilUntilCom = untilCom; untilCom->u.command[0] = newCom; while (get_command(buffer, it, bufSize, newCom, lineNum)) { int t = *it; int* untilIt = &(t); next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type != DO) { untilCom->type = SEQUENCE_COMMAND; untilCom = untilCom->u.command[1]; untilCom = newCom; *it = *untilIt; u++; } else { if (u == 1) com->u.command[0] = untilUntilCom->u.command[0]; else com->u.command[0] = untilUntilCom; command_t udoCom = checked_malloc(sizeof(struct command)); com->u.command[1] = udoCom; if (get_command(buffer, it, bufSize, udoCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type == NEWLINE) { next_word = get_next_word(buffer, it, bufSize, lineNum); } // DONE if (next_word.type == DONE) { // can't have another command after done int z = *it; int* udoneIt = &(z); next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == SEMICOLON || next_word.type == INPUT || next_word.type == OUTPUT || next_word.type == END) { *it = *udoneIt; return generate_from_simple(com, 0, buffer, it, bufSize, com, lineNum); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); } } bad_error(lineNum, __LINE__); return 0; case LPARENS: com->type = SUBSHELL_COMMAND; if (get_command(buffer, it, bufSize, newCom, lineNum)) { next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == RPARENS) { com->u.command[0] = newCom; return 1; } else bad_error(lineNum, __LINE__); } else bad_error(lineNum, __LINE__); case COMMENT: case NEWLINE: return get_command(buffer, it, bufSize, com, lineNum); case SEMICOLON: bad_error(lineNum, __LINE__); return 0; case END: return 0; case SIMPLE: ; // make temporary command command_t tempCom = checked_malloc(sizeof(struct command)); tempCom->type = SIMPLE_COMMAND; //TODO FIX ALLOCATION MAYBE (number of words) tempCom->u.word = checked_malloc(sizeof(char*)*256); int word_len = strlen(next_word.string); tempCom->u.word[0] = checked_malloc(sizeof(char)*word_len); tempCom->u.word[0] = next_word.string; int word_count = 1; return generate_from_simple(tempCom, word_count, buffer, it, bufSize, com, lineNum); case THEN: case ELSE: case FI: case DO: case DONE: default: bad_error(lineNum, __LINE__); return 0; } }
int generate_from_simple(command_t tempCom, int word_count, char* buffer, int* it, int bufSize, command_t com, int* lineNum) { word next_word = get_next_word(buffer, it, bufSize, lineNum); //command_t newCom = checked_malloc(sizeof(struct command)); switch(next_word.type) { case PIPE: com->type = PIPE_COMMAND; com->u.command[0] = checked_malloc(sizeof(struct command)); *(com->u.command[0]) = *tempCom; command_t secondCom = checked_malloc(sizeof(struct command)); if (get_command(buffer, it, bufSize, secondCom, lineNum)) { com->u.command[1] = checked_malloc(sizeof(struct command)); *(com->u.command[1]) = *secondCom; return 1; } else bad_error(lineNum, __LINE__); case SEMICOLON: ; int s = *it; int* seqIt = &(s); next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == END || next_word.type == THEN || next_word.type == ELSE || next_word.type == DO || next_word.type == DONE || next_word.type == FI) { *it = *seqIt; *com = *tempCom; return 1; } else { com->type = SEQUENCE_COMMAND; com->u.command[0] = tempCom; command_t secondCom = checked_malloc(sizeof(struct command)); get_command(buffer, seqIt, bufSize, secondCom, lineNum); com->u.command[1] = secondCom; *it = *seqIt; return 1; } case LPARENS: // NOTE: subshells cannot be a part of simple commands in bash so disregard // tempCom->u.word[1] = checked_malloc(sizeof(char)*128); // next_word = get_next_word(buffer, it, bufSize, lineNum); // char* tempString = checked_malloc(sizeof(char)*128); // tempString = next_word.string; // while (next_word.type != RPARENS) { // next_word = get_next_word(buffer, it, bufSize, lineNum); // strcat(tempString, next_word.string); // if (next_word.type == NEWLINE || next_word.type == END || // next_word.type == PIPE || next_word.type == LPARENS) // { // bad_error(lineNum, __LINE__); // return 0; // } // } // strcat(tempString, next_word.string); // *(tempCom->u.word[1]) = *tempString; // *com = *tempCom; // return 1; bad_error(lineNum, __LINE__); return 0; case RPARENS: *it = (*it)-1; *com = *tempCom; return 1; case INPUT: next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == SEMICOLON || next_word.type == END || next_word.type == PIPE || next_word.type == LPARENS || next_word.type == RPARENS || next_word.type == INPUT || next_word.type == OUTPUT) { bad_error(lineNum, __LINE__); return 0; } tempCom->input = next_word.string; int t = *it; int* inIt = &(t); next_word = get_next_word(buffer, inIt, bufSize, lineNum); if (next_word.type == OUTPUT) { next_word = get_next_word(buffer, inIt, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == SEMICOLON || next_word.type == END || next_word.type == PIPE || next_word.type == LPARENS || next_word.type == RPARENS || next_word.type == INPUT || next_word.type == OUTPUT) { bad_error(lineNum, __LINE__); return 0; } tempCom->output = next_word.string; *it = *inIt; } return generate_from_simple(tempCom, word_count, buffer, it, bufSize, com, lineNum); case OUTPUT: next_word = get_next_word(buffer, it, bufSize, lineNum); if (next_word.type == NEWLINE || next_word.type == SEMICOLON || next_word.type == END || next_word.type == PIPE || next_word.type == LPARENS || next_word.type == RPARENS || next_word.type == INPUT || next_word.type == OUTPUT) { bad_error(lineNum, __LINE__); return 0; } tempCom->output = next_word.string; return generate_from_simple(tempCom, word_count, buffer, it, bufSize, com, lineNum); case COMMENT: next_word = get_next_word(buffer, it, bufSize, lineNum); while (next_word.type != NEWLINE && next_word.type != END) { next_word = get_next_word(buffer, it, bufSize, lineNum); } return 1; case NEWLINE: case END: *com = *tempCom; return 1; case SIMPLE: ; int word_len = strlen(next_word.string); tempCom->u.word[word_count] = checked_malloc(sizeof(char)*word_len); strcpy(tempCom->u.word[word_count], next_word.string); *com = *tempCom; word_count++; return generate_from_simple(tempCom, word_count, buffer, it, bufSize, com, lineNum); case IF: case THEN: case ELSE: case FI: case WHILE: case DO: case DONE: case UNTIL: default: bad_error(lineNum, __LINE__); return 0; } }
/* * The method thread executes a service method to effect a state transition. * The next_state of info->sf_id should be non-_NONE on entrance, and it will * be _NONE on exit (state will either be what next_state was (on success), or * it will be _MAINT (on error)). * * There are six classes of methods to consider: start & other (stop, refresh) * for each of "normal" services, wait services, and transient services. For * each, the method must be fetched from the repository & executed. fork()ed * methods must be waited on, except for the start method of wait services * (which must be registered with the wait subsystem via wait_register()). If * the method succeeded (returned 0), then for start methods its contract * should be recorded as the primary contract for the service. For other * methods, it should be abandoned. If the method fails, then depending on * the failure, either the method should be reexecuted or the service should * be put into maintenance. Either way the contract should be abandoned. */ void * method_thread(void *arg) { fork_info_t *info = arg; restarter_inst_t *inst; scf_handle_t *local_handle; scf_instance_t *s_inst = NULL; int r, exit_code; boolean_t retryable; const char *aux; assert(0 <= info->sf_method_type && info->sf_method_type <= 2); /* Get (and lock) the restarter_inst_t. */ inst = inst_lookup_by_id(info->sf_id); assert(inst->ri_method_thread != 0); assert(instance_in_transition(inst) == 1); /* * We cannot leave this function with inst in transition, because * protocol.c withholds messages for inst otherwise. */ log_framework(LOG_DEBUG, "method_thread() running %s method for %s.\n", method_names[info->sf_method_type], inst->ri_i.i_fmri); local_handle = libscf_handle_create_bound_loop(); rebind_retry: /* get scf_instance_t */ switch (r = libscf_fmri_get_instance(local_handle, inst->ri_i.i_fmri, &s_inst)) { case 0: break; case ECONNABORTED: libscf_handle_rebind(local_handle); goto rebind_retry; case ENOENT: /* * It's not there, but we need to call this so protocol.c * doesn't think it's in transition anymore. */ (void) restarter_instance_update_states(local_handle, inst, inst->ri_i.i_state, RESTARTER_STATE_NONE, RERR_NONE, NULL); goto out; case EINVAL: case ENOTSUP: default: bad_error("libscf_fmri_get_instance", r); } inst->ri_m_inst = s_inst; inst->ri_mi_deleted = B_FALSE; retry: if (info->sf_method_type == METHOD_START) log_transition(inst, START_REQUESTED); r = method_run(&inst, info->sf_method_type, &exit_code); if (r == 0 && exit_code == 0) { /* Success! */ assert(inst->ri_i.i_next_state != RESTARTER_STATE_NONE); /* * When a stop method succeeds, remove the primary contract of * the service, unless we're going to offline, in which case * retain the contract so we can transfer inherited contracts to * the replacement service. */ if (info->sf_method_type == METHOD_STOP && inst->ri_i.i_primary_ctid != 0) { if (inst->ri_i.i_next_state == RESTARTER_STATE_OFFLINE) inst->ri_i.i_primary_ctid_stopped = 1; else method_remove_contract(inst, B_TRUE, B_TRUE); } /* * We don't care whether the handle was rebound because this is * the last thing we do with it. */ (void) restarter_instance_update_states(local_handle, inst, inst->ri_i.i_next_state, RESTARTER_STATE_NONE, info->sf_event_type, NULL); (void) update_fault_count(inst, FAULT_COUNT_RESET); goto out; } /* Failure. Retry or go to maintenance. */ if (r != 0 && r != EAGAIN) { retryable = B_FALSE; } else { switch (exit_code) { case SMF_EXIT_ERR_CONFIG: case SMF_EXIT_ERR_NOSMF: case SMF_EXIT_ERR_PERM: case SMF_EXIT_ERR_FATAL: retryable = B_FALSE; break; default: retryable = B_TRUE; } } if (retryable && update_fault_count(inst, FAULT_COUNT_INCR) != 1) goto retry; /* maintenance */ if (r == ELOOP) log_transition(inst, START_FAILED_REPEATEDLY); else if (r == ERANGE) log_transition(inst, START_FAILED_TIMEOUT_FATAL); else if (exit_code == SMF_EXIT_ERR_CONFIG) log_transition(inst, START_FAILED_CONFIGURATION); else if (exit_code == SMF_EXIT_ERR_FATAL) log_transition(inst, START_FAILED_FATAL); else log_transition(inst, START_FAILED_OTHER); if (r == ELOOP) aux = "restarting_too_quickly"; else if (retryable) aux = "fault_threshold_reached"; else aux = "method_failed"; (void) restarter_instance_update_states(local_handle, inst, RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, RERR_FAULT, (char *)aux); if (!method_is_transient(inst, info->sf_method_type) && inst->ri_i.i_primary_ctid != 0) method_remove_contract(inst, B_TRUE, B_TRUE); out: inst->ri_method_thread = 0; MUTEX_UNLOCK(&inst->ri_lock); (void) pthread_cond_broadcast(&inst->ri_method_cv); scf_instance_destroy(s_inst); scf_handle_destroy(local_handle); startd_free(info, sizeof (fork_info_t)); return (NULL); }
/* * int method_ready_contract(restarter_inst_t *, int, method_restart_t, int) * * Activate a contract template for the type method of inst. type, * restart_on, and cte_mask dictate the critical events term of the contract. * Returns * 0 - success * ECANCELED - inst has been deleted from the repository */ static int method_ready_contract(restarter_inst_t *inst, int type, method_restart_t restart_on, uint_t cte_mask) { int tmpl, err, istrans, iswait, ret; uint_t cevents, fevents; /* * Correctly supporting wait-style services is tricky without * rearchitecting startd to cope with multiple event sources * simultaneously trying to stop an instance. Until a better * solution is implemented, we avoid this problem for * wait-style services by making contract events fatal and * letting the wait code alone handle stopping the service. */ iswait = instance_is_wait_style(inst); istrans = method_is_transient(inst, type); tmpl = open64(CTFS_ROOT "/process/template", O_RDWR); if (tmpl == -1) uu_die("Could not create contract template"); /* * We assume non-login processes are unlikely to create * multiple process groups, and set CT_PR_PGRPONLY for all * wait-style services' contracts. */ err = ct_pr_tmpl_set_param(tmpl, CT_PR_INHERIT | CT_PR_REGENT | (iswait ? CT_PR_PGRPONLY : 0)); assert(err == 0); if (istrans) { cevents = 0; fevents = 0; } else { assert(restart_on >= 0); assert(restart_on <= METHOD_RESTART_ANY_FAULT); cevents = method_events[restart_on] & ~cte_mask; fevents = iswait ? (method_events[restart_on] & ~cte_mask & CT_PR_ALLFATAL) : 0; } err = ct_tmpl_set_critical(tmpl, cevents); assert(err == 0); err = ct_tmpl_set_informative(tmpl, 0); assert(err == 0); err = ct_pr_tmpl_set_fatal(tmpl, fevents); assert(err == 0); err = ct_tmpl_set_cookie(tmpl, istrans ? METHOD_OTHER_COOKIE : METHOD_START_COOKIE); assert(err == 0); if (type == METHOD_START && inst->ri_i.i_primary_ctid != 0) { ret = ct_pr_tmpl_set_transfer(tmpl, inst->ri_i.i_primary_ctid); switch (ret) { case 0: break; case ENOTEMPTY: /* No contracts for you! */ method_remove_contract(inst, B_TRUE, B_TRUE); if (inst->ri_mi_deleted) { ret = ECANCELED; goto out; } break; case EINVAL: case ESRCH: case EACCES: default: bad_error("ct_pr_tmpl_set_transfer", ret); } } err = ct_tmpl_activate(tmpl); assert(err == 0); ret = 0; out: err = close(tmpl); assert(err == 0); return (ret); }
/* * void method_store_contract() * Store the newly created contract id into local structures and * the repository. If the repository connection is broken it is rebound. */ static void method_store_contract(restarter_inst_t *inst, int type, ctid_t *cid) { int r; boolean_t primary; if (errno = contract_latest(cid)) uu_die("%s: Couldn't get new contract's id", inst->ri_i.i_fmri); primary = !method_is_transient(inst, type); if (!primary) { if (inst->ri_i.i_transient_ctid != 0) { log_framework(LOG_INFO, "%s: transient ctid expected to be 0 but " "was set to %ld\n", inst->ri_i.i_fmri, inst->ri_i.i_transient_ctid); } inst->ri_i.i_transient_ctid = *cid; } else { if (inst->ri_i.i_primary_ctid != 0) { /* * There was an old contract that we transferred. * Remove it. */ method_remove_contract(inst, B_TRUE, B_FALSE); } if (inst->ri_i.i_primary_ctid != 0) { log_framework(LOG_INFO, "%s: primary ctid expected to be 0 but " "was set to %ld\n", inst->ri_i.i_fmri, inst->ri_i.i_primary_ctid); } inst->ri_i.i_primary_ctid = *cid; inst->ri_i.i_primary_ctid_stopped = 0; contract_hash_store(*cid, inst->ri_id); } again: if (inst->ri_mi_deleted) return; r = restarter_store_contract(inst->ri_m_inst, *cid, primary ? RESTARTER_CONTRACT_PRIMARY : RESTARTER_CONTRACT_TRANSIENT); switch (r) { case 0: break; case ECANCELED: inst->ri_mi_deleted = B_TRUE; break; case ECONNABORTED: libscf_handle_rebind(scf_instance_handle(inst->ri_m_inst)); /* FALLTHROUGH */ case EBADF: libscf_reget_instance(inst); goto again; case ENOMEM: case EPERM: case EACCES: case EROFS: uu_die("%s: Couldn't store contract id %ld", inst->ri_i.i_fmri, *cid); /* NOTREACHED */ case EINVAL: default: bad_error("restarter_store_contract", r); } }
/*ARGSUSED*/ void * wait_thread(void *args) { for (;;) { port_event_t pe; int fd; wait_info_t *wi; if (port_get(port_fd, &pe, NULL) != 0) { if (errno == EINTR) continue; else { log_error(LOG_WARNING, "port_get() failed with %s\n", strerror(errno)); bad_error("port_get", errno); } } fd = pe.portev_object; wi = pe.portev_user; assert(wi != NULL); assert(fd == wi->wi_fd); if ((pe.portev_events & POLLHUP) == POLLHUP) { psinfo_t psi; if (lseek(fd, 0, SEEK_SET) != 0 || read(fd, &psi, sizeof (psinfo_t)) != sizeof (psinfo_t)) { log_framework(LOG_WARNING, "couldn't get psinfo data for %s (%s); " "assuming failed\n", wi->wi_fmri, strerror(errno)); goto err_remove; } if (psi.pr_nlwp != 0 || psi.pr_nzomb != 0 || psi.pr_lwp.pr_lwpid != 0) { /* * We have determined, in accordance with the * definition in proc(4), this process is not a * zombie. Reassociate. */ if (port_associate(port_fd, PORT_SOURCE_FD, fd, 0, wi)) log_error(LOG_WARNING, "port_association of %d / %s " "failed\n", fd, wi->wi_fmri); continue; } } else if ( (pe.portev_events & POLLERR) == 0) { if (port_associate(port_fd, PORT_SOURCE_FD, fd, 0, wi)) log_error(LOG_WARNING, "port_association of %d / %s " "failed\n", fd, wi->wi_fmri); continue; } err_remove: wait_remove(wi, 0); } /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/ }
int engine_import(uu_list_t *args) { int ret, argc, i, o; bundle_t *b; char *file, *pname; uchar_t hash[MHASH_SIZE]; char **argv; string_list_t *slp; boolean_t verify = B_FALSE; uint_t flags = SCI_GENERALLAST; argc = uu_list_numnodes(args); if (argc < 1) return (-2); argv = calloc(argc + 1, sizeof (char *)); if (argv == NULL) uu_die(gettext("Out of memory.\n")); for (slp = uu_list_first(args), i = 0; slp != NULL; slp = uu_list_next(args, slp), ++i) argv[i] = slp->str; argv[i] = NULL; opterr = 0; optind = 0; /* Remember, no argv[0]. */ for (;;) { o = getopt(argc, argv, "nV"); if (o == -1) break; switch (o) { case 'n': flags |= SCI_NOREFRESH; break; case 'V': verify = B_TRUE; break; case '?': free(argv); return (-2); default: bad_error("getopt", o); } } argc -= optind; if (argc != 1) { free(argv); return (-2); } file = argv[optind]; free(argv); lscf_prep_hndl(); ret = mhash_test_file(g_hndl, file, 0, &pname, hash); if (ret != MHASH_NEWFILE) return (ret); /* Load */ b = internal_bundle_new(); if (lxml_get_bundle_file(b, file, 0) != 0) { internal_bundle_free(b); return (-1); } /* Import */ if (lscf_bundle_import(b, file, flags) != 0) { internal_bundle_free(b); return (-1); } internal_bundle_free(b); if (g_verbose) warn(gettext("Successful import.\n")); if (pname) { char *errstr; if (mhash_store_entry(g_hndl, pname, hash, &errstr)) { if (errstr) semerr(errstr); else semerr(gettext("Unknown error from " "mhash_store_entry()\n")); } free(pname); } /* Verify */ if (verify) warn(gettext("import -V not implemented.\n")); return (0); }