hostres_fs_tbl.c revision 160341
1154133Sharti/*-
2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project
3154133Sharti * All rights reserved.
4154133Sharti *
5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org>
6154133Sharti *
7154133Sharti * Redistribution of this software and documentation and use in source and
8154133Sharti * binary forms, with or without modification, are permitted provided that
9154133Sharti * the following conditions are met:
10154133Sharti *
11154133Sharti * 1. Redistributions of source code or documentation must retain the above
12154133Sharti *    copyright notice, this list of conditions and the following disclaimer.
13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright
14154133Sharti *    notice, this list of conditions and the following disclaimer in the
15154133Sharti *    documentation and/or other materials provided with the distribution.
16154133Sharti *
17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20154133Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27154133Sharti * SUCH DAMAGE.
28154133Sharti *
29154133Sharti * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c 160341 2006-07-14 09:07:56Z harti $
30154133Sharti */
31154133Sharti
32154133Sharti/*
33154133Sharti * Host Resources MIB for SNMPd. Implementation for hrFSTable
34154133Sharti */
35154133Sharti
36154133Sharti#include <sys/types.h>
37154133Sharti#include <sys/param.h>
38154133Sharti#include <sys/sysctl.h>
39154133Sharti#include <sys/mount.h>
40154133Sharti
41154133Sharti#include <assert.h>
42154133Sharti#include <err.h>
43154133Sharti#include <stdlib.h>
44154133Sharti#include <string.h>
45154133Sharti#include <syslog.h>
46160341Sharti#include <sysexits.h>
47154133Sharti
48154133Sharti#include "hostres_snmp.h"
49154133Sharti#include "hostres_oid.h"
50154133Sharti#include "hostres_tree.h"
51154133Sharti
52154133Sharti/*
53154133Sharti * File system access enum
54154133Sharti */
55154133Shartienum hrFSAccess {
56154133Sharti	FS_READ_WRITE = 1,
57154133Sharti	FS_READ_ONLY  = 2
58154133Sharti};
59154133Sharti
60160341Sharti/* maximum length (according to MIB) for fs_entry::mountPoint */
61160341Sharti#define	FS_MP_MLEN	(128 + 1)
62160341Sharti
63160341Sharti/* maximum length (according to MIB) for fs_entry::remoteMountPoint */
64160341Sharti#define	FS_RMP_MLEN	(128 + 1)
65160341Sharti
66154133Sharti/*
67154133Sharti * This structure is used to hold a SNMP table entry
68154133Sharti * for HOST-RESOURCES-MIB's hrFSTable
69154133Sharti */
70154133Shartistruct fs_entry {
71154133Sharti	int32_t		index;
72160341Sharti	u_char		*mountPoint;
73160341Sharti	u_char		*remoteMountPoint;
74154133Sharti	const struct asn_oid *type;
75154133Sharti	int32_t		access;		/* enum hrFSAccess, see above */
76154133Sharti	int32_t		bootable;	/* TruthValue */
77154133Sharti	int32_t		storageIndex;	/* hrStorageTblEntry::index */
78154133Sharti	u_char		lastFullBackupDate[11];
79154133Sharti	u_char		lastPartialBackupDate[11];
80160341Sharti#define	HR_FS_FOUND 0x001
81154133Sharti	uint32_t	flags;		/* not in mib table, for internal use */
82154133Sharti	TAILQ_ENTRY(fs_entry) link;
83154133Sharti};
84154133ShartiTAILQ_HEAD(fs_tbl, fs_entry);
85154133Sharti
86154133Sharti/*
87154133Sharti * Next structure is used to keep o list of mappings from a specific name
88154133Sharti * (a_name) to an entry in the hrFSTblEntry. We are trying to keep the same
89154133Sharti * index for a specific name at least for the duration of one SNMP agent run.
90154133Sharti */
91154133Shartistruct fs_map_entry {
92160341Sharti	int32_t		hrIndex;   /* used for fs_entry::index */
93160341Sharti	u_char		*a_name;   /* map key same as fs_entry::mountPoint */
94154133Sharti
95154133Sharti	/* may be NULL if the respective hrFSTblEntry is (temporally) gone */
96154133Sharti	struct fs_entry *entry;
97154133Sharti	STAILQ_ENTRY(fs_map_entry) 	link;
98154133Sharti};
99154133ShartiSTAILQ_HEAD(fs_map, fs_map_entry);
100154133Sharti
101154133Sharti/* head of the list with hrFSTable's entries */
102154133Shartistatic struct fs_tbl fs_tbl = TAILQ_HEAD_INITIALIZER(fs_tbl);
103154133Sharti
104154133Sharti/* for consistent table indexing */
105154133Shartistatic struct fs_map fs_map = STAILQ_HEAD_INITIALIZER(fs_map);
106154133Sharti
107154133Sharti/* next index available for hrFSTable */
108154133Shartistatic uint32_t	next_fs_index = 1;
109154133Sharti
110154133Sharti/* last tick when hrFSTable was updated */
111154133Shartistatic uint64_t fs_tick;
112154133Sharti
113154133Sharti/* maximum number of ticks between refreshs */
114154133Shartiuint32_t fs_tbl_refresh = HR_FS_TBL_REFRESH * 100;
115154133Sharti
116154133Sharti/* some constants */
117154133Shartistatic const struct asn_oid OIDX_hrFSBerkeleyFFS_c = OIDX_hrFSBerkeleyFFS;
118154133Shartistatic const struct asn_oid OIDX_hrFSiso9660_c = OIDX_hrFSiso9660;
119154133Shartistatic const struct asn_oid OIDX_hrFSNFS_c = OIDX_hrFSNFS;
120154133Shartistatic const struct asn_oid OIDX_hrFSLinuxExt2_c = OIDX_hrFSLinuxExt2;
121154133Shartistatic const struct asn_oid OIDX_hrFSOther_c = OIDX_hrFSOther;
122154133Shartistatic const struct asn_oid OIDX_hrFSFAT32_c = OIDX_hrFSFAT32;
123154133Shartistatic const struct asn_oid OIDX_hrFSNTFS_c = OIDX_hrFSNTFS;
124154133Shartistatic const struct asn_oid OIDX_hrFSNetware_c = OIDX_hrFSNetware;
125154133Shartistatic const struct asn_oid OIDX_hrFSHPFS_c = OIDX_hrFSHPFS;
126154133Shartistatic const struct asn_oid OIDX_hrFSUnknown_c = OIDX_hrFSUnknown;
127154133Sharti
128154133Sharti/* file system type map */
129154133Shartistatic const struct {
130154133Sharti	const char		*str;	/* the type string */
131154133Sharti	const struct asn_oid	*oid;	/* the OID to return */
132154133Sharti} fs_type_map[] = {
133154133Sharti	{ "ufs",	&OIDX_hrFSBerkeleyFFS_c },
134154133Sharti	{ "cd9660",	&OIDX_hrFSiso9660_c },
135154133Sharti	{ "nfs",	&OIDX_hrFSNFS_c },
136154133Sharti	{ "ext2fs",	&OIDX_hrFSLinuxExt2_c },
137154133Sharti	{ "procfs",	&OIDX_hrFSOther_c },
138154133Sharti	{ "devfs",	&OIDX_hrFSOther_c },
139154133Sharti	{ "msdosfs",	&OIDX_hrFSFAT32_c },
140154133Sharti	{ "ntfs",	&OIDX_hrFSNTFS_c },
141154133Sharti	{ "nwfs",	&OIDX_hrFSNetware_c },
142154133Sharti	{ "hpfs",	&OIDX_hrFSHPFS_c },
143154133Sharti	{ "smbfs",	&OIDX_hrFSOther_c },
144154133Sharti};
145154133Sharti#define	N_FS_TYPE_MAP	(sizeof(fs_type_map) / sizeof(fs_type_map[0]))
146154133Sharti
147154133Sharti/**
148154133Sharti * Create an entry into the FS table and an entry in the map (if needed).
149154133Sharti */
150154133Shartistatic struct fs_entry *
151154133Shartifs_entry_create(const char *name)
152154133Sharti{
153154133Sharti	struct fs_entry	*entry;
154154133Sharti	struct fs_map_entry *map;
155154133Sharti
156160341Sharti	assert(name != NULL);
157160341Sharti	assert(strlen(name) > 0);
158154133Sharti
159154133Sharti	STAILQ_FOREACH(map, &fs_map, link)
160160341Sharti		if (strcmp(map->a_name, name) == 0)
161154133Sharti			break;
162154133Sharti
163154133Sharti	if (map == NULL) {
164160341Sharti		size_t mount_point_len;
165160341Sharti
166154133Sharti		/* new object - get a new index */
167154133Sharti		if (next_fs_index > INT_MAX) {
168160341Sharti			/* Unrecoverable error - die clean and quicly*/
169154133Sharti		        syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__);
170160341Sharti			errx(EX_SOFTWARE, "hrFSTable index wrap");
171154133Sharti		}
172154133Sharti
173154133Sharti		if ((map = malloc(sizeof(*map))) == NULL) {
174154133Sharti			syslog(LOG_ERR, "%s: %m", __func__);
175154133Sharti			return (NULL);
176154133Sharti		}
177154133Sharti
178160341Sharti		mount_point_len = strlen(name) + 1;
179160341Sharti		if (mount_point_len > FS_MP_MLEN)
180160341Sharti			mount_point_len = FS_MP_MLEN;
181160341Sharti
182160341Sharti		if ((map->a_name = malloc(mount_point_len)) == NULL) {
183160341Sharti			syslog(LOG_ERR, "%s: %m", __func__);
184160341Sharti			free(map);
185160341Sharti			return (NULL);
186160341Sharti		}
187160341Sharti
188160341Sharti		strlcpy(map->a_name, name, mount_point_len);
189160341Sharti
190154133Sharti		map->hrIndex = next_fs_index++;
191160341Sharti		map->entry = NULL;
192154133Sharti		STAILQ_INSERT_TAIL(&fs_map, map, link);
193154133Sharti
194154133Sharti		HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex);
195154133Sharti	} else {
196154133Sharti		HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex);
197154133Sharti	}
198154133Sharti
199160341Sharti	if ((entry = malloc(sizeof(*entry))) == NULL) {
200160341Sharti		syslog(LOG_WARNING, "%s: %m", __func__);
201160341Sharti		return (NULL);
202160341Sharti	}
203160341Sharti
204160341Sharti	if ((entry->mountPoint = strdup(name)) == NULL) {
205160341Sharti		syslog(LOG_ERR, "%s: %m", __func__);
206160341Sharti		free(entry);
207160341Sharti		return (NULL);
208160341Sharti	}
209160341Sharti
210154133Sharti	entry->index = map->hrIndex;
211160341Sharti	map->entry = entry;
212154133Sharti
213154133Sharti	INSERT_OBJECT_INT(entry, &fs_tbl);
214154133Sharti	return (entry);
215154133Sharti}
216154133Sharti
217154133Sharti/**
218154133Sharti * Delete an entry in the FS table.
219154133Sharti */
220154133Shartistatic void
221154133Shartifs_entry_delete(struct fs_entry* entry)
222154133Sharti{
223154133Sharti	struct fs_map_entry *map;
224154133Sharti
225160341Sharti	assert(entry != NULL);
226160341Sharti
227154133Sharti	TAILQ_REMOVE(&fs_tbl, entry, link);
228154133Sharti	STAILQ_FOREACH(map, &fs_map, link)
229154133Sharti		if (map->entry == entry) {
230154133Sharti			map->entry = NULL;
231154133Sharti			break;
232154133Sharti		}
233160341Sharti	free(entry->mountPoint);
234160341Sharti	free(entry->remoteMountPoint);
235154133Sharti	free(entry);
236154133Sharti}
237154133Sharti
238154133Sharti/**
239154133Sharti * Find a table entry by its name
240154133Sharti */
241154133Shartistatic struct fs_entry *
242154133Shartifs_find_by_name(const char *name)
243154133Sharti{
244154133Sharti	struct fs_entry *entry;
245154133Sharti
246154133Sharti	TAILQ_FOREACH(entry, &fs_tbl, link)
247160341Sharti		if (strcmp(entry->mountPoint, name) == 0)
248154133Sharti			return (entry);
249154133Sharti
250154133Sharti	return (NULL);
251154133Sharti}
252154133Sharti
253154133Sharti/**
254154133Sharti * Get rid of all data
255154133Sharti */
256154133Shartivoid
257154133Shartifini_fs_tbl(void)
258154133Sharti{
259154133Sharti	struct fs_map_entry *n1;
260154133Sharti
261154133Sharti     	while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) {
262154133Sharti		STAILQ_REMOVE_HEAD(&fs_map, link);
263154133Sharti		if (n1->entry != NULL) {
264154133Sharti			TAILQ_REMOVE(&fs_tbl, n1->entry, link);
265160341Sharti			free(n1->entry->mountPoint);
266160341Sharti			free(n1->entry->remoteMountPoint);
267154133Sharti			free(n1->entry);
268154133Sharti		}
269160341Sharti		free(n1->a_name);
270154133Sharti		free(n1);
271154133Sharti     	}
272154133Sharti	assert(TAILQ_EMPTY(&fs_tbl));
273154133Sharti}
274154133Sharti
275154133Sharti/**
276154133Sharti * Called before the refreshing is started from the storage table.
277154133Sharti */
278154133Shartivoid
279154133Shartifs_tbl_pre_refresh(void)
280154133Sharti{
281154133Sharti	struct fs_entry *entry;
282154133Sharti
283154133Sharti	/* mark each entry as missisng */
284154133Sharti	TAILQ_FOREACH(entry, &fs_tbl, link)
285154133Sharti		entry->flags &= ~HR_FS_FOUND;
286154133Sharti}
287154133Sharti
288154133Sharti/**
289154133Sharti * Called after refreshing from the storage table.
290154133Sharti */
291154133Shartivoid
292154133Shartifs_tbl_post_refresh(void)
293154133Sharti{
294154133Sharti	struct fs_entry *entry, *entry_tmp;
295154133Sharti
296154133Sharti	/*
297154133Sharti	 * Purge items that disappeared
298154133Sharti	 */
299154133Sharti	TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp)
300154133Sharti		if (!(entry->flags & HR_FS_FOUND))
301154133Sharti			fs_entry_delete(entry);
302154133Sharti
303154133Sharti	fs_tick = this_tick;
304154133Sharti}
305154133Sharti
306154133Sharti/*
307154133Sharti * Refresh the FS table. This is done by forcing a refresh of the storage table.
308154133Sharti */
309154133Shartivoid
310154133Shartirefresh_fs_tbl(void)
311154133Sharti{
312154133Sharti
313154133Sharti	if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) {
314154133Sharti		refresh_storage_tbl(1);
315154133Sharti		HRDBG("refresh DONE");
316154133Sharti	}
317154133Sharti}
318154133Sharti
319154133Sharti/**
320154133Sharti * Get the type OID for a given file system
321154133Sharti */
322154133Sharticonst struct asn_oid *
323154133Shartifs_get_type(const struct statfs *fs_p)
324154133Sharti{
325154133Sharti	u_int t;
326154133Sharti
327154133Sharti	assert(fs_p != NULL);
328154133Sharti
329154133Sharti	for (t = 0; t < N_FS_TYPE_MAP; t++)
330154133Sharti		if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0)
331154133Sharti			return (fs_type_map[t].oid);
332154133Sharti
333154133Sharti	return (&OIDX_hrFSUnknown_c);
334154133Sharti}
335154133Sharti
336154133Sharti/*
337154133Sharti * Given information returned from statfs(2) either create a new entry into
338154133Sharti * the fs_tbl or refresh the entry if it is already there.
339154133Sharti */
340154133Shartivoid
341154133Shartifs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx)
342154133Sharti{
343154133Sharti	struct fs_entry *entry;
344154133Sharti
345154133Sharti	assert(fs_p != 0);
346154133Sharti
347154133Sharti	HRDBG("for hrStorageEntry::index %d", storage_idx);
348154133Sharti
349154133Sharti	if (fs_p == NULL)
350154133Sharti		return;
351154133Sharti
352154133Sharti	if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL ||
353154133Sharti	    (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) {
354154133Sharti		entry->flags |= HR_FS_FOUND;
355154133Sharti
356160341Sharti		if (!(fs_p->f_flags & MNT_LOCAL)) {
357154133Sharti			/* this is a remote mount */
358160341Sharti			entry->remoteMountPoint = strdup(fs_p->f_mntfromname);
359160341Sharti			/* if strdup failed, let it be NULL */
360154133Sharti
361160341Sharti		} else {
362160341Sharti			entry->remoteMountPoint = strdup("");
363160341Sharti			/* if strdup failed, let it be NULL */
364160341Sharti		}
365160341Sharti
366154133Sharti		entry->type = fs_get_type(fs_p);
367154133Sharti
368154133Sharti		if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY)
369154133Sharti			entry->access = FS_READ_ONLY;
370154133Sharti		else
371154133Sharti			entry->access = FS_READ_WRITE;
372154133Sharti
373154133Sharti		/* FIXME - bootable fs ?! */
374154133Sharti		entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS)
375154133Sharti		    == MNT_ROOTFS);
376154133Sharti
377154133Sharti		entry->storageIndex = storage_idx;
378154133Sharti
379154133Sharti		/* Info not available */
380154133Sharti		memset(entry->lastFullBackupDate, 0,
381154133Sharti		    sizeof(entry->lastFullBackupDate));
382154133Sharti
383154133Sharti		/* Info not available */
384154133Sharti		memset(entry->lastPartialBackupDate, 0,
385154133Sharti		    sizeof(entry->lastPartialBackupDate));
386154133Sharti
387154133Sharti		handle_partition_fs_index(fs_p->f_mntfromname, entry->index);
388154133Sharti	}
389154133Sharti}
390154133Sharti
391154133Sharti/*
392154133Sharti * This is the implementation for a generated (by our SNMP "compiler" tool)
393154133Sharti * function prototype, see hostres_tree.h
394154133Sharti * It handles the SNMP operations for hrFSTable
395154133Sharti */
396154133Shartiint
397154133Shartiop_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value,
398154133Sharti    u_int sub, u_int iidx __unused, enum snmp_op curr_op)
399154133Sharti{
400154133Sharti	struct fs_entry *entry;
401154133Sharti
402154133Sharti	refresh_fs_tbl();
403154133Sharti
404154133Sharti	switch (curr_op) {
405154133Sharti
406154133Sharti	case SNMP_OP_GETNEXT:
407154133Sharti		if ((entry = NEXT_OBJECT_INT(&fs_tbl,
408154133Sharti		    &value->var, sub)) == NULL)
409154133Sharti			return (SNMP_ERR_NOSUCHNAME);
410154133Sharti		value->var.len = sub + 1;
411154133Sharti		value->var.subs[sub] = entry->index;
412154133Sharti		goto get;
413154133Sharti
414154133Sharti	case SNMP_OP_GET:
415154133Sharti		if ((entry = FIND_OBJECT_INT(&fs_tbl,
416154133Sharti		    &value->var, sub)) == NULL)
417154133Sharti			return (SNMP_ERR_NOSUCHNAME);
418154133Sharti		goto get;
419154133Sharti
420154133Sharti	case SNMP_OP_SET:
421154133Sharti		if ((entry = FIND_OBJECT_INT(&fs_tbl,
422154133Sharti		    &value->var, sub)) == NULL)
423154133Sharti			return (SNMP_ERR_NO_CREATION);
424154133Sharti		return (SNMP_ERR_NOT_WRITEABLE);
425154133Sharti
426154133Sharti	case SNMP_OP_ROLLBACK:
427154133Sharti	case SNMP_OP_COMMIT:
428154133Sharti		abort();
429154133Sharti	}
430154133Sharti	abort();
431154133Sharti  get:
432154133Sharti	switch (value->var.subs[sub - 1]) {
433154133Sharti
434154133Sharti	case LEAF_hrFSIndex:
435154133Sharti		value->v.integer = entry->index;
436154133Sharti		return (SNMP_ERR_NOERROR);
437154133Sharti
438154133Sharti	case LEAF_hrFSMountPoint:
439154133Sharti		return (string_get(value, entry->mountPoint, -1));
440154133Sharti
441154133Sharti	case LEAF_hrFSRemoteMountPoint:
442160341Sharti		if (entry->remoteMountPoint == NULL)
443160341Sharti			return (string_get(value, "", -1));
444160341Sharti		else
445160341Sharti			return (string_get(value, entry->remoteMountPoint, -1));
446154133Sharti		break;
447154133Sharti
448154133Sharti	case LEAF_hrFSType:
449160341Sharti		assert(entry->type != NULL);
450160341Sharti		value->v.oid = *(entry->type);
451154133Sharti		return (SNMP_ERR_NOERROR);
452154133Sharti
453154133Sharti	case LEAF_hrFSAccess:
454154133Sharti		value->v.integer = entry->access;
455154133Sharti		return (SNMP_ERR_NOERROR);
456154133Sharti
457154133Sharti	case LEAF_hrFSBootable:
458154133Sharti		value->v.integer = entry->bootable;
459154133Sharti		return (SNMP_ERR_NOERROR);
460154133Sharti
461154133Sharti	case LEAF_hrFSStorageIndex:
462154133Sharti		value->v.integer = entry->storageIndex;
463154133Sharti		return (SNMP_ERR_NOERROR);
464154133Sharti
465154133Sharti	case LEAF_hrFSLastFullBackupDate:
466154133Sharti		return (string_get(value, entry->lastFullBackupDate, 8));
467154133Sharti
468154133Sharti	case LEAF_hrFSLastPartialBackupDate:
469154133Sharti		return (string_get(value, entry->lastPartialBackupDate, 8));
470154133Sharti	}
471154133Sharti	abort();
472154133Sharti}
473