diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2000-03-21 10:25:23 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2000-03-21 10:25:23 +0000 |
| commit | ce7d1eb4914acc59f7408e0f17f0ae69d18869c9 (patch) | |
| tree | 39e6c467cb01b19b7303a7f01d6813178de826f3 | |
| parent | a8f574395cd8235daba4282e257d05aa7c171d80 (diff) | |
Notes
| -rw-r--r-- | contrib/libreadline/USAGE | 37 | ||||
| -rw-r--r-- | contrib/libreadline/doc/rluserman.texinfo | 94 | ||||
| -rw-r--r-- | contrib/libreadline/examples/excallback.c | 186 | ||||
| -rw-r--r-- | contrib/libreadline/examples/rlfe.c | 685 | ||||
| -rw-r--r-- | contrib/libreadline/rlprivate.h | 271 | ||||
| -rw-r--r-- | contrib/libreadline/rlshell.h | 34 | ||||
| -rw-r--r-- | contrib/libreadline/xmalloc.h | 46 | ||||
| -rw-r--r-- | lib/libc/sys/aio_waitcomplete.2 | 129 | ||||
| -rw-r--r-- | sbin/pc98/Makefile | 7 | ||||
| -rw-r--r-- | sbin/pc98/Makefile.inc | 3 | ||||
| -rw-r--r-- | sbin/pc98/fdisk/Makefile | 8 | ||||
| -rw-r--r-- | sbin/pc98/fdisk/fdisk.8 | 468 | ||||
| -rw-r--r-- | sbin/pc98/fdisk/fdisk.c | 1539 | ||||
| -rw-r--r-- | sys/alpha/pci/dwlpx_pci.c | 80 | ||||
| -rw-r--r-- | sys/alpha/tlsb/dwlpxvar.h | 92 | ||||
| -rw-r--r-- | sys/alpha/tlsb/tlsbcpu.c | 121 | ||||
| -rw-r--r-- | usr.bin/fstat/cd9660.c | 78 | ||||
| -rw-r--r-- | usr.bin/fstat/fstat.h | 73 | ||||
| -rw-r--r-- | usr.bin/fstat/msdosfs.c | 150 |
19 files changed, 4101 insertions, 0 deletions
diff --git a/contrib/libreadline/USAGE b/contrib/libreadline/USAGE new file mode 100644 index 000000000000..edc9f5417d4e --- /dev/null +++ b/contrib/libreadline/USAGE @@ -0,0 +1,37 @@ +From rms@gnu.org Thu Jul 22 20:37:55 1999 +Flags: 10 +Return-Path: rms@gnu.org +Received: from arthur.INS.CWRU.Edu (root@arthur.INS.CWRU.Edu [129.22.8.215]) by odin.INS.CWRU.Edu with ESMTP (8.8.6+cwru/CWRU-2.4-ins) + id UAA25349; Thu, 22 Jul 1999 20:37:54 -0400 (EDT) (from rms@gnu.org for <chet@odin.INS.CWRU.Edu>) +Received: from nike.ins.cwru.edu (root@nike.INS.CWRU.Edu [129.22.8.219]) by arthur.INS.CWRU.Edu with ESMTP (8.8.8+cwru/CWRU-3.6) + id UAA05311; Thu, 22 Jul 1999 20:37:51 -0400 (EDT) (from rms@gnu.org for <chet@po.cwru.edu>) +Received: from pele.santafe.edu (pele.santafe.edu [192.12.12.119]) by nike.ins.cwru.edu with ESMTP (8.8.7/CWRU-2.5-bsdi) + id UAA13350; Thu, 22 Jul 1999 20:37:50 -0400 (EDT) (from rms@gnu.org for <chet@nike.ins.cwru.edu>) +Received: from wijiji.santafe.edu (wijiji [192.12.12.5]) + by pele.santafe.edu (8.9.1/8.9.1) with ESMTP id SAA10831 + for <chet@nike.ins.cwru.edu>; Thu, 22 Jul 1999 18:37:47 -0600 (MDT) +Received: (from rms@localhost) + by wijiji.santafe.edu (8.9.1b+Sun/8.9.1) id SAA01089; + Thu, 22 Jul 1999 18:37:46 -0600 (MDT) +Date: Thu, 22 Jul 1999 18:37:46 -0600 (MDT) +Message-Id: <199907230037.SAA01089@wijiji.santafe.edu> +X-Authentication-Warning: wijiji.santafe.edu: rms set sender to rms@gnu.org using -f +From: Richard Stallman <rms@gnu.org> +To: chet@nike.ins.cwru.edu +Subject: Use of Readline +Reply-to: rms@gnu.org + +I think Allbery's suggestion is a good one. So please add this text +in a suitable place. Please don't put it in the GPL itself; that +should be the same as the GPL everywhere else. Putting it in the +README and/or the documentation would be a good idea. + + +====================================================================== +Our position on the use of Readline through a shared-library linking +mechanism is that there is no legal difference between shared-library +linking and static linking--either kind of linking combines various +modules into a single larger work. The conditions for using Readline +in a larger work are stated in section 3 of the GNU GPL. + + diff --git a/contrib/libreadline/doc/rluserman.texinfo b/contrib/libreadline/doc/rluserman.texinfo new file mode 100644 index 000000000000..e6a3dcde2a94 --- /dev/null +++ b/contrib/libreadline/doc/rluserman.texinfo @@ -0,0 +1,94 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header (This is for running Texinfo on a region.) +@setfilename rluserman.info +@settitle GNU Readline Library +@comment %**end of header (This is for running Texinfo on a region.) +@setchapternewpage odd + +@include manvers.texinfo + +@ifinfo +@dircategory Libraries +@direntry +* Readline: (readline). The GNU readline library API +@end direntry + +This document describes the end user interface of the GNU Readline Library, +a utility which aids in the consistency of user interface across discrete +programs that need to provide a command line interface. + +Copyright (C) 1988-1999 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +pare preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). +@end ignore + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Free Software Foundation. +@end ifinfo + +@titlepage +@title GNU Readline Library User Interface +@subtitle Edition @value{EDITION}, for @code{Readline Library} Version @value{VERSION}. +@subtitle @value{UPDATE-MONTH} +@author Brian Fox, Free Software Foundation +@author Chet Ramey, Case Western Reserve University + +@page +This document describes the end user interface of the GNU Readline Library, +a utility which aids in the consistency of user interface across discrete +programs that need to provide a command line interface. + +Published by the Free Software Foundation @* +59 Temple Place, Suite 330, @* +Boston, MA 02111 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Free Software Foundation. + +@vskip 0pt plus 1filll +Copyright @copyright{} 1988-1999 Free Software Foundation, Inc. +@end titlepage + +@ifinfo +@node Top +@top GNU Readline Library + +This document describes the end user interface of the GNU Readline Library, +a utility which aids in the consistency of user interface across discrete +programs that need to provide a command line interface. + +@menu +* Command Line Editing:: GNU Readline User's Manual. +@end menu +@end ifinfo + +@include rluser.texinfo + +@contents +@bye diff --git a/contrib/libreadline/examples/excallback.c b/contrib/libreadline/examples/excallback.c new file mode 100644 index 000000000000..ca03fc3dafd9 --- /dev/null +++ b/contrib/libreadline/examples/excallback.c @@ -0,0 +1,186 @@ +/* +From: Jeff Solomon <jsolomon@stanford.edu> +Date: Fri, 9 Apr 1999 10:13:27 -0700 (PDT) +To: chet@po.cwru.edu +Subject: new readline example +Message-ID: <14094.12094.527305.199695@mrclean.Stanford.EDU> + +Chet, + +I've been using readline 4.0. Specifically, I've been using the perl +version Term::ReadLine::Gnu. It works great. + +Anyway, I've been playing around the alternate interface and I wanted +to contribute a little C program, callback.c, to you that you could +use as an example of the alternate interface in the /examples +directory of the readline distribution. + +My example shows how, using the alternate interface, you can +interactively change the prompt (which is very nice imo). Also, I +point out that you must roll your own terminal setting when using the +alternate interface because readline depreps (using your parlance) the +terminal while in the user callback. I try to demostrate what I mean +with an example. I've included the program below. + +To compile, I just put the program in the examples directory and made +the appropriate changes to the EXECUTABLES and OBJECTS line and added +an additional target 'callback'. + +I compiled on my Sun Solaris2.6 box using Sun's cc. + +Let me know what you think. + +Jeff +*/ + +#if defined (HAVE_CONFIG_H) +#include <config.h> +#endif + +#include <stdio.h> +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <termios.h> /* xxx - should make this more general */ + +#ifdef READLINE_LIBRARY +# include "readline.h" +#else +# include <readline/readline.h> +#endif + +/* This little examples demonstrates the alternate interface to using readline. + * In the alternate interface, the user maintains control over program flow and + * only calls readline when STDIN is readable. Using the alternate interface, + * you can do anything else while still using readline (like talking to a + * network or another program) without blocking. + * + * Specifically, this program highlights two importants features of the + * alternate interface. The first is the ability to interactively change the + * prompt, which can't be done using the regular interface since rl_prompt is + * read-only. + * + * The second feature really highlights a subtle point when using the alternate + * interface. That is, readline will not alter the terminal when inside your + * callback handler. So let's so, your callback executes a user command that + * takes a non-trivial amount of time to complete (seconds). While your + * executing the command, the user continues to type keystrokes and expects them + * to be re-echoed on the new prompt when it returns. Unfortunately, the default + * terminal configuration doesn't do this. After the prompt returns, the user + * must hit one additional keystroke and then will see all of his previous + * keystrokes. To illustrate this, compile and run this program. Type "sleep" at + * the prompt and then type "bar" before the prompt returns (you have 3 + * seconds). Notice how "bar" is re-echoed on the prompt after the prompt + * returns? This is what you expect to happen. Now comment out the 4 lines below + * the line that says COMMENT LINE BELOW. Recompile and rerun the program and do + * the same thing. When the prompt returns, you should not see "bar". Now type + * "f", see how "barf" magically appears? This behavior is un-expected and not + * desired. + */ + +void process_line(char *line); +int change_prompt(void); +char *get_prompt(void); + +int prompt = 1; +char prompt_buf[40], line_buf[256]; +tcflag_t old_lflag; +cc_t old_vtime; +struct termios term; + +int +main() +{ + fd_set fds; + + /* Adjust the terminal slightly before the handler is installed. Disable + * canonical mode processing and set the input character time flag to be + * non-blocking. + */ + if( tcgetattr(STDIN_FILENO, &term) < 0 ) { + perror("tcgetattr"); + exit(1); + } + old_lflag = term.c_lflag; + old_vtime = term.c_cc[VTIME]; + term.c_lflag &= ~ICANON; + term.c_cc[VTIME] = 1; + /* COMMENT LINE BELOW - see above */ + if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) { + perror("tcsetattr"); + exit(1); + } + + rl_add_defun("change-prompt", change_prompt, CTRL('t')); + rl_callback_handler_install(get_prompt(), process_line); + + while(1) { + FD_ZERO(&fds); + FD_SET(fileno(stdin), &fds); + + if( select(FD_SETSIZE, &fds, NULL, NULL, NULL) < 0) { + perror("select"); + exit(1); + } + + if( FD_ISSET(fileno(stdin), &fds) ) { + rl_callback_read_char(); + } + } +} + +void +process_line(char *line) +{ + if( line == NULL ) { + fprintf(stderr, "\n", line); + + /* reset the old terminal setting before exiting */ + term.c_lflag = old_lflag; + term.c_cc[VTIME] = old_vtime; + if( tcsetattr(STDIN_FILENO, TCSANOW, &term) < 0 ) { + perror("tcsetattr"); + exit(1); + } + exit(0); + } + + if( strcmp(line, "sleep") == 0 ) { + sleep(3); + } else { + fprintf(stderr, "|%s|\n", line); + } +} + +int +change_prompt(void) +{ + /* toggle the prompt variable */ + prompt = !prompt; + + /* save away the current contents of the line */ + strcpy(line_buf, rl_line_buffer); + + /* install a new handler which will change the prompt and erase the current line */ + rl_callback_handler_install(get_prompt(), process_line); + + /* insert the old text on the new line */ + rl_insert_text(line_buf); + + /* redraw the current line - this is an undocumented function. It invokes the + * redraw-current-line command. + */ + rl_refresh_line(0, 0); +} + +char * +get_prompt(void) +{ + /* The prompts can even be different lengths! */ + sprintf(prompt_buf, "%s", + prompt ? "Hit ctrl-t to toggle prompt> " : "Pretty cool huh?> "); + return prompt_buf; +} diff --git a/contrib/libreadline/examples/rlfe.c b/contrib/libreadline/examples/rlfe.c new file mode 100644 index 000000000000..5c3c8fde45b3 --- /dev/null +++ b/contrib/libreadline/examples/rlfe.c @@ -0,0 +1,685 @@ +/* A front-end using readline to "cook" input lines for Kawa. + * + * Copyright (C) 1999 Per Bothner + * + * This front-end program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * Some code from Johnson & Troan: "Linux Application Development" + * (Addison-Wesley, 1998) was used directly or for inspiration. + */ + +/* PROBLEMS/TODO: + * + * Only tested under Linux; needs to be ported. + * + * When running mc -c under the Linux console, mc does not recognize + * mouse clicks, which mc does when not running under fep. + * + * Pasting selected text containing tabs is like hitting the tab character, + * which invokes readline completion. We don't want this. I don't know + * if this is fixable without integrating fep into a terminal emulator. + * + * Echo suppression is a kludge, but can only be avoided with better kernel + * support: We need a tty mode to disable "real" echoing, while still + * letting the inferior think its tty driver to doing echoing. + * Stevens's book claims SCR$ and BSD4.3+ have TIOCREMOTE. + * + * The latest readline may have some hooks we can use to avoid having + * to back up the prompt. + * + * Desirable readline feature: When in cooked no-echo mode (e.g. password), + * echo characters are they are types with '*', but remove them when done. + * + * A synchronous output while we're editing an input line should be + * inserted in the output view *before* the input line, so that the + * lines being edited (with the prompt) float at the end of the input. + * + * A "page mode" option to emulate more/less behavior: At each page of + * output, pause for a user command. This required parsing the output + * to keep track of line lengths. It also requires remembering the + * output, if we want an option to scroll back, which suggests that + * this should be integrated with a terminal emulator like xterm. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <signal.h> +#include <netdb.h> +#include <stdlib.h> +#include <errno.h> +#include <grp.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <termios.h> + +#ifdef READLINE_LIBRARY +# include "readline.h" +# include "history.h" +#else +# include <readline/readline.h> +# include <readline/history.h> +#endif + +#ifndef COMMAND +#define COMMAND "/bin/sh" +#endif +#ifndef COMMAND_ARGS +#define COMMAND_ARGS COMMAND +#endif + +#ifndef HAVE_MEMMOVE +# if __GNUC__ > 1 +# define memmove(d, s, n) __builtin_memcpy(d, s, n) +# else +# define memmove(d, s, n) memcpy(d, s, n) +# endif +#else +# define memmove(d, s, n) memcpy(d, s, n) +#endif + +#define APPLICATION_NAME "Fep" + +static int in_from_inferior_fd; +static int out_to_inferior_fd; + +/* Unfortunately, we cannot safely display echo from the inferior process. + The reason is that the echo bit in the pty is "owned" by the inferior, + and if we try to turn it off, we could confuse the inferior. + Thus, when echoing, we get echo twice: First readline echoes while + we're actually editing. Then we send the line to the inferior, and the + terminal driver send back an extra echo. + The work-around is to remember the input lines, and when we see that + line come back, we supress the output. + A better solution (supposedly available on SVR4) would be a smarter + terminal driver, with more flags ... */ +#define ECHO_SUPPRESS_MAX 1024 +char echo_suppress_buffer[ECHO_SUPPRESS_MAX]; +int echo_suppress_start = 0; +int echo_suppress_limit = 0; + +#define DEBUG + +#ifdef DEBUG +FILE *logfile = NULL; +#define DPRINT0(FMT) (fprintf(logfile, FMT), fflush(logfile)) +#define DPRINT1(FMT, V1) (fprintf(logfile, FMT, V1), fflush(logfile)) +#define DPRINT2(FMT, V1, V2) (fprintf(logfile, FMT, V1, V2), fflush(logfile)) +#else +#define DPRINT0(FMT) /* Do nothing */ +#define DPRINT1(FMT, V1) /* Do nothing */ +#define DPRINT2(FMT, V1, V2) /* Do nothing */ +#endif + +struct termios orig_term; + +/* Pid of child process. */ +static pid_t child = -1; + +static void +sig_child (int signo) +{ + int status; + wait (&status); + DPRINT0 ("(Child process died.)\n"); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); + exit (0); +} + +volatile int propagate_sigwinch = 0; + +/* sigwinch_handler + * propagate window size changes from input file descriptor to + * master side of pty. + */ +void sigwinch_handler(int signal) { + propagate_sigwinch = 1; +} + +/* get_master_pty() takes a double-indirect character pointer in which + * to put a slave name, and returns an integer file descriptor. + * If it returns < 0, an error has occurred. + * Otherwise, it has returned the master pty file descriptor, and fills + * in *name with the name of the corresponding slave pty. + * Once the slave pty has been opened, you are responsible to free *name. + */ + +int get_master_pty(char **name) { + int i, j; + /* default to returning error */ + int master = -1; + + /* create a dummy name to fill in */ + *name = strdup("/dev/ptyXX"); + + /* search for an unused pty */ + for (i=0; i<16 && master <= 0; i++) { + for (j=0; j<16 && master <= 0; j++) { + (*name)[5] = 'p'; + (*name)[8] = "pqrstuvwxyzPQRST"[i]; + (*name)[9] = "0123456789abcdef"[j]; + /* open the master pty */ + if ((master = open(*name, O_RDWR)) < 0) { + if (errno == ENOENT) { + /* we are out of pty devices */ + free (*name); + return (master); + } + } + else { + /* By substituting a letter, we change the master pty + * name into the slave pty name. + */ + (*name)[5] = 't'; + if (access(*name, R_OK|W_OK) != 0) + { + close(master); + master = -1; + } + } + } + } + if ((master < 0) && (i == 16) && (j == 16)) { + /* must have tried every pty unsuccessfully */ + free (*name); + return (master); + } + + (*name)[5] = 't'; + + return (master); +} + +/* get_slave_pty() returns an integer file descriptor. + * If it returns < 0, an error has occurred. + * Otherwise, it has returned the slave file descriptor. + */ + +int get_slave_pty(char *name) { + struct group *gptr; + gid_t gid; + int slave = -1; + + /* chown/chmod the corresponding pty, if possible. + * This will only work if the process has root permissions. + * Alternatively, write and exec a small setuid program that + * does just this. + */ + if ((gptr = getgrnam("tty")) != 0) { + gid = gptr->gr_gid; + } else { + /* if the tty group does not exist, don't change the + * group on the slave pty, only the owner + */ + gid = -1; + } + + /* Note that we do not check for errors here. If this is code + * where these actions are critical, check for errors! + */ + chown(name, getuid(), gid); + /* This code only makes the slave read/writeable for the user. + * If this is for an interactive shell that will want to + * receive "write" and "wall" messages, OR S_IWGRP into the + * second argument below. + */ + chmod(name, S_IRUSR|S_IWUSR); + + /* open the corresponding slave pty */ + slave = open(name, O_RDWR); + return (slave); +} + +/* Certain special characters, such as ctrl/C, we want to pass directly + to the inferior, rather than letting readline handle them. */ + +static char special_chars[20]; +static int special_chars_count; + +static void +add_special_char(int ch) +{ + if (ch != 0) + special_chars[special_chars_count++] = ch; +} + +static int eof_char; + +static int +is_special_char(int ch) +{ + int i; +#if 0 + if (ch == eof_char && rl_point == rl_end) + return 1; +#endif + for (i = special_chars_count; --i >= 0; ) + if (special_chars[i] == ch) + return 1; + return 0; +} + +static char buf[1024]; +/* buf[0 .. buf_count-1] is the what has been emitted on the current line. + It is used as the readline prompt. */ +static int buf_count = 0; + +int num_keys = 0; + +static void +null_prep_terminal (int meta) +{ +} + +static void +null_deprep_terminal () +{ +} + +char pending_special_char; + +static void +line_handler (char *line) +{ + if (line == NULL) + { + char buf[1]; + DPRINT0("saw eof!\n"); + buf[0] = '\004'; /* ctrl/d */ + write (out_to_inferior_fd, buf, 1); + } + else + { + static char enter[] = "\r"; + /* Send line to inferior: */ + int length = strlen (line); + if (length > ECHO_SUPPRESS_MAX-2) + { + echo_suppress_start = 0; + echo_suppress_limit = 0; + } + else + { + if (echo_suppress_limit + length > ECHO_SUPPRESS_MAX - 2) + { + if (echo_suppress_limit - echo_suppress_start + length + <= ECHO_SUPPRESS_MAX - 2) + { + memmove (echo_suppress_buffer, + echo_suppress_buffer + echo_suppress_start, + echo_suppress_limit - echo_suppress_start); + echo_suppress_limit -= echo_suppress_start; + echo_suppress_start = 0; + } + else + { + echo_suppress_limit = 0; + } + echo_suppress_start = 0; + } + memcpy (echo_suppress_buffer + echo_suppress_limit, + line, length); + echo_suppress_limit += length; + echo_suppress_buffer[echo_suppress_limit++] = '\r'; + echo_suppress_buffer[echo_suppress_limit++] = '\n'; + } + write (out_to_inferior_fd, line, length); + if (pending_special_char == 0) + { + write (out_to_inferior_fd, enter, sizeof(enter)-1); + if (*line) + add_history (line); + } + free (line); + } + rl_callback_handler_remove (); + buf_count = 0; + num_keys = 0; + if (pending_special_char != 0) + { + write (out_to_inferior_fd, &pending_special_char, 1); + pending_special_char = 0; + } +} + +/* Value of rl_getc_function. + Use this because readline should read from stdin, not rl_instream, + points to the pty (so readline has monitor its terminal modes). */ + +int +my_rl_getc (FILE *dummy) +{ + int ch = rl_getc (stdin); + if (is_special_char (ch)) + { + pending_special_char = ch; + return '\r'; + } + return ch; +} + +int +main(int argc, char** argv) +{ + char *path; + int i; + int master; + char *name; + int in_from_tty_fd; + struct sigaction act; + struct winsize ws; + struct termios t; + int maxfd; + fd_set in_set; + static char empty_string[1] = ""; + char *prompt = empty_string; + int ioctl_err = 0; + +#ifdef DEBUG + logfile = fopen("LOG", "w"); +#endif + + rl_readline_name = APPLICATION_NAME; + + if ((master = get_master_pty(&name)) < 0) + { + perror("ptypair: could not open master pty"); + exit(1); + } + + DPRINT1("pty name: '%s'\n", name); + + /* set up SIGWINCH handler */ + act.sa_handler = sigwinch_handler; + sigemptyset(&(act.sa_mask)); + act.sa_flags = 0; + if (sigaction(SIGWINCH, &act, NULL) < 0) + { + perror("ptypair: could not handle SIGWINCH "); + exit(1); + } + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) + { + perror("ptypair: could not get window size"); + exit(1); + } + + if ((child = fork()) < 0) + { + perror("cannot fork"); + exit(1); + } + + if (child == 0) + { + int slave; /* file descriptor for slave pty */ + + /* We are in the child process */ + close(master); + +#ifdef TIOCSCTTY + if ((slave = get_slave_pty(name)) < 0) + { + perror("ptypair: could not open slave pty"); + exit(1); + } + free(name); +#endif + + /* We need to make this process a session group leader, because + * it is on a new PTY, and things like job control simply will + * not work correctly unless there is a session group leader + * and process group leader (which a session group leader + * automatically is). This also disassociates us from our old + * controlling tty. + */ + if (setsid() < 0) + { + perror("could not set session leader"); + } + + /* Tie us to our new controlling tty. */ +#ifdef TIOCSCTTY + if (ioctl(slave, TIOCSCTTY, NULL)) + { + perror("could not set new controlling tty"); + } +#else + if ((slave = get_slave_pty(name)) < 0) + { + perror("ptypair: could not open slave pty"); + exit(1); + } + free(name); +#endif + + /* make slave pty be standard in, out, and error */ + dup2(slave, STDIN_FILENO); + dup2(slave, STDOUT_FILENO); + dup2(slave, STDERR_FILENO); + + /* at this point the slave pty should be standard input */ + if (slave > 2) + { + close(slave); + } + + /* Try to restore window size; failure isn't critical */ + if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) < 0) + { + perror("could not restore window size"); + } + + /* now start the shell */ + { + static char* command_args[] = { COMMAND_ARGS, NULL }; + if (argc <= 1) + execvp(COMMAND, command_args); + else + execvp(argv[1], &argv[1]); + } + + /* should never be reached */ + exit(1); + } + + /* parent */ + signal (SIGCHLD, sig_child); + free(name); + + /* Note that we only set termios settings for standard input; + * the master side of a pty is NOT a tty. + */ + tcgetattr(STDIN_FILENO, &orig_term); + + t = orig_term; + eof_char = t.c_cc[VEOF]; + /* add_special_char(t.c_cc[VEOF]);*/ + add_special_char(t.c_cc[VINTR]); + add_special_char(t.c_cc[VQUIT]); + add_special_char(t.c_cc[VSUSP]); +#if defined (VDISCARD) + add_special_char(t.c_cc[VDISCARD]); +#endif + +#if 0 + t.c_lflag |= (ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \ + ECHOK | ECHOKE | ECHONL | ECHOPRT ); +#else + t.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOCTL | ECHOE | \ + ECHOK | ECHOKE | ECHONL | ECHOPRT ); +#endif + t.c_iflag |= IGNBRK; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSANOW, &t); + in_from_inferior_fd = master; + out_to_inferior_fd = master; + rl_instream = fdopen (master, "r"); + rl_getc_function = my_rl_getc; + + rl_prep_term_function = null_prep_terminal; + rl_deprep_term_function = null_deprep_terminal; + rl_callback_handler_install (prompt, line_handler); + + in_from_tty_fd = STDIN_FILENO; + FD_ZERO (&in_set); + maxfd = in_from_inferior_fd > in_from_tty_fd ? in_from_inferior_fd + : in_from_tty_fd; + for (;;) + { + int num; + FD_SET (in_from_inferior_fd, &in_set); + FD_SET (in_from_tty_fd, &in_set); + + num = select(maxfd+1, &in_set, NULL, NULL, NULL); + + if (propagate_sigwinch) + { + struct winsize ws; + if (ioctl (STDIN_FILENO, TIOCGWINSZ, &ws) >= 0) + { + ioctl (master, TIOCSWINSZ, &ws); + } + propagate_sigwinch = 0; + continue; + } + + if (num <= 0) + { + perror ("select"); + exit (-1); + } + if (FD_ISSET (in_from_tty_fd, &in_set)) + { + extern int readline_echoing_p; + struct termios term_master; + int do_canon = 1; + int ioctl_ret; + + DPRINT1("[tty avail num_keys:%d]\n", num_keys); + + /* If we can't get tty modes for the master side of the pty, we + can't handle non-canonical-mode programs. Always assume the + master is in canonical echo mode if we can't tell. */ + ioctl_ret = tcgetattr(master, &term_master); + + if (ioctl_ret >= 0) + { + DPRINT2 ("echo:%d, canon:%d\n", + (term_master.c_lflag & ECHO) != 0, + (term_master.c_lflag & ICANON) != 0); + do_canon = (term_master.c_lflag & ICANON) != 0; + readline_echoing_p = (term_master.c_lflag & ECHO) != 0; + } + else + { + if (ioctl_err == 0) + DPRINT1("tcgetattr on master fd failed: errno = %d\n", errno); + ioctl_err = 1; + } + + if (do_canon == 0 && num_keys == 0) + { + char ch[10]; + int count = read (STDIN_FILENO, ch, sizeof(ch)); + write (out_to_inferior_fd, ch, count); + } + else + { + if (num_keys == 0) + { + int i; + /* Re-install callback handler for new prompt. */ + if (prompt != empty_string) + free (prompt); + prompt = malloc (buf_count + 1); + if (prompt == NULL) + prompt = empty_string; + else + { + memcpy (prompt, buf, buf_count); + prompt[buf_count] = '\0'; + DPRINT1("New prompt '%s'\n", prompt); +#if 0 /* ifdef HAVE_RL_ALREADY_PROMPTED -- doesn't work */ + rl_already_prompted = buf_count > 0; +#else + if (buf_count > 0) + write (1, "\r", 1); +#endif + } + rl_callback_handler_install (prompt, line_handler); + } + num_keys++; + rl_callback_read_char (); + } + } + else /* input from inferior. */ + { + int i; + int count; + int old_count; + if (buf_count > (sizeof(buf) >> 2)) + buf_count = 0; + count = read (in_from_inferior_fd, buf+buf_count, + sizeof(buf) - buf_count); + if (count <= 0) + { + DPRINT0 ("(Connection closed by foreign host.)\n"); + tcsetattr(STDIN_FILENO, TCSANOW, &orig_term); + exit (0); + } + old_count = buf_count; + + /* Look for any pending echo that we need to suppress. */ + while (echo_suppress_start < echo_suppress_limit + && count > 0 + && buf[buf_count] == echo_suppress_buffer[echo_suppress_start]) + { + count--; + buf_count++; + echo_suppress_start++; + } + + /* Write to the terminal anything that was not suppressed. */ + if (count > 0) + write (1, buf + buf_count, count); + + /* Finally, look for a prompt candidate. + * When we get around to going input (from the keyboard), + * we will consider the prompt to be anything since the last + * line terminator. So we need to save that text in the + * initial part of buf. However, anything before the + * most recent end-of-line is not interesting. */ + buf_count += count; +#if 1 + for (i = buf_count; --i >= old_count; ) +#else + for (i = buf_count - 1; i-- >= buf_count - count; ) +#endif + { + if (buf[i] == '\n' || buf[i] == '\r') + { + i++; + memmove (buf, buf+i, buf_count - i); + buf_count -= i; + break; + } + } + DPRINT2("-> i: %d, buf_count: %d\n", i, buf_count); + } + } +} diff --git a/contrib/libreadline/rlprivate.h b/contrib/libreadline/rlprivate.h new file mode 100644 index 000000000000..c05230e3325d --- /dev/null +++ b/contrib/libreadline/rlprivate.h @@ -0,0 +1,271 @@ +/* rlprivate.h -- functions and variables global to the readline library, + but not intended for use by applications. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_PRIVATE_H_) +#define _RL_PRIVATE_H_ + +#include "rlconf.h" /* for VISIBLE_STATS */ +#include "rlstdc.h" +#include "posixjmp.h" /* defines procenv_t */ + +/************************************************************************* + * * + * Global functions undocumented in texinfo manual and not in readline.h * + * * + *************************************************************************/ + +/* terminal.c */ +extern char *rl_get_termcap __P((char *)); + +/************************************************************************* + * * + * Global variables undocumented in texinfo manual and not in readline.h * + * * + *************************************************************************/ + +/* complete.c */ +extern int rl_complete_with_tilde_expansion; +#if defined (VISIBLE_STATS) +extern int rl_visible_stats; +#endif /* VISIBLE_STATS */ + +/* readline.c */ +extern int rl_line_buffer_len; +extern int rl_numeric_arg; +extern int rl_arg_sign; +extern int rl_explicit_arg; +extern int rl_editing_mode; +extern int rl_visible_prompt_length; +extern Function *rl_last_func; +extern int readline_echoing_p; +extern int rl_key_sequence_length; + +/* display.c */ +extern int rl_display_fixed; + +/* parens.c */ +extern int rl_blink_matching_paren; + +/************************************************************************* + * * + * Global functions and variables unsed and undocumented * + * * + *************************************************************************/ + +/* bind.c */ +extern char *rl_untranslate_keyseq __P((int)); + +/* kill.c */ +extern int rl_set_retained_kills __P((int)); + +/* readline.c */ +extern int rl_discard_argument __P((void)); + +/* rltty.c */ +extern int rl_stop_output __P((int, int)); + +/* terminal.c */ +extern void _rl_set_screen_size __P((int, int)); + +/* undo.c */ +extern int _rl_fix_last_undo_of_type __P((int, int, int)); + +/* util.c */ +extern char *_rl_savestring __P((char *)); + +/************************************************************************* + * * + * Functions and variables private to the readline library * + * * + *************************************************************************/ + +/* NOTE: Functions and variables prefixed with `_rl_' are + pseudo-global: they are global so they can be shared + between files in the readline library, but are not intended + to be visible to readline callers. */ + +/************************************************************************* + * Undocumented private functions * + *************************************************************************/ + +#if defined(READLINE_CALLBACKS) + +/* readline.c */ +extern void readline_internal_setup __P((void)); +extern char *readline_internal_teardown __P((int)); +extern int readline_internal_char __P((void)); + +#endif /* READLINE_CALLBACKS */ + +/* bind.c */ +extern void _rl_bind_if_unbound __P((char *, Function *)); + +/* display.c */ +extern char *_rl_strip_prompt __P((char *)); +extern void _rl_move_cursor_relative __P((int, char *)); +extern void _rl_move_vert __P((int)); +extern void _rl_save_prompt __P((void)); +extern void _rl_restore_prompt __P((void)); +extern char *_rl_make_prompt_for_search __P((int)); +extern void _rl_erase_at_end_of_line __P((int)); +extern void _rl_clear_to_eol __P((int)); +extern void _rl_clear_screen __P((void)); +extern void _rl_update_final __P((void)); +extern void _rl_redisplay_after_sigwinch __P((void)); +extern void _rl_clean_up_for_exit __P((void)); +extern void _rl_erase_entire_line __P((void)); +extern int _rl_currentb_display_line __P((void)); + +/* input.c */ +extern int _rl_any_typein __P((void)); +extern int _rl_input_available __P((void)); +extern void _rl_insert_typein __P((int)); + +/* macro.c */ +extern void _rl_with_macro_input __P((char *)); +extern int _rl_next_macro_key __P((void)); +extern void _rl_push_executing_macro __P((void)); +extern void _rl_pop_executing_macro __P((void)); +extern void _rl_add_macro_char __P((int)); +extern void _rl_kill_kbd_macro __P((void)); + +/* nls.c */ +extern int _rl_init_eightbit __P((void)); + +/* parens.c */ +extern void _rl_enable_paren_matching __P((int)); + +/* readline.c */ +extern void _rl_init_line_state __P((void)); +extern void _rl_set_the_line __P((void)); +extern int _rl_dispatch __P((int, Keymap)); +extern int _rl_init_argument __P((void)); +extern void _rl_fix_point __P((int)); +extern void _rl_replace_text __P((char *, int, int)); +extern int _rl_char_search_internal __P((int, int, int)); +extern int _rl_set_mark_at_pos __P((int)); + +/* rltty.c */ +extern int _rl_disable_tty_signals __P((void)); +extern int _rl_restore_tty_signals __P((void)); + +/* terminal.c */ +extern void _rl_get_screen_size __P((int, int)); +extern int _rl_init_terminal_io __P((char *)); +#ifdef _MINIX +extern void _rl_output_character_function __P((int)); +#else +extern int _rl_output_character_function __P((int)); +#endif +extern void _rl_output_some_chars __P((char *, int)); +extern int _rl_backspace __P((int)); +extern void _rl_enable_meta_key __P((void)); +extern void _rl_control_keypad __P((int)); + +/* util.c */ +extern int alphabetic __P((int)); +extern int _rl_abort_internal __P((void)); +extern char *_rl_strindex __P((char *, char *)); +extern int _rl_qsort_string_compare __P((char **, char **)); +extern int (_rl_uppercase_p) __P((int)); +extern int (_rl_lowercase_p) __P((int)); +extern int (_rl_pure_alphabetic) __P((int)); +extern int (_rl_digit_p) __P((int)); +extern int (_rl_to_lower) __P((int)); +extern int (_rl_to_upper) __P((int)); +extern int (_rl_digit_value) __P((int)); + +/* vi_mode.c */ +extern void _rl_vi_initialize_line __P((void)); +extern void _rl_vi_reset_last __P((void)); +extern void _rl_vi_set_last __P((int, int, int)); +extern int _rl_vi_textmod_command __P((int)); +extern void _rl_vi_done_inserting __P((void)); + +/************************************************************************* + * Undocumented private variables * + *************************************************************************/ + +/* complete.c */ +extern int _rl_complete_show_all; +extern int _rl_complete_mark_directories; +extern int _rl_print_completions_horizontally; +extern int _rl_completion_case_fold; + +/* display.c */ +extern int _rl_vis_botlin; +extern int _rl_last_c_pos; +extern int _rl_suppress_redisplay; +extern char *rl_display_prompt; + +/* funmap.c */ +extern char *possible_control_prefixes[]; +extern char *possible_meta_prefixes[]; + +/* isearch.c */ +extern unsigned char *_rl_isearch_terminators; + +/* macro.c */ +extern int _rl_defining_kbd_macro; +extern char *_rl_executing_macro; + +/* readline.c */ +extern int _rl_horizontal_scroll_mode; +extern int _rl_mark_modified_lines; +extern int _rl_bell_preference; +extern int _rl_meta_flag; +extern int _rl_convert_meta_chars_to_ascii; +extern int _rl_output_meta_chars; +extern char *_rl_comment_begin; +extern unsigned char _rl_parsing_conditionalized_out; +extern Keymap _rl_keymap; +extern FILE *_rl_in_stream; +extern FILE *_rl_out_stream; +extern int _rl_last_command_was_kill; +extern int _rl_eof_char; +extern procenv_t readline_top_level; + +/* terminal.c */ +extern int _rl_enable_keypad; +extern int _rl_enable_meta; +extern char *term_clreol; +extern char *term_clrpag; +extern char *term_im; +extern char *term_ic; +extern char *term_ei; +extern char *term_DC; +extern char *term_up; +extern char *term_dc; +extern char *term_cr; +extern char *term_IC; +extern int screenheight; +extern int screenwidth; +extern int screenchars; +extern int terminal_can_insert; +extern int _rl_term_autowrap; + +/* undo.c */ +extern int _rl_doing_an_undo; +extern int _rl_undo_group_level; + +#endif /* _RL_PRIVATE_H_ */ diff --git a/contrib/libreadline/rlshell.h b/contrib/libreadline/rlshell.h new file mode 100644 index 000000000000..7a4e69963167 --- /dev/null +++ b/contrib/libreadline/rlshell.h @@ -0,0 +1,34 @@ +/* rlshell.h -- utility functions normally provided by bash. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_RL_SHELL_H_) +#define _RL_SHELL_H_ + +#include "rlstdc.h" + +extern char *single_quote __P((char *)); +extern void set_lines_and_columns __P((int, int)); +extern char *get_env_value __P((char *)); +extern char *get_home_dir __P((void)); +extern int unset_nodelay_mode __P((int)); + +#endif /* _RL_SHELL_H_ */ diff --git a/contrib/libreadline/xmalloc.h b/contrib/libreadline/xmalloc.h new file mode 100644 index 000000000000..bdf251b070a3 --- /dev/null +++ b/contrib/libreadline/xmalloc.h @@ -0,0 +1,46 @@ +/* xmalloc.h -- memory allocation that aborts on errors. */ + +/* Copyright (C) 1999 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library, a library for + reading lines of text with interactive input and history editing. + + The GNU Readline Library is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2, or + (at your option) any later version. + + The GNU Readline Library is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + The GNU General Public License is often shipped with GNU software, and + is generally kept in a file called COPYING or LICENSE. If you do not + have a copy of the license, write to the Free Software Foundation, + 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#if !defined (_XMALLOC_H_) +#define _XMALLOC_H_ + +#if defined (READLINE_LIBRARY) +# include "rlstdc.h" +#else +# include <readline/rlstdc.h> +#endif + +#ifndef PTR_T + +#ifdef __STDC__ +# define PTR_T void * +#else +# define PTR_T char * +#endif + +#endif /* !PTR_T */ + +extern char *xmalloc __P((int)); +extern char *xrealloc __P((void *, int)); +extern void xfree __P((void *)); + +#endif /* _XMALLOC_H_ */ diff --git a/lib/libc/sys/aio_waitcomplete.2 b/lib/libc/sys/aio_waitcomplete.2 new file mode 100644 index 000000000000..2447c9055130 --- /dev/null +++ b/lib/libc/sys/aio_waitcomplete.2 @@ -0,0 +1,129 @@ +.\" Copyright (c) 1999 Christopher M Sedore. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd January 19, 2000 +.Dt AIO_WAITCOMPLETE 2 +.Os +.Sh NAME +.Nm aio_waitcomplete +.Nd wait for the next completion of an aio request +.Sh SYNOPSIS +.Fd #include <aio.h> +.Ft int +.Fn aio_waitcomplete "struct aiocb **iocbp, struct timeval *timeout" +.Sh DESCRIPTION +The +.Fn aio_waitcomplete +function waits for completion of an asynchronous I/O request. Upon completion, +.Fn aio_waitcomplete +returns the result of the function and sets +.Ar iocbp +to point to the structure associated with the original request. If an +asynchronous I/O request is completed before +.Fn aio_waitcomplete +is called, it returns immediately with the completed request. +.Pp +If +.Ar timeout +is a non-NULL pointer, it specifies a maximum interval to wait for a +asynchronous I/O request to complete. If +.Ar timeout +is a NULL pointer, +.Fn aio_waitcomplete +waits indefinitely. To effect a poll, the +.Ar timeout +argument should be non-NULL, pointing to a zero-valued timeval structure. +.Pp +The +.Fn aio_waitcomplete +function also serves the function of +.Fn aio_return , +thus +.Fn aio_return +should not be called for the control block returned in +.Ar iocbp . +.Sh RETURN VALUES +If an asynchronous I/O request has completed, +.Ar iocbp +is set to point to the control block passed with the original request, and +the status is returned as described in +.Xr read 2 , +.Xr write 2 , +or +.Xr fsync 2 . +On failure, +.Fn aio_waitcomplete +returns +.Dv -1 , +sets iocbp to +.Dv NULL +and +.Dv errno +to indicate the error condition. +.Sh ERRORS +The +.Fn aio_waitcomplete +function fails if: +.Bl -tag -width Er +.It Bq Er EINVAL +The specified time limit is invalid. +.It Bq Er EAGAIN +The process has not yet called +.Fn aio_read +or +.Fn aio_write . +.It Bq Er EINTR +A signal was delivered before the timeout expired and before any +asynchronous I/O requests completed. +.It Bq Er EWOULDBLOCK +.It Bq Er EINPROGRESS +The specified time limit expired before any asynchronous I/O requests +completed. +.El +.Sh SEE ALSO +.Xr aio_cancel 2 , +.Xr aio_error 2 , +.Xr aio_read 2 , +.Xr aio_return 2 , +.Xr aio_suspend 2 , +.Xr aio_write 2 , +.Xr fsync 2 , +.Xr read 2 , +.Xr write 2 . +.Sh STANDARDS +The +.Fn aio_waitcomplete +function is a FreeBSD-specific extension. +.Sh HISTORY +The +.Fn aio_waitcomplete +function first appeared in +.Fx 4.0 . +.Sh AUTHORS +The +.Fn aio_waitcomplete +function and this manual page were written by +.An Christopher M Sedore Aq cmsedore@maxwell.syr.edu . diff --git a/sbin/pc98/Makefile b/sbin/pc98/Makefile new file mode 100644 index 000000000000..139ae4312544 --- /dev/null +++ b/sbin/pc98/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +SUBDIR= fdisk +#NOTYET: nextboot +#NOTYET: cxconfig + +.include <bsd.subdir.mk> diff --git a/sbin/pc98/Makefile.inc b/sbin/pc98/Makefile.inc new file mode 100644 index 000000000000..b915adff92ab --- /dev/null +++ b/sbin/pc98/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "${.CURDIR}/../../Makefile.inc" diff --git a/sbin/pc98/fdisk/Makefile b/sbin/pc98/fdisk/Makefile new file mode 100644 index 000000000000..481a000783fe --- /dev/null +++ b/sbin/pc98/fdisk/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= fdisk +MAN8= fdisk.8 + +CFLAGS += -DPC98 + +.include <bsd.prog.mk> diff --git a/sbin/pc98/fdisk/fdisk.8 b/sbin/pc98/fdisk/fdisk.8 new file mode 100644 index 000000000000..7b9d4140a154 --- /dev/null +++ b/sbin/pc98/fdisk/fdisk.8 @@ -0,0 +1,468 @@ +.\" $FreeBSD$ +.\" +.Dd October 4, 1996 +.Dt FDISK 8 +.\".Os BSD 4 +.Sh NAME +.Nm fdisk +.Nd PC partition table maintenance program +.Sh SYNOPSIS +.Nm fdisk +.\" !PC98 .Op Fl BIaistu +.Op Fl Bastu +.Op Fl b Ar bootcode +.Op Fl 1234 +.Op Ar disk +.Bl -tag -width time +.Nm fdisk +.Fl f Ar configfile +.Op Fl itv +.Op Ar disk +.Sh PROLOGUE +In order for the BIOS to boot the kernel, +certain conventions must be adhered to. +Sector 0 of the disk must contain boot code, +a partition table, +and a magic number. +BIOS partitions can be used to break the disk up into several pieces. +The BIOS brings in sector 0 and verifies the magic number. The sector +0 boot code then searches the partition table to determine which +partition is marked +.Em active . +This boot code then brings in the bootstrap from the +.Em active +partition and, if marked bootable, runs it. +Under DOS, +you can have one or more partitions with one +.Em active . +The DOS +.Nm +program can be used to divide space on the disk into partitions and set one +.Em active . +.Sh DESCRIPTION +The +.Bx Free +program +.Nm +serves a similar purpose to the DOS program. The first form is used to +display partition information or to interactively edit the partition +table. The second is used to write a partition table using a +.Ar configfile +and is designed to be used by other scripts/programs. +.Pp +Options are: +.It Fl a +Change the active partition only. Ignored if +.Fl f +is given. +.It Fl b Ar bootcode +Get the boot code from the file +.Ar bootcode . +.It Fl B +Reinitialize the boot code contained in sector 0 of the disk. Ignored +if +.Fl f +is given. +.It Fl f Ar configfile +Set partition values using the file +.Ar configfile . +The +.Ar configfile +always modifies existing partitions, unless +.Fl i +is also given, in which case all existing partitions are deleted (marked +as "unused") before the +.Ar configfile +is read. The +.Ar configfile +can be "-", in which case +.Ar stdin +is read. See +.Sx CONFIGURATION FILE , +below, for file syntax. +.Pp +.Em WARNING Ns : +when +.Fl f +is used, you are not asked if you really want to write the partition +table (as you are in the interactive mode). Use with caution! +.\" !PC98 +.\" .It Fl i +.\" Initialize sector 0 of the disk. This implies +.\" .Fl u , +.\" unless +.\" .Fl f +.\" is given. +.\" .It Fl I +.\" Initialize the contents of sector 0 +.\" with one +/\" .Fx +/\" slice covering the entire disk. +.It Fl s +Print summary information and exit. +.It Fl t +Test mode; do not write partition values. Generally used with the +.Fl f +option to see what would be written to the partition table. Implies +.Fl v . +.It Fl u +Is used for updating (editing) sector 0 of the disk. Ignored if +.Fl f +is given. +.It Fl v +Be verbose. When +.Fl f +is used, +.Nm +prints out the partition table that is written to the disk. +.It Fl 12345678 +Operate on a single fdisk entry only. Ignored if +.Fl f +is given. +.El +.Pp +The final disk name can be provided as a +.Sq bare +disk name only, e.g. +.Ql da0 , +or as a fully qualified device node under +.Pa /dev . +If omitted, the disks +.Ql wd0 , +.Ql da0 , +and +.Ql od0 +are being searched in that order, until one is +being found responding. +.Pp +When called with no arguments, it prints the sector 0 partition table. +An example follows: + +.Bd -literal + ******* Working on device /dev/rda0 ******* + parameters extracted from in-core disklabel are: + cylinders=33075 heads=8 sectors/track=32 (256 blks/cyl) + + parameters to be used for BIOS calculations are: + cylinders=33075 heads=8 sectors/track=32 (256 blks/cyl) + + Media sector size is 512 + Warning: BIOS sector numbering starts with sector 1 + Information from DOS bootblock is: + The data for partition 1 is: + sysmid 148,(FreeBSD/NetBSD/386BSD) + start 256, size 2490112 (1215 Meg), sid 196 + beg: cyl 1/ sector 0/ head 0; + end: cyl 9727/ sector 0/ head 0 + system Name FreeBSD(98) + The data for partition 2 is: + sysmid 148,(FreeBSD/NetBSD/386BSD) + start 2490368, size 5505024 (2688 Meg), sid 196 + beg: cyl 9728/ sector 0/ head 0; + end: cyl 31231/ sector 0/ head 0 + system Name FreeBSD(98) + The data for partition 3 is: + <UNUSED> + The data for partition 4 is: + <UNUSED> + The data for partition 5 is: + <UNUSED> + The data for partition 6 is: + <UNUSED> + The data for partition 7 is: + <UNUSED> + The data for partition 8 is: + <UNUSED> + The data for partition 9 is: + <UNUSED> + The data for partition 10 is: + <UNUSED> + The data for partition 11 is: + <UNUSED> + The data for partition 12 is: + <UNUSED> + The data for partition 13 is: + <UNUSED> + The data for partition 14 is: + <UNUSED> + The data for partition 15 is: + <UNUSED> + The data for partition 16 is: + <UNUSED> +.Ed +.Pp +The disk is divided into three partitions that happen to fill the disk. +The second partition overlaps the end of the first. +(Used for debugging purposes) +.Bl -tag -width "cyl, sector and head" +.It Em "sysmid" +is used to label the partition. +.Bx Free +reserves the +magic number 148 decimal (94 in hex). +.It Em "start and size" +fields provide the start address +and size of a partition in sectors. +.\" !PC98 .It Em "flag 80" +.\" specifies that this is the active partition. +.It Em "cyl, sector and head" +fields are used to specify the beginning address +and end address for the partition. +.It Em "system Name" +is the name of the partition. +.It Em "Note:" +these numbers are calculated using BIOS's understanding of the disk geometry +and saved in the bootblock. +.El +.Pp +The flags +.\" .Fl i +.\" or +.Fl u +are used to indicate that the partition data is to be updated, unless the +.Fl f +option is used. If the +.Fl f +option is not used, the +.Nm +program will enter a conversational mode. +This mode is designed not to change any data unless you explicitly tell it to. +.Nm Fdisk +selects defaults for its questions to guarantee the above behavior. +.Pp +It displays each partition +and ask if you want to edit it. +If you say yes, +it will step through each field showing the old value +and asking for a new one. +When you are done with a partition, +.Nm +will display it and ask if it is correct. +.Nm Fdisk +will then proceed to the next entry. +.Pp +Getting the +.Em cyl, sector, +and +.Em head +fields correct is tricky. +So by default, +they will be calculated for you; +you can specify them if you choose. +.Pp +After all the partitions are processed, +you are given the option to change the +.Em active +partition. +Finally, +when the all the data for the first sector has been accumulated, +you are asked if you really want to rewrite sector 0. +Only if you answer yes, +will the data be written to disk. +.Pp +The difference between the +.Fl u +flag and +.Fl i +flag is that +the +.Fl u +flag just edits the fields as they appear on the disk. +While the +.Fl i +flag is used to "initialize" sector 0; +it will setup the last BIOS partition to use the whole disk for +.Bx Free ; +and make it active. +.Sh NOTES +The automatic calculation of starting cylinder etc. uses +a set of figures that represent what the BIOS thinks is the +geometry of the drive. +These figures are by default taken from the incore disklabel, +but the program initially gives you an opportunity to change them. +This allows the user to create a bootblock that can work with drives +that use geometry translation under the BIOS. +.Pp +If you hand craft your disk layout, +please make sure that the +.Bx Free +partition starts on a cylinder boundary. +A number of decisions made later may assume this. +(This might not be necessary later.) +.Pp +Editing an existing partition will most likely cause you to +lose all the data in that partition. +.Pp +You should run this program interactively once or twice to see how it +works. This is completely safe as long as you answer the last question +in the negative. There are subtleties that the program detects that are +not fully explained in this manual page. +.Sh CONFIGURATION FILE +When the +.Fl f +option is given, a disk's partition table can be written using values +from a +.Ar configfile . +The syntax of this file is very simple. Each line is either a comment or +a specification, and whitespace (except for newlines) are ignored: +.Bl -tag -width Ds +.It Xo +.Ic # +.No Ar comment ... +.Xc +Lines beginning with a "#" are comments and are ignored. +.It Xo +.Ic g +.No Ar spec1 +.No Ar spec2 +.No Ar spec3 +.Xc +Set the BIOS geometry used in partition calculations. There must be +three values specified, with a letter preceding each number: +.Bl -tag -width Ds +.Sm off +.It Cm c No Ar num +.Sm on +Set the number of cylinders to +.Ar num . +.Sm off +.It Cm h No Ar num +.Sm on +Set the number of heads to +.Ar num . +.Sm off +.It Cm s No Ar num +.Sm on +Set the number of sectors/track to +.Ar num . +.El +.Pp +These specs can occur in any order, as the leading letter determines +which value is which; however, all three must be specified. +.Pp +This line must occur before any lines that specify partition +information. +.Pp +It is an error if the following is not true: +.Pp +.nf + 1 <= number of cylinders + 1 <= number of heads <= 256 + 1 <= number of sectors/track < 64 +.fi +.Pp +The number of cylinders should be less than or equal to 1024, but this +is not enforced, although a warning will be output. Note that bootable +.Bx Free +partitions (the "/" filesystem) must lie completely within the +first 1024 cylinders; if this is not true, booting may fail. +Non-bootable partitions do not have this restriction. +.Pp +Example (all of these are equivalent), for a disk with 1019 cylinders, +39 heads, and 63 sectors: +.Pp +.nf + g c1019 h39 s63 + g h39 c1019 s63 + g s63 h39 c1019 +.fi +.It Xo +.Ic p +.No Ar partition +.No Ar type +.No Ar start +.No Ar length +.Xc +Set the partition given by +.Ar partition +(1-4) to type +.Ar type , +starting at sector +.Ar start +for +.Ar length +sectors. +.Pp +Only those partitions explicitly mentioned by these lines are modified; +any partition not referenced by a "p" line will not be modified. +However, if an invalid partition table is present, or the +.Fl i +option is specified, all existing partition entries will be cleared +(marked as unused), and these "p" lines will have to be used to +explicitly set partition information. If multiple partitions need to be +set, multiple "p" lines must be specified; one for each partition. +.Pp +These partition lines must occur after any geometry specification lines, +if one is present. +.Pp +The +.Ar type +is 165 for +.Bx Free +partitions. Specifying a partition type of zero is +the same as clearing the partition and marking it as unused; however, +dummy values (such as "0") must still be specified for +.Ar start +and +.Ar length . +.Pp +Note: the start offset will be rounded upwards to a head boundary if +necessary, and the end offset will be rounded downwards to a cylinder +boundary if necessary. +.Pp +Example: to clear partition 4 and mark it as unused: +.Pp +.nf + p 4 0 0 0 +.fi +.Pp +Example: to set partition 1 to a +.Bx Free +partition, starting at sector 1 +for 2503871 sectors (note: these numbers will be rounded upwards and +downwards to correspond to head and cylinder boundaries): +.Pp +.nf + p 1 165 1 2503871 +.fi +.It Xo +.Ic a +.No Ar partition +.Xc +Make +.Ar partition +the active partition. Can occur anywhere in the config file, but only +one must be present. +.Pp +Example: to make partition 1 the active partition: +.Pp +.nf + a 1 +.fi + +.El +.Pp +.Sh FILES +.Bl -tag -width /boot/mbr -compact +.It Pa /boot/mbr +The default boot code +.El +.Sh SEE ALSO +.Xr disklabel 8 +.Sh BUGS +The default boot code will not necessarily handle all partition types +correctly, in particular those introduced since MS-DOS 6.x. +.Pp +The entire program should be made more user-friendly. +.Pp +Throughout this man page, the term +.Sq partition +is used where it should actually be +.Sq slice , +in order to conform with the terms used elsewhere. +.Pp +You cannot use this command to completely dedicate a disk to +.Bx Free . +The +.Xr disklabel 8 +command must be used for this. diff --git a/sbin/pc98/fdisk/fdisk.c b/sbin/pc98/fdisk/fdisk.c new file mode 100644 index 000000000000..787121d49305 --- /dev/null +++ b/sbin/pc98/fdisk/fdisk.c @@ -0,0 +1,1539 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#include <sys/disklabel.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +int iotest; + +#define LBUF 100 +static char lbuf[LBUF]; + +/* + * + * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 + * + * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University + * Copyright (c) 1989 Robert. V. Baron + * Created. + */ + +#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp +#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp +#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } + +#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) + +#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ +#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ +int secsize = 0; /* the sensed sector size */ + +const char *disk; +const char *disks[] = +{ + "/dev/rad0", "/dev/rwd0", "/dev/rda0", "/dev/rod0", 0 +}; + +struct disklabel disklabel; /* disk parameters */ + +int cyls, sectors, heads, cylsecs, disksecs; + +struct mboot +{ + unsigned char padding[2]; /* force the longs to be long aligned */ +#ifdef PC98 + unsigned char bootinst[510]; +#else + unsigned char bootinst[DOSPARTOFF]; + struct dos_partition parts[4]; +#endif + unsigned short int signature; + +#ifdef PC98 + struct dos_partition parts[8]; +#endif + /* room to read in MBRs that are bigger then DEV_BSIZE */ + unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE]; +}; +struct mboot mboot; + +#define ACTIVE 0x80 +#define BOOT_MAGIC 0xAA55 + +int dos_cyls; +int dos_heads; +int dos_sectors; +int dos_cylsecs; + +#ifdef PC98 +#define DOSSECT(s,c) (s) +#define DOSCYL(c) (c) +#else +#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) +#define DOSCYL(c) (c & 0xff) +#endif +static int partition = -1; + + +#define MAX_ARGS 10 + +static int current_line_number; + +static int geom_processed = 0; +static int part_processed = 0; +static int active_processed = 0; + + +typedef struct cmd { + char cmd; + int n_args; + struct arg { + char argtype; + int arg_val; + } args[MAX_ARGS]; +} CMD; + + +static int B_flag = 0; /* replace boot code */ +static int I_flag = 0; /* use entire disk for FreeBSD */ +static int a_flag = 0; /* set active partition */ +static char *b_flag = NULL; /* path to boot code */ +static int i_flag = 0; /* replace partition data */ +static int u_flag = 0; /* update partition data */ +static int s_flag = 0; /* Print a summary and exit */ +static int t_flag = 0; /* test only, if f_flag is given */ +static char *f_flag = NULL; /* Read config info from file */ +static int v_flag = 0; /* Be verbose */ + +struct part_type +{ + unsigned char type; + char *name; +}part_types[] = +{ + {0x00, "unused"} + ,{0x01, "Primary DOS with 12 bit FAT"} +#ifdef PC98 + ,{0x11, "MSDOS"} + ,{0x20, "MSDOS"} + ,{0x21, "MSDOS"} + ,{0x22, "MSDOS"} + ,{0x23, "MSDOS"} + ,{0x02, "XENIX / filesystem"} + ,{0x03, "XENIX /usr filesystem"} + ,{0x04, "PC-UX"} + ,{0x05, "Extended DOS"} + ,{0x06, "Primary 'big' DOS (> 32MB)"} + ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"} + ,{0x08, "AIX filesystem"} + ,{0x09, "AIX boot partition or Coherent"} + ,{0x0A, "OS/2 Boot Manager or OPUS"} + ,{0x10, "OPUS"} + ,{0x14, "FreeBSD/NetBSD/386BSD"} + ,{0x94, "FreeBSD/NetBSD/386BSD"} + ,{0x40, "VENIX 286"} + ,{0x50, "DM"} + ,{0x51, "DM"} + ,{0x52, "CP/M or Microport SysV/AT"} + ,{0x56, "GB"} + ,{0x61, "Speed"} + ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} + ,{0x64, "Novell Netware 2.xx"} + ,{0x65, "Novell Netware 3.xx"} + ,{0x75, "PCIX"} + ,{0x40, "Minix"} +#else + ,{0x02, "XENIX / filesystem"} + ,{0x03, "XENIX /usr filesystem"} + ,{0x04, "Primary DOS with 16 bit FAT (<= 32MB)"} + ,{0x05, "Extended DOS"} + ,{0x06, "Primary 'big' DOS (> 32MB)"} + ,{0x07, "OS/2 HPFS, NTFS, QNX or Advanced UNIX"} + ,{0x08, "AIX filesystem"} + ,{0x09, "AIX boot partition or Coherent"} + ,{0x0A, "OS/2 Boot Manager or OPUS"} + ,{0x0B, "DOS or Windows 95 with 32 bit FAT"} + ,{0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"} + ,{0x0E, "Primary 'big' DOS (> 32MB, LBA)"} + ,{0x0F, "Extended DOS, LBA"} + ,{0x10, "OPUS"} + ,{0x40, "VENIX 286"} + ,{0x50, "DM"} + ,{0x51, "DM"} + ,{0x52, "CP/M or Microport SysV/AT"} + ,{0x56, "GB"} + ,{0x61, "Speed"} + ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} + ,{0x64, "Novell Netware 2.xx"} + ,{0x65, "Novell Netware 3.xx"} + ,{0x75, "PCIX"} + ,{0x80, "Minix 1.1 ... 1.4a"} + ,{0x81, "Minix 1.4b ... 1.5.10"} + ,{0x82, "Linux swap or Solaris x86"} + ,{0x83, "Linux filesystem"} + ,{0x93, "Amoeba filesystem"} + ,{0x94, "Amoeba bad block table"} + ,{0x9F, "BSD/OS"} + ,{0xA5, "FreeBSD/NetBSD/386BSD"} + ,{0xA6, "OpenBSD"} + ,{0xA7, "NEXTSTEP"} + ,{0xA9, "NetBSD"} + ,{0xB7, "BSDI BSD/386 filesystem"} + ,{0xB8, "BSDI BSD/386 swap"} + ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} + ,{0xE1, "Speed"} + ,{0xE3, "Speed"} + ,{0xE4, "Speed"} + ,{0xF1, "Speed"} + ,{0xF2, "DOS 3.3+ Secondary"} + ,{0xF4, "Speed"} + ,{0xFF, "BBT (Bad Blocks Table)"} +#endif +}; + +static void print_s0(int which); +static void print_part(int i); +static void init_sector0(unsigned long start); +static void init_boot(void); +static void change_part(int i); +static void print_params(); +static void change_active(int which); +static void change_code(); +static void get_params_to_use(); +#ifdef PC98 +static void dos(int sec, int size, unsigned short *c, unsigned char *s, + unsigned char *h); +#else +static void dos(int sec, int size, unsigned char *c, unsigned char *s, + unsigned char *h); +#endif +static int open_disk(int u_flag); +static ssize_t read_disk(off_t sector, void *buf); +static ssize_t write_disk(off_t sector, void *buf); +static int get_params(); +static int read_s0(); +static int write_s0(); +static int ok(char *str); +static int decimal(char *str, int *num, int deflt); +static char *get_type(int type); +static int read_config(char *config_file); +static void reset_boot(void); +static void usage(void); +#if 0 +static int hex(char *str, int *num, int deflt); +#endif +#ifdef PC98 +static int string(char *str, char **ans); +#endif + + + +int +main(int argc, char *argv[]) +{ + int c, i; + +#ifdef PC98 + while ((c = getopt(argc, argv, "Bab:f:istuv12345678")) != -1) +#else + while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1) +#endif + switch (c) { + case 'B': + B_flag = 1; + break; + case 'I': + I_flag = 1; + break; + case 'a': + a_flag = 1; + break; + case 'b': + b_flag = optarg; + break; + case 'f': + f_flag = optarg; + break; + case 'i': + i_flag = 1; + break; + case 's': + s_flag = 1; + break; + case 't': + t_flag = 1; + break; + case 'u': + u_flag = 1; + break; + case 'v': + v_flag = 1; + break; + case '1': + case '2': + case '3': + case '4': +#ifdef PC98 + case '5': + case '6': + case '7': + case '8': +#endif + partition = c - '0'; + break; + default: + usage(); + } + if (f_flag || i_flag) + u_flag = 1; + if (t_flag) + v_flag = 1; + argc -= optind; + argv += optind; + + if (argc > 0) + { + static char realname[12]; + + if(strncmp(argv[0], "/dev", 4) == 0) + disk = argv[0]; + else + { + snprintf(realname, 12, "/dev/%s", argv[0]); + disk = realname; + } + + if (open_disk(u_flag) < 0) + err(1, "cannot open disk %s", disk); + } + else + { + int rv = 0; + + for(i = 0; disks[i]; i++) + { + disk = disks[i]; + rv = open_disk(u_flag); + if(rv != -2) break; + } + if(rv < 0) + err(1, "cannot open any disk"); + } + if (s_flag) + { + int i; + struct dos_partition *partp; + + if (read_s0()) + err(1, "read_s0"); + printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, + dos_sectors); +#ifdef PC98 + printf("Part %11s %11s SID\n", "Start", "Size"); +#else + printf("Part %11s %11s Type Flags\n", "Start", "Size"); +#endif + for (i = 0; i < NDOSPART; i++) { + partp = ((struct dos_partition *) &mboot.parts) + i; +#ifdef PC98 + if (partp->dp_sid == 0) +#else + if (partp->dp_start == 0 && partp->dp_size == 0) +#endif + continue; + printf("%4d: %11lu %11lu 0x%02xn", i + 1, +#ifdef PC98 + partp->dp_scyl * cylsecs, + (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs, + partp->dp_sid); +#else + (u_long) partp->dp_start, + (u_long) partp->dp_size, partp->dp_typ, + partp->dp_flag); +#endif + } + exit(0); + } + + printf("******* Working on device %s *******\n",disk); + +#ifndef PC98 + if (I_flag) + { + struct dos_partition *partp; + + read_s0(); + reset_boot(); + partp = (struct dos_partition *) (&mboot.parts[0]); + partp->dp_typ = DOSPTYP_386BSD; + partp->dp_flag = ACTIVE; + partp->dp_start = dos_sectors; + partp->dp_size = disksecs - dos_sectors; + + dos(partp->dp_start, partp->dp_size, + &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, + &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); + if (v_flag) + print_s0(-1); + write_s0(); + exit(0); + } +#endif + if (f_flag) + { +#ifndef PC98 + if (read_s0() || i_flag) + { + reset_boot(); + } + + if (!read_config(f_flag)) + { + exit(1); + } +#endif + if (v_flag) + { + print_s0(-1); + } + if (!t_flag) + { + write_s0(); + } + } + else + { + if(u_flag) + { + get_params_to_use(); + } + else + { + print_params(); + } + + if (read_s0()) + init_sector0(1); + + printf("Media sector size is %d\n", secsize); + printf("Warning: BIOS sector numbering starts with sector 1\n"); + printf("Information from DOS bootblock is:\n"); + if (partition == -1) + for (i = 1; i <= NDOSPART; i++) + change_part(i); + else + change_part(partition); + + if (u_flag || a_flag) + change_active(partition); + + if (B_flag) + change_code(); + + if (u_flag || a_flag || B_flag) { + if (!t_flag) + { + printf("\nWe haven't changed the partition table yet. "); + printf("This is your last chance.\n"); + } + print_s0(-1); + if (!t_flag) + { + if (ok("Should we write new partition table?")) + write_s0(); + } + else + { + printf("\n-t flag specified -- partition table not written.\n"); + } + } + } + + exit(0); +} + +static void +usage() +{ + fprintf(stderr, "%s%s", + "usage: fdisk [-Batu] [-b bootcode] [-12345678] [disk]\n", + " fdisk -f configfile [-itv] [disk]\n"); + exit(1); +} + +static void +print_s0(int which) +{ +int i; + + print_params(); + printf("Information from DOS bootblock is:\n"); + if (which == -1) + for (i = 1; i <= NDOSPART; i++) + printf("%d: ", i), print_part(i); + else + print_part(which); +} + +static struct dos_partition mtpart = { 0 }; + +static void +print_part(int i) +{ + struct dos_partition *partp; + u_int64_t part_mb; + + partp = ((struct dos_partition *) &mboot.parts) + i - 1; + + if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { + printf("<UNUSED>\n"); + return; + } + /* + * Be careful not to overflow. + */ +#ifdef PC98 + printf("sysmid %d,(%s)\n", partp->dp_mid, get_type(partp->dp_mid)); + printf(" start %d, size %d (%d Meg), sid %d\n", + partp->dp_scyl * cylsecs , + (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs, + (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs * 512 / (1024 * 1024), + partp->dp_sid); +#else + part_mb = partp->dp_size; + part_mb *= secsize; + part_mb /= (1024 * 1024); + printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); + printf(" start %lu, size %lu (%qd Meg), flag %x%s\n", + (u_long)partp->dp_start, + (u_long)partp->dp_size, + part_mb, + partp->dp_flag, + partp->dp_flag == ACTIVE ? " (active)" : ""); +#endif + printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" + ,DPCYL(partp->dp_scyl, partp->dp_ssect) + ,DPSECT(partp->dp_ssect) + ,partp->dp_shd + ,DPCYL(partp->dp_ecyl, partp->dp_esect) + ,DPSECT(partp->dp_esect) + ,partp->dp_ehd); +#ifdef PC98 + printf ("\tsystem Name %.16s\n",partp->dp_name); +#endif +} + + +static void +init_boot(void) +{ +#ifndef PC98 + const char *fname; + int fd; + + fname = b_flag ? b_flag : "/boot/mbr"; + if ((fd = open(fname, O_RDONLY)) == -1 || + read(fd, mboot.bootinst, DOSPARTOFF) == -1 || + close(fd)) + err(1, "%s", fname); +#endif + mboot.signature = BOOT_MAGIC; +} + + +static void +init_sector0(unsigned long start) +{ +struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); +unsigned long size = disksecs - start; + + init_boot(); + +#ifdef PC98 + partp->dp_mid = DOSMID_386BSD; + partp->dp_sid = DOSSID_386BSD; + + dos(start, size, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + partp->dp_ipl_cyl = partp->dp_scyl; + partp->dp_ipl_sct = partp->dp_ssect; + partp->dp_ipl_head = partp->dp_shd; + dos(start+size-cylsecs, size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); +#else + partp->dp_typ = DOSPTYP_386BSD; + partp->dp_flag = ACTIVE; + partp->dp_start = start; + partp->dp_size = size; + + dos(partp->dp_start, partp->dp_size, + &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, + &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); +#endif +} + +static void +change_part(int i) +{ +struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; + + printf("The data for partition %d is:\n", i); + print_part(i); + + if (u_flag && ok("Do you want to change it?")) { + int tmp; + + if (i_flag) { + bzero((char *)partp, sizeof (struct dos_partition)); + if (i == 4) { + init_sector0(1); + printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); + print_part(i); + } + } + + do { +#ifdef PC98 + int x_start = partp->dp_scyl * cylsecs ; + int x_size = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs; + Decimal("sysmid", partp->dp_mid, tmp); + Decimal("syssid", partp->dp_sid, tmp); + String ("system name", partp->dp_name, 16); + Decimal("start", x_start, tmp); + Decimal("size", x_size, tmp); +#else + Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); + Decimal("start", partp->dp_start, tmp); + Decimal("size", partp->dp_size, tmp); +#endif + if (ok("Explicitly specify beg/end address ?")) + { + int tsec,tcyl,thd; + tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); + thd = partp->dp_shd; + tsec = DPSECT(partp->dp_ssect); + Decimal("beginning cylinder", tcyl, tmp); + Decimal("beginning head", thd, tmp); + Decimal("beginning sector", tsec, tmp); + partp->dp_scyl = DOSCYL(tcyl); + partp->dp_ssect = DOSSECT(tsec,tcyl); + partp->dp_shd = thd; +#ifdef PC98 + partp->dp_ipl_cyl = partp->dp_scyl; + partp->dp_ipl_sct = partp->dp_ssect; + partp->dp_ipl_head = partp->dp_shd; +#endif + + tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); + thd = partp->dp_ehd; + tsec = DPSECT(partp->dp_esect); + Decimal("ending cylinder", tcyl, tmp); + Decimal("ending head", thd, tmp); + Decimal("ending sector", tsec, tmp); + partp->dp_ecyl = DOSCYL(tcyl); + partp->dp_esect = DOSSECT(tsec,tcyl); + partp->dp_ehd = thd; + } else { +#ifdef PC98 + dos(x_start, x_size, &partp->dp_scyl, + &partp->dp_ssect, &partp->dp_shd); + partp->dp_ipl_cyl = partp->dp_scyl; + partp->dp_ipl_sct = partp->dp_ssect; + partp->dp_ipl_head = partp->dp_shd; + dos(x_start+x_size - cylsecs, x_size, &partp->dp_ecyl, + &partp->dp_esect, &partp->dp_ehd); +#else + dos(partp->dp_start, partp->dp_size, + &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, + &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); +#endif + } + + print_part(i); + } while (!ok("Are we happy with this entry?")); + } +} + +static void +print_params() +{ + printf("parameters extracted from in-core disklabel are:\n"); + printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" + ,cyls,heads,sectors,cylsecs); +#ifndef PC98 + if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) + printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); +#endif + printf("parameters to be used for BIOS calculations are:\n"); + printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" + ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); +} + +static void +change_active(int which) +{ +int i; +#ifdef PC98 +int active = 8, tmp; +#else +int active = 4, tmp; +#endif + +struct dos_partition *partp = ((struct dos_partition *) &mboot.parts); + + if (a_flag && which != -1) + active = which; + if (!ok("Do you want to change the active partition?")) + return; +setactive: +#ifdef PC98 + active = 4; +#else + active = 4; +#endif + do { + Decimal("active partition", active, tmp); +#ifdef PC98 + if (active < 1 || 8 < active) { + printf("Active partition number must be in range 1-8." + " Try again.\n"); + goto setactive; + } +#else + if (active < 1 || 4 < active) { + printf("Active partition number must be in range 1-4." + " Try again.\n"); + goto setactive; + } +#endif + } while (!ok("Are you happy with this choice")); +#ifdef PC98 + partp[active].dp_sid |= ACTIVE; +#else + for (i = 0; i < NDOSPART; i++) + partp[i].dp_flag = 0; + if (active > 0 && active <= NDOSPART) + partp[active-1].dp_flag = ACTIVE; +#endif +} + +static void +change_code() +{ + if (ok("Do you want to change the boot code?")) + init_boot(); + +} + +void +get_params_to_use() +{ + int tmp; + print_params(); + if (ok("Do you want to change our idea of what BIOS thinks ?")) + { + do + { + Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); + Decimal("BIOS's idea of #heads", dos_heads, tmp); + Decimal("BIOS's idea of #sectors", dos_sectors, tmp); + dos_cylsecs = dos_heads * dos_sectors; + print_params(); + } + while(!ok("Are you happy with this choice")); + } +} + + +/***********************************************\ +* Change real numbers into strange dos numbers * +\***********************************************/ +static void +dos(sec, size, c, s, h) +int sec, size; +#ifdef PC98 +unsigned short *c; +unsigned char *s, *h; +#else +unsigned char *c, *s, *h; +#endif +{ +int cy; +int hd; + + if (sec == 0 && size == 0) { + *s = *c = *h = 0; + return; + } + + cy = sec / ( dos_cylsecs ); + sec = sec - cy * ( dos_cylsecs ); + + hd = sec / dos_sectors; +#ifdef PC98 + sec = (sec - hd * dos_sectors); + + *h = hd; + *c = cy; + *s = sec; +#else + sec = (sec - hd * dos_sectors) + 1; + + *h = hd; + *c = cy & 0xff; + *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); +#endif +} + +int fd; + + /* Getting device status */ + +static int +open_disk(int u_flag) +{ +struct stat st; + + if (stat(disk, &st) == -1) { + warnx("can't get file status of %s", disk); + return -1; + } + if ( !(st.st_mode & S_IFCHR) ) + warnx("device %s is not character special", disk); + if ((fd = open(disk, + a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { + if(errno == ENXIO) + return -2; + warnx("can't open device %s", disk); + return -1; + } + if (get_params(0) == -1) { + warnx("can't get disk parameters on %s", disk); + return -1; + } + return fd; +} + +static ssize_t +read_disk(off_t sector, void *buf) +{ + lseek(fd,(sector * 512), 0); +#ifdef PC98 + return read(fd, buf, secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2); +#else + if( secsize == 0 ) + for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) + { + /* try the read */ + int size = read(fd, buf, secsize); + if( size == secsize ) + /* it worked so return */ + return secsize; + } + else + return read( fd, buf, secsize ); + + /* we failed to read at any of the sizes */ + return -1; +#endif +} + +static ssize_t +write_disk(off_t sector, void *buf) +{ + lseek(fd,(sector * 512), 0); + /* write out in the size that the read_disk found worked */ +#ifdef PC98 + return write(fd, buf, secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2); +#else + return write(fd, buf, secsize); +#endif +} + +static int +get_params() +{ + + if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { + warnx("can't get disk parameters on %s; supplying dummy ones", disk); + dos_cyls = cyls = 1; + dos_heads = heads = 1; + dos_sectors = sectors = 1; + dos_cylsecs = cylsecs = heads * sectors; + disksecs = cyls * heads * sectors; +#ifdef PC98 + secsize = disklabel.d_secsize; +#endif + return disksecs; + } + + dos_cyls = cyls = disklabel.d_ncylinders; + dos_heads = heads = disklabel.d_ntracks; + dos_sectors = sectors = disklabel.d_nsectors; + dos_cylsecs = cylsecs = heads * sectors; + disksecs = cyls * heads * sectors; +#ifdef PC98 + secsize = disklabel.d_secsize; +#endif + return (disksecs); +} + + +static int +read_s0() +{ + if (read_disk(0, (char *) mboot.bootinst) == -1) { + warnx("can't read fdisk partition table"); + return -1; + } + if (mboot.signature != BOOT_MAGIC) { + warnx("invalid fdisk partition table found"); + /* So should we initialize things */ + return -1; + } + return 0; +} + +static int +write_s0() +{ +#ifdef NOT_NOW + int flag; +#endif + if (iotest) { + print_s0(-1); + return 0; + } + /* + * write enable label sector before write (if necessary), + * disable after writing. + * needed if the disklabel protected area also protects + * sector 0. (e.g. empty disk) + */ +#ifdef NOT_NOW + flag = 1; + if (ioctl(fd, DIOCWLABEL, &flag) < 0) + warn("ioctl DIOCWLABEL"); +#endif + if (write_disk(0, (char *) mboot.bootinst) == -1) { + warn("can't write fdisk partition table"); + return -1; +#ifdef NOT_NOW + flag = 0; + (void) ioctl(fd, DIOCWLABEL, &flag); +#endif + } + return(0); +} + + +static int +ok(str) +char *str; +{ + printf("%s [n] ", str); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (*lbuf && + (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || + !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) + return 1; + else + return 0; +} + +static int +decimal(char *str, int *num, int deflt) +{ +int acc = 0, c; +char *cp; + + while (1) { + printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + cp = lbuf; + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) + return 0; + while ((c = *cp++)) { + if (c <= '9' && c >= '0') + acc = acc * 10 + c - '0'; + else + break; + } + if (c == ' ' || c == '\t') + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) { + *num = acc; + return 1; + } else + printf("%s is an invalid decimal number. Try again.\n", + lbuf); + } + +} + +#if 0 +static int +hex(char *str, int *num, int deflt) +{ +int acc = 0, c; +char *cp; + + while (1) { + printf("Supply a hex value for \"%s\" [%x] ", str, deflt); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + cp = lbuf; + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) + return 0; + while ((c = *cp++)) { + if (c <= '9' && c >= '0') + acc = (acc << 4) + c - '0'; + else if (c <= 'f' && c >= 'a') + acc = (acc << 4) + c - 'a' + 10; + else if (c <= 'F' && c >= 'A') + acc = (acc << 4) + c - 'A' + 10; + else + break; + } + if (c == ' ' || c == '\t') + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (!c) { + *num = acc; + return 1; + } else + printf("%s is an invalid hex number. Try again.\n", + lbuf); + } + +} +#endif + +#ifdef PC98 +static int +string(char *str, char **ans) +{ +#ifdef PC98 +int i; +#endif +int c; +char *cp = lbuf; + + while (1) { + printf("Supply a string value for \"%s\" [%s] ", str, *ans); + fgets(lbuf, LBUF, stdin); + lbuf[strlen(lbuf)-1] = 0; + + if (!*lbuf) + return 0; + + while ((c = *cp) && (c == ' ' || c == '\t')) cp++; + if (c == '"') { + c = *++cp; + *ans = cp; + while ((c = *cp) && c != '"') cp++; + } else { + *ans = cp; + while ((c = *cp) && c != ' ' && c != '\t') cp++; + } + +#ifdef PC98 + for (i = strlen(*ans); i < 16; i++) + (*ans)[i] = ' '; + (*ans)[16] = 0; +#else + if (c) + *cp = 0; +#endif + return 1; + } +} +#endif + +static char * +get_type(int type) +{ + int numentries = (sizeof(part_types)/sizeof(struct part_type)); + int counter = 0; + struct part_type *ptr = part_types; + + + while(counter < numentries) + { +#ifdef PC98 + if(ptr->type == (type & 0x7f)) +#else + if(ptr->type == type) +#endif + { + return(ptr->name); + } + ptr++; + counter++; + } + return("unknown"); +} + +#ifndef PC98 +static void +parse_config_line(line, command) + char *line; + CMD *command; +{ + char *cp, *end; + + cp = line; + while (1) /* dirty trick used to insure one exit point for this + function */ + { + memset(command, 0, sizeof(*command)); + + while (isspace(*cp)) ++cp; + if (*cp == '\0' || *cp == '#') + { + break; + } + command->cmd = *cp++; + + /* + * Parse args + */ + while (1) + { + while (isspace(*cp)) ++cp; + if (*cp == '#') + { + break; /* found comment */ + } + if (isalpha(*cp)) + { + command->args[command->n_args].argtype = *cp++; + } + if (!isdigit(*cp)) + { + break; /* assume end of line */ + } + end = NULL; + command->args[command->n_args].arg_val = strtol(cp, &end, 0); + if (cp == end) + { + break; /* couldn't parse number */ + } + cp = end; + command->n_args++; + } + break; + } +} + + +static int +process_geometry(command) + CMD *command; +{ + int status = 1, i; + + while (1) + { + geom_processed = 1; + if (part_processed) + { + warnx( + "ERROR line %d: the geometry specification line must occur before\n\ + all partition specifications", + current_line_number); + status = 0; + break; + } + if (command->n_args != 3) + { + warnx("ERROR line %d: incorrect number of geometry args", + current_line_number); + status = 0; + break; + } + dos_cyls = -1; + dos_heads = -1; + dos_sectors = -1; + for (i = 0; i < 3; ++i) + { + switch (command->args[i].argtype) + { + case 'c': + dos_cyls = command->args[i].arg_val; + break; + case 'h': + dos_heads = command->args[i].arg_val; + break; + case 's': + dos_sectors = command->args[i].arg_val; + break; + default: + warnx( + "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", + current_line_number, command->args[i].argtype, + command->args[i].argtype); + status = 0; + break; + } + } + if (status == 0) + { + break; + } + + dos_cylsecs = dos_heads * dos_sectors; + + /* + * Do sanity checks on parameter values + */ + if (dos_cyls < 0) + { + warnx("ERROR line %d: number of cylinders not specified", + current_line_number); + status = 0; + } + if (dos_cyls == 0 || dos_cyls > 1024) + { + warnx( + "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ + (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ + is dedicated to FreeBSD)", + current_line_number, dos_cyls); + } + + if (dos_heads < 0) + { + warnx("ERROR line %d: number of heads not specified", + current_line_number); + status = 0; + } + else if (dos_heads < 1 || dos_heads > 256) + { + warnx("ERROR line %d: number of heads must be within (1-256)", + current_line_number); + status = 0; + } + + if (dos_sectors < 0) + { + warnx("ERROR line %d: number of sectors not specified", + current_line_number); + status = 0; + } + else if (dos_sectors < 1 || dos_sectors > 63) + { + warnx("ERROR line %d: number of sectors must be within (1-63)", + current_line_number); + status = 0; + } + + break; + } + return (status); +} + + +static int +process_partition(command) + CMD *command; +{ + int status = 0, partition; + unsigned long chunks, adj_size, max_end; + struct dos_partition *partp; + + while (1) + { + part_processed = 1; + if (command->n_args != 4) + { + warnx("ERROR line %d: incorrect number of partition args", + current_line_number); + break; + } + partition = command->args[0].arg_val; + if (partition < 1 || partition > 4) + { + warnx("ERROR line %d: invalid partition number %d", + current_line_number, partition); + break; + } + partp = ((struct dos_partition *) &mboot.parts) + partition - 1; + bzero((char *)partp, sizeof (struct dos_partition)); + partp->dp_typ = command->args[1].arg_val; + partp->dp_start = command->args[2].arg_val; + partp->dp_size = command->args[3].arg_val; + max_end = partp->dp_start + partp->dp_size; + + if (partp->dp_typ == 0) + { + /* + * Get out, the partition is marked as unused. + */ + /* + * Insure that it's unused. + */ + bzero((char *)partp, sizeof (struct dos_partition)); + status = 1; + break; + } + + /* + * Adjust start upwards, if necessary, to fall on an head boundary. + */ + if (partp->dp_start % dos_sectors != 0) + { + adj_size = + (partp->dp_start / dos_sectors + 1) * dos_sectors; + if (adj_size > max_end) + { + /* + * Can't go past end of partition + */ + warnx( + "ERROR line %d: unable to adjust start of partition %d to fall on\n\ + a cylinder boundary", + current_line_number, partition); + break; + } + warnx( + "WARNING: adjusting start offset of partition '%d' from %lu\n\ + to %lu, to round to an head boundary", + partition, (u_long)partp->dp_start, adj_size); + partp->dp_start = adj_size; + } + + /* + * Adjust size downwards, if necessary, to fall on a cylinder + * boundary. + */ + chunks = + ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; + adj_size = chunks - partp->dp_start; + if (adj_size != partp->dp_size) + { + warnx( + "WARNING: adjusting size of partition '%d' from %lu to %lu,\n\ + to round to a cylinder boundary", + partition, (u_long)partp->dp_size, adj_size); + if (chunks > 0) + { + partp->dp_size = adj_size; + } + else + { + partp->dp_size = 0; + } + } + if (partp->dp_size < 1) + { + warnx("ERROR line %d: size for partition '%d' is zero", + current_line_number, partition); + break; + } + + dos(partp->dp_start, partp->dp_size, + &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); + dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, + &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); + status = 1; + break; + } + return (status); +} + + +static int +process_active(command) + CMD *command; +{ + int status = 0, partition, i; + struct dos_partition *partp; + + while (1) + { + active_processed = 1; + if (command->n_args != 1) + { + warnx("ERROR line %d: incorrect number of active args", + current_line_number); + status = 0; + break; + } + partition = command->args[0].arg_val; + if (partition < 1 || partition > 4) + { + warnx("ERROR line %d: invalid partition number %d", + current_line_number, partition); + break; + } + /* + * Reset active partition + */ + partp = ((struct dos_partition *) &mboot.parts); + for (i = 0; i < NDOSPART; i++) + partp[i].dp_flag = 0; + partp[partition-1].dp_flag = ACTIVE; + + status = 1; + break; + } + return (status); +} + + +static int +process_line(line) + char *line; +{ + CMD command; + int status = 1; + + while (1) + { + parse_config_line(line, &command); + switch (command.cmd) + { + case 0: + /* + * Comment or blank line + */ + break; + case 'g': + /* + * Set geometry + */ + status = process_geometry(&command); + break; + case 'p': + status = process_partition(&command); + break; + case 'a': + status = process_active(&command); + break; + default: + status = 0; + break; + } + break; + } + return (status); +} + + +static int +read_config(config_file) + char *config_file; +{ + FILE *fp = NULL; + int status = 1; + char buf[1010]; + + while (1) /* dirty trick used to insure one exit point for this + function */ + { + if (strcmp(config_file, "-") != 0) + { + /* + * We're not reading from stdin + */ + if ((fp = fopen(config_file, "r")) == NULL) + { + status = 0; + break; + } + } + else + { + fp = stdin; + } + current_line_number = 0; + while (!feof(fp)) + { + if (fgets(buf, sizeof(buf), fp) == NULL) + { + break; + } + ++current_line_number; + status = process_line(buf); + if (status == 0) + { + break; + } + } + break; + } + if (fp) + { + /* + * It doesn't matter if we're reading from stdin, as we've reached EOF + */ + fclose(fp); + } + return (status); +} + + +static void +reset_boot(void) +{ + int i; + struct dos_partition *partp; + + init_boot(); + for (i = 0; i < 4; ++i) + { + partp = ((struct dos_partition *) &mboot.parts) + i; + bzero((char *)partp, sizeof (struct dos_partition)); + } +} +#endif diff --git a/sys/alpha/pci/dwlpx_pci.c b/sys/alpha/pci/dwlpx_pci.c new file mode 100644 index 000000000000..dd8612f75e4b --- /dev/null +++ b/sys/alpha/pci/dwlpx_pci.c @@ -0,0 +1,80 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000 Matthew Jacob + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <sys/rman.h> +#include <pci/pcivar.h> + +static devclass_t pcib_devclass; + +static int +dwlpx_pcib_probe(device_t dev) +{ + device_set_desc(dev, "DWLPX PCI host bus adapter"); + device_add_child(dev, "pci", -1); + return (0); +} + +static int +dwlpx_pcib_read_ivar(device_t dev, device_t child, int which, u_long *result) +{ + if (which == PCIB_IVAR_HOSE) { + *result = *(int*) device_get_ivars(dev); + return 0; + } + return ENOENT; +} + +static device_method_t dwlpx_pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dwlpx_pcib_probe), + DEVMETHOD(device_attach, bus_generic_attach), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, dwlpx_pcib_read_ivar), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static driver_t dwlpx_pcib_driver = { + "pcib", dwlpx_pcib_methods, 1 +}; + +DRIVER_MODULE(pcib, dwlpx, dwlpx_pcib_driver, pcib_devclass, 0, 0); diff --git a/sys/alpha/tlsb/dwlpxvar.h b/sys/alpha/tlsb/dwlpxvar.h new file mode 100644 index 000000000000..4720638e1f76 --- /dev/null +++ b/sys/alpha/tlsb/dwlpxvar.h @@ -0,0 +1,92 @@ +/* $FreeBSD$ */ +/* + * Copyright (c) 2000 by Matthew Jacob + * NASA AMES Research Center. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#define DWLPX_NONE 0 +#define DWLPX_SG32K 1 +#define DWLPX_SG64K 2 +#define DWLPX_SG128K 3 + +/* + * Each DWLPX supports up to 15 devices, 12 of which are PCI slots. + * + * Since the STD I/O modules in slots 12-14 are really a PCI-EISA + * bridge, we'll punt on those for the moment. + */ +#define DWLPX_MAXDEV 12 + +/* + * There are 5 possible slots that can have I/O boards, and for each + * one there are 4 possible hoses. To cover them all, we'd have to + * reserve 5 bits of selector out our current 32 bit cookie we use + * for primary PCI address spaces. It turns out that we *just* have + * enough bits for this (see drawing in dwlpxreg.h) + */ + +#define DWLPX_NIONODE 5 +#define DWLPX_NHOSE 4 + +/* + * Interrupt Cookie for DWLPX vectors. + * + * Bits 0..3 PCI Slot (0..11) + * Bits 4..7 I/O Hose (0..3) + * Bits 8..11 I/O Node (0..4) + * Bit 15 Constant 1 + */ +#define DWLPX_VEC_MARK (1<<15) +#define DWLPX_MVEC(ionode, hose, pcislot) \ + (DWLPX_VEC_MARK | (ionode << 8) | (hose << 4) | (pcislot)) + +#define DWLPX_MVEC_IONODE(cookie) \ + ((((u_int64_t)(cookie)) >> 8) & 0xf) +#define DWLPX_MVEC_HOSE(cookie) \ + ((((u_int64_t)(cookie)) >> 4) & 0xf) +#define DWLPX_MVEC_PCISLOT(cookie) \ + (((u_int64_t)(cookie)) & 0xf) + +/* + * DWLPX Error Interrupt + */ +#define DWLPX_VEC_EMARK (1<<14) +#define DWLPX_ERRVEC(ionode, hose) \ + (DWLPX_VEC_EMARK | (ionode << 8) | (hose << 4)) + +/* + * Default values to put into DWLPX IMASK register(s) + */ +#define DWLPX_IMASK_DFLT \ + (1 << 24) | /* IPL 17 for error interrupts */ \ + (1 << 17) | /* IPL 14 for device interrupts */ \ + (1 << 16) /* Enable Error Interrupts */ + +#define DWLPX_BASE(node, hose) \ + ((((unsigned long)(node - 4)) << 36) | \ + (((unsigned long)(hose)) << 34) | \ + (1LL << 39)) diff --git a/sys/alpha/tlsb/tlsbcpu.c b/sys/alpha/tlsb/tlsbcpu.c new file mode 100644 index 000000000000..40fc028fad3c --- /dev/null +++ b/sys/alpha/tlsb/tlsbcpu.c @@ -0,0 +1,121 @@ +/* $FreeBSD$ */ + +/* + * Copyright (c) 1997, 2000 by Matthew Jacob + * NASA AMES Research Center. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Node for TLSB CPU Modules found on + * AlphaServer 8200 and 8400 systems. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/malloc.h> + +#include <machine/rpb.h> +#include <machine/cpuconf.h> + +#include <alpha/tlsb/tlsbreg.h> +#include <alpha/tlsb/tlsbvar.h> + +#define KV(_addr) ((caddr_t)ALPHA_PHYS_TO_K0SEG((_addr))) + +/* + * Device methods + */ +static int tlsbcpu_probe(device_t); + +static device_method_t tlsbcpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, tlsbcpu_probe), + DEVMETHOD(device_attach, bus_generic_attach), + DEVMETHOD(device_detach, bus_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), + DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + { 0, 0 } +}; + +static devclass_t tlsbcpu_devclass; +static driver_t tlsbcpu_driver = { + "tlsbcpu", tlsbcpu_methods, 1 +}; + +static int +tlsbcpu_probe(device_t dev) +{ + u_int32_t vid; + device_t child; + static int inst = 0; + struct tlsb_device *tdev = DEVTOTLSB(dev); + + /* + * Deal with hooking CPU instances to TurboLaser nodes. + */ + if (!TLDEV_ISCPU(tdev->td_tldev)) { + return (-1); + } + + vid = TLSB_GET_NODEREG(tdev->td_node, TLVID) & TLVID_VIDA_MASK; + vid >>= TLVID_VIDA_SHIFT; + + /* + * If this is the primary CPU (unit 0 for us), then + * attach a gbus. Otherwise don't. This is bogus, + * but sufficent for now. + */ + if (device_get_unit(dev) != 0) { + return (0); + } + + /* + * Hook in the first CPU unit. + */ + tlsb_primary_cpu = tdev; + TLSB_PUT_NODEREG(tdev->td_node, TLCPUMASK, (1 << vid)); + + /* + * Attach gbus. + */ + child = device_add_child(dev, "gbus", inst++); + if (child == NULL) { + return (-1); + } + device_set_ivars(child, tdev); + return (0); +} +DRIVER_MODULE(tlsbcpu, tlsb, tlsbcpu_driver, tlsbcpu_devclass, 0, 0); diff --git a/usr.bin/fstat/cd9660.c b/usr.bin/fstat/cd9660.c new file mode 100644 index 000000000000..0d739a656bb5 --- /dev/null +++ b/usr.bin/fstat/cd9660.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000 Peter Edwards + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by Peter Edwards + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * XXX - + * This had to be separated from fstat.c because cd9660s has namespace + * conflicts with UFS. + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/mount.h> + +#include <isofs/cd9660/cd9660_node.h> + +#include <kvm.h> +#include <stdio.h> + +#include "fstat.h" + +int +isofs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct iso_node isonode; + + if (!KVM_READ(VTOI(vp), &isonode, sizeof (isonode))) { + dprintf(stderr, "can't read iso_node at %p for pid %d\n", + (void *)VTOI(vp), Pid); + return 0; + } + fsp->fsid = dev2udev(isonode.i_dev) & 0xffff; + fsp->mode = (mode_t)isonode.inode.iso_mode; + fsp->rdev = isonode.i_dev; + + fsp->fileid = (long)isonode.i_number; + fsp->size = (u_long)isonode.i_size; + return 1; +} + diff --git a/usr.bin/fstat/fstat.h b/usr.bin/fstat/fstat.h new file mode 100644 index 000000000000..02ce12a0d15b --- /dev/null +++ b/usr.bin/fstat/fstat.h @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __FSTAT_H__ +#define __FSTAT_H__ + +/* + * a kvm_read that returns true if everything is read + */ +#define KVM_READ(kaddr, paddr, len) \ + (kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len)) + +#define dprintf if (vflg) fprintf + +typedef struct devs { + struct devs *next; + long fsid; + ino_t ino; + char *name; +} DEVS; + +struct filestat { + long fsid; + long fileid; + mode_t mode; + u_long size; + dev_t rdev; +}; + +/* Ugh */ +extern kvm_t *kd; +extern int vflg; +extern int Pid; + +udev_t dev2udev __P((dev_t dev)); + +/* Additional filesystem types */ +int isofs_filestat __P((struct vnode *vp, struct filestat *fsp)); +int msdosfs_filestat __P((struct vnode *vp, struct filestat *fsp)); + +#endif /* __FSTAT_H__ */ diff --git a/usr.bin/fstat/msdosfs.c b/usr.bin/fstat/msdosfs.c new file mode 100644 index 000000000000..809477d476b3 --- /dev/null +++ b/usr.bin/fstat/msdosfs.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Peter Edwards + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by Peter Edwards + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/vnode.h> + +#define _KERNEL +#include <sys/mount.h> +#include <msdosfs/bpb.h> +#include <msdosfs/msdosfsmount.h> +#undef _KERNEL + +#include <msdosfs/denode.h> +#include <msdosfs/direntry.h> +#include <msdosfs/fat.h> + +#include <err.h> +#include <kvm.h> +#include <stdio.h> +#include <stdlib.h> + +/* + * XXX - + * VTODE is defined in denode.h only if _KERNEL is defined, but that leads to + * header explosion + */ +#define VTODE(vp) ((struct denode *)(vp)->v_data) + +#include "fstat.h" + +struct dosmount { + struct dosmount *next; + struct msdosfsmount *kptr; /* Pointer in kernel space */ + struct msdosfsmount data; /* User space copy of structure */ +}; + +int +msdosfs_filestat(vp, fsp) + struct vnode *vp; + struct filestat *fsp; +{ + struct denode denode; + static struct dosmount *mounts; + struct dosmount *mnt; + u_long dirsperblk; + int fileid; + + if (!KVM_READ(VTODE(vp), &denode, sizeof (denode))) { + dprintf(stderr, "can't read denode at %p for pid %d\n", + (void *)VTODE(vp), Pid); + return 0; + } + + /* + * Find msdosfsmount structure for the vnode's filesystem. Needed + * for some filesystem parameters + */ + for (mnt = mounts; mnt; mnt = mnt->next) + if (mnt->kptr == denode.de_pmp) + break; + + if (!mnt) { + if ((mnt = malloc(sizeof(struct dosmount))) == NULL) + err(1, NULL); + mnt->next = mounts; + mounts = mnt; + mnt->kptr = denode.de_pmp; + if (!KVM_READ(denode.de_pmp, &mnt->data, sizeof mnt->data)) { + dprintf(stderr, + "can't read mount info at %p for pid %d\n", + (void *)denode.de_pmp, Pid); + return 0; + } + } + + fsp->fsid = dev2udev(denode.de_dev) & 0xffff; + fsp->mode = 0555; + fsp->mode |= denode.de_Attributes & ATTR_READONLY ? 0 : 0222; + fsp->mode &= mnt->data.pm_mask; + + /* Distinguish directories and files. No "special" files in FAT. */ + fsp->mode |= denode.de_Attributes & ATTR_DIRECTORY ? S_IFDIR : S_IFREG; + + fsp->size = denode.de_FileSize; + fsp->rdev = denode.de_dev; + + /* + * XXX - + * Culled from msdosfs_vnops.c. There appears to be a problem + * here, in that a directory has the same inode number as the first + * file in the directory. stat(2) suffers from this problem also, so + * I won't try to fix it here. + * + * The following computation of the fileid must be the same as that + * used in msdosfs_readdir() to compute d_fileno. If not, pwd + * doesn't work. + */ + dirsperblk = mnt->data.pm_BytesPerSec / sizeof(struct direntry); + if (denode.de_Attributes & ATTR_DIRECTORY) { + fileid = cntobn(&mnt->data, denode.de_StartCluster) + * dirsperblk; + if (denode.de_StartCluster == MSDOSFSROOT) + fileid = 1; + } else { + fileid = cntobn(&mnt->data, denode.de_dirclust) * dirsperblk; + if (denode.de_dirclust == MSDOSFSROOT) + fileid = roottobn(&mnt->data, 0) * dirsperblk; + fileid += denode.de_diroffset / sizeof(struct direntry); + } + + fsp->fileid = fileid; + return 1; +} |
