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/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/sysctl.h> 34 35 #include <err.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sysexits.h> 41 42 #include "ddb.h" 43 44 /* 45 * These commands manage DDB(4) scripts from user space. For better or worse, 46 * the setting and unsetting of scripts is only poorly represented using 47 * sysctl(8), and this interface provides a more user-friendly way to 48 * accomplish this management, wrapped around lower-level sysctls. For 49 * completeness, listing of scripts is also included. 50 */ 51 52 #define SYSCTL_SCRIPT "debug.ddb.scripting.script" 53 #define SYSCTL_SCRIPTS "debug.ddb.scripting.scripts" 54 #define SYSCTL_UNSCRIPT "debug.ddb.scripting.unscript" 55 56 /* 57 * Print all scripts (scriptname==NULL) or a specific script. 58 */ 59 static void 60 ddb_list_scripts(const char *scriptname) 61 { 62 char *buffer, *line, *nextline; 63 char *line_script, *line_scriptname; 64 size_t buflen, len; 65 int ret; 66 67 repeat: 68 if (sysctlbyname(SYSCTL_SCRIPTS, NULL, &buflen, NULL, 0) < 0) 69 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 70 if (buflen == 0) 71 return; 72 buffer = malloc(buflen); 73 if (buffer == NULL) 74 err(EX_OSERR, "malloc"); 75 bzero(buffer, buflen); 76 len = buflen; 77 ret = sysctlbyname(SYSCTL_SCRIPTS, buffer, &len, NULL, 0); 78 if (ret < 0 && errno != ENOMEM) 79 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 80 if (ret < 0) { 81 free(buffer); 82 goto repeat; 83 } 84 85 /* 86 * We nul'd the buffer before calling sysctl(), so at worst empty. 87 * 88 * If a specific script hasn't been requested, print it all. 89 */ 90 if (scriptname == NULL) { 91 printf("%s", buffer); 92 free(buffer); 93 return; 94 } 95 96 /* 97 * If a specific script has been requested, we have to parse the 98 * string to find it. 99 */ 100 nextline = buffer; 101 while ((line = strsep(&nextline, "\n")) != NULL) { 102 line_script = line; 103 line_scriptname = strsep(&line_script, "="); 104 if (line_script == NULL) 105 continue; 106 if (strcmp(scriptname, line_scriptname) != 0) 107 continue; 108 printf("%s\n", line_script); 109 break; 110 } 111 if (line == NULL) { 112 errno = ENOENT; 113 err(EX_DATAERR, "%s", scriptname); 114 } 115 free(buffer); 116 } 117 118 /* 119 * "ddb script" can be used to either print or set a script. 120 */ 121 void 122 ddb_script(int argc, char *argv[]) 123 { 124 125 if (argc != 2) 126 usage(); 127 argv++; 128 argc--; 129 if (strchr(argv[0], '=') != 0) { 130 if (sysctlbyname(SYSCTL_SCRIPT, NULL, NULL, argv[0], 131 strlen(argv[0]) + 1) < 0) 132 err(EX_OSERR, "sysctl: %s", SYSCTL_SCRIPTS); 133 } else 134 ddb_list_scripts(argv[0]); 135 } 136 137 void 138 ddb_scripts(int argc, char *argv[] __unused) 139 { 140 141 if (argc != 1) 142 usage(); 143 ddb_list_scripts(NULL); 144 } 145 146 void 147 ddb_unscript(int argc, char *argv[]) 148 { 149 int ret; 150 151 if (argc != 2) 152 usage(); 153 argv++; 154 argc--; 155 ret = sysctlbyname(SYSCTL_UNSCRIPT, NULL, NULL, argv[0], 156 strlen(argv[0]) + 1); 157 if (ret < 0 && errno == EINVAL) { 158 errno = ENOENT; 159 err(EX_DATAERR, "sysctl: %s", argv[0]); 160 } else if (ret < 0) 161 err(EX_OSERR, "sysctl: %s", SYSCTL_UNSCRIPT); 162 } 163