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