diff options
author | Karel Zak | 2006-12-07 00:25:32 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:32 +0100 |
commit | 6dbe3af945a63f025561abb83275cee9ff06c57b (patch) | |
tree | 19e59eac8ac465b5bc409b5adf815b582c92f633 /misc-utils | |
download | kernel-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')
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 +} |