From: WanBingjiang Date: Wed, 22 Apr 2026 05:46:56 +0000 (+0800) Subject: lastlog2: add --journal option to manage SQLite journal mode X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=cd112d860bf606662cc4506c4f4475bcb11f068e;p=thirdparty%2Futil-linux.git lastlog2: add --journal option to manage SQLite journal mode Add -j/--journal option to the lastlog2 command to allow users to view and set the SQLite journal mode. Without an argument, it displays the current mode. With an argument, it sets the mode to the specified value (WAL, DELETE, TRUNCATE, PERSIST, MEMORY, OFF). The option supports flexible argument formats: - Short option with space: -j WAL - Short option without space: -jWAL - Long option with equals: --journal=WAL Also update bash-completion to provide journal mode suggestions and add documentation to the man page with usage examples. Addresses: https://github.com/util-linux/util-linux/issues/4157 Addresses: https://github.com/util-linux/util-linux/issues/4261 Assisted-by: Claude:claude-sonnet-4.5 Signed-off-by: WanBingjiang --- diff --git a/bash-completion/lastlog2 b/bash-completion/lastlog2 index 40d867789..e92ad27d8 100644 --- a/bash-completion/lastlog2 +++ b/bash-completion/lastlog2 @@ -17,6 +17,10 @@ _lastlog2_module() COMPREPLY=( $(compgen -W "file" -- "$cur") ) return 0 ;; + '-j'|'--journal') + COMPREPLY=( $(compgen -W "WAL DELETE TRUNCATE PERSIST MEMORY OFF" -- $cur) ) + return 0 + ;; '-r'|'--rename') COMPREPLY=( $(compgen -W "user_name" -- "$cur") ) return 0 @@ -24,11 +28,11 @@ _lastlog2_module() '-u'|'--user') COMPREPLY=( $(compgen -W "login" -- "$cur") ) return 0 - ;; + ;; '-d'|'--database') COMPREPLY=( $(compgen -W "file" -- "$cur") ) return 0 - ;; + ;; '-h'|'--help'|'-V'|'--version') return 0 ;; @@ -41,6 +45,7 @@ _lastlog2_module() --database --help --import + --journal --rename --service --set diff --git a/misc-utils/lastlog2.8.adoc b/misc-utils/lastlog2.8.adoc index 1c9ce2534..b8fcb055c 100644 --- a/misc-utils/lastlog2.8.adoc +++ b/misc-utils/lastlog2.8.adoc @@ -55,6 +55,20 @@ Use _file_ as *lastlog2* database. Import data from an old lastlog file named _file_. Existing entries in the lastlog2 database will be overwritten. +*-j*, *--journal* [_mode_]:: +Show the current SQLite journal mode, or set it to _mode_. +Without an argument, displays the current journal mode. +With an argument, sets the journal mode to the specified value. ++ +Supported modes: *WAL*, *DELETE*, *TRUNCATE*, *PERSIST*, *MEMORY*, *OFF*. ++ +*WAL* (Write-Ahead Logging) mode is recommended for high-concurrency scenarios +as it allows readers and writers to operate concurrently without blocking each other. +This significantly reduces database lock contention in environments with frequent +SSH logins. The journal mode setting is persistent and only needs to be set once. ++ +See *sqlite3*(1) PRAGMA journal_mode for more details about journal modes. + *-r*, *--rename* _newname_:: Rename the user given with *-u* to this _newname_. This option can only be used together with *-u* (*--user*). @@ -74,6 +88,23 @@ Print (or modify) the last-login record of the user _login_. include::man-common/help-version.adoc[] +== EXAMPLES + +Display the current journal mode: +---- +lastlog2 -j +---- + +Enable WAL mode for better concurrency (recommended for high-traffic servers): +---- +lastlog2 -j WAL +---- + +Switch back to the default DELETE mode: +---- +lastlog2 -j DELETE +---- + == FILES */var/lib/lastlog/lastlog2.db*:: diff --git a/misc-utils/lastlog2.c b/misc-utils/lastlog2.c index be33f2ae3..c5e518c3b 100644 --- a/misc-utils/lastlog2.c +++ b/misc-utils/lastlog2.c @@ -116,6 +116,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -C, --clear clear record of a user (requires -u)\n"), output); fputs(_(" -d, --database FILE use FILE as lastlog2 database\n"), output); fputs(_(" -i, --import FILE import data from old lastlog file\n"), output); + fputs(_(" -j, --journal [MODE] show current journal mode, or set it (WAL, DELETE, etc.)\n"), output); fputs(_(" -r, --rename NEWNAME rename existing user to NEWNAME (requires -u)\n"), output); fputs(_(" -s, --service display PAM service\n"), output); fputs(_(" -S, --set set lastlog record to current time (requires -u)\n"), output); @@ -141,6 +142,7 @@ int main(int argc, char **argv) {"database", required_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {"import", required_argument, NULL, 'i'}, + {"journal", optional_argument, NULL, 'j'}, {"rename", required_argument, NULL, 'r'}, {"service", no_argument, NULL, 's'}, {"set", no_argument, NULL, 'S'}, @@ -152,17 +154,19 @@ int main(int argc, char **argv) char *error = NULL; int Cflg = 0; int iflg = 0; + int jflg = 0; int rflg = 0; int Sflg = 0; int uflg = 0; const char *user = NULL; const char *newname = NULL; const char *lastlog_file = NULL; + const char *journal_mode = NULL; struct ll2_context *db_context = NULL; int c; - while ((c = getopt_long(argc, argv, "ab:Cd:hi:r:sSt:u:vV", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "ab:Cd:hi:j::r:sSt:u:vV", longopts, NULL)) != -1) { switch (c) { case 'a': /* active; print lastlog excluding '**Never logged in**' users */ aflg = 1; @@ -189,6 +193,15 @@ int main(int argc, char **argv) lastlog_file = optarg; iflg = 1; break; + case 'j': /* journal [MODE]; Set or show journal mode */ + jflg = 1; + if (optarg) { + journal_mode = optarg; + } else if (optind < argc && argv[optind][0] != '-') { + /* Check if next argument looks like a mode name */ + journal_mode = argv[optind++]; + } + break; case 'r': /* rename ; Rename existing user to NEWNAME (requires -u) */ rflg = 1; newname = optarg; @@ -222,8 +235,8 @@ int main(int argc, char **argv) } } - if ((Cflg + Sflg + iflg) > 1) - errx(EXIT_FAILURE, _("Option -C, -i and -S cannot be used together")); + if ((Cflg + Sflg + iflg + jflg) > 1) + errx(EXIT_FAILURE, _("Option -C, -i, -j and -S cannot be used together")); db_context = ll2_new_context(lastlog2_path); if (!db_context) @@ -238,6 +251,28 @@ int main(int argc, char **argv) goto done; } + if (jflg) { + /* Journal mode operations */ + if (journal_mode) { + /* Set journal mode */ + if (ll2_set_journal_mode(db_context, journal_mode, &error) != 0) { + warnx(_("Couldn't set journal mode to '%s'"), journal_mode); + goto err; + } + printf(_("Journal mode set to '%s' successfully\n"), journal_mode); + } else { + /* Show current journal mode */ + char *mode = NULL; + if (ll2_get_journal_mode(db_context, &mode, &error) != 0) { + warnx(_("Couldn't get journal mode")); + goto err; + } + printf(_("Current journal mode: %s\n"), mode); + free(mode); + } + goto done; + } + if (Cflg || Sflg || rflg) { /* updating, inserting and removing entries */ if (!uflg || strlen(user) == 0) {