/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2007 Robert N. M. Watson4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/types.h>29#include <sys/sysctl.h>3031#include <err.h>32#include <errno.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <sysexits.h>3738#include "ddb.h"3940/*41* These commands manage DDB(4) scripts from user space. For better or worse,42* the setting and unsetting of scripts is only poorly represented using43* sysctl(8), and this interface provides a more user-friendly way to44* accomplish this management, wrapped around lower-level sysctls. For45* completeness, listing of scripts is also included.46*/4748#define SYSCTL_SCRIPT "debug.ddb.scripting.script"49#define SYSCTL_SCRIPTS "debug.ddb.scripting.scripts"50#define SYSCTL_UNSCRIPT "debug.ddb.scripting.unscript"5152/*53* Print all scripts (scriptname==NULL) or a specific script.54*/55static void56ddb_list_scripts(const char *scriptname)57{58char *buffer, *line, *nextline;59char *line_script, *line_scriptname;60size_t buflen, len;61int ret;6263repeat:64if (sysctlbyname(SYSCTL_SCRIPTS, NULL, &buflen, NULL, 0) < 0)65err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);66if (buflen == 0)67return;68buffer = malloc(buflen);69if (buffer == NULL)70err(EX_OSERR, "malloc");71bzero(buffer, buflen);72len = buflen;73ret = sysctlbyname(SYSCTL_SCRIPTS, buffer, &len, NULL, 0);74if (ret < 0 && errno != ENOMEM)75err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);76if (ret < 0) {77free(buffer);78goto repeat;79}8081/*82* We nul'd the buffer before calling sysctl(), so at worst empty.83*84* If a specific script hasn't been requested, print it all.85*/86if (scriptname == NULL) {87printf("%s", buffer);88free(buffer);89return;90}9192/*93* If a specific script has been requested, we have to parse the94* string to find it.95*/96nextline = buffer;97while ((line = strsep(&nextline, "\n")) != NULL) {98line_script = line;99line_scriptname = strsep(&line_script, "=");100if (line_script == NULL)101continue;102if (strcmp(scriptname, line_scriptname) != 0)103continue;104printf("%s\n", line_script);105break;106}107if (line == NULL) {108errno = ENOENT;109err(EX_DATAERR, "%s", scriptname);110}111free(buffer);112}113114/*115* "ddb script" can be used to either print or set a script.116*/117void118ddb_script(int argc, char *argv[])119{120121if (argc != 2)122usage();123argv++;124argc--;125if (strchr(argv[0], '=') != 0) {126if (sysctlbyname(SYSCTL_SCRIPT, NULL, NULL, argv[0],127strlen(argv[0]) + 1) < 0)128err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS);129} else130ddb_list_scripts(argv[0]);131}132133void134ddb_scripts(int argc, char *argv[] __unused)135{136137if (argc != 1)138usage();139ddb_list_scripts(NULL);140}141142void143ddb_unscript(int argc, char *argv[])144{145int ret;146147if (argc != 2)148usage();149argv++;150argc--;151ret = sysctlbyname(SYSCTL_UNSCRIPT, NULL, NULL, argv[0],152strlen(argv[0]) + 1);153if (ret < 0 && errno == EINVAL) {154errno = ENOENT;155err(EX_DATAERR, "sysctl: %s", argv[0]);156} else if (ret < 0)157err(EX_OSERR, "sysctl: %s", SYSCTL_UNSCRIPT);158}159160161