1174915Srwatson/*-
2174915Srwatson * Copyright (c) 2007 Robert N. M. Watson
3174915Srwatson * All rights reserved.
4174915Srwatson *
5174915Srwatson * Redistribution and use in source and binary forms, with or without
6174915Srwatson * modification, are permitted provided that the following conditions
7174915Srwatson * are met:
8174915Srwatson * 1. Redistributions of source code must retain the above copyright
9174915Srwatson *    notice, this list of conditions and the following disclaimer.
10174915Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11174915Srwatson *    notice, this list of conditions and the following disclaimer in the
12174915Srwatson *    documentation and/or other materials provided with the distribution.
13174915Srwatson *
14174915Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15174915Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16174915Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17174915Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18174915Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19174915Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20174915Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21174915Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22174915Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23174915Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24174915Srwatson * SUCH DAMAGE.
25174915Srwatson */
26174915Srwatson
27174915Srwatson#include <sys/cdefs.h>
28174915Srwatson__FBSDID("$FreeBSD$");
29174915Srwatson
30174915Srwatson#include <sys/types.h>
31174915Srwatson#include <sys/sysctl.h>
32174915Srwatson
33174915Srwatson#include <err.h>
34174915Srwatson#include <errno.h>
35174915Srwatson#include <stdio.h>
36174915Srwatson#include <stdlib.h>
37174915Srwatson#include <string.h>
38174915Srwatson#include <sysexits.h>
39174915Srwatson
40174915Srwatson#include "ddb.h"
41174915Srwatson
42174915Srwatson/*
43174915Srwatson * These commands manage DDB(4) scripts from user space.  For better or worse,
44174915Srwatson * the setting and unsetting of scripts is only poorly represented using
45174915Srwatson * sysctl(8), and this interface provides a more user-friendly way to
46174915Srwatson * accomplish this management, wrapped around lower-level sysctls.  For
47174915Srwatson * completeness, listing of scripts is also included.
48174915Srwatson */
49174915Srwatson
50174915Srwatson#define	SYSCTL_SCRIPT	"debug.ddb.scripting.script"
51174915Srwatson#define	SYSCTL_SCRIPTS	"debug.ddb.scripting.scripts"
52174915Srwatson#define	SYSCTL_UNSCRIPT	"debug.ddb.scripting.unscript"
53174915Srwatson
54174915Srwatson/*
55174915Srwatson * Print all scripts (scriptname==NULL) or a specific script.
56174915Srwatson */
57174915Srwatsonstatic void
58174915Srwatsonddb_list_scripts(const char *scriptname)
59174915Srwatson{
60174915Srwatson	char *buffer, *line, *nextline;
61174915Srwatson	char *line_script, *line_scriptname;
62174915Srwatson	size_t buflen, len;
63174915Srwatson	int ret;
64174915Srwatson
65174915Srwatsonrepeat:
66174915Srwatson	if (sysctlbyname(SYSCTL_SCRIPTS, NULL, &buflen, NULL, 0) < 0)
67174915Srwatson		err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);
68174915Srwatson	if (buflen == 0)
69174915Srwatson		return;
70174915Srwatson	buffer = malloc(buflen);
71174915Srwatson	if (buffer == NULL)
72174915Srwatson		err(EX_OSERR, "malloc");
73174915Srwatson	bzero(buffer, buflen);
74174915Srwatson	len = buflen;
75174915Srwatson	ret = sysctlbyname(SYSCTL_SCRIPTS, buffer, &len, NULL, 0);
76174915Srwatson	if (ret < 0 && errno != ENOMEM)
77174915Srwatson		err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);
78174915Srwatson	if (ret < 0) {
79174915Srwatson		free(buffer);
80174915Srwatson		goto repeat;
81174915Srwatson	}
82174915Srwatson
83174915Srwatson	/*
84174915Srwatson	 * We nul'd the buffer before calling sysctl(), so at worst empty.
85174915Srwatson	 *
86174915Srwatson	 * If a specific script hasn't been requested, print it all.
87174915Srwatson	 */
88174915Srwatson	if (scriptname == NULL) {
89174915Srwatson		printf("%s", buffer);
90174915Srwatson		free(buffer);
91174915Srwatson		return;
92174915Srwatson	}
93174915Srwatson
94174915Srwatson	/*
95174915Srwatson	 * If a specific script has been requested, we have to parse the
96174915Srwatson	 * string to find it.
97174915Srwatson	 */
98174915Srwatson	nextline = buffer;
99174915Srwatson	while ((line = strsep(&nextline, "\n")) != NULL) {
100174915Srwatson		line_script = line;
101174915Srwatson		line_scriptname = strsep(&line_script, "=");
102174915Srwatson		if (line_script == NULL)
103174915Srwatson			continue;
104174915Srwatson		if (strcmp(scriptname, line_scriptname) != 0)
105174915Srwatson			continue;
106174915Srwatson		printf("%s\n", line_script);
107174915Srwatson		break;
108174915Srwatson	}
109174915Srwatson	if (line == NULL) {
110174915Srwatson		errno = ENOENT;
111174915Srwatson		err(EX_DATAERR, "%s", scriptname);
112174915Srwatson	}
113174915Srwatson	free(buffer);
114174915Srwatson}
115174915Srwatson
116174915Srwatson/*
117174915Srwatson * "ddb script" can be used to either print or set a script.
118174915Srwatson */
119174915Srwatsonvoid
120174915Srwatsonddb_script(int argc, char *argv[])
121174915Srwatson{
122174915Srwatson
123174915Srwatson	if (argc != 2)
124174915Srwatson		usage();
125174915Srwatson	argv++;
126174915Srwatson	argc--;
127174915Srwatson	if (strchr(argv[0], '=') != 0) {
128174915Srwatson		if (sysctlbyname(SYSCTL_SCRIPT, NULL, NULL, argv[0],
129174915Srwatson		    strlen(argv[0]) + 1) < 0)
130174915Srwatson			err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);
131174915Srwatson	} else
132174915Srwatson		ddb_list_scripts(argv[0]);
133174915Srwatson}
134174915Srwatson
135174915Srwatsonvoid
136174915Srwatsonddb_scripts(int argc, char *argv[])
137174915Srwatson{
138174915Srwatson
139174915Srwatson	if (argc != 1)
140174915Srwatson		usage();
141174915Srwatson	ddb_list_scripts(NULL);
142174915Srwatson}
143174915Srwatson
144174915Srwatsonvoid
145174915Srwatsonddb_unscript(int argc, char *argv[])
146174915Srwatson{
147174915Srwatson	int ret;
148174915Srwatson
149174915Srwatson	if (argc != 2)
150174915Srwatson		usage();
151174915Srwatson	argv++;
152174915Srwatson	argc--;
153174915Srwatson	ret = sysctlbyname(SYSCTL_UNSCRIPT, NULL, NULL, argv[0],
154174915Srwatson	    strlen(argv[0]) + 1);
155174915Srwatson	if (ret < 0 && errno == EINVAL) {
156174915Srwatson		errno = ENOENT;
157174915Srwatson		err(EX_DATAERR, "sysctl: %s", argv[0]);
158174915Srwatson	} else if (ret < 0)
159174915Srwatson		err(EX_OSERR, "sysctl: %s", SYSCTL_UNSCRIPT);
160174915Srwatson}
161