wall: add --group option
The wall command on AIX supports a "-g" option to limit the message to a group of users by gid. Add compatibility to the Linux version. Thanks to Sami Kerola <kerolasa@iki.fi> for an initial skeleton implementation. [kzak@redhat.com: - rename max to ngroups - add free_group_workspace() - some cosmetic changes] Reference: http://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.cmds6/wall.htm Signed-off-by: Jim Patterson <jimp@wegrok.net> Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
3fcbd79789
commit
01544c52f8
|
@ -9,6 +9,10 @@ _wall_module()
|
||||||
COMPREPLY=( $(compgen -W "seconds" -- $cur) )
|
COMPREPLY=( $(compgen -W "seconds" -- $cur) )
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
'-g'|'--group')
|
||||||
|
COMPREPLY=( $(compgen -A 'group' -- $cur) )
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
'-h'|'--help'|'-V'|'--version')
|
'-h'|'--help'|'-V'|'--version')
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -39,6 +39,8 @@ wall \- write a message to all users
|
||||||
.RB [ \-n ]
|
.RB [ \-n ]
|
||||||
.RB [ \-t
|
.RB [ \-t
|
||||||
.IR timeout ]
|
.IR timeout ]
|
||||||
|
.RB [ \-g
|
||||||
|
.IR group ]
|
||||||
.RI [ message " | " file ]
|
.RI [ message " | " file ]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.B wall
|
.B wall
|
||||||
|
@ -68,6 +70,11 @@ This \fItimeout\fR must be a positive integer. The default value
|
||||||
is 300 seconds, which is a legacy from the time when people ran terminals over
|
is 300 seconds, which is a legacy from the time when people ran terminals over
|
||||||
modem lines.
|
modem lines.
|
||||||
.TP
|
.TP
|
||||||
|
.BR \-g , " \-\-group " \fIgroup\fR
|
||||||
|
Limit printing message to members of group defined as a
|
||||||
|
.I group
|
||||||
|
argument. The argument can be group name or gid.
|
||||||
|
.TP
|
||||||
.BR \-V , " \-\-version"
|
.BR \-V , " \-\-version"
|
||||||
Display version information and exit.
|
Display version information and exit.
|
||||||
.TP
|
.TP
|
||||||
|
|
|
@ -58,6 +58,9 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <utmp.h>
|
#include <utmp.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <linux/sysctl.h>
|
||||||
|
|
||||||
#include "nls.h"
|
#include "nls.h"
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
@ -86,6 +89,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
|
||||||
fputs(_("Write a message to all users.\n"), out);
|
fputs(_("Write a message to all users.\n"), out);
|
||||||
|
|
||||||
fputs(USAGE_OPTIONS, out);
|
fputs(USAGE_OPTIONS, out);
|
||||||
|
fputs(_(" -g, --group <group> only send message to group\n"), out);
|
||||||
fputs(_(" -n, --nobanner do not print banner, works only for root\n"), out);
|
fputs(_(" -n, --nobanner do not print banner, works only for root\n"), out);
|
||||||
fputs(_(" -t, --timeout <timeout> write timeout in seconds\n"), out);
|
fputs(_(" -t, --timeout <timeout> write timeout in seconds\n"), out);
|
||||||
fputs(USAGE_SEPARATOR, out);
|
fputs(USAGE_SEPARATOR, out);
|
||||||
|
@ -96,6 +100,67 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
|
||||||
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct group_workspace {
|
||||||
|
gid_t requested_group;
|
||||||
|
int ngroups;
|
||||||
|
gid_t *groups;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gid_t get_group_gid(const char *optarg)
|
||||||
|
{
|
||||||
|
struct group *gr;
|
||||||
|
|
||||||
|
if ((gr = getgrnam(optarg)))
|
||||||
|
return gr->gr_gid;
|
||||||
|
return strtou64_or_err(optarg, _("invalid group argument"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct group_workspace *init_group_workspace(const char *optarg)
|
||||||
|
{
|
||||||
|
struct group_workspace *buf = xmalloc(sizeof(struct group_workspace));
|
||||||
|
|
||||||
|
buf->requested_group = get_group_gid(optarg);
|
||||||
|
buf->ngroups = sysconf(_SC_NGROUPS_MAX) + 1; /* room for the primary gid */
|
||||||
|
buf->groups = xcalloc(sizeof(gid_t), buf->ngroups);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_group_workspace(struct group_workspace *buf)
|
||||||
|
{
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(buf->groups);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_gr_member(const char *login, const struct group_workspace *buf)
|
||||||
|
{
|
||||||
|
struct passwd *pw;
|
||||||
|
int ngroups = buf->ngroups;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pw = getpwnam(login);
|
||||||
|
if (buf->requested_group == pw->pw_gid)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
rc = getgrouplist(login, pw->pw_gid, buf->groups, &ngroups);
|
||||||
|
if (rc < 0) {
|
||||||
|
/* buffer too small, not sure how this can happen, since
|
||||||
|
we used sysconf to get the size... */
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
_("getgrouplist found more groups than sysconf allows"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; ngroups >= 0; --ngroups) {
|
||||||
|
if (buf->requested_group == buf->groups[ngroups])
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
|
@ -104,6 +169,7 @@ int main(int argc, char **argv)
|
||||||
char *p;
|
char *p;
|
||||||
char line[sizeof(utmpptr->ut_line) + 1];
|
char line[sizeof(utmpptr->ut_line) + 1];
|
||||||
int print_banner = TRUE;
|
int print_banner = TRUE;
|
||||||
|
struct group_workspace *group_buf = NULL;
|
||||||
char *mbuf, *fname = NULL;
|
char *mbuf, *fname = NULL;
|
||||||
size_t mbufsize;
|
size_t mbufsize;
|
||||||
unsigned timeout = WRITE_TIME_OUT;
|
unsigned timeout = WRITE_TIME_OUT;
|
||||||
|
@ -113,6 +179,7 @@ int main(int argc, char **argv)
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{ "nobanner", no_argument, 0, 'n' },
|
{ "nobanner", no_argument, 0, 'n' },
|
||||||
{ "timeout", required_argument, 0, 't' },
|
{ "timeout", required_argument, 0, 't' },
|
||||||
|
{ "group", required_argument, 0, 'g' },
|
||||||
{ "version", no_argument, 0, 'V' },
|
{ "version", no_argument, 0, 'V' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
|
@ -123,7 +190,7 @@ int main(int argc, char **argv)
|
||||||
textdomain(PACKAGE);
|
textdomain(PACKAGE);
|
||||||
atexit(close_stdout);
|
atexit(close_stdout);
|
||||||
|
|
||||||
while ((ch = getopt_long(argc, argv, "nt:Vh", longopts, NULL)) != -1) {
|
while ((ch = getopt_long(argc, argv, "nt:g:Vh", longopts, NULL)) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
if (geteuid() == 0)
|
if (geteuid() == 0)
|
||||||
|
@ -136,6 +203,9 @@ int main(int argc, char **argv)
|
||||||
if (timeout < 1)
|
if (timeout < 1)
|
||||||
errx(EXIT_FAILURE, _("invalid timeout argument: %s"), optarg);
|
errx(EXIT_FAILURE, _("invalid timeout argument: %s"), optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'g':
|
||||||
|
group_buf = init_group_workspace(optarg);
|
||||||
|
break;
|
||||||
case 'V':
|
case 'V':
|
||||||
printf(UTIL_LINUX_VERSION);
|
printf(UTIL_LINUX_VERSION);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
@ -172,12 +242,16 @@ int main(int argc, char **argv)
|
||||||
if (utmpptr->ut_line[0] == ':')
|
if (utmpptr->ut_line[0] == ':')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (group_buf && !is_gr_member(utmpptr->ut_user, group_buf))
|
||||||
|
continue;
|
||||||
|
|
||||||
xstrncpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line));
|
xstrncpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line));
|
||||||
if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
|
if ((p = ttymsg(&iov, 1, line, timeout)) != NULL)
|
||||||
warnx("%s", p);
|
warnx("%s", p);
|
||||||
}
|
}
|
||||||
endutent();
|
endutent();
|
||||||
free(mbuf);
|
free(mbuf);
|
||||||
|
free_group_workspace(group_buf);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue