xref: /src/sys/contrib/openzfs/lib/libzfs/libzfs_mnttab.c (revision 80aae8a3f8aa70712930664572be9e6885dc0be7)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or https://opensource.org/licenses/CDDL-1.0.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright 2019 Joyent, Inc.
26  * Copyright (c) 2011, 2020 by Delphix. All rights reserved.
27  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
28  * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
29  * Copyright (c) 2013 Martin Matuska. All rights reserved.
30  * Copyright (c) 2013 Steven Hartland. All rights reserved.
31  * Copyright 2017 Nexenta Systems, Inc.
32  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
33  * Copyright 2017-2018 RackTop Systems.
34  * Copyright (c) 2019 Datto Inc.
35  * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com>
36  * Copyright (c) 2021 Matt Fiddaman
37  * Copyright (c) 2026, TrueNAS.
38  */
39 
40 #include <sys/mntent.h>
41 #include <sys/mutex.h>
42 #include <libzfs.h>
43 #include "libzfs_impl.h"
44 
45 typedef struct mnttab_node {
46 	struct mnttab mtn_mt;
47 	avl_node_t mtn_node;
48 } mnttab_node_t;
49 
50 static mnttab_node_t *
mnttab_node_alloc(libzfs_handle_t * hdl,const char * special,const char * mountp,const char * mntopts)51 mnttab_node_alloc(libzfs_handle_t *hdl, const char *special,
52     const char *mountp, const char *mntopts)
53 {
54 	mnttab_node_t *mtn = zfs_alloc(hdl, sizeof (mnttab_node_t));
55 	mtn->mtn_mt.mnt_special = zfs_strdup(hdl, special);
56 	mtn->mtn_mt.mnt_mountp = zfs_strdup(hdl, mountp);
57 	mtn->mtn_mt.mnt_fstype = (char *)MNTTYPE_ZFS;
58 	mtn->mtn_mt.mnt_mntopts = zfs_strdup(hdl, mntopts);
59 	return (mtn);
60 }
61 
62 static void
mnttab_node_free(libzfs_handle_t * hdl,mnttab_node_t * mtn)63 mnttab_node_free(libzfs_handle_t *hdl, mnttab_node_t *mtn)
64 {
65 	(void) hdl;
66 	free(mtn->mtn_mt.mnt_special);
67 	free(mtn->mtn_mt.mnt_mountp);
68 	free(mtn->mtn_mt.mnt_mntopts);
69 	free(mtn);
70 }
71 
72 static int
mnttab_compare(const void * arg1,const void * arg2)73 mnttab_compare(const void *arg1, const void *arg2)
74 {
75 	const mnttab_node_t *mtn1 = (const mnttab_node_t *)arg1;
76 	const mnttab_node_t *mtn2 = (const mnttab_node_t *)arg2;
77 	int rv;
78 
79 	rv = strcmp(mtn1->mtn_mt.mnt_special, mtn2->mtn_mt.mnt_special);
80 
81 	return (TREE_ISIGN(rv));
82 }
83 
84 void
libzfs_mnttab_init(libzfs_handle_t * hdl)85 libzfs_mnttab_init(libzfs_handle_t *hdl)
86 {
87 	mutex_init(&hdl->zh_mnttab_lock, NULL, MUTEX_DEFAULT, NULL);
88 	assert(avl_numnodes(&hdl->zh_mnttab) == 0);
89 	avl_create(&hdl->zh_mnttab, mnttab_compare,
90 	    sizeof (mnttab_node_t), offsetof(mnttab_node_t, mtn_node));
91 }
92 
93 void
libzfs_mnttab_fini(libzfs_handle_t * hdl)94 libzfs_mnttab_fini(libzfs_handle_t *hdl)
95 {
96 	void *cookie = NULL;
97 	mnttab_node_t *mtn;
98 
99 	while ((mtn = avl_destroy_nodes(&hdl->zh_mnttab, &cookie))
100 	    != NULL)
101 		mnttab_node_free(hdl, mtn);
102 
103 	avl_destroy(&hdl->zh_mnttab);
104 	(void) mutex_destroy(&hdl->zh_mnttab_lock);
105 }
106 
107 void
libzfs_mnttab_cache(libzfs_handle_t * hdl,boolean_t enable)108 libzfs_mnttab_cache(libzfs_handle_t *hdl, boolean_t enable)
109 {
110 	/* This is a no-op to preserve ABI backward compatibility. */
111 	(void) hdl, (void) enable;
112 }
113 
114 static int
mnttab_update(libzfs_handle_t * hdl)115 mnttab_update(libzfs_handle_t *hdl)
116 {
117 	FILE *mnttab;
118 	struct mnttab entry;
119 
120 	ASSERT(MUTEX_HELD(&hdl->zh_mnttab_lock));
121 
122 	if ((mnttab = fopen(MNTTAB, "re")) == NULL)
123 		return (ENOENT);
124 
125 	while (getmntent(mnttab, &entry) == 0) {
126 		mnttab_node_t *mtn;
127 		avl_index_t where;
128 
129 		if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
130 			continue;
131 
132 		mtn = mnttab_node_alloc(hdl, entry.mnt_special,
133 		    entry.mnt_mountp, entry.mnt_mntopts);
134 
135 		/* Exclude duplicate mounts */
136 		if (avl_find(&hdl->zh_mnttab, mtn, &where) != NULL) {
137 			mnttab_node_free(hdl, mtn);
138 			continue;
139 		}
140 
141 		avl_add(&hdl->zh_mnttab, mtn);
142 	}
143 
144 	(void) fclose(mnttab);
145 	return (0);
146 }
147 
148 int
libzfs_mnttab_find(libzfs_handle_t * hdl,const char * fsname,struct mnttab * entry)149 libzfs_mnttab_find(libzfs_handle_t *hdl, const char *fsname,
150     struct mnttab *entry)
151 {
152 	mnttab_node_t find;
153 	mnttab_node_t *mtn;
154 	int ret = ENOENT;
155 
156 	mutex_enter(&hdl->zh_mnttab_lock);
157 	if (avl_numnodes(&hdl->zh_mnttab) == 0) {
158 		int error;
159 
160 		if ((error = mnttab_update(hdl)) != 0) {
161 			mutex_exit(&hdl->zh_mnttab_lock);
162 			return (error);
163 		}
164 	}
165 
166 	find.mtn_mt.mnt_special = (char *)fsname;
167 	mtn = avl_find(&hdl->zh_mnttab, &find, NULL);
168 	if (mtn) {
169 		*entry = mtn->mtn_mt;
170 		ret = 0;
171 	}
172 	mutex_exit(&hdl->zh_mnttab_lock);
173 	return (ret);
174 }
175 
176 void
libzfs_mnttab_add(libzfs_handle_t * hdl,const char * special,const char * mountp,const char * mntopts)177 libzfs_mnttab_add(libzfs_handle_t *hdl, const char *special,
178     const char *mountp, const char *mntopts)
179 {
180 	mnttab_node_t *mtn;
181 
182 	mutex_enter(&hdl->zh_mnttab_lock);
183 
184 	mtn = mnttab_node_alloc(hdl, special, mountp, mntopts);
185 
186 	/*
187 	 * Another thread may have already added this entry
188 	 * via mnttab_update. If so we should skip it.
189 	 */
190 	if (avl_find(&hdl->zh_mnttab, mtn, NULL) != NULL)
191 		mnttab_node_free(hdl, mtn);
192 	else
193 		avl_add(&hdl->zh_mnttab, mtn);
194 
195 	mutex_exit(&hdl->zh_mnttab_lock);
196 }
197 
198 void
libzfs_mnttab_remove(libzfs_handle_t * hdl,const char * fsname)199 libzfs_mnttab_remove(libzfs_handle_t *hdl, const char *fsname)
200 {
201 	mnttab_node_t find;
202 	mnttab_node_t *ret;
203 
204 	mutex_enter(&hdl->zh_mnttab_lock);
205 	find.mtn_mt.mnt_special = (char *)fsname;
206 	if ((ret = avl_find(&hdl->zh_mnttab, (void *)&find, NULL)) != NULL) {
207 		avl_remove(&hdl->zh_mnttab, ret);
208 		mnttab_node_free(hdl, ret);
209 	}
210 	mutex_exit(&hdl->zh_mnttab_lock);
211 }
212