1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * This file defines the compilation unit for the new hush shell version. The 4 * actual implementation from upstream BusyBox can be found in 5 * `cli_hush_upstream.c` which is included at the end of this file. 6 * 7 * This "wrapper" technique is used to keep the changes to the upstream version 8 * as minmal as possible. Instead, all defines and redefines necessary are done 9 * here, outside the upstream sources. This will hopefully make upgrades to 10 * newer revisions much easier. 11 * 12 * Copyright (c) 2021, Harald Seiler, DENX Software Engineering, hws@denx.de 13 */ 14 15#include <env.h> 16#include <malloc.h> /* malloc, free, realloc*/ 17#include <linux/ctype.h> /* isalpha, isdigit */ 18#include <console.h> 19#include <bootretry.h> 20#include <cli.h> 21#include <cli_hush.h> 22#include <command.h> /* find_cmd */ 23#include <asm/global_data.h> 24 25/* 26 * BusyBox Version: UPDATE THIS WHEN PULLING NEW UPSTREAM REVISION! 27 */ 28#define BB_VER "1.35.0.git7d1c7d833785" 29 30/* 31 * Define hush features by the names used upstream. 32 */ 33#define ENABLE_HUSH_INTERACTIVE 1 34#define ENABLE_FEATURE_EDITING 1 35#define ENABLE_HUSH_IF 1 36#define ENABLE_HUSH_LOOPS 1 37/* No MMU in U-Boot */ 38#define BB_MMU 0 39#define USE_FOR_NOMMU(...) __VA_ARGS__ 40#define USE_FOR_MMU(...) 41 42/* 43 * Size-saving "small" ints (arch-dependent) 44 */ 45#if CONFIG_IS_ENABLED(X86) || CONFIG_IS_ENABLED(X86_64) || CONFIG_IS_ENABLED(MIPS) 46/* add other arches which benefit from this... */ 47typedef signed char smallint; 48typedef unsigned char smalluint; 49#else 50/* for arches where byte accesses generate larger code: */ 51typedef int smallint; 52typedef unsigned smalluint; 53#endif 54 55/* 56 * Alignment defines used by BusyBox. 57 */ 58#define ALIGN1 __attribute__((aligned(1))) 59#define ALIGN2 __attribute__((aligned(2))) 60#define ALIGN4 __attribute__((aligned(4))) 61#define ALIGN8 __attribute__((aligned(8))) 62#define ALIGN_PTR __attribute__((aligned(sizeof(void*)))) 63 64/* 65 * Miscellaneous compiler/platform defines. 66 */ 67#define FAST_FUNC /* not used in U-Boot */ 68#define UNUSED_PARAM __always_unused 69#define ALWAYS_INLINE __always_inline 70#define NOINLINE noinline 71 72/* 73 * Defines to provide equivalents to what libc/BusyBox defines. 74 */ 75#define EOF (-1) 76#define EXIT_SUCCESS 0 77#define EXIT_FAILURE 1 78 79/* 80 * Stubs to provide libc/BusyBox functions based on U-Boot equivalents where it 81 * makes sense. 82 */ 83#define utoa simple_itoa 84 85static void __noreturn xfunc_die(void) 86{ 87 panic("HUSH died!"); 88} 89 90#define bb_error_msg_and_die(format, ...) do { \ 91panic("HUSH: " format, __VA_ARGS__); \ 92} while (0); 93 94#define bb_simple_error_msg_and_die(msg) do { \ 95panic_str("HUSH: " msg); \ 96} while (0); 97 98/* fdprintf() is used for debug output. */ 99static int __maybe_unused fdprintf(int fd, const char *format, ...) 100{ 101 va_list args; 102 uint i; 103 104 assert(fd == 2); 105 106 va_start(args, format); 107 i = vprintf(format, args); 108 va_end(args); 109 110 return i; 111} 112 113static void bb_verror_msg(const char *s, va_list p, const char* strerr) 114{ 115 /* TODO: what to do with strerr arg? */ 116 vprintf(s, p); 117} 118 119static void bb_error_msg(const char *s, ...) 120{ 121 va_list p; 122 123 va_start(p, s); 124 bb_verror_msg(s, p, NULL); 125 va_end(p); 126} 127 128static void bb_simple_error_msg(const char *s) 129{ 130 bb_error_msg("%s", s); 131} 132 133static void *xmalloc(size_t size) 134{ 135 void *p = NULL; 136 if (!(p = malloc(size))) 137 panic("out of memory"); 138 return p; 139} 140 141static void *xzalloc(size_t size) 142{ 143 void *p = xmalloc(size); 144 memset(p, 0, size); 145 return p; 146} 147 148static void *xrealloc(void *ptr, size_t size) 149{ 150 void *p = NULL; 151 if (!(p = realloc(ptr, size))) 152 panic("out of memory"); 153 return p; 154} 155 156static void *xmemdup(const void *s, int n) 157{ 158 return memcpy(xmalloc(n), s, n); 159} 160 161#define xstrdup strdup 162#define xstrndup strndup 163 164static void *mempcpy(void *dest, const void *src, size_t len) 165{ 166 return memcpy(dest, src, len) + len; 167} 168 169/* Like strcpy but can copy overlapping strings. */ 170static void overlapping_strcpy(char *dst, const char *src) 171{ 172 /* 173 * Cheap optimization for dst == src case - 174 * better to have it here than in many callers. 175 */ 176 if (dst != src) { 177 while ((*dst = *src) != '\0') { 178 dst++; 179 src++; 180 } 181 } 182} 183 184static char* skip_whitespace(const char *s) 185{ 186 /* 187 * In POSIX/C locale (the only locale we care about: do we REALLY want 188 * to allow Unicode whitespace in, say, .conf files? nuts!) 189 * isspace is only these chars: "\t\n\v\f\r" and space. 190 * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. 191 * Use that. 192 */ 193 while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9)) 194 s++; 195 196 return (char *) s; 197} 198 199static char* skip_non_whitespace(const char *s) 200{ 201 while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9)) 202 s++; 203 204 return (char *) s; 205} 206 207#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) 208#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) 209 210static const char* endofname(const char *name) 211{ 212 if (!is_name(*name)) 213 return name; 214 while (*++name) { 215 if (!is_in_name(*name)) 216 break; 217 } 218 return name; 219} 220 221/** 222 * list_size() - returns the number of elements in char ** before NULL. 223 * 224 * Argument must contain NULL to signalize its end. 225 * 226 * @list The list to count the number of element. 227 * @return The number of element in list. 228 */ 229static size_t list_size(char **list) 230{ 231 size_t size; 232 233 for (size = 0; list[size] != NULL; size++); 234 235 return size; 236} 237 238static int varcmp(const char *p, const char *q) 239{ 240 int c, d; 241 242 while ((c = *p) == (d = *q)) { 243 if (c == '\0' || c == '=') 244 goto out; 245 p++; 246 q++; 247 } 248 if (c == '=') 249 c = '\0'; 250 if (d == '=') 251 d = '\0'; 252out: 253 return c - d; 254} 255 256struct in_str; 257static int u_boot_cli_readline(struct in_str *i); 258 259struct in_str; 260static int u_boot_cli_readline(struct in_str *i); 261 262/* 263 * BusyBox globals which are needed for hush. 264 */ 265static uint8_t xfunc_error_retval; 266 267static const char defifsvar[] __aligned(1) = "IFS= \t\n"; 268#define defifs (defifsvar + 4) 269 270/* This define is used to check if exit command was called. */ 271#define EXIT_RET_CODE -2 272 273/* 274 * This define is used for changes that need be done directly in the upstream 275 * sources still. Ideally, its use should be minimized as much as possible. 276 */ 277#define __U_BOOT__ 278 279/* 280 * 281 * +-- Include of the upstream sources --+ * 282 * V V 283 */ 284#include "cli_hush_upstream.c" 285/* 286 * A A 287 * +-- Include of the upstream sources --+ * 288 * 289 */ 290 291int u_boot_hush_start_modern(void) 292{ 293 INIT_G(); 294 return 0; 295} 296 297static int u_boot_cli_readline(struct in_str *i) 298{ 299 char *prompt; 300 char __maybe_unused *ps_prompt = NULL; 301 302 if (!G.promptmode) 303 prompt = CONFIG_SYS_PROMPT; 304#ifdef CONFIG_SYS_PROMPT_HUSH_PS2 305 else 306 prompt = CONFIG_SYS_PROMPT_HUSH_PS2; 307#else 308 /* TODO: default value? */ 309 #error "SYS_PROMPT_HUSH_PS2 is not defined!" 310#endif 311 312 if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) { 313 if (!G.promptmode) 314 ps_prompt = env_get("PS1"); 315 else 316 ps_prompt = env_get("PS2"); 317 318 if (ps_prompt) 319 prompt = ps_prompt; 320 } 321 322 return cli_readline(prompt); 323} 324