📄 edparams.c
字号:
/* edparams 1.17 - Modify boot parameters Author: Kees J. Bot
* 20 May 1992
*/
#define nil 0
#define _POSIX_SOURCE 1
#define _MINIX 1
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <termios.h>
/* The Minix boot block must start with these bytes: */
char boot_magic[] = { 0x31, 0xC0, 0x8E, 0xD8, 0xFA, 0x8E, 0xD0, 0xBC };
#define SECTOR_SIZE 512
#define PARAMSEC 1 /* Sector containing boot parameters. */
#define ESC 1234 /* Escape key (interrupt). */
int device; /* Device to edit parameters. */
char *devname; /* Name of device. */
struct termios termbuf;
int istty= 1;
void report(char *label)
/* edparams: label: No such file or directory */
{
fprintf(stderr, "edparams: %s: %s\n", label, strerror(errno));
}
void fatal(char *label)
{
report(label);
exit(1);
}
void *alloc(void *m, size_t n)
{
m= m == nil ? malloc(n) : realloc(m, n);
if (m == nil) fatal("");
return m;
}
char null[]= ""; /* This kludge saves lots of memory. */
void sfree(char *s)
/* Free a non-null string. */
{
if (s != nil && s != null) free(s);
}
char *copystr(char *s)
/* Copy a non-null string using malloc. */
{
char *c;
if (*s == 0) return null;
c= alloc(nil, (strlen(s) + 1) * sizeof(char));
strcpy(c, s);
return c;
}
int getch(void)
{
char c;
switch (read(0, &c, 1)) {
case -1:
if (errno != EINTR) fatal("");
return(ESC);
case 0:
if (istty) putchar('\n');
exit(0);
default:
return c & 0xFF;
}
}
/* Sticky attributes. */
#define E_SPECIAL 0x01 /* These are known to the program. */
#define E_DEV 0x02 /* The value is a device name. */
#define E_RESERVED 0x04 /* May not be set by user, e.g. 'boot' */
#define E_STICKY 0x07 /* Don't go once set. */
/* Volatile attributes. */
#define E_VAR 0x08 /* Variable */
#define E_FUNCTION 0x10 /* Function definition. */
typedef struct environment {
struct environment *next;
char flags;
char *name;
char *arg;
char *value;
char *defval; /* Safehouse for default values. */
} environment;
environment *env; /* Lists the environment. */
#define arraysize(a) (sizeof(a) / sizeof((a)[0]))
#define arraylimit(a) ((a) + arraysize(a))
char *readline(void)
/* Read a line including a newline with echoing. */
{
char *line;
size_t i, z;
int c;
i= 0;
z= 20;
line= alloc(nil, z * sizeof(char));
do {
c= getch();
if (c < ' ' && c != '\n') {
printf("\7Don't use control characters!\n");
while ((c= getch()) != '\n') {}
i= 0;
} else {
line[i++]= c;
if (i == z) {
z*= 2;
line= alloc(line, z * sizeof(char));
}
}
} while (c != '\n');
line[i]= 0;
return line;
}
int sugar(char *tok)
/* Recognize special tokens. */
{
return strchr("=(){};\n", tok[0]) != nil;
}
char *onetoken(char **aline, int arg)
/* Returns a string with one token for tokenize. Arg is true when reading
* between ( and ).
*/
{
char *line= *aline;
size_t n;
char *tok;
/* Skip spaces and runs of newlines. */
while (*line == ' ' || (*line == '\n' && line[1] == '\n')) line++;
*aline= line;
/* Don't do odd junk (nor the terminating 0!). */
if ((unsigned) *line < ' ' && *line != '\n') return nil;
if (arg) {
/* Function argument, anything goes except ). */
int depth= 0;
while ((unsigned) *line >= ' ') {
if (*line == '(') depth++;
if (*line == ')' && --depth < 0) break;
line++;
}
while (line > *aline && line[-1] == ' ') line--;
} else
if (sugar(line)) {
/* Single character token. */
line++;
} else {
/* Multicharacter token. */
do line++; while ((unsigned) *line > ' ' && !sugar(line));
}
n= line - *aline;
tok= alloc(nil, (n + 1) * sizeof(char));
memcpy(tok, *aline, n);
tok[n]= 0;
if (tok[0] == '\n') tok[0]= ';'; /* ';' same as '\n' */
*aline= line;
return tok;
}
/* Typed commands form strings of tokens. */
typedef struct token {
struct token *next; /* Next in a command chain. */
char *token;
} token;
token **tokenize(token **acmds, char *line, int *fundef)
/* Takes a line apart to form tokens. The tokens are inserted into a command
* chain at *acmds. Tokenize returns a reference to where another line could
* be added. The fundef variable holds the state tokenize is in when decoding
* a multiline function definition. It is nonzero when more must be read.
* Tokenize looks at spaces as token separators, and recognizes only
* ';', '=', '(', ')' '{', '}', and '\n' as single character tokens.
*/
{
int fd= *fundef;
char *tok;
token *newcmd;
static char funsugar[]= { '(', 0, ')', '{', '}' };
while ((tok= onetoken(&line, fd == 1)) != nil) {
if (fd == 1) {
fd++; /* Function argument. */
} else
if (funsugar[fd] == tok[0]) {
/* Recognize next token as part of a function def. */
fd= tok[0] == '}' ? 0 : fd + 1;
} else
if (fd != 0) {
if (tok[0] == ';' && fd == 3) {
/* Kill separator between ')' and '{'. */
free(tok);
continue;
}
/* Syntax error unless between '{' and '}'. */
if (fd != 4) fd= 0;
}
newcmd= alloc(nil, sizeof(*newcmd));
newcmd->token= tok;
newcmd->next= *acmds;
*acmds= newcmd;
acmds= &newcmd->next;
}
*fundef= fd;
return acmds;
}
token *cmds; /* String of commands to execute. */
int err; /* Set on an error. */
char *poptoken(void)
/* Pop one token off the command chain. */
{
token *cmd= cmds;
char *tok= cmd->token;
cmds= cmd->next;
free(cmd);
return tok;
}
void voidtoken(void)
/* Remove one token from the command chain. */
{
free(poptoken());
}
int trapsig;
void trap(int sig)
{
trapsig= sig;
signal(sig, trap);
alarm(1);
}
void interrupt(void)
/* Clean up after an ESC has been typed. */
{
printf("[ESC]\n");
trapsig= 0;
err= 1;
}
int is_default(environment *e)
{
return (e->flags & E_SPECIAL) && e->defval == nil;
}
environment **searchenv(char *name)
{
environment **aenv= &env;
while (*aenv != nil && strcmp((*aenv)->name, name) != 0) {
aenv= &(*aenv)->next;
}
return aenv;
}
#define b_getenv(name) (*searchenv(name))
/* Return the environment *structure* belonging to name, or nil if not found. */
char *b_value(char *name)
/* The value of a variable. */
{
environment *e= b_getenv(name);
return e == nil || !(e->flags & E_VAR) ? nil : e->value;
}
char *b_body(char *name)
/* The value of a function. */
{
environment *e= b_getenv(name);
return e == nil || !(e->flags & E_FUNCTION) ? nil : e->value;
}
int b_setenv(int flags, char *name, char *arg, char *value)
/* Change the value of an environment variable. Returns the flags of the
* variable if you are not allowed to change it, 0 otherwise.
*/
{
environment **aenv, *e;
if (*(aenv= searchenv(name)) == nil) {
e= alloc(nil, sizeof(*e));
e->name= copystr(name);
e->flags= flags;
e->defval= nil;
e->next= nil;
*aenv= e;
} else {
e= *aenv;
/* Don't touch reserved names and don't change special
* variables to functions or vv.
*/
if (e->flags & E_RESERVED || (e->flags & E_SPECIAL
&& (e->flags & E_FUNCTION) != (flags & E_FUNCTION)
)) return e->flags;
e->flags= (e->flags & E_STICKY) | flags;
if (is_default(e)) {
e->defval= e->value;
} else {
sfree(e->value);
}
sfree(e->arg);
}
e->arg= copystr(arg);
e->value= copystr(value);
return 0;
}
int b_setvar(int flags, char *name, char *value)
/* Set variable or simple function. */
{
return b_setenv(flags, name, null, value);
}
void b_unset(char *name)
/* Remove a variable from the environment. A special variable is reset to
* its default value.
*/
{
environment **aenv, *e;
if ((e= *(aenv= searchenv(name))) == nil) return;
if (e->flags & E_SPECIAL) {
if (e->defval != nil) {
sfree(e->arg);
e->arg= null;
sfree(e->value);
e->value= e->defval;
e->defval= nil;
}
} else {
sfree(e->name);
sfree(e->arg);
sfree(e->value);
*aenv= e->next;
free(e);
}
}
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
long a2l(char *a)
/* Cheap atol(). */
{
int sign= 1;
long n= 0;
if (*a == '-') { sign= -1; a++; }
while (between('0', *a, '9')) n= n * 10 + (*a++ - '0');
return sign * n;
}
char *ul2a(u32_t n)
/* Transform a long number to ascii digits. */
{
static char num[3 * sizeof(n)];
char *a= arraylimit(num) - 1;
do *--a = (n % 10) + '0'; while ((n/= 10) > 0);
return a;
}
char *u2a(U16_t n)
/* Transform a short number to ascii digits. */
{
return ul2a(n);
}
void get_parameters(void)
{
char params[SECTOR_SIZE + 1];
token **acmds;
int fundef= 0;
/* Variables that Minix needs: */
b_setvar(E_SPECIAL|E_VAR|E_DEV, "rootdev", "ram");
b_setvar(E_SPECIAL|E_VAR|E_DEV, "ramimagedev", "bootdev");
b_setvar(E_SPECIAL|E_VAR, "ramsize", "0");
b_setvar(E_SPECIAL|E_VAR, "processor", "?");
b_setvar(E_SPECIAL|E_VAR, "bus", "?");
b_setvar(E_SPECIAL|E_VAR, "memsize", "?");
b_setvar(E_SPECIAL|E_VAR, "emssize", "?");
b_setvar(E_SPECIAL|E_VAR, "video", "?");
b_setvar(E_SPECIAL|E_VAR, "chrome", "?");
/* Variables boot needs: */
b_setvar(E_SPECIAL|E_VAR, "image", "minix");
b_setvar(E_SPECIAL|E_FUNCTION, "main", "menu");
/* Default menu function: */
b_setenv(E_RESERVED|E_FUNCTION, "\1", "=,Start Minix", "boot");
/* Reserved names: */
b_setvar(E_RESERVED|E_VAR, "bootdev", null);
b_setvar(E_RESERVED, "boot", null);
b_setvar(E_RESERVED, "menu", null);
b_setvar(E_RESERVED, "set", null);
b_setvar(E_RESERVED, "unset", null);
b_setvar(E_RESERVED, "save", null);
b_setvar(E_RESERVED, "ls", null);
b_setvar(E_RESERVED, "echo", null);
b_setvar(E_RESERVED, "trap", null);
b_setvar(E_RESERVED, "help", null);
b_setvar(E_RESERVED, "exit", null);
memset(params, 0, sizeof(params));
/* Tokenize bootparams sector. */
if (lseek(device, PARAMSEC * SECTOR_SIZE, SEEK_SET) < 0
|| read(device, params, SECTOR_SIZE) < 0)
fatal(devname);
else {
acmds= tokenize(&cmds, params, &fundef);
/* Syntax check */
(void) tokenize(acmds, ":;", &fundef);
}
}
char *addptr;
void addparm(char *n)
{
while (*n != 0 && *addptr != 0) *addptr++ = *n++;
}
void save_parameters(void)
/* Save nondefault environment variables to the bootparams sector. */
{
environment *e;
char params[SECTOR_SIZE + 1];
/* Default filling: */
memset(params, '\n', SECTOR_SIZE);
/* Don't touch the 0! */
params[SECTOR_SIZE]= 0;
addptr= params;
for (e= env; e != nil; e= e->next) {
if (e->flags & E_RESERVED || is_default(e)) continue;
addparm(e->name);
if (e->flags & E_FUNCTION) {
addparm("(");
addparm(e->arg);
addparm("){");
} else {
addparm((e->flags & (E_DEV|E_SPECIAL)) != E_DEV
? "=" : "=d ");
}
addparm(e->value);
if (e->flags & E_FUNCTION) addparm("}");
if (*addptr == 0) {
printf("The environment is too big\n");
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -