dlmgmt_db.c revision b9e076dcc05b713d74073c0d692dfbb0f6f2c594
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER START
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *
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 *
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * or http://www.opensolaris.org/os/licensing.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * See the License for the specific language governing permissions
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and limitations under the License.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *
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 *
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * CDDL HEADER END
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Use is subject to license terms.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#pragma ident "%Z%%M% %I% %E% SMI"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <assert.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <ctype.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <errno.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <fcntl.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <stdio.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <stdlib.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <strings.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <syslog.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <sys/stat.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <pthread.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include <unistd.h>
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#include "dlmgmt_impl.h"
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lmtypedef enum dlmgmt_db_op {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_DB_OP_WRITE,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_DB_OP_DELETE,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_DB_OP_READ
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm} dlmgmt_db_op_t;
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppotypedef struct dlmgmt_db_req_s {
e1ebb9ec908bc2d0a8810f137ebd6566cc8a8061lm struct dlmgmt_db_req_s *ls_next;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_op_t ls_op;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo datalink_id_t ls_linkid;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo uint32_t ls_flags; /* Either DLMGMT_ACTIVE or */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* DLMGMT_PERSIST, not both. */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo} dlmgmt_db_req_t;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * List of pending db updates (e.g., because of a read-only filesystem).
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic dlmgmt_db_req_t *dlmgmt_db_req_head = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic dlmgmt_db_req_t *dlmgmt_db_req_tail = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int dlmgmt_db_update(dlmgmt_db_op_t, datalink_id_t,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo uint32_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int dlmgmt_process_db_req(dlmgmt_db_req_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
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define MAXLINELEN 1024
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
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.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppotypedef size_t write_func_t(char *, size_t, char *, void *);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
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.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lmtypedef size_t read_func_t(char *, void **);
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lmtypedef struct translator_s {
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm const char *type_name;
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm write_func_t *write_func;
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm read_func_t *read_func;
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm} translator_t;
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator functions, defined later but declared here so that
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * the translator table can be defined.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic write_func_t write_str, write_boolean, write_uint64;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic read_func_t read_str, read_boolean, read_int64;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Translator table, indexed by dladm_datatype_t.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lmstatic translator_t translators[] = {
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm { "string", write_str, read_str },
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm { "boolean", write_boolean, read_boolean },
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo { "int", write_uint64, read_int64 }
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm};
0a55fbb79ee31ed09f84a9ae28e9747bc23f4a08lm
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t ntranslators = sizeof (translators) / sizeof (translator_t);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define LINK_PROPERTY_DELIMINATOR ";"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define LINK_PROPERTY_TYPE_VALUE_SEP ","
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define BASE_PROPERTY_LENGTH(t, n) (strlen(translators[(t)].type_name) +\
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo strlen(LINK_PROPERTY_TYPE_VALUE_SEP) +\
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo strlen(LINK_PROPERTY_DELIMINATOR) +\
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo strlen((n)))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define GENERATE_PROPERTY_STRING(buf, length, conv, name, type, val) \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (snprintf((buf), (length), "%s=%s%s" conv "%s", (name), \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo translators[(type)].type_name, \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo LINK_PROPERTY_TYPE_VALUE_SEP, (val), LINK_PROPERTY_DELIMINATOR))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Name of the cache file to keep the active <link name, linkid> mapping
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic char cachefile[MAXPATHLEN];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define DLMGMT_PERSISTENT_DB_PATH "/etc/dladm/datalink.conf"
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define DLMGMT_MAKE_FILE_DB_PATH(buffer, persistent) \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) snprintf((buffer), MAXPATHLEN, "%s", \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (persistent) ? DLMGMT_PERSISTENT_DB_PATH : cachefile);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_str(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char *ptr = value;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo size_t data_length = strnlen(ptr, buffer_length);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
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 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (data_length + BASE_PROPERTY_LENGTH(DLADM_TYPE_STR, name) ==
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo buffer_length || data_length == 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
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 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%s",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo name, DLADM_TYPE_STR, ptr));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_boolean(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo boolean_t *ptr = value;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Booleans are either zero or one, so we only need room for two
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * characters in the buffer.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (buffer_length <= 1 + BASE_PROPERTY_LENGTH(DLADM_TYPE_BOOLEAN, name))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%d",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo name, DLADM_TYPE_BOOLEAN, *ptr));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppowrite_uint64(char *buffer, size_t buffer_length, char *name, void *value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo uint64_t *ptr = value;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Limit checking for uint64_t is a little trickier.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (snprintf(NULL, 0, "%lld", *ptr) +
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo BASE_PROPERTY_LENGTH(DLADM_TYPE_UINT64, name) >= buffer_length)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (GENERATE_PROPERTY_STRING(buffer, buffer_length, "%lld",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo name, DLADM_TYPE_UINT64, *ptr));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fhepporead_str(char *buffer, void **value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char *ptr = calloc(MAXLINKATTRLEN, sizeof (char));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo ssize_t len;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ptr == NULL || (len = snprintf(ptr, MAXLINKATTRLEN, "%s", buffer))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo >= MAXLINKATTRLEN) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo free(ptr);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *(char **)value = ptr;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /* Account for NULL terminator */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (len + 1);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fhepporead_boolean(char *buffer, void **value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo boolean_t *ptr = calloc(1, sizeof (boolean_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ptr == NULL)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *ptr = atoi(buffer);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *(boolean_t **)value = ptr;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (sizeof (boolean_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic size_t
1ae0874509b6811fdde1dfd46f0d93fd09867a3fhepporead_int64(char *buffer, void **value)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int64_t *ptr = calloc(1, sizeof (int64_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (ptr == NULL)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *ptr = (int64_t)atoll(buffer);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo *(int64_t **)value = ptr;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (sizeof (int64_t));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_db_update(dlmgmt_db_op_t op, datalink_id_t linkid, uint32_t flags)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_t *req;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int err;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * It is either a persistent request or an active request, not both.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert((flags == DLMGMT_PERSIST) || (flags == DLMGMT_ACTIVE));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((req = malloc(sizeof (dlmgmt_db_req_t))) == NULL)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (ENOMEM);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo req->ls_next = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo req->ls_op = op;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo req->ls_linkid = linkid;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo req->ls_flags = flags;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If the return error is EINPROGRESS, this request is handled
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * asynchronously; return success.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = dlmgmt_process_db_req(req);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err != EINPROGRESS)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo free(req);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo else
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = 0;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define DLMGMT_DB_OP_STR(op) \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (((op) == DLMGMT_DB_OP_READ) ? "read" : \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (((op) == DLMGMT_DB_OP_WRITE) ? "write" : "delete"))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo#define DLMGMT_DB_CONF_STR(flag) \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (((flag) == DLMGMT_ACTIVE) ? "active" : \
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (((flag) == DLMGMT_PERSIST) ? "persistent" : ""))
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_process_db_req(dlmgmt_db_req_t *req)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo pthread_t tid;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo boolean_t writeop;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int err;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
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 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo writeop = (req->ls_op != DLMGMT_DB_OP_READ);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (writeop && (req->ls_flags == DLMGMT_PERSIST) &&
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (dlmgmt_db_req_head != NULL)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_tail->ls_next = req;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_tail = req;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (EINPROGRESS);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = dlmgmt_process_db_onereq(req, writeop);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err != EINPROGRESS && err != 0 &&
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (req->ls_flags != DLMGMT_ACTIVE || errno != ENOENT)) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
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 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_log(LOG_WARNING, "dlmgmt_process_db_onereq() %s "
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo "operation on %s configuration failed: %s",
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_DB_OP_STR(req->ls_op),
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_DB_CONF_STR(req->ls_flags), strerror(err));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err == EINPROGRESS) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert(req->ls_flags == DLMGMT_PERSIST);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert(writeop && dlmgmt_db_req_head == NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_tail = dlmgmt_db_req_head = req;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = pthread_create(&tid, NULL, dlmgmt_db_update_thread, NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err == 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (EINPROGRESS);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_process_db_onereq(dlmgmt_db_req_t *req, boolean_t writeop)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int err = 0;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo FILE *fp, *nfp = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char file[MAXPATHLEN];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char newfile[MAXPATHLEN];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int nfd;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo DLMGMT_MAKE_FILE_DB_PATH(file, (req->ls_flags == DLMGMT_PERSIST));
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((fp = fopen(file, (writeop ? "r+" : "r"))) == NULL) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (writeop && errno == EROFS) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
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 */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (EINPROGRESS);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } else if (req->ls_flags == DLMGMT_ACTIVE && errno == ENOENT) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * It is fine if the file keeping active configuration
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * does not exist. This happens during a new reboot.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!writeop)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (ENOENT);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * If this is an update request for the active
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * configuration, create the file.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((fp = fopen(file, "w")) == NULL)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (errno == EROFS ? EINPROGRESS : errno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo } else {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (errno);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (writeop) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) snprintf(newfile, MAXPATHLEN, "%s.new", file);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((nfd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC,
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = errno;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(fp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if ((nfp = fdopen(nfd, "w")) == NULL) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = errno;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) close(nfd);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(fp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) unlink(newfile);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (writeop)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = process_db_write(req, fp, nfp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo else
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = process_db_read(req, fp, nfp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!writeop || err != 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo goto done;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (fflush(nfp) == EOF) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = errno;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo goto done;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(fp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(nfp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (rename(newfile, file) < 0) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = errno;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) unlink(newfile);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (0);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodone:
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (nfp != NULL) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(nfp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err != 0)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) unlink(newfile);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) fclose(fp);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (err);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo/*ARGSUSED*/
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic void *
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppodlmgmt_db_update_thread(void *arg)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_t *req;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int err = 0;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_table_lock(B_TRUE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert(dlmgmt_db_req_head != NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo while ((req = dlmgmt_db_req_head) != NULL) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert(req->ls_flags == DLMGMT_PERSIST);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo err = dlmgmt_process_db_onereq(req, B_TRUE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (err == EINPROGRESS) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The filesystem is still read only. Go to sleep and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * try again.
d10e4ef2fabf16c3237c6d6592496df3eac6a1efnarayan */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_table_unlock();
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (void) sleep(5);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_table_lock(B_TRUE);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo continue;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * The filesystem is no longer read only. Continue processing
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * and remove the request from the pending list.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_head = req->ls_next;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (dlmgmt_db_req_tail == req) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo assert(dlmgmt_db_req_head == NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_db_req_tail = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo free(req);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dlmgmt_table_unlock();
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo return (NULL);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo}
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppostatic int
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppoparse_linkprops(char *buf, dlmgmt_link_t *linkp)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo{
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo boolean_t found_type = B_FALSE;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo dladm_datatype_t type = DLADM_TYPE_STR;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int i, len;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo int err = 0;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char *curr;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char attr_name[MAXLINKATTRLEN];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo size_t attr_buf_len = 0;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo void *attr_buf = NULL;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo curr = buf;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo len = strlen(buf);
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo attr_name[0] = '\0';
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo for (i = 0; i < len && err == 0; i++) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo char c = buf[i];
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo boolean_t match = (c == '=' ||
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo (c == ',' && !found_type) || c == ';');
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * Move to the next character if there is no match and
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * if we have not reached the last character.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (!match && i != len - 1)
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo continue;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (match) {
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo /*
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo * NUL-terminate the string pointed to by 'curr'.
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo */
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo buf[i] = '\0';
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo if (*curr == '\0')
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo goto parse_fail;
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo }
1ae0874509b6811fdde1dfd46f0d93fd09867a3fheppo
if (attr_name[0] != '\0' && found_type) {
/*
* We get here after we have processed the "<prop>="
* pattern. The pattern we are now interested in is
* "<val>;".
*/
if (c == '=')
goto parse_fail;
if (strcmp(attr_name, "name") == 0) {
(void) read_str(curr, &attr_buf);
(void) snprintf(linkp->ll_link,
MAXLINKNAMELEN, "%s", attr_buf);
} else if (strcmp(attr_name, "class") == 0) {
(void) read_int64(curr, &attr_buf);
linkp->ll_class =
(datalink_class_t)*(int64_t *)attr_buf;
} else if (strcmp(attr_name, "media") == 0) {
(void) read_int64(curr, &attr_buf);
linkp->ll_media =
(uint32_t)*(int64_t *)attr_buf;
} else {
attr_buf_len = translators[type].read_func(curr,
&attr_buf);
err = linkattr_set(&(linkp->ll_head), attr_name,
attr_buf, attr_buf_len, type);
}
free(attr_buf);
attr_name[0] = '\0';
found_type = B_FALSE;
} else if (attr_name[0] != '\0') {
/*
* Non-zero length attr_name and found_type of false
* indicates that we have not found the type for this
* attribute. The pattern now is "<type>,<val>;", we
* want the <type> part of the pattern.
*/
for (type = 0; type < ntranslators; type++) {
if (strcmp(curr,
translators[type].type_name) == 0) {
found_type = B_TRUE;
break;
}
}
if (!found_type)
goto parse_fail;
} else {
/*
* A zero length attr_name indicates we are looking
* at the beginning of a link attribute.
*/
if (c != '=')
goto parse_fail;
(void) snprintf(attr_name, MAXLINKATTRLEN, "%s", curr);
}
curr = buf + i + 1;
}
return (err);
parse_fail:
return (-1);
}
static boolean_t
process_link_line(char *buf, dlmgmt_link_t **linkpp)
{
dlmgmt_link_t *linkp;
int i, len, llen;
char *str, *lasts;
char tmpbuf[MAXLINELEN];
/*
* Use a copy of buf for parsing so that we can do whatever we want.
*/
(void) strlcpy(tmpbuf, buf, MAXLINELEN);
/*
* Skip leading spaces, blank lines, and comments.
*/
len = strlen(tmpbuf);
for (i = 0; i < len; i++) {
if (!isspace(tmpbuf[i]))
break;
}
if (i == len || tmpbuf[i] == '#') {
*linkpp = NULL;
return (B_TRUE);
}
linkp = calloc(1, sizeof (dlmgmt_link_t));
if (linkp == NULL)
goto fail;
str = tmpbuf + i;
/*
* Find the link id and assign it to the link structure.
*/
if (strtok_r(str, " \n\t", &lasts) == NULL)
goto fail;
llen = strlen(str);
linkp->ll_linkid = atoi(str);
str += llen + 1;
if (str >= tmpbuf + len)
goto fail;
/*
* Now find the list of link properties.
*/
if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
goto fail;
if (parse_linkprops(str, linkp) < 0)
goto fail;
*linkpp = linkp;
return (B_TRUE);
fail:
link_destroy(linkp);
/*
* Delete corrupted line.
*/
buf[0] = '\0';
return (B_FALSE);
}
static int
process_db_write(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
{
boolean_t done = B_FALSE;
int err = 0;
dlmgmt_link_t *linkp, *link_in_file, link;
char buf[MAXLINELEN];
if (req->ls_op == DLMGMT_DB_OP_WRITE) {
/*
* find the link in the avl tree with the given linkid.
*/
link.ll_linkid = req->ls_linkid;
linkp = avl_find(&dlmgmt_id_avl, &link, NULL);
if (linkp == NULL || (linkp->ll_flags & req->ls_flags) == 0) {
/*
* This link has already been changed. This could
* happen if the request is pending because of
* read-only file-system. If so, we are done.
*/
return (0);
}
}
while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
process_link_line(buf, &link_in_file)) {
if (link_in_file == NULL || done) {
/*
* this is a comment line, write it out.
*/
if (fputs(buf, nfp) == EOF)
err = errno;
continue;
}
switch (req->ls_op) {
case DLMGMT_DB_OP_WRITE:
/*
* For write operations, if the linkid of the link
* read from the file does not match the id of what
* req->ll_linkid points to, write out the buffer.
* Otherwise, generate a new line. If we get to the
* end and have not seen what req->ll_linkid points
* to, write it out then.
*/
if (linkp == NULL ||
linkp->ll_linkid != link_in_file->ll_linkid) {
if (fputs(buf, nfp) == EOF)
err = errno;
} else {
generate_link_line(linkp,
req->ls_flags == DLMGMT_PERSIST, buf);
if (fputs(buf, nfp) == EOF)
err = errno;
done = B_TRUE;
}
break;
case DLMGMT_DB_OP_DELETE:
/*
* Delete is simple. If buf does not represent the
* link we're deleting, write it out.
*/
if (req->ls_linkid != link_in_file->ll_linkid) {
if (fputs(buf, nfp) == EOF)
err = errno;
} else {
done = B_TRUE;
}
break;
case DLMGMT_DB_OP_READ:
default:
err = EINVAL;
break;
}
link_destroy(link_in_file);
}
/*
* If we get to the end of the file and have not seen what
* req->ll_linkid points to, write it out then.
*/
if (req->ls_op == DLMGMT_DB_OP_WRITE && !done) {
generate_link_line(linkp, req->ls_flags == DLMGMT_PERSIST, buf);
done = B_TRUE;
if (fputs(buf, nfp) == EOF)
err = errno;
}
if (!done)
err = ENOENT;
return (err);
}
/* ARGSUSED1 */
static int
process_db_read(dlmgmt_db_req_t *req, FILE *fp, FILE *nfp)
{
avl_index_t name_where, id_where;
dlmgmt_link_t *link_in_file;
dlmgmt_link_t *linkp1, *linkp2;
char buf[MAXLINELEN];
int err = 0;
/*
* This loop processes each line of the configuration file.
*/
while (fgets(buf, MAXLINELEN, fp) != NULL) {
if (!process_link_line(buf, &link_in_file)) {
err = EINVAL;
break;
}
/*
* Skip the comment line.
*/
if (link_in_file == NULL)
continue;
linkp1 = avl_find(&dlmgmt_name_avl, link_in_file, &name_where);
linkp2 = avl_find(&dlmgmt_id_avl, link_in_file, &id_where);
if ((linkp1 != NULL) || (linkp2 != NULL)) {
/*
* If any of the following conditions are met, this is
* a duplicate entry:
*
* 1. link2 (with the given name) and link2 (with the
* given id) are not the same link;
* 2. This is a persistent req and find the link with
* the given name and id. Note that persistent db
* is read before the active one.
* 3. Found the link with the given name and id but
* the link is already active.
*/
if ((linkp1 != linkp2) ||
(req->ls_flags == DLMGMT_PERSIST) ||
((linkp1->ll_flags & DLMGMT_ACTIVE) != 0)) {
dlmgmt_log(LOG_WARNING, "Duplicate link "
"entries in repository: link name %s "
"link id %i", link_in_file->ll_link,
link_in_file->ll_linkid);
} else {
linkp1->ll_flags |= DLMGMT_ACTIVE;
}
link_destroy(link_in_file);
} else {
avl_insert(&dlmgmt_name_avl, link_in_file, name_where);
avl_insert(&dlmgmt_id_avl, link_in_file, id_where);
dlmgmt_advance(link_in_file);
link_in_file->ll_flags |= req->ls_flags;
}
}
return (err);
}
/*
* Generate an entry in the link database.
* Each entry has this format:
* <link id> <prop0>=<type>,<val>;...;<propn>=<type>,<val>;
*/
static void
generate_link_line(dlmgmt_link_t *linkp, boolean_t persist, char *buf)
{
char tmpbuf[MAXLINELEN];
char *ptr;
char *lim = tmpbuf + MAXLINELEN;
char *name_to_write = NULL;
datalink_id_t id_to_write;
dlmgmt_linkattr_t *cur_p = NULL;
uint64_t u64;
ptr = tmpbuf;
id_to_write = linkp->ll_linkid;
ptr += snprintf(ptr, BUFLEN(lim, ptr), "%d\t", id_to_write);
name_to_write = linkp->ll_link;
ptr += write_str(ptr, BUFLEN(lim, ptr), "name", name_to_write);
u64 = linkp->ll_class;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "class", &u64);
u64 = linkp->ll_media;
ptr += write_uint64(ptr, BUFLEN(lim, ptr), "media", &u64);
/*
* The daemon does not keep any active link attribute. If this request
* is for active configuration, we are done.
*/
if (!persist)
goto done;
for (cur_p = linkp->ll_head; cur_p != NULL; cur_p = cur_p->lp_next) {
ptr += translators[cur_p->lp_type].write_func(ptr,
BUFLEN(lim, ptr), cur_p->lp_name, cur_p->lp_val);
}
done:
if (ptr > lim)
return;
(void) snprintf(buf, MAXLINELEN, "%s\n", tmpbuf);
}
int
dlmgmt_delete_db_entry(datalink_id_t linkid, uint32_t flags)
{
return (dlmgmt_db_update(DLMGMT_DB_OP_DELETE, linkid, flags));
}
int
dlmgmt_write_db_entry(datalink_id_t linkid, uint32_t flags)
{
int err;
if (flags & DLMGMT_PERSIST) {
if ((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
linkid, DLMGMT_PERSIST)) != 0) {
return (err);
}
}
if (flags & DLMGMT_ACTIVE) {
if (((err = dlmgmt_db_update(DLMGMT_DB_OP_WRITE,
linkid, DLMGMT_ACTIVE)) != 0) &&
(flags & DLMGMT_PERSIST)) {
(void) dlmgmt_db_update(DLMGMT_DB_OP_DELETE,
linkid, DLMGMT_PERSIST);
return (err);
}
}
return (0);
}
/*
* Initialize the datalink <link name, linkid> mapping and the link's
* attributes list based on the configuration file /etc/dladm/datalink.conf
* and the active configuration cache file
* /etc/svc/volatile/dladm/datalink-management:default.cache.
*
* This function is called when the datalink-management service is started
* during reboot, and when the dlmgmtd daemon is restarted.
*/
int
dlmgmt_db_init()
{
char filename[MAXPATHLEN];
dlmgmt_db_req_t req;
int err;
dlmgmt_link_t *linkp;
char *fmri, *c;
/*
* First derive the name of the cache file from the FMRI name. This
* cache name is used to keep active datalink configuration.
*/
if (debug) {
(void) snprintf(cachefile, MAXPATHLEN, "%s/%s%s",
DLMGMT_TMPFS_DIR, progname, ".debug.cache");
} else {
if ((fmri = getenv("SMF_FMRI")) == NULL) {
dlmgmt_log(LOG_WARNING, "dlmgmtd is an smf(5) managed "
"service and should not be run from the command "
"line.");
return (EINVAL);
}
/*
* The FMRI name is in the form of
* svc:/service/service:instance. We need to remove the
* prefix "svc:/" and replace '/' with '-'. The cache file
* name is in the form of "service:instance.cache".
*/
if ((c = strchr(fmri, '/')) != NULL)
c++;
else
c = fmri;
(void) snprintf(filename, MAXPATHLEN, "%s.cache", c);
for (c = filename; *c != '\0'; c++) {
if (*c == '/')
*c = '-';
}
(void) snprintf(cachefile, MAXPATHLEN, "%s/%s",
DLMGMT_TMPFS_DIR, filename);
}
dlmgmt_table_lock(B_TRUE);
req.ls_next = NULL;
req.ls_op = DLMGMT_DB_OP_READ;
req.ls_linkid = DATALINK_INVALID_LINKID;
req.ls_flags = DLMGMT_PERSIST;
if ((err = dlmgmt_process_db_req(&req)) != 0)
goto done;
req.ls_flags = DLMGMT_ACTIVE;
err = dlmgmt_process_db_req(&req);
if (err == ENOENT) {
/*
* The temporary datalink.conf does not exist. This is
* the first boot. Mark all the physical links active.
*/
for (linkp = avl_first(&dlmgmt_id_avl); linkp != NULL;
linkp = AVL_NEXT(&dlmgmt_id_avl, linkp)) {
if (linkp->ll_class == DATALINK_CLASS_PHYS) {
linkp->ll_flags |= DLMGMT_ACTIVE;
(void) dlmgmt_write_db_entry(
linkp->ll_linkid, DLMGMT_ACTIVE);
}
}
err = 0;
}
done:
dlmgmt_table_unlock();
return (err);
}