diff -Naur -X exclude-files ac_cur/arch/um/config.in ac/arch/um/config.in --- ac_cur/arch/um/config.in Sat Jun 30 11:53:23 2001 +++ ac/arch/um/config.in Sat Jun 30 13:36:05 2001 @@ -32,6 +32,7 @@ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 bool 'Virtual serial line' CONFIG_SSL tristate 'Host filesystem' CONFIG_HOSTFS +bool 'Management console' CONFIG_MCONSOLE fi endmenu diff -Naur -X exclude-files ac_cur/arch/um/drivers/Makefile ac/arch/um/drivers/Makefile --- ac_cur/arch/um/drivers/Makefile Sat Jun 30 11:53:23 2001 +++ ac/arch/um/drivers/Makefile Sat Jun 30 13:36:13 2001 @@ -29,6 +29,8 @@ CFLAGS_net_kern.o := $(CFLAGS) CFLAGS_mcast_user.o := $(USER_CFLAGS) CFLAGS_mcast_kern.o := $(CFLAGS) +CFLAGS_mconsole_kern.o := $(CFLAGS) +CFLAGS_mconsole_user.o := $(USER_CFLAGS) obj-$(CONFIG_STDIO_CONSOLE) += stdio_console.o stdio_console_user.o obj-$(CONFIG_SSL) += ssl.o @@ -40,6 +42,7 @@ obj-$(CONFIG_NET_ETHERTAP) += ethertap_user.o ethertap_kern.o obj-$(CONFIG_NET_DAEMON) += daemon_kern.o daemon_user.o obj-$(CONFIG_NET_MCAST) += mcast_user.o mcast_kern.o +obj-$(CONFIG_MCONSOLE) += mconsole_kern.o mconsole_user.o override CFLAGS = diff -Naur -X exclude-files ac_cur/arch/um/drivers/mconsole_kern.c ac/arch/um/drivers/mconsole_kern.c --- ac_cur/arch/um/drivers/mconsole_kern.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/mconsole_kern.c Sat Jun 30 13:39:41 2001 @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/malloc.h" +#include "linux/init.h" +#include "linux/notifier.h" +#include "linux/reboot.h" +#include "linux/utsname.h" +#include "linux/ctype.h" +#include "asm/irq.h" +#include "user_util.h" +#include "kern_util.h" +#include "kern.h" +#include "mconsole.h" + +extern int create_listening_socket(void); +extern int get_request(int fd, struct mconsole_request *req); +extern void handle_request(struct mconsole_request *req); + +static int do_unlink_socket(struct notifier_block *, unsigned long, void *); + +static struct notifier_block reboot_notifier = { + notifier_call: do_unlink_socket, + priority: 0, +}; + +int do_unlink_socket(struct notifier_block *notifier, unsigned long what, + void *data) +{ + return(unlink_socket()); +} + +void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int fd; + struct mconsole_request req; + + fd = (int) dev_id; + while (get_request(fd, &req)) { + handle_request(&req); + } + + reactivate_fd(fd); +} + +void mconsole_version(struct mconsole_request *req) +{ + char version[256]; + + sprintf(version, "OK %s %s %s %s %s", system_utsname.sysname, + system_utsname.nodename, system_utsname.release, + system_utsname.version, system_utsname.machine); + mconsole_reply(req, version); +} + +void mconsole_halt(struct mconsole_request *req) +{ + static struct tq_struct halt = { + routine: (void (*)(void *))machine_halt, + }; + + mconsole_reply(req, "OK"); + schedule_task(&halt); +} + +void mconsole_reboot(struct mconsole_request *req) +{ + static struct tq_struct reboot = { + routine: (void (*)(void *))machine_restart, + }; + + mconsole_reply(req, "OK"); + schedule_task(&reboot); +} + +static struct config_command configs[] = { + { "gdb=", config_gdb }, +}; + +void mconsole_config(struct mconsole_request *req) +{ + struct config_command *c; + char *ptr = req->buf, *ok; + int i, err; + + ptr += strlen("config"); + while(isspace(*ptr)) ptr++; + for(i=0;icommand, strlen(c->command))){ + err = c->handler(&ptr[strlen(c->command)]); + if(err) ok = "ERR"; + else ok = "OK"; + mconsole_reply(req, ok); + return; + } + } + mconsole_reply(req, "ERR Bad configuration option"); +} + +static struct remove_command removes[] = { + { "gdb", remove_gdb }, +}; + +void mconsole_remove(struct mconsole_request *req) +{ + struct remove_command *r; + char *ptr = req->buf, *ok; + int i, err; + + ptr += strlen("remove"); + while(isspace(*ptr)) ptr++; + for(i=0;icommand, strlen(r->command))){ + err = r->handler(); + if(err) ok = "ERR"; + else ok = "OK"; + mconsole_reply(req, ok); + return; + } + } + mconsole_reply(req, "ERR Bad remove option"); +} + +int mconsole_init(void) +{ + int err; + int sock; + + sock = create_listening_socket(); + if (sock < 0) { + printk("Failed to initialize management console\n"); + return 1; + } + + register_reboot_notifier(&reboot_notifier); + + err = um_request_irq(MCONSOLE_IRQ, sock, mconsole_interrupt, + SA_INTERRUPT | SA_SHIRQ, "mconsole", + (void *)sock); + if (err) { + printk("Failed to get IRQ for management console\n"); + return 1; + } + + printk("mconsole initialized on %s\n", socket_name); + return 0; +} + +__initcall(mconsole_init); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_cur/arch/um/drivers/mconsole_user.c ac/arch/um/drivers/mconsole_user.c --- ac_cur/arch/um/drivers/mconsole_user.c Wed Dec 31 19:00:00 1969 +++ ac/arch/um/drivers/mconsole_user.c Sat Jun 30 13:39:52 2001 @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mconsole.h" + +static struct mconsole_command commands[] = { + { "version", mconsole_version }, + { "halt", mconsole_halt }, + { "reboot", mconsole_reboot }, + { "config", mconsole_config }, + { "remove", mconsole_remove }, +}; + +char socket_name[128]; + +static int has_correct_credentials(struct msghdr *msg) +{ + struct cmsghdr *cmsg; + + cmsg = CMSG_FIRSTHDR(msg); + while (cmsg != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS) { + struct ucred *cred; + + cred = (struct ucred *)CMSG_DATA(cmsg); + if (cred->uid == getuid()) + return 1; + } + cmsg = CMSG_NXTHDR(msg, cmsg); + } + + return 0; +} + +int get_request(int fd, struct mconsole_request *req) +{ + char anc[64]; + struct iovec iov; + struct msghdr msg; + + iov.iov_base = req->buf; + iov.iov_len = sizeof(req->buf) - 1; + + msg.msg_name = &(req->origin); + msg.msg_namelen = sizeof(req->origin); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = anc; + msg.msg_controllen = sizeof(anc); + msg.msg_flags = 0; + + req->len = recvmsg(fd, &msg, 0); + if (req->len < 0) + return 0; + + if (req->len < sizeof(req->buf)) + req->buf[req->len] = 0; + + req->originlen = msg.msg_namelen; + req->originating_fd = fd; + req->has_correct_credentials = has_correct_credentials(&msg); + + return 1; +} + +int mconsole_reply(struct mconsole_request *req, char *reply) +{ + struct iovec iov; + struct msghdr msg; + + iov.iov_base = reply; + iov.iov_len = strlen(reply); + + msg.msg_name = &(req->origin); + msg.msg_namelen = req->originlen; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + return sendmsg(req->originating_fd, &msg, 0); +} + +int unlink_socket(void) +{ + unlink(socket_name); + return 0; +} + +int create_listening_socket(void) +{ + struct sockaddr_un addr; + int sock; + int yes = 1; + + sock = socket(PF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) { + perror("socket"); + return -1; + } + + addr.sun_family = AF_UNIX; + + while (1) { + int err; + char *temp; + + temp = tempnam("/tmp", "uml"); + if (temp == NULL) + return -1; + + strcpy(socket_name, temp); + strcpy(addr.sun_path, temp); + + err = bind(sock, &addr, sizeof(addr)); + if (err < 0) { + if (errno != EADDRINUSE) { + perror("bind"); + return -1; + } + } else + break; + } + + setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &yes, sizeof(yes)); + + return sock; +} + +void handle_request(struct mconsole_request *req) +{ + struct mconsole_command *cmd; + int i; + + if (!req->has_correct_credentials) + return; + + for(i=0;ibuf, cmd->command, strlen(cmd->command))) { + cmd->handler(req); + return; + } + } + mconsole_reply(req, "ERR unknown command"); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_cur/arch/um/include/kern_util.h ac/arch/um/include/kern_util.h --- ac_cur/arch/um/include/kern_util.h Sat Jun 30 11:54:29 2001 +++ ac/arch/um/include/kern_util.h Sat Jun 30 13:36:23 2001 @@ -112,11 +112,13 @@ extern void kern_start_exec(int new_pid); extern void do_exitcalls(void); extern int get_restore_regs(void *t); -extern int attach_debugger(int idle_pid, int pid); +extern int attach_debugger(int idle_pid, int pid, int stop); extern void *round_up(unsigned long addr); extern void *round_down(unsigned long addr); extern void bad_segv(unsigned long address, unsigned long ip, int is_write); extern void handling_signal(void *t); +extern int config_gdb(char *str); +extern int remove_gdb(void); #endif /* diff -Naur -X exclude-files ac_cur/arch/um/include/mconsole.h ac/arch/um/include/mconsole.h --- ac_cur/arch/um/include/mconsole.h Wed Dec 31 19:00:00 1969 +++ ac/arch/um/include/mconsole.h Sat Jun 30 13:40:01 2001 @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) + * Licensed under the GPL + */ + +#ifndef __MCONSOLE_H__ +#define __MCONSOLE_H__ + +struct mconsole_request +{ + int has_correct_credentials; + int len; + char buf[512]; + + int originating_fd; + int originlen; + unsigned char origin[128]; /* sockaddr_un */ +}; + +struct mconsole_command +{ + char *command; + void (*handler)(struct mconsole_request *req); +}; + +struct config_command +{ + char *command; + int (*handler)(char *args); +}; + +struct remove_command +{ + char *command; + int (*handler)(void); +}; + +extern char socket_name[]; + +extern int unlink_socket(void); +extern int mconsole_reply(struct mconsole_request *req, char *reply); +extern void mconsole_version(struct mconsole_request *req); +extern void mconsole_halt(struct mconsole_request *req); +extern void mconsole_reboot(struct mconsole_request *req); +extern void mconsole_config(struct mconsole_request *req); +extern void mconsole_remove(struct mconsole_request *req); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_kern.c ac/arch/um/kernel/trap_kern.c --- ac_cur/arch/um/kernel/trap_kern.c Sat Jun 30 11:53:23 2001 +++ ac/arch/um/kernel/trap_kern.c Sat Jun 30 13:37:59 2001 @@ -152,6 +152,28 @@ struct io_chan gdb_chan = XTERM_IO_CHAN_INIT(0, "", 1, INIT_STATIC); char *gdb_init = "xterm"; +static void exit_debugger_cb(void *unused) +{ + if(debugger_pid != -1){ + if(gdb_pid != -1){ + if(ptrace(PTRACE_DETACH, debugger_pid, 0, 0) < 0) + printk("Detaching debugger failed - " + "errno = %d\n", errno); + gdb_pid = -1; + } + else kill(debugger_pid, SIGKILL); + debugger_pid = -1; + } + close_chan_pair(&gdb_chan); +} + +static void exit_debugger(void) +{ + tracing_cb(exit_debugger_cb, NULL); +} + +__exitcall(exit_debugger); + static void gdb_announce(char *dev_name, int dev) { printf("gdb assigned device '%s'\n", dev_name); @@ -164,6 +186,58 @@ raw_pty: 0 }; +struct gdb_data { + char *str; + int err; +}; + +static void config_gdb_cb(void *arg) +{ + struct gdb_data *data = arg; + int err, pid; + + data->err = -1; + if(debugger_pid != -1) exit_debugger_cb(NULL); + if(!strncmp(data->str, "pid,", strlen("pid,"))){ + data->str += strlen("pid,"); + pid = simple_strtoul(data->str, NULL, 0); + debugger_pid = attach_debugger(current_task->thread.extern_pid, + pid, 0); + if(debugger_pid != -1){ + data->err = 0; + gdb_pid = pid; + } + return; + } + gdb_chan = ((struct io_chan) XTERM_IO_CHAN_INIT(0, "", 1, + INIT_STATIC)); + err = parse_chan_pair(data->str, 0, &gdb_chan, INIT_ONE, &opts); + if(err) return; + data->err = 0; + debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); + init_proxy(debugger_pid, 0, 0); +} + +int config_gdb(char *str) +{ + struct gdb_data data; + + data.str = str; + tracing_cb(config_gdb_cb, &data); + return(data.err); +} + +void remove_gdb_cb(void *unused) +{ + exit_debugger_cb(NULL); +} + +int remove_gdb(void) +{ + tracing_cb(remove_gdb_cb, NULL); + return(0); +} + void signal_usr1(int sig) { if(debugger_pid != -1){ @@ -193,26 +267,19 @@ return(pid); } -int attach_debugger(int idle_pid, int pid) +int attach_debugger(int idle_pid, int pid, int stop) { - int status; + int status = 0; if(ptrace(PTRACE_ATTACH, pid, 0, 0) < 0){ printf("Failed to attach pid %d, errno = %d\n", pid, errno); return(-1); } - status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT); + if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT); init_proxy(pid, 1, status); return(pid); } -static void exit_debugger(void) -{ - close_chan_pair(&gdb_chan); -} - -__exitcall(exit_debugger); - #else void debugger_signal(int status, pid_t pid){ } @@ -230,11 +297,23 @@ printk("debug requested when CONFIG_PT_PROXY is off\n"); } -int attach_debugger(int idle_pid, int pid) +int attach_debugger(int idle_pid, int pid, int stop) +{ + printk(KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " + "is off\n"); + return(-1); +} + +int config_gdb(char *str) +{ + return(-1); +} + +int remove_gdb(void) { - printk("attach_debugger called when CONFIG_PT_PROXY is off\n"); return(-1); } + #endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff -Naur -X exclude-files ac_cur/arch/um/kernel/trap_user.c ac/arch/um/kernel/trap_user.c --- ac_cur/arch/um/kernel/trap_user.c Sat Jun 30 12:06:32 2001 +++ ac/arch/um/kernel/trap_user.c Sat Jun 30 13:38:12 2001 @@ -104,7 +104,7 @@ pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); if(debug){ if(gdb_pid != -1) - debugger_pid = attach_debugger(pid, gdb_pid); + debugger_pid = attach_debugger(pid, gdb_pid, 1); else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); } set_cmdline("(tracing thread)"); @@ -184,10 +184,6 @@ case OP_REBOOT: case OP_HALT: ptrace(PTRACE_KILL, pid, 0, 0); - if(debugger_pid != -1){ - kill(debugger_pid, SIGKILL); - close(debugger_fd); - } return(op == OP_REBOOT); case OP_NONE: printk("Detaching pid %d\n", pid); diff -Naur -X exclude-files ac_cur/include/asm-um/irq.h ac/include/asm-um/irq.h --- ac_cur/include/asm-um/irq.h Sat Jun 30 12:42:39 2001 +++ ac/include/asm-um/irq.h Sat Jun 30 13:42:08 2001 @@ -14,8 +14,9 @@ #define UM_ETH_IRQ 4 #define SSL_IRQ 5 #define ACCEPT_IRQ 6 +#define MCONSOLE_IRQ 7 -#define LAST_IRQ ACCEPT_IRQ +#define LAST_IRQ MCONSOLE_IRQ #define NR_IRQS (LAST_IRQ + 1) extern int um_request_irq(unsigned int irq, int fd,