diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java
index 2effa3425d7..b094acc51fe 100644
--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java
@@ -405,26 +405,38 @@ public final class Main {
         collator.setStrength(Collator.PRIMARY);
     }
 
-    private Main() { }
-
     public static void main(String[] args) throws Exception {
         Main kt = new Main();
-        kt.run(args, System.out);
+        int exitCode = kt.run(args, System.out);
+        if (exitCode != 0) {
+            System.exit(exitCode);
+        }
     }
 
-    private void run(String[] args, PrintStream out) throws Exception {
+    private static class ExitException extends RuntimeException {
+        @java.io.Serial
+        static final long serialVersionUID = 0L;
+        private final int errorCode;
+        public ExitException(int errorCode) {
+            this.errorCode = errorCode;
+        }
+    }
+
+    public int run(String[] args, PrintStream out) throws Exception {
         try {
-            args = parseArgs(args);
+            parseArgs(args);
             if (command != null) {
                 doCommands(out);
             }
+        } catch (ExitException ee) {
+            return ee.errorCode;
         } catch (Exception e) {
             System.out.println(rb.getString("keytool.error.") + e);
             if (verbose) {
                 e.printStackTrace(System.out);
             }
             if (!debug) {
-                System.exit(1);
+                return 1;
             } else {
                 throw e;
             }
@@ -441,6 +453,7 @@ public final class Main {
                 ksStream.close();
             }
         }
+        return 0;
     }
 
     /**
@@ -5247,7 +5260,7 @@ public final class Main {
         if (debug) {
             throw new RuntimeException("NO BIG ERROR, SORRY");
         } else {
-            System.exit(1);
+            throw new ExitException(1);
         }
     }
 
diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
index 813939643c3..a14ece6ee0e 100644
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,14 +92,44 @@ public class Kinit {
      */
 
     public static void main(String[] args) {
-        try {
-            Kinit self = new Kinit(args);
+        Kinit kinit = new Kinit();
+        int exitCode = kinit.run(args);
+        if (exitCode != 0) {
+            System.exit(exitCode);
         }
-        catch (Exception e) {
-            String msg = null;
-            if (e instanceof KrbException) {
-                msg = ((KrbException)e).krbErrorMessage() + " " +
-                    ((KrbException)e).returnCodeMessage();
+    }
+
+    /**
+     * Run the Kinit command.
+     * @param args array of ticket request options.
+     * Available options are: -f, -p, -c, principal, password.
+     * @return the exit code
+     */
+    public int run(String[] args) {
+        try {
+            if (args == null || args.length == 0) {
+                options = new KinitOptions();
+            } else {
+                options = new KinitOptions(args);
+            }
+            switch (options.action) {
+                case 0:
+                    // Help, already displayed in new KinitOptions().
+                    break;
+                case 1:
+                    acquire();
+                    break;
+                case 2:
+                    renew();
+                    break;
+                default:
+                    throw new KrbException("kinit does not support action "
+                            + options.action);
+            }
+        } catch (Exception e) {
+            String msg;
+            if (e instanceof KrbException ke) {
+                msg = ke.krbErrorMessage() + " " + ke.returnCodeMessage();
             } else  {
                 msg = e.getMessage();
             }
@@ -109,37 +139,9 @@ public class Kinit {
                 System.out.println("Exception: " + e);
             }
             e.printStackTrace();
-            System.exit(-1);
-        }
-        return;
-    }
-
-    /**
-     * Constructs a new Kinit object.
-     * @param args array of ticket request options.
-     * Available options are: -f, -p, -c, principal, password.
-     * @exception IOException if an I/O error occurs.
-     * @exception RealmException if the Realm could not be instantiated.
-     * @exception KrbException if error occurs during Kerberos operation.
-     */
-    private Kinit(String[] args)
-        throws IOException, RealmException, KrbException {
-        if (args == null || args.length == 0) {
-            options = new KinitOptions();
-        } else {
-            options = new KinitOptions(args);
-        }
-        switch (options.action) {
-            case 1:
-                acquire();
-                break;
-            case 2:
-                renew();
-                break;
-            default:
-                throw new KrbException("kinit does not support action "
-                        + options.action);
+            return -1;
         }
+        return 0;
     }
 
     private void renew()
diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java
index 5cfc574d95a..445b806bb50 100644
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@ import java.io.FileInputStream;
  */
 class KinitOptions {
 
-    // 1. acquire, 2. renew, 3. validate
+    // 0. Help, 1. acquire, 2. renew, 3. validate
     public int action = 1;
 
     // forwardable and proxiable flags have two states:
@@ -143,7 +143,8 @@ class KinitOptions {
                        // -help: legacy.
                        args[i].equalsIgnoreCase("-help")) {
                 printHelp();
-                System.exit(0);
+                action = 0;
+                return;
             } else if (p == null) { // Haven't yet processed a "principal"
                 p = args[i];
                 try {
diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java
index 5a0c3bee077..16c9fd99ec4 100644
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,115 +78,111 @@ public class Klist {
      */
     public static void main(String[] args) {
         Klist klist = new Klist();
+        int exitCode = klist.run(args);
+        if (exitCode != 0) {
+            System.exit(exitCode);
+        }
+    }
+
+    public int run(String[] args) {
         if ((args == null) || (args.length == 0)) {
-            klist.action = 'c'; // default will list default credentials cache.
+            action = 'c'; // default will list default credentials cache.
         } else {
-            klist.processArgs(args);
-        }
-        switch (klist.action) {
-        case 'c':
-            if (klist.name == null) {
-                klist.target = CredentialsCache.getInstance();
-                klist.name = CredentialsCache.cacheName();
-            } else
-                klist.target = CredentialsCache.getInstance(klist.name);
-
-            if (klist.target != null)  {
-                klist.displayCache();
-            } else {
-                klist.displayMessage("Credentials cache");
-                System.exit(-1);
-            }
-            break;
-        case 'k':
-            KeyTab ktab = KeyTab.getInstance(klist.name);
-            if (ktab.isMissing()) {
-                System.out.println("KeyTab " + klist.name + " not found.");
-                System.exit(-1);
-            } else if (!ktab.isValid()) {
-                System.out.println("KeyTab " + klist.name
-                        + " format not supported.");
-                System.exit(-1);
-            }
-            klist.target = ktab;
-            klist.name = ktab.tabName();
-            klist.displayTab();
-            break;
-        default:
-            if (klist.name != null) {
-                klist.printHelp();
-                System.exit(-1);
-            } else {
-                klist.target = CredentialsCache.getInstance();
-                klist.name = CredentialsCache.cacheName();
-                if (klist.target != null) {
-                    klist.displayCache();
-                } else {
-                    klist.displayMessage("Credentials cache");
-                    System.exit(-1);
-                }
-            }
-        }
-    }
-
-    /**
-     * Parses the command line arguments.
-     */
-    void processArgs(String[] args) {
-        Character arg;
-        for (int i = 0; i < args.length; i++) {
-            if (args[i].equals("-?") ||
-                args[i].equals("-h") ||
-                args[i].equals("--help")) {
-                printHelp();
-                System.exit(0);
-            }
-            if ((args[i].length() >= 2) && (args[i].startsWith("-"))) {
-                arg = Character.valueOf(args[i].charAt(1));
-                switch (arg.charValue()) {
-                case 'c':
-                    action = 'c';
-                    break;
-                case 'k':
-                    action = 'k';
-                    break;
-                case 'a':
-                    options[2] = 'a';
-                    break;
-                case 'n':
-                    options[3] = 'n';
-                    break;
-                case 'f':
-                    options[1] = 'f';
-                    break;
-                case 'e':
-                    options[0] = 'e';
-                    break;
-                case 'K':
-                    options[1] = 'K';
-                    break;
-                case 't':
-                    options[2] = 't';
-                    break;
-                default:
+            Character arg;
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].equals("-?") ||
+                        args[i].equals("-h") ||
+                        args[i].equals("--help")) {
                     printHelp();
-                    System.exit(-1);
+                    return 0;
                 }
-
-            } else {
-                if (!args[i].startsWith("-") && (i == args.length - 1)) {
-                    // the argument is the last one.
-                    name = args[i];
-                    arg = null;
+                if ((args[i].length() >= 2) && (args[i].startsWith("-"))) {
+                    arg = Character.valueOf(args[i].charAt(1));
+                    switch (arg.charValue()) {
+                        case 'c':
+                            action = 'c';
+                            break;
+                        case 'k':
+                            action = 'k';
+                            break;
+                        case 'a':
+                            options[2] = 'a';
+                            break;
+                        case 'n':
+                            options[3] = 'n';
+                            break;
+                        case 'f':
+                            options[1] = 'f';
+                            break;
+                        case 'e':
+                            options[0] = 'e';
+                            break;
+                        case 'K':
+                            options[1] = 'K';
+                            break;
+                        case 't':
+                            options[2] = 't';
+                            break;
+                        default:
+                            System.out.println("Invalid argument: " + args[i]);
+                            printHelp();
+                            return -1;
+                    }
                 } else {
-                    printHelp(); // incorrect input format.
-                    System.exit(-1);
+                    if (!args[i].startsWith("-") && (i == args.length - 1)) {
+                        // the argument is the last one.
+                        name = args[i];
+                    } else {
+                        System.out.println("Invalid argument: " + args[i]);
+                        printHelp(); // incorrect input format.
+                        return -1;
+                    }
+                }
+            }
+        }
+        switch (action) {
+        case 'c':
+            if (name == null) {
+                target = CredentialsCache.getInstance();
+                name = CredentialsCache.cacheName();
+            } else
+                target = CredentialsCache.getInstance(name);
+
+            if (target != null) {
+                return displayCache();
+            } else {
+                return displayError("Credentials cache");
+            }
+        case 'k':
+            KeyTab ktab = KeyTab.getInstance(name);
+            if (ktab.isMissing()) {
+                System.out.println("KeyTab " + name + " not found.");
+                return -1;
+            } else if (!ktab.isValid()) {
+                System.out.println("KeyTab " + name
+                        + " format not supported.");
+                return -1;
+            }
+            target = ktab;
+            name = ktab.tabName();
+            return displayTab();
+        default:
+            if (name != null) {
+                printHelp();
+                return -1;
+            } else {
+                target = CredentialsCache.getInstance();
+                name = CredentialsCache.cacheName();
+                if (target != null) {
+                    return displayCache();
+                } else {
+                    return displayError("Credentials cache");
                 }
             }
         }
     }
 
-    void displayTab() {
+    int displayTab() {
         KeyTab table = (KeyTab)target;
         KeyTabEntry[] entries = table.getEntries();
         if (entries.length == 0) {
@@ -201,7 +197,7 @@ public class Klist {
                                    entries.length + " entries found.\n");
             for (int i = 0; i < entries.length; i++) {
                 System.out.println("[" + (i + 1) + "] " +
-                                   "Service principal: "  +
+                                   "Service principal: " +
                                    entries[i].getService().toString());
                 System.out.println("\t KVNO: " +
                                    entries[i].getKey().getKeyVersionNumber());
@@ -221,18 +217,19 @@ public class Klist {
                 }
             }
         }
+        return 0;
     }
 
-    void displayCache() {
+    int displayCache() {
         CredentialsCache cache = (CredentialsCache)target;
         sun.security.krb5.internal.ccache.Credentials[] creds =
             cache.getCredsList();
         if (creds == null) {
             System.out.println ("No credentials available in the cache " +
                                 name);
-            System.exit(-1);
+            return -1;
         }
-        System.out.println("\nCredentials cache: " +  name);
+        System.out.println("\nCredentials cache: " + name);
         String defaultPrincipal = cache.getPrimaryPrincipal().toString();
         int num = creds.length;
 
@@ -327,7 +324,7 @@ public class Klist {
                     if (DEBUG) {
                         e.printStackTrace();
                     }
-                    System.exit(-1);
+                    return -1;
                 }
             }
         } else {
@@ -342,14 +339,17 @@ public class Klist {
                 System.out.println("     " + e);
             }
         }
+
+        return 0;
     }
 
-    void displayMessage(String target) {
+    int displayError(String target) {
         if (name == null) {
             System.out.println("Default " + target + " not found.");
         } else {
             System.out.println(target + " " + name + " not found.");
         }
+        return -1;
     }
     /**
      * Reformats the date from the form -
@@ -359,7 +359,7 @@ public class Klist {
      * the day, mm is the minute within the hour,
      * ss is the second within the minute, zzz is the time zone,
      * and yyyy is the year.
-     * @param date the string form of Date object.
+     * @param kt the string form of Date object.
      */
     private String format(KerberosTime kt) {
         String date = kt.toDate().toString();
diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java
index df12b2d6c11..21002f3369a 100644
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -73,52 +73,76 @@ public class Ktab {
      */
     public static void main(String[] args) {
         Ktab ktab = new Ktab();
+        int exitCode = ktab.run(args);
+        if (exitCode != 0) {
+            System.exit(exitCode);
+        }
+    }
+
+    private static class ExitException extends RuntimeException {
+        @java.io.Serial
+        static final long serialVersionUID = 0L;
+        private final int errorCode;
+        public ExitException(int errorCode) {
+            this.errorCode = errorCode;
+        }
+    }
+
+    public int run(String[] args) {
+        try {
+            run0(args);
+            return 0;
+        } catch (ExitException ee) {
+            return ee.errorCode;
+        }
+    }
+
+    private void run0(String[] args) throws ExitException {
         if ((args.length == 1) &&
             ((args[0].equalsIgnoreCase("-?")) ||
              (args[0].equalsIgnoreCase("-h")) ||
              (args[0].equalsIgnoreCase("--help")) ||
              // -help: legacy.
              (args[0].equalsIgnoreCase("-help")))) {
-            ktab.printHelp();
-            System.exit(0);
+            printHelp();
             return;
         } else if ((args == null) || (args.length == 0)) {
-            ktab.action = 'l';
+            action = 'l';
         } else {
-            ktab.processArgs(args);
+            processArgs(args);
         }
-        ktab.table = KeyTab.getInstance(ktab.name);
-        if (ktab.table.isMissing() && ktab.action != 'a') {
-            if (ktab.name == null) {
+        table = KeyTab.getInstance(name);
+        if (table.isMissing() && action != 'a') {
+            if (name == null) {
                 System.out.println("No default key table exists.");
             } else {
                 System.out.println("Key table " +
-                        ktab.name + " does not exist.");
+                        name + " does not exist.");
             }
-            System.exit(-1);
+            throw new ExitException(-1);
         }
-        if (!ktab.table.isValid()) {
-            if (ktab.name == null) {
+        if (!table.isValid()) {
+            if (name == null) {
                 System.out.println("The format of the default key table " +
                         " is incorrect.");
             } else {
                 System.out.println("The format of key table " +
-                        ktab.name + " is incorrect.");
+                        name + " is incorrect.");
             }
-            System.exit(-1);
+            throw new ExitException(-1);
         }
-        switch (ktab.action) {
+        switch (action) {
         case 'l':
-            ktab.listKt();
+            listKt();
             break;
         case 'a':
-            ktab.addEntry();
+            addEntry();
             break;
         case 'd':
-            ktab.deleteEntry();
+            deleteEntry();
             break;
         default:
-            ktab.error("A command must be provided");
+            error("A command must be provided");
         }
     }
 
@@ -267,7 +291,7 @@ public class Ktab {
     void addEntry() {
         if (salt != null && fopt) {
             System.err.println("-s and -f cannot coexist when adding a keytab entry.");
-            System.exit(-1);
+            throw new ExitException(-1);
         }
         PrincipalName pname = null;
         try {
@@ -276,7 +300,7 @@ public class Ktab {
             System.err.println("Failed to add " + principal +
                                " to keytab.");
             e.printStackTrace();
-            System.exit(-1);
+            throw new ExitException(-1);
         }
         if (password == null) {
             try {
@@ -288,7 +312,7 @@ public class Ktab {
             } catch (IOException e) {
                 System.err.println("Failed to read the password.");
                 e.printStackTrace();
-                System.exit(-1);
+                throw new ExitException(-1);
             }
 
         }
@@ -313,11 +337,11 @@ public class Ktab {
         } catch (KrbException e) {
             System.err.println("Failed to add " + principal + " to keytab.");
             e.printStackTrace();
-            System.exit(-1);
+            throw new ExitException(-1);
         } catch (IOException e) {
             System.err.println("Failed to save new entry.");
             e.printStackTrace();
-            System.exit(-1);
+            throw new ExitException(-1);
         }
     }
 
@@ -399,22 +423,23 @@ public class Ktab {
                 System.out.flush();
                 answer = cis.readLine();
                 if (answer.equalsIgnoreCase("Y") ||
-                    answer.equalsIgnoreCase("Yes"));
-                else {
+                    answer.equalsIgnoreCase("Yes")) {
+                    ;
+                } else {
                     // no error, the user did not want to delete the entry
-                    System.exit(0);
+                    return;
                 }
             }
         } catch (KrbException e) {
             System.err.println("Error occurred while deleting the entry. "+
                                "Deletion failed.");
             e.printStackTrace();
-            System.exit(-1);
+            throw new ExitException(-1);
         } catch (IOException e) {
             System.err.println("Error occurred while deleting the entry. "+
                                " Deletion failed.");
             e.printStackTrace();
-            System.exit(-1);
+            throw new ExitException(-1);
         }
 
         int count = table.deleteEntries(pname, etype, vDel);
@@ -422,7 +447,7 @@ public class Ktab {
         if (count == 0) {
             System.err.println("No matched entry in the keytab. " +
                                "Deletion fails.");
-            System.exit(-1);
+            throw new ExitException(-1);
         } else {
             try {
                 table.save();
@@ -430,7 +455,7 @@ public class Ktab {
                 System.err.println("Error occurs while saving the keytab. " +
                                    "Deletion fails.");
                 e.printStackTrace();
-                System.exit(-1);
+                throw new ExitException(-1);
             }
             System.out.println("Done! " + count + " entries removed.");
         }
@@ -441,7 +466,7 @@ public class Ktab {
             System.out.println("Error: " + error + ".");
         }
         printHelp();
-        System.exit(-1);
+        throw new ExitException(-1);
     }
 
     /**
diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java
index 117fea688c7..ed2c9be8543 100644
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java
@@ -135,7 +135,19 @@ public class Main {
     // This is the entry that get launched by the security tool jarsigner.
     public static void main(String args[]) throws Exception {
         Main js = new Main();
-        js.run(args);
+        int exitCode = js.run(args);
+        if (exitCode != 0) {
+            System.exit(exitCode);
+        }
+    }
+
+    private static class ExitException extends RuntimeException {
+        @java.io.Serial
+        static final long serialVersionUID = 0L;
+        private final int errorCode;
+        public ExitException(int errorCode) {
+            this.errorCode = errorCode;
+        }
     }
 
     X509Certificate[] certChain;    // signer's cert chain (when composing)
@@ -230,13 +242,13 @@ public class Main {
     PKIXBuilderParameters pkixParameters;
     Set<X509Certificate> trustedCerts = new HashSet<>();
 
-    public void run(String args[]) {
+    public int run(String args[]) {
         try {
-            args = parseArgs(args);
+            parseArgs(args);
 
             // Try to load and install the specified providers
             if (providers != null) {
-                for (String provName: providers) {
+                for (String provName : providers) {
                     try {
                         KeyStoreUtil.loadProviderByName(provName,
                                 providerArgs.get(provName));
@@ -263,7 +275,7 @@ public class Main {
                 } else {
                     cl = ClassLoader.getSystemClassLoader();
                 }
-                for (String provClass: providerClasses) {
+                for (String provClass : providerClasses) {
                     try {
                         KeyStoreUtil.loadProviderByClass(provClass,
                                 providerArgs.get(provClass), cl);
@@ -285,19 +297,9 @@ public class Main {
                     loadKeyStore(keystore, false);
                 } catch (Exception e) {
                     if ((keystore != null) || (storepass != null)) {
-                        System.out.println(rb.getString("jarsigner.error.") +
-                                        e.getMessage());
-                        if (debug) {
-                            e.printStackTrace();
-                        }
-                        System.exit(1);
+                        throw e;
                     }
                 }
-                /*              if (debug) {
-                    SignatureFileVerifier.setDebug(true);
-                    ManifestEntryVerifier.setDebug(true);
-                }
-                */
                 verifyJar(jarfile);
             } else {
                 loadKeyStore(keystore, true);
@@ -305,12 +307,14 @@ public class Main {
 
                 signJar(jarfile, alias);
             }
+        } catch (ExitException ee) {
+            return ee.errorCode;
         } catch (Exception e) {
             System.out.println(rb.getString("jarsigner.error.") + e);
             if (debug) {
                 e.printStackTrace();
             }
-            System.exit(1);
+            return 1;
         } finally {
             // zero-out private key password
             if (keypass != null) {
@@ -343,10 +347,10 @@ public class Main {
             if (tsaChainNotValidated) {
                 exitCode |= 64;
             }
-            if (exitCode != 0) {
-                System.exit(exitCode);
-            }
+            return exitCode;
         }
+
+        return 0;
     }
 
     /*
@@ -612,12 +616,12 @@ public class Main {
     static void usage() {
         System.out.println();
         System.out.println(rb.getString("Please.type.jarsigner.help.for.usage"));
-        System.exit(1);
+        throw new ExitException(1);
     }
 
     static void doPrintVersion() {
         System.out.println("jarsigner " + System.getProperty("java.version"));
-        System.exit(0);
+        throw new ExitException(0);
     }
 
     static void fullusage() {
@@ -719,7 +723,7 @@ public class Main {
                 (".print.this.help.message"));
         System.out.println();
 
-        System.exit(0);
+        throw new ExitException(0);
     }
 
     void verifyJar(String jarName)
@@ -1105,19 +1109,11 @@ public class Main {
             } else {
                 displayMessagesAndResult(false);
             }
-            return;
-        } catch (Exception e) {
-            System.out.println(rb.getString("jarsigner.") + e);
-            if (debug) {
-                e.printStackTrace();
-            }
         } finally { // close the resource
             if (jf != null) {
                 jf.close();
             }
         }
-
-        System.exit(1);
     }
 
     private void displayMessagesAndResult(boolean isSigning) {
@@ -2469,7 +2465,7 @@ public class Main {
 
     void error(String message) {
         System.out.println(rb.getString("jarsigner.")+message);
-        System.exit(1);
+        throw new ExitException(1);
     }
 
 
@@ -2478,7 +2474,7 @@ public class Main {
         if (debug) {
             e.printStackTrace();
         }
-        System.exit(1);
+        throw new ExitException(1);
     }
 
     /**
diff --git a/test/jdk/sun/security/krb5/tools/ExitOrNot.java b/test/jdk/sun/security/krb5/tools/ExitOrNot.java
new file mode 100644
index 00000000000..9f3000dcb75
--- /dev/null
+++ b/test/jdk/sun/security/krb5/tools/ExitOrNot.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8316964
+ * @summary check exit code in kinit, klist, and ktab
+ * @requires os.family == "windows"
+ * @library /test/lib
+ * @modules java.security.jgss/sun.security.krb5.internal.tools
+ */
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Platform;
+import jdk.test.lib.SecurityTools;
+
+public class ExitOrNot {
+
+    private static final int BAD = Platform.isWindows() ? -1 : 255;
+
+    public static void main(String[] args) throws Exception {
+
+        // launching the tool still exits
+        SecurityTools.kinit("u@R p1 p2")
+                .shouldHaveExitValue(BAD);
+
+        SecurityTools.klist("-x")
+                .shouldHaveExitValue(BAD);
+
+        SecurityTools.ktab("-x")
+                .shouldHaveExitValue(BAD);
+
+        // calling the run() methods returns the exit code
+        Asserts.assertEQ(new sun.security.krb5.internal.tools.Kinit()
+                .run("u@R p1 p2".split(" ")), -1);
+        Asserts.assertEQ(new sun.security.krb5.internal.tools.Klist()
+                .run("-x".split(" ")), -1);
+        Asserts.assertEQ(new sun.security.krb5.internal.tools.Ktab()
+                .run("-x".split(" ")), -1);
+    }
+}
diff --git a/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java b/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java
new file mode 100644
index 00000000000..ae55074f3a5
--- /dev/null
+++ b/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8316964
+ * @summary check exit code in jarsigner and keytool
+ * @library /test/lib
+ * @modules java.base/sun.security.tools.keytool
+ *          jdk.jartool/sun.security.tools.jarsigner
+ */
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.SecurityTools;
+
+public class ExitOrNot {
+    public static void main(String[] args) throws Exception {
+
+        // launching the tool still exits
+        SecurityTools.jarsigner("1 2 3")
+                .shouldHaveExitValue(1);
+        SecurityTools.keytool("-x")
+                .shouldHaveExitValue(1);
+
+        // calling the run() methods no longer
+        Asserts.assertEQ(new sun.security.tools.jarsigner.Main()
+                    .run("1 2 3".split(" ")), 1);
+
+        Asserts.assertEQ(new sun.security.tools.keytool.Main()
+                    .run("-x".split(" "), System.out), 1);
+    }
+}