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  */
53 int
di_prof_init(const char * mountpt,di_prof_t * profp)54 di_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  */
73 void
di_prof_fini(di_prof_t prof)74 di_prof_fini(di_prof_t prof)
75 {
76 	nvlist_free((nvlist_t *)prof);
77 }
78 
79 /*
80  * Sends profile to the kernel.
81  */
82 int
di_prof_commit(di_prof_t prof)83 di_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  */
103 int
di_prof_add_dev(di_prof_t prof,const char * dev)104 di_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  */
115 int
di_prof_add_exclude(di_prof_t prof,const char * dev)116 di_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  */
126 int
di_prof_add_symlink(di_prof_t prof,const char * linkname,const char * target)127 di_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  */
142 int
di_prof_add_map(di_prof_t prof,const char * source,const char * target)143 di_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