cs.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1990-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* cs - connect stream control
*/
static const char usage[] =
"[-?\n@(#)$Id: cs (AT&T Research) 2006-06-11 $\n]"
"[+NAME?cs - connect stream control]"
"[+DESCRIPTION?\bcs\b displays, initiates, and terminates connect stream"
" services, and displays the contents of connect stream message files."
" If no options are spcified then the connect stream for \apath\a is"
" opened. If the corresponding service is not running then it is"
" initiated and the connection is attempted again. If \acommand\a is"
" specified then it is executed with the standard input, standard"
" output and standard error redirected to the \apath\a connect stream."
" the connect stream is listed on the standard output.]"
"[a:attribute?List the attribute \aname\a for each host. If \aname\a is \b-\b"
" then all attributes are listed. The hostname attribute is listed"
" without a label, all other attributes are listed as"
" \alabel\a=\avalue\a]:[name]"
"[c:cat?Catenate messages in the named \apath\a operands. If \apath\a is"
" omitted then the standard input is read.]"
"[d:debug?Set the debug trace level to \alevel\a. Higher levels produce"
" more output.]#[level]"
"[f:continuous?Used with \b--cat\b to list messages on a \apath\a or standard"
" input that is continuously updated.]"
"[h:hostenvironment?Lists \bHOSTNAME\b=\aname\a \bHOSTTYPE\b=\atype\a on the"
" standard output for the named \ahost\a operand or the local host if"
" \ahost\a is omitted. This is useful for \b.profile\b initialization.]"
"[i:interactive?Open an interactive connection to the connect stream. The"
" service is initiated if it is not already running.]"
"[k:kill?Send \asignal\a to the server on the connect stream named by"
" \apath\a. \asignal\a may be a signal name or signal number.]:[signal]"
"[l:list?List the active connect stream services on the standard output.]"
"[m:mount?List the active connect stream mount directories on the standard"
" output.]"
"[p:process?List the active connect stream process ids on the standard output.]"
"[q:query?Open an interactive connection to the connect stream if a service"
" is already running; fail otherwise.]"
"[r:raw?Raw mode \b--interactive\b connection.]"
"[s:iservice?List details for each active connect stream service on the"
" standard output. The output format is similar to an \bls\b(1)"
" \b--long\b listing, except the size field is the \btcp\b or \budp\b"
" port number, and the service base name appears as a symbolic link"
"[t:translate?\ahost\a name operands are translated to IP address dot notation"
" and listed on the standard output. If \ahost\a is omitted then the"
" standard input is read for host names, one per line.]"
"[C:call?Used with \b--cat\b to list only messages for the calls in"
" \acall-list\a.]:[call-list]"
"[O:open-flags?Set optional \bcsopen\b(3) flags. Used by the \bcs\b(3) library"
" to initiate remote connections.]:[flags]"
"[T:terse?Used with \b--cat\b to list terse messages for the calls in"
" \acall-list\a]:[call-list]"
"\n"
"\n[ [ - ] host | path [ command ... ] ]\n"
"\n"
"[+DATA?Static information for hosts in the local network is in the file"
" file provides information for a single host. The syntax is:"
" \ahost-name\a [ \aattribute\a=\avalue\a ... ]]. Attributes for the host"
" \blocal\b are inherited by all hosts. Locally administered attributes"
" may be added. \aattribute\a with predefined semantics are:]{"
" [+addr?The host IP address in dot notation.]"
" [+bias?The \bcoshell\b(1) multiplies the host load by \bbias\b"
" to prioritize host availability. \bbias\b > 1 makes"
" the host less likely to be chosen.]"
" [+busy?\bcoshell\b(1) jobs running on a host that has remained"
" busy for this amount of time are suspended until the"
" host returns to idle status.]"
" [+cpu?The number of cpus on the host as reported by"
" \bpackage\b(1).]"
" [+idle?The minimum interactive user idle time before"
" \bcoshell\b(1) will schedule a job on the host.]"
" [+pool?The \bcoshell\b(1) attempts to keep \bpool\b"
" host connections active.]"
" [+rating?The host rating as reported by \bpackage\b(1).]"
" [+type?The host type as reported by \bpackage\b(1).]"
"}"
"[+FILES]{"
"}"
"[+SEE ALSO?\bcoshell\b(1), \bcss\b(1), \bpackage\b(1), \bss\b(1), \bcs\b(3)]"
;
#include <ast.h>
#include <coshell.h>
#include <cs.h>
#include <error.h>
#include <ftwalk.h>
#include <msg.h>
#include <proc.h>
#include <sig.h>
#include <tm.h>
#include <tok.h>
#include <debug.h>
#define LIST (1<<0)
#define MSG_LIST (MSG_LIST_USER<<0)
static struct
{
int list; /* list flags */
char* local; /* csname(0) */
} state;
/*
* host address translation
*/
static void
{
unsigned long addr;
);
else
}
/*
* order by name
*/
static int
{
}
/*
* list the service mount directories
*/
#define PROC_OFF 4
#define SERVICE_COLS 37
static int
{
register char* s;
register char* t;
register char* u;
register char* p;
char* port;
char* proc;
int mode;
int n;
static char qual_buf[64];
static char time_buf[64];
{
{
{
s = qual_buf;
*s++ = '/';
*s = 0;
}
else
qual_buf[0] = 0;
*s = CS_MNT_PROCESS;
{
/*
* check for old single char cs mounts
*/
*(s + 1) = 0;
{
*s = CS_MNT_STREAM;
remove(p);
*(s + 1) = CS_MNT_TAIL[0];
remove(p);
return 0;
}
}
else
{
if (u = strchr(t, '/'))
{
*u = 0;
{
*u = '/';
u = 0;
}
else
*u = '/';
}
}
{
remove(p);
*s = CS_MNT_STREAM;
remove(p);
return 0;
}
{
*s = CS_MNT_STREAM;
port++;
else
port = "";
*s = CS_MNT_LOG;
*(s - 1) = 0;
sfprintf(sfstdout, "%c%s 1 %-8s %-8s %7s %s %s%s%s\n", label[0][0], fmtmode(mode, 0) + 1, fmtuid(st.st_uid), (mode & S_IROTH) ? "other" : fmtgid(ftw->statb.st_gid), port, time_buf, label[2], qual_buf, proc);
}
else
{
{
{
}
else
{
}
}
else
{
sfsprintf(port_buf, sizeof(port_buf) - 1, "%s/%s/%s/%s%s", CS_SVC_DIR, label[0], label[2], label[2], CS_SVC_SUFFIX);
if (!pathpath(port_buf, "", PATH_ABSOLUTE|PATH_EXECUTE, serv_buf, sizeof(serv_buf)) || stat(serv_buf, &st) || st.st_uid != uid)
}
if (qual_buf[0])
if (*label[0] == 't')
{
*s = CS_MNT_AUTH;
}
{
while (n++ < SERVICE_COLS)
{
*(s - 1) = 0;
}
{
*(s - 1) = 0;
}
}
}
}
else
{
s = "local";
}
}
return 0;
}
/*
* list messages in sp
* if continuous!=0 then act like tail -f
*/
static int
{
register long n;
if (flags & MSG_LIST_CONTINUOUS)
for (;;)
{
if (n < 0)
return -1;
if (!(flags & MSG_LIST_CONTINUOUS))
return 0;
sleep(2);
}
}
int
{
char** ap;
int n;
int fd;
int hostenv = 0;
int initiate = CS_OPEN_READ;
int interactive = 0;
int msg = 0;
int clientflags = 0;
int remote = 0;
int translate = 0;
unsigned long call = ~0;
unsigned long terse = 0;
char* attr = 0;
char* host;
char* path;
char* proc;
char* sig = 0;
char* av[8];
for (;;)
{
{
case 'a':
continue;
case 'c':
continue;
case 'd':
continue;
case 'f':
continue;
case 'h':
hostenv = 1;
continue;
case 'r':
/*FALLTHROUGH*/
case 'i':
interactive = 1;
msg |= MSG_LIST_ID;
continue;
case 'k':
continue;
case 'l':
continue;
case 'm':
continue;
case 'p':
continue;
case 'q':
interactive = 1;
initiate |= CS_OPEN_TEST;
continue;
case 's':
continue;
case 't':
translate = 1;
continue;
case 'C':
continue;
case 'T':
continue;
case 'O':
remote = 1;
for (;;)
{
switch (*host++)
{
case 0:
break;
case CS_REMOTE_OPEN_AGENT:
continue;
case CS_REMOTE_OPEN_LOCAL:
continue;
case CS_REMOTE_OPEN_NOW:
initiate |= CS_OPEN_NOW;
continue;
case CS_REMOTE_OPEN_READ:
continue;
case CS_REMOTE_OPEN_SHARE:
continue;
case CS_REMOTE_OPEN_TEST:
initiate |= CS_OPEN_TEST;
continue;
case CS_REMOTE_OPEN_TRUST:
continue;
default:
break;
}
break;
}
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
if (error_info.errors)
{
else if (*argv)
}
if (translate)
{
if (*argv)
else
{
}
return 0;
}
{
initiate |= CS_OPEN_TEST;
}
if (remote)
{
if (!path)
return 1;
if (initiate & CS_OPEN_AGENT)
{
register char* s = path;
register char* t = tmp;
register int n = 0;
/*
* get the unqualified-host connect stream path
*/
while (*t++ = *s)
switch (*s++)
{
case '/':
while (*s == '/')
s++;
n++;
break;
case '.':
if (n == 3)
for (t--; *s && *s != '/'; s++);
break;
}
}
return 1;
if (initiate & CS_OPEN_AGENT)
{
if (remote)
{
return 1;
}
}
}
else if (sig)
{
if (path)
{
do
{
{
continue;
}
else
{
{
continue;
}
host = 0;
{
continue;
}
}
{
*ap++ = CS_REMOTE_SHELL;
{
*ap++ = "-l";
}
}
*ap++ = "kill";
*ap = 0;
}
}
{
if (path)
*ap = 0;
}
else if (attr)
{
if (!path)
{
}
else
{
n = *argv != 0;
do
{
{
if (hostenv)
}
{
{
if (hostenv)
if (!terse)
}
else
}
else
}
return 0;
}
else if (hostenv)
{
return 0;
}
else if (path)
{
{
if (*argv)
else
{
}
}
else if (interactive)
else
{
if (*argv)
{
close(0);
close(1);
}
}
}
else if (interactive)
else
return error_info.errors != 0;
}