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 */ 57static void 58ddb_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 65repeat: 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 */ 119void 120ddb_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 135void 136ddb_scripts(int argc, char *argv[]) 137{ 138 139 if (argc != 1) 140 usage(); 141 ddb_list_scripts(NULL); 142} 143 144void 145ddb_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