summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Sonnenschein <johns@joyent.com>2012-04-11 17:48:11 -0400
committerJohn Sonnenschein <johns@joyent.com>2012-04-11 17:48:11 -0400
commitde6baaf51812fba698b0a3cdfb5c6c0bf3d52960 (patch)
treeb38d68ca607ee60dc0af72825be97041db64ad20
parent89d19e002086cf26431426fe713cfef456067882 (diff)
downloadillumos-joyent-de6baaf51812fba698b0a3cdfb5c6c0bf3d52960.tar.gz
2443 wall(1) needs zones support
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Reviewed by: Joshua M. Clulow <josh@sysmgr.org> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Richard Lowe <richlowe@richlowe.net>
-rw-r--r--usr/src/cmd/wall/Makefile4
-rw-r--r--usr/src/cmd/wall/wall.c193
-rw-r--r--usr/src/man/man1m/wall.1m26
3 files changed, 187 insertions, 36 deletions
diff --git a/usr/src/cmd/wall/Makefile b/usr/src/cmd/wall/Makefile
index 193d5d0035..e338057768 100644
--- a/usr/src/cmd/wall/Makefile
+++ b/usr/src/cmd/wall/Makefile
@@ -21,6 +21,8 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2012 Joyent, Inc. All Rights Reserved.
+#
PROG= wall
@@ -28,6 +30,8 @@ include ../Makefile.cmd
FILEMODE = 02555
+LDLIBS += -lzonecfg -lcontract
+
.KEEP_STATE:
all: $(PROG)
diff --git a/usr/src/cmd/wall/wall.c b/usr/src/cmd/wall/wall.c
index e5b0d56554..64bb4f8918 100644
--- a/usr/src/cmd/wall/wall.c
+++ b/usr/src/cmd/wall/wall.c
@@ -29,14 +29,16 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2012 Joyent, Inc. All rights reserved.
+ */
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <grp.h>
#include <sys/types.h>
#include <unistd.h>
-#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
@@ -51,6 +53,11 @@
#include <syslog.h>
#include <sys/wait.h>
#include <limits.h>
+#include <libzonecfg.h>
+#include <zone.h>
+#include <sys/contract/process.h>
+#include <libcontract.h>
+#include <sys/ctfs.h>
/*
* utmpx defines wider fields for user and line. For compatibility of output,
@@ -79,15 +86,17 @@ static char who[9] = "???";
static char time_buf[50];
#define DATE_FMT "%a %b %e %H:%M:%S"
-static void sendmes(struct utmpx *);
+static void sendmes(struct utmpx *, zoneid_t);
+static void sendmes_tozone(zoneid_t, int);
static int chkgrp(char *);
static char *copy_str_till(char *, char *, char, int);
+static int init_template(void);
+int contract_abandon_id(ctid_t);
+
int
main(int argc, char *argv[])
{
- int i = 0;
- struct utmpx *p;
FILE *f;
char *ptr, *start;
struct passwd *pwd;
@@ -95,10 +104,16 @@ main(int argc, char *argv[])
int c;
int aflag = 0;
int errflg = 0;
+ int zflg = 0;
+ int Zflg = 0;
+
+ char *zonename = NULL;
+ zoneid_t *zoneidlist = NULL;
+ uint_t nzids_saved, nzids = 0;
(void) setlocale(LC_ALL, "");
- while ((c = getopt(argc, argv, "g:a")) != EOF)
+ while ((c = getopt(argc, argv, "g:az:Z")) != EOF)
switch (c) {
case 'a':
aflag++;
@@ -107,15 +122,27 @@ main(int argc, char *argv[])
if (gflag) {
(void) fprintf(stderr,
"Only one group allowed\n");
- exit(1);
+ return (1);
}
if ((pgrp = getgrnam(grpname = optarg)) == NULL) {
(void) fprintf(stderr, "Unknown group %s\n",
grpname);
- exit(1);
+ return (1);
}
gflag++;
break;
+ case 'z':
+ zflg++;
+ zonename = optarg;
+ if (getzoneidbyname(zonename) == -1) {
+ (void) fprintf(stderr, "Specified zone %s "
+ "is invalid", zonename);
+ return (1);
+ }
+ break;
+ case 'Z':
+ Zflg++;
+ break;
case '?':
errflg++;
break;
@@ -123,7 +150,12 @@ main(int argc, char *argv[])
if (errflg) {
(void) fprintf(stderr,
- "Usage: wall [-a] [-g group] [files...]\n");
+ "Usage: wall [-a] [-g group] [-z zone] [-Z] [files...]\n");
+ return (1);
+ }
+
+ if (zflg && Zflg) {
+ (void) fprintf(stderr, "Cannot use -z with -Z\n");
return (1);
}
@@ -133,7 +165,7 @@ main(int argc, char *argv[])
if (uname(&utsn) == -1) {
(void) fprintf(stderr, "wall: uname() failed, %s\n",
strerror(errno));
- exit(2);
+ return (2);
}
(void) strcpy(systm, utsn.nodename);
@@ -158,7 +190,7 @@ main(int argc, char *argv[])
f = fopen(infile, "r");
if (f == NULL) {
(void) fprintf(stderr, "Cannot open %s\n", infile);
- exit(1);
+ return (1);
}
}
@@ -202,24 +234,37 @@ main(int argc, char *argv[])
}
(void) time(&tloc);
(void) strftime(time_buf, sizeof (time_buf),
- DATE_FMT, localtime(&tloc));
-
- setutxent();
- while ((p = getutxent()) != NULL) {
- if (p->ut_type != USER_PROCESS)
- continue;
- /*
- * if (-a option OR NOT pty window login), send the message
- */
- if (aflag || !nonuser(*p))
- sendmes(p);
+ DATE_FMT, localtime(&tloc));
+
+ if (zflg != 0) {
+ if ((zoneidlist =
+ malloc(sizeof (zoneid_t))) == NULL ||
+ (*zoneidlist = getzoneidbyname(zonename)) == -1)
+ return (errno);
+ nzids = 1;
+ } else if (Zflg != 0) {
+ if (zone_list(NULL, &nzids) != 0)
+ return (errno);
+again:
+ nzids *= 2;
+ if ((zoneidlist = malloc(nzids * sizeof (zoneid_t))) == NULL)
+ exit(errno);
+ nzids_saved = nzids;
+ if (zone_list(zoneidlist, &nzids) != 0) {
+ (void) free(zoneidlist);
+ return (errno);
+ }
+ if (nzids > nzids_saved) {
+ free(zoneidlist);
+ goto again;
+ }
}
- endutxent();
-
- (void) alarm(60);
- do {
- i = (int)wait((int *)0);
- } while (i != -1 || errno != ECHILD);
+ if (zflg || Zflg) {
+ for (; nzids > 0; --nzids)
+ sendmes_tozone(zoneidlist[nzids-1], aflag);
+ free(zoneidlist);
+ } else
+ sendmes_tozone(getzoneid(), aflag);
return (0);
}
@@ -249,6 +294,43 @@ copy_str_till(char *dst, char *src, char delim, int len)
return (src);
}
+static void
+sendmes_tozone(zoneid_t zid, int aflag) {
+ int i = 0;
+ char zonename[ZONENAME_MAX], root[MAXPATHLEN];
+ struct utmpx *p;
+
+ if (zid != getzoneid()) {
+ root[0] = '\0';
+ (void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
+ (void) zone_get_rootpath(zonename, root, sizeof (root));
+ (void) strlcat(root, UTMPX_FILE, sizeof (root));
+ if (!utmpxname(root)) {
+ (void) fprintf(stderr, "Cannot open %s\n", root);
+ return;
+ }
+ } else {
+ (void) utmpxname(UTMPX_FILE);
+ }
+ setutxent();
+ while ((p = getutxent()) != NULL) {
+ if (p->ut_type != USER_PROCESS)
+ continue;
+ /*
+ * if (-a option OR NOT pty window login), send the message
+ */
+ if (aflag || !nonuser(*p))
+ sendmes(p, zid);
+ }
+ endutxent();
+
+ (void) alarm(60);
+ do {
+ i = (int)wait((int *)0);
+ } while (i != -1 || errno != ECHILD);
+
+}
+
/*
* Note to future maintainers: with the change of wall to use the
* getutxent() API, the forked children (created by this function)
@@ -257,7 +339,7 @@ copy_str_till(char *dst, char *src, char delim, int len)
* processing).
*/
static void
-sendmes(struct utmpx *p)
+sendmes(struct utmpx *p, zoneid_t zid)
{
int i;
char *s;
@@ -265,11 +347,19 @@ sendmes(struct utmpx *p)
char *bp;
int ibp;
FILE *f;
- int fd;
-
- if (gflag)
- if (!chkgrp(p->ut_user))
+ int fd, tmpl_fd;
+ boolean_t zoneenter = B_FALSE;
+
+ if (zid != getzoneid()) {
+ zoneenter = B_TRUE;
+ tmpl_fd = init_template();
+ if (tmpl_fd == -1) {
+ (void) fprintf(stderr, "Could not initialize "
+ "process contract");
return;
+ }
+ }
+
while ((i = (int)fork()) == -1) {
(void) alarm(60);
(void) wait((int *)0);
@@ -279,6 +369,19 @@ sendmes(struct utmpx *p)
if (i)
return;
+ if (zoneenter && zone_enter(zid) == -1) {
+ char zonename[ZONENAME_MAX];
+ (void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
+ (void) fprintf(stderr, "Could not enter zone "
+ "%s\n", zonename);
+ }
+ if (zoneenter)
+ (void) ct_tmpl_clear(tmpl_fd);
+
+ if (gflag)
+ if (!chkgrp(p->ut_user))
+ _exit(0);
+
(void) signal(SIGHUP, SIG_IGN);
(void) alarm(60);
s = &device[0];
@@ -370,7 +473,8 @@ chkgrp(char *name)
char *p;
for (i = 0; pgrp->gr_mem[i] && pgrp->gr_mem[i][0]; i++) {
- for (p = name; *p && *p != ' '; p++);
+ for (p = name; *p && *p != ' '; p++)
+ ;
*p = 0;
if (strncmp(name, pgrp->gr_mem[i], 8) == 0)
return (1);
@@ -378,3 +482,24 @@ chkgrp(char *name)
return (0);
}
+
+static int
+init_template(void) {
+ int fd = 0;
+ int err = 0;
+
+ fd = open64(CTFS_ROOT "/process/template", O_RDWR);
+ if (fd == -1)
+ return (-1);
+
+ err |= ct_tmpl_set_critical(fd, 0);
+ err |= ct_tmpl_set_informative(fd, 0);
+ err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
+ err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
+ if (err || ct_tmpl_activate(fd)) {
+ (void) close(fd);
+ return (-1);
+ }
+
+ return (fd);
+}
diff --git a/usr/src/man/man1m/wall.1m b/usr/src/man/man1m/wall.1m
index 3b6206d0b8..2f710329f7 100644
--- a/usr/src/man/man1m/wall.1m
+++ b/usr/src/man/man1m/wall.1m
@@ -1,4 +1,5 @@
'\" te
+.\" Copyright (c) 2012 Joyent, Inc. All Rights Reserved.
.\" Copyright (c) 2000 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 1989 AT&T
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
@@ -10,7 +11,7 @@ wall \- write to all users
.SH SYNOPSIS
.LP
.nf
-\fB/usr/sbin/wall\fR [\fB-a\fR] [\fB-g\fR \fIgrpname\fR] [\fIfilename\fR]
+\fB/usr/sbin/wall\fR [\fB-a\fR] [\fB-g\fR \fIgrpname\fR] [\fB-z\fR \fIzonename\fR] [\fB-Z\fR] [\fIfilename\fR]
.fi
.SH DESCRIPTION
@@ -31,7 +32,9 @@ If \fIfilename\fR is given, then the message is read in from that file.
Normally, pseudo-terminals that do not correspond to rlogin sessions are
ignored. Thus, when using a window system, the message appears only on the
console window. However, \fB-a\fR will send the message even to such
-pseudo-terminals.
+pseudo-terminals. Normally, \fBwall\fR sends messages to the current zone
+only, from the global zone \fB-Z\fR will send messages to all nonglobal zones,
+and \fB-z\fR will send messages to a specified nonglobal zone
.sp
.LP
It is used to warn all users, typically prior to shutting down the system.
@@ -73,6 +76,25 @@ Broadcast to the users in a specified group only, per the group database (see
\fBgroup\fR(4)).
.RE
+.sp
+.ne 2
+.na
+\fB\fB-\fR\fBz\fR \fIzonename\fR\fR
+.ad
+.RS 14n
+Broadcast to the users in a specified zone only
+.RE
+
+
+.sp
+.ne 2
+.na
+\fB\fB-Z\fR\fR
+.ad
+.RS 14n
+Broadcast message to the console and pseudo-terminals of all zones.
+.RE
+
.SH ENVIRONMENT VARIABLES
.sp
.LP