Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ss/ss.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1990-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* ss - list local network system status
26
*/
27
28
static const char usage[] =
29
"[-?\n@(#)$Id: ss (AT&T Research) 1995-05-09 $\n]"
30
USAGE_LICENSE
31
"[+NAME?ss - list local network system status]"
32
"[+DESCRIPTION?\bss\b writes the system status of hosts on the local network"
33
" to the standard output. The option order determines the listing sort"
34
" keys, from left to right, hightest to lowest precedence. If one or"
35
" more \ahost\a operands are given then only the status to those hosts"
36
" is listed, otherwise the status for all hosts on the local network is"
37
" listed.]"
38
"[+?Static information for hosts in the local network is in the file"
39
" \b../share/lib/cs/local\b on \b$PATH\b; see \bcs\b(1) for details."
40
" Dynamic status for each active host is maintained in the file"
41
" \b../share/lib/ss/\b\ahost\a by a status daemon \assd\a running on"
42
" each host. This information is updated once a minute, plus or minus"
43
" a random part of a minute. \bss\b starts an \bssd\bs as necessary. An"
44
" \bssd\b may be killed by removing the corresponding host status file.]"
45
46
"[c:cpu?Sort by cpu utilization.]"
47
"[i:idle?Sort by user idle time.]"
48
"[l:load?Sort by load average.]"
49
"[r:reverse?Reverse the sort order.]"
50
"[t:time?Sort by system up time.]"
51
"[u:users?Sort by number of active users.]"
52
53
"\n"
54
"\n[ host ... ]\n"
55
"\n"
56
57
"[+FILES]{"
58
" [+../share/lib/cs/local?Local host info list on \b$PATH\b.]"
59
" [+../share/lib/ss/\ahost\a?Host status files on \b$PATH\b.]"
60
"}"
61
62
"[+SEE ALSO?\bcs\b(1)]"
63
;
64
65
#include <ast.h>
66
#include <cs.h>
67
#include <dirent.h>
68
#include <error.h>
69
70
#define CPU 1
71
#define IDLE 2
72
#define LOAD 3
73
#define TIME 4
74
#define USERS 5
75
76
#define KEYS 4
77
#define SHIFT 3
78
79
#define SORT ((1<<SHIFT)-1)
80
#define MASK ((1<<(KEYS*SHIFT))-1)
81
82
typedef struct
83
{
84
char* name;
85
char* fail;
86
CSSTAT stat;
87
} Sys_t;
88
89
static struct
90
{
91
Sys_t** base;
92
Sys_t** end;
93
Sys_t** next;
94
int keys;
95
int rev;
96
} state;
97
98
99
/*
100
* enter system name into the system vector
101
* alloc!=0 allocate space for name
102
*/
103
104
static void
105
enter(char* name, int alloc)
106
{
107
register int n;
108
register Sys_t* sp;
109
110
if (state.next >= state.end)
111
{
112
n = state.end - state.base;
113
if (!(state.base = newof(state.base, Sys_t*, n * 2, 0)))
114
error(3, "out of space [vec %s]", n * 2);
115
state.end = (state.next = state.base + n) + n;
116
}
117
if (!(*state.next = newof(0, Sys_t, 1, 0)))
118
error(3, "out of space [sys]");
119
sp = *state.next++;
120
if (!alloc) sp->name = name;
121
else if (!(sp->name = strdup(name)))
122
error(3, "out of space [name]");
123
if (!csaddr(sp->name))
124
sp->fail = "*unknown host*";
125
else if (csstat(sp->name, &sp->stat))
126
sp->fail = "*no status*";
127
}
128
129
/*
130
* sys sort
131
*/
132
133
static int
134
sort(const char* pa, const char* pb)
135
{
136
register Sys_t* a = (Sys_t*)pa;
137
register Sys_t* b = (Sys_t*)pb;
138
register int k;
139
register long n;
140
141
for (k = state.keys; k; k >>= SHIFT)
142
switch (k & SORT)
143
{
144
case CPU:
145
if (n = (a->stat.pctusr + a->stat.pctsys) - (b->stat.pctusr + b->stat.pctsys))
146
return(n * state.rev);
147
break;
148
case IDLE:
149
if (a->stat.idle < b->stat.idle)
150
return(state.rev);
151
if (a->stat.idle > b->stat.idle)
152
return(-state.rev);
153
break;
154
case LOAD:
155
if (a->stat.load < b->stat.load)
156
return(-state.rev);
157
if (a->stat.load > b->stat.load)
158
return(state.rev);
159
break;
160
case TIME:
161
if (a->stat.up < b->stat.up)
162
return(state.rev);
163
if (a->stat.up > b->stat.up)
164
return(-state.rev);
165
break;
166
case USERS:
167
if (n = a->stat.users - b->stat.users)
168
return(n * state.rev);
169
break;
170
}
171
return strcoll(a->name, b->name) * state.rev;
172
}
173
174
int
175
main(int argc, char** argv)
176
{
177
register Sys_t* sp;
178
register Sys_t** sv;
179
register struct dirent* entry;
180
int n;
181
DIR* dirp;
182
char buf[PATH_MAX];
183
184
NoP(argc);
185
setlocale(LC_ALL, "");
186
error_info.id = "ss";
187
state.rev = 1;
188
while (n = optget(argv, usage))
189
{
190
switch (n)
191
{
192
case 'c':
193
n = CPU;
194
break;
195
case 'i':
196
n = IDLE;
197
break;
198
case 'l':
199
n = LOAD;
200
break;
201
case 'r':
202
state.rev = -state.rev;
203
continue;
204
case 't':
205
n = TIME;
206
break;
207
case 'u':
208
n = USERS;
209
break;
210
case '?':
211
error(ERROR_USAGE|4, "%s", opt_info.arg);
212
continue;
213
case ':':
214
error(2, "%s", opt_info.arg);
215
continue;
216
}
217
state.keys = (state.keys >> SHIFT) | (n << (SHIFT*(KEYS-1)));
218
}
219
if (error_info.errors)
220
error(ERROR_USAGE|4, "%s", optusage(NiL));
221
if (state.keys)
222
while (!(state.keys & SORT))
223
state.keys >>= SHIFT;
224
if (!pathpath(CS_STAT_DIR, argv[0], PATH_EXECUTE, buf, sizeof(buf)))
225
error(3, "%s: cannot find data directory", CS_STAT_DIR);
226
if (!(state.next = state.base = newof(0, Sys_t*, n = 64, 0)))
227
error(3, "out of space [vec %d]", n);
228
state.end = state.base + n;
229
if (*(argv += opt_info.index))
230
while (*argv)
231
enter(*argv++, 0);
232
else if (!(dirp = opendir(buf)))
233
error(ERROR_SYSTEM|3, "%s: cannot open", buf);
234
else
235
{
236
while (entry = readdir(dirp))
237
if (entry->d_name[0] != '.' && !streq(entry->d_name, "core"))
238
enter(entry->d_name, 1);
239
closedir(dirp);
240
}
241
if (n = state.next - state.base)
242
{
243
strsort((char**)state.base, n, sort);
244
for (sv = state.base; sv < state.next; sv++)
245
if ((sp = *sv)->fail)
246
sfprintf(sfstdout, "%-12s %s\n", sp->name, sp->fail);
247
else
248
sfprintf(sfstdout, "%-12s%4s%7s,%3d user%s idle%7s, load%3d.%02d, %%usr%3d, %%sys%3d\n", sp->name, sp->stat.up < 0 ? "down" : "up", fmtelapsed(sp->stat.up < 0 ? -sp->stat.up : sp->stat.up, 1), sp->stat.users, sp->stat.users == 1 ? ", " : "s,", sp->stat.idle > sp->stat.up ? "%" : fmtelapsed(sp->stat.idle, 1), sp->stat.load / 100, sp->stat.load % 100, sp->stat.pctusr, sp->stat.pctsys);
249
}
250
return error_info.errors != 0;
251
}
252
253