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