Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package wtmpdb for openSUSE:Factory checked in at 2023-06-23 21:52:10 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/wtmpdb (Old) and /work/SRC/openSUSE:Factory/.wtmpdb.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "wtmpdb" Fri Jun 23 21:52:10 2023 rev:5 rq:1094677 version:0.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/wtmpdb/wtmpdb.changes 2023-06-14 16:28:39.950219812 +0200 +++ /work/SRC/openSUSE:Factory/.wtmpdb.new.15902/wtmpdb.changes 2023-06-23 21:52:17.590515959 +0200 @@ -1,0 +2,7 @@ +Wed Jun 21 06:52:21 UTC 2023 - Thorsten Kukuk <ku...@suse.com> + +- Update to version 0.7.0 + - wtmpdb rotate: use sqlite3_bind_* internal + - wtmpdb last: Implement -x, -d, -i and -w options + +------------------------------------------------------------------- Old: ---- wtmpdb-0.6.0.tar.xz New: ---- wtmpdb-0.7.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ wtmpdb.spec ++++++ --- /var/tmp/diff_new_pack.nkaqUE/_old 2023-06-23 21:52:18.346520066 +0200 +++ /var/tmp/diff_new_pack.nkaqUE/_new 2023-06-23 21:52:18.350520088 +0200 @@ -18,7 +18,7 @@ %define lname libwtmpdb0 Name: wtmpdb -Version: 0.6.0 +Version: 0.7.0 Release: 0 Summary: Reports last logged in users and system reboots License: BSD-2-Clause @@ -78,7 +78,8 @@ if [ "$1" -eq 0 ]; then pam-config -d --wtmpdb fi -%service_del_postun_without_restart wtmpdb-update-boot.service wtmpdb-rotate.timer +%service_del_postun_without_restart wtmpdb-update-boot.service +%service_del_postun wtmpdb-rotate.timer %post -n %{lname} -p /sbin/ldconfig %postun -n %{lname} -p /sbin/ldconfig ++++++ wtmpdb-0.6.0.tar.xz -> wtmpdb-0.7.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/NEWS new/wtmpdb-0.7.0/NEWS --- old/wtmpdb-0.6.0/NEWS 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/NEWS 2023-06-22 15:27:58.000000000 +0200 @@ -1,3 +1,7 @@ +Version 0.7.0 +* wtmpdb rotate: use sqlite3_bind_* internal +* wtmpdb last: Implement -x, -d, -i and -w options + Version 0.6.0 * wtmpdb rotate: move old log entries into wtmpdb_<yyyymmdd>.db diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/include/wtmpdb.h new/wtmpdb-0.7.0/include/wtmpdb.h --- old/wtmpdb-0.6.0/include/wtmpdb.h 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/include/wtmpdb.h 2023-06-22 15:27:58.000000000 +0200 @@ -54,9 +54,8 @@ int (*cb_func) (void *unused, int argc, char **argv, char **azColName), char **error); -extern int wtmpdb_logrotate (const char *db_path, - const int days, - char **error); +extern int wtmpdb_rotate (const char *db_path, const int days, char **error, + char **wtmpdb_name, uint64_t *entries); /* helper function */ extern int64_t wtmpdb_get_id (const char *db_path, const char *tty, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/lib/libwtmpdb.map new/wtmpdb-0.7.0/lib/libwtmpdb.map --- old/wtmpdb-0.6.0/lib/libwtmpdb.map 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/lib/libwtmpdb.map 2023-06-22 15:27:58.000000000 +0200 @@ -4,8 +4,11 @@ wtmpdb_login; wtmpdb_logout; wtmpdb_read_all; - wtmpdb_logrotate; wtmpdb_timespec2usec; wtmpdb_get_id; local: *; }; +LIBWTMPDB_0.7 { + global: + wtmpdb_rotate; +} LIBWTMPDB_0.1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/lib/sqlite.c new/wtmpdb-0.7.0/lib/sqlite.c --- old/wtmpdb-0.6.0/lib/sqlite.c 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/lib/sqlite.c 2023-06-22 15:27:58.000000000 +0200 @@ -29,6 +29,7 @@ #include <time.h> #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <libgen.h> #include <string.h> #include <limits.h> @@ -441,23 +442,21 @@ return 0; } -static int logrotate_callback(void *data, int argc, char **argv, char **azColName) { - (void)argc; - (void)azColName; - sqlite3 *db_dest = (sqlite3*)data; - char *error = NULL; +static int +export_row (sqlite3 *db_dest, sqlite3_stmt *sqlStatement, char **error) +{ char *endptr; - const int type = atoi (argv[1]); - const char *user = argv[2]; - const char *tty = argv[5]; - const char *host = argv[6]; - const char *service = argv[7]; - uint64_t login_t = strtoul(argv[3], &endptr, 10); + const int type = sqlite3_column_int( sqlStatement, 1 ); + const char *user = (const char*)sqlite3_column_text( sqlStatement, 2 ); + const char *tty = (const char*)sqlite3_column_text( sqlStatement, 5 ); + const char *host = (const char*)sqlite3_column_text( sqlStatement, 6 ); + const char *service = (const char*)sqlite3_column_text( sqlStatement, 7 ); + uint64_t login_t = strtoul((const char*)sqlite3_column_text( sqlStatement, 3 ), &endptr, 10); if ((errno == ERANGE && login_t == UINT64_MAX) - || (endptr == argv[1]) || (*endptr != '\0')) + || (endptr == (const char *)sqlite3_column_text( sqlStatement, 3 )) || (*endptr != '\0')) fprintf (stderr, "Invalid numeric time entry for 'login': '%s'\n", - argv[3]); + sqlite3_column_text( sqlStatement, 5 )); int id = add_entry (db_dest, type, @@ -466,57 +465,56 @@ tty, host, service, - &error); + error); if (id >=0) { - if ( argv[4] ) + const char *logout = (const char*)sqlite3_column_text( sqlStatement, 4 ); + if (logout) { - int64_t logout_t = strtoul(argv[4], &endptr, 10); + int64_t logout_t = strtoul(logout, &endptr, 10); if ((errno == ERANGE && logout_t == INT64_MAX) - || (endptr == argv[1]) || (*endptr != '\0')) + || (endptr == logout) || (*endptr != '\0')) { - fprintf (stderr, "Invalid numeric time entry for 'logout': '%s'\n", argv[4]); + fprintf (stderr, "Invalid numeric time entry for 'logout': '%s'\n", sqlite3_column_text( sqlStatement, 3 )); return -1; } - if (update_logout (db_dest, id, logout_t, &error) == -1) + if (update_logout (db_dest, id, logout_t, error) == -1) { - fprintf (stderr, "Cannot update DB value: '%s'\n", error); + fprintf (stderr, "Cannot update DB value: '%s'\n", *error); return -1; } } } else { - fprintf (stderr, "Cannot insert DB value: '%s'\n", error); + fprintf (stderr, "Cannot insert DB value: '%s'\n", *error); return -1; } - return 0; + return 0; } /* Reads all entries from database and calls the callback function for each entry. Returns 0 on success, -1 on failure. */ int -wtmpdb_logrotate (const char *db_path, - const int days, - char **error) +wtmpdb_rotate (const char *db_path, const int days, char **error, + char **wtmpdb_name, uint64_t *entries) { sqlite3 *db_src; sqlite3 *db_dest; - char *err_msg = 0; + uint64_t counter = 0; struct timespec ts_now; clock_gettime (CLOCK_REALTIME, &ts_now); - time_t rawtime = time(0); // System time: number of seconds since 00:00, Jan 1 1970 UTC - time(&rawtime); - struct tm *tm = localtime (&rawtime); - uint64_t login_t = (ts_now.tv_sec - days * 86400) * USEC_PER_SEC; + time_t offset = ts_now.tv_sec - days * 86400; + struct tm *tm = localtime (&offset); + uint64_t login_t = offset * USEC_PER_SEC; char date[10]; strftime (date, 10, "%Y%m%d", tm); - char *dest_path = NULL; char *dest_file = strdup(db_path); strip_extension(dest_file); + if (asprintf (&dest_path, "%s/%s_%s.db", dirname(dest_file), basename(dest_file), date) < 0) { *error = strdup ("Out of memory"); @@ -537,11 +535,14 @@ return -1; } - char *sql = NULL; - if (asprintf (&sql, "SELECT * FROM wtmp where Login <= %lld", - (long long unsigned)login_t) < 0) /* conversation for i586/x86_64 build needed */ + char *sql_select = "SELECT * FROM wtmp where Login <= ?"; + sqlite3_stmt *res; + if (sqlite3_prepare_v2 (db_src, sql_select, -1, &res, 0) != SQLITE_OK) { - *error = strdup ("Out of memory"); + if (error) + if (asprintf (error, "Failed to execute statement: %s", + sqlite3_errmsg (db_src)) < 0) + *error = strdup ("Out of memory"); sqlite3_close (db_src); sqlite3_close (db_dest); free(dest_path); @@ -549,26 +550,32 @@ return -1; } - if (sqlite3_exec (db_src, sql, logrotate_callback, (void*)db_dest, &err_msg) != SQLITE_OK) + if (sqlite3_bind_int64 (res, 1, login_t) != SQLITE_OK) { if (error) - if (asprintf (error, "SQL error: %s", err_msg) < 0) - *error = strdup ("Out of memory"); + if (asprintf (error, "Failed to create replace statement for login time: %s", + sqlite3_errmsg (db_src)) < 0) + *error = strdup("Out of memory"); - sqlite3_free (err_msg); + sqlite3_finalize(res); sqlite3_close (db_src); sqlite3_close (db_dest); - free(sql); free(dest_path); free(dest_file); return -1; } - free(sql); - if (asprintf (&sql, "DELETE FROM wtmp where Login <= %lld", - (long long unsigned)login_t) < 0) /* conversation for i586/x86_64 build needed */ + int rc; + while ((rc = sqlite3_step(res)) == SQLITE_ROW) { + export_row (db_dest, res, error); + ++counter; + } + if (rc != SQLITE_DONE) { - *error = strdup ("Out of memory"); + if (asprintf (error, "SQL error: %s", sqlite3_errmsg(db_src)) < 0) + *error = strdup ("Out of memory"); + + sqlite3_finalize(res); sqlite3_close (db_src); sqlite3_close (db_dest); free(dest_path); @@ -576,24 +583,68 @@ return -1; } - if (sqlite3_exec (db_src, sql, NULL, NULL, &err_msg) != SQLITE_OK) + sqlite3_finalize(res); + + char *sql_delete = "DELETE FROM wtmp where Login <= ?"; + if (sqlite3_prepare_v2 (db_src, sql_delete, -1, &res, 0) != SQLITE_OK) { if (error) - if (asprintf (error, "SQL error: %s", err_msg) < 0) + if (asprintf (error, "Failed to execute statement: %s", + sqlite3_errmsg (db_src)) < 0) *error = strdup ("Out of memory"); + sqlite3_close (db_src); + sqlite3_close (db_dest); + free(dest_path); + free(dest_file); + return -1; + } - sqlite3_free (err_msg); + if (sqlite3_bind_int64 (res, 1, login_t) != SQLITE_OK) + { + if (error) + if (asprintf (error, "Failed to create replace statement for login time: %s", + sqlite3_errmsg (db_src)) < 0) + *error = strdup("Out of memory"); + + sqlite3_finalize(res); + sqlite3_close (db_src); + sqlite3_close (db_dest); + free(dest_path); + free(dest_file); + return -1; + } + + int step = sqlite3_step (res); + + if (step != SQLITE_DONE) + { + if (error) + if (asprintf (error, "Adding an entry did not return SQLITE_DONE: %d", + step) < 0) + *error = strdup("Out of memory"); + + sqlite3_finalize(res); sqlite3_close (db_src); sqlite3_close (db_dest); - free(sql); free(dest_path); free(dest_file); return -1; } - free(sql); + sqlite3_finalize(res); sqlite3_close (db_src); sqlite3_close (db_dest); + + if (counter > 0) + { + if (wtmpdb_name) + *wtmpdb_name = strdup (dest_path); + if (entries) + *entries = counter; + } + else + unlink (dest_path); + free(dest_path); free(dest_file); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/man/wtmpdb.8.xml new/wtmpdb-0.7.0/man/wtmpdb.8.xml --- old/wtmpdb-0.6.0/man/wtmpdb.8.xml 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/man/wtmpdb.8.xml 2023-06-22 15:27:58.000000000 +0200 @@ -58,7 +58,7 @@ <variablelist> <varlistentry> <term> - <option>-a, --lasthost</option> + <option>-a, --hostlast</option> </term> <listitem> <para> @@ -68,6 +68,16 @@ </varlistentry> <varlistentry> <term> + <option>-d, --dns</option> + </term> + <listitem> + <para> + Translate IP addresses into a hostname. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> <option>-f, --file</option> <replaceable>FILE</replaceable> </term> <listitem> @@ -88,6 +98,16 @@ </varlistentry> <varlistentry> <term> + <option>-i, --ip</option> + </term> + <listitem> + <para> + Translate hostnames to IP addresses. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> <option>-n, --limit</option> <replaceable>N</replaceable> </term> <listitem> @@ -147,6 +167,26 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term> + <option>-w, --fullnames</option> + </term> + <listitem> + <para> + Display full IP addresses and user and domain names. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <option>-x, --system</option> + </term> + <listitem> + <para> + Display system shutdown entries. + </para> + </listitem> + </varlistentry> </variablelist> <para> <replaceable>TIME</replaceable> must be in the format <option>"YYYY-MM-DD HH:MM:SS"</option>. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/meson.build new/wtmpdb-0.7.0/meson.build --- old/wtmpdb-0.6.0/meson.build 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/meson.build 2023-06-22 15:27:58.000000000 +0200 @@ -11,7 +11,7 @@ 'b_pie=true', 'warning_level=3',], license : ['BSD-2-Clause',], - version : '0.6.0', + version : '0.7.0', ) conf = configuration_data() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/src/wtmpdb.c new/wtmpdb-0.7.0/src/wtmpdb.c --- old/wtmpdb-0.6.0/src/wtmpdb.c 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/src/wtmpdb.c 2023-06-22 15:27:58.000000000 +0200 @@ -35,6 +35,8 @@ #include <string.h> #include <limits.h> #include <getopt.h> +#include <netdb.h> +#include <arpa/inet.h> #include <sys/utsname.h> #if HAVE_AUDIT @@ -58,6 +60,10 @@ static int hostlast = 0; static int nohostname = 0; static int noservice = 1; +static int dflag = 0; +static int iflag = 0; +static int wflag = 0; +static int xflag = 0; static const int name_len = 8; /* LAST_LOGIN_LEN */ static int login_fmt = TIMEFMT_SHORT; static int login_len = 16; /* 16 = short, 24 = full */ @@ -70,6 +76,44 @@ static time_t since = 0; /* Who was logged in after this time? */ static time_t until = 0; /* Who was logged in until this time? */ + +/* isipaddr - find out if string provided is an IP address or not + 0 - no IP address + 1 - is IP address +*/ +static int +isipaddr (const char *string, int *addr_type, + struct sockaddr_storage *addr) +{ + struct sockaddr_storage local_addr; + int is_ip; + + if (addr == NULL) + addr = &local_addr; + + memset(addr, 0, sizeof (struct sockaddr_storage)); + + /* first ipv4 */ + if (inet_pton (AF_INET, string, &((struct sockaddr_in *)addr)->sin_addr) > 0) + { + if (addr_type != NULL) + *addr_type = AF_INET; + addr->ss_family = AF_INET; + is_ip = 1; + } + else if (inet_pton (AF_INET6, string, &((struct sockaddr_in6 *)addr)->sin6_addr) > 0) + { /* then ipv6 */ + if (addr_type != NULL) + *addr_type = AF_INET6; + addr->ss_family = AF_INET6; + is_ip = 1; + } + else + is_ip = 0; + + return is_ip; +} + static int parse_time (const char *str, time_t *time) { @@ -111,15 +155,86 @@ } } +static void +calc_time_length(char *dst, size_t dstlen, int64_t start, int64_t stop) +{ + int64_t secs = (stop - start)/USEC_PER_SEC; + int mins = (secs / 60) % 60; + int hours = (secs / 3600) % 24; + int days = secs / 86400; + + if (days) + snprintf (dst, dstlen, "(%d+%02d:%02d)", days, hours, mins); + else if (hours) + snprintf (dst, dstlen, " (%02d:%02d)", hours, mins); + else + snprintf (dst, dstlen, " (00:%02d)", mins); +} + +static void +print_line (const char *user, const char *tty, const char *host, + const char *print_service, + const char *logintime, const char *logouttime, + const char *length) +{ + char *line; + + if (nohostname) + { + if (asprintf (&line, "%-8.*s %-12.12s%s %-*.*s - %-*.*s %s\n", + wflag?(int)strlen(user):name_len, user, tty, print_service, + login_len, login_len, logintime, + logout_len, logout_len, logouttime, + length) < 0) + { + fprintf (stderr, "Out f memory"); + exit (EXIT_FAILURE); + } + } + else + { + if (hostlast) + { + if (asprintf (&line, "%-8.*s %-12.12s%s %-*.*s - %-*.*s %-12.12s %s\n", + wflag?(int)strlen(user):name_len, user, tty, print_service, + login_len, login_len, logintime, + logout_len, logout_len, logouttime, + length, host) < 0) + { + fprintf (stderr, "Out f memory"); + exit (EXIT_FAILURE); + } + } + else + { + if (asprintf (&line, "%-8.*s %-12.12s %-16.*s%s %-*.*s - %-*.*s %s\n", + wflag?(int)strlen(user):name_len, user, tty, + wflag?(int)strlen(host):host_len, host, print_service, + login_len, login_len, logintime, + logout_len, logout_len, logouttime, + length) < 0) + { + fprintf (stderr, "Out f memory"); + exit (EXIT_FAILURE); + } + } + } + + printf ("%s", line); + free (line); +} + static int print_entry (void *unused __attribute__((__unused__)), int argc, char **argv, char **azColName) { + char host_buf[NI_MAXHOST]; char logintime[32]; /* LAST_TIMESTAMP_LEN */ char logouttime[32]; /* LAST_TIMESTAMP_LEN */ char length[32]; /* LAST_TIMESTAMP_LEN */ - char *line; char *endptr; + int64_t logout_t = -1; + static int64_t newer_boot = -1; /* Yes, it's waste of time to let sqlite iterate through all entries even if we don't need more anymore, but telling sqlite we don't @@ -145,7 +260,7 @@ uint64_t login_t = strtoul(argv[3], &endptr, 10); if ((errno == ERANGE && login_t == UINT64_MAX) - || (endptr == argv[1]) || (*endptr != '\0')) + || (endptr == argv[3]) || (*endptr != '\0')) fprintf (stderr, "Invalid numeric time entry for 'login': '%s'\n", argv[3]); @@ -166,9 +281,9 @@ if (argv[4]) { - int64_t logout_t = strtoul(argv[4], &endptr, 10); + logout_t = strtoul(argv[4], &endptr, 10); if ((errno == ERANGE && logout_t == INT64_MAX) - || (endptr == argv[1]) || (*endptr != '\0')) + || (endptr == argv[4]) || (*endptr != '\0')) fprintf (stderr, "Invalid numeric time entry for 'logout': '%s'\n", argv[4]); @@ -179,17 +294,7 @@ format_time (logout_fmt, logouttime, sizeof (logouttime), logout_t/USEC_PER_SEC); - int64_t secs = (logout_t - login_t)/USEC_PER_SEC; - int mins = (secs / 60) % 60; - int hours = (secs / 3600) % 24; - int days = secs / 86400; - - if (days) - snprintf (length, sizeof(length), "(%d+%02d:%02d)", days, hours, mins); - else if (hours) - snprintf (length, sizeof(length), " (%02d:%02d)", hours, mins); - else - snprintf (length, sizeof(length), " (00:%02d)", mins); + calc_time_length (length, sizeof(length), login_t, logout_t); } else /* login but no logout */ { @@ -252,50 +357,67 @@ } } - if (nohostname) + if (dflag && strlen (host) > 0) { - if (asprintf (&line, "%-8.*s %-12.12s%s %-*.*s - %-*.*s %s\n", - name_len, user, tty, print_service, - login_len, login_len, logintime, - logout_len, logout_len, logouttime, - length) < 0) + struct sockaddr_storage addr; + int addr_type = 0; + + if (isipaddr (host, &addr_type, &addr)) { - fprintf (stderr, "Out f memory"); - exit (EXIT_FAILURE); + if (getnameinfo ((struct sockaddr*)&addr, sizeof (addr), host_buf, sizeof (host_buf), + NULL, 0, NI_NAMEREQD) == 0) + host = host_buf; } } - else + + if (iflag && strlen (host) > 0) { - if (hostlast) + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + if (getaddrinfo(host, NULL, &hints, &result) == 0) { - if (asprintf (&line, "%-8.*s %-12.12s%s %-*.*s - %-*.*s %-12.12s %s\n", - name_len, user, tty, print_service, - login_len, login_len, logintime, - logout_len, logout_len, logouttime, - length, host) < 0) + if (result->ai_family == AF_INET) { - fprintf (stderr, "Out f memory"); - exit (EXIT_FAILURE); + if (inet_ntop(result->ai_family, + &((struct sockaddr_in *)result->ai_addr)->sin_addr, + host_buf, sizeof (host_buf)) != NULL) + host = host_buf; } - } - else - { - if (asprintf (&line, "%-8.*s %-12.12s %-16.*s%s %-*.*s - %-*.*s %s\n", - name_len, user, tty, - host_len, host, print_service, - login_len, login_len, logintime, - logout_len, logout_len, logouttime, - length) < 0) + else if (result->ai_family == AF_INET6) { - fprintf (stderr, "Out f memory"); - exit (EXIT_FAILURE); + if (inet_ntop(result->ai_family, + &((struct sockaddr_in6 *)result->ai_addr)->sin6_addr, + host_buf, sizeof (host_buf)) != NULL) + host = host_buf; } + + freeaddrinfo(result); } } - free (print_service); - printf ("%s", line); - free (line); + print_line (user, tty, host, print_service, logintime, logouttime, length); + + if (xflag && (type == BOOT_TIME) && newer_boot != -1 && logout_t != -1) + { + format_time (login_fmt, logintime, sizeof (logintime), + logout_t/USEC_PER_SEC); + format_time (logout_fmt, logouttime, sizeof (logouttime), + newer_boot/USEC_PER_SEC); + calc_time_length (length, sizeof(length), logout_t, newer_boot); + + print_line ("shutdown", "system down", host, print_service, + logintime, logouttime, length); + } + if (xflag && (type == BOOT_TIME)) + newer_boot = login_t; + + free (print_service); currentry++; @@ -310,15 +432,19 @@ fprintf (output, "Usage: wtmpdb [command] [options]\n"); fputs ("Commands: last, boot, rotate, shutdown\n\n", output); fputs ("Options for last:\n", output); - fputs (" -a, --lasthost Display hostnames as last entry\n", output); + fputs (" -a, --hostlast Display hostnames as last entry\n", output); + fputs (" -d, --dns Translate IP addresses into a hostname\n", output); fputs (" -f, --file FILE Use FILE as wtmpdb database\n", output); fputs (" -F, --fulltimes Display full times and dates\n", output); + fputs (" -i, --ip Translate hostnames to IP addresses\n", output); fputs (" -n, --limit N Display only first N entries\n", output); fputs (" -p, --present TIME Display who was present at TIME\n", output); fputs (" -R, --nohostname Don't display hostname\n", output); fputs (" -S, --service Display PAM service used to login\n", output); fputs (" -s, --since TIME Display who was logged in after TIME\n", output); fputs (" -t, --until TIME Display who was logged in until TIME\n", output); + fputs (" -w, --fullnames Display full IP addresses and user and domain names\n", output); + fputs (" -x, --system Display system shutdown entries\n", output); fputs ("TIME must be in the format \"YYYY-MM-DD HH:MM:SS\"\n", output); fputs ("\n", output); @@ -343,7 +469,7 @@ } static int -main_logrotate (int argc, char **argv) +main_rotate (int argc, char **argv) { struct option const longopts[] = { {"file", required_argument, NULL, 'f'}, @@ -352,6 +478,8 @@ }; char *error = NULL; int days = LOGROTATE_DAYS; + char *wtmpdb_backup = NULL; + uint64_t entries = 0; int c; @@ -377,7 +505,8 @@ usage (EXIT_FAILURE); } - if (wtmpdb_logrotate (wtmpdb_path, days, &error) != 0) + if (wtmpdb_rotate (wtmpdb_path, days, &error, + &wtmpdb_backup, &entries) != 0) { if (error) { @@ -390,10 +519,13 @@ exit (EXIT_FAILURE); } - char wtmptime[32]; - format_time (TIMEFMT_CTIME, wtmptime, sizeof (wtmptime), - wtmp_start/USEC_PER_SEC); - printf ("\n%s begins %s\n", wtmpdb_path, wtmptime); + if (entries == 0 || wtmpdb_backup == NULL) + printf ("No old entries found\n"); + else + printf ("%lli entries moved to %s\n", + (long long unsigned int)entries, wtmpdb_backup); + + free (wtmpdb_backup); return EXIT_SUCCESS; } @@ -403,26 +535,33 @@ { struct option const longopts[] = { {"hostlast", no_argument, NULL, 'a'}, + {"dns", no_argument, NULL, 'd'}, {"file", required_argument, NULL, 'f'}, + {"fullnames", no_argument, NULL, 'w'}, {"fulltimes", no_argument, NULL, 'F'}, + {"ip", no_argument, NULL, 'i'}, {"limit", required_argument, NULL, 'n'}, {"present", required_argument, NULL, 'p'}, {"nohostname", no_argument, NULL, 'R'}, - {"since", required_argument, NULL, 's'}, {"service", no_argument, NULL, 'S'}, + {"since", required_argument, NULL, 's'}, + {"system", no_argument, NULL, 'x'}, {"until", required_argument, NULL, 'u'}, {NULL, 0, NULL, '\0'} }; char *error = NULL; int c; - while ((c = getopt_long (argc, argv, "af:Fn:p:RSs:t:", longopts, NULL)) != -1) + while ((c = getopt_long (argc, argv, "adf:Fin:p:RSs:t:wx", longopts, NULL)) != -1) { switch (c) { case 'a': hostlast = 1; break; + case 'd': + dflag = 1; + break; case 'f': wtmpdb_path = optarg; break; @@ -432,6 +571,9 @@ logout_fmt = TIMEFMT_CTIME; logout_len = 24; break; + case 'i': + iflag = 1; + break; case 'n': maxentries = atoi (optarg); break; @@ -462,6 +604,12 @@ exit (EXIT_FAILURE); } break; + case 'w': + wflag = 1; + break; + case 'x': + xflag = 1; + break; default: usage (EXIT_FAILURE); break; @@ -480,6 +628,24 @@ usage (EXIT_FAILURE); } + if (nohostname && dflag) + { + fprintf (stderr, "The options -d and -R cannot be used together.\n"); + usage (EXIT_FAILURE); + } + + if (nohostname && iflag) + { + fprintf (stderr, "The options -i and -R cannot be used together.\n"); + usage (EXIT_FAILURE); + } + + if (dflag && iflag) + { + fprintf (stderr, "The options -d and -i cannot be used together.\n"); + usage (EXIT_FAILURE); + } + if (wtmpdb_read_all (wtmpdb_path, print_entry, &error) != 0) { if (error) @@ -680,7 +846,7 @@ else if (strcmp (argv[1], "shutdown") == 0) return main_shutdown (--argc, ++argv); else if (strcmp (argv[1], "rotate") == 0) - return main_logrotate (--argc, ++argv); + return main_rotate (--argc, ++argv); while ((c = getopt_long (argc, argv, "hv", longopts, NULL)) != -1) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wtmpdb-0.6.0/tests/tst-login-logout.c new/wtmpdb-0.7.0/tests/tst-login-logout.c --- old/wtmpdb-0.6.0/tests/tst-login-logout.c 2023-06-12 16:15:30.000000000 +0200 +++ new/wtmpdb-0.7.0/tests/tst-login-logout.c 2023-06-22 15:27:58.000000000 +0200 @@ -37,6 +37,8 @@ #include "wtmpdb.h" +#define DAYS 2 + static int test_args (const char *db_path, const char *user, const char *tty, const char *rhost, const char *service) @@ -96,7 +98,7 @@ } static int -test_logrotate (const char *db_path) +test_rotate (const char *db_path) { char *error = NULL; @@ -118,7 +120,7 @@ return 1; } - if (wtmpdb_logrotate (db_path, 1, &error) != 0) + if (wtmpdb_rotate (db_path, DAYS, &error, NULL, NULL) != 0) { if (error) { @@ -126,7 +128,7 @@ free (error); } else - fprintf (stderr, "wtmpdb_logrotate failed\n"); + fprintf (stderr, "wtmpdb_rotate failed\n"); return 1; } @@ -170,13 +172,14 @@ if (test_args (db_path, "user5", NULL, "localhost", NULL) != 0) return 1; - if (test_logrotate (db_path) != 0) + if (test_rotate (db_path) != 0) return 1; /* cleanup */ - time_t rawtime = time(0); /* System time: number of seconds since 00:00, Jan 1 1970 UTC */ - time(&rawtime); - struct tm *tm = localtime (&rawtime); + struct timespec ts_now; + clock_gettime (CLOCK_REALTIME, &ts_now); + time_t offset = ts_now.tv_sec - DAYS * 86400; + struct tm *tm = localtime (&offset); char date[10]; strftime (date, 10, "%Y%m%d", tm); char *backup_path = NULL;