xref: /illumos-gate/usr/src/cmd/wall/wall.c (revision 1eabc4bec6d2a5ad71f6a1f0c019af5438d8b1bf)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
237c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * Copyright 1988-2003 Sun Microsystems, Inc.  All rights reserved.
297c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
32de6baaf5SJohn Sonnenschein /*
33de6baaf5SJohn Sonnenschein  * Copyright 2012 Joyent, Inc. All rights reserved.
340a1278f2SGary Mills  *
350a1278f2SGary Mills  * Copyright (c) 2013 Gary Mills
36de6baaf5SJohn Sonnenschein  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <signal.h>
397c478bd9Sstevel@tonic-gate #include <stdio.h>
40de6baaf5SJohn Sonnenschein #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <grp.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <unistd.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <ctype.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <utmpx.h>
487c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
497c478bd9Sstevel@tonic-gate #include <dirent.h>
507c478bd9Sstevel@tonic-gate #include <pwd.h>
517c478bd9Sstevel@tonic-gate #include <fcntl.h>
527c478bd9Sstevel@tonic-gate #include <time.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <locale.h>
557c478bd9Sstevel@tonic-gate #include <syslog.h>
567c478bd9Sstevel@tonic-gate #include <sys/wait.h>
577c478bd9Sstevel@tonic-gate #include <limits.h>
58de6baaf5SJohn Sonnenschein #include <libzonecfg.h>
59de6baaf5SJohn Sonnenschein #include <zone.h>
60de6baaf5SJohn Sonnenschein #include <sys/contract/process.h>
61de6baaf5SJohn Sonnenschein #include <libcontract.h>
62de6baaf5SJohn Sonnenschein #include <sys/ctfs.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
650a1278f2SGary Mills  * Use the full lengths from utmpx for user and line.
667c478bd9Sstevel@tonic-gate  */
670a1278f2SGary Mills #define	NMAX	(sizeof (((struct utmpx *)0)->ut_user))
680a1278f2SGary Mills #define	LMAX	(sizeof (((struct utmpx *)0)->ut_line))
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static char	mesg[3000];
717c478bd9Sstevel@tonic-gate static char	*infile;
727c478bd9Sstevel@tonic-gate static int	gflag;
737c478bd9Sstevel@tonic-gate static struct	group *pgrp;
747c478bd9Sstevel@tonic-gate static char	*grpname;
757c478bd9Sstevel@tonic-gate static char	line[MAXNAMLEN+1] = "???";
767c478bd9Sstevel@tonic-gate static char	systm[MAXNAMLEN+1];
777c478bd9Sstevel@tonic-gate static time_t	tloc;
787c478bd9Sstevel@tonic-gate static struct	utsname utsn;
790a1278f2SGary Mills static char	who[NMAX+1]	= "???";
807c478bd9Sstevel@tonic-gate static char	time_buf[50];
817c478bd9Sstevel@tonic-gate #define	DATE_FMT	"%a %b %e %H:%M:%S"
827c478bd9Sstevel@tonic-gate 
83de6baaf5SJohn Sonnenschein static void sendmes(struct utmpx *, zoneid_t);
84de6baaf5SJohn Sonnenschein static void sendmes_tozone(zoneid_t, int);
857c478bd9Sstevel@tonic-gate static int chkgrp(char *);
867c478bd9Sstevel@tonic-gate static char *copy_str_till(char *, char *, char, int);
877c478bd9Sstevel@tonic-gate 
88de6baaf5SJohn Sonnenschein static int init_template(void);
89de6baaf5SJohn Sonnenschein int contract_abandon_id(ctid_t);
90de6baaf5SJohn Sonnenschein 
917c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])927c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	FILE	*f;
957c478bd9Sstevel@tonic-gate 	char	*ptr, *start;
967c478bd9Sstevel@tonic-gate 	struct	passwd *pwd;
977c478bd9Sstevel@tonic-gate 	char	*term_name;
987c478bd9Sstevel@tonic-gate 	int	c;
997c478bd9Sstevel@tonic-gate 	int	aflag = 0;
1007c478bd9Sstevel@tonic-gate 	int	errflg = 0;
101de6baaf5SJohn Sonnenschein 	int zflg = 0;
102de6baaf5SJohn Sonnenschein 	int Zflg = 0;
103de6baaf5SJohn Sonnenschein 
104de6baaf5SJohn Sonnenschein 	char *zonename = NULL;
105de6baaf5SJohn Sonnenschein 	zoneid_t *zoneidlist = NULL;
106de6baaf5SJohn Sonnenschein 	uint_t nzids_saved, nzids = 0;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1097c478bd9Sstevel@tonic-gate 
110de6baaf5SJohn Sonnenschein 	while ((c = getopt(argc, argv, "g:az:Z")) != EOF)
1117c478bd9Sstevel@tonic-gate 		switch (c) {
1127c478bd9Sstevel@tonic-gate 		case 'a':
1137c478bd9Sstevel@tonic-gate 			aflag++;
1147c478bd9Sstevel@tonic-gate 			break;
1157c478bd9Sstevel@tonic-gate 		case 'g':
1167c478bd9Sstevel@tonic-gate 			if (gflag) {
1177c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
1187c478bd9Sstevel@tonic-gate 				    "Only one group allowed\n");
119de6baaf5SJohn Sonnenschein 				return (1);
1207c478bd9Sstevel@tonic-gate 			}
1217c478bd9Sstevel@tonic-gate 			if ((pgrp = getgrnam(grpname = optarg)) == NULL) {
1227c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "Unknown group %s\n",
1237c478bd9Sstevel@tonic-gate 				    grpname);
124de6baaf5SJohn Sonnenschein 				return (1);
1257c478bd9Sstevel@tonic-gate 			}
1267c478bd9Sstevel@tonic-gate 			gflag++;
1277c478bd9Sstevel@tonic-gate 			break;
128de6baaf5SJohn Sonnenschein 		case 'z':
129de6baaf5SJohn Sonnenschein 			zflg++;
130de6baaf5SJohn Sonnenschein 			zonename = optarg;
131de6baaf5SJohn Sonnenschein 			if (getzoneidbyname(zonename) == -1) {
132de6baaf5SJohn Sonnenschein 				(void) fprintf(stderr, "Specified zone %s "
133de6baaf5SJohn Sonnenschein 				    "is invalid", zonename);
134de6baaf5SJohn Sonnenschein 				return (1);
135de6baaf5SJohn Sonnenschein 			}
136de6baaf5SJohn Sonnenschein 			break;
137de6baaf5SJohn Sonnenschein 		case 'Z':
138de6baaf5SJohn Sonnenschein 			Zflg++;
139de6baaf5SJohn Sonnenschein 			break;
1407c478bd9Sstevel@tonic-gate 		case '?':
1417c478bd9Sstevel@tonic-gate 			errflg++;
1427c478bd9Sstevel@tonic-gate 			break;
1437c478bd9Sstevel@tonic-gate 		}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (errflg) {
1467c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
147de6baaf5SJohn Sonnenschein 		    "Usage: wall [-a] [-g group] [-z zone] [-Z] [files...]\n");
148de6baaf5SJohn Sonnenschein 		return (1);
149de6baaf5SJohn Sonnenschein 	}
150de6baaf5SJohn Sonnenschein 
151de6baaf5SJohn Sonnenschein 	if (zflg && Zflg) {
152de6baaf5SJohn Sonnenschein 		(void) fprintf(stderr, "Cannot use -z with -Z\n");
1537c478bd9Sstevel@tonic-gate 		return (1);
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if (optind < argc)
1577c478bd9Sstevel@tonic-gate 		infile = argv[optind];
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (uname(&utsn) == -1) {
1607c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "wall: uname() failed, %s\n",
1617c478bd9Sstevel@tonic-gate 		    strerror(errno));
162de6baaf5SJohn Sonnenschein 		return (2);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	(void) strcpy(systm, utsn.nodename);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/*
1677c478bd9Sstevel@tonic-gate 	 * Get the name of the terminal wall is running from.
1687c478bd9Sstevel@tonic-gate 	 */
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((term_name = ttyname(fileno(stderr))) != NULL) {
1717c478bd9Sstevel@tonic-gate 		/*
1727c478bd9Sstevel@tonic-gate 		 * skip the leading "/dev/" in term_name
1737c478bd9Sstevel@tonic-gate 		 */
1747c478bd9Sstevel@tonic-gate 		(void) strncpy(line, &term_name[5], sizeof (line) - 1);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	if (who[0] == '?') {
1787c478bd9Sstevel@tonic-gate 		if (pwd = getpwuid(getuid()))
1797c478bd9Sstevel@tonic-gate 			(void) strncpy(&who[0], pwd->pw_name, sizeof (who));
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	f = stdin;
1837c478bd9Sstevel@tonic-gate 	if (infile) {
1847c478bd9Sstevel@tonic-gate 		f = fopen(infile, "r");
1857c478bd9Sstevel@tonic-gate 		if (f == NULL) {
1867c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "Cannot open %s\n", infile);
187de6baaf5SJohn Sonnenschein 			return (1);
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	start = &mesg[0];
1927c478bd9Sstevel@tonic-gate 	ptr = start;
1937c478bd9Sstevel@tonic-gate 	while ((ptr - start) < 3000) {
1947c478bd9Sstevel@tonic-gate 		size_t n;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 		if (fgets(ptr, &mesg[sizeof (mesg)] - ptr, f) == NULL)
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		if ((n = strlen(ptr)) == 0)
1997c478bd9Sstevel@tonic-gate 			break;
2007c478bd9Sstevel@tonic-gate 		ptr += n;
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 	(void) fclose(f);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	/*
2057c478bd9Sstevel@tonic-gate 	 * If the request is from the rwall daemon then use the caller's
2067c478bd9Sstevel@tonic-gate 	 * name and host.  We determine this if all of the following is true:
2077c478bd9Sstevel@tonic-gate 	 *	1) First 5 characters are "From "
2087c478bd9Sstevel@tonic-gate 	 *	2) Next non-white characters are of the form "name@host:"
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	if (strcmp(line, "???") == 0) {
2117c478bd9Sstevel@tonic-gate 		char rwho[MAXNAMLEN+1];
2127c478bd9Sstevel@tonic-gate 		char rsystm[MAXNAMLEN+1];
2137c478bd9Sstevel@tonic-gate 		char *cp;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 		if (strncmp(mesg, "From ", 5) == 0) {
2167c478bd9Sstevel@tonic-gate 			cp = &mesg[5];
2177c478bd9Sstevel@tonic-gate 			cp = copy_str_till(rwho, cp, '@', MAXNAMLEN + 1);
2187c478bd9Sstevel@tonic-gate 			if (rwho[0] != '\0') {
2197c478bd9Sstevel@tonic-gate 				cp = copy_str_till(rsystm, ++cp, ':',
2207c478bd9Sstevel@tonic-gate 				    MAXNAMLEN + 1);
2217c478bd9Sstevel@tonic-gate 				if (rsystm[0] != '\0') {
2227c478bd9Sstevel@tonic-gate 					(void) strcpy(systm, rsystm);
2230a1278f2SGary Mills 					(void) strncpy(rwho, who,
2240a1278f2SGary Mills 					    sizeof (who));
2257c478bd9Sstevel@tonic-gate 					(void) strcpy(line, "rpc.rwalld");
2267c478bd9Sstevel@tonic-gate 				}
2277c478bd9Sstevel@tonic-gate 			}
2287c478bd9Sstevel@tonic-gate 		}
2297c478bd9Sstevel@tonic-gate 	}
2307c478bd9Sstevel@tonic-gate 	(void) time(&tloc);
2317c478bd9Sstevel@tonic-gate 	(void) strftime(time_buf, sizeof (time_buf),
2327c478bd9Sstevel@tonic-gate 	    DATE_FMT, localtime(&tloc));
2337c478bd9Sstevel@tonic-gate 
234de6baaf5SJohn Sonnenschein 	if (zflg != 0) {
235de6baaf5SJohn Sonnenschein 		if ((zoneidlist =
236de6baaf5SJohn Sonnenschein 		    malloc(sizeof (zoneid_t))) == NULL ||
237de6baaf5SJohn Sonnenschein 		    (*zoneidlist = getzoneidbyname(zonename)) == -1)
238de6baaf5SJohn Sonnenschein 			return (errno);
239de6baaf5SJohn Sonnenschein 		nzids = 1;
240de6baaf5SJohn Sonnenschein 	} else if (Zflg != 0) {
241de6baaf5SJohn Sonnenschein 		if (zone_list(NULL, &nzids) != 0)
242de6baaf5SJohn Sonnenschein 			return (errno);
243de6baaf5SJohn Sonnenschein again:
244de6baaf5SJohn Sonnenschein 		nzids *= 2;
245de6baaf5SJohn Sonnenschein 		if ((zoneidlist = malloc(nzids * sizeof (zoneid_t))) == NULL)
246de6baaf5SJohn Sonnenschein 			exit(errno);
247de6baaf5SJohn Sonnenschein 		nzids_saved = nzids;
248de6baaf5SJohn Sonnenschein 		if (zone_list(zoneidlist, &nzids) != 0) {
249de6baaf5SJohn Sonnenschein 			(void) free(zoneidlist);
250de6baaf5SJohn Sonnenschein 			return (errno);
2517c478bd9Sstevel@tonic-gate 		}
252de6baaf5SJohn Sonnenschein 		if (nzids > nzids_saved) {
253de6baaf5SJohn Sonnenschein 			free(zoneidlist);
254de6baaf5SJohn Sonnenschein 			goto again;
255de6baaf5SJohn Sonnenschein 		}
256de6baaf5SJohn Sonnenschein 	}
257de6baaf5SJohn Sonnenschein 	if (zflg || Zflg) {
258de6baaf5SJohn Sonnenschein 		for (; nzids > 0; --nzids)
259de6baaf5SJohn Sonnenschein 			sendmes_tozone(zoneidlist[nzids-1], aflag);
260de6baaf5SJohn Sonnenschein 		free(zoneidlist);
261de6baaf5SJohn Sonnenschein 	} else
262de6baaf5SJohn Sonnenschein 		sendmes_tozone(getzoneid(), aflag);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	return (0);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /*
2687c478bd9Sstevel@tonic-gate  * Copy src to destination upto but not including the delim.
2697c478bd9Sstevel@tonic-gate  * Leave dst empty if delim not found or whitespace encountered.
2707c478bd9Sstevel@tonic-gate  * Return pointer to next character (delim, whitespace, or '\0')
2717c478bd9Sstevel@tonic-gate  */
2727c478bd9Sstevel@tonic-gate static char *
copy_str_till(char * dst,char * src,char delim,int len)2737c478bd9Sstevel@tonic-gate copy_str_till(char *dst, char *src, char delim, int len)
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	int i = 0;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	while (*src != '\0' && i < len) {
2787c478bd9Sstevel@tonic-gate 		if (isspace(*src)) {
2797c478bd9Sstevel@tonic-gate 			dst[0] = '\0';
2807c478bd9Sstevel@tonic-gate 			return (src);
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 		if (*src == delim) {
2837c478bd9Sstevel@tonic-gate 			dst[i] = '\0';
2847c478bd9Sstevel@tonic-gate 			return (src);
2857c478bd9Sstevel@tonic-gate 		}
2867c478bd9Sstevel@tonic-gate 		dst[i++] = *src++;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	dst[0] = '\0';
2897c478bd9Sstevel@tonic-gate 	return (src);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
292de6baaf5SJohn Sonnenschein static void
sendmes_tozone(zoneid_t zid,int aflag)293de6baaf5SJohn Sonnenschein sendmes_tozone(zoneid_t zid, int aflag) {
294de6baaf5SJohn Sonnenschein 	int i = 0;
295de6baaf5SJohn Sonnenschein 	char zonename[ZONENAME_MAX], root[MAXPATHLEN];
296de6baaf5SJohn Sonnenschein 	struct utmpx *p;
297de6baaf5SJohn Sonnenschein 
298de6baaf5SJohn Sonnenschein 	if (zid != getzoneid()) {
299de6baaf5SJohn Sonnenschein 		root[0] = '\0';
300de6baaf5SJohn Sonnenschein 		(void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
301de6baaf5SJohn Sonnenschein 		(void) zone_get_rootpath(zonename, root, sizeof (root));
302de6baaf5SJohn Sonnenschein 		(void) strlcat(root, UTMPX_FILE, sizeof (root));
303de6baaf5SJohn Sonnenschein 		if (!utmpxname(root)) {
304de6baaf5SJohn Sonnenschein 			(void) fprintf(stderr, "Cannot open %s\n", root);
305de6baaf5SJohn Sonnenschein 			return;
306de6baaf5SJohn Sonnenschein 		}
307de6baaf5SJohn Sonnenschein 	} else {
308de6baaf5SJohn Sonnenschein 		(void) utmpxname(UTMPX_FILE);
309de6baaf5SJohn Sonnenschein 	}
310de6baaf5SJohn Sonnenschein 	setutxent();
311de6baaf5SJohn Sonnenschein 	while ((p = getutxent()) != NULL) {
312de6baaf5SJohn Sonnenschein 		if (p->ut_type != USER_PROCESS)
313de6baaf5SJohn Sonnenschein 			continue;
314de6baaf5SJohn Sonnenschein 		/*
315de6baaf5SJohn Sonnenschein 		 * if (-a option OR NOT pty window login), send the message
316de6baaf5SJohn Sonnenschein 		 */
317*1eabc4beSSachidananda Urs 		if (aflag || !nonuserx(*p))
318de6baaf5SJohn Sonnenschein 			sendmes(p, zid);
319de6baaf5SJohn Sonnenschein 	}
320de6baaf5SJohn Sonnenschein 	endutxent();
321de6baaf5SJohn Sonnenschein 
322de6baaf5SJohn Sonnenschein 	(void) alarm(60);
323de6baaf5SJohn Sonnenschein 	do {
324de6baaf5SJohn Sonnenschein 		i = (int)wait((int *)0);
325de6baaf5SJohn Sonnenschein 	} while (i != -1 || errno != ECHILD);
326de6baaf5SJohn Sonnenschein 
327de6baaf5SJohn Sonnenschein }
328de6baaf5SJohn Sonnenschein 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * Note to future maintainers: with the change of wall to use the
3317c478bd9Sstevel@tonic-gate  * getutxent() API, the forked children (created by this function)
3327c478bd9Sstevel@tonic-gate  * must call _exit as opposed to exit. This is necessary to avoid
3337c478bd9Sstevel@tonic-gate  * unwanted fflushing of getutxent's stdio stream (caused by atexit
3347c478bd9Sstevel@tonic-gate  * processing).
3357c478bd9Sstevel@tonic-gate  */
3367c478bd9Sstevel@tonic-gate static void
sendmes(struct utmpx * p,zoneid_t zid)337de6baaf5SJohn Sonnenschein sendmes(struct utmpx *p, zoneid_t zid)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	int i;
3407c478bd9Sstevel@tonic-gate 	char *s;
3417c478bd9Sstevel@tonic-gate 	static char device[LMAX + 6];
3427c478bd9Sstevel@tonic-gate 	char *bp;
3437c478bd9Sstevel@tonic-gate 	int ibp;
3447c478bd9Sstevel@tonic-gate 	FILE *f;
345de6baaf5SJohn Sonnenschein 	int fd, tmpl_fd;
346de6baaf5SJohn Sonnenschein 	boolean_t zoneenter = B_FALSE;
3477c478bd9Sstevel@tonic-gate 
348de6baaf5SJohn Sonnenschein 	if (zid != getzoneid()) {
349de6baaf5SJohn Sonnenschein 		zoneenter = B_TRUE;
350de6baaf5SJohn Sonnenschein 		tmpl_fd = init_template();
351de6baaf5SJohn Sonnenschein 		if (tmpl_fd == -1) {
352de6baaf5SJohn Sonnenschein 			(void) fprintf(stderr, "Could not initialize "
353de6baaf5SJohn Sonnenschein 			    "process contract");
3547c478bd9Sstevel@tonic-gate 			return;
355de6baaf5SJohn Sonnenschein 		}
356de6baaf5SJohn Sonnenschein 	}
357de6baaf5SJohn Sonnenschein 
3587c478bd9Sstevel@tonic-gate 	while ((i = (int)fork()) == -1) {
3597c478bd9Sstevel@tonic-gate 		(void) alarm(60);
3607c478bd9Sstevel@tonic-gate 		(void) wait((int *)0);
3617c478bd9Sstevel@tonic-gate 		(void) alarm(0);
3627c478bd9Sstevel@tonic-gate 	}
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (i)
3657c478bd9Sstevel@tonic-gate 		return;
3667c478bd9Sstevel@tonic-gate 
367de6baaf5SJohn Sonnenschein 	if (zoneenter && zone_enter(zid) == -1) {
368de6baaf5SJohn Sonnenschein 		char zonename[ZONENAME_MAX];
369de6baaf5SJohn Sonnenschein 		(void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
370de6baaf5SJohn Sonnenschein 		(void) fprintf(stderr, "Could not enter zone "
371de6baaf5SJohn Sonnenschein 		    "%s\n", zonename);
372de6baaf5SJohn Sonnenschein 	}
373de6baaf5SJohn Sonnenschein 	if (zoneenter)
374de6baaf5SJohn Sonnenschein 		(void) ct_tmpl_clear(tmpl_fd);
375de6baaf5SJohn Sonnenschein 
376de6baaf5SJohn Sonnenschein 	if (gflag)
377de6baaf5SJohn Sonnenschein 		if (!chkgrp(p->ut_user))
378de6baaf5SJohn Sonnenschein 			_exit(0);
379de6baaf5SJohn Sonnenschein 
3807c478bd9Sstevel@tonic-gate 	(void) signal(SIGHUP, SIG_IGN);
3817c478bd9Sstevel@tonic-gate 	(void) alarm(60);
3827c478bd9Sstevel@tonic-gate 	s = &device[0];
3837c478bd9Sstevel@tonic-gate 	(void) snprintf(s, sizeof (device), "/dev/%.*s", LMAX, p->ut_line);
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* check if the device is really a tty */
3867c478bd9Sstevel@tonic-gate 	if ((fd = open(s, O_WRONLY|O_NOCTTY|O_NONBLOCK)) == -1) {
3877c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot send to %.*s on %s\n",
3887c478bd9Sstevel@tonic-gate 		    NMAX, p->ut_user, s);
3897c478bd9Sstevel@tonic-gate 		perror("open");
3907c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
3917c478bd9Sstevel@tonic-gate 		_exit(1);
3927c478bd9Sstevel@tonic-gate 	} else {
3937c478bd9Sstevel@tonic-gate 		if (!isatty(fd)) {
3947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
3957c478bd9Sstevel@tonic-gate 			    "Cannot send to device %.*s %s\n",
3967c478bd9Sstevel@tonic-gate 			    LMAX, p->ut_line,
3977c478bd9Sstevel@tonic-gate 			    "because it's not a tty");
3987c478bd9Sstevel@tonic-gate 			openlog("wall", 0, LOG_AUTH);
3997c478bd9Sstevel@tonic-gate 			syslog(LOG_CRIT, "%.*s in utmpx is not a tty\n",
4007c478bd9Sstevel@tonic-gate 			    LMAX, p->ut_line);
4017c478bd9Sstevel@tonic-gate 			closelog();
4027c478bd9Sstevel@tonic-gate 			(void) fflush(stderr);
4037c478bd9Sstevel@tonic-gate 			_exit(1);
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate #ifdef DEBUG
4077c478bd9Sstevel@tonic-gate 	(void) close(fd);
4087c478bd9Sstevel@tonic-gate 	f = fopen("wall.debug", "a");
4097c478bd9Sstevel@tonic-gate #else
4107c478bd9Sstevel@tonic-gate 	f = fdopen(fd, "w");
4117c478bd9Sstevel@tonic-gate #endif
4127c478bd9Sstevel@tonic-gate 	if (f == NULL) {
4137c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot send to %-.*s on %s\n",
4147c478bd9Sstevel@tonic-gate 		    NMAX, &p->ut_user[0], s);
4157c478bd9Sstevel@tonic-gate 		perror("open");
4167c478bd9Sstevel@tonic-gate 		(void) fflush(stderr);
4177c478bd9Sstevel@tonic-gate 		_exit(1);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 	(void) fprintf(f,
4207c478bd9Sstevel@tonic-gate 	    "\07\07\07Broadcast Message from %s (%s) on %s %19.19s",
4217c478bd9Sstevel@tonic-gate 	    who, line, systm, time_buf);
4227c478bd9Sstevel@tonic-gate 	if (gflag)
4237c478bd9Sstevel@tonic-gate 		(void) fprintf(f, " to group %s", grpname);
4247c478bd9Sstevel@tonic-gate 	(void) fprintf(f, "...\n");
4257c478bd9Sstevel@tonic-gate #ifdef DEBUG
4260a1278f2SGary Mills 	(void) fprintf(f, "DEBUG: To %.*s on %s\n", NMAX, p->ut_user, s);
4277c478bd9Sstevel@tonic-gate #endif
4287c478bd9Sstevel@tonic-gate 	i = strlen(mesg);
4297c478bd9Sstevel@tonic-gate 	for (bp = mesg; --i >= 0; bp++) {
4307c478bd9Sstevel@tonic-gate 		ibp = (unsigned int)((unsigned char) *bp);
4317c478bd9Sstevel@tonic-gate 		if (*bp == '\n')
4327c478bd9Sstevel@tonic-gate 			(void) putc('\r', f);
4337c478bd9Sstevel@tonic-gate 		if (isprint(ibp) || *bp == '\r' || *bp == '\013' ||
4347c478bd9Sstevel@tonic-gate 		    *bp == ' ' || *bp == '\t' || *bp == '\n' || *bp == '\007') {
4357c478bd9Sstevel@tonic-gate 			(void) putc(*bp, f);
4367c478bd9Sstevel@tonic-gate 		} else {
4377c478bd9Sstevel@tonic-gate 			if (!isascii(*bp)) {
4387c478bd9Sstevel@tonic-gate 				(void) fputs("M-", f);
4397c478bd9Sstevel@tonic-gate 				*bp = toascii(*bp);
4407c478bd9Sstevel@tonic-gate 			}
4417c478bd9Sstevel@tonic-gate 			if (iscntrl(*bp)) {
4427c478bd9Sstevel@tonic-gate 				(void) putc('^', f);
4437c478bd9Sstevel@tonic-gate 				(void) putc(*bp + 0100, f);
4447c478bd9Sstevel@tonic-gate 			}
4457c478bd9Sstevel@tonic-gate 			else
4467c478bd9Sstevel@tonic-gate 				(void) putc(*bp, f);
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		if (*bp == '\n')
4507c478bd9Sstevel@tonic-gate 			(void) fflush(f);
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		if (ferror(f) || feof(f)) {
4537c478bd9Sstevel@tonic-gate 			(void) printf("\n\007Write failed\n");
4547c478bd9Sstevel@tonic-gate 			(void) fflush(stdout);
4557c478bd9Sstevel@tonic-gate 			_exit(1);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 	(void) fclose(f);
4597c478bd9Sstevel@tonic-gate 	(void) close(fd);
4607c478bd9Sstevel@tonic-gate 	_exit(0);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static int
chkgrp(char * name)4657c478bd9Sstevel@tonic-gate chkgrp(char *name)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	int i;
4680a1278f2SGary Mills 	char user[NMAX + 1];
4697c478bd9Sstevel@tonic-gate 
4700a1278f2SGary Mills 	(void) strlcpy(user, name, sizeof (user));
4717c478bd9Sstevel@tonic-gate 	for (i = 0; pgrp->gr_mem[i] && pgrp->gr_mem[i][0]; i++) {
4720a1278f2SGary Mills 		if (strcmp(user, pgrp->gr_mem[i]) == 0)
4737c478bd9Sstevel@tonic-gate 			return (1);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (0);
4777c478bd9Sstevel@tonic-gate }
478de6baaf5SJohn Sonnenschein 
479de6baaf5SJohn Sonnenschein static int
init_template(void)480de6baaf5SJohn Sonnenschein init_template(void) {
481de6baaf5SJohn Sonnenschein 	int fd = 0;
482de6baaf5SJohn Sonnenschein 	int err = 0;
483de6baaf5SJohn Sonnenschein 
484de6baaf5SJohn Sonnenschein 	fd = open64(CTFS_ROOT "/process/template", O_RDWR);
485de6baaf5SJohn Sonnenschein 	if (fd == -1)
486de6baaf5SJohn Sonnenschein 		return (-1);
487de6baaf5SJohn Sonnenschein 
488de6baaf5SJohn Sonnenschein 	err |= ct_tmpl_set_critical(fd, 0);
489de6baaf5SJohn Sonnenschein 	err |= ct_tmpl_set_informative(fd, 0);
490de6baaf5SJohn Sonnenschein 	err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
491de6baaf5SJohn Sonnenschein 	err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
492de6baaf5SJohn Sonnenschein 	if (err || ct_tmpl_activate(fd)) {
493de6baaf5SJohn Sonnenschein 		(void) close(fd);
494de6baaf5SJohn Sonnenschein 		return (-1);
495de6baaf5SJohn Sonnenschein 	}
496de6baaf5SJohn Sonnenschein 
497de6baaf5SJohn Sonnenschein 	return (fd);
498de6baaf5SJohn Sonnenschein }
499