⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 last.c

📁 sysvinit--linux系统下的init
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * last.c	Re-implementation of the 'last' command, this time *		for Linux. Yes I know there is BSD last, but I *		just felt like writing this. No thanks :-). *		Also, this version gives lots more info (especially with -x) * * Author:	Miquel van Smoorenburg, miquels@cistron.nl * * Version:	@(#)last  2.85  30-Jul-2004  miquels@cistron.nl * *		This file is part of the sysvinit suite, *		Copyright 1991-2004 Miquel van Smoorenburg. * *		This program is free software; you can redistribute it and/or *		modify it under the terms of the GNU General Public License *		as published by the Free Software Foundation; either version *		2 of the License, or (at your option) any later version. */#include <sys/types.h>#include <sys/stat.h>#include <sys/fcntl.h>#include <time.h>#include <stdio.h>#include <ctype.h>#include <utmp.h>#include <errno.h>#include <malloc.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <signal.h>#include <getopt.h>#include <netinet/in.h>#include <netdb.h>#include <arpa/inet.h>#include "oldutmp.h"#ifndef SHUTDOWN_TIME#  define SHUTDOWN_TIME 254#endifchar *Version = "@(#) last 2.85 31-Apr-2004 miquels";#define CHOP_DOMAIN	0	/* Define to chop off local domainname. */#define NEW_UTMP	1	/* Fancy & fast utmp read code. */#define UCHUNKSIZE	16384	/* How much we read at once. *//* Double linked list of struct utmp's */struct utmplist {  struct utmp ut;  struct utmplist *next;  struct utmplist *prev;};struct utmplist *utmplist = NULL;/* Types of listing */#define R_CRASH		1 /* No logout record, system boot in between */#define R_DOWN		2 /* System brought down in decent way */#define R_NORMAL	3 /* Normal */#define R_NOW		4 /* Still logged in */#define R_REBOOT	5 /* Reboot record. */#define R_PHANTOM	6 /* No logout record but session is stale. */#define R_TIMECHANGE	7 /* NEW_TIME or OLD_TIME *//* Global variables */int maxrecs = 0;	/* Maximum number of records to list. */int recsdone = 0;	/* Number of records listed */int showhost = 1;	/* Show hostname too? */int altlist = 0;	/* Show hostname at the end. */int usedns = 0;		/* Use DNS to lookup the hostname. */int useip = 0;		/* Print IP address in number format */int oldfmt = 0;		/* Use old libc5 format? */char **show = NULL;	/* What do they want us to show */char *ufile;		/* Filename of this file */time_t lastdate;	/* Last date we've seen */char *progname;		/* Name of this program */#if CHOP_DOMAINchar hostname[256];	/* For gethostbyname() */char *domainname;	/* Our domainname. */#endif/* *	Convert old utmp format to new. */void uconv(struct oldutmp *oldut, struct utmp *utn){	memset(utn, 0, sizeof(struct utmp));	utn->ut_type = oldut->ut_type;	utn->ut_pid  = oldut->ut_pid;	utn->ut_time = oldut->ut_oldtime;	utn->ut_addr = oldut->ut_oldaddr;	strncpy(utn->ut_line, oldut->ut_line, OLD_LINESIZE);	strncpy(utn->ut_user, oldut->ut_user, OLD_NAMESIZE);	strncpy(utn->ut_host, oldut->ut_host, OLD_HOSTSIZE);}#if NEW_UTMP/* *	Read one utmp entry, return in new format. *	Automatically reposition file pointer. */int uread(FILE *fp, struct utmp *u, int *quit){	static int utsize;	static char buf[UCHUNKSIZE];	char tmp[1024];	static off_t fpos;	static int bpos;	struct oldutmp uto;	int r;	off_t o;	if (quit == NULL && u != NULL) {		/*		 *	Normal read.		 */		if (oldfmt) {			r = fread(&uto, sizeof(uto), 1, fp);			uconv(&uto, u);		} else			r = fread(u, sizeof(struct utmp), 1, fp);		return r;	}	if (u == NULL) {		/*		 *	Initialize and position.		 */		utsize = oldfmt ? sizeof(uto) : sizeof(struct utmp);		fseeko(fp, 0, SEEK_END);		fpos = ftello(fp);		if (fpos == 0)			return 0;		o = ((fpos - 1) / UCHUNKSIZE) * UCHUNKSIZE;		if (fseeko(fp, o, SEEK_SET) < 0) {			fprintf(stderr, "%s: seek failed!\n", progname);			return 0;		}		bpos = (int)(fpos - o);		if (fread(buf, bpos, 1, fp) != 1) {			fprintf(stderr, "%s: read failed!\n", progname);			return 0;		}		fpos = o;		return 1;	}	/*	 *	Read one struct. From the buffer if possible.	 */	bpos -= utsize;	if (bpos >= 0) {		if (oldfmt)			uconv((struct oldutmp *)(buf + bpos), u);		else			memcpy(u, buf + bpos, sizeof(struct utmp));		return 1;	}	/*	 *	Oops we went "below" the buffer. We should be able to	 *	seek back UCHUNKSIZE bytes.	 */	fpos -= UCHUNKSIZE;	if (fpos < 0)		return 0;	/*	 *	Copy whatever is left in the buffer.	 */	memcpy(tmp + (-bpos), buf, utsize + bpos);	if (fseeko(fp, fpos, SEEK_SET) < 0) {		perror("fseek");		return 0;	}	/*	 *	Read another UCHUNKSIZE bytes.	 */	if (fread(buf, UCHUNKSIZE, 1, fp) != 1) {		perror("fread");		return 0;	}	/*	 *	The end of the UCHUNKSIZE byte buffer should be the first	 *	few bytes of the current struct utmp.	 */	memcpy(tmp, buf + UCHUNKSIZE + bpos, -bpos);	bpos += UCHUNKSIZE;	if (oldfmt)		uconv((struct oldutmp *)tmp, u);	else		memcpy(u, tmp, sizeof(struct utmp));	return 1;}#else /* NEW_UTMP *//* *	Read one utmp entry, return in new format. *	Automatically reposition file pointer. */int uread(FILE *fp, struct utmp *u, int *quit){	struct oldutmp uto;	off_t r;	if (u == NULL) {		r = oldfmt ? sizeof(struct oldutmp) : sizeof(struct utmp);		fseek(fp, -1 * r, SEEK_END);		return 1;	}	if (!oldfmt) {		r = fread(u, sizeof(struct utmp), 1, fp);		if (r == 1) {			if (fseeko(fp, -2 * sizeof(struct utmp), SEEK_CUR) < 0)				if (quit) *quit = 1;		}		return r;	}	r = fread(&uto, sizeof(struct oldutmp), 1, fp);	if (r == 1) {		if (fseeko(fp, -2 * sizeof(struct oldutmp), SEEK_CUR) < 0)			if (quit) *quit = 1;		uconv(&uto, u);	}	return r;}#endif/* *	Try to be smart about the location of the BTMP file */#ifndef BTMP_FILE#define BTMP_FILE getbtmp()char *getbtmp(){	static char btmp[128];	char *p;	strcpy(btmp, WTMP_FILE);	if ((p = strrchr(btmp, '/')) == NULL)		p = btmp;	else		p++;	*p = 0;	strcat(btmp, "btmp");	return btmp;}#endif/* *	Print a short date. */char *showdate(){	char *s = ctime(&lastdate);	s[16] = 0;	return s;}/* *	SIGINT handler */void int_handler(){	printf("Interrupted %s\n", showdate());	exit(1);}/* *	SIGQUIT handler */void quit_handler(){	printf("Interrupted %s\n", showdate());	signal(SIGQUIT, quit_handler);}/* *	Get the basename of a filename */char *mybasename(char *s){	char *p;	if ((p = strrchr(s, '/')) != NULL)		p++;	else		p = s;	return p;}/* *	Lookup a host with DNS. */int dns_lookup(char *result, int size, int useip, int32_t *a){	struct sockaddr_in	sin;	struct sockaddr_in6	sin6;	struct sockaddr		*sa;	int			salen, flags;	unsigned int		topnibble;	int			mapped = 0;	flags = useip ? NI_NUMERICHOST : 0;	/*	 *	IPv4 or IPv6 ? We use 2 heuristics:	 *	1. Current IPv6 range uses 2000-3fff. Outside of	 *	   that is illegal and must be IPv4.	 *	2. If last 3 bytes are 0, must be IPv4	 *	3. If IPv6 in IPv4, handle as IPv4	 *	 *	Ugly.	 */	if (a[0] == 0 && a[1] == 0 && a[2] == htonl (0xffff))		mapped = 1;	topnibble = ntohl((unsigned int)a[0]) >> 28;	if (topnibble < 2 || topnibble > 3 || mapped ||	    (a[1] == 0 && a[2] == 0 && a[3] == 0)) {		/* IPv4 */		sin.sin_family = AF_INET;		sin.sin_port = 0;		sin.sin_addr.s_addr = mapped ? a[3] : a[0];		sa = (struct sockaddr *)&sin;		salen = sizeof(sin);	} else {		/* IPv6 */		memset(&sin6, 0, sizeof(sin6));		sin6.sin6_family = AF_INET6;		sin6.sin6_port = 0;		memcpy(sin6.sin6_addr.s6_addr, a, 16);		sa = (struct sockaddr *)&sin6;		salen = sizeof(sin6);	}	return getnameinfo(sa, salen, result, size, NULL, 0, flags);}/* *	Show one line of information on screen */int list(struct utmp *p, time_t t, int what){	time_t		secs, tmp;	char		logintime[32];	char		logouttime[32];	char		length[32];	char		final[128];	char		utline[UT_LINESIZE+1];	char		domain[256];	char		*s, **walk;	int		mins, hours, days;	int		r, len;	/*	 *	uucp and ftp have special-type entries	 */	utline[0] = 0;	strncat(utline, p->ut_line, UT_LINESIZE);	if (strncmp(utline, "ftp", 3) == 0 && isdigit(utline[3]))		utline[3] = 0;	if (strncmp(utline, "uucp", 4) == 0 && isdigit(utline[4]))		utline[4] = 0;	/*	 *	Is this something we wanna show?	 */	if (show) {		for (walk = show; *walk; walk++) {			if (strncmp(p->ut_name, *walk, UT_NAMESIZE) == 0 ||			    strcmp(utline, *walk) == 0 ||			    (strncmp(utline, "tty", 3) == 0 &&			     strcmp(utline + 3, *walk) == 0)) break;		}		if (*walk == NULL) return 0;	}	/*	 *	Calculate times	 */	tmp = (time_t)p->ut_time;	strcpy(logintime, ctime(&tmp));	logintime[16] = 0;	sprintf(logouttime, "- %s", ctime(&t) + 11);	logouttime[7] = 0;	secs = t - p->ut_time;	mins  = (secs / 60) % 60;	hours = (secs / 3600) % 24;	days  = secs / 86400;	if (days)		sprintf(length, "(%d+%02d:%02d)", days, hours, mins);	else		sprintf(length, " (%02d:%02d)", hours, mins);	switch(what) {		case R_CRASH:			sprintf(logouttime, "- crash");			break;		case R_DOWN:			sprintf(logouttime, "- down ");			break;		case R_NOW:			length[0] = 0;			sprintf(logouttime, "  still");			sprintf(length, "logged in");			break;		case R_PHANTOM:			length[0] = 0;			sprintf(logouttime, "   gone");			sprintf(length, "- no logout");			break;		case R_REBOOT:			logouttime[0] = 0;      /* Print machine uptime */			break;		case R_TIMECHANGE:			logouttime[0] = 0;			length[0] = 0;			break;		case R_NORMAL:			break; 	}	/*	 *	Look up host with DNS if needed.	 */	r = -1;	if (usedns || useip)		r = dns_lookup(domain, sizeof(domain), useip, p->ut_addr_v6);	if (r < 0) {		len = UT_HOSTSIZE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -