diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1995-08-30 17:42:29 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1995-08-30 17:42:29 +0000 |
commit | 09adf59b71be5536e90072a21ff0a298de13b31e (patch) | |
tree | 5472a1168e90c3da5a19b92d4eec77fdec82325a | |
parent | 11ae5136afc310ef71c58826e0faa94cc2b415f4 (diff) |
Notes
118 files changed, 28390 insertions, 0 deletions
diff --git a/eBones/Copyright.MIT b/eBones/Copyright.MIT new file mode 100644 index 0000000000000..cd1d89bc88d79 --- /dev/null +++ b/eBones/Copyright.MIT @@ -0,0 +1,24 @@ +# $Id: Copyright.MIT,v 1.3 1995/07/18 16:34:16 mark Exp $ + +The following Copyright notice applies to the original Bones package. + +/*- + Copyright (C) 1989 by the Massachusetts Institute of Technology + + Export of this software from the United States of America is assumed + to require a specific license from the United States Government. + It is the responsibility of any person or organization contemplating + export to obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. M.I.T. makes no representations about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. + + */ diff --git a/eBones/Copyright.SIPB b/eBones/Copyright.SIPB new file mode 100644 index 0000000000000..5e6c38af38e7f --- /dev/null +++ b/eBones/Copyright.SIPB @@ -0,0 +1,23 @@ +# $Id: Copyright.SIPB,v 1.3 1995/07/18 16:34:18 mark Exp $ + +The following Copyright notice applies to parts of the Bones package. +See source code for exact references. + +/*- +Copyright 1987 by the Student Information Processing Board + of the Massachusetts Institute of Technology + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is +hereby granted, provided that the above copyright notice +appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, +and that the names of M.I.T. and the M.I.T. S.I.P.B. not be +used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. +M.I.T. and the M.I.T. S.I.P.B. make no representations about +the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. + + */ + diff --git a/eBones/README.libdes b/eBones/README.libdes new file mode 100644 index 0000000000000..a2aa1eb43099b --- /dev/null +++ b/eBones/README.libdes @@ -0,0 +1,56 @@ + + libdes, Version 3.00 93/10/07 + + Copyright (c) 1993, Eric Young + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of either: + + a) the GNU General Public License as published by the Free + Software Foundation; either version 1, or (at your option) any + later version, or + + b) the "Artistic License" which comes with this Kit. + + This program 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 either + the GNU General Public License or the Artistic License for more details. + + You should have received a copy of the Artistic License with this + Kit, in the file named "Artistic". If not, I'll be glad to provide one. + + You should also have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +--- +This kit builds a DES encryption library and a DES encryption program. +It suports ecb, cbc, ofb, cfb, triple ecb, triple cbc and MIT's pcbc +encryption modes and also has a fast implementation of crypt(3). +It contains support routines to read keys from a terminal, +generate a random key, generate a key from an arbitary length string, +read/write encrypted data from/to a file descriptor. + +The implementation was written so as to conform with the manual entry +for the des_crypt(3) library routines from MIT's project Athena. + +destest should be run after compilation to test the des routines. +rpw should be run after compilation to test the read password routines. +The des program is a replacement for the sun des command. I believe it +conforms to the sun version. + +The Imakefile is setup for use in the kerberos distribution. + +These routines are best compiled with gcc or any other good +optimising compiler. +Just turn you optimiser up to the highest settings and run destest +after the build to make sure everything works. + +I believe these routines are close to the fastest and most portable DES +routines that use small lookup tables (4.5k) that are publicly available. +The fcrypt routine is faster than ufc's fcrypt (when compiling with +gcc2 -O2) on the sparc 2 (1410 vs 1270) but is not so good on other machines +(on a sun3/260 168 vs 336). + +Eric Young (eay@psych.psy.uq.oz.au) diff --git a/eBones/include/ChangeLog b/eBones/include/ChangeLog new file mode 100644 index 0000000000000..77bc7552a42fd --- /dev/null +++ b/eBones/include/ChangeLog @@ -0,0 +1,25 @@ +# $Id: ChangeLog,v 1.3 1995/07/18 16:35:58 mark Exp $ + +Mon Mar 21 15:48:59 MET 1994 Piero Serini + * 1st port to FreeBSD + +Tue Nov 29 11:52:51 1988 John T Kohl (jtkohl at lycus) + + * osconf.h: add #ifdef's for SUN processors (bsd/m68k) + + * conf-bsdm68k.h: new file for BSD unix/M68000-based unix boxes + +Mon Sep 12 14:33:58 1988 Bill Sommerfeld (wesommer at ra) + + * des_conf.h: deleted file (superceded by conf.h) + + * des.h: remove #include of des_conf.h + + * des.h: remove internal details (sbox structure, bit_{32,64}) from +interface. + Rename data types. + Add #defines, turned off if NCOMPAT, for compatibility with old + versions. + + + diff --git a/eBones/include/addr_comp.h b/eBones/include/addr_comp.h new file mode 100644 index 0000000000000..2421bc683de5a --- /dev/null +++ b/eBones/include/addr_comp.h @@ -0,0 +1,35 @@ +/* + * Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Include file for address comparison macros. + * + * from: addr_comp.h,v 4.0 89/01/23 09:57:44 jtkohl Exp $ + * $Id: addr_comp.h,v 1.3 1995/07/18 16:36:01 mark Exp $ + */ + +#ifndef ADDR_COMP_DEFS +#define ADDR_COMP_DEFS + +/* +** Look boys and girls, a big kludge +** We need to compare the two internet addresses in network byte order, not +** local byte order. This is a *really really slow way of doing that* +** But..... +** .....it works +** so we run with it +** +** long_less_than gets fed two (u_char *)'s.... +*/ + +#define u_char_comp(x,y) \ + (((x)>(y))?(1):(((x)==(y))?(0):(-1))) + +#define long_less_than(x,y) \ + (u_char_comp((x)[0],(y)[0])?u_char_comp((x)[0],(y)[0]): \ + (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \ + (u_char_comp((x)[2],(y)[2])?u_char_comp((x)[2],(y)[2]): \ + (u_char_comp((x)[3],(y)[3]))))) + +#endif /* ADDR_COMP_DEFS */ diff --git a/eBones/include/admin_server.h b/eBones/include/admin_server.h new file mode 100644 index 0000000000000..ca0977da63b22 --- /dev/null +++ b/eBones/include/admin_server.h @@ -0,0 +1,42 @@ +/* + * Copyright 1987, 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Include file for the Kerberos administration server. + * + * from: admin_server.h,v 4.7 89/01/11 11:59:42 steiner Exp $ + * $Id: admin_server.h,v 1.3 1995/07/18 16:36:03 mark Exp $ + */ + +#ifndef ADMIN_SERVER_DEFS +#define ADMIN_SERVER_DEFS + +#define PW_SRV_VERSION 2 /* version number */ + +#define INSTALL_NEW_PW (1<<0) /* + * ver, cmd, name, password, + * old_pass, crypt_pass, uid + */ + +#define ADMIN_NEW_PW (2<<1) /* + * ver, cmd, name, passwd, + * old_pass + * (grot), crypt_pass (grot) + */ + +#define ADMIN_SET_KDC_PASSWORD (3<<1) /* ditto */ +#define ADMIN_ADD_NEW_KEY (4<<1) /* ditto */ +#define ADMIN_ADD_NEW_KEY_ATTR (5<<1) /* + * ver, cmd, name, passwd, + * inst, attr (grot) + */ +#define INSTALL_REPLY (1<<1) /* ver, cmd, name, password */ +#define RETRY_LIMIT 1 +#define TIME_OUT 30 +#define USER_TIMEOUT 90 +#define MAX_KPW_LEN 40 + +#define KADM "changepw" /* service name */ + +#endif /* ADMIN_SERVER_DEFS */ diff --git a/eBones/include/conf-bsd386i.h b/eBones/include/conf-bsd386i.h new file mode 100644 index 0000000000000..a009450d70e0c --- /dev/null +++ b/eBones/include/conf-bsd386i.h @@ -0,0 +1,16 @@ +/* + * Copyright 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: Sun 386i using SunOS (~BSD) + * + * from: conf-bsd386i.h,v 4.0 89/12/19 13:26:55 jtkohl Exp $ + * $Id: conf-bsd386i.h,v 1.3 1995/07/18 16:36:05 mark Exp $ + */ + +#define BITS32 +#define BIG +#define LSBFIRST +#define BSDUNIX + diff --git a/eBones/include/conf-bsdapollo.h b/eBones/include/conf-bsdapollo.h new file mode 100644 index 0000000000000..12dc5806c8e55 --- /dev/null +++ b/eBones/include/conf-bsdapollo.h @@ -0,0 +1,21 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * from: conf-bsdapollo.h,v 4.1 89/01/24 14:26:22 jtkohl Exp $ + * $Id: conf-bsdapollo.h,v 1.3 1995/07/18 16:36:06 mark Exp $ + */ + +#define BSDUNIX +#define BITS32 +#define BIG +#define MSBFIRST +#define DES_SHIFT_SHIFT +/* + * As of SR10, the C compiler claims to be __STDC__, but doesn't support + * const. Sigh. + */ +#define const + + diff --git a/eBones/include/conf-bsdibm032.h b/eBones/include/conf-bsdibm032.h new file mode 100644 index 0000000000000..8331498e55dc5 --- /dev/null +++ b/eBones/include/conf-bsdibm032.h @@ -0,0 +1,18 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: IBM 032 (RT/PC) + * + * from: conf-bsdibm032.h,v 4.0 89/01/23 09:58:01 jtkohl Exp $ + * $Id: conf-bsdibm032.h,v 1.3 1995/07/18 16:36:08 mark Exp $ + */ + +#define BSDUNIX +#define IBMWS +#define IBMWSASM +#define BITS32 +#define BIG +#define MSBFIRST +#define MUSTALIGN diff --git a/eBones/include/conf-bsdm68k.h b/eBones/include/conf-bsdm68k.h new file mode 100644 index 0000000000000..9e60e060e509a --- /dev/null +++ b/eBones/include/conf-bsdm68k.h @@ -0,0 +1,16 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: 68000 with BSD Unix, e.g. SUN + * + * from: conf-bsdm68k.h,v 4.0 88/11/29 11:46:58 jtkohl Exp $ + * $Id: conf-bsdm68k.h,v 1.3 1995/07/18 16:36:10 mark Exp $ + */ + +#define BITS32 +#define BIG +#define MSBFIRST +#define BSDUNIX + diff --git a/eBones/include/conf-bsdsparc.h b/eBones/include/conf-bsdsparc.h new file mode 100644 index 0000000000000..7359aec78ec3f --- /dev/null +++ b/eBones/include/conf-bsdsparc.h @@ -0,0 +1,17 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: SPARC with BSD Unix, e.g. SUN-4 + * + * from: conf-bsdsparc.h,v 4.0 89/06/02 13:04:06 jtkohl Exp $ + * $Id: conf-bsdsparc.h,v 1.3 1995/07/18 16:36:12 mark Exp $ + */ + +#define BITS32 +#define BIG +#define MSBFIRST +#define BSDUNIX +#define MUSTALIGN + diff --git a/eBones/include/conf-bsdtahoe.h b/eBones/include/conf-bsdtahoe.h new file mode 100644 index 0000000000000..fa8c462cf3af6 --- /dev/null +++ b/eBones/include/conf-bsdtahoe.h @@ -0,0 +1,16 @@ +/* + * Copyright 1989 by the Regents of the University of California + * + * Machine Description : TAHOE. + * + * from: conf-bsdtahoe.h,v 4.0 89/08/30 11:06:53 jtkohl Exp $ + * $Id: conf-bsdtahoe.h,v 1.3 1995/07/18 16:36:14 mark Exp $ + */ + +#define TAHOE +#define BSDUNIX +#define BITS32 +#define BIG +#define MSBFIRST +#define MUSTALIGN +#define NOASM diff --git a/eBones/include/conf-bsdvax.h b/eBones/include/conf-bsdvax.h new file mode 100644 index 0000000000000..ef0c05228fc0b --- /dev/null +++ b/eBones/include/conf-bsdvax.h @@ -0,0 +1,22 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: VAX + * + * from: conf-bsdvax.h,v 4.0 89/01/23 09:58:12 jtkohl Exp $ + * $Id: conf-bsdvax.h,v 1.3 1995/07/18 16:36:15 mark Exp $ + */ + +#define VAX +#define BITS32 +#define BIG +#define LSBFIRST +#define BSDUNIX + +#ifndef __STDC__ +#ifndef NOASM +#define VAXASM +#endif /* no assembly */ +#endif /* standard C */ diff --git a/eBones/include/conf-ibm370.h b/eBones/include/conf-ibm370.h new file mode 100644 index 0000000000000..7b8b504ba4deb --- /dev/null +++ b/eBones/include/conf-ibm370.h @@ -0,0 +1,15 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: IBM 370 + * + * from: conf-ibm370.h,v 4.0 89/01/23 09:58:19 jtkohl Exp $ + * $Id: conf-ibm370.h,v 1.3 1995/07/18 16:36:17 mark Exp $ + */ + +/* What else? */ +#define BIG +#define NONASCII +#define SHORTNAMES diff --git a/eBones/include/conf-pc.h b/eBones/include/conf-pc.h new file mode 100644 index 0000000000000..4b633ffdba33d --- /dev/null +++ b/eBones/include/conf-pc.h @@ -0,0 +1,16 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: IBM PC 8086 + * + * from: conf-pc.h,v 4.0 89/01/23 09:58:26 jtkohl Exp $ + * $Id: conf-pc.h,v 1.3 1995/07/18 16:36:19 mark Exp $ + * + */ + +#define IBMPC +#define BITS16 +#define CROSSMSDOS +#define LSBFIRST diff --git a/eBones/include/conf-pyr.h b/eBones/include/conf-pyr.h new file mode 100644 index 0000000000000..f47c2155031fd --- /dev/null +++ b/eBones/include/conf-pyr.h @@ -0,0 +1,15 @@ +/* + * Copyright 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: Pyramid + * + * from: conf-pyr.h,v 4.0 89/12/19 13:27:16 jtkohl Exp $ + * $Id: conf-pyr.h,v 1.3 1995/07/18 16:36:20 mark Exp $ + */ + +#define BITS32 +#define BIG +#define MSBFIRST +#define BSDUNIX diff --git a/eBones/include/conf-ultmips2.h b/eBones/include/conf-ultmips2.h new file mode 100644 index 0000000000000..9733090aa2aaf --- /dev/null +++ b/eBones/include/conf-ultmips2.h @@ -0,0 +1,17 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Machine-type definitions: DECstation 3100 (MIPS R2000) + * + * from: conf-ultmips2.h,v 4.0 89/01/23 09:58:32 jtkohl Exp $ + * $Id: conf-ultmips2.h,v 1.3 1995/07/18 16:36:22 mark Exp $ + */ + +#define MIPS2 +#define BITS32 +#define BIG +#define LSBFIRST +#define BSDUNIX +#define MUSTALIGN diff --git a/eBones/include/conf.h b/eBones/include/conf.h new file mode 100644 index 0000000000000..64797e6bdfc46 --- /dev/null +++ b/eBones/include/conf.h @@ -0,0 +1,73 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Configuration info for operating system, hardware description, + * language implementation, C library, etc. + * + * This file should be included in (almost) every file in the Kerberos + * sources, and probably should *not* be needed outside of those + * sources. (How do we deal with /usr/include/des.h and + * /usr/include/krb.h?) + * + * from: conf.h,v 4.0 89/01/23 09:58:40 jtkohl Exp $ + * $Id: conf.h,v 1.3 1995/07/18 16:36:24 mark Exp $ + */ + +#ifndef _CONF_H_ + +#include "osconf.h" + +#ifdef SHORTNAMES +#include "names.h" +#endif + +/* + * Language implementation-specific definitions + */ + +/* special cases */ +#ifdef __HIGHC__ +/* broken implementation of ANSI C */ +#undef __STDC__ +#endif + +#ifndef __STDC__ +#define const +#define volatile +#define signed +typedef char *pointer; /* pointer to generic data */ +#define PROTOTYPE(p) () +#else +typedef void *pointer; +#define PROTOTYPE(p) p +#endif + +/* Does your compiler understand "void"? */ +#ifdef notdef +#define void int +#endif + +/* + * A few checks to see that necessary definitions are included. + */ + +/* byte order */ + +#ifndef MSBFIRST +#ifndef LSBFIRST +Error: byte order not defined. +#endif +#endif + +/* machine size */ +#ifndef BITS16 +#ifndef BITS32 +Error: how big is this machine anyways? +#endif +#endif + +/* end of checks */ + +#endif /* _CONF_H_ */ diff --git a/eBones/include/highc.h b/eBones/include/highc.h new file mode 100644 index 0000000000000..7ff2f7cbd5e04 --- /dev/null +++ b/eBones/include/highc.h @@ -0,0 +1,32 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Known breakage in the version of Metaware's High C compiler that + * we've got available.... + * + * from: highc.h,v 4.0 89/01/23 09:59:15 jtkohl Exp $ + * $Id: highc.h,v 1.3 1995/07/18 16:36:27 mark Exp $ + */ + +#define const +/*#define volatile*/ + +/* + * Some builtin functions we can take advantage of for inlining.... + */ + +#define abs _abs +/* the _max and _min builtins accept any number of arguments */ +#undef MAX +#define MAX(x,y) _max(x,y) +#undef MIN +#define MIN(x,y) _min(x,y) +/* + * I'm not sure if 65535 is a limit for this builtin, but it's + * reasonable for a string length. Or is it? + */ +/*#define strlen(s) _find_char(s,65535,0)*/ +#define bzero(ptr,len) _fill_char(ptr,len,'\0') +#define bcmp(b1,b2,len) _compare(b1,b2,len) diff --git a/eBones/include/kdc.h b/eBones/include/kdc.h new file mode 100644 index 0000000000000..70756a49afde0 --- /dev/null +++ b/eBones/include/kdc.h @@ -0,0 +1,36 @@ +/* + * Copyright 1987, 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Include file for the Kerberos Key Distribution Center. + * + * from: kdc.h,v 4.1 89/01/24 17:54:04 jon Exp $ + * $Id: kdc.h,v 1.3 1995/07/18 16:36:29 mark Exp $ + */ + +#ifndef KDC_DEFS +#define KDC_DEFS + +#define S_AD_SZ sizeof(struct sockaddr_in) + +#define max(a,b) (a>b ? a : b) +#define min(a,b) (a<b ? a : b) + +#define TRUE 1 +#define FALSE 0 + +#define MKEYFILE "/etc/kerberosIV/master_key" +#define K_LOGFIL "/var/log/kpropd.log" +#define KS_LOGFIL "/var/log/kerberos_slave.log" +#define KRB_ACL "/etc/kerberosIV/kerberos.acl" +#define KRB_PROG "./kerberos" + +#define ONE_MINUTE 60 +#define FIVE_MINUTES (5 * ONE_MINUTE) +#define ONE_HOUR (60 * ONE_MINUTE) +#define ONE_DAY (24 * ONE_HOUR) +#define THREE_DAYS (3 * ONE_DAY) + +#endif /* KDC_DEFS */ + diff --git a/eBones/include/klog.h b/eBones/include/klog.h new file mode 100644 index 0000000000000..c8ca55778696b --- /dev/null +++ b/eBones/include/klog.h @@ -0,0 +1,39 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * This file defines the types of log messages logged by klog. Each + * type of message may be selectively turned on or off. + * + * from: klog.h,v 4.7 89/01/24 17:55:07 jon Exp $ + * $Id: klog.h,v 1.3 1995/07/18 16:36:30 mark Exp $ + */ + +#ifndef KLOG_DEFS +#define KLOG_DEFS + +#define KRBLOG "/var/log/kerberos.log" /* master server */ +#define KRBSLAVELOG "/var/log/kerberos_slave.log" /* master server */ +#define NLOGTYPE 100 /* Maximum number of log msg types */ + +#define L_NET_ERR 1 /* Error in network code */ +#define L_NET_INFO 2 /* Info on network activity */ +#define L_KRB_PERR 3 /* Kerberos protocol errors */ +#define L_KRB_PINFO 4 /* Kerberos protocol info */ +#define L_INI_REQ 5 /* Request for initial ticket */ +#define L_NTGT_INTK 6 /* Initial request not for TGT */ +#define L_DEATH_REQ 7 /* Request for server death */ +#define L_TKT_REQ 8 /* All ticket requests using a tgt */ +#define L_ERR_SEXP 9 /* Service expired */ +#define L_ERR_MKV 10 /* Master key version incorrect */ +#define L_ERR_NKY 11 /* User's key is null */ +#define L_ERR_NUN 12 /* Principal not unique */ +#define L_ERR_UNK 13 /* Principal Unknown */ +#define L_ALL_REQ 14 /* All requests */ +#define L_APPL_REQ 15 /* Application requests (using tgt) */ +#define L_KRB_PWARN 16 /* Protocol warning messages */ + +char *klog(); + +#endif /* KLOG_DEFS */ diff --git a/eBones/include/krb_conf.h b/eBones/include/krb_conf.h new file mode 100644 index 0000000000000..ac7c2a83ec70f --- /dev/null +++ b/eBones/include/krb_conf.h @@ -0,0 +1,29 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * This file contains configuration information for the Kerberos library + * which is machine specific; currently, this file contains + * configuration information for the vax, the "ibm032" (RT), and the + * "PC8086" (IBM PC). + * + * Note: cross-compiled targets must appear BEFORE their corresponding + * cross-compiler host. Otherwise, both will be defined when running + * the native compiler on the programs that construct cross-compiled + * sources. + * + * from: krb_conf.h,v 4.0 89/01/23 09:59:27 jtkohl Exp $ + * $Id: krb_conf.h,v 1.3 1995/07/18 16:36:36 mark Exp $ + */ + +#ifndef KRB_CONF_DEFS +#define KRB_CONF_DEFS + +/* Byte ordering */ +extern int krbONE; +#define HOST_BYTE_ORDER (* (char *) &krbONE) +#define MSB_FIRST 0 /* 68000, IBM RT/PC */ +#define LSB_FIRST 1 /* Vax, PC8086 */ + +#endif KRB_CONF_DEFS diff --git a/eBones/include/lsb_addr_comp.h b/eBones/include/lsb_addr_comp.h new file mode 100644 index 0000000000000..2686ade5481f3 --- /dev/null +++ b/eBones/include/lsb_addr_comp.h @@ -0,0 +1,40 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Comparison macros to emulate LSBFIRST comparison results of network + * byte-order quantities + * + * from: lsb_addr_comp.h,v 4.0 89/01/23 15:44:46 jtkohl Exp $ + * $Id: lsb_addr_comp.h,v 1.3 1995/07/18 16:36:39 mark Exp $ + */ + +#ifndef LSB_ADDR_COMP_DEFS +#define LSB_ADDR_COMP_DEFS + +#include "osconf.h" + +#ifdef LSBFIRST +#define lsb_net_ulong_less(x,y) ((x < y) ? -1 : ((x > y) ? 1 : 0)) +#define lsb_net_ushort_less(x,y) ((x < y) ? -1 : ((x > y) ? 1 : 0)) +#else +/* MSBFIRST */ +#define u_char_comp(x,y) \ + (((x)>(y))?(1):(((x)==(y))?(0):(-1))) +/* This is gross, but... */ +#define lsb_net_ulong_less(x, y) long_less_than((u_char *)&x, (u_char *)&y) +#define lsb_net_ushort_less(x, y) short_less_than((u_char *)&x, (u_char *)&y) + +#define long_less_than(x,y) \ + (u_char_comp((x)[3],(y)[3])?u_char_comp((x)[3],(y)[3]): \ + (u_char_comp((x)[2],(y)[2])?u_char_comp((x)[2],(y)[2]): \ + (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \ + (u_char_comp((x)[0],(y)[0]))))) +#define short_less_than(x,y) \ + (u_char_comp((x)[1],(y)[1])?u_char_comp((x)[1],(y)[1]): \ + (u_char_comp((x)[0],(y)[0]))) + +#endif /* LSBFIRST */ + +#endif /* LSB_ADDR_COMP_DEFS */ diff --git a/eBones/include/osconf.h b/eBones/include/osconf.h new file mode 100644 index 0000000000000..e0af41a9570c7 --- /dev/null +++ b/eBones/include/osconf.h @@ -0,0 +1,51 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Athena configuration. + * + * from: osconf.h,v 4.4 89/12/19 13:26:27 jtkohl Exp $ + * $Id: osconf.h,v 1.3 1995/07/18 16:36:41 mark Exp $ + */ + +#ifdef tahoe +#include "conf-bsdtahoe.h" +#else /* !tahoe */ +#ifdef vax +#include "conf-bsdvax.h" +#else /* !vax */ +#if defined(mips) && defined(ultrix) +#include "conf-ultmips2.h" +#else /* !Ultrix MIPS-2 */ +#ifdef ibm032 +#include "conf-bsdibm032.h" +#else /* !ibm032 */ +#ifdef apollo +#include "conf-bsdapollo.h" +#else /* !apollo */ +#ifdef sun +#ifdef sparc +#include "conf-bsdsparc.h" +#else /* sun but not sparc */ +#ifdef i386 +#include "conf-bsd386i.h" +#else /* sun but not (sparc or 386i) */ +#include "conf-bsdm68k.h" +#endif /* i386 */ +#endif /* sparc */ +#else /* !sun */ +#ifdef pyr +#include "conf-pyr.h" +#endif /* pyr */ +#endif /* sun */ +#endif /* apollo */ +#endif /* ibm032 */ +#endif /* mips */ +#endif /* vax */ +#endif /* tahoe */ + +#if defined(__FreeBSD__) && defined(i386) +#include "conf-bsd386i.h" +#endif + diff --git a/eBones/include/passwd_server.h b/eBones/include/passwd_server.h new file mode 100644 index 0000000000000..662e65423cd2f --- /dev/null +++ b/eBones/include/passwd_server.h @@ -0,0 +1,28 @@ +/* + * Copyright 1987, 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Include file for password server + * + * from: passwd_server.h,v 4.6 89/01/11 15:12:22 steiner Exp $ + * $Id: passwd_server.h,v 1.3 1995/07/18 16:36:43 mark Exp $ + */ + +#ifndef PASSWD_SERVER_DEFS +#define PASSWD_SERVER_DEFS + +#define PW_SRV_VERSION 2 /* version number */ +#define RETRY_LIMIT 1 +#define TIME_OUT 30 +#define USER_TIMEOUT 90 +#define MAX_KPW_LEN 40 /* hey, seems like a good number */ + +#define INSTALL_NEW_PW (1<<0) /* + * ver, cmd, name, password, old_pass, + * crypt_pass, uid + */ + +#define INSTALL_REPLY (1<<1) /* ver, cmd, name, password */ + +#endif /* PASSWD_SERVER_DEFS */ diff --git a/eBones/include/principal.h b/eBones/include/principal.h new file mode 100644 index 0000000000000..7fa67bc42976d --- /dev/null +++ b/eBones/include/principal.h @@ -0,0 +1,18 @@ +/* + * Copyright 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Definitions for principal names. + * + * from: principal.h,v 4.5 89/01/11 15:15:01 steiner Exp $ + * $Id: principal.h,v 1.3 1995/07/18 16:36:45 mark Exp $ + */ + +#ifndef PRINCIPAL_DEFS +#define PRINCIPAL_DEFS + +#define NAME_LEN 39 +#define INSTANCE_LEN 39 + +#endif /* PRINCIPAL_DEFS */ diff --git a/eBones/include/prot.h b/eBones/include/prot.h new file mode 100644 index 0000000000000..ec0ee07dcc9f3 --- /dev/null +++ b/eBones/include/prot.h @@ -0,0 +1,92 @@ +/* + * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute + * of Technology. + * For copying and distribution information, please see the file + * <Copyright.MIT>. + * + * Include file with authentication protocol information. + * + * from: prot.h,v 4.13 89/01/24 14:27:22 jtkohl Exp $ + * $Id: prot.h,v 1.3 1995/07/18 16:36:46 mark Exp $ + */ + +#include <krb_conf.h> + +#ifndef PROT_DEFS +#define PROT_DEFS + +#define KRB_PORT 750 /* PC's don't have + * /etc/services */ +#define KRB_PROT_VERSION 4 +#define MAX_PKT_LEN 1000 +#define MAX_TXT_LEN 1000 +#define TICKET_GRANTING_TICKET "krbtgt" + +/* Macro's to obtain various fields from a packet */ + +#define pkt_version(packet) (unsigned int) *(packet->dat) +#define pkt_msg_type(packet) (unsigned int) *(packet->dat+1) +#define pkt_a_name(packet) (packet->dat+2) +#define pkt_a_inst(packet) \ + (packet->dat+3+strlen((char *)pkt_a_name(packet))) +#define pkt_a_realm(packet) \ + (pkt_a_inst(packet)+1+strlen((char *)pkt_a_inst(packet))) + +/* Macro to obtain realm from application request */ +#define apreq_realm(auth) (auth->dat + 3) + +#define pkt_time_ws(packet) (char *) \ + (packet->dat+5+strlen((char *)pkt_a_name(packet)) + \ + strlen((char *)pkt_a_inst(packet)) + \ + strlen((char *)pkt_a_realm(packet))) + +#define pkt_no_req(packet) (unsigned short) \ + *(packet->dat+9+strlen((char *)pkt_a_name(packet)) + \ + strlen((char *)pkt_a_inst(packet)) + \ + strlen((char *)pkt_a_realm(packet))) +#define pkt_x_date(packet) (char *) \ + (packet->dat+10+strlen((char *)pkt_a_name(packet)) + \ + strlen((char *)pkt_a_inst(packet)) + \ + strlen((char *)pkt_a_realm(packet))) +#define pkt_err_code(packet) ( (char *) \ + (packet->dat+9+strlen((char *)pkt_a_name(packet)) + \ + strlen((char *)pkt_a_inst(packet)) + \ + strlen((char *)pkt_a_realm(packet)))) +#define pkt_err_text(packet) \ + (packet->dat+13+strlen((char *)pkt_a_name(packet)) + \ + strlen((char *)pkt_a_inst(packet)) + \ + strlen((char *)pkt_a_realm(packet))) + +/* Routines to create and read packets may be found in prot.c */ + +KTEXT create_auth_reply(); +KTEXT create_death_packet(); +KTEXT pkt_cipher(); + +/* Message types , always leave lsb for byte order */ + +#define AUTH_MSG_KDC_REQUEST 1<<1 +#define AUTH_MSG_KDC_REPLY 2<<1 +#define AUTH_MSG_APPL_REQUEST 3<<1 +#define AUTH_MSG_APPL_REQUEST_MUTUAL 4<<1 +#define AUTH_MSG_ERR_REPLY 5<<1 +#define AUTH_MSG_PRIVATE 6<<1 +#define AUTH_MSG_SAFE 7<<1 +#define AUTH_MSG_APPL_ERR 8<<1 +#define AUTH_MSG_DIE 63<<1 + +/* values for kerb error codes */ + +#define KERB_ERR_OK 0 +#define KERB_ERR_NAME_EXP 1 +#define KERB_ERR_SERVICE_EXP 2 +#define KERB_ERR_AUTH_EXP 3 +#define KERB_ERR_PKT_VER 4 +#define KERB_ERR_NAME_MAST_KEY_VER 5 +#define KERB_ERR_SERV_MAST_KEY_VER 6 +#define KERB_ERR_BYTE_ORDER 7 +#define KERB_ERR_PRINCIPAL_UNKNOWN 8 +#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9 +#define KERB_ERR_NULL_KEY 10 + +#endif /* PROT_DEFS */ diff --git a/eBones/lib/libacl/acl_files.doc b/eBones/lib/libacl/acl_files.doc new file mode 100644 index 0000000000000..4096f9bbb3d38 --- /dev/null +++ b/eBones/lib/libacl/acl_files.doc @@ -0,0 +1,107 @@ +PROTOTYPE ACL LIBRARY + +Introduction + +An access control list (ACL) is a list of principals, where each +principal is is represented by a text string which cannot contain +whitespace. The library allows application programs to refer to named +access control lists to test membership and to atomically add and +delete principals using a natural and intuitive interface. At +present, the names of access control lists are required to be Unix +filenames, and refer to human-readable Unix files; in the future, when +a networked ACL server is implemented, the names may refer to a +different namespace specific to the ACL service. + + +Usage + +cc <files> -lacl -lkrb. + + + +Principal Names + +Principal names have the form + +<name>[.<instance>][@<realm>] + +e.g. + +asp +asp.root +asp@ATHENA.MIT.EDU +asp.@ATHENA.MIT.EDU +asp.root@ATHENA.MIT.EDU + +It is possible for principals to be underspecified. If instance is +missing, it is assumed to be "". If realm is missing, it is assumed +to be local_realm. The canonical form contains all of name, instance, +and realm; the acl_add and acl_delete routines will always +leave the file in that form. Note that the canonical form of +asp@ATHENA.MIT.EDU is actually asp.@ATHENA.MIT.EDU. + + +Routines + +acl_canonicalize_principal(principal, buf) +char *principal; +char *buf; /*RETVAL*/ + +Store the canonical form of principal in buf. Buf must contain enough +space to store a principal, given the limits on the sizes of name, +instance, and realm specified in /usr/include/krb.h. + +acl_check(acl, principal) +char *acl; +char *principal; + +Returns nonzero if principal appears in acl. Returns 0 if principal +does not appear in acl, or if an error occurs. Canonicalizes +principal before checking, and allows the ACL to contain wildcards. + +acl_exact_match(acl, principal) +char *acl; +char *principal; + +Like acl_check, but does no canonicalization or wildcarding. + +acl_add(acl, principal) +char *acl; +char *principal; + +Atomically adds principal to acl. Returns 0 if successful, nonzero +otherwise. It is considered a failure if principal is already in acl. +This routine will canonicalize principal, but will treat wildcards +literally. + +acl_delete(acl, principal) +char *acl; +char *principal; + +Atomically deletes principal from acl. Returns 0 if successful, +nonzero otherwise. It is consider a failure if principal is not +already in acl. This routine will canonicalize principal, but will +treat wildcards literally. + +acl_initialize(acl, mode) +char *acl; +int mode; + +Initialize acl. If acl file does not exist, creates it with mode +mode. If acl exists, removes all members. Returns 0 if successful, +nonzero otherwise. WARNING: Mode argument is likely to change with +the eventual introduction of an ACL service. + + +Known problems + +In the presence of concurrency, there is a very small chance that +acl_add or acl_delete could report success even though it would have +had no effect. This is a necessary side effect of using lock files +for concurrency control rather than flock(2), which is not supported +by NFS. + +The current implementation caches ACLs in memory in a hash-table +format for increased efficiency in checking membership; one effect of +the caching scheme is that one file descriptor will be kept open for +each ACL cached, up to a maximum of 8. diff --git a/eBones/patchlevel.h b/eBones/patchlevel.h new file mode 100644 index 0000000000000..87e5061c8a8bd --- /dev/null +++ b/eBones/patchlevel.h @@ -0,0 +1,6 @@ +/*- + * $Id: patchlevel.h,v 1.3 1995/07/18 16:34:26 mark Exp $ + */ + +#define PATCHLEVEL 9 +#define FreeBSD_PL 0.1 diff --git a/eBones/usr.sbin/kdb_edit/kdb_edit.8 b/eBones/usr.sbin/kdb_edit/kdb_edit.8 new file mode 100644 index 0000000000000..44a0fa61ed70d --- /dev/null +++ b/eBones/usr.sbin/kdb_edit/kdb_edit.8 @@ -0,0 +1,58 @@ +.\" from: kdb_edit.8,v 4.1 89/01/23 11:08:55 jtkohl Exp $ +.\" $Id: kdb_edit.8,v 1.2 1995/02/08 10:54:20 jkh Exp $ +.\" Copyright 1989 by the Massachusetts Institute of Technology. +.\" +.\" For copying and distribution information, +.\" please see the file <Copyright.MIT>. +.\" +.TH KDB_EDIT 8 "Kerberos Version 4.0" "MIT Project Athena" +.SH NAME +kdb_edit \- Kerberos key distribution center database editing utility +.SH SYNOPSIS +kdb_edit [ +.B \-n +] +.SH DESCRIPTION +.I kdb_edit +is used to create or change principals stored in the Kerberos key +distribution center (KDC) database. +.PP +When executed, +.I kdb_edit +prompts for the master key string and verifies that it matches the +master key stored in the database. +If the +.B \-n +option is specified, the master key is instead fetched from the master +key cache file. +.PP +Once the master key has been verified, +.I kdb_edit +begins a prompt loop. The user is prompted for the principal and +instance to be modified. If the entry is not found the user may create +it. +Once an entry is found or created, the user may set the password, +expiration date, maximum ticket lifetime, and attributes. +Default expiration dates, maximum ticket lifetimes, and attributes are +presented in brackets; if the user presses return the default is selected. +There is no default password. +The password "RANDOM" and an empty password are interpreted specially, +if entered the user may have the program select a random DES key for the +principal. +.PP +Upon successfully creating or changing the entry, ``Edit O.K.'' is +printed. +.SH DIAGNOSTICS +.TP 20n +"verify_master_key: Invalid master key, does not match database." +The master key string entered was incorrect. +.SH FILES +.TP 20n +/etc/kerberosIV/principal.db +DBM file containing database +.TP +/etc/kerberosIV/principal.ok +Semaphore indicating that the DBM database is not being modified. +.TP +/etc/kerberosIV/master_key +Master key cache file. diff --git a/eBones/usr.sbin/kdb_edit/time.h b/eBones/usr.sbin/kdb_edit/time.h new file mode 100644 index 0000000000000..ae84e2e24585e --- /dev/null +++ b/eBones/usr.sbin/kdb_edit/time.h @@ -0,0 +1,45 @@ +/* Structure for use by time manipulating subroutines. + * The following library routines use it: + * libc: ctime, localtime, gmtime, asctime + * libcx: partime, maketime (may not be installed yet) + */ + +/* + * from: time.h,v 1.1 82/05/06 11:34:29 wft Exp $ + * $Id: time.h,v 1.3 1995/07/18 16:37:31 mark Exp $ + */ + +struct tm { /* See defines below for allowable ranges */ + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + int tm_zon; /* NEW: mins westward of Greenwich */ + int tm_ampm; /* NEW: 1 if AM, 2 if PM */ +}; + +#define LCLZONE (5*60) /* Until V7 ftime(2) works, this defines local zone*/ +#define TMNULL (-1) /* Items not specified are given this value + * in order to distinguish null specs from zero + * specs. This is only used by partime and + * maketime. */ + + /* Indices into TM structure */ +#define TM_SEC 0 /* 0-59 */ +#define TM_MIN 1 /* 0-59 */ +#define TM_HOUR 2 /* 0-23 */ +#define TM_MDAY 3 /* 1-31 day of month */ +#define TM_DAY TM_MDAY /* " synonym */ +#define TM_MON 4 /* 0-11 */ +#define TM_YEAR 5 /* (year-1900) (year) */ +#define TM_WDAY 6 /* 0-6 day of week (0 = Sunday) */ +#define TM_YDAY 7 /* 0-365 day of year */ +#define TM_ISDST 8 /* 0 Std, 1 DST */ + /* New stuff */ +#define TM_ZON 9 /* 0-(24*60) minutes west of Greenwich */ +#define TM_AMPM 10 /* 1 AM, 2 PM */ diff --git a/gnu/libexec/uucp/libunix/failed.c b/gnu/libexec/uucp/libunix/failed.c new file mode 100644 index 0000000000000..66c98a80df69e --- /dev/null +++ b/gnu/libexec/uucp/libunix/failed.c @@ -0,0 +1,26 @@ +/* failed.c + Save a file in the .Failed directory. */ + +#include "uucp.h" + +#include "sysdep.h" +#include "uudefs.h" +#include "system.h" + +char * +zsysdep_save_failed_file (zfile) + const char *zfile; +{ + char *zto; + + zto = zsappend3 (zSspooldir, FAILEDDIR, zfile); + + if (! fsysdep_move_file (zfile, zto, TRUE, FALSE, FALSE, + (const char *) NULL)) + { + ubuffree (zto); + return NULL; + } + + return zto; +} diff --git a/gnu/libexec/uucp/libunix/sync.c b/gnu/libexec/uucp/libunix/sync.c new file mode 100644 index 0000000000000..c346c58ccb7ad --- /dev/null +++ b/gnu/libexec/uucp/libunix/sync.c @@ -0,0 +1,42 @@ +/* sync.c + Sync a file to disk, if FSYNC_ON_CLOSE is set. */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" +#include "system.h" + +#include <errno.h> + +boolean +fsysdep_sync (e, zmsg) + openfile_t e; + const char *zmsg; +{ + int o; + +#if USE_STDIO + if (fflush (e) == EOF) + { + ulog (LOG_ERROR, "%s: fflush: %s", zmsg, strerror (errno)); + return FALSE; + } +#endif + +#if USE_STDIO + o = fileno (e); +#else + o = e; +#endif + +#if FSYNC_ON_CLOSE + if (fsync (o) < 0) + { + ulog (LOG_ERROR, "%s: fsync: %s", zmsg, strerror (errno)); + return FALSE; + } +#endif + + return TRUE; +} diff --git a/gnu/libexec/uucp/libunix/tcp.c b/gnu/libexec/uucp/libunix/tcp.c new file mode 100644 index 0000000000000..6ec39f26a63ba --- /dev/null +++ b/gnu/libexec/uucp/libunix/tcp.c @@ -0,0 +1,444 @@ +/* tcp.c + Code to handle TCP connections. + + Copyright (C) 1991, 1992, 1993, 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This 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 of the + License, or (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tcp_rcsid[] = "$Id: tcp.c,v 1.5 1995/06/21 19:20:46 ian Rel $"; +#endif + +#if HAVE_TCP + +#include "uudefs.h" +#include "uuconf.h" +#include "sysdep.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_TYPES_TCP_H +#include <sys/types.tcp.h> +#endif +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* This code handles TCP connections. It assumes a Berkeley socket + interface. */ + +/* The normal "uucp" port number. */ +#define IUUCP_PORT (540) + +/* Local functions. */ +static void utcp_free P((struct sconnection *qconn)); +static boolean ftcp_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftcp_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftcp_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); +static int itcp_port_number P((const char *zport)); + +/* The command table for a TCP connection. */ +static const struct sconncmds stcpcmds = +{ + utcp_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftcp_open, + ftcp_close, + ftcp_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Initialize a TCP connection. */ + +boolean +fsysdep_tcp_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->ord = -1; + q->owr = -1; + q->zdevice = NULL; + q->iflags = -1; + q->iwr_flags = -1; + q->fterminal = FALSE; + q->ftli = FALSE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stcpcmds; + return TRUE; +} + +/* Free a TCP connection. */ + +static void +utcp_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Open a TCP connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftcp_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + struct sockaddr_in s; + const char *zport; + uid_t ieuid; + boolean fswap; + + ulog_device ("TCP"); + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + qsysdep->o = socket (AF_INET, SOCK_STREAM, 0); + if (qsysdep->o < 0) + { + ulog (LOG_ERROR, "socket: %s", strerror (errno)); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* We save our process ID in the qconn structure. This is checked + in ftcp_close. */ + qsysdep->ipid = getpid (); + + /* If we aren't waiting for a connection, we're done. */ + if (! fwait) + return TRUE; + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + bzero ((pointer) &s, sizeof s); + s.sin_family = AF_INET; + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + s.sin_addr.s_addr = htonl (INADDR_ANY); + + /* Swap to our real user ID when doing the bind call. This will + permit the server to use privileged TCP ports when invoked by + root. We only swap if our effective user ID is not root, so that + the program can also be made suid root in order to get privileged + ports when invoked by anybody. */ + fswap = geteuid () != 0; + if (fswap) + { + if (! fsuser_perms (&ieuid)) + { + (void) close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + } + + if (bind (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "bind: %s", strerror (errno)); + } + + /* Now swap back to the uucp user ID. */ + if (fswap) + { + if (! fsuucp_perms ((long) ieuid)) + ulog (LOG_FATAL, "Could not swap back to UUCP user permissions"); + } + + if (listen (qsysdep->o, 5) < 0) + ulog (LOG_FATAL, "listen: %s", strerror (errno)); + + while (! FGOT_SIGNAL ()) + { + size_t clen; + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Waiting for connections"); + + clen = sizeof s; + onew = accept (qsysdep->o, (struct sockaddr *) &s, &clen); + if (onew < 0) + ulog (LOG_FATAL, "accept: %s", strerror (errno)); + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftcp_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + (void) close (qsysdep->o); + qsysdep->o = onew; + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftcp_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + fret = TRUE; + if (qsysdep->o >= 0 && close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + qsysdep->o = -1; + + /* If the current pid is not the one we used to open the port, then + we must have forked up above and we are now the child. In this + case, we are being called from within the fendless loop in + uucico.c. We return FALSE to force the loop to end and the child + to exit. This should be handled in a cleaner fashion. */ + if (qsysdep->ipid != getpid ()) + fret = FALSE; + + return fret; +} + +/* Dial out on a TCP port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftcp_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialer) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialer; +{ + struct ssysdep_conn *qsysdep; + const char *zhost; + struct hostent *q; + struct sockaddr_in s; + const char *zport; + char **pzdialer; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialer = DIALERFOUND_FALSE; + + zhost = zphone; + if (zhost == NULL) + { + if (qsys == NULL) + { + ulog (LOG_ERROR, "No address for TCP connection"); + return FALSE; + } + zhost = qsys->uuconf_zname; + } + + errno = 0; + q = gethostbyname ((char *) zhost); + if (q != NULL) + { + s.sin_family = q->h_addrtype; + memcpy (&s.sin_addr.s_addr, q->h_addr, (size_t) q->h_length); + } + else + { + if (errno != 0) + { + ulog (LOG_ERROR, "gethostbyname (%s): %s", zhost, strerror (errno)); + return FALSE; + } + + s.sin_family = AF_INET; + s.sin_addr.s_addr = inet_addr ((char *) zhost); + if ((long) s.sin_addr.s_addr == (long) -1) + { + ulog (LOG_ERROR, "%s: unknown host name", zhost); + return FALSE; + } + } + + zport = qconn->qport->uuconf_u.uuconf_stcp.uuconf_zport; + s.sin_port = itcp_port_number (zport); + + if (connect (qsysdep->o, (struct sockaddr *) &s, sizeof s) < 0) + { + ulog (LOG_ERROR, "connect: %s", strerror (errno)); + return FALSE; + } + + /* Handle the dialer sequence, if any. */ + pzdialer = qconn->qport->uuconf_u.uuconf_stcp.uuconf_pzdialer; + if (pzdialer != NULL && *pzdialer != NULL) + { + if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, + qdialer, ptdialer)) + return FALSE; + } + + return TRUE; +} + +/* Get the port number given a name. The argument will almost always + be "uucp" so we cache that value. The return value is always in + network byte order. This returns -1 on error. */ + +static int +itcp_port_number (zname) + const char *zname; +{ + boolean fuucp; + static int iuucp; + int i; + char *zend; + struct servent *q; + + fuucp = strcmp (zname, "uucp") == 0; + if (fuucp && iuucp != 0) + return iuucp; + + /* Try it as a number first. */ + i = strtol ((char *) zname, &zend, 10); + if (i != 0 && *zend == '\0') + return htons (i); + + q = getservbyname ((char *) zname, (char *) "tcp"); + if (q == NULL) + { + /* We know that the "uucp" service should be 540, even if isn't + in /etc/services. */ + if (fuucp) + { + iuucp = htons (IUUCP_PORT); + return iuucp; + } + ulog (LOG_ERROR, "getservbyname (%s): %s", zname, strerror (errno)); + return -1; + } + + if (fuucp) + iuucp = q->s_port; + + return q->s_port; +} + +#endif /* HAVE_TCP */ diff --git a/gnu/libexec/uucp/libunix/tli.c b/gnu/libexec/uucp/libunix/tli.c new file mode 100644 index 0000000000000..3e546c844991b --- /dev/null +++ b/gnu/libexec/uucp/libunix/tli.c @@ -0,0 +1,628 @@ +/* tli.c + Code to handle TLI connections. + + Copyright (C) 1992, 1993, 1994 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This 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 of the + License, or (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char tli_rcsid[] = "$Id: tli.c,v 1.4 1995/06/21 19:20:50 ian Rel $"; +#endif + +#if HAVE_TLI + +#include "sysdep.h" +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "system.h" + +#include <errno.h> + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#if HAVE_TIUSER_H +#include <tiuser.h> +#else +#if HAVE_XTI_H +#include <xti.h> +#else +#if HAVE_SYS_TLI_H +#include <sys/tli.h> +#endif +#endif +#endif + +#if HAVE_STROPTS_H +#include <stropts.h> +#endif + +#if HAVE_FCNTL_H +#include <fcntl.h> +#else +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* The arguments to t_alloca have two different names. I want the + SVID ones, not the XPG3 ones. */ +#ifndef T_BIND +#define T_BIND T_BIND_STR +#endif +#ifndef T_CALL +#define T_CALL T_CALL_STR +#endif + +/* Hopefully these externs will not cause any trouble. This is how + they are shown in the SVID. */ +extern int t_errno; +extern char *t_errlist[]; +extern int t_nerr; + +#ifndef HAVE_TIUSER_H +#ifndef t_alloc +extern pointer t_alloc (); +#endif +#endif + +/* This code handles TLI connections. It's Unix specific. It's + largely based on code from Unix Network Programming, by W. Richard + Stevens. */ + +/* Local functions. */ +static const char *ztlierror P((void)); +static void utli_free P((struct sconnection *qconn)); +static boolean ftli_push P((struct sconnection *qconn)); +static boolean ftli_open P((struct sconnection *qconn, long ibaud, + boolean fwait)); +static boolean ftli_close P((struct sconnection *qconn, + pointer puuconf, + struct uuconf_dialer *qdialer, + boolean fsuccess)); +static boolean ftli_dial P((struct sconnection *qconn, pointer puuconf, + const struct uuconf_system *qsys, + const char *zphone, + struct uuconf_dialer *qdialer, + enum tdialerfound *ptdialer)); + +/* The command table for a TLI connection. */ +static const struct sconncmds stlicmds = +{ + utli_free, + NULL, /* pflock */ + NULL, /* pfunlock */ + ftli_open, + ftli_close, + ftli_dial, + fsysdep_conn_read, + fsysdep_conn_write, + fsysdep_conn_io, + NULL, /* pfbreak */ + NULL, /* pfset */ + NULL, /* pfcarrier */ + fsysdep_conn_chat, + NULL /* pibaud */ +}; + +/* Get a TLI error string. */ + +static const char * +ztlierror () +{ + if (t_errno == TSYSERR) + return strerror (errno); + if (t_errno < 0 || t_errno >= t_nerr) + return "Unknown TLI error"; + return t_errlist[t_errno]; +} + +/* Initialize a TLI connection. This may be called with qconn->qport + NULL, when opening standard input as a TLI connection. */ + +boolean +fsysdep_tli_init (qconn) + struct sconnection *qconn; +{ + struct ssysdep_conn *q; + + q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn)); + q->o = -1; + q->ord = -1; + q->owr = -1; + q->zdevice = NULL; + q->iflags = -1; + q->iwr_flags = -1; + q->fterminal = FALSE; + q->ftli = TRUE; + q->ibaud = 0; + + qconn->psysdep = (pointer) q; + qconn->qcmds = &stlicmds; + return TRUE; +} + +/* Free a TLI connection. */ + +static void +utli_free (qconn) + struct sconnection *qconn; +{ + xfree (qconn->psysdep); +} + +/* Push all desired modules onto a TLI stream. If the user requests a + STREAMS connection without giving a list of modules, we just push + tirdwr. If the I_PUSH ioctl is not defined on this system, we just + ignore any list of modules. */ + +static boolean +ftli_push (qconn) + struct sconnection *qconn; +{ +#ifdef I_PUSH + + struct ssysdep_conn *qsysdep; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush != NULL) + { + char **pz; + + for (pz = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzpush; + *pz != NULL; + pz++) + { + if (ioctl (qsysdep->o, I_PUSH, *pz) < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, %s): %s", *pz, + strerror (errno)); + return FALSE; + } + } + } + else if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + { + if (ioctl (qsysdep->o, I_PUSH, "tirdwr") < 0) + { + ulog (LOG_ERROR, "ioctl (I_PUSH, tirdwr): %s", + strerror (errno)); + return FALSE; + } + } + + /* If we have just put the connection into stream mode, we must turn + off the TLI flag to avoid using TLI calls on it. */ + if (qconn->qport->uuconf_u.uuconf_stli.uuconf_fstream) + qsysdep->ftli = FALSE; + +#endif /* defined (I_PUSH) */ + + return TRUE; +} + +/* Open a TLI connection. If the fwait argument is TRUE, we are + running as a server. Otherwise we are just trying to reach another + system. */ + +static boolean +ftli_open (qconn, ibaud, fwait) + struct sconnection *qconn; + long ibaud; + boolean fwait; +{ + struct ssysdep_conn *qsysdep; + const char *zdevice; + char *zfreedev; + const char *zservaddr; + char *zfreeaddr; + uid_t ieuid; + boolean fswap; + struct t_bind *qtbind; + struct t_call *qtcall; + + /* Unlike most other device types, we don't bother to call + ulog_device here, because fconn_open calls it with the name of + the port anyhow. */ + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + zdevice = qconn->qport->uuconf_u.uuconf_stli.uuconf_zdevice; + if (zdevice == NULL) + zdevice = qconn->qport->uuconf_zname; + + zfreedev = NULL; + if (*zdevice != '/') + { + zfreedev = zbufalc (sizeof "/dev/" + strlen (zdevice)); + sprintf (zfreedev, "/dev/%s", zdevice); + zdevice = zfreedev; + } + + /* If we are acting as a server, swap to our real user ID before + calling t_open. This will permit the server to use privileged + TCP ports when invoked by root. We only swap if our effective + user ID is not root, so that the program can also be made suid + root in order to get privileged ports when invoked by anybody. */ + fswap = fwait && geteuid () != 0; + if (fswap) + { + if (! fsuser_perms (&ieuid)) + { + ubuffree (zfreedev); + return FALSE; + } + } + + qsysdep->o = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (qsysdep->o < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "t_open (%s): %s", zdevice, ztlierror ()); + ubuffree (zfreedev); + return FALSE; + } + + if (fcntl (qsysdep->o, F_SETFD, + fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + qsysdep->iflags = fcntl (qsysdep->o, F_GETFL, 0); + if (qsysdep->iflags < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_ERROR, "fcntl: %s", strerror (errno)); + ubuffree (zfreedev); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + + /* We save our process ID in the qconn structure. This is checked + in ftli_close. */ + qsysdep->ipid = getpid (); + + /* If we aren't waiting for a connection, we can bind to any local + address, and then we're finished. */ + if (! fwait) + { + /* fswap is known to be FALSE here. */ + ubuffree (zfreedev); + if (t_bind (qsysdep->o, (struct t_bind *) NULL, + (struct t_bind *) NULL) < 0) + { + ulog (LOG_ERROR, "t_bind: %s", ztlierror ()); + (void) t_close (qsysdep->o); + qsysdep->o = -1; + return FALSE; + } + return TRUE; + } + + /* Run as a server and wait for a new connection. The code in + uucico.c has already detached us from our controlling terminal. + From this point on if the server gets an error we exit; we only + return if we have received a connection. It would be more robust + to respawn the server if it fails; someday. */ + qtbind = (struct t_bind *) t_alloc (qsysdep->o, T_BIND, T_ALL); + if (qtbind == NULL) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "t_alloc (T_BIND): %s", ztlierror ()); + } + + zservaddr = qconn->qport->uuconf_u.uuconf_stli.uuconf_zservaddr; + if (zservaddr == NULL) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "Can't run as TLI server; no server address"); + } + + zfreeaddr = zbufcpy (zservaddr); + qtbind->addr.len = cescape (zfreeaddr); + if (qtbind->addr.len > qtbind->addr.maxlen) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "%s: TLI server address too long (max %d)", + zservaddr, qtbind->addr.maxlen); + } + memcpy (qtbind->addr.buf, zfreeaddr, qtbind->addr.len); + ubuffree (zfreeaddr); + + qtbind->qlen = 5; + + if (t_bind (qsysdep->o, qtbind, (struct t_bind *) NULL) < 0) + { + if (fswap) + (void) fsuucp_perms ((long) ieuid); + ulog (LOG_FATAL, "t_bind (%s): %s", zservaddr, ztlierror ()); + } + + if (fswap) + { + if (! fsuucp_perms ((long) ieuid)) + ulog (LOG_FATAL, "Could not swap back to UUCP user permissions"); + } + + (void) t_free ((pointer) qtbind, T_BIND); + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ALL); + if (qtcall == NULL) + ulog (LOG_FATAL, "t_alloc (T_CALL): %s", ztlierror ()); + + while (! FGOT_SIGNAL ()) + { + int onew; + pid_t ipid; + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Waiting for connections"); + + if (t_listen (qsysdep->o, qtcall) < 0) + ulog (LOG_FATAL, "t_listen: %s", ztlierror ()); + + onew = t_open (zdevice, O_RDWR, (struct t_info *) NULL); + if (onew < 0) + ulog (LOG_FATAL, "t_open (%s): %s", zdevice, ztlierror ()); + + if (fcntl (onew, F_SETFD, + fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0) + ulog (LOG_FATAL, "fcntl (FD_CLOEXEC): %s", strerror (errno)); + + if (t_bind (onew, (struct t_bind *) NULL, (struct t_bind *) NULL) < 0) + ulog (LOG_FATAL, "t_bind: %s", ztlierror ()); + + if (t_accept (qsysdep->o, onew, qtcall) < 0) + { + /* We may have received a disconnect. */ + if (t_errno != TLOOK) + ulog (LOG_FATAL, "t_accept: %s", ztlierror ()); + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_FATAL, "t_rcvdis: %s", ztlierror ()); + (void) t_close (onew); + continue; + } + + DEBUG_MESSAGE0 (DEBUG_PORT, + "ftli_open: Got connection; forking"); + + ipid = ixsfork (); + if (ipid < 0) + ulog (LOG_FATAL, "fork: %s", strerror (errno)); + if (ipid == 0) + { + ulog_close (); + + (void) t_close (qsysdep->o); + qsysdep->o = onew; + + /* Push any desired modules. */ + if (! ftli_push (qconn)) + _exit (EXIT_FAILURE); + + /* Now we fork and let our parent die, so that we become + a child of init. This lets the main server code wait + for its child and then continue without accumulating + zombie children. */ + ipid = ixsfork (); + if (ipid < 0) + { + ulog (LOG_ERROR, "fork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + } + + if (ipid != 0) + _exit (EXIT_SUCCESS); + + ulog_id (getpid ()); + + return TRUE; + } + + (void) t_close (onew); + + /* Now wait for the child. */ + (void) ixswait ((unsigned long) ipid, (const char *) NULL); + } + + /* We got a signal. */ + usysdep_exit (FALSE); + + /* Avoid compiler warnings. */ + return FALSE; +} + +/* Close the port. */ + +/*ARGSUSED*/ +static boolean +ftli_close (qconn, puuconf, qdialer, fsuccess) + struct sconnection *qconn; + pointer puuconf; + struct uuconf_dialer *qdialer; + boolean fsuccess; +{ + struct ssysdep_conn *qsysdep; + boolean fret; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + fret = TRUE; + if (qsysdep->o >= 0) + { + if (qsysdep->ftli) + { + if (t_close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "t_close: %s", ztlierror ()); + fret = FALSE; + } + } + else + { + if (close (qsysdep->o) < 0) + { + ulog (LOG_ERROR, "close: %s", strerror (errno)); + fret = FALSE; + } + } + + qsysdep->o = -1; + } + + /* If the current pid is not the one we used to open the port, then + we must have forked up above and we are now the child. In this + case, we are being called from within the fendless loop in + uucico.c. We return FALSE to force the loop to end and the child + to exit. This should be handled in a cleaner fashion. */ + if (qsysdep->ipid != getpid ()) + fret = FALSE; + + return fret; +} + +/* Dial out on a TLI port, so to speak: connect to a remote computer. */ + +/*ARGSUSED*/ +static boolean +ftli_dial (qconn, puuconf, qsys, zphone, qdialer, ptdialerfound) + struct sconnection *qconn; + pointer puuconf; + const struct uuconf_system *qsys; + const char *zphone; + struct uuconf_dialer *qdialer; + enum tdialerfound *ptdialerfound; +{ + struct ssysdep_conn *qsysdep; + char **pzdialer; + const char *zaddr; + struct t_call *qtcall; + char *zescape; + + qsysdep = (struct ssysdep_conn *) qconn->psysdep; + + *ptdialerfound = DIALERFOUND_FALSE; + + pzdialer = qconn->qport->uuconf_u.uuconf_stli.uuconf_pzdialer; + if (*pzdialer == NULL) + pzdialer = NULL; + + /* If the first dialer is "TLI" or "TLIS", we use the first token + (pzdialer[1]) as the address to connect to. */ + zaddr = zphone; + if (pzdialer != NULL + && (strcmp (pzdialer[0], "TLI") == 0 + || strcmp (pzdialer[0], "TLIS") == 0)) + { + if (pzdialer[1] == NULL) + ++pzdialer; + else + { + if (strcmp (pzdialer[1], "\\D") != 0 + && strcmp (pzdialer[1], "\\T") != 0) + zaddr = pzdialer[1]; + pzdialer += 2; + } + } + + if (zaddr == NULL) + { + ulog (LOG_ERROR, "No address for TLI connection"); + return FALSE; + } + + qtcall = (struct t_call *) t_alloc (qsysdep->o, T_CALL, T_ADDR); + if (qtcall == NULL) + { + ulog (LOG_ERROR, "t_alloc (T_CALL): %s", ztlierror ()); + return FALSE; + } + + zescape = zbufcpy (zaddr); + qtcall->addr.len = cescape (zescape); + if (qtcall->addr.len > qtcall->addr.maxlen) + { + ulog (LOG_ERROR, "%s: TLI address too long (max %d)", zaddr, + qtcall->addr.maxlen); + ubuffree (zescape); + return FALSE; + } + memcpy (qtcall->addr.buf, zescape, qtcall->addr.len); + ubuffree (zescape); + + if (t_connect (qsysdep->o, qtcall, (struct t_call *) NULL) < 0) + { + if (t_errno != TLOOK) + ulog (LOG_ERROR, "t_connect: %s", ztlierror ()); + else + { + if (t_rcvdis (qsysdep->o, (struct t_discon *) NULL) < 0) + ulog (LOG_ERROR, "t_rcvdis: %s", ztlierror ()); + else + ulog (LOG_ERROR, "Connection refused"); + } + return FALSE; + } + + /* We've connected to the remote. Push any desired modules. */ + if (! ftli_push (qconn)) + return FALSE; + + /* Handle the rest of the dialer sequence. */ + if (pzdialer != NULL && *pzdialer != NULL) + { + if (! fconn_dial_sequence (qconn, puuconf, pzdialer, qsys, zphone, + qdialer, ptdialerfound)) + return FALSE; + } + + return TRUE; +} + +#endif /* HAVE_TLI */ diff --git a/gnu/libexec/uucp/libunix/uid.c b/gnu/libexec/uucp/libunix/uid.c new file mode 100644 index 0000000000000..66b8fc70001fe --- /dev/null +++ b/gnu/libexec/uucp/libunix/uid.c @@ -0,0 +1,116 @@ +/* uid.c + Switch back and forth between UUCP and user permissions. + + Copyright (C) 1992, 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This 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 of the + License, or (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucp.h" + +#include "uudefs.h" +#include "sysdep.h" + +#include <errno.h> + +/* NetBSD apparently does not support setuid as required by POSIX when + using saved setuid, so use seteuid instead. */ + +#if HAVE_SETEUID +#define setuid seteuid +#endif + +/* Switch to permissions of the invoking user. */ + +boolean +fsuser_perms (pieuid) + uid_t *pieuid; +{ + uid_t ieuid, iuid; + + ieuid = geteuid (); + iuid = getuid (); + if (pieuid != NULL) + *pieuid = ieuid; + +#if HAVE_SETREUID + /* Swap the effective user id and the real user id. We can then + swap them back again when we want to return to the uucp user's + permissions. */ + if (setreuid (ieuid, iuid) < 0) + { + ulog (LOG_ERROR, "setreuid (%ld, %ld): %s", + (long) ieuid, (long) iuid, strerror (errno)); + return FALSE; + } +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set the effective user id to the real user id. Since the + effective user id is saved (it's the saved setuid) we will able + to set back to it later. If the real user id is root we will not + be able to switch back and forth, so don't even try. */ + if (iuid != 0) + { + if (setuid (iuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) iuid, strerror (errno)); + return FALSE; + } + } +#else /* ! HAVE_SAVED_SETUID */ + /* There's no way to switch between real permissions and effective + permissions. Just try to open the file with the uucp + permissions. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} + +/* Restore the uucp permissions. */ + +/*ARGSUSED*/ +boolean +fsuucp_perms (ieuid) + long ieuid; +{ +#if HAVE_SETREUID + /* Swap effective and real user id's back to what they were. */ + if (! fsuser_perms ((uid_t *) NULL)) + return FALSE; +#else /* ! HAVE_SETREUID */ +#if HAVE_SAVED_SETUID + /* Set ourselves back to our original effective user id. */ + if (setuid ((uid_t) ieuid) < 0) + { + ulog (LOG_ERROR, "setuid (%ld): %s", (long) ieuid, strerror (errno)); + /* Is this error message helpful or confusing? */ + if (errno == EPERM) + ulog (LOG_ERROR, + "Probably HAVE_SAVED_SETUID in policy.h should be set to 0"); + return FALSE; + } +#else /* ! HAVE_SAVED_SETUID */ + /* We didn't switch, no need to switch back. */ +#endif /* ! HAVE_SAVED_SETUID */ +#endif /* ! HAVE_SETREUID */ + + return TRUE; +} diff --git a/gnu/libexec/uucp/libuuconf/strip.c b/gnu/libexec/uucp/libuuconf/strip.c new file mode 100644 index 0000000000000..fc314a77e939f --- /dev/null +++ b/gnu/libexec/uucp/libuuconf/strip.c @@ -0,0 +1,50 @@ +/* maxuxq.c + Get information about what things should be stripped. + + Copyright (C) 1995 Ian Lance Taylor + + This file is part of the Taylor UUCP uuconf library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + The author of the program may be contacted at ian@airs.com or + c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. + */ + +#include "uucnfi.h" + +#if USE_RCS_ID +const char _uuconf_strip_rcsid[] = "$Id: strip.c,v 1.2 1995/06/28 15:43:14 ian Rel $"; +#endif + +/* Get information about what types of global information should be + stripped. There are currently only two, which we return as a + couple of bits. We store them as two separate variables, so we + don't need to have a special function to set the values correctly. */ + +int +uuconf_strip (pglobal, pistrip) + pointer pglobal; + int *pistrip; +{ + struct sglobal *qglobal = (struct sglobal *) pglobal; + + *pistrip = 0; + if (qglobal->qprocess->fstrip_login) + *pistrip |= UUCONF_STRIP_LOGIN; + if (qglobal->qprocess->fstrip_proto) + *pistrip |= UUCONF_STRIP_PROTO; + return UUCONF_SUCCESS; +} diff --git a/gnu/libexec/uucp/uucico/proty.c b/gnu/libexec/uucp/uucico/proty.c new file mode 100644 index 0000000000000..f15671e2b4d34 --- /dev/null +++ b/gnu/libexec/uucp/uucico/proty.c @@ -0,0 +1,660 @@ +/* proty.c + The 'y' protocol. + + Copyright (C) 1994, 1995 Jorge Cwik and Ian Lance Taylor + + This file is part of the Taylor UUCP package. + + This 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 of the + License, or (at your option) any later version. + + This program 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. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "uucp.h" + +#if USE_RCS_ID +const char proty_id[] = "$Id: proty.c,v 1.4 1995/06/21 19:15:40 ian Rel $"; +#endif + +#include "uudefs.h" +#include "uuconf.h" +#include "conn.h" +#include "trans.h" +#include "system.h" +#include "prot.h" + +/* The 'y' protocol, and this implementation, was written and designed + by Jorge Cwik <jorge@satlink.net>. Some of the routines, and the + coding style in general, were taken verbatim or adapted from other + Taylor UUCP modules. Mark Delany made the initial testings and + helped in portability issues. + + This protocol does not perform any kind of error correction or flow + control. It does do error checking. It does not require an end to + end reliable link. It is recommended for error-free (also called + semi-reliable) connections as provided by error correcting modems. + It needs an eight bit clean channel and some kind of flow control + at the lower layers, typically RTS/CTS hardware flow control. + + The flow of the file transmission is completely unidirectional. + There are no ACKs or NAKs outside file boundaries. This makes it + very suitable for half duplex modulations (like PEP) and + connections with very long delays, like multihop satellite links. */ + +/* This protocol uses 16 bit little-endian ints in the packet header. */ +#define FROMLITTLE(p) (((p)[0] & 0xff) + (((p)[1] & 0xff) << 8)) +#define TOLITTLE(p, i) ((p)[0] = (i) & 0xff, (p)[1] = ((i) >> 8) & 0xff) + +/* The buffer and packet size we use. */ +#define CYBUFSIZE (1024) +#define IYPACKSIZE (1024) + +/* The offset in the buffer to the data. */ +#define CYFRAMELEN (6) + +/* Offsets in a packet header. */ +#define YFRAME_SEQ_OFF (0) +#define YFRAME_LEN_OFF (2) +#define YFRAME_CTL_OFF (2) +#define YFRAME_CHK_OFF (4) + +/* Offsets in a packet header viewed as an array of shorts. */ +#define YFRAME_SEQ (0) +#define YFRAME_LEN (1) +#define YFRAME_CTL (1) +#define YFRAME_CHK (2) + +/* The default timeout. */ +#define CYTIMEOUT (60) + +/* Control packet types. */ +#define YPKT_ACK (0xFFFE) +#define YPKT_ERR (0xFFFD) +#define YPKT_BAD (0xFFFC) + +/* The protocol version number. */ +#define Y_VERSION (1) + +/* When the protocol starts up, it transmit the following information: + 1 byte version + 1 byte packet size + 2 byte flags (none currently defined) + Future revision may expand the structure as long as these members + keep their current offset. */ +#define Y_INIT_HDR_LEN (4) +#define Y_INIT_HDR_VERSION_OFF (0) +#define Y_INIT_HDR_PKTSIZE_OFF (1) +#define Y_INIT_HDR_FLAGS_OFF (2) + +/* The initialization length of the lowest accepted version. */ +#define MIN_Y_SYNC (4) + +/* Not strictly needed, but I would not want to accept a 32k sync pkt. */ +#define MAX_Y_SYNC IYPACKSIZE + +/* Local and remote packet sizes (we actually use the same value for + both). */ +static size_t iYlocal_packsize = IYPACKSIZE; +static size_t iYremote_packsize = IYPACKSIZE; + +/* Local and remote packet sequence numbers. */ +static unsigned short iYlocal_pktnum; +static unsigned short iYremote_pktnum; + +/* The timeout. */ +static int cYtimeout = CYTIMEOUT; + +/* Transmitter buffer. */ +static char *zYbuf; + +/* Protocol parameters. */ + +struct uuconf_cmdtab asYproto_params[] = +{ + { "timeout", UUCONF_CMDTABTYPE_INT, (pointer) &cYtimeout, NULL }, + { "packet-size", UUCONF_CMDTABTYPE_INT, (pointer) &iYlocal_packsize, NULL }, + { NULL, 0, NULL, NULL } +}; + +/* Local functions. */ + +static boolean fywait_for_packet P((struct sdaemon *qdaemon, + boolean *pfexit)); +static unsigned short iychecksum P((const char *z, size_t c)); +static unsigned short iychecksum2 P((const char *zfirst, size_t cfirst, + const char *zsecond, size_t csecond)); +static boolean fywait_for_header P((struct sdaemon *qdaemon, + unsigned short header[3], int timeout)); +static boolean fysend_pkt P((struct sdaemon *qdaemon, + const void *zdata, size_t cdata)); +static boolean fysend_control P((struct sdaemon *qdaemon, + int itype)); +static boolean fyread_data P((struct sdaemon *qdaemon, size_t clen, + int timeout)); + +/* Exchange sync packets at protocol startup. */ + +static boolean +fyxchg_syncs (qdaemon) + struct sdaemon *qdaemon; +{ + char inithdr[Y_INIT_HDR_LEN]; + unsigned short header[3]; + unsigned short ichk; + size_t clen, cfirst; + int rpktsize; + + /* Send our configuration. We could use only one array (for local + and remote). But this is safer in case the code changes and + depend on separate ones. */ + + inithdr[Y_INIT_HDR_VERSION_OFF] = Y_VERSION; + inithdr[Y_INIT_HDR_PKTSIZE_OFF] = iYlocal_packsize >> 8; + TOLITTLE (inithdr + Y_INIT_HDR_FLAGS_OFF, 0); + + if (! fysend_pkt (qdaemon, inithdr, Y_INIT_HDR_LEN)) + return FALSE; + + if (! fywait_for_header (qdaemon, header, cYtimeout)) + return FALSE; + + DEBUG_MESSAGE0 (DEBUG_UUCP_PROTO, "fyxchg_syncs: Got sync header"); + clen = header[YFRAME_LEN]; + + if (clen < MIN_Y_SYNC || clen > MAX_Y_SYNC) + { + ulog (LOG_ERROR, "Bad 'y' protocol sync packet length"); + return FALSE; + } + + /* It may be better to integrate this code with fywait_for_packet. */ + if (! fyread_data (qdaemon, clen, cYtimeout)) + return FALSE; + + cfirst = CRECBUFLEN - iPrecstart; + ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst); + + rpktsize = BUCHAR (abPrecbuf[(iPrecstart + 1) % CRECBUFLEN]); + + /* Future versions of the protocol may need to check and react + according to the version number. */ + + if (rpktsize == 0 || header[YFRAME_CHK] != ichk) + { + ulog (LOG_ERROR, "Bad 'y' protocol sync packet"); + return FALSE; + } + + iYremote_packsize = rpktsize << 8; + + /* Some may want to do this different and in effect the protocol + support this. But I like the idea that the packet size would be + the same in both directions. This allows the caller to select + both packet sizes without changing the configuration at the + server. */ + if (iYremote_packsize > iYlocal_packsize) + iYremote_packsize = iYlocal_packsize; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + return TRUE; +} + +/* Start the protocol. */ + +boolean +fystart (qdaemon, pzlog) + struct sdaemon *qdaemon; + char **pzlog; +{ + *pzlog = NULL; + + /* This should force, or at least enable if available, RTS/CTS + hardware flow control !! */ + + /* The 'y' protocol requires an eight bit clean link */ + if (! fconn_set (qdaemon->qconn, PARITYSETTING_NONE, + STRIPSETTING_EIGHTBITS, XONXOFF_OFF)) + return FALSE; + + iYlocal_pktnum = iYremote_pktnum = 0; + + /* Only multiple of 256 sizes are allowed */ + iYlocal_packsize &= ~0xff; + if (iYlocal_packsize < 256 || iYlocal_packsize > (16*1024)) + iYlocal_packsize = IYPACKSIZE; + + /* Exhange SYNC packets */ + if (! fyxchg_syncs (qdaemon)) + { + /* Restore defaults */ + cYtimeout = CYTIMEOUT; + iYlocal_packsize = IYPACKSIZE; + return FALSE; + } + + zYbuf = (char *) xmalloc (CYBUFSIZE + CYFRAMELEN); + return TRUE; +} + +/* Shutdown the protocol. */ + +boolean +fyshutdown (qdaemon) + struct sdaemon *qdaemon; +{ + xfree ((pointer) zYbuf); + zYbuf = NULL; + cYtimeout = CYTIMEOUT; + iYlocal_packsize = IYPACKSIZE; + return TRUE; +} + +/* Send a command string. We send packets containing the string until + the entire string has been sent, including the zero terminator. */ + +/*ARGSUSED*/ +boolean +fysendcmd (qdaemon, z, ilocal, iremote) + struct sdaemon *qdaemon; + const char *z; + int ilocal; + int iremote; +{ + size_t clen; + + DEBUG_MESSAGE1 (DEBUG_UUCP_PROTO, "fysendcmd: Sending command \"%s\"", z); + + clen = strlen (z) + 1; + + while (clen > 0) + { + size_t csize; + + csize = clen; + if (csize > iYremote_packsize) + csize = iYremote_packsize; + + if (! fysend_pkt (qdaemon, z, csize)) + return FALSE; + + z += csize; + clen -= csize; + } + + return TRUE; +} + +/* Get space to be filled with data. We always use zYbuf, which was + allocated from the heap. */ + +char * +zygetspace (qdaemon, pclen) + struct sdaemon *qdaemon; + size_t *pclen; +{ + *pclen = iYremote_packsize; + return zYbuf + CYFRAMELEN; +} + +/* Send out a data packet. */ + +boolean +fysenddata (qdaemon, zdata, cdata, ilocal, iremote, ipos) + struct sdaemon *qdaemon; + char *zdata; + size_t cdata; + int ilocal; + int iremote; + long ipos; +{ +#if DEBUG > 0 + if (cdata > iYremote_packsize) + ulog (LOG_FATAL, "fysend_packet: Packet size too large"); +#endif + + TOLITTLE (zYbuf + YFRAME_SEQ_OFF, iYlocal_pktnum); + ++iYlocal_pktnum; + TOLITTLE (zYbuf + YFRAME_LEN_OFF, cdata); + TOLITTLE (zYbuf + YFRAME_CHK_OFF, iychecksum (zdata, cdata)); + + /* We pass FALSE to fsend_data since we don't expect the other side + to be sending us anything just now. */ + return fsend_data (qdaemon->qconn, zYbuf, cdata + CYFRAMELEN, FALSE); +} + +/* Wait for data to come in and process it until we've finished a + command or a file. */ + +boolean +fywait (qdaemon) + struct sdaemon *qdaemon; +{ + boolean fexit = FALSE; + + while (! fexit) + { + if (! fywait_for_packet (qdaemon, &fexit)) + return FALSE; + } + return TRUE; +} + +/* File level routines + We could handle this inside the other public routines, + but this is cleaner and better for future expansions */ + +boolean +fyfile (qdaemon, qtrans, fstart, fsend, cbytes, pfhandled) + struct sdaemon *qdaemon; + struct stransfer *qtrans; + boolean fstart; + boolean fsend; + long cbytes; + boolean *pfhandled; +{ + unsigned short header[3]; + + *pfhandled = FALSE; + + if (! fstart) + { + if (fsend) + { + /* It is critical that the timeout here would be long + enough. We have just sent a full file without any kind + of flow control at the protocol level. The traffic may + be buffered in many places of the link, and the remote + may take a while until cathing up. */ + if (! fywait_for_header (qdaemon, header, cYtimeout * 2)) + return FALSE; + + if (header[YFRAME_CTL] != (unsigned short) YPKT_ACK) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fyfile: Error from remote: 0x%04X", header[1]); + ulog (LOG_ERROR, "Received 'y' protocol error from remote"); + return FALSE; + } + } + else + { + /* This is technically not requireed. But I've put this in + the protocol to allow easier expansions. */ + return fysend_control (qdaemon, YPKT_ACK); + } + } + + return TRUE; +} + +/* Send a control packet, not used during the normal file + transmission. */ + +static boolean +fysend_control (qdaemon, itype) + struct sdaemon *qdaemon; + int itype; +{ + char header[CYFRAMELEN]; + + TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum); + iYlocal_pktnum++; + TOLITTLE (header + YFRAME_CTL_OFF, itype); + TOLITTLE (header + YFRAME_CHK_OFF, 0); + + return fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE); +} + +/* Private function to send a packet. This one doesn't need the data + to be in the buffer provided by zygetspace. I've found it worth + for avoiding memory copies. Somebody may want to do it otherwise */ + +static boolean +fysend_pkt (qdaemon, zdata, cdata) + struct sdaemon *qdaemon; + const void *zdata; + size_t cdata; +{ + char header[CYFRAMELEN]; + + TOLITTLE (header + YFRAME_SEQ_OFF, iYlocal_pktnum); + iYlocal_pktnum++; + TOLITTLE (header + YFRAME_LEN_OFF, cdata); + TOLITTLE (header + YFRAME_CHK_OFF, iychecksum (zdata, cdata)); + + if (! fsend_data (qdaemon->qconn, header, CYFRAMELEN, FALSE)) + return FALSE; + return fsend_data (qdaemon->qconn, zdata, cdata, FALSE); +} + +/* Wait until enough data arrived from the comm line. This protocol + doesn't need to perform any kind of action while waiting. */ + +static boolean +fyread_data (qdaemon, clen, timeout) + struct sdaemon *qdaemon; + size_t clen; + int timeout; +{ + int cinbuf; + size_t crec; + + cinbuf = iPrecend - iPrecstart; + if (cinbuf < 0) + cinbuf += CRECBUFLEN; + + if (cinbuf < clen) + { + if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec, + timeout, TRUE)) + return FALSE; + cinbuf += crec; + if (cinbuf < clen) + { + if (! freceive_data (qdaemon->qconn, clen - cinbuf, &crec, + timeout, TRUE)) + return FALSE; + } + cinbuf += crec; + if (cinbuf < clen) + { + ulog (LOG_ERROR, "Timed out waiting for data"); + return FALSE; + } + } + + return TRUE; +} + +/* Receive a remote packet header, check for correct sequence number. */ + +static boolean +fywait_for_header (qdaemon, header, timeout) + struct sdaemon *qdaemon; + unsigned short header[3]; + int timeout; +{ + if (! fyread_data (qdaemon, CYFRAMELEN, timeout)) + return FALSE; + + /* Somebody may want to optimize this in a portable way. I'm not + sure it's worth, but the output by gcc for the portable construct + is so bad (even with optimization), that I couldn't resist. */ + + if (iPrecstart <= (CRECBUFLEN - CYFRAMELEN)) + { + header[0] = FROMLITTLE (abPrecbuf + iPrecstart); + header[1] = FROMLITTLE (abPrecbuf + iPrecstart + 2); + header[2] = FROMLITTLE (abPrecbuf + iPrecstart + 4); + } + else + { + register int i, j; + + for (i = j = 0; j < CYFRAMELEN; i++, j += 2) + { + header[i] = + (((abPrecbuf[(iPrecstart + j + 1) % CRECBUFLEN] & 0xff) << 8) + + (abPrecbuf[(iPrecstart + j) % CRECBUFLEN] & 0xff)); + } + } + + iPrecstart = (iPrecstart + CYFRAMELEN) % CRECBUFLEN; + + DEBUG_MESSAGE3 (DEBUG_UUCP_PROTO, + "fywait_for_header: Got header: 0x%04X, 0x%04X, 0x%04X", + header[0], header[1], header[2]); + + if (header[YFRAME_SEQ] != iYremote_pktnum++) + { + ulog (LOG_ERROR, "Incorrect 'y' packet sequence"); + fysend_control (qdaemon, YPKT_BAD); + return FALSE; + } + + return TRUE; +} + +/* Receive a remote data packet */ + +static boolean +fywait_for_packet (qdaemon, pfexit) + struct sdaemon *qdaemon; + boolean *pfexit; +{ + unsigned short header[3], ichk; + size_t clen, cfirst; + + if (! fywait_for_header (qdaemon, header, cYtimeout)) + return FALSE; + + clen = header[YFRAME_LEN]; + if (clen == 0 && pfexit != NULL) + { + /* I Suppose the pointers could be NULL ??? */ + return fgot_data (qdaemon, abPrecbuf, 0, abPrecbuf, 0, + -1, -1, (long) -1, TRUE, pfexit); + } + + if (clen & 0x8000) + { + DEBUG_MESSAGE1 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fywait_for_packet: Error from remote: 0x%04X", + header[YFRAME_CTL]); + ulog (LOG_ERROR, "Remote error packet"); + return FALSE; + } + + /* This is really not neccessary. But if this check is removed, + take in mind that the packet may be up to 32k long. */ + if (clen > iYlocal_packsize) + { + ulog (LOG_ERROR, "Packet too large"); + return FALSE; + } + + if (! fyread_data (qdaemon, clen, cYtimeout)) + return FALSE; + + cfirst = CRECBUFLEN - iPrecstart; + if (cfirst > clen) + cfirst = clen; + + if (cfirst == clen) + ichk = iychecksum (abPrecbuf + iPrecstart, clen); + else + ichk = iychecksum2 (abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst); + if (header[YFRAME_CHK] != ichk) + { + DEBUG_MESSAGE2 (DEBUG_PROTO | DEBUG_ABNORMAL, + "fywait_for_packet: Bad checksum 0x%x != 0x%x", + header[YFRAME_CHK], ichk); + fysend_control (qdaemon, YPKT_ERR); + ulog (LOG_ERROR, "Checksum error"); + return FALSE; + } + + if (pfexit != NULL + && ! fgot_data (qdaemon, abPrecbuf + iPrecstart, cfirst, + abPrecbuf, clen - cfirst, + -1, -1, (long) -1, TRUE, pfexit)) + return FALSE; + + iPrecstart = (iPrecstart + clen) % CRECBUFLEN; + + return TRUE; +} + +/* Compute 16 bit checksum */ + +#ifdef __GNUC__ +#ifdef __i386__ +#define I386_ASM +#endif +#endif + +#ifdef I386_ASM +#define ROTATE(i) \ + asm ("rolw $1,%0" : "=g" (i) : "g" (i)) +#else +#define ROTATE(i) i += i + ((i & 0x8000) >> 15) +#endif + +static unsigned short +iychecksum (z, c) + register const char *z; + register size_t c; +{ + register unsigned short ichk; + + ichk = 0xffff; + + while (c-- > 0) + { + ROTATE (ichk); + ichk += BUCHAR (*z++); + } + + return ichk; +} + +static unsigned short +iychecksum2 (zfirst, cfirst, zsecond, csecond) + const char *zfirst; + size_t cfirst; + const char *zsecond; + size_t csecond; +{ + register unsigned short ichk; + register const char *z; + register size_t c; + + z = zfirst; + c = cfirst + csecond; + + ichk = 0xffff; + + while (c-- > 0) + { + ROTATE (ichk); + ichk += BUCHAR (*z++); + + /* If the first buffer has been finished, switch to the second. */ + if (--cfirst == 0) + z = zsecond; + } + + return ichk; +} diff --git a/gnu/usr.bin/ld/rtld/rtld.1 b/gnu/usr.bin/ld/rtld/rtld.1 new file mode 100644 index 0000000000000..9179f25793a11 --- /dev/null +++ b/gnu/usr.bin/ld/rtld/rtld.1 @@ -0,0 +1,144 @@ +.\" $NetBSD: rtld.1,v 1.1 1995/06/30 12:23:10 pk Exp $ +.\" +.\" Copyright (c) 1995 Paul Kranenburg +.\" 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 Paul Kranenburg. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +.\" +.Dd June 27, 1995 +.Dt RTLD 1 +.Os NetBSD +.Sh NAME +.Nm ld.so +.Nd run-time link-editor +.Sh DESCRIPTION +.Nm +is a self-contained, position independent program image providing run-time +support for loading and link-editing shared objects into a process' +address space. It uses the data structures +.Po +see +.Xr link 5 +.Pc +contained within dynamically linked programs to determine which shared +libraries are needed and loads them at a convenient virtual address +using the +.Xr mmap 2 +system call. +.Pp +After all shared libraries have been succesfully loaded, +.Nm +proceeds to resolve external references from both the main program and +all objects loaded. A mechanism is provided for initialisation routines +to be called, on a per-object basis, giving a shared object an opportunity +to perfrom any extra set-up, before execution of the program proper begins. +This is useful for C++ libraries that contain static constrictors. +.Pp +.Nm +is itself a shared object that is initially loaded by the startup module +.Em crt0 . +Since +.Xr a.out 5 +formats do not provide easy access to the file header from within a running +process, +.Em crt0 +uses the special symbol +.Va _DYNAMIC +to determine whether a program is in fact dynamically linked or not. Whenever +the linker +.Xr ld 1 +has relocated this symbol to a location other then 0, +.Em crt0 +assumes the services of +.Nm +are needed +.Po +see +.Xr link 5 +for details +.Pc \&. +.Em crt0 +passes control to +.Nm +\&'s entry point before the program's +.Fn main +routine is called. Thus, +.Nm +can complete the link-editing process before the dynamic program calls upon +services of any dynamic library. +.Pp +To quickly locate the required shared objects in the filesystem, +.Nm +may use a +.Dq hints +file, prepared by the +.Xr ldconfig 8 +utility, in which the full path specification of the shared objects can be +looked up by hashing on the 3-tuple +.Ao +library-name, major-version-number, minor-version-number +.Ac \&. +.Pp +.Nm +recognises a number of environment variables that can be used to modify +its behaviour as follows: +.Pp +.Bl -tag -width "LD_TRACE_LOADED_OBJECTS" +.It Ev LD_LIBRARY_PATH +A colon separated list of directories, overriding the default search path +for shared libraries. +.It Ev LD_WARN_NON_PURE_CODE +When set, issue a warning whenever a link-editing operation requires +modification of the text segment of some loaded object. This is usually +indicative of an incorrectly built library. +.It Ev LD_SUPPRESS_WARNINGS +When set, no warning messages of any kind are issued. Normally, a warning +is given if satisfactorily versioned library could not be found. +.It Ev LD_TRACE_LOADED_OBJECTS +When set, causes +.Nm +to exit after loading the shared objects and printing a summary which includes +the absolute pathnames of all objects, to standard output. +.It Ev LD_NO_INTERN_SEARCH +When set, +.Nm +does not process any internal search paths that were recorded in the +executable. +.It Ev LD_NOSTD_PATH +When set, do not include a set of built-in standard directory paths for +searching. This might be useful when running on a system with a completely +non-standard filesystem layout. +.El +.Pp +.Sh FILES +/var/run/ld.so.hints +.Pp +.Sh SEE ALSO +.Xr ld 1 +.Xr ldconfig 8 +.Xr link 5 +.Sh HISTORY +The shared library model employed first appeared in SunOS 4.0 diff --git a/gnu/usr.sbin/ypserv/svc_run.c b/gnu/usr.sbin/ypserv/svc_run.c new file mode 100644 index 0000000000000..6f4a52c0b8a64 --- /dev/null +++ b/gnu/usr.sbin/ypserv/svc_run.c @@ -0,0 +1,85 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";*/ +static char *rcsid = "$Id: svc_run.c,v 1.2 1995/05/30 05:41:35 rgrimes Exp $"; +#endif + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <rpc/rpc.h> +#include <sys/errno.h> + +extern int _rpc_dtablesize __P((void)); + +void +my_svc_run() +{ +#ifdef FD_SETSIZE + fd_set readfds; +#else + int readfds; +#endif /* def FD_SETSIZE */ + extern int errno; + extern int forked; + int pid; + + /* Establish the identity of the parent ypserv process. */ + pid = getpid(); + + for (;;) { +#ifdef FD_SETSIZE + readfds = svc_fdset; +#else + readfds = svc_fds; +#endif /* def FD_SETSIZE */ + switch (select(_rpc_dtablesize(), &readfds, NULL, NULL, + (struct timeval *)0)) { + case -1: + if (errno == EINTR) { + continue; + } + perror("svc_run: - select failed"); + return; + case 0: + continue; + default: + svc_getreqset(&readfds); + if (forked && pid != getpid()) + exit(0); + } + } +} diff --git a/lib/libc/net/res_config.h b/lib/libc/net/res_config.h new file mode 100644 index 0000000000000..a1339d9652a14 --- /dev/null +++ b/lib/libc/net/res_config.h @@ -0,0 +1,7 @@ +#define DEBUG 1 /* enable debugging code (needed for dig) */ +#undef ALLOW_T_UNSPEC /* enable the "unspec" RR type for old athena */ +#define RESOLVSORT /* allow sorting of addresses in gethostbyname */ +#undef RFC1535 /* comply with RFC1535 */ +#undef ALLOW_UPDATES /* destroy your system security */ +#undef USELOOPBACK /* res_init() bind to localhost */ +#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DONT NEED IT */ diff --git a/lib/libtermcap/tospeed.c b/lib/libtermcap/tospeed.c new file mode 100644 index 0000000000000..dd2026ad3ecbc --- /dev/null +++ b/lib/libtermcap/tospeed.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1995 by Andrey A. Chernov, Moscow, Russia. + * 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 ``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 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 <termios.h> +#include "termcap.h" + +static struct stable { + speed_t speed; + short code; +} table[] = { + {B115200,17}, + {B57600, 16}, + {B38400, 15}, + {B19200, 14}, + {B9600, 13}, + {B4800, 12}, + {B2400, 11}, + {B1800, 10}, + {B1200, 9}, + {B600, 8}, + {B300, 7}, + {B200, 6}, + {B150, 5}, + {B134, 4}, + {B110, 3}, + {B75, 2}, + {B50, 1}, + {B0, 0}, + {-1, -1} +}; + +void __set_ospeed(speed_t speed) +{ + struct stable *stable; + + if (speed == B0) { + ospeed = 0; + return; + } + for (stable = table; stable->speed > B0; stable++) { + /* nearest one, rounded down */ + if (stable->speed <= speed) { + ospeed = stable->code; + return; + } + } + ospeed = 1; /* 50, min and not hangup */ +} + diff --git a/lkm/linux/Makefile b/lkm/linux/Makefile new file mode 100644 index 0000000000000..11650c59e8334 --- /dev/null +++ b/lkm/linux/Makefile @@ -0,0 +1,16 @@ +# $Id$ + +.PATH: ${.CURDIR}/../../sys/i386/linux +KMOD= linux_mod +SRCS= linux.c linux_file.c linux_ioctl.c linux_misc.c linux_signal.c \ + linux_generic.c linux_ipc.c linux_socket.c linux_stats.c \ + linux_dummy.c linux_sysent.c imgact_linux.c vnode_if.h +NOMAN= +CFLAGS+= -DLKM -I. -DCOMPAT_LINUX -DSYSVSHM #-DSYSVMSG -DSYSVSEM #-DDEBUG +CLEANFILES+= vnode_if.h vnode_if.c + +afterinstall: + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/linux /usr/bin + +.include <bsd.kmod.mk> diff --git a/lkm/linux/linux b/lkm/linux/linux new file mode 100644 index 0000000000000..e4c36068cfa31 --- /dev/null +++ b/lkm/linux/linux @@ -0,0 +1,3 @@ +#!/bin/sh +# $Id$ +modload -e linux_init /lkm/linux_mod.o diff --git a/lkm/linux/linux.c b/lkm/linux/linux.c new file mode 100644 index 0000000000000..183ad3e492549 --- /dev/null +++ b/lkm/linux/linux.c @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 1994 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux.c,v 1.1 1994/10/14 08:46:12 sos Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/conf.h> +#include <sys/sysent.h> +#include <sys/lkm.h> +#include <sys/errno.h> + +extern const struct execsw linux_execsw; + +MOD_EXEC("linux_emulator", -1, (struct execsw*)&linux_execsw) + +linux_load(struct lkm_table *lkmtp, int cmd) +{ + uprintf("Linux emulator installed\n"); + return 0; +} + +linux_unload(struct lkm_table *lkmtp, int cmd) +{ + uprintf("Linux emulator removed\n"); + return 0; +} + +linux_init(struct lkm_table *lkmtp, int cmd, int ver) +{ + DISPATCH(lkmtp, cmd, ver, linux_load, linux_unload, nosys); +} diff --git a/secure/libexec/Makefile b/secure/libexec/Makefile new file mode 100644 index 0000000000000..9bd4d2e61f2c1 --- /dev/null +++ b/secure/libexec/Makefile @@ -0,0 +1,6 @@ +# From: @(#)Makefile 8.1 (Berkeley) 5/31/93 +# $Id: Makefile,v 1.2 1995/07/25 14:03:35 mark Exp $ + +SUBDIR= telnetd + +.include <bsd.subdir.mk> diff --git a/secure/libexec/Makefile.inc b/secure/libexec/Makefile.inc new file mode 100644 index 0000000000000..6657676abc6f9 --- /dev/null +++ b/secure/libexec/Makefile.inc @@ -0,0 +1,4 @@ +# @(#)Makefile.inc 8.1 (Berkeley) 6/4/93 +# $Id: Makefile,v 1.2 1995/07/25 14:03:35 mark Exp $ + +BINDIR?= /usr/libexec diff --git a/share/doc/handbook/install.sgml b/share/doc/handbook/install.sgml new file mode 100644 index 0000000000000..a22d9a2b6fc77 --- /dev/null +++ b/share/doc/handbook/install.sgml @@ -0,0 +1,652 @@ +<!-- $Id: install.sgml,v 1.8 1995/08/26 03:09:12 jfieber Exp $ --> +<!-- The FreeBSD Documentation Project --> + +<!-- +<!DOCTYPE linuxdoc PUBLIC '-//FreeBSD//DTD linuxdoc//EN'> +--> +<chapt><heading>Installing FreeBSD<label id="install"></heading> + + <sect><heading>MS-DOS user's Questions and Answers</heading> + + <p><bf>Help! I have no space! Do I need to delete + everything first?</bf> + + If your machine is already running MS-DOS and has little + or no free space available for FreeBSD's installation, + all is not lost! You may find the FIPS utility, provided + in the <tt>tools</tt> directory on the FreeBSD CDROM or + on the various FreeBSD ftp sites, to be quite useful. + + FIPS allows you to split an existing MS-DOS partition + into two pieces, preserving the original partition and + allowing you to install onto the second free piece. You + first defragment your MS-DOS partition, using the DOS + 6.xx DEFRAG utility or the Norton Disk tools, then run + FIPS. It will prompt you for the rest of the information + it needs. Afterwards, you can reboot and install FreeBSD + on the new free slice. See the <em>Distributions</em> + menu for an estimation of how much free space you'll need + for the kind of installation you want. + + + <bf>Can I use compressed MS-DOS filesystems from + FreeBSD?</bf> + + No. If you are using a utility such as Stacker(tm) or + DoubleSpace(tm), FreeBSD will only be able to use + whatever portion of the filesystem you leave + uncompressed. The rest of the filesystem will show up as + one large file (the stacked/dblspaced file!). <bf>Do not + remove that file!</bf> You will probably regret it + greatly! + + It is probably better to create another uncompressed + MS-DOS primary partition and use this for communications + between MS-DOS and FreeBSD. + + + <bf>Can I mount my MS-DOS extended partitions?</bf> + + This feature isn't in FreeBSD 2.0.5 but should be in 2.1. + We've laid all the groundwork for making this happen, now + we just need to do the last 1 percent of the work involved. + + + <bf>Can I run MS-DOS binaries under FreeBSD?</bf> + + Not yet! We'd like to add support for this someday, but + are still lacking anyone to actually do the work. + Ongoing work with Linux's PCEMU utility may bring this + much closer to being a reality sometime soon. Send mail + to hackers@freebsd.org if you're interested in joining + this effort! + + + + <sect><heading>Supported Configurations<label id="install:hw"></heading> + + <p>FreeBSD currently runs on a wide variety of ISA, VLB, + EISA and PCI bus based PC's, ranging from 386sx to + Pentium class machines (though the 386sx is not + recommended). Support for generic IDE or ESDI drive + configurations, various SCSI controller, network and + serial cards is also provided. + + A minimum of four megabytes of RAM is required to run FreeBSD. + To run the X-window system, eight megabytes of RAM is the + recommended minimum. + + Following is a list of all disk controllers and ethernet + cards currently known to work with FreeBSD. Other + configurations may very well work, and we have simply not + received any indication of this. + + <sect1><heading>Disk Controllers</heading> + + <p> + <itemize> + <item>WD1003 (any generic MFM/RLL) + <item>WD1007 (any generic IDE/ESDI) + <item>WD7000 + <item>IDE + <item>ATA + + <item>Adaptec 152x series ISA SCSI controllers + <item>Adaptec 154x series ISA SCSI controllers + <item>Adaptec 174x series EISA SCSI controller in + standard and enhanced mode. + <item>Adaptec 274X/284X/2940 <!-- 3940 (in 2.1) --> + (Narrow/Wide/Twin) + series EISA/VLB/PCI SCSI controllers + <item>Adaptec AIC-6260 and AIC-6360 based boards, + which includes the AHA-152x and SoundBlaster SCSI + cards. + + <bf>Note:</bf> You cannot boot from the + SoundBlaster cards as they have no on-board BIOS, + which is necessary for mapping the boot device into + the system BIOS I/O vectors. They are perfectly + usable for external tapes, CDROMs, etc, however. + The same goes for any other AIC-6x60 based card + without a boot ROM. Some systems DO have a boot + ROM, which is generally indicated by some sort of + message when the system is first powered up or + reset. Check your system/board documentation for + more details. + + <item>Buslogic 545S & 545c + <bf>Note:</bf> that Buslogic was formerly known as "Bustec". + <item>Buslogic 445S/445c VLB SCSI controller + <item>Buslogic 742A, 747S, 747c EISA SCSI controller. + <item>Buslogic 946c PCI SCSI controller + <item>Buslogic 956c PCI SCSI controller + + <item>NCR 53C810 and 53C825 PCI SCSI controller. + <item>NCR5380/NCR53400 ("ProAudio Spectrum") SCSI controller. + + <item>DTC 3290 EISA SCSI controller in 1542 emulation mode. + + <item>UltraStor 14F, 24F and 34F SCSI controllers. + + <item>Seagate ST01/02 SCSI controllers. + + <item>Future Domain 8xx/950 series SCSI controllers. + </itemize> + + With all supported SCSI controllers, full support is + provided for SCSI-I & SCSI-II peripherals, + including Disks, tape drives (including DAT) and CD ROM + drives. + + The following CD-ROM type systems are supported at this + time: + + <itemize> + <item>SCSI (also includes ProAudio Spectrum and + SoundBlaster SCSI) (cd) + <item>Mitsumi proprietary interface (mcd) + <item>Matsushita/Panasonic (Creative) proprietary + interface (matcd) + <item>Sony proprietary interface (scd) + </itemize> + + <bf>Note:</bf> CD-Drives with IDE interfaces are not + supported at this time. + + Some controllers have limitations with the way they + deal with >16MB of memory, due to the fact that the + ISA bus only has a DMA address space of 24 bits. If + you do your arithmetic, you'll see that this makes it + impossible to do direct DMA to any address >16MB. + This limitation is even true of some EISA controllers + (which are normally 32 bit) when they're configured to + emulate an ISA card, which they then do in *all* + respects. This problem is avoided entirely by IDE + controllers (which do not use DMA), true EISA + controllers (like the UltraStor, Adaptec 1742A or + Adaptec 2742) and most VLB (local bus) controllers. In + the cases where it's necessary, the system will use + "bounce buffers" to talk to the controller so that you + can still use more than 16Mb of memory without + difficulty. + + + <sect1><heading>Ethernet cards</heading> + + <p> + <itemize> + + <item>SMC Elite 16 WD8013 ethernet interface, and + most other WD8003E, WD8003EBT, WD8003W, WD8013W, + WD8003S, WD8003SBT and WD8013EBT based clones. SMC + Elite Ultra is also supported. + + <item>DEC EtherWORKS III NICs (DE203, DE204, and DE205) + <item>DEC EtherWORKS II NICs (DE200, DE201, DE202, and DE422) + <item>DEC DC21140 based NICs (SMC???? DE???) + <item>DEC FDDI (DEFPA/DEFEA) NICs + + <item>Fujitsu MB86960A family of NICs + + <item>Intel EtherExpress + + <item>Isolan AT 4141-0 (16 bit) + <item>Isolink 4110 (8 bit) + + <item>Novell NE1000, NE2000, and NE2100 ethernet interface. + + <item>3Com 3C501 cards + + <item>3Com 3C503 Etherlink II + + <item>3Com 3c505 Etherlink/+ + + <item>3Com 3C507 Etherlink 16/TP + + <item>3Com 3C509, 3C579, 3C589 (PCMCIA) Etherlink III + + <item>Toshiba ethernet cards + + <item>PCMCIA ethernet cards from IBM and National + Semiconductor are also supported. + </itemize> + + <sect1><heading>Miscellaneous devices</heading> + + <p> + <itemize> + <item>AST 4 port serial card using shared IRQ. + + <item>ARNET 8 port serial card using shared IRQ. + + <item>BOCA ATIO66 6 port serial card using shared IRQ. + + <item>Cyclades Cyclom-y Serial Board. + + <item>STB 4 port card using shared IRQ. + + <item>Mitsumi (all models) CDROM interface and drive. + + <item>SDL Communications Riscom/8 Serial Board. + + <item>Soundblaster SCSI and ProAudio Spectrum SCSI + CDROM interface and drive. + + <item>Matsushita/Panasonic (Creative SoundBlaster) + CDROM interface and drive. + + <item>Adlib, SoundBlaster, SoundBlaster Pro, + ProAudioSpectrum, Gravis UltraSound and Roland + MPU-401 sound cards. + + </itemize> + + FreeBSD currently does NOT support IBM's microchannel + (MCA) bus, but support is apparently close to + materializing. Details will be posted as the situation + develops. + + <sect><heading>Preparing for the installation</heading> + + <p>There are a number of different methods by which FreeBSD + can be installed. The following describes what + preparation needs to be done for each type. + + <sect1><heading>Before installing from CDROM</heading> + + <p>If your CDROM is of an unsupported type, such as an + IDE CDROM, then please skip to section 2.3: MS-DOS + Preparation. + + There is not a lot of preparatory work that needs to be + done to successfully install from one of Walnut Creek's + FreeBSD CDROMs (other CDROM distributions may work as + well, but I can't say for sure as I have no hand or say + in their creation). You can either boot into the CD + installation directly from MS-DOS using Walnut Creek's + supplied "install" batch file or you can make a boot + floppy by writing the supplied image + (floppies/boot.flp) onto a floppy with the "go" + command, which invokes the rawrite.exe command found in + the tools/ subdirectory. + + If you're creating the boot floppy from a UNIX machine, + you may find that ``dd if=floppies/boot.flp + of=/dev/rfd0'' or ``dd if=floppies/boot.flp + of=/dev/floppy'' works well, depending on your hardware + and operating system environment. + + Once you've booted from MS-DOS or floppy, you should be + able to select CDROM as the media type in the Media + menu and load the entire distribution from CDROM. No + other types of installation media should be required. + + After your system is fully installed and you have + rebooted from the hard disk, you should find the CD + mounted on the directory /cdrom. A utility called + `lndir' comes with the XFree86 distribution which you + may also find useful: It allows you to create "link + tree" directories to things on Read-Only media like + CDROM. One example might be something like this: + <tscreen>mkdir /usr/ports<newline>lndir /cdrom/ports + /usr/ports</tscreen> + + Which would allow you to then "cd /usr/ports; make" and + get all the sources from the CD, but yet create all the + intermediate files in /usr/ports, which is presumably + on a more writable media! + + + <sect1><heading>Before installing from Floppy</heading> + + <p>If you must install from floppy disks, either due to + unsupported hardware or just because you enjoy doing + things the hard way, you must first prepare some + floppies for the install. + + The first floppy you'll need is ``floppies/root.flp'', + which is somewhat special in that it's not a MS-DOS + filesystem floppy at all, but rather an "image" floppy + (it's actually a gzip'd cpio file). You can use the + rawrite.exe program to do this under DOS, or ``dd'' to + do it on a UNIX Workstation (see notes in section 2.1 + concerning the ``floppies/boot.flp'' image). Once this + floppy is made, put it aside. You'll be asked for it + later. + + You will also need, at minimum, as many 1.44MB or 1.2MB + floppies as it takes to hold all files in the bin + (binary distribution) directory. THESE floppies *must* + be formatted using MS-DOS, using with the FORMAT + command in MS-DOS or the File Manager format command in + Microsoft Windows(tm). Factory preformatted floppies + will also work well, provided that they haven't been + previously used for something else. + + Many problems reported by our users in the past have + resulted from the use of improperly formatted media, so + we simply take special care to mention it here! + + After you've MS-DOS formatted the floppies, you'll need + to copy the files onto them. The distribution files + are split into chunks conveniently sized so that 5 of + them will fit on a conventional 1.44MB floppy. Go + through all your floppies, packing as many files as + will fit on each one, until you've got all the + distributions you want packed up in this fashion. + Select ``Floppy'' from the Media menu at installation + time and you will be prompted for everything after + that. + + + <sect1><heading>Before installing from a MS-DOS partition</heading> + + <p>To prepare for installation from an MS-DOS partition, + copy the files from the distribution into a directory + called <tt>C:\FREEBSD</tt>. The directory tree structure + of the CDROM must be partially reproduced within this directory + so we suggest using the DOS <tt>xcopy</tt> + command. For example, to prepare for a minimal installation of + FreeBSD: +<tscreen><verb> +C> MD C:\FREEBSD +C> XCOPY /S E:\FLOPPIES C:\FREEBSD\FLOPPIES\ +C> XCOPY /S E:\DISTS\BIN C:\FREEBSD\BIN\ +</verb></tscreen> + asssuming that <tt>C:</tt> is where you have free space + and <tt>E:</tt> is where your CDROM is mounted. Note + that you need the <tt>FLOPPIES</tt> directory because + the <tt>root.flp</tt> image is needed during an MS-DOS + installation. + + For as many `DISTS' you wish to install from MS-DOS + (and you have free space for), install each one under + <tt>C:\FREEBSD</tt> - the <tt>BIN</tt> dist is only the + minimal requirement. If you have room on your MS-DOS + partition for all the distributions, you could replace + the last line above with: +<tscreen><verb> +C> XCOPY /S E:\DISTS C:\FREEBSD\ +</verb></tscreen> + which would copy all the subdirectories of + <tt>E:\DISTS</tt> to <tt>C:\FREEBSD</tt>. + + <sect1><heading>Before installing from QIC/SCSI Tape</heading> + + <p>Installing from tape is probably the easiest method, + short of an on-line install using FTP or a CDROM + instal. The installation program expects the files to + be simply tar'ed onto the tape, so after getting all of + the files for distribution you're interested in, simply + tar them onto the tape with a command like: +<tscreen> + cd /freebsd/distdir<newline> + tar cvf /dev/rwt0 (or /dev/rst0) dist1 .. dist2 + </tscreen> + Make sure that the `floppies/' directory is one of the + "dists" given above, since the installation will look + for `floppies/root.flp' on the tape. + + When you go to do the installation, you should also + make sure that you leave enough room in some temporary + directory (which you'll be allowed to choose) to + accommodate the FULL contents of the tape you've + created. Due to the non-random access nature of tapes, + this method of installation requires quite a bit of + temporary storage! You should expect to require as + much temporary storage as you have stuff written on + tape. + + +<sect1><heading>Before installing over a network</heading> + + <p>You can do network installations over 3 types of + communications links: + <descrip> + <tag>Serial port</tag> SLIP or PPP <tag>Parallel + port</tag> PLIP (laplink cable) <tag>Ethernet</tag> A + standard ethernet controller (includes some PCMCIA). + </descrip> + + SLIP support is rather primitive, and limited primarily + to hard-wired links, such as a serial cable running + between a laptop computer and another computer. The link + should be hard-wired as the SLIP installation doesn't + currently offer a dialing capability; that facility is + provided with the PPP utility, which should be used in + preference to SLIP whenever possible. + + If you're using a modem, then PPP is almost certainly + your only choice. Make sure that you have your service + provider's information handy as you'll need to know it + fairly soon in the installation process. You will need + to know, at the minimum, your service provider's IP + address and possibly your own (though you can also leave + it blank and allow PPP to negotiate it with your ISP). + You also need to know how to use the various "AT + commands" to dial the ISP with your particular modem as + the PPP dialer provides only a very simple terminal + emulator. + + If a hard-wired connection to another FreeBSD (2.0R or + later) machine is available, you might also consider + installing over a "laplink" parallel port cable. The + data rate over the parallel port is much higher than is + what's typically possible over a serial line (up to + 50k/sec), thus resulting in a quicker installation. + + Finally, for the fastest possible network installation, + an ethernet adaptor is always a good choice! FreeBSD + supports most common PC ethernet cards, a table of + supported cards (and their required settings) provided as + part of the FreeBSD Hardware Guide - see the + Documentation menu on the boot floppy. If you are using + one of the supported PCMCIA ethernet cards, also be sure + that it's plugged in _before_ the laptop is powered on! + FreeBSD does not, unfortunately, currently support "hot + insertion" of PCMCIA cards. + + You will also need to know your IP address on the + network, the "netmask" value for your address class and + the name of your machine. Your system administrator can + tell you which values to use for your particular network + setup. If you will be referring to other hosts by name + rather than IP address, you'll also need a name server + and possibly the address of a gateway (if you're using + PPP, it's your provider's IP address) to use in talking + to it. If you do not know the answers to all or most of + these questions, then you should really probably talk to + your system administrator _first_ before trying this type + of installation! + + Once you have a network link of some sort working, the + installation can continue over NFS or FTP. + + <sect2><heading>Preparing for NFS installation</heading> + + <p>NFS installation is fairly straight-forward: Simply + copy the FreeBSD distribution files you're interested + onto a server somewhere and then point the NFS media + selection at it. + + If this server supports only "privileged port" access + (as is generally the default for Sun workstations), + you will need to set this option in the Options menu + before installation can proceed. + + If you have a poor quality ethernet card which + suffers from very slow transfer rates, you may also + wish to toggle the appropriate Options flag. + + In order for NFS installation to work, the server + must support "subdir mounts", e.g. if your FreeBSD + 2.0.5 distribution directory lives on: + ziggy:/usr/archive/stuff/FreeBSD Then ziggy will have + to allow the direct mounting of + /usr/archive/stuff/FreeBSD, not just /usr or + /usr/archive/stuff. + + In FreeBSD's /etc/exports file, this is controlled by + the ``-alldirs'' option. Other NFS servers may have + different conventions. If you are getting + `Permission Denied' messages from the server then + it's likely that you don't have this enabled + properly! + + + <sect2><heading>Preparing for FTP Installation</heading> + + <p>FTP installation may be done from any mirror site + containing a reasonably up-to-date version of FreeBSD + 2.0.5, a full menu of reasonable choices from almost + anywhere in the world being provided by the FTP site + menu. + + If you are installing from some other FTP site not + listed in this menu, or you are having troubles + getting your name server configured properly, you can + also specify your own URL by selecting the ``Other'' + choice in that menu. A URL can also be a direct IP + address, so the following would work in the absence + of a name server: <tscreen> + ftp://192.216.222.4/pub/FreeBSD/2.0.5-RELEASE</tscreen> + + <em><bf>NOTE:</bf> Substitute "ALPHA" for "RELEASE" + during the ALPHA test period!</em> + + If you are installing through a firewall then you + should probably select ``Passive mode'' ftp, which is + the default. If you are talking to a server which + does not support passive mode for some reason, see + the Options menu to select Active mode transfers. + + + <sect><heading>Installing FreeBSD</heading> + + <p>Once you've taken note of the appropriate + preinstallation steps, you should be able to install + FreeBSD without any further trouble. + + Should this not be true, then you may wish to go back and + re-read the relevant preparation section (section 2.x) + for the installation media type you're trying to use - + perhaps there's a helpful hint there that you missed the + first time? If you're having hardware trouble, or + FreeBSD refuses to boot at all, read the Hardware Guide + provided on the boot floppy for a list of possible + solutions. + + The FreeBSD boot floppy contains all the on-line + documentation you should need to be able to navigate + through an installation and if it doesn't then I'd like + to know what you found most confusing! It is the + objective of the FreeBSD installation program + (sysinstall) to be self-documenting enough that painful + "step-by-step" guides are no longer necessary. It may + take us a little while to reach that objective, but + that's the objective! + + Meanwhile, you may also find the following "typical + installation sequence" to be helpful: + + <enum> + + <item>Boot the boot floppy. After a boot sequence + which can take anywhere from from 30 seconds to 3 + minutes, depending on your hardware, you should be + presented with a menu of initial choices. If the + floppy doesn't boot at all, or the boot hangs at some + stage, go read the Q&A section of the Hardware Guide + for possible causes. + + <item>Press F1. You should see some basic usage + instructions on the menu system and general + navigation. If you haven't used this menu system + before then PLEASE read this thoroughly! + + <item>If English is not your native language, you may + wish to proceed directly to the Language option and + set your preferred language. This will bring up some + of the documentation in that language instead of + english. + + <item>Select the Options item and set any special + preferences you may have. + + <item>Select Proceed, bringing you to the Installation Menu. + + </enum> + + <sect1><heading>The installation menu</heading> + + <p>You can do anything you like in this menu without + altering your system <em>except</em> for "Commit", + which will perform any requests to alter your system + you may have made. + + If you're confused at any point, the F1 key usually + pulls up the right information for the screen you're + in. + + <enum> + + <item>The first step is generally `Partition', which + allows you to chose how your drives will be used + for FreeBSD. + + <item>Next, with the `Label' editor, you can specify + how the space in any allocated FreeBSD partitions + should be used by FreeBSD, or where to mount a + non-FreeBSD partition (such as DOS). + + <item>Next, the `Distributions' menu allows you to + specify which parts of FreeBSD you wish to load. A + good choice is "User" for a small system or + "Developer" for someone wanting a bit more out of + FreeBSD. If none of the existing collections sound + applicable, select Custom. + + <item>Next, the `Media' menu allows you to specify + what kind of media you wish to install from. If a + desired media choice is found and configured + automatically then this menu will simply return, + otherwise you'll be asked for additional details on + the media device type. + + <item>Finally, the Commit command will actually + perform all the actions at once (nothing has been + written to your disk so far, nor will it until you + give the final confirmation). All new or changed + partition information will be written out, file + systems will be created and/or non-destructively + labelled (depending on how you set their newfs + flags in the Label editor) and all selected + distributions will be extracted. + + <item>The Configure menu choice allows you to furthur + configure your FreeBSD installation by giving you + menu-driven access to various system defaults. + Some items, like networking, may be especially + important if you did a CDROM/Tape/Floppy + installation and have not yet configured your + network interfaces (assuming you have some). + Properly configuring your network here will allow + FreeBSD to come up on the network when you first + reboot from the hard disk. + + <item>Exit returns you to the top menu. + + </enum> + + At this point, you're generally done with the + sysinstall utility and can select the final `Quit'. If + you're running it as an installer (e.g. before the + system is all the way up) then the system will now + reboot. If you selected the boot manager option, you + will see a small boot menu with an `F?' prompt. Press + the function key for BSD (it will be shown) and you + should boot up into FreeBSD off the hard disk. + + If this fails to happen for some reason, see the Q&A + section of the Hardware Guide for possible clues! + diff --git a/share/doc/handbook/kerneldebug.sgml b/share/doc/handbook/kerneldebug.sgml new file mode 100644 index 0000000000000..6afbd419bbb87 --- /dev/null +++ b/share/doc/handbook/kerneldebug.sgml @@ -0,0 +1,425 @@ +<!-- $Id: kerneldebug.sgml,v 1.2 1995/06/30 17:37:41 jfieber Exp $ --> +<!-- The FreeBSD Documentation Project --> + +<chapt><heading>Kernel Debugging<label id="kerneldebug"></heading> + +<p><em>Contributed by &a.paul; and &a.joerg;</em> + +<sect><heading>Debugging a kernel crash dump with kgdb</heading> + + <p>Here are some instructions for getting kernel debugging + working on a crash dump, it assumes that you have enough swap + space for a crash dump. If you have multiple swap + partitions and the first one is too small to hold the dump, + you can configure your kernel to use an alternate dump device + (in the <tt>config kernel</tt> line), or + you can specify an alternate using the dumpon(8) command. + Dumps to non-swap devices, + tapes for example, are currently not supported. Config your + kernel using <tt>config -g</tt>. + See <ref id="kernelconfig" name="Kernel Configuration"> for + details on configuring the FreeBSD kernel. + + Use the <tt>dumpon(8)</tt> command to tell the kernel where to dump + to (note that this will have to be done after configuring the + partition in question as swap space via <tt>swapon(8)</tt>). This is + normally arranged via <tt>/etc/sysconfig</tt> and <tt>/etc/rc</tt>. + Alternatively, you can + hard-code the dump device via the `dump' clause in the `config' line + of your kernel config file. This is deprecated, but might be the + only chance to get a crash dump from a kernel that's not booting at + all, so that you didn't had the ability to run any command before it + used to crash. + + <em><bf>Note:</bf> In the following, the term `<tt>kgdb</tt>' refers + to <tt>gdb</tt> run in `kernel debug mode'. This can be accomplished by + either starting the <tt>gdb</tt> with the option <tt>-k</tt>, or by linking + and starting it under the name <tt>kgdb</tt>. This is not being + done by default, however.</em> + + When the kernel has been built make a copy of it, say + <tt>kernel.debug</tt>, and then run <tt>strip -x</tt> on the + original. Install the original as normal. You may also install + the unstripped kernel, but symbol table lookup time for some + programs will drastically increase, and since + the whole kernel is loaded entirely at boot time and cannot be + swapped out later, several megabytes of + physical RAM willl be wasted. + + If you are testing a new kernel, for example by typing the new + kernel's name at the boot prompt, but need to boot a different + one in order to get your system up and running again, boot it + only into single user state using the <tt>-s</tt> flag at the + boot prompt, and then perform the following steps: +<tscreen><verb> + fsck -p + mount -a -t ufs # so your file system for /var/crash is writable + savecore -N /kernel.panicked /var/crash + exit # ...to multi-user +</verb></tscreen> + This instructs <tt>savecore(8)</tt> to use another kernel for symbol name + extraction. It would otherwise default to the currently running kernel. + + Now, after a crash dump, go to <tt>/sys/compile/WHATEVER</tt> and run + <tt>kgdb</tt>. From <tt>kgdb</tt> do: +<tscreen><verb> + symbol-file kernel.debug + exec-file /var/crash/system.0 + core-file /var/crash/ram.0 +</verb></tscreen> + and voila, you can debug the crash dump using the kernel sources + just like you can for any other program. + + If your kernel panicked due to a trap, perhaps the most common + case for getting a core dump, the following trick might help + you. Examine the stack using <tt>kgdb</tt>'s `where' command, + and look for the stack frame in the function <tt>trap()</tt>. Go `up' + to that frame, and then type: +<tscreen><verb> + frame frame->tf_ebp frame->tf_eip +</verb></tscreen> + This will tell <tt>kgdb</tt> to go to the stack frame explicitly named by a + frame pointer and instruction pointer, which is the location where + the trap occured. There are still some bugs in <tt>kgdb</tt> (you can go + `up' from there, but not `down'; the stack trace will still remain + as it was before going to here), but generally this method will lead + you much closer to the failing piece of code. + + Here's a script log of a <tt>kgdb</tt> session illustrating the above. Long + lines have been folded to improve readability, and the lines are + numbered for reference. Despite of this, it's a real-world error + trace taken during the development of the pcvt console driver. +<tscreen><verb> + 1:Script started on Fri Dec 30 23:15:22 1994 + 2:uriah # cd /sys/compile/URIAH + 3:uriah # kgdb kernel /var/crash/vmcore.1 + 4:Reading symbol data from /usr/src/sys/compile/URIAH/kernel...done. + 5:IdlePTD 1f3000 + 6:panic: because you said to! + 7:current pcb at 1e3f70 + 8:Reading in symbols for ../../i386/i386/machdep.c...done. + 9:(kgdb) where + 10:#0 boot (arghowto=256) (../../i386/i386/machdep.c line 767) + 11:#1 0xf0115159 in panic () + 12:#2 0xf01955bd in diediedie () (../../i386/i386/machdep.c line 698) + 13:#3 0xf010185e in db_fncall () + 14:#4 0xf0101586 in db_command (-266509132, -266509516, -267381073) + 15:#5 0xf0101711 in db_command_loop () + 16:#6 0xf01040a0 in db_trap () + 17:#7 0xf0192976 in kdb_trap (12, 0, -272630436, -266743723) + 18:#8 0xf019d2eb in trap_fatal (...) + 19:#9 0xf019ce60 in trap_pfault (...) + 20:#10 0xf019cb2f in trap (...) + 21:#11 0xf01932a1 in exception:calltrap () + 22:#12 0xf0191503 in cnopen (...) + 23:#13 0xf0132c34 in spec_open () + 24:#14 0xf012d014 in vn_open () + 25:#15 0xf012a183 in open () + 26:#16 0xf019d4eb in syscall (...) + 27:(kgdb) up 10 + 28:Reading in symbols for ../../i386/i386/trap.c...done. + 29:#10 0xf019cb2f in trap (frame={tf_es = -260440048, tf_ds = 16, tf_\ + 30:edi = 3072, tf_esi = -266445372, tf_ebp = -272630356, tf_isp = -27\ + 31:2630396, tf_ebx = -266427884, tf_edx = 12, tf_ecx = -266427884, tf\ + 32:_eax = 64772224, tf_trapno = 12, tf_err = -272695296, tf_eip = -26\ + 33:6672343, tf_cs = -266469368, tf_eflags = 66066, tf_esp = 3072, tf_\ + 34:ss = -266427884}) (../../i386/i386/trap.c line 283) + 35:283 (void) trap_pfault(&frame, FALSE); + 36:(kgdb) frame frame->tf_ebp frame->tf_eip + 37:Reading in symbols for ../../i386/isa/pcvt/pcvt_drv.c...done. + 38:#0 0xf01ae729 in pcopen (dev=3072, flag=3, mode=8192, p=(struct p\ + 39:roc *) 0xf07c0c00) (../../i386/isa/pcvt/pcvt_drv.c line 403) + 40:403 return ((*linesw[tp->t_line].l_open)(dev, tp)); + 41:(kgdb) list + 42:398 + 43:399 tp->t_state |= TS_CARR_ON; + 44:400 tp->t_cflag |= CLOCAL; /* cannot be a modem (:-) */ + 45:401 + 46:402 #if PCVT_NETBSD || (PCVT_FREEBSD >= 200) + 47:403 return ((*linesw[tp->t_line].l_open)(dev, tp)); + 48:404 #else + 49:405 return ((*linesw[tp->t_line].l_open)(dev, tp, flag)); + 50:406 #endif /* PCVT_NETBSD || (PCVT_FREEBSD >= 200) */ + 51:407 } + 52:(kgdb) print tp + 53:Reading in symbols for ../../i386/i386/cons.c...done. + 54:$1 = (struct tty *) 0x1bae + 55:(kgdb) print tp->t_line + 56:$2 = 1767990816 + 57:(kgdb) up + 58:#1 0xf0191503 in cnopen (dev=0x00000000, flag=3, mode=8192, p=(st\ + 59:ruct proc *) 0xf07c0c00) (../../i386/i386/cons.c line 126) + 60: return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p)); + 61:(kgdb) up + 62:#2 0xf0132c34 in spec_open () + 63:(kgdb) up + 64:#3 0xf012d014 in vn_open () + 65:(kgdb) up + 66:#4 0xf012a183 in open () + 67:(kgdb) up + 68:#5 0xf019d4eb in syscall (frame={tf_es = 39, tf_ds = 39, tf_edi =\ + 69: 2158592, tf_esi = 0, tf_ebp = -272638436, tf_isp = -272629788, tf\ + 70:_ebx = 7086, tf_edx = 1, tf_ecx = 0, tf_eax = 5, tf_trapno = 582, \ + 71:tf_err = 582, tf_eip = 75749, tf_cs = 31, tf_eflags = 582, tf_esp \ + 72:= -272638456, tf_ss = 39}) (../../i386/i386/trap.c line 673) + 73:673 error = (*callp->sy_call)(p, args, rval); + 74:(kgdb) up + 75:Initial frame selected; you cannot go up. + 76:(kgdb) quit + 77:uriah # exit + 78:exit + 79: + 80:Script done on Fri Dec 30 23:18:04 1994 +</verb></tscreen> + Comments to the above script: + +<descrip> +<tag/line 6:/ This is a dump taken from within DDB (see below), hence the + panic comment ``because you said to!'', and a rather long + stack trace; the initial reason for going into DDB has been + a page fault trap though. +<tag/line 20:/ This is the location of function <tt>trap()</tt> + in the stack trace. +<tag/line 36:/ Force usage of a new stack frame, kgdb responds and displays + the source line where the trap happened; from looking at the + code, there's a high probability that either the pointer + access for ``tp'' was messed up, or the array access was + out of bounds. +<tag/line 52:/ The pointer looks suspicious, but happens to be a valid + address. +<tag/line 56:/ However, it obviously points to garbage, so we have found our + error! (For those unfamiliar with that particular piece + of code: <tt>tp->t_line</tt> refers to the line discipline + of the console device here, which must be a rather small integer + number.) +</descrip> + + +<sect><heading>Post-mortem analysis of a dump</heading> + +<p>What do you do if a kernel dumped core but you did not expect + it, and it's therefore not compiled using <tt>config -g</tt>? + Not everything is lost here. Don't panic! + + Of course, you still need to enable crash dumps. See above + on the options you've got to do this. + (This is for safety reasons in the default kernels, to avoid them + trying to dump e.g. during system installation where there's no + FreeBSD partition at all and valuable data on the disk could be + destroyed.) + + Go to your kernel compile directory, and edit the line + containing <tt>COPTFLAGS?=-O</tt>. Add the <tt>-g</tt> option + there (but <em>don't</em> change anything on the level of + optimization). If you do already know roughly the probable + location of the failing piece of code (e.g., the <tt>pcvt</tt> + driver in the example above), remove all the object files for + this code. Rebuild the kernel. Due to the time stamp change on + the Makefile, there will be some other object files rebuild, + for example <tt>trap.o</tt>. With a bit of luck, the added + <tt>-g</tt> option won't change anything for the generated + code, so you'll finally get a new kernel with similiar code to + the faulting one but some debugging symbols. You should at + least verify the old and new sizes with the <tt>size(1)</tt> command. If + there is a mismatch, you probably need to give up here. + + Go and examine the dump as described above. The debugging + symbols might be incomplete for some places, as can be seen in + the stack trace in the example above where some functions are + displayed without line numbers and argument lists. If you need + more debugging symbols, remove the appropriate object files and + repeat the <tt>kgdb</tt> session until you know enough. + + All this is not guaranteed to work, but it will do it fine in + most cases. + +<sect><heading>On-line kernel debugging using DDB</heading> + +<p>While <tt>kgdb</tt> as an offline debugger provides a very + high level of user interface, there are some things it cannot do. + The most important ones being breakpointing and single-stepping + kernel code. + + If you need to do low-level debugging on your kernel, there's + an on- line debugger available called DDB. It allows to + setting breakpoints, single-steping kernel functions, examining + and changeing kernel variables, etc. However, it cannot not + access kernel source files, and only has access to the global + and static symbols, not to the full debug information like + <tt>kgdb</tt>. + + To configure your kernel to include DDB, add the option line +<tscreen><verb> + options DDB +</verb></tscreen> + to your config file, and rebuild. (See <ref id="kernelconfig" + name="Kernel Configuration"> for details on configuring the + FreeBSD kernel. Note that if you have an older version of the + boot blocks, your debugger symbols might not be loaded at all. + Update the boot blocks, the recent ones do load the DDB symbols + automagically.) + + Once your DDB kernel is running, there are several ways to + enter DDB. The first, and earliest way is to type the boot + flag <tt>-d</tt> right at the boot prompt. The kernel will + start up in debug mode and enter DDB prior to any device + probing. Hence you are able to even debug the device + probe/attach functions. + + The second scenario is a hot-key on the keyboard, usually + Ctrl-Alt-ESC. For syscons, this can be remapped, and some of + the distributed maps do this, so watch out. + There's an option + available for a COMCONSOLE kernel (``options BREAK_TO_DEBUGGER'') + that allows the use of a serial line BREAK on the console line to + enter DDB. + + The third way is that any panic condition will branch to DDB if + the kernel is configured to use it. It is not wise to + configure a kernel with DDB for a machine running unattended + for this reason. + + The DDB commands roughly resemble some <tt>gdb</tt> commands. The first you + probably need is to set a breakpoint: +<tscreen><verb> + b function-name + b address +</verb></tscreen> + + Numbers are taken hexadecimal by default, but to make them + distinct from symbol names, hexadecimal numbers starting with the + letters <tt>a</tt>-<tt>f</tt> need to be preceded with + <tt>0x</tt> (for other numbers, this is optional). Simple + expressions are allowed, for example: <tt>function-name + 0x103</tt>. + + To continue the operation of an interrupted kernel, simply type +<tscreen><verb> + c +</verb></tscreen> + To get a stack trace, use +<tscreen><verb> + trace +</verb></tscreen> + Note that when entering DDB via a hot-key, the kernel is currently + servicing an interrupt, so the stack trace might be not of much use + for you. + + If you want to remove a breakpoint, use +<tscreen><verb> + del + del address-expression +</verb></tscreen> + The first form will be accepted immediately after a breakpoint hit, + and deletes the current breakpoint. The second form can remove any + breakpoint, but you need to specify the exact address, as it can be + obtained from +<tscreen><verb> + show b +</verb></tscreen> + To single-step the kernel, try +<tscreen><verb> + s +</verb></tscreen> + This will step into functions, but you can make DDB trace them until + the matching return statement is reached by +<tscreen><verb> + n +</verb></tscreen> + Note: this is different from <tt>gdb</tt>'s `next' statement, it's like + <tt>gdb</tt>'s `finish'. + + To examine data from memory, use (for example): +<tscreen><verb> + x/wx 0xf0133fe0,40 + x/hd db_symtab_space + x/bc termbuf,10 + x/s stringbuf +</verb></tscreen> + for word/halfword/byte access, and hexadecimal/decimal/character/ + string display. The number after the comma is the object count. + To display the next 0x10 items, simply use +<tscreen><verb> + x ,10 +</verb></tscreen> + Similiarly, use +<tscreen><verb> + x/ia foofunc,10 +</verb></tscreen> + to disassemble the first 0x10 instructions of <tt>foofunc</tt>, and display + them along with their offset from the beginning of <tt>foofunc</tt>. + + To modify the memory, use the write command: +<tscreen><verb> + w/b termbuf 0xa 0xb 0 + w/w 0xf0010030 0 0 +</verb></tscreen> + The command modifier (<tt>b</tt>/<tt>h</tt>/<tt>w</tt>) + specifies the size of the data to be writtten, the first + following expression is the address to write to, the remainder + is interpreted as data to write to successive memory locations. + + If you need to know the current registers, use +<tscreen><verb> + show reg +</verb></tscreen> + Alternatively, you can display a single register value by e.g. +<tscreen><verb> + print $eax +</verb></tscreen> + and modify it by +<tscreen><verb> + set $eax new-value +</verb></tscreen> + + Should you need to call some kernel functions from DDB, simply + say +<tscreen><verb> + call func(arg1, arg2, ...) +</verb></tscreen> + The return value will be printed. + + For a <tt>ps(1)</tt> style summary of all running processes, use +<tscreen><verb> + ps +</verb></tscreen> + + Now you have now examined why your kernel failed, and you wish to + reboot. Remember that, depending on the severity of previous + malfunctioning, not all parts of the kernel might still be working + as expected. Perform one of the following actions to shut down and + reboot your system: +<tscreen><verb> + call diediedie() +</verb></tscreen> + + will cause your kernel to dump core and reboot, so you can + later analyze the core on a higher level with kgdb. This + command usually must be followed by another + `<tt>continue</tt>' statement. + There is now an alias for this: `<tt>panic</tt>'. + +<tscreen><verb> + call boot(0) +</verb></tscreen> + might be a good way to cleanly shut down the running system, <tt>sync()</tt> + all disks, and finally reboot. As long as the disk and file system + interfaces of the kernel are not damaged, this might be a good way + for an almost clean shutdown. + +<tscreen><verb> + call cpu_reset() +</verb></tscreen> + is the final way out of disaster and almost the same as hitting + the Big Red Button. + + + +<sect><heading>Debugging a console driver</heading> + +<p>Since you need a console driver to run DDB on, things are more + complicated if the console driver itself is flakey. You might + remember the <tt>options COMCONSOLE</tt> line, and hook up a standard + terminal onto your first serial port. DDB works on any configured + console driver, of course it also works on a <tt>COMCONSOLE</tt>. + + diff --git a/share/doc/handbook/relnotes.sgml b/share/doc/handbook/relnotes.sgml new file mode 100644 index 0000000000000..d85f2992ccefd --- /dev/null +++ b/share/doc/handbook/relnotes.sgml @@ -0,0 +1,503 @@ +<!-- $Id: relnotes.sgml,v 1.3 1995/06/30 17:37:47 jfieber Exp $ --> +<!-- The FreeBSD Documentation Project --> + +<!-- +<!DOCTYPE linuxdoc PUBLIC '-//FreeBSD//DTD linuxdoc//EN'> +<linuxdoc><book><chapt>foo +--> + <sect><heading>About this release<label id="relnotes"></heading> + + <p>Since our first release of FreeBSD 1.0 nearly two + years ago, FreeBSD has changed dramatically. Since + release 2.0, FreeBSD has been based on the Berkeley BSD + 4.4-lite code rather than the Net2 code used for + previous versions. In addition to clearing the legal + issues that surrounded the Net2 code, the port to 4.4 + has also brought in numerous new features, filesystems + and enhanced driver support. + + Since our release of FreeBSD 2.0 in November of 1994, + the performance, feature set, and stability of FreeBSD + has improved dramatically. The largest change is a + revamped Virtual Memory (VM) system with a merged + virtual memory and file buffer cache. This increases + performance while reducing FreeBSD's memory footprint, + making a system with 4 megabytes of RAM a more + acceptable minimum. Other enhancements include full + NIS client and server support, transaction TCP support, + dial on demand PPP, an improved SCSI subsystem, early + support for ISDN, support for FDDI and 100Mbit Fast + Ethernet adapters, improved support for the Adaptec + 2940 and hundreds of bug fixes. + + We've also taken the comments and suggestions of many + of our users to heart and have attempted to provide + what we hope is a more sane and easily understood + installation process. Your feedback on this constantly + evolving process is especially welcome! + + In addition to the base distributions, FreeBSD offers a + new ported software collection with some 270 commonly + sought-after programs. The list of ports ranges from + World Wide Web (http) servers, to games, languages, + editors and almost everything in between. The entire + ports collection requires only 10MB of storage because + each port contains only the changes required for the + source code to compile on FreeBSD and the information + necessary to automatically retrieve the original + sources. The original distribution for each port you + build is automatically retrieved off of CD-ROM or a via + anonymous ftp, so you need only enough disk space to + build the ports you want. Each port is also provided + as a pre-compiled package which can be installed with + the <tt>pkg_add(1)</tt> command for those who do not + wish to compile their own ports from source. See <ref + id="ports" name="The Ports Collection"> for a more + complete description. + +<!-- XXX make xref + For a list of contributors and a general project + description, please see the file "CONTRIB.FreeBSD" + which should be bundled with your binary distribution. + + Also see the "REGISTER.FreeBSD" file for information on + registering with the "Free BSD user counter". This + counter is for ALL freely available variants of BSD, + not just FreeBSD, and we urge you to register yourself + with it. +--> + + The core of FreeBSD does not contain DES code which + would inhibit its being exported outside the United + States. An add-on package, for use only in the United + States, contains the programs that normally use DES. + The auxiliary packages provided separately can be used + by anyone. A freely exportable European distribution + of DES for our non-U.S. users also exists and is + described in the <url + url="http://www.freebsd.org/How/faq" name="FreeBSD + FAQ">. If password security for FreeBSD is all you + need, and you have no requirement for copying encrypted + passwords from other hosts using DES into FreeBSD + password entries, then FreeBSD's MD5 based security may + be all you require. We feel that our default security + model is more than a match for DES, and without any + messy export issues to deal with. + + FreeBSD 2.0.5 represents the culmination of 2 years of + work and many thousands of man hours put in by an + international development team. We hope you enjoy it! + + <sect1><heading>New feature highlights</heading> + + <p>The following features were added or substantially + improved between the release of 2.0 and this 2.0.5 + release. In order to facilitate better + communication, the person, or persons, responsible + for each enhancement is noted. Any questions + regarding the new functionality should be directed to + them first. + + <sect2><heading>Kernel</heading> + + <p> + <descrip> + + <tag>Merged VM-File Buffer Cache</tag> A merged + VM/buffer cache design greatly enhances overall + system performance and makes it possible to do + a number of more optimal memory allocation + strategies that were not possible before. + + Owner: David Greenman (davidg@FreeBSD.org) and + John Dyson (dyson@implode.root.com) + + <tag>Network PCB hash optimization</tag> For + systems with a great number of active TCP + connections (WEB and ftp servers, for example), + this greatly speeds up the lookup time required + to match an incoming packet up to its + associated connection. + + Owner: David Greenman (davidg@FreeBSD.org) + + <tag>Name cache optimization</tag> The name-cache + would cache all files of the same name to the + same bucket, which would put for instance all + ".." entries in the same bucket. We added the + parent directory version to frustrate the hash, + and improved the management of the cache in + various other ways while we were at it. + + Owner: Poul-Henning Kamp (phk@FreeBSD.org) + David Greenman (davidg@FreeBSD.org) + + <tag>Less restrictive swap-spaces</tag> The need + to compile the names of the swap devices into + the kernel has been removed. Now + <tt>swapon(8)</tt> will accept any block + devices, up to the maximum number of swap + devices configured in the kernel. + + Owner: Poul-Henning Kamp (phk@FreeBSD.org) + David Greenman (davidg@FreeBSD.org) + + <tag>Hard Wired SCSI Devices</tag> Prior to + 2.0.5, FreeBSD performed dynamic assignment of + unit numbers to SCSI devices as they were + probed, allowing a SCSI device failure to + possibly change unit number assignment. This + could cause filesystems other disks in the + system to be incorrectly mounted, or not + mounted at all. Hard wiring allows static + allocation of unit numbers (and hence device + names) to scsi devices based on SCSI ID and + bus. SCSI configuration occurs in the kernel + config file. Samples of the configuration + syntax can be found in the <tt>scsi(4)</tt> man + page or the LINT kernel config file. + + Owner: Peter Dufault (dufault@hda.com) + + Sources involved: <tt>sys/scsi/*</tt> + <tt>usr.sbin/config/*</tt> + + <tag>Slice Support</tag> FreeBSD now supports a + <em>slice</em> abstraction which enhances + FreeBSD's ability to share disks with other + operating systems. This support will allow + FreeBSD to inhabit DOS extended partitions. + + Owner: Bruce Evans (bde@FreeBSD.org) + + Sources involved: <tt>sys/disklabel.h</tt> + <tt>sys/diskslice.h</tt> <tt>sys/dkbad.h</tt> + <tt>kern/subr_diskslice.c</tt> <tt>kern/subr_dkbad.c</tt> + <tt>i386/isa/diskslice_machdep.c</tt> <tt>i386/isa/wd.c</tt> + <tt>scsi/sd.c</tt> <tt>dev/vn/vn.c</tt> + + <tag>Support for Ontrack Disk Manager Version + 6.0</tag> Support has been added for disks + which use Ontrack Disk Manager. The fdisk + program does <em>not</em> know about it + however, so make all changes using the install + program on the boot.flp or the Ontrack Disk + Manager tool under MS-DOS. + + Owner: Poul-Henning Kamp (phk@FreeBSD.org) + + <tag>Bad144 is back and working</tag> Bad144 + works again, though the semantics are slightly + different than before in that the bad-spots are + kept relative to the slice rather than absolute + on the disk. + + Owner: Bruce Evans (bde@FreeBSD.org) + Poul-Henning Kamp (phk@FreeBSD.org) + + </descrip> + + <sect2><heading>New device support</heading> + + <sect3><heading>SCSI and CDROM devices</heading> + + <p><descrip> + + <tag>Matsushita/Panasonic (Creative) CD-ROM + driver</tag> The Matsushita/Panasonic CR-562 and + CR-563 drives are now supported when connected to + a Sound Blaster or 100% compatible host adapter. + Up to four host adapters are supported for a + total of 16 CD-ROM drives. The audio functions + are supported with the Karoke variable speed + playback. + + Owner: Frank Durda IV + (bsdmail@nemesis.lonestar.org) + + Sources involved: <tt>isa/matcd</tt> + + <tag>Adaptec 2742/2842/2940 SCSI driver</tag> The + original 274x/284x driver has evolved + considerably since the 2.0 release of FreeBSD. + We now offer full support for the 2940 series as + well as the Wide models of these cards. The + arbitration bug that caused problems with fast + devices has been corrected and + <em>experimental</em> tagged queuing support has + been added (kernel option + <tt>AHC_TAGENABLE</tt>). John Aycock has also + released the sequencer code under a Berkeley + style copyright making the driver entirely clean + of the GPL. + + Owner: Justin Gibbs (gibbs@FreeBSD.org) + + Sources involved: <tt>isa/aic7770.c</tt> <tt>pci/aic7870.c</tt> + <tt>i386/scsi/*</tt> <tt>sys/dev/aic7xxx/*</tt> + + <tag>NCR5380/NCR53400 SCSI (ProAudio Spectrum) + driver</tag> Owner: core + + Submitted by: Serge Vakulenko (vak@cronyx.ru) + + Sources involved: <tt>isa/ncr5380.c</tt> + + <tag>Sony CDROM driver</tag> Owner: core + + Submitted by: Mikael Hybsch (micke@dynas.se) + + Sources involved: <tt>isa/scd.c</tt> + + </descrip> + + <sect3><heading>Serial devices</heading> + + <p><descrip> + + <tag>SDL Communications Riscom/8 Serial Board + Driver</tag> Owner: Andrey Chernov + (ache@FreeBSD.org) + + Sources involved: <tt>isa/rc.c</tt> <tt>isa/rcreg.h</tt> + + <tag>Cyclades Cyclom-y Serial Board Driver</tag> + Owner: Bruce Evans (bde@FreeBSD.org) + + Submitted by: Andrew Werple + (andrew@werple.apana.org.au) and Heikki Suonsivu + (hsu@cs.hut.fi) + + Obtained from: NetBSD + + Sources involved: <tt>isa/cy.c</tt> + + <tag>Cronyx/Sigma sync/async serial driver</tag> + Owner: core + + Submitted by: Serge Vakulenko + + Sources involved: <tt>isa/cronyx.c</tt> + + </descrip> + + <sect2><heading>Networking</heading> + + <p><descrip> + + <tag>Diskless booting</tag> Diskless booting in 2.0.5 + is much improved over previous releases. The boot + program is in <tt>src/sys/i386/boot/netboot</tt>, + and can be run from an MS-DOS system or burned into + an EPROM. WD, SMC, 3COM and Novell ethernet cards + are currently supported. Local swapping is also + supported. + + <tag>DEC DC21140 Fast Ethernet driver</tag> This + driver supports any of the numerous NICs using the + DC21140 chipset including the 100Mb DEC DE-500-XA + and SMC 9332. + + Owner: core + + Submitted by: Matt Thomas (thomas@lkg.dec.com) + + Sources involved: <tt>pci/if_de.c</tt> <tt>pci/dc21040.h</tt> + + + <tag>DEC FDDI (DEFPA/DEFEA) driver</tag> Owner: core + + Submitted by: Matt Thomas (thomas@lkg.dec.com) + + Sources involved: <tt>pci/if_pdq.c</tt> <tt>pci/pdq.c</tt> + <tt>pci/pdq_os.h</tt> <tt>pci/pdqreg.h</tt> + + + <tag>3Com 3c505 (Etherlink/+) NIC driver</tag> Owner: + core + + Submitted by: Dean Huxley (dean@fsa.ca) + + Obtained from: NetBSD + + Sources involved: <tt>isa/if_eg.c</tt> + + + <tag>Fujitsu MB86960A family of NICs driver</tag> + Owner: core + + Submitted by: M.S. (seki@sysrap.cs.fujitsu.co.jp) + + Sources involved: <tt>isa/if_fe.c</tt> + + + <tag>Intel EtherExpress driver</tag> Owner: Rodney + W. Grimes (rgrimes@FreeBSD.org) + + Sources involved: <tt>isa/if_ix.c</tt> <tt>isa/if_ixreg.h</tt> + + + <tag>3Com 3c589 driver</tag> Owner: core + + Submitted by: "HOSOKAWA Tatsumi" + (hosokawa@mt.cs.keio.ac.jp), Seiji Murata + (seiji@mt.cs.keio.ac.jp) and Noriyuki Takahashi + (hor@aecl.ntt.jp) + + Sources involved: <tt>isa/if_zp.c</tt> + + + <tag>IBM Credit Card Adapter driver</tag> Owner: core + + Submitted by: "HOSOKAWA Tatsumi" + (hosokawa@mt.cs.keio.ac.jp), + + Sources involved: <tt>isa/pcic.c</tt> <tt>isa/pcic.h</tt> + + + <tag>EDSS1 and 1TR6 ISDN interface driver</tag> + Owner: core + + Submitted by: Dietmar Friede + (dfriede@drnhh.neuhaus.de) and Juergen Krause + (jkr@saarlink.de) + + Sources involved: <tt>gnu/isdn/*</tt> + + </descrip> + + <sect2><heading>Miscellaneous drivers</heading> + + <p><descrip> + + <tag>Joystick driver</tag> Owner: Jean-Marc Zucconi + (jmz@FreeBSD.org) + + Sources involved: <tt>isa/joy.c</tt> + + <tag>National Instruments "LabPC" driver</tag> Owner: + Peter Dufault (dufault@hda.com) + + Sources involved: <tt>isa/labpc.c</tt> + + <tag>WD7000 driver</tag> Owner: Olof Johansson + (offe@ludd.luth.se) + + <tag>Pcvt Console driver</tag> Owner: Joerg Wunsch + (joerg@FreeBSD.org) + + Submitted by: Hellmuth Michaelis + (hm@altona.hamburg.com) + + Sources involved: <tt>isa/pcvt/*</tt> + + <tag>BSD-audio emulator for VAT driver</tag> Owner: + Amancio Hasty (ahasty@FreeBSD.org) and + Paul Traina (pst@FreeBSD.org) + + Sources involved: <tt>isa/sound/vat_audio.c</tt> + <tt>isa/sound/vat_audioio.h</tt> + + <tag>National Instruments AT-GPIB and AT-GPIB/TNT + GPIB driver</tag> Owner: core + + Submitted by: Fred Cawthorne + (fcawth@delphi.umd.edu) + + Sources involved: <tt>isa/gpib.c</tt> <tt>isa/gpib.h</tt> + <tt>isa/gpibreg.h</tt> + + <tag>Genius GS-4500 hand scanner driver</tag> Owner: + core + + Submitted by: Gunther Schadow + (gusw@fub46.zedat.fu-berlin.de) + + Sources involved: <tt>isa/gsc.c</tt> <tt>isa/gscreg.h</tt> + + <tag>CORTEX-I Frame Grabber</tag> Owner: core + + Submitted by: Paul S. LaFollette, Jr. ( + + Sources involved: <tt>isa/ctx.c</tt> <tt>isa/ctxreg.h</tt> + + + <tag>Video Spigot video capture card</tag> Owner: Jim + Lowe + + </descrip> + + <sect1><heading>Experimental features</heading> + + <p><descrip> + + <tag>UNIONFS and LFS</tag> The unionfs and LFS file + systems are known to be severely broken in FreeBSD + 2.0.5. This is in part due to old bugs that we + haven't had time to resolve yet and the need to + update these file systems to deal with the new VM + system. We hope to address these issues in a later + release of FreeBSD. + + <tag>iBCS2 Support</tag> FreeBSD now supports running + iBCS2 compatible binaries. Currently SCO UNIX 3.2.2 + and 3.2.4, and ISC 2.2 COFF are supported. The iBCS2 + emulator is in its early stages and has not been + extensively tested, but it is functional. Most of + SCO's 3.2.2 binaries work, as does an old + INFORMIX-2.10 for SCO. Further testing is nessesary + to complete this project. There is also work under + way for ELF and XOUT loaders, and most of the svr4 + syscall wrappers are written. + + Owner: Soren Schmidt (sos) and Sean Eric Fagan (sef) + + Sources involved: <tt>sys/i386/ibcs2/*</tt> and misc + kernel changes. + + </descrip> +<!-- + <sect1><heading>Reporting problems, making suggestions, submitting code</heading> + + <p>Your suggestions, bug reports and contributions of code + are always valued - please do not hesitate to report any + problems you may find (preferably with a fix attached if + you can!). + + The preferred method to submit bug reports from a machine + with internet mail connectivity is to use the send-pr + command. Bug reports will be dutifully filed by our + faithful bugfiler program and you can be sure that we'll + do our best to respond to all reported bugs as soon as + possible. + + If, for some reason, you are unable to use the send-pr + command to submit a bug report, you can try to send it + to: <tscreen>bugs@FreeBSD.org</tscreen> Otherwise, for + any questions or suggestions, please send mail to: + <tscreen>questions@FreeBSD.org</tscreen> + + Additionally, being a volunteer effort, we are always + happy to have extra hands willing to help - there are + already far more enhancements to be done than we can ever + manage to do by ourselves! To contact us on technical + matters, or with offers of help, you may send mail to: + <tscreen>hackers@FreeBSD.org</tscreen> + + Since these mailing lists can experience significant + amounts of traffic, if you have slow or expensive mail + access and you are only interested in keeping up with + significant FreeBSD events, you may find it preferable to + subscribe to: <tscreen>announce@FreeBSD.org</tscreen> + + All but the freebsd-bugs groups can be freely joined by + anyone wishing to do so. Send mail to + MajorDomo@FreeBSD.org and include the keyword `help' on a + line by itself somewhere in the body of the message. + This will give you more information on joining the + various lists, accessing archives, etc. There are a + number of mailing lists targeted at special interest + groups not mentioned here, so send mail to majordomo and + ask about them! + +--> diff --git a/share/doc/handbook/userppp.sgml b/share/doc/handbook/userppp.sgml new file mode 100644 index 0000000000000..cd1c50cdc66db --- /dev/null +++ b/share/doc/handbook/userppp.sgml @@ -0,0 +1,360 @@ +<!-- $Id: userppp.sgml,v 1.2 1995/08/19 22:16:06 jfieber Exp $ --> +<!-- The FreeBSD Documentation Project --> + +<sect>Setting up user PPP<label id="userppp"> + +<p><em>Contributed by &a.nik;<newline> +28 July 1995</em>. + +<!-- This FAQ/HowTo is intended to get you up and running with + iijppp, also known as the <em>user level ppp</em> for FreeBSD 2.0.5 + (and above). + + I hope this document turns into a collaborative effort, largely + because I am not really much of an authority on PPP. I've got + it working, and want to pass on details of what I did so that + other people can get it working. But I'm not 100% clear on some + details, so I hope that by writing this and haveing others + flesh out some of the information I'm going to learn something + as well. +--> + + <p>User PPP was intruduced to FreeBSD in release 2.0.5 as an + addition to the exisiting kernel implementation of PPP. So, + what is different about this new PPP that warrants its + addition? To quote from the manual page: + +<quote> + This is a user process PPP software package. Normally, PPP is + implemented as a part of the kernel (e.g. as managed by pppd) and + it's thus somewhat hard to debug and/or modify its behavior. However, + in this implementation PPP is done as a user process with the help of + the tunnel device driver (tun). +</quote> + + In essence, this means that rather than running a PPP daemon, the ppp + program can be run as and when desired. No PPP interface needs to be + compiled into the kernel, as the program can use the generic tunnel + device to to get data into and out of the kernel. + + From here on out, user ppp will be referred to as simply as ppp unless a + distinction need to be made be it and any other PPP client/server software. + Unless otherwise stated, all commands in this section should be + executed as root. + + Parts in this section marked with an asterisk (*) are + incomplete. Comments and suggestions are appreciated and + should be submitted to &a.nik;. + Thanks to Rob Snow <rsnow@txdirect.net> who proved to be a mine of + useful information when I was first experimenting with user ppp. + +<sect1><heading>Before you start</heading> + +<p>This document assumes you're in roughly this position: + + You have an account with an Internet Service Provider (ISP) which lets you + use PPP. Further, you have a modem (or other device) connected and + configured correctly which allows you to connect to your ISP. + + You are going to need the following information to hand: + +<itemize> + <item>IP address of your ISP's gateway + + <item>Your ISP's netmask setting + + <item>IP adresses of one or more nameservers + + <item>If your ISP allocates you a static IP address and/or hostname then + you will need that as well. If not, you will need to know from what + range of IP addresses your allocated IP address will fall in. +</itemize> + + If you do not have any of this information then contact your ISP and make + sure they provide it to you. + + As well as this, you may need the files required to recompile + your kernel. Check <ref id="kernelconfig" name="Kernel + Configuration"> for more information on how to acquire these. + + In addition, I've assumed that because your connection to the Internet is + not full time you are not running a name server (<tt>named(8)</tt>). + +<sect1><heading>Building a ppp ready kernel</heading> + +<p>As the description states, ``ppp'' uses the kernel ``tun'' device. It is + necessary to make sure that your kernel has support for this device compiled + in. + + To check this, go to your kernel compile directory (probably /sys/i386/conf) + and examine your kernel configuration file. It needs to have the line +<tscreen><verb> +pseudo-device tun 1 +</verb></tscreen> + in it somewhere. The stock GENERIC kernel has this as standard, so if you + have not installed a custom kernel you don't have to change anything. + If your kernel configuration file does not have this line in it then you + should add the line, re-compile and then re-install the kernel. Boot from + this new kernel. + +<sect1><heading>Check the tun device</heading> + +<p>My experiences with ppp have only been with one ``tun'' device (tun0). If + you have used more (i.e., a number other than `1' in the pseudo-device line + in the kernel configuration file) then alter all references to ``tun0'' + below to reflect whichever device number you are using. + + The easiest way to make sure that the tun0 device is configured correctly is + to re-make it. To this end, execute the following commands, +<tscreen><verb> +# cd /dev +# ./MAKEDEV tun0 +</verb></tscreen> + +<sect1><heading>PPP Configuration</heading> + +<p>The meat of the problem. + + Confusingly, it appears that both user ppp and pppd (the kernel level + implementation of PPP) both assume configuration files kept in + /etc/ppp. However, the sample configuration files provided are good for + user ppp, so keep them around for reference. The easiest way to do this is, +<tscreen><verb> +# cd /etc +# mv ppp ppp.orig +# mkdir ppp +</verb></tscreen> + Configuring ppp requires that you edit somewhere between one and three + files, depending on your requirements. What you put in them depends to some + extent on whether your ISP allocates IP addresses statically (i.e., you get + given one IP address, and always use that one) or dynamically (i.e., your IP + address can be different during different PPP sessions). + + However, there are a few things that you should do first, regardless of + whether you are using static or dynamic IP addresses. + + +<sect2><heading>Configure the resolver(5)</heading> + +<p>The resolver is the part of the networking system that turns IP addresses + into hostnames. It can be configured to look for maps that describe IP to + hostname mappings in one of two places. + + The first is a file called /etc/hosts (``hosts'' in section 5 of the + manual). The second is the Internet Domain Name Service, a distributed + data base, the discussion of which is beyond the realm of this document. + + The resolver is a set of system calls that do the mappings, + and you have to tell them where to get their information + from. You do this by editing the file /etc/host.conf. Do + <bf>not</bf> call this file /etc/hosts.conf (note the extra + ``s'') as the results can be confusing. + + This file should contain the following two lines, +<tscreen><verb> +hosts +bind +</verb></tscreen> + which instruct the resolver to look in the file /etc/hosts first, and + then to consult the DNS if the name was not found in the /etc/hosts file. + + It's probably a good idea to make sure you are not running the ``named'' + service. Check your /etc/sysconfig file for the line that refers to + ``namedflags'', and make sure the line reads +<tscreen><verb> +namedflags="NO" +</verb></tscreen> + +<sect2><heading>Create the /etc/hosts(5) file</heading> + +<p>This file should contain the IP addresses and names of machines on your + network. At a bare minimum it should contain entries for the machine + which will be running ppp. Assuming that you're machine is called + foo.bar.com with the IP address 10.0.0.1, /etc/hosts should contain +<tscreen><verb> +127.0.0.0 localhost +10.0.0.1 foo.bar.com foo +</verb></tscreen> + The first line defines the alias ``localhost'' as a synonym for the + current machine. Regardless of your own IP address, the IP address for + this line should always be 127.0.0.1. The second line maps the name + ``foo.bar.com'' (and the shorthand ``foo'') to the IP address 10.0.0.1. + + If your provider allocates you a static IP address then use this in place + of 10.0.0.1. + + <!-- XXX <em>(* What should they do if they are + allocated an IP address dynamically?)</em> --> + +<sect2><heading>Create the /etc/resolv.conf file</heading> + +<p>/etc/resolv.conf contains some extra information required when you are + not running a nameserver. It points the resolver routines at real + nameservers, and specifies some other information. + + At the very least, /etc/resolv.conf should contain one line with a + nameserver which can be queried. You should enter this as an IP + address. My /etc/resolv.conf contains +<tscreen><verb> +nameserver 158.152.1.193 +nameserver 158.152.1.65 +</verb></tscreen> + Which are Demon Internet's two nameservers. Add as many ``nameserver'' + lines as your ISP provides nameservers. + +<sect1><heading>PPP and static IP addresses</heading> + +<p>Probably the easiest to configure for. You will need to create three files + in the /etc/ppp directory. + + The first of these is ppp.conf. It should look similar to the example + below. Note that lines that end in a ``:'' start in column 1, all other + lines should be indented as shown. + + /etc/ppp/ppp.conf +<tscreen><verb> +1 default: +2 set device /dev/cuaa0 +3 set speed 9600 +4 disable lqr +5 deny lqr +6 set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" ATE1Q0 OK-AT-OK +\\dATDT\\T TIMEOUT 40 CONNECT" +7 provider: +8 set phone 01234567890 +9 set login "TIMEOUT 10 gin:-BREAK-gin: foo word: bar col: ppp" +10 set timeout 120 +11 set ifaddr x.x.x.x y.y.y.y +</verb></tscreen> + Don't include the line numbers, they're just for this discussion. + +<descrip> +<tag/Line 1:/ Identifies the default entry. Commands in this entry are + executed automatically when ppp is run. + +<tag/Line 2:/ Identifies the device that has the modem hanging from it. + COM1: is /dev/cuaa0 and COM2: is /dev/cuaa1 + +<tag/Line 3:/ Sets the speed you want to connect at. + +<tag/* Lines 4 and 5:/ Don't know exactly what effect these lines have + +<tag/Line 6:/ Dial string commands. user ppp uses the chat(8) language. Check + the manual page for information on the features of this + language. + +<tag/Line 7:/ Identifies an entry for a provider called ``provider''. + +<tag/Line 8:/ Sets the phone number for this provider. Don't include any + spaces in the phone number. + +<tag/Line 9:/ Set's the login string sequence. In this example, the string is + for a service who's login session looks like +<tscreen><verb> +J. Random Provider +login: foo +password: bar +protocol: ppp +</verb></tscreen> + You will need to alter this script to suit your own needs. It is + written in the chat(8) language. + +<tag/Line 10:/ Sets the default timeout (in seconds) for the connection. So + the connectioned will be closed automatically after 120 seconds + of inactivity. + +<tag/Line 11:/ Sets the interface addresses. The string x.x.x.x should be + replaced by the IP address that your provider allocates you. The + string y.y.y.y should be replaced by the IP address that your + ISP indicated for their gateway. +</descrip> + + Now you have to edit the file /etc/ppp/ppp.linkup: +<tscreen><verb> +x.x.x.x: + add 0 0 HISADDR +</verb></tscreen> + Replace x.x.x.x with your IP address as before. This file is used to + automatically add a default route from your ISP (who's address is + automatically inserted with the HISADDR macro) to you. + + Finally, you can create the file /etc/ppp/ppp.secret, which sets some + passwords to prevent people messing around with ppp on your system. You + may or may not want to do this, depending on how many people have access + to your ppp system. + +<sect1><heading>PPP and Dynamic IP configuration</heading> + +<!-- XXX --> + <p>If you service provider does not assign static IP numbers, + <tt>ppp</tt> can be configured to negotiate the local address. This is + done by specifying 0 as the local IP address: +<tscreen><verb> +set ifaddr 0 0 +</verb></tscreen> + See the <tt>ppp(8)</tt> manual page for more detailed information. + +<sect1><heading>Final system configuration</heading> + +<p>You now have PPP configured, but there's a few more things to do before + it's ready to work. They all involve editing the /etc/sysconfig file. + + Working from the top down in this file, make sure the ``hostname='' line + is set, e.g., +<tscreen><verb> +hostname=foo.bar.com +</verb></tscreen> + Look for the network_interfaces variable, and make sure the tun0 device is + added to the list. My line looks like +<tscreen><verb> +network_interfaces="lo0 tun0 ep0" +</verb></tscreen> + but I have an ethernet card (ep0) to configure as well. + + Now add an ifconfig line for the tun0 device. It should look something + like +<tscreen><verb> +ifconfig_tun0="inet foo.bar.com y.y.y.y netmask 0xffffffff" +</verb></tscreen> + as before, change ``foo.bar.com'' to be your hostname, y.y.y.y is the IP + address of your providers gateway, and 0xffffffff is the netmask they + provided you with (in hexadecimal). Two common values for the netmask are +<tscreen><verb> +255.255.255.255 = 0xffffffff +255.255.255.0 = 0xffffff00 +</verb></tscreen> + Set the routed flags to ``-s'' with the line +<tscreen><verb> +routedflags=-s +</verb></tscreen> + It's probably worth your while ensuring that the ``sendmail_flags'' line + does not include the ``-q'' option, otherwise sendmail will attempt to do + a network lookup every now and then, possibly causing your machine to dial + out. My sendmail line looks like +<tscreen><verb> +sendmail_flags="-bd" +</verb></tscreen> + The upshot of this is that I must force sendmail to re-examine the + mailqueue whenever I have the PPP link up, by typing +<tscreen><verb> +# /usr/sbin/sendmail -q +</verb></tscreen> + That should be about all you need to do to get PPP working with a static + IP address. All that's left is to reboot the machine. During startup the + tun0 device should be detected, and two lines like the following should be + printed, +<tscreen><verb> +tun0: flags=51<UP,POINTOPOINT,RUNNING> mtu 1500 +inet x.x.x.x --> y.y.y.y netmask 0xffffffff +</verb></tscreen> + At this point, it should all be working. You can now either type +<tscreen><verb> +# ppp +</verb></tscreen> + and then ``dial provider'' to start the PPP session, or, if you want ppp + to establish sessions automatically when there is outbound traffic, type +<tscreen><verb> +# ppp -auto provider +</verb></tscreen> + This line could be added to your /etc/rc.local file. + diff --git a/share/examples/find_interface/Makefile b/share/examples/find_interface/Makefile new file mode 100644 index 0000000000000..fcc330cc19496 --- /dev/null +++ b/share/examples/find_interface/Makefile @@ -0,0 +1,6 @@ +# $Id$ + +PROG= find_interface +NOMAN= + +.include <bsd.prog.mk> diff --git a/share/examples/find_interface/README b/share/examples/find_interface/README new file mode 100644 index 0000000000000..4df4399cdbc7b --- /dev/null +++ b/share/examples/find_interface/README @@ -0,0 +1,9 @@ +This is a simple program which demonstrates how to query the kernel +routing mechanism using only a UDP socket. Pass it a hostname on +the command line (sorry, it doesn't parse dotted decimal) and it will +print out an IP address which names the interface over which UDP +packets intended for that destination would be sent. +A more sophisticated program might use the list obtained from SIOCGIFCONF +to match the address with an interface name, but applications programmers +much more often need to know the address of the interface rather than +the name. diff --git a/share/syscons/keymaps/spanish.iso.kbd b/share/syscons/keymaps/spanish.iso.kbd new file mode 100644 index 0000000000000..584941a5311ff --- /dev/null +++ b/share/syscons/keymaps/spanish.iso.kbd @@ -0,0 +1,109 @@ +# alt +# scan cntrl alt alt cntrl lock +# code base shift cntrl shift alt shift cntrl shift state +# ------------------------------------------------------------------ + 000 nop nop nop nop nop nop nop nop O + 001 esc esc esc esc esc esc esc esc O + 002 '1' '!' nop nop '|' '|' nop nop O + 003 '2' '"' nul nul '@' '@' nul nul O + 004 '3' 183 nop nop '#' '#' nop nop O + 005 '4' '$' nop nop '4' '4' nop nop O + 006 '5' '%' nop nop '5' '5' nop nop O + 007 '6' '&' rs rs 172 172 rs rs O + 008 '7' '/' esc esc '7' '7' esc esc O + 009 '8' '(' nop nop '8' '8' nop nop O + 010 '9' ')' gs gs '8' '8' gs gs O + 011 '0' '=' nop nop '9' '9' nop nop O + 012 ''' '?' nop nop ''' ''' nop nop O + 013 161 191 nop nop ''' '`' nop nop O + 014 bs bs del del bs bs del del O + 015 ht btab nop nop ht btab nop nop O + 016 'q' 'Q' dc1 dc1 'q' 'Q' dc1 dc1 C + 017 'w' 'W' etb etb 'w' 'W' etb etb C + 018 'e' 'E' enq enq 233 201 enq enq C + 019 'r' 'R' dc2 dc2 'r' 'R' dc2 dc2 C + 020 't' 'T' dc4 dc4 't' 'T' dc4 dc4 C + 021 'y' 'Y' em em 'y' 'Y' sub sub C + 022 'u' 'U' nak nak 250 218 nak nak C + 023 'i' 'I' ht ht 237 205 ht ht C + 024 'o' 'O' si si 243 211 si si C + 025 'p' 'P' dle dle 'p' 'P' dle dle C + 026 '`' '^' esc esc '[' '[' esc esc C + 027 '+' '*' gs gs ']' '[' gs gs O + 028 cr cr nl nl cr cr nl nl O + 029 lctrl lctrl lctrl lctrl lctrl lctrl lctrl lctrl O + 030 'a' 'A' soh soh 225 193 soh soh C + 031 's' 'S' dc3 dc3 's' 'S' dc3 dc3 C + 032 'd' 'D' eot eot 'd' 'D' eot eot C + 033 'f' 'F' ack ack 'f' 'F' ack ack C + 034 'g' 'G' bel bel 'g' 'G' bel bel C + 035 'h' 'H' bs bs 'h' 'H' bs bs C + 036 'j' 'J' nl nl 'j' 'J' nl nl C + 037 'k' 'K' vt vt 'k' 'K' vt vt C + 038 'l' 'L' ff ff 'l' 'L' ff ff C + 039 241 209 nop nop '~' nop nop nop C + 040 252 220 nop nop '{' 220 nop nop C + 041 186 170 fs fs '\' '\' fs fs O + 042 lshift lshift lshift lshift lshift lshift lshift lshift O + 043 231 199 rs rs '}' '}' rs rs O + 044 'z' 'Z' sub sub 'z' 'Z' em em C + 045 'x' 'X' can can 'x' 'X' can can C + 046 'c' 'C' etx etx 'c' 'C' etx etx C + 047 'v' 'V' syn syn 'v' 'V' syn syn C + 048 'b' 'B' stx stx 'b' 'B' stx stx C + 049 'n' 'N' so so 'n' 'N' so so C + 050 'm' 'M' cr cr 'm' 'M' cr cr C + 051 ',' ';' nop nop ',' ';' nop nop O + 052 '.' ':' nop nop '.' ':' nop nop O + 053 '-' '_' ns ns '-' '_' ns ns O + 054 rshift rshift rshift rshift rshift rshift rshift rshift O + 055 '*' '*' nscr nscr '*' '*' nscr nscr O + 056 lalt lalt lalt lalt lalt lalt lalt lalt O + 057 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' O + 058 clock clock clock clock clock clock clock clock O + 059 fkey01 fkey13 fkey25 fkey37 scr01 scr11 scr01 scr11 O + 060 fkey02 fkey14 fkey26 fkey38 scr02 scr12 scr02 scr12 O + 061 fkey03 fkey15 fkey27 fkey39 scr03 scr13 scr03 scr13 O + 062 fkey04 fkey16 fkey28 fkey40 scr04 scr14 scr04 scr14 O + 063 fkey05 fkey17 fkey29 fkey41 scr05 scr15 scr05 scr15 O + 064 fkey06 fkey18 fkey30 fkey42 scr06 scr16 scr06 scr16 O + 065 fkey07 fkey19 fkey31 fkey43 scr07 scr07 scr07 scr07 O + 066 fkey08 fkey20 fkey32 fkey44 scr08 scr08 scr08 scr08 O + 067 fkey09 fkey21 fkey33 fkey45 scr09 scr09 scr09 scr09 O + 068 fkey10 fkey22 fkey34 fkey46 scr10 scr10 scr10 scr10 O + 069 nlock nlock dc3 dc3 nlock nlock dc3 dc3 O + 070 slock slock del del slock slock del del O + 071 fkey49 '7' '7' '7' '7' '7' '7' '7' N + 072 fkey50 '8' '8' '8' '8' '8' '8' '8' N + 073 fkey51 '9' '9' '9' '9' '9' '9' '9' N + 074 fkey52 '-' ns ns '-' '-' '-' '-' N + 075 fkey53 '4' '4' '4' '4' '4' '4' '4' N + 076 fkey54 '5' '5' '5' '5' '5' '5' '5' N + 077 fkey55 '6' rs rs '6' '6' '6' '6' N + 078 fkey56 '+' '+' '+' '+' '+' '+' '+' N + 079 fkey57 '1' '1' '1' '1' '1' '1' '1' N + 080 fkey58 '2' '2' '2' '2' '2' '2' '2' N + 081 fkey59 '3' '3' '3' '3' '3' '3' '3' N + 082 fkey60 '0' '0' '0' '0' '0' '0' '0' N + 083 del '.' del del del del del del N + 084 ns ns ns ns ns ns ns ns O + 085 nop nop nop nop nop nop nop nop O + 086 '<' '>' fs fs '\' '>' fs fs O + 087 fkey11 fkey23 fkey35 fkey47 scr11 scr11 scr11 scr11 O + 088 fkey12 fkey24 fkey36 fkey48 scr12 scr12 scr12 scr12 O + 089 scr03 scr03 scr03 scr03 scr03 scr03 scr03 scr03 N + 090 rctrl rctrl rctrl rctrl rctrl rctrl rctrl rctrl O + 091 '/' '/' '/' '/' '/' '/' '/' '/' N + 092 '*' '*' '*' '*' '*' '*' '*' '*' N + 093 ralt ralt ralt ralt ralt ralt ralt ralt O + 094 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 fkey49 O + 095 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 fkey50 O + 096 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 fkey51 O + 097 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 fkey53 O + 098 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 fkey55 O + 099 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 fkey57 O + 100 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 fkey58 O + 101 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 fkey59 O + 102 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 fkey60 O + 103 fkey54 fkey54 fkey54 fkey54 fkey54 fkey54 boot fkey54 O + 104 slock slock slock slock slock slock slock slock O diff --git a/sys/i386/include/ioctl_meteor.h b/sys/i386/include/ioctl_meteor.h new file mode 100644 index 0000000000000..e1fed36e5985f --- /dev/null +++ b/sys/i386/include/ioctl_meteor.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1995 Mark Tinguely and Jim Lowe + * 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 Mark Tinguely and Jim Lowe + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ +/* + * ioctl constants for Matrox Meteor Capture card. + */ + +#ifndef _MACHINE_IOCTL_METEOR_H +#define _MACHINE_IOCTL_METEOR_H + +#include <sys/ioctl.h> + +struct meteor_capframe { + short command; /* see below for valid METEORCAPFRM commands */ + short signal; /* signal to send to the user program, + when a buffer is full */ + short lowat; /* start transfer if < this number */ + short hiwat; /* stop transfer if > this number */ +} ; + +/* structure for METEOR[GS]ETGEO - get/set geometry */ +struct meteor_geomet { + u_short rows; + u_short columns; + u_short frames; + u_long oformat; +} ; + +/* structure for METEORGCOUNT-get count of frames, fifo errors and dma errors */ +struct meteor_counts { + u_long fifo_errors; /* count of fifo errors since open */ + u_long dma_errors; /* count of dma errors since open */ + u_long frames_captured; /* count of frames captured since open */ +} ; + +#define METEORCAPTUR _IOW('x', 1, int) /* capture a frame */ +#define METEORCAPFRM _IOW('x', 2, struct meteor_capframe) /* sync capture */ +#define METEORSETGEO _IOW('x', 3, struct meteor_geomet) /* set geometry */ +#define METEORGETGEO _IOR('x', 4, struct meteor_geomet) /* get geometry */ +#define METEORSTATUS _IOR('x', 5, unsigned short) /* get status */ +#define METEORSHUE _IOW('x', 6, signed char) /* set hue */ +#define METEORGHUE _IOR('x', 6, signed char) /* get hue */ +#define METEORSFMT _IOW('x', 7, unsigned long) /* set format */ +#define METEORGFMT _IOR('x', 7, unsigned long) /* get format */ +#define METEORSINPUT _IOW('x', 8, unsigned long) /* set input dev */ +#define METEORGINPUT _IOR('x', 8, unsigned long) /* get input dev */ +#define METEORSCHCV _IOW('x', 9, unsigned char) /* set uv gain */ +#define METEORGCHCV _IOR('x', 9, unsigned char) /* get uv gain */ +#define METEORSCOUNT _IOW('x',10, struct meteor_counts) +#define METEORGCOUNT _IOR('x',10, struct meteor_counts) + +#define METEOR_STATUS_ID_MASK 0xf000 /* ID of 7196 */ +#define METEOR_STATUS_DIR 0x0800 /* Direction of Expansion port YUV */ +#define METEOR_STATUS_OEF 0x0200 /* Field detected: Even/Odd */ +#define METEOR_STATUS_SVP 0x0100 /* State of VRAM Port:inactive/active */ +#define METEOR_STATUS_STTC 0x0080 /* Time Constant: TV/VCR */ +#define METEOR_STATUS_HCLK 0x0040 /* Horiz PLL: locked/unlocked */ +#define METEOR_STATUS_FIDT 0x0020 /* Field detect: 50/60hz */ +#define METEOR_STATUS_ALTD 0x0002 /* Line alt: no line alt/line alt */ +#define METEOR_STATUS_CODE 0x0001 /* Colour info: no colour/colour */ + + /* METEORCAPTUR capture options */ +#define METEOR_CAP_SINGLE 0x0001 /* capture one frame */ +#define METEOR_CAP_CONTINOUS 0x0002 /* contiuously capture */ +#define METEOR_CAP_STOP_CONT 0x0004 /* stop the continous capture */ + + /* METEORCAPFRM capture commands */ +#define METEOR_CAP_N_FRAMES 0x0001 /* capture N frames */ +#define METEOR_CAP_STOP_FRAMES 0x0002 /* stop capture N frames */ + + /* valid video input formats: */ +#define METEOR_FMT_NTSC 0x00100 /* NTSC -- initialized default */ +#define METEOR_FMT_PAL 0x00200 /* PAL */ +#define METEOR_FMT_SECAM 0x00400 /* SECAM */ +#define METEOR_FMT_AUTOMODE 0x00800 /* auto-mode */ +#define METEOR_INPUT_DEV0 0x01000 /* camera input 0 -- default */ +#define METEOR_INPUT_DEV_RCA METEOR_GEO_DEV0 +#define METEOR_INPUT_DEV1 0x02000 /* camera input 1 */ +#define METEOR_INPUT_DEV2 0x04000 /* camera input 2 */ +#define METEOR_INPUT_DEV3 0x08000 /* camera input 3 */ +#define METEOR_INPUT_DEV_SVIDEO METEOR_GEO_DEV3 + + /* valid video output formats: */ +#define METEOR_GEO_RGB16 0x10000 /* packed -- initialized default */ +#define METEOR_GEO_RGB24 0x20000 /* RBG 24 bits packed */ + /* internally stored in 32 bits */ +#define METEOR_GEO_YUV_PACKED 0x40000 /* 4-2-2 YUV 16 bits packed */ +#define METEOR_GEO_YUV_PLANER 0x80000 /* 4-2-2 YUV 16 bits planer */ + + /* following structure is used to coordinate the syncronous */ + +struct meteor_mem { + /* kernel write only */ + int frame_size; /* row*columns*depth */ + unsigned num_bufs; /* number of frames in buffer (1-32) */ + /* user and kernel change these */ + int signal; /* signal raised to the user program, + on completion of frame capture */ + int lowat; /* kernel starts capture if < this number */ + int hiwat; /* kernel stops capture if > this number. + hiwat <= numbufs */ + unsigned active; /* bit mask of active frame buffers + kernel sets, user clears */ + int num_active_bufs; /* count of active frame buffer + kernel increments, user decrements */ + + /* reference to mmapped data */ + caddr_t buf; /* The real space (virtual addr) */ +} ; + +#endif /* ifndef _MACHINE_IOCTL_METEOR_H */ diff --git a/sys/i386/isa/cyreg.h b/sys/i386/isa/cyreg.h new file mode 100644 index 0000000000000..8df7294c9a944 --- /dev/null +++ b/sys/i386/isa/cyreg.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 1995 Bruce Evans. + * 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. Neither the name of the author nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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. + * + * $Id: $ + */ + +/* + * Definitions for Cyclades Cyclom-Y serial boards. + */ + +#define CY8_SVCACKR 0x100 +#define CY8_SVCACKT 0x200 +#define CY8_SVCACKM 0x300 +#define CY_CD1400_MEMSIZE 0x400 +#define CY16_RESET 0x1400 +#define CY_CLEAR_INTR 0x1800 /* intr ack address */ + +#define CY_MAX_CD1400s 4 /* for Cyclom-16Y */ + +#define CY_CLOCK 25000000 /* baud rate clock */ + +#ifdef CyDebug +#define cd_inb(iobase, reg) (++cd_inbs, *((iobase) + 2 * (reg))) +#define cy_inb(iobase, reg) (++cy_inbs, *((iobase) + (reg))) +#define cd_outb(iobase, reg, val) (++cd_outbs, (void)(*((iobase) + 2 * (reg)) = (val))) +#define cy_outb(iobase, reg, val) (++cy_outbs, (void)(*((iobase) + (reg)) = (val))) +#else +#define cd_inb(iobase, reg) (*((iobase) + 2 * (reg))) +#define cy_inb(iobase, reg) (*((iobase) + (reg))) +#define cd_outb(iobase, reg, val) ((void)(*((iobase) + 2 * (reg)) = (val))) +#define cy_outb(iobase, reg, val) ((void)(*((iobase) + (reg)) = (val))) +#endif diff --git a/sys/i386/isa/si_code.c b/sys/i386/isa/si_code.c new file mode 100644 index 0000000000000..e1282eabf9827 --- /dev/null +++ b/sys/i386/isa/si_code.c @@ -0,0 +1,804 @@ +/* + * Device driver for Specialix range (SLXOS) of serial line multiplexors. + * + * Copyright (C) 1988, 1992, Specialix International, + * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> + * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> + * + * Downloadable code for Z280 + * Ported from BSDI version to FreeBSD by Peter Wemm. + * + * 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 + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, 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 Andy Rutter of + * Advanced Methods and Tools Ltd. based on original information + * from Specialix International. + * 4. Neither the name of Advanced Methods and Tools, nor Specialix + * International may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``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 AUTHORS BE LIABLE. + * + * $Id$ + */ + +/* +** @(#)download.c 1.20 +** SLXOS download code processed on Thu Aug 5 17:53:28 1993 +** (C)1992 Specialix International plc +** All rights reserved. +*/ + +unsigned char +si_download[] = +{ + 0x0,0xc3,0x86,0x0,0x2,0x0,0x8,0x1,0x0,0x0, + 0x7e,0x18,0x0,0x0,0x82,0x18,0x0,0x0,0xe4,0x1a,0x0, + 0x0,0xc7,0x4,0x2,0x0,0x8,0x1,0x2,0x0,0x8,0x1, + 0x2,0x0,0x8,0x1,0x2,0x0,0x8,0x1,0x2,0x0,0x8, + 0x1,0x0,0x0,0xe1,0xf,0x0,0x0,0x0,0x10,0x2,0x0, + 0x8,0x1,0x2,0x0,0x8,0x1,0x0,0x0,0x0,0x0,0x20, + 0x0,0x0,0x1,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x3a,0x47,0x0,0xfe,0x0,0xc2,0x8,0x1,0xdd,0x3e, + 0x48,0x0,0x1,0x31,0xbf,0x0,0xc3,0x1e,0x13,0xff,0xff, + 0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0x3a,0x41,0x0,0xfe,0x0,0xc2, + 0x1e,0x13,0x21,0x0,0x8,0xe,0xf0,0xed,0xbf,0x0,0x0, + 0x0,0x21,0x40,0x0,0xe,0x12,0xed,0x6e,0x3a,0x92,0x0, + 0xfe,0x1,0x20,0x5,0x21,0xc4,0x5,0x18,0x3,0x21,0x82, + 0x18,0x7d,0xe6,0xf0,0x6f,0x3e,0x0,0x46,0x23,0x3d,0xfe, + 0x0,0x20,0xf9,0x21,0x80,0x0,0xe,0x12,0xed,0x6e,0xdd, + 0x3e,0x47,0x0,0x1,0xcd,0x15,0x1,0x0,0x18,0xfe,0x0, + 0x0,0xdd,0xd1,0x6,0x1,0xed,0x55,0xdd,0x3e,0x0,0x0, + 0xfe,0x76,0xc9,0xcd,0xf9,0x1,0xfe,0x1,0x20,0x3,0xcd, + 0x8b,0x4,0xc9,0xe0,0x81,0x80,0x80,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8c,0x0,0xf0, + 0xd0,0xf0,0xd0,0x0,0xc0,0x0,0x0,0xf0,0xd0,0xf0,0xd0, + 0x0,0xc0,0x0,0x0,0x21,0xd,0x0,0xe,0xff,0xed,0x6e, + 0x21,0xf8,0x2f,0x11,0xe,0x80,0x1,0x8,0x0,0xed,0xb0, + 0x2a,0x43,0x0,0xe,0xff,0xed,0x6e,0xdd,0x3e,0x16,0x80, + 0x0,0xc9,0x79,0xfe,0x0,0x28,0x2a,0xed,0x2d,0xa0,0xff, + 0xed,0x2a,0x0,0x0,0x3a,0x2f,0x1,0xfe,0x40,0x20,0x7, + 0xfd,0xed,0xf6,0xa0,0x18,0x18,0x5,0xfd,0xed,0xf6,0xa0, + 0x2,0xdd,0x2a,0x24,0x1,0xed,0x2d,0x0,0x0,0xe5,0xdd, + 0xe1,0xdd,0x22,0x24,0x1,0x78,0x32,0x2f,0x1,0xed,0x2a, + 0x0,0x0,0xdd,0x1,0x0,0x0,0xdd,0x73,0x8,0xdd,0x36, + 0x1c,0x0,0xdd,0x36,0x1d,0x0,0x7b,0xe6,0xf,0xdd,0x77, + 0x2,0xdd,0x71,0x3,0xfd,0xed,0x2d,0x6,0x0,0x7b,0xe6, + 0xe0,0xfe,0x0,0x20,0x8,0xdd,0x36,0x4,0x0,0xfd,0x36, + 0x40,0xff,0xdd,0xe5,0xfd,0x7e,0x7f,0xdd,0x77,0x1e,0x3e, + 0x8,0xed,0x2a,0xa,0x0,0xdd,0xed,0x2a,0x60,0x1,0xdd, + 0xe5,0xdd,0xc1,0x3d,0x28,0xc,0xdd,0xed,0x2a,0x0,0x3, + 0xfd,0xed,0xf6,0x2,0x0,0x18,0xed,0xdd,0xe1,0xed,0x2a, + 0x0,0x0,0xfd,0xed,0xf6,0x60,0x1,0xe5,0xdd,0xe1,0xc9, + 0x21,0x40,0x0,0x5e,0xdd,0x11,0x2,0x80,0xff,0xff,0xdd, + 0x3e,0x6,0x80,0x1,0xdd,0x3e,0x82,0x80,0x0,0xdd,0x21, + 0x80,0x80,0xdd,0x22,0x24,0x1,0xfd,0x21,0x0,0x70,0xfd, + 0x22,0x28,0x1,0xe,0x0,0x16,0x1,0xe5,0x2a,0x30,0x1, + 0x7e,0xdd,0x13,0x30,0x1,0xe1,0xfe,0xff,0xca,0x78,0x3, + 0x5f,0xfe,0x4,0x28,0x10,0xfe,0x24,0x28,0xc,0x6,0x8, + 0xdd,0x3e,0x2e,0x1,0x8,0xcd,0x61,0x1,0x18,0xc,0x6, + 0x4,0xdd,0x3e,0x2e,0x1,0x4,0xcd,0x61,0x1,0x18,0x0, + 0x21,0xa0,0x2,0xdd,0xe,0x0,0x2b,0xfd,0xed,0xf7,0xa0, + 0xff,0x20,0xf5,0xfd,0xed,0x2d,0xa2,0xff,0xdd,0x36,0xc2, + 0xff,0x7b,0xe6,0xe0,0xdd,0x77,0xc4,0xfe,0x20,0x28,0x31, + 0xed,0x32,0x0,0x0,0xcb,0x9d,0xfd,0x36,0x2,0xa,0xfd, + 0x1e,0x4,0x0,0xe0,0xfd,0x1e,0x5,0x0,0x0,0xfd,0x1e, + 0x6,0x0,0x0,0xfd,0x1e,0x7,0x0,0x2,0xfd,0x7b,0xe, + 0x0,0xfd,0x1e,0xd,0x0,0x0,0xfd,0x36,0x2,0x90,0xdd, + 0x36,0xa6,0x1,0x18,0x0,0xdd,0x36,0xae,0x10,0xdd,0x36, + 0xbf,0x1,0xdd,0x72,0xaf,0x2a,0x24,0x1,0xed,0x2d,0xa4, + 0xff,0x3a,0x2e,0x1,0x90,0xdd,0x77,0xa7,0xfe,0x4,0xfa, + 0xd0,0x2,0xfd,0x7e,0x7f,0xe6,0xf0,0xcb,0x3f,0xcb,0x3f, + 0xcb,0x3f,0xcb,0x3f,0x18,0x5,0xfd,0x7e,0x7f,0xe6,0xf, + 0xdd,0x77,0xc4,0x21,0x32,0x1,0xc5,0x4f,0xe6,0x7,0xfe, + 0x5,0x20,0x17,0x78,0xfe,0x8,0x28,0x4,0xfe,0x4,0x20, + 0xe,0xdd,0x36,0xc7,0x1,0x3e,0x8,0x90,0xfd,0x77,0x7f, + 0xfd,0x36,0x4b,0x80,0x6,0x0,0xed,0xc6,0x7e,0xdd,0x77, + 0xc6,0xc1,0x5,0x20,0x23,0x2a,0x28,0x1,0xfd,0xed,0xf6, + 0x80,0x0,0x22,0x28,0x1,0xfd,0x2a,0x28,0x1,0x2a,0x20, + 0x1,0xed,0x2d,0xa0,0xff,0xed,0x2a,0x0,0x0,0xfd,0xed, + 0xf6,0x0,0x4,0xc,0xc3,0x1f,0x2,0xed,0x2a,0x0,0x0, + 0xfd,0xed,0xf6,0x0,0x3,0xed,0x2d,0xa0,0xff,0xe5,0xdd, + 0xe1,0xed,0x32,0x0,0x0,0x3a,0x2e,0x1,0xfe,0x8,0x20, + 0xf,0x7b,0xfe,0x28,0xca,0x51,0x2,0xfd,0xed,0xf6,0x8, + 0x0,0xcb,0x2,0x18,0x1f,0x7b,0xfe,0x24,0xca,0x51,0x2, + 0x78,0xfe,0x2,0x20,0x9,0xfd,0xed,0xf6,0x8,0x0,0xcb, + 0x2,0x18,0xb,0xfd,0xed,0xf6,0x18,0x0,0xcb,0x2,0xcb, + 0x2,0xcb,0x2,0xe5,0xfd,0xe1,0xc3,0x51,0x2,0xcd,0x42, + 0x1,0xdd,0x11,0x4,0x80,0x22,0x1,0xdd,0x3e,0x0,0x80, + 0x1,0x3e,0x1,0xc9,0xfd,0xed,0x2c,0xa2,0xff,0xcd,0x7f, + 0xe,0x18,0x5,0xfd,0xed,0x2c,0xa2,0xff,0xcd,0xd6,0xd, + 0x26,0x0,0xc3,0xf3,0x5,0xfd,0xed,0x2c,0xa2,0xff,0xcd, + 0x7f,0xe,0x26,0x0,0xc3,0xf3,0x5,0xfd,0xed,0x2c,0xa2, + 0xff,0xcd,0x3,0xe,0x26,0x0,0xc3,0xf3,0x5,0xfd,0xed, + 0x2c,0xa2,0xff,0xcd,0x20,0xe,0x26,0x0,0xc3,0xf3,0x5, + 0xfd,0xed,0x2c,0xa2,0xff,0xfd,0x36,0x2,0x60,0xdd,0x36, + 0xae,0x12,0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0,0xc3,0xf3, + 0x5,0xfd,0xed,0x2c,0xa2,0xff,0xfd,0x36,0x2,0x75,0xdd, + 0x36,0xae,0x0,0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0,0xc3, + 0xf3,0x5,0x26,0x0,0xc3,0xf3,0x5,0xfd,0xed,0x2c,0xa2, + 0xff,0xdd,0x7e,0xad,0xdd,0x77,0xac,0xdd,0x7e,0xb5,0xe6, + 0x10,0x28,0x25,0xed,0x32,0x0,0x0,0xcb,0x5d,0x28,0xa, + 0xcb,0x9d,0xfd,0x7b,0xd,0x0,0xcb,0x2f,0x18,0x6,0xfd, + 0x7b,0xd,0x0,0xcb,0x27,0x2f,0xe6,0x2,0x20,0x8,0xfd, + 0x36,0x2,0x30,0xfd,0x36,0x2,0x4,0xdd,0x7e,0xa8,0xe6, + 0x6,0xfe,0x6,0x20,0xe,0xdd,0xcb,0xa8,0x96,0xdd,0xcb, + 0xa9,0x4e,0x20,0x4,0xdd,0xcb,0xa3,0xa6,0xdd,0x36,0xae, + 0x0,0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0,0xc3,0xf3,0x5, + 0xfd,0xed,0x2c,0xa2,0xff,0xdd,0x7e,0xab,0xdd,0x77,0xaa, + 0xdd,0x36,0xae,0x0,0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0, + 0xc3,0xf3,0x5,0xdd,0xcb,0xa8,0x4e,0x28,0x8,0xdd,0xcb, + 0xa8,0xd6,0xdd,0xcb,0xa3,0xe6,0xdd,0x36,0xae,0x0,0xdd, + 0x3e,0xc5,0x5,0x1,0x26,0x0,0xc3,0xf3,0x5,0xdd,0x2a, + 0x20,0x1,0x21,0xfe,0x0,0xe,0x8,0xed,0x6e,0x3e,0x28, + 0xd3,0xe0,0x2a,0x2,0x80,0x1,0xe2,0x0,0xed,0xbf,0x3e, + 0xe0,0xd3,0xe1,0x3a,0x6,0x80,0x32,0xc4,0x4,0x21,0xff, + 0x0,0xe,0x8,0xed,0x6e,0x26,0x0,0x3a,0x93,0x0,0xfe, + 0x1,0xc2,0xf8,0x5,0xd9,0x26,0x0,0xd9,0xc3,0xc,0xd, + 0x0,0x0,0x0,0xdd,0xd1,0xc5,0x4,0xf5,0xc5,0xe5,0xdd, + 0xe5,0xfd,0xe5,0x3a,0x16,0x80,0xfe,0x1,0x20,0x8,0xcd, + 0x42,0x1,0xdd,0x3e,0xc5,0x5,0x1,0x3a,0x93,0x0,0xfe, + 0x1,0x28,0x2c,0xdd,0x21,0xe0,0x81,0x18,0x10,0xdd,0xed, + 0x2c,0xa0,0xff,0xed,0x2a,0x0,0x0,0xfd,0xed,0xf7,0xe0, + 0x81,0x28,0x16,0xdd,0x7e,0xae,0xfe,0x0,0x20,0xe9,0xfd, + 0xed,0x2c,0xa2,0xff,0xdd,0x46,0xa9,0xcb,0x68,0x28,0xdd, + 0xc3,0x74,0x8,0x21,0xfe,0x0,0xe,0x8,0xed,0x6e,0x2a, + 0x2,0x80,0x1,0xe2,0x0,0xed,0xbf,0x3e,0x0,0xd3,0xe1, + 0x3e,0xe0,0xd3,0xe1,0x3a,0x93,0x0,0xfe,0x1,0x28,0x3, + 0xed,0x7f,0x1,0xdd,0x13,0xa,0x80,0xdd,0x3c,0xc,0x80, + 0x3a,0xc5,0x5,0xfe,0x0,0x20,0xe,0x3a,0xc4,0x5,0xfe, + 0x0,0x28,0x27,0x3a,0xc4,0x4,0xfe,0x0,0x20,0x20,0xdd, + 0x3e,0x1,0xf0,0x1,0xdd,0x3e,0xc4,0x5,0x0,0x3a,0x8, + 0x80,0xfe,0x1,0x28,0xa,0xdd,0x3e,0xc,0x80,0x0,0xdd, + 0x3e,0x8,0x80,0x1,0xdd,0x3e,0xc5,0x5,0x0,0xf3,0x3a, + 0xc4,0x4,0xfe,0x0,0x20,0x6,0x3a,0x6,0x80,0x32,0xc4, + 0x4,0xdd,0x3d,0xc4,0x4,0x21,0xff,0x0,0xe,0x8,0xed, + 0x6e,0xfd,0xe1,0xdd,0xe1,0xe1,0xc1,0xf1,0xed,0x55,0xc6, + 0x5,0xa0,0x3,0x89,0x3,0x93,0x3,0xa0,0x3,0xad,0x3, + 0xc7,0x3,0xde,0x3,0xf5,0x3,0xf5,0x3,0xba,0x3,0x31, + 0x4,0xfa,0x3,0x56,0x4,0x6f,0x4,0xf5,0x3,0xf5,0x3, + 0xf5,0x3,0x1d,0x10,0xf1,0x10,0xf5,0x3,0xf5,0x3,0xbb, + 0x11,0x1d,0x10,0x0,0x0,0xfd,0xed,0x2c,0xa2,0xff,0xfd, + 0x4c,0xfd,0x5e,0x1,0xcb,0x61,0x20,0x38,0xcb,0x53,0x28, + 0x17,0xdd,0x6e,0xac,0xdd,0x7e,0xad,0x95,0x28,0xe,0xe6, + 0x3f,0xca,0x29,0x7,0xdd,0x79,0xfd,0x77,0x3,0x2c,0xdd, + 0x75,0xac,0xcb,0x43,0x20,0x52,0xdd,0x7e,0xa1,0xdd,0x67, + 0xdd,0x7e,0xae,0xfe,0x0,0x28,0xc7,0xfe,0x10,0x28,0xf0, + 0x6f,0xfd,0xed,0xf6,0x94,0x5,0xed,0x26,0xe9,0xdd,0x4e, + 0xa8,0xdd,0x46,0xa9,0xcb,0x53,0x28,0x25,0xcb,0x71,0xc2, + 0xde,0x6,0xcb,0x51,0x20,0x1c,0xdd,0x6e,0xac,0xdd,0x7e, + 0xad,0x95,0x28,0x13,0xe6,0x3f,0xca,0x2,0x7,0xdd,0x79, + 0xfe,0xa,0xca,0xe5,0x6,0xfd,0x77,0x3,0x2c,0xdd,0x75, + 0xac,0xcb,0x43,0x20,0xc,0xcb,0x61,0x20,0x6a,0x18,0xae, + 0xdd,0x4e,0xa8,0xdd,0x46,0xa9,0xfd,0x36,0x2,0x40,0xfd, + 0x7e,0x3,0xdd,0xa6,0xc3,0xfe,0x0,0xca,0x12,0x8,0xcb, + 0x49,0x20,0x34,0x8,0xdd,0x6e,0xaa,0x7d,0x3c,0xdd,0x96, + 0xab,0xcb,0x7f,0x28,0x5,0xfe,0xfe,0xf2,0xef,0x8,0x8, + 0x26,0x1,0xcb,0x78,0xc2,0x31,0x8,0xed,0xb,0x26,0x0, + 0x2c,0xdd,0x75,0xaa,0xdd,0x3e,0xc4,0x5,0x1,0xcb,0x59, + 0xca,0xef,0x8,0x8,0xfe,0xc0,0xca,0x98,0x7,0x18,0x23, + 0xcb,0x41,0xca,0xe8,0x7,0xcb,0x51,0xc2,0xee,0x7,0xdd, + 0xbe,0xb1,0x20,0xbd,0xcb,0xd1,0xdd,0xcb,0xa3,0xe6,0xdd, + 0x71,0xa8,0xc3,0xef,0x8,0xdd,0x6e,0xaa,0x7d,0x3c,0xdd, + 0x96,0xab,0xcb,0x7f,0xc2,0xef,0x8,0xfe,0x40,0xf2,0xef, + 0x8,0xcb,0x79,0xc2,0xc4,0x7,0xcb,0x69,0xca,0xef,0x8, + 0xcb,0xa1,0xcb,0xf1,0xdd,0x71,0xa8,0xdd,0xcb,0xb4,0x7e, + 0xca,0xef,0x8,0xfd,0x36,0x2,0x80,0xc3,0xef,0x8,0xcb, + 0x79,0xc2,0x80,0x7,0x18,0x6b,0xcb,0x50,0xca,0x34,0x6, + 0xcb,0x40,0x20,0xc,0xfd,0x36,0x3,0xd,0xcb,0xc0,0xdd, + 0x70,0xa9,0xc3,0x3b,0x6,0xcb,0x80,0xdd,0x70,0xa9,0xc3, + 0x34,0x6,0xdd,0x7e,0xad,0x95,0xfe,0x40,0x20,0x12,0xcb, + 0x58,0xca,0x2d,0x6,0xcb,0x98,0xdd,0x70,0xa9,0xdd,0x3e, + 0xc5,0x5,0x1,0xc3,0x2d,0x6,0xfe,0xc0,0xc2,0x2d,0x6, + 0xcb,0xd8,0xdd,0x70,0xa9,0xc3,0x2d,0x6,0xdd,0x7e,0xad, + 0x95,0xfe,0x40,0x20,0x13,0xdd,0xcb,0xa9,0x5e,0xca,0xe6, + 0x5,0xdd,0xcb,0xa9,0x9e,0xdd,0x3e,0xc5,0x5,0x1,0xc3, + 0xe6,0x5,0xfe,0xc0,0xc2,0xe6,0x5,0xdd,0xcb,0xa9,0xde, + 0xc3,0xe6,0x5,0xdd,0xcb,0xba,0x5e,0x28,0x6,0xdd,0x56, + 0xb2,0xfd,0x72,0x3,0xdd,0xcb,0xb4,0x7e,0x28,0x4,0xfd, + 0x36,0x2,0x80,0xcb,0xb1,0xcb,0xa9,0xcb,0xa1,0xdd,0x71, + 0xa8,0xcb,0x48,0xc2,0x3b,0x6,0xcb,0x51,0xc2,0x3b,0x6, + 0xdd,0xcb,0xa3,0xa6,0xc3,0x3b,0x6,0xdd,0xcb,0xba,0x5e, + 0x28,0x6,0xdd,0x56,0xb3,0xfd,0x72,0x3,0xcb,0xe9,0xcb, + 0xb9,0xcb,0xb1,0xdd,0x71,0xa8,0xc3,0x3b,0x6,0xcb,0x69, + 0x20,0xf,0xcb,0xf9,0xcb,0xf1,0xcb,0xe1,0xdd,0xcb,0xa3, + 0xe6,0xdd,0x71,0xa8,0x18,0x2,0xcb,0xb1,0xdd,0xcb,0xb4, + 0x7e,0xca,0xef,0x8,0xfd,0x36,0x2,0x90,0xcb,0xe1,0xdd, + 0xcb,0xa3,0xe6,0xdd,0x71,0xa8,0xc3,0xef,0x8,0xcb,0xb9, + 0xcb,0xb1,0xcb,0xa1,0xdd,0x71,0xa8,0xdd,0xcb,0xb4,0x7e, + 0x28,0x4,0xfd,0x36,0x2,0x80,0xcb,0x48,0xc2,0xef,0x8, + 0xcb,0x51,0xc2,0xef,0x8,0xdd,0xcb,0xa3,0xa6,0xc3,0xef, + 0x8,0xdd,0xbe,0xb0,0xc2,0x9c,0x6,0xcb,0x91,0xcb,0x48, + 0x20,0xc,0xcb,0x61,0x20,0x8,0xcb,0x71,0x20,0x4,0xdd, + 0xcb,0xa3,0xa6,0xdd,0x71,0xa8,0xdd,0xbe,0xb0,0xca,0xef, + 0x8,0xdd,0xbe,0xb1,0xca,0xef,0x8,0xc3,0x5e,0x6,0xcb, + 0x7b,0xca,0x5a,0x6,0xdd,0xcb,0xc1,0x46,0xc2,0xef,0x8, + 0xdd,0xcb,0xc1,0x4e,0xca,0x5a,0x6,0xdd,0xcb,0xb9,0xc6, + 0xdd,0x3e,0xc5,0x5,0x1,0xc3,0xef,0x8,0x57,0x7b,0xe6, + 0x70,0x7a,0x20,0xe,0xdd,0xcb,0xc1,0x56,0xca,0x78,0x6, + 0xfe,0xff,0x28,0x27,0xc3,0x78,0x6,0xdd,0xcb,0xc1,0x5e, + 0x28,0x5,0x26,0x0,0xc3,0xef,0x8,0xdd,0xcb,0xc1,0x56, + 0x20,0x6,0xdd,0xe,0x0,0xc3,0x7a,0x6,0xdd,0xe,0xff, + 0x2c,0xdd,0xe,0x0,0x2c,0xed,0xb,0xc3,0x7a,0x6,0xdd, + 0xe,0xff,0x2c,0xdd,0xe,0xff,0xc3,0x7a,0x6,0xed,0x32, + 0x0,0x0,0xcb,0x5d,0x28,0xa,0xcb,0x9d,0xfd,0x7b,0xd, + 0x0,0xcb,0x2f,0x18,0x6,0xfd,0x7b,0xd,0x0,0xcb,0x27, + 0x26,0x0,0x2f,0xcb,0x60,0x20,0x4,0xe6,0x26,0x18,0x2, + 0xe6,0x24,0xdd,0xbe,0xb8,0xca,0xee,0x4,0xf5,0xdd,0xae, + 0xb8,0xe6,0x4,0x20,0x10,0xf1,0xdd,0x77,0xb8,0xdd,0xcb, + 0xb9,0xce,0xdd,0x3e,0xc5,0x5,0x1,0xc3,0xee,0x4,0xdd, + 0xcb,0xb5,0x66,0x28,0xea,0xf1,0xf5,0xfd,0x36,0x2,0x10, + 0xfd,0x36,0x2,0x30,0xfd,0x36,0x2,0x20,0xcb,0x57,0x28, + 0xf,0xfd,0x7e,0x0,0xdd,0x7e,0xb5,0xfd,0x77,0x0,0xfd, + 0x36,0x2,0x5,0x18,0xc9,0xfd,0x7e,0x0,0xdd,0x7e,0xb5, + 0xe6,0xef,0xfd,0x77,0x0,0xfd,0x36,0x2,0x5,0x18,0xb8, + 0xfd,0x5e,0x1,0xc3,0xef,0x5,0xfd,0xed,0x2c,0xa2,0xff, + 0xdd,0x7e,0xa7,0xfd,0x77,0x7f,0xe6,0x3,0xfd,0x77,0x68, + 0xc9,0xf5,0xc5,0xdd,0x7e,0xc6,0xfd,0x46,0x6c,0xa0,0x47, + 0xe,0x0,0xcb,0x78,0x28,0x12,0xcb,0xd1,0xdd,0xcb,0xb5, + 0x66,0x28,0x12,0xfd,0x7e,0x9,0xf6,0x2,0xfd,0x77,0x9, + 0x18,0x8,0xfd,0x7e,0x9,0xe6,0xfd,0xfd,0x77,0x9,0xcb, + 0x68,0x28,0x2,0xcb,0xf1,0xcb,0x60,0x28,0x2,0xcb,0xe9, + 0xcb,0x70,0x28,0x2,0xcb,0xc9,0xdd,0x71,0xb8,0xc1,0xf1, + 0xc9,0xcd,0xf5,0x8,0xdd,0x7e,0xbf,0xfe,0x1,0x20,0x22, + 0xed,0x2c,0xa4,0xff,0xdd,0x7e,0xa7,0xfe,0x4,0xf2,0x69, + 0x9,0xfd,0x1c,0x1c,0x0,0xf6,0x8,0xfd,0x77,0x7f,0x18, + 0x2d,0xfd,0x1c,0x1d,0x0,0xf6,0x20,0xfd,0x77,0x7f,0x18, + 0x22,0xdd,0x7e,0xc5,0xfe,0x1,0x28,0x1b,0xdd,0xcb,0xa9, + 0x4e,0x20,0x15,0xdd,0xcb,0xa9,0xc6,0xdd,0x7e,0xc7,0xfe, + 0x1,0x28,0x5,0xfd,0x36,0x6,0x92,0xc9,0xfd,0x36,0x6, + 0x94,0xc9,0xdd,0x36,0xbf,0x0,0xfd,0x7e,0x5,0xfe,0x0, + 0xc0,0xdd,0x7e,0xc5,0xfe,0x1,0xca,0x5c,0xb,0xdd,0x7e, + 0xc7,0xfe,0x1,0x20,0xb,0xfd,0x36,0x76,0x0,0xfd,0x36, + 0x72,0x42,0xc3,0xd3,0xa,0xdd,0x7e,0xb6,0xe6,0xf,0xcb, + 0x27,0x4f,0x6,0x0,0xfd,0x7e,0x40,0xfe,0x42,0x28,0x5, + 0x21,0x5e,0x18,0x18,0x3,0x21,0x42,0x18,0xed,0xc6,0x46, + 0xfd,0x70,0x72,0x23,0x46,0xfd,0x70,0x76,0xdd,0x7e,0xb6, + 0xe6,0xf0,0xcb,0x3f,0xcb,0x3f,0xcb,0x3f,0x4f,0x6,0x0, + 0xfd,0x7e,0x40,0xfe,0x42,0x28,0x5,0x21,0x5e,0x18,0x18, + 0x3,0x21,0x42,0x18,0xed,0xc6,0x46,0xfd,0x70,0x78,0x23, + 0x46,0xfd,0x70,0x7c,0xdd,0x7e,0xbb,0xfd,0x77,0x1a,0xdd, + 0x7e,0xbc,0xfd,0x77,0x1b,0xdd,0x7e,0xbd,0xfd,0x77,0x1c, + 0xdd,0x7e,0xbe,0xfd,0x77,0x1d,0xdd,0x36,0xb9,0x0,0xdd, + 0x7e,0xb4,0xe6,0x3,0x47,0xdd,0x7e,0xb4,0xe6,0x14,0xfe, + 0x10,0x28,0xc,0xfe,0x4,0x28,0x4,0x3e,0x40,0x18,0x6, + 0x3e,0xc0,0x18,0x2,0x3e,0x0,0xb0,0x47,0xdd,0x7e,0xba, + 0xe6,0x80,0x20,0x4,0x78,0xf6,0x10,0x47,0xdd,0x7e,0xb5, + 0xe6,0xf,0xfe,0x7,0x78,0x20,0x4,0xf6,0x0,0x18,0x2, + 0xf6,0x8,0xfd,0x77,0x8,0xdd,0x7e,0xb5,0xe6,0x10,0x28, + 0x4,0x6,0x2,0x18,0x2,0x6,0x0,0xdd,0x7e,0xb5,0xe6, + 0x80,0x28,0x4,0x3e,0x10,0xb0,0x47,0xdd,0x7e,0xba,0xe6, + 0x2,0x28,0x11,0xdd,0x7e,0xba,0xe6,0x1,0x28,0x6,0x3e, + 0xc0,0xb0,0x47,0x18,0x4,0x3e,0x40,0xb0,0x47,0xfd,0x70, + 0x9,0xdd,0x7e,0xba,0xe6,0x2,0x28,0x6,0xfd,0x36,0xa, + 0x36,0x18,0x4,0xfd,0x36,0xa,0x6,0xdd,0xcb,0xc0,0x5e, + 0x28,0x4,0x6,0x2,0x18,0xc,0xdd,0xcb,0xc0,0x56,0x28, + 0x4,0x6,0x4,0x18,0x2,0x6,0x3,0xdd,0xcb,0xc0,0x46, + 0x28,0x4,0x3e,0x18,0x18,0xc,0xdd,0xcb,0xc0,0x4e,0x28, + 0x4,0x3e,0x0,0x18,0x2,0x3e,0x8,0xb0,0xfd,0x77,0x1e, + 0xdd,0x7e,0xba,0xe6,0x4,0x28,0x16,0xdd,0x7e,0xc7,0xfe, + 0x1,0x20,0x7,0xfd,0x7e,0x40,0xfe,0x42,0x28,0x8,0x6, + 0x2,0xdd,0xcb,0xa9,0x96,0x18,0x2,0x6,0x0,0xdd,0x7e, + 0xc2,0xfe,0xff,0x28,0x4,0x3e,0x80,0xb0,0x47,0xfd,0x70, + 0x1f,0xdd,0x7e,0xba,0xdd,0xcb,0xb4,0x7e,0x20,0x6,0xdd, + 0xcb,0xba,0x76,0x28,0x2,0xf6,0x8,0x4f,0xdd,0xae,0xa8, + 0xe6,0x9b,0x47,0xdd,0x7e,0xa8,0xa8,0xcb,0x5f,0x28,0x2, + 0xe6,0xf,0x47,0xdd,0x70,0xa8,0x79,0xe6,0xfb,0xdd,0xae, + 0xa9,0xe6,0xa4,0x47,0xdd,0x7e,0xa9,0xa8,0xdd,0x77,0xa9, + 0xdd,0x7e,0xc7,0xfe,0x1,0x20,0x12,0xfd,0x7e,0x40,0xfe, + 0x42,0x20,0xb,0xdd,0x7e,0xba,0xe6,0x4,0x28,0x4,0xdd, + 0xcb,0xa9,0xd6,0xfd,0x36,0x21,0x2,0xfd,0x36,0x5,0x4e, + 0xdd,0x36,0xc5,0x1,0xc9,0xdd,0x36,0xc5,0x0,0xdd,0xcb, + 0xa8,0x86,0xdd,0x7e,0xc7,0xfe,0x1,0xca,0x17,0xc,0xfd, + 0x36,0x5,0x1a,0xdd,0xcb,0xb7,0x46,0x20,0x6,0xdd,0xcb, + 0xb4,0x7e,0x28,0x13,0xdd,0x7e,0xc4,0xe6,0x8,0x20,0x6, + 0xfd,0x36,0x6c,0x1,0x18,0x17,0xfd,0x36,0x6d,0x2,0x18, + 0x11,0xdd,0x7e,0xc4,0xe6,0x8,0x20,0x6,0xfd,0x36,0x6c, + 0x0,0x18,0x4,0xfd,0x36,0x6d,0x0,0xdd,0xcb,0xb7,0x4e, + 0x20,0x6,0xdd,0xcb,0xba,0x76,0x28,0x13,0xdd,0x7e,0xc4, + 0xe6,0x8,0x20,0x6,0xfd,0x36,0x6d,0x2,0x18,0x17,0xfd, + 0x36,0x6c,0x1,0x18,0x11,0xdd,0x7e,0xc4,0xe6,0x8,0x20, + 0x6,0xfd,0x36,0x6d,0x0,0x18,0x4,0xfd,0x36,0x6c,0x0, + 0xdd,0xcb,0xba,0x6e,0x28,0x15,0xcd,0x6,0x9,0xdd,0x7e, + 0xb5,0xe6,0x10,0x28,0x4,0x3e,0xb0,0x18,0x2,0x3e,0xf0, + 0xdd,0xa6,0xc6,0x18,0x6,0x3e,0x0,0xdd,0x36,0xb8,0x24, + 0xfd,0x77,0x16,0xdd,0xcb,0xba,0x76,0x28,0xa,0xdd,0xcb, + 0xc4,0x5e,0x20,0x4,0xf6,0x8,0x18,0xe,0xdd,0xcb,0xb4, + 0x7e,0x28,0x8,0xdd,0xcb,0xc4,0x5e,0x28,0x2,0xf6,0x8, + 0xfd,0x77,0x15,0x18,0xc,0xfd,0x36,0x15,0x0,0xfd,0x36, + 0x16,0x0,0xfd,0x36,0x5,0x18,0xfd,0x36,0x6,0x90,0xdd, + 0x36,0xae,0x0,0xdd,0x3e,0xc5,0x5,0x1,0xc9,0xcd,0xf5, + 0x8,0xfd,0x7e,0x6c,0xe6,0x80,0x28,0xa,0xdd,0x36,0xae, + 0x0,0xdd,0x3e,0xc5,0x5,0x1,0xc9,0xdd,0x36,0xae,0x6, + 0xc9,0xcd,0x48,0x9,0x18,0x5,0xfd,0xed,0x2c,0xa2,0xff, + 0xcd,0x31,0xc,0x26,0x0,0xc3,0xc,0xd,0xcd,0x48,0x9, + 0x26,0x0,0xc3,0xc,0xd,0xcd,0xea,0x1c,0x26,0x0,0xc3, + 0xc,0xd,0xcd,0xea,0x1c,0x26,0x0,0xc3,0xc,0xd,0x26, + 0x0,0xc3,0xc,0xd,0xcd,0xf5,0x8,0xfd,0x7e,0x5,0xfe, + 0x0,0x28,0x5,0x26,0x0,0xc3,0xc,0xd,0xdd,0x7e,0xad, + 0xdd,0x77,0xac,0xfd,0x36,0x5,0x82,0xcd,0xf5,0x8,0xdd, + 0x7e,0xc7,0xfe,0x1,0x28,0x8,0xfd,0x7e,0xb,0xe6,0xfb, + 0xfd,0x77,0xb,0xdd,0x36,0xae,0x0,0xdd,0x3e,0xc5,0x5, + 0x1,0x26,0x0,0x18,0x5b,0xfd,0xed,0x2c,0xa2,0xff,0xdd, + 0x7e,0xab,0xdd,0x77,0xaa,0xdd,0x36,0xae,0x0,0xdd,0x3e, + 0xc5,0x5,0x1,0x26,0x0,0x18,0x43,0xcd,0xf5,0x8,0xfd, + 0x7e,0xb,0xf6,0x4,0xfd,0x77,0xb,0xdd,0x36,0xae,0x0, + 0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0,0x18,0x2b,0xcd,0x72, + 0x1b,0x26,0x0,0x18,0x24,0x74,0xc,0x5c,0xc,0x4a,0xc, + 0x4f,0xc,0x5c,0xc,0x64,0xc,0x2d,0x1c,0x89,0x1c,0x74, + 0xc,0x74,0xc,0x6c,0xc,0x92,0xc,0x79,0xc,0xb1,0xc, + 0xc9,0xc,0xe1,0xc,0x74,0xc,0x74,0xc,0xed,0x7f,0x17, + 0xdd,0x7e,0xa1,0xdd,0x67,0xdd,0x7e,0xae,0xfe,0x0,0xf3, + 0xc2,0xa9,0xd,0xdd,0x46,0xa8,0xcb,0x40,0xca,0xb6,0xd, + 0xcb,0x60,0x28,0xe3,0xcd,0xf5,0x8,0xcb,0x78,0x28,0x16, + 0xfd,0x7e,0x5,0xfe,0x0,0x20,0xd5,0xfd,0x36,0x5,0x24, + 0xcb,0xe8,0xcb,0xb8,0xcb,0xb0,0xdd,0x70,0xa8,0x18,0xc6, + 0xdd,0x6e,0xaa,0x7d,0xdd,0x96,0xab,0xcb,0x7f,0x20,0xbb, + 0xfe,0x40,0xf2,0xc,0xd,0xdd,0xcb,0xba,0x5e,0x28,0xb, + 0xfd,0x7e,0x5,0xfe,0x0,0x20,0xa9,0xfd,0x36,0x5,0x23, + 0xdd,0xcb,0xb4,0x7e,0x28,0x15,0xdd,0x7e,0xc4,0xe6,0x8, + 0x20,0x6,0xfd,0x36,0x6c,0x1,0x18,0x8,0xfd,0x7e,0x6, + 0xf6,0x10,0xfd,0x77,0x6,0xdd,0xcb,0xba,0x76,0x28,0x15, + 0xdd,0x7e,0xc4,0xe6,0x8,0x20,0xa,0xfd,0x7e,0x6,0xf6, + 0x10,0xfd,0x77,0x6,0x18,0x4,0xfd,0x36,0x6c,0x1,0xcb, + 0xb0,0xcb,0xa8,0xcb,0xa0,0xdd,0x70,0xa8,0xc3,0xc,0xd, + 0xfe,0x10,0xca,0xc,0xd,0x6f,0xfd,0xed,0x3c,0xe8,0xc, + 0xfd,0xe9,0xdd,0x6e,0xac,0xdd,0x7e,0xad,0x95,0xca,0x25, + 0xd,0xdd,0xcb,0xa8,0xc6,0xcd,0xf5,0x8,0xfd,0x7e,0x6, + 0xf6,0x4,0xfd,0x77,0x6,0xdd,0x36,0xc9,0x1,0xc3,0x25, + 0xd,0xed,0x32,0x0,0x0,0xcb,0x5d,0x28,0xb,0xcb,0x9d, + 0xfd,0x7b,0xd,0x0,0x2f,0xe6,0x8,0x18,0x7,0xfd,0x7b, + 0xd,0x0,0x2f,0xe6,0x2,0xfe,0x0,0x28,0xa,0xdd,0x36, + 0xae,0x0,0xdd,0x3e,0xc5,0x5,0x1,0xc9,0xdd,0x36,0xae, + 0x6,0xc9,0x26,0x0,0xdd,0x7e,0xac,0xdd,0x96,0xad,0x28, + 0x4,0xf1,0xc3,0xc6,0x5,0xdd,0x7e,0xbf,0xfe,0x1,0x28, + 0x8,0xfd,0x7e,0x1,0xcb,0x5f,0xc8,0x18,0x10,0xdd,0x36, + 0xaa,0x0,0xdd,0x36,0xab,0x0,0xdd,0x36,0xac,0x0,0xdd, + 0x36,0xad,0x0,0xfd,0xed,0x2c,0xa2,0xff,0xdd,0xcb,0xb7, + 0x46,0x20,0x4,0xfd,0x36,0x2,0x90,0xfd,0x36,0x2,0x30, + 0xfd,0x36,0x2,0x20,0xdd,0x36,0xbf,0x1,0xdd,0xcb,0xb7, + 0x4e,0x20,0x24,0xfd,0xe5,0xed,0x32,0x0,0x0,0x7d,0xe6, + 0x80,0x6f,0xfd,0xed,0x2c,0xa4,0xff,0xfd,0x7e,0x4,0x47, + 0xdd,0x7e,0xaf,0x2f,0xa0,0xfd,0x77,0x4,0xe5,0xfd,0xe1, + 0x2f,0xfd,0x77,0x40,0xfd,0xe1,0xdd,0x36,0xae,0x10,0xdd, + 0x3e,0xc5,0x5,0x1,0xc9,0xdd,0x7e,0xbf,0xfe,0x1,0x28, + 0x6,0xfd,0x7e,0x1,0xcb,0x5f,0xc8,0xdd,0x36,0xbf,0x0, + 0xfd,0x36,0x2,0x18,0xdd,0x7e,0xb4,0xe6,0x7f,0xfd,0x77, + 0x0,0xdd,0xcb,0xb4,0x7e,0x20,0x12,0xdd,0xcb,0xb7,0x46, + 0x20,0x6,0xfd,0x36,0x2,0x90,0x18,0xa,0xfd,0x36,0x2, + 0x80,0x18,0x4,0xfd,0x36,0x2,0x80,0xdd,0x7e,0xb5,0xfd, + 0x77,0x0,0xcb,0x67,0x20,0x6,0xdd,0xcb,0xa9,0xa6,0x18, + 0x4,0xdd,0xcb,0xa9,0xe6,0xfd,0xe5,0xed,0x32,0x0,0x0, + 0x7d,0xe6,0x80,0x6f,0xfd,0xed,0x2c,0xa4,0xff,0xfd,0x7e, + 0x4,0xdd,0xcb,0xb7,0x4e,0x28,0x5,0xdd,0xb6,0xaf,0x18, + 0x6,0x47,0xdd,0x7e,0xaf,0x2f,0xa0,0xfd,0x77,0x4,0xe5, + 0xfd,0xe1,0x2f,0xfd,0x77,0x40,0xfd,0xe1,0xdd,0x7e,0xb6, + 0xfd,0x77,0x1,0xdd,0x36,0xb9,0x0,0xdd,0x7e,0xbb,0xdd, + 0x77,0xb0,0xdd,0x7e,0xbc,0xdd,0x77,0xb1,0xdd,0x7e,0xbd, + 0xdd,0x77,0xb2,0xdd,0x7e,0xbe,0xdd,0x77,0xb3,0xdd,0x36, + 0xb9,0x0,0xdd,0x7e,0xba,0xdd,0xcb,0xb4,0x7e,0x28,0x2, + 0xf6,0x8,0x4f,0xdd,0xae,0xa8,0xe6,0xdb,0x47,0xdd,0x7e, + 0xa8,0xa8,0xcb,0x48,0x28,0x2,0xcb,0x97,0xcb,0x5f,0x28, + 0x2,0xe6,0xf,0x47,0x79,0xe6,0x54,0x20,0xa,0xdd,0xcb, + 0xa9,0x8e,0xdd,0xcb,0xa3,0xa6,0x18,0x8,0xdd,0xcb,0xa3, + 0xe6,0xdd,0xcb,0xa9,0xce,0xdd,0x70,0xa8,0x79,0xdd,0xae, + 0xa9,0xe6,0xa4,0x47,0xdd,0x7e,0xa9,0xa8,0xcb,0x50,0x28, + 0x2,0xcb,0x87,0xdd,0x77,0xa9,0xcb,0x6f,0x20,0x6,0xdd, + 0x36,0xb8,0x24,0x18,0x3b,0xed,0x32,0x0,0x0,0xcb,0x5d, + 0x28,0xa,0xcb,0x9d,0xfd,0x7b,0xd,0x0,0xcb,0x2f,0x18, + 0x6,0xfd,0x7b,0xd,0x0,0xcb,0x27,0x2f,0xdd,0xcb,0xa9, + 0x66,0x20,0x4,0xe6,0x26,0x18,0x15,0xe6,0x24,0xdd,0x77, + 0xb8,0xcb,0x57,0x28,0x2,0x18,0xd,0xdd,0x7e,0xb5,0xe6, + 0xef,0xfd,0x77,0x0,0x18,0x3,0xdd,0x77,0xb8,0xdd,0x7e, + 0xc0,0xdd,0x77,0xc1,0xdd,0x7e,0xc2,0xdd,0x77,0xc3,0xfd, + 0x36,0x2,0x5,0xdd,0x36,0xae,0x0,0xdd,0x3e,0xc5,0x5, + 0x1,0xc9,0x45,0x6e,0x64,0x20,0x6f,0x66,0x20,0x74,0x61, + 0x20,0x63,0x6f,0x64,0x65,0x0,0x0,0xdd,0xd1,0xdf,0xf, + 0xe5,0xdd,0xe5,0xc5,0xdd,0x2a,0x2a,0x1,0xe,0x15,0xed, + 0xb7,0x21,0x0,0x0,0xed,0xbf,0xdd,0x36,0xae,0x2a,0xc1, + 0xdd,0xe1,0xe1,0xed,0x55,0xdd,0xd1,0xdf,0xf,0xe5,0xdd, + 0xe5,0xc5,0xdd,0x2a,0x2c,0x1,0xe,0x1d,0x21,0x0,0x0, + 0xed,0xbf,0xdd,0x36,0xae,0x2a,0xc1,0xdd,0xe1,0xe1,0xed, + 0x55,0xfd,0xed,0x2c,0xa2,0xff,0xdd,0x7e,0xb2,0xe6,0xc, + 0x20,0x25,0xdd,0x7e,0xb2,0xe6,0x10,0x28,0x1e,0xfd,0x36, + 0x0,0xf,0xfd,0x36,0x0,0x1,0xfd,0x36,0x0,0x7,0xfd, + 0x36,0x0,0x3,0xdd,0x7e,0xb3,0xf6,0x9,0xfd,0x36,0x0, + 0x5,0xfd,0x77,0x0,0x18,0xc,0xdd,0x7e,0xb3,0xf6,0x8, + 0xfd,0x36,0x0,0x5,0xfd,0x77,0x0,0xed,0x32,0x2,0x0, + 0x7c,0xf6,0xf0,0x67,0xdd,0x7e,0xa7,0xfe,0x1,0x20,0x44, + 0xe,0x10,0xed,0xbf,0x21,0xf,0x80,0xe,0x11,0xed,0xbf, + 0xed,0x2a,0x0,0x0,0x7c,0xf6,0xf0,0x67,0xe,0x12,0xed, + 0xbf,0xdd,0x7c,0xe6,0x7f,0xf6,0xf,0x6f,0x26,0x0,0xe, + 0x13,0xed,0xbf,0xed,0x2c,0xaa,0xff,0xe,0x14,0xed,0xbf, + 0x21,0x84,0x88,0xe,0x15,0xed,0xbf,0xfd,0x36,0x0,0x1, + 0xfd,0x36,0x0,0xc0,0x26,0x0,0xdd,0x36,0xae,0x28,0xc3, + 0xf3,0x5,0xe,0x18,0xed,0xbf,0x21,0xf,0x80,0xe,0x19, + 0xed,0xbf,0xed,0x2a,0x0,0x0,0x7c,0xf6,0xf0,0x67,0xe, + 0x1a,0xed,0xbf,0xdd,0x7c,0xe6,0x7f,0xf6,0xf,0x6f,0x26, + 0x0,0xe,0x1b,0xed,0xbf,0xed,0x2c,0xaa,0xff,0xe,0x1c, + 0xed,0xbf,0x21,0x84,0x88,0xe,0x1d,0xed,0xbf,0xfd,0x36, + 0x0,0x1,0xfd,0x36,0x0,0xc0,0x26,0x0,0xdd,0x36,0xae, + 0x28,0xc3,0xf3,0x5,0xfd,0xed,0x2c,0xa2,0xff,0xdd,0x7e, + 0xb2,0xe6,0xc,0x20,0x15,0xdd,0x7e,0xb2,0xe6,0x10,0x28, + 0xe,0xdd,0x7e,0xb1,0xf6,0x11,0xfd,0x36,0x0,0x3,0xfd, + 0x77,0x0,0x18,0xc,0xdd,0x7e,0xb1,0xf6,0x1,0xfd,0x36, + 0x0,0x3,0xfd,0x77,0x0,0xed,0x32,0x2,0x0,0x7c,0xf6, + 0xf0,0x67,0xdd,0x7e,0xa7,0xfe,0x1,0x20,0x47,0xe,0x12, + 0xed,0xbf,0x21,0xf,0x80,0xe,0x13,0xed,0xbf,0xed,0x2a, + 0x0,0xc,0x7c,0xf6,0xf0,0x67,0xe,0x10,0xed,0xbf,0xed, + 0x2a,0x0,0xc,0x7c,0xe6,0x7f,0xf6,0xf,0x6f,0x26,0x0, + 0xe,0x11,0xed,0xbf,0xed,0x2c,0xaa,0xff,0xe,0x14,0xed, + 0xbf,0x21,0x80,0xa0,0xe,0x15,0xed,0xbf,0xfd,0x36,0x0, + 0x1,0xfd,0x36,0x0,0xe0,0x26,0x0,0xdd,0x36,0xae,0x28, + 0xc3,0xf3,0x5,0xe,0x1a,0xed,0xbf,0x21,0xf,0x80,0xe, + 0x1b,0xed,0xbf,0xed,0x2a,0x0,0xc,0x7c,0xf6,0xf0,0x67, + 0xe,0x18,0xed,0xbf,0xed,0x2a,0x0,0xc,0x7c,0xe6,0x7f, + 0xf6,0xf,0x6f,0x26,0x0,0xe,0x19,0xed,0xbf,0xed,0x2c, + 0xaa,0xff,0xe,0x1c,0xed,0xbf,0x21,0x80,0xa0,0xe,0x1d, + 0xed,0xbf,0xfd,0x36,0x0,0x1,0xfd,0x36,0x0,0xe0,0x26, + 0x0,0xdd,0x36,0xae,0x28,0xc3,0xf3,0x5,0xfd,0xed,0x2c, + 0xa2,0xff,0xdd,0x7e,0xb1,0xfd,0x36,0x0,0x3,0xfd,0x77, + 0x0,0xdd,0x7e,0xb2,0xfd,0x36,0x0,0x4,0xfd,0x77,0x0, + 0xdd,0x7e,0xb3,0xfd,0x36,0x0,0x5,0xfd,0x77,0x0,0xdd, + 0x7e,0xb4,0xfd,0x36,0x0,0x6,0xfd,0x77,0x0,0xdd,0x7e, + 0xb5,0xfd,0x36,0x0,0x7,0xfd,0x77,0x0,0xdd,0x7e,0xb8, + 0xfd,0x36,0x0,0xa,0xfd,0x77,0x0,0xdd,0x7e,0xba,0xfd, + 0x36,0x0,0xc,0xfd,0x77,0x0,0xdd,0x7e,0xbb,0xfd,0x36, + 0x0,0xd,0xfd,0x77,0x0,0xdd,0x36,0xae,0x2a,0xdd,0x3e, + 0xc5,0x5,0x1,0x26,0x0,0xc3,0xf3,0x5,0x8,0x0,0x18, + 0x0,0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68,0x0, + 0x8,0x80,0x8,0x0,0x18,0x0,0x28,0x0,0x38,0x0,0x48, + 0x0,0x58,0x0,0x68,0x0,0x78,0x0,0x8,0x0,0x18,0x0, + 0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68,0x0,0x8, + 0x80,0x8,0x0,0x18,0x0,0x28,0x0,0x38,0x0,0x48,0x0, + 0x58,0x0,0x68,0x0,0x78,0x0,0x7a,0x0,0x6a,0x0,0xfa, + 0x0,0xaa,0x0,0xba,0x0,0xca,0x0,0x8,0x80,0x8,0x80, + 0x8,0x0,0x18,0x0,0x28,0x0,0x38,0x0,0x48,0x0,0x58, + 0x0,0x68,0x0,0x8,0x1,0x7a,0x0,0x6a,0x0,0xfa,0x0, + 0xaa,0x0,0xba,0x0,0xca,0x0,0x8,0x80,0x8,0x80,0x8, + 0x0,0x18,0x0,0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0, + 0x68,0x0,0x8,0x1,0x6a,0x0,0x7a,0x0,0xfa,0x0,0x9a, + 0x0,0xaa,0x0,0xba,0x0,0x8,0x80,0x8,0x80,0x8,0x0, + 0x18,0x0,0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68, + 0x0,0x8,0x1,0x6a,0x0,0x7a,0x0,0xfa,0x0,0x9a,0x0, + 0xaa,0x0,0xba,0x0,0x8,0x80,0x8,0x80,0x8,0x0,0x18, + 0x0,0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68,0x0, + 0x8,0x1,0x8a,0x0,0x9a,0x0,0xfa,0x0,0xba,0x0,0xca, + 0x0,0xda,0x0,0x8,0x80,0x8,0x80,0x8,0x0,0x18,0x0, + 0x28,0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68,0x0,0x8, + 0x1,0x8a,0x0,0x9a,0x0,0xfa,0x0,0xba,0x0,0xca,0x0, + 0xda,0x0,0x8,0x80,0x8,0x80,0x8,0x0,0x18,0x0,0x28, + 0x0,0x38,0x0,0x48,0x0,0x58,0x0,0x68,0x0,0x8,0x1, + 0x3a,0x41,0x0,0xfe,0x0,0x20,0xf9,0x3a,0x0,0x80,0x2f, + 0x47,0x32,0x0,0x80,0x3a,0x0,0x80,0xb8,0x28,0x7,0xdd, + 0x3e,0x1,0x0,0x20,0x18,0x5,0xdd,0x3e,0x1,0x0,0x40, + 0x3a,0x42,0x0,0xfe,0x1,0x20,0x6,0xdd,0x11,0x1c,0x13, + 0x8,0x40,0x2a,0x43,0x0,0xe,0xff,0xed,0x6e,0x2a,0x45, + 0x0,0xe,0x2,0xed,0x6e,0x21,0x60,0x0,0xe,0x12,0xed, + 0x6e,0x21,0x2,0x0,0xe,0x0,0xed,0x6e,0x21,0xff,0x0, + 0xe,0x8,0xed,0x6e,0x21,0x0,0x0,0xe,0x16,0xed,0x6e, + 0x3e,0x3f,0xd3,0xe8,0xe,0x1f,0x21,0x0,0x0,0xed,0xbf, + 0xed,0x4e,0x3e,0x0,0xe,0xf5,0xdd,0x21,0x1e,0x12,0xed, + 0x2c,0x0,0x0,0xd3,0xf1,0xed,0xbf,0x3c,0xdd,0x23,0xdd, + 0x23,0xfe,0x20,0x20,0xef,0x21,0x0,0x8,0xe,0xf0,0xed, + 0xbf,0x0,0x0,0x0,0xdd,0x21,0x8c,0x0,0xfd,0x21,0x0, + 0x70,0x21,0x80,0x0,0xe,0x0,0xfd,0xe5,0x6,0x4,0xfd, + 0x7e,0xd,0xe6,0xa0,0xfe,0xa0,0x20,0x44,0xe5,0xed,0x32, + 0x0,0x0,0xfd,0xed,0xf6,0x10,0x0,0xe5,0xfd,0xe1,0xe1, + 0x10,0xe7,0xfd,0xe1,0xfd,0x7e,0x1,0xfe,0xff,0xca,0x5d, + 0x14,0xdd,0x3e,0x92,0x0,0x1,0x3a,0x93,0x0,0xfe,0x1, + 0xca,0xa5,0x14,0xfd,0x7e,0x40,0xe6,0x1,0x20,0xb,0xdd, + 0x36,0x0,0x8,0xfd,0xed,0xf6,0x0,0x19,0x18,0x4d,0xdd, + 0x36,0x0,0x4,0xfd,0xed,0xf6,0x0,0xd,0x18,0x42,0xfd, + 0xe1,0xfd,0x36,0x7f,0x8,0xdd,0x3e,0x93,0x0,0x1,0x3a, + 0x92,0x0,0xfe,0x1,0xca,0xa5,0x14,0xcd,0x4d,0x15,0xfd, + 0x36,0x7f,0x10,0xfd,0x7e,0x7f,0xe6,0xf0,0xfe,0xf0,0x20, + 0xb,0xdd,0x36,0x0,0x24,0xfd,0xed,0xf6,0x0,0xd,0x18, + 0x14,0xfd,0x36,0x7f,0x34,0xcd,0x4d,0x15,0xfd,0x36,0x7f, + 0x40,0xdd,0x36,0x0,0x28,0xfd,0xed,0xf6,0x0,0x19,0xdd, + 0x23,0xe5,0xed,0x32,0x0,0x0,0xfd,0xed,0xf6,0x80,0x0, + 0xe5,0xfd,0xe1,0xe1,0xc,0x79,0xfe,0x4,0xc2,0xb3,0x13, + 0x79,0xfe,0x0,0x28,0x43,0xe5,0x21,0xd1,0xf,0xfd,0xed, + 0xf7,0x0,0x10,0xe1,0xf2,0x76,0x14,0x3a,0x91,0x0,0xfe, + 0x1,0x20,0x5,0xdd,0x3e,0x94,0x0,0x1,0x3a,0x1,0x0, + 0xfe,0x40,0x28,0x39,0x22,0x95,0x0,0x21,0x0,0x80,0x3a, + 0x94,0x0,0xfe,0x1,0x20,0x7,0xfd,0xed,0xfe,0x0,0x20, + 0x18,0x5,0xfd,0xed,0xfe,0x0,0x10,0xdd,0xed,0xde,0x95, + 0x0,0xfa,0xb3,0x14,0x18,0x16,0xdd,0x3e,0x0,0x0,0xff, + 0x18,0xe,0xdd,0x3e,0x0,0x0,0x2,0x18,0x7,0xdd,0x3e, + 0x0,0x0,0x3,0x18,0x0,0x76,0x21,0x0,0x0,0xe,0xf0, + 0xed,0xbf,0x0,0x0,0x0,0x1,0xc1,0x1d,0x21,0x0,0x0, + 0x3a,0x1,0x0,0xfe,0x20,0x20,0x14,0x3a,0x94,0x0,0xfe, + 0x1,0x20,0x5,0x11,0x0,0x60,0x18,0xb,0x1,0xd1,0xf, + 0x11,0x0,0x70,0x18,0x3,0x11,0x0,0x80,0xed,0xb0,0x3a, + 0x1,0x0,0xfe,0x20,0x20,0x12,0x3a,0x94,0x0,0xfe,0x1, + 0x28,0xb,0x1,0xc1,0xd,0x11,0x0,0x60,0x21,0x0,0x10, + 0xed,0xb0,0x3a,0x1,0x0,0xfe,0x20,0x20,0x5,0x21,0x70, + 0x0,0x18,0x3,0x21,0x80,0x0,0xe,0x6,0xed,0x6e,0x3a, + 0x1,0x0,0xfe,0x20,0x20,0x13,0x3a,0x94,0x0,0xfe,0x1, + 0x20,0x6,0xdd,0x21,0x9e,0x12,0x18,0xa,0xdd,0x21,0x5e, + 0x12,0x18,0x4,0xdd,0x21,0xde,0x12,0x3e,0x0,0xe,0xf5, + 0xed,0x2c,0x0,0x0,0xd3,0xf1,0xed,0xbf,0x3c,0xdd,0x23, + 0xdd,0x23,0xfe,0x20,0x20,0xef,0xc3,0xc7,0x0,0xf5,0xc5, + 0xe5,0xfd,0x36,0x66,0x1,0xfd,0x36,0x68,0x3,0xfd,0x36, + 0x74,0x0,0xfd,0x36,0x68,0x2,0xfd,0x36,0x74,0x0,0xfd, + 0x36,0x68,0x1,0xfd,0x36,0x74,0x0,0xfd,0x36,0x68,0x0, + 0xfd,0x36,0x74,0x0,0xfd,0x36,0x68,0x3,0xfd,0x36,0x7a, + 0x0,0xfd,0x36,0x68,0x2,0xfd,0x36,0x7a,0x0,0xfd,0x36, + 0x68,0x1,0xfd,0x36,0x7a,0x0,0xfd,0x36,0x68,0x0,0xfd, + 0x36,0x7a,0x0,0xfd,0x36,0x68,0x4,0xfd,0x36,0x6d,0xa8, + 0xfd,0x36,0x6e,0x0,0xfd,0x36,0x6f,0x0,0xfd,0x36,0x6c, + 0x1,0xfd,0x36,0x66,0x3,0xfd,0x36,0x66,0x3,0xfd,0x36, + 0x66,0x3,0xfd,0x36,0x68,0x4,0xfd,0x36,0x6d,0xa8,0xfd, + 0x36,0x6e,0x20,0xfd,0x36,0x6f,0x0,0xfd,0x36,0x66,0x3, + 0xfd,0x36,0x66,0x3,0xfd,0x36,0x66,0x3,0xfd,0x36,0x6c, + 0x0,0x6,0xf,0xfd,0x36,0x66,0x3,0x10,0xfa,0xfd,0x36, + 0x68,0x4,0xfd,0x36,0x6d,0x0,0xfd,0x36,0x6e,0x20,0xfd, + 0x36,0x6f,0x3,0xfd,0x36,0x6c,0x1,0xfd,0x36,0x66,0x3, + 0xfd,0x36,0x66,0x3,0xfd,0x36,0x66,0x3,0xfd,0x36,0x66, + 0x3,0xfd,0x36,0x6c,0x0,0xfd,0x36,0x66,0x0,0xfd,0x36, + 0x68,0x0,0x21,0xff,0x7f,0x2b,0xfd,0xed,0xf7,0x0,0x0, + 0x20,0xf8,0xfd,0x36,0x40,0x0,0xfd,0x36,0x5,0x81,0x21, + 0xff,0x7f,0xfd,0x7e,0x40,0xfe,0x0,0x28,0xf9,0xfd,0x36, + 0x4b,0x0,0xfd,0x36,0x7e,0xc3,0x6,0x4,0x5,0xfd,0x70, + 0x68,0xfd,0x36,0x18,0x0,0x78,0xfe,0x0,0x20,0xf3,0xe1, + 0xc1,0xf1,0xc9,0x53,0x70,0x65,0x63,0x69,0x61,0x6c,0x69, + 0x78,0x20,0x53,0x4c,0x58,0x4f,0x53,0x20,0x2d,0x20,0x44, + 0x6f,0x77,0x6e,0x6c,0x6f,0x61,0x64,0x20,0x43,0x6f,0x64, + 0x65,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31, + 0x2e,0x33,0x34,0xd,0xa,0x43,0x6f,0x70,0x79,0x72,0x69, + 0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x53,0x70,0x65, + 0x63,0x69,0x61,0x6c,0x69,0x78,0x20,0x49,0x6e,0x74,0x65, + 0x72,0x6e,0x61,0x74,0x69,0x6f,0x6e,0x61,0x6c,0x20,0x31, + 0x39,0x38,0x38,0x2f,0x38,0x39,0x2f,0x39,0x30,0x2f,0x39, + 0x31,0x2f,0x39,0x32,0x2f,0x39,0x33,0xd,0xa,0x41,0x6c, + 0x6c,0x20,0x72,0x69,0x67,0x68,0x74,0x73,0x20,0x72,0x65, + 0x73,0x65,0x72,0x76,0x65,0x64,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x42,0x41,0x82,0x4,0x16,0x0, + 0x41,0x0,0x41,0x4,0x82,0x3,0x41,0x3,0x82,0x2,0x4e, + 0x2,0x41,0x2,0x82,0x1,0x57,0x2,0x41,0x1,0x82,0x0, + 0x2b,0x0,0xa3,0x4,0x1b,0x0,0x51,0x0,0x51,0x4,0xa3, + 0x3,0x51,0x3,0xa3,0x2,0x62,0x2,0x51,0x2,0xa3,0x1, + 0x6d,0x2,0x51,0x1,0xa3,0x0,0x36,0x0,0x49,0x4e,0x0, + 0x0,0x1e,0x1,0x18,0x2,0x1e,0x0,0xdd,0xd1,0x7c,0x18, + 0xf5,0xdd,0xe5,0x21,0x80,0x80,0x54,0xfd,0x7b,0x8,0x0, + 0xfd,0xed,0x3c,0x6,0x0,0xfe,0x24,0x28,0x4,0x6,0x4, + 0x18,0x2,0x6,0x0,0xfd,0x70,0x7f,0xcb,0x43,0x20,0x5, + 0xfd,0x7e,0x6a,0x18,0x3,0xfd,0x7e,0x6b,0x4f,0xcb,0x7f, + 0xca,0x4c,0x19,0xe6,0x3,0xfd,0x77,0x68,0xed,0x3a,0x8, + 0x0,0xb0,0xcb,0x27,0x85,0x6f,0xdd,0xed,0x3c,0x2,0x0, + 0xcb,0x43,0xc2,0x7e,0x19,0xd9,0xdd,0x6e,0xac,0xdd,0x7e, + 0xad,0x95,0x4f,0xe6,0xc,0xfe,0xc,0x28,0x6,0x79,0xe6, + 0x30,0xca,0xaf,0x1a,0xdd,0x7e,0xa9,0xe6,0x5,0xc2,0x5c, + 0x1a,0x79,0xcb,0x7f,0x20,0x5,0xfe,0xc,0xfa,0xa0,0x1a, + 0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd,0x79,0xfd,0x77,0x63, + 0x2c,0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd,0x79,0xfd,0x77, + 0x63,0x2c,0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd,0x79,0xfd, + 0x77,0x63,0x2c,0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd,0x79, + 0xfd,0x77,0x63,0x2c,0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd, + 0x79,0xfd,0x77,0x63,0x2c,0xdd,0x79,0xfd,0x77,0x63,0x2c, + 0xdd,0x79,0xfd,0x77,0x63,0x2c,0xdd,0x75,0xac,0xd9,0x79, + 0xe6,0x3f,0xcb,0x43,0x20,0x30,0xfd,0x77,0x6a,0x62,0x2e, + 0x80,0xcb,0x50,0x28,0x5,0x6,0x0,0xc3,0xa2,0x18,0xdd, + 0xed,0x3a,0x2,0x0,0xdd,0x66,0xff,0xfd,0xed,0xf7,0x80, + 0x0,0xc2,0x8e,0x18,0xdd,0xe1,0xf1,0xed,0x55,0xfd,0x7e, + 0x62,0xed,0xb,0x2c,0x10,0xf8,0x18,0x2a,0x49,0x4e,0xfd, + 0x77,0x6b,0x18,0xce,0xd9,0xfd,0x7e,0x43,0xfe,0x7,0x28, + 0x57,0x26,0x1,0xdd,0x7e,0xab,0xdd,0x6e,0xaa,0x95,0x3d, + 0x4f,0xfd,0x46,0xe,0x58,0xcb,0x7f,0x20,0x4,0xb8,0xfa, + 0xc9,0x19,0x16,0x0,0x18,0xcc,0xdd,0x3e,0xc4,0x5,0x1, + 0x7a,0xfe,0x0,0x20,0x2a,0xdd,0xcb,0xa8,0x5e,0x28,0x10, + 0x79,0xcb,0x7f,0x20,0xb,0xfe,0x40,0xfa,0xc1,0x19,0x93, + 0xfe,0x40,0xfa,0xee,0x19,0xdd,0x75,0xaa,0x26,0x0,0xc3, + 0x41,0x19,0xfe,0x0,0x28,0x9,0x16,0x1,0x78,0x91,0x5f, + 0x41,0x18,0x98,0x43,0xfd,0x7e,0x62,0x10,0xfb,0x18,0xe4, + 0xdd,0xcb,0xb9,0xc6,0xdd,0x3e,0xc5,0x5,0x1,0xfd,0x7e, + 0x62,0xfd,0x7e,0x62,0x18,0xd6,0xdd,0xcb,0xba,0x5e,0x28, + 0x1f,0xdd,0xcb,0xa8,0x6e,0x20,0x19,0xfd,0x7e,0x5,0xfe, + 0x0,0x20,0xa,0xfd,0x36,0x5,0x24,0xdd,0xcb,0xa8,0xee, + 0x18,0x8,0xdd,0xcb,0xa8,0xfe,0xdd,0xcb,0xa8,0xf6,0xdd, + 0xcb,0xa8,0xe6,0xdd,0xcb,0xb4,0x7e,0x28,0x15,0xdd,0x7e, + 0xc4,0xe6,0x8,0x20,0x6,0xfd,0x36,0x6c,0x0,0x18,0x8, + 0xfd,0x7e,0x6,0xe6,0xef,0xfd,0x77,0x6,0xdd,0xcb,0xba, + 0x76,0x28,0x89,0xdd,0x7e,0xc4,0xe6,0x8,0x20,0xa,0xfd, + 0x7e,0x6,0xe6,0xef,0xfd,0x77,0x6,0x18,0x4,0xfd,0x36, + 0x6c,0x0,0xdd,0xcb,0xa8,0xee,0xdd,0xcb,0xa8,0xbe,0xdd, + 0xcb,0xa8,0xb6,0xc3,0xc1,0x19,0xdd,0xcb,0xa9,0x46,0x28, + 0x13,0xdd,0xcb,0xa9,0xce,0xdd,0xcb,0xa9,0x86,0xfd,0x7e, + 0x6,0xe6,0xf9,0xfd,0x77,0x6,0xc3,0x3e,0x19,0x79,0xcb, + 0x7f,0x20,0xc,0xfe,0xc,0xf2,0x86,0x1a,0xfe,0x0,0x28, + 0x52,0x47,0x18,0x2,0x6,0xc,0xdd,0x79,0xfe,0xa,0x28, + 0x8,0xfd,0x77,0x63,0x2c,0x10,0xf4,0x18,0x3f,0xfd,0x36, + 0x63,0xd,0xfd,0x36,0x63,0xa,0x18,0xf1,0xfe,0x0,0x28, + 0x31,0x47,0xdd,0x79,0xfd,0x77,0x63,0x2c,0x10,0xf8,0x18, + 0x26,0x79,0xe6,0xc0,0xfe,0x40,0x20,0x13,0xdd,0xcb,0xa9, + 0x5e,0xca,0xe4,0x18,0xdd,0xcb,0xa9,0x9e,0xdd,0x3e,0xc5, + 0x5,0x1,0xc3,0xe4,0x18,0xfe,0xc0,0xc2,0xe4,0x18,0xdd, + 0xcb,0xa9,0xde,0xc3,0xe4,0x18,0xfd,0x7e,0x6,0xe6,0xf9, + 0xfd,0x77,0x6,0xdd,0xcb,0xa8,0x86,0xc3,0x3e,0x19,0xdd, + 0xd1,0x7c,0x18,0xf5,0xc5,0xd5,0xe5,0xfd,0xe5,0xdd,0xe5, + 0x21,0x80,0x80,0x54,0xfd,0x7b,0x8,0x0,0xfd,0xed,0x3c, + 0x6,0x0,0xfe,0x24,0x28,0x4,0x6,0x4,0x18,0x2,0x6, + 0x0,0x78,0xed,0x3b,0x1a,0x0,0xfd,0x70,0x7f,0xfd,0x7e, + 0x69,0xcb,0x7f,0x28,0x2c,0xfd,0x5e,0x68,0xe6,0x3,0xfd, + 0x77,0x68,0xed,0x3a,0xa,0x0,0xb0,0xcb,0x27,0x85,0x6f, + 0xed,0x26,0xe5,0xdd,0xe1,0xc5,0xcd,0x6,0x9,0xdd,0x3e, + 0xc5,0x5,0x1,0xdd,0xcb,0xb9,0xce,0xfd,0x7e,0x69,0xe6, + 0x3f,0xfd,0x77,0x69,0xc1,0x62,0x2e,0x80,0xcb,0x50,0x28, + 0x4,0x6,0x0,0x18,0xba,0xe5,0xdd,0xe1,0xdd,0x66,0x1, + 0xfd,0xed,0xf7,0x80,0x0,0x20,0x99,0xdd,0xe1,0xfd,0xe1, + 0xe1,0xd1,0xc1,0xf1,0xed,0x55,0xe5,0x21,0xe8,0x3,0x2b, + 0xfd,0xed,0xf7,0x0,0x0,0x20,0xf8,0xe1,0xc9,0xcd,0xf5, + 0x8,0xdd,0x7e,0xc7,0xfe,0x1,0xc2,0x16,0x1c,0xfd,0x36, + 0x6f,0x3,0xcd,0x64,0x1b,0xfd,0x7e,0x6f,0xe6,0x20,0x20, + 0x7,0xdd,0x36,0xc8,0x9,0xc3,0x16,0x1c,0xfd,0x36,0x6f, + 0x2,0xcd,0x64,0x1b,0xfd,0x7e,0x6f,0xe6,0x20,0x28,0x6, + 0xdd,0x36,0xc8,0xa,0x18,0x70,0xfd,0x36,0x6f,0x6,0xcd, + 0x64,0x1b,0xfd,0x7e,0x6f,0xe6,0x10,0x20,0x6,0xdd,0x36, + 0xc8,0xb,0x18,0x5c,0xfd,0x36,0x6f,0x2,0xcd,0x64,0x1b, + 0xfd,0x7e,0x6f,0xe6,0x20,0x28,0x6,0xdd,0x36,0xc8,0xa, + 0x18,0x48,0x6,0x8,0xfd,0x36,0x6f,0x2,0xcd,0x64,0x1b, + 0xfd,0x36,0x6f,0x0,0xcd,0x64,0x1b,0xfd,0x7e,0x6f,0xe6, + 0x80,0x20,0x28,0x10,0xe9,0xfd,0x36,0x6f,0x2,0xcd,0x64, + 0x1b,0xfd,0x36,0x6f,0x0,0x21,0xe8,0x3,0xfd,0x7e,0x6f, + 0xe6,0x40,0x20,0x16,0x2b,0xfd,0xed,0xf7,0x0,0x0,0x20, + 0xf1,0xdd,0x36,0xc8,0xd,0xdd,0x77,0xb8,0x18,0x9,0xdd, + 0x70,0xc8,0x18,0x4,0xdd,0x36,0xc8,0x0,0xcd,0x64,0x1b, + 0xfd,0x36,0x6f,0x2,0xcd,0x64,0x1b,0xfd,0x36,0x6f,0x0, + 0xfd,0x36,0x5,0x80,0xdd,0x36,0xae,0x0,0xc9,0xcd,0xf5, + 0x8,0xdd,0xcb,0xa9,0x4e,0x20,0x23,0xdd,0xcb,0xa9,0xc6, + 0xdd,0x7e,0xc7,0xfe,0x1,0x28,0xf,0xfd,0x7e,0x6,0xf6, + 0x2,0xe6,0xfb,0xfd,0x77,0x6,0x26,0x0,0xc3,0xc,0xd, + 0xfd,0x36,0x6,0x84,0x26,0x0,0xc3,0xc,0xd,0xfd,0x7e, + 0x6,0xe6,0xf9,0xfd,0x77,0x6,0xfd,0x7e,0x9,0xf6,0x20, + 0xfd,0x77,0x9,0xfd,0x7e,0x50,0xfd,0x77,0x65,0xfd,0x36, + 0x63,0x0,0xfd,0x36,0x63,0x81,0xfd,0x36,0x12,0x2,0xdd, + 0x36,0xae,0x12,0xdd,0x3e,0xc5,0x5,0x1,0x26,0x0,0xc3, + 0xc,0xd,0xcd,0xf5,0x8,0xdd,0x7e,0xc5,0xfe,0x1,0x28, + 0x27,0xfd,0x7e,0x12,0xfe,0x0,0x28,0x5,0x26,0x0,0xc3, + 0xc,0xd,0xfd,0x7e,0x50,0xfd,0x77,0x65,0xfd,0x36,0x63, + 0x0,0xfd,0x36,0x63,0x83,0xfd,0x36,0x12,0x2,0xdd,0x36, + 0xc5,0x1,0x26,0x0,0xc3,0xc,0xd,0xfd,0x7e,0x12,0xfe, + 0x0,0x28,0x5,0x26,0x0,0xc3,0xc,0xd,0xfd,0x7e,0x6, + 0xf6,0x4,0xe6,0xfd,0xfd,0x77,0x6,0xfd,0x7e,0x9,0xe6, + 0xdf,0xfd,0x77,0x9,0xdd,0x36,0xae,0x0,0xdd,0x3e,0xc5, + 0x5,0x1,0xdd,0x36,0xc5,0x0,0x26,0x0,0xc3,0xc,0xd, + 0x26,0x0,0xdd,0x7e,0xac,0xdd,0x96,0xad,0x28,0x4,0xf1, + 0xc3,0x1d,0xd,0xcd,0xf5,0x8,0xdd,0x7e,0xbf,0xfe,0x1, + 0x28,0x4d,0xdd,0xcb,0xa9,0x4e,0x28,0x26,0xed,0x2c,0xa4, + 0xff,0xdd,0x7e,0xa7,0xfe,0x4,0xf2,0x21,0x1d,0xfd,0x1d, + 0x1c,0x0,0x20,0x35,0xf6,0x10,0xfd,0x77,0x7f,0x18,0x2e, + 0xfd,0x1d,0x1d,0x0,0x20,0x28,0xf6,0x40,0xfd,0x77,0x7f, + 0x18,0x21,0xdd,0x7e,0xc9,0xfe,0x1,0x20,0x10,0xdd,0xcb, + 0xa9,0xc6,0xdd,0x7e,0xc7,0xfe,0x1,0x28,0xa,0xfd,0x36, + 0x6,0x92,0xc9,0xdd,0xcb,0xa9,0xce,0xc9,0xfd,0x36,0x6, + 0x94,0xc9,0xdd,0x36,0xaa,0x0,0xdd,0x36,0xab,0x0,0xdd, + 0x36,0xac,0x0,0xdd,0x36,0xad,0x0,0xdd,0x36,0xc9,0x0, + 0xcd,0xf5,0x8,0xfd,0x7e,0x5,0xfe,0x0,0xc0,0xdd,0xcb, + 0xa9,0x8e,0xdd,0x7e,0xc7,0xfe,0x1,0x20,0x6,0xfd,0x36, + 0x5,0x14,0x18,0x32,0xdd,0xcb,0xb7,0x46,0x20,0x11,0xdd, + 0x7e,0xc4,0xe6,0x8,0x20,0x6,0xfd,0x36,0x6c,0x0,0x18, + 0x4,0xfd,0x36,0x6d,0x0,0xdd,0xcb,0xb7,0x4e,0x20,0x11, + 0xdd,0x7e,0xc4,0xe6,0x8,0x20,0x6,0xfd,0x36,0x6d,0x0, + 0x18,0x4,0xfd,0x36,0x6c,0x0,0xfd,0x36,0x5,0x80,0xfd, + 0x36,0x6,0x0,0xdd,0x36,0xbf,0x1,0xdd,0x36,0xae,0x10, + 0xdd,0x3e,0xc5,0x5,0x1,0xc9,0x2,0x44,0x2,0x44,0x2, + 0x40,0x2,0x40,0x2,0x40,0x2,0x40,0x2,0x44,0x2,0x44, + 0x2,0x44,0x2,0x44,0x2,0x44,0x2,0x40,0x2,0x40,0x2, + 0x44,0x2,0x44,0x20,0x1e,0x44,0x3,0x44,0x2,0x44,0x2, + 0x44,0x1,0x40,0x20,0x14,0x44,0x3,0x40,0x12,0x44,0x5, + 0x40,0x3,0x40,0x16,0x44,0x2,0x40,0x7,0x44,0xa,0x40, + 0x5,0x40,0x11,0x40,0x20,0x3,0x40,0x18,0x44,0x12,0x44, + 0x9,0x44,0x2,0x44,0x20,0x46,0x40,0x17,0x44,0x6,0x44, + 0x6,0x44,0x3,0x44,0x4,0x44,0xd,0x44,0x2,0x44,0x6, + 0x44,0x2,0x44,0x20,0x40,0x44,0x5,0x44,0x7,0x44,0x18, + 0x44,0x20,0xc,0x44,0x6,0x44,0x2,0x44,0x1,0x44,0xf, + 0x44,0x15,0x44,0x8,0x44,0xd,0x44,0x1d,0x44,0x1,0x44, + 0x14,0x40,0x8,0x40,0x3,0x44,0x6,0x40,0x3,0x44,0x6, + 0x40,0x3,0x44,0x6,0x40,0x3,0x44,0xf,0x44,0x4,0x44, + 0xf,0x44,0x4,0x44,0x3,0x44,0x20,0x34,0x44,0x4,0x44, + 0x11,0x44,0x4,0x44,0x14,0x44,0x4,0x44,0x2,0x40,0x1b, + 0x44,0xa,0x40,0x3,0x44,0x5,0x40,0x5,0x44,0xf,0x40, + 0x2,0x44,0x2,0x40,0x20,0xe,0x44,0x18,0x40,0x10,0x44, + 0x5,0x44,0x5,0x44,0xb,0x44,0x14,0x44,0x3,0x44,0x8, + 0x44,0x2,0x44,0x10,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x40,0x40,0x44,0x44,0x40,0x40,0x20,0x0,0x44,0x20,0x1, + 0x44,0x10,0x44,0x10,0x44,0x5,0x44,0x20,0x4,0x44,0x14, + 0x44,0x6,0x44,0xa,0x44,0x4,0x44,0x4,0x44,0x5,0x44, + 0x3,0x44,0xf,0x44,0xb,0x44,0x3,0x44,0x3,0x44,0x3, + 0x44,0xc,0x44,0x5,0x44,0x3,0x44,0x5,0x44,0xe,0x44, + 0x6,0x44,0xb,0x44,0x7,0x44,0x2,0x44,0x3,0x44,0x6, + 0x44,0xd,0x44,0x6,0x44,0x2,0x44,0x3,0x44,0x5,0x44, + 0x20,0x2,0x44,0x3,0x44,0x5,0x44,0x16,0x44,0x1a,0x44, + 0xe,0x44,0x16,0x44,0x3,0x44,0x5,0x44,0x4,0x44,0x19, + 0x44,0x4,0x44,0x1,0x44,0x3,0x44,0x5,0x44,0x5,0x44, + 0x6,0x44,0x2,0x44,0xc,0x44,0x5,0x44,0x9,0x44,0xa, + 0x44,0xb,0x44,0x8,0x44,0x20,0x9,0x44,0x12,0x44,0x2, + 0x44,0x20,0x1c,0x44,0x20,0x34,0x44,0x11,0x44,0x20,0x28, + 0x44,0x10,0x44,0x12,0x40,0x3,0x40,0x20,0x1,0x40,0x3, + 0x40,0x21,0x4f,0x44,0x20,0x4b,0x44,0x20,0x34,0x40,0x3, + 0x44,0xd,0x40,0x8,0x44,0x8,0x44,0x3,0x44,0x1,0x44, + 0x3,0x44,0x1,0x40,0x3,0x44,0x1,0x40,0x3,0x44,0x3, + 0x44,0x1,0x44,0xa,0x44,0xb,0x44,0x15,0x40,0x16,0x40, + 0x6,0x44,0xe,0x40,0x6,0x40,0x4,0x44,0x44,0x44,0x44, + 0x44,0x44,0x40,0x40,0x44,0x44,0x44,0x44,0x44,0x44,0x44, + 0x44,0x44,0x44,0xf,0x44,0x6,0x44,0x5,0x44,0x20,0x8, + 0x44,0x20,0x31,0x44,0x3,0x44,0x4,0x44,0xa,0x44,0x5, + 0x44,0xd,0x44,0x20,0x4,0x40,0x13,0x40,0x20,0x4a,0x40, + 0x21,0x30,0x40,0x14,0x44,0x6,0x40,0x15,0x44,0x6,0x40, + 0x20,0x7f,0x40,0x20,0x22,0x40,0x20,0x61,0x40,0x20,0x25, + 0x40,0x20,0x3b,0x40,0x4,0x40,0x20,0xe1,0x40,0x1f,0x40, + 0x6,0x44,0x3,0x40,0x5,0x40,0x20,0x13,0x44,0x1d,0x40, + 0x20,0xe,0x44,0x2,0x40,0x2,0x40,0x3,0x44,0x20,0x5, + 0x40,0x2,0x40,0x3,0x44,0x1,0x44,0x1d,0x44,0x20,0x2, + 0x44,0x7,0x40,0x7,0x44,0x1,0x40,0x6,0x40,0x9,0x40, + 0x4,0x40,0x13,0x40,0x1,0x44,0x20,0x3,0x44,0xb,0x40, + 0xa,0x40,0x12,0x40,0x5,0x44,0x20,0x3,0x40,0x6,0x44, + 0x4,0x44,0x4,0x44,0x16,0x40,0x23,0x19,0x44,0x20,0xd, + 0x44,0x16,0x44,0x13,0x44,0x6,0x44,0x8,0x44,0x20,0x40, + 0x44,0xe,0x44,0x20,0x13,0x44,0x6,0x40,0x14,0x44,0x4, + 0x44,0x6,0x44,0x1a,0x40,0x20,0x55,0x44,0x17,0x44,0x8, + 0x44,0x20,0x1c,0x44,0x6,0x40,0x2,0x44,0x3,0x44,0x5, + 0x44,0xd,0x44,0x2,0x44,0x20,0x26,0x40,0x2,0x40,0x20, + 0x1f,0x40,0x6,0x44,0x5,0x44,0xc,0x44,0x5,0x44,0x12, + 0x44,0x12,0x44,0x14,0x44,0x5,0x44,0xe,0x44,0x20,0x9, + 0x44,0x5,0x44,0xe,0x40,0x1e,0x40,0x7,0x40,0x20,0x8, + 0x40,0x4,0x40,0x1,0x40,0x11,0x40,0x19,0x40,0xa,0x40, + 0x18,0x40,0x8,0x40,0xc,0x40,0x1,0x40,0x17,0x44,0x20, + 0x30,0x40,0x20,0x37,0x40,0x0,0x0,0xff, +}; +int si_dsize = sizeof(si_download); diff --git a/sys/i386/isa/sireg.h b/sys/i386/isa/sireg.h new file mode 100644 index 0000000000000..6a8dd4fc88f8c --- /dev/null +++ b/sys/i386/isa/sireg.h @@ -0,0 +1,69 @@ +/* + * Device driver for Specialix range (SLXOS) of serial line multiplexors. + * 'C' definitions for Specialix serial multiplex driver. + * + * Copyright (C) 1990, 1992 Specialix International, + * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> + * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> + * + * Derived from: SunOS 4.x version + * + * 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 + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, 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 Andy Rutter of + * Advanced Methods and Tools Ltd. based on original information + * from Specialix International. + * 4. Neither the name of Advanced Methods and Tools, nor Specialix + * International may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``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 AUTHORS BE LIABLE. + * + * $Id$ + */ + +/* + * Hardware parameters which should be changed at your peril! + */ + +/* Base and mask for SI Host 2.x (SIHOST2) */ +#define SIPLSIG 0x7FF8 /* Start of control space */ +#define SIPLCNTL 0x7FF8 /* Ditto */ +#define SIPLRESET SIPLCNTL /* 0 = reset */ +#define SIPLIRQ11 (SIPLCNTL+1) /* 0 = mask irq 11 */ +#define SIPLIRQ12 (SIPLCNTL+2) /* 0 = mask irq 12 */ +#define SIPLIRQ15 (SIPLCNTL+3) /* 0 = mask irq 15 */ +#define SIPLIRQSET (SIPLCNTL+4) /* 0 = interrupt host */ +#define SIPLIRQCLR (SIPLCNTL+5) /* 0 = clear irq */ + +/* SI Host 1.x */ +#define SIRAM 0x0000 /* Ram Starts here */ +#define SIRESET 0x8000 /* Set reset */ +#define SIRESET_CL 0xc000 /* Clear reset */ +#define SIWAIT 0x9000 /* Set wait */ +#define SIWAIT_CL 0xd000 /* Set wait */ +#define SIINTCL 0xA000 /* Clear host int */ +#define SIINTCL_CL 0xE000 /* Clear host int */ + +/* + * MEMSIZE is the total shared mem region + * RAMSIZE is value to use when probing + */ +#define SIHOST_MEMSIZE 0x10000 +#define SIHOST_RAMSIZE 0x8000 +#define SIHOST2_MEMSIZE 0x8000 +#define SIHOST2_RAMSIZE 0x7ff7 +#define SIEISA_MEMSIZE 0x10000 +#define SEISAT_RAMSIZE 0x10000 + diff --git a/sys/i386/isa/sound/Readme.aedsp16 b/sys/i386/isa/sound/Readme.aedsp16 new file mode 100644 index 0000000000000..b205a9d0ff56f --- /dev/null +++ b/sys/i386/isa/sound/Readme.aedsp16 @@ -0,0 +1,6 @@ +Informations about Audio Excel DSP 16 can be found in the source +file aedsp16.c +Please, read the head of the source before using it. It contain useful +informations. + + Riccardo diff --git a/sys/i386/isa/sound/Readme.modules b/sys/i386/isa/sound/Readme.modules new file mode 100644 index 0000000000000..315540f510c17 --- /dev/null +++ b/sys/i386/isa/sound/Readme.modules @@ -0,0 +1,87 @@ + Linux sound-driver module + (c) Peter Trattler + License: GPL (Gnu Public License) + + +Idea: + +I've modified the sources for the sound driver to allow simply insert and +remove the sound driver from the kernel by calling (only available for Linux) + + insmod /usr/src/linux/modules/sound.o + +and + + rmmod sound + +This may be useful if you are doing one of the following things: + +1) Debugging the sound driver +2) Creating a new device within the sound-driver +3) You do not the sound driver all the time (as it wastes quite a lot of +memory for its buffers) + + +Compilation: + +Go to /usr/src/linux and make the following steps: + +a) configure the sound driver: To do that call "make config" and enable the +sound-driver -- you will be asked different questions about your +sound-hardware (remember not to use a too big DMA-Buffer size; you +should use 16kB, if you have 16Bit devices, otherwise you can use 32kB) + +b) disable the sound driver in the kernel: call make config again but answer +'N' to "Sound card support" + +c) run "make modules"; the sound-driver sound.o should end up in +/usr/src/linux/modules + + +If memory is tight: + +I've allocated at about 70kB for the sound-drivers internal tables. If this +is too much, 'insmod sound.o' will generate the following warning +... +use 'insmod memsize=xxxx' +... +You can only use this command, if you have (I think) at least +modules-1.1.87 or up. You can also switch debugging on by running the command + +insmod sound.o debugmem=1 + + +Files I changed: + +I've only changed the files soundcard.c(most changes) and some changes within +the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers + + +Bugs: + +a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if +it is my fault), I created some code, which is (by default) enabled by + +#define KMALLOC_DMA_BROKEN 1 (within soundcard.c). + +It trys to allocate a large enough region, so that the complete dma-buffer +can be occupied in this space. If it does not fit within this region it +doubles the size of it. But this can cause problems, if the sound-buffer is +too big (as kmalloc can only handle regions at up to circa 100kB). + +So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum) +and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme +might fail. + +b) Buffers allocated by the different sound devices via calls to kmalloc are +not freed, if the sound driver is removed again (these buffers tend to be +quite small -- so it does not harm a lot) + +c) If there is not enough (kernel-) memory available, the installation of +the sound-driver fails. (This happens quite often, if you did not install the +driver right after booting -- [PS: I've only got 5MB of Ram, so this might +be the source for this problem]) + + +Author: + Peter Trattler (peter@sbox.tu-graz.ac.at) diff --git a/sys/i386/isa/sound/ad1848_mixer.h b/sys/i386/isa/sound/ad1848_mixer.h new file mode 100644 index 0000000000000..9404047ce77de --- /dev/null +++ b/sys/i386/isa/sound/ad1848_mixer.h @@ -0,0 +1,130 @@ +/* + * sound/ad1848_mixer.h + * + * Definitions for the mixer of AD1848 and compatible codecs. + * + * Copyright by Hannu Savolainen 1994 + * + * 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. + */ +/* + * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. + * Soundcard manufacturers have connected actual inputs (CD, synth, line, + * etc) to these inputs in different order. Therefore it's difficult + * to assign mixer channels to to these inputs correctly. The following + * contains two alternative mappings. The first one is for GUS MAX and + * the second is just a generic one (line1, line2 and line3). + * (Actually this is not a mapping but rather some kind of interleaving + * solution). + */ +#ifdef GUSMAX_MIXER +#define MODE1_REC_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_MIC | \ + SOUND_MASK_CD | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM|SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#else /* Generic mapping */ +#define MODE1_REC_DEVICES (SOUND_MASK_LINE3 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE1) + +#define MODE1_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE2 | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) + +#define MODE2_MIXER_DEVICES (SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \ + SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \ + SOUND_MASK_IGAIN | \ + SOUND_MASK_PCM | SOUND_MASK_IMIX) +#endif + +struct mixer_def { + unsigned int regno: 7; + unsigned int polarity:1; /* 0=normal, 1=reversed */ + unsigned int bitpos:4; + unsigned int nbits:4; +}; + + +typedef struct mixer_def mixer_ent; + +/* + * Most of the mixer entries work in backwards. Setting the polarity field + * makes them to work correctly. + * + * The channel numbering used by individual soundcards is not fixed. Some + * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs. + * The current version doesn't try to compensate this. + */ + +#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \ + {{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}} + +mixer_ent mix_devices[32][2] = { /* As used in GUS MAX */ +MIX_ENT(SOUND_MIXER_VOLUME, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_PCM, 6, 1, 0, 6, 7, 1, 0, 6), +MIX_ENT(SOUND_MIXER_SPEAKER, 26, 1, 0, 4, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 18, 1, 0, 5, 19, 1, 0, 5), +MIX_ENT(SOUND_MIXER_MIC, 0, 1, 5, 1, 1, 1, 5, 1), +MIX_ENT(SOUND_MIXER_CD, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_IMIX, 13, 1, 2, 6, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 4, 1, 0, 0, 4), +MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0), +MIX_ENT(SOUND_MIXER_LINE1, 2, 1, 0, 5, 3, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE2, 4, 1, 0, 5, 5, 1, 0, 5), +MIX_ENT(SOUND_MIXER_LINE3, 18, 1, 0, 5, 19, 1, 0, 5) +}; + +static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] = +{ + 0x5a5a, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x4b4b, /* FM */ + 0x6464, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x1010, /* Mic */ + 0x4b4b, /* CD */ + 0x0000, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b, /* Recording level */ + 0x4b4b, /* Input gain */ + 0x4b4b, /* Output gain */ + 0x4b4b, /* Line1 */ + 0x4b4b, /* Line2 */ + 0x4b4b /* Line3 */ +}; + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 diff --git a/sys/i386/isa/sound/aedsp16.c b/sys/i386/isa/sound/aedsp16.c new file mode 100644 index 0000000000000..b14a24618f0cc --- /dev/null +++ b/sys/i386/isa/sound/aedsp16.c @@ -0,0 +1,838 @@ +/* + sound/aedsp16.c + + Audio Excel DSP 16 software configuration routines + + Copyright (C) 1995 Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it) + + 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. + + READ THIS + + This module is intended for Audio Excel DSP 16 Sound Card. + + Audio Excel DSP 16 is an SB pro II, Microsoft Sound System + and MPU-401 compatible card. + It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq), + so before this module, the only way to configure the DSP under linux was + boot the MS-BAU loading the sound.sys device driver (this driver soft- + configure the sound board hardware by massaging someone of its registers), + and then ctrl-alt-del to boot linux with the DSP configured by the DOG + driver. + + This module works configuring your Audio Excel DSP 16's + irq, dma and mpu-401-irq. The voxware probe routines rely on the + fact that if the hardware is there, they can detect it. The problem + with AEDSP16 is that no hardware can be found by the probe routines + if the sound card is not well configured. Sometimes the kernel probe + routines can find an SBPRO even when the card is not configured (this + is the standard setup of the card), but the SBPRO emulation don't work + well if the card is not properly initialized. For this reason + + InitAEDSP16_...() + + routines are called before the voxware probe routines try to detect the + hardware. + + NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS) + + The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; + the voxware sound driver can be configured for SBPRO and MSS cards + at the same time, but the aedsp16 can't be two cards!! + When we configure it, we have to choose the SBPRO or the MSS emulation + for AEDSP16. We also can install a *REAL* card of the other type + (see [1], not tested but I can't see any reason for it to fail). + + NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO + please let me know if it works. + + The MPU-401 support can be compiled in together with one of the other + two operating modes. + + The board configuration calls, are in the probe_...() routines because + we have to configure the board before probing it for a particular + hardware. After card configuration, we can probe the hardware. + + NOTE: This is something like plug-and-play: we have only to plug + the AEDSP16 board in the socket, and then configure and compile + a kernel that uses the AEDSP16 software configuration capability. + No jumper setting is needed! + + For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3 + you have just to make config the voxware package, configuring + the SBPro sound card with that parameters, then when configure + asks if you have an AEDSP16, answer yes. That's it. + Compile the kernel and run it. + + NOTE: This means that you can choose irq and dma, but not the + I/O addresses. To change I/O addresses you have to set them + with jumpers. + + NOTE: InitAEDSP16_...() routines get as parameter the hw_config, + the hardware configuration of the - to be configured - board. + The InitAEDSP16() routine, configure the board following our + wishes, that are in the hw_config structure. + + You can change the irq/dma/mirq settings WITHOUT THE NEED to open + your computer and massage the jumpers (there are no irq/dma/mirq + jumpers to be configured anyway, only I/O port ones have to be + configured with jumpers) + + For some ununderstandable reason, the card default of irq 7, dma 1, + don't work for me. Seems to be an IRQ or DMA conflict. Under heavy + HDD work, the kernel start to erupt out a lot of messages like: + + 'Sound: DMA timed out - IRQ/DRQ config error?' + + For what I can say, I have NOT any conflict at irq 7 (under linux I'm + using the lp polling driver), and dma line 1 is unused as stated by + /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so + I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows! + Anyway a setting of irq 10, dma 3 works really fine. + + NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know + the emulation mode, all the installed hardware and the hardware + configuration (irq and dma settings of all the hardware). + + This init module should work with SBPRO+MSS, when one of the two is + the AEDSP16 emulation and the other the real card. (see [1]) + For example: + + AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other + AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other + + MPU401 should work. (see [1]) + + [1] Not tested by me for lack of hardware. + + TODO, WISHES AND TECH + + May be there's lot of redundant delays, but for now I want to leave it + this way. + + Should be interesting eventually write down a new ioctl for the + aedsp16, to let the suser() change the irq/dma/mirq on the fly. + The thing is not trivial. + In the real world, there's no need to have such an ioctl because + when we configure the kernel for compile, we can choose the config + parameters. If we change our mind, we can easily re-config the kernel + and re-compile. + Why let the suser() change the config parameters on the fly ? + If anyone have a reasonable answer to this question, I will write down + the code to do it. + + More integration with voxware, using voxware low level routines to + read-write dsp is not possible because you may want to have MSS + support and in that case we can not rely on the functions included + in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my + own I/O functions. + + - About I/O ports allocation - + + The request_region should be done at device probe in every sound card + module. This module is not the best site for requesting regions. + When the request_region code will be added to the main modules such as + sb, adlib, gus, ad1848, etc, the requesting code in this module should + go away. + + I think the request regions should be done this way: + + if (check_region(...)) + return ERR; // I/O region alredy reserved + device_probe(...); + device_attach(...); + request_region(...); // reserve only when we are sure all is okay + + Request the 2x0h region in any case if we are using this card. + + NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region + (see code) does not mean necessarly that we are emulating sbpro. + It mean that the region is the sbpro I/O ports region. We use this + region to access the control registers of the card, and if emulating + sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro + registers are not used, in no way, to emulate an sbpro: they are + used only for configuration pourposes. + + Someone pointed out that should be possible use both the SBPRO and MSS + modes because the sound card have all the two chipsets, supposing that + the card is really two cards. I have tried something to have the two + modes work together, but, for some reason unknown to me, without success. + + I think all the soft-config only cards have an init sequence similar to + this. If you have a card that is not an aedsp16, you can try to start + with this module changing it (mainly in the CMD? I think) to fit your + needs. + + Started Fri Mar 17 16:13:18 MET 1995 + + v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c) + - Initial code. + v0.2 (ALPHA) + - Cleanups. + - Integrated with Linux voxware v 2.90-2 kernel sound driver. + - SoundBlaster Pro mode configuration. + - Microsoft Sound System mode configuration. + - MPU-401 mode configuration. + v0.3 (ALPHA) + - Cleanups. + - Rearranged the code to let InitAEDSP16 be more general. + - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h + inclusion too. We rely on os.h + - Used the INB and OUTB #defined in os.h instead of inb and outb. + - Corrected the code for GetCardName (DSP Copyright) to get a variable + len string (we are not sure about the len of Copyright string). + This works with any SB and compatible. + - Added the code to request_region at device init (should go in + the main body of voxware). + v0.4 (BETA) + - Better configure.c patch for aedsp16 configuration (better + logic of inclusion of AEDSP16 support) + - Modified the conditional compilation to better support more than + one sound card of the emulated type (read the NOTES above) + - Moved the sb init routine from the attach to the very first + probe in sb_card.c + - Rearrangemens and cleanups + - Wiped out some unnecessary code and variables: this is kernel + code so it is better save some TEXT and DATA + - Fixed the request_region code. We must allocate the aedsp16 (sbpro) + I/O ports in any case because they are used to access the DSP + configuration registers and we can not allow anyone to get them. + v0.5 + - cleanups on comments + - prep for diffs against v3.0-proto-950402 + + */ + +/* + * Include the main voxware header file. It include all the os/voxware/etc + * headers needed by this source. + */ +#include "sound_config.h" +/* + * all but ioport.h :) + */ +#include <linux/ioport.h> + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16) + +#define VERSION "0.5" /* Version of Audio Excel DSP 16 driver */ + +#undef AEDSP16_DEBUG /* Define this to enable debug code */ +/* Actually no debug code is activated */ + +/* + * Hardware related defaults + */ +#define IRQ 7 /* 5 7(default) 9 10 11 */ +#define MIRQ 0 /* 5 7 9 10 0(default), 0 means disable */ +#define DMA 1 /* 0 1(default) 3 */ + +/* + * Commands of AEDSP16's DSP (SBPRO+special). + * For now they are CMDn, in the future they may change. + */ +#define CMD1 0xe3 /* Get DSP Copyright */ +#define CMD2 0xe1 /* Get DSP Version */ +#define CMD3 0x88 /* */ +#define CMD4 0x5c /* */ +#define CMD5 0x50 /* Set M&I&DRQ mask (the real config) */ +#define CMD6 0x8c /* Enable Microsoft Sound System mode */ + +/* + * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase + * to have the actual I/O port. + * Register permissions are: + * (wo) == Write Only + * (ro) == Read Only + * (w-) == Write + * (r-) == Read + */ +#define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ +#define DSP_READ 0x0a /* offset of DSP READ (ro) */ +#define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ +#define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ +#define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ +#define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ + + +#define RETRY 10 /* Various retry values on I/O opera- */ +#define STATUSRETRY 1000 /* tions. Sometimes we have to */ +#define HARDRETRY 500000 /* wait for previous cmd to complete */ + +/* + * Size of character arrays that store name and version of sound card + */ +#define CARDNAMELEN 15 /* Size of the card's name in chars */ +#define CARDVERLEN 2 /* Size of the card's version in chars */ + +/* + * Bit mapped flags for calling InitAEDSP16(), and saving the current + * emulation mode. + */ +#define INIT_NONE (0 ) +#define INIT_SBPRO (1<<0) +#define INIT_MSS (1<<1) +#define INIT_MPU401 (1<<2) +#define RESET_DSP16 (1<<3) + +/* Base HW Port for Audio Card */ +static int portbase = AEDSP16_BASE; +static int irq = IRQ; /* irq for DSP I/O */ +static int mirq = MIRQ; /* irq for MPU-401 I/O */ +static int dma = DMA; /* dma for DSP I/O */ + +/* Init status of the card */ +static int ae_init = INIT_NONE; /* (bitmapped variable) */ +static int oredparams = 0; /* Will contain or'ed values of params */ +static int gc = 0; /* generic counter (utility counter) */ +struct orVals + { /* Contain the values to be or'ed */ + int val; /* irq|mirq|dma */ + int or; /* oredparams |= TheStruct.or */ + }; + +/* + * Magic values that the DSP will eat when configuring irq/mirq/dma + */ +/* DSP IRQ conversion array */ +static struct orVals orIRQ[] = +{ + {0x05, 0x28}, + {0x07, 0x08}, + {0x09, 0x10}, + {0x0a, 0x18}, + {0x0b, 0x20}, + {0x00, 0x00} +}; + +/* MPU-401 IRQ conversion array */ +static struct orVals orMIRQ[] = +{ + {0x05, 0x04}, + {0x07, 0x44}, + {0x09, 0x84}, + {0x0a, 0xc4}, + {0x00, 0x00} +}; + +/* DMA Channels conversion array */ +static struct orVals orDMA[] = +{ + {0x00, 0x01}, + {0x01, 0x02}, + {0x03, 0x03}, + {0x00, 0x00} +}; + +/* + * Buffers to store audio card informations + */ +static char AudioExcelName[CARDNAMELEN + 1]; +static char AudioExcelVersion[CARDVERLEN + 1]; + +static void +tenmillisec (void) +{ + + for (gc = 0; gc < 1000; gc++) + tenmicrosec (); +} + +static int +WaitForDataAvail (int port) +{ + int loop = STATUSRETRY; + unsigned char ret = 0; + + do + { + ret = INB (port + DSP_DATAVAIL); + /* + * Wait for data available (bit 7 of ret == 1) + */ + } + while (!(ret & 0x80) && loop--); + + if (ret & 0x80) + return 0; + + return -1; +} + +static int +ReadData (int port) +{ + if (WaitForDataAvail (port)) + return -1; + return INB (port + DSP_READ); +} + +static int +CheckDSPOkay (int port) +{ + return ((ReadData (port) == 0xaa) ? 0 : -1); +} + +static int +ResetBoard (int port) +{ + /* + * Reset DSP + */ + OUTB (1, (port + DSP_RESET)); + tenmicrosec (); + OUTB (0, (port + DSP_RESET)); + tenmicrosec (); + tenmicrosec (); + return CheckDSPOkay (port); +} + +static int +WriteDSPCommand (int port, int cmd) +{ + unsigned char ret; + int loop = HARDRETRY; + + do + { + ret = INB (port + DSP_STATUS); + /* + * DSP ready to receive data if bit 7 of ret == 0 + */ + if (!(ret & 0x80)) + { + OUTB (cmd, port + DSP_COMMAND); + return 0; + } + } + while (loop--); + + printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd); + return -1; +} + +int +InitMSS (int port) +{ + + tenmillisec (); + + if (WriteDSPCommand (port, CMD6)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6); + return -1; + } + + tenmillisec (); + + return 0; +} + +static int +SetUpBoard (int port) +{ + int loop = RETRY; + + do + { + if (WriteDSPCommand (portbase, CMD3)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3); + return -1; + } + + tenmillisec (); + + } + while (WaitForDataAvail (port) && loop--); + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (port)) + { + printk ("[aedsp16] CheckDSPOkay: failed\n"); + return -1; + } +#else + if (ReadData (port) == -1) + { + printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD4)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4); + return -1; + } + + if (WriteDSPCommand (portbase, CMD5)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5); + return -1; + } + + if (WriteDSPCommand (portbase, oredparams)) + { + printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n"); + return -1; + } + return 0; +} + +static int +GetCardVersion (int port) +{ + int len = 0; + int ret; + int ver[3]; + + do + { + if ((ret = ReadData (port)) == -1) + return -1; + /* + * We alredy know how many int are stored (2), so we know when the + * string is finished. + */ + ver[len++] = ret; + } + while (len < CARDVERLEN); + sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]); + return 0; +} + +static int +GetCardName (int port) +{ + int len = 0; + int ret; + + do + { + if ((ret = ReadData (port)) == -1) + /* + * If no more data availabe, return to the caller, no error if len>0. + * We have no other way to know when the string is finished. + */ + return (len ? 0 : -1); + + AudioExcelName[len++] = ret; + + } + while (len < CARDNAMELEN); + return 0; +} + +static void +InitializeHardParams (void) +{ + + memset (AudioExcelName, 0, CARDNAMELEN + 1); + memset (AudioExcelVersion, 0, CARDVERLEN + 1); + + for (gc = 0; orIRQ[gc].or; gc++) + if (orIRQ[gc].val == irq) + oredparams |= orIRQ[gc].or; + + for (gc = 0; orMIRQ[gc].or; gc++) + if (orMIRQ[gc].or == mirq) + oredparams |= orMIRQ[gc].or; + + for (gc = 0; orDMA[gc].or; gc++) + if (orDMA[gc].val == dma) + oredparams |= orDMA[gc].or; +} + +static int +InitAEDSP16 (int which) +{ + static char *InitName = NULL; + + InitializeHardParams (); + + if (ResetBoard (portbase)) + { + printk ("[aedsp16] ResetBoard: failed!\n"); + return -1; + } + +#if defined(THIS_SHOULD_GO_AWAY) + if (CheckDSPOkay (portbase)) + { + printk ("[aedsp16] CheckDSPOkay: failed!\n"); + return -1; + } +#endif + + if (WriteDSPCommand (portbase, CMD1)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1); + return -1; + } + + if (GetCardName (portbase)) + { + printk ("[aedsp16] GetCardName: failed!\n"); + return -1; + } + + /* + * My AEDSP16 card return SC-6000 in AudioExcelName, so + * if we have something different, we have to be warned. + */ + if (strcmp ("SC-6000", AudioExcelName)) + printk ("[aedsp16] Warning: non SC-6000 audio card!\n"); + + if (WriteDSPCommand (portbase, CMD2)) + { + printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2); + return -1; + } + + if (GetCardVersion (portbase)) + { + printk ("[aedsp16] GetCardVersion: failed!\n"); + return -1; + } + + if (SetUpBoard (portbase)) + { + printk ("[aedsp16] SetUpBoard: failed!\n"); + return -1; + } + + if (which == INIT_MSS) + { + if (InitMSS (portbase)) + { + printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n"); + return -1; + } + } + + /* + * If we are resetting, do not print any message because we may be + * in playing and we do not want lost too much time. + */ + if (!(which & RESET_DSP16)) + { + if (which & INIT_MPU401) + InitName = "MPU401"; + else if (which & INIT_SBPRO) + InitName = "SBPro"; + else if (which & INIT_MSS) + InitName = "MSS"; + else + InitName = "None"; + + printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n", + VERSION, AudioExcelName, + AudioExcelVersion, InitName); + } + + tenmillisec (); + + return 0; +} + +#if defined(AEDSP16_SBPRO) + +int +InitAEDSP16_SBPRO (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed MSS, we can not init it to SBPRO too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_MSS) + return -1; + if (ae_init & INIT_SBPRO) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (hw_config->io_base, 0x0f)) + { + printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * Set up the internal hardware parameters, to let the driver reach + * the Sound Card. + */ + portbase = hw_config->io_base; + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_SBPRO)) + return -1; + + if (!(ae_init & INIT_MPU401)) + request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_SBPRO; + return 0; +} + +#endif /* AEDSP16_SBPRO */ + +#if defined(AEDSP16_MSS) + +int +InitAEDSP16_MSS (struct address_info *hw_config) +{ + /* + * If the card is alredy init'ed SBPRO, we can not init it to MSS too + * because the board can not emulate simultaneously MSS and SBPRO. + */ + if (ae_init & INIT_SBPRO) + return -1; + if (ae_init & INIT_MSS) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x08)) + { + printk ("MSS I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & INIT_MPU401)) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + + /* + * If we are configuring the card for MSS, the portbase for card configuration + * is the default one (0x220 unless you have changed the factory default + * with board switches), so no need to modify the portbase variable. + * The default is AEDSP16_BASE, that is the right value. + */ + irq = hw_config->irq; + dma = hw_config->dma; + if (InitAEDSP16 (INIT_MSS)) + return -1; + + request_region (hw_config->io_base, 0x08, "aedsp16 (mss)"); + + if (!(ae_init & INIT_MPU401)) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MSS; + return 0; +} + +#endif /* AEDSP16_MSS */ + +#if defined(AEDSP16_MPU401) + +int +InitAEDSP16_MPU401 (struct address_info *hw_config) +{ + if (ae_init & INIT_MPU401) + return 0; + + /* + * For now we will leave this + * code included only when INCLUDE_AEDSP16 is configured in, but it should + * be better include it every time. + */ + if (check_region (hw_config->io_base, 0x02)) + { + printk ("SB I/O port region is alredy in use.\n"); + return -1; + } + + /* + * We must allocate the AEDSP16 region too because these are the I/O ports + * to access card's control registers. + */ + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + { + if (check_region (AEDSP16_BASE, 0x0f)) + { + printk ("AEDSP16 I/O port region is alredy in use.\n"); + return -1; + } + } + + /* + * If mpu401, the irq and dma are not important, do not touch it + * because we may use the default if sbpro is not yet configured, + * we may use the sbpro ones if configured, and nothing wrong + * should happen. + * + * The mirq default is 0, but once set it to non-0 value, we should + * not touch it anymore (unless I write an ioctl to do it, of course). + */ + mirq = hw_config->irq; + if (InitAEDSP16 (INIT_MPU401)) + return -1; + + request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)"); + + if (!(ae_init & (INIT_MSS | INIT_SBPRO))) + request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + + ae_init |= INIT_MPU401; + return 0; +} + +#endif /* AEDSP16_MPU401 */ + +#if 0 /* Leave it out for now. We are not using this portion of code. */ + +/* + * Entry point for a reset function. + * May be I will write the infamous ioctl :) + */ +int +ResetAEDSP16 (void) +{ +#if defined(AEDSP16_DEBUG) + printk ("[aedsp16] ResetAEDSP16 called.\n"); +#endif + return InitAEDSP16 (RESET_DSP16); +} + +#endif /* 0 */ + +#endif /* !EXCLUDE_AEDSP16 */ diff --git a/sys/i386/isa/sound/coproc.h b/sys/i386/isa/sound/coproc.h new file mode 100644 index 0000000000000..f9023821d3f25 --- /dev/null +++ b/sys/i386/isa/sound/coproc.h @@ -0,0 +1,12 @@ +/* + * Definitions for various on board processors on the soundcards. For + * example DSP processors. + */ + +/* + * Coprocessor access types + */ +#define COPR_CUSTOM 0x0001 /* Custom applications */ +#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */ +#define COPR_PCM 0x0004 /* Digitized voice applications */ +#define COPR_SYNTH 0x0008 /* Music synthesis */ diff --git a/sys/i386/isa/sound/hex2hex.h b/sys/i386/isa/sound/hex2hex.h new file mode 100644 index 0000000000000..ecd7b4c4239c6 --- /dev/null +++ b/sys/i386/isa/sound/hex2hex.h @@ -0,0 +1,97 @@ +/* + * This file is a part of configure.c + * + * hex2hex reads an input file in Intel HEX format and produces + * an (unsigned char) array which contains the bytes and writes it to the + * output file using C syntax + */ + +#define MAX_SIZE (256*1024) +#define ABANDON(why) { \ + fprintf(stderr, "%s: " why "\n", source); \ + fclose(inf);fclose(outf);return 0; \ + } + +int hex2hex(char *source, char *target, char *varline) +{ + FILE *inf, *outf; + + int i,l, c; + unsigned char buf[MAX_SIZE]; + + if ((inf=fopen(source, "r"))==NULL) + { + perror(source); + return 0; + } + + if ((outf=fopen(target, "w"))==NULL) + { + perror(target); + fclose(inf); + return 0; + } + + l=0; + + while ((c=getc(inf))!=EOF) + { + if (c == ':') /* Sync with beginning of line */ + { + int n, check; + unsigned char sum; + int addr; + int linetype; + + if (fscanf(inf, "%02x", &n) != 1) + ABANDON("File format error"); + sum = n; + + if (fscanf(inf, "%04x", &addr) != 1) + ABANDON("File format error"); + sum += addr/256; + sum += addr%256; + + if (fscanf(inf, "%02x", &linetype) != 1) + ABANDON("File format error"); + sum += linetype; + + if (linetype != 0) + continue; + + for (i=0;i<n;i++) + { + if (fscanf(inf, "%02x", &c) != 1) + ABANDON("File format error"); + if (addr >= MAX_SIZE) + ABANDON("File too large"); + buf[addr++] = c; + if (addr > l) + l = addr; + sum += c; + } + + if (fscanf(inf, "%02x", &check) != 1) + ABANDON("File format error"); + + sum = ~sum + 1; + if (check != sum) + ABANDON("Line checksum error"); + } + } + + fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n"); + fprintf(outf, "%s[] = {\n", varline); + + for (i=0;i<l;i++) + { + if (i) fprintf(outf, ","); + if (i && !(i % 16)) fprintf(outf, "\n"); + fprintf(outf, "0x%02x", buf[i]); + } + + fprintf(outf, "\n};\n\n"); + fclose(inf); + fclose(outf); + return 1; +} diff --git a/sys/i386/isa/sound/mad16.h b/sys/i386/isa/sound/mad16.h new file mode 100644 index 0000000000000..0370973667a40 --- /dev/null +++ b/sys/i386/isa/sound/mad16.h @@ -0,0 +1,91 @@ + +/* + * Initialization code for OPTI MAD16 interface chip by + * Davor Jadrijevic <davor@emard.pub.hr> + * (Included by ad1848.c when MAD16 support is enabled) + * + * It looks like MAD16 is similar than the Mozart chip (OAK OTI-601). + * It could be even possible that these chips are exactly the same. Can + * anybody confirm this? + */ + +static void wr_a_mad16(int base, int v, int a) +{ + OUTB(a, base + 0xf); + OUTB(v, base + 0x11); +} + +static void wr_b_mad16(int base, int v, int a) +{ + OUTB(a, base + 0xf); + OUTB(v, base + 0xd); +} + +/* +static int rd_a_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0x11); +} +*/ + +static int rd_b_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0xd); +} + +/* +static int rd_0_mad16(int base, int a) +{ + OUTB(a, base + 0xf); + return INB(base + 0xf); +} + +static void wr_ad(int base, int v, int a) +{ + OUTB(a, base + 4); + OUTB(v, base + 5); +} + +static int rd_ad(int base, int a) +{ + OUTB(a, base + 4); + return INB(base + 5); +} +*/ + +static int mad16init(int adr) +{ + int j; + long i; + + static int ad1848_bases[] = +{ 0x220, -1, -1, 0x240, -1, -1, -1, -1, 0x530, 0xE80, 0xF40, 0x604, 0 }; + + int mad16_base = 0xf80, ad1848_base; + + + for(j = 0; (j < 16) && (ad1848_bases[j] != 0); j++) + if(adr == ad1848_bases[j]) + break; + + if( (ad1848_base = ad1848_bases[j]) < 0x530) + { + printk("Unknown MAD16 setting 0x%3X\n", adr); + return -1; + } + + /* printk("OPTi MAD16 WSS at 0x%3X\n", ad1848_base); */ + + rd_b_mad16(mad16_base, 0xe2); + wr_a_mad16(mad16_base, 0x1a, 0xe2); + wr_b_mad16(mad16_base, j * 16 + 1, 0xe2); + wr_a_mad16(mad16_base, 0x1a, 0xe2); + for( i = 0; i < 10000; i++) + if( (INB(ad1848_base+4) & 0x80) == 0 ) + break; + + return 0; +}; + diff --git a/sys/i386/isa/sound/soundvers.h b/sys/i386/isa/sound/soundvers.h new file mode 100644 index 0000000000000..ca892e8259da1 --- /dev/null +++ b/sys/i386/isa/sound/soundvers.h @@ -0,0 +1 @@ +#define SOUND_VERSION_STRING "3.0-beta-950506" diff --git a/sys/i386/isa/sound/sscape.c b/sys/i386/isa/sound/sscape.c new file mode 100644 index 0000000000000..9204b188aab87 --- /dev/null +++ b/sys/i386/isa/sound/sscape.c @@ -0,0 +1,1120 @@ +/* + * sound/sscape.c + * + * Low level driver for Ensoniq Soundscape + * + * Copyright by Hannu Savolainen 1994 + * + * 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 "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE) + +#include "coproc.h" + +/* + * I/O ports + */ +#define MIDI_DATA 0 +#define MIDI_CTRL 1 +#define HOST_CTRL 2 +#define TX_READY 0x02 +#define RX_READY 0x01 +#define HOST_DATA 3 +#define ODIE_ADDR 4 +#define ODIE_DATA 5 + +/* + * Indirect registers + */ +#define GA_INTSTAT_REG 0 +#define GA_INTENA_REG 1 +#define GA_DMAA_REG 2 +#define GA_DMAB_REG 3 +#define GA_INTCFG_REG 4 +#define GA_DMACFG_REG 5 +#define GA_CDCFG_REG 6 +#define GA_SMCFGA_REG 7 +#define GA_SMCFGB_REG 8 +#define GA_HMCTL_REG 9 + +/* + * DMA channel identifiers (A and B) + */ +#define SSCAPE_DMA_A 0 +#define SSCAPE_DMA_B 1 + +#define PORT(name) (devc->base+name) + +/* + * Host commands recognized by the OBP microcode + */ +#define CMD_GEN_HOST_ACK 0x80 +#define CMD_GEN_MPU_ACK 0x81 +#define CMD_GET_BOARD_TYPE 0x82 +#define CMD_SET_CONTROL 0x88 +#define CMD_GET_CONTROL 0x89 +#define CMD_SET_MT32 0x96 +#define CMD_GET_MT32 0x97 +#define CMD_SET_EXTMIDI 0x9b +#define CMD_GET_EXTMIDI 0x9c + +#define CMD_ACK 0x80 + +typedef struct sscape_info + { + int base, irq, dma; + int ok; /* Properly detected */ + int dma_allocated; + int my_audiodev; + int opened; + } + +sscape_info; +static struct sscape_info dev_info = +{0}; +static struct sscape_info *devc = &dev_info; + +DEFINE_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + +#ifdef REVEAL_SPEA +/* Spea and Reveal have assigned interrupt bits differently than Ensoniq */ +static char valid_interrupts[] = +{9, 7, 5, 15}; + +#else +static char valid_interrupts[] = +{9, 5, 7, 10}; + +#endif + +static unsigned char +sscape_read (struct sscape_info *devc, int reg) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + val = INB (PORT (ODIE_DATA)); + RESTORE_INTR (flags); + return val; +} + +static void +sscape_write (struct sscape_info *devc, int reg, int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB (reg, PORT (ODIE_ADDR)); + OUTB (data, PORT (ODIE_DATA)); + RESTORE_INTR (flags); +} + +static void +host_open (struct sscape_info *devc) +{ + OUTB (0x00, PORT (HOST_CTRL)); /* Put the board to the host mode */ +} + +static void +host_close (struct sscape_info *devc) +{ + OUTB (0x03, PORT (HOST_CTRL)); /* Put the board to the MIDI mode */ +} + +static int +host_write (struct sscape_info *devc, unsigned char *data, int count) +{ + unsigned long flags; + int i, timeout; + + DISABLE_INTR (flags); + + /* + * Send the command and data bytes + */ + + for (i = 0; i < count; i++) + { + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & TX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return 0; + } + + OUTB (data[i], PORT (HOST_DATA)); + } + + + RESTORE_INTR (flags); + + return 1; +} + +static int +host_read (struct sscape_info *devc) +{ + unsigned long flags; + int timeout; + unsigned char data; + + DISABLE_INTR (flags); + + /* + * Read a byte + */ + + for (timeout = 10000; timeout > 0; timeout--) + if (INB (PORT (HOST_CTRL)) & RX_READY) + break; + + if (timeout <= 0) + { + RESTORE_INTR (flags); + return -1; + } + + data = INB (PORT (HOST_DATA)); + + RESTORE_INTR (flags); + + return data; +} + +static int +host_command1 (struct sscape_info *devc, int cmd) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + + return host_write (devc, buf, 1); +} + +static int +host_command2 (struct sscape_info *devc, int cmd, int parm1) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + + return host_write (devc, buf, 2); +} + +static int +host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2) +{ + unsigned char buf[10]; + + buf[0] = (unsigned char) (cmd & 0xff); + buf[1] = (unsigned char) (parm1 & 0xff); + buf[2] = (unsigned char) (parm2 & 0xff); + + return host_write (devc, buf, 3); +} + +static void +set_mt32 (struct sscape_info *devc, int value) +{ + host_open (devc); + host_command2 (devc, CMD_SET_MT32, + value ? 1 : 0); + if (host_read (devc) != CMD_ACK) + { + printk ("SNDSCAPE: Setting MT32 mode failed\n"); + } + host_close (devc); +} + +static int +get_board_type (struct sscape_info *devc) +{ + int tmp; + + host_open (devc); + if (!host_command1 (devc, CMD_GET_BOARD_TYPE)) + tmp = -1; + else + tmp = host_read (devc); + host_close (devc); + return tmp; +} + +void +sscapeintr (INT_HANDLER_PARMS (irq, dummy)) +{ + unsigned char bits, tmp; + static int debug = 0; + + printk ("sscapeintr(0x%02x)\n", (bits = sscape_read (devc, GA_INTSTAT_REG))); + if (SOMEONE_WAITING (sscape_sleeper, sscape_sleep_flag)) + { + WAKE_UP (sscape_sleeper, sscape_sleep_flag); + } + + if (bits & 0x02) /* Host interface interrupt */ + { + printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); + } + +#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI) + if (bits & 0x01) + { + mpuintr (INT_HANDLER_CALL (irq)); + if (debug++ > 10) /* Temporary debugging hack */ + { + sscape_write (devc, GA_INTENA_REG, 0x00); /* Disable all interrupts */ + } + } +#endif + + /* + * Acknowledge interrupts (toggle the interrupt bits) + */ + + tmp = sscape_read (devc, GA_INTENA_REG); + sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1)); + +} + +static void +sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp |= intr_bits; + temp |= 0x80; /* Master IRQ enable */ + + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits) +{ + unsigned char temp, orig; + + temp = orig = sscape_read (devc, GA_INTENA_REG); + temp &= ~intr_bits; + if ((temp & ~0x80) == 0x00) + temp = 0x00; /* Master IRQ disable */ + if (temp == orig) + return; /* No change */ + + sscape_write (devc, GA_INTENA_REG, temp); +} + +static void +do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) +{ + unsigned char temp; + + if (dma_chan != SSCAPE_DMA_A) + { + printk ("SSCAPE: Tried to use DMA channel != A. Why?\n"); + return; + } + + DMAbuf_start_dma (devc->my_audiodev, + buf, + blk_size, mode); + + temp = devc->dma << 4; /* Setup DMA channel select bits */ + if (devc->dma <= 3) + temp |= 0x80; /* 8 bit DMA channel */ + + temp |= 1; /* Trigger DMA */ + sscape_write (devc, GA_DMAA_REG, temp); + temp &= 0xfe; /* Clear DMA trigger */ + sscape_write (devc, GA_DMAA_REG, temp); +} + +static int +verify_mpu (struct sscape_info *devc) +{ + /* + * The SoundScape board could be in three modes (MPU, 8250 and host). + * If the card is not in the MPU mode, enabling the MPU driver will + * cause infinite loop (the driver believes that there is always some + * received data in the buffer. + * + * Detect this by looking if there are more than 10 received MIDI bytes + * (0x00) in the buffer. + */ + + int i; + + for (i = 0; i < 10; i++) + { + if (INB (devc->base + HOST_CTRL) & 0x80) + return 1; + + if (INB (devc->base) != 0x00) + return 1; + } + + printk ("SoundScape: The device is not in the MPU-401 mode\n"); + return 0; +} + +static int +sscape_coproc_open (void *dev_info, int sub_device) +{ + if (sub_device == COPR_MIDI) + { + set_mt32 (devc, 0); + if (!verify_mpu (devc)) + return RET_ERROR (EIO); + } + + return 0; +} + +static void +sscape_coproc_close (void *dev_info, int sub_device) +{ + struct sscape_info *devc = dev_info; + unsigned long flags; + + DISABLE_INTR (flags); + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ +#ifndef EXCLUDE_NATIVE_PCM + DMAbuf_close_dma (devc->my_audiodev); +#endif + devc->dma_allocated = 0; + } + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + RESTORE_INTR (flags); + + return; +} + +static void +sscape_coproc_reset (void *dev_info) +{ +} + +static int +sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag) +{ + unsigned long flags; + unsigned char temp; + int done, timeout; + + if (flag & CPF_FIRST) + { + /* + * First block. Have to allocate DMA and to reset the board + * before continuing. + */ + + DISABLE_INTR (flags); + if (devc->dma_allocated == 0) + { +#ifndef EXCLUDE_NATIVE_PCM + if (DMAbuf_open_dma (devc->my_audiodev) < 0) + { + RESTORE_INTR (flags); + return 0; + } +#endif + + devc->dma_allocated = 1; + } + RESTORE_INTR (flags); + + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ + + for (timeout = 10000; timeout > 0; timeout--) + sscape_read (devc, GA_HMCTL_REG); /* Delay */ + + /* Take board out of reset */ + sscape_write (devc, GA_HMCTL_REG, + (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80); + } + + /* + * Transfer one code block using DMA + */ + memcpy (audio_devs[devc->my_audiodev]->dmap->raw_buf[0], block, size); + + DISABLE_INTR (flags); +/******** INTERRUPTS DISABLED NOW ********/ + do_dma (devc, SSCAPE_DMA_A, + audio_devs[devc->my_audiodev]->dmap->raw_buf_phys[0], + size, DMA_MODE_WRITE); + + /* + * Wait until transfer completes. + */ + RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag); + done = 0; + timeout = 100; + while (!done && timeout-- > 0) + { + int resid; + + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + clear_dma_ff (devc->dma); + if ((resid = get_dma_residue (devc->dma)) == 0) + done = 1; + } + + RESTORE_INTR (flags); + if (!done) + return 0; + + if (flag & CPF_LAST) + { + /* + * Take the board out of reset + */ + OUTB (0x00, PORT (HOST_CTRL)); + OUTB (0x00, PORT (MIDI_CTRL)); + + temp = sscape_read (devc, GA_HMCTL_REG); + temp |= 0x40; + sscape_write (devc, GA_HMCTL_REG, temp); /* Kickstart the board */ + + /* + * Wait until the ODB wakes up + */ + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: The OBP didn't respond after code download\n"); + return 0; + } + + DISABLE_INTR (flags); + done = 0; + timeout = 5 * HZ; + while (!done && timeout-- > 0) + { + DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1); + if (INB (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ + done = 1; + } + RESTORE_INTR (flags); + if (!done) + { + printk ("SoundScape: OBP Initialization failed.\n"); + return 0; + } + + printk ("SoundScape board of type %d initialized OK\n", + get_board_type (devc)); + +#ifdef SSCAPE_DEBUG3 + /* + * Temporary debugging aid. Print contents of the registers after + * downloading the code. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + + } + + return 1; +} + +static int +download_boot_block (void *dev_info, copr_buffer * buf) +{ + if (buf->len <= 0 || buf->len > sizeof (buf->data)) + return RET_ERROR (EINVAL); + + if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) + { + printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); + return RET_ERROR (EIO); + } + + return 0; +} + +static int +sscape_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local) +{ + + switch (cmd) + { + case SNDCTL_COPR_RESET: + sscape_coproc_reset (dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer)); + IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf)); + err = download_boot_block (dev_info, buf); + KERNEL_FREE (buf); + return err; + } + break; + + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static coproc_operations sscape_coproc_operations = +{ + "SoundScape M68K", + sscape_coproc_open, + sscape_coproc_close, + sscape_coproc_ioctl, + sscape_coproc_reset, + &dev_info +}; + +static int +sscape_audio_open (int dev, int mode) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DISABLE_INTR (flags); + if (devc->opened) + { + RESTORE_INTR (flags); + return RET_ERROR (EBUSY); + } + + if (devc->dma_allocated == 0) + { + int err; + + if ((err = DMAbuf_open_dma (devc->my_audiodev)) < 0) + { + RESTORE_INTR (flags); + return err; + } + + devc->dma_allocated = 1; + } + + devc->opened = 1; + RESTORE_INTR (flags); +#ifdef SSCAPE_DEBUG4 + /* + * Temporary debugging aid. Print contents of the registers + * when the device is opened. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return 0; +} + +static void +sscape_audio_close (int dev) +{ + unsigned long flags; + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + DEB (printk ("sscape_audio_close(void)\n")); + + DISABLE_INTR (flags); + + if (devc->dma_allocated) + { + sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ + DMAbuf_close_dma (dev); + devc->dma_allocated = 0; + } + devc->opened = 0; + + RESTORE_INTR (flags); +} + +static int +set_speed (sscape_info * devc, int arg) +{ + return 8000; +} + +static int +set_channels (sscape_info * devc, int arg) +{ + return 1; +} + +static int +set_format (sscape_info * devc, int arg) +{ + return AFMT_U8; +} + +static int +sscape_audio_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return set_speed (devc, arg); + return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return 8000; + return IOCTL_OUT (arg, 8000); + + case SNDCTL_DSP_STEREO: + if (local) + return set_channels (devc, arg + 1) - 1; + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return set_channels (devc, arg); + return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return 1; + return IOCTL_OUT (arg, 1); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return set_format (devc, arg); + return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return 8; + return IOCTL_OUT (arg, 8); + + default:; + } + return RET_ERROR (EINVAL); +} + +static void +sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static void +sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) +{ +} + +static int +sscape_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + return 0; +} + +static int +sscape_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + return 0; +} + +static void +sscape_audio_halt (int dev) +{ +} + +static void +sscape_audio_reset (int dev) +{ + sscape_audio_halt (dev); +} + +static struct audio_operations sscape_audio_operations = +{ + "Ensoniq SoundScape channel A", + 0, + AFMT_U8 | AFMT_S16_LE, + NULL, + sscape_audio_open, + sscape_audio_close, + sscape_audio_output_block, + sscape_audio_start_input, + sscape_audio_ioctl, + sscape_audio_prepare_for_input, + sscape_audio_prepare_for_output, + sscape_audio_reset, + sscape_audio_halt, + NULL, + NULL +}; + +long +attach_sscape (long mem_start, struct address_info *hw_config) +{ + int my_dev; + +#ifndef SSCAPE_REGS + /* + * Config register values for Spea/V7 Media FX and Ensoniq S-2000. + * These values are card + * dependent. If you have another SoundScape based card, you have to + * find the correct values. Do the following: + * - Compile this driver with SSCAPE_DEBUG1 defined. + * - Shut down and power off your machine. + * - Boot with DOS so that the SSINIT.EXE program is run. + * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed + * when detecting the SoundScape. + * - Modify the following list to use the values printed during boot. + * Undefine the SSCAPE_DEBUG1 + */ +#define SSCAPE_REGS { \ +/* I0 */ 0x00, \ + 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0x20, /* Note! Ignored. Set always to 0x20 */ \ + 0xf5, /* Ignored */ \ + 0x10, \ + 0x00, \ + 0x2e, /* I7 MEM config A. Likely to vary between models */ \ + 0x00, /* I8 MEM config A. Likely to vary between models */ \ +/* I9 */ 0x40 /* Ignored */ \ + } +#endif + + unsigned long flags; + static unsigned char regs[10] = SSCAPE_REGS; + + int i, irq_bits = 0xff; + + if (!probe_sscape (hw_config)) + return mem_start; + + printk (" <Ensoniq Soundscape>"); + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) + { + printk ("Invalid IRQ%d\n", hw_config->irq); + return mem_start; + } + + DISABLE_INTR (flags); + + for (i = 1; i < 10; i++) + switch (i) + { + case 1: /* Host interrupt enable */ + sscape_write (devc, i, 0xf0); /* All interrupts enabled */ + break; + + case 2: /* DMA A status/trigger register */ + case 3: /* DMA B status/trigger register */ + sscape_write (devc, i, 0x20); /* DMA channel disabled */ + break; + + case 4: /* Host interrupt config reg */ + sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits); + break; + + case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ + sscape_write (devc, i, (regs[i] & 0x3f) | + (sscape_read (devc, i) & 0x0c)); + break; + + case 6: /* CD-ROM config. Don't touch. */ + break; + + case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ + sscape_write (devc, i, + (sscape_read (devc, i) & 0xf0) | 0x00); + break; + + default: + sscape_write (devc, i, regs[i]); + } + + RESTORE_INTR (flags); + +#ifdef SSCAPE_DEBUG2 + /* + * Temporary debugging aid. Print contents of the registers after + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i)); + } +#endif + +#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU) + hw_config->always_detect = 1; + if (probe_mpu401 (hw_config)) + { + int prev_devs; + + prev_devs = num_midis; + mem_start = attach_mpu401 (mem_start, hw_config); + + if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ + midi_devs[prev_devs]->coproc = &sscape_coproc_operations; + } +#endif + +#ifndef EXCLUDE_NATIVE_PCM + /* Not supported yet */ + +#ifndef EXCLUDE_AUDIO + if (num_audiodevs < MAX_AUDIO_DEV) + { + audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; + audio_devs[my_dev]->dmachan = hw_config->dma; + audio_devs[my_dev]->buffcount = 1; + audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; + audio_devs[my_dev]->devc = devc; + devc->my_audiodev = my_dev; + devc->opened = 0; + audio_devs[my_dev]->coproc = &sscape_coproc_operations; + if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape") < 0) + printk ("Error: Can't allocate IRQ for SoundScape\n"); + + sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ + } + else + printk ("SoundScape: More than enough audio devices detected\n"); +#endif +#endif + devc->ok = 1; + return mem_start; +} + +int +probe_sscape (struct address_info *hw_config) +{ + unsigned char save; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + + /* + * First check that the address register of "ODIE" is + * there and that it has exactly 4 writeable bits. + * First 4 bits + */ + if ((save = INB (PORT (ODIE_ADDR))) & 0xf0) + return 0; + + OUTB (0x00, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x00) + return 0; + + OUTB (0xff, PORT (ODIE_ADDR)); + if (INB (PORT (ODIE_ADDR)) != 0x0f) + return 0; + + OUTB (save, PORT (ODIE_ADDR)); + + /* + * Now verify that some indirect registers return zero on some bits. + * This may break the driver with some future revisions of "ODIE" but... + */ + + if (sscape_read (devc, 0) & 0x0c) + return 0; + + if (sscape_read (devc, 1) & 0x0f) + return 0; + + if (sscape_read (devc, 5) & 0x0f) + return 0; + +#ifdef SSCAPE_DEBUG1 + /* + * Temporary debugging aid. Print contents of the registers before + * changing them. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i)); + } +#endif + + return 1; +} + +int +probe_ss_ms_sound (struct address_info *hw_config) +{ + int i, irq_bits = 0xff; + + if (devc->ok == 0) + { + printk ("SoundScape: Invalid initialization order.\n"); + return 0; + } + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } +#ifdef REVEAL_SPEA + { + int tmp, status = 0; + int cc; + + if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0)) + { + sscape_write (devc, GA_HMCTL_REG, tmp | 0x80); + for (cc = 0; cc < 200000; ++cc) + INB (devc->base + ODIE_ADDR); + } + } +#endif + + if (hw_config->irq > 15 || irq_bits == 0xff) + { + printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base); +} + +long +attach_ss_ms_sound (long mem_start, struct address_info *hw_config) +{ + /* + * This routine configures the SoundScape card for use with the + * Win Sound System driver. The AD1848 codec interface uses the CD-ROM + * config registers of the "ODIE". + */ + + int i, irq_bits = 0xff; + +#ifdef EXCLUDE_NATIVE_PCM + int prev_devs = num_audiodevs; + +#endif + + /* + * Setup the DMA polarity. + */ + sscape_write (devc, GA_DMACFG_REG, 0x50); + + /* + * Take the gate-arry off of the DMA channel. + */ + sscape_write (devc, GA_DMAB_REG, 0x20); + + /* + * Init the AD1848 (CD-ROM) config reg. + */ + + for (i = 0; i < sizeof (valid_interrupts); i++) + if (hw_config->irq == valid_interrupts[i]) + { + irq_bits = i; + break; + } + + sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | + (irq_bits << 1)); + + if (hw_config->irq == devc->irq) + printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n"); + + ad1848_init ("SoundScape", hw_config->io_base, + hw_config->irq, + hw_config->dma, + hw_config->dma); + +#ifdef EXCLUDE_NATIVE_PCM + if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ + audio_devs[prev_devs]->coproc = &sscape_coproc_operations; +#endif +#ifdef SSCAPE_DEBUG5 + /* + * Temporary debugging aid. Print contents of the registers + * after the AD1848 device has been initialized. + */ + { + int i; + + for (i = 0; i < 13; i++) + printk ("I%d = %02x\n", i, sscape_read (devc, i)); + } +#endif + + return mem_start; +} + +#endif diff --git a/sys/i386/isa/sound/trix.c b/sys/i386/isa/sound/trix.c new file mode 100644 index 0000000000000..6e3db0fa7c901 --- /dev/null +++ b/sys/i386/isa/sound/trix.c @@ -0,0 +1,323 @@ +/* + * sound/trix.c + * + * Low level driver for the MediaTriX AudioTriX Pro + * (MT-0002-PC Control Chip) + * + * Copyright by Hannu Savolainen 1995 + * + * 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 "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX) + +#ifdef INCLUDE_TRIX_BOOT +#include "trix_boot.h" +#endif + +static int kilroy_was_here = 0; /* Don't detect twice */ +static int sb_initialized = 0; +static int mpu_initialized = 0; + +static unsigned char +trix_read (int addr) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + return INB (0x391); /* MT-0002-PC ASIC data */ +} + +static void +trix_write (int addr, int data) +{ + OUTB ((unsigned char) addr, 0x390); /* MT-0002-PC ASIC address */ + OUTB ((unsigned char) data, 0x391); /* MT-0002-PC ASIC data */ +} + +static void +download_boot (int base) +{ + int i = 0, n = sizeof (trix_boot); + + trix_write (0xf8, 0x00); /* ??????? */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x00, base + 6); /* Restart */ + + /* + * Write the boot code to the RAM upload/download register. + * Each write increments the internal data pointer. + */ + OUTB (0x01, base + 6); /* Clear the internal data pointer */ + OUTB (0x1A, 0x390); /* Select RAM download/upload port */ + + for (i = 0; i < n; i++) + OUTB (trix_boot[i], 0x391); + for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ + OUTB (0x00, 0x391); + OUTB (0x00, base + 6); /* Reset */ + OUTB (0x50, 0x390); /* ?????? */ +} + +static int +trix_set_wss_port (struct address_info *hw_config) +{ + unsigned char addr_bits; + + if (kilroy_was_here) /* Already initialized */ + return 0; + + kilroy_was_here = 1; + + if (trix_read (0x15) != 0x71) /* No asic signature */ + return 0; + + /* + * Disable separate wave playback and recording DMA channels since + * the driver doesn't support duplex mode yet. + */ + + trix_write (0x13, trix_read (0x13) & ~0x80); + trix_write (0x14, trix_read (0x14) & ~0x80); + + /* + * Configure the ASIC to place the codec to the proper I/O location + */ + + switch (hw_config->io_base) + { + case 0x530: + addr_bits = 0; + break; + case 0x604: + addr_bits = 1; + break; + case 0xE80: + addr_bits = 2; + break; + case 0xF40: + addr_bits = 3; + break; + default: + return 0; + } + + trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits); + return 1; +} + +/* + * Probe and attach routines for the Windows Sound System mode of + * AudioTriX Pro + */ + +int +probe_trix_wss (struct address_info *hw_config) +{ + /* + * Check if the IO port returns valid signature. The original MS Sound + * system returns 0x04 while some cards (AudioTriX Pro for example) + * return 0x00. + */ + if (!trix_set_wss_port (hw_config)) + return 0; + + if ((INB (hw_config->io_base + 3) & 0x3f) != 0x00) + { + DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base)); + return 0; + } + + if (hw_config->irq > 11) + { + printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq); + return 0; + } + + if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) + { + printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma); + return 0; + } + + /* + * Check that DMA0 is not in use with a 8 bit board. + */ + + if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n"); + return 0; + } + + if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80) + { + printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); + return 0; + } + + return ad1848_detect (hw_config->io_base + 4); +} + +long +attach_trix_wss (long mem_start, struct address_info *hw_config) +{ + static unsigned char interrupt_bits[12] = + {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + char bits; + + static unsigned char dma_bits[4] = + {1, 2, 0, 3}; + + int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + + if (!kilroy_was_here) + return mem_start; + + /* + * Set the IRQ and DMA addresses. + */ + + bits = interrupt_bits[hw_config->irq]; + if (bits == -1) + return mem_start; + + OUTB (bits | 0x40, config_port); + if ((INB (version_port) & 0x40) == 0) + printk ("[IRQ Conflict?]"); + + OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("AudioTriX Pro", hw_config->io_base + 4, + hw_config->irq, + hw_config->dma, + hw_config->dma); + return mem_start; +} + +int +probe_trix_sb (struct address_info *hw_config) +{ + + int tmp; + unsigned char conf; + static char irq_translate[] = + {-1, -1, -1, 0, 1, 2, -1, 3}; + +#ifndef INCLUDE_TRIX_BOOT + return 0; /* No boot code -> no fun */ +#endif + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (sb_initialized) + return 0; + + if (hw_config->io_base & 0xffffff8f != 0x200) + return 0; + + tmp = hw_config->irq; + if (tmp > 7) + return 0; + if (irq_translate[tmp] == -1) + return 0; + + tmp = hw_config->dma; + if (tmp != 1 && tmp != 3) + return 0; + + conf = 0x84; /* DMA and IRQ enable */ + conf |= hw_config->io_base & 0x70; /* I/O address bits */ + conf |= irq_translate[hw_config->irq]; + if (hw_config->dma == 3) + conf |= 0x08; + trix_write (0x1b, conf); + + download_boot (hw_config->io_base); + sb_initialized = 1; + + return 1; +} + +long +attach_trix_sb (long mem_start, struct address_info *hw_config) +{ + printk (" <AudioTriX>"); + return mem_start; +} + +long +attach_trix_mpu (long mem_start, struct address_info *hw_config) +{ + return attach_mpu401 (mem_start, hw_config); +} + +int +probe_trix_mpu (struct address_info *hw_config) +{ + unsigned char conf; + static char irq_bits[] = + {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; + + if (!kilroy_was_here) + return 0; /* AudioTriX Pro has not been detected earlier */ + + if (!sb_initialized) + return 0; + + if (mpu_initialized) + return 0; + + if (hw_config->irq > 9) + return 0; + + if (irq_bits[hw_config->irq] == -1) + return 0; + + switch (hw_config->io_base) + { + case 0x330: + conf = 0x00; + break; + case 0x370: + conf = 0x04; + break; + case 0x3b0: + conf = 0x08; + break; + case 0x3f0: + conf = 0x0c; + break; + default: + return 0; /* Invalid port */ + } + + conf |= irq_bits[hw_config->irq] << 4; + + trix_write (0x19, (trix_read (0x19) & 0x83) | conf); + + mpu_initialized = 1; + + return probe_mpu401 (hw_config); +} + +#endif diff --git a/sys/i386/linux/imgact_linux.c b/sys/i386/linux/imgact_linux.c new file mode 100644 index 0000000000000..d9650d3150ecc --- /dev/null +++ b/sys/i386/linux/imgact_linux.c @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * All rights reserved. + * + * Based heavily on /sys/kern/imgact_aout.c which is: + * Copyright (c) 1993, David Greenman + * + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: imgact_linux.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/resourcevar.h> +#include <sys/exec.h> +#include <sys/mman.h> +#include <sys/imgact.h> +#include <sys/imgact_aout.h> +#include <sys/kernel.h> +#include <sys/sysent.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> + +int +exec_linux_imgact(iparams) + struct image_params *iparams; +{ + struct exec *a_out = (struct exec *) iparams->image_header; + struct vmspace *vmspace = iparams->proc->p_vmspace; + unsigned long vmaddr, virtual_offset, file_offset; + unsigned long buffer, bss_size; + int error; + extern struct sysentvec linux_sysvec; + + if (((a_out->a_magic >> 16) & 0xff) != 0x64) + return -1; + + /* + * Set file/virtual offset based on a.out variant. + */ + switch ((int)(a_out->a_magic & 0xffff)) { + case 0413: + virtual_offset = 0; + file_offset = 1024; + break; + case 0314: + virtual_offset = 4096; + file_offset = 0; + break; + default: + return (-1); + } + bss_size = round_page(a_out->a_bss); + + /* + * Check various fields in header for validity/bounds. + */ + if (a_out->a_entry < virtual_offset || + a_out->a_entry >= virtual_offset + a_out->a_text || + a_out->a_text % NBPG || a_out->a_data % NBPG) + return (-1); + + /* text + data can't exceed file size */ + if (a_out->a_data + a_out->a_text > iparams->attr->va_size) + return (EFAULT); + /* + * text/data/bss must not exceed limits + */ + if (a_out->a_text > MAXTSIZ || a_out->a_data + bss_size > MAXDSIZ || + a_out->a_data+bss_size > iparams->proc->p_rlimit[RLIMIT_DATA].rlim_cur) + return (ENOMEM); + + /* copy in arguments and/or environment from old process */ + error = exec_extract_strings(iparams); + if (error) + return (error); + + /* + * Destroy old process VM and create a new one (with a new stack) + */ + exec_new_vmspace(iparams); + + /* + * Check if file_offset page aligned,. + * Currently we cannot handle misalinged file offsets, + * and so we read in the entire image (what a waste). + */ + if (file_offset & PGOFSET) { +#ifdef DEBUG + printf("imgact: Non page aligned binary %d\n", file_offset); +#endif + /* + * Map text read/execute + */ + vmaddr = virtual_offset; + error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, + round_page(a_out->a_text), FALSE); + if (error) + return error; + + error = vm_mmap(kernel_map, &buffer, + round_page(a_out->a_text + file_offset), + VM_PROT_READ, VM_PROT_READ, MAP_FILE, + (caddr_t) iparams->vnodep, trunc_page(file_offset)); + if (error) + return error; + + error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, + a_out->a_text); + if (error) + return error; + + vm_map_remove(kernel_map, trunc_page(vmaddr), + round_page(a_out->a_text + file_offset)); + + error = vm_map_protect(&vmspace->vm_map, vmaddr, + round_page(a_out->a_text), + VM_PROT_EXECUTE|VM_PROT_READ, TRUE); + if (error) + return error; + /* + * Map data read/write + */ + vmaddr = virtual_offset + a_out->a_text; + error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, + round_page(a_out->a_data + bss_size), FALSE); + if (error) + return error; + + error = vm_mmap(kernel_map, &buffer, + round_page(a_out->a_data + file_offset), + VM_PROT_READ, VM_PROT_READ, MAP_FILE, + (caddr_t) iparams->vnodep, + trunc_page(a_out->a_text + file_offset)); + if (error) + return error; + + error = copyout((caddr_t)(buffer + file_offset), + (caddr_t)vmaddr, + a_out->a_data); + if (error) + return error; + + vm_map_remove(kernel_map, trunc_page(vmaddr), + round_page(a_out->a_data + file_offset)); + + error = vm_map_protect(&vmspace->vm_map, vmaddr, + round_page(a_out->a_data + bss_size), + VM_PROT_WRITE|VM_PROT_READ, TRUE); + if (error) + return error; + } + else { +#ifdef DEBUG + printf("imgact: Page aligned binary %d\n", file_offset); +#endif + /* + * Map text read/execute + */ + vmaddr = virtual_offset; + error = vm_mmap(&vmspace->vm_map, &vmaddr, a_out->a_text, + VM_PROT_READ | VM_PROT_EXECUTE, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, + (caddr_t)iparams->vnodep, file_offset); + if (error) + return (error); + + /* + * Map data read/write + */ + vmaddr = virtual_offset + a_out->a_text; + error = vm_mmap(&vmspace->vm_map, &vmaddr, a_out->a_data, + VM_PROT_READ | VM_PROT_WRITE, + VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, + (caddr_t)iparams->vnodep, file_offset + a_out->a_text); + if (error) + return (error); + + /* + * Allocate demand-zeroed area for uninitialized data + */ + if (bss_size != 0) { + vmaddr = virtual_offset + a_out->a_text + a_out->a_data; + error = vm_map_find(&vmspace->vm_map, NULL, 0, &vmaddr, + bss_size, FALSE); + if (error) + return (error); + } + } + /* Fill in process VM information */ + vmspace->vm_tsize = round_page(a_out->a_text) >> PAGE_SHIFT; + vmspace->vm_dsize = round_page(a_out->a_data + bss_size) >> PAGE_SHIFT; + vmspace->vm_taddr = (caddr_t)virtual_offset; + vmspace->vm_daddr = (caddr_t)virtual_offset + a_out->a_text; + + /* Fill in image_params */ + iparams->interpreted = 0; + iparams->entry_addr = a_out->a_entry; + + iparams->proc->p_sysent = &linux_sysvec; + return (0); +} + +/* + * Tell kern_execve.c about it, with a little help from the linker. + * Since `const' objects end up in the text segment, TEXT_SET is the + * correct directive to use. + */ +const struct execsw linux_execsw = { exec_linux_imgact, "linux" }; +TEXT_SET(execsw_set, linux_execsw); + diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h new file mode 100644 index 0000000000000..9d13bd156057d --- /dev/null +++ b/sys/i386/linux/linux.h @@ -0,0 +1,406 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux.h,v 1.3 1995/06/08 13:50:52 sos Exp $ + */ + +#ifndef LINUX_H +#define LINUX_H + +typedef unsigned short linux_uid_t; +typedef unsigned short linux_gid_t; +typedef unsigned short linux_dev_t; +typedef unsigned long linux_ino_t; +typedef unsigned short linux_mode_t; +typedef unsigned short linux_nlink_t; +typedef long linux_time_t; +typedef long linux_clock_t; +typedef char * linux_caddr_t; +typedef long linux_off_t; +typedef struct { + long val[2]; +} linux_fsid_t; +typedef int linux_pid_t; +typedef unsigned long linux_sigset_t; +typedef void (*linux_handler_t)(int); +typedef struct { + void (*sa_handler)(int); + linux_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +} linux_sigaction_t; +typedef int linux_key_t; + +extern int bsd_to_linux_signal[]; +extern int linux_to_bsd_signal[]; + +/* misc defines */ +#define LINUX_NAME_MAX 255 + +/* signal numbers */ +#define LINUX_SIGHUP 1 +#define LINUX_SIGINT 2 +#define LINUX_SIGQUIT 3 +#define LINUX_SIGILL 4 +#define LINUX_SIGTRAP 5 +#define LINUX_SIGABRT 6 +#define LINUX_SIGIOT 6 +#define LINUX_SIGUNUSED 7 +#define LINUX_SIGFPE 8 +#define LINUX_SIGKILL 9 +#define LINUX_SIGUSR1 10 +#define LINUX_SIGSEGV 11 +#define LINUX_SIGUSR2 12 +#define LINUX_SIGPIPE 13 +#define LINUX_SIGALRM 14 +#define LINUX_SIGTERM 15 +#define LINUX_SIGSTKFLT 16 +#define LINUX_SIGCHLD 17 +#define LINUX_SIGCONT 18 +#define LINUX_SIGSTOP 19 +#define LINUX_SIGTSTP 20 +#define LINUX_SIGTTIN 21 +#define LINUX_SIGTTOU 22 +#define LINUX_SIGIO 23 +#define LINUX_SIGPOLL LINUX_SIGIO +#define LINUX_SIGURG LINUX_SIGIO +#define LINUX_SIGXCPU 24 +#define LINUX_SIGXFSZ 25 +#define LINUX_SIGVTALRM 26 +#define LINUX_SIGPROF 27 +#define LINUX_SIGWINCH 28 +#define LINUX_SIGLOST 29 +#define LINUX_SIGPWR 30 +#define LINUX_SIGBUS LINUX_SIGUNUSED +#define LINUX_NSIG 32 + +/* sigaction flags */ +#define LINUX_SA_NOCLDSTOP 0x00000001 +#define LINUX_SA_ONSTACK 0x08000000 +#define LINUX_SA_RESTART 0x10000000 +#define LINUX_SA_INTERRUPT 0x20000000 +#define LINUX_SA_NOMASK 0x40000000 +#define LINUX_SA_ONESHOT 0x80000000 + +/* sigprocmask actions */ +#define LINUX_SIG_BLOCK 0 +#define LINUX_SIG_UNBLOCK 1 +#define LINUX_SIG_SETMASK 2 + +/* termio commands */ +#define LINUX_TCGETS 0x5401 +#define LINUX_TCSETS 0x5402 +#define LINUX_TCSETSW 0x5403 +#define LINUX_TCSETSF 0x5404 +#define LINUX_TCGETA 0x5405 +#define LINUX_TCSETA 0x5406 +#define LINUX_TCSETAW 0x5407 +#define LINUX_TCSETAF 0x5408 +#define LINUX_TCSBRK 0x5409 +#define LINUX_TCXONC 0x540A +#define LINUX_TCFLSH 0x540B +#define LINUX_TIOCEXCL 0x540C +#define LINUX_TIOCNXCL 0x540D +#define LINUX_TIOCSCTTY 0x540E +#define LINUX_TIOCGPGRP 0x540F +#define LINUX_TIOCSPGRP 0x5410 +#define LINUX_TIOCOUTQ 0x5411 +#define LINUX_TIOCSTI 0x5412 +#define LINUX_TIOCGWINSZ 0x5413 +#define LINUX_TIOCSWINSZ 0x5414 +#define LINUX_TIOCMGET 0x5415 +#define LINUX_TIOCMBIS 0x5416 +#define LINUX_TIOCMBIC 0x5417 +#define LINUX_TIOCMSET 0x5418 +#define LINUX_TIOCGSOFTCAR 0x5419 +#define LINUX_TIOCSSOFTCAR 0x541A +#define LINUX_FIONREAD 0x541B +#define LINUX_TIOCINQ FIONREAD +#define LINUX_TIOCLINUX 0x541C +#define LINUX_TIOCCONS 0x541D +#define LINUX_TIOCGSERIAL 0x541E +#define LINUX_TIOCSSERIAL 0x541F +#define LINUX_TIOCPKT 0x5420 +#define LINUX_FIONBIO 0x5421 +#define LINUX_TIOCNOTTY 0x5422 +#define LINUX_TIOCSETD 0x5423 +#define LINUX_TIOCGETD 0x5424 +#define LINUX_TCSBRKP 0x5425 +#define LINUX_TIOCTTYGSTRUCT 0x5426 +#define LINUX_FIONCLEX 0x5450 +#define LINUX_FIOCLEX 0x5451 +#define LINUX_FIOASYNC 0x5452 +#define LINUX_TIOCSERCONFIG 0x5453 +#define LINUX_TIOCSERGWILD 0x5454 +#define LINUX_TIOCSERSWILD 0x5455 +#define LINUX_TIOCGLCKTRMIOS 0x5456 +#define LINUX_TIOCSLCKTRMIOS 0x5457 + +/* line disciplines */ +#define LINUX_N_TTY 0 +#define LINUX_N_SLIP 1 +#define LINUX_N_MOUSE 2 +#define LINUX_N_PPP 3 + +/* Linux termio c_cc values */ +#define LINUX_VINTR 0 +#define LINUX_VQUIT 1 +#define LINUX_VERASE 2 +#define LINUX_VKILL 3 +#define LINUX_VEOF 4 +#define LINUX_VTIME 5 +#define LINUX_VMIN 6 +#define LINUX_VSWTC 7 +#define LINUX_NCC 8 + +/* Linux termios c_cc values */ +#define LINUX_VSTART 8 +#define LINUX_VSTOP 9 +#define LINUX_VSUSP 10 +#define LINUX_VEOL 11 +#define LINUX_VREPRINT 12 +#define LINUX_VDISCARD 13 +#define LINUX_VWERASE 14 +#define LINUX_VLNEXT 15 +#define LINUX_VEOL2 16 +#define LINUX_NCCS 17 + +/* Linux c_iflag masks */ +#define LINUX_IGNBRK 0x0000001 +#define LINUX_BRKINT 0x0000002 +#define LINUX_IGNPAR 0x0000004 +#define LINUX_PARMRK 0x0000008 +#define LINUX_INPCK 0x0000010 +#define LINUX_ISTRIP 0x0000020 +#define LINUX_INLCR 0x0000040 +#define LINUX_IGNCR 0x0000080 +#define LINUX_ICRNL 0x0000100 +#define LINUX_IUCLC 0x0000200 +#define LINUX_IXON 0x0000400 +#define LINUX_IXANY 0x0000800 +#define LINUX_IXOFF 0x0001000 +#define LINUX_IMAXBEL 0x0002000 + +/* Linux c_oflag masks */ +#define LINUX_OPOST 0x0000001 +#define LINUX_OLCUC 0x0000002 +#define LINUX_ONLCR 0x0000004 +#define LINUX_OCRNL 0x0000008 +#define LINUX_ONOCR 0x0000010 +#define LINUX_ONLRET 0x0000020 +#define LINUX_OFILL 0x0000040 +#define LINUX_OFDEL 0x0000080 +#define LINUX_NLDLY 0x0000100 + +#define LINUX_NL0 0x0000000 +#define LINUX_NL1 0x0000100 +#define LINUX_CRDLY 0x0000600 +#define LINUX_CR0 0x0000000 +#define LINUX_CR1 0x0000200 +#define LINUX_CR2 0x0000400 +#define LINUX_CR3 0x0000600 +#define LINUX_TABDLY 0x0001800 +#define LINUX_TAB0 0x0000000 +#define LINUX_TAB1 0x0000800 +#define LINUX_TAB2 0x0001000 +#define LINUX_TAB3 0x0001800 +#define LINUX_XTABS 0x0001800 +#define LINUX_BSDLY 0x0002000 +#define LINUX_BS0 0x0000000 +#define LINUX_BS1 0x0002000 +#define LINUX_VTDLY 0x0004000 +#define LINUX_VT0 0x0000000 +#define LINUX_VT1 0x0004000 +#define LINUX_FFDLY 0x0008000 +#define LINUX_FF0 0x0000000 +#define LINUX_FF1 0x0008000 + +#define LINUX_CBAUD 0x0000100f +#define LINUX_B0 0x00000000 +#define LINUX_B50 0x00000001 +#define LINUX_B75 0x00000002 +#define LINUX_B110 0x00000003 +#define LINUX_B134 0x00000004 +#define LINUX_B150 0x00000005 +#define LINUX_B200 0x00000006 +#define LINUX_B300 0x00000007 +#define LINUX_B600 0x00000008 +#define LINUX_B1200 0x00000009 +#define LINUX_B1800 0x0000000a +#define LINUX_B2400 0x0000000b +#define LINUX_B4800 0x0000000c +#define LINUX_B9600 0x0000000d +#define LINUX_B19200 0x0000000e +#define LINUX_B38400 0x0000000f +#define LINUX_EXTA LINUX_B19200 +#define LINUX_EXTB LINUX_B38400 +#define LINUX_CBAUDEX 0x00001000 +#define LINUX_B57600 0x00001001 +#define LINUX_B115200 0x00001002 + +#define LINUX_CSIZE 0x00000030 +#define LINUX_CS5 0x00000000 +#define LINUX_CS6 0x00000010 +#define LINUX_CS7 0x00000020 +#define LINUX_CS8 0x00000030 +#define LINUX_CSTOPB 0x00000040 +#define LINUX_CREAD 0x00000080 +#define LINUX_PARENB 0x00000100 +#define LINUX_PARODD 0x00000200 +#define LINUX_HUPCL 0x00000400 +#define LINUX_CLOCAL 0x00000800 +#define LINUX_CRTSCTS 0x80000000 + +/* Linux c_lflag masks */ +#define LINUX_ISIG 0x00000001 +#define LINUX_ICANON 0x00000002 +#define LINUX_XCASE 0x00000004 +#define LINUX_ECHO 0x00000008 +#define LINUX_ECHOE 0x00000010 +#define LINUX_ECHOK 0x00000020 +#define LINUX_ECHONL 0x00000040 +#define LINUX_NOFLSH 0x00000080 +#define LINUX_TOSTOP 0x00000100 +#define LINUX_ECHOCTL 0x00000200 +#define LINUX_ECHOPRT 0x00000400 +#define LINUX_ECHOKE 0x00000800 +#define LINUX_FLUSHO 0x00001000 +#define LINUX_PENDIN 0x00002000 +#define LINUX_IEXTEN 0x00008000 + +/* open/fcntl flags */ +#define LINUX_O_RDONLY 00 +#define LINUX_O_WRONLY 01 +#define LINUX_O_RDWR 02 +#define LINUX_O_CREAT 0100 +#define LINUX_O_EXCL 0200 +#define LINUX_O_NOCTTY 0400 +#define LINUX_O_TRUNC 01000 +#define LINUX_O_APPEND 02000 +#define LINUX_O_NONBLOCK 04000 +#define LINUX_O_NDELAY LINUX_O_NONBLOCK +#define LINUX_O_SYNC 010000 +#define LINUX_FASYNC 020000 + +/* fcntl flags */ +#define LINUX_F_DUPFD 0 +#define LINUX_F_GETFD 1 +#define LINUX_F_SETFD 2 +#define LINUX_F_GETFL 3 +#define LINUX_F_SETFL 4 +#define LINUX_F_GETLK 5 +#define LINUX_F_SETLK 6 +#define LINUX_F_SETLKW 7 +#define LINUX_F_SETOWN 8 +#define LINUX_F_GETOWN 9 + +#define LINUX_F_RDLCK 0 +#define LINUX_F_WRLCK 1 +#define LINUX_F_UNLCK 2 + +/* mmap options */ +#define LINUX_MAP_SHARED 0x0001 +#define LINUX_MAP_PRIVATE 0x0002 +#define LINUX_MAP_FIXED 0x0010 +#define LINUX_MAP_ANON 0x0020 + +/* SystemV ipc defines */ +#define LINUX_SEMOP 1 +#define LINUX_SEMGET 2 +#define LINUX_SEMCTL 3 +#define LINUX_MSGSND 11 +#define LINUX_MSGRCV 12 +#define LINUX_MSGGET 13 +#define LINUX_MSGCTL 14 +#define LINUX_SHMAT 21 +#define LINUX_SHMDT 22 +#define LINUX_SHMGET 23 +#define LINUX_SHMCTL 24 + +#define LINUX_IPC_RMID 0 +#define LINUX_IPC_SET 1 +#define LINUX_IPC_STAT 2 +#define LINUX_IPC_INFO 3 + +#define LINUX_SHM_LOCK 11 +#define LINUX_SHM_UNLOCK 12 +#define LINUX_SHM_STAT 13 +#define LINUX_SHM_INFO 14 + +#define LINUX_SHM_RDONLY 0x1000 +#define LINUX_SHM_RND 0x2000 +#define LINUX_SHM_REMAP 0x4000 + +/* Socket defines */ +#define LINUX_SOCKET 1 +#define LINUX_BIND 2 +#define LINUX_CONNECT 3 +#define LINUX_LISTEN 4 +#define LINUX_ACCEPT 5 +#define LINUX_GETSOCKNAME 6 +#define LINUX_GETPEERNAME 7 +#define LINUX_SOCKETPAIR 8 +#define LINUX_SEND 9 +#define LINUX_RECV 10 +#define LINUX_SENDTO 11 +#define LINUX_RECVFROM 12 +#define LINUX_SHUTDOWN 13 +#define LINUX_SETSOCKOPT 14 +#define LINUX_GETSOCKOPT 15 + +#define LINUX_AF_UNSPEC 0 +#define LINUX_AF_UNIX 1 +#define LINUX_AF_INET 2 +#define LINUX_AF_AX25 3 +#define LINUX_AF_IPX 4 +#define LINUX_AF_APPLETALK 5 + +#define LINUX_SOL_SOCKET 1 +#define LINUX_SOL_IP 0 +#define LINUX_SOL_IPX 256 +#define LINUX_SOL_AX25 257 +#define LINUX_SOL_TCP 6 +#define LINUX_SOL_UDP 17 + +#define LINUX_SO_DEBUG 1 +#define LINUX_SO_REUSEADDR 2 +#define LINUX_SO_TYPE 3 +#define LINUX_SO_ERROR 4 +#define LINUX_SO_DONTROUTE 5 +#define LINUX_SO_BROADCAST 6 +#define LINUX_SO_SNDBUF 7 +#define LINUX_SO_RCVBUF 8 +#define LINUX_SO_KEEPALIVE 9 +#define LINUX_SO_OOBINLINE 10 +#define LINUX_SO_NO_CHECK 11 +#define LINUX_SO_PRIORITY 12 +#define LINUX_SO_LINGER 13 + +#define LINUX_IP_TOS 1 +#define LINUX_IP_TTL 2 + +#endif /* LINUX_H */ diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c new file mode 100644 index 0000000000000..13288acf297c6 --- /dev/null +++ b/sys/i386/linux/linux_dummy.c @@ -0,0 +1,316 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_dummy.c,v 1.3 1995/06/08 13:50:52 sos Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/resourcevar.h> +#include <sys/errno.h> +#include <vm/vm.h> + +int +linux_setup(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): setup() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_break(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): break() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_stat(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): stat() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_fstat(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): fstat() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_mount(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): mount() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_umount(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): umount() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_stime(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): stime() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_ptrace(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): ptrace() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_pause(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): pause() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_stty(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): stty() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_gtty(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): gtty() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_nice(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): nice() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_ftime(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): ftime() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_prof(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): prof() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_signal(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): signal() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_phys(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): phys() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_lock(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): lock() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_mpx(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): mpx() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_ulimit(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): ulimit() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_olduname(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): olduname() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_ustat(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): ustat() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_ioperm(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): ioperm() not supported\n", p->p_pid); + return 0; /* EINVAL SOS XXX */ +} + +int +linux_syslog(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): syslog() not supported (BSD sigreturn)\n",p->p_pid); + return sigreturn(p, args, retval); +} + +int +linux_iopl(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): iopl() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_vhangup(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): vhangup() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_idle(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): idle() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_vm86(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): vm86() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_swapoff(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): swapoff() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_sysinfo(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): sysinfo() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_sigreturn(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): sigreturn() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_clone(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): clone() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_uname(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): uname() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_modify_ldt(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): modify_ldt() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_adjtimex(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): adjtimex() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_create_module(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): create_module() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_init_module(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): init_module() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_delete_module(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): delete_module() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_get_kernel_syms(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): get_kernel_syms() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_quotactl(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): quotactl() not supported\n", p->p_pid); + return ENOSYS; +} + +int +linux_bdflush(struct proc *p, void *args, int *retval) +{ + printf("Linux-emul(%d): bdflush() not supported\n", p->p_pid); + return ENOSYS; +} diff --git a/sys/i386/linux/linux_file.c b/sys/i386/linux/linux_file.c new file mode 100644 index 0000000000000..b846068ccd9ab --- /dev/null +++ b/sys/i386/linux/linux_file.c @@ -0,0 +1,436 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_file.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/vnode.h> +#include <sys/malloc.h> +#include <sys/exec.h> +#include <sys/dirent.h> +#include <vm/vm.h> +#include <ufs/ufs/dir.h> + + +struct linux_creat_args { + char *path; + int mode; +}; + +int +linux_creat(struct proc *p, struct linux_creat_args *args, int *retval) +{ + struct { + char *path; + int flags; + int mode; + } bsd_open_args; + +#ifdef DEBUG + printf("Linux-emul(%d): creat(%s, %d)\n", + p->p_pid, args->path, args->mode); +#endif + bsd_open_args.path = args->path; + bsd_open_args.mode = args->mode; + bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC; + return open(p, &bsd_open_args, retval); +} + +struct linux_open_args { + char *path; + int flags; + int mode; +}; + +int +linux_open(struct proc *p, struct linux_open_args *args, int *retval) +{ + struct { + char *path; + int flags; + int mode; + } bsd_open_args; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n", + p->p_pid, args->path, args->flags, args->mode); +#endif + bsd_open_args.flags = 0; + if (args->flags & LINUX_O_RDONLY) + bsd_open_args.flags |= O_RDONLY; + if (args->flags & LINUX_O_WRONLY) + bsd_open_args.flags |= O_WRONLY; + if (args->flags & LINUX_O_RDWR) + bsd_open_args.flags |= O_RDWR; + if (args->flags & LINUX_O_NDELAY) + bsd_open_args.flags |= O_NONBLOCK; + if (args->flags & LINUX_O_APPEND) + bsd_open_args.flags |= O_APPEND; + if (args->flags & LINUX_O_SYNC) + bsd_open_args.flags |= O_FSYNC; + if (args->flags & LINUX_O_NONBLOCK) + bsd_open_args.flags |= O_NONBLOCK; + if (args->flags & LINUX_FASYNC) + bsd_open_args.flags |= O_ASYNC; + if (args->flags & LINUX_O_CREAT) + bsd_open_args.flags |= O_CREAT; + if (args->flags & LINUX_O_TRUNC) + bsd_open_args.flags |= O_TRUNC; + if (args->flags & LINUX_O_EXCL) + bsd_open_args.flags |= O_EXCL; + if (args->flags & LINUX_O_NOCTTY) + bsd_open_args.flags |= O_NOCTTY; + bsd_open_args.path = args->path; + bsd_open_args.mode = args->mode; + + error = open(p, &bsd_open_args, retval); + if (!error && !(bsd_open_args.flags & O_NOCTTY) && + SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { + struct filedesc *fdp = p->p_fd; + struct file *fp = fdp->fd_ofiles[*retval]; + + if (fp->f_type == DTYPE_VNODE) + (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); + } + return error; +} + +struct linux_flock { + short l_type; + short l_whence; + linux_off_t l_start; + linux_off_t l_len; + linux_pid_t l_pid; +}; + +static void +linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) +{ + switch (linux_flock->l_type) { + case LINUX_F_RDLCK: + bsd_flock->l_type = F_RDLCK; + break; + case LINUX_F_WRLCK: + bsd_flock->l_type = F_WRLCK; + break; + case LINUX_F_UNLCK: + bsd_flock->l_type = F_UNLCK; + break; + } + bsd_flock->l_whence = linux_flock->l_whence; + bsd_flock->l_start = (off_t)linux_flock->l_start; + bsd_flock->l_len = (off_t)linux_flock->l_len; + bsd_flock->l_pid = (pid_t)linux_flock->l_pid; +} + +static void +bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) +{ + switch (bsd_flock->l_type) { + case F_RDLCK: + linux_flock->l_type = LINUX_F_RDLCK; + break; + case F_WRLCK: + linux_flock->l_type = LINUX_F_WRLCK; + break; + case F_UNLCK: + linux_flock->l_type = LINUX_F_UNLCK; + break; + } + linux_flock->l_whence = bsd_flock->l_whence; + linux_flock->l_start = (linux_off_t)bsd_flock->l_start; + linux_flock->l_len = (linux_off_t)bsd_flock->l_len; + linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; +} + +struct linux_fcntl_args { + int fd; + int cmd; + int arg; +}; + +int +linux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval) +{ + int error, result; + struct fcntl_args { + int fd; + int cmd; + int arg; + } fcntl_args; + struct linux_flock linux_flock; + struct flock *bsd_flock = + (struct flock *)ua_alloc_init(sizeof(struct flock)); + +#ifdef DEBUG + printf("Linux-emul(%d): fcntl(%d, %08x, *)\n", + p->p_pid, args->fd, args->cmd); +#endif + fcntl_args.fd = args->fd; + fcntl_args.arg = 0; + + switch (args->cmd) { + case LINUX_F_DUPFD: + fcntl_args.cmd = F_DUPFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETFD: + fcntl_args.cmd = F_GETFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_SETFD: + fcntl_args.cmd = F_SETFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETFL: + fcntl_args.cmd = F_GETFL; + error = fcntl(p, &fcntl_args, &result); + *retval = 0; + if (result & O_RDONLY) *retval |= LINUX_O_RDONLY; + if (result & O_WRONLY) *retval |= LINUX_O_WRONLY; + if (result & O_RDWR) *retval |= LINUX_O_RDWR; + if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK; + if (result & O_APPEND) *retval |= LINUX_O_APPEND; + if (result & O_FSYNC) *retval |= LINUX_O_SYNC; + return error; + + case LINUX_F_SETFL: + if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; + if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; + if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; + fcntl_args.cmd = F_SETFL; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETLK: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_GETLK; + fcntl_args.arg = (int)bsd_flock; + if (error = fcntl(p, &fcntl_args, retval)) + return error; + bsd_to_linux_flock(bsd_flock, &linux_flock); + return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, + sizeof(struct linux_flock)); + + case LINUX_F_SETLK: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_SETLK; + fcntl_args.arg = (int)bsd_flock; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_SETLKW: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_SETLKW; + fcntl_args.arg = (int)bsd_flock; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_SETOWN: + fcntl_args.cmd = F_SETOWN; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETOWN: + fcntl_args.cmd = F_GETOWN; + return fcntl(p, &fcntl_args, retval); + } + return EINVAL; +} + +struct linux_lseek_args { + int fdes; + unsigned long off; + int whence; +}; + +int +linux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval) +{ + + struct lseek_args { + int fdes; + int pad; + off_t off; + int whence; + } tmp_args; + off_t tmp_retval; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): lseek(%d, %d, %d)\n", + p->p_pid, args->fdes, args->off, args->whence); +#endif + tmp_args.fdes = args->fdes; + tmp_args.off = (off_t)args->off; + tmp_args.whence = args->whence; + error = lseek(p, &tmp_args, &tmp_retval); + *retval = (int)tmp_retval; + return error; +} + +struct linux_dirent { + long dino; + linux_off_t doff; + unsigned short dreclen; + char dname[LINUX_NAME_MAX + 1]; +}; + +#define LINUX_RECLEN(de,namlen) \ + ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1)) + +struct linux_readdir_args { + int fd; + struct linux_dirent *dent; + unsigned int count; +}; + +int +linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval) +{ + register struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* Linux-format */ + int resid, linuxreclen=0; /* Linux-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + struct vattr va; + off_t off; + struct linux_dirent linux_dirent; + int buflen, error, eofflag, nbytes, justone; + +#ifdef DEBUG + printf("Linux-emul(%d): readdir(%d, *, %d)\n", + p->p_pid, args->fd, args->count); +#endif + if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) + return (error); + + if ((fp->f_flag & FREAD) == 0) + return (EBADF); + + vp = (struct vnode *) fp->f_data; + + if (vp->v_type != VDIR) + return (EINVAL); + + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) + return error; + + nbytes = args->count; + if (nbytes == 1) { + nbytes = sizeof (struct linux_dirent); + justone = 1; + } + else + justone = 0; + + buflen = max(va.va_blocksize, nbytes); + buf = malloc(buflen, M_TEMP, M_WAITOK); + VOP_LOCK(vp); + off = fp->f_offset; +again: + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = p; + auio.uio_resid = buflen; + auio.uio_offset = off; + + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *) 0, 0); + if (error) + goto out; + + inp = buf; + outp = (caddr_t) args->dent; + resid = nbytes; + if ((len = buflen - auio.uio_resid) == 0) + goto eof; + + while (len > 0) { + reclen = ((struct dirent *) inp)->d_reclen; + if (reclen & 3) + panic("linux_readdir"); + off += reclen; + bdp = (struct dirent *) inp; + if (bdp->d_fileno == 0) { + inp += reclen; + continue; + } + linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); + if (reclen > len || resid < linuxreclen) { + outp++; + break; + } + linux_dirent.dino = (long) bdp->d_fileno; + linux_dirent.doff = (linux_off_t) linuxreclen; + linux_dirent.dreclen = (u_short) bdp->d_namlen; + strcpy(linux_dirent.dname, bdp->d_name); + if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) + goto out; + inp += reclen; + outp += linuxreclen; + resid -= linuxreclen; + len -= reclen; + if (justone) + break; + } + + if (outp == (caddr_t) args->dent) + goto again; + fp->f_offset = off; + + if (justone) + nbytes = resid + linuxreclen; +eof: + *retval = nbytes - resid; +out: + VOP_UNLOCK(vp); + free(buf, M_TEMP); + return error; +} diff --git a/sys/i386/linux/linux_generic.c b/sys/i386/linux/linux_generic.c new file mode 100644 index 0000000000000..48df332aeb98e --- /dev/null +++ b/sys/i386/linux/linux_generic.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_generic.c,v 1.3 1995/06/25 17:30:46 sos Exp $ + */ + +#include <i386/linux/linux.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/namei.h> +#include <sys/proc.h> +#include <sys/malloc.h> +#include <sys/vnode.h> + +#include <vm/vm.h> + + +static caddr_t ua_ptr = NULL; + +caddr_t ua_alloc_init(int len) +{ + caddr_t ptr; + + ptr = (caddr_t)ALIGN((PS_STRINGS)); + ptr += sizeof(struct ps_strings); + ua_ptr = (caddr_t)(ptr + ALIGN(len)); + return ptr; +} + +caddr_t ua_alloc(int len) +{ + caddr_t ptr; + + ptr = ua_ptr; + ua_ptr += ALIGN(len); + return ptr; +} diff --git a/sys/i386/linux/linux_ioctl.c b/sys/i386/linux/linux_ioctl.c new file mode 100644 index 0000000000000..12adff4a18a85 --- /dev/null +++ b/sys/i386/linux/linux_ioctl.c @@ -0,0 +1,495 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_ioctl.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/ioctl_compat.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/tty.h> +#include <sys/termios.h> +#include <machine/console.h> + + +struct linux_termios { + unsigned long c_iflag; + unsigned long c_oflag; + unsigned long c_cflag; + unsigned long c_lflag; + unsigned char c_line; + unsigned char c_cc[LINUX_NCCS]; +}; + +struct linux_winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + +static struct speedtab sptab[] = { + { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 }, + { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 }, + { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 }, + { 2400, 11 }, { 4800, 12 }, { 9600, 13 }, + { 19200, 14 }, { 38400, 15 }, + { 57600, 4097 }, { 115200, 4098 }, {-1, -1 } +}; + +static int +linux_to_bsd_speed(int code, struct speedtab *table) +{ + for ( ; table->sp_code != -1; table++) + if (table->sp_code == code) + return (table->sp_speed); + return -1; +} + +static int +bsd_to_linux_speed(int speed, struct speedtab *table) +{ + for ( ; table->sp_speed != -1; table++) + if (table->sp_speed == speed) + return (table->sp_code); + return -1; +} + +static void +bsd_to_linux_termios(struct termios *bsd_termios, + struct linux_termios *linux_termios) +{ + int i, speed; + +#ifdef DEBUG + printf("LINUX: BSD termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bsd_termios->c_cc[i]); + printf("\n"); +#endif + linux_termios->c_iflag = 0; + if (bsd_termios->c_iflag & IGNBRK) + linux_termios->c_iflag |= LINUX_IGNBRK; + if (bsd_termios->c_iflag & BRKINT) + linux_termios->c_iflag |= LINUX_BRKINT; + if (bsd_termios->c_iflag & IGNPAR) + linux_termios->c_iflag |= LINUX_IGNPAR; + if (bsd_termios->c_iflag & PARMRK) + linux_termios->c_iflag |= LINUX_PARMRK; + if (bsd_termios->c_iflag & INPCK) + linux_termios->c_iflag |= LINUX_INPCK; + if (bsd_termios->c_iflag & ISTRIP) + linux_termios->c_iflag |= LINUX_ISTRIP; + if (bsd_termios->c_iflag & INLCR) + linux_termios->c_iflag |= LINUX_INLCR; + if (bsd_termios->c_iflag & IGNCR) + linux_termios->c_iflag |= LINUX_IGNCR; + if (bsd_termios->c_iflag & ICRNL) + linux_termios->c_iflag |= LINUX_ICRNL; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXANY; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXON; + if (bsd_termios->c_iflag & IXOFF) + linux_termios->c_iflag |= LINUX_IXOFF; + if (bsd_termios->c_iflag & IMAXBEL) + linux_termios->c_iflag |= LINUX_IMAXBEL; + + linux_termios->c_oflag = 0; + if (bsd_termios->c_oflag & OPOST) + linux_termios->c_oflag |= LINUX_OPOST; + if (bsd_termios->c_oflag & ONLCR) + linux_termios->c_oflag |= LINUX_ONLCR; + if (bsd_termios->c_oflag & OXTABS) + linux_termios->c_oflag |= LINUX_XTABS; + + linux_termios->c_cflag = + bsd_to_linux_speed(bsd_termios->c_ispeed, sptab); + linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4; + if (bsd_termios->c_cflag & CSTOPB) + linux_termios->c_cflag |= LINUX_CSTOPB; + if (bsd_termios->c_cflag & CREAD) + linux_termios->c_cflag |= LINUX_CREAD; + if (bsd_termios->c_cflag & PARENB) + linux_termios->c_cflag |= LINUX_PARENB; + if (bsd_termios->c_cflag & PARODD) + linux_termios->c_cflag |= LINUX_PARODD; + if (bsd_termios->c_cflag & HUPCL) + linux_termios->c_cflag |= LINUX_HUPCL; + if (bsd_termios->c_cflag & CLOCAL) + linux_termios->c_cflag |= LINUX_CLOCAL; + if (bsd_termios->c_cflag & CRTSCTS) + linux_termios->c_cflag |= LINUX_CRTSCTS; + + linux_termios->c_lflag = 0; + if (bsd_termios->c_lflag & ISIG) + linux_termios->c_lflag |= LINUX_ISIG; + if (bsd_termios->c_lflag & ICANON) + linux_termios->c_lflag |= LINUX_ICANON; + if (bsd_termios->c_lflag & ECHO) + linux_termios->c_lflag |= LINUX_ECHO; + if (bsd_termios->c_lflag & ECHOE) + linux_termios->c_lflag |= LINUX_ECHOE; + if (bsd_termios->c_lflag & ECHOK) + linux_termios->c_lflag |= LINUX_ECHOK; + if (bsd_termios->c_lflag & ECHONL) + linux_termios->c_lflag |= LINUX_ECHONL; + if (bsd_termios->c_lflag & NOFLSH) + linux_termios->c_lflag |= LINUX_NOFLSH; + if (bsd_termios->c_lflag & TOSTOP) + linux_termios->c_lflag |= LINUX_TOSTOP; + if (bsd_termios->c_lflag & ECHOCTL) + linux_termios->c_lflag |= LINUX_ECHOCTL; + if (bsd_termios->c_lflag & ECHOPRT) + linux_termios->c_lflag |= LINUX_ECHOPRT; + if (bsd_termios->c_lflag & ECHOKE) + linux_termios->c_lflag |= LINUX_ECHOKE; + if (bsd_termios->c_lflag & FLUSHO) + linux_termios->c_lflag |= LINUX_FLUSHO; + if (bsd_termios->c_lflag & PENDIN) + linux_termios->c_lflag |= LINUX_PENDIN; + if (bsd_termios->c_lflag & IEXTEN) + linux_termios->c_lflag |= LINUX_IEXTEN; + + for (i=0; i<LINUX_NCCS; i++) + linux_termios->c_cc[i] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR]; + linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT]; + linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE]; + linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL]; + linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF]; + linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL]; + linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN]; + linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME]; + linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2]; + linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP]; + linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART]; + linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP]; + linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT]; + linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD]; + linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE]; + linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT]; + + linux_termios->c_line = 0; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", linux_termios->c_cc[i]); + printf("\n"); +#endif +} + +static void +linux_to_bsd_termios(struct linux_termios *linux_termios, + struct termios *bsd_termios) +{ + int i, speed; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; i<LINUX_NCCS; i++) + printf("%02x ", linux_termios->c_cc[i]); + printf("\n"); +#endif + bsd_termios->c_iflag = 0; + if (linux_termios->c_iflag & LINUX_IGNBRK) + bsd_termios->c_iflag |= IGNBRK; + if (linux_termios->c_iflag & LINUX_BRKINT) + bsd_termios->c_iflag |= BRKINT; + if (linux_termios->c_iflag & LINUX_IGNPAR) + bsd_termios->c_iflag |= IGNPAR; + if (linux_termios->c_iflag & LINUX_PARMRK) + bsd_termios->c_iflag |= PARMRK; + if (linux_termios->c_iflag & LINUX_INPCK) + bsd_termios->c_iflag |= INPCK; + if (linux_termios->c_iflag & LINUX_ISTRIP) + bsd_termios->c_iflag |= ISTRIP; + if (linux_termios->c_iflag & LINUX_INLCR) + bsd_termios->c_iflag |= INLCR; + if (linux_termios->c_iflag & LINUX_IGNCR) + bsd_termios->c_iflag |= IGNCR; + if (linux_termios->c_iflag & LINUX_ICRNL) + bsd_termios->c_iflag |= ICRNL; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXANY; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXON; + if (linux_termios->c_iflag & LINUX_IXOFF) + bsd_termios->c_iflag |= IXOFF; + if (linux_termios->c_iflag & LINUX_IMAXBEL) + bsd_termios->c_iflag |= IMAXBEL; + + bsd_termios->c_oflag = 0; + if (linux_termios->c_oflag & LINUX_OPOST) + bsd_termios->c_oflag |= OPOST; + if (linux_termios->c_oflag & LINUX_ONLCR) + bsd_termios->c_oflag |= ONLCR; + if (linux_termios->c_oflag & LINUX_XTABS) + bsd_termios->c_oflag |= OXTABS; + + bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4; + if (linux_termios->c_cflag & LINUX_CSTOPB) + bsd_termios->c_cflag |= CSTOPB; + if (linux_termios->c_cflag & LINUX_PARENB) + bsd_termios->c_cflag |= PARENB; + if (linux_termios->c_cflag & LINUX_PARODD) + bsd_termios->c_cflag |= PARODD; + if (linux_termios->c_cflag & LINUX_HUPCL) + bsd_termios->c_cflag |= HUPCL; + if (linux_termios->c_cflag & LINUX_CLOCAL) + bsd_termios->c_cflag |= CLOCAL; + if (linux_termios->c_cflag & LINUX_CRTSCTS) + bsd_termios->c_cflag |= CRTSCTS; + + bsd_termios->c_lflag = 0; + if (linux_termios->c_lflag & LINUX_ISIG) + bsd_termios->c_lflag |= ISIG; + if (linux_termios->c_lflag & LINUX_ICANON) + bsd_termios->c_lflag |= ICANON; + if (linux_termios->c_lflag & LINUX_ECHO) + bsd_termios->c_lflag |= ECHO; + if (linux_termios->c_lflag & LINUX_ECHOE) + bsd_termios->c_lflag |= ECHOE; + if (linux_termios->c_lflag & LINUX_ECHOK) + bsd_termios->c_lflag |= ECHOK; + if (linux_termios->c_lflag & LINUX_ECHONL) + bsd_termios->c_lflag |= ECHONL; + if (linux_termios->c_lflag & LINUX_NOFLSH) + bsd_termios->c_lflag |= NOFLSH; + if (linux_termios->c_lflag & LINUX_TOSTOP) + bsd_termios->c_lflag |= TOSTOP; + if (linux_termios->c_lflag & LINUX_ECHOCTL) + bsd_termios->c_lflag |= ECHOCTL; + if (linux_termios->c_lflag & LINUX_ECHOPRT) + bsd_termios->c_lflag |= ECHOPRT; + if (linux_termios->c_lflag & LINUX_ECHOKE) + bsd_termios->c_lflag |= ECHOKE; + if (linux_termios->c_lflag & LINUX_FLUSHO) + bsd_termios->c_lflag |= FLUSHO; + if (linux_termios->c_lflag & LINUX_PENDIN) + bsd_termios->c_lflag |= PENDIN; + if (linux_termios->c_lflag & IEXTEN) + bsd_termios->c_lflag |= IEXTEN; + + for (i=0; i<NCCS; i++) + bsd_termios->c_cc[i] = _POSIX_VDISABLE; + bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR]; + bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT]; + bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE]; + bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL]; + bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF]; + bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL]; + bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN]; + bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME]; + bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2]; + bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP]; + bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART]; + bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP]; + bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT]; + bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD]; + bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE]; + bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT]; + + bsd_termios->c_ispeed = bsd_termios->c_ospeed = + linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab); +#ifdef DEBUG + printf("LINUX: BSD termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; i<NCCS; i++) + printf("%02x ", bsd_termios->c_cc[i]); + printf("\n"); +#endif +} + + +struct linux_ioctl_args { + int fd; + int cmd; + int arg; +}; + +int +linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval) +{ + struct termios bsd_termios; + struct winsize bsd_winsize; + struct linux_termios linux_termios; + struct linux_winsize linux_winsize; + struct filedesc *fdp = p->p_fd; + struct file *fp; + int (*func)(); + int bsd_line, linux_line; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): ioctl(%d, %04x, *)\n", + p->p_pid, args->fd, args->cmd); +#endif + if ((unsigned)args->fd >= fdp->fd_nfiles + || (fp = fdp->fd_ofiles[args->fd]) == 0) + return EBADF; + + if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) { + return EBADF; + } + + func = fp->f_ops->fo_ioctl; + switch (args->cmd) { + case LINUX_TCGETS: + if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0) + return error; + bsd_to_linux_termios(&bsd_termios, &linux_termios); + return copyout((caddr_t)&linux_termios, (caddr_t)args->arg, + sizeof(linux_termios)); + + case LINUX_TCSETS: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSW: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSF: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p); + + case LINUX_TIOCGPGRP: + args->cmd = TIOCGPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCSPGRP: + args->cmd = TIOCSPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCGWINSZ: + args->cmd = TIOCGWINSZ; + return ioctl(p, args, retval); + + case LINUX_TIOCSWINSZ: + args->cmd = TIOCSWINSZ; + return ioctl(p, args, retval); + + case LINUX_FIONREAD: + args->cmd = FIONREAD; + return ioctl(p, args, retval); + + case LINUX_FIONBIO: + args->cmd = FIONBIO; + return ioctl(p, args, retval); + + case LINUX_FIOASYNC: + args->cmd = FIOASYNC; + return ioctl(p, args, retval); + + case LINUX_FIONCLEX: + args->cmd = FIONCLEX; + return ioctl(p, args, retval); + + case LINUX_FIOCLEX: + args->cmd = FIOCLEX; + return ioctl(p, args, retval); + + case LINUX_TIOCEXCL: + args->cmd = TIOCEXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCNXCL: + args->cmd = TIOCNXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCCONS: + args->cmd = TIOCCONS; + return ioctl(p, args, retval); + + case LINUX_TIOCNOTTY: + args->cmd = TIOCNOTTY; + return ioctl(p, args, retval); + + case LINUX_TIOCSETD: + switch (args->arg) { + case LINUX_N_TTY: + bsd_line = TTYDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_SLIP: + bsd_line = SLIPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_PPP: + bsd_line = PPPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + default: + return EINVAL; + } + break; + + case LINUX_TIOCGETD: + bsd_line = TTYDISC; + if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p)) + return error; + switch (bsd_line) { + case TTYDISC: + linux_line = LINUX_N_TTY; + break; + case SLIPDISC: + linux_line = LINUX_N_SLIP; + break; + case PPPDISC: + linux_line = LINUX_N_PPP; + break; + default: + return EINVAL; + } + return copyout(&linux_line, (caddr_t)args->arg, + sizeof(int)); + } + uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n", + args->fd, (args->cmd&0xffff00)>>8, + (args->cmd&0xffff00)>>8, args->cmd&0xff); + return EINVAL; +} diff --git a/sys/i386/linux/linux_ipc.c b/sys/i386/linux/linux_ipc.c new file mode 100644 index 0000000000000..b38b229c691f5 --- /dev/null +++ b/sys/i386/linux/linux_ipc.c @@ -0,0 +1,308 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_ipc.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/proc.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/msg.h> + +#include <vm/vm.h> + +struct linux_ipc_perm { + linux_key_t key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +static void +linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp) +{ + bpp->key = lpp->key; + bpp->uid = lpp->uid; + bpp->gid = lpp->gid; + bpp->cuid = lpp->cuid; + bpp->cgid = lpp->cgid; + bpp->mode = lpp->mode; + bpp->seq = lpp->seq; +} + + +static void +bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp) +{ + lpp->key = bpp->key; + lpp->uid = bpp->uid; + lpp->gid = bpp->gid; + lpp->cuid = bpp->cuid; + lpp->cgid = bpp->cgid; + lpp->mode = bpp->mode; + lpp->seq = bpp->seq; +} + +struct linux_shmid_ds { + struct linux_ipc_perm shm_perm; + int shm_segsz; + linux_time_t shm_atime; + linux_time_t shm_dtime; + linux_time_t shm_ctime; + ushort shm_cpid; + ushort shm_lpid; + short shm_nattch; + ushort private1; + void *private2; + void *private3; +}; + +static void +linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp) +{ + linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); + bsp->shm_segsz = lsp->shm_segsz; + bsp->shm_lpid = lsp->shm_lpid; + bsp->shm_cpid = lsp->shm_cpid; + bsp->shm_nattch = lsp->shm_nattch; + bsp->shm_atime = lsp->shm_atime; + bsp->shm_dtime = lsp->shm_dtime; + bsp->shm_ctime = lsp->shm_ctime; + bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */ +} + +static void +bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp) +{ + bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); + lsp->shm_segsz = bsp->shm_segsz; + lsp->shm_lpid = bsp->shm_lpid; + lsp->shm_cpid = bsp->shm_cpid; + lsp->shm_nattch = bsp->shm_nattch; + lsp->shm_atime = bsp->shm_atime; + lsp->shm_dtime = bsp->shm_dtime; + lsp->shm_ctime = bsp->shm_ctime; + lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ +} + +struct linux_ipc_args { + int what; + int arg1; + int arg2; + int arg3; + caddr_t ptr; +}; + +int +linux_semop(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_semget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_semctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgsnd(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgrcv(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_shmat(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + struct shmat_args { + int shmid; + void *shmaddr; + int shmflg; + } bsd_args; + int error; + + bsd_args.shmid = args->arg1; + bsd_args.shmaddr = args->ptr; + bsd_args.shmflg = args->arg2; + if ((error = shmat(p, &bsd_args, retval))) + return error; + if ((error = copyout(retval, (caddr_t)args->arg3, sizeof(int)))) + return error; + retval[0] = 0; + return 0; +} + +int +linux_shmdt(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + struct shmdt_args { + void *shmaddr; + } bsd_args; + + bsd_args.shmaddr = args->ptr; + return shmdt(p, &bsd_args, retval); +} + +int +linux_shmget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + struct shmget_args { + key_t key; + int size; + int shmflg; + } bsd_args; + + bsd_args.key = args->arg1; + bsd_args.size = args->arg2; + bsd_args.shmflg = args->arg3; + return shmget(p, &bsd_args, retval); +} + +int +linux_shmctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + struct shmid_ds bsd_shmid; + struct linux_shmid_ds linux_shmid; + struct shmctl_args { + int shmid; + int cmd; + struct shmid_ds *buf; + } bsd_args; + int error; + + switch (args->arg2) { + case LINUX_IPC_STAT: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_STAT; + bsd_args.buf = (struct shmid_ds*)ua_alloc_init(sizeof(struct shmid_ds)); + if ((error = shmctl(p, &bsd_args, retval))) + return error; + if ((error = copyin((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + sizeof(struct shmid_ds)))) + return error; + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); + return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid)); + + case LINUX_IPC_SET: + if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, + sizeof(linux_shmid)))) + return error; + linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); + bsd_args.buf = (struct shmid_ds*)ua_alloc_init(sizeof(struct shmid_ds)); + if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + sizeof(struct shmid_ds)))) + return error; + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_SET; + return shmctl(p, &bsd_args, retval); + + case LINUX_IPC_RMID: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_RMID; + if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, + sizeof(linux_shmid)))) + return error; + linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); + bsd_args.buf = (struct shmid_ds*)ua_alloc_init(sizeof(struct shmid_ds)); + if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + sizeof(struct shmid_ds)))) + return error; + return shmctl(p, &bsd_args, retval); + + case LINUX_IPC_INFO: + case LINUX_SHM_STAT: + case LINUX_SHM_INFO: + case LINUX_SHM_LOCK: + case LINUX_SHM_UNLOCK: + default: + uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); + return EINVAL; + } +} + +int +linux_ipc(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + switch (args->what) { + case LINUX_SEMOP: + return linux_semop(p, args, retval); + case LINUX_SEMGET: + return linux_semget(p, args, retval); + case LINUX_SEMCTL: + return linux_semctl(p, args, retval); + case LINUX_MSGSND: + return linux_msgsnd(p, args, retval); + case LINUX_MSGRCV: + return linux_msgrcv(p, args, retval); + case LINUX_MSGGET: + return linux_msgget(p, args, retval); + case LINUX_MSGCTL: + return linux_msgctl(p, args, retval); + case LINUX_SHMAT: + return linux_shmat(p, args, retval); + case LINUX_SHMDT: + return linux_shmdt(p, args, retval); + case LINUX_SHMGET: + return linux_shmget(p, args, retval); + case LINUX_SHMCTL: + return linux_shmctl(p, args, retval); + default: + uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); + return ENOSYS; + } +} diff --git a/sys/i386/linux/linux_misc.c b/sys/i386/linux/linux_misc.c new file mode 100644 index 0000000000000..bf40786e28a8a --- /dev/null +++ b/sys/i386/linux/linux_misc.c @@ -0,0 +1,660 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_misc.c,v 1.4 1995/06/08 13:50:52 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/exec.h> +#include <sys/mman.h> +#include <sys/proc.h> +#include <sys/dirent.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/ioctl.h> +#include <sys/imgact_aout.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/resource.h> +#include <sys/resourcevar.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/utsname.h> +#include <sys/vnode.h> +#include <sys/wait.h> + +#include <machine/cpu.h> +#include <machine/psl.h> +#include <machine/reg.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> + + +struct linux_alarm_args { + unsigned int secs; +}; + +int +linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval) +{ + extern struct timeval time; + struct itimerval it, old_it; + int s; + +#ifdef DEBUG + printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs); +#endif + it.it_value.tv_sec = (long)args->secs; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + s = splclock(); + old_it = p->p_realtimer; + if (timerisset(&old_it.it_value)) + if (timercmp(&old_it.it_value, &time, <)) + timerclear(&old_it.it_value); + else + timevalsub(&old_it.it_value, &time); + splx(s); + if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) + return EINVAL; + s = splclock(); + untimeout(realitexpire, (caddr_t)p); + if (timerisset(&it.it_value)) { + timevaladd(&it.it_value, &time); + timeout(realitexpire, (caddr_t)p, hzto(&it.it_value)); + } + p->p_realtimer = it; + splx(s); + if (old_it.it_value.tv_usec) + old_it.it_value.tv_sec++; + *retval = old_it.it_value.tv_sec; + return 0; +} + +struct linux_brk_args { + linux_caddr_t dsend; +}; + +int +linux_brk(struct proc *p, struct linux_brk_args *args, int *retval) +{ +#if 0 + struct vmspace *vm = p->p_vmspace; + vm_offset_t new, old; + int error; + extern int swap_pager_full; + + if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr) + return EINVAL; + if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr) + > p->p_rlimit[RLIMIT_DATA].rlim_cur) + return ENOMEM; + + old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize); + new = round_page((vm_offset_t)args->dsend); + *retval = old; + if ((new-old) > 0) { + if (swap_pager_full) + return ENOMEM; + error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE); + if (error) + return error; + vm->vm_dsize += btoc((new-old)); + *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize)); + } + return 0; +#else + struct vmspace *vm = p->p_vmspace; + vm_offset_t new, old; + struct obreak_args { + vm_offset_t newsize; + } tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend); +#endif + old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); + new = (vm_offset_t)args->dsend; + tmp.newsize = new; + if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval)) + retval[0] = (int)new; + else + retval[0] = (int)old; + + return 0; +#endif +} + +struct linux_uselib_args { + char *library; +}; + +int +linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) +{ + struct nameidata ni; + struct vnode *vnodep; + struct exec *a_out = 0; + struct vattr attr; + unsigned long vmaddr, virtual_offset, file_offset; + unsigned long buffer, bss_size; + char *ptr; + char path[MAXPATHLEN]; + const char *prefix = "/compat/linux"; + size_t sz, len; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library); +#endif + + for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ; + sz = MAXPATHLEN - (ptr - path); + if (error = copyinstr(args->library, ptr, sz, &len)) + return error; + if (*ptr != '/') + return EINVAL; + +#ifdef DEBUG + printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path); +#endif + + NDINIT(&ni, LOOKUP, FOLLOW, UIO_SYSSPACE, path, p); + if (error = namei(&ni)) + return error; + + vnodep = ni.ni_vp; + if (vnodep == NULL) + return ENOEXEC; + + if (vnodep->v_writecount) + return ETXTBSY; + + if (error = VOP_GETATTR(vnodep, &attr, p->p_ucred, p)) + return error; + + if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) + || ((attr.va_mode & 0111) == 0) + || (attr.va_type != VREG)) + return ENOEXEC; + + if (attr.va_size == 0) + return ENOEXEC; + + if (error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p)) + return error; + + if (error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p)) + return error; + + error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024, + VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vnodep, 0); + if (error) + return (error); + + /* + * Is it a Linux binary ? + */ + if (((a_out->a_magic >> 16) & 0xff) != 0x64) + return -1; + + /* + * Set file/virtual offset based on a.out variant. + */ + switch ((int)(a_out->a_magic & 0xffff)) { + case 0413: /* ZMAGIC */ + virtual_offset = 0; + file_offset = 1024; + break; + case 0314: /* QMAGIC */ + virtual_offset = 4096; + file_offset = 0; + break; + default: + return (-1); + } + + vnodep->v_flag |= VTEXT; + bss_size = round_page(a_out->a_bss); + /* + * Check if file_offset page aligned,. + * Currently we cannot handle misalinged file offsets, + * and so we read in the entire image (what a waste). + */ + if (file_offset & PGOFSET) { +#ifdef DEBUG +printf("uselib: Non page aligned binary %d\n", file_offset); +#endif + /* + * Map text+data read/write/execute + */ + vmaddr = virtual_offset + round_page(a_out->a_entry); + error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, + round_page(a_out->a_text + a_out->a_data), FALSE); + if (error) + return error; + + error = vm_mmap(kernel_map, &buffer, + round_page(a_out->a_text + a_out->a_data + file_offset), + VM_PROT_READ, VM_PROT_READ, MAP_FILE, + (caddr_t)vnodep, trunc_page(file_offset)); + if (error) + return error; + + error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, + a_out->a_text + a_out->a_data); + if (error) + return error; + + vm_map_remove(kernel_map, trunc_page(vmaddr), + round_page(a_out->a_text + a_out->a_data + file_offset)); + + error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, + round_page(a_out->a_text + a_out->a_data), + VM_PROT_ALL, TRUE); + if (error) + return error; + } + else { +#ifdef DEBUG +printf("uselib: Page aligned binary %d\n", file_offset); +#endif + vmaddr = virtual_offset + round_page(a_out->a_entry); + error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, + a_out->a_text + a_out->a_data, + VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, + (caddr_t)vnodep, file_offset); + if (error) + return (error); + } +#ifdef DEBUG +printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]); +#endif + if (bss_size != 0) { + vmaddr = virtual_offset + round_page(a_out->a_entry) + + round_page(a_out->a_text + a_out->a_data); + error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, + bss_size, FALSE); + if (error) + return error; + error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size, + VM_PROT_ALL, TRUE); + if (error) + return error; + } + return 0; +} + +struct linux_select_args { + void *ptr; +}; + +int +linux_select(struct proc *p, struct linux_select_args *args, int *retval) +{ + struct { + int nfds; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; + struct timeval *timeout; + } linux_args; + struct { + unsigned int nd; + fd_set *in; + fd_set *ou; + fd_set *ex; + struct timeval *tv; + } bsd_args; + int error; + + if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, + sizeof(linux_args)))) + return error; +#ifdef DEBUG + printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n", + p->p_pid, linux_args.nfds, linux_args.readfds, + linux_args.writefds, linux_args.exceptfds, + linux_args.timeout); +#endif + bsd_args.nd = linux_args.nfds; + bsd_args.in = linux_args.readfds; + bsd_args.ou = linux_args.writefds; + bsd_args.ex = linux_args.exceptfds; + bsd_args.tv = linux_args.timeout; + return select(p, &bsd_args, retval); +} + +struct linux_getpgid_args { + int pid; +}; + +int +linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval) +{ + struct proc *curproc; + +#ifdef DEBUG + printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid); +#endif + if (args->pid != p->p_pid) { + if (!(curproc = pfind(args->pid))) + return ESRCH; + } + else + curproc = p; + *retval = curproc->p_pgid; + return 0; +} + +int +linux_fork(struct proc *p, void *args, int *retval) +{ + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): fork()\n", p->p_pid); +#endif + if (error = fork(p, args, retval)) + return error; + if (retval[1] == 1) + retval[0] = 0; + return 0; +} + +struct linux_mmap_args { + void *ptr; +}; + +int +linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval) +{ + struct { + linux_caddr_t addr; + int len; + int prot; + int flags; + int fd; + int pos; + } linux_args; + struct { + caddr_t addr; + size_t len; + int prot; + int flags; + int fd; + long pad; + off_t pos; + } bsd_args; + int error; + + if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, + sizeof(linux_args)))) + return error; +#ifdef DEBUG + printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n", + p->p_pid, linux_args.addr, linux_args.len, linux_args.prot, + linux_args.flags, linux_args.fd, linux_args.pos); +#endif + bsd_args.flags = 0; + if (linux_args.flags & LINUX_MAP_SHARED) + bsd_args.flags |= MAP_SHARED; + if (linux_args.flags & LINUX_MAP_PRIVATE) + bsd_args.flags |= MAP_PRIVATE; + if (linux_args.flags & LINUX_MAP_FIXED) + bsd_args.flags |= MAP_FIXED; + if (linux_args.flags & LINUX_MAP_ANON) + bsd_args.flags |= MAP_ANON; + bsd_args.addr = linux_args.addr; + bsd_args.len = linux_args.len; + bsd_args.prot = linux_args.prot; + bsd_args.fd = linux_args.fd; + bsd_args.pos = linux_args.pos; + bsd_args.pad = 0; + return mmap(p, &bsd_args, retval); +} + +struct linux_pipe_args { + int *pipefds; +}; + +int +linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval) +{ + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): pipe(*)\n", p->p_pid); +#endif + if (error = pipe(p, 0, retval)) + return error; + if (error = copyout(retval, args->pipefds, 2*sizeof(int))) + return error; + *retval = 0; + return 0; +} + +struct linux_time_args { + linux_time_t *tm; +}; + +int +linux_time(struct proc *p, struct linux_time_args *args, int *retval) +{ + struct timeval tv; + linux_time_t tm; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): time(*)\n", p->p_pid); +#endif + microtime(&tv); + tm = tv.tv_sec; + if (error = copyout(&tm, args->tm, sizeof(linux_time_t))) + return error; + *retval = tv.tv_sec; + return 0; +} + +struct linux_tms { + long tms_utime; + long tms_stime; + long tms_cutime; + long tms_cstime; +}; + +struct linux_tms_args { + char *buf; +}; + +int +linux_times(struct proc *p, struct linux_tms_args *args, int *retval) +{ + extern int hz; + struct timeval tv; + struct linux_tms tms; + +#ifdef DEBUG + printf("Linux-emul(%d): times(*)\n", p->p_pid); +#endif + tms.tms_utime = p->p_uticks; + tms.tms_stime = p->p_sticks; + tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz + + ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000); + tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz + + ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000); + microtime(&tv); + *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000; + return (copyout((caddr_t)&tms, (caddr_t)args->buf, + sizeof(struct linux_tms))); +} + +struct linux_newuname_t { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +struct linux_newuname_args { + char *buf; +}; + +int +linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval) +{ + struct linux_newuname_t linux_newuname; + extern char ostype[], osrelease[], machine[]; + extern char hostname[], domainname[]; + +#ifdef DEBUG + printf("Linux-emul(%d): newuname(*)\n", p->p_pid); +#endif + bzero(&linux_newuname, sizeof(struct linux_newuname_args)); + strncpy(linux_newuname.sysname, ostype, 64); + strncpy(linux_newuname.nodename, hostname, 64); + strncpy(linux_newuname.release, osrelease, 64); + strncpy(linux_newuname.version, version, 64); + strncpy(linux_newuname.machine, machine, 64); + strncpy(linux_newuname.domainname, domainname, 64); + return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf, + sizeof(struct linux_newuname_t))); +} + +struct linux_utime_args { + char *fname; + linux_time_t *timeptr; +}; + +int +linux_utime(struct proc *p, struct linux_utime_args *args, int *retval) +{ + struct bsd_utimes_args { + char *fname; + struct timeval *tptr; + } bsdutimes; + struct timeval tv; + +#ifdef DEBUG + printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname); +#endif + tv.tv_sec = (long)args->timeptr; + tv.tv_usec = 0; + bsdutimes.tptr = &tv; + bsdutimes.fname = args->fname; + return utimes(p, &bsdutimes, retval); +} + +struct linux_waitpid_args { + int pid; + int *status; + int options; +}; + +int +linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval) +{ + struct wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; + int compat; + } tmp; + int error, tmpstat; + +#ifdef DEBUG + printf("Linux-emul(%d): waitpid(%d, *, %d)\n", + p->p_pid, args->pid, args->options); +#endif + tmp.pid = args->pid; + tmp.status = args->status; + tmp.options = args->options; + tmp.rusage = NULL; + tmp.compat = 0; + + if (error = wait4(p, &tmp, retval)) + return error; + if (error = copyin(args->status, &tmpstat, sizeof(int))) + return error; + if (WIFSIGNALED(tmpstat)) + tmpstat = (tmpstat & 0xffffff80) | + bsd_to_linux_signal[WTERMSIG(tmpstat)]; + else if (WIFSTOPPED(tmpstat)) + tmpstat = (tmpstat & 0xffff00ff) | + (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); + return copyout(&tmpstat, args->status, sizeof(int)); +} + +struct linux_wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; +}; + +int +linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval) +{ + struct wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; + int compat; + } tmp; + int error, tmpstat; + +#ifdef DEBUG + printf("Linux-emul(%d): wait4(%d, *, %d, *)\n", + p->p_pid, args->pid, args->options); +#endif + tmp.pid = args->pid; + tmp.status = args->status; + tmp.options = args->options; + tmp.rusage = args->rusage; + tmp.compat = 0; + + if (error = wait4(p, &tmp, retval)) + return error; + if (error = copyin(args->status, &tmpstat, sizeof(int))) + return error; + if (WIFSIGNALED(tmpstat)) + tmpstat = (tmpstat & 0xffffff80) | + bsd_to_linux_signal[WTERMSIG(tmpstat)]; + else if (WIFSTOPPED(tmpstat)) + tmpstat = (tmpstat & 0xffff00ff) | + (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); + return copyout(&tmpstat, args->status, sizeof(int)); +} diff --git a/sys/i386/linux/linux_signal.c b/sys/i386/linux/linux_signal.c new file mode 100644 index 0000000000000..528bb62d2aa3b --- /dev/null +++ b/sys/i386/linux/linux_signal.c @@ -0,0 +1,259 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_signal.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/exec.h> +#include <sys/signal.h> +#include <sys/signalvar.h> + +#include <vm/vm.h> + +#include <i386/linux/linux.h> + +#define DONTMASK (sigmask(SIGKILL)|sigmask(SIGSTOP)|sigmask(SIGCHLD)) + +static sigset_t +linux_to_bsd_sigmask(linux_sigset_t mask) { + int i; + sigset_t new = 0; + + for (i = 1; i <= LINUX_NSIG; i++) + if (mask & (1 << i-1)) + new |= (1 << (linux_to_bsd_signal[i]-1)); + return new; +} + +static linux_sigset_t +bsd_to_linux_sigmask(sigset_t mask) { + int i; + sigset_t new = 0; + + for (i = 1; i <= NSIG; i++) + if (mask & (1 << i-1)) + new |= (1 << (bsd_to_linux_signal[i]-1)); + return new; +} + +struct linux_sigaction_args { + int sig; + linux_sigaction_t *nsa; + linux_sigaction_t *osa; +}; + +int +linux_sigaction(struct proc *p, struct linux_sigaction_args *args, int *retval) +{ + linux_sigaction_t linux_sa; + struct sigaction *nsa = NULL, *osa = NULL, bsd_sa; + struct sigaction_args { + int sig; + struct sigaction *nsa; + struct sigaction *osa; + } sa; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): sigaction(%d, *, *)\n", p->p_pid, args->sig); +#endif + if (args->osa) + osa = (struct sigaction *)ua_alloc_init(sizeof(struct sigaction)); + + if (args->nsa) { + nsa = (struct sigaction *)ua_alloc(sizeof(struct sigaction)); + if (error = copyin(args->nsa, &linux_sa, sizeof(linux_sigaction_t))) + return error; + bsd_sa.sa_mask = linux_to_bsd_sigmask(linux_sa.sa_mask); + bsd_sa.sa_handler = linux_sa.sa_handler; + bsd_sa.sa_flags = 0; + if (linux_sa.sa_flags & LINUX_SA_NOCLDSTOP) + bsd_sa.sa_flags |= SA_NOCLDSTOP; + if (linux_sa.sa_flags & LINUX_SA_ONSTACK) + bsd_sa.sa_flags |= SA_ONSTACK; + if (linux_sa.sa_flags & LINUX_SA_RESTART) + bsd_sa.sa_flags |= SA_RESTART; + if (error = copyout(&bsd_sa, nsa, sizeof(struct sigaction))) + return error; + } + sa.sig = linux_to_bsd_signal[args->sig]; + sa.nsa = nsa; + sa.osa = osa; + if ((error = sigaction(p, &sa, retval))) + return error; + + if (args->osa) { + if (error = copyin(osa, &bsd_sa, sizeof(struct sigaction))) + return error; + linux_sa.sa_handler = bsd_sa.sa_handler; + linux_sa.sa_restorer = NULL; + linux_sa.sa_mask = bsd_to_linux_sigmask(bsd_sa.sa_mask); + linux_sa.sa_flags = 0; + if (bsd_sa.sa_flags & SA_NOCLDSTOP) + linux_sa.sa_flags |= LINUX_SA_NOCLDSTOP; + if (bsd_sa.sa_flags & SA_ONSTACK) + linux_sa.sa_flags |= LINUX_SA_ONSTACK; + if (bsd_sa.sa_flags & SA_RESTART) + linux_sa.sa_flags |= LINUX_SA_RESTART; + if (error = copyout(&linux_sa, args->osa, sizeof(linux_sigaction_t))) + return error; + } + return 0; +} + +struct linux_sigprocmask_args { + int how; + linux_sigset_t *mask; + linux_sigset_t *omask; +}; + +int +linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args, + int *retval) +{ + int error, s; + sigset_t mask; + sigset_t omask; + +#ifdef DEBUG + printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); +#endif + if (args->omask != NULL) { + omask = bsd_to_linux_sigmask(p->p_sigmask); + if (error = copyout(&omask, args->omask, sizeof(sigset_t))) + return error; + } + if (!(args->mask)) + return 0; + if (error = copyin(args->mask, &mask, sizeof(linux_sigset_t))) + return error; + + mask = linux_to_bsd_sigmask(mask); + s = splhigh(); + switch (args->how) { + case LINUX_SIG_BLOCK: + p->p_sigmask |= (mask & ~DONTMASK); + break; + case LINUX_SIG_UNBLOCK: + p->p_sigmask &= ~mask; + break; + case LINUX_SIG_SETMASK: + p->p_sigmask = (mask & ~DONTMASK); + break; + default: + error = EINVAL; + break; + } + splx(s); + return error; +} + +int +linux_siggetmask(struct proc *p, void *args, int *retval) +{ +#ifdef DEBUG + printf("Linux-emul(%d): siggetmask()\n", p->p_pid); +#endif + *retval = bsd_to_linux_sigmask(p->p_sigmask); + return 0; +} + +struct linux_sigsetmask_args { + linux_sigset_t mask; +}; + +int +linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args,int *retval) +{ + int s; + +#ifdef DEBUG + printf("Linux-emul(%d): sigsetmask(%08x)\n", p->p_pid, args->mask); +#endif + s = splhigh(); + p->p_sigmask = (linux_to_bsd_sigmask(args->mask) & ~DONTMASK); + splx(s); + *retval = bsd_to_linux_sigmask(p->p_sigmask); + return 0; +} + +struct linux_sigpending_args { + linux_sigset_t *mask; +}; + +int +linux_sigpending(struct proc *p, struct linux_sigpending_args *args,int *retval) +{ + linux_sigset_t linux_sig; + +#ifdef DEBUG + printf("Linux-emul(%d): sigpending(*)\n", p->p_pid); +#endif + linux_sig = bsd_to_linux_sigmask(p->p_siglist & p->p_sigmask); + return copyout(&linux_sig, args->mask, sizeof(linux_sig)); +} + +struct linux_sigsuspend_args { + linux_sigset_t mask; +}; + +int +linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args,int *retval) +{ + sigset_t tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): sigsuspend(%08x)\n", p->p_pid, args->mask); +#endif + tmp = linux_to_bsd_sigmask(args->mask); + return sigsuspend(p, &tmp , retval); +} + +struct linux_kill_args { + int pid; + int signum; +}; + +int +linux_kill(struct proc *p, struct linux_kill_args *args, int *retval) +{ + struct { + int pid; + int signum; + } tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): kill(%d, %d)\n", + p->p_pid, args->pid, args->signum); +#endif + tmp.pid = args->pid; + tmp.signum = linux_to_bsd_signal[args->signum]; + return kill(p, &tmp, retval); +} diff --git a/sys/i386/linux/linux_socket.c b/sys/i386/linux/linux_socket.c new file mode 100644 index 0000000000000..9267063a7f7e1 --- /dev/null +++ b/sys/i386/linux/linux_socket.c @@ -0,0 +1,595 @@ +/*- + * Copyright (c) 1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_socket.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <netinet/in.h> + + +static int +linux_to_bsd_domain(int domain) +{ + switch (domain) { + case LINUX_AF_UNSPEC: + return AF_UNSPEC; + case LINUX_AF_UNIX: + return AF_LOCAL; + case LINUX_AF_INET: + return AF_INET; + case LINUX_AF_AX25: + return AF_CCITT; + case LINUX_AF_IPX: + return AF_IPX; + case LINUX_AF_APPLETALK: + return AF_APPLETALK; + default: + return -1; + } +} + +static int +linux_to_bsd_sockopt_level(int level) +{ + switch (level) { + case LINUX_SOL_SOCKET: + return SOL_SOCKET; + default: + return level; + } +} + +static int linux_to_bsd_ip_sockopt(int opt) +{ + switch (opt) { + case LINUX_IP_TOS: + return IP_TOS; + case LINUX_IP_TTL: + return IP_TTL; + default: + return -1; + } +} + +static int +linux_to_bsd_so_sockopt(int opt) +{ + switch (opt) { + case LINUX_SO_DEBUG: + return SO_DEBUG; + case LINUX_SO_REUSEADDR: + return SO_REUSEADDR; + case LINUX_SO_TYPE: + return SO_TYPE; + case LINUX_SO_ERROR: + return SO_ERROR; + case LINUX_SO_DONTROUTE: + return SO_DONTROUTE; + case LINUX_SO_BROADCAST: + return SO_BROADCAST; + case LINUX_SO_SNDBUF: + return SO_SNDBUF; + case LINUX_SO_RCVBUF: + return SO_RCVBUF; + case LINUX_SO_KEEPALIVE: + return SO_KEEPALIVE; + case LINUX_SO_OOBINLINE: + return SO_OOBINLINE; + case LINUX_SO_LINGER: + return SO_LINGER; + case LINUX_SO_PRIORITY: + case LINUX_SO_NO_CHECK: + default: + return -1; + } +} + +struct linux_socket_args { + int domain; + int type; + int protocol; +}; + +static int +linux_socket(struct proc *p, struct linux_socket_args *args, int *retval) +{ + struct linux_socket_args linux_args; + struct { + int domain; + int type; + int protocol; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.protocol = linux_args.protocol; + bsd_args.type = linux_args.type; + bsd_args.domain = linux_to_bsd_domain(linux_args.domain); + if (bsd_args.domain == -1) + return EINVAL; + return socket(p, &bsd_args, retval); +} + +struct linux_bind_args { + int s; + struct sockaddr *name; + int namelen; +}; + +static int +linux_bind(struct proc *p, struct linux_bind_args *args, int *retval) +{ + struct linux_bind_args linux_args; + struct { + int s; + caddr_t name; + int namelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.name; + bsd_args.namelen = linux_args.namelen; + return bind(p, &bsd_args, retval); +} + +struct linux_connect_args { + int s; + struct sockaddr * name; + int namelen; +}; + +static int +linux_connect(struct proc *p, struct linux_connect_args *args, int *retval) +{ + struct linux_connect_args linux_args; + struct { + int s; + caddr_t name; + int namelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.name; + bsd_args.namelen = linux_args.namelen; + return connect(p, &bsd_args, retval); +} + +struct linux_listen_args { + int s; + int backlog; +}; + +static int +linux_listen(struct proc *p, struct linux_listen_args *args, int *retval) +{ + struct linux_listen_args linux_args; + struct { + int s; + int backlog; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.backlog = linux_args.backlog; + return listen(p, &bsd_args, retval); +} + +struct linux_accept_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_accept(struct proc *p, struct linux_accept_args *args, int *retval) +{ + struct linux_accept_args linux_args; + struct accept_args { + int s; + caddr_t name; + int *anamelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.addr; + bsd_args.anamelen = linux_args.namelen; + return oaccept(p, &bsd_args, retval); +} + +struct linux_getsockname_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_getsockname(struct proc *p, struct linux_getsockname_args *args, int *retval) +{ + struct linux_getsockname_args linux_args; + struct { + int fdes; + caddr_t asa; + int *alen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.fdes = linux_args.s; + bsd_args.asa = (caddr_t) linux_args.addr; + bsd_args.alen = linux_args.namelen; + return ogetsockname(p, &bsd_args, retval); +} + +struct linux_getpeername_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_getpeername(struct proc *p, struct linux_getpeername_args *args, int *retval) +{ + struct linux_getpeername_args linux_args; + struct getpeername_args { + int fdes; + caddr_t asa; + int *alen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.fdes = linux_args.s; + bsd_args.asa = (caddr_t) linux_args.addr; + bsd_args.alen = linux_args.namelen; + return ogetpeername(p, &bsd_args, retval); +} + +struct linux_socketpair_args { + int domain; + int type; + int protocol; + int *rsv; +}; + +static int +linux_socketpair(struct proc *p, struct linux_socketpair_args *args, int *retval) +{ + struct linux_socketpair_args linux_args; + struct { + int domain; + int type; + int protocol; + int *rsv; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.domain = linux_to_bsd_domain(linux_args.domain); + if (bsd_args.domain == -1) + return EINVAL; + bsd_args.type = linux_args.type; + bsd_args.protocol = linux_args.protocol; + bsd_args.rsv = linux_args.rsv; + return socketpair(p, &bsd_args, retval); +} + +struct linux_send_args { + int s; + void *msg; + int len; + int flags; +}; + +static int +linux_send(struct proc *p, struct linux_send_args *args, int *retval) +{ + struct linux_send_args linux_args; + struct { + int s; + caddr_t buf; + int len; + int flags; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + return osend(p, &bsd_args, retval); +} + +struct linux_recv_args { + int s; + void *msg; + int len; + int flags; +}; + +static int +linux_recv(struct proc *p, struct linux_recv_args *args, int *retval) +{ + struct linux_recv_args linux_args; + struct { + int s; + caddr_t buf; + int len; + int flags; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + return orecv(p, &bsd_args, retval); +} + +struct linux_sendto_args { + int s; + void *msg; + int len; + int flags; + caddr_t to; + int tolen; +}; + +static int +linux_sendto(struct proc *p, struct linux_sendto_args *args, int *retval) +{ + struct linux_sendto_args linux_args; + struct { + int s; + caddr_t buf; + size_t len; + int flags; + caddr_t to; + int tolen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + bsd_args.to = linux_args.to; + bsd_args.tolen = linux_args.tolen; + return sendto(p, &bsd_args, retval); +} + +struct linux_recvfrom_args { + int s; + void *buf; + int len; + int flags; + caddr_t from; + int *fromlen; +}; + +static int +linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args, int *retval) +{ + struct linux_recvfrom_args linux_args; + struct { + int s; + caddr_t buf; + size_t len; + int flags; + caddr_t from; + int *fromlenaddr; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.buf; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + bsd_args.from = linux_args.from; + bsd_args.fromlenaddr = linux_args.fromlen; + return orecvfrom(p, &bsd_args, retval); +} + +struct linux_shutdown_args { + int s; + int how; +}; + +static int +linux_shutdown(struct proc *p, struct linux_shutdown_args *args, int *retval) +{ + struct linux_shutdown_args linux_args; + struct { + int s; + int how; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.how = linux_args.how; + return shutdown(p, &bsd_args, retval); +} + +struct linux_setsockopt_args { + int s; + int level; + int optname; + void *optval; + int optlen; +}; + +static int +linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args, int *retval) +{ + struct linux_setsockopt_args linux_args; + struct { + int s; + int level; + int name; + caddr_t val; + int valsize; + } bsd_args; + int error, name; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(linux_args.optname); + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(linux_args.optname); + break; + default: + return EINVAL; + } + if (name == -1) + return EINVAL; + bsd_args.name = name; + bsd_args.val = linux_args.optval; + bsd_args.valsize = linux_args.optlen; + return setsockopt(p, &bsd_args, retval); +} + +struct linux_getsockopt_args { + int s; + int level; + int optname; + void *optval; + int *optlen; +}; + +static int +linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args, int *retval) +{ + struct linux_getsockopt_args linux_args; + struct { + int s; + int level; + int name; + caddr_t val; + int *avalsize; + } bsd_args; + int error, name; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(linux_args.optname); + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(linux_args.optname); + break; + default: + return EINVAL; + } + if (name == -1) + return EINVAL; + bsd_args.val = linux_args.optval; + bsd_args.avalsize = linux_args.optlen; + return getsockopt(p, &bsd_args, retval); +} + +struct linux_socketcall_args { + int what; + void *args; +}; + +int +linux_socketcall(struct proc *p, struct linux_socketcall_args *args,int *retval) +{ + switch (args->what) { + case LINUX_SOCKET: + return linux_socket(p, args->args, retval); + case LINUX_BIND: + return linux_bind(p, args->args, retval); + case LINUX_CONNECT: + return linux_connect(p, args->args, retval); + case LINUX_LISTEN: + return linux_listen(p, args->args, retval); + case LINUX_ACCEPT: + return linux_accept(p, args->args, retval); + case LINUX_GETSOCKNAME: + return linux_getsockname(p, args->args, retval); + case LINUX_GETPEERNAME: + return linux_getpeername(p, args->args, retval); + case LINUX_SOCKETPAIR: + return linux_socketpair(p, args->args, retval); + case LINUX_SEND: + return linux_send(p, args->args, retval); + case LINUX_RECV: + return linux_recv(p, args->args, retval); + case LINUX_SENDTO: + return linux_sendto(p, args->args, retval); + case LINUX_RECVFROM: + return linux_recvfrom(p, args->args, retval); + case LINUX_SHUTDOWN: + return linux_shutdown(p, args->args, retval); + case LINUX_SETSOCKOPT: + return linux_setsockopt(p, args->args, retval); + case LINUX_GETSOCKOPT: + return linux_getsockopt(p, args->args, retval); + default: + uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); + return ENOSYS; + } +} diff --git a/sys/i386/linux/linux_stats.c b/sys/i386/linux/linux_stats.c new file mode 100644 index 0000000000000..1dbfcf11e64bf --- /dev/null +++ b/sys/i386/linux/linux_stats.c @@ -0,0 +1,273 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_stats.c,v 1.3 1995/06/08 13:50:52 sos Exp $ + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/dirent.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/proc.h> +#include <sys/mount.h> +#include <sys/namei.h> +#include <sys/stat.h> +#include <sys/vnode.h> + +#include <machine/cpu.h> +#include <machine/psl.h> +#include <machine/reg.h> + +#include <i386/linux/linux.h> + +struct linux_newstat { + unsigned short stat_dev; + unsigned short __pad1; + unsigned long stat_ino; + unsigned short stat_mode; + unsigned short stat_nlink; + unsigned short stat_uid; + unsigned short stat_gid; + unsigned short stat_rdev; + unsigned short __pad2; + unsigned long stat_size; + unsigned long stat_blksize; + unsigned long stat_blocks; + unsigned long stat_atime; + unsigned long __unused1; + unsigned long stat_mtime; + unsigned long __unused2; + unsigned long stat_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +struct linux_newstat_args { + char *path; + struct linux_newstat *buf; +}; + +static int +newstat_copyout(struct stat *buf, void *ubuf) +{ + struct linux_newstat tbuf; + + tbuf.stat_dev = (buf->st_dev & 0xff) | ((buf->st_dev & 0xff00)<<10); + tbuf.stat_ino = buf->st_ino; + tbuf.stat_mode = buf->st_mode; + tbuf.stat_nlink = buf->st_nlink; + tbuf.stat_uid = buf->st_uid; + tbuf.stat_gid = buf->st_gid; + tbuf.stat_rdev = buf->st_rdev; + tbuf.stat_size = buf->st_size; + tbuf.stat_atime = buf->st_atime; + tbuf.stat_mtime = buf->st_mtime; + tbuf.stat_ctime = buf->st_ctime; + tbuf.stat_blksize = buf->st_blksize; + tbuf.stat_blocks = buf->st_blocks; + return copyout(&tbuf, ubuf, sizeof(tbuf)); +} + +int +linux_newstat(struct proc *p, struct linux_newstat_args *args, int *retval) +{ + struct stat buf; + struct linux_newstat tbuf; + struct nameidata nd; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newstat(%s, *)\n", p->p_pid, args->path); +#endif + NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_USERSPACE, args->path, p); + error = namei(&nd); + if (!error) { + error = vn_stat(nd.ni_vp, &buf, p); + vput(nd.ni_vp); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +int +linux_newlstat(struct proc *p, struct linux_newstat_args *args, int *retval) +{ + struct stat buf; + struct linux_newstat tbuf; + struct nameidata nd; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newlstat(%s, *)\n", p->p_pid, args->path); +#endif + NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_USERSPACE, args->path, p); + error = namei(&nd); + if (!error) { + error = vn_stat(nd.ni_vp, &buf, p); + vput(nd.ni_vp); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +struct linux_newfstat_args { + int fd; + struct linux_newstat *buf; +}; + +int +linux_newfstat(struct proc *p, struct linux_newfstat_args *args, int *retval) +{ + struct linux_newstat tbuf; + struct filedesc *fdp = p->p_fd; + struct file *fp; + struct stat buf; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newlstat(%d, *)\n", p->p_pid, args->fd); +#endif + if ((unsigned)args->fd >= fdp->fd_nfiles + || (fp = fdp->fd_ofiles[args->fd]) == NULL) + return EBADF; + switch (fp->f_type) { + case DTYPE_VNODE: + error = vn_stat((struct vnode *)fp->f_data, &buf, p); + break; + case DTYPE_SOCKET: + error = soo_stat((struct socket *)fp->f_data, &buf); + break; + default: + panic("LINUX newfstat"); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +struct linux_statfs { + long ftype; + long fbsize; + long fblocks; + long fbfree; + long fbavail; + long ffiles; + long fffree; + linux_fsid_t ffsid; + long fnamelen; + long fspare[6]; +}; + + +struct linux_statfs_args { + char *path; + struct statfs *buf; +}; + +int +linux_statfs(struct proc *p, struct linux_statfs_args *args, int *retval) +{ + struct mount *mp; + struct nameidata *ndp; + struct statfs *bsd_statfs; + struct nameidata nd; + struct linux_statfs linux_statfs; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): statfs(%s, *)\n", p->p_pid, args->path); +#endif + ndp = &nd; + ndp->ni_cnd.cn_nameiop = LOOKUP; + ndp->ni_cnd.cn_flags = FOLLOW; + ndp->ni_cnd.cn_proc = curproc; + ndp->ni_cnd.cn_cred = curproc->p_cred->pc_ucred; + ndp->ni_segflg = UIO_USERSPACE; + ndp->ni_dirp = args->path; + if (error = namei(ndp)) + return error; + mp = ndp->ni_vp->v_mount; + bsd_statfs = &mp->mnt_stat; + vrele(ndp->ni_vp); + if (error = VFS_STATFS(mp, bsd_statfs, p)) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs.ftype = bsd_statfs->f_type; + linux_statfs.fbsize = bsd_statfs->f_bsize; + linux_statfs.fblocks = bsd_statfs->f_blocks; + linux_statfs.fbfree = bsd_statfs->f_bfree; + linux_statfs.fbavail = bsd_statfs->f_bavail; + linux_statfs.fffree = bsd_statfs->f_ffree; + linux_statfs.ffiles = bsd_statfs->f_files; + linux_statfs.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs, (caddr_t)args->buf, + sizeof(struct linux_statfs)); +} + +struct linux_fstatfs_args { + int fd; + struct statfs *buf; +}; + +int +linux_fstatfs(struct proc *p, struct linux_fstatfs_args *args, int *retval) +{ + struct file *fp; + struct mount *mp; + struct statfs *bsd_statfs; + struct linux_statfs linux_statfs; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): fstatfs(%d, *)\n", p->p_pid, args->fd); +#endif + if (error = getvnode(p->p_fd, args->fd, &fp)) + return error; + mp = ((struct vnode *)fp->f_data)->v_mount; + bsd_statfs = &mp->mnt_stat; + if (error = VFS_STATFS(mp, bsd_statfs, p)) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs.ftype = bsd_statfs->f_type; + linux_statfs.fbsize = bsd_statfs->f_bsize; + linux_statfs.fblocks = bsd_statfs->f_blocks; + linux_statfs.fbfree = bsd_statfs->f_bfree; + linux_statfs.fbavail = bsd_statfs->f_bavail; + linux_statfs.fffree = bsd_statfs->f_ffree; + linux_statfs.ffiles = bsd_statfs->f_files; + linux_statfs.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs, (caddr_t)args->buf, + sizeof(struct linux_statfs)); +} diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c new file mode 100644 index 0000000000000..015d49a6d9499 --- /dev/null +++ b/sys/i386/linux/linux_sysent.c @@ -0,0 +1,367 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * 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 + * in this position and unchanged. + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $Id: linux_sysent.c,v 1.3 1995/06/08 13:50:52 sos Exp $ + */ + +#include <i386/linux/linux.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysent.h> +#include <sys/imgact.h> +#include <sys/errno.h> +#include <sys/signal.h> + +extern int access(); +extern int acct(); +extern int linux_adjtimex(); +extern int linux_alarm(); +extern int linux_bdflush(); +extern int linux_break(); +extern int linux_brk(); +extern int chdir(); +extern int chmod(); +extern int chown(); +extern int chroot(); +extern int linux_clone(); +extern int close(); +extern int linux_creat(); +extern int linux_create_module(); +extern int linux_delete_module(); +extern int dup(); +extern int dup2(); +extern int execve(); +extern int exit(); +extern int fchdir(); +extern int fchmod(); +extern int fchown(); +extern int linux_fcntl(); +extern int linux_fork(); +extern int linux_fstat(); +extern int linux_fstatfs(); +extern int fsync(); +extern int linux_ftime(); +extern int oftruncate(); +extern int linux_get_kernel_syms(); +extern int getegid(); +extern int geteuid(); +extern int getgid(); +extern int getgroups(); +extern int getitimer(); +extern int linux_getpgid(); +extern int getpgrp(); +extern int getpid(); +extern int getppid(); +extern int getpriority(); +extern int ogetrlimit(); +extern int getrusage(); +extern int gettimeofday(); +extern int getuid(); +extern int linux_gtty(); +extern int linux_idle(); +extern int linux_init_module(); +extern int linux_ioctl(); +extern int linux_ioperm(); +extern int linux_iopl(); +extern int linux_ipc(); +extern int linux_kill(); +extern int link(); +extern int linux_lock(); +extern int linux_lseek(); +extern int ostat(); +extern int mkdir(); +extern int mknod(); +extern int linux_mmap(); +extern int linux_modify_ldt(); +extern int linux_mount(); +extern int mprotect(); +extern int linux_mpx(); +extern int munmap(); +extern int linux_newfstat(); +extern int linux_newlstat(); +extern int linux_newstat(); +extern int linux_newuname(); +extern int linux_nice(); +extern int linux_olduname(); +extern int linux_open(); +extern int linux_pause(); +extern int linux_phys(); +extern int linux_pipe(); +extern int linux_prof(); +extern int profil(); +extern int linux_ptrace(); +extern int linux_quotactl(); +extern int read(); +extern int linux_readdir(); +extern int readlink(); +extern int reboot(); +extern int rename(); +extern int rmdir(); +extern int linux_select(); +extern int setdomainname(); +extern int setgid(); +extern int setgroups(); +extern int osethostname(); +extern int setitimer(); +extern int setpgid(); +extern int setpriority(); +extern int setregid(); +extern int setreuid(); +extern int osetrlimit(); +extern int setsid(); +extern int settimeofday(); +extern int setuid(); +extern int sigreturn(); +extern int linux_setup(); +extern int linux_sigaction(); +extern int linux_siggetmask(); +extern int linux_signal(); +extern int linux_sigpending(); +extern int linux_sigprocmask(); +extern int linux_sigreturn(); +extern int linux_sigsetmask(); +extern int linux_sigsuspend(); +extern int linux_socketcall(); +extern int linux_stat(); +extern int linux_statfs(); +extern int linux_stime(); +extern int linux_stty(); +extern int linux_swapoff(); +extern int swapon(); +extern int symlink(); +extern int sync(); +extern int linux_sysinfo(); +extern int linux_syslog(); +extern int linux_time(); +extern int linux_times(); +extern int otruncate(); +extern int linux_ulimit(); +extern int umask(); +extern int linux_umount(); +extern int linux_uname(); +extern int unlink(); +extern int linux_uselib(); +extern int linux_ustat(); +extern int linux_utime(); +extern int linux_vhangup(); +extern int linux_vm86(); +extern int linux_wait4(); +extern int linux_waitpid(); +extern int write(); + +static struct sysent linux_sysent[] = { + 0, linux_setup, /* 0 */ + 1, exit, /* 1 */ + 0, linux_fork, /* 2 */ + 3, read, /* 3 */ + 3, write, /* 4 */ + 3, linux_open, /* 5 */ + 1, close, /* 6 */ + 3, linux_waitpid, /* 7 */ + 2, linux_creat, /* 8 */ + 2, link, /* 9 */ + 1, unlink, /* 10 */ + 3, execve, /* 11 */ + 1, chdir, /* 12 */ + 1, linux_time, /* 13 */ + 3, mknod, /* 14 */ + 2, chmod, /* 15 */ + 3, chown, /* 16 */ + 1, linux_break, /* 17 */ + 2, linux_stat, /* 18 */ + 3, linux_lseek, /* 19 */ + 0, getpid, /* 20 */ + 5, linux_mount, /* 21 */ + 1, linux_umount, /* 22 */ + 1, setuid, /* 23 */ + 0, getuid, /* 24 */ + 1, linux_stime, /* 25 */ + 4, linux_ptrace, /* 26 */ + 1, linux_alarm, /* 27 */ + 2, linux_fstat, /* 28 */ + 0, linux_pause, /* 29 */ + 2, linux_utime, /* 30 */ + 0, linux_stty, /* 31 */ + 0, linux_gtty, /* 32 */ + 2, access, /* 33 */ + 1, linux_nice, /* 34 */ + 0, linux_ftime, /* 35 */ + 0, sync, /* 36 */ + 2, linux_kill, /* 37 */ + 2, rename, /* 38 */ + 2, mkdir, /* 39 */ + 1, rmdir, /* 40 */ + 1, dup, /* 41 */ + 1, linux_pipe, /* 42 */ + 1, linux_times, /* 43 */ + 0, linux_prof, /* 44 */ + 1, linux_brk, /* 45 */ + 1, setgid, /* 46 */ + 0, getgid, /* 47 */ + 2, linux_signal, /* 48 */ + 0, geteuid, /* 49 */ + 0, getegid, /* 50 */ + 0, acct, /* 51 */ + 0, linux_phys, /* 52 */ + 0, linux_lock, /* 53 */ + 3, linux_ioctl, /* 54 */ + 3, linux_fcntl, /* 55 */ + 0, linux_mpx, /* 56 */ + 2, setpgid, /* 57 */ + 0, linux_ulimit, /* 58 */ + 1, linux_olduname, /* 59 */ + 1, umask, /* 60 */ + 1, chroot, /* 61 */ + 2, linux_ustat, /* 62 */ + 2, dup2, /* 63 */ + 0, getppid, /* 64 */ + 0, getpgrp, /* 65 */ + 0, setsid, /* 66 */ + 3, linux_sigaction, /* 67 */ + 0, linux_siggetmask, /* 68 */ + 1, linux_sigsetmask, /* 69 */ + 2, setreuid, /* 70 */ + 2, setregid, /* 71 */ + 1, linux_sigsuspend, /* 72 */ + 1, linux_sigpending, /* 73 */ + 2, osethostname, /* 74 */ + 2, osetrlimit, /* 75 */ + 2, ogetrlimit, /* 76 */ + 2, getrusage, /* 77 */ + 2, gettimeofday, /* 78 */ + 2, settimeofday, /* 79 */ + 2, getgroups, /* 80 */ + 2, setgroups, /* 81 */ + 1, linux_select, /* 82 */ + 2, symlink, /* 83 */ + 2, ostat, /* 84 */ + 3, readlink, /* 85 */ + 1, linux_uselib, /* 86 */ + 1, swapon, /* 87 */ + 3, reboot, /* 88 */ + 3, linux_readdir, /* 89 */ + 1, linux_mmap, /* 90 */ + 2, munmap, /* 91 */ + 2, otruncate, /* 92 */ + 2, oftruncate, /* 93 */ + 2, fchmod, /* 94 */ + 3, fchown, /* 95 */ + 2, getpriority, /* 96 */ + 3, setpriority, /* 97 */ + 0, profil, /* 98 */ + 2, linux_statfs, /* 99 */ + 2, linux_fstatfs, /* 100 */ + 3, linux_ioperm, /* 101 */ + 2, linux_socketcall, /* 102 */ + 3, linux_syslog, /* 103 */ + 3, setitimer, /* 104 */ + 2, getitimer, /* 105 */ + 2, linux_newstat, /* 106 */ + 2, linux_newlstat, /* 107 */ + 2, linux_newfstat, /* 108 */ + 2, linux_uname, /* 109 */ + 1, linux_iopl, /* 110 */ + 0, linux_vhangup, /* 111 */ + 0, linux_idle, /* 112 */ + 1, linux_vm86, /* 113 */ + 4, linux_wait4, /* 114 */ + 1, linux_swapoff, /* 115 */ + 1, linux_sysinfo, /* 116 */ + 4, linux_ipc, /* 117 */ + 1, fsync, /* 118 */ + 1, linux_sigreturn, /* 119 */ + 0, linux_clone, /* 120 */ + 2, setdomainname, /* 121 */ + 1, linux_newuname, /* 122 */ + 3, linux_modify_ldt, /* 123 */ + 1, linux_adjtimex, /* 124 */ + 3, mprotect, /* 125 */ + 3, linux_sigprocmask, /* 126 */ + 2, linux_create_module, /* 127 */ + 4, linux_init_module, /* 128 */ + 1, linux_delete_module, /* 129 */ + 1, linux_get_kernel_syms, /* 130 */ + 0, linux_quotactl, /* 131 */ + 1, linux_getpgid, /* 132 */ + 1, fchdir, /* 133 */ + 0, linux_bdflush, /* 134 */ +}; + +int bsd_to_linux_errno[ELAST] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 35, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 11,115,114, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100,101,102,103,104,105,106,107,108,109, + 110,111, 40, 36,112,113, 39, 11, 87,122, + 116, 66, 6, 6, 6, 6, 6, 37, 38, 9, + 6, +}; + +int bsd_to_linux_signal[NSIG] = { + 0, LINUX_SIGHUP, LINUX_SIGINT, LINUX_SIGQUIT, + LINUX_SIGILL, LINUX_SIGTRAP, LINUX_SIGABRT, 0, + LINUX_SIGFPE, LINUX_SIGKILL, LINUX_SIGBUS, LINUX_SIGSEGV, + 0, LINUX_SIGPIPE, LINUX_SIGALRM, LINUX_SIGTERM, + LINUX_SIGURG, LINUX_SIGSTOP, LINUX_SIGTSTP, LINUX_SIGCONT, + LINUX_SIGCHLD, LINUX_SIGTTIN, LINUX_SIGTTOU, LINUX_SIGIO, + LINUX_SIGXCPU, LINUX_SIGXFSZ, LINUX_SIGVTALRM, LINUX_SIGPROF, + LINUX_SIGWINCH, 0, LINUX_SIGUSR1, LINUX_SIGUSR2 +}; + +int linux_to_bsd_signal[LINUX_NSIG] = { + 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGEMT, + SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, + SIGBUS, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGIO, + SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGURG, SIGURG, 0 +}; + +int linux_fixup(int **stack_base, struct image_params *iparams) +{ + int *argv, *envp; + + argv = *stack_base; + envp = *stack_base + (iparams->argc + 1); + (*stack_base)--; + **stack_base = (int)envp; + (*stack_base)--; + **stack_base = (int)argv; + (*stack_base)--; + **stack_base = (int)iparams->argc; +} + +struct sysentvec linux_sysvec = { + sizeof (linux_sysent) / sizeof(linux_sysent[0]), + linux_sysent, + 0xff, + NSIG, + bsd_to_linux_signal, + ELAST, + bsd_to_linux_errno, + linux_fixup +}; diff --git a/sys/i386/scsi/93cx6.c b/sys/i386/scsi/93cx6.c new file mode 100644 index 0000000000000..280af0c556aae --- /dev/null +++ b/sys/i386/scsi/93cx6.c @@ -0,0 +1,175 @@ +/* + * Interface for the 93C46/26/06 serial eeprom parts. + * + * Copyright (c) 1995 Daniel M. Eischen + * 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. + * 3. Absolutely no warranty of function or purpose is made by the author + * Daniel M. Eischen. + * 4. Modifications may be freely made to this file if the above conditions + * are met. + * + * $Id$ + */ + +/* + * The instruction set of the 93C46/26/06 chips are as follows: + * + * Start OP + * Function Bit Code Address Data Description + * ------------------------------------------------------------------- + * READ 1 10 A5 - A0 Reads data stored in memory, + * starting at specified address + * EWEN 1 00 11XXXX Write enable must preceed + * all programming modes + * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 + * WRITE 1 01 A5 - A0 D15 - D0 Writes register + * ERAL 1 00 10XXXX Erase all registers + * WRAL 1 00 01XXXX D15 - D0 Writes to all registers + * EWDS 1 00 00XXXX Disables all programming + * instructions + * *Note: A value of X for address is a don't care condition. + * + * The 93C46 has a four wire interface: clock, chip select, data in, and + * data out. In order to perform one of the above functions, you need + * to enable the chip select for a clock period (typically a minimum of + * 1 usec, with the clock high and low a minimum of 750 and 250 nsec + * respectively. While the chip select remains high, you can clock in + * the instructions (above) starting with the start bit, followed by the + * OP code, Address, and Data (if needed). For the READ instruction, the + * requested 16-bit register contents is read from the data out line but + * is preceded by an initial zero (leading 0, followed by 16-bits, MSB + * first). The clock cycling from low to high initiates the next data + * bit to be sent from the chip. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <machine/clock.h> +#include <i386/scsi/93cx6.h> + +/* + * Right now, we only have to read the SEEPROM. But we make it easier to + * add other 93Cx6 functions. + */ +struct seeprom_cmd { + unsigned char len; + unsigned char bits[3]; +} seeprom_read = {3, {1, 1, 0}}; + + +/* + * Wait for the SEERDY to go high; about 800 ns. + */ +#define CLOCK_PULSE(p, rdy) \ + while ((inb(p) & rdy) == 0) { \ + ; /* Do nothing */ \ + } + +/* + * Read the serial EEPROM and returns 1 if successful and 0 if + * not successful. + */ +int read_seeprom (u_long offset, + u_short *buf, + int count, + u_short CS, /* chip select */ + u_short CK, /* clock */ + u_short DO, /* data out */ + u_short DI, /* data in */ + u_short RDY, /* ready */ + u_short MS /* mode select */) +{ + int i = 0, k = 0; + int wait; + unsigned char temp; + + /* + * Read the requested registers of the seeprom. The loop + * will range from 0 to count-1. + */ + for (k = 0; k < count; k = k + 1) { + /* Send chip select for one clock cycle. */ + outb(offset, MS | CK | CS); + CLOCK_PULSE(offset, RDY); + + /* + * Now we're ready to send the read command followed by the + * address of the 16-bit register we want to read. + */ + for (i = 0; i < seeprom_read.len; i = i + 1) { + if (seeprom_read.bits[i]) + temp = MS | CS | DO; + else + temp = MS | CS; + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + temp = temp ^ CK; + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + } + /* Send the 6 bit address (MSB first, LSB last). */ + for (i = 5; i >= 0; i = i - 1) { + /* k is the address, i is the bit */ + if (k & (1 << i)) + temp = MS | CS | DO; + else + temp = MS | CS; + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + temp = temp ^ CK; + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + } + + /* + * Now read the 16 bit register. An initial 0 precedes the + * register contents which begins with bit 15 (MSB) and ends + * with bit 0 (LSB). The initial 0 will be shifted off the + * top of our word as we let the loop run from 0 to 16. + */ + for (i = 0; i <= 16; i = i + 1) { + temp = MS | CS; + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + temp = temp ^ CK; + if (inb(offset) & DI) + buf[k] = (buf[k] << 1) | 0x1; + else + buf[k] = (buf[k] << 1); + outb(offset, temp); + CLOCK_PULSE(offset, RDY); + } + + /* Reset the chip select for the next command cycle. */ + outb(offset, MS); + CLOCK_PULSE(offset, RDY); + outb(offset, MS | CK); + CLOCK_PULSE(offset, RDY); + outb(offset, MS); + CLOCK_PULSE(offset, RDY); + } + +#if 0 + printf ("Serial EEPROM:"); + for (k = 0; k < count; k = k + 1) { + if (((k % 8) == 0) && (k != 0)) + { + printf ("\n "); + } + printf (" 0x%x", buf[k]); + } + printf ("\n"); +#endif + return (1); +} diff --git a/sys/i386/scsi/93cx6.h b/sys/i386/scsi/93cx6.h new file mode 100644 index 0000000000000..dad5e3917148b --- /dev/null +++ b/sys/i386/scsi/93cx6.h @@ -0,0 +1,52 @@ +/* + * Interface to the 93C46 serial EEPROM that is used to store BIOS + * settings for the aic7xxx based adaptec SCSI controllers. It can + * also be used for 93C26 and 93C06 serial EEPROMS. + * + * Copyright (c) 1994, 1995 Justin T. Gibbs. + * 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. + * 3. Absolutely no warranty of function or purpose is made by the author + * Justin T. Gibbs. + * 4. Modifications may be freely made to this file if the above conditions + * are met. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/systm.h> + +/* + * This function will read count 16-bit words from the serial EEPROM and + * return their value in buf. The port address of the aic7xxx serial EEPROM + * control register is passed in as offset. The following parameters are + * also passed in: + * + * CS - Chip select + * CK - Clock + * DO - Data out + * DI - Data in + * RDY - SEEPROM ready + * MS - Memory port mode select + * + * A failed read attempt returns 0, and a successful read returns 1. + */ +int read_seeprom (u_long offset, + u_short *buf, + int count, + u_short CS, + u_short CK, + u_short DO, + u_short DI, + u_short RDY, + u_short MS); diff --git a/sys/pccard/cis.h b/sys/pccard/cis.h new file mode 100644 index 0000000000000..677b197a0a8c9 --- /dev/null +++ b/sys/pccard/cis.h @@ -0,0 +1,250 @@ + +/* + * PCMCIA card structures and defines. + * These defines relate to the user level + * structures and card information, not + * driver/process communication. + *------------------------------------------------------------------------- + * + * Copyright (c) 1995 Andrew McRae. 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + */ + +/* + * Card Information Structure tuples definitions + * The structure of a tuple is basically: + * + * Tuple_code + * Tuple_data_length + * Tuple_data ... + * + * Tuples are contiguous in attribute memory, and + * are terminated with a 0xFF for the tuple code or + * the tuple length. + */ +#define CIS_NULL 0 /* Empty tuple */ +#define CIS_MEM_COMMON 0x01 /* Device descriptor, common memory */ +#define CIS_CHECKSUM 0x10 /* Checksum */ +#define CIS_LONGLINK_A 0x11 /* Link to Attribute memory */ +#define CIS_LONGLINK_C 0x12 /* Link to Common memory */ +#define CIS_LINKTARGET 0x13 /* Linked tuple must start with this. */ +#define CIS_NOLINK 0x14 /* Assume no common memory link tuple. */ +#define CIS_INFO_V1 0x15 /* Card info data, version 1 */ +#define CIS_ALTSTR 0x16 /* Alternate language string tuple. */ +#define CIS_MEM_ATTR 0x17 /* Device descriptor, Attribute memory */ +#define CIS_JEDEC_C 0x18 /* JEDEC descr for common memory */ +#define CIS_JEDEC_A 0x19 /* JEDEC descr for Attribute memory */ +#define CIS_CONF_MAP 0x1A /* Card Configuration map */ +#define CIS_CONFIG 0x1B /* Card Configuration entry */ +#define CIS_DEVICE_OC 0x1C /* Other conditions info - common memory */ +#define CIS_DEVICE_OA 0x1D /* Other conditions info - attribute memory */ +#define CIS_DEVICEGEO 0x1E /* Geometry info for common memory */ +#define CIS_DEVICEGEO_A 0x1F /* Geometry info for attribute memory */ +#define CIS_MANUF_ID 0x20 /* Card manufacturer's ID */ +#define CIS_FUNC_ID 0x21 /* Function of card */ +#define CIS_FUNC_EXT 0x22 /* Functional extension */ +/* + * Data recording format tuples. + */ +#define CIS_SW_INTERLV 0x23 /* Software interleave */ +#define CIS_VERS_2 0x40 /* Card info data, version 2 */ +#define CIS_FORMAT 0x41 /* Memory card format */ +#define CIS_GEOMETRY 0x42 /* Disk sector layout */ +#define CIS_BYTEORDER 0x43 /* Byte order of memory data */ +#define CIS_DATE 0x44 /* Format data/time */ +#define CIS_BATTERY 0x45 /* Battery replacement date */ +#define CIS_ORG 0x46 /* Organisation of data on card */ +#define CIS_END 0xFF /* Termination code */ + +/* + * Internal tuple definitions. + * + * Device descriptor for memory (CIS_MEM_ATTR, CIS_MEM_COMMON) + * + * Byte 1: + * 0xF0 - Device type + * 0x08 - Write protect switch + * 0x07 - Speed index (7 = extended speed) + * Byte 2: Extended speed (bit 7 = another follows) + * Byte 3: (ignored if 0xFF) + * 0xF8 - Addressable units (0's numbered) + * 0x07 - Unit size + * The three byte sequence is repeated until byte 1 == 0xFF + */ + +/* + * CIS_INFO_V1 - Version one card information. + * + * Byte 1: Major version number (should be 4) + * Byte 2: Minor version number (should be 1) + * Byte 3-x: Null terminated Manufacturer name + * Byte x-x: Null terminated product name + * Byte x-x: Null terminated additional info 1 + * Byte x-x: Null terminated additional info 2 + * Byte x: final byte must be 0xFF + */ +#define CIS_MAJOR_VERSION 4 +#define CIS_MINOR_VERSION 1 + +/* + * CIS_CONF_MAP - Provides an address map for the card + * configuration register(s), and a max value + * identifying the last configuration tuple. + * + * Byte 1: + * 0x3C - Register mask size (0's numbered) + * 0x03 - Register address size (0's numbered) + * Byte 2: + * 0x3F - ID of last configuration. + * Byte 3-n: Card register address (size is determined by + * the value in byte 1). + * Byte x-x: Card register masks (size determined by the + * value in byte 1) + */ + +/* + * CIS_CONFIG - Card configuration entry. Multiple tuples may + * exist of this type, each one describing a different + * memory/I-O map that can be used to address this card. + * The first one usually has extra config data about the + * card features. The final configuration tuple number + * is stored in the CIS_CONF_MAP tuple so that the complete + * list can be scanned. + * + * Byte 1: + * 0x3F - Configuration ID number. + * 0x40 - Indicates this is the default configuration + * 0x80 - Interface byte exists + * Byte 2: (exists only if bit 0x80 set in byte 1) + * 0x0F - Interface type value + * 0x10 - Battery voltage detect + * 0x20 - Write protect active + * 0x40 - RdyBsy active bit + * 0x80 - Wait signal required + * Byte 3: (features byte) + * 0x03 - Power sub-tuple(s) exists + * 0x04 - Timing sub-tuple exists + * 0x08 - I/O space sub-tuple exists + * 0x10 - IRQ sub-tuple exists + * 0x60 - Memory space sub-tuple(s) exists + * 0x80 - Miscellaneous sub-tuple exists + */ +#define CIS_FEAT_POWER(x) ((x) & 0x3) +#define CIS_FEAT_TIMING 0x4 +#define CIS_FEAT_I_O 0x8 +#define CIS_FEAT_IRQ 0x10 +#define CIS_FEAT_MEMORY(x) (((x) >> 5) & 0x3) +#define CIS_FEAT_MISC 0x80 +/* + * Depending on whether the "features" byte has the corresponding + * bit set, a number of sub-tuples follow. Some features have + * more than one sub-tuple, depending on the count within the + * features byte (e.g power feature bits allows up to 3 sub-tuples). + * + * Power structure sub-tuple: + * Byte 1: parameter exists - Each bit (starting from 0x01) indicates + * that a parameter block exists - up to 8 parameter blocks + * are therefore allowed). + * Byte 2: + * 0x7F - Parameter data + * 0x80 - More bytes follow (0 = last byte) + * + * Timing sub-tuple + * Byte 1: + * 0x03 - Wait scale + * 0x1C - Ready scale + * 0xE0 - Reserved scale + * Byte 2: extended wait scale if wait scale != 3 + * Byte 3: extended ready scale if ready scale != 7 + * Byte 4: extended reserved scale if reserved scale != 7 + */ +#define CIS_WAIT_SCALE(x) ((x) & 0x3) +#define CIS_READY_SCALE(x) (((x)>>2) & 0x7) +#define CIS_RESERVED_SCALE(x) (((x)>>5) & 0x7) +/* + * I/O mapping sub-tuple: + * Byte 1: + * 0x1F - I/O address lines + * 0x20 - 8 bit I/O + * 0x40 - 16 bit I/O + * 0x80 - I/O range?? + * Byte 2: + * 0x0F - 0's numbered count of I/O block subtuples following. + * 0x30 - Size of I/O address value within subtuple. Values + * can be 1 (8 bits), 2 (16 bits) or 3 (32 bits). + * 0xC0 - Size of I/O port block size value within subtuple. + * I/O block sub-tuples, count from previous block: + * Byte 1-n: I/O start address + * Byte x-x: Size of I/O port block. + */ +#define CIS_IO_ADDR(x) ((x) & 0x1F) +#define CIS_IO_8BIT 0x20 +#define CIS_IO_16BIT 0x40 +#define CIS_IO_RANGE 0x80 +#define CIS_IO_BLKS(x) ((x) & 0xF) +#define CIS_IO_ADSZ(x) (((x)>>4) & 3) +#define CIS_IO_BLKSZ(x) (((x)>>6) & 3) +/* + * IRQ sub-tuple. + * Byte 1: + * 0x0F - Irq number or mask bits + * 0x10 - IRQ mask values exist + * 0x20 - Level triggered interrupts + * 0x40 - Pulse triggered requests + * 0x80 - Interrupt sharing. + * Byte 2-3: Interrupt req mask (if 0x10 of byte 1 set). + */ +#define CIS_IRQ_IRQN(x) ((x) & 0xF) +#define CIS_IRQ_MASK 0x10 +#define CIS_IRQ_LEVEL 0x20 +#define CIS_IRQ_PULSE 0x40 +#define CIS_IRQ_SHARING 0x80 +/* + * Memory block subtuple. Depending on the features bits, the + * following subtuples are used: + * mem features == 1 + * Byte 1-2: upper 16 bits of 24 bit memory length. + * mem features == 2 + * Byte 1-2: upper 16 bits of 24 bit memory length. + * Byte 3-4: upper 16 bits of 24 bit memory address. + * mem_features == 3 + * Byte 1: + * 0x07 - 0's numbered count of memory sub-tuples + * 0x18 - Memory length size (1's numbered) + * 0x60 - Memory address size (1's numbered) + * 0x80 - Host address value exists + * Memory sub-tuples follow: + * Byte 1-n: Memory length value (<< 8) + * Byte n-n: Memory card address value (<< 8) + * Byte n-n: Memory host address value (<< 8) + */ +#define CIS_FEAT_MEM_NONE 0 /* No memory config */ +#define CIS_FEAT_MEM_LEN 1 /* Just length */ +#define CIS_FEAT_MEM_ADDR 2 /* Card address & length */ +#define CIS_FEAT_MEM_WIN 3 /* Multiple windows */ + +#define CIS_MEM_WINS(x) (((x) & 0x7)+1) +#define CIS_MEM_LENSZ(x) (((x) >> 3) & 0x3) +#define CIS_MEM_ADDRSZ(x) (((x) >> 5) & 0x3) +#define CIS_MEM_HOST 0x80 diff --git a/sys/pccard/i82365.h b/sys/pccard/i82365.h new file mode 100644 index 0000000000000..4c4d233b05764 --- /dev/null +++ b/sys/pccard/i82365.h @@ -0,0 +1,207 @@ +/* + * i82365.h - Definitions for Intel 82365 PCIC + * PCMCIA Card Interface Controller + * + * originally by Barry Jaspan; hacked over by Keith Moore + * hacked to unrecognisability by Andrew McRae (andrew@mega.com.au) + * + * Updated 3/3/95 to include Cirrus Logic stuff. + *------------------------------------------------------------------------- + * + * Copyright (c) 1995 Andrew McRae. 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 PCIC_I82365 0 /* Intel chip */ +#define PCIC_IBM 1 /* IBM clone */ +#define PCIC_VLSI 2 /* VLSI chip */ +#define PCIC_PD672X 3 /* Cirrus logic 627x */ +#define PCIC_PD6710 4 +#define PCIC_CL6729 5 +#define PCIC_VG468 6 +/* + * Address of the controllers. Each controller can manage + * two PCMCIA slots. Up to 8 slots are supported in total. + * The PCIC controller is accessed via an index port and a + * data port. The index port has the 8 bit address of the + * register accessed via the data port. How I long for + * real memory mapped I/O! + * The top two bits of the index address are used to + * identify the port number, and the lower 6 bits + * select one of the 64 possible data registers. + */ +#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */ +#define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */ +#define PCIC_INDEX_1 0x3E2 /* index reg, chips 2 and 3 */ +#define PCIC_DATA_1 0x3E3 /* data register, chips 2 and 3 */ +/* + * Register index addresses. + */ +#define PCIC_ID_REV 0x00 /* Identification and Revision */ +#define PCIC_STATUS 0x01 /* Interface Status */ +#define PCIC_POWER 0x02 /* Power and RESETDRV control */ +#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */ +#define PCIC_STAT_CHG 0x04 /* Card Status Change */ +#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */ +#define PCIC_ADDRWINE 0x06 /* Address Window Enable */ +#define PCIC_IOCTL 0x07 /* I/O Control */ +#define PCIC_IO0 0x08 /* I/O Address 0 */ +#define PCIC_IO1 0x0c /* I/O Address 1 */ +#define PCIC_MEMBASE 0x10 /* Base of memory window registers */ +#define PCIC_CDGC 0x16 /* Card Detect and General Control */ +#define PCIC_GLO_CTRL 0x1e /* Global Control Register */ + +#define PCIC_TIME_SETUP0 0x3a +#define PCIC_TIME_CMD0 0x3b +#define PCIC_TIME_RECOV0 0x3c +#define PCIC_TIME_SETUP1 0x3d +#define PCIC_TIME_CMD1 0x3e +#define PCIC_TIME_RECOV1 0x3f + +#define PCIC_SLOT_SIZE 0x40 /* Size of register set for one slot */ + +/* Now register bits, ordered by reg # */ + +/* For Identification and Revision (PCIC_ID_REV) */ +#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */ +#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */ +#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */ +#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */ + +/* For Interface Status register (PCIC_STATUS) */ +#define PCIC_VPPV 0x80 /* Vpp_valid */ +#define PCIC_POW 0x40 /* PC Card power active */ +#define PCIC_READY 0x20 /* Ready/~Busy */ +#define PCIC_MWP 0x10 /* Memory Write Protect */ +#define PCIC_CD 0x0C /* Both card detect bits */ +#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */ + +/* For the Power and RESETDRV register (PCIC_POWER) */ +#define PCIC_OUTENA 0x80 /* Output Enable */ +#define PCIC_DISRST 0x40 /* Disable RESETDRV */ +#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */ +#define PCIC_VCC 0x18 /* Vcc control bits */ +#define PCIC_VCC_5V 0x10 /* 5 volts */ +#define PCIC_VCC_3V 0x18 /* 3 volts */ +#define PCIC_VPP 0x0C /* Vpp control bits */ +#define PCIC_VPP_5V 0x01 /* 5 volts */ +#define PCIC_VPP_12V 0x02 /* 12 volts */ + +/* For the Interrupt and General Control register (PCIC_INT_GEN) */ +#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */ +#define PCIC_IOCARD 0x20 +#define PCIC_MEMCARD 0x00 +#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */ +#define PCIC_INTR_ENA 0x10 /* Interrupt enable */ + +/* For the Card Status Change register (PCIC_STAT_CHG) */ +#define PCIC_CDTCH 0x08 /* Card Detect Change */ +#define PCIC_RDYCH 0x04 /* Ready Change */ +#define PCIC_BATWRN 0x02 /* Battery Warning */ +#define PCIC_BATDED 0x01 /* Battery Dead */ + +/* + * For the Address Window Enable Register (PCIC_ADDRWINE) + * The lower 6 bits contain enable bits for the memory + * windows (LSB = memory window 0). + */ +#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */ +#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */ +#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */ + +/* + * For the I/O Control Register (PCIC_IOCTL) + * The lower nybble is the flags for I/O window 0 + * The upper nybble is the flags for I/O window 1 + */ +#define PCIC_IO_16BIT 0x01 /* I/O to this segment is 16 bit */ +#define PCIC_IO_CS16 0x02 /* I/O cs16 source is the card */ +#define PCIC_IO_0WS 0x04 /* zero wait states added on 8 bit cycles */ +#define PCIC_IO_WS 0x08 /* Wait states added for 16 bit cycles */ + +/* + * The memory window registers contain the start and end + * physical host address that the PCIC maps to the card, + * and an offset calculated from the card memory address. + * All values are shifted down 12 bits, so allocation is + * done in 4Kb blocks. Only 12 bits of each value is + * stored, limiting the range to the ISA address size of + * 24 bits. The upper 4 bits of the most significant byte + * within the values are used for various flags. + * + * The layout is: + * + * base+0 : lower 8 bits of system memory start address + * base+1 : upper 4 bits of system memory start address + flags + * base+2 : lower 8 bits of system memory end address + * base+3 : upper 4 bits of system memory end address + flags + * base+4 : lower 8 bits of offset to card address + * base+5 : upper 4 bits of offset to card address + flags + * + * The following two bytes are reserved for other use. + */ +#define PCIC_MEMSIZE 8 +/* + * Flags for system memory start address upper byte + */ +#define PCIC_ZEROWS 0x40 /* Zero wait states */ +#define PCIC_DATA16 0x80 /* Data width is 16 bits */ + +/* + * Flags for system memory end address upper byte + */ +#define PCIC_MW0 0x40 /* Wait state bit 0 */ +#define PCIC_MW1 0x80 /* Wait state bit 1 */ + +/* + * Flags for card offset upper byte + */ +#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */ +#define PCIC_WP 0x80 /* Write-protect this window */ + +/* For Card Detect and General Control register (PCIC_CDGC) */ +#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */ +#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */ +#define PCIC_GPI_EN 0x04 /* GPI Enable */ +#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */ +#define PCIC_CDRES_EN 0x10 /* card detect resume enable */ +#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */ + +/* For Global Control register (PCIC_GLO_CTRL) */ +#define PCIC_PWR_DOWN 0x01 /* power down */ +#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */ +#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */ +#define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */ +#define PCIC_IRQ1_LEVEL 0x10 + +/* + * Mask of allowable interrupts. + * Ints are 3,4,5,7,9,10,11,12,14,15 + */ +#define PCIC_INT_MASK_ALLOWED 0xDEB8 + +#define PCIC_IO_WIN 2 +#define PCIC_MEM_WIN 5 + +#define PCIC_MAX_SLOTS 8 diff --git a/sys/pccard/skel.c b/sys/pccard/skel.c new file mode 100644 index 0000000000000..dd5b503bee582 --- /dev/null +++ b/sys/pccard/skel.c @@ -0,0 +1,189 @@ +/* + * Loadable kernel module skeleton driver + * 11 July 1995 Andrew McRae + * + *------------------------------------------------------------------------- + * + * Copyright (c) 1995 Andrew McRae. 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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/ioctl.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/mount.h> +#include <sys/sysent.h> +#include <sys/exec.h> +#include <sys/lkm.h> +#include <sys/errno.h> + +#include <pccard/card.h> +#include <pccard/slot.h> + +/* + * This defines the lkm_misc module use by modload + * to define the module name. + */ + MOD_MISC( "skel") + + +static int skelintr(struct pccard_dev *); /* Interrupt handler */ +static void skelunload(struct pccard_dev *); /* Disable driver */ +static void skelsuspend(struct pccard_dev *); /* Suspend driver */ +static int skelinit(struct pccard_dev *, int); /* init device */ + +static struct pccard_drv skel_info = + { + "skel", + skelintr, + skelunload, + skelsuspend, + skelinit, + }; +static int opened; /* Rather minimal device state... */ + +/* + * Module handler that processes loads and unloads. + * Once the module is loaded, the add driver routine is called + * to register the driver. + * If an unload is requested the remove driver routine is + * called to deregister the driver before unloading. + */ +static int +skel_handle( lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + int i; + struct lkm_misc *args = lkmtp->private.lkm_misc; + int err = 0; /* default = success*/ + + switch( cmd) { + case LKM_E_LOAD: + + /* + * Don't load twice! (lkmexists() is exported by kern_lkm.c) + */ + if( lkmexists( lkmtp)) + return( EEXIST); +/* + * Now register the driver + */ + pccard_add_driver(&skel_info); + break; /* Success*/ +/* + * Attempt to deregister the driver. + */ + case LKM_E_UNLOAD: + pccard_remove_driver(&skel_info); + break; /* Success*/ + + default: /* we only understand load/unload*/ + err = EINVAL; + break; + } + + return( err); +} + + +/* + * External entry point; should generally match name of .o file. The + * arguments are always the same for all loaded modules. The "load", + * "unload", and "stat" functions in "DISPATCH" will be called under + * their respective circumstances unless their value is "nosys". If + * called, they are called with the same arguments (cmd is included to + * allow the use of a single function, ver is included for version + * matching between modules and the kernel loader for the modules). + * + * Since we expect to link in the kernel and add external symbols to + * the kernel symbol name space in a future version, generally all + * functions used in the implementation of a particular module should + * be static unless they are expected to be seen in other modules or + * to resolve unresolved symbols alread existing in the kernel (the + * second case is not likely to ever occur). + * + * The entry point should return 0 unless it is refusing load (in which + * case it should return an errno from errno.h). + */ +int +lkm_skel(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd; +int ver; +{ + DISPATCH(lkmtp,cmd,ver,skel_handle,skel_handle,nosys) +} +/* + * Skeleton driver entry points for PCCARD configuration. + */ +/* + * The device entry is being removed. Shut it down, + * and turn off interrupts etc. Not called unless + * the device was successfully installed. + */ +static void +skelunload(struct pccard_dev *dp) +{ + printf("skel%d: unload\n", dp->unit); + opened &= ~(1 << dp->unit); +} +/* + * Called when a power down is wanted. Shuts down the + * device and configures the device as unavailable (but + * still loaded...). A resume is done by calling + * skelinit with first=0. + */ +static void +skelsuspend(struct pccard_dev *dp) +{ + printf("skel%d: suspending\n", dp->unit); +} +/* + * Initialize the device. + * if first is set, then initially check for + * the device's existence before initialising it. + * Once initialised, the device table may be set up. + */ +static int +skelinit(struct pccard_dev *dp, int first) +{ + if (first && ((1 << dp->unit)&opened)) + return(EBUSY); + if (first) + opened |= 1 << dp->unit; + printf("skel%d: init, first = %d\n", dp->unit, first); + printf("iomem = 0x%x, iobase = 0x%x\n", dp->memory, dp->ioaddr); + return(0); +} +/* + * Interrupt handler. + * Returns true if the interrupt is for us. + */ +static int +skelintr(struct pccard_dev *dp) +{ + return(0); +} diff --git a/usr.bin/at/LEGAL b/usr.bin/at/LEGAL new file mode 100644 index 0000000000000..92b1b4983110c --- /dev/null +++ b/usr.bin/at/LEGAL @@ -0,0 +1,29 @@ +-----BEGIN PGP SIGNED MESSAGE----- + +Sorry for the long wait, but there still were a few things to +be ironed out in at, which I've finally done :-) + +The FreeBSD team does have my permission to use at, version 2.9, +under the BSD license. + +You'll find it on sunsite.unc.edu's Incoming, hopefully; the +md5 checksum is + +3ba2ca3c0e87e1a04feae2c6c1376b0d at-2.9.tgz + +Best regards + Thomas +- -- +Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet. +The joy of engineering is to find a straight line on a double +logarithmic diagram. + +-----BEGIN PGP SIGNATURE----- +Version: 2.6.2i + +iQCVAwUBMCjVrPBu+cbJcKCVAQFNiQP/dpWP57s/E8plVGUD3zfgOXDmKUvg8U7a +VwRzJrIMuSgnSJs0wkpvcomc3NLicipfX7hhWLh/xatPM2YbF7O5HZoNdvWvexD2 +1Y67zJ+0HFb1mPnSBOrS5RFiQAe3KqmGec6E14Rih/qNoFQZBVRFXZ4xxuwP+0Rs +e2U+TVTUz6A= +=TvyW +-----END PGP SIGNATURE----- diff --git a/usr.bin/chpass/pw_yp.c b/usr.bin/chpass/pw_yp.c new file mode 100644 index 0000000000000..6fd87f5470794 --- /dev/null +++ b/usr.bin/chpass/pw_yp.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1995 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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. + * + * NIS interface routines for chpass + * + * Written by Bill Paul <wpaul@ctr.columbia.edu> + * Center for Telecommunications Research + * Columbia University, New York City + * + * $Id$ + */ + +#ifdef YP +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <time.h> +#include <sys/types.h> +#include <pwd.h> +#include <errno.h> +#include <err.h> +#include <unistd.h> +#include <db.h> +#include <fcntl.h> +#include <utmp.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <limits.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yppasswd.h> +#include <pw_util.h> +#include "pw_yp.h" + +#define PERM_SECURE (S_IRUSR|S_IWUSR) +HASHINFO openinfo = { + 4096, /* bsize */ + 32, /* ffactor */ + 256, /* nelem */ + 2048 * 1024, /* cachesize */ + NULL, /* hash */ + 0, /* lorder */ +}; + +int _use_yp = 0; + +/* + * Check if the user we're working with is local or in NIS. + */ +int use_yp (user) +char *user; +{ + int yp_enabled = 0, user_not_local = 0, exists = 0; + DB *dbp; + DBT key,data; + char bf[UT_NAMESIZE + 2]; + + if ((dbp = dbopen(_PATH_MP_DB, O_RDONLY, PERM_SECURE, + DB_HASH, &openinfo)) == NULL) + errx(1, "error opening database: %s.", _PATH_MP_DB); + bf[0] = _PW_KEYYPENABLED; + key.data = (u_char *)bf; + key.size = 1; + if (!(dbp->get)(dbp,&key,&data,0)) + yp_enabled = 1; + + bf[0] = _PW_KEYBYNAME; + bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE)); + key.data = (u_char *)bf; + key.size = strlen(user) + 1; + if ((dbp->get)(dbp,&key,&data,0)) + user_not_local = 1; + + (dbp->close)(dbp); + + if (getpwnam(user) != NULL) + exists = 1; + + if (yp_enabled && user_not_local && exists) + return(1); + else + return(0); +} + +/* + * Find the name of the NIS master server for this domain + * and make sure it's running yppasswdd. + */ +static char *get_yp_master(void) +{ + char *domain, *mastername; + int rval; + + /* Get default NIS domain. */ + + if ((rval = yp_get_default_domain(&domain))) { + warnx("can't get local NIS domain name: %s",yperr_string(rval)); + pw_error(NULL, 0, 1); + } + + /* Get master server of passwd map. */ + + if ((rval = yp_master(domain, "passwd.byname", &mastername))) { + warnx("can't get master NIS server: %s", yperr_string(rval)); + pw_error(NULL, 0, 1); + } + + /* Check if yppasswdd is out there. */ + + if ((rval = getrpcport(mastername, YPPASSWDPROG, YPPASSWDPROC_UPDATE, + IPPROTO_UDP)) == 0) { + warnx("yppasswdd not running on NIS master server"); + pw_error(NULL, 0, 1); + } + + /* + * Make sure it's on a reserved port. + * XXX Might break with yppasswdd servers running on Solaris 2.x. + */ + + if (rval >= IPPORT_RESERVED) { + warnx("yppasswdd server not running on reserved port"); + pw_error(NULL, 0, 1); + } + + /* Everything checks out: return the name of the server. */ + + return (mastername); +} +/* + * Ask the user for his NIS password and submit the new information + * to yppasswdd. Note that yppasswdd requires password authentication + * and only allows changes to existing records rather than the addition + * of new records. (To do actual updates we would need something like + * secure RPC and ypupdated, which FreeBSD doesn't have yet.) This means + * that the superuser cannot use chpass(1) to add new users records to + * the NIS password database. + */ +void yp_submit(pw) +struct passwd *pw; +{ + struct yppasswd yppasswd; + CLIENT *clnt; + char *master, *password, *encpass; + int rval, status = 0; + struct timeval tv; + + /* Populate the yppasswd structure that gets handed to yppasswdd. */ + /* + * XXX This is done first to work around what looks like a very + * strange memory corruption bug: the text fields pointed to + * by the members of the 'pw' structure appear to be clobbered + * after get_yp_master() returns (in particular, it happens + * during getrpcport()). I don't know exactly where the problem + * lies: I traced it all the way to gethostbyname(), then gave + * up. + */ + yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd); + yppasswd.newpw.pw_name = strdup(pw->pw_name); + yppasswd.newpw.pw_uid = pw->pw_uid; + yppasswd.newpw.pw_gid = pw->pw_gid; + yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos); + yppasswd.newpw.pw_dir = strdup(pw->pw_dir); + yppasswd.newpw.pw_shell = strdup(pw->pw_shell); + + /* Get NIS master server name */ + + master = get_yp_master(); + + /* Get the user's password for authentication purposes. */ + + printf ("Changing NIS information for %s on %s\n", + yppasswd.newpw.pw_name, master); + encpass = (getpwnam(yppasswd.newpw.pw_name))->pw_passwd; + password = getpass("Please enter password: "); + if (strncmp(crypt(password, encpass), encpass, strlen(encpass))) { + warnx("Password incorrect."); + pw_error(NULL, 0, 1); + } + + yppasswd.oldpass = password; /* XXX */ + + /* Create a handle to yppasswdd. */ + + clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp"); + clnt->cl_auth = authunix_create_default(); + + /* Set a timeout and make the RPC call. */ + + tv.tv_sec = 20; + tv.tv_usec = 0; + rval = clnt_call(clnt, YPPASSWDPROC_UPDATE, xdr_yppasswd, + (char *)&yppasswd, xdr_int, (char *)&status, &tv); + + /* Call failed: signal the error. */ + + if (rval) { + warnx("NIS update failed: %s", clnt_sperrno(rval)); + pw_error(NULL, 0, 1); + } + + /* Success. */ + + auth_destroy(clnt->cl_auth); + clnt_destroy(clnt); + warnx("NIS information changed on host %s", master); + + return; +} +#endif /* YP */ diff --git a/usr.bin/chpass/pw_yp.h b/usr.bin/chpass/pw_yp.h new file mode 100644 index 0000000000000..94c7a74090d2b --- /dev/null +++ b/usr.bin/chpass/pw_yp.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1995 + * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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. + * + * NIS interface routines for chpass + * + * Written by Bill Paul <wpaul@ctr.columbia.edu> + * Center for Telecommunications Research + * Columbia University, New York City + * + * $Id$ + */ + +#ifdef YP +extern int _use_yp; +void yp_submit __P(( struct passwd * )); +int use_yp __P(( char * )); +#endif /* YP */ diff --git a/usr.bin/ee/Makefile b/usr.bin/ee/Makefile new file mode 100644 index 0000000000000..dbe6f4e1613f0 --- /dev/null +++ b/usr.bin/ee/Makefile @@ -0,0 +1,18 @@ +CFLAGS+= -DCAP -DHAS_NCURSES -DHAS_UNISTD -DHAS_STDARG -DHAS_STDLIB \ + -DHAS_CTYPE -DHAS_SYS_IOCTL -DHAS_SYS_WAIT -DSLCT_HDR + +PROG= ee +SRCS= ee.c +LINKS= ${BINDIR}/ee ${BINDIR}/ree +DPADD= ${LIBNCURSES} ${LIBMYTINFO} +LDADD= -lncurses -lmytinfo + +LANGS= en_US.ISO_8859-1 + +afterinstall: + @for i in ${LANGS}; do \ + gencat -new ${DESTDIR}/usr/share/nls/$$i/ee.cat ${.CURDIR}/nls/$$i/ee.msg; \ + chmod 444 ${.CURDIR}/nls/$$i/ee.msg; \ + done + +.include <bsd.prog.mk> diff --git a/usr.bin/ee/README b/usr.bin/ee/README new file mode 100644 index 0000000000000..e15070077a981 --- /dev/null +++ b/usr.bin/ee/README @@ -0,0 +1,116 @@ + THIS MATERIAL IS PROVIDED "AS IS". THERE ARE NO WARRANTIES OF + ANY KIND WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. Neither Hewlett-Packard nor + Hugh Mahon shall be liable for errors contained herein, nor for + incidental or consequential damages in connection with the + furnishing, performance or use of this material. Neither + Hewlett-Packard nor Hugh Mahon assumes any responsibility for + the use or reliability of this software or documentation. This + software and documentation is totally UNSUPPORTED. There is no + support contract available. Hewlett-Packard has done NO + Quality Assurance on ANY of the program or documentation. You + may find the quality of the materials inferior to supported + materials. + + This software may be distributed under the terms of Larry Wall's + Artistic license, a copy of which is included in this distribution. + (see doc/Artistic). + + This notice must be included with this software and any + derivatives. + + Any modifications to this software by anyone but the original author + must be so noted. + + +The editor 'ee' (easy editor) is intended to be a simple, easy to use +terminal-based screen oriented editor that requires no instruction to +use. Its primary use would be for people who are new to computers, or who +use computers only for things like e-mail. + +ee's simplified interface is highlighted by the use of pop-up menus which +make it possible for users to carry out tasks without the need to +remember commands. An information window at the top of the screen shows +the user the operations available with control-keys. + +ee allows users to use full eight-bit characters. If the host system has +the capabilities, ee can use message catalogs, which would allow users to +translate the message catalog into other languages which use eight-bit +characters. See the file ee.i18n.guide for more details. + +ee relies on the virtual memory abilities of the platform it is running on +and does not have its own memory management capabilities. + +I am releasing ee because I hate to see new users and non-computer types +get frustrated by vi, and would like to see more intuitive interfaces for +basic tools (both character-based and graphical) become more pervasive. +Terminal capabilities and communication speeds have evolved considerably +since the time in which vi's interface was created, allowing much more +intuitive interfaces to be used. Since character-based I/O won't be +completely replaced by graphical user interfaces for at least a few more +years, I'd like to do what I can to make using computers with less +glamorous interfaces as easy to use as possible. If terminal interfaces +are still used in ten years, I hope neophytes won't still be stuck with +only vi. + +For a text editor to be easy to use requires a certain set of abilities. In +order for ee to work, a terminal must have the ability to position the cursor +on the screen, and should have arrow keys that send unique sequences +(multiple characters, the first character is an "escape", octal code +'\033'). All of this information needs to be in a database called "terminfo" +(System V implementations) or "termcap" (usually used for BSD systems). In +case the arrow keys do not transmit unique sequences, motion operations are +mapped to control keys as well, but this at least partially defeats the +purpose. The curses package is used to handle the I/O which deals with the +terminal's capabilities. + +While ee is based on curses, I have included here the source code to +new_curse, a subset of curses developed for use with ee. 'curses' often +will have a defect that reduces the usefulness of the editor relying upon +it. This is unused by the FreeBSD version of ee (the existing ncurses +library works just fine) but is included in the doc subdirectory for +reference purposes should anyone wish to port ee to a platform for +which the existing curses libraries are insufficient. + +The files doc/new_curse.[ch] contain a subset of the 'curses' library +used by applications to handle screen output. Unfortunately, curses +varies from system to system, so I developed new_curse to provide +consistent behavior across systems. It works on both SystemV and BSD +systems, and while it can sometimes be slower than other curses packages, +it will get the information on the screen painted correctly more often +than vendor supplied curses. Again, FreeBSD does not have this problem +but you may find it useful on other platforms. + +If you experience problems with data being displayed improperly, check +your terminal configuration, especially if you're using a terminal +emulator, and make sure that you are using the right terminfo entry +before rummaging through code. Terminfo entries often contain +inaccuracies, or incomplete information, or may not totally match the +terminal or emulator the terminal information is being used with. +Complaints that ee isn't working quite right often end up being something +else (like the terminal emulator being used). + +Both ee and new_curse were developed using K&R C (also known as "classic +C"), but it can also be compiled with ANSI C. You should be able to +build ee by simply typing "make". + +ee is the result of several conflicting design goals. While I know that it +solves the problems of some users, I also have no doubt that some will decry +its lack of more features. I will settle for knowing that ee does fulfill +the needs of a minority (but still large number) of users. The goals of ee +are: + + 1. To be so easy to use as to require no instruction. + 2. To be easy to compile and, if necessary, port to new platforms + by people with relatively little knowledge of C and UNIX. + 3. To have a minimum number of files to be dealt with, for compile + and installation. + 4. To have enough functionality to be useful to a large number of + people. + +Hugh Mahon |___| +h_mahon@fc.hp.com | | + |\ /| + | \/ | + diff --git a/usr.bin/ee/doc/Artistic b/usr.bin/ee/doc/Artistic new file mode 100644 index 0000000000000..fbf798977589c --- /dev/null +++ b/usr.bin/ee/doc/Artistic @@ -0,0 +1,117 @@ + + + + + The "Artistic License" + + Preamble + +The intent of this document is to state the conditions under which a +Package may be copied, such that the Copyright Holder maintains some +semblance of artistic control over the development of the package, +while giving the users of the package the right to use and distribute +the Package in a more-or-less customary fashion, plus the right to make +reasonable modifications. + +Definitions: + + "Package" refers to the collection of files distributed by the + Copyright Holder, and derivatives of that collection of files + created through textual modification. + + "Standard Version" refers to such a Package if it has not been + modified, or has been modified in accordance with the wishes + of the Copyright Holder. + + "Copyright Holder" is whoever is named in the copyright or + copyrights for the package. + + "You" is you, if you're thinking about copying or distributing + this Package. + + "Reasonable copying fee" is whatever you can justify on the + basis of media cost, duplication charges, time of people involved, + and so on. (You will not be required to justify it to the + Copyright Holder, but only to the computing community at large + as a market that must bear the fee.) + + "Freely Available" means that no fee is charged for the item + itself, though there may be fees involved in handling the item. + It also means that recipients of the item may redistribute it + under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the +Standard Version of this Package without restriction, provided that you +duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications +derived from the Public Domain or from the Copyright Holder. A Package +modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided +that you insert a prominent notice in each changed file stating how and +when you changed that file, and provided that you do at least ONE of the +following: + + a) place your modifications in the Public Domain or otherwise make them + Freely Available, such as by posting said modifications to Usenet or + an equivalent medium, or placing the modifications on a major archive + site such as uunet.uu.net, or by allowing the Copyright Holder to include + your modifications in the Standard Version of the Package. + + b) use the modified Package only within your corporation or organization. + + c) rename any non-standard executables so the names do not conflict + with standard executables, which must also be provided, and provide + a separate manual page for each non-standard executable that clearly + documents how it differs from the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or +executable form, provided that you do at least ONE of the following: + + a) distribute a Standard Version of the executables and library files, + together with instructions (in the manual page or equivalent) on where + to get the Standard Version. + + b) accompany the distribution with the machine-readable source of + the Package with your modifications. + + c) accompany any non-standard executables with their corresponding + Standard Version executables, giving the non-standard executables + non-standard names, and clearly documenting the differences in manual + pages (or equivalent), together with instructions on where to get + the Standard Version. + + d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this +Package. You may charge any fee you choose for support of this Package. +You may not charge a fee for this Package itself. However, +you may distribute this Package in aggregate with other (possibly +commercial) programs as part of a larger (possibly commercial) software +distribution provided that you do not advertise this Package as a +product of your own. + +6. The scripts and library files supplied as input to or produced as +output from the programs of this Package do not automatically fall +under the copyright of this Package, but belong to whomever generated +them, and may be sold commercially, and may be aggregated with this +Package. + +7. C subroutines supplied by you and linked into this Package in order +to emulate subroutines and variables of the language defined by this +Package shall not be considered part of this Package, but are the +equivalent of input as in Paragraph 6, provided these subroutines do +not change the language in any way that would cause it to fail the +regression tests for the language. + +8. The name of the Copyright Holder may not be used to endorse or promote +products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + The End diff --git a/usr.bin/ee/doc/ee.i18n.guide b/usr.bin/ee/doc/ee.i18n.guide new file mode 100644 index 0000000000000..0850c2e7400d0 --- /dev/null +++ b/usr.bin/ee/doc/ee.i18n.guide @@ -0,0 +1,141 @@ +Easy Editor ("ee") provides the ability to translate the messages displayed to +the user and the commands entered. This is done via message catalogs, +following X/Open standards. ee only supports eight bit characters. + +(The name ee.i18n.guide is for "ee internationalization guide". The i18n +abbreviation is used because there are 18 characters between the first +letter ("i") and last ("n") of "internationalization".) + +All of the messages, warnings, information, and commands, are contained in the +message catalog. Each numbered entry represents an individual string used by +ee. Some strings contain formatting information for formatted print +statements, which are of the form "%s", or "%d", these must be preserved in +the translation, or the correct information will not be displayed. For those +strings containing multiple formatting codes, the order of each item must be +preserved as well. + +Message content +1 title for modes, or settings menu +2 - 8 entries for modes menu, each line should be the same length + (padded with spaces) +9 - 34 other menu titles and entries +35 - 56 help screen +57 - 61 actions assigned to control keys +62 - 66 commands information +67 message displayed when info window turned off +68 indication that no file name was entered when invoking ee +69 prompt for decimal value of character to be entered +70 message displaying the print command being invoked +71 prompt for command +72 prompt for name of file to be written +73 prompt for name of file to be read +74 string used to display the decimal value of the character + the cursor is on +75 string displaying an unrecognized command +76 string indicating that the command entered is not a unique + substring of a valid command +77 string indicating the current line number +78 string for displaying the length of the line +79 string for displaying the name of the file +80 - 83 strings showing how to invoke ee, and its options +84 message indicating that the file entered is a directory, not a + text file +85 message informing that the entered file does not yet exist +86 message informing that the file can't be opened (because of + permission problems) +87 message after file has been read with the file name and number + of lines read +88 message indicating that the file has been read +89 message indicating that the file is being read +90 message indicating that permissions only allow the file to be + read, not written +91 message after file has been read with the file name and number + of lines read +92 prompt for name of file to be saved (used when no name was + entered for a file to edit) +93 message indicating that the file was not written, since no + name was entered at the prompt +94 prompt asking user if changes should not be saved ("yes_char" + will be expected for affirmative response) +95 "yes" character, single character expected to confirm action + (can be upper or lower case, will be converted to upper-case + during test) +96 prompt +97 error message +98 message indicating that the named file is being written +99 message indicating the name of the file written, the number of + lines, and the number of characters (order of items must be + maintained) +100 search in progress message +101 message that the string was not found +102 prompt for search +103 message that string could not be executed +104 self-explanatory +105 message for menus, indicating that the Escape character will + allow the user to exit the menu +106 error message indicating the menu won't fit on the screen +107 self-explanatory +108 prompt for shell command +109 message displayed while formatting a paragraph +110 string which places message for spell checking at top of + buffer (the portions 'list of unrecognized words' and + '-=-=-=-=-=-' may be replaced, but the rest must remain the + same) +111 message informing that spell checking is in progress +112 prompt for right margin +113 error informing user that operation is not permitted in ree +114 string indicating mode is turned 'on' in modes menu +115 string indicating mode is turned 'off' in modes menu +116 - 131 strings used for commands (some also used for initialization) +132 - 144 strings used for initialization +145 entry for settings menu for emacs key bindings settings +146 - 153 help screen entries for emacs key bindings info +154 - 158 info window entries for emacs key bindings info +159 string for turning on emacs key bindings in the init file +160 string for turning off emacs key bindings in the init file + +Care should be taken when translating commands and initialization keywords +because the algorithm used for detecting uniqueness of entered commands +will not be able to distinguish words that are not unique before the end +of the shorter word, for example, it would not be able to distinguish the +command 'abcd' from 'abcde'. + +After translating the messages, use the 'gencat' command to create the compiled +catalog used when running the software. The standard syntax would be: + + gencat ee.cat ee.msg + +Where ee.msg is the file containing the translations, and ee.cat is the +compiled catalog. If the file ee.cat does not exist, it will be created. +Check the documentation for your system for proper syntax. + +Message catalog placement varies from system to system. A common location +for message catalogs is in /usr/lib/nls. In this directory are +directories with the names of other languages. The default language is +'C'. There is also an environment variable, named NLSPATH used to +determine where message catalogs can be found. This variable is similar +to the PATH variable used for commands, but with some differences. The +NLSPATH variable must have the ability to handle different names for +languages and the catalog files, so it has field descriptors for these. A +typical setting for NLSPATH could be: + + NLSPATH=/usr/lib/nls/%L/%N.cat:/usr/local/lib/nls/%L/%N.cat + +Where "%L" is the field descriptor for the language (obtained from the +LANG environment variable) and "%N" is the name of the file (with the +".cat" appended by the path variable, it is not passed from the requesting +program). The colon (:) is used to separate paths, so in the above +example there are two paths possible for message catalogs. You may wish +to maintain catalogs for applications that are not supported by your +system vendor in a location unique for you, and this is facilitated by the +NLSPATH variable. Remember to set and export both the LANG and NLSPATH +variables for each user that expects to use localization either in a +system-wide profile or in each user's profile. See your system +documentation for more information. + +The message catalog supplied with ee also uses the '$quote' directive to +specify a quote around strings to ensure proper padding. This directive +may not be supported on all systems, and lead to quotes being included in +the string used in ee, which will cause incorrect behavior. If the +'$quote' directive is not supported by your system's gencat command, edit +the msg file to remove the leading and trailing quotation marks. diff --git a/usr.bin/ee/doc/new_curse.c b/usr.bin/ee/doc/new_curse.c new file mode 100644 index 0000000000000..0e6cd54831cfe --- /dev/null +++ b/usr.bin/ee/doc/new_curse.c @@ -0,0 +1,3574 @@ +/* + | new_curse.c + | + | A subset of curses developed for use with ae. + | + | written by Hugh Mahon + | + | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE + | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS + | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE + | IMPLIED WARRANTIES OF MERCHANTABILITY AND + | FITNESS FOR A PARTICULAR PURPOSE. Neither + | Hewlett-Packard nor Hugh Mahon shall be liable + | for errors contained herein, nor for + | incidental or consequential damages in + | connection with the furnishing, performance or + | use of this material. Neither Hewlett-Packard + | nor Hugh Mahon assumes any responsibility for + | the use or reliability of this software or + | documentation. This software and + | documentation is totally UNSUPPORTED. There + | is no support contract available. Hewlett- + | Packard has done NO Quality Assurance on ANY + | of the program or documentation. You may find + | the quality of the materials inferior to + | supported materials. + | + | This software is not a product of Hewlett-Packard, Co., or any + | other company. No support is implied or offered with this software. + | You've got the source, and you're on your own. + | + | This software may be distributed under the terms of Larry Wall's + | Artistic license, a copy of which is included in this distribution. + | + | This notice must be included with this software and any derivatives. + | + | Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon + | All are rights reserved. + | + | $Header: /home/hugh/sources/old_ae/RCS/new_curse.c,v 1.37 1995/08/28 23:49:26 hugh Exp $ + | + */ + +char *copyright_message[] = { "Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995 Hugh Mahon", + "All rights are reserved."}; + +char * new_curse_name= "@(#) new_curse.c $Revision: 1.37 $"; + +#include "new_curse.h" +#include <signal.h> +#include <fcntl.h> + +#ifdef SYS5 +#include <string.h> +#else +#include <strings.h> +#endif + +#ifdef BSD_SELECT +#include <sys/types.h> +#include <sys/time.h> + +#ifdef SLCT_HDR +#include <sys/select.h> /* on AIX */ +#endif /* SLCT_HDR */ + +#endif /* BSD_SELECT */ + +#ifdef HAS_STDLIB +#include <stdlib.h> +#endif + +#if defined(__STDC__) +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifdef HAS_UNISTD +#include <unistd.h> +#endif + +#ifdef HAS_SYS_IOCTL +#include <sys/ioctl.h> +#endif + + +WINDOW *curscr; +static WINDOW *virtual_scr; +WINDOW *stdscr; +WINDOW *last_window_refreshed; + +#ifdef TIOCGWINSZ + struct winsize ws; +#endif + +#define min(a, b) (a < b ? a : b) + +#ifndef CAP +#define String_Out(table, stack, place) Info_Out(table, stack, place) +#else +#define String_Out(table, stack, place) Cap_Out(table, stack, place) +#endif + +#define bw__ 0 /* booleans */ +#define am__ 1 +#define xb__ 2 +#define xs__ 3 /* hp glitch (standout not erased by overwrite) */ +#define xn__ 4 +#define eo__ 5 +#define gn__ 6 /* generic type terminal */ +#define hc__ 7 /* hardcopy terminal */ +#define km__ 8 +#define hs__ 9 +#define in__ 10 +#define da__ 11 +#define db__ 12 +#define mi__ 13 /* safe to move during insert mode */ +#define ms__ 14 /* safe to move during standout mode */ +#define os__ 15 +#define es__ 16 +#define xt__ 17 +#define hz__ 18 /* hazeltine glitch */ +#define ul__ 19 +#define xo__ 20 +#define chts__ 21 +#define nxon__ 22 +#define nrrmc__ 23 +#define npc__ 24 +#define mc5i__ 25 + +#define co__ 0 /* number of columns */ /* numbers */ +#define it__ 1 /* spaces per tab */ +#define li__ 2 /* number of lines */ +#define lm__ 3 +#define sg__ 4 /* magic cookie glitch */ +#define pb__ 5 +#define vt__ 6 +#define ws__ 7 + +#define cols__ 0 +#define lines__ 2 +#define xmc__ 4 +#define vt__ 6 +#define wsl__ 7 +#define nlab__ 8 +#define lh__ 9 +#define lw__ 10 + +#define bt__ 0 /* back tab */ /* strings */ +#define bl__ 1 /* bell */ +#define cr__ 2 /* carriage return */ +#define cs__ 3 /* change scroll region */ +#define ct__ 4 /* clear all tab stops */ +#define cl__ 5 /* clear screen and home cursor */ +#define ce__ 6 /* clear to end of line */ +#define cd__ 7 /* clear to end of display */ +#define ch__ 8 /* set cursor column */ +#define CC__ 9 /* term, settable cmd char in */ +#define cm__ 10 /* screen rel cursor motion, row, column */ +#define do__ 11 /* down one line */ +#define ho__ 12 /* home cursor */ +#define vi__ 13 /* make cursor invisible */ +#define le__ 14 /* move cursor left one space */ +#define CM__ 15 /* memory rel cursor addressing */ +#define ve__ 16 /* make cursor appear normal */ +#define nd__ 17 /* non-destructive space (cursor right) */ +#define ll__ 18 /* last line, first col */ +#define up__ 19 /* cursor up */ +#define vs__ 20 +#define dc__ 21 /* delete character */ +#define dl__ 22 /* delete line */ +#define ds__ 23 +#define hd__ 24 +#define as__ 25 +#define mb__ 26 +#define md__ 27 /* turn on bold */ +#define ti__ 28 +#define dm__ 29 /* turn on delete mode */ +#define mh__ 30 /* half bright mode */ +#define im__ 31 /* insert mode */ +#define mk__ 32 +#define mp__ 33 +#define mr__ 34 +#define so__ 35 /* enter standout mode */ +#define us__ 36 +#define ec__ 37 +#define ae__ 38 +#define me__ 39 +#define te__ 40 +#define ed__ 41 +#define ei__ 42 /* exit insert mode */ +#define se__ 43 /* exit standout mode */ +#define ue__ 44 +#define vb__ 45 +#define ff__ 46 +#define fs__ 47 +#define i1__ 48 +#define i2__ 49 +#define i3__ 50 +#define if__ 51 +#define ic__ 52 +#define al__ 53 +#define ip__ 54 +#define kb__ 55 /* backspace key */ +#define ka__ 56 +#define kC__ 57 +#define kt__ 58 +#define kD__ 59 +#define kL__ 60 +#define kd__ 61 +#define kM__ 62 +#define kE__ 63 +#define kS__ 64 +#define k0__ 65 +#define k1__ 66 +#define kf10__ 67 +#define k2__ 68 +#define k3__ 69 +#define k4__ 70 +#define k5__ 71 +#define k6__ 72 +#define k7__ 73 +#define k8__ 74 +#define k9__ 75 +#define kh__ 76 +#define kI__ 77 +#define kA__ 78 +#define kl__ 79 +#define kH__ 80 +#define kN__ 81 +#define kP__ 82 +#define kr__ 83 +#define kF__ 84 +#define kR__ 85 +#define kT__ 86 +#define ku__ 87 /* key up */ +#define ke__ 88 +#define ks__ 89 +#define l0__ 90 +#define l1__ 91 +#define la__ 92 +#define l2__ 93 +#define l3__ 94 +#define l4__ 95 +#define l5__ 96 +#define l6__ 97 +#define l7__ 98 +#define l8__ 99 +#define l9__ 100 +#define mo__ 101 +#define mm__ 102 +#define nw__ 103 +#define pc__ 104 +#define DC__ 105 +#define DL__ 106 +#define DO__ 107 +#define IC__ 118 +#define SF__ 109 +#define AL__ 110 +#define LE__ 111 +#define RI__ 112 +#define SR__ 113 +#define UP__ 114 +#define pk__ 115 +#define pl__ 116 +#define px__ 117 +#define ps__ 118 +#define pf__ 119 +#define po__ 120 +#define rp__ 121 +#define r1__ 122 +#define r2__ 123 +#define r3__ 124 +#define rf__ 125 +#define rc__ 126 +#define cv__ 127 +#define sc__ 128 +#define sf__ 129 +#define sr__ 130 +#define sa__ 131 /* sgr */ +#define st__ 132 +#define wi__ 133 +#define ta__ 134 +#define ts__ 135 +#define uc__ 136 +#define hu__ 137 +#define iP__ 138 +#define K1__ 139 +#define K2__ 140 +#define K3__ 141 +#define K4__ 142 +#define K5__ 143 +#define pO__ 144 +#define ml__ 145 +#define mu__ 146 +#define rmp__ 145 +#define acsc__ 146 +#define pln__ 147 +#define kcbt__ 148 +#define smxon__ 149 +#define rmxon__ 150 +#define smam__ 151 +#define rmam__ 152 +#define xonc__ 153 +#define xoffc__ 154 +#define enacs__ 155 +#define smln__ 156 +#define rmln__ 157 +#define kbeg__ 158 +#define kcan__ 159 +#define kclo__ 160 +#define kcmd__ 161 +#define kcpy__ 162 +#define kcrt__ 163 +#define kend__ 164 +#define kent__ 165 +#define kext__ 166 +#define kfnd__ 167 +#define khlp__ 168 +#define kmrk__ 169 +#define kmsg__ 170 +#define kmov__ 171 +#define knxt__ 172 +#define kopn__ 173 +#define kopt__ 174 +#define kprv__ 175 +#define kprt__ 176 +#define krdo__ 177 +#define kref__ 178 +#define krfr__ 179 +#define krpl__ 180 +#define krst__ 181 +#define kres__ 182 +#define ksav__ 183 +#define kspd__ 184 +#define kund__ 185 +#define kBEG__ 186 +#define kCAN__ 187 +#define kCMD__ 188 +#define kCPY__ 189 +#define kCRT__ 190 +#define kDC__ 191 +#define kDL__ 192 +#define kslt__ 193 +#define kEND__ 194 +#define kEOL__ 195 +#define kEXT__ 196 +#define kFND__ 197 +#define kHLP__ 198 +#define kHOM__ 199 +#define kIC__ 200 +#define kLFT__ 201 +#define kMSG__ 202 +#define kMOV__ 203 +#define kNXT__ 204 +#define kOPT__ 205 +#define kPRV__ 206 +#define kPRT__ 207 +#define kRDO__ 208 +#define kRPL__ 209 +#define kRIT__ 210 +#define kRES__ 211 +#define kSAV__ 212 +#define kSPD__ 213 +#define kUND__ 214 +#define rfi__ 215 +#define kf11__ 216 +#define kf12__ 217 +#define kf13__ 218 +#define kf14__ 219 +#define kf15__ 220 +#define kf16__ 221 +#define kf17__ 222 +#define kf18__ 223 +#define kf19__ 224 +#define kf20__ 225 +#define kf21__ 226 +#define kf22__ 227 +#define kf23__ 228 +#define kf24__ 229 +#define kf25__ 230 +#define kf26__ 231 +#define kf27__ 232 +#define kf28__ 233 +#define kf29__ 234 +#define kf30__ 235 +#define kf31__ 236 +#define kf32__ 237 +#define kf33__ 238 +#define kf34__ 239 +#define kf35__ 240 +#define kf36__ 241 +#define kf37__ 242 +#define kf38__ 243 +#define kf39__ 244 +#define kf40__ 245 +#define kf41__ 246 +#define kf42__ 247 +#define kf43__ 248 +#define kf44__ 249 +#define kf45__ 250 +#define kf46__ 251 +#define kf47__ 252 +#define kf48__ 253 +#define kf49__ 254 +#define kf50__ 255 +#define kf51__ 256 +#define kf52__ 257 +#define kf53__ 258 +#define kf54__ 259 +#define kf55__ 260 +#define kf56__ 261 +#define kf57__ 262 +#define kf58__ 263 +#define kf59__ 264 +#define kf60__ 265 +#define kf61__ 266 +#define kf62__ 267 +#define kf63__ 268 +#define el1__ 269 +#define mgc__ 270 +#define smgl__ 271 +#define smgr__ 272 + +#ifdef CAP +char *Boolean_names[] = { +"bw", "am", "xb", "xs", "xn", "eo", "gn", "hc", "km", "hs", "in", "da", "db", +"mi", "ms", "os", "es", "xt", "hz", "ul", "xo", "HC", "nx", "NR", "NP", "5i" +}; + +char *Number_names[] = { +"co#", "it#", "li#", "lm#", "sg#", "pb#", "vt#", "ws#", "Nl#", "lh#", "lw#" +}; + +char *String_names[] = { +"bt=", "bl=", "cr=", "cs=", "ct=", "cl=", "ce=", "cd=", "ch=", "CC=", "cm=", +"do=", "ho=", "vi=", "le=", "CM=", "ve=", "nd=", "ll=", "up=", "vs=", "dc=", +"dl=", "ds=", "hd=", "as=", "mb=", "md=", "ti=", "dm=", "mh=", "im=", "mk=", +"mp=", "mr=", "so=", "us=", "ec=", "ae=", "me=", "te=", "ed=", "ei=", "se=", +"ue=", "vb=", "ff=", "fs=", "i1=", "i2=", "i3=", "if=", "ic=", "al=", "ip=", +"kb=", "ka=", "kC=", "kt=", "kD=", "kL=", "kd=", "kM=", "kE=", "kS=", "k0=", +"k1=", "k;=", "k2=", "k3=", "k4=", "k5=", "k6=", "k7=", "k8=", "k9=", "kh=", +"kI=", "kA=", "kl=", "kH=", "kN=", "kP=", "kr=", "kF=", "kR=", "kT=", "ku=", +"ke=", "ks=", "l0=", "l1=", "la=", "l2=", "l3=", "l4=", "l5=", "l6=", "l7=", +"l8=", "l9=", "mo=", "mm=", "nw=", "pc=", "DC=", "DL=", "DO=", "IC=", "SF=", +"AL=", "LE=", "RI=", "SR=", "UP=", "pk=", "pl=", "px=", "ps=", "pf=", "po=", +"rp=", "r1=", "r2=", "r3=", "rf=", "rc=", "cv=", "sc=", "sf=", "sr=", "sa=", +"st=", "wi=", "ta=", "ts=", "uc=", "hu=", "iP=", "K1=", "K3=", "K2=", "K4=", +"K5=", "pO=", "rP=", "ac=", "pn=", "kB=", "SX=", "RX=", "SA=", "RA=", "XN=", +"XF=", "eA=", "LO=", "LF=", "@1=", "@2=", "@3=", "@4=", "@5=", "@6=", "@7=", +"@8=", "@9=", "@0=", "%1=", "%2=", "%3=", "%4=", "%5=", "%6=", "%7=", "%8=", +"%9=", "%0=", "&1=", "&2=", "&3=", "&4=", "&5=", "&6=", "&7=", "&8=", "&9=", +"&0=", "*1=", "*2=", "*3=", "*4=", "*5=", "*6=", "*7=", "*8=", "*9=", "*0=", +"#1=", "#2=", "#3=", "#4=", "%a=", "%b=", "%c=", "%d=", "%e=", "%f=", "%g=", +"%h=", "%i=", "%j=", "!1=", "!2=", "!3=", "RF=", "F1=", "F2=", "F3=", "F4=", +"F5=", "F6=", "F7=", "F8=", "F9=", "FA=", "FB=", "FC=", "FD=", "FE=", "FF=", +"FG=", "FH=", "FI=", "FJ=", "FK=", "FL=", "FM=", "FN=", "FO=", "FP=", "FQ=", +"FR=", "FS=", "FT=", "FU=", "FV=", "FW=", "FX=", "FY=", "FZ=", "Fa=", "Fb=", +"Fc=", "Fd=", "Fe=", "Ff=", "Fg=", "Fh=", "Fi=", "Fj=", "Fk=", "Fl=", "Fm=", +"Fn=", "Fo=", "Fp=", "Fq=", "Fr=", "cb=", "MC=", "ML=", "MR=" +}; +#endif + +char *new_curse = "October 1987"; + +char in_buff[100]; /* buffer for ungetch */ +int bufp; /* next free position in in_buff */ + +char *TERMINAL_TYPE = NULL; /* terminal type to be gotten from environment */ +int CFOUND = FALSE; +int Data_Line_len = 0; +int Max_Key_len; /* max length of a sequence sent by a key */ +char *Data_Line = NULL; +char *TERM_PATH = NULL; +char *TERM_data_ptr = NULL; +char *Term_File_name = NULL; /* name of file containing terminal description */ +FILE *TFP; /* file pointer to file with terminal des. */ +int Fildes; /* file descriptor for terminfo file */ +int STAND = FALSE; /* is standout mode activated? */ +int TERM_INFO = FALSE; /* is terminfo being used (TRUE), or termcap (FALSE) */ +int Time_Out; /* set when time elapsed while trying to read function key */ +int Curr_x; /* current x position on screen */ +int Curr_y; /* current y position on the screen */ +int LINES; +int COLS; +int Move_It; /* flag to move cursor if magic cookie glitch */ +int initialized = FALSE; /* tells whether new_curse is initialized */ +float speed; +float chars_per_millisecond; +int Repaint_screen; /* if an operation to change screen impossible, repaint screen */ +int Intr; /* storeage for interrupt character */ +int Parity; /* 0 = no parity, 1 = odd parity, 2 = even parity */ +int Noblock; /* for BSD systems */ +int Num_bits; /* number of bits per character */ +int Flip_Bytes; /* some systems have byte order reversed */ +int interrupt_flag = FALSE; /* set true if SIGWINCH received */ + +#ifndef CAP +char *Strings; +#endif + +struct KEYS { + int length; /* length of string sent by key */ + char *string; /* string sent by key */ + int value; /* CURSES value of key (9-bit) */ + }; + +struct KEY_STACK { + struct KEYS *element; + struct KEY_STACK *next; + }; + +struct KEY_STACK *KEY_TOS = NULL; +struct KEY_STACK *KEY_POINT; + +struct Parameters { + int value; + struct Parameters *next; + }; + +int Key_vals[] = { + 0407, 0526, 0515, 0525, 0512, 0510, 0402, 0514, 0517, 0516, 0410, 0411, + 0422, 0412, 0413, 0414, 0415, 0416, 0417, 0420, 0421, 0406, 0513, 0511, + 0404, 0533, 0522, 0523, 0405, 0520, 0521, 0524, 0403, + 0534, 0535, 0536, 0537, 0540, 0541, 0542, 0543, 0544, 0545, 0546, 0547, + 0550, 0527, 0551, 0552, 0553, 0554, 0555, 0556, 0557, 0560, 0561, 0562, + 0532, 0563, 0564, 0565, 0566, 0567, 0570, 0571, 0627, 0630, 0572, 0573, + 0574, 0575, 0576, 0577, 0600, 0601, 0602, 0603, 0604, 0605, 0606, 0607, + 0610, 0611, 0612, 0613, 0614, 0615, 0616, 0617, 0620, 0621, 0622, 0623, + 0624, 0625, 0626, 0423, 0424, 0425, 0426, 0427, 0430, 0431, + 0432, 0433, 0434, 0435, 0436, 0437, 0440, 0441, 0442, 0443, 0444, 0445, + 0446, 0447, 0450, 0451, 0452, 0453, 0454, 0455, 0456, 0457, 0460, 0461, + 0462, 0463, 0464, 0465, 0466, 0467, 0470, 0471, 0472, 0473, 0474, 0475, + 0476, 0477, 0500, 0501, 0502, 0503, 0504, 0505, 0506, 0507 +}; + +int attributes_set[9]; + +#ifdef SYS5 +struct termio Terminal; +struct termio Saved_tty; +#else +struct sgttyb Terminal; +struct sgttyb Saved_tty; +#endif + +char *tc_; + +int Booleans[128]; +int Numbers[128]; +char *String_table[1024]; + +int *virtual_lines; + +static char nc_scrolling_ability = FALSE; + +#ifdef CAP + +#if __STDC__ || defined(__cplusplus) +#define P_(s) s +#else +#define P_(s) () +#endif /* __STDC__ */ + +int tc_Get_int P_((int)); +void CAP_PARSE P_((void)); +void Find_term P_((void)); + +#undef P_ + +#endif /* CAP */ + + +#ifndef __STDC__ +#ifndef HAS_STDLIB +extern char *fgets(); +extern char *malloc(); +extern char *getenv(); +FILE *fopen(); /* declaration for open function */ +#endif /* HAS_STDLIB */ +#endif /* __STDC__ */ + +#ifdef SIGWINCH + +/* + | Copy the contents of one window to another. + */ + +void +copy_window(origin, destination) +WINDOW *origin, *destination; +{ + int row, column; + struct _line *orig, *dest; + + orig = origin->first_line; + dest = destination->first_line; + + for (row = 0; + row < (min(origin->Num_lines, destination->Num_lines)); + row++) + { + for (column = 0; + column < (min(origin->Num_cols, destination->Num_cols)); + column++) + { + dest->row[column] = orig->row[column]; + dest->attributes[column] = orig->attributes[column]; + } + dest->changed = orig->changed; + dest->scroll = orig->scroll; + dest->last_char = min(orig->last_char, destination->Num_cols); + orig = orig->next_screen; + dest = dest->next_screen; + } + destination->LX = min((destination->Num_cols - 1), origin->LX); + destination->LY = min((destination->Num_lines - 1), origin->LY); + destination->Attrib = origin->Attrib; + destination->scroll_up = origin->scroll_up; + destination->scroll_down = origin->scroll_down; + destination->SCROLL_CLEAR = origin->SCROLL_CLEAR; +} + +void +reinitscr(foo) +int foo; +{ + WINDOW *local_virt; + WINDOW *local_std; + WINDOW *local_cur; + + signal(SIGWINCH, reinitscr); +#ifdef TIOCGWINSZ + if (ioctl(0, TIOCGWINSZ, &ws) >= 0) + { + if (ws.ws_row == LINES && ws.ws_col == COLS) + return; + if (ws.ws_row > 0) + LINES = ws.ws_row; + if (ws.ws_col > 0) + COLS = ws.ws_col; + } +#endif /* TIOCGWINSZ */ + local_virt = newwin(LINES, COLS, 0, 0); + local_std = newwin(LINES, COLS, 0, 0); + local_cur = newwin(LINES, COLS, 0, 0); + copy_window(virtual_scr, local_virt); + copy_window(stdscr, local_std); + copy_window(curscr, local_cur); + delwin(virtual_scr); + delwin(stdscr); + delwin(curscr); + virtual_scr = local_virt; + stdscr = local_std; + curscr = local_cur; + free(virtual_lines); + virtual_lines = (int *) malloc(LINES * (sizeof(int))); + interrupt_flag = TRUE; +} +#endif /* SIGWINCH */ + +void +initscr() /* initialize terminal for operations */ +{ + int value; + char *lines_string; + char *columns_string; +#ifdef CAP + char *pointer; +#endif /* CAP */ + +#ifdef DIAG +printf("starting initscr \n");fflush(stdout); +#endif + if (initialized) + return; +#ifdef BSD_SELECT + setbuf(stdin, NULL); +#endif /* BSD_SELECT */ + Flip_Bytes = FALSE; + Parity = 0; + Time_Out = FALSE; + bufp = 0; + Move_It = FALSE; + Noblock = FALSE; +#ifdef SYS5 + value = ioctl(0, TCGETA, &Terminal); + if (Terminal.c_cflag & PARENB) + { + if (Terminal.c_cflag & PARENB) + Parity = 1; + else + Parity = 2; + } + if ((Terminal.c_cflag & CS8) == CS8) + { + Num_bits = 8; + } + else if ((Terminal.c_cflag & CS7) == CS7) + Num_bits = 7; + else if ((Terminal.c_cflag & CS6) == CS6) + Num_bits = 6; + else + Num_bits = 5; + value = Terminal.c_cflag & 037; + switch (value) { + case 01: speed = 50.0; + break; + case 02: speed = 75.0; + break; + case 03: speed = 110.0; + break; + case 04: speed = 134.5; + break; + case 05: speed = 150.0; + break; + case 06: speed = 200.0; + break; + case 07: speed = 300.0; + break; + case 010: speed = 600.0; + break; + case 011: speed = 900.0; + break; + case 012: speed = 1200.0; + break; + case 013: speed = 1800.0; + break; + case 014: speed = 2400.0; + break; + case 015: speed = 3600.0; + break; + case 016: speed = 4800.0; + break; + case 017: speed = 7200.0; + break; + case 020: speed = 9600.0; + break; + case 021: speed = 19200.0; + break; + case 022: speed = 38400.0; + break; + default: speed = 0.0; + } +#else + value = ioctl(0, TIOCGETP, &Terminal); + if (Terminal.sg_flags & EVENP) + Parity = 2; + else if (Terminal.sg_flags & ODDP) + Parity = 1; + value = Terminal.sg_ospeed; + switch (value) { + case 01: speed = 50.0; + break; + case 02: speed = 75.0; + break; + case 03: speed = 110.0; + break; + case 04: speed = 134.5; + break; + case 05: speed = 150.0; + break; + case 06: speed = 200.0; + break; + case 07: speed = 300.0; + break; + case 010: speed = 600.0; + break; + case 011: speed = 1200.0; + break; + case 012: speed = 1800.0; + break; + case 013: speed = 2400.0; + break; + case 014: speed = 4800.0; + break; + case 015: speed = 9600.0; + break; + default: speed = 0.0; + } +#endif + chars_per_millisecond = (0.001 * speed) / 8.0; + TERMINAL_TYPE = getenv("TERM"); + if (TERMINAL_TYPE == NULL) + { + printf("unknown terminal type\n"); + exit(0); + } +#ifndef CAP + Fildes = -1; + TERM_PATH = getenv("TERMINFO"); + if (TERM_PATH != NULL) + { + Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE); + Term_File_name = malloc(Data_Line_len); + sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE); + Fildes = open(Term_File_name, O_RDONLY); + } + if (Fildes == -1) + { + TERM_PATH = "/usr/lib/terminfo"; + Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE); + Term_File_name = malloc(Data_Line_len); + sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE); + Fildes = open(Term_File_name, O_RDONLY); + } + if (Fildes == -1) + { + TERM_PATH = "/usr/share/lib/terminfo"; + Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE); + Term_File_name = malloc(Data_Line_len); + sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE); + Fildes = open(Term_File_name, O_RDONLY); + } + if (Fildes == -1) + { + free(Term_File_name); + Term_File_name = NULL; + } + else + TERM_INFO = INFO_PARSE(); +#else + /* + | termcap information can be in the TERMCAP env variable, if so + | use that, otherwise check the /etc/termcap file + */ + if ((pointer = Term_File_name = getenv("TERMCAP")) != NULL) + { + if (*Term_File_name != '/') + Term_File_name = "/etc/termcap"; + } + else + { + Term_File_name = "/etc/termcap"; + } + if ((TFP = fopen(Term_File_name, "r")) == NULL) + { + printf("unable to open /etc/termcap file \n"); + exit(0); + } + for (value = 0; value < 1024; value++) + String_table[value] = NULL; + for (value = 0; value < 128; value++) + Booleans[value] = 0; + for (value = 0; value < 128; value++) + Numbers[value] = 0; + Data_Line = malloc(512); + if (pointer && *pointer != '/') + { + TERM_data_ptr = pointer; + CAP_PARSE(); + } + else + { + Find_term(); + CAP_PARSE(); + } +#endif + if (String_table[pc__] == NULL) + String_table[pc__] = "\0"; + if ((String_table[cm__] == NULL) || (Booleans[hc__])) + { + fprintf(stderr, "sorry, unable to use this terminal type for screen editing\n"); + exit(0); + } + Key_Get(); + LINES = Numbers[li__]; + COLS = Numbers[co__]; + if ((lines_string = getenv("LINES")) != NULL) + { + value = atoi(lines_string); + if (value > 0) + LINES = value; + } + if ((columns_string = getenv("COLUMNS")) != NULL) + { + value = atoi(columns_string); + if (value > 0) + COLS = value; + } +#ifdef TIOCGWINSZ + /* + | get the window size + */ + if (ioctl(0, TIOCGWINSZ, &ws) >= 0) + { + if (ws.ws_row > 0) + LINES = ws.ws_row; + if (ws.ws_col > 0) + COLS = ws.ws_col; + } +#endif + virtual_scr = newwin(LINES, COLS, 0, 0); + stdscr = newwin(LINES, COLS, 0, 0); + curscr = newwin(LINES, COLS, 0, 0); + wmove(stdscr, 0, 0); + werase(stdscr); + Repaint_screen = TRUE; + initialized = TRUE; + virtual_lines = (int *) malloc(LINES * (sizeof(int))); + +#ifdef SIGWINCH + /* + | reset size of windows and LINES and COLS if term window + | changes size + */ + signal(SIGWINCH, reinitscr); +#endif /* SIGWINCH */ + + /* + | check if scrolling is available + */ + + nc_scrolling_ability = ((String_table[al__] != NULL) && + (String_table[dl__])) || ((String_table[cs__]) + && (String_table[sr__])); + +} + +#ifndef CAP +int +Get_int() /* get a two-byte integer from the terminfo file */ +{ + int High_byte; + int Low_byte; + int temp; + + Low_byte = *((unsigned char *) TERM_data_ptr++); + High_byte = *((unsigned char *) TERM_data_ptr++); + if (Flip_Bytes) + { + temp = Low_byte; + Low_byte = High_byte; + High_byte = temp; + } + if ((High_byte == 255) && (Low_byte == 255)) + return (-1); + else + return(Low_byte + (High_byte * 256)); +} + +int +INFO_PARSE() /* parse off the data in the terminfo data file */ +{ + int offset; + int magic_number = 0; + int counter = 0; + int Num_names = 0; + int Num_bools = 0; + int Num_ints = 0; + int Num_strings = 0; + int string_table_len = 0; + char *temp_ptr; + + TERM_data_ptr = Data_Line = malloc((10240 * (sizeof(char)))); + Data_Line_len = read(Fildes, Data_Line, 10240); + if ((Data_Line_len >= 10240) || (Data_Line_len < 0)) + return(0); + /* + | get magic number + */ + magic_number = Get_int(); + /* + | if magic number not right, reverse byte order and check again + */ + if (magic_number != 282) + { + Flip_Bytes = TRUE; + TERM_data_ptr--; + TERM_data_ptr--; + magic_number = Get_int(); + if (magic_number != 282) + return(0); + } + /* + | get the number of each type in the terminfo data file + */ + Num_names = Get_int(); + Num_bools = Get_int(); + Num_ints = Get_int(); + Num_strings = Get_int(); + string_table_len = Get_int(); + Strings = malloc(string_table_len); + while (Num_names > 0) + { + TERM_data_ptr++; + Num_names--; + } + counter = 0; + while (Num_bools) + { + Num_bools--; + Booleans[counter++] = *TERM_data_ptr++; + } + if (((unsigned int) TERM_data_ptr) & 1) /* force alignment */ + TERM_data_ptr++; + counter = 0; + while (Num_ints) + { + Num_ints--; + Numbers[counter] = Get_int(); + counter++; + } + temp_ptr = TERM_data_ptr + Num_strings + Num_strings; + memcpy(Strings, temp_ptr, string_table_len); + counter = bt__; + while (Num_strings) + { + Num_strings--; + if ((offset=Get_int()) != -1) + { + if (String_table[counter] == NULL) + String_table[counter] = Strings + offset; + } + else + String_table[counter] = NULL; + counter++; + } + close(Fildes); + free(Data_Line); + return(TRUE); +} +#endif /* ifndef CAP */ + +int +AtoI() /* convert ascii text to integers */ +{ + int Temp; + + Temp = 0; + while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9')) + { + Temp = (Temp * 10) + (*TERM_data_ptr - '0'); + TERM_data_ptr++; + } + return(Temp); +} + +void +Key_Get() /* create linked list with all key sequences obtained from terminal database */ +{ + int Counter; + int Klen; + int key_def; + struct KEY_STACK *Spoint; + + Max_Key_len = 0; + Counter = 0; + key_def = kb__; + while (key_def <= kf63__) + { + if (key_def == ke__) + key_def = K1__; + else if (key_def == (K5__ + 1)) + key_def = kcbt__; + else if (key_def == (kcbt__ + 1)) + key_def = kbeg__; + else if (key_def == (kUND__ + 1)) + key_def = kf11__; + if (String_table[key_def] != NULL) + { + if (KEY_TOS == NULL) + Spoint = KEY_TOS = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK)); + else + { + Spoint = KEY_TOS; + while (Spoint->next != NULL) + Spoint = Spoint->next; + Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK)); + Spoint = Spoint->next; + } + Spoint->next = NULL; + Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS)); + Spoint->element->string = String_table[key_def]; + Spoint->element->length = strlen(String_table[key_def]); + Spoint->element->value = Key_vals[Counter]; + Klen = strlen(Spoint->element->string); + if (Klen > Max_Key_len) + Max_Key_len = Klen; + /* + | Some terminal types accept keystrokes of the form + | \E[A and \EOA, substituting '[' for 'O'. Make a + | duplicate of such key strings (since the + | database will only have one version) so new_curse + | can understand both. + */ + if ((Spoint->element->length > 1) && + ((String_table[key_def][1] == '[') || + (String_table[key_def][1] == 'O'))) + { + Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK)); + Spoint = Spoint->next; + Spoint->next = NULL; + Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS)); + Spoint->element->length = strlen(String_table[key_def]); + Spoint->element->string = malloc(Spoint->element->length + 1); + strcpy(Spoint->element->string, String_table[key_def]); + Spoint->element->value = Key_vals[Counter]; + Klen = strlen(Spoint->element->string); + if (Klen > Max_Key_len) + Max_Key_len = Klen; + + if (String_table[key_def][1] == '[') + Spoint->element->string[1] = 'O'; + else + Spoint->element->string[1] = '['; + } + } + key_def++; + Counter++; + } +} + +#ifdef CAP +char * +String_Get(param) /* read the string */ +char *param; +{ + char *String; + char *Temp; + int Counter; + + if (param == NULL) + { + while (*TERM_data_ptr != '=') + TERM_data_ptr++; + Temp = ++TERM_data_ptr; + Counter = 1; + while ((*Temp != ':') && (*Temp != (char)NULL)) + { + Counter++; + Temp++; + } + if (Counter == 1) /* no data */ + return(NULL); + String = Temp = malloc(Counter); + while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL)) + { + if (*TERM_data_ptr == '\\') + { + TERM_data_ptr++; + if (*TERM_data_ptr == 'n') + *Temp = '\n'; + else if (*TERM_data_ptr == 't') + *Temp = '\t'; + else if (*TERM_data_ptr == 'b') + *Temp = '\b'; + else if (*TERM_data_ptr == 'r') + *Temp = '\r'; + else if (*TERM_data_ptr == 'f') + *Temp = '\f'; + else if ((*TERM_data_ptr == 'e') || (*TERM_data_ptr == 'E')) + *Temp = '\033'; /* escape */ + else if (*TERM_data_ptr == '\\') + *Temp = '\\'; + else if (*TERM_data_ptr == '\'') + *Temp = '\''; + else if ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9')) + { + Counter = 0; + while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9')) + { + Counter = (8 * Counter) + (*TERM_data_ptr - '0'); + TERM_data_ptr++; /* ? */ + } + *Temp = Counter; + TERM_data_ptr--; + } + TERM_data_ptr++; + Temp++; + } + else if (*TERM_data_ptr == '^') + { + TERM_data_ptr++; + if ((*TERM_data_ptr >= '@') && (*TERM_data_ptr <= '_')) + *Temp = *TERM_data_ptr - '@'; + else if (*TERM_data_ptr == '?') + *Temp = 127; + TERM_data_ptr++; + Temp++; + } + else + *Temp++ = *TERM_data_ptr++; + } + *Temp = (char)NULL; + param = String; + } + else + { + while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != ':')) + TERM_data_ptr++; + } + return(param); +} + +int +tc_Get_int(param) /* read the integer */ +int param; +{ + int Itemp; + + if (param == 0) + { + while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '#')) + TERM_data_ptr++; + TERM_data_ptr++; + Itemp = AtoI(); + param = Itemp; + } + else + { + while (*TERM_data_ptr != ':') + TERM_data_ptr++; + } + return(param); +} + +void +Find_term() /* find terminal description in termcap file */ +{ + char *Name; + char *Ftemp; + + Ftemp = Name = malloc(strlen(TERMINAL_TYPE + 1) + 1); + strcpy(Name, TERMINAL_TYPE); + while (*Ftemp != (char)NULL) + Ftemp++; + *Ftemp++ = '|'; + *Ftemp = (char)NULL; + CFOUND = FALSE; + Data_Line_len = strlen(TERMINAL_TYPE) + 1; + while ((!CFOUND) && ((TERM_data_ptr=fgets(Data_Line, 512, TFP)) != NULL)) + { + if ((*TERM_data_ptr != ' ') && (*TERM_data_ptr != '\t') && (*TERM_data_ptr != '#')) + { + while ((!CFOUND) && (*TERM_data_ptr != (char)NULL)) + { + CFOUND = !strncmp(TERM_data_ptr, Name, Data_Line_len); + while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '|') && (*TERM_data_ptr != '#') && (*TERM_data_ptr != ':')) + TERM_data_ptr++; + if (*TERM_data_ptr == '|') + TERM_data_ptr++; + else if (!CFOUND) + *TERM_data_ptr = (char)NULL; + } + } + } + if (!CFOUND) + { + printf("terminal type %s not found\n", TERMINAL_TYPE); + exit(0); + } +} + +void +CAP_PARSE() /* parse off the data in the termcap data file */ +{ + int offset; + int found; + + do + { + while (*TERM_data_ptr != (char)NULL) + { + for (found = FALSE, offset = 0; (!found) && (offset < 26); offset++) + { + if (!strncmp(TERM_data_ptr, Boolean_names[offset], 2)) + { + found = TRUE; + Booleans[offset] = TRUE; + } + } + if (!found) + { + for (found = FALSE, offset = 0; (!found) && (offset < lw__); offset++) + { + if (!strncmp(TERM_data_ptr, Number_names[offset], 3)) + { + found = TRUE; + Numbers[offset] = tc_Get_int(Numbers[offset]); + } + } + } + if (!found) + { + for (found = FALSE, offset = 0; (!found) && (offset < smgr__); offset++) + { + if (!strncmp(TERM_data_ptr, String_names[offset], 3)) + { + found = TRUE; + String_table[offset] = String_Get(String_table[offset]); + } + } + } + + if (!strncmp(TERM_data_ptr, "tc=", 3)) + tc_ = String_Get(NULL); + while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL)) + TERM_data_ptr++; + if (*TERM_data_ptr == ':') + TERM_data_ptr++; + } + } while (((TERM_data_ptr = fgets(Data_Line, 512, TFP)) != NULL) && ((*TERM_data_ptr == ' ') || (*TERM_data_ptr == '\t'))); + if (tc_ != NULL) + { + TERMINAL_TYPE = tc_; + rewind(TFP); + Find_term(); + free(tc_); + tc_ = NULL; + CAP_PARSE(); + } + else + fclose(TFP); +} +#endif /* ifdef CAP */ + +struct _line * +Screenalloc(columns) +int columns; +{ + int i; + struct _line *tmp; + + tmp = (struct _line *) malloc(sizeof (struct _line)); + tmp->row = malloc(columns + 1); + tmp->attributes = malloc(columns + 1); + tmp->prev_screen = NULL; + tmp->next_screen = NULL; + for (i = 0; i < columns; i++) + { + tmp->row[i] = ' '; + tmp->attributes[i] = (char) NULL; + } + tmp->scroll = tmp->changed = FALSE; + tmp->row[0] = (char) NULL; + tmp->attributes[0] = (char) NULL; + tmp->row[columns] = (char) NULL; + tmp->attributes[columns] = (char) NULL; + tmp->last_char = 0; + return(tmp); +} + +WINDOW *newwin(lines, cols, start_l, start_c) +int lines, cols; /* number of lines and columns to be in window */ +int start_l, start_c; /* starting line and column to be inwindow */ +{ + WINDOW *Ntemp; + struct _line *temp_screen; + int i; + + Ntemp = (WINDOW *) malloc(sizeof(WINDOW)); + Ntemp->SR = start_l; + Ntemp->SC = start_c; + Ntemp->Num_lines = lines; + Ntemp->Num_cols = cols; + Ntemp->LX = 0; + Ntemp->LY = 0; + Ntemp->scroll_down = Ntemp->scroll_up = 0; + Ntemp->SCROLL_CLEAR = FALSE; + Ntemp->Attrib = FALSE; + Ntemp->first_line = temp_screen = Screenalloc(cols); + Ntemp->first_line->number = 0; + for (i = 1; i < lines; i++) + { + temp_screen->next_screen = Screenalloc(cols); + temp_screen->next_screen->number = i; + temp_screen->next_screen->prev_screen = temp_screen; + temp_screen = temp_screen->next_screen; + } + Ntemp->first_line->prev_screen = NULL; + temp_screen->next_screen = NULL; + return(Ntemp); +} + +#ifdef CAP +void +Cap_Out(string, p_list, place) /* interpret the output string if necessary */ +char *string; +int p_list[]; /* stack of values */ +int place; /* place keeper of top of stack */ +{ + char *Otemp; /* temporary string pointer to parse output */ + int delay; + int p1, p2, temp; + float chars; + + if (string == NULL) + return; + + if (p_list != NULL) + { + p1 = p_list[--place]; + p2 = p_list[--place]; + } + delay = 0; + Otemp = string; + if ((*Otemp >= '0') && (*Otemp <= '9')) + { + delay = atoi(Otemp); + while ((*Otemp >= '0') && (*Otemp <= '9')) + Otemp++; + if (*Otemp == '*') + Otemp++; + } + while (*Otemp != (char)NULL) + { + if (*Otemp == '%') + { + Otemp++; + if ((*Otemp == 'd') || (*Otemp == '2') || (*Otemp == '3') || (*Otemp == '.') || (*Otemp == '+')) + { + if (*Otemp == 'd') + printf("%d", p1); + else if (*Otemp == '2') + printf("%02d", p1); + else if (*Otemp == '3') + printf("%03d", p1); + else if (*Otemp == '+') + { + Otemp++; + p1 += *Otemp; + putchar(p1); + } + else if (*Otemp == '.') + putchar(p1); + p1 = p2; + p2 = 0; + } + else if (*Otemp == '>') + { + Otemp++; + if (p1 > *Otemp) + { + Otemp++; + p1 += *Otemp; + } + else + Otemp++; + } + else if (*Otemp == 'r') + { + temp = p1; + p1 = p2; + p2 = temp; + } + else if (*Otemp == 'i') + { + p1++; + p2++; + } + else if (*Otemp == '%') + putchar(*Otemp); + else if (*Otemp == 'n') + { + p1 ^= 0140; + p2 ^= 0140; + } + else if (*Otemp == 'B') + { + p1 = (16 * (p1/10)) + (p1 % 10); + p2 = (16 * (p2/10)) + (p2 % 10); + } + else if (*Otemp == 'D') + { + p1 = (p1 - 2 * (p1 % 16)); + p2 = (p2 - 2 * (p2 % 16)); + } + } + else + putchar (*Otemp); + Otemp++; + } + if (delay != 0) + { + chars = delay * chars_per_millisecond; + delay = chars; + if ((chars - delay) > 0.0) + delay++; + for (; delay > 0; delay--) + putchar(*String_table[pc__]); + } + fflush(stdout); +} + +#else + + char *Otemp; /* temporary string pointer to parse output */ + float chars; + int p[10]; + int variable[27]; + +int +Operation(Temp_Stack, place) /* handle conditional operations */ +int Temp_Stack[]; +int place; +{ + int temp; + + if (*Otemp == 'd') + { + Otemp++; + temp = Temp_Stack[--place]; + printf("%d", temp); + } + else if (!strncmp(Otemp, "2d", 2)) + { + temp = Temp_Stack[--place]; + printf("%2d", temp); + Otemp++; + Otemp++; + } + else if (!strncmp(Otemp, "3d", 2)) + { + temp = Temp_Stack[--place]; + printf("%0d", temp); + Otemp++; + Otemp++; + } + else if (!strncmp(Otemp, "02d", 3)) + { + temp = Temp_Stack[--place]; + printf("%02d", temp); + Otemp++; + Otemp++; + Otemp++; + } + else if (!strncmp(Otemp, "03d", 3)) + { + temp = Temp_Stack[--place]; + printf("%03d", temp); + Otemp++; + Otemp++; + Otemp++; + } + else if (*Otemp == '+') + { + Otemp++; + temp = Temp_Stack[--place]; + temp += Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '-') + { + Otemp++; + temp = Temp_Stack[--place]; + temp -= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '*') + { + Otemp++; + temp = Temp_Stack[--place]; + temp *= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '/') + { + Otemp++; + temp = Temp_Stack[--place]; + temp /= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == 'm') + { + Otemp++; + temp = Temp_Stack[--place]; + temp %= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '&') + { + Otemp++; + temp = Temp_Stack[--place]; + temp &= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '|') + { + Otemp++; + temp = Temp_Stack[--place]; + temp |= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '^') + { + Otemp++; + temp = Temp_Stack[--place]; + temp ^= Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '=') + { + Otemp++; + temp = Temp_Stack[--place]; + temp = (temp == Temp_Stack[--place]); + Temp_Stack[place++] = temp; + } + else if (*Otemp == '>') + { + Otemp++; + temp = Temp_Stack[--place]; + temp = temp > Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == '<') + { + Otemp++; + temp = Temp_Stack[--place]; + temp = temp < Temp_Stack[--place]; + Temp_Stack[place++] = temp; + } + else if (*Otemp == 'c') + { + Otemp++; + putchar(Temp_Stack[--place]); + } + else if (*Otemp == 'i') + { + Otemp++; + p[1]++; + p[2]++; + } + else if (*Otemp == '%') + { + putchar(*Otemp); + Otemp++; + } + else if (*Otemp == '!') + { + temp = ! Temp_Stack[--place]; + Temp_Stack[place++] = temp; + Otemp++; + } + else if (*Otemp == '~') + { + temp = ~Temp_Stack[--place]; + Temp_Stack[place++] = temp; + Otemp++; + } + else if (*Otemp == 'p') + { + Otemp++; + Temp_Stack[place++] = p[*Otemp - '0']; + Otemp++; + } + else if (*Otemp == 'P') + { + Otemp++; + Temp_Stack[place++] = variable[*Otemp - 'a']; + Otemp++; + } + else if (*Otemp == 'g') + { + Otemp++; + variable[*Otemp - 'a'] = Temp_Stack[--place]; + Otemp++; + } + else if (*Otemp == '\'') + { + Otemp++; + Temp_Stack[place++] = *Otemp; + Otemp++; + Otemp++; + } + else if (*Otemp == '{') + { + Otemp++; + temp = atoi(Otemp); + Temp_Stack[place++] = temp; + while (*Otemp != '}') + Otemp++; + Otemp++; + } + return(place); +} + +void +Info_Out(string, p_list, place) /* interpret the output string if necessary */ +char *string; +int p_list[]; +int place; +{ + char *tchar; + int delay; + int temp; + int Cond_FLAG; + int EVAL; + int Cond_Stack[128]; + int Cond_place; + int Stack[128]; + int Top_of_stack; + + if (string == NULL) + return; + + Cond_FLAG = FALSE; + Cond_place = 0; + Top_of_stack = 0; + p[0] = 0; + p[1] = 0; + p[2] = 0; + p[3] = 0; + p[4] = 0; + p[5] = 0; + p[6] = 0; + p[7] = 0; + p[8] = 0; + p[9] = 0; + if (p_list != NULL) + { + for (temp = 1; (place != 0); temp++) + { + p[temp] = p_list[--place]; + } + } + delay = 0; + Otemp = string; + while (*Otemp != (char) NULL) + { + if (*Otemp == '%') + { + Otemp++; + if ((*Otemp == '?') || (*Otemp == 't') || (*Otemp == 'e') || (*Otemp == ';')) + { + if (*Otemp == '?') + { + Otemp++; + Cond_FLAG = TRUE; + EVAL = TRUE; + while (EVAL) + { + /* + | find the end of the + | conditional statement + */ + while ((strncmp(Otemp, "%t", 2)) && (*Otemp != (char) NULL)) + { + /* + | move past '%' + */ + Otemp++; + Cond_place = Operation(Cond_Stack, Cond_place); + } + + /* + | if condition is true + */ + if ((Cond_place > 0) && (Cond_Stack[Cond_place-1])) + { + /* + | end conditional + | parsing + */ + EVAL = FALSE; + Otemp++; + Otemp++; + } + else /* condition is false */ + { + /* + | find 'else' or end + | of if statement + */ + while ((strncmp(Otemp, "%e", 2)) && (strncmp(Otemp, "%;", 2)) && (*Otemp != (char) NULL)) + Otemp++; + /* + | if an 'else' found + */ + if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%e", 2))) + { + Otemp++; + Otemp++; + tchar = Otemp; + /* + | check for 'then' part + */ + while ((*tchar != (char) NULL) && (strncmp(tchar, "%t", 2)) && (strncmp(tchar, "%;", 2))) + tchar++; + /* + | if end of string + */ + if (*tchar == (char) NULL) + { + EVAL = FALSE; + Cond_FLAG = FALSE; + Otemp = tchar; + } + /* + | if end of if found, + | set up to parse + | info + */ + else if (!strncmp(tchar, "%;", 2)) + EVAL = FALSE; + /* + | otherwise, check + | conditional in + | 'else' + */ + } + /* + | if end of if found, + | get out of if + | statement + */ + else if ((*Otemp != (char) NULL) && (!strncmp(Otemp, "%;", 2))) + { + EVAL = FALSE; + Otemp++; + Otemp++; + } + else /* Otemp == NULL */ + { + EVAL = FALSE; + Cond_FLAG = FALSE; + } + } + } + } + else + { + Otemp++; + Cond_FLAG = FALSE; + if (*Otemp != ';') + { + while ((*Otemp != (char) NULL) && (strncmp(Otemp, "%;", 2))) + Otemp++; + if (*Otemp != (char) NULL) + { + Otemp++; + Otemp++; + } + } + else + Otemp++; + } + } + else + { + Top_of_stack = Operation(Stack, Top_of_stack); + } + } + else if (!strncmp(Otemp, "$<", 2)) + { + Otemp++; + Otemp++; + delay = atoi(Otemp); + while (*Otemp != '>') + Otemp++; + Otemp++; + chars = delay * chars_per_millisecond; + delay = chars; + if ((chars - delay) > 0.0) + delay++; + if (String_table[pc__] == NULL) + temp = 0; + else + temp = *String_table[pc__]; + for (; delay > 0; delay--) + putc(temp, stdout); + } + else + { + putchar(*Otemp); + Otemp++; + } + } + fflush(stdout); +} +#endif + +void +wmove(window, row, column) /* move cursor to indicated position in window */ +WINDOW *window; +int row, column; +{ + if ((row < window->Num_lines) && (column < window->Num_cols)) + { + window->LX = column; + window->LY = row; + } +} + +void +clear_line(line, column, cols) +struct _line *line; +int column; +int cols; +{ + int j; + + if (column > line->last_char) + line->row[line->last_char] = ' '; + line->last_char = column; + line->row[column] = (char) NULL; + line->attributes[column] = (char) NULL; + line->changed = TRUE; + for (j = column + 1; j < cols; j++) + { + line->row[j] = ' '; + line->attributes[j] = (char) NULL; + } +} + +void +werase(window) /* clear the specified window */ +WINDOW *window; +{ + int i; + struct _line *tmp; + + window->SCROLL_CLEAR = CLEAR; + window->scroll_up = window->scroll_down = 0; + for (i = 0, tmp = window->first_line; i < window->Num_lines; i++, tmp = tmp->next_screen) + clear_line(tmp, 0, window->Num_cols); +} + +void +wclrtoeol(window) /* erase from current cursor position to end of line */ +WINDOW *window; +{ + int column, row; + struct _line *tmp; + + window->SCROLL_CLEAR = CHANGE; + column = window->LX; + row = window->LY; + for (row = 0, tmp = window->first_line; row < window->LY; row++) + tmp = tmp->next_screen; + clear_line(tmp, column, window->Num_cols); +} + +void +wrefresh(window) /* flush all previous output */ +WINDOW *window; +{ + wnoutrefresh(window); +#ifdef DIAG +{ + struct _line *temp; + int value; + fprintf(stderr, "columns=%d, lines=%d, SC=%d, SR=%d\n",window->Num_cols, window->Num_lines, window->SC, window->SR); + for (value = 0, temp = window->first_line; value < window->Num_lines; value++, temp = temp->next_screen) + { + if (temp->number == -1) + fprintf(stderr, "line moved "); + if (temp->scroll) + fprintf(stderr, "scroll_x is set: "); + fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row); + } + fprintf(stderr, "+-------------------- virtual screen ----------------------------------------+\n"); + fprintf(stderr, "columns=%d, lines=%d \n",virtual_scr->Num_cols, virtual_scr->Num_lines); + for (value = 0, temp = virtual_scr->first_line; value < virtual_scr->Num_lines; value++, temp = temp->next_screen) + { + if (temp->number == -1) + fprintf(stderr, "line moved "); + if (temp->scroll) + fprintf(stderr, "scroll_x is set: "); + fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row); + } + fprintf(stderr, "columns=%d, lines=%d \n",curscr->Num_cols, curscr->Num_lines); + for (value = 0, temp = curscr->first_line; value < curscr->Num_lines; value++, temp = temp->next_screen) + fprintf(stderr, "line=%s|\n", temp->row); +} +#endif + doupdate(); + virtual_scr->SCROLL_CLEAR = FALSE; + virtual_scr->scroll_down = virtual_scr->scroll_up = 0; + fflush(stdout); +} + +void +touchwin(window) +WINDOW *window; +{ + struct _line *user_line; + int line_counter = 0; + + for (line_counter = 0, user_line = window->first_line; + line_counter < window->Num_lines; line_counter++) + { + user_line->changed = TRUE; + } + window->SCROLL_CLEAR = TRUE; +} + +void +wnoutrefresh(window) +WINDOW *window; +{ + struct _line *user_line; + struct _line *virtual_line; + int line_counter = 0; + int user_col = 0; + int virt_col = 0; + + if (window->SR >= virtual_scr->Num_lines) + return; + user_line = window->first_line; + virtual_line = virtual_scr->first_line; + virtual_scr->SCROLL_CLEAR = window->SCROLL_CLEAR; + virtual_scr->LX = window->LX + window->SC; + virtual_scr->LY = window->LY + window->SR; + virtual_scr->scroll_up = window->scroll_up; + virtual_scr->scroll_down = window->scroll_down; + if ((last_window_refreshed == window) && (!window->SCROLL_CLEAR)) + return; + for (line_counter = 0; line_counter < window->SR; line_counter++) + { + virtual_line = virtual_line->next_screen; + } + for (line_counter = 0; (line_counter < window->Num_lines) + && ((line_counter + window->SR) < virtual_scr->Num_lines); + line_counter++) + { + if ((last_window_refreshed != window) || (user_line->changed) || ((SCROLL | CLEAR) & window->SCROLL_CLEAR)) + { + for (user_col = 0, virt_col = window->SC; + (virt_col < virtual_scr->Num_cols) + && (user_col < window->Num_cols); + virt_col++, user_col++) + { + virtual_line->row[virt_col] = user_line->row[user_col]; + virtual_line->attributes[virt_col] = user_line->attributes[user_col]; + } + } + if (virtual_scr->Num_cols != window->Num_cols) + { + if (virtual_line->last_char < (user_line->last_char + window->SC)) + { + if (virtual_line->row[virtual_line->last_char] == (char) NULL) + virtual_line->row[virtual_line->last_char] = ' '; + virtual_line->last_char = + min(virtual_scr->Num_cols, + (user_line->last_char + window->SC)); + } + else if (virtual_line->last_char > (user_line->last_char + window->SC)) + { + virtual_line->row[min(virtual_scr->Num_cols, + (user_line->last_char + window->SC))] = ' '; + } + } + else + virtual_line->last_char = user_line->last_char; + virtual_line->row[virtual_line->last_char] = (char) NULL; + virtual_line->changed = user_line->changed; + virtual_line = virtual_line->next_screen; + user_line = user_line->next_screen; + } + window->SCROLL_CLEAR = FALSE; + window->scroll_up = window->scroll_down = 0; + last_window_refreshed = window; +} + +void +flushinp() /* flush input */ +{ +} + +void +ungetch(c) /* push a character back on input */ +int c; +{ + if (bufp < 100) + in_buff[bufp++] = c; +} + +#ifdef BSD_SELECT +int +timed_getchar() +{ + struct timeval tv; + fd_set fds; + int ret_val; + int nfds = 1; + char temp; + + FD_ZERO(&fds); + tv.tv_sec = 0; + tv.tv_usec = 500000; /* half a second */ + FD_SET(0, &fds); + Time_Out = FALSE; /* just in case */ + + ret_val = select(nfds, &fds, 0, 0, &tv); + + /* + | if ret_val is less than zero, there was no input + | otherwise, get a character and return it + */ + + if (ret_val <= 0) + { + Time_Out = TRUE; + return(-1); + } + + return(read(0, &temp, 1)? temp : -1); +} +#endif + +int +wgetch(window) /* get character from specified window */ +WINDOW *window; +{ + int in_value; + char temp; +#ifndef SYS5 + int old_arg; +#endif /* SYS5 */ + +#ifdef BSD_SELECT + if (Noblock) + in_value = ((bufp > 0) ? in_buff[--bufp] : timed_getchar()); + else + in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1); +#else /* BSD_SELECT */ +#ifdef SYS5 + in_value = ((bufp > 0) ? in_buff[--bufp] : + (read(0, &temp, 1)> 0) ? temp : -1); +#else /* SYS5 */ + if (Noblock) + { + Time_Out = FALSE; + old_arg = fcntl(0, F_GETFL, 0); + in_value = fcntl(0, F_SETFL, old_arg | FNDELAY); + } + in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1); + if (Noblock) + { + fcntl(0, F_SETFL, old_arg); + if (Time_Out) + in_value = -1; + } +#endif /* SYS5 */ +#endif /* BSD_SELECT */ + + if (in_value != -1) + { + in_value &= 0xff; + if ((Parity) && (Num_bits < 8)) + /* strip eighth bit if parity in use */ + in_value &= 0177; + } + else if (interrupt_flag) + { + interrupt_flag = FALSE; + in_value = wgetch(window); + } + + if ((in_value == '\033') || (in_value == '\037'))/* escape character */ + in_value = Get_key(in_value); + return(in_value); +} + +#ifndef BSD_SELECT +void +Clear(arg) /* notify that time out has occurred */ +int arg; +{ + Time_Out = TRUE; +#ifdef DEBUG +fprintf(stderr, "inside Clear()\n"); +fflush(stderr); +#endif /* DEBUG */ +} +#endif /* BSD_SELECT */ + +int +Get_key(first_char) /* try to decode key sequence */ +int first_char; /* first character of sequence */ +{ + int in_char; + int Count; + char string[128]; + char *Gtemp; + int Found; +#ifdef SYS5 + struct termio Gterminal; +#else + struct sgttyb Gterminal; +#endif + struct KEY_STACK *St_point; +#if (!defined( BSD_SELECT)) || (!defined(SYS5)) + int value; +#endif /* BSD_SELECT */ + + Count = 0; + Gtemp = string; + string[Count++] = first_char; + string[Count] = (char) NULL; + Time_Out = FALSE; +#ifndef BSD_SELECT + signal(SIGALRM, Clear); + value = alarm(1); +#endif /* BSD_SELECT */ + Noblock = TRUE; +#ifdef SYS5 + Gterminal.c_cc[VTIME] = 0; /* timeout value */ + Gterminal.c_lflag &= ~ICANON; /* disable canonical operation */ + Gterminal.c_lflag &= ~ECHO; /* disable echo */ +#endif + Count = 1; + Found = FALSE; + while ((Count < Max_Key_len) && (!Time_Out) && (!Found)) + { + in_char = wgetch(stdscr); +#ifdef DEBUG +fprintf(stderr, "back in GetKey()\n"); +fflush(stderr); +#endif /* DEBUG */ + if (in_char != -1) + { + string[Count++] = in_char; + string[Count] = (char) NULL; + St_point = KEY_TOS; + while ((St_point != NULL) && (!Found)) + { + if (!strcmp(string, St_point->element->string)) + Found = TRUE; + else + St_point = St_point->next; + } + } + } +#ifndef BSD_SELECT + if (!Time_Out) + value = alarm(0); +#endif /* BSD_SELECT */ +#ifdef SYS5 +/* value = ioctl(0, TCSETA, &Terminal);*/ +#else + value = ioctl(0, TIOCSETP, &Terminal); +/* value = fcntl(0, F_SETFL, old_arg);*/ +#endif + Noblock = FALSE; + if (Found) + { + return(St_point->element->value); + } + else + { + while (Count > 1) + { + if ((string[--Count] != -1) && + ((unsigned char) (string[Count]) != 255)) + { +#ifdef DIAG +fprintf(stderr, "ungetting character %d\n", string[Count]);fflush(stdout); +#endif + ungetch(string[Count]); + } + } + return(first_char); + } +} + +void +waddch(window, c) /* output the character in the specified window */ +WINDOW *window; +int c; +{ + int row, column; + int shift; /* number of spaces to shift if a tab */ + struct _line *tmpline; + +#ifdef DIAG +/*printf("starting waddch \n");fflush(stdout);*/ +#endif + row = window->LY; + column = window->LX; + if (c == '\t') + { + shift = (column + 1) % 8; + if (shift == 0) + shift++; + else + shift = 9 - shift; + while (shift > 0) + { + shift--; + waddch(window, ' '); + } + } + else if ((column < window->Num_cols) && (row < window->Num_lines)) + { + if ((c == '~') && (Booleans[hz__])) + c = '@'; + + if (( c != '\b') && (c != '\n') && (c != '\r')) + { + row = 0; + tmpline = window->first_line; + while (row < window->LY) + { + row++; + tmpline = tmpline->next_screen; + } + tmpline->row[column] = c; + tmpline->attributes[column] = window->Attrib; + tmpline->changed = TRUE; + if (column >= tmpline->last_char) + { + if (column > tmpline->last_char) + tmpline->row[tmpline->last_char] = ' '; + tmpline->row[column + 1] = (char) NULL; + tmpline->attributes[column + 1] = (char) NULL; + tmpline->last_char = column + 1; + } + } + if (c == '\n') + { + wclrtoeol(window); + window->LX = window->Num_cols; + } + else if (c == '\r') + window->LX = 0; + else if (c == '\b') + window->LX--; + else + window->LX++; + } + if (window->LX >= window->Num_cols) + { + window->LX = 0; + window->LY++; + if (window->LY >= window->Num_lines) + { + window->LY = window->Num_lines - 1; +/* window->LY = row; + wmove(window, 0, 0); + wdeleteln(window); + wmove(window, row, 0);*/ + } + } + window->SCROLL_CLEAR = CHANGE; +} + +void +winsertln(window) /* insert a blank line into the specified window */ +WINDOW *window; +{ + int row, column; + struct _line *tmp; + struct _line *tmp1; + + window->scroll_down += 1; + window->SCROLL_CLEAR = SCROLL; + column = window->LX; + row = window->LY; + for (row = 0, tmp = window->first_line; (row < window->Num_lines) && (tmp->next_screen != NULL); row++) + tmp = tmp->next_screen; + if (tmp->prev_screen != NULL) + tmp->prev_screen->next_screen = NULL; + tmp1 = tmp; + clear_line(tmp1, 0, window->Num_cols); + tmp1->number = -1; + for (row = 0, tmp = window->first_line; (row < window->LY) && (tmp->next_screen != NULL); row++) + tmp = tmp->next_screen; + if ((window->LY == (window->Num_lines - 1)) && (window->Num_lines > 1)) + { + tmp1->next_screen = tmp->next_screen; + tmp->next_screen = tmp1; + tmp->changed = TRUE; + tmp->next_screen->prev_screen = tmp; + } + else if (window->Num_lines > 1) + { + if (tmp->prev_screen != NULL) + tmp->prev_screen->next_screen = tmp1; + tmp1->prev_screen = tmp->prev_screen; + tmp->prev_screen = tmp1; + tmp1->next_screen = tmp; + tmp->changed = TRUE; + tmp->scroll = DOWN; + } + if (window->LY == 0) + window->first_line = tmp1; +} + +void +wdeleteln(window) /* delete a line in the specified window */ +WINDOW *window; +{ + int row, column; + struct _line *tmp; + struct _line *tmpline; + + if (window->Num_lines > 1) + { + window->scroll_up += 1; + window->SCROLL_CLEAR = SCROLL; + column = window->LX; + row = window->LY; + for (row = 0, tmp = window->first_line; row < window->LY; row++) + tmp = tmp->next_screen; + if (window->LY == 0) + window->first_line = tmp->next_screen; + if (tmp->prev_screen != NULL) + tmp->prev_screen->next_screen = tmp->next_screen; + if (tmp->next_screen != NULL) + { + tmp->next_screen->changed = TRUE; + tmp->next_screen->scroll = UP; + tmp->next_screen->prev_screen = tmp->prev_screen; + } + tmpline = tmp; + clear_line(tmpline, 0, window->Num_cols); + tmpline->number = -1; + for (row = 0, tmp = window->first_line; tmp->next_screen != NULL; row++) + tmp = tmp->next_screen; + if (tmp != NULL) + { + tmp->next_screen = tmpline; + tmp->next_screen->prev_screen = tmp; + tmp->changed = TRUE; + tmp = tmp->next_screen; + } + else + tmp = tmpline; + tmp->next_screen = NULL; + } + else + { + clear_line(window->first_line, 0, window->Num_cols); + } +} + +void +wclrtobot(window) /* delete from current position to end of the window */ +WINDOW *window; +{ + int row, column; + struct _line *tmp; + + window->SCROLL_CLEAR |= CLEAR; + column = window->LX; + row = window->LY; + for (row = 0, tmp = window->first_line; row < window->LY; row++) + tmp = tmp->next_screen; + clear_line(tmp, column, window->Num_cols); + for (row = (window->LY + 1); row < window->Num_lines; row++) + { + tmp = tmp->next_screen; + clear_line(tmp, 0, window->Num_cols); + } + wmove(window, row, column); +} + +void +wstandout(window) /* begin standout mode in window */ +WINDOW *window; +{ + if (Numbers[sg__] < 1) /* if not magic cookie glitch */ + window->Attrib |= A_STANDOUT; +} + +void +wstandend(window) /* end standout mode in window */ +WINDOW *window; +{ + window->Attrib &= ~A_STANDOUT; +} + +void +waddstr(window, string) /* write 'string' in window */ +WINDOW *window; +char *string; +{ + char *wstring; + + for (wstring = string; *wstring != (char) NULL; wstring++) + waddch(window, *wstring); +} + +void +clearok(window, flag) /* erase screen and redraw at next refresh */ +WINDOW *window; +int flag; +{ + Repaint_screen = TRUE; +} + +void +echo() /* turn on echoing */ +{ + int value; + +#ifdef SYS5 + Terminal.c_lflag |= ECHO; /* enable echo */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#else + Terminal.sg_flags |= ECHO; /* enable echo */ + value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */ +#endif +} + +void +noecho() /* turn off echoing */ +{ + int value; + +#ifdef SYS5 + Terminal.c_lflag &= ~ECHO; /* disable echo */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#else + Terminal.sg_flags &= ~ECHO; /* disable echo */ + value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */ +#endif +} + +void +raw() /* set to read characters immediately */ +{ + int value; + +#ifdef SYS5 + Intr = Terminal.c_cc[VINTR]; /* get the interrupt character */ + Terminal.c_lflag &= ~ICANON; /* disable canonical operation */ + Terminal.c_lflag &= ~ISIG; /* disable signal checking */ +#ifdef FLUSHO + Terminal.c_lflag &= ~FLUSHO; +#endif +#ifdef PENDIN + Terminal.c_lflag &= ~PENDIN; +#endif +#ifdef IEXTEN + Terminal.c_lflag &= ~IEXTEN; +#endif + Terminal.c_cc[VMIN] = 1; /* minimum of one character */ + Terminal.c_cc[VTIME] = 255; /* timeout value */ + Terminal.c_cc[VINTR] = 0; /* eliminate interrupt */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#else + Terminal.sg_flags |= RAW; /* enable raw mode */ + value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */ +#endif +} + +void +noraw() /* set to normal character read mode */ +{ + int value; + +#ifdef SYS5 + Terminal.c_lflag |= ICANON; /* enable canonical operation */ + Terminal.c_lflag |= ISIG; /* enable signal checking */ + Terminal.c_cc[VEOF] = 4; /* EOF character = 4 */ + Terminal.c_cc[VEOL] = (char) NULL; /* EOL = 0 */ + Terminal.c_cc[VINTR] = Intr; /* reset interrupt char */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#else + Terminal.sg_flags &= ~RAW; /* disable raw mode */ + value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */ +/* old_arg = fcntl(0, F_GETFL, 0); + value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/ +#endif +} + +void +nl() +{ + int value; + +#ifdef SYS5 + Terminal.c_iflag |= ICRNL; /* enable carriage-return to line-feed mapping */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#endif +} + +void +nonl() +{ + int value; + +#ifdef SYS5 + Terminal.c_iflag &= ~ICRNL; /* disable carriage-return to line-feed mapping */ + Terminal.c_iflag &= ~IGNCR; /* do not ignore carriage-return */ + value = ioctl(0, TCSETA, &Terminal); /* set characteristics */ +#endif +} + +void +saveterm() +{ +} + +void +fixterm() +{ +} + +void +resetterm() +{ +} + +void +nodelay(window, flag) +WINDOW *window; +int flag; +{ +} + +void +idlok(window, flag) +WINDOW *window; +int flag; +{ +} + +void +keypad(window, flag) +WINDOW *window; +int flag; +{ + if (flag) + String_Out(String_table[ks__], NULL, 0); + else + String_Out(String_table[ke__], NULL, 0); +} + +void +savetty() /* save current tty stats */ +{ + int value; + +#ifdef SYS5 + value = ioctl(0, TCGETA, &Saved_tty); /* set characteristics */ +#else + value = ioctl(0, TIOCGETP, &Saved_tty); /* set characteristics */ +#endif +} + +void +resetty() /* restore previous tty stats */ +{ + int value; + +#ifdef SYS5 + value = ioctl(0, TCSETA, &Saved_tty); /* set characteristics */ +#else + value = ioctl(0, TIOCSETP, &Saved_tty); /* set characteristics */ +#endif +} + +void +endwin() /* end windows */ +{ + keypad(stdscr, FALSE); + free(stdscr); + initialized = FALSE; + delwin(curscr); + delwin(virtual_scr); + delwin(stdscr); +#ifndef SYS5 +{ + int old_arg, value; +/* old_arg = fcntl(0, F_GETFL, 0); + value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/ +} +#endif +} + +void +delwin(window) /* delete the window structure */ +WINDOW *window; +{ + int i; + + for (i = 1; (i < window->Num_lines) && (window->first_line->next_screen != NULL); i++) + { + window->first_line = window->first_line->next_screen; + free(window->first_line->prev_screen->row); + free(window->first_line->prev_screen->attributes); + free(window->first_line->prev_screen); + } + if (window == last_window_refreshed) + last_window_refreshed = 0; + if (window->first_line != NULL) + { + free(window->first_line->row); + free(window->first_line->attributes); + free(window->first_line); + free(window); + } +} + +#ifndef __STDC__ +void +wprintw(va_alist) +va_dcl +#else /* __STDC__ */ +void +wprintw(WINDOW *window, const char *format, ...) +#endif /* __STDC__ */ +{ +#ifndef __STDC__ + WINDOW *window; + char *format; + va_list ap; +#else + va_list ap; +#endif + int value; + char *fpoint; + char *wtemp; + +#ifndef __STDC__ + va_start(ap); + window = va_arg(ap, WINDOW *); + format = va_arg(ap, char *); +#else /* __STDC__ */ + va_start(ap, format); +#endif /* __STDC__ */ + + fpoint = (char *) format; + while (*fpoint != (char) NULL) + { + if (*fpoint == '%') + { + fpoint++; + if (*fpoint == 'd') + { + value = va_arg(ap, int); + iout(window, value); + } + else if (*fpoint == 'c') + { + value = va_arg(ap, int); + waddch(window, value); + } + else if (*fpoint == 's') + { + wtemp = va_arg(ap, char *); + waddstr(window, wtemp); + } + fpoint++; + } + else if (*fpoint == '\\') + { + fpoint++; + if (*fpoint == 'n') + waddch(window, '\n'); + else if ((*fpoint >= '0') && (*fpoint <= '9')) + { + value = 0; + while ((*fpoint >= '0') && (*fpoint <= '9')) + { + value = (value * 8) + (*fpoint - '0'); + fpoint++; + } + waddch(window, value); + } + fpoint++; + } + else + waddch(window, *fpoint++); + } +#ifdef __STDC__ + va_end(ap); +#endif /* __STDC__ */ +} + +void +iout(window, value) /* output characters */ +WINDOW *window; +int value; +{ + int i; + + if ((i = value / 10) != 0) + iout(window, i); + waddch(window, ((value % 10) + '0')); +} + +int +Comp_line(line1, line2) /* compare lines */ +struct _line *line1; +struct _line *line2; +{ + int count1, count2; + int i; + char *att1, *att2; + char *c1, *c2; + + c1 = line1->row; + c2 = line2->row; + att1 = line1->attributes; + att2 = line2->attributes; + count2 = strlen(c1) + 1; + count1 = strlen(c2) + 1; + if (count1 > count2) + { + i = count2; + count2 = count1; + count1 = i; + } + if (count2 > (count1 + count1)) + return(2); + i = 0; + while ((c1[i] != (char) NULL) && (c2[i] != (char) NULL) && (c1[i] == c2[i]) && (att1[i] == att2[i])) + i++; + count1 = i + 1; + if ((count1 == 1) && (count2 == 1)) + count1 = 0; /* both lines blank */ + else if (count2 == count1) + count1 = -1; /* equal */ + else + count1 = count2 / count1; /* lines unequal */ + return(count1); +} + +struct _line * +Insert_line(row, end_row, window) /* insert line into screen */ +int row; +int end_row; +WINDOW *window; +{ + int i; + struct _line *tmp; + struct _line *tmp1; + + for (i = 0, tmp = curscr->first_line; i < window->SR; i++) + tmp = tmp->next_screen; + if ((end_row + window->SR) == 0) + curscr->first_line = curscr->first_line->next_screen; + top_of_win = tmp; + /* + | find bottom line to delete + */ + for (i = 0, tmp = top_of_win; (tmp->next_screen != NULL) && (i < end_row); i++) + tmp = tmp->next_screen; + if (tmp->prev_screen != NULL) + tmp->prev_screen->next_screen = tmp->next_screen; + if (tmp->next_screen != NULL) + tmp->next_screen->prev_screen = tmp->prev_screen; + tmp1 = tmp; + /* + | clear deleted line + */ + clear_line(tmp, 0, window->Num_cols); + tmp1->number = -1; + for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++) + tmp = tmp->next_screen; + top_of_win = tmp; + for (i = 0, tmp = top_of_win; i < row; i++) + tmp = tmp->next_screen; + if ((tmp->prev_screen != NULL) && (window->Num_lines > 0)) + tmp->prev_screen->next_screen = tmp1; + tmp1->prev_screen = tmp->prev_screen; + tmp->prev_screen = tmp1; + tmp1->next_screen = tmp; + if ((row + window->SR) == 0) + curscr->first_line = tmp1; + if (tmp1->next_screen != NULL) + tmp1 = tmp1->next_screen; + + if ((!String_table[cs__]) && (end_row < window->Num_lines)) + { + Position(window, (window->SR + end_row), 0); + String_Out(String_table[dl__], NULL, 0); + } + Position(window, (window->SR + row), 0); + if (String_table[al__] != NULL) + String_Out(String_table[al__], NULL, 0); + else + String_Out(String_table[sr__], NULL, 0); + + for (i = 0, top_of_win = curscr->first_line; (top_of_win->next_screen != NULL) && (i < window->SR); i++) + top_of_win = top_of_win->next_screen; + return(tmp1); +} + + +struct _line * +Delete_line(row, end_row, window) /* delete a line on screen */ +int row; +int end_row; +WINDOW *window; +{ + int i; + struct _line *tmp; + struct _line *tmp1; + struct _line *tmp2; + + i = 0; + tmp = curscr->first_line; + while (i < window->SR) + { + i++; + tmp = tmp->next_screen; + } + /* + | find line to delete + */ + top_of_win = tmp; + if ((row + window->SR) == 0) + curscr->first_line = top_of_win->next_screen; + for (i = 0, tmp = top_of_win; i < row; i++) + tmp = tmp->next_screen; + if (tmp->prev_screen != NULL) + tmp->prev_screen->next_screen = tmp->next_screen; + if (tmp->next_screen != NULL) + tmp->next_screen->prev_screen = tmp->prev_screen; + tmp2 = tmp->next_screen; + tmp1 = tmp; + /* + | clear deleted line + */ + clear_line(tmp1, 0, window->Num_cols); + tmp1->number = -1; + /* + | find location to insert deleted line + */ + for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++) + tmp = tmp->next_screen; + top_of_win = tmp; + for (i = 0, tmp = top_of_win; (i < end_row) && (tmp->next_screen != NULL); i++) + tmp = tmp->next_screen; + tmp1->next_screen = tmp; + tmp1->prev_screen = tmp->prev_screen; + if (tmp1->prev_screen != NULL) + tmp1->prev_screen->next_screen = tmp1; + tmp->prev_screen = tmp1; + + Position(window, (window->SR + row), 0); + String_Out(String_table[dl__], NULL, 0); + if ((!String_table[cs__]) && (end_row < window->Num_lines)) + { + Position(window, (window->SR + end_row), 0); + String_Out(String_table[al__], NULL, 0); + } + else if ((String_table[cs__] != NULL) && (String_table[dl__] == NULL)) + { + Position(window, (window->SR + end_row), 0); + putchar('\n'); + } + + if (row == (window->Num_lines-1)) + tmp2 = tmp1; + if ((row + window->SR) == 0) + curscr->first_line = top_of_win = tmp2; + return(tmp2); +} + +void +CLEAR_TO_EOL(window, row, column) +WINDOW *window; +int row, column; +{ + int x, y; + struct _line *tmp1; + + for (y = 0, tmp1 = curscr->first_line; (y < (window->SR+row)) && (tmp1->next_screen != NULL); y++) + tmp1 = tmp1->next_screen; + for (x = column; x<window->Num_cols; x++) + { + tmp1->row[x] = ' '; + tmp1->attributes[x] = (char) NULL; + } + tmp1->row[column] = (char) NULL; + tmp1->last_char = column; + if (column < COLS) + { + if (STAND) + { + STAND = FALSE; + Position(window, row, column); + attribute_off(); + } + if (String_table[ce__] != NULL) + String_Out(String_table[ce__], NULL, 0); + else + { + for (x = column; x < window->Num_cols; x++) + putchar(' '); + Curr_x = x; + } + } +} + +int +check_delete(window, line, offset, pointer_new, pointer_old) +WINDOW *window; +int line, offset; +struct _line *pointer_new, *pointer_old; +{ + int end_old; + int end_new; + int k; + int changed; + char *old_lin; + char *new_lin; + char *old_att; + char *new_att; + + changed = FALSE; + new_lin = pointer_new->row; + new_att = pointer_new->attributes; + old_lin = pointer_old->row; + old_att = pointer_old->attributes; + end_old = end_new = offset; + while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (old_lin[end_old] != (char) NULL) && (new_lin[end_old] != (char) NULL)) + end_old++; + if (old_lin[end_old] != (char) NULL) + { + k = 0; + while ((old_lin[end_old+k] == new_lin[end_new+k]) && (new_att[end_new+k] == old_att[end_old+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10)) + k++; + if ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0))) + { + if (new_lin[end_new+k] == (char) NULL) + { + Position(window, line, (end_new+k)); + CLEAR_TO_EOL(window, line, (end_new+k)); + } + Position(window, line, offset); + for (k = offset; k < end_old; k++) + Char_del(old_lin, old_att, offset, window->Num_cols); + while ((old_lin[offset] != (char) NULL) && (offset < COLS)) + offset++; + pointer_old->last_char = offset; + changed = TRUE; + } + } + return(changed); +} + +int +check_insert(window, line, offset, pointer_new, pointer_old) +WINDOW *window; +int line, offset; +struct _line *pointer_new, *pointer_old; +{ + int changed; + int end_old, end_new; + int k; + int same = FALSE; + int old_off; + int insert; + char *old_lin; + char *new_lin; + char *old_att; + char *new_att; + + changed = FALSE; + new_lin = pointer_new->row; + new_att = pointer_new->attributes; + old_lin = pointer_old->row; + old_att = pointer_old->attributes; + end_old = end_new = offset; + while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (new_lin[end_new] != (char) NULL) && (old_lin[end_new] != (char) NULL)) + end_new++; + if (new_lin[end_new] != (char) NULL) + { + k = 0; + while ((old_lin[end_old+k] == new_lin[end_new+k]) && (old_att[end_old+k] == new_att[end_new+k]) && (new_lin[end_new+k] != (char) NULL) && (old_lin[end_old+k] != (char) NULL) && (k < 10)) + k++; + /* + | check for commonality between rest of lines (are the old + | and new lines the same, except for a chunk in the middle?) + | if the rest of the lines are common, do not insert text + */ + old_off = end_new; + while ((old_lin[old_off] != (char) NULL) && (new_lin[old_off] != (char) NULL) && (old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off])) + old_off++; + if ((old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off])) + same = TRUE; + if ((!same) && ((k > 8) || ((new_lin[end_new+k] == (char) NULL) && (k != 0)))) + { + Position(window, line, offset); + insert = FALSE; + if (String_table[ic__] == NULL) + { + String_Out(String_table[im__], NULL, 0); + insert = TRUE; + } + for (k = offset; k < end_new; k++) + { + if (!insert) + String_Out(String_table[ic__], NULL, 0); + Char_ins(old_lin, old_att, new_lin[k], new_att[k], k, window->Num_cols); + } + if (insert) + String_Out(String_table[ei__], NULL, 0); + while ((old_lin[offset] != (char) NULL) && (offset < COLS)) + offset++; + pointer_old->last_char = offset; + changed = TRUE; + } + } + return(changed); +} + +void +doupdate() +{ + WINDOW *window; + int similar; + int diff; + int begin_old, begin_new; + int end_old, end_new; + int count1, j; + int from_top, tmp_ft, offset; + int changed; + int first_time; + int first_same; + int last_same; + int list[10]; + + struct _line *curr; + struct _line *virt; + struct _line *old; + + struct _line *new; + + char *cur_lin; + char *vrt_lin; + char *cur_att; + char *vrt_att; + char *att1, *att2; + char *c1, *c2; + + window = virtual_scr; + + if (Repaint_screen) + { + if (String_table[cl__]) + String_Out(String_table[cl__], NULL, 0); + else + { + from_top = 0; + while (from_top < LINES) + { + Position(curscr, from_top, 0); + if (String_table[ce__] != NULL) + String_Out(String_table[ce__], NULL, 0); + else + { + for (j = 0; j < window->Num_cols; j++) + putchar(' '); + } + from_top++; + } + } + for (from_top = 0, curr = curscr->first_line; from_top < curscr->Num_lines; from_top++, curr = curr->next_screen) + { + Position(curscr, from_top, 0); + for (j = 0; (curr->row[j] != (char) NULL) && (j < curscr->Num_cols); j++) + { + Char_out(curr->row[j], curr->attributes[j], curr->row, curr->attributes, j); + } + if (STAND) + { + STAND = FALSE; + Position(curscr, from_top, j); + attribute_off(); + } + } + Repaint_screen = FALSE; + } + + similar = 0; + diff = FALSE; + top_of_win = curscr->first_line; + + for (from_top = 0, curr = top_of_win, virt = window->first_line; + from_top < window->Num_lines; from_top++) + { + virtual_lines[from_top] = TRUE; + if ((similar = Comp_line(curr, virt)) > 0) + { + virtual_lines[from_top] = FALSE; + diff = TRUE; + } + curr = curr->next_screen; + virt = virt->next_screen; + } + + from_top = 0; + virt = window->first_line; + curr = top_of_win; + similar = 0; + /* + | if the window has lines that are different + */ + if (diff) + { + last_same = -1; + changed = FALSE; + for (first_same = window->Num_lines; + (first_same > from_top) && (virtual_lines[first_same - 1]); + first_same--) + ; + count1 = first_same - 1; + for (last_same = 0; + (last_same < window->Num_lines) && (virtual_lines[last_same]== FALSE); + last_same++) + ; + while ((from_top < first_same) && nc_scrolling_ability) + /* check entire lines for diffs */ + { + + + if (from_top >= last_same) + { + for (last_same = from_top; + (last_same < window->Num_lines) && + (virtual_lines[last_same] == FALSE); + last_same++) + ; + } + if (!virtual_lines[from_top]) + { + diff = TRUE; + /* + | check for lines deleted (scroll up) + */ + for (tmp_ft = from_top+1, old = curr->next_screen; + ((window->scroll_up) && (diff) && + (tmp_ft < last_same) && + (!virtual_lines[tmp_ft])); + tmp_ft++) + { + if ((Comp_line(old, virt) == -1) && (!virtual_lines[from_top])) + { + if (String_table[cs__]) /* scrolling region */ + { + list[1] = from_top; + list[0] = min((last_same - 1), (window->Num_lines - 1)); + String_Out(String_table[cs__], list, 2); + Curr_y = Curr_x = -1; + } + + for (offset = (tmp_ft - from_top); (offset > 0); offset--) + { + old = Delete_line(from_top, min((last_same - 1), (window->Num_lines - 1)), window); + diff = FALSE; + } + + if (String_table[cs__]) /* scrolling region */ + { + list[1] = 0; + list[0] = LINES; + String_Out(String_table[cs__], list, 2); + Curr_y = Curr_x = -1; + } + + top_of_win = curscr->first_line; + curr = top_of_win; + for (offset = 0; offset < from_top; offset++) + curr = curr->next_screen; + for (offset = from_top, old=curr, new=virt; + offset < window->Num_lines; + old=old->next_screen, new=new->next_screen, + offset++) + { + similar = Comp_line(old, new); + virtual_lines[offset] = (similar > 0 ? FALSE : TRUE); + } + } + else + old = old->next_screen; + } + /* + | check for lines inserted (scroll down) + */ + for (tmp_ft = from_top-1, old = curr->prev_screen; + ((window->scroll_down) && (tmp_ft >= 0) && + (diff) && + (!virtual_lines[tmp_ft])); + tmp_ft--) + { + if (Comp_line(old, virt) == -1) + { + if (String_table[cs__]) /* scrolling region */ + { + list[1] = tmp_ft; + list[0] = min((last_same - 1), (window->Num_lines - 1)); + String_Out(String_table[cs__], list, 2); + Curr_y = Curr_x = -1; + } + + for (offset = (from_top - tmp_ft); (offset > 0); offset--) + { + old = Insert_line(tmp_ft, min((last_same - 1), (window->Num_lines -1)), window); + diff = FALSE; + } + + if (String_table[cs__]) /* scrolling region */ + { + list[1] = 0; + list[0] = LINES; + String_Out(String_table[cs__], list, 2); + Curr_y = Curr_x = -1; + } + + top_of_win = curscr->first_line; + curr = top_of_win; + for (offset = 0; offset < from_top; offset++) + curr = curr->next_screen; + for (offset = from_top, old=curr, new=virt; + offset < window->Num_lines; + old=old->next_screen, new=new->next_screen, + offset++) + { + similar = Comp_line(old, new); + virtual_lines[offset] = (similar > 0 ? FALSE : TRUE); + } + } + else + old = old->prev_screen; + } + } + from_top++; + curr = curr->next_screen; + virt = virt->next_screen; + } + } + + for (from_top = 0, curr = curscr->first_line; from_top < window->SR; from_top++) + curr = curr->next_screen; + top_of_win = curr; + for (from_top = 0, curr = top_of_win, virt = window->first_line; from_top < window->Num_lines; from_top++, curr = curr->next_screen, virt = virt->next_screen) + { + if (((String_table[ic__]) || (String_table[im__])) && (String_table[dc__]) && (curr->row[0] != (char) NULL)) + { + j = 0; + first_time = TRUE; + vrt_lin = virt->row; + vrt_att = virt->attributes; + cur_lin = curr->row; + cur_att = curr->attributes; + while ((vrt_lin[j] != (char) NULL) && (j < window->Num_cols)) + { + if ((STAND) && (Booleans[xs__])) + { + while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL) && (vrt_att[j])) + j++; + if ((STAND) && (!vrt_att[j])) + { + STAND = FALSE; + Position(window, from_top, j); + attribute_off(); + attribute_off(); + } + } + else + { + while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != (char) NULL)) + j++; + } + if ((vrt_att[j] != cur_att[j]) && (cur_att[j]) && (Booleans[xs__])) + { + Position(window, from_top, j); +/* CLEAR_TO_EOL(window, from_top, j);*/ + attribute_off(); + attribute_off(); + } + if (vrt_lin[j] != (char) NULL) + { + begin_new = j; + begin_old = j; + end_old = j; + end_new = j; + if ((first_time) && (virt->changed)) + { + if (curr->last_char <= virt->last_char) + changed = check_insert(window, from_top, j, virt, curr); + } + changed = check_delete(window, from_top, j, virt, curr); + first_time = FALSE; + virt->changed = FALSE; + if (!changed) + changed = check_insert(window, from_top, j, virt, curr); + if (((!changed) || (cur_lin[j] != vrt_lin[j]) || (cur_att[j] != vrt_att[j])) && (j < window->Num_cols)) + { + if ((vrt_lin[j] == ' ') && (cur_lin[j] == (char) NULL) && (vrt_att[j] == cur_att[j])) + cur_lin[j] = ' '; + else + { + Position(window, from_top, j); + Char_out(vrt_lin[j], vrt_att[j], cur_lin, cur_att, j); + } + } + if ((vrt_lin[j] != (char) NULL)) + j++; + } + if ((STAND) && (!vrt_att[j])) + { + STAND = FALSE; + Position(window, from_top, j); + attribute_off(); + } + } + if ((vrt_lin[j] == (char) NULL) && (cur_lin[j] != (char) NULL)) + { + Position(window, from_top, j); + CLEAR_TO_EOL(window, from_top, j); + } + } + else /*if ((similar != -1) && (similar != 0))*/ + { + j = 0; + c1 = curr->row; + att1 = curr->attributes; + c2 = virt->row; + att2 = virt->attributes; + while ((j < window->Num_cols) && (c2[j] != (char) NULL)) + { + while ((c1[j] == c2[j]) && (att1[j] == att2[j]) && (j < window->Num_cols) && (c2[j] != (char) NULL)) + j++; + begin_old = j; + begin_new = j; + if ((j < window->Num_cols) && (c2[j] != (char) NULL)) + { + Position(window, from_top, begin_old); + CLEAR_TO_EOL(window, from_top, j); + Position(window, from_top, begin_old); + for (j = begin_old; (c2[j] != (char) NULL) && (j < window->Num_cols); j++) + Char_out(c2[j], att2[j], c1, att1, j); + } + } + if ((c2[j] == (char) NULL) && (c1[j] != (char) NULL)) + { + Position(window, from_top, j); + CLEAR_TO_EOL(window, from_top, j); + } + } + if (STAND) + { + STAND = FALSE; + Position(window, from_top, j); + attribute_off(); + } + virt->number = from_top; + } + Position(window, window->LY, window->LX); +} + +void +Position(window, row, col) /* position the cursor for output on the screen */ +WINDOW *window; +int row; +int col; +{ + int list[10]; + int place; + + int pos_row; + int pos_column; + + pos_row = row + window->SR; + pos_column = col + window->SC; + if ((pos_row != Curr_y) || (pos_column != Curr_x)) + { + if (String_table[cm__] != NULL) /* && (row < window->Num_lines) && (column < window->Num_cols))*/ + { + place = 0; + list[place++] = pos_column; + list[place++] = pos_row; + String_Out(String_table[cm__], list, place); + if ((STAND) && (!Booleans[ms__])) + attribute_on(); + } + Curr_x = pos_column; + Curr_y = pos_row; + } +} + +void +Char_del(line, attrib, offset, maxlen) /* delete chars from line */ +char *line; +char *attrib; +int offset; +int maxlen; +{ + int one, two; + + for (one = offset, two = offset+1; (line[one] != (char) NULL) && (one < maxlen); one++, two++) + { + line[one] = line[two]; + attrib[one] = attrib[two]; + } + String_Out(String_table[dc__], NULL, 0); +} + +void +Char_ins(line, attrib, newc, newatt, offset, maxlen) /* insert chars in line */ +char *line; +char *attrib; +char newc; +char newatt; +int offset; +int maxlen; +{ + int one, two; + + one = 0; + while ((line[one] != (char) NULL) && (one < (maxlen - 2))) + one++; + for (two = one + 1; (two > offset); one--, two--) + { + line[two] = line[one]; + attrib[two] = attrib[one]; + } + line[offset] = newc; + attrib[offset] = newatt; + Char_out(newc, newatt, line, attrib, offset); +} + +void +attribute_on() +{ + if (String_table[sa__]) + { + attributes_set[0] = 1; + String_Out(String_table[sa__], attributes_set, 1); + } + else if (String_table[so__]) + String_Out(String_table[so__], NULL, 0); +} + +void +attribute_off() +{ + if (String_table[me__]) + String_Out(String_table[me__], NULL, 0); + else if (String_table[sa__]) + { + attributes_set[0] = 0; + String_Out(String_table[sa__], attributes_set, 1); + } + else if (String_table[se__]) + String_Out(String_table[se__], NULL, 0); +} + +void +Char_out(newc, newatt, line, attrib, offset) /* output character with proper attribute */ +char newc; +char newatt; +char *line; +char *attrib; +int offset; +{ + + + if ((newatt) && (!STAND)) + { + STAND = TRUE; + attribute_on(); + } + else if ((STAND) && (!newatt)) + { + STAND = FALSE; + attribute_off(); + } + + if ((newatt) && (STAND) && (Booleans[xs__])) + { + attribute_on(); + } + + if (!((Curr_y >= (LINES - 1)) && (Curr_x >= (COLS - 1)))) + { + putchar(newc); + line[offset] = newc; + attrib[offset] = newatt; + } + Curr_x++; +} + diff --git a/usr.bin/ee/doc/new_curse.h b/usr.bin/ee/doc/new_curse.h new file mode 100644 index 0000000000000..f69ee5910bda0 --- /dev/null +++ b/usr.bin/ee/doc/new_curse.h @@ -0,0 +1,255 @@ +/* + | new_curse.h + | + | A subset of curses developed for use with ae. + | + | written by Hugh Mahon + | + | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE + | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS + | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE + | IMPLIED WARRANTIES OF MERCHANTABILITY AND + | FITNESS FOR A PARTICULAR PURPOSE. Neither + | Hewlett-Packard nor Hugh Mahon shall be liable + | for errors contained herein, nor for + | incidental or consequential damages in + | connection with the furnishing, performance or + | use of this material. Neither Hewlett-Packard + | nor Hugh Mahon assumes any responsibility for + | the use or reliability of this software or + | documentation. This software and + | documentation is totally UNSUPPORTED. There + | is no support contract available. Hewlett- + | Packard has done NO Quality Assurance on ANY + | of the program or documentation. You may find + | the quality of the materials inferior to + | supported materials. + | + | This software is not a product of Hewlett-Packard, Co., or any + | other company. No support is implied or offered with this software. + | You've got the source, and you're on your own. + | + | This software may be distributed under the terms of Larry Wall's + | Artistic license, a copy of which is included in this distribution. + | + | This notice must be included with this software and any derivatives. + | + | Copyright (c) 1986, 1987, 1988, 1991, 1995 Hugh Mahon + | All are rights reserved. + | + */ + +#include <stdio.h> + +#ifdef SYS5 +#include <termio.h> +#else +#include <sgtty.h> +#include <fcntl.h> +#endif + +#define KEY_BREAK 0401 +#define KEY_DOWN 0402 +#define KEY_UP 0403 +#define KEY_LEFT 0404 +#define KEY_RIGHT 0405 +#define KEY_HOME 0406 +#define KEY_BACKSPACE 0407 +#define KEY_F0 0410 +#define KEY_F(n) (KEY_F0+(n)) +#define KEY_DL 0510 +#define KEY_IL 0511 +#define KEY_DC 0512 +#define KEY_IC 0513 +#define KEY_EIC 0514 +#define KEY_CLEAR 0515 +#define KEY_EOS 0516 +#define KEY_EOL 0517 +#define KEY_SF 0520 +#define KEY_SR 0521 +#define KEY_NPAGE 0522 +#define KEY_PPAGE 0523 +#define KEY_STAB 0524 +#define KEY_CTAB 0525 +#define KEY_CATAB 0526 +#define KEY_ENTER 0527 +#define KEY_SRESET 0530 +#define KEY_RESET 0531 +#define KEY_PRINT 0532 +#define KEY_LL 0533 +#define KEY_A1 0534 +#define KEY_A3 0535 +#define KEY_B2 0536 +#define KEY_C1 0537 +#define KEY_C3 0540 +#define KEY_BTAB 0541 +#define KEY_BEG 0542 +#define KEY_CANCEL 0543 +#define KEY_CLOSE 0544 +#define KEY_COMMAND 0545 +#define KEY_COPY 0546 +#define KEY_CREATE 0547 +#define KEY_END 0550 +#define KEY_EXIT 0551 +#define KEY_FIND 0552 +#define KEY_HELP 0553 +#define KEY_MARK 0554 +#define KEY_MESSAGE 0555 +#define KEY_MOVE 0556 +#define KEY_NEXT 0557 +#define KEY_OPEN 0560 +#define KEY_OPTIONS 0561 +#define KEY_PREVIOUS 0562 +#define KEY_REDO 0563 +#define KEY_REFERENCE 0564 +#define KEY_REFRESH 0565 +#define KEY_REPLACE 0566 +#define KEY_RESTART 0567 +#define KEY_RESUME 0570 +#define KEY_SAVE 0571 +#define KEY_SBEG 0572 +#define KEY_SCANCEL 0573 +#define KEY_SCOMMAND 0574 +#define KEY_SCOPY 0575 +#define KEY_SCREATE 0576 +#define KEY_SDC 0577 +#define KEY_SDL 0600 +#define KEY_SELECT 0601 +#define KEY_SEND 0602 +#define KEY_SEOL 0603 +#define KEY_SEXIT 0604 +#define KEY_SFIND 0605 +#define KEY_SHELP 0606 +#define KEY_SHOME 0607 +#define KEY_SIC 0610 +#define KEY_SLEFT 0611 +#define KEY_SMESSAGE 0612 +#define KEY_SMOVE 0613 +#define KEY_SNEXT 0614 +#define KEY_SOPTIONS 0615 +#define KEY_SPREVIOUS 0616 +#define KEY_SPRINT 0617 +#define KEY_SREDO 0620 +#define KEY_SREPLACE 0621 +#define KEY_SRIGHT 0622 +#define KEY_SRSUME 0623 +#define KEY_SSAVE 0624 +#define KEY_SSUSPEND 0625 +#define KEY_SUNDO 0626 +#define KEY_SUSPEND 0627 +#define KEY_UNDO 0630 + +#define TRUE 1 +#define FALSE 0 + +#define A_STANDOUT 0001 /* standout mode */ +#define SCROLL 1 /* text has been scrolled */ +#define CLEAR 2 /* window has been cleared */ +#define CHANGE 3 /* window has been changed */ +#define UP 1 /* direction of scroll */ +#define DOWN 2 + +struct _line { + struct _line *next_screen; + struct _line *prev_screen; + char *row; + char *attributes; + int last_char; + int changed; + int scroll; + int number; + }; + +struct _line *top_of_win; + +typedef struct WIND { + int SR; /* starting row */ + int SC; /* starting column */ + int LC; /* last column */ + int LX; /* last cursor column position */ + int LY; /* last cursor row position */ + int Attrib; /* attributes active in window */ + int Num_lines; /* number of lines */ + int Num_cols; /* number of columns */ + int scroll_up; /* number of lines moved */ + int scroll_down; + int SCROLL_CLEAR; /* indicates that window has been scrolled or cleared */ + struct _line *first_line; + } WINDOW; + +extern WINDOW *curscr; +extern WINDOW *stdscr; + +extern int LINES, COLS; + +#if __STDC__ || defined(__cplusplus) +#define P_(s) s +#else +#define P_(s) () +#endif + +extern void copy_window P_((WINDOW *origin, WINDOW *destination)); +extern void reinitscr P_((int)); +extern void initscr P_((void)); +extern int Get_int P_((void)); +extern int INFO_PARSE P_((void)); +extern int AtoI P_((void)); +extern void Key_Get P_((void)); +extern struct _line *Screenalloc P_((int columns)); +extern WINDOW *newwin P_((int lines, int cols, int start_l, int start_c)); +extern int Operation P_((int Temp_Stack[], int place)); +extern void Info_Out P_((char *string, int p_list[], int place)); +extern void wmove P_((WINDOW *window, int row, int column)); +extern void clear_line P_((struct _line *line, int column, int cols)); +extern void werase P_((WINDOW *window)); +extern void wclrtoeol P_((WINDOW *window)); +extern void wrefresh P_((WINDOW *window)); +extern void touchwin P_((WINDOW *window)); +extern void wnoutrefresh P_((WINDOW *window)); +extern void flushinp P_((void)); +extern void ungetch P_((int c)); +extern int wgetch P_((WINDOW *window)); +extern void Clear P_((int)); +extern int Get_key P_((int first_char)); +extern void waddch P_((WINDOW *window, int c)); +extern void winsertln P_((WINDOW *window)); +extern void wdeleteln P_((WINDOW *window)); +extern void wclrtobot P_((WINDOW *window)); +extern void wstandout P_((WINDOW *window)); +extern void wstandend P_((WINDOW *window)); +extern void waddstr P_((WINDOW *window, char *string)); +extern void clearok P_((WINDOW *window, int flag)); +extern void echo P_((void)); +extern void noecho P_((void)); +extern void raw P_((void)); +extern void noraw P_((void)); +extern void nl P_((void)); +extern void nonl P_((void)); +extern void saveterm P_((void)); +extern void fixterm P_((void)); +extern void resetterm P_((void)); +extern void nodelay P_((WINDOW *window, int flag)); +extern void idlok P_((WINDOW *window, int flag)); +extern void keypad P_((WINDOW *window, int flag)); +extern void savetty P_((void)); +extern void resetty P_((void)); +extern void endwin P_((void)); +extern void delwin P_((WINDOW *window)); +extern void wprintw P_((WINDOW *window, __const char* format, ...)); +extern void iout P_((WINDOW *window, int value)); +extern int Comp_line P_((struct _line *line1, struct _line *line2)); +extern struct _line *Insert_line P_((int row, int end_row, WINDOW *window)); +extern struct _line *Delete_line P_((int row, int end_row, WINDOW *window)); +extern void CLEAR_TO_EOL P_((WINDOW *window, int row, int column)); +extern int check_delete P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old)); +extern int check_insert P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old)); +extern void doupdate P_((void)); +extern void Position P_((WINDOW *window, int row, int col)); +extern void Char_del P_((char *line, char *attrib, int offset, int maxlen)); +extern void Char_ins P_((char *line, char *attrib, int newc, int newatt, int offset, int maxlen)); +extern void attribute_on P_((void)); +extern void attribute_off P_((void)); +extern void Char_out P_((int newc, int newatt, char *line, char *attrib, int offset)); + +#undef P_ + diff --git a/usr.bin/ee/ee.c b/usr.bin/ee/ee.c new file mode 100644 index 0000000000000..876a58c79399e --- /dev/null +++ b/usr.bin/ee/ee.c @@ -0,0 +1,4795 @@ +/* + | ee (easy editor) + | + | An easy to use, simple screen oriented editor. + | + | written by Hugh Mahon + | + | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE + | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS + | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE + | IMPLIED WARRANTIES OF MERCHANTABILITY AND + | FITNESS FOR A PARTICULAR PURPOSE. Neither + | Hewlett-Packard nor Hugh Mahon shall be liable + | for errors contained herein, nor for + | incidental or consequential damages in + | connection with the furnishing, performance or + | use of this material. Neither Hewlett-Packard + | nor Hugh Mahon assumes any responsibility for + | the use or reliability of this software or + | documentation. This software and + | documentation is totally UNSUPPORTED. There + | is no support contract available. Hewlett- + | Packard has done NO Quality Assurance on ANY + | of the program or documentation. You may find + | the quality of the materials inferior to + | supported materials. + | + | This software is not a product of Hewlett-Packard, Co., or any + | other company. No support is implied or offered with this software. + | You've got the source, and you're on your own. + | + | This software may be distributed under the terms of Larry Wall's + | Artistic license, a copy of which is included in this distribution. + | + | This notice must be included with this software and any derivatives. + | + | This editor was purposely developed to be simple, both in + | interface and implementation. This editor was developed to + | address a specific audience: the user who is new to computers + | (especially UNIX). + | + | ee is not aimed at technical users; for that reason more + | complex features were intentionally left out. In addition, + | ee is intended to be compiled by people with little computer + | experience, which means that it needs to be small, relatively + | simple in implementation, and portable. + | + | This software and documentation contains + | proprietary information which is protected by + | copyright. All rights are reserved. + | + | $Header: /home/ncvs/src/usr.bin/ee/ee.c,v 1.2 1995/08/30 17:11:54 ache Exp $ + | + */ + +char *ee_copyright_message = +"Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995 Hugh Mahon "; + +char *ee_long_notice[] = { + "This software and documentation contains", + "proprietary information which is protected by", + "copyright. All rights are reserved." + }; + +char *version = "@(#) ee, version 1.2.4 $Revision: 1.2 $"; + +#ifdef NCURSE +#include "new_curse.h" +#else +#ifdef HAS_NCURSES +#include <ncurses.h> +#else +#include <curses.h> +#endif +#endif + +#include <signal.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <pwd.h> + +#ifdef HAS_SYS_WAIT +#include <sys/wait.h> +#endif + +#ifdef HAS_STDLIB +#include <stdlib.h> +#endif + +#ifdef HAS_STDARG +#include <stdarg.h> +#endif + +#ifdef HAS_UNISTD +#include <unistd.h> +#endif + +#ifdef HAS_CTYPE +#include <ctype.h> +#endif + + +#ifndef NO_CATGETS +#include <locale.h> +#include <nl_types.h> + +nl_catd catalog; +#else +#define catgetlocal(a, b) (b) +#endif /* NO_CATGETS */ + +#ifndef SIGCHLD +#define SIGCHLD SIGCLD +#endif + +#define TAB 9 +#define max(a, b) (a > b ? a : b) +#define min(a, b) (a < b ? a : b) + +/* + | defines for type of data to show in info window + */ + +#define CONTROL_KEYS 1 +#define COMMANDS 2 + +struct text { + char *line; /* line of characters */ + int line_number; /* line number */ + int line_length; /* actual number of characters in the line */ + int max_length; /* maximum number of characters the line handles */ + struct text *next_line; /* next line of text */ + struct text *prev_line; /* previous line of text */ + }; + +struct text *first_line; /* first line of current buffer */ +struct text *dlt_line; /* structure for info on deleted line */ +struct text *curr_line; /* current line cursor is on */ +struct text *tmp_line; /* temporary line pointer */ +struct text *srch_line; /* temporary pointer for search routine */ + +struct files { /* structure to store names of files to be edited*/ + char *name; /* name of file */ + struct files *next_name; + }; + +struct files *top_of_stack = NULL; + +int d_wrd_len; /* length of deleted word */ +int position; /* offset in bytes from begin of line */ +int scr_pos; /* horizontal position */ +int scr_vert; /* vertical position on screen */ +int scr_horz; /* horizontal position on screen */ +int tmp_vert, tmp_horz; +int input_file; /* indicate to read input file */ +int recv_file; /* indicate reading a file */ +int edit; /* continue executing while true */ +int gold; /* 'gold' function key pressed */ +int fildes; /* file descriptor */ +int case_sen; /* case sensitive search flag */ +int last_line; /* last line for text display */ +int last_col; /* last column for text display */ +int horiz_offset = 0; /* offset from left edge of text */ +int clear_com_win; /* flag to indicate com_win needs clearing */ +int text_changes = FALSE; /* indicate changes have been made to text */ +int get_fd; /* file descriptor for reading a file */ +int info_window = TRUE; /* flag to indicate if help window visible */ +int info_type = CONTROL_KEYS; /* flag to indicate type of info to display */ +int expand_tabs = TRUE; /* flag for expanding tabs */ +int right_margin = 0; /* the right margin */ +int observ_margins = TRUE; /* flag for whether margins are observed */ +int shell_fork; +int temp_stdin; /* temporary storage for stdin */ +int temp_stdout; /* temp storage for stdout descriptor */ +int temp_stderr; /* temp storage for stderr descriptor */ +int pipe_out[2]; /* pipe file desc for output */ +int pipe_in[2]; /* pipe file descriptors for input */ +int out_pipe; /* flag that info is piped out */ +int in_pipe; /* flag that info is piped in */ +int formatted = FALSE; /* flag indicating paragraph formatted */ +int auto_format = FALSE; /* flag for auto_format mode */ +int restricted = FALSE; /* flag to indicate restricted mode */ +int nohighlight = FALSE; /* turns off highlighting */ +int eightbit = TRUE; /* eight bit character flag */ +int local_LINES = 0; /* copy of LINES, to detect when win resizes */ +int local_COLS = 0; /* copy of COLS, to detect when win resizes */ +int curses_initialized = FALSE; /* flag indicating if curses has been started*/ +int emacs_keys_mode = FALSE; /* mode for if emacs key binings are used */ + +char *point; /* points to current position in line */ +char *srch_str; /* pointer for search string */ +char *u_srch_str; /* pointer to non-case sensitive search */ +char *srch_1; /* pointer to start of suspect string */ +char *srch_2; /* pointer to next character of string */ +char *srch_3; +char *in_file_name = NULL; /* name of input file */ +char *tmp_file; /* temporary file name */ +char d_char; /* deleted character */ +char *d_word; /* deleted word */ +char *d_line; /* deleted line */ +char in_string[513]; /* buffer for reading a file */ +char *print_command = "lp"; /* string to use for the print command */ +char *start_at_line = NULL; /* move to this line at start of session*/ +int in; /* input character */ + +FILE *temp_fp; /* temporary file pointer */ +FILE *bit_bucket; /* file pointer to /dev/null */ + +char *table[] = { + "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "\t", "^J", + "^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", + "^V", "^W", "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_" + }; + +WINDOW *com_win; +WINDOW *text_win; +WINDOW *help_win; +WINDOW *info_win; + +#if defined(__STDC__) || defined(__cplusplus) +#define P_(s) s +#else +#define P_(s) () +#endif + + +/* + | The following structure allows menu items to be flexibly declared. + | The first item is the string describing the selection, the second + | is the address of the procedure to call when the item is selected, + | and the third is the argument for the procedure. + | + | For those systems with i18n, the string should be accompanied by a + | catalog number. The 'int *' should be replaced with 'void *' on + | systems with that type. + | + | The first menu item will be the title of the menu, with NULL + | parameters for the procedure and argument, followed by the menu items. + | + | If the procedure value is NULL, the menu item is displayed, but no + | procedure is called when the item is selected. The number of the + | item will be returned. If the third (argument) parameter is -1, no + | argument is given to the procedure when it is called. + */ + +struct menu_entries { + char *item_string; + int (*procedure)P_((struct menu_entries *)); + struct menu_entries *ptr_argument; + int (*iprocedure)P_((int)); + void (*nprocedure)P_((void)); + unsigned int argument; + }; + +int main P_((int argc, char *argv[])); +char *resiz_line P_((int factor, struct text *rline, int rpos)); +void insert P_((int character)); +void delete P_((int disp)); +void scanline P_((char *pos)); +int tabshift P_((int temp_int)); +int out_char P_((WINDOW *window, int character, int column)); +int len_char P_((int character, int column)); +void draw_line P_((int vertical, int horiz, char *ptr, int t_pos, int length)); +void insert_line P_((int disp)); +struct text *txtalloc P_((void)); +struct files *name_alloc P_((void)); +char *next_word P_((char *string)); +void prev_word P_((void)); +void control P_((void)); +void emacs_control P_((void)); +void bottom P_((void)); +void top P_((void)); +void nextline P_((void)); +void prevline P_((void)); +void left P_((int disp)); +void right P_((int disp)); +void find_pos P_((void)); +void up P_((void)); +void down P_((void)); +void function_key P_((void)); +void print_buffer P_((void)); +void command_prompt P_((void)); +void command P_((char *cmd_str1)); +int scan P_((char *line, int offset, int column)); +char *get_string P_((char *prompt, int advance)); +int compare P_((char *string1, char *string2, int sensitive)); +void goto_line P_((char *cmd_str)); +void midscreen P_((int line, char *pnt)); +void get_options P_((int numargs, char *arguments[])); +void check_fp P_((void)); +void get_file P_((char *file_name)); +void get_line P_((int length, char *in_string, int *append)); +void draw_screen P_((void)); +void finish P_((void)); +int quit P_((int noverify)); +void edit_abort P_((int arg)); +void delete_text P_((void)); +int write_file P_((char *file_name)); +int search P_((int display_message)); +void search_prompt P_((void)); +void del_char P_((void)); +void undel_char P_((void)); +void del_word P_((void)); +void undel_word P_((void)); +void del_line P_((void)); +void undel_line P_((void)); +void adv_word P_((void)); +void move_rel P_((char *direction, int lines)); +void eol P_((void)); +void bol P_((void)); +void adv_line P_((void)); +void sh_command P_((char *string)); +void set_up_term P_((void)); +void resize_check P_((void)); +int menu_op P_((struct menu_entries *)); +void help P_((void)); +void paint_info_win P_((void)); +void no_info_window P_((void)); +void create_info_window P_((void)); +int file_op P_((int arg)); +void shell_op P_((void)); +void leave_op P_((void)); +void redraw P_((void)); +int Blank_Line P_((struct text *test_line)); +void Format P_((void)); +void ee_init P_((void)); +void echo_string P_((char *string)); +void spell_op P_((void)); +void ispell_op P_((void)); +int first_word_len P_((struct text *test_line)); +void Auto_Format P_((void)); +void modes_op P_((void)); +char *is_in_string P_((char *string, char *substring)); +char *resolve_name P_((char *name)); +int restrict_mode P_((void)); +int unique_test P_((char *string, char *list[])); +void strings_init P_((void)); + +#undef P_ +/* + | allocate space here for the strings that will be in the menu + */ + +struct menu_entries modes_menu[] = { + {"", NULL, NULL, NULL, NULL, 0}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, NULL, -1}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +char *mode_strings[9]; + +#define NUM_MODES_ITEMS 9 + +struct menu_entries leave_menu[] = { + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, finish, -1}, + {"", NULL, NULL, quit, NULL, TRUE}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +#define READ_FILE 1 +#define WRITE_FILE 2 +#define SAVE_FILE 3 + +struct menu_entries file_menu[] = { + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, file_op, NULL, READ_FILE}, + {"", NULL, NULL, file_op, NULL, WRITE_FILE}, + {"", NULL, NULL, file_op, NULL, SAVE_FILE}, + {"", NULL, NULL, NULL, print_buffer, -1}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +struct menu_entries search_menu[] = { + {"", NULL, NULL, NULL, NULL, 0}, + {"", NULL, NULL, NULL, search_prompt, -1}, + {"", NULL, NULL, search, NULL, TRUE}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +struct menu_entries spell_menu[] = { + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, spell_op, -1}, + {"", NULL, NULL, NULL, ispell_op, -1}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +struct menu_entries misc_menu[] = { + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, Format, -1}, + {"", NULL, NULL, NULL, shell_op, -1}, + {"", menu_op, spell_menu, NULL, NULL, -1}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +struct menu_entries main_menu[] = { + {"", NULL, NULL, NULL, NULL, -1}, + {"", NULL, NULL, NULL, leave_op, -1}, + {"", NULL, NULL, NULL, help, -1}, + {"", menu_op, file_menu, NULL, NULL, -1}, + {"", NULL, NULL, NULL, redraw, -1}, + {"", NULL, NULL, NULL, modes_op, -1}, + {"", menu_op, search_menu, NULL, NULL, -1}, + {"", menu_op, misc_menu, NULL, NULL, -1}, + {NULL, NULL, NULL, NULL, NULL, -1} + }; + +char *help_text[22]; +char *control_keys[5]; + +char *emacs_help_text[22]; +char *emacs_control_keys[5]; + +char *command_strings[5]; +char *commands[30]; +char *init_strings[20]; + +/* + | Declarations for strings for localization + */ + +char *com_win_message; /* to be shown in com_win if no info window */ +char *no_file_string; +char *ascii_code_str; +char *printer_msg_str; +char *command_str; +char *file_write_prompt_str; +char *file_read_prompt_str; +char *char_str; +char *unkn_cmd_str; +char *non_unique_cmd_msg; +char *line_num_str; +char *line_len_str; +char *current_file_str; +char *usage0; +char *usage1; +char *usage2; +char *usage3; +char *usage4; +char *file_is_dir_msg; +char *new_file_msg; +char *cant_open_msg; +char *open_file_msg; +char *file_read_fin_msg; +char *reading_file_msg; +char *read_only_msg; +char *file_read_lines_msg; +char *save_file_name_prompt; +char *file_not_saved_msg; +char *changes_made_prompt; +char *yes_char; +char *file_exists_prompt; +char *create_file_fail_msg; +char *writing_file_msg; +char *file_written_msg; +char *searching_msg; +char *str_not_found_msg; +char *search_prompt_str; +char *exec_err_msg; +char *continue_msg; +char *menu_cancel_msg; +char *menu_size_err_msg; +char *press_any_key_msg; +char *shell_prompt; +char *formatting_msg; +char *shell_echo_msg; +char *spell_in_prog_msg; +char *margin_prompt; +char *restricted_msg; +char *ON; +char *OFF; +char *HELP; +char *WRITE; +char *READ; +char *LINE; +char *FILE_str; +char *CHARACTER; +char *REDRAW; +char *RESEQUENCE; +char *AUTHOR; +char *VERSION; +char *CASE; +char *NOCASE; +char *EXPAND; +char *NOEXPAND; +char *Exit_string; +char *QUIT_string; +char *INFO; +char *NOINFO; +char *MARGINS; +char *NOMARGINS; +char *AUTOFORMAT; +char *NOAUTOFORMAT; +char *Echo; +char *PRINTCOMMAND; +char *RIGHTMARGIN; +char *HIGHLIGHT; +char *NOHIGHLIGHT; +char *EIGHTBIT; +char *NOEIGHTBIT; +char *EMACS_string; +char *NOEMACS_string; + +#ifndef __STDC__ +#ifndef HAS_STDLIB +extern char *malloc(); +extern char *realloc(); +extern char *getenv(); +FILE *fopen(); /* declaration for open function */ +#endif /* HAS_STDLIB */ +#endif /* __STDC__ */ + +int +main(argc, argv) /* beginning of main program */ +int argc; +char *argv[]; +{ + int counter; + + for (counter = 1; counter < 24; counter++) + signal(counter, SIG_IGN); + + signal(SIGCHLD, SIG_DFL); + signal(SIGSEGV, SIG_DFL); + signal(SIGINT, edit_abort); + + d_char = 0; + d_word = malloc(150); + *d_word = (char) NULL; + d_line = NULL; + dlt_line = txtalloc(); + dlt_line->line = d_line; + curr_line = first_line = txtalloc(); + curr_line->line = point = malloc(10); + curr_line->line_length = 1; + curr_line->max_length = 10; + curr_line->prev_line = NULL; + curr_line->next_line = NULL; + curr_line->line_number = 1; + srch_str = NULL; + u_srch_str = NULL; + position = 1; + scr_pos =0; + scr_vert = 0; + scr_horz = 0; + bit_bucket = fopen("/dev/null", "w"); + edit = TRUE; + gold = case_sen = FALSE; + shell_fork = TRUE; + strings_init(); + ee_init(); + if (argc > 0 ) + get_options(argc, argv); + set_up_term(); + if (right_margin == 0) + right_margin = COLS - 1; + if (top_of_stack == NULL) + { + wprintw(com_win, no_file_string); + wrefresh(com_win); + } + else + check_fp(); + + clear_com_win = TRUE; + + while(edit) + { + wrefresh(text_win); + in = wgetch(text_win); + if (in == -1) + exit(0); + + resize_check(); + + if (clear_com_win) + { + clear_com_win = FALSE; + wmove(com_win, 0, 0); + werase(com_win); + if (!info_window) + { + wprintw(com_win, "%s", com_win_message); + } + wrefresh(com_win); + } + + if (in > 255) + function_key(); + else if ((in == '\10') || (in == 127)) + delete(TRUE); + else if ((in > 31) || (in == 9)) + insert(in); + else if ((in >= 0) && (in <= 31)) + { + if (emacs_keys_mode) + emacs_control(); + else + control(); + } + } + return(0); +} + +char * +resiz_line(factor, rline, rpos) /* resize the line to length + factor*/ +int factor; /* resize factor */ +struct text *rline; /* position in line */ +int rpos; +{ + char *rpoint; + int resiz_var; + + rline->max_length += factor; + rpoint = rline->line = realloc(rline->line, rline->max_length ); + for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++) + rpoint++; + return(rpoint); +} + +void +insert(character) /* insert character into line */ +int character; /* new character */ +{ + int counter; + int value; + char *temp; /* temporary pointer */ + char *temp2; /* temporary pointer */ + + if ((character == '\011') && (expand_tabs)) + { + counter = len_char('\011', scr_horz); + for (; counter > 0; counter--) + insert(' '); + if (auto_format) + Auto_Format(); + return; + } + text_changes = TRUE; + if ((curr_line->max_length - curr_line->line_length) < 5) + point = resiz_line(10, curr_line, position); + curr_line->line_length++; + temp = point; + counter = position; + while (counter < curr_line->line_length) /* find end of line */ + { + counter++; + temp++; + } + temp++; /* increase length of line by one */ + while (point < temp) + { + temp2=temp - 1; + *temp= *temp2; /* shift characters over by one */ + temp--; + } + *point = character; /* insert new character */ + wclrtoeol(text_win); + if (((character >= 0) && (character < ' ')) || (character >= 127)) /* check for TAB character*/ + { + scr_pos = scr_horz += out_char(text_win, character, scr_horz); + point++; + position++; + } + else + { + waddch(text_win, character); + scr_pos = ++scr_horz; + point++; + position ++; + } + + if ((observ_margins) && (right_margin < scr_pos)) + { + counter = position; + while (scr_pos > right_margin) + prev_word(); + if (scr_pos == 0) + { + while (position < counter) + right(TRUE); + } + else + { + counter -= position; + insert_line(TRUE); + for (value = 0; value < counter; value++) + right(TRUE); + } + } + + if ((scr_horz - horiz_offset) > last_col) + { + horiz_offset += 8; + midscreen(scr_vert, point); + } + + if ((auto_format) && (character == ' ') && (!formatted)) + Auto_Format(); + else if ((character != ' ') && (character != '\t')) + formatted = FALSE; + + draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); +} + +void +delete(disp) /* delete character */ +int disp; +{ + char *tp; + char *temp2; + struct text *temp_buff; + int temp_vert; + int temp_pos; + + if (point != curr_line->line) /* if not at beginning of line */ + { + text_changes = TRUE; + temp2 = tp = point; + tp--; + point--; + if ((*tp >= '\000') && (*tp < ' ')) /* check for TAB */ + scanline(tp); + else + --scr_horz; + scr_pos = scr_horz; + if (in == 8) + d_char = *point; /* save deleted character */ + temp_pos = --position; + curr_line->line_length--; + while (temp_pos <= curr_line->line_length) + { + temp_pos++; + *tp= *temp2; + tp++; + temp2++; + } + if (scr_horz < horiz_offset) + { + horiz_offset -= 8; + midscreen(scr_vert, point); + } + } + else if (curr_line->prev_line != NULL) + { + text_changes = TRUE; + left(disp); /* go to previous line */ + temp_buff = curr_line->next_line; + point = resiz_line(temp_buff->line_length, curr_line, position); + if (temp_buff->next_line != NULL) + temp_buff->next_line->prev_line = curr_line; + curr_line->next_line = temp_buff->next_line; + temp2 = temp_buff->line; + if (in == 8) + d_char = '\n'; + tp = point; + temp_pos = 1; + while (temp_pos < temp_buff->line_length) + { + curr_line->line_length++; + temp_pos++; + *tp = *temp2; + tp++; + temp2++; + } + *tp = (char) NULL; + free(temp_buff->line); + free(temp_buff); + temp_buff = curr_line; + temp_vert = scr_vert; + scr_pos = scr_horz; + if (scr_vert < last_line) + { + wmove(text_win, scr_vert + 1, 0); + wdeleteln(text_win); + } + while ((temp_buff != NULL) && (temp_vert < last_line)) + { + temp_buff = temp_buff->next_line; + temp_vert++; + } + if ((temp_vert == last_line) && (temp_buff != NULL)) + { + tp = temp_buff->line; + wmove(text_win, last_line,0); + wclrtobot(text_win); + draw_line(last_line, 0, tp, 1, temp_buff->line_length); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + } + } + draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); + formatted = FALSE; +} + +void +scanline(pos) /* find the proper horizontal position for the pointer */ +char *pos; +{ + int temp; + char *ptr; + + ptr = curr_line->line; + temp = 0; + while (ptr < pos) + { + if ((*ptr >= 0) && (*ptr <= 8)) + temp += 2; + else if (*ptr == 9) + temp += tabshift(temp); + else if ((*ptr >= 10) && (*ptr <= 31)) + temp += 2; + else if ((*ptr >= 32) && (*ptr < 127)) + temp++; + else if (*ptr == 127) + temp += 2; + else if (!eightbit) + temp += 5; + else + temp++; + ptr++; + } + scr_horz = temp; + if ((scr_horz - horiz_offset) > last_col) + { + horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8); + midscreen(scr_vert, point); + } + else if (scr_horz < horiz_offset) + { + horiz_offset = max(0, (scr_horz - (scr_horz % 8))); + midscreen(scr_vert, point); + } +} + +int +tabshift(temp_int) /* give the number of spaces to shift */ +int temp_int; +{ + int leftover; + + leftover = ((temp_int + 1) % 8); + if (leftover == 0) + return (1); + else + return (9 - leftover); +} + +int +out_char(window, character, column) /* output non-printing character */ +WINDOW *window; +char character; +int column; +{ + int i1, i2; + char *string; + char string2[8]; + + if (character == TAB) + { + i1 = tabshift(column); + for (i2 = 0; + (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++) + { + waddch(window, ' '); + } + return(i1); + } + else if ((character >= '\0') && (character < ' ')) + { + string = table[(int) character]; + } + else if ((character < 0) || (character >= 127)) + { + if (character == 127) + string = "^?"; + else if (!eightbit) + { + sprintf(string2, "<%d>", (character < 0) ? (character + 256) : character); + string = string2; + } + else + { + waddch(window, character & 0xFF); + return(1); + } + } + else + { + waddch(window, character); + return(1); + } + for (i2 = 0; (string[i2] != (char) NULL) && (((column+i2+1)-horiz_offset) < last_col); i2++) + waddch(window, string[i2]); + return(strlen(string)); +} + +int +len_char(character, column) /* return the length of the character */ +char character; +int column; /* the column must be known to provide spacing for tabs */ +{ + int length; + + if (character == '\t') + length = tabshift(column); + else if ((character >= 0) && (character < 32)) + length = 2; + else if ((character >= 32) && (character <= 126)) + length = 1; + else if (character == 127) + length = 2; + else if (((character > 126) || (character < 0)) && (!eightbit)) + length = 5; + else + length = 1; + + return(length); +} + +void +draw_line(vertical, horiz, ptr, t_pos, length) /* redraw line from current position */ +int vertical; /* current vertical position on screen */ +int horiz; /* current horizontal position on screen */ +char *ptr; /* pointer to line */ +int t_pos; /* current position (offset in bytes) from bol */ +int length; /* length (in bytes) of line */ +{ + int d; /* partial length of special or tab char to display */ + char *temp; /* temporary pointer to position in line */ + int abs_column; /* offset in screen units from begin of line */ + int column; /* horizontal position on screen */ + int row; /* vertical position on screen */ + int posit; /* temporary position indicator within line */ + + abs_column = horiz; + column = horiz - horiz_offset; + row = vertical; + temp = ptr; + d = 0; + posit = t_pos; + if (column < 0) + { + wmove(text_win, row, 0); + wclrtoeol(text_win); + } + while (column < 0) + { + d = len_char(*temp, abs_column); + abs_column += d; + column += d; + posit++; + temp++; + } + wmove(text_win, row, column); + wclrtoeol(text_win); + while ((posit < length) && (column <= last_col)) + { + if ((*temp < 32) || (*temp == 127)) + { + column += len_char(*temp, abs_column); + abs_column += out_char(text_win, *temp, abs_column); + } + else + { + abs_column++; + column++; + waddch(text_win, *temp); + } + posit++; + temp++; + } + if (column < last_col) + wclrtoeol(text_win); + wmove(text_win, vertical, (horiz - horiz_offset)); +} + +void +insert_line(disp) /* insert new line */ +int disp; +{ + int temp_pos; + int temp_pos2; + char *temp; + char *extra; + struct text *temp_nod; + + text_changes = TRUE; + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + wclrtoeol(text_win); + temp_nod= txtalloc(); + temp_nod->line = extra= malloc(10); + temp_nod->line_length = 1; + temp_nod->max_length = 10; + temp_nod->line_number = curr_line->line_number + 1; + temp_nod->next_line = curr_line->next_line; + if (temp_nod->next_line != NULL) + temp_nod->next_line->prev_line = temp_nod; + temp_nod->prev_line = curr_line; + curr_line->next_line = temp_nod; + temp_pos2 = position; + temp = point; + if (temp_pos2 < curr_line->line_length) + { + temp_pos = 1; + while (temp_pos2 < curr_line->line_length) + { + if ((temp_nod->max_length - temp_nod->line_length)< 5) + extra = resiz_line(10, temp_nod, temp_pos); + temp_nod->line_length++; + temp_pos++; + temp_pos2++; + *extra= *temp; + extra++; + temp++; + } + temp=point; + *temp = (char) NULL; + temp = resiz_line((1 - temp_nod->line_length), curr_line, position); + curr_line->line_length = 1 + temp - curr_line->line; + } + curr_line->line_length = position; + curr_line = temp_nod; + *extra = (char) NULL; + position = 1; + point= curr_line->line; + if (disp) + { + if (scr_vert < last_line) + { + scr_vert++; + wclrtoeol(text_win); + wmove(text_win, scr_vert, 0); + winsertln(text_win); + } + else + { + wmove(text_win, 0,0); + wdeleteln(text_win); + wmove(text_win, last_line,0); + wclrtobot(text_win); + } + scr_pos = scr_horz = 0; + if (horiz_offset) + { + horiz_offset = 0; + midscreen(scr_vert, point); + } + draw_line(scr_vert, scr_horz, point, position, + curr_line->line_length); + } +} + +struct text *txtalloc() /* allocate space for line structure */ +{ + return((struct text *) malloc(sizeof( struct text))); +} + +struct files *name_alloc() /* allocate space for file name list node */ +{ + return((struct files *) malloc(sizeof( struct files))); +} + +char *next_word(string) /* move to next word in string */ +char *string; +{ + while ((*string != (char) NULL) && ((*string != 32) && (*string != 9))) + string++; + while ((*string != (char) NULL) && ((*string == 32) || (*string == 9))) + string++; + return(string); +} + +void +prev_word() /* move to start of previous word in text */ +{ + if (position != 1) + { + if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t'))) + { /* if at the start of a word */ + while ((position != 1) && ((*point != ' ') && (*point != '\t'))) + left(TRUE); + } + while ((position != 1) && ((*point == ' ') || (*point == '\t'))) + left(TRUE); + while ((position != 1) && ((*point != ' ') && (*point != '\t'))) + left(TRUE); + if ((position != 1) && ((*point == ' ') || (*point == '\t'))) + right(TRUE); + } + else + left(TRUE); +} + +void +control() /* use control for commands */ +{ + char *string; + + if (in == 1) /* control a */ + { + string = get_string(ascii_code_str, TRUE); + if (*string != (char) NULL) + { + in = atoi(string); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + insert(in); + } + free(string); + } + else if (in == 2) /* control b */ + bottom(); + else if (in == 3) /* control c */ + { + command_prompt(); + } + else if (in == 4) /* control d */ + down(); + else if (in == 5) /* control e */ + search_prompt(); + else if (in == 6) /* control f */ + undel_char(); + else if (in == 7) /* control g */ + bol(); + else if (in == 8) /* control h */ + delete(TRUE); + else if (in == 9) /* control i */ + ; + else if (in == 10) /* control j */ + insert_line(TRUE); + else if (in == 11) /* control k */ + del_char(); + else if (in == 12) /* control l */ + left(TRUE); + else if (in == 13) /* control m */ + insert_line(TRUE); + else if (in == 14) /* control n */ + move_rel("d", max(5, (last_line - 5))); + else if (in == 15) /* control o */ + eol(); + else if (in == 16) /* control p */ + move_rel("u", max(5, (last_line - 5))); + else if (in == 17) /* control q */ + ; + else if (in == 18) /* control r */ + right(TRUE); + else if (in == 19) /* control s */ + ; + else if (in == 20) /* control t */ + top(); + else if (in == 21) /* control u */ + up(); + else if (in == 22) /* control v */ + undel_word(); + else if (in == 23) /* control w */ + del_word(); + else if (in == 24) /* control x */ + search(TRUE); + else if (in == 25) /* control y */ + del_line(); + else if (in == 26) /* control z */ + undel_line(); + else if (in == 27) /* control [ (escape) */ + { + menu_op(main_menu); + } +} + +/* + | Emacs control-key bindings + */ + +void +emacs_control() +{ + char *string; + + if (in == 1) /* control a */ + bol(); + else if (in == 2) /* control b */ + left(TRUE); + else if (in == 3) /* control c */ + { + command_prompt(); + } + else if (in == 4) /* control d */ + del_char(); + else if (in == 5) /* control e */ + eol(); + else if (in == 6) /* control f */ + right(TRUE); + else if (in == 7) /* control g */ + move_rel("u", max(5, (last_line - 5))); + else if (in == 8) /* control h */ + delete(TRUE); + else if (in == 9) /* control i */ + ; + else if (in == 10) /* control j */ + undel_char(); + else if (in == 11) /* control k */ + del_line(); + else if (in == 12) /* control l */ + undel_line(); + else if (in == 13) /* control m */ + insert_line(TRUE); + else if (in == 14) /* control n */ + down(); + else if (in == 15) /* control o */ + { + string = get_string(ascii_code_str, TRUE); + if (*string != (char) NULL) + { + in = atoi(string); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + insert(in); + } + free(string); + } + else if (in == 16) /* control p */ + up(); + else if (in == 17) /* control q */ + ; + else if (in == 18) /* control r */ + undel_word(); + else if (in == 19) /* control s */ + ; + else if (in == 20) /* control t */ + top(); + else if (in == 21) /* control u */ + bottom(); + else if (in == 22) /* control v */ + move_rel("d", max(5, (last_line - 5))); + else if (in == 23) /* control w */ + del_word(); + else if (in == 24) /* control x */ + search(TRUE); + else if (in == 25) /* control y */ + search_prompt(); + else if (in == 26) /* control z */ + adv_word(); + else if (in == 27) /* control [ (escape) */ + { + menu_op(main_menu); + } +} + +void +bottom() /* go to bottom of file */ +{ + while (curr_line->next_line != NULL) + curr_line = curr_line->next_line; + point = curr_line->line; + if (horiz_offset) + horiz_offset = 0; + position = 1; + midscreen(last_line, point); + scr_pos = scr_horz; +} + +void +top() /* go to top of file */ +{ + while (curr_line->prev_line != NULL) + curr_line = curr_line->prev_line; + point = curr_line->line; + if (horiz_offset) + horiz_offset = 0; + position = 1; + midscreen(0, point); + scr_pos = scr_horz; +} + +void +nextline() /* move pointers to start of next line */ +{ + curr_line = curr_line->next_line; + point = curr_line->line; + position = 1; + if (scr_vert == last_line) + { + wmove(text_win, 0,0); + wdeleteln(text_win); + wmove(text_win, last_line,0); + wclrtobot(text_win); + draw_line(last_line,0,point,1,curr_line->line_length); + } + else + scr_vert++; +} + +void +prevline() /* move pointers to start of previous line*/ +{ + curr_line = curr_line->prev_line; + point = curr_line->line; + position = 1; + if (scr_vert == 0) + { + winsertln(text_win); + draw_line(0,0,point,1,curr_line->line_length); + } + else + scr_vert--; + while (position < curr_line->line_length) + { + position++; + point++; + } +} + +void +left(disp) /* move left one character */ +int disp; +{ + if (point != curr_line->line) /* if not at begin of line */ + { + point--; + position--; + scanline(point); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + scr_pos = scr_horz; + } + else if (curr_line->prev_line != NULL) + { + if (!disp) + { + curr_line = curr_line->prev_line; + point = curr_line->line + curr_line->line_length; + position = curr_line->line_length; + return; + } + position = 1; + prevline(); + scanline(point); + scr_pos = scr_horz; + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + } +} + +void +right(disp) /* move right one character */ +int disp; +{ + if (position < curr_line->line_length) + { + point++; + position++; + scanline(point); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + scr_pos = scr_horz; + } + else if (curr_line->next_line != NULL) + { + if (!disp) + { + curr_line = curr_line->next_line; + point = curr_line->line; + position = 1; + return; + } + nextline(); + scr_pos = scr_horz = 0; + if (horiz_offset) + { + horiz_offset = 0; + midscreen(scr_vert, point); + } + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + position = 1; + } +} + +void +find_pos() /* move to the same column as on other line */ +{ + scr_horz = 0; + position = 1; + while ((scr_horz < scr_pos) && (position < curr_line->line_length)) + { + if (*point == 9) + scr_horz += tabshift(scr_horz); + else if ((*point >= '\0') && (*point < ' ')) + scr_horz += 2; + else + scr_horz++; + position++; + point++; + } + if ((scr_horz - horiz_offset) > last_col) + { + horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8); + midscreen(scr_vert, point); + } + else if (scr_horz < horiz_offset) + { + horiz_offset = max(0, (scr_horz - (scr_horz % 8))); + midscreen(scr_vert, point); + } + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); +} + +void +up() /* move up one line */ +{ + if (curr_line->prev_line != NULL) + { + prevline(); + point = curr_line->line; + find_pos(); + } +} + +void +down() /* move down one line */ +{ + if (curr_line->next_line != NULL) + { + nextline(); + find_pos(); + } +} + +void +function_key() /* process function key */ +{ + if (in == KEY_LEFT) + left(TRUE); + else if (in == KEY_RIGHT) + right(TRUE); + else if ( in == KEY_HOME) + top(); + else if ( in == KEY_UP) + up(); + else if (in == KEY_DOWN) + down(); + else if (in == KEY_NPAGE) + move_rel("d", max( 5, (last_line - 5))); + else if (in == KEY_PPAGE) + move_rel("u", max(5, (last_line - 5))); + else if (in == KEY_DL) + del_line(); + else if (in == KEY_DC) + del_char(); + else if (in == KEY_BACKSPACE) + delete(TRUE); + else if (in == KEY_IL) + { /* insert a line before current line */ + insert_line(TRUE); + left(TRUE); + } + else if (in == KEY_F(1)) + gold = !gold; + else if (in == KEY_F(2)) + { + if (gold) + { + gold = FALSE; + undel_line(); + } + else + undel_char(); + } + else if (in == KEY_F(3)) + { + if (gold) + { + gold = FALSE; + undel_word(); + } + else + del_word(); + } + else if (in == KEY_F(4)) + { + if (gold) + { + gold = FALSE; + paint_info_win(); + midscreen(scr_vert, point); + } + else + adv_word(); + } + else if (in == KEY_F(5)) + { + if (gold) + { + gold = FALSE; + search_prompt(); + } + else + search(TRUE); + } + else if (in == KEY_F(6)) + { + if (gold) + { + gold = FALSE; + bottom(); + } + else + top(); + } + else if (in == KEY_F(7)) + { + if (gold) + { + gold = FALSE; + eol(); + } + else + bol(); + } + else if (in == KEY_F(8)) + { + if (gold) + { + gold = FALSE; + command_prompt(); + } + else + adv_line(); + } +} + +void +print_buffer() +{ + char buffer[256]; + + sprintf(buffer, ">!%s", print_command); + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, printer_msg_str, print_command); + wrefresh(com_win); + command(buffer); +} + +void +command_prompt() +{ + char *cmd_str; + int result; + + info_type = COMMANDS; + paint_info_win(); + cmd_str = get_string(command_str, TRUE); + if ((result = unique_test(cmd_str, commands)) != 1) + { + werase(com_win); + wmove(com_win, 0, 0); + if (result == 0) + wprintw(com_win, unkn_cmd_str, cmd_str); + else + wprintw(com_win, non_unique_cmd_msg); + + wrefresh(com_win); + + info_type = CONTROL_KEYS; + paint_info_win(); + + if (cmd_str != NULL) + free(cmd_str); + return; + } + command(cmd_str); + wrefresh(com_win); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + info_type = CONTROL_KEYS; + paint_info_win(); + if (cmd_str != NULL) + free(cmd_str); +} + +void +command(cmd_str1) /* process commands from keyboard */ +char *cmd_str1; +{ + char *cmd_str2 = NULL; + char *cmd_str = cmd_str1; + + clear_com_win = TRUE; + if (compare(cmd_str, HELP, FALSE)) + help(); + else if (compare(cmd_str, WRITE, FALSE)) + { + if (restrict_mode()) + { + return; + } + cmd_str = next_word(cmd_str); + if (*cmd_str == (char) NULL) + { + cmd_str = cmd_str2 = get_string(file_write_prompt_str, TRUE); + } + tmp_file = resolve_name(cmd_str); + write_file(tmp_file); + if (tmp_file != cmd_str) + free(tmp_file); + } + else if (compare(cmd_str, READ, FALSE)) + { + if (restrict_mode()) + { + return; + } + cmd_str = next_word(cmd_str); + if (*cmd_str == (char) NULL) + { + cmd_str = cmd_str2 = get_string(file_read_prompt_str, TRUE); + } + tmp_file = cmd_str; + recv_file = TRUE; + tmp_file = resolve_name(cmd_str); + check_fp(); + if (tmp_file != cmd_str) + free(tmp_file); + } + else if (compare(cmd_str, LINE, FALSE)) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, line_num_str, curr_line->line_number); + wprintw(com_win, line_len_str, curr_line->line_length); + } + else if (compare(cmd_str, FILE_str, FALSE)) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + if (in_file_name == NULL) + wprintw(com_win, no_file_string); + else + wprintw(com_win, current_file_str, in_file_name); + } + else if ((*cmd_str >= '0') && (*cmd_str <= '9')) + goto_line(cmd_str); + else if (compare(cmd_str, CHARACTER, FALSE)) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + if (*point >= '\0') + wprintw(com_win, char_str, *point); + else + wprintw(com_win, char_str, (*point + 256)); + } + else if (compare(cmd_str, REDRAW, FALSE)) + redraw(); + else if (compare(cmd_str, RESEQUENCE, FALSE)) + { + tmp_line = first_line->next_line; + while (tmp_line != NULL) + { + tmp_line->line_number = tmp_line->prev_line->line_number + 1; + tmp_line = tmp_line->next_line; + } + } + else if (compare(cmd_str, AUTHOR, FALSE)) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, "written by Hugh Mahon"); + } + else if (compare(cmd_str, VERSION, FALSE)) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, "%s", version); + } + else if (compare(cmd_str, CASE, FALSE)) + case_sen = TRUE; + else if (compare(cmd_str, NOCASE, FALSE)) + case_sen = FALSE; + else if (compare(cmd_str, EXPAND, FALSE)) + expand_tabs = TRUE; + else if (compare(cmd_str, NOEXPAND, FALSE)) + expand_tabs = FALSE; + else if (compare(cmd_str, Exit_string, FALSE)) + finish(); + else if (compare(cmd_str, QUIT_string, FALSE)) + quit(0); + else if (*cmd_str == '!') + { + cmd_str++; + if ((*cmd_str == ' ') || (*cmd_str == 9)) + cmd_str = next_word(cmd_str); + sh_command(cmd_str); + } + else if ((*cmd_str == '<') && (!in_pipe)) + { + in_pipe = TRUE; + shell_fork = FALSE; + cmd_str++; + if ((*cmd_str == ' ') || (*cmd_str == '\t')) + cmd_str = next_word(cmd_str); + command(cmd_str); + in_pipe = FALSE; + shell_fork = TRUE; + } + else if ((*cmd_str == '>') && (!out_pipe)) + { + out_pipe = TRUE; + cmd_str++; + if ((*cmd_str == ' ') || (*cmd_str == '\t')) + cmd_str = next_word(cmd_str); + command(cmd_str); + out_pipe = FALSE; + } + else + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, unkn_cmd_str, cmd_str); + } + if (cmd_str2 != NULL) + free(cmd_str2); +} + +int +scan(line, offset, column) /* determine horizontal position for get_string */ +char *line; +int offset; +int column; +{ + char *stemp; + int i; + int j; + + stemp = line; + i = 0; + j = column; + while (i < offset) + { + i++; + j += len_char(*stemp, j); + stemp++; + } + return(j); +} + +char * +get_string(prompt, advance) /* read string from input on command line */ +char *prompt; /* string containing user prompt message */ +int advance; /* if true, skip leading spaces and tabs */ +{ + char *string; + char *tmp_string; + char *nam_str; + char *g_point; + int tmp_int; + int g_horz, g_position, g_pos; + int esc_flag; + + g_point = tmp_string = malloc(512); + wmove(com_win,0,0); + wclrtoeol(com_win); + waddstr(com_win, prompt); + wrefresh(com_win); + nam_str = tmp_string; + clear_com_win = TRUE; + g_horz = g_position = scan(prompt, strlen(prompt), 0); + g_pos = 0; + keypad(com_win, FALSE); + do + { + esc_flag = FALSE; + in = wgetch(com_win); + if (in == -1) + exit(0); + if (((in == 8) || (in == 127)) && (g_pos > 0)) + { + tmp_int = g_horz; + g_pos--; + g_horz = scan(g_point, g_pos, g_position); + tmp_int = tmp_int - g_horz; + for (; 0 < tmp_int; tmp_int--) + { + if ((g_horz+tmp_int) < (last_col - 1)) + { + waddch(com_win, '\010'); + waddch(com_win, ' '); + waddch(com_win, '\010'); + } + } + nam_str--; + } + else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r')) + { + if (in == '\026') /* control-v, accept next character verbatim */ + { /* allows entry of ^m, ^j, and ^h */ + esc_flag = TRUE; + in = wgetch(com_win); + if (in == -1) + exit(0); + } + *nam_str = in; + g_pos++; + if (((in < ' ') || (in > 126)) && (g_horz < (last_col - 1))) + g_horz += out_char(com_win, in, g_horz); + else + { + g_horz++; + if (g_horz < (last_col - 1)) + waddch(com_win, in); + } + nam_str++; + } + wrefresh(com_win); + if (esc_flag) + in = (char) NULL; + } while ((in != '\n') && (in != '\r')); + keypad(com_win, TRUE); + *nam_str = (char) NULL; + nam_str = tmp_string; + if (((*nam_str == ' ') || (*nam_str == 9)) && (advance)) + nam_str = next_word(nam_str); + string = malloc(strlen(nam_str) + 1); + strcpy(string, nam_str); + free(tmp_string); + wrefresh(com_win); + return(string); +} + +int +compare(string1, string2, sensitive) /* compare two strings */ +char *string1; +char *string2; +int sensitive; +{ + char *strng1; + char *strng2; + int tmp; + int equal; + + strng1 = string1; + strng2 = string2; + tmp = 0; + if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == (char) NULL) || (*strng2 == (char) NULL)) + return(FALSE); + equal = TRUE; + while (equal) + { + if (sensitive) + { + if (*strng1 != *strng2) + equal = FALSE; + } + else + { + if (toupper(*strng1) != toupper(*strng2)) + equal = FALSE; + } + strng1++; + strng2++; + if ((*strng1 == (char) NULL) || (*strng2 == (char) NULL) || (*strng1 == ' ') || (*strng2 == ' ')) + break; + tmp++; + } + return(equal); +} + +void +goto_line(cmd_str) +char *cmd_str; +{ + int number; + int i; + char *ptr; + char *direction; + struct text *t_line; + + ptr = cmd_str; + i= 0; + while ((*ptr >='0') && (*ptr <= '9')) + { + i= i * 10 + (*ptr - '0'); + ptr++; + } + number = i; + i = 0; + t_line = curr_line; + while ((t_line->line_number > number) && (t_line->prev_line != NULL)) + { + i++; + t_line = t_line->prev_line; + direction = "u"; + } + while ((t_line->line_number < number) && (t_line->next_line != NULL)) + { + i++; + direction = "d"; + t_line = t_line->next_line; + } + if ((i < 30) && (i > 0)) + { + move_rel(direction, i); + } + else + { + curr_line = t_line; + point = curr_line->line; + position = 1; + midscreen((last_line / 2), point); + scr_pos = scr_horz; + } + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, line_num_str, curr_line->line_number); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); +} + +void +midscreen(line, pnt) /* put current line in middle of screen */ +int line; +char *pnt; +{ + struct text *mid_line; + int i; + + line = min(line, last_line); + mid_line = curr_line; + for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++) + curr_line = curr_line->prev_line; + scr_vert = scr_horz = 0; + wmove(text_win, 0, 0); + draw_screen(); + scr_vert = i; + curr_line = mid_line; + scanline(pnt); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); +} + +void +get_options(numargs, arguments) /* get arguments from command line */ +int numargs; +char *arguments[]; +{ + char *buff; + int count; + struct files *temp_names; + char *name; + char *ptr; + + /* + | see if editor was invoked as 'ree' (restricted mode) + */ + + if (!(name = strrchr(arguments[0], '/'))) + name = arguments[0]; + else + name++; + if (!strcmp(name, "ree")) + restricted = TRUE; + + top_of_stack = NULL; + input_file = FALSE; + recv_file = FALSE; + count = 1; + while (count < numargs) + { + buff = arguments[count]; + if (!strcmp("-i", buff)) + { + info_window = FALSE; + } + else if (!strcmp("-e", buff)) + { + expand_tabs = FALSE; + } + else if (!strcmp("-h", buff)) + { + nohighlight = TRUE; + } + else if (!strcmp("-?", buff)) + { + fprintf(stderr, usage0, arguments[0]); + fprintf(stderr, usage1); + fprintf(stderr, usage2); + fprintf(stderr, usage3); + fprintf(stderr, usage4); + exit(1); + } + else if (*buff == '+') + { + buff++; + start_at_line = buff; + } + + else + { + if (top_of_stack == NULL) + { + temp_names = top_of_stack = name_alloc(); + } + else + { + temp_names->next_name = name_alloc(); + temp_names = temp_names->next_name; + } + ptr = temp_names->name = malloc(strlen(buff) + 1); + while (*buff != (char) NULL) + { + *ptr = *buff; + buff++; + ptr++; + } + *ptr = (char) NULL; + temp_names->next_name = NULL; + input_file = TRUE; + recv_file = TRUE; + } + count++; + } +} + +void +check_fp() /* open or close files according to flags */ +{ + int line_num; + int temp; + struct stat buf; + + clear_com_win = TRUE; + tmp_vert = scr_vert; + tmp_horz = scr_horz; + tmp_line = curr_line; + if (input_file) + { + in_file_name = tmp_file = top_of_stack->name; + top_of_stack = top_of_stack->next_name; + } + temp = stat(tmp_file, &buf); + buf.st_mode &= ~07777; + if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0)) + { + wprintw(com_win, file_is_dir_msg, tmp_file); + wrefresh(com_win); + if (input_file) + { + quit(0); + return; + } + else + return; + } + if ((get_fd = open(tmp_file, O_RDONLY)) == -1) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + if (input_file) + wprintw(com_win, new_file_msg, tmp_file); + else + wprintw(com_win, cant_open_msg, tmp_file); + wrefresh(com_win); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + wrefresh(text_win); + recv_file = FALSE; + input_file = FALSE; + return; + } + else + get_file(tmp_file); + + recv_file = FALSE; + line_num = curr_line->line_number; + scr_vert = tmp_vert; + scr_horz = tmp_horz; + if (input_file) + curr_line= first_line; + else + curr_line = tmp_line; + point = curr_line->line; + draw_screen(); + wmove(com_win, 0, 0); + wclrtoeol(com_win); + if (input_file) + { + wprintw(com_win, open_file_msg, in_file_name, line_num); + input_file = FALSE; + if (start_at_line != NULL) + { + line_num = atoi(start_at_line) - 1; + move_rel("d", line_num); + line_num = 0; + start_at_line = NULL; + } + } + else + { + text_changes = TRUE; + if ((tmp_file != NULL) && (*tmp_file != (char) NULL)) + wprintw(com_win, file_read_fin_msg, tmp_file); + } + wrefresh(com_win); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); + wrefresh(text_win); +} + +void +get_file(file_name) /* read specified file into current buffer */ +char *file_name; +{ + int can_read; /* file has at least one character */ + int length; /* length of line read by read */ + int append; /* should text be appended to current line */ + struct text *temp_line; + + if (recv_file) /* if reading a file */ + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, reading_file_msg, file_name); + if (access(file_name, 2)) /* check permission to write */ + { + if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT)) + wprintw(com_win, read_only_msg); + } + wrefresh(com_win); + } + if (curr_line->line_length > 1) /* if current line is not blank */ + { + insert_line(FALSE); + left(FALSE); + append = FALSE; + } + else + append = TRUE; + can_read = FALSE; /* test if file has any characters */ + while (((length = read(get_fd, in_string, 512)) != 0) && (length != -1)) + { + can_read = TRUE; /* if set file has at least 1 character */ + get_line(length, in_string, &append); + } + if ((can_read) && (curr_line->line_length == 1)) + { + temp_line = curr_line->prev_line; + temp_line->next_line = curr_line->next_line; + if (temp_line->next_line != NULL) + temp_line->next_line->prev_line = temp_line; + if (curr_line->line != NULL) + free(curr_line->line); + free(curr_line); + curr_line = temp_line; + } + if (input_file) /* if this is the file to be edited display number of lines */ + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number); + wrefresh(com_win); + } + else if (can_read) /* not input_file and file is non-zero size */ + text_changes = TRUE; + + if (recv_file) /* if reading a file */ + { + in = EOF; + } +} + +void +get_line(length, in_string, append) /* read string and split into lines */ +int length; /* length of string read by read */ +char *in_string; /* string read by read */ +int *append; /* TRUE if must append more text to end of current line */ +{ + char *str1; + char *str2; + int num; /* offset from start of string */ + int char_count; /* length of new line (or added portion */ + int temp_counter; /* temporary counter value */ + struct text *tline; /* temporary pointer to new line */ + int first_time; /* if TRUE, the first time through the loop */ + + str2 = in_string; + num = 0; + first_time = TRUE; + while (num < length) + { + if (!first_time) + { + if (num < length) + { + str2++; + num++; + } + } + else + first_time = FALSE; + str1 = str2; + char_count = 1; + /* find end of line */ + while ((*str2 != '\n') && (num < length)) + { + str2++; + num++; + char_count++; + } + if (!(*append)) /* if not append to current line, insert new one */ + { + tline = txtalloc(); /* allocate data structure for next line */ + tline->line_number = curr_line->line_number + 1; + tline->next_line = curr_line->next_line; + tline->prev_line = curr_line; + curr_line->next_line = tline; + if (tline->next_line != NULL) + tline->next_line->prev_line = tline; + curr_line = tline; + curr_line->line = point = (char *) malloc(char_count); + curr_line->line_length = char_count; + curr_line->max_length = char_count; + } + else + { + point = resiz_line(char_count, curr_line, curr_line->line_length); + curr_line->line_length += (char_count - 1); + } + for (temp_counter = 1; temp_counter < char_count; temp_counter++) + { + *point = *str1; + point++; + str1++; + } + *point = (char) NULL; + *append = FALSE; + if ((num == length) && (*str2 != '\n')) + *append = TRUE; + } +} + +void +draw_screen() /* redraw the screen from current postion */ +{ + struct text *temp_line; + char *line_out; + int temp_vert; + + temp_line = curr_line; + temp_vert = scr_vert; + wclrtobot(text_win); + while ((temp_line != NULL) && (temp_vert <= last_line)) + { + line_out = temp_line->line; + draw_line(temp_vert, 0, line_out, 1, temp_line->line_length); + temp_vert++; + temp_line = temp_line->next_line; + } + wmove(text_win, temp_vert, 0); + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); +} + +void +finish() /* prepare to exit edit session */ +{ + char *file_name = in_file_name; + + /* + | changes made here should be reflected in the 'save' + | portion of file_op() + */ + + if ((file_name == NULL) || (*file_name == (char) NULL)) + file_name = get_string(save_file_name_prompt, TRUE); + + if ((file_name == NULL) || (*file_name == (char) NULL)) + { + wmove(com_win, 0, 0); + wprintw(com_win, file_not_saved_msg); + wclrtoeol(com_win); + wrefresh(com_win); + clear_com_win = TRUE; + return; + } + + tmp_file = resolve_name(file_name); + if (tmp_file != file_name) + { + free(file_name); + file_name = tmp_file; + } + + if (write_file(file_name)) + { + text_changes = FALSE; + quit(0); + } +} + +int +quit(noverify) /* exit editor */ +int noverify; +{ + char *ans; + + touchwin(text_win); + wrefresh(text_win); + if ((text_changes) && (!noverify)) + { + ans = get_string(changes_made_prompt, TRUE); + if (toupper(*ans) == toupper(*yes_char)) + text_changes = FALSE; + else + return(0); + free(ans); + } + if (top_of_stack == NULL) + { + if (info_window) + wrefresh(info_win); + wrefresh(com_win); + resetty(); + endwin(); + putchar('\n'); + exit(0); + } + else + { + delete_text(); + recv_file = TRUE; + input_file = TRUE; + check_fp(); + } + return(0); +} + +void +edit_abort(arg) +int arg; +{ + wrefresh(com_win); + resetty(); + endwin(); + putchar('\n'); + exit(1); +} + +void +delete_text() +{ + while (curr_line->next_line != NULL) + curr_line = curr_line->next_line; + while (curr_line != first_line) + { + free(curr_line->line); + curr_line = curr_line->prev_line; + free(curr_line->next_line); + } + curr_line->next_line = NULL; + *curr_line->line = (char) NULL; + curr_line->line_length = 1; + curr_line->line_number = 1; + point = curr_line->line; + scr_pos = scr_vert = scr_horz = 0; + position = 1; +} + +int +write_file(file_name) +char *file_name; +{ + char cr; + char *tmp_point; + struct text *out_line; + int lines, charac; + int temp_pos; + int write_flag = TRUE; + + charac = lines = 0; + if ((in_file_name == NULL) || strcmp(in_file_name, file_name)) + { + if ((temp_fp = fopen(file_name, "r"))) + { + tmp_point = get_string(file_exists_prompt, TRUE); + if (toupper(*tmp_point) == toupper(*yes_char)) + write_flag = TRUE; + else + write_flag = FALSE; + fclose(temp_fp); + free(tmp_point); + } + } + + clear_com_win = TRUE; + + if (write_flag) + { + if ((temp_fp = fopen(file_name, "w")) == NULL) + { + clear_com_win = TRUE; + wmove(com_win,0,0); + wclrtoeol(com_win); + wprintw(com_win, create_file_fail_msg, file_name); + wrefresh(com_win); + return(FALSE); + } + else + { + wmove(com_win,0,0); + wclrtoeol(com_win); + wprintw(com_win, writing_file_msg, file_name); + wrefresh(com_win); + cr = '\n'; + out_line = first_line; + while (out_line != NULL) + { + temp_pos = 1; + tmp_point= out_line->line; + while (temp_pos < out_line->line_length) + { + putc(*tmp_point, temp_fp); + tmp_point++; + temp_pos++; + } + charac += out_line->line_length; + out_line = out_line->next_line; + putc(cr, temp_fp); + lines++; + } + fclose(temp_fp); + wmove(com_win,0,0); + wclrtoeol(com_win); + wprintw(com_win, file_written_msg, file_name, lines, charac); + wrefresh(com_win); + return(TRUE); + } + } + else + return(FALSE); +} + +int +search(display_message) /* search for string in srch_str */ +int display_message; +{ + int lines_moved; + int iter; + int found; + + if ((srch_str == NULL) || (*srch_str == (char) NULL)) + return(FALSE); + if (display_message) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, searching_msg); + wrefresh(com_win); + clear_com_win = TRUE; + } + lines_moved = 0; + found = FALSE; + srch_line = curr_line; + srch_1 = point; + if (position < curr_line->line_length) + srch_1++; + iter = position + 1; + while ((!found) && (srch_line != NULL)) + { + while ((iter < srch_line->line_length) && (!found)) + { + srch_2 = srch_1; + if (case_sen) /* if case sensitive */ + { + srch_3 = srch_str; + while ((*srch_2 == *srch_3) && (*srch_3 != (char) NULL)) + { + found = TRUE; + srch_2++; + srch_3++; + } /* end while */ + } + else /* if not case sensitive */ + { + srch_3 = u_srch_str; + while ((toupper(*srch_2) == *srch_3) && (*srch_3 != (char) NULL)) + { + found = TRUE; + srch_2++; + srch_3++; + } + } /* end else */ + if (!((*srch_3 == (char) NULL) && (found))) + { + found = FALSE; + if (iter < srch_line->line_length) + srch_1++; + iter++; + } + } + if (!found) + { + srch_line = srch_line->next_line; + if (srch_line != NULL) + srch_1 = srch_line->line; + iter = 1; + lines_moved++; + } + } + if (found) + { + if (display_message) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wrefresh(com_win); + } + if (lines_moved == 0) + { + while (position < iter) + right(TRUE); + } + else + { + if (lines_moved < 30) + { + move_rel("d", lines_moved); + while (position < iter) + right(TRUE); + } + else + { + curr_line = srch_line; + point = srch_1; + position = iter; + scanline(point); + scr_pos = scr_horz; + midscreen((last_line / 2), point); + } + } + } + else + { + if (display_message) + { + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, str_not_found_msg, srch_str); + wrefresh(com_win); + } + wmove(text_win, scr_vert,(scr_horz - horiz_offset)); + } + return(found); +} + +void +search_prompt() /* prompt and read search string (srch_str) */ +{ + if (srch_str != NULL) + free(srch_str); + if ((u_srch_str != NULL) && (*u_srch_str != (char) NULL)) + free(u_srch_str); + srch_str = get_string(search_prompt_str, FALSE); + gold = FALSE; + srch_3 = srch_str; + srch_1 = u_srch_str = malloc(strlen(srch_str) + 1); + while (*srch_3 != (char) NULL) + { + *srch_1 = toupper(*srch_3); + srch_1++; + srch_3++; + } + *srch_1 = (char) NULL; + search(TRUE); +} + +void +del_char() /* delete current character */ +{ + in = 8; /* backspace */ + if (position < curr_line->line_length) /* if not end of line */ + { + position++; + point++; + scanline(point); + delete(TRUE); + } + else + { + right(FALSE); + delete(FALSE); + } +} + +void +undel_char() /* undelete last deleted character */ +{ + if (d_char == '\n') /* insert line if last del_char deleted eol */ + insert_line(TRUE); + else + { + in = d_char; + insert(in); + } +} + +void +del_word() /* delete word in front of cursor */ +{ + int tposit; + int difference; + char *d_word2; + char *d_word3; + char tmp_char; + + if (d_word != NULL) + free(d_word); + d_word = malloc(curr_line->line_length); + tmp_char = d_char; + d_word3 = point; + d_word2 = d_word; + tposit = position; + while ((tposit < curr_line->line_length) && + ((*d_word3 != ' ') && (*d_word3 != '\t'))) + { + tposit++; + *d_word2 = *d_word3; + d_word2++; + d_word3++; + } + while ((tposit < curr_line->line_length) && + ((*d_word3 == ' ') || (*d_word3 == '\t'))) + { + tposit++; + *d_word2 = *d_word3; + d_word2++; + d_word3++; + } + *d_word2 = (char) NULL; + d_wrd_len = difference = d_word2 - d_word; + d_word2 = point; + while (tposit < curr_line->line_length) + { + tposit++; + *d_word2 = *d_word3; + d_word2++; + d_word3++; + } + curr_line->line_length -= difference; + *d_word2 = (char) NULL; + draw_line(scr_vert, scr_horz,point,position,curr_line->line_length); + d_char = tmp_char; + text_changes = TRUE; + formatted = FALSE; +} + +void +undel_word() /* undelete last deleted word */ +{ + int temp; + int tposit; + char *tmp_old_ptr; + char *tmp_space; + char *tmp_ptr; + char *d_word_ptr; + + /* + | resize line to handle undeleted word + */ + if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5) + point = resiz_line(d_wrd_len, curr_line, position); + tmp_ptr = tmp_space = malloc(curr_line->line_length + d_wrd_len); + d_word_ptr = d_word; + temp = 1; + /* + | copy d_word contents into temp space + */ + while (temp <= d_wrd_len) + { + temp++; + *tmp_ptr = *d_word_ptr; + tmp_ptr++; + d_word_ptr++; + } + tmp_old_ptr = point; + tposit = position; + /* + | copy contents of line from curent position to eol into + | temp space + */ + while (tposit < curr_line->line_length) + { + temp++; + tposit++; + *tmp_ptr = *tmp_old_ptr; + tmp_ptr++; + tmp_old_ptr++; + } + curr_line->line_length += d_wrd_len; + tmp_old_ptr = point; + *tmp_ptr = (char) NULL; + tmp_ptr = tmp_space; + tposit = 1; + /* + | now copy contents from temp space back to original line + */ + while (tposit < temp) + { + tposit++; + *tmp_old_ptr = *tmp_ptr; + tmp_ptr++; + tmp_old_ptr++; + } + *tmp_old_ptr = (char) NULL; + free(tmp_space); + draw_line(scr_vert, scr_horz, point, position, curr_line->line_length); +} + +void +del_line() /* delete from cursor to end of line */ +{ + char *dl1; + char *dl2; + int tposit; + + if (d_line != NULL) + free(d_line); + d_line = malloc(curr_line->line_length); + dl1 = d_line; + dl2 = point; + tposit = position; + while (tposit < curr_line->line_length) + { + *dl1 = *dl2; + dl1++; + dl2++; + tposit++; + } + dlt_line->line_length = 1 + tposit - position; + *dl1 = (char) NULL; + *point = (char) NULL; + curr_line->line_length = position; + wclrtoeol(text_win); + if (curr_line->next_line != NULL) + { + right(FALSE); + delete(FALSE); + } + text_changes = TRUE; +} + +void +undel_line() /* undelete last deleted line */ +{ + char *ud1; + char *ud2; + int tposit; + + insert_line(TRUE); + left(TRUE); + point = resiz_line(dlt_line->line_length, curr_line, position); + curr_line->line_length += dlt_line->line_length - 1; + ud1 = point; + ud2 = d_line; + tposit = 1; + while (tposit < dlt_line->line_length) + { + tposit++; + *ud1 = *ud2; + ud1++; + ud2++; + } + *ud1 = (char) NULL; + draw_line(scr_vert, scr_horz,point,position,curr_line->line_length); +} + +void +adv_word() /* advance to next word */ +{ +while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9))) + right(TRUE); +while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9))) + right(TRUE); +} + +void +move_rel(direction, lines) /* move relative to current line */ +char *direction; +int lines; +{ + int i; + char *tmp; + + if (*direction == 'u') + { + scr_pos = 0; + while (position > 1) + left(TRUE); + for (i = 0; i < lines; i++) + { + up(); + } + if ((last_line > 5) && ( scr_vert < 4)) + { + tmp = point; + tmp_line = curr_line; + for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++) + { + up(); + } + scr_vert = scr_vert + i; + curr_line = tmp_line; + point = tmp; + scanline(point); + } + } + else + { + if ((position != 1) && (curr_line->next_line != NULL)) + { + nextline(); + scr_pos = scr_horz = 0; + if (horiz_offset) + { + horiz_offset = 0; + midscreen(scr_vert, point); + } + } + else + adv_line(); + for (i = 1; i < lines; i++) + { + down(); + } + if ((last_line > 10) && (scr_vert > (last_line - 5))) + { + tmp = point; + tmp_line = curr_line; + for (i=0; (i<5) && (curr_line->next_line != NULL); i++) + { + down(); + } + scr_vert = scr_vert - i; + curr_line = tmp_line; + point = tmp; + scanline(point); + } + } + wmove(text_win, scr_vert, (scr_horz - horiz_offset)); +} + +void +eol() /* go to end of line */ +{ + if (position < curr_line->line_length) + { + while (position < curr_line->line_length) + right(TRUE); + } + else if (curr_line->next_line != NULL) + { + right(TRUE); + while (position < curr_line->line_length) + right(TRUE); + } +} + +void +bol() /* move to beginning of line */ +{ + if (point != curr_line->line) + { + while (point != curr_line->line) + left(TRUE); + } + else if (curr_line->prev_line != NULL) + { + scr_pos = 0; + up(); + } +} + +void +adv_line() /* advance to beginning of next line */ +{ + if ((point != curr_line->line) || (scr_pos > 0)) + { + while (position < curr_line->line_length) + right(TRUE); + right(TRUE); + } + else if (curr_line->next_line != NULL) + { + scr_pos = 0; + down(); + } +} + +void +sh_command(string) /* execute shell command */ +char *string; /* string containing user command */ +{ + char *temp_point; + char *last_slash; + char *path; /* directory path to executable */ + int parent; /* zero if child, child's pid if parent */ + int value; + int return_val; + struct text *line_holder; + + if (restrict_mode()) + { + return; + } + + if (!(path = getenv("SHELL"))) + path = "/bin/sh"; + last_slash = temp_point = path; + while (*temp_point != (char) NULL) + { + if (*temp_point == '/') + last_slash = ++temp_point; + else + temp_point++; + } + + /* + | if in_pipe is true, then output of the shell operation will be + | read by the editor, and curses doesn't need to be turned off + */ + + if (!in_pipe) + { + keypad(com_win, FALSE); + keypad(text_win, FALSE); + echo(); + nl(); + noraw(); + resetty(); + +#ifndef NCURSE + endwin(); +#endif + } + + if (in_pipe) + { + pipe(pipe_in); /* create a pipe */ + parent = fork(); + if (!parent) /* if the child */ + { +/* + | child process which will fork and exec shell command (if shell output is + | to be read by editor) + */ + in_pipe = FALSE; +/* + | redirect stdout to pipe + */ + temp_stdout = dup(1); + close(1); + dup(pipe_in[1]); +/* + | redirect stderr to pipe + */ + temp_stderr = dup(2); + close(2); + dup(pipe_in[1]); + close(pipe_in[1]); + /* + | child will now continue down 'if (!in_pipe)' + | path below + */ + } + else /* if the parent */ + { +/* + | prepare editor to read from the pipe + */ + signal(SIGCHLD, SIG_IGN); + line_holder = curr_line; + tmp_vert = scr_vert; + close(pipe_in[1]); + get_fd = pipe_in[0]; + get_file(""); + close(pipe_in[0]); + scr_vert = tmp_vert; + scr_horz = scr_pos = 0; + position = 1; + curr_line = line_holder; + point = curr_line->line; + out_pipe = FALSE; + signal(SIGCHLD, SIG_DFL); +/* + | since flag "in_pipe" is still TRUE, the path which waits for the child + | process to die will be avoided. + | (the pipe is closed, no more output can be expected) + */ + } + } + if (!in_pipe) + { + signal(SIGINT, SIG_IGN); + if (out_pipe) + { + pipe(pipe_out); + } +/* + | fork process which will exec command + */ + parent = fork(); + if (!parent) /* if the child */ + { + if (shell_fork) + putchar('\n'); + if (out_pipe) + { +/* + | prepare the child process (soon to exec a shell command) to read from the + | pipe (which will be output from the editor's buffer) + */ + close(0); + dup(pipe_out[0]); + close(pipe_out[0]); + close(pipe_out[1]); + } + for (value = 1; value < 24; value++) + signal(value, SIG_DFL); + execl(path, last_slash, "-c", string, NULL); + printf(exec_err_msg, path); + exit(-1); + } + else /* if the parent */ + { + if (out_pipe) + { +/* + | output the contents of the buffer to the pipe (to be read by the + | process forked and exec'd above as stdin) + */ + close(pipe_out[0]); + line_holder = first_line; + while (line_holder != NULL) + { + write(pipe_out[1], line_holder->line, (line_holder->line_length-1)); + write(pipe_out[1], "\n", 1); + line_holder = line_holder->next_line; + } + close(pipe_out[1]); + out_pipe = FALSE; + } + do + { + return_val = wait((int *) 0); + } + while ((return_val != parent) && (return_val != -1)); +/* + | if this process is actually the child of the editor, exit. Here's how it + | works: + | The editor forks a process. If output must be sent to the command to be + | exec'd another process is forked, and that process (the child's child) + | will exec the command. In this case, "shell_fork" will be FALSE. If no + | output is to be performed to the shell command, "shell_fork" will be TRUE. + | If this is the editor process, shell_fork will be true, otherwise this is + | the child of the edit process. + */ + if (!shell_fork) + exit(0); + } + signal(SIGINT, edit_abort); + } + if (shell_fork) + { + printf(continue_msg); + fflush(stdout); + while ((in = getchar()) != '\n') + ; + } + + if (!in_pipe) + { + fixterm(); + noecho(); + nonl(); + raw(); + keypad(text_win, TRUE); + keypad(com_win, TRUE); + if (info_window) + clearok(info_win, TRUE); + } + + redraw(); +} + +void +set_up_term() /* set up the terminal for operating with ae */ +{ + if (!curses_initialized) + { + initscr(); + savetty(); + noecho(); + raw(); + nonl(); + curses_initialized = TRUE; + } + + if (((LINES > 15) && (COLS >= 80)) && info_window) + last_line = LINES - 8; + else + { + info_window = FALSE; + last_line = LINES - 2; + } + + idlok(stdscr, TRUE); + com_win = newwin(1, COLS, (LINES - 1), 0); + keypad(com_win, TRUE); + idlok(com_win, TRUE); + wrefresh(com_win); + if (!info_window) + text_win = newwin((LINES - 1), COLS, 0, 0); + else + text_win = newwin((LINES - 7), COLS, 6, 0); + keypad(text_win, TRUE); + idlok(text_win, TRUE); + wrefresh(text_win); + help_win = newwin((LINES - 1), COLS, 0, 0); + keypad(help_win, TRUE); + idlok(help_win, TRUE); + if (info_window) + { + info_type = CONTROL_KEYS; + info_win = newwin(6, COLS, 0, 0); + werase(info_win); + paint_info_win(); + } + + last_col = COLS - 1; + local_LINES = LINES; + local_COLS = COLS; +} + +void +resize_check() +{ + if ((LINES == local_LINES) && (COLS == local_COLS)) + return; + + if (info_window) + delwin(info_win); + delwin(text_win); + delwin(com_win); + delwin(help_win); + set_up_term(); + redraw(); + wrefresh(text_win); +} + +int +menu_op(menu_list) +struct menu_entries * menu_list; +{ + WINDOW *temp_win; + int max_width, max_height; + int x_off, y_off; + int counter; + int length; + int input; + int list_size; + int top_offset; + int temp_int; + char *cancel_string = menu_cancel_msg; + + /* + | determine number and width of menu items + */ + + list_size = 1; + while (menu_list[list_size + 1].item_string != NULL) + list_size++; + max_width = strlen(cancel_string); + for (counter = 0; counter <= list_size; counter++) + { + if ((length = strlen(menu_list[counter].item_string)) > max_width) + max_width = length; + } + max_width += 6; + + /* + | make sure that window is large enough to handle menu + | if not, print error message and return to calling function + */ + + if ((LINES < list_size) || (max_width > COLS)) + { + wmove(com_win, 0, 0); + werase(com_win); + wprintw(com_win, menu_size_err_msg); + clear_com_win = TRUE; + return(0); + } + + top_offset = 0; + max_height = list_size; + + if (LINES >= (list_size + 8)) + { + max_height = list_size + 8; + top_offset = 4; + } + x_off = (COLS - max_width) / 2; + y_off = (LINES - max_height - 1) / 2; + temp_win = newwin(max_height, max_width, y_off, x_off); + keypad(temp_win, TRUE); + werase(temp_win); + + /* + | output top and bottom portions of menu box only if window + | large enough + */ + + if (max_height > list_size) + { + wmove(temp_win, 1, 1); + if (!nohighlight) + wstandout(temp_win); + waddch(temp_win, '+'); + for (counter = 0; counter < (max_width - 4); counter++) + waddch(temp_win, '-'); + waddch(temp_win, '+'); + + wmove(temp_win, (max_height - 2), 1); + waddch(temp_win, '+'); + for (counter = 0; counter < (max_width - 4); counter++) + waddch(temp_win, '-'); + waddch(temp_win, '+'); + wstandend(temp_win); + wmove(temp_win, 2, 3); + waddstr(temp_win, menu_list[0].item_string); + wmove(temp_win, (max_height - 3), 3); + waddstr(temp_win, cancel_string); + } + if (!nohighlight) + wstandout(temp_win); + for (counter = 0; counter < (list_size + top_offset); counter++) + { + if (top_offset == 4) + { + temp_int = counter + 2; + } + else + temp_int = counter; + + wmove(temp_win, temp_int, 1); + waddch(temp_win, '|'); + wmove(temp_win, temp_int, (max_width - 2)); + waddch(temp_win, '|'); + } + wstandend(temp_win); + for (counter = 1; counter <= list_size; counter++) + { + wmove(temp_win, (top_offset + counter - 1), 3); + waddstr(temp_win, menu_list[counter].item_string); + } + counter = 1; + do + { + wmove(temp_win, (counter + top_offset - 1), 3); + wrefresh(temp_win); + input = wgetch(temp_win); + if (input == -1) + exit(0); + switch (input) + { + case ' ': /* space */ + case '\022': /* ^r, right */ + case '\004': /* ^d, down */ + case KEY_RIGHT: + case KEY_DOWN: + counter++; + if (counter > list_size) + counter = 1; + break; + case '\010': /* ^h, backspace*/ + case '\014': /* ^l, left */ + case '\025': /* ^u, up */ + case 127: /* ^?, delete */ + case KEY_LEFT: + case KEY_UP: + counter--; + if (counter == 0) + counter = list_size; + break; + case '\033': /* escape key */ + counter = 0; + break; + default: + break; + } + } + while ((input != '\r') && (input != '\n') && (input != '\033')); + + werase(temp_win); + wrefresh(temp_win); + delwin(temp_win); + + if ((menu_list[counter].procedure != NULL) || + (menu_list[counter].iprocedure != NULL) || + (menu_list[counter].nprocedure != NULL)) + { + if (menu_list[counter].argument != -1) + (*menu_list[counter].iprocedure)(menu_list[counter].argument); + else if (menu_list[counter].ptr_argument != NULL) + (*menu_list[counter].procedure)(menu_list[counter].ptr_argument); + else + (*menu_list[counter].nprocedure)(); + } + + if (info_window) + paint_info_win(); + midscreen(scr_vert, point); + + return(counter); +} + +void +help() +{ + int counter; + + werase(help_win); + clearok(help_win, TRUE); + for (counter = 0; counter < 22; counter++) + { + wmove(help_win, counter, 0); + waddstr(help_win, (emacs_keys_mode) ? + emacs_help_text[counter] : help_text[counter]); + } + wrefresh(help_win); + werase(com_win); + wmove(com_win, 0, 0); + wprintw(com_win, press_any_key_msg); + wrefresh(com_win); + counter = wgetch(com_win); + if (counter == -1) + exit(0); + werase(com_win); + wmove(com_win, 0, 0); + werase(help_win); + wrefresh(help_win); + wrefresh(com_win); + redraw(); +} + +void +paint_info_win() +{ + int counter; + + if (!info_window) + return; + + werase(info_win); + for (counter = 0; counter < 5; counter++) + { + wmove(info_win, counter, 0); + wclrtoeol(info_win); + if (info_type == CONTROL_KEYS) + waddstr(info_win, (emacs_keys_mode) ? + emacs_control_keys[counter] : control_keys[counter]); + else if (info_type == COMMANDS) + waddstr(info_win, command_strings[counter]); + } + wmove(info_win, 5, 0); + if (!nohighlight) + wstandout(info_win); + waddstr(info_win, "==============================================================================="); + wstandend(info_win); + wrefresh(info_win); +} + +void +no_info_window() +{ + if (!info_window) + return; + delwin(info_win); + delwin(text_win); + info_window = FALSE; + last_line = LINES - 2; + text_win = newwin((LINES - 1), COLS, 0, 0); + keypad(text_win, TRUE); + idlok(text_win, TRUE); + clearok(text_win, TRUE); + midscreen(scr_vert, point); + wrefresh(text_win); + clear_com_win = TRUE; +} + +void +create_info_window() +{ + if (info_window) + return; + last_line = LINES - 8; + delwin(text_win); + text_win = newwin((LINES - 7), COLS, 6, 0); + keypad(text_win, TRUE); + idlok(text_win, TRUE); + werase(text_win); + info_window = TRUE; + info_win = newwin(6, COLS, 0, 0); + werase(info_win); + info_type = CONTROL_KEYS; + midscreen(min(scr_vert, last_line), point); + clearok(info_win, TRUE); + paint_info_win(); + wrefresh(text_win); + clear_com_win = TRUE; +} + +int +file_op(arg) +int arg; +{ + char *string; + int flag; + + if (restrict_mode()) + { + return(0); + } + + if (arg == READ_FILE) + { + string = get_string(file_read_prompt_str, TRUE); + recv_file = TRUE; + tmp_file = resolve_name(string); + check_fp(); + if (tmp_file != string) + free(tmp_file); + free(string); + } + else if (arg == WRITE_FILE) + { + string = get_string(file_write_prompt_str, TRUE); + tmp_file = resolve_name(string); + write_file(tmp_file); + if (tmp_file != string) + free(tmp_file); + free(string); + } + else if (arg == SAVE_FILE) + { + /* + | changes made here should be reflected in finish() + */ + + if (in_file_name) + flag = TRUE; + else + flag = FALSE; + + string = in_file_name; + if ((string == NULL) || (*string == (char) NULL)) + string = get_string(save_file_name_prompt, TRUE); + if ((string == NULL) || (*string == (char) NULL)) + { + wmove(com_win, 0, 0); + wprintw(com_win, file_not_saved_msg); + wclrtoeol(com_win); + wrefresh(com_win); + clear_com_win = TRUE; + return(0); + } + if (!flag) + { + tmp_file = resolve_name(string); + if (tmp_file != string) + { + free(string); + string = tmp_file; + } + } + if (write_file(string)) + { + in_file_name = string; + text_changes = FALSE; + } + else if (!flag) + free(string); + } + return(0); +} + +void +shell_op() +{ + char *string; + + if (((string = get_string(shell_prompt, TRUE)) != NULL) && + (*string != (char) NULL)) + { + sh_command(string); + free(string); + } +} + +void +leave_op() +{ + if (text_changes) + { + menu_op(leave_menu); + } + else + quit(TRUE); +} + +void +redraw() +{ + if (info_window) + { + clearok(info_win, TRUE); + paint_info_win(); + } + else + clearok(text_win, TRUE); + midscreen(scr_vert, point); +} + +/* + | The following routines will "format" a paragraph (as defined by a + | block of text with blank lines before and after the block). + */ + +int +Blank_Line(test_line) /* test if line has any non-space characters */ +struct text *test_line; +{ + char *line; + int length; + + if (test_line == NULL) + return(TRUE); + + length = 1; + line = test_line->line; + + /* + | To handle troff/nroff documents, consider a line with a + | period ('.') in the first column to be blank. To handle mail + | messages with included text, consider a line with a '>' blank. + */ + + if ((*line == '.') || (*line == '>')) + return(TRUE); + + while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length)) + { + length++; + line++; + } + if (length != test_line->line_length) + return(FALSE); + else + return(TRUE); +} + +void +Format() /* format the paragraph according to set margins */ +{ + int string_count; + int offset; + int temp_case; + int status; + int tmp_af; + int counter; + char *line; + char *tmp_srchstr; + char *temp1, *temp2; + char *temp_dword; + char temp_d_char = d_char; + +/* + | if observ_margins is not set, or the current line is blank, + | do not format the current paragraph + */ + + if ((!observ_margins) || (Blank_Line(curr_line))) + return; + +/* + | save the currently set flags, and clear them + */ + + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, formatting_msg); + wrefresh(com_win); + +/* + | get current position in paragraph, so after formatting, the cursor + | will be in the same relative position + */ + + tmp_af = auto_format; + auto_format = FALSE; + offset = position; + if (position != 1) + prev_word(); + temp_dword = d_word; + d_word = NULL; + temp_case = case_sen; + case_sen = TRUE; + tmp_srchstr = srch_str; + temp2 = srch_str = (char *) malloc(1 + curr_line->line_length - position); + if ((*point == ' ') || (*point == '\t')) + adv_word(); + offset -= position; + counter = position; + line = temp1 = point; + while ((*temp1 != (char) NULL) && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length)) + { + *temp2 = *temp1; + temp2++; + temp1++; + counter++; + } + *temp2 = (char) NULL; + if (position != 1) + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + string_count = 0; + status = TRUE; + while ((line != point) && (status)) + { + status = search(FALSE); + string_count++; + } + + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, formatting_msg); + wrefresh(com_win); + +/* + | now get back to the start of the paragraph to start formatting + */ + + if (position != 1) + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + + observ_margins = FALSE; + +/* + | Start going through lines, putting spaces at end of lines if they do + | not already exist. Append lines together to get one long line, and + | eliminate spacing at begin of lines. + */ + + while (!Blank_Line(curr_line->next_line)) + { + eol(); + left(TRUE); + if (*point != ' ') + { + right(TRUE); + insert(' '); + } + else + right(TRUE); + del_char(); + if ((*point == ' ') || (*point == '\t')) + del_word(); + } + +/* + | Now there is one long line. Eliminate extra spaces within the line + | after the first word (so as not to blow away any indenting the user + | may have put in). + */ + + bol(); + adv_word(); + while (position < curr_line->line_length) + { + if ((*point == ' ') && (*(point + 1) == ' ')) + del_char(); + else + right(TRUE); + } + +/* + | Now make sure there are two spaces after a '.'. + */ + + bol(); + while (position < curr_line->line_length) + { + if ((*point == '.') && (*(point + 1) == ' ')) + { + right(TRUE); + insert(' '); + insert(' '); + while (*point == ' ') + del_char(); + } + right(TRUE); + } + + observ_margins = TRUE; + bol(); + + wmove(com_win, 0, 0); + wclrtoeol(com_win); + wprintw(com_win, formatting_msg); + wrefresh(com_win); + +/* + | create lines between margins + */ + + while (position < curr_line->line_length) + { + while ((scr_pos < right_margin) && (position < curr_line->line_length)) + right(TRUE); + if (position < curr_line->line_length) + { + prev_word(); + if (position == 1) + adv_word(); + insert_line(TRUE); + } + } + +/* + | go back to begin of paragraph, put cursor back to original position + */ + + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + +/* + | find word cursor was in + */ + + while ((status) && (string_count > 0)) + { + search(FALSE); + string_count--; + } + +/* + | offset the cursor to where it was before from the start of the word + */ + + while (offset > 0) + { + offset--; + right(TRUE); + } + +/* + | reset flags and strings to what they were before formatting + */ + + if (d_word != NULL) + free(d_word); + d_word = temp_dword; + case_sen = temp_case; + free(srch_str); + srch_str = tmp_srchstr; + d_char = temp_d_char; + auto_format = tmp_af; + + midscreen(scr_vert, point); + werase(com_win); + wrefresh(com_win); +} + +char *init_name[3] = { + "/usr/share/misc/init.ee", + NULL, + ".init.ee" + }; + +void +ee_init() /* check for init file and read it if it exists */ +{ + FILE *init_file; + char *string; + char *str1; + char *str2; + char *home; + int counter; + int temp_int; + + string = getenv("HOME"); + str1 = home = malloc(strlen(string)+10); + strcpy(home, string); + strcat(home, "/.init.ee"); + init_name[1] = home; + string = malloc(512); + + for (counter = 0; counter < 3; counter++) + { + if (!(access(init_name[counter], 4))) + { + init_file = fopen(init_name[counter], "r"); + while ((str2 = fgets(string, 512, init_file)) != NULL) + { + if (unique_test(string, init_strings) != 1) + continue; + str1 = str2 = string; + while (*str2 != '\n') + str2++; + *str2 = (char) NULL; + if (compare(str1, CASE, FALSE)) + case_sen = TRUE; + else if (compare(str1, NOCASE, FALSE)) + case_sen = FALSE; + else if (compare(str1, EXPAND, FALSE)) + expand_tabs = TRUE; + else if (compare(str1, NOEXPAND, FALSE)) + expand_tabs = FALSE; + else if (compare(str1, INFO, FALSE)) + info_window = TRUE; + else if (compare(str1, NOINFO, FALSE)) + info_window = FALSE; + else if (compare(str1, MARGINS, FALSE)) + observ_margins = TRUE; + else if (compare(str1, NOMARGINS, FALSE)) + observ_margins = FALSE; + else if (compare(str1, AUTOFORMAT, FALSE)) + { + auto_format = TRUE; + observ_margins = TRUE; + } + else if (compare(str1, NOAUTOFORMAT, FALSE)) + auto_format = FALSE; + else if (compare(str1, Echo, FALSE)) + { + str1 = next_word(str1); + if (*str1 != (char) NULL) + echo_string(str1); + } + else if (compare(str1, PRINTCOMMAND, FALSE)) + { + str1 = next_word(str1); + print_command = malloc(strlen(str1)+1); + strcpy(print_command, str1); + } + else if (compare(str1, RIGHTMARGIN, FALSE)) + { + str1 = next_word(str1); + if ((*str1 >= '0') && (*str1 <= '9')) + { + temp_int = atoi(str1); + if (temp_int > 0) + right_margin = temp_int; + } + } + else if (compare(str1, HIGHLIGHT, FALSE)) + nohighlight = FALSE; + else if (compare(str1, NOHIGHLIGHT, FALSE)) + nohighlight = TRUE; + else if (compare(str1, EIGHTBIT, FALSE)) + eightbit = TRUE; + else if (compare(str1, NOEIGHTBIT, FALSE)) + eightbit = FALSE; + else if (compare(str1, EMACS_string, FALSE)) + emacs_keys_mode = TRUE; + else if (compare(str1, NOEMACS_string, FALSE)) + emacs_keys_mode = FALSE; + } + fclose(init_file); + } + } + free(string); + free(home); +} + +void +echo_string(string) /* echo the given string */ +char *string; +{ + char *temp; + int Counter; + + temp = string; + while (*temp != (char) NULL) + { + if (*temp == '\\') + { + temp++; + if (*temp == 'n') + putchar('\n'); + else if (*temp == 't') + putchar('\t'); + else if (*temp == 'b') + putchar('\b'); + else if (*temp == 'r') + putchar('\r'); + else if (*temp == 'f') + putchar('\f'); + else if ((*temp == 'e') || (*temp == 'E')) + putchar('\033'); /* escape */ + else if (*temp == '\\') + putchar('\\'); + else if (*temp == '\'') + putchar('\''); + else if ((*temp >= '0') && (*temp <= '9')) + { + Counter = 0; + while ((*temp >= '0') && (*temp <= '9')) + { + Counter = (8 * Counter) + (*temp - '0'); + temp++; + } + putchar(Counter); + temp--; + } + temp++; + } + else + { + putchar(*temp); + temp++; + } + } + + fflush(stdout); +} + +void +spell_op() /* check spelling of words in the editor */ +{ + if (restrict_mode()) + { + return; + } + top(); /* go to top of file */ + insert_line(FALSE); /* create two blank lines */ + insert_line(FALSE); + top(); + command(shell_echo_msg); + adv_line(); + wmove(com_win, 0, 0); + wprintw(com_win, spell_in_prog_msg); + wrefresh(com_win); + command("<>!spell"); /* send contents of buffer to command 'spell' + and read the results back into the editor */ +} + +void +ispell_op() +{ + char name[128]; + char string[256]; + int pid; + + if (restrict_mode()) + { + return; + } + pid = getpid(); + sprintf(name, "/tmp/ee.%d", pid); + if (write_file(name)) + { + sprintf(string, "ispell %s", name); + sh_command(string); + delete_text(); + tmp_file = name; + recv_file = TRUE; + check_fp(); + unlink(name); + } +} + +int +first_word_len(test_line) +struct text *test_line; +{ + int counter; + char *pnt; + + pnt = test_line->line; + if ((test_line == NULL) || (pnt == NULL) || (*pnt == (char) NULL) || + (*pnt == '.') || (*pnt == '>')) + return(0); + + if ((*pnt == ' ') || (*pnt == '\t')) + { + pnt = next_word(pnt); + } + + if (*pnt == (char) NULL) + return(0); + + counter = 0; + while ((*pnt != (char) NULL) && ((*pnt != ' ') && (*pnt != '\t'))) + { + pnt++; + counter++; + } + while ((*pnt != (char) NULL) && ((*pnt == ' ') || (*pnt == '\t'))) + { + pnt++; + counter++; + } + return(counter); +} + +void +Auto_Format() /* format the paragraph according to set margins */ +{ + int string_count; + int offset; + int temp_case; + int word_len; + int temp_dwl; + int tmp_d_line_length; + int leave_loop = FALSE; + int status; + int counter; + char *line; + char *tmp_srchstr; + char *temp1, *temp2; + char *temp_dword; + char temp_d_char = d_char; + char *tmp_d_line; + +/* + | if observ_margins is not set, or the current line is blank, + | do not format the current paragraph + */ + + if ((!observ_margins) || (Blank_Line(curr_line))) + return; + +/* + | get current position in paragraph, so after formatting, the cursor + | will be in the same relative position + */ + + tmp_d_line = d_line; + tmp_d_line_length = dlt_line->line_length; + d_line = NULL; + auto_format = FALSE; + offset = position; + if ((position != 1) && ((*point == ' ') || (*point == '\t') || (position == curr_line->line_length) || (*point == (char) NULL))) + prev_word(); + temp_dword = d_word; + temp_dwl = d_wrd_len; + d_wrd_len = 0; + d_word = NULL; + temp_case = case_sen; + case_sen = TRUE; + tmp_srchstr = srch_str; + temp2 = srch_str = (char *) malloc(1 + curr_line->line_length - position); + if ((*point == ' ') || (*point == '\t')) + adv_word(); + offset -= position; + counter = position; + line = temp1 = point; + while ((*temp1 != (char) NULL) && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length)) + { + *temp2 = *temp1; + temp2++; + temp1++; + counter++; + } + *temp2 = (char) NULL; + if (position != 1) + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + string_count = 0; + status = TRUE; + while ((line != point) && (status)) + { + status = search(FALSE); + string_count++; + } + +/* + | now get back to the start of the paragraph to start checking + */ + + if (position != 1) + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + +/* + | Start going through lines, putting spaces at end of lines if they do + | not already exist. Check line length, and move words to the next line + | if they cross the margin. Then get words from the next line if they + | will fit in before the margin. + */ + + while (!leave_loop) + { + if (position != curr_line->line_length) + eol(); + left(TRUE); + if (*point != ' ') + { + right(TRUE); + insert(' '); + } + else + right(TRUE); + + /* + | fill line if first word on next line will fit + | in the line without crossing the margin + */ + + while ((curr_line->next_line != NULL) && + ((word_len = first_word_len(curr_line->next_line)) > 0) + && ((scr_pos + word_len) < right_margin)) + { + adv_line(); + if ((*point == ' ') || (*point == '\t')) + adv_word(); + del_word(); + if (position != 1) + bol(); + if (Blank_Line(curr_line)) + { + del_line(); + } + /* + | go to end of previous line + */ + left(TRUE); + undel_word(); + eol(); + /* + | make sure there's a space at the end of the line + */ + left(TRUE); + if (*point != ' ') + { + right(TRUE); + insert(' '); + } + else + right(TRUE); + } + + /* + | make sure line does not cross right margin + */ + + while (right_margin <= scr_pos) + { + prev_word(); + if (position != 1) + { + del_word(); + if (Blank_Line(curr_line->next_line)) + insert_line(TRUE); + else + adv_line(); + if ((*point == ' ') || (*point == '\t')) + adv_word(); + undel_word(); + if (position != 1) + bol(); + left(TRUE); + } + } + + if (!Blank_Line(curr_line->next_line)) + adv_line(); + else + leave_loop = TRUE; + } + +/* + | go back to begin of paragraph, put cursor back to original position + */ + + bol(); + while (!Blank_Line(curr_line->prev_line)) + bol(); + +/* + | find word cursor was in + */ + + status = TRUE; + while ((status) && (string_count > 0)) + { + status = search(FALSE); + string_count--; + } + +/* + | offset the cursor to where it was before from the start of the word + */ + + while (offset > 0) + { + offset--; + right(TRUE); + } + + if ((string_count > 0) && (offset < 0)) + { + while (offset < 0) + { + offset++; + left(TRUE); + } + } + +/* + | reset flags and strings to what they were before formatting + */ + + if (d_word != NULL) + free(d_word); + d_word = temp_dword; + d_wrd_len = temp_dwl; + case_sen = temp_case; + free(srch_str); + srch_str = tmp_srchstr; + d_char = temp_d_char; + auto_format = TRUE; + dlt_line->line_length = tmp_d_line_length; + d_line = tmp_d_line; + + formatted = TRUE; + midscreen(scr_vert, point); +} + +void +modes_op() +{ + int ret_value; + int counter; + char *string; + + do + { + sprintf(modes_menu[1].item_string, "%s %s", mode_strings[1], + (expand_tabs ? ON : OFF)); + sprintf(modes_menu[2].item_string, "%s %s", mode_strings[2], + (case_sen ? ON : OFF)); + sprintf(modes_menu[3].item_string, "%s %s", mode_strings[3], + (observ_margins ? ON : OFF)); + sprintf(modes_menu[4].item_string, "%s %s", mode_strings[4], + (auto_format ? ON : OFF)); + sprintf(modes_menu[5].item_string, "%s %s", mode_strings[5], + (eightbit ? ON : OFF)); + sprintf(modes_menu[6].item_string, "%s %s", mode_strings[6], + (info_window ? ON : OFF)); + sprintf(modes_menu[7].item_string, "%s %s", mode_strings[7], + (emacs_keys_mode ? ON : OFF)); + sprintf(modes_menu[8].item_string, "%s %d", mode_strings[8], + right_margin); + + ret_value = menu_op(modes_menu); + + switch (ret_value) + { + case 1: + expand_tabs = !expand_tabs; + break; + case 2: + case_sen = !case_sen; + break; + case 3: + observ_margins = !observ_margins; + break; + case 4: + auto_format = !auto_format; + if (auto_format) + observ_margins = TRUE; + break; + case 5: + eightbit = !eightbit; + redraw(); + wnoutrefresh(text_win); + break; + case 6: + if (info_window) + no_info_window(); + else + create_info_window(); + break; + case 7: + emacs_keys_mode = !emacs_keys_mode; + if (info_window) + paint_info_win(); + break; + case 8: + string = get_string(margin_prompt, TRUE); + if (string != NULL) + { + counter = atoi(string); + if (counter > 0) + right_margin = counter; + free(string); + } + break; + default: + break; + } + } + while (ret_value != 0); +} + +char * +is_in_string(string, substring) /* a strstr() look-alike for systems without + strstr() */ +char * string, *substring; +{ + char *full, *sub; + + for (sub = substring; (sub != NULL) && (*sub != (char)NULL); sub++) + { + for (full = string; (full != NULL) && (*full != (char)NULL); + full++) + { + if (*sub == *full) + return(full); + } + } + return(NULL); +} + +/* + | handle names of the form "~/file", "~user/file", + | "$HOME/foo", "~/$FOO", etc. + */ + +char * +resolve_name(name) +char *name; +{ + char long_buffer[1024]; + char short_buffer[128]; + char *buffer; + char *slash; + char *tmp; + char *start_of_var; + int offset; + int index; + int counter; + struct passwd *user; + + if (name[0] == '~') + { + if (name[1] == '/') + { + index = getuid(); + user = (struct passwd *) getpwuid(index); + slash = name + 1; + } + else + { + slash = strchr(name, '/'); + if (slash == NULL) + return(name); + *slash = (char) NULL; + user = (struct passwd *) getpwnam((name + 1)); + *slash = '/'; + } + if (user == NULL) + { + return(name); + } + buffer = malloc(strlen(user->pw_dir) + strlen(slash) + 1); + strcpy(buffer, user->pw_dir); + strcat(buffer, slash); + } + else + buffer = name; + + if (is_in_string(buffer, "$")) + { + tmp = buffer; + index = 0; + + while ((*tmp != (char) NULL) && (index < 1024)) + { + + while ((*tmp != (char) NULL) && (*tmp != '$') && + (index < 1024)) + { + long_buffer[index] = *tmp; + tmp++; + index++; + } + + if ((*tmp == '$') && (index < 1024)) + { + counter = 0; + start_of_var = tmp; + tmp++; + if (*tmp == '{') /* } */ /* bracketed variable name */ + { + tmp++; /* { */ + while ((*tmp != (char) NULL) && + (*tmp != '}') && + (counter < 128)) + { + short_buffer[counter] = *tmp; + counter++; + tmp++; + } /* { */ + if (*tmp == '}') + tmp++; + } + else + { + while ((*tmp != (char) NULL) && + (*tmp != '/') && + (*tmp != '$') && + (counter < 128)) + { + short_buffer[counter] = *tmp; + counter++; + tmp++; + } + } + short_buffer[counter] = (char) NULL; + if ((slash = getenv(short_buffer)) != NULL) + { + offset = strlen(slash); + if ((offset + index) < 1024) + strcpy(&long_buffer[index], slash); + index += offset; + } + else + { + while ((start_of_var != tmp) && (index < 1024)) + { + long_buffer[index] = *start_of_var; + start_of_var++; + index++; + } + } + } + } + + if (index == 1024) + return(buffer); + else + long_buffer[index] = (char) NULL; + + if (name != buffer) + free(buffer); + buffer = malloc(index + 1); + strcpy(buffer, long_buffer); + } + + return(buffer); +} + +int +restrict_mode() +{ + if (!restricted) + return(FALSE); + + wmove(com_win, 0, 0); + wprintw(com_win, restricted_msg); + wclrtoeol(com_win); + wrefresh(com_win); + clear_com_win = TRUE; + return(TRUE); +} + +/* + | The following routine tests the input string against the list of + | strings, to determine if the string is a unique match with one of the + | valid values. + */ + +int +unique_test(string, list) +char *string; +char *list[]; +{ + int counter; + int num_match; + int result; + + num_match = 0; + counter = 0; + while (list[counter] != NULL) + { + result = compare(string, list[counter], FALSE); + if (result) + num_match++; + counter++; + } + return(num_match); +} + +#ifndef NO_CATGETS +/* + | Get the catalog entry, and if it got it from the catalog, + | make a copy, since the buffer will be overwritten by the + | next call to catgets(). + */ + +char * +catgetlocal(number, string) +int number; +char *string; +{ + char *temp1; + char *temp2; + + temp1 = catgets(catalog, 1, number, string); + if (temp1 != string) + { + temp2 = malloc(strlen(temp1) + 1); + strcpy(temp2, temp1); + temp1 = temp2; + } + return(temp1); +} +#endif /* NO_CATGETS */ + +/* + | The following is to allow for using message catalogs which allow + | the software to be 'localized', that is, to use different languages + | all with the same binary. For more information, see your system + | documentation, or the X/Open Internationalization Guide. + */ + +void +strings_init() +{ + int counter; + +#ifndef NO_CATGETS + setlocale(LC_ALL, ""); + catalog = catopen("ee", 0); +#endif /* NO_CATGETS */ + + modes_menu[0].item_string = catgetlocal( 1, "modes menu"); + mode_strings[1] = catgetlocal( 2, "tabs to spaces "); + mode_strings[2] = catgetlocal( 3, "case sensitive search"); + mode_strings[3] = catgetlocal( 4, "margins observed "); + mode_strings[4] = catgetlocal( 5, "auto-paragraph format"); + mode_strings[5] = catgetlocal( 6, "eightbit characters "); + mode_strings[6] = catgetlocal( 7, "info window "); + mode_strings[8] = catgetlocal( 8, "right margin "); + leave_menu[0].item_string = catgetlocal( 9, "leave menu"); + leave_menu[1].item_string = catgetlocal( 10, "save changes"); + leave_menu[2].item_string = catgetlocal( 11, "no save"); + file_menu[0].item_string = catgetlocal( 12, "file menu"); + file_menu[1].item_string = catgetlocal( 13, "read a file"); + file_menu[2].item_string = catgetlocal( 14, "write a file"); + file_menu[3].item_string = catgetlocal( 15, "save file"); + file_menu[4].item_string = catgetlocal( 16, "print editor contents"); + search_menu[0].item_string = catgetlocal( 17, "search menu"); + search_menu[1].item_string = catgetlocal( 18, "search for ..."); + search_menu[2].item_string = catgetlocal( 19, "search"); + spell_menu[0].item_string = catgetlocal( 20, "spell menu"); + spell_menu[1].item_string = catgetlocal( 21, "use 'spell'"); + spell_menu[2].item_string = catgetlocal( 22, "use 'ispell'"); + misc_menu[0].item_string = catgetlocal( 23, "miscellaneous menu"); + misc_menu[1].item_string = catgetlocal( 24, "format paragraph"); + misc_menu[2].item_string = catgetlocal( 25, "shell command"); + misc_menu[3].item_string = catgetlocal( 26, "check spelling"); + main_menu[0].item_string = catgetlocal( 27, "main menu"); + main_menu[1].item_string = catgetlocal( 28, "leave editor"); + main_menu[2].item_string = catgetlocal( 29, "help"); + main_menu[3].item_string = catgetlocal( 30, "file operations"); + main_menu[4].item_string = catgetlocal( 31, "redraw screen"); + main_menu[5].item_string = catgetlocal( 32, "settings"); + main_menu[6].item_string = catgetlocal( 33, "search"); + main_menu[7].item_string = catgetlocal( 34, "miscellaneous"); + help_text[0] = catgetlocal( 35, "Control keys: "); + help_text[1] = catgetlocal( 36, "^a ascii code ^i tab ^r right "); + help_text[2] = catgetlocal( 37, "^b bottom of text ^j newline ^t top of text "); + help_text[3] = catgetlocal( 38, "^c command ^k delete char ^u up "); + help_text[4] = catgetlocal( 39, "^d down ^l left ^v undelete word "); + help_text[5] = catgetlocal( 40, "^e search prompt ^m newline ^w delete word "); + help_text[6] = catgetlocal( 41, "^f undelete char ^n next page ^x search "); + help_text[7] = catgetlocal( 42, "^g begin of line ^o end of line ^y delete line "); + help_text[8] = catgetlocal( 43, "^h backspace ^p prev page ^z undelete line "); + help_text[9] = catgetlocal( 44, "^[ (escape) menu "); + help_text[10] = catgetlocal( 45, " "); + help_text[11] = catgetlocal( 46, "Commands: "); + help_text[12] = catgetlocal( 47, "help : get this info file : print file name "); + help_text[13] = catgetlocal( 48, "read : read a file char : ascii code of char "); + help_text[14] = catgetlocal( 49, "write : write a file case : case sensitive search "); + help_text[15] = catgetlocal( 50, "exit : leave and save nocase : case insensitive search "); + help_text[16] = catgetlocal( 51, "quit : leave, no save !cmd : execute \"cmd\" in shell "); + help_text[17] = catgetlocal( 52, "line : display line # 0-9 : go to line \"#\" "); + help_text[18] = catgetlocal( 53, "expand : expand tabs noexpand: do not expand tabs "); + help_text[19] = catgetlocal( 54, " "); + help_text[20] = catgetlocal( 55, " ee [-i] [-e] [-h] [file(s)] "); + help_text[21] = catgetlocal( 56, " -i : no information window -e : do not expand tabs -h : no highlight "); + control_keys[0] = catgetlocal( 57, "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "); + control_keys[1] = catgetlocal( 58, "^a ascii code ^x search ^z undelete line ^d down ^n next page "); + control_keys[2] = catgetlocal( 59, "^b bottom of text ^g begin of line ^w delete word ^l left "); + control_keys[3] = catgetlocal( 60, "^t top of text ^o end of line ^v undelete word ^r right "); + control_keys[4] = catgetlocal( 61, "^c command ^k delete char ^f undelete char "); + command_strings[0] = catgetlocal( 62, "help : get help info |file : print file name |line : print line # "); + command_strings[1] = catgetlocal( 63, "read : read a file |char : ascii code of char |0-9 : go to line \"#\""); + command_strings[2] = catgetlocal( 64, "write: write a file |case : case sensitive search |exit : leave and save "); + command_strings[3] = catgetlocal( 65, "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"); + command_strings[4] = catgetlocal( 66, "expand: expand tabs |noexpand: do not expand tabs "); + com_win_message = catgetlocal( 67, " press Escape (^[) for menu"); + no_file_string = catgetlocal( 68, "no file"); + ascii_code_str = catgetlocal( 69, "ascii code: "); + printer_msg_str = catgetlocal( 70, "sending contents of buffer to \"%s\" "); + command_str = catgetlocal( 71, "command: "); + file_write_prompt_str = catgetlocal( 72, "name of file to write: "); + file_read_prompt_str = catgetlocal( 73, "name of file to read: "); + char_str = catgetlocal( 74, "character = %d"); + unkn_cmd_str = catgetlocal( 75, "unknown command \"%s\""); + non_unique_cmd_msg = catgetlocal( 76, "entered command is not unique"); + line_num_str = catgetlocal( 77, "line %d "); + line_len_str = catgetlocal( 78, "length = %d"); + current_file_str = catgetlocal( 79, "current file is \"%s\" "); + usage0 = catgetlocal( 80, "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"); + usage1 = catgetlocal( 81, " -i turn off info window\n"); + usage2 = catgetlocal( 82, " -e do not convert tabs to spaces\n"); + usage3 = catgetlocal( 83, " -h do not use highlighting\n"); + file_is_dir_msg = catgetlocal( 84, "file \"%s\" is a directory"); + new_file_msg = catgetlocal( 85, "new file \"%s\""); + cant_open_msg = catgetlocal( 86, "can't open \"%s\""); + open_file_msg = catgetlocal( 87, "file \"%s\", %d lines"); + file_read_fin_msg = catgetlocal( 88, "finished reading file \"%s\""); + reading_file_msg = catgetlocal( 89, "reading file \"%s\""); + read_only_msg = catgetlocal( 90, ", read only"); + file_read_lines_msg = catgetlocal( 91, "file \"%s\", %d lines"); + save_file_name_prompt = catgetlocal( 92, "enter name of file: "); + file_not_saved_msg = catgetlocal( 93, "no filename entered: file not saved"); + changes_made_prompt = catgetlocal( 94, "changes have been made, are you sure? (y/n [n]) "); + yes_char = catgetlocal( 95, "y"); + file_exists_prompt = catgetlocal( 96, "file already exists, overwrite? (y/n) [n] "); + create_file_fail_msg = catgetlocal( 97, "unable to create file \"%s\""); + writing_file_msg = catgetlocal( 98, "writing file \"%s\""); + file_written_msg = catgetlocal( 99, "\"%s\" %d lines, %d characters"); + searching_msg = catgetlocal( 100, " ...searching"); + str_not_found_msg = catgetlocal( 101, "string \"%s\" not found"); + search_prompt_str = catgetlocal( 102, "search for: "); + exec_err_msg = catgetlocal( 103, "could not exec %s\n"); + continue_msg = catgetlocal( 104, "press return to continue "); + menu_cancel_msg = catgetlocal( 105, "press Esc to cancel"); + menu_size_err_msg = catgetlocal( 106, "menu too large for window"); + press_any_key_msg = catgetlocal( 107, "press any key to continue "); + shell_prompt = catgetlocal( 108, "shell command: "); + formatting_msg = catgetlocal( 109, "...formatting paragraph..."); + shell_echo_msg = catgetlocal( 110, "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-"); + spell_in_prog_msg = catgetlocal( 111, "sending contents of edit buffer to 'spell'"); + margin_prompt = catgetlocal( 112, "right margin is: "); + restricted_msg = catgetlocal( 113, "restricted mode: unable to perform requested operation"); + ON = catgetlocal( 114, "ON"); + OFF = catgetlocal( 115, "OFF"); + HELP = catgetlocal( 116, "HELP"); + WRITE = catgetlocal( 117, "WRITE"); + READ = catgetlocal( 118, "READ"); + LINE = catgetlocal( 119, "LINE"); + FILE_str = catgetlocal( 120, "FILE"); + CHARACTER = catgetlocal( 121, "CHARACTER"); + REDRAW = catgetlocal( 122, "REDRAW"); + RESEQUENCE = catgetlocal( 123, "RESEQUENCE"); + AUTHOR = catgetlocal( 124, "AUTHOR"); + VERSION = catgetlocal( 125, "VERSION"); + CASE = catgetlocal( 126, "CASE"); + NOCASE = catgetlocal( 127, "NOCASE"); + EXPAND = catgetlocal( 128, "EXPAND"); + NOEXPAND = catgetlocal( 129, "NOEXPAND"); + Exit_string = catgetlocal( 130, "EXIT"); + QUIT_string = catgetlocal( 131, "QUIT"); + INFO = catgetlocal( 132, "INFO"); + NOINFO = catgetlocal( 133, "NOINFO"); + MARGINS = catgetlocal( 134, "MARGINS"); + NOMARGINS = catgetlocal( 135, "NOMARGINS"); + AUTOFORMAT = catgetlocal( 136, "AUTOFORMAT"); + NOAUTOFORMAT = catgetlocal( 137, "NOAUTOFORMAT"); + Echo = catgetlocal( 138, "ECHO"); + PRINTCOMMAND = catgetlocal( 139, "PRINTCOMMAND"); + RIGHTMARGIN = catgetlocal( 140, "RIGHTMARGIN"); + HIGHLIGHT = catgetlocal( 141, "HIGHLIGHT"); + NOHIGHLIGHT = catgetlocal( 142, "NOHIGHLIGHT"); + EIGHTBIT = catgetlocal( 143, "EIGHTBIT"); + NOEIGHTBIT = catgetlocal( 144, "NOEIGHTBIT"); + /* + | additions + */ + mode_strings[7] = catgetlocal( 145, "emacs key bindings "); + emacs_help_text[0] = help_text[0]; + emacs_help_text[1] = catgetlocal( 146, "^a beginning of line ^i tab ^r restore word "); + emacs_help_text[2] = catgetlocal( 147, "^b back 1 char ^j undel char ^t top of text "); + emacs_help_text[3] = catgetlocal( 148, "^c command ^k delete line ^u bottom of text "); + emacs_help_text[4] = catgetlocal( 149, "^d delete char ^l undelete line ^v next page "); + emacs_help_text[5] = catgetlocal( 150, "^e end of line ^m newline ^w delete word "); + emacs_help_text[6] = catgetlocal( 151, "^f forward 1 char ^n next line ^x search "); + emacs_help_text[7] = catgetlocal( 152, "^g go back 1 page ^o ascii char insert ^y search prompt "); + emacs_help_text[8] = catgetlocal( 153, "^h backspace ^p prev line ^z next word "); + emacs_help_text[9] = help_text[9]; + emacs_help_text[10] = help_text[10]; + emacs_help_text[11] = help_text[11]; + emacs_help_text[12] = help_text[12]; + emacs_help_text[13] = help_text[13]; + emacs_help_text[14] = help_text[14]; + emacs_help_text[15] = help_text[15]; + emacs_help_text[16] = help_text[16]; + emacs_help_text[17] = help_text[17]; + emacs_help_text[18] = help_text[18]; + emacs_help_text[19] = help_text[19]; + emacs_help_text[20] = help_text[20]; + emacs_help_text[21] = help_text[21]; + emacs_control_keys[0] = catgetlocal( 154, "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page"); + emacs_control_keys[1] = catgetlocal( 155, "^o ascii code ^x search ^l undelete line ^n next li ^v next page"); + emacs_control_keys[2] = catgetlocal( 156, "^u end of file ^a begin of line ^w delete word ^b back 1 char "); + emacs_control_keys[3] = catgetlocal( 157, "^t top of text ^e end of line ^r restore word ^f forward 1 char "); + emacs_control_keys[4] = catgetlocal( 158, "^c command ^d delete char ^j undelete char ^z next word "); + EMACS_string = catgetlocal( 159, "EMACS"); + NOEMACS_string = catgetlocal( 160, "NOEMACS"); + usage4 = catgetlocal( 161, " +# put cursor at line #\n"); + + commands[0] = HELP; + commands[1] = WRITE; + commands[2] = READ; + commands[3] = LINE; + commands[4] = FILE_str; + commands[5] = REDRAW; + commands[6] = RESEQUENCE; + commands[7] = AUTHOR; + commands[8] = VERSION; + commands[9] = CASE; + commands[10] = NOCASE; + commands[11] = EXPAND; + commands[12] = NOEXPAND; + commands[13] = Exit_string; + commands[14] = QUIT_string; + commands[15] = "<"; + commands[16] = ">"; + commands[17] = "!"; + commands[18] = "0"; + commands[19] = "1"; + commands[20] = "2"; + commands[21] = "3"; + commands[22] = "4"; + commands[23] = "5"; + commands[24] = "6"; + commands[25] = "7"; + commands[26] = "8"; + commands[27] = "9"; + commands[28] = CHARACTER; + commands[29] = NULL; + init_strings[0] = CASE; + init_strings[1] = NOCASE; + init_strings[2] = EXPAND; + init_strings[3] = NOEXPAND; + init_strings[4] = INFO; + init_strings[5] = NOINFO; + init_strings[6] = MARGINS; + init_strings[7] = NOMARGINS; + init_strings[8] = AUTOFORMAT; + init_strings[9] = NOAUTOFORMAT; + init_strings[10] = Echo; + init_strings[11] = PRINTCOMMAND; + init_strings[12] = RIGHTMARGIN; + init_strings[13] = HIGHLIGHT; + init_strings[14] = NOHIGHLIGHT; + init_strings[15] = EIGHTBIT; + init_strings[16] = NOEIGHTBIT; + init_strings[17] = EMACS_string; + init_strings[18] = NOEMACS_string; + init_strings[19] = NULL; + + /* + | allocate space for strings here for settings menu + */ + + for (counter = 1; counter < NUM_MODES_ITEMS; counter++) + { + modes_menu[counter].item_string = malloc(80); + } + +#ifndef NO_CATGETS + catclose(catalog); +#endif /* NO_CATGETS */ +} + diff --git a/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg b/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg new file mode 100644 index 0000000000000..1ed22aa1bed48 --- /dev/null +++ b/usr.bin/ee/nls/en_US.ISO_8859-1/ee.msg @@ -0,0 +1,170 @@ +$ This file contains the messages for ee ("easy editor"). See the file +$ ee.i18n.guide for more information +$ +$ For ee patchlevel 3 +$ +$ $Header: /home/ncvs/src/usr.bin/ee/ee.msg,v 1.1.1.1 1995/08/30 07:28:06 jkh Exp $ +$ +$set 1 +$quote " +1 "modes menu" +2 "tabs to spaces " +3 "case sensitive search" +4 "margins observed " +5 "auto-paragraph format" +6 "eightbit characters " +7 "info window " +8 "right margin " +9 "leave menu" +10 "save changes" +11 "no save" +12 "file menu" +13 "read a file" +14 "write a file" +15 "save file" +16 "print editor contents" +17 "search menu" +18 "search for ..." +19 "search" +20 "spell menu" +21 "use 'spell'" +22 "use 'ispell'" +23 "miscellaneous menu" +24 "format paragraph" +25 "shell command" +26 "check spelling" +27 "main menu" +28 "leave editor" +29 "help" +30 "file operations" +31 "redraw screen" +32 "settings" +33 "search" +34 "miscellaneous" +35 "Control keys: " +36 "^a ascii code ^i tab ^r right " +37 "^b bottom of text ^j newline ^t top of text " +38 "^c command ^k delete char ^u up " +39 "^d down ^l left ^v undelete word " +40 "^e search prompt ^m newline ^w delete word " +41 "^f undelete char ^n next page ^x search " +42 "^g begin of line ^o end of line ^y delete line " +43 "^h backspace ^p prev page ^z undelete line " +44 "^[ (escape) menu " +45 " " +46 "Commands: " +47 "help : get this info file : print file name " +48 "read : read a file char : ascii code of char " +49 "write : write a file case : case sensitive search " +50 "exit : leave and save nocase : case insensitive search " +51 "quit : leave, no save !cmd : execute \"cmd\" in shell " +52 "line : display line # 0-9 : go to line \"#\" " +53 "expand : expand tabs noexpand: do not expand tabs " +54 " " +55 " ee [-i] [-e] [-h] [file(s)] " +56 " -i : no information window -e : do not expand tabs -h : no highlight " +57 "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page " +58 "^a ascii code ^x search ^z undelete line ^d down ^n next page " +59 "^b bottom of text ^g begin of line ^w delete word ^l left " +60 "^t top of text ^o end of line ^v undelete word ^r right " +61 "^c command ^k delete char ^f undelete char " +62 "help : get help info |file : print file name |line : print line # " +63 "read : read a file |char : ascii code of char |0-9 : go to line \"#\"" +64 "write: write a file |case : case sensitive search |exit : leave and save " +65 "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save" +66 "expand: expand tabs |noexpand: do not expand tabs " +67 " press Escape (^[) for menu" +68 "no file" +69 "ascii code: " +70 "sending contents of buffer to \"%s\" " +71 "command: " +72 "name of file to write: " +73 "name of file to read: " +74 "character = %d" +75 "unknown command \"%s\"" +76 "entered command is not unique" +77 "line %d " +78 "length = %d" +79 "current file is \"%s\" " +80 "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n" +81 " -i turn off info window\n" +82 " -e do not convert tabs to spaces\n" +83 " -h do not use highlighting\n" +84 "file \"%s\" is a directory" +85 "new file \"%s\"" +86 "can't open \"%s\"" +87 "file \"%s\", %d lines" +88 "finished reading file \"%s\"" +89 "reading file \"%s\"" +90 ", read only" +91 "file \"%s\", %d lines" +92 "enter name of file: " +93 "no filename entered: file not saved" +94 "changes have been made, are you sure? (y/n [n]) " +95 "y" +96 "file already exists, overwrite? (y/n) [n] " +97 "unable to create file \"%s\"" +98 "writing file \"%s\"" +99 "\"%s\" %d lines, %d characters" +100 " ...searching" +101 "string \"%s\" not found" +102 "search for: " +103 "could not exec %s\n" +104 "press return to continue " +105 "press Esc to cancel" +106 "menu too large for window" +107 "press any key to continue " +108 "shell command: " +109 "...formatting paragraph..." +110 "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-" +111 "sending contents of edit buffer to 'spell'" +112 "right margin is: " +113 "restricted mode: unable to perform requested operation" +114 "ON" +115 "OFF" +116 "HELP" +117 "WRITE" +118 "READ" +119 "LINE" +120 "FILE" +121 "CHARACTER" +122 "REDRAW" +123 "RESEQUENCE" +124 "AUTHOR" +125 "VERSION" +126 "CASE" +127 "NOCASE" +128 "EXPAND" +129 "NOEXPAND" +130 "EXIT" +131 "QUIT" +132 "INFO" +133 "NOINFO" +134 "MARGINS" +135 "NOMARGINS" +136 "AUTOFORMAT" +137 "NOAUTOFORMAT" +138 "ECHO" +139 "PRINTCOMMAND" +140 "RIGHTMARGIN" +141 "HIGHLIGHT" +142 "NOHIGHLIGHT" +143 "EIGHTBIT" +144 "NOEIGHTBIT" +145 "emacs key bindings " +146 "^a beginning of line ^i tab ^r restore word " +147 "^b back 1 char ^j undel char ^t top of text " +148 "^c command ^k delete line ^u bottom of text " +149 "^d delete char ^l undelete line ^v next page " +150 "^e end of line ^m newline ^w delete word " +151 "^f forward 1 char ^n next line ^x search " +152 "^g go back 1 page ^o ascii char insert ^y search prompt " +153 "^h backspace ^p prev line ^z next word " +154 "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page" +155 "^o ascii code ^x search ^l undelete line ^n next li ^v next page" +156 "^u end of file ^a begin of line ^w delete word ^b back 1 char " +157 "^t top of text ^e end of line ^r restore word ^f forward 1 char " +158 "^c command ^d delete char ^j undelete char ^z next word " +159 "EMACS" +160 "NOEMACS" +161 " +# put cursor at line #\n" diff --git a/usr.bin/killall/Makefile b/usr.bin/killall/Makefile new file mode 100644 index 0000000000000..17cfc53c0e9a4 --- /dev/null +++ b/usr.bin/killall/Makefile @@ -0,0 +1,7 @@ +MAN1= killall.1 + +beforeinstall: + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + ${.CURDIR}/killall.pl ${DESTDIR}${BINDIR}/killall + +.include <bsd.prog.mk> diff --git a/usr.sbin/cdcontrol/Makefile b/usr.sbin/cdcontrol/Makefile new file mode 100644 index 0000000000000..86a42ebfab7f3 --- /dev/null +++ b/usr.sbin/cdcontrol/Makefile @@ -0,0 +1,4 @@ +PROG= cdcontrol +CFLAGS+= -Wall + +.include <bsd.prog.mk> diff --git a/usr.sbin/cdcontrol/cdcontrol.1 b/usr.sbin/cdcontrol/cdcontrol.1 new file mode 100644 index 0000000000000..095c170c756e1 --- /dev/null +++ b/usr.sbin/cdcontrol/cdcontrol.1 @@ -0,0 +1,144 @@ +.Dd July 3, 1995 +.Dt CDCONTROL 1 +.Os FreeBSD +.Sh NAME +.Nm cdcontrol +.Nd compact disc control utility +.Sh SYNOPSIS +.Nm cdcontrol +.Op Fl s +.Op Fl v +.Op Fl f Ar discname +.Op Ar command args... +.Sh DESCRIPTION +.Nm cdcontrol +is a program to control audio features of a CD drive. The device is a name such +as cd0 or mcd0. +.Pp +If the device not specified, the environment variable +.Ev DISC +will be used to find the cd device. +.Pp +If no command is given, then +.Nm cdcontrol +enters an interactive mode, reading commands from the standard input. +.Pp +The following options are available: +.Bl -tag -width flag +.It Fl s +Silent mode - do not print table headers and human readable comments. +.It Fl v +Verbose mode - print as much information as possible. +.It Fl f Ar discname +Specifies a device name, such as /dev/cd0c or mcd0. +Both absolute path and relative to /dev filename are possible. +Suffix `c' is added to the device name if needed. +.El +.Pp +The available commands are listed below. Only as many +characters as are required to uniquely identify a command +need be specified. +.Bl -tag -width Cm + +.It Cm play Op Ar first_track Op Ar last_track +Play from track +.Nm first_track +to track +.Nm last_track. +The first track has number 1. + +.It Cm play Ar start_m:start_s.start_f Op Ar end_m:end_s.end_f +Play from the absolute address +(MSF) defined by +.Nm start_m +in minutes, +.Nm start_s, +in seconds and +.Nm start_f +(frame number) to the abolute address defined by +.Nm end_m +in minutes, +.Nm end_s, +in seconds and +.Nm end_f +(frame number). Minutes are in the range 0-99. Seconds are in the range 0-59. +Frame numbers are in the range 0-74. + +.It Cm play Ar #start_block Op length +Play starting from the logical block +.Nm start_block +using +.Nm length +logical blocks. + +.It Cm pause +Stop playing. Do not stop the disc. + +.It Cm resume +Resume playing. Used after the +.Nm pause + command. + +.It Cm stop +Stop the disc. + +.It Cm eject +Eject the disc. + +.It Cm volume Ar left_channel Ar right_channel +Set the volume of left channel to +.Nm left_channel +and the volume of right channel to +.Nm right_channel. +Allowed values are in the range 0-255. + +.It Cm volume Ar mute +Turn the sound off. + +.It Cm volume Ar mono +Set the mono mode. + +.It Cm volume Ar stereo +Set the stereo mode. + +.It Cm volume Ar left +Play the left subtrack on both left and right channels. + +.It Cm volume Ar right +Play the right subtrack on both left and right channels. + +.It Cm info +Print the information about the disc: +the current playing status and position, +the current values of the volume for left and right channels, +and the table of contents. + +.It Cm help +Print the list of available commands. + +.It Cm debug Ar on +Enable the debugging mode of the CD device driver. + +.It Cm debug Ar off +Disable the driver debugging mode. + +.It Cm debug Ar reset +Perform the hardware reset of the device. + +.It Cm quit +Quit the program. + +.Sh FILES +.Bl -tag -width /dev/rmcd0c -compact +.It Pa /dev/rcd0c +.It Pa /dev/rmcd0c +.It Pa /dev/rwcd0c +.El +.Sh AUTHORS +Jean-Marc Zucconi, +Andrew A.\ Chernov, +Serge V.\ Vakulenko +.Sh HISTORY +The +.Nm cdcontrol +command appeared in FreeBSD 2.1 diff --git a/usr.sbin/cdcontrol/cdcontrol.c b/usr.sbin/cdcontrol/cdcontrol.c new file mode 100644 index 0000000000000..8a8274aef8744 --- /dev/null +++ b/usr.sbin/cdcontrol/cdcontrol.c @@ -0,0 +1,622 @@ +/* + * Compact Disc Control Utility by Serge V. Vakulenko, <vak@cronyx.ru>. + * Based on the non-X based CD player by Jean-Marc Zucconi and + * Andrew A. Chernov. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/file.h> +#include <sys/cdio.h> +#include <sys/ioctl.h> + +#define VERSION "1.0" + +/* + * Audio Status Codes + */ +#define ASTS_INVALID 0x00 /* Audio status byte not valid */ +#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ +#define ASTS_PAUSED 0x12 /* Audio play operation paused */ +#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ +#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ +#define ASTS_VOID 0x15 /* No current audio status to return */ + +struct cmdtab { + int command; + char *name; + char *args; +} cmdtab[] = { +#define CMD_DEBUG 1 + { CMD_DEBUG, "Debug", "[ on | off | reset ]", }, +#define CMD_EJECT 2 + { CMD_EJECT, "Eject", "", }, +#define CMD_HELP 3 + { CMD_HELP, "?", 0, }, + { CMD_HELP, "Help", "", }, +#define CMD_INFO 4 + { CMD_INFO, "Info", "", }, +#define CMD_PAUSE 5 + { CMD_PAUSE, "PAuse", "", }, +#define CMD_PLAY 6 + { CMD_PLAY, "P", 0, }, + { CMD_PLAY, "Play", "min1:sec1.fr1 [ min2:sec2.fr2 ]", }, + { CMD_PLAY, "Play", "track1.index1 [ track2.index2 ]", }, + { CMD_PLAY, "Play", "#block [ len ]", }, +#define CMD_QUIT 7 + { CMD_QUIT, "Quit", "", }, +#define CMD_RESUME 8 + { CMD_RESUME, "Resume", "", }, +#define CMD_STOP 9 + { CMD_STOP, "Stop", "", }, +#define CMD_VOLUME 10 + { CMD_VOLUME, "Volume", "<l> <r> | left | right | mute | mono | stereo", }, + { 0, 0, }, +}; + +struct cd_toc_entry toc_buffer[100]; + +char *cdname; +int fd = -1; +int verbose = 1; + +extern char *optarg; +extern int optind; + +int setvol (int, int); +int read_toc_entrys (int); +int play_msf (int, int, int, int, int, int); +int play_track (int, int, int, int); +int get_vol (int *, int *); +int status (int *, int *, int *, int *); +int open_cd (void); +int play (char *arg); +int info (char *arg); +char *input (int*); +void prtrack (struct cd_toc_entry *e, int lastflag); +void lba2msf (int lba, u_char *m, u_char *s, u_char *f); +int msf2lba (u_char m, u_char s, u_char f); +int play_blocks (int blk, int len); +int run (int cmd, char *arg); +char *parse (char *buf, int *cmd); + +extern int errno; + +void help () +{ + struct cmdtab *c; + + for (c=cmdtab; c->name; ++c) { + if (! c->args) + continue; + printf ("\t%s", c->name); + if (*c->args) + printf (" %s", c->args); + printf ("\n"); + } +} + +void usage () +{ + printf ("Usage:\n\tcdcontrol [ -vs ] [ -f disc ] [ command args... ]\n"); + printf ("Options:\n"); + printf ("\t-v - verbose mode\n"); + printf ("\t-s - silent mode\n"); + printf ("\t-f disc - device name such as /dev/cd0c\n"); + printf ("\tDISC - shell variable with device name\n"); + printf ("Commands:\n"); + help (); + exit (1); +} + +int main (int argc, char **argv) +{ + int cmd; + char *arg; + + cdname = getenv ("DISC"); + if (! cdname) + cdname = getenv ("CDPLAY"); + + for (;;) { + switch (getopt (argc, argv, "svhf:")) { + case EOF: + break; + case 's': + verbose = 0; + continue; + case 'v': + verbose = 2; + continue; + case 'f': + cdname = optarg; + continue; + case 'h': + default: + usage (); + } + break; + } + argc -= optind; + argv += optind; + + if (argc > 0 && strcasecmp (*argv, "help") == 0) + usage (); + + if (! cdname) { + fprintf (stderr, "No CD device name specified.\n"); + usage (); + } + + if (argc > 0) { + char buf[80], *p; + int len; + + for (p=buf; argc-- > 0; ++argv) { + len = strlen (*argv); + if (p + len >= buf + sizeof (buf) - 1) + usage (); + if (p > buf) + *p++ = ' '; + strcpy (p, *argv); + p += len; + } + *p = 0; + arg = parse (buf, &cmd); + return run (cmd, arg); + } + + if (verbose == 1) + verbose = isatty (0); + if (verbose) { + printf ("Compact Disc Control Utility, Version %s\n", VERSION); + printf ("Type `?' for command list\n\n"); + } + + for (;;) { + arg = input (&cmd); + if (run (cmd, arg) < 0) { + if (verbose) + perror ("cdplay"); + close (fd); + fd = -1; + } + fflush (stdout); + } +} + +int run (int cmd, char *arg) +{ + int l, r, rc; + + switch (cmd) { + case CMD_QUIT: + exit (0); + + default: + case CMD_HELP: + help (); + return (0); + + case CMD_INFO: + if (fd<0 && ! open_cd ()) return (0); + return info (arg); + + case CMD_PAUSE: + if (fd<0 && ! open_cd ()) return (0); + return ioctl (fd, CDIOCPAUSE); + + case CMD_RESUME: + if (fd<0 && ! open_cd ()) return (0); + return ioctl (fd, CDIOCRESUME); + + case CMD_STOP: + if (fd<0 && ! open_cd ()) return (0); + return ioctl (fd, CDIOCSTOP); + + case CMD_DEBUG: + if (fd<0 && ! open_cd ()) return (0); + if (strcasecmp (arg, "on") == 0) + return ioctl (fd, CDIOCSETDEBUG); + if (strcasecmp (arg, "off") == 0) + return ioctl (fd, CDIOCCLRDEBUG); + if (strcasecmp (arg, "reset") == 0) + return ioctl (fd, CDIOCRESET); + printf ("Invalid command arguments\n"); + return (0); + + case CMD_EJECT: + if (fd<0 && ! open_cd ()) return (0); + (void) ioctl (fd, CDIOCALLOW); + rc = ioctl (fd, CDIOCEJECT); + if (rc < 0) + return (rc); + close (fd); + fd = -1; + return (0); + + case CMD_PLAY: + if (fd<0 && ! open_cd ()) return (0); + return play (arg); + + case CMD_VOLUME: + if (fd<0 && ! open_cd ()) return (0); + + if (strcasecmp (arg, "left") == 0) + return ioctl (fd, CDIOCSETLEFT); + else if (strcasecmp (arg, "right") == 0) + return ioctl (fd, CDIOCSETRIGHT); + else if (strcasecmp (arg, "mute") == 0) + return ioctl (fd, CDIOCSETMUTE); + else if (strcasecmp (arg, "mono") == 0) + return ioctl (fd, CDIOCSETMONO); + else if (strcasecmp (arg, "stereo") == 0) + return ioctl (fd, CDIOCSETSTERIO); + + if (2 != sscanf (arg, "%d %d", &l, &r)) { + printf ("Invalid command arguments\n"); + return (0); + } + return setvol (l, r); + } +} + +int play (char *arg) +{ + struct ioc_toc_header h; + int rc, n, start, end = 0, istart = 1, iend = 1; + + rc = ioctl (fd, CDIOREADTOCHEADER, &h); + if (rc < 0) + return (rc); + + n = h.ending_track - h.starting_track + 1; + rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); + if (rc < 0) + return (rc); + + if (! *arg) + /* + * Play the whole disc + */ + return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, + toc_buffer[n].addr.msf.second, + toc_buffer[n].addr.msf.frame)); + + if (strchr (arg, '#')) { + /* + * Play block #blk [ len ] + */ + int blk, len = 0; + + if (2 != sscanf (arg, "#%d%d", &blk, &len) && + 1 != sscanf (arg, "#%d", &blk)) { +err: printf ("Invalid command arguments\n"); + return (0); + } + if (len == 0) + len = msf2lba (toc_buffer[n].addr.msf.minute, + toc_buffer[n].addr.msf.second, + toc_buffer[n].addr.msf.frame) - blk; + return play_blocks (blk, len); + } + + if (strchr (arg, ':')) { + /* + * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] + */ + int m1, m2 = 0, s1, s2 = 0, f1 = 0, f2 = 0; + + if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", &m1, &s1, &f1, &m2, &s2, &f2) && + 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && + 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && + 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && + 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && + 2 != sscanf (arg, "%d:%d", &m1, &s1)) + goto err; + if (m2 == 0) { + m2 = toc_buffer[n].addr.msf.minute; + s2 = toc_buffer[n].addr.msf.second; + f2 = toc_buffer[n].addr.msf.frame; + } + return play_msf (m1, s1, f1, m2, s2, f2); + } + + /* + * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] + */ + if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && + 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && + 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && + 2 != sscanf (arg, "%d.%d", &start, &istart) && + 2 != sscanf (arg, "%d%d", &start, &end) && + 1 != sscanf (arg, "%d", &start)) + goto err; + if (end == 0) + end = n; + return play_track (start, istart, end, iend); +} + +char *strstatus (int sts) +{ + switch (sts) { + case ASTS_INVALID: return ("invalid"); + case ASTS_PLAYING: return ("playing"); + case ASTS_PAUSED: return ("paused"); + case ASTS_COMPLETED: return ("completed"); + case ASTS_ERROR: return ("error"); + case ASTS_VOID: return ("void"); + default: return ("??"); + } +} + +int info (char *arg) +{ + struct ioc_toc_header h; + struct ioc_vol v; + int rc, i, n, trk, m, s, f; + + rc = status (&trk, &m, &s, &f); + if (rc >= 0) + if (verbose) + printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", + rc, strstatus (rc), trk, m, s, f); + else + printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); + else + printf ("No current status info\n"); + + rc = ioctl (fd, CDIOCGETVOL, &v); + if (rc >= 0) + if (verbose) + printf ("Left volume = %d, right volume = %d\n", + v.vol[0], v.vol[1]); + else + printf ("%d %d\n", v.vol[0], v.vol[1]); + else + printf ("No volume info\n"); + + rc = ioctl (fd, CDIOREADTOCHEADER, &h); + if (rc >= 0) + if (verbose) + printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", + h.starting_track, h.ending_track, h.len); + else + printf ("%d %d %d\n", h.starting_track, + h.ending_track, h.len); + else { + perror ("getting toc header"); + return (rc); + } + + n = h.ending_track - h.starting_track + 1; + rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); + if (rc < 0) + return (rc); + if (verbose) { + printf ("track start duration block length type\n"); + printf ("-------------------------------------------------\n"); + } + for (i = 0; i < n; i++) { + printf ("%5d ", toc_buffer[i].track); + prtrack (toc_buffer + i, 0); + } + printf (" end "); + prtrack (toc_buffer + n, 1); + return (0); +} + +void lba2msf (int lba, u_char *m, u_char *s, u_char *f) +{ + lba += 150; /* block start offset */ + lba &= 0xffffff; /* negative lbas use only 24 bits */ + *m = lba / (60 * 75); + lba %= (60 * 75); + *s = lba / 75; + *f = lba % 75; +} + +int msf2lba (u_char m, u_char s, u_char f) +{ + return (((m * 60) + s) * 75 + f) - 150; +} + +void prtrack (struct cd_toc_entry *e, int lastflag) +{ + int block, next, len; + u_char m, s, f; + + /* Print track start */ + printf ("%2d:%02d.%02d ", e->addr.msf.minute, + e->addr.msf.second, e->addr.msf.frame); + + block = msf2lba (e->addr.msf.minute, e->addr.msf.second, + e->addr.msf.frame); + if (lastflag) { + /* Last track -- print block */ + printf (" - %6d - -\n", block); + return; + } + + next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, + e[1].addr.msf.frame); + len = next - block; + lba2msf (len, &m, &s, &f); + + /* Print duration, block, length, type */ + printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, + e->control & 4 ? "data" : "audio"); +} + +int play_track (int tstart, int istart, int tend, int iend) +{ + struct ioc_play_track t; + + t.start_track = tstart; + t.start_index = istart; + t.end_track = tend; + t.end_index = iend; + return ioctl (fd, CDIOCPLAYTRACKS, &t); +} + +int play_blocks (int blk, int len) +{ + struct ioc_play_blocks t; + + t.blk = blk; + t.len = len; + return ioctl (fd, CDIOCPLAYBLOCKS, &t); +} + +int setvol (int l, int r) +{ + struct ioc_vol v; + + v.vol[0] = l; + v.vol[1] = r; + v.vol[2] = 0; + v.vol[3] = 0; + return ioctl (fd, CDIOCSETVOL, &v); +} + +int read_toc_entrys (int len) +{ + struct ioc_read_toc_entry t; + + t.address_format = CD_MSF_FORMAT; + t.starting_track = 1; + t.data_len = len; + t.data = toc_buffer; + return ioctl (fd, CDIOREADTOCENTRYS, (char *) &t); +} + +int play_msf (int start_m, int start_s, int start_f, + int end_m, int end_s, int end_f) +{ + struct ioc_play_msf a; + + a.start_m = start_m; + a.start_s = start_s; + a.start_f = start_f; + a.end_m = end_m; + a.end_s = end_s; + a.end_f = end_f; + return ioctl (fd, CDIOCPLAYMSF, (char *) &a); +} + +int status (int *trk, int *min, int *sec, int *frame) +{ + struct ioc_read_subchannel s; + struct cd_sub_channel_info data; + + bzero (&s, sizeof (s)); + s.data = &data; + s.data_len = sizeof (data); + s.address_format = CD_MSF_FORMAT; + s.data_format = CD_CURRENT_POSITION; + if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) + return -1; + *trk = s.data->what.position.track_number; + *min = s.data->what.position.reladdr.msf.minute; + *sec = s.data->what.position.reladdr.msf.second; + *frame = s.data->what.position.reladdr.msf.frame; + return s.data->header.audio_status; +} + +char *input (int *cmd) +{ + static char buf[80]; + char *p; + + do { + if (verbose) + fprintf (stderr, "cd> "); + if (! fgets (buf, sizeof (buf), stdin)) { + *cmd = CMD_QUIT; + return 0; + } + p = parse (buf, cmd); + } while (! p); + return (p); +} + +char *parse (char *buf, int *cmd) +{ + struct cmdtab *c; + char *p; + int len; + + for (p=buf; *p; ++p) + if (*p == '\t') + *p = ' '; + else if (*p == '\n') + *p = 0; + + for (p=buf; *p; ++p) + if (*p == ' ') { + *p++ = 0; + break; + } + while (*p == ' ') + ++p; + + len = strlen (buf); + if (! len) + return (0); + *cmd = -1; + for (c=cmdtab; c->name; ++c) { + /* Try short command form. */ + if (! c->args && len == strlen (c->name) && + strncasecmp (buf, c->name, len) == 0) { + *cmd = c->command; + break; + } + + /* Try long form. */ + if (strncasecmp (buf, c->name, len) != 0) + continue; + + /* Check inambiguity. */ + if (*cmd != -1) { + fprintf (stderr, "Ambiguous command\n"); + return (0); + } + *cmd = c->command; + } + if (*cmd == -1) { + fprintf (stderr, "Invalid command, enter ``help'' for command list\n"); + return (0); + } + return p; +} + +int open_cd () +{ + char devbuf[80]; + + if (fd > -1) + return (1); + if (*cdname == '/') + strcpy (devbuf, cdname); + else if (*cdname == 'r') + sprintf (devbuf, "/dev/%s", cdname); + else + sprintf (devbuf, "/dev/r%s", cdname); + fd = open (devbuf, O_RDONLY); + if (fd < 0 && errno == ENOENT) { + strcat (devbuf, "c"); + fd = open (devbuf, O_RDONLY); + } + if (fd < 0) { + if (errno != ENXIO) { + perror (devbuf); + exit (1); + } + /* open says 'Device not configured' if no cd in */ + fprintf (stderr, "open: No CD in\n"); + return (0); + } + return (1); +} diff --git a/usr.sbin/mrouted/cfparse.y b/usr.sbin/mrouted/cfparse.y new file mode 100644 index 0000000000000..c08938d4a47a2 --- /dev/null +++ b/usr.sbin/mrouted/cfparse.y @@ -0,0 +1,564 @@ +%{ +/* + * Configuration file parser for mrouted. + * + * Written by Bill Fenner, NRL, 1994 + * + * $Id: cfparse.y,v 3.6 1995/06/25 18:49:46 fenner Exp $ + */ +#include <stdio.h> +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include "defs.h" + +/* + * Local function declarations + */ +static void fatal __P((char *fmt, ...)); +static void warn __P((char *fmt, ...)); +static void yyerror __P((char *s)); +static char * next_word __P((void)); +static int yylex __P((void)); +static u_int32 valid_if __P((char *s)); +static struct ifreq * ifconfaddr __P((struct ifconf *ifcp, u_int32 a)); +int yyparse __P((void)); + +static FILE *f; + +extern int udp_socket; +char *configfilename = _PATH_MROUTED_CONF; + +extern int cache_lifetime; +extern int max_prune_lifetime; + +static int lineno; +static struct ifreq ifbuf[32]; +static struct ifconf ifc; + +static struct uvif *v; + +static int order; + +struct addrmask { + u_int32 addr; + int mask; +}; + +struct boundnam { + char *name; + struct addrmask bound; +}; + +#define MAXBOUNDS 20 + +struct boundnam boundlist[MAXBOUNDS]; /* Max. of 20 named boundaries */ +int numbounds = 0; /* Number of named boundaries */ + +%} + +%union +{ + int num; + char *ptr; + struct addrmask addrmask; + u_int32 addr; +}; + +%token CACHE_LIFETIME PRUNING +%token PHYINT TUNNEL NAME +%token DISABLE METRIC THRESHOLD RATE_LIMIT SRCRT BOUNDARY NETMASK ALTNET +%token <num> BOOLEAN +%token <num> NUMBER +%token <ptr> STRING +%token <addrmask> ADDRMASK +%token <addr> ADDR + +%type <addr> interface +%type <addrmask> bound boundary addrmask + +%start conf + +%% + +conf : stmts + ; + +stmts : /* Empty */ + | stmts stmt + ; + +stmt : error + | PHYINT interface { + + vifi_t vifi; + + if (order) + fatal("phyints must appear before tunnels"); + + for (vifi = 0, v = uvifs; + vifi < numvifs; + ++vifi, ++v) + if (!(v->uv_flags & VIFF_TUNNEL) && + $2 == v->uv_lcl_addr) + break; + + if (vifi == numvifs) + fatal("%s is not a configured interface", + inet_fmt($2,s1)); + + /*log(LOG_INFO, 0, "phyint: %x\n", v);*/ + } + ifmods + | TUNNEL interface ADDR { + + struct ifreq *ifr; + struct ifreq ffr; + vifi_t vifi; + + order++; + + ifr = ifconfaddr(&ifc, $2); + if (ifr == 0) + fatal("Tunnel local address %s is not mine", + inet_fmt($2, s1)); + + strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ); + if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr)<0) + fatal("ioctl SIOCGIFFLAGS on %s",ffr.ifr_name); + if (ffr.ifr_flags & IFF_LOOPBACK) + fatal("Tunnel local address %s is a loopback interface", + inet_fmt($2, s1)); + + if (ifconfaddr(&ifc, $3) != 0) + fatal("Tunnel remote address %s is one of mine", + inet_fmt($3, s1)); + + for (vifi = 0, v = uvifs; + vifi < numvifs; + ++vifi, ++v) + if (v->uv_flags & VIFF_TUNNEL) { + if ($3 == v->uv_rmt_addr) + fatal("Duplicate tunnel to %s", + inet_fmt($3, s1)); + } else if (!(v->uv_flags & VIFF_DISABLED)) { + if (($3 & v->uv_subnetmask) == v->uv_subnet) + fatal("Unnecessary tunnel to %s", + inet_fmt($3,s1)); + } + + if (numvifs == MAXVIFS) + fatal("too many vifs"); + + v = &uvifs[numvifs]; + v->uv_flags = VIFF_TUNNEL; + v->uv_metric = DEFAULT_METRIC; + v->uv_rate_limit= DEFAULT_TUN_RATE_LIMIT; + v->uv_threshold = DEFAULT_THRESHOLD; + v->uv_lcl_addr = $2; + v->uv_rmt_addr = $3; + v->uv_subnet = 0; + v->uv_subnetmask= 0; + v->uv_subnetbcast= 0; + strncpy(v->uv_name, ffr.ifr_name, IFNAMSIZ); + v->uv_groups = NULL; + v->uv_neighbors = NULL; + v->uv_acl = NULL; + v->uv_addrs = NULL; + + if (!(ffr.ifr_flags & IFF_UP)) { + v->uv_flags |= VIFF_DOWN; + vifs_down = TRUE; + } + /*log(LOG_INFO, 0, "tunnel: %x\n", v);*/ + } + tunnelmods + { + log(LOG_INFO, 0, + "installing tunnel from %s to %s as vif #%u - rate=%d", + inet_fmt($2, s1), inet_fmt($3, s2), + numvifs, v->uv_rate_limit); + + ++numvifs; + } + | PRUNING BOOLEAN { pruning = $2; } + | CACHE_LIFETIME NUMBER { cache_lifetime = $2; + max_prune_lifetime = cache_lifetime * 2; + } + | NAME STRING boundary { if (numbounds >= MAXBOUNDS) { + fatal("Too many named boundaries (max %d)", MAXBOUNDS); + } + + boundlist[numbounds].name = malloc(strlen($2) + 1); + strcpy(boundlist[numbounds].name, $2); + boundlist[numbounds++].bound = $3; + } + ; + +tunnelmods : /* empty */ + | tunnelmods /*{ log(LOG_INFO, 0, "tunnelmod: %x", v); }*/ tunnelmod + ; + +tunnelmod : mod + | SRCRT { fatal("Source-route tunnels not supported"); } + ; + +ifmods : /* empty */ + | ifmods /*{ log(LOG_INFO, 0, "ifmod: %x", v); }*/ ifmod + ; + +ifmod : mod + | DISABLE { v->uv_flags |= VIFF_DISABLED; } + | NETMASK ADDR { + u_int32 subnet, mask; + + mask = $2; + subnet = v->uv_lcl_addr & mask; + if (!inet_valid_subnet(subnet, mask)) + fatal("Invalid netmask"); + v->uv_subnet = subnet; + v->uv_subnetmask = mask; + v->uv_subnetbcast = subnet | ~mask; + } + | ALTNET addrmask { + + struct phaddr *ph; + + ph = (struct phaddr *)malloc(sizeof(struct phaddr)); + if (ph == NULL) + fatal("out of memory"); + if ($2.mask) { + VAL_TO_MASK(ph->pa_subnetmask, $2.mask); + } else + ph->pa_subnetmask = v->uv_subnetmask; + ph->pa_subnet = $2.addr & ph->pa_subnetmask; + ph->pa_subnetbcast = ph->pa_subnet | ~ph->pa_subnetmask; + if ($2.addr & ~ph->pa_subnetmask) + warn("Extra subnet %s/%d has host bits set", + inet_fmt($2.addr,s1), $2.mask); + ph->pa_next = v->uv_addrs; + v->uv_addrs = ph; + + } + ; + +mod : THRESHOLD NUMBER { if ($2 < 1 || $2 > 255) + fatal("Invalid threshold %d",$2); + v->uv_threshold = $2; + } + | THRESHOLD { + + warn("Expected number after threshold keyword"); + + } + | METRIC NUMBER { if ($2 < 1 || $2 > UNREACHABLE) + fatal("Invalid metric %d",$2); + v->uv_metric = $2; + } + | METRIC { + + warn("Expected number after metric keyword"); + + } + | RATE_LIMIT NUMBER { if ($2 > MAX_RATE_LIMIT) + fatal("Invalid rate_limit %d",$2); + v->uv_rate_limit = $2; + } + | RATE_LIMIT { + + warn("Expected number after rate_limit keyword"); + + } + | BOUNDARY bound { + + struct vif_acl *v_acl; + + v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl)); + if (v_acl == NULL) + fatal("out of memory"); + VAL_TO_MASK(v_acl->acl_mask, $2.mask); + v_acl->acl_addr = $2.addr & v_acl->acl_mask; + if ($2.addr & ~v_acl->acl_mask) + warn("Boundary spec %s/%d has host bits set", + inet_fmt($2.addr,s1),$2.mask); + v_acl->acl_next = v->uv_acl; + v->uv_acl = v_acl; + + } + | BOUNDARY { + + warn("Expected boundary spec after boundary keyword"); + + } + ; + +interface : ADDR { $$ = $1; } + | STRING { + $$ = valid_if($1); + if ($$ == 0) + fatal("Invalid interface name %s",$1); + } + ; + +bound : boundary { $$ = $1; } + | STRING { int i; + + for (i=0; i < numbounds; i++) { + if (!strcmp(boundlist[i].name, $1)) { + $$ = boundlist[i].bound; + break; + } + } + if (i == numbounds) { + fatal("Invalid boundary name %s",$1); + } + } + ; + +boundary : ADDRMASK { + + if ((ntohl($1.addr) & 0xff000000) != 0xef000000) { + fatal("Boundaries must be 239.x.x.x, not %s/%d", + inet_fmt($1.addr, s1), $1.mask); + } + $$ = $1; + + } + ; + +addrmask : ADDRMASK { $$ = $1; } + | ADDR { $$.addr = $1; $$.mask = 0; } + ; +%% +#ifdef __STDC__ +static void +fatal(char *fmt, ...) +{ + va_list ap; + char buf[200]; + + va_start(ap, fmt); +#else +/*VARARGS1*/ +static void +fatal(fmt, va_alist) +char *fmt; +va_dcl +{ + va_list ap; + char buf[200]; + + va_start(ap); +#endif + vsprintf(buf, fmt, ap); + va_end(ap); + + log(LOG_ERR,0,"%s: %s near line %d", configfilename, buf, lineno); +} + +#ifdef __STDC__ +static void +warn(char *fmt, ...) +{ + va_list ap; + char buf[200]; + + va_start(ap, fmt); +#else +/*VARARGS1*/ +static void +warn(fmt, va_alist) +char *fmt; +va_dcl +{ + va_list ap; + char buf[200]; + + va_start(ap); +#endif + vsprintf(buf, fmt, ap); + va_end(ap); + + log(LOG_WARNING,0,"%s: %s near line %d", configfilename, buf, lineno); +} + +static void +yyerror(s) +char *s; +{ + log(LOG_ERR, 0, "%s: %s near line %d", configfilename, s, lineno); +} + +static char * +next_word() +{ + static char buf[1024]; + static char *p=NULL; + extern FILE *f; + char *q; + + while (1) { + if (!p || !*p) { + lineno++; + if (fgets(buf, sizeof(buf), f) == NULL) + return NULL; + p = buf; + } + while (*p && (*p == ' ' || *p == '\t')) /* skip whitespace */ + p++; + if (*p == '#') { + p = NULL; /* skip comments */ + continue; + } + q = p; + while (*p && *p != ' ' && *p != '\t' && *p != '\n') + p++; /* find next whitespace */ + *p++ = '\0'; /* null-terminate string */ + + if (!*q) { + p = NULL; + continue; /* if 0-length string, read another line */ + } + + return q; + } +} + +static int +yylex() +{ + int n; + u_int32 addr; + char *q; + + if ((q = next_word()) == NULL) { + return 0; + } + + if (!strcmp(q,"cache_lifetime")) + return CACHE_LIFETIME; + if (!strcmp(q,"pruning")) + return PRUNING; + if (!strcmp(q,"phyint")) + return PHYINT; + if (!strcmp(q,"tunnel")) + return TUNNEL; + if (!strcmp(q,"disable")) + return DISABLE; + if (!strcmp(q,"metric")) + return METRIC; + if (!strcmp(q,"threshold")) + return THRESHOLD; + if (!strcmp(q,"rate_limit")) + return RATE_LIMIT; + if (!strcmp(q,"srcrt") || !strcmp(q,"sourceroute")) + return SRCRT; + if (!strcmp(q,"boundary")) + return BOUNDARY; + if (!strcmp(q,"netmask")) + return NETMASK; + if (!strcmp(q,"name")) + return NAME; + if (!strcmp(q,"altnet")) + return ALTNET; + if (!strcmp(q,"on") || !strcmp(q,"yes")) { + yylval.num = 1; + return BOOLEAN; + } + if (!strcmp(q,"off") || !strcmp(q,"no")) { + yylval.num = 0; + return BOOLEAN; + } + if (sscanf(q,"%[.0-9]/%d%c",s1,&n,s2) == 2) { + if ((addr = inet_parse(s1)) != 0xffffffff) { + yylval.addrmask.mask = n; + yylval.addrmask.addr = addr; + return ADDRMASK; + } + /* fall through to returning STRING */ + } + if (sscanf(q,"%[.0-9]%c",s1,s2) == 1) { + if ((addr = inet_parse(s1)) != 0xffffffff && + inet_valid_host(addr)) { + yylval.addr = addr; + return ADDR; + } + } + if (sscanf(q,"0x%8x%c",&n,s1) == 1) { + yylval.addr = n; + return ADDR; + } + if (sscanf(q,"%d%c",&n,s1) == 1) { + yylval.num = n; + return NUMBER; + } + yylval.ptr = q; + return STRING; +} + +void +config_vifs_from_file() +{ + extern FILE *f; + + order = 0; + numbounds = 0; + lineno = 0; + + if ((f = fopen(configfilename, "r")) == NULL) { + if (errno != ENOENT) + log(LOG_ERR, errno, "can't open %s", configfilename); + return; + } + + ifc.ifc_buf = (char *)ifbuf; + ifc.ifc_len = sizeof(ifbuf); + if (ioctl(udp_socket, SIOCGIFCONF, (char *)&ifc) < 0) + log(LOG_ERR, errno, "ioctl SIOCGIFCONF"); + + yyparse(); + + fclose(f); +} + +static u_int32 +valid_if(s) +char *s; +{ + register vifi_t vifi; + register struct uvif *v; + + for (vifi=0, v=uvifs; vifi<numvifs; vifi++, v++) + if (!strcmp(v->uv_name, s)) + return v->uv_lcl_addr; + + return 0; +} + +static struct ifreq * +ifconfaddr(ifcp, a) + struct ifconf *ifcp; + u_int32 a; +{ + int n; + struct ifreq *ifrp = (struct ifreq *)ifcp->ifc_buf; + struct ifreq *ifend = (struct ifreq *)((char *)ifrp + ifcp->ifc_len); + + while (ifrp < ifend) { + if (ifrp->ifr_addr.sa_family == AF_INET && + ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr == a) + return (ifrp); +#if (defined(BSD) && (BSD >= 199006)) + n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); + if (n < sizeof(*ifrp)) + ++ifrp; + else + ifrp = (struct ifreq *)((char *)ifrp + n); +#else + ++ifrp; +#endif + } + return (0); +} diff --git a/usr.sbin/mrouted/mtrace.8 b/usr.sbin/mrouted/mtrace.8 new file mode 100644 index 0000000000000..c4ac21866af70 --- /dev/null +++ b/usr.sbin/mrouted/mtrace.8 @@ -0,0 +1,498 @@ +.\" Copyright (c) 1995 by the University of Southern California +.\" All rights reserved. +.\" +.\" Permission to use, copy, modify, and distribute this software and its +.\" documentation in source and binary forms for non-commercial purposes +.\" and without fee is hereby granted, provided that the above copyright +.\" notice appear in all copies and that both the copyright notice and +.\" this permission notice appear in supporting documentation, and that +.\" any documentation, advertising materials, and other materials related +.\" to such distribution and use acknowledge that the software was +.\" developed by the University of Southern California, Information +.\" Sciences Institute. The name of the University may not be used to +.\" endorse or promote products derived from this software without +.\" specific prior written permission. +.\" +.\" THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about +.\" the suitability of this software for any purpose. THIS SOFTWARE IS +.\" PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, +.\" INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" Other copyrights might apply to parts of this software and are so +.\" noted when applicable. +.\" +.\" This manual page (but not the software) was derived from the +.\" manual page for the traceroute program which bears the following +.\" copyright notice: +.\" +.\" Copyright (c) 1988 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" $Id: mtrace.8,v 3.6 1995/06/25 19:14:07 fenner Exp $ +.\" +.TH MTRACE 8 "May 8, 1995" +.UC 6 +.SH NAME +mtrace \- print multicast path from a source to a receiver +.SH SYNOPSIS +.B mtrace +[ +.B \-g +.I gateway +] [ +.B \-i +.I if_addr +] [ +.B \-l +] [ +.B \-M +] [ +.B \-m +.I max_hops +] [ +.B \-n +] [ +.B \-p +] [ +.B \-q +.I nqueries +] [ +.B \-r +.I resp_dest +] [ +.B \-s +] [ +.B \-t +.I ttl +] [ +.B \-w +.I waittime +] +.I source +[ +.I receiver +] [ +.I group +] +.SH DESCRIPTION +Assessing problems in the distribution of IP multicast traffic +can be difficult. +.B mtrace +utilizes a tracing feature implemented in multicast routers +.RB ( mrouted +version 3.3 and later) that is +accessed via an extension to the IGMP protocol. A trace query is +passed hop-by-hop along the reverse path from the +.I receiver +to the +.IR source , +collecting hop addresses, packet counts, and routing error conditions +along the path, and then the response is returned to the requestor. +.PP +The only required parameter is the +.I source +host name or address. The default +.I receiver +is the host running mtrace, and the default +.I group +is "MBone Audio" (224.2.0.1), which is sufficient if packet loss +statistics for a particular multicast group are not needed. These two +optional parameters may be specified to test the path to some other +receiver in a particular group, subject to some constraints as +detailed below. The two parameters can be distinguished because the +.I receiver +is a unicast address and the +.I group +is a multicast address. +.SH OPTIONS +.TP 8 8 +.BI \-g\ gwy +Send the trace query via unicast directly to the multicast router +.I gwy +rather than multicasting the query. +This must be the last-hop router on the path from the intended +.I source +to the +.IR receiver . +.RS 8 +.TP 12 12 +.I CAUTION!! +Version 3.3 of +.B mrouted +will crash if a trace query is received via a +unicast packet and +.B mrouted +has no route for the +.I source +address. Therefore, do not use the +.B \-g +option unless the target +.B mrouted +has been verified to be newer than 3.3. +.RE +.TP 8 8 +.BI \-i\ addr +Use +.I addr +as the local interface address (on a multi-homed host) for sending the +trace query and as the default for the +.I receiver +and the response destination. +.TP 8 8 +.B \-l +Loop indefinitely printing packet rate and loss statistics for the +multicast path every 10 seconds. +.TP 8 8 +.B \-M +Always send the response using multicast rather than attempting +unicast first. +.TP 8 8 +.BI \-m\ n +Set to +.I n +the maximum number of hops that will be traced from the +.I receiver +back toward the +.IR source . +The default is 32 hops (infinity for the DVMRP routing protocol). +.TP 8 8 +.B \-n +Print hop addresses numerically rather than symbolically and numerically +(saves a nameserver address-to-name lookup for each router found on the +path). +.TP 8 8 +.BI \-q\ n +Set the maximum number of query attempts for any hop to +.IR n . +The default is 3. +.TP 8 8 +.B \-p +Listen passively for multicast responses from traces initiated by +others (not implemented yet). +.TP 8 8 +.BI \-r\ host +Send the trace response to +.I host +rather than to the host on which +.B mtrace +is being run, or to a multicast address other than the one registered +for this purpose (224.0.1.32). +.TP 8 8 +.B \-s +Print a short form output including only the multicast path and not +the packet rate and loss statistics. +.TP 8 8 +.BI \-t\ ttl +Set the +.I ttl +(time-to-live, or number of hops) for multicast trace queries and +responses. The default is 64, except for local queries to the "all +routers" multicast group which use ttl 1. +.TP 8 8 +.BI \-w\ n +Set the time to wait for a trace response to +.I n +seconds (default 3 seconds). +.SH USAGE +.SS How It Works +The technique used by the +.B traceroute +tool to trace unicast network paths will not work for IP multicast +because ICMP responses are specifically forbidden for multicast traffic. +Instead, a tracing feature has been built into the multicast routers. +This technique has the advantage that additional information about +packet rates and losses can be accumulated while the number of packets +sent is minimized. +.PP +Since multicast uses +reverse path forwarding, the trace is run backwards from the +.I receiver +to the +.IR source . +A trace query packet is sent to the last +hop multicast router (the leaf router for the desired +.I receiver +address). The last hop router builds a trace response packet, fills in +a report for its hop, and forwards the trace packet using unicast to +the router it believes is the previous hop for packets originating +from the specified +.IR source . +Each router along the path adds its report and forwards the packet. +When the trace response packet reaches the first hop router (the router +that is directly connected to the source's net), that router sends the +completed response to the response destination address specified in +the trace query. +.PP +If some multicast router along the path does not implement the +multicast traceroute feature or if there is some outage, then no +response will be returned. To solve this problem, the trace query +includes a maximum hop count field to limit the number of hops traced +before the response is returned. That allows a partial path to be +traced. +.PP +The reports inserted by each router contain not only the address of +the hop, but also the ttl required to forward and some flags to indicate +routing errors, plus counts of the total number of packets on the +incoming and outgoing interfaces and those forwarded for the specified +.IR group . +Taking differences in these counts for two traces separated in time +and comparing the output packet counts from one hop with the input +packet counts of the next hop allows the calculation of packet rate +and packet loss statistics for each hop to isolate congestion +problems. +.SS Finding the Last-Hop Router +The trace query must be sent to the multicast router which is the +last hop on the path from the +.I source +to the +.IR receiver . +If the receiver is on the local subnet (as determined using the subnet +mask), then the default method is to multicast the trace query to +all-routers.mcast.net (224.0.0.2) with a ttl of 1. Otherwise, the +trace query is multicast to the +.I group +address since the last hop router will be a member of that group if +the receiver is. Therefore it is necessary to specify a group that +the intended receiver has joined. This multicast is sent with a +default ttl of 64, which may not be sufficient for all cases (changed +with the +.B \-t +option). +If the last hop router is known, it may also be addressed directly +using the +.B \-g +option). Alternatively, if it is desired to trace a group that the +receiver has not joined, but it is known that the last-hop router is a +member of another group, the +.B \-g +option may also be used to specify a different multicast address for the +trace query. +.PP +When tracing from a multihomed host or router, the default receiver +address may not be the desired interface for the path from the source. +In that case, the desired interface should be specified explicitly as +the +.IR receiver . +.SS Directing the Response +By default, +.B mtrace +first attempts to trace the full reverse path, unless the number of +hops to trace is explicitly set with the +.B \-m +option. If there is no response within a 3 second timeout interval +(changed with the +.B \-w +option), a "*" is printed and the probing switches to hop-by-hop mode. +Trace queries are issued starting with a maximum hop count of one and +increasing by one until the full path is traced or no response is +received. At each hop, multiple probes are sent (default is three, +changed with +.B \-q +option). The first half of the attempts (default is one) are made with +the unicast address of the host running +.B mtrace +as the destination for the response. Since the unicast route may be +blocked, the remainder of attempts request that the response be +multicast to mtrace.mcast.net (224.0.1.32) with the ttl set to 32 more +than what's needed to pass the thresholds seen so far along the path +to the receiver. For the last quarter of the attempts (default is +one), the ttl is increased by another 32 each time up to a maximum of +192. Alternatively, the ttl may be set explicity with the +.B \-t +option and/or the initial unicast attempts can be forced to use +multicast instead with the +.B \-M +option. For each attempt, if no response is received within the +timeout, a "*" is printed. After the specified number of attempts +have failed, +.B mtrace +will try to query the next hop router with a DVMRP_ASK_NEIGHBORS2 +request (as used by the +.B mrinfo +program) to see what kind of router it is. +.SH EXAMPLES +The output of +.B mtrace +is in two sections. The first section is a short listing of the hops +in the order they are queried, that is, in the reverse of the order +from the +.I source +to the +.IR receiver . +For each hop, a line is printed showing the hop number (counted +negatively to indicate that this is the reverse path); the multicast +routing protocol (DVMRP, MOSPF, PIM, etc.); the threshold required to +forward data (to the previous hop in the listing as indicated by the +up-arrow character); and the cumulative delay for the query to reach +that hop (valid only if the clocks are synchronized). This first +section ends with a line showing the round-trip time which measures +the interval from when the query is issued until the response is +received, both derived from the local system clock. A sample use and +output might be: +.PP +.nf +.ft C +oak.isi.edu 80# mtrace -l caraway.lcs.mit.edu 224.2.0.3 +Mtrace from 18.26.0.170 to 128.9.160.100 via group 224.2.0.3 +Querying full reverse path... + 0 oak.isi.edu (128.9.160.100) + -1 cub.isi.edu (128.9.160.153) DVMRP thresh^ 1 3 ms + -2 la.dart.net (140.173.128.1) DVMRP thresh^ 1 14 ms + -3 dc.dart.net (140.173.64.1) DVMRP thresh^ 1 50 ms + -4 bbn.dart.net (140.173.32.1) DVMRP thresh^ 1 63 ms + -5 mit.dart.net (140.173.48.2) DVMRP thresh^ 1 71 ms + -6 caraway.lcs.mit.edu (18.26.0.170) +Round trip time 124 ms +.fi +.PP +The second section provides a pictorial view of the path in the +forward direction with data flow indicated by arrows pointing downward +and the query path indicated by arrows pointing upward. For each hop, +both the entry and exit addresses of the router are shown if +different, along with the initial ttl required on the packet in order +to be forwarded at this hop and the propagation delay across the hop +assuming that the routers at both ends have synchronized clocks. The +right half of this section is composed of several columns of +statistics in two groups. Within each group, the columns are the +number of packets lost, the number of packets sent, the percentage +lost, and the average packet rate at each hop. These statistics are +calculated from differences between traces and from hop to hop as +explained above. The first group shows the statistics for all traffic +flowing out the interface at one hop and in the interface at the next +hop. The second group shows the statistics only for traffic forwarded +from the specified +.I source +to the specified +.IR group . +.PP +These statistics are shown on one or two lines for each hop. Without +any options, this second section of the output is printed only once, +approximately 10 seconds after the initial trace. One line is shown +for each hop showing the statistics over that 10-second period. If +the +.B \-l +option is given, the second section is repeated every 10 seconds and +two lines are shown for each hop. The first line shows the statistics +for the last 10 seconds, and the second line shows the cumulative +statistics over the period since the initial trace, which is 101 +seconds in the example below. The second section of the output is +omitted if the +.B \-s +option is set. +.ie t \{\ +.ft C +. ie \w'i'<>\w'm' \{\" looks like this is not proper Courier font +(If this example is not properly columned with a fixed-width font, get +.B groff +and try again.) +. \} +.\} +.PP +.ft C +.nf +Waiting to accumulate statistics... Results after 101 seconds: + + Source Response Dest Packet Statistics For Only For Traffic +18.26.0.170 128.9.160.100 All Multicast Traffic From 18.26.0.170 + | __/ rtt 125 ms Lost/Sent = Pct Rate To 224.2.0.3 + v / hop 65 ms --------------------- ------------------ +18.26.0.144 +140.173.48.2 mit.dart.net + | ^ ttl 1 0/6 = --% 0 pps 0/2 = --% 0 pps + v | hop 8 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps +140.173.48.1 +140.173.32.1 bbn.dart.net + | ^ ttl 2 0/6 = --% 0 pps 0/2 = --% 0 pps + v | hop 12 ms 1/52 = 2% 0 pps 0/18 = 0% 0 pps +140.173.32.2 +140.173.64.1 dc.dart.net + | ^ ttl 3 0/271 = 0% 27 pps 0/2 = --% 0 pps + v | hop 34 ms -1/2652 = 0% 26 pps 0/18 = 0% 0 pps +140.173.64.2 +140.173.128.1 la.dart.net + | ^ ttl 4 -2/831 = 0% 83 pps 0/2 = --% 0 pps + v | hop 11 ms -3/8072 = 0% 79 pps 0/18 = 0% 0 pps +140.173.128.2 +128.9.160.153 cub.isi.edu + | \\__ ttl 5 833 83 pps 2 0 pps + v \\ hop -8 ms 8075 79 pps 18 0 pps +128.9.160.100 128.9.160.100 + Receiver Query Source +.fi +.PP +Because the packet counts may be changing as the trace query is +propagating, there may be small errors (off by 1 or 2) in these +statistics. However, those errors should not accumulate, so the +cumulative statistics line should increase in accuracy as a new trace +is run every 10 seconds. There are two sources of larger errors, both +of which show up as negative losses: +.LP +.RS +.PD 0 +.TP 3 +\(bu +If the input to a node is from a multi-access network with more than +one other node attached, then the input count will be (close to) the +sum of the output counts from all the attached nodes, but the output +count from the previous hop on the traced path will be only part of +that. Hence the output count minus the input count will be negative. +.TP 3 +\(bu +In release 3.3 of the DVMRP multicast forwarding software for SunOS +and other systems, a multicast packet generated on a router will be +counted as having come in an interface even though it did not. This +creates the negative loss that can be seen in the example above. +.PD +.RE +.LP +Note that these negative losses may mask positive losses. +.PP +In the example, there is also one negative hop time. This simply +indicates a lack of synchronization between the system clocks across +that hop. This example also illustrates how the percentage loss is +shown as two dashes when the number of packets sent is less than 10 +because the percentage would not be statistically valid. +.PP +A second example shows a trace to a receiver that is not local; the +query is sent to the last-hop router with the +.B \-g +option. In this example, the trace of the full reverse path resulted +in no response because there was a node running an old version of +.B mrouted +that did not implement the multicast traceroute function, so +.B mtrace +switched to hop-by-hop mode. The \*(lqRoute pruned\*(rq error code +indicates that traffic for group 224.2.143.24 would not be forwarded. +.PP +.nf +.ft C +oak.isi.edu 108# mtrace -g 140.173.48.2 204.62.246.73 \\ + butter.lcs.mit.edu 224.2.143.24 +Mtrace from 204.62.246.73 to 18.26.0.151 via group 224.2.143.24 +Querying full reverse path... * switching to hop-by-hop: + 0 butter.lcs.mit.edu (18.26.0.151) + -1 jam.lcs.mit.edu (18.26.0.144) DVMRP thresh^ 1 33 ms Route pruned + -2 bbn.dart.net (140.173.48.1) DVMRP thresh^ 1 36 ms + -3 dc.dart.net (140.173.32.2) DVMRP thresh^ 1 44 ms + -4 darpa.dart.net (140.173.240.2) DVMRP thresh^ 16 47 ms + -5 * * * noc.hpc.org (192.187.8.2) [mrouted 2.2] didn't respond +Round trip time 95 ms +.fi +.SH AUTHOR +Implemented by Steve Casner based on an initial prototype written by +Ajit Thyagarajan. The multicast traceroute mechanism was designed by +Van Jacobson with help from Steve Casner, Steve Deering, Dino +Farinacci, and Deb Agrawal; it was implemented in +.B mrouted +by Ajit Thyagarajan and Bill Fenner. The option syntax and the output +format of +.B mtrace +are modeled after the unicast +.B traceroute +program written by Van Jacobson. +.SH SEE ALSO +.BR mrouted (8) , +.BR mrinfo (8) , +.BR map-mbone (8) , +.BR traceroute (8) diff --git a/usr.sbin/mrouted/pathnames.h b/usr.sbin/mrouted/pathnames.h new file mode 100644 index 0000000000000..22b0019f089d1 --- /dev/null +++ b/usr.sbin/mrouted/pathnames.h @@ -0,0 +1,25 @@ +/* + * The mrouted program is covered by the license in the accompanying file + * named "LICENSE". Use of the mrouted program represents acceptance of + * the terms and conditions listed in that file. + * + * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of + * Leland Stanford Junior University. + * + * + * $Id: pathnames.h,v 3.6 1995/06/25 19:17:45 fenner Exp $ + */ + +#define _PATH_MROUTED_CONF "/etc/mrouted.conf" + +#if (defined(BSD) && (BSD >= 199103)) +#define _PATH_MROUTED_PID "/var/run/mrouted.pid" +#define _PATH_MROUTED_GENID "/var/run/mrouted.genid" +#define _PATH_MROUTED_DUMP "/var/tmp/mrouted.dump" +#define _PATH_MROUTED_CACHE "/var/tmp/mrouted.cache" +#else +#define _PATH_MROUTED_PID "/etc/mrouted.pid" +#define _PATH_MROUTED_GENID "/etc/mrouted.genid" +#define _PATH_MROUTED_DUMP "/usr/tmp/mrouted.dump" +#define _PATH_MROUTED_CACHE "/usr/tmp/mrouted.cache" +#endif diff --git a/usr.sbin/mrouted/rsrr.c b/usr.sbin/mrouted/rsrr.c new file mode 100644 index 0000000000000..c7bbc892379f6 --- /dev/null +++ b/usr.sbin/mrouted/rsrr.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 1993 by the University of Southern California + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation in source and binary forms for non-commercial purposes + * and without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both the copyright notice and + * this permission notice appear in supporting documentation. and that + * any documentation, advertising materials, and other materials related + * to such distribution and use acknowledge that the software was + * developed by the University of Southern California, Information + * Sciences Institute. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about + * the suitability of this software for any purpose. THIS SOFTWARE IS + * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Other copyrights might apply to parts of this software and are so + * noted when applicable. + */ + +/* RSRR code written by Daniel Zappala, USC Information Sciences Institute, + * April 1995. + */ + +/* May 1995 -- Added support for Route Change Notification */ + +#ifdef RSRR + +#include "defs.h" +#include <sys/param.h> +#if (defined(BSD) && (BSD >= 199103)) +#include <stddef.h> +#endif + +/* Taken from prune.c */ +/* + * checks for scoped multicast addresses + */ +#define GET_SCOPE(gt) { \ + register int _i; \ + if (((gt)->gt_mcastgrp & 0xff000000) == 0xef000000) \ + for (_i = 0; _i < numvifs; _i++) \ + if (scoped_addr(_i, (gt)->gt_mcastgrp)) \ + VIFM_SET(_i, (gt)->gt_scope); \ + } + +/* + * Exported variables. + */ +int rsrr_socket; /* interface to reservation protocol */ + +/* + * Global RSRR variables. + */ +char rsrr_recv_buf[RSRR_MAX_LEN]; /* RSRR receive buffer */ +char rsrr_send_buf[RSRR_MAX_LEN]; /* RSRR send buffer */ + +struct sockaddr_un client_addr; +int client_length = sizeof(client_addr); + + +/* + * Procedure definitions needed internally. + */ +static void rsrr_accept __P((int recvlen)); +static void rsrr_accept_iq __P((void)); +static int rsrr_accept_rq __P((struct rsrr_rq *route_query, int flags, + struct gtable *gt_notify)); +static int rsrr_send __P((int sendlen)); +static void rsrr_cache __P((struct gtable *gt, + struct rsrr_rq *route_query)); + +/* Initialize RSRR socket */ +void +rsrr_init() +{ + int servlen; + struct sockaddr_un serv_addr; + + if ((rsrr_socket = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) + log(LOG_ERR, errno, "Can't create RSRR socket"); + + unlink(RSRR_SERV_PATH); + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, RSRR_SERV_PATH); +#if (defined(BSD) && (BSD >= 199103)) + servlen = offsetof(struct sockaddr_un, sun_path) + + strlen(serv_addr.sun_path); + serv_addr.sun_len = servlen; +#else + servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path); +#endif + + if (bind(rsrr_socket, (struct sockaddr *) &serv_addr, servlen) < 0) + log(LOG_ERR, errno, "Can't bind RSRR socket"); + + if (register_input_handler(rsrr_socket,rsrr_read) < 0) + log(LOG_WARNING, 0, "Couldn't register RSRR as an input handler"); +} + +/* Read a message from the RSRR socket */ +void +rsrr_read(rfd) + fd_set *rfd; +{ + register int rsrr_recvlen; + register int omask; + + bzero((char *) &client_addr, sizeof(client_addr)); + rsrr_recvlen = recvfrom(rsrr_socket, rsrr_recv_buf, sizeof(rsrr_recv_buf), + 0, (struct sockaddr *)&client_addr, &client_length); + if (rsrr_recvlen < 0) { + if (errno != EINTR) + log(LOG_ERR, errno, "RSRR recvfrom"); + return; + } + /* Use of omask taken from main() */ + omask = sigblock(sigmask(SIGALRM)); + rsrr_accept(rsrr_recvlen); + (void)sigsetmask(omask); +} + +/* Accept a message from the reservation protocol and take + * appropriate action. + */ +static void +rsrr_accept(recvlen) + int recvlen; +{ + struct rsrr_header *rsrr; + struct rsrr_rq *route_query; + + if (recvlen < RSRR_HEADER_LEN) { + log(LOG_WARNING, 0, + "Received RSRR packet of %d bytes, which is less than min size", + recvlen); + return; + } + + rsrr = (struct rsrr_header *) rsrr_recv_buf; + + if (rsrr->version > RSRR_MAX_VERSION) { + log(LOG_WARNING, 0, + "Received RSRR packet version %d, which I don't understand", + rsrr->version); + return; + } + + switch (rsrr->version) { + case 1: + switch (rsrr->type) { + case RSRR_INITIAL_QUERY: + /* Send Initial Reply to client */ + log(LOG_INFO, 0, "Received Initial Query\n"); + rsrr_accept_iq(); + break; + case RSRR_ROUTE_QUERY: + /* Check size */ + if (recvlen < RSRR_RQ_LEN) { + log(LOG_WARNING, 0, + "Received Route Query of %d bytes, which is too small", + recvlen); + break; + } + /* Get the query */ + route_query = (struct rsrr_rq *) (rsrr_recv_buf + RSRR_HEADER_LEN); + log(LOG_INFO, 0, + "Received Route Query for src %s grp %s notification %d", + inet_fmt(route_query->source_addr.s_addr, s1), + inet_fmt(route_query->dest_addr.s_addr,s2), + BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)); + /* Send Route Reply to client */ + rsrr_accept_rq(route_query,rsrr->flags,NULL); + break; + default: + log(LOG_WARNING, 0, + "Received RSRR packet type %d, which I don't handle", + rsrr->type); + break; + } + break; + + default: + log(LOG_WARNING, 0, + "Received RSRR packet version %d, which I don't understand", + rsrr->version); + break; + } +} + +/* Send an Initial Reply to the reservation protocol. */ +static void +rsrr_accept_iq() +{ + struct rsrr_header *rsrr; + struct rsrr_vif *vif_list; + struct uvif *v; + int vifi, sendlen; + + /* Check for space. There should be room for plenty of vifs, + * but we should check anyway. + */ + if (numvifs > RSRR_MAX_VIFS) { + log(LOG_WARNING, 0, + "Can't send RSRR Route Reply because %d is too many vifs %d", + numvifs); + return; + } + + /* Set up message */ + rsrr = (struct rsrr_header *) rsrr_send_buf; + rsrr->version = 1; + rsrr->type = RSRR_INITIAL_REPLY; + rsrr->flags = 0; + rsrr->num = numvifs; + + vif_list = (struct rsrr_vif *) (rsrr_send_buf + RSRR_HEADER_LEN); + + /* Include the vif list. */ + for (vifi=0, v = uvifs; vifi < numvifs; vifi++, v++) { + vif_list[vifi].id = vifi; + vif_list[vifi].status = 0; + if (v->uv_flags & VIFF_DISABLED) + BIT_SET(vif_list[vifi].status,RSRR_DISABLED_BIT); + vif_list[vifi].threshold = v->uv_threshold; + vif_list[vifi].local_addr.s_addr = v->uv_lcl_addr; + } + + /* Get the size. */ + sendlen = RSRR_HEADER_LEN + numvifs*RSRR_VIF_LEN; + + /* Send it. */ + log(LOG_INFO, 0, "Send RSRR Initial Reply"); + rsrr_send(sendlen); +} + +/* Send a Route Reply to the reservation protocol. The Route Query + * contains the query to which we are responding. The flags contain + * the incoming flags from the query or, for route change + * notification, the flags that should be set for the reply. The + * kernel table entry contains the routing info to use for a route + * change notification. + */ +static int +rsrr_accept_rq(route_query,flags,gt_notify) + struct rsrr_rq *route_query; + int flags; + struct gtable *gt_notify; +{ + struct rsrr_header *rsrr; + struct rsrr_rr *route_reply; + struct gtable *gt,local_g; + struct rtentry *r; + int sendlen,i; + u_long mcastgrp; + + /* Set up message */ + rsrr = (struct rsrr_header *) rsrr_send_buf; + rsrr->version = 1; + rsrr->type = RSRR_ROUTE_REPLY; + rsrr->flags = 0; + rsrr->num = 0; + + route_reply = (struct rsrr_rr *) (rsrr_send_buf + RSRR_HEADER_LEN); + route_reply->dest_addr.s_addr = route_query->dest_addr.s_addr; + route_reply->source_addr.s_addr = route_query->source_addr.s_addr; + route_reply->query_id = route_query->query_id; + + /* Blank routing entry for error. */ + route_reply->in_vif = 0; + route_reply->reserved = 0; + route_reply->out_vif_bm = 0; + + /* Get the size. */ + sendlen = RSRR_RR_LEN; + + /* If kernel table entry is defined, then we are sending a Route Reply + * due to a Route Change Notification event. Use the kernel table entry + * to supply the routing info. + */ + if (gt_notify) { + /* Set flags */ + rsrr->flags = flags; + /* Include the routing entry. */ + route_reply->in_vif = gt_notify->gt_route->rt_parent; + route_reply->out_vif_bm = gt_notify->gt_grpmems; + + } else if (find_src_grp(route_query->source_addr.s_addr, 0, + route_query->dest_addr.s_addr)) { + + /* Found kernel entry. Code taken from add_table_entry() */ + gt = gtp ? gtp->gt_gnext : kernel_table; + + /* Include the routing entry. */ + route_reply->in_vif = gt->gt_route->rt_parent; + route_reply->out_vif_bm = gt->gt_grpmems; + + /* Cache reply if using route change notification. */ + if BIT_TST(flags,RSRR_NOTIFICATION_BIT) { + rsrr_cache(gt,route_query); + BIT_SET(rsrr->flags,RSRR_NOTIFICATION_BIT); + } + + } else { + /* No kernel entry; use routing table. */ + r = determine_route(route_query->source_addr.s_addr); + + if (r != NULL) { + /* We need to mimic what will happen if a data packet + * is forwarded by multicast routing -- the kernel will + * make an upcall and mrouted will install a route in the kernel. + * Our outgoing vif bitmap should reflect what that table + * will look like. Grab code from add_table_entry(). + * This is gross, but it's probably better to be accurate. + */ + + gt = &local_g; + mcastgrp = route_query->dest_addr.s_addr; + + gt->gt_mcastgrp = mcastgrp; + gt->gt_grpmems = 0; + gt->gt_scope = 0; + gt->gt_route = r; + + /* obtain the multicast group membership list */ + for (i = 0; i < numvifs; i++) { + if (VIFM_ISSET(i, r->rt_children) && + !(VIFM_ISSET(i, r->rt_leaves))) + VIFM_SET(i, gt->gt_grpmems); + + if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp)) + VIFM_SET(i, gt->gt_grpmems); + } + + GET_SCOPE(gt); + gt->gt_grpmems &= ~gt->gt_scope; + + /* Include the routing entry. */ + route_reply->in_vif = gt->gt_route->rt_parent; + route_reply->out_vif_bm = gt->gt_grpmems; + + } else { + /* Set error bit. */ + BIT_SET(rsrr->flags,RSRR_ERROR_BIT); + } + } + + if (gt_notify) + log(LOG_INFO, 0, "Route Change: Send RSRR Route Reply"); + + else + log(LOG_INFO, 0, "Send RSRR Route Reply"); + + log(LOG_INFO, 0, "for src %s dst %s in vif %d out vif %d\n", + inet_fmt(route_reply->source_addr.s_addr,s1), + inet_fmt(route_reply->dest_addr.s_addr,s2), + route_reply->in_vif,route_reply->out_vif_bm); + + /* Send it. */ + return rsrr_send(sendlen); +} + +/* Send an RSRR message. */ +static int +rsrr_send(sendlen) + int sendlen; +{ + int error; + + /* Send it. */ + error = sendto(rsrr_socket, rsrr_send_buf, sendlen, 0, + (struct sockaddr *)&client_addr, client_length); + + /* Check for errors. */ + if (error < 0) { + log(LOG_WARNING, errno, "Failed send on RSRR socket"); + } else if (error != sendlen) { + log(LOG_WARNING, 0, + "Sent only %d out of %d bytes on RSRR socket\n", error, sendlen); + } + return error; +} + +/* Cache a message being sent to a client. Currently only used for + * caching Route Reply messages for route change notification. + */ +static void +rsrr_cache(gt,route_query) + struct gtable *gt; + struct rsrr_rq *route_query; +{ + struct rsrr_cache *rc, **rcnp; + struct rsrr_header *rsrr; + + rsrr = (struct rsrr_header *) rsrr_send_buf; + + rcnp = >->gt_rsrr_cache; + while ((rc = *rcnp) != NULL) { + if ((rc->route_query.source_addr.s_addr == + route_query->source_addr.s_addr) && + (rc->route_query.dest_addr.s_addr == + route_query->dest_addr.s_addr) && + (!strcmp(rc->client_addr.sun_path,client_addr.sun_path))) { + /* Cache entry already exists. + * Check if route notification bit has been cleared. + */ + if (!BIT_TST(rsrr->flags,RSRR_NOTIFICATION_BIT)) { + /* Delete cache entry. */ + *rcnp = rc->next; + free(rc); + } else { + /* Update */ + rc->route_query.query_id = route_query->query_id; + log(LOG_DEBUG, 0, + "Update cached query id %ld from client %s\n", + rc->route_query.query_id, rc->client_addr.sun_path); + } + return; + } + rcnp = &rc->next; + } + + /* Cache entry doesn't already exist. Create one and insert at + * front of list. + */ + rc = (struct rsrr_cache *) malloc(sizeof(struct rsrr_cache)); + if (rc == NULL) + log(LOG_ERR, 0, "ran out of memory"); + rc->route_query.source_addr.s_addr = route_query->source_addr.s_addr; + rc->route_query.dest_addr.s_addr = route_query->dest_addr.s_addr; + rc->route_query.query_id = route_query->query_id; + strcpy(rc->client_addr.sun_path, client_addr.sun_path); + rc->client_length = client_length; + rc->next = gt->gt_rsrr_cache; + gt->gt_rsrr_cache = rc; + log(LOG_DEBUG, 0, "Cached query id %ld from client %s\n", + rc->route_query.query_id,rc->client_addr.sun_path); +} + +/* Send all the messages in the cache. Currently this is used to send + * all the cached Route Reply messages for route change notification. + */ +void +rsrr_cache_send(gt,notify) + struct gtable *gt; + int notify; +{ + struct rsrr_cache *rc, **rcnp; + int flags = 0; + + if (notify) + BIT_SET(flags,RSRR_NOTIFICATION_BIT); + + rcnp = >->gt_rsrr_cache; + while ((rc = *rcnp) != NULL) { + if (rsrr_accept_rq(&rc->route_query,flags,gt) < 0) { + log(LOG_DEBUG, 0, "Deleting cached query id %ld from client %s\n", + rc->route_query.query_id,rc->client_addr.sun_path); + /* Delete cache entry. */ + *rcnp = rc->next; + free(rc); + } else { + rcnp = &rc->next; + } + } +} + +/* Clean the cache by deleting all entries. */ +void +rsrr_cache_clean(gt) + struct gtable *gt; +{ + struct rsrr_cache *rc,*rc_next; + + printf("cleaning cache for group %s\n",inet_fmt(gt->gt_mcastgrp, s1)); + rc = gt->gt_rsrr_cache; + while (rc) { + rc_next = rc->next; + free(rc); + rc = rc_next; + } + gt->gt_rsrr_cache = NULL; +} + +void +rsrr_clean() +{ + unlink(RSRR_SERV_PATH); +} + +#endif /* RSRR */ diff --git a/usr.sbin/mrouted/rsrr.h b/usr.sbin/mrouted/rsrr.h new file mode 100644 index 0000000000000..8bc8c91765353 --- /dev/null +++ b/usr.sbin/mrouted/rsrr.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1993 by the University of Southern California + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation in source and binary forms for non-commercial purposes + * and without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both the copyright notice and + * this permission notice appear in supporting documentation. and that + * any documentation, advertising materials, and other materials related + * to such distribution and use acknowledge that the software was + * developed by the University of Southern California, Information + * Sciences Institute. The name of the University may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THE UNIVERSITY OF SOUTHERN CALIFORNIA makes no representations about + * the suitability of this software for any purpose. THIS SOFTWARE IS + * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Other copyrights might apply to parts of this software and are so + * noted when applicable. + */ + +#define RSRR_SERV_PATH "/tmp/.rsrr_svr" +/* Note this needs to be 14 chars for 4.3 BSD compatibility */ +#define RSRR_CLI_PATH "/tmp/.rsrr_cli" + +#define RSRR_MAX_LEN 2048 +#define RSRR_HEADER_LEN (sizeof(struct rsrr_header)) +#define RSRR_RQ_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rq)) +#define RSRR_RR_LEN (RSRR_HEADER_LEN + sizeof(struct rsrr_rr)) +#define RSRR_VIF_LEN (sizeof(struct rsrr_vif)) + +/* Current maximum number of vifs. */ +#define RSRR_MAX_VIFS 32 + +/* Maximum acceptable version */ +#define RSRR_MAX_VERSION 1 + +/* RSRR message types */ +#define RSRR_ALL_TYPES 0 +#define RSRR_INITIAL_QUERY 1 +#define RSRR_INITIAL_REPLY 2 +#define RSRR_ROUTE_QUERY 3 +#define RSRR_ROUTE_REPLY 4 + +/* RSRR Initial Reply (Vif) Status bits + * Each definition represents the position of the bit from right to left. + * + * Right-most bit is the disabled bit, set if the vif is administratively + * disabled. + */ +#define RSRR_DISABLED_BIT 0 +/* All other bits are zeroes */ + +/* RSRR Route Query/Reply flag bits + * Each definition represents the position of the bit from right to left. + * + * Right-most bit is the Route Change Notification bit, set if the + * reservation protocol wishes to receive notification of + * a route change for the source-destination pair listed in the query. + * Notification is in the form of an unsolicitied Route Reply. + */ +#define RSRR_NOTIFICATION_BIT 0 +/* Next bit indicates an error returning the Route Reply. */ +#define RSRR_ERROR_BIT 1 +/* All other bits are zeroes */ + +/* Definition of an RSRR message header. + * An Initial Query uses only the header, and an Initial Reply uses + * the header and a list of vifs. + */ +struct rsrr_header { + u_char version; /* RSRR Version, currently 1 */ + u_char type; /* type of message, as defined above */ + u_char flags; /* flags; defined by type */ + u_char num; /* number; defined by type */ +}; + +/* Definition of a vif as seen by the reservation protocol. + * + * Routing gives the reservation protocol a list of vifs in the + * Initial Reply. + * + * We explicitly list the ID because we can't assume that all routing + * protocols will use the same numbering scheme. + * + * The status is a bitmask of status flags, as defined above. It is the + * responsibility of the reservation protocol to perform any status checks + * if it uses the MULTICAST_VIF socket option. + * + * The threshold indicates the ttl an outgoing packet needs in order to + * be forwarded. The reservation protocol must perform this check itself if + * it uses the MULTICAST_VIF socket option. + * + * The local address is the address of the physical interface over which + * packets are sent. + */ +struct rsrr_vif { + u_char id; /* vif id */ + u_char threshold; /* vif threshold ttl */ + u_short status; /* vif status bitmask */ + struct in_addr local_addr; /* vif local address */ +}; + +/* Definition of an RSRR Route Query. + * + * The query asks routing for the forwarding entry for a particular + * source and destination. The query ID uniquely identifies the query + * for the reservation protocol. Thus, the combination of the client's + * address and the query ID forms a unique identifier for routing. + * Flags are defined above. + */ +struct rsrr_rq { + struct in_addr dest_addr; /* destination */ + struct in_addr source_addr; /* source */ + u_long query_id; /* query ID */ +}; + +/* Definition of an RSRR Route Reply. + * + * Routing uses the reply to give the reservation protocol the + * forwarding entry for a source-destination pair. Routing copies the + * query ID from the query and fills in the incoming vif and a bitmask + * of the outgoing vifs. + * Flags are defined above. + */ +struct rsrr_rr { + struct in_addr dest_addr; /* destination */ + struct in_addr source_addr; /* source */ + u_long query_id; /* query ID */ + u_short in_vif; /* incoming vif */ + u_short reserved; /* reserved */ + u_long out_vif_bm; /* outgoing vif bitmask */ +}; diff --git a/usr.sbin/mrouted/testrsrr/Makefile b/usr.sbin/mrouted/testrsrr/Makefile new file mode 100644 index 0000000000000..9e710ff3a55e6 --- /dev/null +++ b/usr.sbin/mrouted/testrsrr/Makefile @@ -0,0 +1,14 @@ +# $Id: Makefile,v 1.1 1994/09/08 02:51:37 wollman Exp $ + +PROG= testrsrr + +S= ${.CURDIR}/.. +.PATH: $S +CFLAGS+= -I$S + +SRCS= testrsrr.c +NOMAN= + +install: + +.include <bsd.prog.mk> diff --git a/usr.sbin/mrouted/testrsrr/testrsrr.c b/usr.sbin/mrouted/testrsrr/testrsrr.c new file mode 100644 index 0000000000000..b99b593284f2c --- /dev/null +++ b/usr.sbin/mrouted/testrsrr/testrsrr.c @@ -0,0 +1,124 @@ +/* + * Copyright 1995 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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. + * + * $Id$ + */ +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <err.h> +#include <sysexits.h> + +#include <sys/param.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "rsrr.h" + +char sunpath[MAXPATHLEN]; +int s; + +void exitfn(void) { + close(s); + unlink(sunpath); +} + +int main(void) { + struct sockaddr_un sun; + char buf[RSRR_MAX_LEN]; + struct rsrr_header *rh; + struct rsrr_vif *rvp; + int i; + + s = socket(PF_LOCAL, SOCK_DGRAM, 0); + if (s < 0) { + err(EX_OSERR, "socket(PF_LOCAL, SOCK_DGRAM, 0)"); + } + + sun.sun_family = AF_LOCAL; + snprintf(sunpath, sizeof sun.sun_path, "/tmp/testrsrr.%lu", + (unsigned long)getpid()); + strcpy(sun.sun_path, sunpath); + sun.sun_len = (offsetof(struct sockaddr_un, sun_path) + + strlen(sunpath)); + + if (bind(s, (struct sockaddr *)&sun, sun.sun_len) < 0) { + err(EX_OSERR, "bind: %s", sunpath); + } + + atexit(exitfn); /* clean up if we exit on error */ + + strcpy(sun.sun_path, RSRR_SERV_PATH); + sun.sun_len = (offsetof(struct sockaddr_un, sun_path) + + strlen(sunpath)); + + if (connect(s, (struct sockaddr *)&sun, sun.sun_len) < 0) { + err(EX_OSERR, "connect: %s", RSRR_SERV_PATH); + } + + rh = (struct rsrr_header *)buf; + rh->version = RSRR_MAX_VERSION; + rh->type = RSRR_INITIAL_QUERY; + rh->flags = 0; + rh->num = 0; + + if (write(s, rh, sizeof *rh) == (ssize_t)-1) { + err(EX_OSERR, "write(initial query)"); + } + + if (read(s, buf, sizeof buf) == (ssize_t)-1) { + err(EX_OSERR, "read(initial reply)"); + } + + if (rh->version != RSRR_MAX_VERSION) { + errx(EX_PROTOCOL, "bad remote version %d", rh->version); + } + + if (rh->type != RSRR_INITIAL_REPLY) { + errx(EX_PROTOCOL, "remote returned unexpected message type %d", + rh->type); + } + + if (rh->flags) { + printf("confusing flags: %d\n", rh->flags); + } + + printf("There are %d vifs configured:\n", rh->num); + + printf(" Vif Thresh Status Local address\n"); + for(i = 0, rvp = (struct rsrr_vif *)(rh + 1); i < rh->num; i++,rvp++) { + printf(" %3d %6d %6d %s\n", rvp->id, rvp->threshold, + rvp->status, inet_ntoa(rvp->local_addr)); + } + exit(0); +} diff --git a/usr.sbin/named/tools/ndc/Makefile b/usr.sbin/named/tools/ndc/Makefile new file mode 100644 index 0000000000000..043d510015875 --- /dev/null +++ b/usr.sbin/named/tools/ndc/Makefile @@ -0,0 +1,25 @@ +MAN8= ndc.8 +CLEANFILES+=ndc + +PIDDIR=/var/run +INDOT= +PS=ps +IOT=IOT +DESTSBIN=${DESTDIR}${BINDIR} + +beforeinstall: + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 555 \ + ndc ${DESTDIR}${BINDIR} + +all: ndc + +ndc: ndc.sh Makefile + sed -e "s|%DESTSBIN%|${DESTSBIN}|" \ + -e "s|%INDOT%|${INDOT}|" \ + -e "s|%PIDDIR%|${PIDDIR}|" \ + -e "s|%PS%|${PS}|" \ + -e "s|%IOT%|${IOT}|" \ + < ${.CURDIR}/ndc.sh > ndc + +.include "${.CURDIR}/../../../Makefile.inc" +.include <bsd.prog.mk> diff --git a/usr.sbin/named/tools/ndc/ndc.8 b/usr.sbin/named/tools/ndc/ndc.8 new file mode 100644 index 0000000000000..46eda3926d511 --- /dev/null +++ b/usr.sbin/named/tools/ndc/ndc.8 @@ -0,0 +1,127 @@ +.\" Copyright (c) 1994 +.\" 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. +.\" +.TH NDC 8 "November 27, 1994" +.UC 5 +.SH NAME +ndc \- name daemon control interface +.SH SYNOPSYS +.B ndc +.I directive +[ ... ] +.SH DESCRIPTION +This command allows the name server administrator to send various signals +to the name server, or to restart it. Zero or more directives may be given, +from the following list: +.TP +.B status +Displays the current status of +.B named +as shown by +.BR ps (1). +.TP +.B dumpdb +Causes +.B named +to dump its database and cache to +.B /var/tmp/named_dump.db +(uses the INT signal.) +.TP +.B reload +Causes +.B named +to check the serial numbers of all primary and secondary zones +and to reload those that have changed (uses the HUP signal.) +.TP +.B stats +Causes +.B named +to dump its statistics to +.B /var/tmp/named.stats +(uses the IOT or ABRT signal.) +.TP +.B trace +Causes +.B named +to increment its ``tracing level'' by one. Whenever the tracing level +is nonzero, trace information will be written to +.BR /var/tmp/named.run . +Higher tracing levels result in more detailed information. +(Uses the USR1 signal.) +.TP +.B notrace +Causes +.B named +to set its ``tracing level'' to zero, closing +.B /var/tmp/named.run +if it is open (uses the USR2 signal.) +.TP +.B querylog +Causes +.B named +to toggle the ``query logging'' feature, which while on will result in a +.BR syslog (3) +of each incoming query (uses the WINCH signal.) Note that query logging +consumes quite a lot of log file space. This directive may also be given as +.BR qrylog . +.TP +.B start +Causes +.B named +to be started, as long as it isn't already running. +.TP +.B stop +Causes +.B named +to be stopped, if it is running. +.TP +.B restart +Causes +.B named +to be killed and restarted. +.SH BUGS +Arguments to +.B named +are not preserved by +.BR restart , +or known by +.BR start . +Some mechanism for controlling the parameters and environment should exist. +.PP +Implemented as a +.BR sh (1) +script. +.SH AUTHOR +Paul Vixie (Internet Software Consortium) +.SH SEE ALSO +named(8), +named.reload(8), +named.restart(8) diff --git a/usr.sbin/named/tools/ndc/ndc.sh b/usr.sbin/named/tools/ndc/ndc.sh new file mode 100644 index 0000000000000..b258d202c61dc --- /dev/null +++ b/usr.sbin/named/tools/ndc/ndc.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +USAGE='echo \ + "usage: $0 \ + (status|dumpdb|reload|stats|trace|notrace|querylog|start|stop|restart) \ + ... \ + "; exit 1' + +PATH=%DESTSBIN%:/bin:/usr/bin:/usr/ucb:$PATH +PIDFILE=%PIDDIR%/named.pid + +[ -f $PIDFILE ] || { + echo "$0: $PIDFILE does not exist" + exit 1 +} +PID=`cat $PIDFILE` +PS=`%PS% $PID | tail -1 | grep $PID` +RUNNING=1 +[ `echo $PS | wc -w` -ne 0 ] || { + PS="named (pid $PID?) not running" + RUNNING=0 +} + +for ARG +do + case $ARG in + start|stop|restart) + ;; + *) + [ $RUNNING -eq 0 ] && { + echo $PS + exit 1 + } + esac + + case $ARG in + status) echo "$PS";; + dumpdb) kill -INT $PID && echo Dumping Database;; + reload) kill -HUP $PID && echo Reloading Database;; + stats) kill -%IOT% $PID && echo Dumping Statistics;; + trace) kill -USR1 $PID && echo Trace Level Incremented;; + notrace) kill -USR2 $PID && echo Tracing Cleared;; + querylog|qrylog) kill -WINCH $PID && echo Query Logging Toggled;; + start) + [ $RUNNING -eq 1 ] && { + echo "$0: start: named (pid $PID) already running" + continue + } + # If there is a global system configuration file, suck it in. + if [ -f /etc/sysconfig ]; then + . /etc/sysconfig + fi + # $namedflags is imported from /etc/sysconfig + if [ "X${namedflags}" != "XNO" ]; then + %INDOT%named ${namedflags} && echo Name Server Started + fi + ;; + stop) + [ $RUNNING -eq 0 ] && { + echo "$0: stop: named not running" + continue + } + kill $PID && { + sleep 5 + echo Name Server Stopped + } + ;; + restart) + [ $RUNNING -eq 1 ] && { + kill $PID && sleep 5 + } + # If there is a global system configuration file, suck it in. + if [ -f /etc/sysconfig ]; then + . /etc/sysconfig + fi + # $namedflags is imported from /etc/sysconfig + if [ "X${namedflags}" != "XNO" ]; then + %INDOT%named ${namedflags} && echo Name Server Restarted + fi + ;; + *) eval "$USAGE";; + esac +done +test -z "$ARG" && eval "$USAGE" + +exit 0 diff --git a/usr.sbin/pkg_install/lib/ftp.c b/usr.sbin/pkg_install/lib/ftp.c new file mode 100644 index 0000000000000..7b78ee4c97543 --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.c @@ -0,0 +1,424 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * $Id: ftp.c,v 1.2 1995/07/31 02:27:58 jkh Exp $ + * + * Return values have been sanitized: + * -1 error, but you (still) have a session. + * -2 error, your session is dead. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <netdb.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <ctype.h> +#include "ftp.h" +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +/* Handy global for us to stick the port # */ +int FtpPort; + +static void +debug(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + va_list ap; + va_start(ap, fmt); + strcpy(p,"LIBFTP: "); + (void) vsnprintf(p+strlen(p), sizeof p - strlen(p), fmt, ap); + va_end(ap); + write(ftp->fd_debug,p,strlen(p)); +} + +static int +writes(int fd, char *s) +{ + int i = strlen(s); + if (i != write(fd,s,i)) + return -2; + return 0; +} + +static __inline char* +get_a_line(FTP_t ftp) +{ + static char buf[BUFSIZ]; + int i,j; + + for(i=0;i<BUFSIZ;) { + j = read(ftp->fd_ctrl,buf+i,1); + if (j != 1) + return 0; + if (buf[i] == '\r' || buf[i] == '\n') { + if (!i) + continue; + buf[i] = '\0'; + debug(ftp, "received <%s>\n",buf); + return buf; + } + i++; + } + return buf; +} + +static int +get_a_number(FTP_t ftp, char **q) +{ + char *p; + int i = -1,j; + + while(1) { + p = get_a_line(ftp); + if (!p) + return -2; + if (!(isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2]))) + continue; + if (i == -1 && p[3] == '-') { + i = strtol(p, 0, 0); + continue; + } + if (p[3] != ' ' && p[3] != '\t') + continue; + j = strtol(p, 0, 0); + if (i == -1) { + if (q) *q = p+4; + return j; + } else if (j == i) { + if (q) *q = p+4; + return j; + } + } +} + +static int +zap(FTP_t ftp) +{ + int i; + + i = writes(ftp->fd_ctrl,"QUIT\r\n"); + debug(ftp, "Zapping ftp connection on %d returns %d\n", ftp->fd_ctrl, i); + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = init; + return -2; +} + +static int +botch(FTP_t ftp, char *func, char *state) +{ + debug(ftp, "Botch: %s called outside state %s\n",func,state); + return -2; +} + +static int +cmd(FTP_t ftp, const char *fmt, ...) +{ + char p[BUFSIZ]; + int i; + + va_list ap; + va_start(ap, fmt); + (void) vsnprintf(p, sizeof p, fmt, ap); + va_end(ap); + + debug(ftp, "send <%s>\n",p); + strcat(p,"\r\n"); + if (writes(ftp->fd_ctrl,p)) + return -2; + i = get_a_number(ftp,0); + return i; +} + +FTP_t +FtpInit() +{ + FTP_t ftp; + + ftp = malloc(sizeof *ftp); + if (!ftp) + return ftp; + memset(ftp, 0, sizeof *ftp); + ftp->fd_ctrl = -1; + ftp->fd_xfer = -1; + ftp->fd_debug = -1; + ftp->state = init; + return ftp; +} + +void +FtpDebug(FTP_t ftp, int i) +{ + ftp->fd_debug = i; +} + +int +FtpOpen(FTP_t ftp, char *host, char *user, char *passwd) +{ + struct hostent *he = NULL; + struct sockaddr_in sin; + int s; + unsigned long temp; + int i; + + if (ftp->state != init) + return botch(ftp,"FtpOpen","init"); + + if (!user) + user = "ftp"; + + if (!passwd) + passwd = "??@??(FreeBSD:libftp)"; /* XXX */ + + debug(ftp, "FtpOpen(ftp, %s, %s, %s)\n", host, user, passwd); + + temp = inet_addr(host); + if (temp != INADDR_NONE) { + debug(ftp, "Using dotted IP address `%s'\n", host); + ftp->addrtype = sin.sin_family = AF_INET; + sin.sin_addr.s_addr = temp; + } + else { + debug(ftp, "Trying to resolve `%s'\n", host); + he = gethostbyname(host); + if (!he) { + debug(ftp, "Lookup of `%s' failed!\n", host); + return zap(ftp); + } + ftp->addrtype = sin.sin_family = he->h_addrtype; + bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length); + } + + sin.sin_port = htons(FtpPort ? FtpPort : 21); + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + { + debug(ftp, "Socket open failed: %s (%i)\n", strerror(errno), errno); + return zap(ftp); + } + + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + debug(ftp,"Connection failed: %s (%i)\n", strerror(errno), errno); + (void)close(s); + return zap(ftp); + } + + ftp->fd_ctrl = s; + + debug(ftp, "open (%d)\n",get_a_number(ftp,0)); + + i = cmd(ftp,"USER %s",user); + if (i >= 300 && i < 400) + i = cmd(ftp,"PASS %s",passwd); + if (i >= 299 || i < 0) { + close(ftp->fd_ctrl); ftp->fd_ctrl = -1; + return zap(ftp); + } + ftp->state = isopen; + return 0; +} + +void +FtpClose(FTP_t ftp) +{ + if (ftp->state != init) + return; + + if (ftp->state != isopen) + botch(ftp,"FtpClose","open or init"); + + debug(ftp, "FtpClose(ftp)\n"); + zap(ftp); +} + +int +FtpChdir(FTP_t ftp, char *dir) +{ + int i; + if (ftp->state != isopen) + return botch(ftp,"FtpChdir","open"); + i = cmd(ftp,"CWD %s",dir); + if (i < 0) + return i; + else if (i != 250) + return -1; + return 0; +} + +int +FtpGet(FTP_t ftp, char *file) +{ + int i,s; + char *q; + unsigned char addr[64]; + struct sockaddr_in sin; + u_long a; + + debug(ftp, "FtpGet(ftp,%s)\n",file); + if (ftp->state != isopen) + return botch(ftp,"FtpGet","open"); + if(ftp->binary) { + i = cmd(ftp,"TYPE I"); + if (i < 0) + return zap(ftp); + if (i > 299) + return -1; + } else { + return -1; + } + + if ((s = socket(ftp->addrtype, SOCK_STREAM, 0)) < 0) + return zap(ftp); + + if (ftp->passive) { + debug(ftp, "send <%s>\n","PASV"); + if (writes(ftp->fd_ctrl,"PASV\r\n")) + return zap(ftp); + i = get_a_number(ftp,&q); + if (i < 0) + return zap(ftp); + if (i != 227) + return zap(ftp); + while (*q && !isdigit(*q)) + q++; + if (!*q) + return zap(ftp); + q--; + for(i=0;i<6;i++) { + q++; + addr[i] = strtol(q,&q,10); + } + + sin.sin_family = ftp->addrtype; + bcopy(addr, (char *)&sin.sin_addr, 4); + bcopy(addr+4, (char *)&sin.sin_port, 2); + debug(ftp, "Opening active socket to %s : %u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + + debug(ftp, "Connecting to %s:%u\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + (void)close(s); + debug(ftp, "connect: %s (%d)\n", strerror(errno), errno); + return -1; + } + ftp->fd_xfer = s; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + debug(ftp, "FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->state = xfer; + return s; + } else { + i = sizeof sin; + getsockname(ftp->fd_ctrl,(struct sockaddr *)&sin,&i); + sin.sin_port = 0; + i = sizeof sin; + if (bind(s,(struct sockaddr *)&sin, i) < 0) { + close (s); + debug(ftp,"bind failed %d\n",errno); + return zap(ftp); + } + getsockname(s,(struct sockaddr *)&sin,&i); + if (listen(s,1) < 0) { + close (s); + debug(ftp,"listen failed %d\n",errno); + return zap(ftp); + } + a = ntohl(sin.sin_addr.s_addr); + i = cmd(ftp,"PORT %d,%d,%d,%d,%d,%d", + (a >> 24) & 0xff, + (a >> 16) & 0xff, + (a >> 8) & 0xff, + a & 0xff, + (ntohs(sin.sin_port) >> 8) & 0xff, + ntohs(sin.sin_port) & 0xff); + if (i != 200) + return -1; + i = cmd(ftp,"RETR %s",file); + if (i < 0) { + close(s); + return zap(ftp); + } + else if (i > 299) { + debug(ftp, "FTP: No such file %s, moving on.\n", file); + close(s); + return -1; + } + ftp->fd_xfer = accept(s, 0, 0); + if (ftp->fd_xfer < 0) { + close(s); + return zap(ftp); + } + ftp->state = xfer; + close(s); + return(ftp->fd_xfer); + } +} + +int +FtpEOF(FTP_t ftp) +{ + int i; + + if (ftp->state != xfer) + return botch(ftp,"FtpEOF","xfer"); + debug(ftp, "FtpEOF(ftp)\n"); + close(ftp->fd_xfer); ftp->fd_xfer = -1; + ftp->state = isopen; + i = get_a_number(ftp,0); + if (i < 0) + return zap(ftp); + else if (i != 250 && i != 226) + return -1; + else + return 0; +} + +#ifdef STANDALONE_FTP + +/* main.c */ +int +main(int argc, char **argv) +{ + FTP_t ftp; + int i; + char c; + + ftp = FtpInit(); + if (!ftp) + err(1, "FtpInit()"); + + FtpDebug(ftp, 1); + i = FtpOpen(ftp, "freefall.cdrom.com", "ftp", "phk-libftp@"); + FtpBinary(ftp, 1); + FtpPassive(ftp, 0); + FtpChdir(ftp, "/pub"); + FtpChdir(ftp, "FreeBSD"); + i = FtpGet(ftp, "README"); + while (1 == read(i, &c, 1)) + putchar(c); + FtpEOF(ftp); + return 0; +} + +#endif /*STANDALONE_FTP*/ diff --git a/usr.sbin/pkg_install/lib/ftp.h b/usr.sbin/pkg_install/lib/ftp.h new file mode 100644 index 0000000000000..9275dd4f35c6a --- /dev/null +++ b/usr.sbin/pkg_install/lib/ftp.h @@ -0,0 +1,26 @@ +#ifndef _FTP_H_INCLUDE +#define _FTP_H_INCLUDE + +typedef struct { + enum {init, isopen, xfer} state; + int fd_ctrl; + int fd_xfer; + int fd_debug; + int binary; + int passive; + int addrtype; + char *host; + char *file; +} *FTP_t; + +FTP_t FtpInit(); +int FtpOpen(FTP_t, char *host, char *user, char *passwd); +#define FtpBinary(ftp,bool) { (ftp)->binary = (bool); } +#define FtpPassive(ftp,bool) { (ftp)->passive = (bool); } +int FtpChdir(FTP_t, char *); +int FtpGet(FTP_t, char *); +int FtpEOF(FTP_t); +void FtpClose(FTP_t); + +#endif +/* _FTP_H_INCLUDE */ diff --git a/usr.sbin/sicontrol/Makefile b/usr.sbin/sicontrol/Makefile new file mode 100644 index 0000000000000..48dab5812dfcf --- /dev/null +++ b/usr.sbin/sicontrol/Makefile @@ -0,0 +1,5 @@ +PROG= sicontrol +SRCS= sicontrol.c +MAN8= sicontrol.8 + +.include <bsd.prog.mk> diff --git a/usr.sbin/sicontrol/sicontrol.c b/usr.sbin/sicontrol/sicontrol.c new file mode 100644 index 0000000000000..0924ee0f1d93c --- /dev/null +++ b/usr.sbin/sicontrol/sicontrol.c @@ -0,0 +1,585 @@ +/* + * Device driver for Specialix range (SLXOS) of serial line multiplexors. + * SLXOS configuration and debug interface + * + * Copyright (C) 1990, 1992 Specialix International, + * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> + * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> + * + * Derived from: SunOS 4.x version + * + * 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 + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, 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 Andy Rutter of + * Advanced Methods and Tools Ltd. based on original information + * from Specialix International. + * 4. Neither the name of Advanced Methods and Tools, nor Specialix + * International may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``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 AUTHORS BE LIABLE. + * + * $Id: sicontrol.c,v 1.2 1995/08/14 01:56:17 peter Exp $ + */ + +#include <stdio.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/tty.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +#include <machine/si.h> + +struct lv { + char *lv_name; + int lv_bit; +} lv[] = { + "entry", DBG_ENTRY, + "open", DBG_OPEN, + "close", DBG_CLOSE, + "read", DBG_READ, + "write", DBG_WRITE, + "param", DBG_PARAM, + "modem", DBG_MODEM, + "select", DBG_SELECT, + "optim", DBG_OPTIM, + "intr", DBG_INTR, + "start", DBG_START, + "lstart", DBG_LSTART, + "ioctl", DBG_IOCTL, + "fail", DBG_FAIL, + "autoboot", DBG_AUTOBOOT, + "download", DBG_DOWNLOAD, + "drain", DBG_DRAIN, + "poll", DBG_POLL, + 0, 0 +}; + +static int alldev = 0; +int getnum(char *str); + +int debug(), rxint(), txint(); +int mstate(), nport(); +int ccb_stat(), tty_stat(); +struct opt { + char *o_name; + int (*o_func)(); +} opt[] = { + "debug", debug, + "rxint_throttle", rxint, + "int_throttle", txint, + "mstate", mstate, + "nport", nport, + "ccbstat", ccb_stat, + "ttystat", tty_stat, + 0, 0, +}; + +struct stat_list { + int (*st_func)(); +} stat_list[] = { + mstate, + 0 +}; + +#define U_DEBUG 0 +#define U_TXINT 1 +#define U_RXINT 2 +#define U_MSTATE 3 +#define U_NPORT 4 +#define U_STAT_CCB 5 +#define U_STAT_TTY 6 +#define U_STAT_PORT 7 + +#define U_MAX 7 +#define U_ALL -1 +char *usage[] = { + "debug [[add|del|set debug_levels] | [off]]\n", + "int_throttle [newvalue]\n", + "rxint_throttle [newvalue]\n", + "mstate\n", + "nport\n", + "ccbstat\n", + "ttystat\n", + "portstat\n", + 0 +}; + +int ctlfd; +char *Devname; +struct si_tcsi tc; + +main(argc, argv) + char **argv; +{ + struct opt *op; + int (*func)() = NULL; + + if (argc < 2) + prusage(U_ALL, 1); + Devname = argv[1]; + if (strcmp(Devname, "-") == 0) { + alldev = 1; + } else { + sidev_t dev; + struct stat st; + + if (strchr(Devname, '/') == NULL) { + char *acp = malloc(6 + strlen(Devname)); + strcpy(acp, "/dev/"); + strcat(acp, Devname); + Devname = acp; + } + if (stat(Devname, &st) < 0) { + fprintf(stderr, "can't stat %s\n", Devname); + exit(1); + } + dev.sid_card = SI_CARD(minor(st.st_rdev)); + dev.sid_port = SI_PORT(minor(st.st_rdev)); + tc.tc_dev = dev; + } + ctlfd = opencontrol(); + if (argc == 2) { + dostat(); + exit(0); + } + + argc--; argv++; + for (op = opt; op->o_name; op++) { + if (strcmp(argv[1], op->o_name) == 0) { + func = op->o_func; + break; + } + } + if (func == NULL) + prusage(U_ALL, 1); + + argc -= 2; + argv += 2; + (*func)(argc, argv); + exit(0); +} + +opencontrol() +{ + int fd; + + fd = open(CONTROLDEV, O_RDWR|O_NDELAY); + if (fd < 0) { + fprintf(stderr, "open on %s - ", CONTROLDEV); + perror(""); + exit(1); + } + return(fd); +} + +/* + * Print a usage message - this relies on U_DEBUG==0 and U_BOOT==1. + * Don't print the DEBUG usage string unless explicity requested. + */ +prusage(strn, eflag) + int strn, eflag; +{ + char **cp; + + if (strn == U_ALL) { + fprintf(stderr, "Usage: sicontrol - %s", usage[1]); + fprintf(stderr, " sicontrol - %s", usage[2]); + fprintf(stderr, " sicontrol devname %s", usage[3]); + for (cp = &usage[4]; *cp; cp++) + fprintf(stderr, " %s", *cp); + } + else if (strn >= 0 && strn <= U_MAX) + fprintf(stderr, "Usage: sicontrol devname %s", usage[strn]); + else + fprintf(stderr, "sicontrol: usage ???\n"); + exit(eflag); +} + +/* print port status */ +dostat() +{ + char *av[1], *acp; + struct stat_list *stp; + struct si_tcsi stc; + int (*func)(); + int donefirst = 0; + + printf("%s: ", alldev ? "ALL" : Devname); + acp = malloc(strlen(Devname) + 3); + memset(acp, ' ', strlen(Devname)); + strcat(acp, " "); + stc = tc; + for (stp = stat_list; stp->st_func != NULL; stp++) { + if (donefirst) + fputs(acp, stdout); + else + donefirst++; + av[0] = NULL; + tc = stc; + (*stp->st_func)(-1, av); + } +} + +/* + * debug + * debug [[set|add|del debug_lvls] | [off]] + */ +debug(ac, av) + char **av; +{ + int level, cmd; + char *str; + + if (ac > 2) + prusage(U_DEBUG, 1); + if (alldev) { + if (ioctl(ctlfd, TCSIGDBG_ALL, &tc.tc_dbglvl) < 0) + Perror("TCSIGDBG_ALL on %s", Devname); + } else { + if (ioctl(ctlfd, TCSIGDBG_LEVEL, &tc) < 0) + Perror("TCSIGDBG_LEVEL on %s", Devname); + } + + switch (ac) { + case 0: + printf("%s: debug levels - ", Devname); + prlevels(tc.tc_dbglvl); + return; + case 1: + if (strcmp(av[0], "off") == 0) { + tc.tc_dbglvl = 0; + break; + } + prusage(U_DEBUG, 1); + /* no return */ + case 2: + level = lvls2bits(av[1]); + if (strcmp(av[0], "add") == 0) + tc.tc_dbglvl |= level; + else if (strcmp(av[0], "del") == 0) + tc.tc_dbglvl &= ~level; + else if (strcmp(av[0], "set") == 0) + tc.tc_dbglvl = level; + else + prusage(U_DEBUG, 1); + } + if (alldev) { + if (ioctl(ctlfd, TCSISDBG_ALL, &tc.tc_dbglvl) < 0) + Perror("TCSISDBG_ALL on %s", Devname); + } else { + if (ioctl(ctlfd, TCSISDBG_LEVEL, &tc) < 0) + Perror("TCSISDBG_LEVEL on %s", Devname); + } +} + +rxint(ac, av) + char **av; +{ + tc.tc_port = 0; + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + if (ioctl(ctlfd, TCSIGRXIT, &tc) < 0) + Perror("TCSIGRXIT"); + printf("RX interrupt throttle: %d msec\n", tc.tc_int*10); + break; + case 1: + tc.tc_int = getnum(av[0]) / 10; + if (tc.tc_int == 0) + tc.tc_int = 1; + if (ioctl(ctlfd, TCSIRXIT, &tc) < 0) + Perror("TCSIRXIT on %s at %d msec", Devname, tc.tc_int*10); + break; + default: + prusage(U_RXINT, 1); + } +} + +txint(ac, av) + char **av; +{ + + tc.tc_port = 0; + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + if (ioctl(ctlfd, TCSIGIT, &tc) < 0) + Perror("TCSIGIT"); + printf("aggregate interrupt throttle: %d\n", tc.tc_int); + break; + case 1: + tc.tc_int = getnum(av[0]); + if (ioctl(ctlfd, TCSIIT, &tc) < 0) + Perror("TCSIIT on %s at %d", Devname, tc.tc_int); + break; + default: + prusage(U_TXINT, 1); + } +} + +onoff(ac, av, cmd, cmdstr, prstr, usage) + char **av, *cmdstr, *prstr; + int ac, cmd, usage; +{ + if (ac > 1) + prusage(usage, 1); + if (ac == 1) { + if (strcmp(av[0], "on") == 0) + tc.tc_int = 1; + else if (strcmp(av[0], "off") == 0) + tc.tc_int = 0; + else + prusage(usage, 1); + } else + tc.tc_int = -1; + if (ioctl(ctlfd, cmd, &tc) < 0) + Perror("%s on %s", cmdstr, Devname); + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + printf("%s ", prstr); + if (tc.tc_int) + printf("on\n"); + else + printf("off\n"); + } +} + +mstate(ac, av) + char **av; +{ + u_char state; + + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + break; + default: + prusage(U_MSTATE, 1); + } + if (ioctl(ctlfd, TCSISTATE, &tc) < 0) + Perror("TCSISTATE on %s", Devname); + printf("modem bits state - (0x%x)", tc.tc_int); + if (tc.tc_int & IP_DCD) printf(" DCD"); + if (tc.tc_int & IP_DTR) printf(" DTR"); + if (tc.tc_int & IP_RTS) printf(" RTS"); + printf("\n"); +} + +nport(ac, av) + char **av; +{ + int ports; + + if (ac != 0) + prusage(U_NPORT, 1); + if (ioctl(ctlfd, TCSIPORTS, &ports) < 0) + Perror("TCSIPORTS on %s", Devname); + printf("SLXOS: total of %d ports\n", ports); +} + +ccb_stat(ac, av) +char **av; +{ + struct si_pstat sip; +#define CCB sip.tc_ccb + + if (ac != 0) + prusage(U_STAT_CCB); + sip.tc_dev = tc.tc_dev; + if (ioctl(ctlfd, TCSI_CCB, &sip) < 0) + Perror("TCSI_CCB on %s", Devname); + printf("%s: ", Devname); + + /* WORD next - Next Channel */ + /* WORD addr_uart - Uart address */ + /* WORD module - address of module struct */ + printf("\tuart_type 0x%x\n", CCB.type); /* BYTE type - Uart type */ + /* BYTE fill - */ + printf("\tx_status 0x%x\n", CCB.x_status); /* BYTE x_status - XON / XOFF status */ + printf("\tc_status 0x%x\n", CCB.c_status); /* BYTE c_status - cooking status */ + printf("\thi_rxipos 0x%x\n", CCB.hi_rxipos); /* BYTE hi_rxipos - stuff into rx buff */ + printf("\thi_rxopos 0x%x\n", CCB.hi_rxopos); /* BYTE hi_rxopos - stuff out of rx buffer */ + printf("\thi_txopos 0x%x\n", CCB.hi_txopos); /* BYTE hi_txopos - Stuff into tx ptr */ + printf("\thi_txipos 0x%x\n", CCB.hi_txipos); /* BYTE hi_txipos - ditto out */ + printf("\thi_stat 0x%x\n", CCB.hi_stat); /* BYTE hi_stat - Command register */ + printf("\tdsr_bit 0x%x\n", CCB.dsr_bit); /* BYTE dsr_bit - Magic bit for DSR */ + printf("\ttxon 0x%x\n", CCB.txon); /* BYTE txon - TX XON char */ + printf("\ttxoff 0x%x\n", CCB.txoff); /* BYTE txoff - ditto XOFF */ + printf("\trxon 0x%x\n", CCB.rxon); /* BYTE rxon - RX XON char */ + printf("\trxoff 0x%x\n", CCB.rxoff); /* BYTE rxoff - ditto XOFF */ + printf("\thi_mr1 0x%x\n", CCB.hi_mr1); /* BYTE hi_mr1 - mode 1 image */ + printf("\thi_mr2 0x%x\n", CCB.hi_mr2); /* BYTE hi_mr2 - mode 2 image */ + printf("\thi_csr 0x%x\n", CCB.hi_csr); /* BYTE hi_csr - clock register */ + printf("\thi_op 0x%x\n", CCB.hi_op); /* BYTE hi_op - Op control */ + printf("\thi_ip 0x%x\n", CCB.hi_ip); /* BYTE hi_ip - Input pins */ + printf("\thi_state 0x%x\n", CCB.hi_state); /* BYTE hi_state - status */ + printf("\thi_prtcl 0x%x\n", CCB.hi_prtcl); /* BYTE hi_prtcl - Protocol */ + printf("\thi_txon 0x%x\n", CCB.hi_txon); /* BYTE hi_txon - host copy tx xon stuff */ + printf("\thi_txoff 0x%x\n", CCB.hi_txoff); /* BYTE hi_txoff - */ + printf("\thi_rxon 0x%x\n", CCB.hi_rxon); /* BYTE hi_rxon - */ + printf("\thi_rxoff 0x%x\n", CCB.hi_rxoff); /* BYTE hi_rxoff - */ + printf("\tclose_prev 0x%x\n", CCB.close_prev); /* BYTE close_prev - Was channel previously closed */ + printf("\thi_break 0x%x\n", CCB.hi_break); /* BYTE hi_break - host copy break process */ + printf("\tbreak_state 0x%x\n", CCB.break_state); /* BYTE break_state - local copy ditto */ + printf("\thi_mask 0x%x\n", CCB.hi_mask); /* BYTE hi_mask - Mask for CS7 etc. */ + printf("\tmask_z280 0x%x\n", CCB.mask_z280); /* BYTE mask_z280 - Z280's copy */ + /* BYTE res[0x60 - 36] - */ + /* BYTE hi_txbuf[SLXOS_BUFFERSIZE] - */ + /* BYTE hi_rxbuf[SLXOS_BUFFERSIZE] - */ + /* BYTE res1[0xA0] - */ + +} + +tty_stat(ac, av) +char **av; +{ + struct si_pstat sip; +#define TTY sip.tc_tty + + if (ac != 0) + prusage(U_STAT_TTY); + sip.tc_dev = tc.tc_dev; + if (ioctl(ctlfd, TCSI_TTY, &sip) < 0) + Perror("TCSI_TTY on %s", Devname); + printf("%s: ", Devname); + + printf("\tt_outq.c_cc %d.\n", TTY.t_outq.c_cc); /* struct clist t_outq */ + printf("\tt_dev 0x%x\n", TTY.t_dev); /* dev_t t_dev */ + printf("\tt_flags 0x%x\n", TTY.t_flags); /* int t_flags */ + printf("\tt_state 0x%x\n", TTY.t_state); /* int t_state */ + printf("\tt_hiwat %d.\n", TTY.t_hiwat); /* short t_hiwat */ + printf("\tt_lowat %d.\n", TTY.t_lowat); /* short t_lowat */ + printf("\tt_iflag 0x%x\n", TTY.t_iflag); /* t_iflag */ + printf("\tt_oflag 0x%x\n", TTY.t_oflag); /* t_oflag */ + printf("\tt_cflag 0x%x\n", TTY.t_cflag); /* t_cflag */ + printf("\tt_lflag 0x%x\n", TTY.t_lflag); /* t_lflag */ + printf("\tt_cc 0x%x\n", TTY.t_cc); /* t_cc */ + printf("\tt_termios.c_ispeed 0x%x\n", TTY.t_termios.c_ispeed); /* t_termios.c_ispeed */ + printf("\tt_termios.c_ospeed 0x%x\n", TTY.t_termios.c_ospeed); /* t_termios.c_ospeed */ + +} + +islevel(tk) + char *tk; +{ + register struct lv *lvp; + register char *acp; + + for (acp = tk; *acp; acp++) + if (isupper(*acp)) + *acp = tolower(*acp); + for (lvp = lv; lvp->lv_name; lvp++) + if (strcmp(lvp->lv_name, tk) == 0) + return(lvp->lv_bit); + return(0); +} + +/* + * Convert a string consisting of tokens separated by white space, commas + * or `|' into a bitfield - flag any unrecognised tokens. + */ +lvls2bits(str) + char *str; +{ + int i, bits = 0; + int errflag = 0; + char token[20]; + + while (sscanf(str, "%[^,| \t]", token) == 1) { + str += strlen(token); + while (isspace(*str) || *str==',' || *str=='|') + str++; + if (strcmp(token, "all") == 0) + return(0xffffffff); + if ((i = islevel(token)) == 0) { + fprintf(stderr, "sicontrol: unknown token '%s'\n", token); + errflag++; + } else + bits |= i; + } + if (errflag) + exit(1); + + return(bits); +} + +int +getnum(char *str) +{ + int x; + register char *acp = str; + + x = 0; + while (*acp) { + if (!isdigit(*acp)) { + error("%s is not a number\n", str); + exit(1); + } + x *= 10; + x += (*acp - '0'); + acp++; + } + return(x); +} + +prlevels(x) + int x; +{ + struct lv *lvp; + + switch (x) { + case 0: + printf("(none)\n"); + break; + case 0xffffffff: + printf("all\n"); + break; + default: + for (lvp = lv; lvp->lv_name; lvp++) + if (x & lvp->lv_bit) + printf(" %s", lvp->lv_name); + printf("\n"); + } +} + +/* VARARGS */ +Perror(str, a1, a2, a3, a4, a5) + char *str; + int a1, a2, a3, a4, a5; +{ + fprintf(stderr, str, a1, a2, a3, a4, a5); + perror(" "); + exit(1); +} + +/* VARARGS */ +error(str, a1, a2, a3, a4, a5) + char *str; + int a1, a2, a3, a4, a5; +{ + fprintf(stderr, str, a1, a2, a3, a4, a5); + exit(1); +} diff --git a/usr.sbin/spkrtest/spkrtest.8 b/usr.sbin/spkrtest/spkrtest.8 new file mode 100644 index 0000000000000..056e0b4de28a8 --- /dev/null +++ b/usr.sbin/spkrtest/spkrtest.8 @@ -0,0 +1,32 @@ +.Dd May, 1995 +.Dt SPKRTEST 8 +.Os FreeBSD + +.Sh NAME +.Nm spkrtest +.Nd test script for the speaker driver + +.Sh DESCRIPTION +.Nm +is an easy to use test script for the speaker driver. + +.Sh FILES +.Bl -tag -width /dev/speakerxx +.It Pa /dev/speaker +speaker device file +.El + +.Sh SEE ALSO +.Xr spkr 4 , +.Xr dialog 1 , +.Xr perl 1 + +.\" only for the record +.\" .Sh AUTHOR +.\" Eric S. Raymond <esr@snark.thyrsus.com) June 1990; +.\" dialog+perl by Wolfram Schneider <wosch@cs.tu-berlin.de>, May 1995 + +.Sh HISTORY +The +.Nm +script appeared in FreeBSD 1.0 diff --git a/usr.sbin/spkrtest/spkrtest.pl b/usr.sbin/spkrtest/spkrtest.pl new file mode 100644 index 0000000000000..d0fe260924ad0 --- /dev/null +++ b/usr.sbin/spkrtest/spkrtest.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl +# +# Test script for the speaker driver +# +# v1.0 by Eric S. Raymond (Feb 1990) +# v1.1 rightstuff contributed by Eric S. Tiedemann (est@snark.thyrsus.com) +# v2.0 dialog+perl by Wolfram Schneider <wosch@cs.tu-berlin.de>, May 1995 +# +# NOTE for iso-* (latin1) fonts: use TERM=cons25-iso8859-1 +# + +$title = " +reveille -- Reveille +contact -- Contact theme from Close Encounters +dance -- Lord of the Dance (aka Simple Gifts) +loony -- Loony Toons theme +sinister -- standard villain's entrance music +rightstuff -- a trope from \"The Right Stuff\" score by Bill Conti +toccata -- opening bars of Bach's Toccata and Fugue in D Minor +startrek -- opening bars of the theme from Star Trek Classic +"; + +$music = " +reveille -- t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.. +contact -- <cd<a#~<a#>f +dance -- t240<cfcfgagaa#b#>dc<a#a.~fg.gaa#.agagegc.~cfcfgagaa#b#>dc<a#a.~fg.gga.agfgfgf. +loony -- t255cf8f8edc<a>~cf8f8edd#e~ce8cdce8cd.<a>c8c8c#def8af8 +sinister -- mst200o2ola.l8bc.~a.~>l2d# +rightstuff -- olcega.a8f>cd2bgc.c8dee2 +toccata -- msl16oldcd4mll8pcb-agf+4.g4p4<msl16dcd4mll8pa.a+f+4p16g4 +startrek -- l2b.f+.p16a.c+.p l4mn<b.>e8a2mspg+e8c+f+8b2 +"; + +$checklist = 'dialog \ +--title "Speaker test" \ +--checklist "Please select the melodies you wish to play (space for select)" \ +-1 -1 10 \ +'; + + +sub Exit { + unlink $tmp if $tmp; +} + +$SIG{'INT'} = $SIG{'HUP'} = $SIG{'TRAP'} = $SIG{'QUIT'} = + $SIG{'TERM'} = '&Exit'; + + +# make assoc array from variable 'var' +# 'name -- description' -> $var{$name} = $description +sub splitconfig { + local(*var) = @_; + local($t, $name, $description); + + foreach $t (split('\n', $var)) { + ($name, $description) = split('--', $t); + + $name =~ s/^\s+//; $name =~ s/\s+$//; + $description =~ s/\s+//; $description =~ s/\s+$//; + + $var{$name} = $description if $name && $description; + } +} + +&splitconfig(*title); +&splitconfig(*music); + +foreach $e (sort keys %title) { + ($t = $title{$e}) =~ s/(\")/\\$1/g; # quote '"' + $checklist .= "\"$e\" \"$t\" OFF "; +} + +$tmp = ($ENV{'TMP'} || "/tmp") . "/_spkrtest$$"; +system("$checklist 2> $tmp"); # start dialog + +if (!$?) { # not cancel + open(SPEAKER, ">/dev/speaker") || die "/dev/speaker: $!\n"; + select(SPEAKER); $| = 1; + select(STDOUT); $| = 1; + + if (! -z $tmp) { # select melod(y/ies) + foreach $melody (split($", `cat $tmp`)) { + $melody =~ s/^"//; $melody =~ s/"$//; + print STDOUT "$title{$melody}\n"; + print SPEAKER "$music{$melody}"; + sleep 1; + } + } else { # use default melody + $melody = (sort keys %title)[0]; + print STDOUT "Use default melody: $title{$melody}\n"; + print SPEAKER "$music{$melody}"; + } + close SPEAKER; +} + +unlink $tmp; diff --git a/usr.sbin/tcpdump/tcpdump/print-krb.c b/usr.sbin/tcpdump/tcpdump/print-krb.c new file mode 100644 index 0000000000000..e5470726f84ab --- /dev/null +++ b/usr.sbin/tcpdump/tcpdump/print-krb.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1995 + * 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: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Initial contribution from John Hawkinson (jhawk@mit.edu). + */ + +#ifndef lint +static char rcsid[] = + "$Id$"; +/* + "@(#) Header: /afs/sipb/project/tcpdump/src/tcpdump-3.0.2/RCS/print-krb.c,v 1.3 1995/08/16 05:33:27 jhawk Exp "; +*/ +#endif + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> + +#include "interface.h" +#include "addrtoname.h" + +const char *c_print(register const u_char *s, register const u_char *ep); +const u_char *krb4_print_hdr(const u_char *cp); +void krb4_print(const u_char *cp); +void krb_print(const u_char *dat, int length); + + +#define AUTH_MSG_KDC_REQUEST 1<<1 +#define AUTH_MSG_KDC_REPLY 2<<1 +#define AUTH_MSG_APPL_REQUEST 3<<1 +#define AUTH_MSG_APPL_REQUEST_MUTUAL 4<<1 +#define AUTH_MSG_ERR_REPLY 5<<1 +#define AUTH_MSG_PRIVATE 6<<1 +#define AUTH_MSG_SAFE 7<<1 +#define AUTH_MSG_APPL_ERR 8<<1 +#define AUTH_MSG_DIE 63<<1 + +#define KERB_ERR_OK 0 +#define KERB_ERR_NAME_EXP 1 +#define KERB_ERR_SERVICE_EXP 2 +#define KERB_ERR_AUTH_EXP 3 +#define KERB_ERR_PKT_VER 4 +#define KERB_ERR_NAME_MAST_KEY_VER 5 +#define KERB_ERR_SERV_MAST_KEY_VER 6 +#define KERB_ERR_BYTE_ORDER 7 +#define KERB_ERR_PRINCIPAL_UNKNOWN 8 +#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9 +#define KERB_ERR_NULL_KEY 10 + +struct krb { + u_char pvno; /* Protocol Version */ + u_char type; /* Type+B */ +} ; + +static char tstr[] = " [|kerberos]"; + +static struct token type2str[] = { + { AUTH_MSG_KDC_REQUEST, "KDC_REQUEST" }, + { AUTH_MSG_KDC_REPLY, "KDC_REPLY" }, + { AUTH_MSG_APPL_REQUEST, "APPL_REQUEST" }, + { AUTH_MSG_APPL_REQUEST_MUTUAL, "APPL_REQUEST_MUTUAL" }, + { AUTH_MSG_ERR_REPLY, "ERR_REPLY" }, + { AUTH_MSG_PRIVATE, "PRIVATE" }, + { AUTH_MSG_SAFE, "SAFE" }, + { AUTH_MSG_APPL_ERR, "APPL_ERR" }, + { AUTH_MSG_DIE, "DIE" }, + { 0, NULL } +}; + +static struct token kerr2str[] = { + { KERB_ERR_OK, "OK" }, + { KERB_ERR_NAME_EXP, "NAME_EXP" }, + { KERB_ERR_SERVICE_EXP, "SERVICE_EXP" }, + { KERB_ERR_AUTH_EXP, "AUTH_EXP" }, + { KERB_ERR_PKT_VER, "PKT_VER" }, + { KERB_ERR_NAME_MAST_KEY_VER, "NAME_MAST_KEY_VER" }, + { KERB_ERR_SERV_MAST_KEY_VER, "SERV_MAST_KEY_VER" }, + { KERB_ERR_BYTE_ORDER, "BYTE_ORDER" }, + { KERB_ERR_PRINCIPAL_UNKNOWN, "PRINCIPAL_UNKNOWN" }, + { KERB_ERR_PRINCIPAL_NOT_UNIQUE, "PRINCIPAL_NOT_UNIQUE" }, + { KERB_ERR_NULL_KEY, "NULL_KEY"}, + { 0, NULL} + }; + + +/* little endian (unaligned) to host byte order */ +#define vtohlp(x) ((( ((char*)(x))[0] ) ) | \ + (( ((char*)(x))[1] ) << 8) | \ + (( ((char*)(x))[2] ) << 16) | \ + (( ((char*)(x))[3] ) << 24)) +#define vtohsp(x) ((( ((char*)(x))[0] ) ) | \ + (( ((char*)(x))[1] ) << 8)) +/* network (big endian) (unaligned) to host byte order */ +#define ntohlp(x) ((( ((char*)(x))[3] ) ) | \ + (( ((char*)(x))[2] ) << 8) | \ + (( ((char*)(x))[1] ) << 16) | \ + (( ((char*)(x))[0] ) << 24)) +#define ntohsp(x) ((( ((char*)(x))[1] ) ) | \ + (( ((char*)(x))[0] ) << 8)) + + + +const char * +c_print(register const u_char *s, register const u_char *ep) +{ + register u_char c; + register int flag; + + flag = 1; + while (ep == NULL || s < ep) { + c = *s++; + if (c == '\0') { + flag = 0; + break; + } + if (!isascii(c)) { + c = toascii(c); + putchar('M'); + putchar('-'); + } + if (!isprint(c)) { + c ^= 0x40; /* DEL to ?, others to alpha */ + putchar('^'); + } + putchar(c); + } + if (flag) + return NULL; + return(s); +} + + +const u_char * +krb4_print_hdr(const u_char *cp) +{ + cp+=2; + +#define TCHECK if (cp >= snapend) goto trunc +#define PRINT if ((cp=c_print(cp, snapend))==NULL) goto trunc + + TCHECK; + PRINT; + TCHECK; + putchar('.'); PRINT; + TCHECK; + putchar('@'); PRINT; + return(cp); + + trunc: + fputs(tstr, stdout); + return(NULL); + +#undef TCHECK +#undef PRINT +} + +void krb4_print(const u_char *cp) +{ + register const struct krb *kp; + u_char type; + u_short len; + +#define TCHECK if (cp >= snapend) goto trunc +#define PRINT if ((cp=c_print(cp, snapend))==NULL) goto trunc +#define ENDIAN (kp->type & 0x01) +/* ENDIAN is 1 for little, 0 for big */ + + kp = (struct krb *)cp; + + if ((&kp->type) >= snapend) { + fputs(tstr, stdout); + return; + } + + type = kp->type & (0xFF << 1); + + printf(" %s %s: ", ENDIAN?"le":"be", tok2str(type2str, NULL, type)); + + switch(type) { + case AUTH_MSG_KDC_REQUEST: + if ((cp=krb4_print_hdr(cp)) == NULL) + return; + cp+=4; /* ctime */ + TCHECK; + printf(" %dmin ", *cp++ * 5); + TCHECK; + PRINT; + TCHECK; + putchar('.'); PRINT; + break; + case AUTH_MSG_APPL_REQUEST: + cp+=2; + TCHECK; + printf("v%d ", *cp++); + TCHECK; + PRINT; + TCHECK; + printf(" (%d)", *cp++); + TCHECK; + printf(" (%d)", *cp); + TCHECK; + break; + case AUTH_MSG_KDC_REPLY: + if ((cp=krb4_print_hdr(cp)) == NULL) + return; + cp+=10; /* timestamp + n + exp + kvno */ + TCHECK; + len=ENDIAN? vtohsp(cp) : ntohsp(cp); + printf(" (%d)", len); + TCHECK; + break; + case AUTH_MSG_ERR_REPLY: + if ((cp=krb4_print_hdr(cp)) == NULL) + return; + cp+=4; /* timestamp */ + TCHECK; + printf(" %s ", tok2str(kerr2str, NULL, + ENDIAN? vtohlp(cp) : + ntohlp(cp) + )); + cp+=4; + TCHECK; + PRINT; + break; + default: + fputs("(unknown)", stdout); + break; + } + + return; +trunc: + fputs(tstr, stdout); +#undef TCHECK +} + +void +krb_print(const u_char *dat, int length) +{ + register const struct krb *kp; + + kp = (struct krb *)dat; + + if (dat >= snapend) { + fputs(tstr, stdout); + return; + } + + switch (kp->pvno) { + case 1: + case 2: + case 3: + printf(" v%d", kp->pvno); + break; + case 4: + printf(" v%d", kp->pvno); + krb4_print((const u_char*)kp); + break; + case 106: + case 107: + fputs(" v5", stdout); + /* Decode ASN.1 here "someday" */ + break; + } + return; +} diff --git a/usr.sbin/xntpd/conf/ntp.conf.dcf77 b/usr.sbin/xntpd/conf/ntp.conf.dcf77 new file mode 100644 index 0000000000000..678d719d815c3 --- /dev/null +++ b/usr.sbin/xntpd/conf/ntp.conf.dcf77 @@ -0,0 +1,19 @@ +# +# XNTP configuration file (/etc/ntp.conf) +# + +# +# Server is a Boeder DCF77 receiver +# +# Use: +# 127.127.8.40 for /dev/refclock-0 (/dev/ttyd0) +# 127.127.8.41 for /dev/refclock-1 (/dev/ttyd1) +# 127.127.8.42 for /dev/refclock-2 (/dev/ttyd2) +# 127.127.8.43 for /dev/refclock-3 (/dev/ttyd3) +# +server 127.127.8.40 + +# +# drift file +# +driftfile /etc/ntp.drift |