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