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: stable/11/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_fs_tbl.c 317062 2017-04-17 18:55:54Z araujo $
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 },
134310899Sngie	{ "zfs",	&OIDX_hrFSOther_c },
135154133Sharti	{ "cd9660",	&OIDX_hrFSiso9660_c },
136154133Sharti	{ "nfs",	&OIDX_hrFSNFS_c },
137154133Sharti	{ "ext2fs",	&OIDX_hrFSLinuxExt2_c },
138154133Sharti	{ "procfs",	&OIDX_hrFSOther_c },
139154133Sharti	{ "devfs",	&OIDX_hrFSOther_c },
140154133Sharti	{ "msdosfs",	&OIDX_hrFSFAT32_c },
141154133Sharti	{ "ntfs",	&OIDX_hrFSNTFS_c },
142154133Sharti	{ "nwfs",	&OIDX_hrFSNetware_c },
143154133Sharti	{ "hpfs",	&OIDX_hrFSHPFS_c },
144154133Sharti	{ "smbfs",	&OIDX_hrFSOther_c },
145154133Sharti};
146317062Saraujo#define	N_FS_TYPE_MAP	nitems(fs_type_map)
147154133Sharti
148154133Sharti/**
149154133Sharti * Create an entry into the FS table and an entry in the map (if needed).
150154133Sharti */
151154133Shartistatic struct fs_entry *
152154133Shartifs_entry_create(const char *name)
153154133Sharti{
154154133Sharti	struct fs_entry	*entry;
155154133Sharti	struct fs_map_entry *map;
156154133Sharti
157160341Sharti	assert(name != NULL);
158160341Sharti	assert(strlen(name) > 0);
159154133Sharti
160154133Sharti	STAILQ_FOREACH(map, &fs_map, link)
161160341Sharti		if (strcmp(map->a_name, name) == 0)
162154133Sharti			break;
163154133Sharti
164154133Sharti	if (map == NULL) {
165160341Sharti		size_t mount_point_len;
166160341Sharti
167154133Sharti		/* new object - get a new index */
168154133Sharti		if (next_fs_index > INT_MAX) {
169160341Sharti			/* Unrecoverable error - die clean and quicly*/
170310899Sngie			syslog(LOG_ERR, "%s: hrFSTable index wrap", __func__);
171160341Sharti			errx(EX_SOFTWARE, "hrFSTable index wrap");
172154133Sharti		}
173154133Sharti
174154133Sharti		if ((map = malloc(sizeof(*map))) == NULL) {
175154133Sharti			syslog(LOG_ERR, "%s: %m", __func__);
176154133Sharti			return (NULL);
177154133Sharti		}
178154133Sharti
179160341Sharti		mount_point_len = strlen(name) + 1;
180160341Sharti		if (mount_point_len > FS_MP_MLEN)
181160341Sharti			mount_point_len = FS_MP_MLEN;
182160341Sharti
183160341Sharti		if ((map->a_name = malloc(mount_point_len)) == NULL) {
184160341Sharti			syslog(LOG_ERR, "%s: %m", __func__);
185160341Sharti			free(map);
186160341Sharti			return (NULL);
187160341Sharti		}
188160341Sharti
189160341Sharti		strlcpy(map->a_name, name, mount_point_len);
190160341Sharti
191154133Sharti		map->hrIndex = next_fs_index++;
192160341Sharti		map->entry = NULL;
193154133Sharti		STAILQ_INSERT_TAIL(&fs_map, map, link);
194154133Sharti
195154133Sharti		HRDBG("%s added into hrFSMap at index=%d", name, map->hrIndex);
196154133Sharti	} else {
197154133Sharti		HRDBG("%s exists in hrFSMap index=%d", name, map->hrIndex);
198154133Sharti	}
199154133Sharti
200160341Sharti	if ((entry = malloc(sizeof(*entry))) == NULL) {
201160341Sharti		syslog(LOG_WARNING, "%s: %m", __func__);
202160341Sharti		return (NULL);
203160341Sharti	}
204160341Sharti
205160341Sharti	if ((entry->mountPoint = strdup(name)) == NULL) {
206160341Sharti		syslog(LOG_ERR, "%s: %m", __func__);
207160341Sharti		free(entry);
208160341Sharti		return (NULL);
209160341Sharti	}
210160341Sharti
211154133Sharti	entry->index = map->hrIndex;
212160341Sharti	map->entry = entry;
213154133Sharti
214154133Sharti	INSERT_OBJECT_INT(entry, &fs_tbl);
215154133Sharti	return (entry);
216154133Sharti}
217154133Sharti
218154133Sharti/**
219154133Sharti * Delete an entry in the FS table.
220154133Sharti */
221154133Shartistatic void
222154133Shartifs_entry_delete(struct fs_entry* entry)
223154133Sharti{
224154133Sharti	struct fs_map_entry *map;
225154133Sharti
226160341Sharti	assert(entry != NULL);
227160341Sharti
228154133Sharti	TAILQ_REMOVE(&fs_tbl, entry, link);
229154133Sharti	STAILQ_FOREACH(map, &fs_map, link)
230154133Sharti		if (map->entry == entry) {
231154133Sharti			map->entry = NULL;
232154133Sharti			break;
233154133Sharti		}
234160341Sharti	free(entry->mountPoint);
235160341Sharti	free(entry->remoteMountPoint);
236154133Sharti	free(entry);
237154133Sharti}
238154133Sharti
239154133Sharti/**
240154133Sharti * Find a table entry by its name
241154133Sharti */
242154133Shartistatic struct fs_entry *
243154133Shartifs_find_by_name(const char *name)
244154133Sharti{
245154133Sharti	struct fs_entry *entry;
246154133Sharti
247154133Sharti	TAILQ_FOREACH(entry, &fs_tbl, link)
248160341Sharti		if (strcmp(entry->mountPoint, name) == 0)
249154133Sharti			return (entry);
250154133Sharti
251154133Sharti	return (NULL);
252154133Sharti}
253154133Sharti
254154133Sharti/**
255154133Sharti * Get rid of all data
256154133Sharti */
257154133Shartivoid
258154133Shartifini_fs_tbl(void)
259154133Sharti{
260154133Sharti	struct fs_map_entry *n1;
261154133Sharti
262154133Sharti     	while ((n1 = STAILQ_FIRST(&fs_map)) != NULL) {
263154133Sharti		STAILQ_REMOVE_HEAD(&fs_map, link);
264154133Sharti		if (n1->entry != NULL) {
265154133Sharti			TAILQ_REMOVE(&fs_tbl, n1->entry, link);
266160341Sharti			free(n1->entry->mountPoint);
267160341Sharti			free(n1->entry->remoteMountPoint);
268154133Sharti			free(n1->entry);
269154133Sharti		}
270160341Sharti		free(n1->a_name);
271154133Sharti		free(n1);
272154133Sharti     	}
273154133Sharti	assert(TAILQ_EMPTY(&fs_tbl));
274154133Sharti}
275154133Sharti
276154133Sharti/**
277154133Sharti * Called before the refreshing is started from the storage table.
278154133Sharti */
279154133Shartivoid
280154133Shartifs_tbl_pre_refresh(void)
281154133Sharti{
282154133Sharti	struct fs_entry *entry;
283154133Sharti
284154133Sharti	/* mark each entry as missisng */
285154133Sharti	TAILQ_FOREACH(entry, &fs_tbl, link)
286154133Sharti		entry->flags &= ~HR_FS_FOUND;
287154133Sharti}
288154133Sharti
289154133Sharti/**
290154133Sharti * Called after refreshing from the storage table.
291154133Sharti */
292154133Shartivoid
293154133Shartifs_tbl_post_refresh(void)
294154133Sharti{
295154133Sharti	struct fs_entry *entry, *entry_tmp;
296154133Sharti
297154133Sharti	/*
298154133Sharti	 * Purge items that disappeared
299154133Sharti	 */
300154133Sharti	TAILQ_FOREACH_SAFE(entry, &fs_tbl, link, entry_tmp)
301154133Sharti		if (!(entry->flags & HR_FS_FOUND))
302154133Sharti			fs_entry_delete(entry);
303154133Sharti
304154133Sharti	fs_tick = this_tick;
305154133Sharti}
306154133Sharti
307154133Sharti/*
308154133Sharti * Refresh the FS table. This is done by forcing a refresh of the storage table.
309154133Sharti */
310154133Shartivoid
311154133Shartirefresh_fs_tbl(void)
312154133Sharti{
313154133Sharti
314154133Sharti	if (fs_tick == 0 || this_tick - fs_tick >= fs_tbl_refresh) {
315154133Sharti		refresh_storage_tbl(1);
316154133Sharti		HRDBG("refresh DONE");
317154133Sharti	}
318154133Sharti}
319154133Sharti
320154133Sharti/**
321154133Sharti * Get the type OID for a given file system
322154133Sharti */
323154133Sharticonst struct asn_oid *
324154133Shartifs_get_type(const struct statfs *fs_p)
325154133Sharti{
326154133Sharti	u_int t;
327154133Sharti
328154133Sharti	assert(fs_p != NULL);
329154133Sharti
330154133Sharti	for (t = 0; t < N_FS_TYPE_MAP; t++)
331154133Sharti		if (strcmp(fs_type_map[t].str, fs_p->f_fstypename) == 0)
332154133Sharti			return (fs_type_map[t].oid);
333154133Sharti
334154133Sharti	return (&OIDX_hrFSUnknown_c);
335154133Sharti}
336154133Sharti
337154133Sharti/*
338154133Sharti * Given information returned from statfs(2) either create a new entry into
339154133Sharti * the fs_tbl or refresh the entry if it is already there.
340154133Sharti */
341154133Shartivoid
342154133Shartifs_tbl_process_statfs_entry(const struct statfs *fs_p, int32_t storage_idx)
343154133Sharti{
344154133Sharti	struct fs_entry *entry;
345154133Sharti
346154133Sharti	assert(fs_p != 0);
347154133Sharti
348154133Sharti	HRDBG("for hrStorageEntry::index %d", storage_idx);
349154133Sharti
350154133Sharti	if (fs_p == NULL)
351154133Sharti		return;
352154133Sharti
353154133Sharti	if ((entry = fs_find_by_name(fs_p->f_mntonname)) != NULL ||
354154133Sharti	    (entry = fs_entry_create(fs_p->f_mntonname)) != NULL) {
355154133Sharti		entry->flags |= HR_FS_FOUND;
356154133Sharti
357160341Sharti		if (!(fs_p->f_flags & MNT_LOCAL)) {
358154133Sharti			/* this is a remote mount */
359160341Sharti			entry->remoteMountPoint = strdup(fs_p->f_mntfromname);
360160341Sharti			/* if strdup failed, let it be NULL */
361154133Sharti
362160341Sharti		} else {
363160341Sharti			entry->remoteMountPoint = strdup("");
364160341Sharti			/* if strdup failed, let it be NULL */
365160341Sharti		}
366160341Sharti
367154133Sharti		entry->type = fs_get_type(fs_p);
368154133Sharti
369154133Sharti		if ((fs_p->f_flags & MNT_RDONLY) == MNT_RDONLY)
370154133Sharti			entry->access = FS_READ_ONLY;
371154133Sharti		else
372154133Sharti			entry->access = FS_READ_WRITE;
373154133Sharti
374154133Sharti		/* FIXME - bootable fs ?! */
375154133Sharti		entry->bootable = TRUTH_MK((fs_p->f_flags & MNT_ROOTFS)
376154133Sharti		    == MNT_ROOTFS);
377154133Sharti
378154133Sharti		entry->storageIndex = storage_idx;
379154133Sharti
380154133Sharti		/* Info not available */
381154133Sharti		memset(entry->lastFullBackupDate, 0,
382154133Sharti		    sizeof(entry->lastFullBackupDate));
383154133Sharti
384154133Sharti		/* Info not available */
385154133Sharti		memset(entry->lastPartialBackupDate, 0,
386154133Sharti		    sizeof(entry->lastPartialBackupDate));
387154133Sharti
388154133Sharti		handle_partition_fs_index(fs_p->f_mntfromname, entry->index);
389154133Sharti	}
390154133Sharti}
391154133Sharti
392154133Sharti/*
393154133Sharti * This is the implementation for a generated (by our SNMP "compiler" tool)
394154133Sharti * function prototype, see hostres_tree.h
395154133Sharti * It handles the SNMP operations for hrFSTable
396154133Sharti */
397154133Shartiint
398154133Shartiop_hrFSTable(struct snmp_context *ctx __unused, struct snmp_value *value,
399154133Sharti    u_int sub, u_int iidx __unused, enum snmp_op curr_op)
400154133Sharti{
401154133Sharti	struct fs_entry *entry;
402154133Sharti
403154133Sharti	refresh_fs_tbl();
404154133Sharti
405154133Sharti	switch (curr_op) {
406154133Sharti
407154133Sharti	case SNMP_OP_GETNEXT:
408154133Sharti		if ((entry = NEXT_OBJECT_INT(&fs_tbl,
409154133Sharti		    &value->var, sub)) == NULL)
410154133Sharti			return (SNMP_ERR_NOSUCHNAME);
411154133Sharti		value->var.len = sub + 1;
412154133Sharti		value->var.subs[sub] = entry->index;
413154133Sharti		goto get;
414154133Sharti
415154133Sharti	case SNMP_OP_GET:
416154133Sharti		if ((entry = FIND_OBJECT_INT(&fs_tbl,
417154133Sharti		    &value->var, sub)) == NULL)
418154133Sharti			return (SNMP_ERR_NOSUCHNAME);
419154133Sharti		goto get;
420154133Sharti
421154133Sharti	case SNMP_OP_SET:
422154133Sharti		if ((entry = FIND_OBJECT_INT(&fs_tbl,
423154133Sharti		    &value->var, sub)) == NULL)
424154133Sharti			return (SNMP_ERR_NO_CREATION);
425154133Sharti		return (SNMP_ERR_NOT_WRITEABLE);
426154133Sharti
427154133Sharti	case SNMP_OP_ROLLBACK:
428154133Sharti	case SNMP_OP_COMMIT:
429154133Sharti		abort();
430154133Sharti	}
431154133Sharti	abort();
432154133Sharti  get:
433154133Sharti	switch (value->var.subs[sub - 1]) {
434154133Sharti
435154133Sharti	case LEAF_hrFSIndex:
436154133Sharti		value->v.integer = entry->index;
437154133Sharti		return (SNMP_ERR_NOERROR);
438154133Sharti
439154133Sharti	case LEAF_hrFSMountPoint:
440154133Sharti		return (string_get(value, entry->mountPoint, -1));
441154133Sharti
442154133Sharti	case LEAF_hrFSRemoteMountPoint:
443160341Sharti		if (entry->remoteMountPoint == NULL)
444160341Sharti			return (string_get(value, "", -1));
445160341Sharti		else
446160341Sharti			return (string_get(value, entry->remoteMountPoint, -1));
447154133Sharti		break;
448154133Sharti
449154133Sharti	case LEAF_hrFSType:
450160341Sharti		assert(entry->type != NULL);
451160341Sharti		value->v.oid = *(entry->type);
452154133Sharti		return (SNMP_ERR_NOERROR);
453154133Sharti
454154133Sharti	case LEAF_hrFSAccess:
455154133Sharti		value->v.integer = entry->access;
456154133Sharti		return (SNMP_ERR_NOERROR);
457154133Sharti
458154133Sharti	case LEAF_hrFSBootable:
459154133Sharti		value->v.integer = entry->bootable;
460154133Sharti		return (SNMP_ERR_NOERROR);
461154133Sharti
462154133Sharti	case LEAF_hrFSStorageIndex:
463154133Sharti		value->v.integer = entry->storageIndex;
464154133Sharti		return (SNMP_ERR_NOERROR);
465154133Sharti
466154133Sharti	case LEAF_hrFSLastFullBackupDate:
467154133Sharti		return (string_get(value, entry->lastFullBackupDate, 8));
468154133Sharti
469154133Sharti	case LEAF_hrFSLastPartialBackupDate:
470154133Sharti		return (string_get(value, entry->lastPartialBackupDate, 8));
471154133Sharti	}
472154133Sharti	abort();
473154133Sharti}
474