00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #include <sys/types.h>
00052 #include <signal.h>
00053 #include <string.h>
00054 #include <utmp.h>
00055 #include <time.h>
00056 #include <stdlib.h>
00057 #include <stdio.h>
00058 #include <errno.h>
00059
00060 #include <minix/paths.h>
00061
00062 #define FALSE 0
00063 #define TRUE 1
00064 #define RLOGIN 1
00065
00066 #define BUFFER_SIZE 4096
00067 #define MAX_WTMP_COUNT ( BUFFER_SIZE / sizeof(struct utmp) )
00068
00069 #define min( a, b ) ( (a < b) ? a : b )
00070 #define max( a, b ) ( (a > b) ? a : b )
00071
00072
00073 typedef struct logout {
00074 char line[12];
00075 long time;
00076 struct logout *next;
00077 } logout;
00078
00079
00080 static char *Version = "@(#) LAST 1.7 (10/24/92)";
00081
00082
00083
00084 char boot_limit = FALSE;
00085 char count_limit = FALSE;
00086 char tell_uptime = FALSE;
00087 int print_count;
00088 char *prog;
00089 int arg_count;
00090 char **args;
00091
00092
00093 long boot_time = 0;
00094 char *boot_down;
00095 logout *first_link = NULL;
00096 int interrupt = FALSE;
00097
00098 _PROTOTYPE(int main, (int argc, char **argv));
00099 _PROTOTYPE(void Sigint, (int sig));
00100 _PROTOTYPE(void Sigquit, (int sig));
00101 _PROTOTYPE(void usage, (void));
00102 _PROTOTYPE(void Process, (struct utmp *wtmp));
00103 _PROTOTYPE(int Print_Record, (struct utmp *wtmp));
00104 _PROTOTYPE(void Print_Duration, (long from, long to));
00105 _PROTOTYPE(void Print_Uptime, (void));
00106 _PROTOTYPE(void Record_Logout_Time, (struct utmp *wtmp));
00107
00108
00109 void Sigint(sig)
00110 int sig;
00111 {
00112 interrupt = SIGINT;
00113 }
00114
00115
00116 void Sigquit(sig)
00117 int sig;
00118 {
00119 interrupt = SIGQUIT;
00120 }
00121
00122
00123 void usage()
00124 {
00125 fprintf(stderr,
00126 "Usage: last [-r] [-u] [-count] [-f file] [name] [tty] ...\n");
00127 exit(-1);
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 void Process(wtmp)
00176 struct utmp *wtmp;
00177 {
00178 logout *link;
00179 logout *next_link;
00180 char is_reboot;
00181
00182
00183 if (!strncmp(wtmp->ut_line, "ftp", (size_t)3)) strncpy(wtmp->ut_line, "ftp", (size_t)8);
00184
00185 if (!strcmp(wtmp->ut_line, "~")) {
00186
00187 if (boot_limit) exit(0);
00188
00189 if (Print_Record(wtmp)) putchar('\n');
00190 boot_time = wtmp->ut_time;
00191
00192 is_reboot = !strcmp(wtmp->ut_name, "reboot");
00193 if (is_reboot)
00194 boot_down = "crash";
00195 else
00196 boot_down = "down ";
00197
00198 if (tell_uptime) {
00199 if (!is_reboot) {
00200 fprintf(stderr,
00201 "%s: no reboot record added to wtmp file on system boot!\n",
00202 prog);
00203 exit(1);
00204 }
00205 Print_Uptime();
00206 exit(0);
00207 }
00208
00209
00210 for (link = first_link; link != NULL; link = next_link) {
00211 next_link = link->next;
00212 free(link);
00213 }
00214 first_link = NULL;
00215 } else if (wtmp->ut_name[0] == '\0') {
00216
00217 Record_Logout_Time(wtmp);
00218 } else {
00219
00220 for (link = first_link; link != NULL; link = link->next)
00221 if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) {
00222
00223 if (Print_Record(wtmp)) {
00224 printf("- %.5s ", ctime(&link->time) + 11);
00225 Print_Duration(wtmp->ut_time, link->time);
00226 }
00227
00228 link->time = wtmp->ut_time;
00229 return;
00230 }
00231
00232 if (Print_Record(wtmp))
00233 if (boot_time == 0)
00234 printf(" still logged in\n");
00235 else {
00236 printf("- %s ", boot_down);
00237 Print_Duration(wtmp->ut_time, boot_time);
00238 }
00239 Record_Logout_Time(wtmp);
00240
00241 }
00242 }
00243
00244
00245
00246
00247
00248 int Print_Record(wtmp)
00249 struct utmp *wtmp;
00250 {
00251 int i;
00252 char print_flag = FALSE;
00253
00254
00255 if (tell_uptime) return(FALSE);
00256
00257
00258 if (count_limit && print_count == 0) exit(0);
00259
00260 for (i = 0; i < arg_count; ++i)
00261 if (!strncmp(args[i], wtmp->ut_name, sizeof(wtmp->ut_name)) ||
00262 !strncmp(args[i], wtmp->ut_line, sizeof(wtmp->ut_line)))
00263 print_flag = TRUE;
00264
00265 if (arg_count == 0 || print_flag) {
00266 #ifdef RLOGIN
00267 printf("%-8.8s %-8.8s %-16.16s %.16s ",
00268 wtmp->ut_name, wtmp->ut_line, wtmp->ut_host,
00269 ctime(&wtmp->ut_time));
00270 #else
00271 printf("%-8.8s %-8.8s %.16s ",
00272 wtmp->ut_name, wtmp->ut_line, ctime(&wtmp->ut_time));
00273 #endif
00274 --print_count;
00275 return(TRUE);
00276 }
00277 return(FALSE);
00278 }
00279
00280
00281
00282
00283
00284 void Print_Duration(from, to)
00285 long from;
00286 long to;
00287 {
00288 long delta, days, hours, minutes;
00289
00290 delta = max(to - from, 0);
00291 days = delta / (24L * 60L * 60L);
00292 delta = delta % (24L * 60L * 60L);
00293 hours = delta / (60L * 60L);
00294 delta = delta % (60L * 60L);
00295 minutes = delta / 60L;
00296
00297 if (days > 0)
00298 printf("(%ld+", days);
00299 else
00300 printf(" (");
00301
00302 printf("%02ld:%02ld)\n", hours, minutes);
00303 }
00304
00305
00306
00307
00308
00309 void Print_Uptime()
00310 {
00311 #define NLOADS 3
00312 int nloads;
00313 double loads[NLOADS];
00314 char *utmp_file = _PATH_UTMP;
00315 unsigned nusers;
00316 struct utmp ut;
00317 FILE *uf;
00318 time_t now;
00319 struct tm *tm;
00320 unsigned long up;
00321
00322
00323 if ((uf = fopen(utmp_file, "r")) == NULL) {
00324 fprintf(stderr, "%s: %s: %s\n", prog, utmp_file, strerror(errno));
00325 exit(1);
00326 }
00327
00328 nusers = 0;
00329 while (fread(&ut, sizeof(ut), 1, uf) == 1) {
00330 #ifdef USER_PROCESS
00331 if (ut.ut_type == USER_PROCESS) nusers++;
00332 #else
00333 if (ut.ut_name[0] != 0 && ut.ut_line[0] != 0) nusers++;
00334 #endif
00335 }
00336 fclose(uf);
00337
00338
00339 now = time((time_t *) NULL);
00340 tm = localtime(&now);
00341
00342
00343 up = now - boot_time;
00344
00345 printf(" %d:%02d up", tm->tm_hour, tm->tm_min);
00346 if (up >= 24 * 3600L) {
00347 unsigned long days = up / (24 * 3600L);
00348 printf(" %lu day%s,", days, days == 1 ? "" : "s");
00349 }
00350 printf(" %lu:%02lu,", (up % (24 * 3600L)) / 3600, (up % 3600) / 60);
00351 printf(" %u user%s", nusers, nusers == 1 ? "" : "s");
00352 if((nloads = getloadavg(loads, NLOADS)) > 0) {
00353 int i;
00354 printf(", load averages:");
00355 for(i = 0; i < nloads; i++)
00356 printf("%s %.2f", (i > 0) ? "," : "", loads[i]);
00357 }
00358 printf("\n");
00359 }
00360
00361
00362
00363
00364
00365 void Record_Logout_Time(wtmp)
00366 struct utmp *wtmp;
00367 {
00368 logout *link;
00369
00370
00371 for (link = first_link; link != NULL; link = link->next)
00372 if (!strncmp(link->line, wtmp->ut_line, (size_t)8)) {
00373 link->time = wtmp->ut_time;
00374 return;
00375 }
00376
00377 link = (logout *) malloc(sizeof(logout));
00378 if (link == NULL) {
00379 fprintf(stderr, "%s: malloc failure\n", prog);
00380 exit(1);
00381 }
00382 strncpy(link->line, wtmp->ut_line, (size_t)8);
00383 link->time = wtmp->ut_time;
00384 link->next = first_link;
00385
00386 first_link = link;
00387 }
00388
00389
00390 int main(argc, argv)
00391 int argc;
00392 char *argv[];
00393 {
00394 char *wtmp_file = _PATH_WTMP;
00395 FILE *f;
00396 long size;
00397 int wtmp_count;
00398 struct utmp wtmp_buffer[MAX_WTMP_COUNT];
00399
00400 if ((prog = strrchr(argv[0], '/')) == NULL) prog = argv[0]; else prog++;
00401
00402 --argc;
00403 ++argv;
00404
00405 while (argc > 0 && *argv[0] == '-') {
00406 if (!strcmp(argv[0], "-r"))
00407 boot_limit = TRUE;
00408 else
00409 if (!strcmp(argv[0], "-u"))
00410 tell_uptime = TRUE;
00411 else if (argc > 1 && !strcmp(argv[0], "-f")) {
00412 wtmp_file = argv[1];
00413 --argc;
00414 ++argv;
00415 } else if ((print_count = atoi(argv[0] + 1)) > 0)
00416 count_limit = TRUE;
00417 else
00418 usage();
00419
00420 --argc;
00421 ++argv;
00422 }
00423
00424 arg_count = argc;
00425 args = argv;
00426
00427 if (!strcmp(prog, "uptime")) tell_uptime = TRUE;
00428
00429 if ((f = fopen(wtmp_file, "r")) == NULL) {
00430 perror(wtmp_file);
00431 exit(1);
00432 }
00433 if (fseek(f, 0L, 2) != 0 || (size = ftell(f)) % sizeof(struct utmp) != 0) {
00434 fprintf(stderr, "%s: invalid wtmp file\n", prog);
00435 exit(1);
00436 }
00437 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
00438 signal(SIGINT, Sigint);
00439 signal(SIGQUIT, Sigquit);
00440 }
00441 size /= sizeof(struct utmp);
00442
00443 if (size == 0) wtmp_buffer[0].ut_time = time((time_t *)0);
00444
00445 while (size > 0) {
00446 wtmp_count = (int) min(size, MAX_WTMP_COUNT);
00447 size -= (long) wtmp_count;
00448
00449 fseek(f, size * sizeof(struct utmp), 0);
00450
00451
00452 if (fread(&wtmp_buffer[0], sizeof(struct utmp), (size_t)wtmp_count, f)
00453 != wtmp_count) {
00454 fprintf(stderr, "%s: read error on wtmp file\n", prog);
00455 exit(1);
00456 }
00457 while (--wtmp_count >= 0) {
00458 Process(&wtmp_buffer[wtmp_count]);
00459 if (interrupt) {
00460 printf("\ninterrupted %.16s \n",
00461 ctime(&wtmp_buffer[wtmp_count].ut_time));
00462
00463 if (interrupt == SIGINT) exit(2);
00464
00465 interrupt = FALSE;
00466 signal(SIGQUIT, Sigquit);
00467 }
00468 }
00469
00470 }
00471
00472 if (tell_uptime) {
00473 fprintf(stderr,
00474 "%s: no reboot record in wtmp file to compute uptime from\n",
00475 prog);
00476 return(1);
00477 }
00478
00479 printf("\nwtmp begins %.16s \n", ctime(&wtmp_buffer[0].ut_time));
00480 return(0);
00481 }