write.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <utmpx.h>
#include <pwd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <locale.h>
#include <stdlib.h>
#include <limits.h>
#include <wctype.h>
#include <errno.h>
#include <syslog.h>
#define TRUE 1
#define FALSE 0
#define FAILURE -1
#define DATE_FMT "%a %b %e %H:%M:%S"
#define UTMP_HACK /* work around until utmpx is world writable */
/*
* DATE-TIME format
* %a abbreviated weekday name
* %b abbreviated month name
* %e day of month
* %H hour - 24 hour clock
* %M minute
* %S second
*
*/
static int permit1(int);
static int permit(char *);
static int readcsi(int, char *, int);
static void setsignals();
static void shellcmd(char *);
static void openfail();
static void eof();
static char *thissys;
int
{
int i;
"/dev/";
extern char *rterm, *receipient;
short count;
char *ptr;
char time_buf[40];
int bad = 0;
char *bp;
int n;
int c;
int newline;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case '?':
gettext("user_name [terminal]"));
exit(2);
}
/* Set "rterm" to location where receipient's terminal will go. */
if (--argc <= 0) {
gettext("user_name [terminal]"));
exit(1);
}
else
{
receipient = *++argv;
}
/* Was a terminal name supplied? If so, save it. */
if (--argc > 1) {
gettext("user_name [terminal]"));
exit(1);
} else {
}
/* One of the standard file descriptors must be attached to a */
/* terminal in "/dev". */
gettext("I cannot determine your terminal name."
" No reply possible.\n"));
ownterminal = "/dev/???";
}
/*
* Set "ownterminal" past the "/dev/" at the beginning of
* the device name.
*/
/*
* Scan through the "utmpx" file for your own entry and the
* entry for the person we want to send to.
*/
/* Is this a USER_PROCESS entry? */
/* Is it our entry? (ie. The line matches ours?) */
/* Is this the person we want to send to? */
/* If a terminal name was supplied, is this login at the correct */
/* terminal? If not, ignore. If it is right place, copy over the */
/* name. */
bad++;
rterm[0] = '\0';
}
}
}
/* If no terminal was supplied, then take this terminal if no */
/* other terminal has been encountered already. */
else
{
/* If this is the first encounter, copy the string into */
/* "rterminal". */
if (*rterm == '\0') {
if (bad < 20) {
}
rterm[0] = '\0';
} else if (bad > 0) {
"%s is logged on more than one place.\n"
"You are connected to \"%s\".\nOther locations are:\n"),
receipient, rterm);
for (i = 0; i < bad; i++)
}
}
/* If this is the second terminal, print out the first. In all */
/* cases of multiple terminals, list out all the other terminals */
"%s is logged on more than one place.\n"
"You are connected to \"%s\".\nOther locations are:\n"),
receipient, rterm);
}
1, stderr);
}
count++;
} /* End of "else" */
} /* End of "else if (strncmp" */
} /* End of "if (USER_PROCESS" */
} /* End of "for(count=0" */
/* Did we find a place to talk to? If we were looking for a */
/* specific spot and didn't find it, complain and quit. */
if (bad > 0) {
exit(1);
} else {
#ifdef UTMP_HACK
sizeof (rterminal)) {
gettext("Terminal name too long.\n"));
exit(1);
}
gettext("Cannot determine who you are.\n"));
exit(1);
}
sizeof (ownname));
} else {
}
exit(1);
}
#else
exit(1);
#endif /* UTMP_HACK */
}
}
/* If we were just looking for anyplace to talk and didn't find */
/* one, complain and quit. */
/* If permissions prevent us from sending to this person - exit */
else if (*rterm == '\0') {
if (bad > 0)
else
exit(1);
}
/* Did we find our own entry? */
/* Use the user id instead of utmp name if the entry in the */
/* utmp file couldn't be found. */
gettext("Cannot determine who you are.\n"));
exit(1);
}
}
else
{
}
if (!permit1(1))
gettext("Warning: You have your terminal set to \"mesg -n\"."
" No reply possible.\n"));
/* Close the utmpx files. */
endutxent();
/* Try to open up the line to the receipient's terminal. */
alarm(5);
alarm(0);
/* Make sure executed subshell doesn't inherit this fd - close-on-exec */
perror("fcntl(F_SETFD)");
exit(1);
}
/* Catch signals SIGHUP, SIGINT, SIGQUIT, and SIGTERM, and send */
/* <EOT> message to receipient before dying away. */
/* Get the time of day, convert it to a string and throw away the */
/* year information at the end of the string. */
gettext("\n\007\007\007\tMessage from %s on %s (%s) [ %s ] ...\n"),
/* Get input from user and send to receipient unless it begins */
/* with a !, when it is to be a shell command. */
newline = 1;
/* Is this a shell command? */
/* Send line to the receipient. */
else {
break;
}
/*
* All non-printable characters are displayed using a special notation:
* Control characters shall be displayed using the two character
* sequence of ^ (carat) and the ASCII character - decimal 64 greater
* that the character being encoded - eg., a \003 is displayed ^C.
* Characters with the eighth bit set shall be displayed using
* the three or four character meta notation - e.g., \372 is
* displayed M-z and \203 is displayed M-^C.
*/
newline = 0;
if (*bp == '\n') {
newline = 1;
}
if (*bp == ' ' ||
*bp == '\007') {
for (; n > 0; --n, --i, ++bp)
bp--, ++i;
} else {
}
/* add decimal 64 to the control character */
}
else
}
if (*bp == '\n')
"\n\007Write failed (%s logged out?)\n"),
exit(1);
}
} /* for */
} /* else */
} /* while */
/* Since "end of file" received, send <EOT> message to receipient. */
eof();
return (0);
}
static void
void (*catch)();
{
}
static void
char *command;
{
extern void eof();
{
gettext("Unable to fork. Try again later.\n"));
return;
/* Reset the signals to the default actions and exec a shell. */
exit(1);
exit(0);
}
else
{
/* Allow user to type <del> and <quit> without dying during */
/* commands. */
/* As parent wait around for user to finish spunoff command. */
/* Reset the signals to their normal state. */
}
}
static void
openfail()
{
extern char *rterm, *receipient;
gettext("Timeout trying to open %s's line(%s).\n"),
receipient, rterm);
exit(1);
}
static void
eof()
{
exit(0);
}
/*
* permit: check mode of terminal - if not writable by all disallow writing to
*/
static int
char *term;
{
int fildes;
return (0);
/* check if the device really is a tty */
closelog();
return (0);
}
}
/*
* permit1: check mode of terminal - if not writable by all disallow writing
*/
/* this is used with fstat (which is faster than stat) where possible */
static int
int fildes;
{
}
/*
* Read a string of multi-byte characters from specified file.
* The requested # of bytes are attempted to read.
* readcsi() tries to complete the last multibyte character
* by calling mbtowc(), if the leftovers form mbtowc(),
* left the last char imcomplete, moves into delta_spool to use later,
* next called. The caller must reserve
* nbytereq+MB_LEN_MAX bytes for the buffer. When the attempt
* is failed, it truncate the last char.
* Returns the number of bytes that constitutes the valid multi-byte characters.
*/
int d;
char *buf;
int nbytereq;
{
static char delta_size;
int n;
int r_size;
if (delta_size) {
} else {
}
r_size = 0;
if ((n = delta_size + r_size) <= 0)
return (n);
/* Scan the result to test the completeness of each EUC characters. */
n = (unsigned int)MB_CUR_MAX;
break;
n = 1;
}
nextp += n;
}
/* How many bytes needed to complete the last char? */
if (delta_size > 0) {
/* the remnants store into delta_pool */
} else
}
*nextp = '\0';
}