1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <stdio.h>
27#include <strings.h>
28#include <unistd.h>
29#include <stdarg.h>
30#include <fcntl.h>
31#include <stdlib.h>
32#include <libnvpair.h>
33#include <libdevinfo.h>
34#include <syslog.h>
35#include <sys/param.h>
36#include <errno.h>
37#include <assert.h>
38#include <sys/systeminfo.h>
39#include <sys/modctl.h>
40#include <sys/fs/sdev_impl.h>
41
42/*
43 * Private interfaces for non-global /dev profile
44 */
45
46/*
47 * Allocate opaque data structure for passing profile to the kernel for
48 * the given mount point.
49 *
50 * Note that this interface returns an empty, initialized, profile.
51 * It does not return what may have been previously committed.
52 */
53int
54di_prof_init(const char *mountpt, di_prof_t *profp)
55{
56	nvlist_t	*nvl;
57
58	if (nvlist_alloc(&nvl, 0, 0))
59		return (-1);
60
61	if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) {
62		nvlist_free(nvl);
63		return (-1);
64	}
65
66	*profp = (di_prof_t)nvl;
67	return (0);
68}
69
70/*
71 * Free space allocated by di_prof_init().
72 */
73void
74di_prof_fini(di_prof_t prof)
75{
76	nvlist_free((nvlist_t *)prof);
77}
78
79/*
80 * Sends profile to the kernel.
81 */
82int
83di_prof_commit(di_prof_t prof)
84{
85	char	*buf = NULL;
86	size_t	buflen = 0;
87	int	rv;
88
89	if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0))
90		return (-1);
91	rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen);
92	free(buf);
93	return (rv);
94}
95
96/*
97 * Add a device or directory to profile's include list.
98 *
99 * Note that there is no arbitration between conflicting
100 * include and exclude profile entries, most recent
101 * is the winner.
102 */
103int
104di_prof_add_dev(di_prof_t prof, const char *dev)
105{
106	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev))
107		return (-1);
108	return (0);
109}
110
111/*
112 * Add a device or directory to profile's exclude list.
113 * This can effectively remove a previously committed device.
114 */
115int
116di_prof_add_exclude(di_prof_t prof, const char *dev)
117{
118	if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_EXCLUDE, dev))
119		return (-1);
120	return (0);
121}
122
123/*
124 * Add a symlink to profile.
125 */
126int
127di_prof_add_symlink(di_prof_t prof, const char *linkname, const char *target)
128{
129	nvlist_t	*nvl = (nvlist_t *)prof;
130	char		*syml[2];
131
132	syml[0] = (char *)linkname;	/* 1st entry must be the symlink */
133	syml[1] = (char *)target;	/* 2nd entry must be the target */
134	if (nvlist_add_string_array(nvl, SDEV_NVNAME_SYMLINK, syml, 2))
135		return (-1);
136	return (0);
137}
138
139/*
140 * Add a name mapping to profile.
141 */
142int
143di_prof_add_map(di_prof_t prof, const char *source, const char *target)
144{
145	nvlist_t	*nvl = (nvlist_t *)prof;
146	char		*map[2];
147
148	map[0] = (char *)source;	/* 1st entry must be the source */
149	map[1] = (char *)target;	/* 2nd entry must be the target */
150	if (nvlist_add_string_array(nvl, SDEV_NVNAME_MAP, map, 2))
151		return (-1);
152	return (0);
153}
154