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