1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2007 Robert N. M. Watson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/types.h> 30 #include <sys/sysctl.h> 31 32 #include <err.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sysexits.h> 38 39 #include "ddb.h" 40 41 /* 42 * These commands manage DDB(4) scripts from user space. For better or worse, 43 * the setting and unsetting of scripts is only poorly represented using 44 * sysctl(8), and this interface provides a more user-friendly way to 45 * accomplish this management, wrapped around lower-level sysctls. For 46 * completeness, listing of scripts is also included. 47 */ 48 49 #define SYSCTL_SCRIPT "debug.ddb.scripting.script" 50 #define SYSCTL_SCRIPTS "debug.ddb.scripting.scripts" 51 #define SYSCTL_UNSCRIPT "debug.ddb.scripting.unscript" 52 53 /* 54 * Print all scripts (scriptname==NULL) or a specific script. 55 */ 56 static void 57 ddb_list_scripts(const char *scriptname) 58 { 59 char *buffer, *line, *nextline; 60 char *line_script, *line_scriptname; 61 size_t buflen, len; 62 int ret; 63 64 repeat: 65 if (sysctlbyname(SYSCTL_SCRIPTS, NULL, &buflen, NULL, 0) < 0) 66 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 67 if (buflen == 0) 68 return; 69 buffer = malloc(buflen); 70 if (buffer == NULL) 71 err(EX_OSERR, "malloc"); 72 bzero(buffer, buflen); 73 len = buflen; 74 ret = sysctlbyname(SYSCTL_SCRIPTS, buffer, &len, NULL, 0); 75 if (ret < 0 && errno != ENOMEM) 76 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 77 if (ret < 0) { 78 free(buffer); 79 goto repeat; 80 } 81 82 /* 83 * We nul'd the buffer before calling sysctl(), so at worst empty. 84 * 85 * If a specific script hasn't been requested, print it all. 86 */ 87 if (scriptname == NULL) { 88 printf("%s", buffer); 89 free(buffer); 90 return; 91 } 92 93 /* 94 * If a specific script has been requested, we have to parse the 95 * string to find it. 96 */ 97 nextline = buffer; 98 while ((line = strsep(&nextline, "\n")) != NULL) { 99 line_script = line; 100 line_scriptname = strsep(&line_script, "="); 101 if (line_script == NULL) 102 continue; 103 if (strcmp(scriptname, line_scriptname) != 0) 104 continue; 105 printf("%s\n", line_script); 106 break; 107 } 108 if (line == NULL) { 109 errno = ENOENT; 110 err(EX_DATAERR, "%s", scriptname); 111 } 112 free(buffer); 113 } 114 115 /* 116 * "ddb script" can be used to either print or set a script. 117 */ 118 void 119 ddb_script(int argc, char *argv[]) 120 { 121 122 if (argc != 2) 123 usage(); 124 argv++; 125 argc--; 126 if (strchr(argv[0], '=') != 0) { 127 if (sysctlbyname(SYSCTL_SCRIPT, NULL, NULL, argv[0], 128 strlen(argv[0]) + 1) < 0) 129 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 130 } else 131 ddb_list_scripts(argv[0]); 132 } 133 134 void 135 ddb_scripts(int argc, char *argv[] __unused) 136 { 137 138 if (argc != 1) 139 usage(); 140 ddb_list_scripts(NULL); 141 } 142 143 void 144 ddb_unscript(int argc, char *argv[]) 145 { 146 int ret; 147 148 if (argc != 2) 149 usage(); 150 argv++; 151 argc--; 152 ret = sysctlbyname(SYSCTL_UNSCRIPT, NULL, NULL, argv[0], 153 strlen(argv[0]) + 1); 154 if (ret < 0 && errno == EINVAL) { 155 errno = ENOENT; 156 err(EX_DATAERR, "sysctl: %s", argv[0]); 157 } else if (ret < 0) 158 err(EX_OSERR, "sysctl: %s", SYSCTL_UNSCRIPT); 159 } 160