dlmgmt_db.c revision 0dc974a9a2e66d676505db23524ebff105fb36a9
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * CDDL HEADER START
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The contents of this file are subject to the terms of the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Common Development and Distribution License (the "License").
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * You may not use this file except in compliance with the License.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * See the License for the specific language governing permissions
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * and limitations under the License.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * When distributing Covered Code, include this CDDL HEADER in each
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If applicable, add the following below this CDDL HEADER, with the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * fields enclosed by brackets "[]" replaced with your own identifying
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * information: Portions Copyright [yyyy] [name of copyright owner]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * CDDL HEADER END
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Use is subject to license terms.
d62bc4badc1c1f1549c961cfb8b420e650e1272byztypedef enum dlmgmt_db_op {
d62bc4badc1c1f1549c961cfb8b420e650e1272byztypedef struct dlmgmt_db_req_s {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* DLMGMT_PERSIST, not both. */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * List of pending db updates (e.g., because of a read-only filesystem).
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t,
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void *dlmgmt_db_update_thread(void *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic boolean_t process_link_line(char *, dlmgmt_link_t **);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic int process_db_read(dlmgmt_db_req_t *, FILE *, FILE *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void generate_link_line(dlmgmt_link_t *, boolean_t, char *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Translator functions to go from dladm_datatype_t to character strings.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Each function takes a pointer to a buffer, the size of the buffer,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the name of the attribute, and the value to be written. The functions
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * return the number of bytes written to the buffer. If the buffer is not big
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * enough to hold the string representing the value, then nothing is written
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * and 0 is returned.
d62bc4badc1c1f1549c961cfb8b420e650e1272byztypedef size_t write_func_t(char *, size_t, char *, void *);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Translator functions to read from a NULL terminated string buffer into
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * something of the given DLADM_TYPE_*. The functions each return the number
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * of bytes read from the string buffer. If there is an error reading data
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * from the buffer, then 0 is returned. It is the caller's responsibility
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * to free the data allocated by these functions.
d62bc4badc1c1f1549c961cfb8b420e650e1272byztypedef struct translator_s {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz const char *type_name;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Translator functions, defined later but declared here so that
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the translator table can be defined.
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic write_func_t write_str, write_boolean, write_uint64;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Translator table, indexed by dladm_datatype_t.
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic size_t ntranslators = sizeof (translators) / sizeof (translator_t);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Name of the cache file to keep the active <link name, linkid> mapping
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
d62bc4badc1c1f1549c961cfb8b420e650e1272byzwrite_str(char *buffer, size_t buffer_length, char *name, void *value)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Strings are assumed to be NULL terminated. In order to fit in
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the buffer, the string's length must be less then buffer_length.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If the value is empty, there's no point in writing it, in fact,
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * we shouldn't even see that case.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) ==
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Since we know the string will fit in the buffer, snprintf will
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * always return less than buffer_length, so we can just return
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * whatever snprintf returns.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s",
d62bc4badc1c1f1549c961cfb8b420e650e1272byzwrite_boolean(char *buffer, size_t buffer_length, char *name, void *value)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Booleans are either zero or one, so we only need room for two
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * characters in the buffer.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d",
d62bc4badc1c1f1549c961cfb8b420e650e1272byzwrite_uint64(char *buffer, size_t buffer_length, char *name, void *value)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Limit checking for uint64_t is a little trickier.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld",
024b0a258461f282a92b1b1283c3b8b083f9f33fseb if (ptr == NULL || (len = strlcpy(ptr, buffer, MAXLINKATTRVALLEN))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz /* Account for NULL terminator */
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (sizeof (boolean_t));
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (sizeof (int64_t));
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * It is either a persistent request or an active request, not both.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If the return error is EINPROGRESS, this request is handled
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * asynchronously; return success.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If there are already pending "write" requests, queue this request in
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the pending list. Note that this function is called while the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * dlmgmt_rw_lock is held, so it is safe to access the global variables.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Log the error unless the request processing:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * - is successful;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * - is still in progress;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * - has failed with ENOENT because the active configuration
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * file is not created yet;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz "operation on %s configuration failed: %s",
d62bc4badc1c1f1549c961cfb8b420e650e1272byz err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL);
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * This can happen at boot when the file system is
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * read-only. So add this request to the pending
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * request list and start a retry thread.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * It is fine if the file keeping active configuration
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * does not exist. This happens during a new reboot.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If this is an update request for the active
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * configuration, create the file.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz/*ARGSUSED*/
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void *
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The filesystem is still read only. Go to sleep and
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * try again.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The filesystem is no longer read only. Continue processing
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * and remove the request from the pending list.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz char c = buf[i];
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Move to the next character if there is no match and
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * if we have not reached the last character.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * NUL-terminate the string pointed to by 'curr'.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * We get here after we have processed the "<prop>="
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * pattern. The pattern we are now interested in is
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * "<val>;".
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (c == '=')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Non-zero length attr_name and found_type of false
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * indicates that we have not found the type for this
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * attribute. The pattern now is "<type>,<val>;", we
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * want the <type> part of the pattern.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * A zero length attr_name indicates we are looking
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * at the beginning of a link attribute.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (c != '=')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (-1);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Use a copy of buf for parsing so that we can do whatever we want.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Skip leading spaces, blank lines, and comments.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz for (i = 0; i < len; i++) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Find the link id and assign it to the link structure.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Now find the list of link properties.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Delete corrupted line.
d62bc4badc1c1f1549c961cfb8b420e650e1272byzprocess_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * find the link in the avl tree with the given linkid.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * This link has already been changed. This could
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * happen if the request is pending because of
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * read-only file-system. If so, we are done.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
0dc974a9a2e66d676505db23524ebff105fb36a9Cathy Zhou * this is a comment line or we are done updating the
0dc974a9a2e66d676505db23524ebff105fb36a9Cathy Zhou * link of the given link, write the rest of lines out.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * For write operations, if the linkid of the link
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * read from the file does not match the id of what
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * req->ll_linkid points to, write out the buffer.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Otherwise, generate a new line. If we get to the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * end and have not seen what req->ll_linkid points
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * to, write it out then.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Delete is simple. If buf does not represent the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * link we're deleting, write it out.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If we get to the end of the file and have not seen what
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * req->ll_linkid points to, write it out then.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz generate_link_line(linkp, req->ls_flags == DLMGMT_PERSIST, buf);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz/* ARGSUSED1 */
d62bc4badc1c1f1549c961cfb8b420e650e1272byzprocess_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * This loop processes each line of the configuration file.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Skip the comment line.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz linkp1 = avl_find(&dlmgmt_name_avl, link_in_file, &name_where);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz linkp2 = avl_find(&dlmgmt_id_avl, link_in_file, &id_where);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * If any of the following conditions are met, this is
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * a duplicate entry:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 1. link2 (with the given name) and link2 (with the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * given id) are not the same link;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 2. This is a persistent req and find the link with
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the given name and id. Note that persistent db
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * is read before the active one.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * 3. Found the link with the given name and id but
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the link is already active.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz "entries in repository: link name %s "
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Generate an entry in the link database.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Each entry has this format:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * <link id> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
d62bc4badc1c1f1549c961cfb8b420e650e1272byzstatic void
d62bc4badc1c1f1549c961cfb8b420e650e1272byzgenerate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ptr += snprintf(ptr, BUFLEN(lim, ptr), "%d\t", id_to_write);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ptr += write_str(ptr, BUFLEN(lim, ptr), "name", name_to_write);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The daemon does not keep any active link attribute. If this request
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * is for active configuration, we are done.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz for (cur_p = linkp->ll_head; cur_p != NULL; cur_p = cur_p->lp_next) {
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdlmgmt_delete_db_entry(datalink_id_t linkid, uint32_t flags)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkid, flags));
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return (0);
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * Initialize the datalink <link name, linkid> mapping and the link's
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * attributes list based on the configuration file /etc/dladm/datalink.conf
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * and the active configuration cache file
b9e076dcc05b713d74073c0d692dfbb0f6f2c594yz * /etc/svc/volatile/dladm/datalink-management:default.cache.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * This function is called when the datalink-management service is started
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * during reboot, and when the dlmgmtd daemon is restarted.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz char *fmri, *c;
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * First derive the name of the cache file from the FMRI name. This
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * cache name is used to keep active datalink configuration.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz "service and should not be run from the command "
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The FMRI name is in the form of
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * svc:/service/service:instance. We need to remove the
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * prefix "svc:/" and replace '/' with '-'. The cache file
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * name is in the form of "service:instance.cache".
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if (*c == '/')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * The temporary datalink.conf does not exist. This is
d62bc4badc1c1f1549c961cfb8b420e650e1272byz * the first boot. Mark all the physical links active.