summaryrefslogtreecommitdiffstats
path: root/misc-utils
diff options
context:
space:
mode:
authorKarel Zak2006-12-07 00:25:32 +0100
committerKarel Zak2006-12-07 00:25:32 +0100
commit6dbe3af945a63f025561abb83275cee9ff06c57b (patch)
tree19e59eac8ac465b5bc409b5adf815b582c92f633 /misc-utils
downloadkernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.gz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.tar.xz
kernel-qcow2-util-linux-6dbe3af945a63f025561abb83275cee9ff06c57b.zip
Imported from util-linux-2.2 tarball.
Diffstat (limited to 'misc-utils')
-rw-r--r--misc-utils/Makefile71
-rw-r--r--misc-utils/README.cal42
-rw-r--r--misc-utils/README.hostname29
-rw-r--r--misc-utils/README.namei31
-rw-r--r--misc-utils/README.script7
-rw-r--r--misc-utils/README1.namei14
-rw-r--r--misc-utils/cal.181
-rw-r--r--misc-utils/cal.c450
-rw-r--r--misc-utils/clear.125
-rw-r--r--misc-utils/clear.sh2
-rw-r--r--misc-utils/dnsdomainname.11
-rw-r--r--misc-utils/domainname.143
-rw-r--r--misc-utils/domainname.c29
-rw-r--r--misc-utils/dsplit.146
-rw-r--r--misc-utils/dsplit.c271
-rw-r--r--misc-utils/getoptprog.1104
-rw-r--r--misc-utils/getoptprog.c30
-rw-r--r--misc-utils/hostid.123
-rw-r--r--misc-utils/hostid.c36
-rw-r--r--misc-utils/hostname.177
-rw-r--r--misc-utils/hostname.c184
-rw-r--r--misc-utils/kill.149
-rw-r--r--misc-utils/kill.c272
-rw-r--r--misc-utils/logger.1100
-rw-r--r--misc-utils/logger.c192
-rw-r--r--misc-utils/look.1109
-rw-r--r--misc-utils/look.c365
-rw-r--r--misc-utils/mcookie.117
-rw-r--r--misc-utils/mcookie.c44
-rw-r--r--misc-utils/md5.c253
-rw-r--r--misc-utils/md5.h27
-rw-r--r--misc-utils/md5sum.164
-rw-r--r--misc-utils/md5sum.c243
-rw-r--r--misc-utils/namei.160
-rw-r--r--misc-utils/namei.c341
-rw-r--r--misc-utils/procs.c113
-rw-r--r--misc-utils/reset.129
-rw-r--r--misc-utils/reset.sh13
-rw-r--r--misc-utils/script.1123
-rw-r--r--misc-utils/script.c294
-rw-r--r--misc-utils/setterm.188
-rw-r--r--misc-utils/setterm.c1137
-rw-r--r--misc-utils/tsort.174
-rw-r--r--misc-utils/tsort.c395
-rw-r--r--misc-utils/whereis.1198
-rw-r--r--misc-utils/whereis.c458
-rw-r--r--misc-utils/write.1110
-rw-r--r--misc-utils/write.c347
48 files changed, 7111 insertions, 0 deletions
diff --git a/misc-utils/Makefile b/misc-utils/Makefile
new file mode 100644
index 000000000..e8e517fea
--- /dev/null
+++ b/misc-utils/Makefile
@@ -0,0 +1,71 @@
+# Makefile -- Makefile for util-linux Linux utilities
+# Created: Sat Dec 26 20:09:40 1992
+# Revised: Thu Feb 16 10:00:24 1995 by faith@cs.unc.edu
+# Copyright 1992, 1993, 1994, 1995 Rickard E. Faith (faith@cs.unc.edu)
+#
+
+include ../MCONFIG
+
+# Where to put man pages?
+
+MAN1= cal.1 clear.1 dnsdomainname.1 domainname.1 dsplit.1 \
+ hostid.1 hostname.1 kill.1 logger.1 look.1 mcookie.1 \
+ md5sum.1 namei.1 reset.1 script.1 setterm.1 tsort.1 \
+ whereis.1 write.1
+
+# Where to put binaries?
+# See the "install" rule for the links. . .
+
+BIN= domainname hostname kill
+
+USRBIN= cal clear dsplit hostid logger look mcookie md5sum namei \
+ reset script setterm tsort whereis write
+
+# Programs requiring special compilation
+
+NEEDS_TERMCAP= setterm
+SCRIPTS= clear reset
+
+all: $(BIN) $(USRBIN) $(USRBIN.NONSHADOW) $(USRGAMES) getoptprog
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) $< -o $@
+
+$(NEEDS_TERMCAP):
+ $(CC) $(LDFLAGS) $^ -o $@ -ltermcap
+
+$(SCRIPTS):
+ cp $@.sh $@
+
+# Rules for everything else
+
+cal: cal.o $(BSD)/getopt.o $(BSD)/err.o
+clear: clear.sh
+domainname: domainname.o
+dsplit: dsplit.o
+getoptprog: getoptprog.o $(BSD)/getopt.o
+hostid: hostid.o
+hostname: hostname.o
+kill: kill.o procs.o
+logger: logger.o $(BSD)/getopt.o
+md5sum: md5.o
+md5.o: md5.h
+namei: namei.o
+reset: reset.sh
+script: script.o
+setterm: setterm.o
+tsort: tsort.o
+
+install: all
+ $(INSTALLDIR) $(BINDIR) $(USRBINDIR)
+ $(INSTALLBIN) $(BIN) $(BINDIR)
+ $(INSTALLBIN) $(USRBIN) $(USRBINDIR)
+ $(INSTALLBIN) getoptprog $(USRBINDIR)/getopt
+ (cd $(BINDIR); ln -sf hostname dnsdomainname)
+ $(INSTALLDIR) $(MAN1DIR) $(MAN8DIR)
+ $(INSTALLMAN) $(MAN1) $(MAN1DIR)
+ $(INSTALLMAN) getoptprog.1 $(MAN1DIR)/getopt.1
+
+.PHONY: clean
+clean:
+ -rm -f *.o *~ core $(BIN) $(USRBIN) getoptprog
diff --git a/misc-utils/README.cal b/misc-utils/README.cal
new file mode 100644
index 000000000..638ac9dff
--- /dev/null
+++ b/misc-utils/README.cal
@@ -0,0 +1,42 @@
+The cal(1) date routines were written from scratch, basically from first
+principles. The algorithm for calculating the day of week from any
+Gregorian date was "reverse engineered". This was necessary as most of
+the documented algorithms have to do with date calculations for other
+calendars (e.g. julian) and are only accurate when converted to gregorian
+within a narrow range of dates.
+
+1 Jan 1 is a Saturday because that's what cal says and I couldn't change
+that even if I was dumb enough to try. From this we can easily calculate
+the day of week for any date. The algorithm for a zero based day of week:
+
+ calculate the number of days in all prior years (year-1)*365
+ add the number of leap years (days?) since year 1
+ (not including this year as that is covered later)
+ add the day number within the year
+ this compensates for the non-inclusive leap year
+ calculation
+ if the day in question occurs before the gregorian reformation
+ (3 sep 1752 for our purposes), then simply return
+ (value so far - 1 + SATURDAY's value of 6) modulo 7.
+ if the day in question occurs during the reformation (3 sep 1752
+ to 13 sep 1752 inclusive) return THURSDAY. This is my
+ idea of what happened then. It does not matter much as
+ this program never tries to find day of week for any day
+ that is not the first of a month.
+ otherwise, after the reformation, use the same formula as the
+ days before with the additional step of subtracting the
+ number of days (11) that were adjusted out of the calendar
+ just before taking the modulo.
+
+It must be noted that the number of leap years calculation is sensitive
+to the date for which the leap year is being calculated. A year that occurs
+before the reformation is determined to be a leap year if its modulo of
+4 equals zero. But after the reformation, a year is only a leap year if
+its modulo of 4 equals zero and its modulo of 100 does not. Of course,
+there is an exception for these century years. If the modulo of 400 equals
+zero, then the year is a leap year anyway. This is, in fact, what the
+gregorian reformation was all about (a bit of error in the old algorithm
+that caused the calendar to be inaccurate.)
+
+Once we have the day in year for the first of the month in question, the
+rest is trivial.
diff --git a/misc-utils/README.hostname b/misc-utils/README.hostname
new file mode 100644
index 000000000..1e82b8cfe
--- /dev/null
+++ b/misc-utils/README.hostname
@@ -0,0 +1,29 @@
+
+You may ask "Why another version of the hostname command?". The answer is
+simple. A lot of people misuse the domainname command to get the DNS domain
+name. Since the domainname command should ONLY be used to set/show the NIS
+domain name (formerly known as Yellow Pages) there was no easy way to get
+the FQDN (Fully Qualified Domain Name) or the DNS domainname from within a
+shell script.
+
+This hostname command offers you some additional features:
+
+- show the FQDN (long host name)
+- show the short host name
+- show the DNS domain name
+- read the host name from file
+
+For further informations simply type "hostname --help" or read the manual
+page.
+
+If the program is called as dnsdomainname it will simply show the DNS domain
+name.
+
+If you ONLY use the loopback mode you can only use the normal features
+(set/show the host name) since you probably don't have a FQDN (Fully Qualified
+Domain Name) in the /etc/hosts file. You can change this by either using
+the dummy device or by changing the localhost line in /etc/hosts to
+something like this (it will use localhost as an alias name):
+
+127.0.0.1 erdos.maths.groucho.edu localhost erdos
+
diff --git a/misc-utils/README.namei b/misc-utils/README.namei
new file mode 100644
index 000000000..490939e06
--- /dev/null
+++ b/misc-utils/README.namei
@@ -0,0 +1,31 @@
+Tired of running into "Too many levels of symlinks" problems on
+your 4.2 BSD derivitive machine?
+
+We sure did... our NFS'ed network of lots of Suns, Vaxen and so forth
+made it impossible at times to trace down where a file REALLY lived.
+I mean ls -l is nice, but wouldn't you like to follow things like
+the namei routine in the kernel does?
+
+Well here it is.... the namei program. It follows things out until
+a terminal state is found.
+
+This program compiles and runs under:
+
+ SunOS 4.0.1 (sun3's)
+ SunOS 4.0.3 (sun4's)
+ SunOS 4.1.1 (sun4's)
+ Ultrix 3.1
+ BSD 4.3
+
+and probably a host of other 4.2 derived systems (but probably not
+System V).
+
+Anyway, if anyone has any bugs (or enhancements), please send them to
+me in E-mail form.
+
+And, by the way, if you make LOTS of money off of this program, please
+don't tell me :-).
+
+ -Roger (rogers@fangorn.wr.tek.com)
+ UUCP: ...!uunet!tektronix!fangorn.wr.tek.com!rogers
+ ARPA: <rogers%fangorn.wr.tek.com@RELAY.CS.NET>
diff --git a/misc-utils/README.script b/misc-utils/README.script
new file mode 100644
index 000000000..83dfcc5da
--- /dev/null
+++ b/misc-utils/README.script
@@ -0,0 +1,7 @@
+Here is a working version of the BSD script command which captures
+the output of a terminal session in a file.
+
+If you have libc-4.2 you don't need cfmakeraw.c or paths.h
+
+Rick Sladkey
+jrs@world.std.com
diff --git a/misc-utils/README1.namei b/misc-utils/README1.namei
new file mode 100644
index 000000000..fea56a3ce
--- /dev/null
+++ b/misc-utils/README1.namei
@@ -0,0 +1,14 @@
+
+** NAMEI has local modifications, do not delete source when cleaning up **
+
+"You're in a twisty maze of symbolic links, all different"
+
+namei - a utility to chase down a pathname and print details at each
+level, especialy when following symbolic links. Very useful for figuring
+out whats really going on in our large environment. Named after the routine
+in the kernel that does essentialy the same thing whenever anyone tries to
+find a file.
+
+Local modifications by Steve Tell include: changing the -m option to print
+the file mode in a readable fashion, like "ls -l" does, instead of in octal.
+
diff --git a/misc-utils/cal.1 b/misc-utils/cal.1
new file mode 100644
index 000000000..80d95b27d
--- /dev/null
+++ b/misc-utils/cal.1
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kim Letkeman.
+.\"
+.\" 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.
+.\"
+.\" @(#)cal.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt CAL 1
+.Os
+.Sh NAME
+.Nm cal
+.Nd displays a calendar
+.Sh SYNOPSIS
+.Nm cal
+.Op Fl jy
+.Op Ar month Op Ar year
+.Sh DESCRIPTION
+.Nm Cal
+displays a simple calendar.
+If arguments are not specified,
+the current month is displayed.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl j
+Display julian dates (days one-based, numbered from January 1).
+.It Fl y
+Display a calendar for the current year.
+.El
+.Pp
+A single parameter specifies the year (1 - 9999) to be displayed;
+note the year must be fully specified:
+.Dq Li cal 89
+will
+.Em not
+display a calendar for 1989.
+Two parameters denote the month (1 - 12) and year.
+If no parameters are specified, the current month's calendar is
+displayed.
+.Pp
+A year starts on Jan 1.
+.Pp
+The Gregorian Reformation is assumed to have occurred in 1752 on the 3rd
+of September.
+By this time, most countries had recognized the reformation (although a
+few did not recognize it until the early 1900's.)
+Ten days following that date were eliminated by the reformation, so the
+calendar for that month is a bit unusual.
+.Sh HISTORY
+A
+.Nm
+command appeared in Version 6 AT&T UNIX.
diff --git a/misc-utils/cal.c b/misc-utils/cal.c
new file mode 100644
index 000000000..8004016d6
--- /dev/null
+++ b/misc-utils/cal.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kim Letkeman.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <locale.h>
+#include <localeinfo.h>
+
+#define THURSDAY 4 /* for reformation */
+#define SATURDAY 6 /* 1 Jan 1 was a Saturday */
+
+#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */
+#define NUMBER_MISSING_DAYS 11 /* 11 day correction */
+
+#define MAXDAYS 42 /* max slots in a month array */
+#define SPACE -1 /* used in day array */
+
+static int days_in_month[2][13] = {
+ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+ {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+};
+
+int sep1752[MAXDAYS] = {
+ SPACE, SPACE, 1, 2, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+}, j_sep1752[MAXDAYS] = {
+ SPACE, SPACE, 245, 246, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+}, empty[MAXDAYS] = {
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+ SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE,
+};
+
+char *day_headings = " S M Tu W Th F S ";
+char *j_day_headings = " S M Tu W Th F S ";
+
+/* leap year -- account for gregorian reformation in 1752 */
+#define leap_year(yr) \
+ ((yr) <= 1752 ? !((yr) % 4) : \
+ !((yr) % 4) && ((yr) % 100) || !((yr) % 400))
+
+/* number of centuries since 1700, not inclusive */
+#define centuries_since_1700(yr) \
+ ((yr) > 1700 ? (yr) / 100 - 17 : 0)
+
+/* number of centuries since 1700 whose modulo of 400 is 0 */
+#define quad_centuries_since_1700(yr) \
+ ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
+
+/* number of leap years between year 1 and this year, not inclusive */
+#define leap_years_since_year_1(yr) \
+ ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
+
+int julian;
+
+void ascii_day __P((char *, int));
+void center __P((char *, int, int));
+void day_array __P((int, int, int *));
+int day_in_week __P((int, int, int));
+int day_in_year __P((int, int, int));
+void j_yearly __P((int));
+void monthly __P((int, int));
+void trim_trailing_spaces __P((char *));
+void usage __P((void));
+void yearly __P((int));
+void headers_init(void);
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct tm *local_time;
+ time_t now;
+ int ch, month, year, yflag;
+
+#ifdef __linux__
+ extern char *__progname;
+ __progname = argv[0];
+#endif
+
+ setlocale(LC_ALL,"");
+ headers_init();
+ yflag = 0;
+ while ((ch = getopt(argc, argv, "jy")) != EOF)
+ switch(ch) {
+ case 'j':
+ julian = 1;
+ break;
+ case 'y':
+ yflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ month = 0;
+ switch(argc) {
+ case 2:
+ if ((month = atoi(*argv++)) < 1 || month > 12)
+ errx(1, "illegal month value: use 1-12");
+ /* FALLTHROUGH */
+ case 1:
+ if ((year = atoi(*argv)) < 1 || year > 9999)
+ errx(1, "illegal year value: use 1-9999");
+ break;
+ case 0:
+ (void)time(&now);
+ local_time = localtime(&now);
+ year = local_time->tm_year + 1900;
+ if (!yflag)
+ month = local_time->tm_mon + 1;
+ break;
+ default:
+ usage();
+ }
+
+ if (month)
+ monthly(month, year);
+ else if (julian)
+ j_yearly(year);
+ else
+ yearly(year);
+ exit(0);
+}
+
+#define DAY_LEN 3 /* 3 spaces per day */
+#define J_DAY_LEN 4 /* 4 spaces per day */
+#define WEEK_LEN 21 /* 7 days * 3 characters */
+#define J_WEEK_LEN 28 /* 7 days * 4 characters */
+#define HEAD_SEP 2 /* spaces between day headings */
+#define J_HEAD_SEP 2
+
+void headers_init(void)
+{
+ int i;
+
+ strcpy(day_headings,"");
+ for(i = 0 ; i < 7 ; i++ )
+ {
+ strncat(day_headings,_time_info->abbrev_wkday[i],2);
+ strcat(day_headings," ");
+ }
+ strcpy(j_day_headings,"");
+ for(i = 0 ; i < 7 ; i++ )
+ {
+ strcat(j_day_headings,_time_info->abbrev_wkday[i]);
+ strcat(j_day_headings," ");
+ }
+}
+
+void
+monthly(month, year)
+ int month, year;
+{
+ int col, row, len, days[MAXDAYS];
+ char *p, lineout[30];
+
+ day_array(month, year, days);
+ len = sprintf(lineout, "%s %d", _time_info->full_month[month - 1], year);
+ (void)printf("%*s%s\n%s\n",
+ ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
+ lineout, julian ? j_day_headings : day_headings);
+ for (row = 0; row < 6; row++) {
+ for (col = 0, p = lineout; col < 7; col++,
+ p += julian ? J_DAY_LEN : DAY_LEN)
+ ascii_day(p, days[row * 7 + col]);
+ *p = '\0';
+ trim_trailing_spaces(lineout);
+ (void)printf("%s\n", lineout);
+ }
+}
+
+void
+j_yearly(year)
+ int year;
+{
+ int col, *dp, i, month, row, which_cal;
+ int days[12][MAXDAYS];
+ char *p, lineout[80];
+
+ (void)sprintf(lineout, "%d", year);
+ center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
+ (void)printf("\n\n");
+ for (i = 0; i < 12; i++)
+ day_array(i + 1, year, days[i]);
+ (void)memset(lineout, ' ', sizeof(lineout) - 1);
+ lineout[sizeof(lineout) - 1] = '\0';
+ for (month = 0; month < 12; month += 2) {
+ center(_time_info->full_month[month], J_WEEK_LEN, J_HEAD_SEP);
+ center(_time_info->full_month[month + 1], J_WEEK_LEN, 0);
+ (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
+ j_day_headings);
+ for (row = 0; row < 6; row++) {
+ for (which_cal = 0; which_cal < 2; which_cal++) {
+ p = lineout + which_cal * (J_WEEK_LEN + 2);
+ dp = &days[month + which_cal][row * 7];
+ for (col = 0; col < 7; col++, p += J_DAY_LEN)
+ ascii_day(p, *dp++);
+ }
+ *p = '\0';
+ trim_trailing_spaces(lineout);
+ (void)printf("%s\n", lineout);
+ }
+ }
+ (void)printf("\n");
+}
+
+void
+yearly(year)
+ int year;
+{
+ int col, *dp, i, month, row, which_cal;
+ int days[12][MAXDAYS];
+ char *p, lineout[80];
+
+ (void)sprintf(lineout, "%d", year);
+ center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
+ (void)printf("\n\n");
+ for (i = 0; i < 12; i++)
+ day_array(i + 1, year, days[i]);
+ (void)memset(lineout, ' ', sizeof(lineout) - 1);
+ lineout[sizeof(lineout) - 1] = '\0';
+ for (month = 0; month < 12; month += 3) {
+ center(_time_info->full_month[month], WEEK_LEN, HEAD_SEP);
+ center(_time_info->full_month[month + 1], WEEK_LEN, HEAD_SEP);
+ center(_time_info->full_month[month + 2], WEEK_LEN, 0);
+ (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
+ "", day_headings, HEAD_SEP, "", day_headings);
+ for (row = 0; row < 6; row++) {
+ for (which_cal = 0; which_cal < 3; which_cal++) {
+ p = lineout + which_cal * (WEEK_LEN + 2);
+ dp = &days[month + which_cal][row * 7];
+ for (col = 0; col < 7; col++, p += DAY_LEN)
+ ascii_day(p, *dp++);
+ }
+ *p = '\0';
+ trim_trailing_spaces(lineout);
+ (void)printf("%s\n", lineout);
+ }
+ }
+ (void)printf("\n");
+}
+
+/*
+ * day_array --
+ * Fill in an array of 42 integers with a calendar. Assume for a moment
+ * that you took the (maximum) 6 rows in a calendar and stretched them
+ * out end to end. You would have 42 numbers or spaces. This routine
+ * builds that array for any month from Jan. 1 through Dec. 9999.
+ */
+void
+day_array(month, year, days)
+ int month, year;
+ int *days;
+{
+ int day, dw, dm;
+
+ if (month == 9 && year == 1752) {
+ memmove(days,
+ julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
+ return;
+ }
+ memmove(days, empty, MAXDAYS * sizeof(int));
+ dm = days_in_month[leap_year(year)][month];
+ dw = day_in_week(1, month, year);
+ day = julian ? day_in_year(1, month, year) : 1;
+ while (dm--)
+ days[dw++] = day++;
+}
+
+/*
+ * day_in_year --
+ * return the 1 based day number within the year
+ */
+int
+day_in_year(day, month, year)
+ int day, month, year;
+{
+ int i, leap;
+
+ leap = leap_year(year);
+ for (i = 1; i < month; i++)
+ day += days_in_month[leap][i];
+ return (day);
+}
+
+/*
+ * day_in_week
+ * return the 0 based day number for any date from 1 Jan. 1 to
+ * 31 Dec. 9999. Assumes the Gregorian reformation eliminates
+ * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all
+ * missing days.
+ */
+int
+day_in_week(day, month, year)
+ int day, month, year;
+{
+ long temp;
+
+ temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
+ + day_in_year(day, month, year);
+ if (temp < FIRST_MISSING_DAY)
+ return ((temp - 1 + SATURDAY) % 7);
+ if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
+ return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
+ return (THURSDAY);
+}
+
+void
+ascii_day(p, day)
+ char *p;
+ int day;
+{
+ int display, val;
+ static char *aday[] = {
+ "",
+ " 1", " 2", " 3", " 4", " 5", " 6", " 7",
+ " 8", " 9", "10", "11", "12", "13", "14",
+ "15", "16", "17", "18", "19", "20", "21",
+ "22", "23", "24", "25", "26", "27", "28",
+ "29", "30", "31",
+ };
+
+ if (day == SPACE) {
+ memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
+ return;
+ }
+ if (julian) {
+ if (val = day / 100) {
+ day %= 100;
+ *p++ = val + '0';
+ display = 1;
+ } else {
+ *p++ = ' ';
+ display = 0;
+ }
+ val = day / 10;
+ if (val || display)
+ *p++ = val + '0';
+ else
+ *p++ = ' ';
+ *p++ = day % 10 + '0';
+ } else {
+ *p++ = aday[day][0];
+ *p++ = aday[day][1];
+ }
+ *p = ' ';
+}
+
+void
+trim_trailing_spaces(s)
+ char *s;
+{
+ char *p;
+
+ for (p = s; *p; ++p)
+ continue;
+ while (p > s && isspace(*--p))
+ continue;
+ if (p > s)
+ ++p;
+ *p = '\0';
+}
+
+void
+center(str, len, separate)
+ char *str;
+ int len;
+ int separate;
+{
+
+ len -= strlen(str);
+ (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
+ if (separate)
+ (void)printf("%*s", separate, "");
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
+ exit(1);
+}
diff --git a/misc-utils/clear.1 b/misc-utils/clear.1
new file mode 100644
index 000000000..1d4a5df79
--- /dev/null
+++ b/misc-utils/clear.1
@@ -0,0 +1,25 @@
+.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH CLEAR 1 "10 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+clear \- clear terminal screen
+.SH SYNOPSIS
+.BR clear
+.SH DESCRIPTION
+.B clear
+calls
+.BR tput (1)
+with the
+.I clear
+argument. This causes
+.B tput
+to attempt to clear the screen checking the data in
+.I /etc/termcap
+and sending the appropriate sequence to the terminal. This command can be
+redirected to clear the screen of some other terminal.
+.SH "SEE ALSO"
+.BR reset (1),
+.BR stty (1),
+.BR tput (1)
+.SH AUTHOR
+Rik Faith (faith@cs.unc.edu)
diff --git a/misc-utils/clear.sh b/misc-utils/clear.sh
new file mode 100644
index 000000000..73d1ebe1c
--- /dev/null
+++ b/misc-utils/clear.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+tput clear
diff --git a/misc-utils/dnsdomainname.1 b/misc-utils/dnsdomainname.1
new file mode 100644
index 000000000..1f45128b5
--- /dev/null
+++ b/misc-utils/dnsdomainname.1
@@ -0,0 +1 @@
+.so man1/hostname.1
diff --git a/misc-utils/domainname.1 b/misc-utils/domainname.1
new file mode 100644
index 000000000..447c71266
--- /dev/null
+++ b/misc-utils/domainname.1
@@ -0,0 +1,43 @@
+.\" Copyright 1992, 1995 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH DOMAINNAME 1 "16 February 1995" "Linux 1.0" "Linux Programmer's Manual"
+.SH NAME
+domainname \- set or print NIS domain of current host
+.SH SYNOPSIS
+.BR "domainname [ " name " ]"
+.SH DESCRIPTION
+.B domainname
+prints the NIS domainname of the current host, from the
+.BR getdomainname (3)
+library call. If an argument is present and the effective UID is 0,
+.B domainname
+changes the NIS domainname of the host, with the
+.BR setdomainname (2)
+system call. This is usually done at boot time in the
+.I /etc/rc.local
+script.
+.PP
+.B Note:
+This command sets the NIS (Network Information Services) domain,
+.I not
+the DNS (Domain Name System) domain. Unless you are running NIS
+(formerly known as Sun Yellow Pages (YP)), you should
+.I not
+use the
+.B domainname
+command to set your domain. You probably want to set the DNS domain, which
+is used to map human-readable machine names into IP addresses on the
+InterNet. See
+.BR dnsdomainname (1)
+for more information.
+.SH FILES
+.I /etc/rc.local
+.SH "SEE ALSO"
+.BR hostname (1),
+.BR dnsdomainname (1),
+.BR named (8),
+.BR sendmail (8),
+.bR ypinit (8)
+.SH AUTHOR
+Lars Wirzenius by substituting in hostname.c
+
diff --git a/misc-utils/domainname.c b/misc-utils/domainname.c
new file mode 100644
index 000000000..107091e87
--- /dev/null
+++ b/misc-utils/domainname.c
@@ -0,0 +1,29 @@
+/* domainname.c - poe@daimi.aau.dk */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define MAXDNAME 64
+
+int main(int argc, char *argv[])
+{
+ char hn[MAXDNAME + 1];
+
+ if(argc >= 2) {
+ if(geteuid() || getuid()) {
+ puts("You must be root to change the domainname");
+ exit(1);
+ }
+ if(strlen(argv[1]) > MAXDNAME) {
+ puts("That name is too long.");
+ exit(1);
+ }
+ setdomainname(argv[1], strlen(argv[1]));
+ } else {
+ getdomainname(hn, MAXDNAME);
+ puts(hn);
+ }
+ exit(0);
+}
diff --git a/misc-utils/dsplit.1 b/misc-utils/dsplit.1
new file mode 100644
index 000000000..f78f058fb
--- /dev/null
+++ b/misc-utils/dsplit.1
@@ -0,0 +1,46 @@
+.\" Public Domain 1994 Rik Faith (faith@cs.unc.edu)
+.TH DSPLIT 1 "5 July 1994" "Linux 1.1" "Linux Programmer's Manual"
+.SH NAME
+dsplit \- split a large file into pieces
+.SH SYNOPSIS
+.BI "dsplit [ \-size " nnn " ] [ " input_file " [ " output_base " ] ]"
+.SH DESCRIPTION
+.B dsplit
+splits binary files into smaller chunks so that they may be placed on
+floppy disks.
+.SH OPTIONS
+.TP
+.BI \-size " nnn"
+Specifies the size of each output file, in bytes. The default is 1457000,
+which is enough to will a 1.44 MB floppy disk.
+.TP
+.I input_file
+Specifies the name of the file to split up. A \- indicates standard input.
+The default is standard input.
+.TP
+.I output_base
+Specifies the name of the output files to be written.
+.B dsplit
+will append 000, 001, ..., to the
+.IR output_base .
+The default is "dsplit".
+.SH "AUTHOR'S NOTES"
+Submitted-by: arnstein@netcom.com (David Arnstein)
+.br
+Posting-number: Volume 40, Issue 51
+.br
+Archive-name: dsplit/part01
+.br
+Environment: MS-DOS, UNIX
+.PP
+Here is a portable binary file splitting program. It reads a binary file
+and splits it into pieces. I use this program to put large binary files on
+floppy disks. For this reason, the default size of the output files is
+1,457,000 bytes, which just about fills up a 1.44 MB floppy disk.
+.PP
+Unlike other binary split programs I have seen, dsplit does not malloc a
+huge block of memory. Dsplit is suitable for use under MSDOS and other
+primitive operating systems.
+.PP
+(The program came from
+gatekeeper.dec.com:/pub/usenet/comp.sources.misc/volume40/dsplit).
diff --git a/misc-utils/dsplit.c b/misc-utils/dsplit.c
new file mode 100644
index 000000000..14d8ffff1
--- /dev/null
+++ b/misc-utils/dsplit.c
@@ -0,0 +1,271 @@
+#ifdef lint
+ static char RCSid[] = "dsplit.c,v 1.1.1.1 1995/02/22 19:09:14";
+#endif
+/*
+ Program dsplit: Splits a large file into pieces.
+
+ Usage:
+ dsplit [-size nnn] [input_file [output_base]]
+ Size is size of each output file, in bytes. The default is 1457000,
+ enough to fill a "1.44MB" diskette, save 152 bytes.
+ input_file is the name of the file to split up. A dash (-) indicates
+ standard input. Defaults to standard input.
+ output_base is the name of the output files to be written, minus the
+ extension. Dsplit adds suffixes 000, 001, ...
+ The default base name is dsplit.
+*/
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if (defined (__MSDOS__) || defined (WIN32))
+#include <io.h>
+#include <fcntl.h>
+#endif /* __MSDOS__ or WIN32 */
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 1024
+#endif
+
+#define DEFAULT_NAME "dsplit"
+#define DEFAULT_SIZE 1457000L
+#if (defined (__MSDOS__) || defined (WIN32))
+# define READ_OPTIONS "rb"
+# define WRITE_OPTIONS "wb"
+#else
+# define READ_OPTIONS "r"
+# define WRITE_OPTIONS "w"
+#endif /* __MSDOS__ or WIN32 */
+
+#ifndef MIN
+#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
+#endif
+
+static unsigned long output_size = DEFAULT_SIZE;
+static char* base_name = DEFAULT_NAME;
+static FILE* input_handle;
+static char* input_name = "-";
+
+#ifdef __STDC__
+static void init (int argc, char* argv[]);
+static int write_one (int count);
+static void ToLower (char* string);
+static void usage_error (void);
+#else /* not __STDC__ */
+static void init (/* int argc, char* argv[] */);
+static int write_one (/* int count */);
+static void ToLower (/* char* string */);
+static void usage_error (/* void */);
+#endif /* __STDC__ */
+
+
+
+#ifdef __STDC__
+int main (int argc, char* argv[])
+#else
+int main (argc, argv)
+int argc;
+char* argv[];
+#endif
+{
+ int count;
+
+ /* Process command line arguments, open input file. */
+ init (argc, argv);
+
+ /* Write the output files */
+ for (count = 0 ; write_one (count) ; ++count)
+ ;
+
+ /* Close input file (a matter of style) */
+ if (fclose (input_handle) != 0)
+ {
+ (void)fprintf (stderr, "Could not close file \"%s\" for input\n",
+ input_name);
+ return 1;
+ }
+
+ /* Normal successful conclusion */
+ return 0;
+}
+
+
+
+#ifdef __STDC__
+static void init (int argc, char* argv[])
+#else
+static void init (argc, argv)
+int argc;
+char* argv[];
+#endif
+{
+ int iarg;
+ int name_count;
+
+ /* Initialize the input file handle to standard input. IBM's Toolset++
+ won't let me do this statically, unfortunately. */
+ input_handle = stdin;
+
+ /* Initialize for following loop */
+ name_count = 0;
+
+ /* Loop over command line arguments */
+ for (iarg = 1 ; iarg < argc ; ++iarg)
+ {
+ /* Point to argument,for convenience */
+ char* arg = argv[iarg];
+
+ /* If this argument is an option */
+ if (arg[0] == '-' && arg[1] != '\0')
+ {
+ /* Process option if recognized */
+ ToLower (arg+1);
+ if (strcmp (arg+1, "size") != 0)
+ usage_error ();
+ ++iarg;
+ if (iarg >= argc)
+ usage_error ();
+ arg = argv[iarg];
+ if (sscanf (arg, "%ld", &output_size) != 1)
+ {
+ (void)fprintf (stderr, "Illegal numeric expression \"%s\"\n", arg);
+ exit (1);
+ }
+ }
+ else /* argument is not an option */
+ {
+ /* Argument is a name string. Determine which one. */
+ switch (name_count)
+ {
+ case 0:
+ input_name = argv[iarg];
+ break;
+ case 1:
+ base_name = argv[iarg];
+ break;
+ default:
+ usage_error ();
+ break;
+ }
+ ++name_count;
+
+ } /* End if this argument is an option */
+
+ } /* End loop over command line arguments */
+
+ /* Open the input file */
+ if (strcmp (input_name, "-") == 0)
+ {
+# if (defined (__MSDOS__) || defined (WIN32))
+ if (setmode (0, O_BINARY) == -1)
+ {
+ perror ("dsplit: setmode");
+ exit (1);
+ }
+# endif
+ }
+ else
+ {
+ if ((input_handle = fopen (input_name, READ_OPTIONS)) == NULL)
+ {
+ (void)fprintf (stderr, "Could not open file \"%s\" for input\n",
+ input_name);
+ exit (1);
+ }
+ }
+}
+
+
+
+#ifdef __STDC__
+static int write_one (int count)
+#else
+static int write_one (count)
+int count;
+#endif
+{
+ char output_name[FILENAME_MAX];
+ int bytes_written;
+ unsigned long total_written;
+ FILE* output_handle;
+
+ /* Read the first buffer full now, just to see if any data is left */
+ static char buff[1024];
+ int to_read = MIN (sizeof(buff), output_size);
+ int bytes_read = fread (buff, 1, to_read, input_handle);
+ if (bytes_read <= 0)
+ return 0;
+
+ /* Open file for output */
+ sprintf (output_name, "%s.%03d", base_name, count);
+ output_handle = fopen (output_name, WRITE_OPTIONS);
+ if (output_handle == NULL)
+ {
+ (void)fprintf (stderr,
+ "Could not open file \"%s\" for output\n", output_name);
+ exit (1);
+ }
+
+ /* Write the first output buffer */
+ bytes_written = fwrite (buff, 1, bytes_read, output_handle);
+ if (bytes_written != bytes_read)
+ {
+ (void)fprintf (stderr, "Error writing to file \"%s\"\n", output_name);
+ exit (1);
+ }
+ total_written = bytes_written;
+
+ /* Write output file */
+ while (total_written < output_size)
+ {
+ to_read = MIN (sizeof(buff), output_size-total_written);
+ bytes_read = fread (buff, 1, to_read, input_handle);
+ if (bytes_read <= 0)
+ break;
+ bytes_written = fwrite (buff, 1, bytes_read, output_handle);
+ if (bytes_written != bytes_read)
+ {
+ (void)fprintf (stderr, "Error writing to file \"%s\"\n", output_name);
+ exit (1);
+ }
+ total_written += bytes_written;
+ }
+
+ /* Close the output file, it is complete */
+ if (fclose (output_handle) != 0)
+ {
+ (void)fprintf (stderr,
+ "Could not close file \"%s\" for output\n", output_name);
+ exit (1);
+ }
+
+ /* Indicate whether more data remains to be transferred */
+ return (bytes_read == to_read);
+}
+
+
+
+#ifdef __STDC__
+static void ToLower (char* string)
+#else
+static void ToLower (string)
+char* string;
+#endif
+{
+
+ while (*string != '\0')
+ tolower (*string++);
+}
+
+
+
+#ifdef __STDC__
+static void usage_error (void)
+#else
+static void usage_error ()
+#endif
+{
+ (void)fprintf (stderr,
+ "Usage: dsplit [-size nnn] [input_file [output_base]]\n");
+ exit (1);
+}
+
diff --git a/misc-utils/getoptprog.1 b/misc-utils/getoptprog.1
new file mode 100644
index 000000000..12853af7d
--- /dev/null
+++ b/misc-utils/getoptprog.1
@@ -0,0 +1,104 @@
+.Dd June 21, 1993
+.Dt GETOPT 1
+.Os
+.Sh NAME
+.Nm getopt
+.Nd parse command options
+.Sh SYNOPSIS
+.Nm set \-\- \`getopt optstring $*\`
+.Sh DESCRIPTION
+.Nm Getopt
+is used to break up options in command lines for easy parsing by
+shell procedures, and to check for legal options.
+.Op Optstring
+is a string of recognized option letters (see
+.Xr getopt 3
+);
+if a letter is followed by a colon, the option
+is expected to have an argument which may or may not be
+separated from it by white space.
+The special option
+.B \-\-
+is used to delimit the end of the options.
+.Nm Getopt
+will place
+.B \-\-
+in the arguments at the end of the options,
+or recognize it if used explicitly.
+The shell arguments
+(\fB$1 $2\fR ...) are reset so that each option is
+preceded by a
+.B \-
+and in its own shell argument;
+each option argument is also in its own shell argument.
+.Sh EXAMPLE
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Op a
+and
+.Op b ,
+and the option
+.Op o ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+set \-\- \`getopt abo: $*\`
+if test $? != 0
+then
+ echo 'Usage: ...'
+ exit 2
+fi
+for i
+do
+ case "$i"
+ in
+ \-a|\-b)
+ flag=$i; shift;;
+ \-o)
+ oarg=$2; shift; shift;;
+ \-\-)
+ shift; break;;
+ esac
+done
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-aoarg file file
+cmd \-a \-o arg file file
+cmd \-oarg -a file file
+cmd \-a \-oarg \-\- file file
+.Ed
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr getopt 3
+.Sh DIAGNOSTICS
+.Nm Getopt
+prints an error message on the standard error output when it
+encounters an option letter not included in
+.Op optstring .
+.Sh HISTORY
+Written by Henry Spencer, working from a Bell Labs manual page.
+Behavior believed identical to the Bell version.
+.Sh BUGS
+Whatever
+.Xr getopt 3
+has.
+.Pp
+Arguments containing white space or imbedded shell metacharacters
+generally will not survive intact; this looks easy to fix but isn't.
+.Pp
+The error message for an invalid option is identified as coming
+from
+.Nm getopt
+rather than from the shell procedure containing the invocation
+of
+.Nm getopt ;
+this again is hard to fix.
+.Pp
+The precise best way to use the
+.Nm set
+command to set the arguments without disrupting the value(s) of
+shell options varies from one shell version to another.
+varies from one shell version to another.
diff --git a/misc-utils/getoptprog.c b/misc-utils/getoptprog.c
new file mode 100644
index 000000000..03b0987ef
--- /dev/null
+++ b/misc-utils/getoptprog.c
@@ -0,0 +1,30 @@
+#include <stdio.h>
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int c;
+ int status = 0;
+
+ optind = 2; /* Past the program name and the option letters. */
+ while ((c = getopt(argc, argv, argv[1])) != EOF)
+ switch (c) {
+ case '?':
+ status = 1; /* getopt routine gave message */
+ break;
+ default:
+ if (optarg != NULL)
+ printf(" -%c %s", c, optarg);
+ else
+ printf(" -%c", c);
+ break;
+ }
+ printf(" --");
+ for (; optind < argc; optind++)
+ printf(" %s", argv[optind]);
+ printf("\n");
+ exit(status);
+}
diff --git a/misc-utils/hostid.1 b/misc-utils/hostid.1
new file mode 100644
index 000000000..9830a53d8
--- /dev/null
+++ b/misc-utils/hostid.1
@@ -0,0 +1,23 @@
+.TH hostid 1
+.SH NAME
+hostid \- set or print system's host id.
+.SH SYNTAX
+.B hostid
+[\-v] [\|\fIdecimal-id\fR\|]
+.SH DESCRIPTION
+.\".NXR "hostid command"
+The
+.B hostid
+command prints the current host id number in hexadecimal and both
+decimal and hexadecimal in parenthesis if the \-v option is given.
+This numeric value is expected to be unique across all hosts
+and is normally set to resemble the host's Internet address.
+
+Only the super-user can set the hostid by giving an argument. This value is
+stored in the file /etc/hostid and need only be performed once.
+
+.SH AUTHOR
+Hostid is written by Mitch DSouza \- (m.dsouza@mrc-apu.cam.ac.uk)
+
+.SH SEE ALSO
+gethostid(2), sethostid(2)
diff --git a/misc-utils/hostid.c b/misc-utils/hostid.c
new file mode 100644
index 000000000..829c5b672
--- /dev/null
+++ b/misc-utils/hostid.c
@@ -0,0 +1,36 @@
+/* Mitch DSouza - (m.dsouza@mrc-apu.cam.ac.uk) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+
+void main (int argc, char **argv)
+{
+ int verbose = 0;
+
+ if(argc == 2 && strcmp(argv[1], "-v") == 0) {
+ verbose = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc==2) {
+ if (sethostid(atoi(argv[1]))!=0) {
+ perror("sethostid");
+ exit(1);
+ }
+ } else if (argc==1) {
+ unsigned long id = gethostid();
+
+ if(id && verbose) {
+ printf("Hostid is %lu (0x%lx)\n",id,id);
+ } else if(id) {
+ printf("0x%lx\n", id);
+ } else {
+ printf("Usage: %s hostid_number\n",*argv);
+ }
+ }
+ exit(0);
+}
diff --git a/misc-utils/hostname.1 b/misc-utils/hostname.1
new file mode 100644
index 000000000..9efc07586
--- /dev/null
+++ b/misc-utils/hostname.1
@@ -0,0 +1,77 @@
+.TH HOSTNAME 1 "28 July 1994" "Linux" "Linux Programmer's Manual"
+.SH NAME
+hostname \- show or set the system's host name
+.br
+dnsdomainname \- show the system's domain name
+.SH SYNOPSIS
+.B hostname
+.RB [ \-d ]
+.RB [ \-\-domain ]
+.RB [ \-F\ filename ]
+.RB [ \-\-file\ filename ]
+.RB [ \-f ]
+.RB [ \-\-fqdn ]
+.RB [ \-h ]
+.RB [ \-\-help ]
+.RB [ \-\-long ]
+.RB [ \-s ]
+.RB [ \-\-short ]
+.RB [ \-v ]
+.RB [ \-\-version ]
+.RB [ name ]
+.br
+.B dnsdomainname
+.SH DESCRIPTION
+.B Hostname
+is the program that is used to either set the host name or display
+the current host or domain name of the system. This name is used
+by many of the networking programs to identify the machine.
+.LP
+When called without any arguments, the program displays the current
+name as set by the
+.B hostname
+command. You can change the output format to display always the short
+or the long host name (FQDN). When called with arguments, the program will
+set the value of the host name to the value specified. This usually is
+done only once, at system startup time, by the
+.I /etc/rc.d/rc.inet1
+configuration script.
+.LP
+Note, that only the super-user can change the host name.
+.LP
+If the program was called as
+.B dnsdomainname
+it will show the DNS domain name. You can't change the DNS domain name with
+.B dnsdomainname
+(see below).
+.SH OPTIONS
+.TP
+.I "\-d, \-\-domain"
+Display the name of the DNS domain. Don't use the command
+.B domainname
+to get the DNS domain name because it will show the NIS domain name and
+not the DNS domain name.
+.TP
+.I "\-F, \-\-file filename"
+Read the host name from the specified file. Comments (lines starting with
+a `#') are ignored.
+.TP
+.I "\-f, \-\-fqdn, \-\-long"
+Display the FQDN (Fully Qualified Domain Name). A FQDN consists of a
+short host name and the DNS domain name. Unless you are using bind or NIS
+for host lookups you can change the FQDN and the DNS domain name (which is
+part of the FQDN) in the \fI/etc/hosts\fR file.
+.TP
+.I "\-h, \-\-help"
+Print a usage message on standard output and exit successfully.
+.TP
+.I "\-s, \-\-short"
+Display the short host name.
+.TP
+.I "\-v, \-\-version"
+Print version information on standard output and exit successfully.
+.SH FILES
+.B /etc/hosts
+.SH AUTHOR
+Peter Tobias, <tobias@server.et-inf.fho-emden.de>
+
diff --git a/misc-utils/hostname.c b/misc-utils/hostname.c
new file mode 100644
index 000000000..2ff915afe
--- /dev/null
+++ b/misc-utils/hostname.c
@@ -0,0 +1,184 @@
+/* hostname -- set the host name or show the host/domain name
+
+ Copyright (C) 1994 Peter Tobias
+
+ 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#define NO_OPT -1
+
+static char *program_name;
+static const char *version_string = "hostname 1.6";
+
+static void sethname(char *);
+static void showhname(char *, int);
+static void usage(void);
+
+static void sethname(char *hname)
+{
+ if(sethostname(hname, strlen(hname))) {
+ switch(errno) {
+ case EPERM:
+ fprintf(stderr,"%s: you must be root to change the host name\n", program_name);
+ break;
+ case EINVAL:
+ fprintf(stderr,"%s: name too long\n", program_name);
+ break;
+ default:
+ }
+ exit(1);
+ };
+}
+
+static void showhname(char *hname, int c)
+{
+ struct hostent *hp;
+ register char *p;
+
+ if (!(hp = gethostbyname(hname))) {
+ herror(program_name);
+ exit(1);
+ }
+
+ if (!(p = strchr(hp->h_name, '.')) && (c == 'd')) return;
+
+ switch(c) {
+ case 'd':
+ printf("%s\n", ++p);
+ break;
+ case 'f':
+ printf("%s\n", hp->h_name);
+ break;
+ case 's':
+ if (p != NULL) *p = '\0';
+ printf("%s\n", hp->h_name);
+ break;
+ default:
+ }
+}
+
+static void usage(void)
+{
+ printf("Usage: %s [OPTION]... [hostname]\n\n\
+ -d, --domain display the DNS domain name\n\
+ -F, --file filename read the host name from file\n\
+ -f, --fqdn, --long display the long host name (FQDN)\n\
+ -s, --short display the short host name\n\
+ -h, --help display this help and exit\n\
+ -v, --version output version information and exit\n\
+\n\
+ When the program is called without any arguments, it displays the\n\
+ current host name as set by the hostname command. If an argument\n\
+ is given, the program will set the value of the host name to the\n\
+ value specified.\n\
+ Unless you are using bind or NIS for host lookups you can change the\n\
+ FQDN (Fully Qualified Domain Name) and the DNS domain name (which is\n\
+ part of the FQDN) in the /etc/hosts file.\n", program_name);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int option_index = 0;
+
+ char myname[MAXHOSTNAMELEN+1];
+
+ static const struct option long_options[] =
+ {
+ {"domain", no_argument, 0, 'd'},
+ {"file", required_argument, 0, 'F'},
+ {"fqdn", no_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {"long", no_argument, 0, 'f'},
+ {"short", no_argument, 0, 's'},
+ {"version", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+ program_name = (rindex(argv[0], '/')) ? rindex(argv[0], '/') + 1 : argv[0];
+
+ if (strcmp(program_name, "dnsdomainname") == 0) {
+ if (argc > 1) {
+ fprintf(stderr,"%s: You can't change the DNS domainname with this command\n", program_name);
+ fprintf(stderr,"\nUnless you are using bind or NIS for host lookups you can change the DNS\n");
+ fprintf(stderr,"domain name (which is part of the FQDN) in the /etc/hosts file.\n");
+ exit(1);
+ }
+ c = 'd';
+ } else
+ c = getopt_long(argc, argv, "dfF:hsv", long_options, &option_index);
+
+ gethostname(myname, sizeof(myname));
+
+ switch(c)
+ {
+ case 'd':
+ case 'f':
+ case 's':
+ showhname(myname, c);
+ break;
+ case 'F':
+ {
+ register FILE *fd;
+ register char *p;
+ char fline[MAXHOSTNAMELEN];
+
+ if ((fd = fopen(optarg, "r")) != NULL) {
+ while (fgets(fline, sizeof(fline), fd) != NULL)
+ if ((p = index(fline, '\n')) != NULL) {
+ *p = '\0';
+ if (fline[0] == '#')
+ continue;
+ sethname(fline);
+ }
+ (void) fclose(fd);
+ } else {
+ fprintf(stderr,"%s: can't open `%s'\n",
+ program_name, optarg);
+ exit(1);
+ }
+ }
+ break;
+ case 'h':
+ usage();
+ break;
+ case 'v':
+ printf("%s\n", version_string);
+ break;
+ case '?':
+ fprintf(stderr,"Try `%s --help' for more information.\n", program_name);
+ exit(1);
+ break;
+ case NO_OPT:
+ if (optind < argc) {
+ sethname(argv[optind]);
+ exit(0);
+ }
+ default:
+ printf("%s\n", myname);
+
+ };
+ exit(0);
+}
diff --git a/misc-utils/kill.1 b/misc-utils/kill.1
new file mode 100644
index 000000000..aad5c23ba
--- /dev/null
+++ b/misc-utils/kill.1
@@ -0,0 +1,49 @@
+.\" Copyright 1994 Salvatore Valente (svalente@mit.edu)
+.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH KILL 1 "14 October 1994" "Linux Utilities" "Linux Programmer's Manual"
+.SH NAME
+kill \- terminate a process
+.SH SYNOPSIS
+.BR "kill" " [ \-s signal | \-p ] " " [ -a ] " "pid ..."
+.br
+.B "kill -l [ signal ]"
+.SH DESCRIPTION
+.B kill
+sends the specified signal to the specified process. If no signal is
+specified, the TERM signal is sent. The TERM signal will kill processes
+which do not catch this signal. For other processes, if may be necessary
+to use the KILL (9) signal, since this signal cannot be caught.
+
+Most modern shells have a builtin kill function.
+.SH OPTIONS
+.TP
+.BR "pid ..."
+Specify the list of processes that
+.B kill
+should signal. Each
+.I pid
+can be a process id, or a process name.
+.TP
+.BR \-s
+Specify the signal to send.
+The signal may be given as a signal name or number.
+.TP
+.BR \-p
+Specify that
+.B kill
+should only print the process id
+.I (pid)
+of the named process, and should not send it a signal.
+.TP
+.BR \-l
+Print a list of signal names. These are found in
+.I /usr/include/linux/signal.h
+.SH "SEE ALSO"
+.BR bash (1),
+.BR tcsh (1),
+.BR kill (2),
+.BR sigvec (2)
+.SH AUTHOR
+Taken from BSD 4.4. The ability to translate process names to process
+ids was added by Salvatore Valente <svalente@mit.edu>.
diff --git a/misc-utils/kill.c b/misc-utils/kill.c
new file mode 100644
index 000000000..f89ff67c1
--- /dev/null
+++ b/misc-utils/kill.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1988, 1993, 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.
+ */
+/*
+ * oct 5 1994 -- almost entirely re-written to allow for process names.
+ * modifications (c) salvatore valente <svalente@mit.edu>
+ * may be used / modified / distributed under the same terms as the original.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+
+#ifdef __linux__
+/*
+ * sys_signame -- an ordered list of signals.
+ * lifted from /usr/include/linux/signal.h
+ * this particular order is only correct for linux.
+ * this is _not_ portable.
+ */
+char *sys_signame[NSIG] = {
+ "zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED",
+ "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
+ "STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO",
+ "XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL
+};
+#endif
+
+int main (int argc, char *argv[]);
+char *mybasename(char *pathname);
+int signame_to_signum (char *sig);
+int arg_to_signum (char *arg);
+void nosig (char *name);
+void printsig (int sig);
+void printsignals (FILE *fp);
+int usage (int status);
+int kill_verbose (char *procname, int pid, int sig);
+
+extern int *get_pids (char *, int);
+
+char version_string[] = "kill v2.0\n";
+char *whoami;
+
+int main (int argc, char *argv[])
+{
+ int errors, numsig, pid;
+ char *ep, *arg;
+ int do_pid, do_kill, check_all;
+ int *pids, *ip;
+
+ whoami = mybasename (*argv);
+ numsig = SIGTERM;
+ do_pid = (! strcmp (whoami, "pid"));
+ do_kill = 0;
+ check_all = 0;
+
+ /* loop through the arguments.
+ actually, -a is the only option can be used with other options.
+ `kill' is basically a one-option-at-most program. */
+ for (argc--, argv++; argc > 0; argc--, argv++) {
+ arg = *argv;
+ if (*arg != '-') {
+ break;
+ }
+ if (! strcmp (arg, "-u")) {
+ return usage (0);
+ }
+ if (! strcmp (arg, "-v")) {
+ fputs (version_string, stdout);
+ return 0;
+ }
+ if (! strcmp (arg, "-a")) {
+ check_all++;
+ continue;
+ }
+ if (! strcmp (arg, "-l")) {
+ if (argc < 2) {
+ printsignals (stdout);
+ return 0;
+ }
+ if (argc > 2) {
+ return usage (1);
+ }
+ /* argc == 2 */
+ arg = argv[1];
+ if ((numsig = arg_to_signum (arg)) < 0) {
+ fprintf (stderr, "%s: unknown signal %s\n", whoami, arg);
+ return 1;
+ }
+ printsig (numsig);
+ return 0;
+ }
+ if (! strcmp (arg, "-p")) {
+ do_pid++;
+ if (do_kill)
+ return usage (1);
+ continue;
+ }
+ if (! strcmp (arg, "-s")) {
+ if (argc < 2) {
+ return usage (1);
+ }
+ do_kill++;
+ if (do_pid)
+ return usage (1);
+ argc--, argv++;
+ arg = *argv;
+ if ((numsig = arg_to_signum (arg)) < 0) {
+ nosig (arg);
+ return 1;
+ }
+ continue;
+ }
+ /* `arg' begins with a dash but is not a known option.
+ so it's probably something like -HUP.
+ try to deal with it. */
+ arg++;
+ if ((numsig = arg_to_signum (arg)) < 0) {
+ return usage (1);
+ }
+ do_kill++;
+ if (do_pid)
+ return usage (1);
+ continue;
+ }
+
+ if (! *argv) {
+ return usage (1);
+ }
+ if (do_pid) {
+ numsig = -1;
+ }
+
+ /* we're done with the options.
+ the rest of the arguments should be process ids and names.
+ kill them. */
+ for (errors = 0; (arg = *argv) != NULL; argv++) {
+ pid = strtol (arg, &ep, 10);
+ if (! *ep)
+ errors += kill_verbose (arg, pid, numsig);
+ else {
+ pids = get_pids (arg, check_all);
+ if (! pids) {
+ errors++;
+ fprintf (stderr, "%s: can't find process \"%s\"\n",
+ whoami, arg);
+ continue;
+ }
+ for (ip = pids; *ip >= 0; ip++)
+ errors += kill_verbose (arg, *ip, numsig);
+ free (pids);
+ }
+ }
+ return (errors);
+}
+
+char *mybasename (char *path)
+{
+ char *cp;
+
+ cp = strrchr (path, '/');
+ return (cp ? cp + 1 : path);
+}
+
+int signame_to_signum (char *sig)
+{
+ int n;
+
+ if (! strncasecmp (sig, "sig", 3))
+ sig += 3;
+ for (n = 1; (n < NSIG) && (sys_signame[n] != NULL); n++) {
+ if (! strcasecmp (sys_signame[n], sig))
+ return n;
+ }
+ return (-1);
+}
+
+int arg_to_signum (char *arg)
+{
+ int numsig;
+ char *ep;
+
+ if (isdigit (*arg)) {
+ numsig = strtol (arg, &ep, 10);
+ if (*ep != 0 || numsig < 0 || numsig >= NSIG)
+ return (-1);
+ return (numsig);
+ }
+ return (signame_to_signum (arg));
+}
+
+void nosig (char *name)
+{
+ fprintf (stderr, "%s: unknown signal %s; valid signals:\n", whoami, name);
+ printsignals (stderr);
+}
+
+void printsig (int sig)
+{
+ printf ("%s\n", sys_signame[sig]);
+}
+
+void printsignals (FILE *fp)
+{
+ int n;
+
+ for (n = 1; (n < NSIG) && (sys_signame[n] != NULL); n++) {
+ fputs (sys_signame[n], fp);
+ if (n == (NSIG / 2) || n == (NSIG - 1))
+ fputc ('\n', fp);
+ else
+ fputc (' ', fp);
+ }
+ if (n < (NSIG - 1))
+ fputc ('\n', fp);
+}
+
+int usage (int status)
+{
+ FILE *fp;
+
+ fp = (status == 0 ? stdout : stderr);
+ fprintf (fp, "usage: %s [ -s signal | -p ] [ -a ] pid ...\n", whoami);
+ fprintf (fp, " %s -l [ signal ]\n", whoami);
+ return status;
+}
+
+int kill_verbose (char *procname, int pid, int sig)
+{
+ if (sig < 0) {
+ printf ("%d\n", pid);
+ return 0;
+ }
+ if (kill (pid, sig) < 0) {
+ fprintf (stderr, "%s ", whoami);
+ perror (procname);
+ return 1;
+ }
+ return 0;
+}
diff --git a/misc-utils/logger.1 b/misc-utils/logger.1
new file mode 100644
index 000000000..0621dba10
--- /dev/null
+++ b/misc-utils/logger.1
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)logger.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LOGGER 1
+.Os BSD 4.3
+.Sh NAME
+.Nm logger
+.Nd make entries in the system log
+.Sh SYNOPSIS
+.Nm logger
+.Op Fl is
+.Op Fl f Ar file
+.Op Fl p Ar pri
+.Op Fl t Ar tag
+.Op Ar message ...
+.Sh DESCRIPTION
+.Nm Logger
+provides a shell command interface to the
+.Xr syslog 3
+system log module.
+.Pp
+Options:
+.Pp
+.Bl -tag -width "message"
+.It Fl i
+Log the process id of the logger process
+with each line.
+.It Fl s
+Log the message to standard error, as well as the system log.
+.It Fl f Ar file
+Log the specified file.
+.It Fl p Ar pri
+Enter the message with the specified priority.
+The priority may be specified numerically or as a ``facility.level''
+pair.
+For example, ``\-p local3.info'' logs the message(s) as
+.Ar info Ns rmational
+level in the
+.Ar local3
+facility.
+The default is ``user.notice.''
+.It Fl t Ar tag
+Mark every line in the log with the specified
+.Ar tag .
+.It Ar message
+Write the message to log; if not specified, and the
+.Fl f
+flag is not
+provided, standard input is logged.
+.El
+.Pp
+The
+.Nm logger
+utility exits 0 on success, and >0 if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent -compact
+logger System rebooted
+
+logger \-p local0.notice \-t HOSTIDM \-f /dev/idmc
+.Ed
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr syslogd 8
+.Sh STANDARDS
+The
+.Nm logger
+command is expected to be
+.St -p1003.2
+compatible.
diff --git a/misc-utils/logger.c b/misc-utils/logger.c
new file mode 100644
index 000000000..3fd3b6b20
--- /dev/null
+++ b/misc-utils/logger.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#define SYSLOG_NAMES
+#include <syslog.h>
+
+int decode __P((char *, CODE *));
+int pencode __P((char *));
+void usage __P((void));
+
+/*
+ * logger -- read and log utility
+ *
+ * Reads from an input and arranges to write the result on the system
+ * log.
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, logflags, pri;
+ char *tag, buf[1024];
+
+ tag = NULL;
+ pri = LOG_NOTICE;
+ logflags = 0;
+ while ((ch = getopt(argc, argv, "f:ip:st:")) != EOF)
+ switch((char)ch) {
+ case 'f': /* file to log */
+ if (freopen(optarg, "r", stdin) == NULL) {
+ (void)fprintf(stderr, "logger: %s: %s.\n",
+ optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+ case 'i': /* log process id also */
+ logflags |= LOG_PID;
+ break;
+ case 'p': /* priority */
+ pri = pencode(optarg);
+ break;
+ case 's': /* log to standard error */
+ logflags |= LOG_PERROR;
+ break;
+ case 't': /* tag */
+ tag = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* setup for logging */
+ openlog(tag ? tag : getlogin(), logflags, 0);
+ (void) fclose(stdout);
+
+ /* log input line if appropriate */
+ if (argc > 0) {
+ register char *p, *endp;
+ int len;
+
+ for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
+ len = strlen(*argv);
+ if (p + len > endp && p > buf) {
+ syslog(pri, "%s", buf);
+ p = buf;
+ }
+ if (len > sizeof(buf) - 1)
+ syslog(pri, "%s", *argv++);
+ else {
+ if (p != buf)
+ *p++ = ' ';
+ bcopy(*argv++, p, len);
+ *(p += len) = '\0';
+ }
+ }
+ if (p != buf)
+ syslog(pri, "%s", buf);
+ } else
+ while (fgets(buf, sizeof(buf), stdin) != NULL)
+ syslog(pri, "%s", buf);
+ exit(0);
+}
+
+/*
+ * Decode a symbolic name to a numeric value
+ */
+int
+pencode(s)
+ register char *s;
+{
+ char *save;
+ int fac, lev;
+
+ for (save = s; *s && *s != '.'; ++s);
+ if (*s) {
+ *s = '\0';
+ fac = decode(save, facilitynames);
+ if (fac < 0) {
+ (void)fprintf(stderr,
+ "logger: unknown facility name: %s.\n", save);
+ exit(1);
+ }
+ *s++ = '.';
+ }
+ else {
+ fac = 0;
+ s = save;
+ }
+ lev = decode(s, prioritynames);
+ if (lev < 0) {
+ (void)fprintf(stderr,
+ "logger: unknown priority name: %s.\n", save);
+ exit(1);
+ }
+ return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+}
+
+int
+decode(name, codetab)
+ char *name;
+ CODE *codetab;
+{
+ register CODE *c;
+
+ if (isdigit(*name))
+ return (atoi(name));
+
+ for (c = codetab; c->c_name; c++)
+ if (!strcasecmp(name, c->c_name))
+ return (c->c_val);
+
+ return (-1);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "logger: [-is] [-f file] [-p pri] [-t tag] [ message ... ]\n");
+ exit(1);
+}
diff --git a/misc-utils/look.1 b/misc-utils/look.1
new file mode 100644
index 000000000..872d4af75
--- /dev/null
+++ b/misc-utils/look.1
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)look.1 8.1 (Berkeley) 6/14/93
+.\"
+.Dd June 14, 1993
+.Dt LOOK 1
+.Os
+.Sh NAME
+.Nm look
+.Nd display lines beginning with a given string
+.Sh SYNOPSIS
+.Nm look
+.Op Fl dfa
+.Op Fl t Ar termchar
+.Ar string
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm look
+utility displays any lines in
+.Ar file
+which contain
+.Ar string
+as a prefix.
+As
+.Nm look
+performs a binary search, the lines in
+.Ar file
+must be sorted.
+.Pp
+If
+.Ar file
+is not specified, the file
+.Pa /usr/dict/words
+is used, only alphanumeric characters are compared and the case of
+alphabetic characters is ignored.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl d
+Dictionary character set and order, i.e. only alphanumeric characters
+are compared.
+.It Fl f
+Ignore the case of alphabetic characters.
+.It Fl a
+Use the alternate dictionary
+.Pa /usr/dict/web2
+.It Fl t
+Specify a string termination character, i.e. only the characters
+in
+.Ar string
+up to and including the first occurrence of
+.Ar termchar
+are compared.
+.El
+.Pp
+The
+.Nm look
+utility exits 0 if one or more lines were found and displayed,
+1 if no lines were found, and >1 if an error occurred.
+.Sh FILES
+.Bl -tag -width /usr/dict/words -compact
+.It Pa /usr/dict/words
+the dictionary
+.It Pa /usr/dict/web2
+the alternate dictionary
+.El
+.Sh SEE ALSO
+.Xr grep 1 ,
+.Xr sort 1
+.Sh COMPATIBILITY
+The original manual page stated that tabs and blank characters participated
+in comparisons when the
+.Fl d
+option was specified.
+This was incorrect and the current man page matches the historic
+implementation.
+.Sh HISTORY
+.Nm Look
+appeared in Version 7 AT&T Unix.
diff --git a/misc-utils/look.c b/misc-utils/look.c
new file mode 100644
index 000000000..5a47970ed
--- /dev/null
+++ b/misc-utils/look.c
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems, Inc.
+ *
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)look.c 8.1 (Berkeley) 6/14/93";
+#endif /* not lint */
+
+/*
+ * look -- find lines in a sorted list.
+ *
+ * The man page said that TABs and SPACEs participate in -d comparisons.
+ * In fact, they were ignored. This implements historic practice, not
+ * the manual page.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <getopt.h>
+#include "pathnames.h"
+
+/*
+ * FOLD and DICT convert characters to a normal form for comparison,
+ * according to the user specified flags.
+ *
+ * DICT expects integers because it uses a non-character value to
+ * indicate a character which should not participate in comparisons.
+ */
+#define EQUAL 0
+#define GREATER 1
+#define LESS (-1)
+#define NO_COMPARE (-2)
+
+#define FOLD(c) (isascii(c) && isupper(c) ? tolower(c) : (c))
+#define DICT(c) (isascii(c) && isalnum(c) ? (c) : NO_COMPARE)
+
+int dflag, fflag;
+
+char *binary_search __P((char *, char *, char *));
+int compare __P((char *, char *, char *));
+void err __P((const char *fmt, ...));
+char *linear_search __P((char *, char *, char *));
+int look __P((char *, char *, char *));
+void print_from __P((char *, char *, char *));
+
+static void usage __P((void));
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct stat sb;
+ int ch, fd, termchar;
+ char *back, *file, *front, *string, *p;
+
+ file = _PATH_WORDS;
+ termchar = '\0';
+ while ((ch = getopt(argc, argv, "adft:")) != EOF)
+ switch(ch) {
+ case 'a':
+ file = _PATH_WORDS_ALT;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 't':
+ termchar = *optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 2: /* Don't set -df for user. */
+ string = *argv++;
+ file = *argv;
+ break;
+ case 1: /* But set -df by default. */
+ dflag = fflag = 1;
+ string = *argv;
+ break;
+ default:
+ usage();
+ }
+
+ if (termchar != '\0' && (p = strchr(string, termchar)) != NULL)
+ *++p = '\0';
+
+ if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
+ err("%s: %s", file, strerror(errno));
+ if ((void *)(front = mmap(NULL,
+ (size_t)sb.st_size,
+ PROT_READ,
+ MAP_FILE|MAP_SHARED,
+ fd,
+ (off_t)0)) <= (void *)0)
+ err("%s: %s", file, strerror(errno));
+ back = front + sb.st_size;
+ exit(look(string, front, back));
+}
+
+look(string, front, back)
+ char *string, *front, *back;
+{
+ register int ch;
+ register char *readp, *writep;
+
+ /* Reformat string string to avoid doing it multiple times later. */
+ for (readp = writep = string; ch = *readp++;) {
+ if (fflag)
+ ch = FOLD(ch);
+ if (dflag)
+ ch = DICT(ch);
+ if (ch != NO_COMPARE)
+ *(writep++) = ch;
+ }
+ *writep = '\0';
+
+ front = binary_search(string, front, back);
+ front = linear_search(string, front, back);
+
+ if (front)
+ print_from(string, front, back);
+ return (front ? 0 : 1);
+}
+
+
+/*
+ * Binary search for "string" in memory between "front" and "back".
+ *
+ * This routine is expected to return a pointer to the start of a line at
+ * *or before* the first word matching "string". Relaxing the constraint
+ * this way simplifies the algorithm.
+ *
+ * Invariants:
+ * front points to the beginning of a line at or before the first
+ * matching string.
+ *
+ * back points to the beginning of a line at or after the first
+ * matching line.
+ *
+ * Base of the Invariants.
+ * front = NULL;
+ * back = EOF;
+ *
+ * Advancing the Invariants:
+ *
+ * p = first newline after halfway point from front to back.
+ *
+ * If the string at "p" is not greater than the string to match,
+ * p is the new front. Otherwise it is the new back.
+ *
+ * Termination:
+ *
+ * The definition of the routine allows it return at any point,
+ * since front is always at or before the line to print.
+ *
+ * In fact, it returns when the chosen "p" equals "back". This
+ * implies that there exists a string is least half as long as
+ * (back - front), which in turn implies that a linear search will
+ * be no more expensive than the cost of simply printing a string or two.
+ *
+ * Trying to continue with binary search at this point would be
+ * more trouble than it's worth.
+ */
+#define SKIP_PAST_NEWLINE(p, back) \
+ while (p < back && *p++ != '\n');
+
+char *
+binary_search(string, front, back)
+ register char *string, *front, *back;
+{
+ register char *p;
+
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+
+ /*
+ * If the file changes underneath us, make sure we don't
+ * infinitely loop.
+ */
+ while (p < back && back > front) {
+ if (compare(string, p, back) == GREATER)
+ front = p;
+ else
+ back = p;
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+ }
+ return (front);
+}
+
+/*
+ * Find the first line that starts with string, linearly searching from front
+ * to back.
+ *
+ * Return NULL for no such line.
+ *
+ * This routine assumes:
+ *
+ * o front points at the first character in a line.
+ * o front is before or at the first line to be printed.
+ */
+char *
+linear_search(string, front, back)
+ char *string, *front, *back;
+{
+ while (front < back) {
+ switch (compare(string, front, back)) {
+ case EQUAL: /* Found it. */
+ return (front);
+ break;
+ case LESS: /* No such string. */
+ return (NULL);
+ break;
+ case GREATER: /* Keep going. */
+ break;
+ }
+ SKIP_PAST_NEWLINE(front, back);
+ }
+ return (NULL);
+}
+
+/*
+ * Print as many lines as match string, starting at front.
+ */
+void
+print_from(string, front, back)
+ register char *string, *front, *back;
+{
+ for (; front < back && compare(string, front, back) == EQUAL; ++front) {
+ for (; front < back && *front != '\n'; ++front)
+ if (putchar(*front) == EOF)
+ err("stdout: %s", strerror(errno));
+ if (putchar('\n') == EOF)
+ err("stdout: %s", strerror(errno));
+ }
+}
+
+/*
+ * Return LESS, GREATER, or EQUAL depending on how the string1 compares with
+ * string2 (s1 ??? s2).
+ *
+ * o Matches up to len(s1) are EQUAL.
+ * o Matches up to len(s2) are GREATER.
+ *
+ * Compare understands about the -f and -d flags, and treats comparisons
+ * appropriately.
+ *
+ * The string "s1" is null terminated. The string s2 is '\n' terminated (or
+ * "back" terminated).
+ */
+int
+compare(s1, s2, back)
+ register char *s1, *s2, *back;
+{
+ register int ch;
+
+ for (; *s1 && s2 < back && *s2 != '\n';) {
+ ch = *s2;
+ if (fflag)
+ ch = FOLD(ch);
+ if (dflag)
+ ch = DICT(ch);
+
+ if (ch == NO_COMPARE) {
+ ++s2; /* Ignore character in comparison. */
+ continue;
+ }
+ if (*s1 != ch)
+ return (*s1 < ch ? LESS : GREATER);
+ ++s1;
+ ++s2;
+ }
+ return (*s1 ? GREATER : EQUAL);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: look [-dfa] [-t char] string [file]\n");
+ exit(2);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "look: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(2);
+ /* NOTREACHED */
+}
diff --git a/misc-utils/mcookie.1 b/misc-utils/mcookie.1
new file mode 100644
index 000000000..395082548
--- /dev/null
+++ b/misc-utils/mcookie.1
@@ -0,0 +1,17 @@
+.\" mcookie.1 --
+.\" Public Domain 1995 Rickard E. Faith (faith@cs.unc.edu)
+.TH MCOOKIE 1 "12 Feb 1995" "" "Linux Programmer's Manual"
+.SH NAME
+mcookie \- generate magic cookies for xauth
+.SH SYNOPSIS
+.B mcookie
+.SH DESCRIPTION
+.B mcookie
+generates a 128-bit random hexadecimal number for use with the X authority
+system. Typical usage:
+.RS
+xauth add :0 . `mcookie`
+.RE
+.SH "SEE ALSO"
+.BR X (1),
+.BR xauth (1)
diff --git a/misc-utils/mcookie.c b/misc-utils/mcookie.c
new file mode 100644
index 000000000..d0730edde
--- /dev/null
+++ b/misc-utils/mcookie.c
@@ -0,0 +1,44 @@
+/* mcookie.c -- Generates random numbers for xauth
+ * Created: Fri Feb 3 10:42:48 1995 by faith@cs.unc.edu
+ * Revised: Sun Feb 12 20:29:58 1995 by faith@cs.unc.edu
+ * Public Domain 1995 Rickard E. Faith (faith@cs.unc.edu)
+ * This program comes with ABSOLUTELY NO WARRANTY.
+ *
+ * mcookie.c,v 1.1.1.1 1995/02/22 19:09:16 faith Exp
+ */
+
+#define SECURE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#if SECURE
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+int main( void )
+{
+ int i;
+#if SECURE
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday( &tv, &tz );
+ srand( tv.tv_sec + tv.tv_usec );
+#else
+ long int t;
+
+ time( &t );
+ srand( t );
+#endif
+
+ for (i = 0; i < 32; i++) {
+ int r = (rand() & 0x0f0) >> 4;
+
+ if (r < 10) putchar( '0' + r );
+ else putchar( 'a' + r - 10 );
+ }
+ putchar ( '\n' );
+
+ return 0;
+}
diff --git a/misc-utils/md5.c b/misc-utils/md5.c
new file mode 100644
index 000000000..005568b5e
--- /dev/null
+++ b/misc-utils/md5.c
@@ -0,0 +1,253 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
+
diff --git a/misc-utils/md5.h b/misc-utils/md5.h
new file mode 100644
index 000000000..e264f686d
--- /dev/null
+++ b/misc-utils/md5.h
@@ -0,0 +1,27 @@
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/misc-utils/md5sum.1 b/misc-utils/md5sum.1
new file mode 100644
index 000000000..86094b27b
--- /dev/null
+++ b/misc-utils/md5sum.1
@@ -0,0 +1,64 @@
+.\" md5sum.1 --
+.\" Public Domain 1995 Rik Faith (faith@cs.unc.edu)
+.\" Revised: Sat Feb 11 12:16:48 1995 by faith@cs.unc.edu
+.\" "
+.TH MD5SUM 1 "11 February 1995" "Linux 1.0" "Linux Programmer's Manual"
+.SH NAME
+md5sum \- generate/check MD5 message digests
+.SH SYNOPSIS
+.BR "md5sum [" \-bv "] [" \-c
+.BR "[ " file " ] ]"
+.br
+.BR "md5sum " file " ..."
+.SH DESCRIPTION
+.B md5sum
+generates and checks MD5 message digests, as described in RFC-1321. The
+"message digest" produced can be thought of as a 128-bit "signature" of the
+input file. Typically,
+.B md5sum
+is used to verify the integrity of files made available for distribution
+via anonymous ftp (for example, announcements for new versions of
+.BR irc(1)
+usually contain MD5 signatures).
+.P
+Message digests for a tree of files can be generated with a command similar
+to the following:
+.RS
+.sp
+find . -type f -print | xargs md5sum
+.sp
+.RE
+The output of this command is suitable as input for the
+.B \-c
+option.
+.SH OPTIONS
+.TP
+.BI "\-c [" file "]"
+Check message digests. Input is taken from
+.B stdin
+or from the spcified
+.IR file .
+The input should be in the same format as the output generated by
+.BR md5sum .
+.TP
+.B \-v
+Verbose. Print file names when checking.
+.TP
+.B \-b
+Read files in binary mode (otherwise, end-of-file conventions will be
+ignored).
+.SH HISTOY
+The
+.B md5sum
+program was written by Branko Lankester and may be freely distributed. The
+original source code is in the MIT PGP 2.6.2 distribution. Those concerned
+about the integrity of this version should obtain the original sources and
+compile their own version.
+.PP
+The underlying implementation of Ron Rivest's MD5 algorithm was written by
+Colin Plumb and is in the Public Domain. (Equivalent code is also
+available from RSA Data Security, Inc.)
+.SH "SEE ALSO"
+.BR sum (1),
+.BR cksum (1),
+.BR pgp (1)
diff --git a/misc-utils/md5sum.c b/misc-utils/md5sum.c
new file mode 100644
index 000000000..e0b1dc9c0
--- /dev/null
+++ b/misc-utils/md5sum.c
@@ -0,0 +1,243 @@
+/*
+ * md5sum.c - Generate/check MD5 Message Digests
+ *
+ * Compile and link with md5.c. If you don't have getopt() in your library
+ * also include getopt.c. For MSDOS you can also link with the wildcard
+ * initialization function (wildargs.obj for Turbo C and setargv.obj for MSC)
+ * so that you can use wildcards on the commandline.
+ *
+ * Written March 1993 by Branko Lankester
+ * Modified June 1993 by Colin Plumb for altered md5.c.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "md5.h"
+
+#ifdef UNIX
+#define FOPRTXT "r"
+#define FOPRBIN "r"
+#else
+#ifdef VMS
+#define FOPRTXT "r","ctx=stm"
+#define FOPRBIN "rb","ctx=stm"
+#else
+#define FOPRTXT "r"
+#define FOPRBIN "rb"
+#endif
+#endif
+
+extern char *optarg;
+extern int optind;
+
+void usage();
+void print_digest();
+int mdfile(FILE *fp, unsigned char *digest);
+int do_check(FILE *chkf);
+
+char *progname;
+int verbose = 0;
+int bin_mode = 0;
+
+void
+main(int argc, char **argv)
+{
+ int opt, rc = 0;
+ int check = 0;
+ FILE *fp;
+ unsigned char digest[16];
+
+ progname = *argv;
+ while ((opt = getopt(argc, argv, "cbvp:h")) != EOF) {
+ switch (opt) {
+ case 'c': check = 1; break;
+ case 'v': verbose = 1; break;
+ case 'b': bin_mode = 1; break;
+ default: usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (check) {
+ switch (argc) {
+ case 0: fp = stdin; break;
+ case 1: if ((fp = fopen(*argv, FOPRTXT)) == NULL) {
+ perror(*argv);
+ exit(2);
+ }
+ break;
+ default: usage();
+ }
+ exit(do_check(fp));
+ }
+ if (argc == 0) {
+ if (mdfile(stdin, digest)) {
+ fprintf(stderr, "%s: read error on stdin\n", progname);
+ exit(2);
+ }
+ print_digest(digest);
+ printf("\n");
+ exit(0);
+ }
+ for ( ; argc > 0; --argc, ++argv) {
+ if (bin_mode)
+ fp = fopen(*argv, FOPRBIN);
+ else
+ fp = fopen(*argv, FOPRTXT);
+ if (fp == NULL) {
+ perror(*argv);
+ rc = 2;
+ continue;
+ }
+ if (mdfile(fp, digest)) {
+ fprintf(stderr, "%s: error reading %s\n", progname, *argv);
+ rc = 2;
+ } else {
+ print_digest(digest);
+ printf(" %c%s\n", bin_mode ? '*' : ' ', *argv);
+ }
+ fclose(fp);
+ }
+ exit(rc);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "usage: md5sum [-bv] [-c [file]] | [file...]\n");
+ fprintf(stderr, "Generates or checks MD5 Message Digests\n");
+ fprintf(stderr, " -c check message digests (default is generate)\n");
+ fprintf(stderr, " -v verbose, print file names when checking\n");
+ fprintf(stderr, " -b read files in binary mode\n");
+ fprintf(stderr, "The input for -c should be the list of message digests and file names\n");
+ fprintf(stderr, "that is printed on stdout by this program when it generates digests.\n");
+ exit(2);
+}
+
+int
+mdfile(FILE *fp, unsigned char *digest)
+{
+ unsigned char buf[1024];
+ MD5_CTX ctx;
+ int n;
+
+ MD5Init(&ctx);
+ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0)
+ MD5Update(&ctx, buf, n);
+ MD5Final(digest, &ctx);
+ if (ferror(fp))
+ return -1;
+ return 0;
+}
+
+void
+print_digest(unsigned char *p)
+{
+ int i;
+
+ for (i = 0; i < 16; ++i)
+ printf("%02x", *p++);
+}
+
+int
+hex_digit(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return -1;
+}
+
+int
+get_md5_line(FILE *fp, unsigned char *digest, char *file)
+{
+ char buf[1024];
+ int i, d1, d2, rc;
+ char *p = buf;
+
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ return -1;
+
+ for (i = 0; i < 16; ++i) {
+ if ((d1 = hex_digit(*p++)) == -1)
+ return 0;
+ if ((d2 = hex_digit(*p++)) == -1)
+ return 0;
+ *digest++ = d1*16 + d2;
+ }
+ if (*p++ != ' ')
+ return 0;
+ /*
+ * next char is an attribute char, space means text file
+ * if it's a '*' the file should be checked in binary mode.
+ */
+ if (*p == ' ')
+ rc = 1;
+ else if (*p == '*')
+ rc = 2;
+ else {
+ fprintf(stderr, "%s: unrecognized line: %s", progname, buf);
+ return 0;
+ }
+ ++p;
+ i = strlen(p);
+ if (i < 2 || i > 255)
+ return 0;
+ p[i-1] = '\0';
+ strcpy(file, p);
+ return rc;
+}
+
+int
+do_check(FILE *chkf)
+{
+ int rc, ex = 0, failed = 0, checked = 0;
+ unsigned char chk_digest[16], file_digest[16];
+ char filename[256];
+ FILE *fp;
+ int flen = 14;
+
+ while ((rc = get_md5_line(chkf, chk_digest, filename)) >= 0) {
+ if (rc == 0) /* not an md5 line */
+ continue;
+ if (verbose) {
+ if (strlen(filename) > flen)
+ flen = strlen(filename);
+ fprintf(stderr, "%-*s ", flen, filename);
+ }
+ if (bin_mode || rc == 2)
+ fp = fopen(filename, FOPRBIN);
+ else
+ fp = fopen(filename, FOPRTXT);
+ if (fp == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, filename);
+ ex = 2;
+ continue;
+ }
+ if (mdfile(fp, file_digest)) {
+ fprintf(stderr, "%s: error reading %s\n", progname, filename);
+ ex = 2;
+ fclose(fp);
+ continue;
+ }
+ fclose(fp);
+ if (memcmp(chk_digest, file_digest, 16) != 0) {
+ if (verbose)
+ fprintf(stderr, "FAILED\n");
+ else
+ fprintf(stderr, "%s: MD5 check failed for '%s'\n", progname, filename);
+ ++failed;
+ } else if (verbose)
+ fprintf(stderr, "OK\n");
+ ++checked;
+ }
+ if (verbose && failed)
+ fprintf(stderr, "%s: %d of %d file(s) failed MD5 check\n", progname, failed, checked);
+ if (!checked) {
+ fprintf(stderr, "%s: no files checked\n", progname);
+ return 3;
+ }
+ if (!ex && failed)
+ ex = 1;
+ return ex;
+}
diff --git a/misc-utils/namei.1 b/misc-utils/namei.1
new file mode 100644
index 000000000..348a37894
--- /dev/null
+++ b/misc-utils/namei.1
@@ -0,0 +1,60 @@
+.\"
+.\" Version 1.4 of namei
+.\"
+.TH NAMEI 1 "Local"
+.SH NAME
+namei - follow a pathname until a terminal point is found
+.SH SYNOPSIS
+.B namei
+.I [-mx]
+.I pathname
+.I "[ pathname ... ]"
+.SH DESCRIPTION
+.I Namei
+uses its arguments as pathnames to any type
+of Unix file (symlinks, files, directories, and so forth).
+.I Namei
+then follows each pathname until a terminal
+point is found (a file, directory, char device, etc).
+If it finds a symbolic link, we show the link, and start
+following it, indenting the output to show the context.
+.PP
+This program is useful for finding a "too many levels of
+symbolic links" problems.
+.PP
+For each line output,
+.I namei
+outputs a the following characters to identify the file types found:
+.LP
+.nf
+ f: = the pathname we are currently trying to resolve
+ d = directory
+ l = symbolic link (both the link and it's contents are output)
+ s = socket
+ b = block device
+ c = character device
+ - = regular file
+ ? = an error of some kind
+.fi
+.PP
+.I Namei
+prints an informative message when
+the maximum number of symbolic links this system can have has been exceeded.
+.SH OPTIONS
+.TP 8
+.B -x
+Show mount point directories with a 'D', rather than a 'd'.
+.TP 8
+.B -m
+Show the mode bits of each file type in the style of ls(1),
+for example 'rwxr-xr-x'.
+.SH AUTHOR
+Roger Southwick (rogers@amadeus.wr.tek.com)
+.SH BUGS
+To be discovered.
+.SH CAVEATS
+.I Namei
+will follow an infinite loop of symbolic links forever. To escape, use
+SIGINT (usually ^C).
+.SH "SEE ALSO"
+ls(1), stat(1)
diff --git a/misc-utils/namei.c b/misc-utils/namei.c
new file mode 100644
index 000000000..0424af0b8
--- /dev/null
+++ b/misc-utils/namei.c
@@ -0,0 +1,341 @@
+/*-------------------------------------------------------------
+
+The namei program
+
+By: Roger S. Southwick
+
+May 2, 1990
+
+
+Modifications by Steve Tell March 28, 1991
+
+usage: namei pathname [pathname ... ]
+
+This program reads it's arguments as pathnames to any type
+of Unix file (symlinks, files, directories, and so forth).
+The program then follows each pathname until a terminal
+point is found (a file, directory, char device, etc).
+If it finds a symbolic link, we show the link, and start
+following it, indenting the output to show the context.
+
+This program is useful for finding a "too many levels of
+symbolic links" problems.
+
+For each line output, the program puts a file type first:
+
+ f: = the pathname we are currently trying to resolve
+ d = directory
+ D = directory that is a mount point
+ l = symbolic link (both the link and it's contents are output)
+ s = socket
+ b = block device
+ c = character device
+ - = regular file
+ ? = an error of some kind
+
+The program prints an informative messages when we exceed
+the maximum number of symbolic links this system can have.
+
+The program exits with a 1 status ONLY if it finds it cannot
+chdir to /, or if it encounters an unknown file type.
+
+-------------------------------------------------------------*/
+
+#ifndef lint
+static char *RCSid = "namei.c,v 1.1.1.1 1995/02/22 19:09:16 faith Exp";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+extern char *sys_errlist[];
+extern int errno;
+#define ERR sys_errlist[errno],errno
+
+int symcount;
+int mflag = 0;
+int xflag = 0;
+
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 256
+#endif
+
+static char *pperm();
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ void namei(), usage();
+ char *getwd();
+ int getopt();
+ extern int optind;
+ register int c;
+ char curdir[MAXPATHLEN];
+
+ if(argc < 2)
+ usage();
+
+ while((c = getopt(argc, argv, "mx")) != EOF){
+ switch(c){
+ case 'm':
+ mflag = !mflag;
+ break;
+
+ case 'x':
+ xflag = !xflag;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if(getwd(curdir) == NULL){
+ (void)fprintf(stderr, "namei: unable to get current directory - %s\n", curdir);
+ exit(1);
+ }
+
+
+ for(; optind < argc; optind++){
+ (void)printf("f: %s\n", argv[optind]);
+ symcount = 1;
+ namei(argv[optind], 0);
+
+ if(chdir(curdir) == -1){
+ (void)fprintf(stderr, "namei: unable to chdir to %s - %s (%d)\n", curdir, ERR);
+ exit(1);
+ }
+ }
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,"usage: namei [-mx] pathname [pathname ...]\n");
+ exit(1);
+}
+
+#ifndef NODEV
+#define NODEV (dev_t)(-1)
+#endif
+
+void
+namei(file, lev)
+
+register char *file;
+register int lev;
+{
+ register char *cp;
+ char buf[BUFSIZ], sym[BUFSIZ];
+ struct stat stb;
+ register int i;
+ dev_t lastdev = NODEV;
+
+ /*
+ * See if the file has a leading /, and if so cd to root
+ */
+
+ if(*file == '/'){
+ while(*file == '/')
+ file++;
+
+ if(chdir("/") == -1){
+ (void)fprintf(stderr,"namei: could not chdir to root!\n");
+ exit(1);
+ }
+ for(i = 0; i < lev; i++)
+ (void)printf(" ");
+
+ if(stat("/", &stb) == -1){
+ (void)fprintf(stderr, "namei: could not stat root!\n");
+ exit(1);
+ }
+ lastdev = stb.st_dev;
+
+ if(mflag)
+ (void)printf(" d%s /\n", pperm(stb.st_mode));
+ else
+ (void)printf(" d /\n");
+ }
+
+ for(;;){
+
+ /*
+ * Copy up to the next / (or nil) into buf
+ */
+
+ for(cp = buf; *file != '\0' && *file != '/'; cp++, file++)
+ *cp = *file;
+
+ while(*file == '/') /* eat extra /'s */
+ file++;
+
+ *cp = '\0';
+
+ if(buf[0] == '\0'){
+
+ /*
+ * Buf is empty, so therefore we are done
+ * with this level of file
+ */
+
+ return;
+ }
+
+ for(i = 0; i < lev; i++)
+ (void)printf(" ");
+
+ /*
+ * See what type of critter this file is
+ */
+
+ if(lstat(buf, &stb) == -1){
+ (void)printf(" ? %s - %s (%d)\n", buf, ERR);
+ return;
+ }
+
+ switch(stb.st_mode & S_IFMT){
+ case S_IFDIR:
+
+ /*
+ * File is a directory, chdir to it
+ */
+
+ if(chdir(buf) == -1){
+ (void)printf(" ? could not chdir into %s - %s (%d)\n", buf, ERR );
+ return;
+ }
+ if(xflag && lastdev != stb.st_dev && lastdev != NODEV){
+ /* Across mnt point */
+ if(mflag)
+ (void)printf(" D%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" D %s\n", buf);
+ }
+ else {
+ if(mflag)
+ (void)printf(" d%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" d %s\n", buf);
+ }
+ lastdev = stb.st_dev;
+
+ (void)fflush(stdout);
+ break;
+
+ case S_IFLNK:
+ /*
+ * Sigh, another symlink. Read it's contents and
+ * call namei()
+ */
+
+ bzero(sym, BUFSIZ);
+ if(readlink(buf, sym, BUFSIZ) == -1){
+ (void)printf(" ? problems reading symlink %s - %s (%d)\n", buf, ERR);
+ return;
+ }
+
+ if(mflag)
+ (void)printf(" l%s %s -> %s", pperm(stb.st_mode), buf, sym);
+ else
+ (void)printf(" l %s -> %s", buf, sym);
+
+ if(symcount > 0 && symcount++ > MAXSYMLINKS){
+ (void)printf(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***");
+ symcount = -1;
+ }
+ (void)printf("\n");
+ namei(sym, lev + 1);
+ break;
+
+ case S_IFCHR:
+ if(mflag)
+ (void)printf(" c%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" c %s\n", buf);
+ break;
+
+ case S_IFBLK:
+ if(mflag)
+ (void)printf(" b%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" b %s\n", buf);
+ break;
+
+ case S_IFSOCK:
+ if(mflag)
+ (void)printf(" s%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" s %s\n", buf);
+ break;
+
+ case S_IFREG:
+ if(mflag)
+ (void)printf(" -%s %s\n", pperm(stb.st_mode), buf);
+ else
+ (void)printf(" - %s\n", buf);
+ break;
+
+ default:
+ (void)fprintf(stderr,"namei: unknown file type 0%06o on file %s\n", stb.st_mode, buf );
+ exit(1);
+
+ }
+ }
+}
+
+/* Take a
+ * Mode word, as from a struct stat, and return
+ * a pointer to a static string containing a printable version like ls.
+ * For example 0755 produces "rwxr-xr-x"
+ */
+static char *
+pperm(mode)
+unsigned short mode;
+{
+ unsigned short m;
+ static char buf[16];
+ char *bp;
+ char *lschars = "xwrxwrxwr"; /* the complete string backwards */
+ char *cp;
+ int i;
+
+ for(i = 0, cp = lschars, m = mode, bp = &buf[8];
+ i < 9;
+ i++, cp++, m >>= 1, bp--) {
+
+ if(m & 1)
+ *bp = *cp;
+ else
+ *bp = '-';
+ }
+ buf[9] = '\0';
+
+ if(mode & S_ISUID) {
+ if(buf[2] == 'x')
+ buf[2] = 's';
+ else
+ buf[2] = 'S';
+ }
+ if(mode & S_ISGID) {
+ if(buf[5] == 'x')
+ buf[5] = 's';
+ else
+ buf[5] = 'S';
+ }
+ if(mode & S_ISVTX) {
+ if(buf[8] == 'x')
+ buf[8] = 't';
+ else
+ buf[8] = 'T';
+ }
+
+ return &buf[0];
+}
+
+
diff --git a/misc-utils/procs.c b/misc-utils/procs.c
new file mode 100644
index 000000000..1d232415c
--- /dev/null
+++ b/misc-utils/procs.c
@@ -0,0 +1,113 @@
+/*
+ * procs.c -- functions to parse the linux /proc filesystem.
+ * (c) 1994 salvatore valente <svalente@mit.edu>
+ *
+ * this program is free software. you can redistribute it and
+ * modify it under the terms of the gnu general public license.
+ * there is no warranty.
+ *
+ * faith
+ * 1.2
+ * 1995/02/23 01:20:40
+ *
+ */
+
+#define _POSIX_SOURCE 1
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+
+extern char *mybasename (char *);
+static char *parse_parens (char *buf);
+
+int *get_pids (char *process_name, int get_all)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int status;
+ char *dname, fname[100], *cp, buf[256];
+ struct stat st;
+ uid_t uid;
+ FILE *fp;
+ int pid, *pids, num_pids, pids_size;
+
+ dir = opendir ("/proc");
+ if (! dir) {
+ perror ("opendir /proc");
+ return NULL;
+ }
+ uid = getuid ();
+ pids = NULL;
+ num_pids = pids_size = 0;
+
+ while ((ent = readdir (dir)) != NULL) {
+ dname = ent->d_name;
+ if (! isdigit (*dname)) continue;
+ pid = atoi (dname);
+ sprintf (fname, "/proc/%d/cmdline", pid);
+ /* get the process owner */
+ status = stat (fname, &st);
+ if (status != 0) continue;
+ if (! get_all && uid != st.st_uid) continue;
+ /* get the command line */
+ fp = fopen (fname, "r");
+ if (! fp) continue;
+ cp = fgets (buf, sizeof (buf), fp);
+ fclose (fp);
+ /* an empty command line means the process is swapped out */
+ if (! cp || ! *cp) {
+ /* get the process name from the statfile */
+ sprintf (fname, "/proc/%d/stat", pid);
+ fp = fopen (fname, "r");
+ if (! fp) continue;
+ cp = fgets (buf, sizeof (buf), fp);
+ if (cp == NULL) continue;
+ fclose (fp);
+ cp = parse_parens (buf);
+ if (cp == NULL) continue;
+ }
+ /* ok, we got the process name. */
+ if (strcmp (process_name, mybasename (cp))) continue;
+ while (pids_size < num_pids + 2) {
+ pids_size += 5;
+ pids = (int *) realloc (pids, sizeof (int) * pids_size);
+ }
+ pids[num_pids++] = pid;
+ pids[num_pids] = -1;
+ }
+ closedir (dir);
+ return (pids);
+}
+
+/*
+ * parse_parens () -- return an index just past the first open paren in
+ * buf, and terminate the string at the matching close paren.
+ */
+static char *parse_parens (char *buf)
+{
+ char *cp, *ip;
+ int depth;
+
+ cp = strchr (buf, '(');
+ if (cp == NULL) return NULL;
+ cp++;
+ depth = 1;
+ for (ip = cp; *ip; ip++) {
+ if (*ip == '(')
+ depth++;
+ if (*ip == ')') {
+ depth--;
+ if (depth == 0) {
+ *ip = 0;
+ break;
+ }
+ }
+ }
+ return cp;
+}
diff --git a/misc-utils/reset.1 b/misc-utils/reset.1
new file mode 100644
index 000000000..06ce4b2b7
--- /dev/null
+++ b/misc-utils/reset.1
@@ -0,0 +1,29 @@
+.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
+.\" May be distributed under the GNU General Public License
+.TH RESET 1 "10 October 1993" "Linux 0.99" "Linux Programmer's Manual"
+.SH NAME
+reset \- reset the terminal
+.SH SYNOPSIS
+.BR clear
+.SH DESCRIPTION
+.B reset
+calls
+.BR tput (1)
+with the
+.IR clear , rmacs , rmm , rmul , rs1 , rs2 ", and " rs3
+arguments. This causes
+.B tput
+to send appropriate reset strings to the terminal based on information in
+.IR /etc/termcap .
+This sequence seems to be sufficient to reset the Linux VC's when they
+start printing "funny-looking" characters. For good measure,
+.BR stty (1)
+is called with the
+.I sane
+argument in an attempt to get cooked mode back.
+.SH "SEE ALSO"
+.BR reset (1),
+.BR stty (1),
+.BR tput (1)
+.SH AUTHOR
+Rik Faith (faith@cs.unc.edu)
diff --git a/misc-utils/reset.sh b/misc-utils/reset.sh
new file mode 100644
index 000000000..92d253907
--- /dev/null
+++ b/misc-utils/reset.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+stty sane
+tput clear
+tput rmacs
+tput rmm
+tput rmso
+tput rmul
+tput rs1
+tput rs2
+tput rs3
+bot=$[ ${LINES:-`tput lines`} - 1 ]
+if test "$bot" -le "0"; then bot=24; fi
+tput csr 0 $bot
diff --git a/misc-utils/script.1 b/misc-utils/script.1
new file mode 100644
index 000000000..ddc35223d
--- /dev/null
+++ b/misc-utils/script.1
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1980, 1990 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.
+.\"
+.\" @(#)script.1 6.5 (Berkeley) 7/27/91
+.\"
+.Dd July 27, 1991
+.Dt SCRIPT 1
+.Os BSD 4
+.Sh NAME
+.Nm script
+.Nd make typescript of terminal session
+.Sh SYNOPSIS
+.Nm script
+.Op Fl a
+.Op Ar file
+.Sh DESCRIPTION
+.Nm Script
+makes a typescript of everything printed on your terminal.
+It is useful for students who need a hardcopy record of an interactive
+session as proof of an assignment, as the typescript file
+can be printed out later with
+.Xr lpr 1 .
+.Pp
+If the argument
+.Ar file
+is given,
+.Nm
+saves all dialogue in
+.Ar file .
+If no file name is given, the typescript is saved in the file
+.Pa typescript .
+.Pp
+Option:
+.Bl -tag -width Ds
+.It Fl a
+Append the output to
+.Ar file
+or
+.Pa typescript ,
+retaining the prior contents.
+.El
+.Pp
+The script ends when the forked shell exits (a
+.Em control-D
+to exit
+the Bourne shell
+.Pf ( Xr sh 1 ) ,
+and
+.Em exit ,
+.Em logout
+or
+.Em control-d
+(if
+.Em ignoreeof
+is not set) for the
+C-shell,
+.Xr csh 1 ) .
+.Pp
+Certain interactive commands, such as
+.Xr vi 1 ,
+create garbage in the typescript file.
+.Nm Script
+works best with commands that do not manipulate the
+screen, the results are meant to emulate a hardcopy
+terminal.
+.Sh ENVIRONMENT
+The following environment variable is utilized by
+.Nm script :
+.Bl -tag -width SHELL
+.It Ev SHELL
+If the variable
+.Ev SHELL
+exists, the shell forked by
+.Nm script
+will be that shell. If
+.Ev SHELL
+is not set, the Bourne shell
+is assumed. (Most shells set this variable automatically).
+.El
+.Sh SEE ALSO
+.Xr csh 1
+(for the
+.Em history
+mechanism).
+.Sh HISTORY
+The
+.Nm script
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+.Nm Script
+places
+.Sy everything
+in the log file, including linefeeds and backspaces.
+This is not what the naive user expects.
diff --git a/misc-utils/script.c b/misc-utils/script.c
new file mode 100644
index 000000000..d1e8b1e94
--- /dev/null
+++ b/misc-utils/script.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1980 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.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)script.c 5.13 (Berkeley) 3/5/91";
+#endif /* not lint */
+
+/*
+ * script
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#include <sys/signal.h>
+#include <stdio.h>
+#include <paths.h>
+
+#ifdef linux
+#include <unistd.h>
+#include <string.h>
+#endif
+
+char *shell;
+FILE *fscript;
+int master;
+int slave;
+int child;
+int subchild;
+char *fname;
+
+struct termios tt;
+struct winsize win;
+int lb;
+int l;
+char line[] = "/dev/ptyXX";
+int aflg;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ void finish();
+ char *getenv();
+
+ while ((ch = getopt(argc, argv, "a")) != EOF)
+ switch((char)ch) {
+ case 'a':
+ aflg++;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: script [-a] [file]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ fname = argv[0];
+ else
+ fname = "typescript";
+ if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
+ perror(fname);
+ fail();
+ }
+
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = _PATH_BSHELL;
+
+ getmaster();
+ printf("Script started, file is %s\n", fname);
+ fixtty();
+
+ (void) signal(SIGCHLD, finish);
+ child = fork();
+ if (child < 0) {
+ perror("fork");
+ fail();
+ }
+ if (child == 0) {
+ subchild = child = fork();
+ if (child < 0) {
+ perror("fork");
+ fail();
+ }
+ if (child)
+ dooutput();
+ else
+ doshell();
+ }
+ doinput();
+}
+
+doinput()
+{
+ register int cc;
+ char ibuf[BUFSIZ];
+
+ (void) fclose(fscript);
+ while ((cc = read(0, ibuf, BUFSIZ)) > 0)
+ (void) write(master, ibuf, cc);
+ done();
+}
+
+#include <sys/wait.h>
+
+void
+finish()
+{
+ union wait status;
+ register int pid;
+ register int die = 0;
+
+ while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
+ if (pid == child)
+ die = 1;
+
+ if (die)
+ done();
+}
+
+dooutput()
+{
+ register int cc;
+ time_t tvec, time();
+ char obuf[BUFSIZ], *ctime();
+
+ (void) close(0);
+ tvec = time((time_t *)NULL);
+ fprintf(fscript, "Script started on %s", ctime(&tvec));
+ for (;;) {
+ cc = read(master, obuf, sizeof (obuf));
+ if (cc <= 0)
+ break;
+ (void) write(1, obuf, cc);
+ (void) fwrite(obuf, 1, cc, fscript);
+ }
+ done();
+}
+
+doshell()
+{
+ int t;
+
+ /***
+ t = open(_PATH_TTY, O_RDWR);
+ if (t >= 0) {
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
+ (void) close(t);
+ }
+ ***/
+ getslave();
+ (void) close(master);
+ (void) fclose(fscript);
+ (void) dup2(slave, 0);
+ (void) dup2(slave, 1);
+ (void) dup2(slave, 2);
+ (void) close(slave);
+#ifdef linux
+ execl(shell, strrchr(shell, '/') + 1, "-i", 0);
+#else
+ execl(shell, "sh", "-i", 0);
+#endif
+ perror(shell);
+ fail();
+}
+
+fixtty()
+{
+ struct termios rtt;
+
+ rtt = tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ (void) tcsetattr(0, TCSAFLUSH, &rtt);
+}
+
+fail()
+{
+
+ (void) kill(0, SIGTERM);
+ done();
+}
+
+done()
+{
+ time_t tvec, time();
+ char *ctime();
+
+ if (subchild) {
+ tvec = time((time_t *)NULL);
+ fprintf(fscript,"\nScript done on %s", ctime(&tvec));
+ (void) fclose(fscript);
+ (void) close(master);
+ } else {
+ (void) tcsetattr(0, TCSAFLUSH, &tt);
+ printf("Script done, file is %s\n", fname);
+ }
+ exit(0);
+}
+
+getmaster()
+{
+ char *pty, *bank, *cp;
+ struct stat stb;
+
+ pty = &line[strlen("/dev/ptyp")];
+ for (bank = "pqrs"; *bank; bank++) {
+ line[strlen("/dev/pty")] = *bank;
+ *pty = '0';
+ if (stat(line, &stb) < 0)
+ break;
+ for (cp = "0123456789abcdef"; *cp; cp++) {
+ *pty = *cp;
+ master = open(line, O_RDWR);
+ if (master >= 0) {
+ char *tp = &line[strlen("/dev/")];
+ int ok;
+
+ /* verify slave side is usable */
+ *tp = 't';
+ ok = access(line, R_OK|W_OK) == 0;
+ *tp = 'p';
+ if (ok) {
+ (void) tcgetattr(0, &tt);
+ (void) ioctl(0, TIOCGWINSZ,
+ (char *)&win);
+ return;
+ }
+ (void) close(master);
+ }
+ }
+ }
+ fprintf(stderr, "Out of pty's\n");
+ fail();
+}
+
+getslave()
+{
+
+ line[strlen("/dev/")] = 't';
+ slave = open(line, O_RDWR);
+ if (slave < 0) {
+ perror(line);
+ fail();
+ }
+ (void) tcsetattr(slave, TCSAFLUSH, &tt);
+ (void) ioctl(slave, TIOCSWINSZ, (char *)&win);
+ (void) setsid();
+ (void) ioctl(slave, TIOCSCTTY, 0);
+}
diff --git a/misc-utils/setterm.1 b/misc-utils/setterm.1
new file mode 100644
index 000000000..794fea7db
--- /dev/null
+++ b/misc-utils/setterm.1
@@ -0,0 +1,88 @@
+.\" Copyright 1990 Gordon Irlam (gordoni@cs.ua.oz.au)
+.\" Copyright 1992 Rickard E. Faith (faith@cs.unc.edu)
+.\" Most of this was copied from the source code. Do not restrict distribution.
+.\" May be distributed under the GNU General Public License
+.TH SETTERM 1 "25 December 1992" "Linux 0.98" "Linux Programmer's Manual"
+.SH NAME
+setterm \- set terminal attributes
+.SH SYNOPSIS
+.nf
+.BR "setterm [ \-term " terminal_name " ]"
+.B "setterm [ \-reset ]"
+.B "setterm [ \-initialize ]"
+.B "setterm [ \-cursor [on|off] ]"
+.B "setterm [ \-keyboard pc|olivetti|dutch|extended ]"
+.B "setterm [ \-repeat [on|off] ]"
+.B "setterm [ \-appcursorkeys [on|off] ]"
+.B "setterm [ \-linewrap [on|off] ]"
+.B "setterm [ \-snow [on|off] ]"
+.B "setterm [ \-softscroll [on|off] ]"
+.B "setterm [ \-defaults ]"
+.B "setterm [ \-foreground black|red|green|yellow|blue|magenta|cyan|white|default ]"
+.B "setterm [ \-background black|red|green|yellow|blue|magenta|cyan|white|default ]"
+.B "setterm [ \-ulcolor black|grey|red|green|yellow|blue|magenta|cyan|white ]"
+.B "setterm [ \-ulcolor bright red|green|yellow|blue|magenta|cyan|white ]"
+.B "setterm [ \-hbcolor black|grey|red|green|yellow|blue|magenta|cyan|white ]"
+.B "setterm [ \-hbcolor bright red|green|yellow|blue|magenta|cyan|white ]"
+.B "setterm [ \-inversescreen [on|off] ]"
+.B "setterm [ \-bold [on|off] ]"
+.B "setterm [ \-half-bright [on|off] ]"
+.B "setterm [ \-blink [on|off] ]"
+.B "setterm [ \-reverse [on|off] ]"
+.B "setterm [ \-underline [on|off] ]"
+.B "setterm [ \-store ]"
+.B "setterm [ \-clear [ all|rest ] ]"
+.BR "setterm [ \-tabs [tab1 tab2 tab3 ... ] ]" " where (tabn = 1-160)"
+.BR "setterm [ \-clrtabs [ tab1 tab2 tab3 ... ]" " where (tabn = 1-160)"
+.BR "setterm [ \-regtabs [" " 1-160 " "] ]"
+.BR "setterm [ \-blank [" " 0-60 " "] ]"
+.BR "setterm [ \-dump [" " 1-NR_CONS " "] ]"
+.BR "setterm [ \-append [" " 1-NR_CONS " "] ]"
+.BR "setterm [ \-file" " dumpfilename " ]
+.BR "setterm [ \-standout [" " attr " "] ]"
+.fi
+.SH DESCRIPTION
+.B setterm
+writes to standard output a character string that will invoke the specified
+terminal capabilities. Where possibile
+.I /etc/termcap
+is consulted to find the string to use. Some options however do not
+correspond to a
+.BR termcap (5)
+capability. In this case, if the terminal type is "minix-vc", or
+"minix-vcam" the string that invokes the specified capabilities on the PC
+Minix virtual console driver is output. Options that are not implemented
+by the terminal are ignored.
+.SH OPTIONS
+Most options are self explanatory. The less obvious options are as
+follows:
+.TP
+.B \-term
+can be used to override the TERM environment variable.
+.TP
+.B \-reset
+displays the terminal reset string, which typically resets the terminal to
+its power on state.
+.TP
+.B \-initialize
+displays the terminal initialization string, which typically sets the
+terminal's rendering options, and other attributes to the default values.
+.TP
+.B \-default
+sets the terminal's rendering options to the default values.
+.TP
+.B \-store
+stores the terminal's current rendering options as the default values.
+.SH "SEE ALSO"
+.BR tput (1),
+.BR stty (1),
+.BR termcap (5),
+.BR tty (4)
+.SH BUGS
+Differences between the Minux and Linux versions are not documented.
+.SH AUTHORS
+Gordon Irlam (gordoni@cs.ua.oz.au)
+.br
+Adaption to Linux by Peter MacDonald
+.br
+Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI)
diff --git a/misc-utils/setterm.c b/misc-utils/setterm.c
new file mode 100644
index 000000000..e81fccc3b
--- /dev/null
+++ b/misc-utils/setterm.c
@@ -0,0 +1,1137 @@
+/* setterm.c, set terminal attributes.
+ *
+ * Copyright (C) 1990 Gordon Irlam (gordoni@cs.ua.oz.au). Conditions of use,
+ * modification, and redistribution are contained in the file COPYRIGHT that
+ * forms part of this distribution.
+ *
+ * Adaption to Linux by Peter MacDonald.
+ *
+ * Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI)
+ *
+ *
+ * Syntax:
+ *
+ * setterm
+ * [ -term terminal_name ]
+ * [ -reset ]
+ * [ -initialize ]
+ * [ -cursor [on|off] ]
+ * [ -keyboard pc|olivetti|dutch|extended ]
+ * [ -repeat [on|off] ]
+ * [ -appcursorkeys [on|off] ]
+ * [ -linewrap [on|off] ]
+ * [ -snow [on|off] ]
+ * [ -softscroll [on|off] ]
+ * [ -defaults ]
+ * [ -foreground black|red|green|yellow|blue|magenta|cyan|white|default ]
+ * [ -background black|red|green|yellow|blue|magenta|cyan|white|default ]
+ * [ -ulcolor black|grey|red|green|yellow|blue|magenta|cyan|white ]
+ * [ -ulcolor bright red|green|yellow|blue|magenta|cyan|white ]
+ * [ -hbcolor black|grey|red|green|yellow|blue|magenta|cyan|white ]
+ * [ -hbcolor bright red|green|yellow|blue|magenta|cyan|white ]
+ * [ -inversescreen [on|off] ]
+ * [ -bold [on|off] ]
+ * [ -half-bright [on|off] ]
+ * [ -blink [on|off] ]
+ * [ -reverse [on|off] ]
+ * [ -underline [on|off] ]
+ * [ -store ]
+ * [ -clear [ all|rest ] ]
+ * [ -tabs [tab1 tab2 tab3 ... ] ] (tabn = 1-160)
+ * [ -clrtabs [ tab1 tab2 tab3 ... ] (tabn = 1-160)
+ * [ -regtabs [1-160] ]
+ * [ -blank [0-60] ]
+ * [ -dump [1-NR_CONS ] ]
+ * [ -append [1-NR_CONS ] ]
+ * [ -file dumpfilename ]
+ * [ -standout [attr] ]
+ * [ -msg [on|off] ]
+ * [ -msglevel [0-8] ]
+ * [ -powersave [on|off] ]
+ *
+ *
+ * Semantics:
+ *
+ * Setterm writes to standard output a character string that will invoke the
+ * specified terminal capabilities. Where possibile termcap is consulted to
+ * find the string to use. Some options however do not correspond to a
+ * termcap capability. In this case if the terminal type is "con*", or
+ * "linux*" the string that invokes the specified capabilities on the PC
+ * Linux virtual console driver is output. Options that are not implemented
+ * by the terminal are ignored.
+ *
+ * The following options are non-obvious.
+ *
+ * -term can be used to override the TERM environment variable.
+ *
+ * -reset displays the terminal reset string, which typically resets the
+ * terminal to its power on state.
+ *
+ * -initialize displays the terminal initialization string, which typically
+ * sets the terminal's rendering options, and other attributes to the
+ * default values.
+ *
+ * -default sets the terminal's rendering options to the default values.
+ *
+ * -store stores the terminal's current rendering options as the default
+ * values.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <termcap.h>
+#include <linux/config.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <termios.h>
+#include <string.h>
+
+/* for syslog system call */
+#include <linux/unistd.h>
+#include <errno.h>
+_syscall3(int, syslog, int, type, char*, buf, int, len);
+
+/* Constants. */
+
+/* Termcap constants. */
+#define TC_BUF_SIZE 1024 /* Size of termcap(3) buffer. */
+#define TC_ENT_SIZE 50 /* Size of termcap(3) entry buffer. */
+
+/* General constants. */
+#define TRUE 1
+#define FALSE 0
+
+/* Keyboard types. */
+#define PC 0
+#define OLIVETTI 1
+#define DUTCH 2
+#define EXTENDED 3
+
+/* Colors. */
+#define BLACK 0
+#define RED 1
+#define GREEN 2
+#define YELLOW 3
+#define BLUE 4
+#define MAGENTA 5
+#define CYAN 6
+#define WHITE 7
+#define GREY 8
+#define DEFAULT 9
+
+/* Control sequences. */
+#define ESC "\033"
+#define DCS "\033P"
+#define ST "\033\\"
+
+/* Static variables. */
+
+char tc_buf[TC_BUF_SIZE]; /* Termcap buffer. */
+
+/* Option flags. Set if the option is to be invoked. */
+int opt_term, opt_reset, opt_initialize, opt_cursor, opt_keyboard;
+int opt_linewrap, opt_snow, opt_softscroll, opt_default, opt_foreground;
+int opt_background, opt_bold, opt_blink, opt_reverse, opt_underline;
+int opt_store, opt_clear, opt_blank, opt_snap, opt_snapfile, opt_standout;
+int opt_append, opt_ulcolor, opt_hbcolor, opt_halfbright, opt_repeat;
+int opt_tabs, opt_clrtabs, opt_regtabs, opt_appcursorkeys, opt_inversescreen;
+int opt_msg, opt_msglevel, opt_powersave;
+
+/* Option controls. The variable names have been contracted to ensure
+ * uniqueness.
+ */
+char *opt_te_terminal_name; /* Terminal name. */
+int opt_cu_on, opt_li_on, opt_sn_on, opt_so_on, opt_bo_on, opt_hb_on, opt_bl_on;
+int opt_re_on, opt_un_on, opt_rep_on, opt_appck_on, opt_invsc_on;
+int opt_msg_on, opt_ps_on; /* Boolean switches. */
+int opt_ke_type; /* Keyboard type. */
+int opt_fo_color, opt_ba_color; /* Colors. */
+int opt_ul_color, opt_hb_color;
+int opt_cl_all; /* Clear all or rest. */
+int opt_bl_min; /* Blank screen. */
+int opt_sn_num = 0; /* Snap screen. */
+int opt_st_attr;
+int opt_rt_len; /* regular tab length */
+int opt_tb_array[161]; /* Array for tab list */
+int opt_msglevel_num;
+
+char opt_sn_name[200] = "screen.dump";
+
+/* Command line parsing routines.
+ *
+ * Note that it is an error for a given option to be invoked more than once.
+ */
+
+void parse_term(argc, argv, option, opt_term, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Term flag to set. */
+char **opt_term; /* Terminal name to set. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -term specification. */
+
+ if (argc != 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ *opt_term = argv[0];
+ }
+}
+
+void parse_none(argc, argv, option, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Option flag to set. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a parameterless specification. */
+
+ if (argc != 0 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+}
+
+void parse_switch(argc, argv, option, opt_on, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Option flag to set. */
+int *opt_on; /* Boolean option switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a boolean (on/off) specification. */
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ if (strcmp(argv[0], "on") == 0)
+ *opt_on = TRUE;
+ else if (strcmp(argv[0], "off") == 0)
+ *opt_on = FALSE;
+ else
+ *bad_arg = TRUE;
+ } else {
+ *opt_on = TRUE;
+ }
+}
+
+#if 0
+void parse_keyboard(argc, argv, option, opt_keyboard, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Keyboard flag to set. */
+int *opt_keyboard; /* Keyboard type to set. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -keyboard specification. */
+
+ if (argc != 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ if (strcmp(argv[0], "pc") == 0)
+ *opt_keyboard = PC;
+ else if (strcmp(argv[0], "olivetti") == 0)
+ *opt_keyboard = OLIVETTI;
+ else if (strcmp(argv[0], "dutch") == 0)
+ *opt_keyboard = DUTCH;
+ else if (strcmp(argv[0], "extended") == 0)
+ *opt_keyboard = EXTENDED;
+ else
+ *bad_arg = TRUE;
+ }
+}
+#endif
+
+void par_color(argc, argv, option, opt_color, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Color flag to set. */
+int *opt_color; /* Color to set. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -foreground or -background specification. */
+
+ if (argc != 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ if (strcmp(argv[0], "black") == 0)
+ *opt_color = BLACK;
+ else if (strcmp(argv[0], "red") == 0)
+ *opt_color = RED;
+ else if (strcmp(argv[0], "green") == 0)
+ *opt_color = GREEN;
+ else if (strcmp(argv[0], "yellow") == 0)
+ *opt_color = YELLOW;
+ else if (strcmp(argv[0], "blue") == 0)
+ *opt_color = BLUE;
+ else if (strcmp(argv[0], "magenta") == 0)
+ *opt_color = MAGENTA;
+ else if (strcmp(argv[0], "cyan") == 0)
+ *opt_color = CYAN;
+ else if (strcmp(argv[0], "white") == 0)
+ *opt_color = WHITE;
+ else if (strcmp(argv[0], "default") == 0)
+ *opt_color = DEFAULT;
+ else if (isdigit(argv[0][0]))
+ *opt_color = atoi(argv[0]);
+ else
+ *bad_arg = TRUE;
+ if(*opt_color < 0 || *opt_color > 15)
+ *bad_arg = TRUE;
+ }
+}
+
+void par_color2(argc, argv, option, opt_color, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Color flag to set. */
+int *opt_color; /* Color to set. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -ulcolor or -hbcolor specification. */
+
+ if (!argc || argc > 2 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ *opt_color = 0;
+ if (argc == 2) {
+ if (strcmp(argv[0], "bright") == 0)
+ *opt_color = 8;
+ else {
+ *bad_arg = TRUE;
+ return;
+ }
+ }
+ if (argc) {
+ if (strcmp(argv[argc-1], "black") == 0) {
+ if(*opt_color)
+ *bad_arg = TRUE;
+ else
+ *opt_color = BLACK;
+ } else if (strcmp(argv[argc-1], "grey") == 0) {
+ if(*opt_color)
+ *bad_arg = TRUE;
+ else
+ *opt_color = GREY;
+ } else if (strcmp(argv[argc-1], "red") == 0)
+ *opt_color |= RED;
+ else if (strcmp(argv[argc-1], "green") == 0)
+ *opt_color |= GREEN;
+ else if (strcmp(argv[argc-1], "yellow") == 0)
+ *opt_color |= YELLOW;
+ else if (strcmp(argv[argc-1], "blue") == 0)
+ *opt_color |= BLUE;
+ else if (strcmp(argv[argc-1], "magenta") == 0)
+ *opt_color |= MAGENTA;
+ else if (strcmp(argv[argc-1], "cyan") == 0)
+ *opt_color |= CYAN;
+ else if (strcmp(argv[argc-1], "white") == 0)
+ *opt_color |= WHITE;
+ else if (isdigit(argv[argc-1][0]))
+ *opt_color = atoi(argv[argc-1]);
+ else
+ *bad_arg = TRUE;
+ if(*opt_color < 0 || *opt_color > 15)
+ *bad_arg = TRUE;
+ }
+}
+
+void parse_clear(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -clear specification. */
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ if (strcmp(argv[0], "all") == 0)
+ *opt_all = TRUE;
+ else if (strcmp(argv[0], "rest") == 0)
+ *opt_all = FALSE;
+ else
+ *bad_arg = TRUE;
+ } else {
+ *opt_all = TRUE;
+ }
+}
+
+void parse_blank(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -clear specification. */
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ *opt_all = atoi(argv[0]);
+ if ((*opt_all > 60) || (*opt_all < 0))
+ *bad_arg = TRUE;
+ } else {
+ *opt_all = 0;
+ }
+}
+
+#if 0
+void parse_standout(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -clear specification. */
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ *opt_all = atoi(argv[0]);
+ } else {
+ *opt_all = -1;
+ }
+}
+#endif
+
+void parse_msglevel(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ *opt_all = atoi(argv[0]);
+ if (*opt_all < 0 || *opt_all > 8)
+ *bad_arg = TRUE;
+ } else {
+ *opt_all = -1;
+ }
+}
+
+void parse_snap(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -clear specification. */
+
+ if (argc > 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ *opt_all = atoi(argv[0]);
+ if ((*opt_all <= 0))
+ *bad_arg = TRUE;
+ } else {
+ *opt_all = 0;
+ }
+}
+
+void parse_snapfile(argc, argv, option, opt_all, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_all; /* Clear all switch to set or reset. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a -clear specification. */
+
+ if (argc != 1 || *option) *bad_arg = TRUE;
+ *option = TRUE;
+ if (argc == 1) {
+ strcpy((char *)opt_all, argv[0]);
+ }
+}
+
+void parse_tabs(argc, argv, option, tab_array, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *tab_array; /* Array of tabs */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+ if (*option || argc > 160) *bad_arg = TRUE;
+ *option = TRUE;
+ tab_array[argc] = -1;
+ while(argc--) {
+ tab_array[argc] = atoi(argv[argc]);
+ if(tab_array[argc] < 1 || tab_array[argc] > 160) {
+ *bad_arg = TRUE;
+ return;
+ }
+ }
+}
+
+void parse_clrtabs(argc, argv, option, tab_array, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *tab_array; /* Array of tabs */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+ if (*option || argc > 160) *bad_arg = TRUE;
+ *option = TRUE;
+ if(argc == 0) {
+ tab_array[0] = -1;
+ return;
+ }
+ tab_array[argc] = -1;
+ while(argc--) {
+ tab_array[argc] = atoi(argv[argc]);
+ if(tab_array[argc] < 1 || tab_array[argc] > 160) {
+ *bad_arg = TRUE;
+ return;
+ }
+ }
+}
+
+void parse_regtabs(argc, argv, option, opt_len, bad_arg)
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *option; /* Clear flag to set. */
+int *opt_len; /* Regular tab length. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+ if (*option || argc > 1) *bad_arg = TRUE;
+ *option = TRUE;
+ if(argc == 0) {
+ *opt_len = 8;
+ return;
+ }
+ *opt_len = atoi(argv[0]);
+ if(*opt_len < 1 || *opt_len > 160) {
+ *bad_arg = TRUE;
+ return;
+ }
+}
+
+void show_tabs()
+{
+ int i, co = tgetnum("co");
+
+ if(co > 0) {
+ printf("\r ");
+ for(i = 10; i < co-2; i+=10)
+ printf("%-10d", i);
+ putchar('\n');
+ for(i = 1; i <= co; i++)
+ putchar(i%10+'0');
+ putchar('\n');
+ for(i = 1; i < co; i++)
+ printf("\tT\b");
+ putchar('\n');
+ }
+}
+
+
+#define STRCMP(str1,str2) strncmp(str1,str2,strlen(str1))
+
+void parse_option(option, argc, argv, bad_arg)
+char *option; /* Option with leading '-' removed. */
+int argc; /* Number of arguments for this option. */
+char *argv[]; /* Arguments for this option. */
+int *bad_arg; /* Set to true if an error is detected. */
+{
+/* Parse a single specification. */
+
+ if (STRCMP(option, "term") == 0)
+ parse_term(argc, argv, &opt_term, &opt_te_terminal_name, bad_arg);
+ else if (STRCMP(option, "reset") == 0)
+ parse_none(argc, argv, &opt_reset, bad_arg);
+ else if (STRCMP(option, "initialize") == 0)
+ parse_none(argc, argv, &opt_initialize, bad_arg);
+ else if (STRCMP(option, "cursor") == 0)
+ parse_switch(argc, argv, &opt_cursor, &opt_cu_on, bad_arg);
+#if 0
+ else if (STRCMP(option, "keyboard") == 0)
+ parse_keyboard(argc, argv, &opt_keyboard, &opt_ke_type, bad_arg);
+#endif
+ else if (STRCMP(option, "repeat") == 0)
+ parse_switch(argc, argv, &opt_repeat, &opt_rep_on, bad_arg);
+ else if (STRCMP(option, "appcursorkeys") == 0)
+ parse_switch(argc, argv, &opt_appcursorkeys, &opt_appck_on, bad_arg);
+ else if (STRCMP(option, "linewrap") == 0)
+ parse_switch(argc, argv, &opt_linewrap, &opt_li_on, bad_arg);
+#if 0
+ else if (STRCMP(option, "snow") == 0)
+ parse_switch(argc, argv, &opt_snow, &opt_sn_on, bad_arg);
+ else if (STRCMP(option, "softscroll") == 0)
+ parse_switch(argc, argv, &opt_softscroll, &opt_so_on, bad_arg);
+#endif
+ else if (STRCMP(option, "default") == 0)
+ parse_none(argc, argv, &opt_default, bad_arg);
+ else if (STRCMP(option, "foreground") == 0)
+ par_color(argc, argv, &opt_foreground, &opt_fo_color, bad_arg);
+ else if (STRCMP(option, "background") == 0)
+ par_color(argc, argv, &opt_background, &opt_ba_color, bad_arg);
+ else if (STRCMP(option, "ulcolor") == 0)
+ par_color2(argc, argv, &opt_ulcolor, &opt_ul_color, bad_arg);
+ else if (STRCMP(option, "hbcolor") == 0)
+ par_color2(argc, argv, &opt_hbcolor, &opt_hb_color, bad_arg);
+ else if (STRCMP(option, "inversescreen") == 0)
+ parse_switch(argc, argv, &opt_inversescreen, &opt_invsc_on, bad_arg);
+ else if (STRCMP(option, "bold") == 0)
+ parse_switch(argc, argv, &opt_bold, &opt_bo_on, bad_arg);
+ else if (STRCMP(option, "half-bright") == 0)
+ parse_switch(argc, argv, &opt_halfbright, &opt_hb_on, bad_arg);
+ else if (STRCMP(option, "blink") == 0)
+ parse_switch(argc, argv, &opt_blink, &opt_bl_on, bad_arg);
+ else if (STRCMP(option, "reverse") == 0)
+ parse_switch(argc, argv, &opt_reverse, &opt_re_on, bad_arg);
+ else if (STRCMP(option, "underline") == 0)
+ parse_switch(argc, argv, &opt_underline, &opt_un_on, bad_arg);
+ else if (STRCMP(option, "store") == 0)
+ parse_none(argc, argv, &opt_store, bad_arg);
+ else if (STRCMP(option, "clear") == 0)
+ parse_clear(argc, argv, &opt_clear, &opt_cl_all, bad_arg);
+ else if (STRCMP(option, "tabs") == 0)
+ parse_tabs(argc, argv, &opt_tabs, opt_tb_array, bad_arg);
+ else if (STRCMP(option, "clrtabs") == 0)
+ parse_clrtabs(argc, argv, &opt_clrtabs, opt_tb_array, bad_arg);
+ else if (STRCMP(option, "regtabs") == 0)
+ parse_regtabs(argc, argv, &opt_regtabs, &opt_rt_len, bad_arg);
+ else if (STRCMP(option, "blank") == 0)
+ parse_blank(argc, argv, &opt_blank, &opt_bl_min, bad_arg);
+ else if (STRCMP(option, "dump") == 0)
+ parse_snap(argc, argv, &opt_snap, &opt_sn_num, bad_arg);
+ else if (STRCMP(option, "append") == 0)
+ parse_snap(argc, argv, &opt_append, &opt_sn_num, bad_arg);
+ else if (STRCMP(option, "file") == 0)
+ parse_snapfile(argc, argv, &opt_snapfile, (int *)opt_sn_name, bad_arg);
+ else if (STRCMP(option, "msg") == 0)
+ parse_switch(argc, argv, &opt_msg, &opt_msg_on, bad_arg);
+ else if (STRCMP(option, "msglevel") == 0)
+ parse_msglevel(argc, argv, &opt_msglevel, &opt_msglevel_num, bad_arg);
+ else if (STRCMP(option, "powersave") == 0)
+ parse_switch(argc, argv, &opt_powersave, &opt_ps_on, bad_arg);
+#if 0
+ else if (STRCMP(option, "standout") == 0)
+ parse_standout(argc, argv, &opt_standout, &opt_st_attr, bad_arg);
+#endif
+ else
+ *bad_arg = TRUE;
+}
+
+/* End of command line parsing routines. */
+
+void usage(prog_name)
+char *prog_name; /* Name of this program. */
+{
+/* Print error message about arguments, and the command's syntax. */
+
+ fprintf(stderr, "%s: Argument error, usage\n", prog_name);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "%s\n", prog_name);
+ fprintf(stderr, " [ -term terminal_name ]\n");
+ fprintf(stderr, " [ -reset ]\n");
+ fprintf(stderr, " [ -initialize ]\n");
+ fprintf(stderr, " [ -cursor [on|off] ]\n");
+#if 0
+ fprintf(stderr, " [ -snow [on|off] ]\n");
+ fprintf(stderr, " [ -softscroll [on|off] ]\n");
+ fprintf(stderr, " [ -keyboard pc|olivetti|dutch|extended ]\n");
+#endif
+ fprintf(stderr, " [ -repeat [on|off] ]\n");
+ fprintf(stderr, " [ -appcursorkeys [on|off] ]\n");
+ fprintf(stderr, " [ -linewrap [on|off] ]\n");
+ fprintf(stderr, " [ -default ]\n");
+ fprintf(stderr, " [ -foreground black|blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white|default ]\n");
+ fprintf(stderr, " [ -background black|blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white|default ]\n");
+ fprintf(stderr, " [ -ulcolor black|grey|blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white ]\n");
+ fprintf(stderr, " [ -ulcolor bright blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white ]\n");
+ fprintf(stderr, " [ -hbcolor black|grey|blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white ]\n");
+ fprintf(stderr, " [ -hbcolor bright blue|green|cyan");
+ fprintf(stderr, "|red|magenta|yellow|white ]\n");
+#if 0
+ fprintf(stderr, " [ -standout [ attr ] ]\n");
+#endif
+ fprintf(stderr, " [ -inversescreen [on|off] ]\n");
+ fprintf(stderr, " [ -bold [on|off] ]\n");
+ fprintf(stderr, " [ -half-bright [on|off] ]\n");
+ fprintf(stderr, " [ -blink [on|off] ]\n");
+ fprintf(stderr, " [ -reverse [on|off] ]\n");
+ fprintf(stderr, " [ -underline [on|off] ]\n");
+ fprintf(stderr, " [ -store ]\n");
+ fprintf(stderr, " [ -clear [all|rest] ]\n");
+ fprintf(stderr, " [ -tabs [ tab1 tab2 tab3 ... ] ] (tabn = 1-160)\n");
+ fprintf(stderr, " [ -clrtabs [ tab1 tab2 tab3 ... ] ] (tabn = 1-160)\n");
+ fprintf(stderr, " [ -regtabs [1-160] ]\n");
+ fprintf(stderr, " [ -blank [0-60] ]\n");
+ fprintf(stderr, " [ -dump [1-NR_CONSOLES] ]\n");
+ fprintf(stderr, " [ -append [1-NR_CONSOLES] ]\n");
+ fprintf(stderr, " [ -file dumpfilename ]\n");
+ fprintf(stderr, " [ -msg [on|off] ]\n");
+ fprintf(stderr, " [ -msglevel [0-8] ]\n");
+ fprintf(stderr, " [ -powersave [on|off] ]\n");
+}
+
+char tc_ent_buf[TC_ENT_SIZE]; /* Buffer for storing a termcap entry. */
+
+char *tc_entry(name)
+char *name; /* Termcap capability string to lookup. */
+{
+/* Return the specified termcap string, or an empty string if no such termcap
+ * capability exists.
+ */
+
+ char *buf_ptr;
+
+ buf_ptr = tc_ent_buf;
+ if (tgetstr(name, &buf_ptr) == NULL) tc_ent_buf[0] = '\0';
+ return tc_ent_buf;
+}
+
+void perform_sequence(vcterm)
+int vcterm; /* Set if terminal is a virtual console. */
+{
+ int result;
+/* Perform the selected options. */
+
+ /* -reset. */
+ if (opt_reset) {
+ printf("%s", tc_entry("rs"));
+ }
+
+ /* -initialize. */
+ if (opt_initialize) {
+ printf("%s", tc_entry("is"));
+ }
+
+ /* -cursor [on|off]. */
+ if (opt_cursor) {
+ if (opt_cu_on)
+ printf("%s", tc_entry("ve"));
+ else
+ printf("%s", tc_entry("vi"));
+ }
+
+#if 0
+ /* -keyboard pc|olivetti|dutch|extended. Vc only. */
+ if (opt_keyboard && vcterm) {
+ switch (opt_ke_type) {
+ case PC:
+ printf("%s%s%s", DCS, "keyboard.pc", ST);
+ break;
+ case OLIVETTI:
+ printf("%s%s%s", DCS, "keyboard.olivetti", ST);
+ break;
+ case DUTCH:
+ printf("%s%s%s", DCS, "keyboard.dutch", ST);
+ break;
+ case EXTENDED:
+ printf("%s%s%s", DCS, "keyboard.extended", ST);
+ break;
+ }
+ }
+#endif
+
+ /* -linewrap [on|off]. Vc only (vt102) */
+ if (opt_linewrap && vcterm) {
+ if (opt_li_on)
+ printf("\033[?7h");
+ else
+ printf("\033[?7l");
+ }
+
+ /* -repeat [on|off]. Vc only (vt102) */
+ if (opt_repeat && vcterm) {
+ if (opt_rep_on)
+ printf("\033[?8h");
+ else
+ printf("\033[?8l");
+ }
+
+ /* -appcursorkeys [on|off]. Vc only (vt102) */
+ if (opt_appcursorkeys && vcterm) {
+ if (opt_appck_on)
+ printf("\033[?1h");
+ else
+ printf("\033[?1l");
+ }
+
+#if 0
+ /* -snow [on|off]. Vc only. */
+ if (opt_snow && vcterm) {
+ if (opt_sn_on)
+ printf("%s%s%s", DCS, "snow.on", ST);
+ else
+ printf("%s%s%s", DCS, "snow.off", ST);
+ }
+
+ /* -softscroll [on|off]. Vc only. */
+ if (opt_softscroll && vcterm) {
+ if (opt_so_on)
+ printf("%s%s%s", DCS, "softscroll.on", ST);
+ else
+ printf("%s%s%s", DCS, "softscroll.off", ST);
+ }
+#endif
+
+ /* -default. Vc sets default rendition, otherwise clears all
+ * attributes.
+ */
+ if (opt_default) {
+ if (vcterm)
+ printf("\033[0m");
+ else
+ printf("%s", tc_entry("me"));
+ }
+
+ /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default.
+ * Vc only (ANSI).
+ */
+ if (opt_foreground && vcterm) {
+ printf("%s%s%c%s", ESC, "[3", '0' + opt_fo_color, "m");
+ }
+
+ /* -background black|red|green|yellow|blue|magenta|cyan|white|default.
+ * Vc only (ANSI).
+ */
+ if (opt_background && vcterm) {
+ printf("%s%s%c%s", ESC, "[4", '0' + opt_ba_color, "m");
+ }
+
+ /* -ulcolor black|red|green|yellow|blue|magenta|cyan|white|default.
+ * Vc only.
+ */
+ if (opt_ulcolor && vcterm) {
+ printf("\033[1;%d]", opt_ul_color);
+ }
+
+ /* -hbcolor black|red|green|yellow|blue|magenta|cyan|white|default.
+ * Vc only.
+ */
+ if (opt_hbcolor && vcterm) {
+ printf("\033[2;%d]", opt_hb_color);
+ }
+
+ /* -inversescreen [on|off]. Vc only (vt102).
+ */
+ if (opt_inversescreen) {
+ if (vcterm)
+ if (opt_invsc_on)
+ printf("\033[?5h");
+ else
+ printf("\033[?5l");
+ }
+
+ /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
+ * all attributes.
+ */
+ if (opt_bold) {
+ if (opt_bo_on)
+ printf("%s", tc_entry("md"));
+ else {
+ if (vcterm)
+ printf("%s%s", ESC, "[22m");
+ else
+ printf("%s", tc_entry("me"));
+ }
+ }
+
+ /* -half-bright [on|off]. Vc behaves as expected, otherwise off turns off
+ * all attributes.
+ */
+ if (opt_halfbright) {
+ if (opt_hb_on)
+ printf("%s", tc_entry("mh"));
+ else {
+ if (vcterm)
+ printf("%s%s", ESC, "[22m");
+ else
+ printf("%s", tc_entry("me"));
+ }
+ }
+
+ /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
+ * all attributes.
+ */
+ if (opt_blink) {
+ if (opt_bl_on)
+ printf("%s", tc_entry("mb"));
+ else {
+ if (vcterm)
+ printf("%s%s", ESC, "[25m");
+ else
+ printf("%s", tc_entry("me"));
+ }
+ }
+
+ /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
+ * off all attributes.
+ */
+ if (opt_reverse) {
+ if (opt_re_on)
+ printf("%s", tc_entry("mr"));
+ else {
+ if (vcterm)
+ printf("%s%s", ESC, "[27m");
+ else
+ printf("%s", tc_entry("me"));
+ }
+ }
+
+ /* -underline [on|off]. */
+ if (opt_underline) {
+ if (opt_un_on)
+ printf("%s", tc_entry("us"));
+ else
+ printf("%s", tc_entry("ue"));
+ }
+
+ /* -store. Vc only. */
+ if (opt_store && vcterm) {
+ printf("\033[8]");
+ }
+
+ /* -clear [all|rest]. */
+ if (opt_clear) {
+ if (opt_cl_all)
+ printf("%s", tc_entry("cl"));
+ else
+ printf("%s", tc_entry("cd"));
+ }
+
+ /* -tabs Vc only. */
+ if (opt_tabs && vcterm) {
+ int i;
+
+ if (opt_tb_array[0] == -1)
+ show_tabs();
+ else {
+ for(i=0; opt_tb_array[i] > 0; i++)
+ printf("\033[%dG\033H", opt_tb_array[i]);
+ putchar('\r');
+ }
+ }
+
+ /* -clrtabs Vc only. */
+ if (opt_clrtabs && vcterm) {
+ int i;
+
+ if (opt_tb_array[0] == -1)
+ printf("\033[3g");
+ else
+ for(i=0; opt_tb_array[i]; i++)
+ printf("\033[%dG\033[g", opt_tb_array[i]);
+ putchar('\r');
+ }
+
+ /* -regtabs Vc only. */
+ if (opt_regtabs && vcterm) {
+ int i;
+
+ printf("\033[3g\r");
+ for(i=opt_rt_len+1; i<=160; i+=opt_rt_len)
+ printf("\033[%dC\033H",opt_rt_len);
+ putchar('\r');
+ }
+
+ /* -blank [0-60]. */
+ if (opt_blank)
+ printf("\033[9;%d]", opt_bl_min);
+
+ /* -powersave [on|off] (console) */
+ if (opt_powersave) {
+ char ioctlarg[2];
+ ioctlarg[0] = 10; /* powersave */
+ ioctlarg[1] = opt_ps_on;
+ if (ioctl(0,TIOCLINUX,ioctlarg))
+ fprintf(stderr,"cannot (un)set powersave mode\n");
+ }
+
+#if 0
+ /* -standout [num]. */
+ if (opt_standout)
+ /* nothing */;
+#endif
+
+ /* -snap [1-NR_CONS]. */
+ if (opt_snap || opt_append) {
+ FILE *F;
+
+ F = fopen(opt_sn_name, opt_snap ? "w" : "a");
+ if (!F) {
+ perror(opt_sn_name);
+ fprintf(stderr,"setterm: can not open dump file %s for output\n",
+ opt_sn_name);
+ exit(-1);
+ }
+ screendump(opt_sn_num, F);
+ fclose(F);
+ }
+
+ /* -msg [on|off]. */
+ if (opt_msg && vcterm) {
+ if (opt_msg_on)
+ /* 7 -- Enable printk's to console */
+ result = syslog(7, NULL, 0);
+ else
+ /* 6 -- Disable printk's to console */
+ result = syslog(6, NULL, 0);
+
+ if (result != 0)
+ printf("syslog error: %s\n", strerror(result));
+ }
+
+ /* -msglevel [0-8] */
+ if (opt_msglevel && vcterm) {
+ /* 8 -- Set level of messages printed to console */
+ result = syslog(8, NULL, opt_msglevel_num);
+ if (result != 0)
+ printf("syslog error: %s\n", strerror(result));
+ }
+}
+
+extern char *malloc();
+
+screendump(int vcnum, FILE *F){
+#include <sys/param.h>
+ char infile[MAXPATHLEN];
+ unsigned char header[4];
+ unsigned int rows, cols;
+ int fd, i, j;
+ char *inbuf, *outbuf, *p, *q;
+
+ sprintf(infile, "/dev/vcsa%d", vcnum);
+ fd = open(infile, 0);
+ if (fd < 0 || read(fd, header, 4) != 4)
+ goto try_ioctl;
+ rows = header[0];
+ cols = header[1];
+ if (rows * cols == 0)
+ goto try_ioctl;
+ inbuf = malloc(rows*cols*2);
+ outbuf = malloc(rows*(cols+1));
+ if(!inbuf || !outbuf) {
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+ }
+ if (read(fd, inbuf, rows*cols*2) != rows*cols*2) {
+ fprintf(stderr, "Error reading %s\n", infile);
+ exit(1);
+ }
+ p = inbuf;
+ q = outbuf;
+ for(i=0; i<rows; i++) {
+ for(j=0; j<cols; j++) {
+ *q++ = *p;
+ p += 2;
+ }
+ while(j-- > 0 && q[-1] == ' ')
+ q--;
+ *q++ = '\n';
+ }
+ if (fwrite(outbuf, 1, q-outbuf, F) != q-outbuf) {
+ fprintf(stderr, "Error writing screendump\n");
+ exit(1);
+ }
+ return;
+
+try_ioctl:
+ {
+#define NUM_COLS 160
+#define NUM_ROWS 75
+ char buf[NUM_COLS+1];
+ unsigned char screenbuf[NUM_ROWS*NUM_COLS];
+ screenbuf[0] = 0;
+ screenbuf[1] = (unsigned char) vcnum;
+ if (ioctl(0,TIOCLINUX,screenbuf) < 0) {
+ fprintf(stderr,"couldn't read %s, and cannot ioctl dump\n",
+ infile);
+ exit(1);
+ }
+ rows = screenbuf[0];
+ cols = screenbuf[1];
+ for (i=0; i<rows; i++) {
+ strncpy(buf, screenbuf+2+(cols*i), cols);
+ buf[cols] = '\0';
+ j = cols;
+ while (--j && (buf[j] == ' '))
+ buf[j] = '\0';
+ fputs(buf,F);
+ fputc('\n',F);
+ }
+ }
+}
+
+void main(int argc, char **argv)
+{
+ int bad_arg = FALSE; /* Set if error in arguments. */
+ int arg, modifier;
+ char *term; /* Terminal type. */
+ int vcterm; /* Set if terminal is a virtual console. */
+
+ if (argc < 2) bad_arg = TRUE;
+
+ /* Parse arguments. */
+
+ for (arg = 1; arg < argc;) {
+ if (*argv[arg] == '-') {
+
+ /* Parse a single option. */
+
+ for (modifier = arg + 1; modifier < argc; modifier++) {
+ if (*argv[modifier] == '-') break;
+ }
+ parse_option(argv[arg] + 1, modifier - arg - 1,
+ &argv[arg + 1], &bad_arg);
+ arg = modifier;
+ } else {
+
+ bad_arg = TRUE;
+ arg++;
+ }
+ }
+
+ /* Display syntax message if error in arguments. */
+
+ if (bad_arg) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ /* Find out terminal name. */
+
+ if (opt_term) {
+ term = opt_te_terminal_name;
+ } else {
+ term = getenv("TERM");
+ if (term == NULL) {
+ fprintf(stderr, "%s: $TERM is not defined.\n", argv[0]);
+ exit(1);
+ }
+ }
+
+ /* Find termcap entry. */
+
+ if (tgetent(tc_buf, term) != 1) {
+ fprintf(stderr, "%s: Could not find termcap entry for %s.\n",
+ argv[0], term);
+ exit(1);
+ }
+
+ /* See if the terminal is a virtual console terminal. */
+
+ vcterm = (!strncmp(term, "con", 3) || !strncmp(term, "linux", 5));
+
+ /* Perform the selected options. */
+
+ perform_sequence(vcterm);
+
+ exit(0);
+}
diff --git a/misc-utils/tsort.1 b/misc-utils/tsort.1
new file mode 100644
index 000000000..72ea964a9
--- /dev/null
+++ b/misc-utils/tsort.1
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This manual is derived from one contributed to Berkeley by
+.\" Michael Rendell of Memorial University of Newfoundland.
+.\" 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.
+.\"
+.\" @(#)tsort.1 6.3 (Berkeley) 4/23/91
+.\"
+.Dd April 23, 1991
+.Dt TSORT 1
+.Os
+.Sh NAME
+.Nm tsort
+.Nd topological sort of a directed graph
+.Sh SYNOPSIS
+.Nm tsort
+.Op Ar file
+.Sh DESCRIPTION
+.Nm Tsort
+takes a list of pairs of node names representing directed arcs in
+a graph and prints the nodes in topological order on standard output.
+Input is taken from the named
+.Ar file ,
+or from standard input if no file
+is given.
+.Pp
+Node names in the input are separated by white space and there must be an
+even number of nodes.
+.Pp
+Presence of a node in a graph can be represented by an arc from the node
+to itself.
+This is useful when a node is not connected to any other nodes.
+.Pp
+If the graph contains a cycle (and therefore cannot be properly sorted),
+one of the arcs in the cycle is ignored and the sort continues.
+Cycles are reported on standard error.
+.Sh SEE ALSO
+.Xr ar 1
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v7 .
+This
+.Nm tsort
+command and manual page are derived from sources contributed to Berkeley by
+Michael Rendell of Memorial University of Newfoundland.
diff --git a/misc-utils/tsort.c b/misc-utils/tsort.c
new file mode 100644
index 000000000..4ccfcd539
--- /dev/null
+++ b/misc-utils/tsort.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Rendell of Memorial University of Newfoundland.
+ *
+ * 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.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)tsort.c 5.3 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/*
+ * Topological sort. Input is a list of pairs of strings seperated by
+ * white space (spaces, tabs, and/or newlines); strings are written to
+ * standard output in sorted order, one per line.
+ *
+ * usage:
+ * tsort [inputfile]
+ * If no input file is specified, standard input is read.
+ *
+ * Should be compatable with AT&T tsort HOWEVER the output is not identical
+ * (i.e. for most graphs there is more than one sorted order, and this tsort
+ * usually generates a different one then the AT&T tsort). Also, cycle
+ * reporting seems to be more accurate in this version (the AT&T tsort
+ * sometimes says a node is in a cycle when it isn't).
+ *
+ * Michael Rendell, michael@stretch.cs.mun.ca - Feb 26, '90
+ */
+#define HASHSIZE 53 /* doesn't need to be big */
+#define NF_MARK 0x1 /* marker for cycle detection */
+#define NF_ACYCLIC 0x2 /* this node is cycle free */
+
+typedef struct node_str NODE;
+
+struct node_str {
+ char *n_name; /* name of this node */
+ NODE **n_prevp; /* pointer to previous node's n_next */
+ NODE *n_next; /* next node in graph */
+ NODE *n_hash; /* next node in hash table */
+ int n_narcs; /* number of arcs in n_arcs[] */
+ int n_arcsize; /* size of n_arcs[] array */
+ NODE **n_arcs; /* array of arcs to other nodes */
+ int n_refcnt; /* # of arcs pointing to this node */
+ int n_flags; /* NF_* */
+};
+
+typedef struct _buf {
+ char *b_buf;
+ int b_bsize;
+} BUF;
+
+NODE *add_node(), *find_node();
+void add_arc(), no_memory(), remove_node(), tsort();
+char *grow_buf(), *malloc();
+
+extern int errno;
+NODE *graph;
+NODE *hashtable[HASHSIZE];
+NODE **cycle_buf;
+NODE **longest_cycle;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register BUF *b;
+ register int c, n;
+ FILE *fp;
+ int bsize, nused;
+ BUF bufs[2];
+
+ if (argc < 2)
+ fp = stdin;
+ /* == becomes > in next line per Volker Meyer_zu_Bexten
+ <vmzb@ims.fhg.de> -- faith@cs.unc.edu, Sat Feb 4 21:25:09 1995 */
+ else if (argc > 2) {
+ (void)fprintf(stderr, "usage: tsort [ inputfile ]\n");
+ exit(1);
+ } else if (!(fp = fopen(argv[1], "r"))) {
+ (void)fprintf(stderr, "tsort: %s.\n", strerror(errno));
+ exit(1);
+ }
+
+ for (b = bufs, n = 2; --n >= 0; b++)
+ b->b_buf = grow_buf((char *)NULL, b->b_bsize = 1024);
+
+ /* parse input and build the graph */
+ for (n = 0, c = getc(fp);;) {
+ while (c != EOF && isspace(c))
+ c = getc(fp);
+ if (c == EOF)
+ break;
+
+ nused = 0;
+ b = &bufs[n];
+ bsize = b->b_bsize;
+ do {
+ b->b_buf[nused++] = c;
+ if (nused == bsize) {
+ bsize *= 2;
+ b->b_buf = grow_buf(b->b_buf, bsize);
+ }
+ c = getc(fp);
+ } while (c != EOF && !isspace(c));
+
+ b->b_buf[nused] = '\0';
+ b->b_bsize = bsize;
+ if (n)
+ add_arc(bufs[0].b_buf, bufs[1].b_buf);
+ n = !n;
+ }
+ (void)fclose(fp);
+ if (n) {
+ (void)fprintf(stderr, "tsort: odd data count.\n");
+ exit(1);
+ }
+
+ /* do the sort */
+ tsort();
+ exit(0);
+}
+
+/* double the size of oldbuf and return a pointer to the new buffer. */
+char *
+grow_buf(bp, size)
+ char *bp;
+ int size;
+{
+ char *realloc();
+
+ if (!(bp = realloc(bp, (u_int)size)))
+ no_memory();
+ return(bp);
+}
+
+/*
+ * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in
+ * the graph, then add them.
+ */
+void
+add_arc(s1, s2)
+ char *s1, *s2;
+{
+ register NODE *n1;
+ NODE *n2;
+ int bsize;
+
+ n1 = find_node(s1);
+ if (!n1)
+ n1 = add_node(s1);
+
+ if (!strcmp(s1, s2))
+ return;
+
+ n2 = find_node(s2);
+ if (!n2)
+ n2 = add_node(s2);
+
+ /*
+ * could check to see if this arc is here already, but it isn't
+ * worth the bother -- there usually isn't and it doesn't hurt if
+ * there is (I think :-).
+ */
+ if (n1->n_narcs == n1->n_arcsize) {
+ if (!n1->n_arcsize)
+ n1->n_arcsize = 10;
+ bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2;
+ n1->n_arcs = (NODE **)grow_buf((char *)n1->n_arcs, bsize);
+ n1->n_arcsize = bsize / sizeof(*n1->n_arcs);
+ }
+ n1->n_arcs[n1->n_narcs++] = n2;
+ ++n2->n_refcnt;
+}
+
+hash_string(s)
+ char *s;
+{
+ register int hash, i;
+
+ for (hash = 0, i = 1; *s; s++, i++)
+ hash += *s * i;
+ return(hash % HASHSIZE);
+}
+
+/*
+ * find a node in the graph and return a pointer to it - returns null if not
+ * found.
+ */
+NODE *
+find_node(name)
+ char *name;
+{
+ register NODE *n;
+
+ for (n = hashtable[hash_string(name)]; n; n = n->n_hash)
+ if (!strcmp(n->n_name, name))
+ return(n);
+ return((NODE *)NULL);
+}
+
+/* Add a node to the graph and return a pointer to it. */
+NODE *
+add_node(name)
+ char *name;
+{
+ register NODE *n;
+ int hash;
+
+ if (!(n = (NODE *)malloc(sizeof(NODE))) || !(n->n_name = strdup(name)))
+ no_memory();
+
+ n->n_narcs = 0;
+ n->n_arcsize = 0;
+ n->n_arcs = (NODE **)NULL;
+ n->n_refcnt = 0;
+ n->n_flags = 0;
+
+ /* add to linked list */
+ if (n->n_next = graph)
+ graph->n_prevp = &n->n_next;
+ n->n_prevp = &graph;
+ graph = n;
+
+ /* add to hash table */
+ hash = hash_string(name);
+ n->n_hash = hashtable[hash];
+ hashtable[hash] = n;
+ return(n);
+}
+
+/* do topological sort on graph */
+void
+tsort()
+{
+ register NODE *n, *next;
+ register int cnt;
+
+ while (graph) {
+ /*
+ * keep getting rid of simple cases until there are none left,
+ * if there are any nodes still in the graph, then there is
+ * a cycle in it.
+ */
+ do {
+ for (cnt = 0, n = graph; n; n = next) {
+ next = n->n_next;
+ if (n->n_refcnt == 0) {
+ remove_node(n);
+ ++cnt;
+ }
+ }
+ } while (graph && cnt);
+
+ if (!graph)
+ break;
+
+ if (!cycle_buf) {
+ /*
+ * allocate space for two cycle logs - one to be used
+ * as scratch space, the other to save the longest
+ * cycle.
+ */
+ for (cnt = 0, n = graph; n; n = n->n_next)
+ ++cnt;
+ cycle_buf =
+ (NODE **)malloc((u_int)sizeof(NODE *) * cnt);
+ longest_cycle =
+ (NODE **)malloc((u_int)sizeof(NODE *) * cnt);
+ if (!cycle_buf || !longest_cycle)
+ no_memory();
+ }
+ for (n = graph; n; n = n->n_next)
+ if (!(n->n_flags & NF_ACYCLIC)) {
+ if (cnt = find_cycle(n, n, 0, 0)) {
+ register int i;
+
+ (void)fprintf(stderr,
+ "tsort: cycle in data.\n");
+ for (i = 0; i < cnt; i++)
+ (void)fprintf(stderr,
+ "tsort: %s.\n", longest_cycle[i]->n_name);
+ remove_node(n);
+ break;
+ } else
+ /* to avoid further checks */
+ n->n_flags = NF_ACYCLIC;
+ }
+
+ if (!n) {
+ (void)fprintf(stderr,
+ "tsort: internal error -- could not find cycle.\n");
+ exit(1);
+ }
+ }
+}
+
+/* print node and remove from graph (does not actually free node) */
+void
+remove_node(n)
+ register NODE *n;
+{
+ register NODE **np;
+ register int i;
+
+ (void)printf("%s\n", n->n_name);
+ for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++)
+ --(*np)->n_refcnt;
+ n->n_narcs = 0;
+ *n->n_prevp = n->n_next;
+ if (n->n_next)
+ n->n_next->n_prevp = n->n_prevp;
+}
+
+/* look for the longest cycle from node from to node to. */
+find_cycle(from, to, longest_len, depth)
+ NODE *from, *to;
+ int depth, longest_len;
+{
+ register NODE **np;
+ register int i, len;
+
+ /*
+ * avoid infinite loops and ignore portions of the graph known
+ * to be acyclic
+ */
+ if (from->n_flags & (NF_MARK|NF_ACYCLIC))
+ return(0);
+ from->n_flags = NF_MARK;
+
+ for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) {
+ cycle_buf[depth] = *np;
+ if (*np == to) {
+ if (depth + 1 > longest_len) {
+ longest_len = depth + 1;
+ (void)memcpy((char *)longest_cycle,
+ (char *)cycle_buf,
+ longest_len * sizeof(NODE *));
+ }
+ } else {
+ len = find_cycle(*np, to, longest_len, depth + 1);
+ if (len > longest_len)
+ longest_len = len;
+ }
+ }
+ from->n_flags &= ~NF_MARK;
+ return(longest_len);
+}
+
+void
+no_memory()
+{
+ (void)fprintf(stderr, "tsort: %s.\n", strerror(ENOMEM));
+ exit(1);
+}
diff --git a/misc-utils/whereis.1 b/misc-utils/whereis.1
new file mode 100644
index 000000000..4d55ac6d3
--- /dev/null
+++ b/misc-utils/whereis.1
@@ -0,0 +1,198 @@
+.\" Copyright (c) 1980, 1990 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.
+.\"
+.\" @(#)whereis.1 from UCB 4.2
+.TH WHEREIS 1 "8 May 1994"
+.SH NAME
+whereis \- locate the binary, source, and manual page files for a command
+.SH SYNOPSIS
+.B whereis
+[
+.B \-bmsu
+] [
+.B \-BMS
+.IR directory .\|.\|.
+.B \-f
+]
+\fIfilename\fP\|
+\&.\|.\|.
+.IX "whereis command" "" "\fLwhereis\fP \(em find program"
+.IX find "program \(em \fLwhereis\fP"
+.IX "locate program" "" "locate program \(em \fLwhereis\fP"
+.IX command locate "" "locate \(em \fLwhereis\fP"
+.SH DESCRIPTION
+.B whereis
+locates source/binary and manuals sections for specified
+files.
+The supplied names are first stripped of leading pathname components
+and any (single) trailing extension of the form
+.BI . ext,
+for example,
+.BR .c .
+Prefixes of
+.B s.
+resulting from use of source code control are also dealt with.
+.B whereis
+then attempts to locate the desired program in
+a list of standard Linux places:
+.IP
+.nf
+.ft B
+/bin
+/usr/bin
+/etc
+/usr/etc
+/sbin
+/usr/sbin
+/usr/games
+/usr/games/bin
+/usr/emacs/etc
+/usr/lib/emacs/19.22/etc
+/usr/lib/emacs/19.23/etc
+/usr/lib/emacs/19.24/etc
+/usr/lib/emacs/19.25/etc
+/usr/lib/emacs/19.26/etc
+/usr/lib/emacs/19.27/etc
+/usr/lib/emacs/19.28/etc
+/usr/lib/emacs/19.29/etc
+/usr/lib/emacs/19.30/etc
+/usr/TeX/bin
+/usr/tex/bin
+/usr/interviews/bin/LINUX
+/usr/bin/X11
+/usr/X11/bin
+/usr/X11R5/bin
+/usr/X11R6/bin
+/usr/X386/bin
+/usr/local/bin
+/usr/local/etc
+/usr/local/sbin
+/usr/local/games
+/usr/local/games/bin
+/usr/local/emacs/etc
+/usr/local/TeX/bin
+/usr/local/tex/bin
+/usr/local/bin/X11
+
+/usr/contrib",
+/usr/hosts",
+/usr/include",
+
+/usr/g++-include",
+.ft R
+.fi
+.SH OPTIONS
+.TP
+\fB\-b
+Search only for binaries.
+.TP
+.B \-m
+Search only for manual sections.
+.TP
+.B \-s
+Search only for sources.
+.TP
+.B \-u
+Search for unusual entries. A file is said to be unusual if it does
+not have one entry of each requested type.
+Thus
+.RB ` "whereis\ \ \-m\ \ \-u\ \ *" '
+asks for those files in the current
+directory which have no documentation.
+.TP
+.B \-B
+Change or otherwise limit the places where
+.B whereis
+searches for binaries.
+.TP
+.B \-M
+Change or otherwise limit the places where
+.B whereis
+searches for
+manual sections.
+.TP
+.B \-S
+Change or otherwise limit the places where
+.B whereis
+searches for sources.
+.TP
+.B \-f
+Terminate the last directory list and signals the start of file names,
+and
+.I must
+be used when any of the
+.BR \-B ,
+.BR \-M ,
+or
+.B \-S
+options are used.
+.SH EXAMPLE
+Find all files in
+.B /usr/bin
+which are not documented
+in
+.B /usr/man/man1
+with source in
+.BR /usr/src :
+.IP
+.nf
+.ft B
+example% cd /usr/bin
+example% whereis \-u \-M /usr/man/man1 \-S /usr/src \-f *
+.fi
+.ft R
+.SH FILES
+.PD 0
+.TP 20
+.B /{bin,sbin,etc}
+.TP
+.B /usr/{lib,bin,old,new,local,games,include,etc,src,man,sbin,
+.B X386,TeX,g++-include}
+.TP
+.B /usr/local/{X386,TeX,X11,include,lib,man,etc,bin,games,
+.B emacs}
+.TP
+.B
+.PD
+.SH SEE ALSO
+.BR chdir (2V)
+.SH BUGS
+Since
+.B whereis
+uses
+.BR chdir (2V)
+to run faster, pathnames given with the
+.BR \-M ,
+.BR \-S ,
+or
+.B \-B
+must be full; that is, they must begin with a
+.RB ` / '.
diff --git a/misc-utils/whereis.c b/misc-utils/whereis.c
new file mode 100644
index 000000000..f869040a9
--- /dev/null
+++ b/misc-utils/whereis.c
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 1980 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.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)whereis.c 5.5 (Berkeley) 4/18/91";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/dir.h>
+#include <stdio.h>
+#include <ctype.h>
+
+static char *bindirs[] = {
+#ifdef __linux__
+ "/bin",
+ "/usr/bin",
+ "/etc",
+ "/usr/etc",
+ "/sbin",
+ "/usr/sbin",
+ "/usr/games",
+ "/usr/games/bin",
+ "/usr/emacs/etc",
+ "/usr/lib/emacs/19.22/etc",
+ "/usr/lib/emacs/19.23/etc",
+ "/usr/lib/emacs/19.24/etc",
+ "/usr/lib/emacs/19.25/etc",
+ "/usr/lib/emacs/19.26/etc",
+ "/usr/lib/emacs/19.27/etc",
+ "/usr/lib/emacs/19.28/etc",
+ "/usr/lib/emacs/19.29/etc",
+ "/usr/lib/emacs/19.30/etc",
+ "/usr/TeX/bin",
+ "/usr/tex/bin",
+ "/usr/interviews/bin/LINUX",
+
+ "/usr/bin/X11",
+ "/usr/X11/bin",
+ "/usr/X11R5/bin",
+ "/usr/X11R6/bin",
+ "/usr/X386/bin",
+
+ "/usr/local/bin",
+ "/usr/local/etc",
+ "/usr/local/sbin",
+ "/usr/local/games",
+ "/usr/local/games/bin",
+ "/usr/local/emacs/etc",
+ "/usr/local/TeX/bin",
+ "/usr/local/tex/bin",
+ "/usr/local/bin/X11",
+
+ "/usr/contrib",
+ "/usr/hosts",
+ "/usr/include",
+
+ "/usr/g++-include",
+#else
+ "/bin",
+ "/sbin",
+ "/usr/ucb",
+ "/usr/bin",
+ "/usr/sbin",
+ "/usr/old",
+ "/usr/contrib",
+ "/usr/games",
+ "/usr/local",
+ "/usr/libexec",
+ "/usr/include",
+ "/usr/hosts",
+ "/usr/share", /*?*/
+ "/etc",
+#ifdef notdef
+ /* before reorg */
+ "/etc",
+ "/bin",
+ "/usr/bin",
+ "/usr/games",
+ "/lib",
+ "/usr/ucb",
+ "/usr/lib",
+ "/usr/local",
+ "/usr/new",
+ "/usr/old",
+ "/usr/hosts",
+ "/usr/include",
+#endif
+#endif
+ 0
+};
+/* This needs to be redone - man pages live with sources */
+static char *mandirs[] = {
+ "/usr/man/man1",
+ "/usr/man/man2",
+ "/usr/man/man3",
+ "/usr/man/man4",
+ "/usr/man/man5",
+ "/usr/man/man6",
+ "/usr/man/man7",
+ "/usr/man/man8",
+#ifdef __linux__
+ "/usr/man/man9",
+#endif
+ "/usr/man/manl",
+ "/usr/man/mann",
+ "/usr/man/mano",
+#ifdef __linux__
+ "/usr/X386/man/man1",
+ "/usr/X386/man/man2",
+ "/usr/X386/man/man3",
+ "/usr/X386/man/man4",
+ "/usr/X386/man/man5",
+ "/usr/X386/man/man6",
+ "/usr/X386/man/man7",
+ "/usr/X386/man/man8",
+ "/usr/X11/man/man1",
+ "/usr/X11/man/man2",
+ "/usr/X11/man/man3",
+ "/usr/X11/man/man4",
+ "/usr/X11/man/man5",
+ "/usr/X11/man/man6",
+ "/usr/X11/man/man7",
+ "/usr/X11/man/man8",
+ "/usr/TeX/man/man1",
+ "/usr/TeX/man/man2",
+ "/usr/TeX/man/man3",
+ "/usr/TeX/man/man4",
+ "/usr/TeX/man/man5",
+ "/usr/TeX/man/man6",
+ "/usr/TeX/man/man7",
+ "/usr/TeX/man/man8",
+ "/usr/interviews/man/mann",
+#endif
+ 0
+};
+static char *srcdirs[] = {
+ "/usr/src/bin",
+ "/usr/src/sbin",
+ "/usr/src/etc",
+ "/usr/src/pgrm",
+ "/usr/src/usr.bin",
+ "/usr/src/usr.sbin",
+ "/usr/src/usr.ucb",
+ "/usr/src/usr.new",
+ "/usr/src/usr.lib",
+ "/usr/src/libexec",
+ "/usr/src/libdata",
+ "/usr/src/share",
+ "/usr/src/contrib",
+ "/usr/src/athena",
+ "/usr/src/devel",
+ "/usr/src/games",
+ "/usr/src/local",
+ "/usr/src/man",
+ "/usr/src/root",
+ "/usr/src/old",
+ "/usr/src/include",
+ /* still need libs */
+#ifdef notdef /* before reorg */
+ "/usr/src/bin",
+ "/usr/src/usr.bin",
+ "/usr/src/etc",
+ "/usr/src/ucb",
+ "/usr/src/games",
+ "/usr/src/usr.lib",
+ "/usr/src/lib",
+ "/usr/src/local",
+ "/usr/src/new",
+ "/usr/src/old",
+ "/usr/src/include",
+ "/usr/src/lib/libc/gen",
+ "/usr/src/lib/libc/stdio",
+ "/usr/src/lib/libc/sys",
+ "/usr/src/lib/libc/net/common",
+ "/usr/src/lib/libc/net/inet",
+ "/usr/src/lib/libc/net/misc",
+ "/usr/src/ucb/pascal",
+ "/usr/src/ucb/pascal/utilities",
+ "/usr/src/undoc",
+#endif
+ 0
+};
+
+char sflag = 1;
+char bflag = 1;
+char mflag = 1;
+char **Sflag;
+int Scnt;
+char **Bflag;
+int Bcnt;
+char **Mflag;
+int Mcnt;
+char uflag;
+/*
+ * whereis name
+ * look for source, documentation and binaries
+ */
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ argc--, argv++;
+ if (argc == 0) {
+usage:
+ fprintf(stderr, "whereis [ -sbmu ] [ -SBM dir ... -f ] name...\n");
+ exit(1);
+ }
+ do
+ if (argv[0][0] == '-') {
+ register char *cp = argv[0] + 1;
+ while (*cp) switch (*cp++) {
+
+ case 'f':
+ break;
+
+ case 'S':
+ getlist(&argc, &argv, &Sflag, &Scnt);
+ break;
+
+ case 'B':
+ getlist(&argc, &argv, &Bflag, &Bcnt);
+ break;
+
+ case 'M':
+ getlist(&argc, &argv, &Mflag, &Mcnt);
+ break;
+
+ case 's':
+ zerof();
+ sflag++;
+ continue;
+
+ case 'u':
+ uflag++;
+ continue;
+
+ case 'b':
+ zerof();
+ bflag++;
+ continue;
+
+ case 'm':
+ zerof();
+ mflag++;
+ continue;
+
+ default:
+ goto usage;
+ }
+ argv++;
+ } else
+ lookup(*argv++);
+ while (--argc > 0);
+ exit(0);
+}
+
+getlist(argcp, argvp, flagp, cntp)
+ char ***argvp;
+ int *argcp;
+ char ***flagp;
+ int *cntp;
+{
+
+ (*argvp)++;
+ *flagp = *argvp;
+ *cntp = 0;
+ for ((*argcp)--; *argcp > 0 && (*argvp)[0][0] != '-'; (*argcp)--)
+ (*cntp)++, (*argvp)++;
+ (*argcp)++;
+ (*argvp)--;
+}
+
+
+zerof()
+{
+
+ if (sflag && bflag && mflag)
+ sflag = bflag = mflag = 0;
+}
+int count;
+int print;
+
+
+lookup(cp)
+ register char *cp;
+{
+ register char *dp;
+
+ for (dp = cp; *dp; dp++)
+ continue;
+ for (; dp > cp; dp--) {
+ if (*dp == '.') {
+ *dp = 0;
+ break;
+ }
+ }
+ for (dp = cp; *dp; dp++)
+ if (*dp == '/')
+ cp = dp + 1;
+ if (uflag) {
+ print = 0;
+ count = 0;
+ } else
+ print = 1;
+again:
+ if (print)
+ printf("%s:", cp);
+ if (sflag) {
+ looksrc(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ goto again;
+ }
+ }
+ count = 0;
+ if (bflag) {
+ lookbin(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ goto again;
+ }
+ }
+ count = 0;
+ if (mflag) {
+ lookman(cp);
+ if (uflag && print == 0 && count != 1) {
+ print = 1;
+ goto again;
+ }
+ }
+ if (print)
+ printf("\n");
+}
+
+looksrc(cp)
+ char *cp;
+{
+ if (Sflag == 0) {
+ find(srcdirs, cp);
+ } else
+ findv(Sflag, Scnt, cp);
+}
+
+lookbin(cp)
+ char *cp;
+{
+ if (Bflag == 0)
+ find(bindirs, cp);
+ else
+ findv(Bflag, Bcnt, cp);
+}
+
+lookman(cp)
+ char *cp;
+{
+ if (Mflag == 0) {
+ find(mandirs, cp);
+ } else
+ findv(Mflag, Mcnt, cp);
+}
+
+findv(dirv, dirc, cp)
+ char **dirv;
+ int dirc;
+ char *cp;
+{
+
+ while (dirc > 0)
+ findin(*dirv++, cp), dirc--;
+}
+
+find(dirs, cp)
+ char **dirs;
+ char *cp;
+{
+
+ while (*dirs)
+ findin(*dirs++, cp);
+}
+
+findin(dir, cp)
+ char *dir, *cp;
+{
+ DIR *dirp;
+ struct direct *dp;
+
+ dirp = opendir(dir);
+ if (dirp == NULL)
+ return;
+ while ((dp = readdir(dirp)) != NULL) {
+ if (itsit(cp, dp->d_name)) {
+ count++;
+ if (print)
+ printf(" %s/%s", dir, dp->d_name);
+ }
+ }
+ closedir(dirp);
+}
+
+itsit(cp, dp)
+ register char *cp, *dp;
+{
+ register int i = strlen(dp);
+
+ if (dp[0] == 's' && dp[1] == '.' && itsit(cp, dp+2))
+ return (1);
+ while (*cp && *dp && *cp == *dp)
+ cp++, dp++, i--;
+ if (*cp == 0 && *dp == 0)
+ return (1);
+ while (isdigit(*dp))
+ dp++;
+ if (*cp == 0 && *dp++ == '.') {
+ --i;
+ while (i > 0 && *dp)
+ if (--i, *dp++ == '.')
+ return (*dp++ == 'C' && *dp++ == 0);
+ return (1);
+ }
+ return (0);
+}
diff --git a/misc-utils/write.1 b/misc-utils/write.1
new file mode 100644
index 000000000..5125e156b
--- /dev/null
+++ b/misc-utils/write.1
@@ -0,0 +1,110 @@
+.\" Copyright (c) 1989 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
+.\"
+.\" 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.
+.\"
+.\" @(#)write.1 6.5 (Berkeley) 4/24/91
+.\"
+.\" Modified for Linux, Mon Mar 8 18:22:44 1993, faith@cs.unc.edu
+.\"
+.Dd March 8, 1993
+.Dt WRITE 1
+.Os "Linux 0.99"
+.Sh NAME
+.Nm write
+.Nd send a message to another user
+.Sh SYNOPSIS
+.Nm write
+.Ar user
+.Op Ar ttyname
+.Sh DESCRIPTION
+.Nm Write
+allows you to communicate with other users, by copying lines from
+your terminal to theirs.
+.Pp
+When you run the
+.Nm write
+command, the user you are writing to gets a message of the form:
+.Pp
+.Dl Message from yourname@yourhost on yourtty at hh:mm ...
+.Pp
+Any further lines you enter will be copied to the specified user's
+terminal.
+If the other user wants to reply, they must run
+.Nm write
+as well.
+.Pp
+When you are done, type an end-of-file or interrupt character.
+The other user will see the message
+.Ql EOF
+indicating that the
+conversation is over.
+.Pp
+You can prevent people (other than the super-user) from writing to you
+with the
+.Xr mesg 1
+command.
+Some commands, for example
+.Xr nroff 1
+and
+.Xr pr 1 ,
+disallow writing automatically, so that your output isn't overwritten.
+.Pp
+If the user you want to write to is logged in on more than one terminal,
+you can specify which terminal to write to by specifying the terminal
+name as the second operand to the
+.Nm write
+command.
+Alternatively, you can let
+.Nm write
+select one of the terminals \- it will pick the one with the shortest
+idle time.
+This is so that if the user is logged in at work and also dialed up from
+home, the message will go to the right place.
+.Pp
+The traditional protocol for writing to someone is that the string
+.Ql \-o ,
+either at the end of a line or on a line by itself, means that it's the
+other person's turn to talk.
+The string
+.Ql oo
+means that the person believes the conversation to be
+over.
+.Sh SEE ALSO
+.Xr mesg 1 ,
+.Xr talk 1 ,
+.Xr who 1
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
diff --git a/misc-utils/write.c b/misc-utils/write.c
new file mode 100644
index 000000000..f2fe4a086
--- /dev/null
+++ b/misc-utils/write.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
+ *
+ * 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.
+ *
+ * Modified for Linux, Mon Mar 8 18:16:24 1993, faith@cs.unc.edu
+ * Wed Jun 22 21:41:56 1994, faith@cs.unc.edu:
+ * Added fix from Mike Grupenhoff (kashmir@umiacs.umd.edu)
+ *
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)write.c 4.22 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <utmp.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef __linux__
+#include <paths.h>
+#endif
+
+extern int errno;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register char *cp;
+ time_t atime;
+ uid_t myuid;
+ int msgsok, myttyfd;
+ char tty[MAXPATHLEN], *mytty, *ttyname();
+ void done();
+
+ /* check that sender has write enabled */
+ if (isatty(fileno(stdin)))
+ myttyfd = fileno(stdin);
+ else if (isatty(fileno(stdout)))
+ myttyfd = fileno(stdout);
+ else if (isatty(fileno(stderr)))
+ myttyfd = fileno(stderr);
+ else {
+ (void)fprintf(stderr, "write: can't find your tty\n");
+ exit(1);
+ }
+ if (!(mytty = ttyname(myttyfd))) {
+ (void)fprintf(stderr, "write: can't find your tty's name\n");
+ exit(1);
+ }
+ if (cp = rindex(mytty, '/'))
+ mytty = cp + 1;
+ if (term_chk(mytty, &msgsok, &atime, 1))
+ exit(1);
+ if (!msgsok) {
+ (void)fprintf(stderr,
+ "write: you have write permission turned off.\n");
+ exit(1);
+ }
+
+ myuid = getuid();
+
+ /* check args */
+ switch (argc) {
+ case 2:
+ search_utmp(argv[1], tty, mytty, myuid);
+ do_write(tty, mytty, myuid);
+ break;
+ case 3:
+ if (!strncmp(argv[2], "/dev/", 5))
+ argv[2] += 5;
+ if (utmp_chk(argv[1], argv[2])) {
+ (void)fprintf(stderr,
+ "write: %s is not logged in on %s.\n",
+ argv[1], argv[2]);
+ exit(1);
+ }
+ if (term_chk(argv[2], &msgsok, &atime, 1))
+ exit(1);
+ if (myuid && !msgsok) {
+ (void)fprintf(stderr,
+ "write: %s has messages disabled on %s\n",
+ argv[1], argv[2]);
+ exit(1);
+ }
+ do_write(argv[2], mytty, myuid);
+ break;
+ default:
+ (void)fprintf(stderr, "usage: write user [tty]\n");
+ exit(1);
+ }
+ done();
+ /* NOTREACHED */
+}
+
+/*
+ * utmp_chk - checks that the given user is actually logged in on
+ * the given tty
+ */
+utmp_chk(user, tty)
+ char *user, *tty;
+{
+ struct utmp u;
+ int ufd;
+
+ if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
+ return(0); /* ignore error, shouldn't happen anyway */
+
+ while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
+ if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
+ strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
+ (void)close(ufd);
+ return(0);
+ }
+
+ (void)close(ufd);
+ return(1);
+}
+
+/*
+ * search_utmp - search utmp for the "best" terminal to write to
+ *
+ * Ignores terminals with messages disabled, and of the rest, returns
+ * the one with the most recent access time. Returns as value the number
+ * of the user's terminals with messages enabled, or -1 if the user is
+ * not logged in at all.
+ *
+ * Special case for writing to yourself - ignore the terminal you're
+ * writing from, unless that's the only terminal with messages enabled.
+ */
+search_utmp(user, tty, mytty, myuid)
+ char *user, *tty, *mytty;
+ uid_t myuid;
+{
+ struct utmp u;
+ time_t bestatime, atime;
+ int ufd, nloggedttys, nttys, msgsok, user_is_me;
+#ifdef __linux__
+ char atty[sizeof(u.ut_line) + 1];
+#else
+ char atty[UT_LINESIZE + 1];
+#endif
+
+ if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
+ perror("utmp");
+ exit(1);
+ }
+
+ nloggedttys = nttys = 0;
+ bestatime = 0;
+ user_is_me = 0;
+ while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
+ if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
+ ++nloggedttys;
+#ifdef __linux__
+ (void)strncpy(atty, u.ut_line, sizeof(u.ut_line));
+ atty[sizeof(u.ut_line)] = '\0';
+#else
+ (void)strncpy(atty, u.ut_line, UT_LINESIZE);
+ atty[UT_LINESIZE] = '\0';
+#endif
+ if (term_chk(atty, &msgsok, &atime, 0))
+ continue; /* bad term? skip */
+ if (myuid && !msgsok)
+ continue; /* skip ttys with msgs off */
+ if (strcmp(atty, mytty) == 0) {
+ user_is_me = 1;
+ continue; /* don't write to yourself */
+ }
+#ifdef __linux__
+ if (u.ut_type != USER_PROCESS)
+ continue; /* it's not a valid entry */
+#endif
+ ++nttys;
+ if (atime > bestatime) {
+ bestatime = atime;
+ (void)strcpy(tty, atty);
+ }
+ }
+
+ (void)close(ufd);
+ if (nloggedttys == 0) {
+ (void)fprintf(stderr, "write: %s is not logged in\n", user);
+ exit(1);
+ }
+ if (nttys == 0) {
+ if (user_is_me) { /* ok, so write to yourself! */
+ (void)strcpy(tty, mytty);
+ return;
+ }
+ (void)fprintf(stderr,
+ "write: %s has messages disabled\n", user);
+ exit(1);
+ } else if (nttys > 1) {
+ (void)fprintf(stderr,
+ "write: %s is logged in more than once; writing to %s\n",
+ user, tty);
+ }
+}
+
+/*
+ * term_chk - check that a terminal exists, and get the message bit
+ * and the access time
+ */
+term_chk(tty, msgsokP, atimeP, showerror)
+ char *tty;
+ int *msgsokP, showerror;
+ time_t *atimeP;
+{
+ struct stat s;
+ char path[MAXPATHLEN];
+
+ (void)sprintf(path, "/dev/%s", tty);
+ if (stat(path, &s) < 0) {
+ if (showerror)
+ (void)fprintf(stderr,
+ "write: %s: %s\n", path, strerror(errno));
+ return(1);
+ }
+ *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
+ *atimeP = s.st_atime;
+ return(0);
+}
+
+/*
+ * do_write - actually make the connection
+ */
+do_write(tty, mytty, myuid)
+ char *tty, *mytty;
+ uid_t myuid;
+{
+ register char *login, *nows;
+ register struct passwd *pwd;
+ time_t now, time();
+ char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
+ void done();
+
+ /* Determine our login name before the we reopen() stdout */
+ if ((login = getlogin()) == NULL)
+ if (pwd = getpwuid(myuid))
+ login = pwd->pw_name;
+ else
+ login = "???";
+
+ (void)sprintf(path, "/dev/%s", tty);
+ if ((freopen(path, "w", stdout)) == NULL) {
+ (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
+ exit(1);
+ }
+
+ (void)signal(SIGINT, done);
+ (void)signal(SIGHUP, done);
+
+ /* print greeting */
+ if (gethostname(host, sizeof(host)) < 0)
+ (void)strcpy(host, "???");
+ now = time((time_t *)NULL);
+ nows = ctime(&now);
+ nows[16] = '\0';
+ (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
+ login, host, mytty, nows + 11);
+
+ while (fgets(line, sizeof(line), stdin) != NULL)
+ wr_fputs(line);
+}
+
+/*
+ * done - cleanup and exit
+ */
+void
+done()
+{
+ (void)printf("EOF\r\n");
+ exit(0);
+}
+
+/*
+ * wr_fputs - like fputs(), but makes control characters visible and
+ * turns \n into \r\n
+ */
+wr_fputs(s)
+ register char *s;
+{
+ register char c;
+
+#define PUTC(c) if (putchar(c) == EOF) goto err;
+
+ for (; *s != '\0'; ++s) {
+ c = toascii(*s);
+ if (c == '\n') {
+ PUTC('\r');
+ PUTC('\n');
+ } else if (!isprint(c) && !isspace(c) && c != '\007') {
+ PUTC('^');
+ PUTC(c^0x40); /* DEL to ?, others to alpha */
+ } else
+ PUTC(c);
+ }
+ return;
+
+err: (void)fprintf(stderr, "write: %s\n", strerror(errno));
+ exit(1);
+#undef PUTC
+}