dlmgmt_db.c revision b9e076dcc05b713d74073c0d692dfbb0f6f2c594
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER START
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The contents of this file are subject to the terms of the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Common Development and Distribution License (the "License").
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You may not use this file except in compliance with the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * See the License for the specific language governing permissions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and limitations under the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * When distributing Covered Code, include this CDDL HEADER in each
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If applicable, add the following below this CDDL HEADER, with the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * fields enclosed by brackets "[]" replaced with your own identifying
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * information: Portions Copyright [yyyy] [name of copyright owner]
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER END
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Use is subject to license terms.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#pragma ident "%Z%%M% %I% %E% SMI"
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lmtypedef enum dlmgmt_db_op {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppotypedef struct dlmgmt_db_req_s {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* DLMGMT_PERSIST, not both. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * List of pending db updates (e.g., because of a read-only filesystem).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int dlmgmt_process_db_onereq(dlmgmt_db_req_t *, boolean_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void *dlmgmt_db_update_thread(void *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic boolean_t process_link_line(char *, dlmgmt_link_t **);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int process_db_write(dlmgmt_db_req_t *, FILE *, FILE *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int process_db_read(dlmgmt_db_req_t *, FILE *, FILE *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void generate_link_line(dlmgmt_link_t *, boolean_t, char *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator functions to go from dladm_datatype_t to character strings.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Each function takes a pointer to a buffer, the size of the buffer,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the name of the attribute, and the value to be written. The functions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * return the number of bytes written to the buffer. If the buffer is not big
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * enough to hold the string representing the value, then nothing is written
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and 0 is returned.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppotypedef size_t write_func_t(char *, size_t, char *, void *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator functions to read from a NULL terminated string buffer into
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * something of the given DLADM_TYPE_*. The functions each return the number
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * of bytes read from the string buffer. If there is an error reading data
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * from the buffer, then 0 is returned. It is the caller's responsibility
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * to free the data allocated by these functions.
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lmtypedef struct translator_s {
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm const char *type_name;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator functions, defined later but declared here so that
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the translator table can be defined.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic write_func_t write_str, write_boolean, write_uint64;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator table, indexed by dladm_datatype_t.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t ntranslators = sizeof (translators) / sizeof (translator_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Name of the cache file to keep the active <link name, linkid> mapping
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_str(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Strings are assumed to be NULL terminated. In order to fit in
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the buffer, the string's length must be less then buffer_length.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If the value is empty, there's no point in writing it, in fact,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * we shouldn't even see that case.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) ==
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Since we know the string will fit in the buffer, snprintf will
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * always return less than buffer_length, so we can just return
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * whatever snprintf returns.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_boolean(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Booleans are either zero or one, so we only need room for two
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * characters in the buffer.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_uint64(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Limit checking for uint64_t is a little trickier.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ptr == NULL || (len = snprintf(ptr, MAXLINKATTRLEN, "%s", buffer))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Account for NULL terminator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (sizeof (boolean_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (sizeof (int64_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * It is either a persistent request or an active request, not both.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If the return error is EINPROGRESS, this request is handled
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * asynchronously; return success.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If there are already pending "write" requests, queue this request in
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the pending list. Note that this function is called while the
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * dlmgmt_rw_lock is held, so it is safe to access the global variables.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (req->ls_flags != DLMGMT_ACTIVE || errno != ENOENT)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Log the error unless the request processing:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * - is successful;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * - is still in progress;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * - has failed with ENOENT because the active configuration
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * file is not created yet;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "operation on %s configuration failed: %s",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * This can happen at boot when the file system is
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * read-only. So add this request to the pending
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * request list and start a retry thread.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * It is fine if the file keeping active configuration
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * does not exist. This happens during a new reboot.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If this is an update request for the active
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * configuration, create the file.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*ARGSUSED*/
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void *
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The filesystem is still read only. Go to sleep and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * try again.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The filesystem is no longer read only. Continue processing
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and remove the request from the pending list.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char c = buf[i];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Move to the next character if there is no match and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if we have not reached the last character.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * NUL-terminate the string pointed to by 'curr'.
goto parse_fail;
&attr_buf);
if (!found_type)
goto parse_fail;
goto parse_fail;
return (err);
static boolean_t
for (i = 0; i < len; i++) {
return (B_TRUE);
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
return (B_TRUE);
fail:
return (B_FALSE);
int err = 0;
case DLMGMT_DB_OP_WRITE:
case DLMGMT_DB_OP_DELETE:
case DLMGMT_DB_OP_READ:
if (!done)
return (err);
int err = 0;
return (err);
char *ptr;
if (!persist)
goto done;
done:
int err;
return (err);
return (err);
* attributes list based on the configuration file /etc/dladm/datalink.conf
int err;
char *fmri, *c;
if (debug) {
return (EINVAL);
* name is in the form of "service:instance.cache".
c = fmri;
goto done;
* The temporary datalink.conf does not exist. This is
(void) dlmgmt_write_db_entry(
err = 0;
done:
return (err);