]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lastlog2: add --journal option to manage SQLite journal mode
authorWanBingjiang <wanbingjiang@webray.com.cn>
Wed, 22 Apr 2026 05:46:56 +0000 (13:46 +0800)
committerWanBingjiang <wanbingjiang@webray.com.cn>
Fri, 24 Apr 2026 08:50:07 +0000 (16:50 +0800)
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 <wanbingjiang@webray.com.cn>
bash-completion/lastlog2
misc-utils/lastlog2.8.adoc
misc-utils/lastlog2.c

index 40d867789bc6324715bba9f00f02c41c1f323ae1..e92ad27d80721f2cee74a009ae3d55913d56b47e 100644 (file)
@@ -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
index 1c9ce2534f6e28f592be27bba2eec40e43cb7b00..b8fcb055c99c5e54e023c86b1c6d4675296e325b 100644 (file)
@@ -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*::
index be33f2ae3cd9986d6f3090d35f8890db7e4bdb0b..c5e518c3b9f14cd695520ba60db0493b194246c0 100644 (file)
@@ -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 <NEWNAME>; 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) {