1 /* $NetBSD: commands.c,v 1.18 2023/12/10 15:42:29 rillig Exp $ */ 2 3 /*- 4 * Copyright 2009 Brett Lymn <blymn@NetBSD.org> 5 * Copyright 2021 Roland Illig <rillig@NetBSD.org> 6 * 7 * All rights reserved. 8 * 9 * This code has been donated to The NetBSD Foundation by the Author. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <curses.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <unistd.h> 36 #include <err.h> 37 #include <sys/types.h> 38 39 #include "returns.h" 40 #include "slave.h" 41 #include "command_table.h" 42 43 extern int initdone; 44 45 static void report_message(data_enum_t, const char *); 46 47 /* 48 * Match the passed command string and execute the associated test 49 * function. 50 */ 51 void 52 command_execute(char *func, int nargs, char **args) 53 { 54 size_t i, j; 55 56 for (i = 0; i < ncmds; i++) { 57 if (strcmp(func, commands[i].name) != 0) 58 continue; 59 60 /* Check only restricted set of functions is called before 61 * initscr/newterm */ 62 if (initdone) { 63 /* matched function */ 64 commands[i].func(nargs, args); 65 return; 66 } 67 68 for (j = 0; j < nrcmds; j++) { 69 if (strcmp(func, restricted_commands[j]) != 0) 70 continue; 71 72 if (strcmp(func, "initscr") == 0 || 73 strcmp(func, "newterm") == 0) 74 initdone = 1; 75 76 /* matched function */ 77 commands[i].func(nargs, args); 78 return; 79 } 80 report_status("YOU NEED TO CALL INITSCR/NEWTERM FIRST"); 81 return; 82 } 83 84 report_status("UNKNOWN_FUNCTION"); 85 } 86 87 static void 88 write_to_director(const void *mem, size_t size) 89 { 90 ssize_t nwritten = write(to_director, mem, size); 91 if (nwritten == -1) 92 err(1, "writing to director failed"); 93 if ((size_t)nwritten != size) 94 errx(1, "short write to director, expected %zu, got %zd", 95 size, nwritten); 96 } 97 98 static void 99 write_to_director_int(int i) 100 { 101 write_to_director(&i, sizeof(i)); 102 } 103 104 static void 105 write_to_director_type(data_enum_t return_type) 106 { 107 write_to_director_int(return_type); 108 } 109 110 /* 111 * Report a pointer value back to the director 112 */ 113 void 114 report_ptr(void *ptr) 115 { 116 char *string; 117 118 if (ptr == NULL) 119 asprintf(&string, "NULL"); 120 else 121 asprintf(&string, "%p", ptr); 122 report_status(string); 123 free(string); 124 } 125 126 /* 127 * Report an integer value back to the director 128 */ 129 void 130 report_int(int value) 131 { 132 char *string; 133 134 asprintf(&string, "%d", value); 135 report_status(string); 136 free(string); 137 } 138 139 /* 140 * Report either an ERR or OK back to the director 141 */ 142 void 143 report_return(int status) 144 { 145 if (status == ERR) 146 write_to_director_type(data_err); 147 else if (status == OK) 148 write_to_director_type(data_ok); 149 else if (status == KEY_CODE_YES) 150 report_int(status); 151 else 152 report_status("INVALID_RETURN"); 153 } 154 155 /* 156 * Report the number of returns back to the director via the command pipe 157 */ 158 void 159 report_count(int count) 160 { 161 write_to_director_type(data_count); 162 write_to_director_int(count); 163 } 164 165 /* 166 * Report the status back to the director via the command pipe 167 */ 168 void 169 report_status(const char *status) 170 { 171 report_message(data_string, status); 172 } 173 174 /* 175 * Report an error message back to the director via the command pipe. 176 */ 177 void 178 report_error(const char *status) 179 { 180 report_message(data_slave_error, status); 181 } 182 183 /* 184 * Report the message with the given type back to the director via the 185 * command pipe. 186 */ 187 static void 188 report_message(data_enum_t type, const char *status) 189 { 190 size_t len = strlen(status); 191 write_to_director_type(type); 192 write_to_director_int(len); 193 write_to_director(status, len); 194 } 195 196 /* 197 * Report a single chtype back to the director via the command pipe. 198 */ 199 void 200 report_byte(chtype c) 201 { 202 chtype string[2]; 203 204 string[0] = c; 205 string[1] = A_NORMAL | '\0'; 206 report_nstr(string); 207 } 208 209 /* 210 * Report a string of chtype back to the director via the command pipe. 211 */ 212 void 213 report_nstr(chtype *string) 214 { 215 size_t size; 216 chtype *p; 217 218 for (p = string; (*p & __CHARTEXT) != 0; p++) 219 continue; 220 221 size = (size_t)(p + 1 - string) * sizeof(*p); 222 223 write_to_director_type(data_byte); 224 write_to_director_int(size); 225 write_to_director(string, size); 226 } 227 228 /* 229 * Report a cchar_t back to the director via the command pipe. 230 */ 231 void 232 report_cchar(cchar_t c) 233 { 234 235 write_to_director_type(data_cchar); 236 write_to_director_int(sizeof(c)); 237 write_to_director(&c, sizeof(c)); 238 } 239 240 /* 241 * Report a wchar_t back to the director via the command pipe. 242 */ 243 void 244 report_wchar(wchar_t ch) 245 { 246 wchar_t wstr[2]; 247 248 wstr[0] = ch; 249 wstr[1] = L'\0'; 250 report_wstr(wstr); 251 } 252 253 254 /* 255 * Report a string of wchar_t back to the director via the command pipe. 256 */ 257 void 258 report_wstr(wchar_t *wstr) 259 { 260 size_t size; 261 wchar_t *p; 262 263 for (p = wstr; *p != L'\0'; p++) 264 continue; 265 size = (size_t)(p + 1 - wstr) * sizeof(*p); 266 267 268 write_to_director_type(data_wchar); 269 write_to_director_int(size); 270 write_to_director(wstr, size); 271 } 272 273 /* 274 * Check the number of args we received are what we expect. Return an 275 * error if they do not match. 276 */ 277 int 278 check_arg_count(int nargs, int expected) 279 { 280 if (nargs != expected) { 281 report_count(1); 282 report_error("INCORRECT_ARGUMENT_NUMBER"); 283 return 1; 284 } 285 286 return 0; 287 } 288