1d76947f3SHartmut Brandt /*-
2d76947f3SHartmut Brandt  * Copyright (c) 2005-2006 The FreeBSD Project
3d76947f3SHartmut Brandt  * All rights reserved.
4d76947f3SHartmut Brandt  *
5d76947f3SHartmut Brandt  * Author: Victor Cruceru <soc-victor@freebsd.org>
6d76947f3SHartmut Brandt  *
7d76947f3SHartmut Brandt  * Redistribution of this software and documentation and use in source and
8d76947f3SHartmut Brandt  * binary forms, with or without modification, are permitted provided that
9d76947f3SHartmut Brandt  * the following conditions are met:
10d76947f3SHartmut Brandt  *
11d76947f3SHartmut Brandt  * 1. Redistributions of source code or documentation must retain the above
12d76947f3SHartmut Brandt  *    copyright notice, this list of conditions and the following disclaimer.
13d76947f3SHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
14d76947f3SHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
15d76947f3SHartmut Brandt  *    documentation and/or other materials provided with the distribution.
16d76947f3SHartmut Brandt  *
17d76947f3SHartmut Brandt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d76947f3SHartmut Brandt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d76947f3SHartmut Brandt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d76947f3SHartmut Brandt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d76947f3SHartmut Brandt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d76947f3SHartmut Brandt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d76947f3SHartmut Brandt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d76947f3SHartmut Brandt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d76947f3SHartmut Brandt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d76947f3SHartmut Brandt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d76947f3SHartmut Brandt  * SUCH DAMAGE.
28d76947f3SHartmut Brandt  */
29d76947f3SHartmut Brandt 
30d76947f3SHartmut Brandt /*
31d76947f3SHartmut Brandt  * Host Resources MIB: hrPartitionTable implementation for SNMPd.
32d76947f3SHartmut Brandt  */
33d76947f3SHartmut Brandt 
34d76947f3SHartmut Brandt #include <sys/types.h>
35d76947f3SHartmut Brandt #include <sys/limits.h>
36d76947f3SHartmut Brandt 
37d76947f3SHartmut Brandt #include <assert.h>
38d76947f3SHartmut Brandt #include <err.h>
39e8689b4cSHartmut Brandt #include <inttypes.h>
40e8689b4cSHartmut Brandt #include <libgeom.h>
41d76947f3SHartmut Brandt #include <paths.h>
42d76947f3SHartmut Brandt #include <stdlib.h>
43d76947f3SHartmut Brandt #include <string.h>
44d76947f3SHartmut Brandt #include <syslog.h>
45e55adffcSHartmut Brandt #include <sysexits.h>
46d76947f3SHartmut Brandt 
47d76947f3SHartmut Brandt #include "hostres_snmp.h"
48d76947f3SHartmut Brandt #include "hostres_oid.h"
49d76947f3SHartmut Brandt #include "hostres_tree.h"
50d76947f3SHartmut Brandt 
51e8689b4cSHartmut Brandt #define	HR_FREEBSD_PART_TYPE	165
52e8689b4cSHartmut Brandt 
53e55adffcSHartmut Brandt /* Maximum length for label and id including \0 */
54e55adffcSHartmut Brandt #define	PART_STR_MLEN	(128 + 1)
55e55adffcSHartmut Brandt 
56d76947f3SHartmut Brandt /*
57d76947f3SHartmut Brandt  * One row in the hrPartitionTable
58d76947f3SHartmut Brandt  */
59d76947f3SHartmut Brandt struct partition_entry {
60e55adffcSHartmut Brandt 	asn_subid_t	index[2];
61e55adffcSHartmut Brandt 	u_char		*label;	/* max allocated len will be PART_STR_MLEN */
62e55adffcSHartmut Brandt 	u_char		*id;	/* max allocated len will be PART_STR_MLEN */
63d76947f3SHartmut Brandt 	int32_t		size;
64d76947f3SHartmut Brandt 	int32_t		fs_Index;
65d76947f3SHartmut Brandt 	TAILQ_ENTRY(partition_entry) link;
66d76947f3SHartmut Brandt #define	HR_PARTITION_FOUND		0x001
67d76947f3SHartmut Brandt 	uint32_t	flags;
68d76947f3SHartmut Brandt };
69d76947f3SHartmut Brandt TAILQ_HEAD(partition_tbl, partition_entry);
70d76947f3SHartmut Brandt 
71d76947f3SHartmut Brandt /*
72d76947f3SHartmut Brandt  * This table is used to get a consistent indexing. It saves the name -> index
73d76947f3SHartmut Brandt  * mapping while we rebuild the partition table.
74d76947f3SHartmut Brandt  */
75d76947f3SHartmut Brandt struct partition_map_entry {
76e55adffcSHartmut Brandt 	int32_t		index;	/* partition_entry::index */
77e55adffcSHartmut Brandt 	u_char		*id;	/* max allocated len will be PART_STR_MLEN */
78d76947f3SHartmut Brandt 
79d76947f3SHartmut Brandt 	/*
80d76947f3SHartmut Brandt 	 * next may be NULL if the respective partition_entry
81d76947f3SHartmut Brandt 	 * is (temporally) gone.
82d76947f3SHartmut Brandt 	 */
83d76947f3SHartmut Brandt 	struct partition_entry	*entry;
84d76947f3SHartmut Brandt 	STAILQ_ENTRY(partition_map_entry) link;
85d76947f3SHartmut Brandt };
86d76947f3SHartmut Brandt STAILQ_HEAD(partition_map, partition_map_entry);
87d76947f3SHartmut Brandt 
88d76947f3SHartmut Brandt /* Mapping table for consistent indexing */
89d76947f3SHartmut Brandt static struct partition_map partition_map =
90d76947f3SHartmut Brandt     STAILQ_HEAD_INITIALIZER(partition_map);
91d76947f3SHartmut Brandt 
92d76947f3SHartmut Brandt /* THE partition table. */
93d76947f3SHartmut Brandt static struct partition_tbl partition_tbl =
94d76947f3SHartmut Brandt     TAILQ_HEAD_INITIALIZER(partition_tbl);
95d76947f3SHartmut Brandt 
96d76947f3SHartmut Brandt /* next int available for indexing the hrPartitionTable */
97d76947f3SHartmut Brandt static uint32_t next_partition_index = 1;
98d76947f3SHartmut Brandt 
99e55adffcSHartmut Brandt /*
100e55adffcSHartmut Brandt  * Partition_entry_cmp is used for INSERT_OBJECT_FUNC_LINK
101e55adffcSHartmut Brandt  * macro.
102e55adffcSHartmut Brandt  */
103e55adffcSHartmut Brandt static int
partition_entry_cmp(const struct partition_entry * a,const struct partition_entry * b)104e55adffcSHartmut Brandt partition_entry_cmp(const struct partition_entry *a,
105e55adffcSHartmut Brandt     const struct partition_entry *b)
106e55adffcSHartmut Brandt {
107e55adffcSHartmut Brandt 	assert(a != NULL);
108e55adffcSHartmut Brandt 	assert(b != NULL);
109e55adffcSHartmut Brandt 
110e55adffcSHartmut Brandt 	if (a->index[0] < b->index[0])
111e55adffcSHartmut Brandt 		return (-1);
112e55adffcSHartmut Brandt 
113e55adffcSHartmut Brandt 	if (a->index[0] > b->index[0])
114e55adffcSHartmut Brandt 		return (+1);
115e55adffcSHartmut Brandt 
116e55adffcSHartmut Brandt 	if (a->index[1] < b->index[1])
117e55adffcSHartmut Brandt 		return (-1);
118e55adffcSHartmut Brandt 
119e55adffcSHartmut Brandt 	if (a->index[1] > b->index[1])
120e55adffcSHartmut Brandt 		return (+1);
121e55adffcSHartmut Brandt 
122e55adffcSHartmut Brandt 	return (0);
123e55adffcSHartmut Brandt }
124e55adffcSHartmut Brandt 
125e55adffcSHartmut Brandt /*
126e55adffcSHartmut Brandt  * Partition_idx_cmp is used for NEXT_OBJECT_FUNC and FIND_OBJECT_FUNC
127e55adffcSHartmut Brandt  * macros
128e55adffcSHartmut Brandt  */
129e55adffcSHartmut Brandt static int
partition_idx_cmp(const struct asn_oid * oid,u_int sub,const struct partition_entry * entry)130e55adffcSHartmut Brandt partition_idx_cmp(const struct asn_oid *oid, u_int sub,
131e55adffcSHartmut Brandt     const struct partition_entry *entry)
132e55adffcSHartmut Brandt {
133e55adffcSHartmut Brandt 	u_int i;
134e55adffcSHartmut Brandt 
135e55adffcSHartmut Brandt 	for (i = 0; i < 2 && i < oid->len - sub; i++) {
136e55adffcSHartmut Brandt 		if (oid->subs[sub + i] < entry->index[i])
137e55adffcSHartmut Brandt 			return (-1);
138e55adffcSHartmut Brandt 		if (oid->subs[sub + i] > entry->index[i])
139e55adffcSHartmut Brandt 			return (+1);
140e55adffcSHartmut Brandt 	}
141e55adffcSHartmut Brandt 	if (oid->len - sub < 2)
142e55adffcSHartmut Brandt 		return (-1);
143e55adffcSHartmut Brandt 	if (oid->len - sub > 2)
144e55adffcSHartmut Brandt 		return (+1);
145e55adffcSHartmut Brandt 
146e55adffcSHartmut Brandt 	return (0);
147e55adffcSHartmut Brandt }
148e55adffcSHartmut Brandt 
149d76947f3SHartmut Brandt /**
150d76947f3SHartmut Brandt  * Create a new partition table entry
151d76947f3SHartmut Brandt  */
152d76947f3SHartmut Brandt static struct partition_entry *
partition_entry_create(int32_t ds_index,const char * chunk_name)153e8689b4cSHartmut Brandt partition_entry_create(int32_t ds_index, const char *chunk_name)
154d76947f3SHartmut Brandt {
155d76947f3SHartmut Brandt 	struct partition_entry *entry;
156e55adffcSHartmut Brandt 	struct partition_map_entry *map;
157e55adffcSHartmut Brandt 	size_t id_len;
158d76947f3SHartmut Brandt 
159d76947f3SHartmut Brandt 	/* sanity checks */
160e8689b4cSHartmut Brandt 	assert(chunk_name != NULL);
161e8689b4cSHartmut Brandt 	if (chunk_name == NULL || chunk_name[0] == '\0')
162d76947f3SHartmut Brandt 		return (NULL);
163d76947f3SHartmut Brandt 
164d76947f3SHartmut Brandt 	/* check whether we already have seen this partition */
165d76947f3SHartmut Brandt 	STAILQ_FOREACH(map, &partition_map, link)
166e55adffcSHartmut Brandt 		if (strcmp(map->id, chunk_name) == 0)
167d76947f3SHartmut Brandt 			break;
168d76947f3SHartmut Brandt 
169d76947f3SHartmut Brandt 	if (map == NULL) {
170d76947f3SHartmut Brandt 		/* new object - get a new index and create a map */
171e55adffcSHartmut Brandt 
172d76947f3SHartmut Brandt 		if (next_partition_index > INT_MAX) {
173e55adffcSHartmut Brandt 			/* Unrecoverable error - die clean and quicly*/
174d76947f3SHartmut Brandt 			syslog(LOG_ERR, "%s: hrPartitionTable index wrap",
175d76947f3SHartmut Brandt 			    __func__);
176e55adffcSHartmut Brandt 			errx(EX_SOFTWARE, "hrPartitionTable index wrap");
177d76947f3SHartmut Brandt 		}
178d76947f3SHartmut Brandt 
179d76947f3SHartmut Brandt 		if ((map = malloc(sizeof(*map))) == NULL) {
180d76947f3SHartmut Brandt 			syslog(LOG_ERR, "hrPartitionTable: %s: %m", __func__);
181e55adffcSHartmut Brandt 			return (NULL);
182e55adffcSHartmut Brandt 		}
183e55adffcSHartmut Brandt 
184e55adffcSHartmut Brandt 		id_len = strlen(chunk_name) + 1;
185e55adffcSHartmut Brandt 		if (id_len > PART_STR_MLEN)
186e55adffcSHartmut Brandt 			id_len = PART_STR_MLEN;
187e55adffcSHartmut Brandt 
188e55adffcSHartmut Brandt 		if ((map->id = malloc(id_len)) == NULL) {
189e55adffcSHartmut Brandt 			free(map);
190d76947f3SHartmut Brandt 			return (NULL);
191d76947f3SHartmut Brandt 		}
192d76947f3SHartmut Brandt 
193d76947f3SHartmut Brandt 		map->index = next_partition_index++;
194d76947f3SHartmut Brandt 
195e55adffcSHartmut Brandt 		strlcpy(map->id, chunk_name, id_len);
196d76947f3SHartmut Brandt 
197e55adffcSHartmut Brandt 		map->entry = NULL;
198e55adffcSHartmut Brandt 
199d76947f3SHartmut Brandt 		STAILQ_INSERT_TAIL(&partition_map, map, link);
200d76947f3SHartmut Brandt 
201d76947f3SHartmut Brandt 		HRDBG("%s added into hrPartitionMap at index=%d",
202e8689b4cSHartmut Brandt 		    chunk_name, map->index);
203d76947f3SHartmut Brandt 
204d76947f3SHartmut Brandt 	} else {
205d76947f3SHartmut Brandt 		HRDBG("%s exists in hrPartitionMap index=%d",
206e8689b4cSHartmut Brandt 		    chunk_name, map->index);
207d76947f3SHartmut Brandt 	}
208d76947f3SHartmut Brandt 
209e55adffcSHartmut Brandt 	if ((entry = malloc(sizeof(*entry))) == NULL) {
210e55adffcSHartmut Brandt 		syslog(LOG_WARNING, "hrPartitionTable: %s: %m", __func__);
211e55adffcSHartmut Brandt 		return (NULL);
212e55adffcSHartmut Brandt 	}
213e55adffcSHartmut Brandt 	memset(entry, 0, sizeof(*entry));
214e55adffcSHartmut Brandt 
215d76947f3SHartmut Brandt 	/* create the index */
216e55adffcSHartmut Brandt 	entry->index[0] = ds_index;
217e55adffcSHartmut Brandt 	entry->index[1] = map->index;
218d76947f3SHartmut Brandt 
219e55adffcSHartmut Brandt 	map->entry = entry;
220d76947f3SHartmut Brandt 
221e55adffcSHartmut Brandt 	if ((entry->id = strdup(map->id)) == NULL) {
222e55adffcSHartmut Brandt 		free(entry);
223e55adffcSHartmut Brandt 		return (NULL);
224e55adffcSHartmut Brandt 	}
225d76947f3SHartmut Brandt 
226e55adffcSHartmut Brandt 	/*
227e55adffcSHartmut Brandt 	 * reuse id_len from here till the end of this function
228e55adffcSHartmut Brandt 	 * for partition_entry::label
229e55adffcSHartmut Brandt 	 */
230e55adffcSHartmut Brandt 	id_len = strlen(_PATH_DEV) + strlen(chunk_name) + 1;
231e55adffcSHartmut Brandt 
232e55adffcSHartmut Brandt 	if (id_len > PART_STR_MLEN)
233e55adffcSHartmut Brandt 		id_len = PART_STR_MLEN;
234e55adffcSHartmut Brandt 
235e55adffcSHartmut Brandt 	if ((entry->label = malloc(id_len )) == NULL) {
236e55adffcSHartmut Brandt 		free(entry->id);
237e55adffcSHartmut Brandt 		free(entry);
238e55adffcSHartmut Brandt 		return (NULL);
239e55adffcSHartmut Brandt 	}
240e55adffcSHartmut Brandt 
241e55adffcSHartmut Brandt 	snprintf(entry->label, id_len, "%s%s", _PATH_DEV, chunk_name);
242e55adffcSHartmut Brandt 
243e55adffcSHartmut Brandt 	INSERT_OBJECT_FUNC_LINK(entry, &partition_tbl, link,
244e55adffcSHartmut Brandt 	    partition_entry_cmp);
245d76947f3SHartmut Brandt 
246d76947f3SHartmut Brandt 	return (entry);
247d76947f3SHartmut Brandt }
248d76947f3SHartmut Brandt 
249d76947f3SHartmut Brandt /**
250d76947f3SHartmut Brandt  * Delete a partition table entry but keep the map entry intact.
251d76947f3SHartmut Brandt  */
252d76947f3SHartmut Brandt static void
partition_entry_delete(struct partition_entry * entry)253d76947f3SHartmut Brandt partition_entry_delete(struct partition_entry *entry)
254d76947f3SHartmut Brandt {
255d76947f3SHartmut Brandt 	struct partition_map_entry *map;
256d76947f3SHartmut Brandt 
257d76947f3SHartmut Brandt 	assert(entry != NULL);
258d76947f3SHartmut Brandt 
259d76947f3SHartmut Brandt 	TAILQ_REMOVE(&partition_tbl, entry, link);
260d76947f3SHartmut Brandt 	STAILQ_FOREACH(map, &partition_map, link)
261d76947f3SHartmut Brandt 		if (map->entry == entry) {
262d76947f3SHartmut Brandt 			map->entry = NULL;
263d76947f3SHartmut Brandt 			break;
264d76947f3SHartmut Brandt 		}
265e55adffcSHartmut Brandt 	free(entry->id);
266e55adffcSHartmut Brandt 	free(entry->label);
267d76947f3SHartmut Brandt 	free(entry);
268d76947f3SHartmut Brandt }
269d76947f3SHartmut Brandt 
270d76947f3SHartmut Brandt /**
271d76947f3SHartmut Brandt  * Find a partition table entry by name. If none is found, return NULL.
272d76947f3SHartmut Brandt  */
273d76947f3SHartmut Brandt static struct partition_entry *
partition_entry_find_by_name(const char * name)274d76947f3SHartmut Brandt partition_entry_find_by_name(const char *name)
275d76947f3SHartmut Brandt {
276d76947f3SHartmut Brandt 	struct partition_entry *entry =  NULL;
277d76947f3SHartmut Brandt 
278d76947f3SHartmut Brandt 	TAILQ_FOREACH(entry, &partition_tbl, link)
279d76947f3SHartmut Brandt 		if (strcmp(entry->id, name) == 0)
280d76947f3SHartmut Brandt 			return (entry);
281d76947f3SHartmut Brandt 
282d76947f3SHartmut Brandt 	return (NULL);
283d76947f3SHartmut Brandt }
284d76947f3SHartmut Brandt 
285d76947f3SHartmut Brandt /**
286d76947f3SHartmut Brandt  * Find a partition table entry by label. If none is found, return NULL.
287d76947f3SHartmut Brandt  */
288d76947f3SHartmut Brandt static struct partition_entry *
partition_entry_find_by_label(const char * name)289d76947f3SHartmut Brandt partition_entry_find_by_label(const char *name)
290d76947f3SHartmut Brandt {
291d76947f3SHartmut Brandt 	struct partition_entry *entry =  NULL;
292d76947f3SHartmut Brandt 
293d76947f3SHartmut Brandt 	TAILQ_FOREACH(entry, &partition_tbl, link)
294d76947f3SHartmut Brandt 		if (strcmp(entry->label, name) == 0)
295d76947f3SHartmut Brandt 			return (entry);
296d76947f3SHartmut Brandt 
297d76947f3SHartmut Brandt 	return (NULL);
298d76947f3SHartmut Brandt }
299d76947f3SHartmut Brandt 
300d76947f3SHartmut Brandt /**
301e8689b4cSHartmut Brandt  * Process a chunk from libgeom(4). A chunk is either a slice or a partition.
302d76947f3SHartmut Brandt  * If necessary create a new partition table entry for it. In any case
303d76947f3SHartmut Brandt  * set the size field of the entry and set the FOUND flag.
304d76947f3SHartmut Brandt  */
305d76947f3SHartmut Brandt static void
handle_chunk(int32_t ds_index,const char * chunk_name,off_t chunk_size)306e8689b4cSHartmut Brandt handle_chunk(int32_t ds_index, const char *chunk_name, off_t chunk_size)
307d76947f3SHartmut Brandt {
308e55adffcSHartmut Brandt 	struct partition_entry *entry;
309d76947f3SHartmut Brandt 	daddr_t k_size;
310d76947f3SHartmut Brandt 
311e8689b4cSHartmut Brandt 	assert(chunk_name != NULL);
312e8689b4cSHartmut Brandt 	assert(chunk_name[0] != '\0');
313e5cb99d5SAndriy Voskoboinyk 	if (chunk_name == NULL || chunk_name[0] == '\0')
314d76947f3SHartmut Brandt 		return;
315d76947f3SHartmut Brandt 
316e8689b4cSHartmut Brandt 	HRDBG("ANALYZE chunk %s", chunk_name);
317d76947f3SHartmut Brandt 
318e8689b4cSHartmut Brandt 	if ((entry = partition_entry_find_by_name(chunk_name)) == NULL)
319e8689b4cSHartmut Brandt 		if ((entry = partition_entry_create(ds_index,
320e8689b4cSHartmut Brandt 		    chunk_name)) == NULL)
321d76947f3SHartmut Brandt 			return;
322d76947f3SHartmut Brandt 
323d76947f3SHartmut Brandt 	entry->flags |= HR_PARTITION_FOUND;
324d76947f3SHartmut Brandt 
325d76947f3SHartmut Brandt 	/* actual size may overflow the SNMP type */
326e8689b4cSHartmut Brandt 	k_size = chunk_size / 1024;
327e8689b4cSHartmut Brandt 	entry->size = (k_size > (off_t)INT_MAX ? INT_MAX : k_size);
328d76947f3SHartmut Brandt }
329d76947f3SHartmut Brandt 
330d76947f3SHartmut Brandt /**
331d76947f3SHartmut Brandt  * Start refreshing the partition table. A call to this function will
332d76947f3SHartmut Brandt  * be followed by a call to handleDiskStorage() for every disk, followed
333d76947f3SHartmut Brandt  * by a single call to the post_refresh function.
334d76947f3SHartmut Brandt  */
335d76947f3SHartmut Brandt void
partition_tbl_pre_refresh(void)336d76947f3SHartmut Brandt partition_tbl_pre_refresh(void)
337d76947f3SHartmut Brandt {
338e55adffcSHartmut Brandt 	struct partition_entry *entry;
339d76947f3SHartmut Brandt 
340d76947f3SHartmut Brandt 	/* mark each entry as missing */
341d76947f3SHartmut Brandt 	TAILQ_FOREACH(entry, &partition_tbl, link)
342d76947f3SHartmut Brandt 		entry->flags &= ~HR_PARTITION_FOUND;
343d76947f3SHartmut Brandt }
344d76947f3SHartmut Brandt 
345d76947f3SHartmut Brandt /**
346e8689b4cSHartmut Brandt  * Try to find a geom(4) class by its name. Returns a pointer to that
347e8689b4cSHartmut Brandt  * class if found NULL otherways.
348e8689b4cSHartmut Brandt  */
349e8689b4cSHartmut Brandt static struct gclass *
find_class(struct gmesh * mesh,const char * name)350e8689b4cSHartmut Brandt find_class(struct gmesh *mesh, const char *name)
351e8689b4cSHartmut Brandt {
352e8689b4cSHartmut Brandt 	struct gclass *classp;
353e8689b4cSHartmut Brandt 
354e8689b4cSHartmut Brandt 	LIST_FOREACH(classp, &mesh->lg_class, lg_class)
355e8689b4cSHartmut Brandt 		if (strcmp(classp->lg_name, name) == 0)
356e8689b4cSHartmut Brandt 			return (classp);
357e8689b4cSHartmut Brandt 	return (NULL);
358e8689b4cSHartmut Brandt }
359e8689b4cSHartmut Brandt 
360e8689b4cSHartmut Brandt /**
361e8689b4cSHartmut Brandt  * Process all MBR-type partitions from the given disk.
362e8689b4cSHartmut Brandt  */
363e8689b4cSHartmut Brandt static void
get_mbr(struct gclass * classp,int32_t ds_index,const char * disk_dev_name)364e8689b4cSHartmut Brandt get_mbr(struct gclass *classp, int32_t ds_index, const char *disk_dev_name)
365e8689b4cSHartmut Brandt {
366e8689b4cSHartmut Brandt 	struct ggeom *gp;
367e8689b4cSHartmut Brandt 	struct gprovider *pp;
368e8689b4cSHartmut Brandt 	struct gconfig *conf;
369e8689b4cSHartmut Brandt 	long part_type;
370e8689b4cSHartmut Brandt 
371e8689b4cSHartmut Brandt 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
372e8689b4cSHartmut Brandt 		/* We are only interested in partitions from this disk */
373e8689b4cSHartmut Brandt 		if (strcmp(gp->lg_name, disk_dev_name) != 0)
374e8689b4cSHartmut Brandt 			continue;
375e8689b4cSHartmut Brandt 
376e8689b4cSHartmut Brandt 		/*
377e8689b4cSHartmut Brandt 		 * Find all the non-BSD providers (these are handled in get_bsd)
378e8689b4cSHartmut Brandt 		 */
379e8689b4cSHartmut Brandt 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
380e8689b4cSHartmut Brandt 			LIST_FOREACH(conf, &pp->lg_config, lg_config) {
381e8689b4cSHartmut Brandt 				if (conf->lg_name == NULL ||
382e8689b4cSHartmut Brandt 				    conf->lg_val == NULL ||
383e8689b4cSHartmut Brandt 				    strcmp(conf->lg_name, "type") != 0)
384e8689b4cSHartmut Brandt 					continue;
385e8689b4cSHartmut Brandt 
386e8689b4cSHartmut Brandt 				/*
387e8689b4cSHartmut Brandt 				 * We are not interested in BSD partitions
388e8689b4cSHartmut Brandt 				 * (ie ad0s1 is not interesting at this point).
389e8689b4cSHartmut Brandt 				 * We'll take care of them in detail (slice
390e8689b4cSHartmut Brandt 				 * by slice) in get_bsd.
391e8689b4cSHartmut Brandt 				 */
392e8689b4cSHartmut Brandt 				part_type = strtol(conf->lg_val, NULL, 10);
393e8689b4cSHartmut Brandt 				if (part_type == HR_FREEBSD_PART_TYPE)
394e8689b4cSHartmut Brandt 					break;
395e8689b4cSHartmut Brandt 				HRDBG("-> MBR PROVIDER Name: %s", pp->lg_name);
396e8689b4cSHartmut Brandt 				HRDBG("Mediasize: %jd",
397e8689b4cSHartmut Brandt 				    (intmax_t)pp->lg_mediasize / 1024);
398e8689b4cSHartmut Brandt 				HRDBG("Sectorsize: %u", pp->lg_sectorsize);
399e8689b4cSHartmut Brandt 				HRDBG("Mode: %s", pp->lg_mode);
400e8689b4cSHartmut Brandt 				HRDBG("CONFIG: %s: %s",
401e8689b4cSHartmut Brandt 				    conf->lg_name, conf->lg_val);
402e8689b4cSHartmut Brandt 
403e8689b4cSHartmut Brandt 				handle_chunk(ds_index, pp->lg_name,
404e8689b4cSHartmut Brandt 				    pp->lg_mediasize);
405e8689b4cSHartmut Brandt 			}
406e8689b4cSHartmut Brandt 		}
407e8689b4cSHartmut Brandt 	}
408e8689b4cSHartmut Brandt }
409e8689b4cSHartmut Brandt 
410e8689b4cSHartmut Brandt /**
411e8689b4cSHartmut Brandt  * Process all BSD-type partitions from the given disk.
412e8689b4cSHartmut Brandt  */
413e8689b4cSHartmut Brandt static void
get_bsd_sun(struct gclass * classp,int32_t ds_index,const char * disk_dev_name)414e8689b4cSHartmut Brandt get_bsd_sun(struct gclass *classp, int32_t ds_index, const char *disk_dev_name)
415e8689b4cSHartmut Brandt {
416e8689b4cSHartmut Brandt 	struct ggeom *gp;
417e8689b4cSHartmut Brandt 	struct gprovider *pp;
418e8689b4cSHartmut Brandt 
419e8689b4cSHartmut Brandt 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
420e8689b4cSHartmut Brandt 		/*
421e8689b4cSHartmut Brandt 		 * We are only interested in those geoms starting with
422e8689b4cSHartmut Brandt 		 * the disk_dev_name passed as parameter to this function.
423e8689b4cSHartmut Brandt 		 */
424e8689b4cSHartmut Brandt 		if (strncmp(gp->lg_name, disk_dev_name,
425e8689b4cSHartmut Brandt 		    strlen(disk_dev_name)) != 0)
426e8689b4cSHartmut Brandt 			continue;
427e8689b4cSHartmut Brandt 
428e8689b4cSHartmut Brandt 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
429e8689b4cSHartmut Brandt 			if (pp->lg_name == NULL)
430e8689b4cSHartmut Brandt 				continue;
431e8689b4cSHartmut Brandt 			handle_chunk(ds_index, pp->lg_name, pp->lg_mediasize);
432e8689b4cSHartmut Brandt 		}
433e8689b4cSHartmut Brandt 	}
434e8689b4cSHartmut Brandt }
435e8689b4cSHartmut Brandt 
436e8689b4cSHartmut Brandt /**
437e8689b4cSHartmut Brandt  * Called from the DiskStorage table for every row. Open the GEOM(4) framework
438e8689b4cSHartmut Brandt  * and process all the partitions in it.
439e8689b4cSHartmut Brandt  * ds_index is the index into the DiskStorage table.
440e8689b4cSHartmut Brandt  * This is done in two steps: for non BSD partitions the geom class "MBR" is
441e8689b4cSHartmut Brandt  * used, for our BSD slices the "BSD" geom class.
442d76947f3SHartmut Brandt  */
443d76947f3SHartmut Brandt void
partition_tbl_handle_disk(int32_t ds_index,const char * disk_dev_name)444d76947f3SHartmut Brandt partition_tbl_handle_disk(int32_t ds_index, const char *disk_dev_name)
445d76947f3SHartmut Brandt {
446e8689b4cSHartmut Brandt 	struct gmesh mesh;	/* GEOM userland tree */
447e8689b4cSHartmut Brandt 	struct gclass *classp;
448e8689b4cSHartmut Brandt 	int error;
449d76947f3SHartmut Brandt 
450d76947f3SHartmut Brandt 	assert(disk_dev_name != NULL);
451d76947f3SHartmut Brandt 	assert(ds_index > 0);
452d76947f3SHartmut Brandt 
453e8689b4cSHartmut Brandt 	HRDBG("===> getting partitions for %s <===", disk_dev_name);
454e8689b4cSHartmut Brandt 
455e8689b4cSHartmut Brandt 	/* try to construct the GEOM tree */
456e8689b4cSHartmut Brandt 	if ((error = geom_gettree(&mesh)) != 0) {
457e8689b4cSHartmut Brandt 		syslog(LOG_WARNING, "cannot get GEOM tree: %m");
458d76947f3SHartmut Brandt 		return;
459d76947f3SHartmut Brandt 	}
460d76947f3SHartmut Brandt 
461e8689b4cSHartmut Brandt 	/*
462e8689b4cSHartmut Brandt 	 * First try the GEOM "MBR" class.
463e8689b4cSHartmut Brandt 	 * This is needed for non-BSD slices (aka partitions)
464e8689b4cSHartmut Brandt 	 * on PC architectures.
465e8689b4cSHartmut Brandt 	 */
466e8689b4cSHartmut Brandt 	if ((classp = find_class(&mesh, "MBR")) != NULL) {
467e8689b4cSHartmut Brandt 		get_mbr(classp, ds_index, disk_dev_name);
468e8689b4cSHartmut Brandt 	} else {
469e8689b4cSHartmut Brandt 		HRDBG("cannot find \"MBR\" geom class");
470d76947f3SHartmut Brandt 	}
471e8689b4cSHartmut Brandt 
472e8689b4cSHartmut Brandt 	/*
473e8689b4cSHartmut Brandt 	 * Get the "BSD" GEOM class.
474e8689b4cSHartmut Brandt 	 * Here we'll find all the info needed about the BSD slices.
475e8689b4cSHartmut Brandt 	 */
476e8689b4cSHartmut Brandt 	if ((classp = find_class(&mesh, "BSD")) != NULL) {
477e8689b4cSHartmut Brandt 		get_bsd_sun(classp, ds_index, disk_dev_name);
478e8689b4cSHartmut Brandt 	} else {
479e8689b4cSHartmut Brandt 		/* no problem on sparc64 */
480e8689b4cSHartmut Brandt 		HRDBG("cannot find \"BSD\" geom class");
481e8689b4cSHartmut Brandt 	}
482e8689b4cSHartmut Brandt 
483e8689b4cSHartmut Brandt 	/*
484e8689b4cSHartmut Brandt 	 * Get the "SUN" GEOM class.
4850d94b31aSWarner Losh 	 * Here we'll find all the info needed about the SUN slices.
486e8689b4cSHartmut Brandt 	 */
487e8689b4cSHartmut Brandt 	if ((classp = find_class(&mesh, "SUN")) != NULL) {
488e8689b4cSHartmut Brandt 		get_bsd_sun(classp, ds_index, disk_dev_name);
489e8689b4cSHartmut Brandt 	} else {
490e8689b4cSHartmut Brandt 		/* no problem on i386 */
491e8689b4cSHartmut Brandt 		HRDBG("cannot find \"SUN\" geom class");
492e8689b4cSHartmut Brandt 	}
493e8689b4cSHartmut Brandt 
494e8689b4cSHartmut Brandt 	geom_deletetree(&mesh);
495d76947f3SHartmut Brandt }
496d76947f3SHartmut Brandt 
497d76947f3SHartmut Brandt /**
498d76947f3SHartmut Brandt  * Finish refreshing the table.
499d76947f3SHartmut Brandt  */
500d76947f3SHartmut Brandt void
partition_tbl_post_refresh(void)501d76947f3SHartmut Brandt partition_tbl_post_refresh(void)
502d76947f3SHartmut Brandt {
503d76947f3SHartmut Brandt 	struct partition_entry *e, *etmp;
504d76947f3SHartmut Brandt 
505d76947f3SHartmut Brandt 	/*
506d76947f3SHartmut Brandt 	 * Purge items that disappeared
507d76947f3SHartmut Brandt 	 */
508d76947f3SHartmut Brandt 	TAILQ_FOREACH_SAFE(e, &partition_tbl, link, etmp)
509d76947f3SHartmut Brandt 		if (!(e->flags & HR_PARTITION_FOUND))
510d76947f3SHartmut Brandt 			partition_entry_delete(e);
511d76947f3SHartmut Brandt }
512d76947f3SHartmut Brandt 
513d76947f3SHartmut Brandt /*
514d76947f3SHartmut Brandt  * Finalization routine for hrPartitionTable
515d76947f3SHartmut Brandt  * It destroys the lists and frees any allocated heap memory
516d76947f3SHartmut Brandt  */
517d76947f3SHartmut Brandt void
fini_partition_tbl(void)518d76947f3SHartmut Brandt fini_partition_tbl(void)
519d76947f3SHartmut Brandt {
520d76947f3SHartmut Brandt 	struct partition_map_entry *m;
521d76947f3SHartmut Brandt 
522d76947f3SHartmut Brandt 	while ((m = STAILQ_FIRST(&partition_map)) != NULL) {
523d76947f3SHartmut Brandt 		STAILQ_REMOVE_HEAD(&partition_map, link);
524d76947f3SHartmut Brandt 		if(m->entry != NULL) {
525d76947f3SHartmut Brandt 			TAILQ_REMOVE(&partition_tbl, m->entry, link);
526e55adffcSHartmut Brandt 			free(m->entry->id);
527e55adffcSHartmut Brandt 			free(m->entry->label);
528d76947f3SHartmut Brandt 			free(m->entry);
529d76947f3SHartmut Brandt 		}
530e55adffcSHartmut Brandt 		free(m->id);
531d76947f3SHartmut Brandt 		free(m);
532d76947f3SHartmut Brandt 	}
533d76947f3SHartmut Brandt 	assert(TAILQ_EMPTY(&partition_tbl));
534d76947f3SHartmut Brandt }
535d76947f3SHartmut Brandt 
536d76947f3SHartmut Brandt /**
537d76947f3SHartmut Brandt  * Called from the file system code to insert the file system table index
538d76947f3SHartmut Brandt  * into the partition table entry. Note, that an partition table entry exists
539d76947f3SHartmut Brandt  * only for local file systems.
540d76947f3SHartmut Brandt  */
541d76947f3SHartmut Brandt void
handle_partition_fs_index(const char * name,int32_t fs_idx)542d76947f3SHartmut Brandt handle_partition_fs_index(const char *name, int32_t fs_idx)
543d76947f3SHartmut Brandt {
544d76947f3SHartmut Brandt 	struct partition_entry *entry;
545d76947f3SHartmut Brandt 
546d76947f3SHartmut Brandt 	if ((entry = partition_entry_find_by_label(name)) == NULL) {
547d76947f3SHartmut Brandt 		HRDBG("%s IS MISSING from hrPartitionTable", name);
548d76947f3SHartmut Brandt 		return;
549d76947f3SHartmut Brandt 	}
550d76947f3SHartmut Brandt 	HRDBG("%s [FS index = %d] IS in hrPartitionTable", name, fs_idx);
551d76947f3SHartmut Brandt 	entry->fs_Index = fs_idx;
552d76947f3SHartmut Brandt }
553d76947f3SHartmut Brandt 
554d76947f3SHartmut Brandt /*
555d76947f3SHartmut Brandt  * This is the implementation for a generated (by our SNMP tool)
556d76947f3SHartmut Brandt  * function prototype, see hostres_tree.h
557d76947f3SHartmut Brandt  * It handles the SNMP operations for hrPartitionTable
558d76947f3SHartmut Brandt  */
559d76947f3SHartmut Brandt int
op_hrPartitionTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)560d76947f3SHartmut Brandt op_hrPartitionTable(struct snmp_context *ctx __unused, struct snmp_value *value,
561d76947f3SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
562d76947f3SHartmut Brandt {
563d76947f3SHartmut Brandt 	struct partition_entry *entry;
564d76947f3SHartmut Brandt 
565d76947f3SHartmut Brandt 	/*
566d76947f3SHartmut Brandt 	 * Refresh the disk storage table (which refreshes the partition
567d76947f3SHartmut Brandt 	 * table) if necessary.
568d76947f3SHartmut Brandt 	 */
569d76947f3SHartmut Brandt 	refresh_disk_storage_tbl(0);
570d76947f3SHartmut Brandt 
571d76947f3SHartmut Brandt 	switch (op) {
572d76947f3SHartmut Brandt 
573d76947f3SHartmut Brandt 	case SNMP_OP_GETNEXT:
574e55adffcSHartmut Brandt 		if ((entry = NEXT_OBJECT_FUNC(&partition_tbl,
575e55adffcSHartmut Brandt 		    &value->var, sub, partition_idx_cmp)) == NULL)
576d76947f3SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
577d76947f3SHartmut Brandt 
578e55adffcSHartmut Brandt 		value->var.len = sub + 2;
579e55adffcSHartmut Brandt 		value->var.subs[sub] = entry->index[0];
580e55adffcSHartmut Brandt 		value->var.subs[sub + 1] = entry->index[1];
581e55adffcSHartmut Brandt 
582d76947f3SHartmut Brandt 		goto get;
583d76947f3SHartmut Brandt 
584d76947f3SHartmut Brandt 	case SNMP_OP_GET:
585e55adffcSHartmut Brandt 		if ((entry = FIND_OBJECT_FUNC(&partition_tbl,
586e55adffcSHartmut Brandt 		    &value->var, sub, partition_idx_cmp)) == NULL)
587d76947f3SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
588d76947f3SHartmut Brandt 		goto get;
589d76947f3SHartmut Brandt 
590d76947f3SHartmut Brandt 	case SNMP_OP_SET:
591e55adffcSHartmut Brandt 		if ((entry = FIND_OBJECT_FUNC(&partition_tbl,
592e55adffcSHartmut Brandt 		    &value->var, sub, partition_idx_cmp)) == NULL)
593d76947f3SHartmut Brandt 			return (SNMP_ERR_NOT_WRITEABLE);
594d76947f3SHartmut Brandt 		return (SNMP_ERR_NO_CREATION);
595d76947f3SHartmut Brandt 
596d76947f3SHartmut Brandt 	case SNMP_OP_ROLLBACK:
597d76947f3SHartmut Brandt 	case SNMP_OP_COMMIT:
598d76947f3SHartmut Brandt 		abort();
599d76947f3SHartmut Brandt 	}
600d76947f3SHartmut Brandt 	abort();
601d76947f3SHartmut Brandt 
602d76947f3SHartmut Brandt   get:
603d76947f3SHartmut Brandt 	switch (value->var.subs[sub - 1]) {
604d76947f3SHartmut Brandt 
605d76947f3SHartmut Brandt 	case LEAF_hrPartitionIndex:
606e55adffcSHartmut Brandt 		value->v.integer = entry->index[1];
607d76947f3SHartmut Brandt 		return (SNMP_ERR_NOERROR);
608d76947f3SHartmut Brandt 
609d76947f3SHartmut Brandt 	case LEAF_hrPartitionLabel:
610d76947f3SHartmut Brandt 		return (string_get(value, entry->label, -1));
611d76947f3SHartmut Brandt 
612d76947f3SHartmut Brandt 	case LEAF_hrPartitionID:
613d76947f3SHartmut Brandt 		return(string_get(value, entry->id, -1));
614d76947f3SHartmut Brandt 
615d76947f3SHartmut Brandt 	case LEAF_hrPartitionSize:
616d76947f3SHartmut Brandt 		value->v.integer = entry->size;
617d76947f3SHartmut Brandt 		return (SNMP_ERR_NOERROR);
618d76947f3SHartmut Brandt 
619d76947f3SHartmut Brandt 	case LEAF_hrPartitionFSIndex:
620d76947f3SHartmut Brandt 		value->v.integer = entry->fs_Index;
621d76947f3SHartmut Brandt 		return (SNMP_ERR_NOERROR);
622d76947f3SHartmut Brandt 	}
623d76947f3SHartmut Brandt 	abort();
624d76947f3SHartmut Brandt }
625