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