OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / tools / gnu / classpath / tools / jarsigner / Main.java
1 /* Main.java -- JAR signing and verification tool not unlike jarsigner
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package gnu.classpath.tools.jarsigner;
40
41 import gnu.classpath.Configuration;
42 import gnu.classpath.SystemProperties;
43 import gnu.classpath.tools.common.CallbackUtil;
44 import gnu.classpath.tools.common.ClasspathToolParser;
45 import gnu.classpath.tools.common.ProviderUtil;
46 import gnu.classpath.tools.getopt.FileArgumentCallback;
47 import gnu.classpath.tools.getopt.Option;
48 import gnu.classpath.tools.getopt.OptionException;
49 import gnu.classpath.tools.getopt.OptionGroup;
50 import gnu.java.security.OID;
51 import gnu.java.security.Registry;
52 import gnu.javax.security.auth.callback.ConsoleCallbackHandler;
53
54 import java.io.File;
55 import java.io.FileNotFoundException;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.net.URL;
59 import java.security.Key;
60 import java.security.KeyStore;
61 import java.security.KeyStoreException;
62 import java.security.NoSuchAlgorithmException;
63 import java.security.PrivateKey;
64 import java.security.Provider;
65 import java.security.Security;
66 import java.security.UnrecoverableKeyException;
67 import java.security.cert.Certificate;
68 import java.security.cert.CertificateException;
69 import java.util.ArrayList;
70 import java.util.Locale;
71 import java.util.jar.Attributes.Name;
72 import java.util.logging.Logger;
73
74 import javax.security.auth.callback.Callback;
75 import javax.security.auth.callback.CallbackHandler;
76 import javax.security.auth.callback.PasswordCallback;
77 import javax.security.auth.callback.UnsupportedCallbackException;
78
79 /**
80  * The GNU Classpath implementation of the <i>jarsigner</i> tool.
81  * <p>
82  * The <i>jarsigner</i> tool is used to sign and verify JAR (Java ARchive)
83  * files.
84  * <p>
85  * This implementation is intended to be compatible with the behaviour
86  * described in the public documentation of the same tool included in JDK 1.4.
87  */
88 public class Main
89 {
90   protected static final Logger log = Logger.getLogger(Main.class.getName());
91   static final String KEYTOOL_TOOL = "jarsigner"; //$NON-NLS-1$
92   private static final Locale EN_US_LOCALE = new Locale("en", "US"); //$NON-NLS-1$ //$NON-NLS-2$
93   static final String DIGEST = "SHA1-Digest"; //$NON-NLS-1$
94   static final String DIGEST_MANIFEST = "SHA1-Digest-Manifest"; //$NON-NLS-1$
95   static final Name DIGEST_ATTR = new Name(DIGEST);
96   static final Name DIGEST_MANIFEST_ATTR = new Name(DIGEST_MANIFEST);
97   static final OID DSA_SIGNATURE_OID = new OID(Registry.DSA_OID_STRING);
98   static final OID RSA_SIGNATURE_OID = new OID(Registry.RSA_OID_STRING);
99
100   protected boolean verify;
101   protected String ksURL;
102   protected String ksType;
103   protected String password;
104   protected String ksPassword;
105   protected String sigFileName;
106   protected String signedJarFileName;
107   protected boolean verbose;
108   protected boolean certs;
109   protected boolean internalSF;
110   protected boolean sectionsOnly;
111   protected String providerClassName;
112   protected String jarFileName;
113   protected String alias;
114
115   protected Provider provider;
116   private boolean providerInstalled;
117   private char[] ksPasswordChars;
118   private KeyStore store;
119   private char[] passwordChars;
120   private PrivateKey signerPrivateKey;
121   private Certificate[] signerCertificateChain;
122   /** The callback handler to use when needing to interact with user. */
123   private CallbackHandler handler;
124   /** The command line parser. */
125   private ToolParser cmdLineParser;
126   protected ArrayList fileAndAlias = new ArrayList();;
127
128   private Main()
129   {
130     super();
131   }
132
133   public static final void main(String[] args)
134   {
135     if (Configuration.DEBUG)
136       log.entering(Main.class.getName(), "main", args); //$NON-NLS-1$
137     Main tool = new Main();
138     int result = 1;
139     try
140       {
141         tool.processArgs(args);
142         tool.start();
143         result = 0;
144       }
145     catch (SecurityException x)
146       {
147         if (Configuration.DEBUG)
148           log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
149         System.err.println(Messages.getString("Main.7") + x.getMessage()); //$NON-NLS-1$
150       }
151     catch (Exception x)
152       {
153         if (Configuration.DEBUG)
154           log.throwing(Main.class.getName(), "main", x); //$NON-NLS-1$
155         System.err.println(Messages.getString("Main.9") + x); //$NON-NLS-1$
156       }
157     finally
158       {
159         tool.teardown();
160       }
161     if (Configuration.DEBUG)
162       log.exiting(Main.class.getName(), "main", Integer.valueOf(result)); //$NON-NLS-1$
163     System.exit(result);
164   }
165
166   // helper methods -----------------------------------------------------------
167
168   /**
169    * Read the command line arguments setting the tool's parameters in
170    * preparation for the user desired action.
171    * 
172    * @param args an array of options (strings).
173    * @throws Exception if an exception occurs during the process.
174    */
175   private void processArgs(String[] args) throws Exception
176   {
177     if (Configuration.DEBUG)
178       log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$
179     cmdLineParser = new ToolParser();
180     cmdLineParser.initializeParser();
181     cmdLineParser.parse(args, new ToolParserCallback());
182
183     setupCommonParams();
184     if (verify)
185       {
186         if (Configuration.DEBUG)
187           {
188             log.fine("Will verify with the following parameters:"); //$NON-NLS-1$
189             log.fine("     jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
190             log.fine("Options:"); //$NON-NLS-1$
191             log.fine("     provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
192             log.fine("      verbose ? " + verbose); //$NON-NLS-1$
193             log.fine("        certs ? " + certs); //$NON-NLS-1$
194             log.fine("   internalsf ? " + internalSF); //$NON-NLS-1$
195             log.fine(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
196           }
197       }
198     else // sign
199       {
200         setupSigningParams();
201         if (Configuration.DEBUG)
202           {
203             log.fine("Will sign with the following parameters:"); //$NON-NLS-1$
204             log.fine("     jar-file = '" + jarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
205             log.fine("        alias = '" + alias + "'"); //$NON-NLS-1$ //$NON-NLS-2$
206             log.fine("Options:"); //$NON-NLS-1$
207             log.fine("     keystore = '" + ksURL + "'"); //$NON-NLS-1$ //$NON-NLS-2$
208             log.fine("    storetype = '" + ksType + "'"); //$NON-NLS-1$ //$NON-NLS-2$
209             log.fine("    storepass = '" + ksPassword + "'"); //$NON-NLS-1$ //$NON-NLS-2$
210             log.fine("      keypass = '" + password + "'"); //$NON-NLS-1$ //$NON-NLS-2$
211             log.fine("      sigfile = '" + sigFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
212             log.fine("    signedjar = '" + signedJarFileName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
213             log.fine("     provider = '" + providerClassName + "'"); //$NON-NLS-1$ //$NON-NLS-2$
214             log.fine("      verbose ? " + verbose); //$NON-NLS-1$
215             log.fine("   internalsf ? " + internalSF); //$NON-NLS-1$
216             log.fine(" sectionsonly ? " + sectionsOnly); //$NON-NLS-1$
217           }
218       }
219     if (Configuration.DEBUG)
220       log.exiting(this.getClass().getName(), "processArgs"); //$NON-NLS-1$
221   }
222
223   /**
224    * Invokes the <code>start()</code> method of the concrete handler.
225    * <p>
226    * Depending on the result of processing the command line arguments, this
227    * handler may be one for signing the jar, or verifying it.
228    * 
229    * @throws Exception if an exception occurs during the process.
230    */
231   private void start() throws Exception
232   {
233     if (Configuration.DEBUG)
234       log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
235     if (verify)
236       {
237         JarVerifier jv = new JarVerifier(this);
238         jv.start();
239       }
240     else
241       {
242         JarSigner js = new JarSigner(this);
243         js.start();
244       }
245     if (Configuration.DEBUG)
246       log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
247   }
248
249   /**
250    * Ensures that the underlying JVM is left in the same state as we found it
251    * when we first launched the tool. Specifically, if we have installed a new
252    * security provider then now is the time to remove it.
253    * <p>
254    * Note (rsn): this may not be necessary if we terminate the JVM; i.e. call
255    * {@link System#exit(int)} at the end of the tool's invocation. Nevertheless
256    * it's good practive to return the JVM to its initial state.
257    */
258   private void teardown()
259   {
260     if (Configuration.DEBUG)
261       log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
262     if (providerInstalled)
263       ProviderUtil.removeProvider(provider.getName());
264
265     if (Configuration.DEBUG)
266       log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
267   }
268
269   /**
270    * After processing the command line arguments, this method is invoked to
271    * process the common parameters which may have been encountered among the
272    * actual arguments.
273    * <p>
274    * Common parameters are those which are allowed in both signing and
275    * verification modes.
276    * 
277    * @throws InstantiationException if a security provider class name is
278    *           specified but that class name is that of either an interface or
279    *           an abstract class.
280    * @throws IllegalAccessException if a security provider class name is
281    *           specified but no 0-arguments constructor is defined for that
282    *           class.
283    * @throws ClassNotFoundException if a security provider class name is
284    *           specified but no such class was found in the classpath.
285    * @throws IOException if the JAR file name for signing, or verifying, does
286    *           not exist, exists but denotes a directory, or is not readable.
287    */
288   private void setupCommonParams() throws InstantiationException,
289       IllegalAccessException, ClassNotFoundException, IOException
290   {
291     if (Configuration.DEBUG)
292       log.entering(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$
293     File jar = new File(jarFileName);
294     if (! jar.exists())
295       throw new FileNotFoundException(jarFileName);
296
297     if (jar.isDirectory())
298       throw new IOException(Messages.getFormattedString("Main.70", jarFileName)); //$NON-NLS-1$
299
300     if (! jar.canRead())
301       throw new IOException(Messages.getFormattedString("Main.72", jarFileName)); //$NON-NLS-1$ //$NON-NLS-2$
302
303     if (providerClassName != null && providerClassName.length() > 0)
304       {
305         provider = (Provider) Class.forName(providerClassName).newInstance();
306         // is it already installed?
307         String providerName = provider.getName();
308         Provider installedProvider = Security.getProvider(providerName);
309         if (installedProvider != null)
310           {
311             if (Configuration.DEBUG)
312               log.finer("Provider " + providerName + " is already installed"); //$NON-NLS-1$ //$NON-NLS-2$
313           }
314         else // install it
315           installNewProvider();
316       }
317
318     if (! verbose && certs)
319       {
320         if (Configuration.DEBUG)
321           log.fine("Option <certs> is set but <verbose> is not. Ignored"); //$NON-NLS-1$
322         certs = false;
323       }
324
325     if (Configuration.DEBUG)
326       log.exiting(this.getClass().getName(), "setupCommonParams"); //$NON-NLS-1$
327   }
328
329   /**
330    * Install the user defined security provider in the underlying JVM.
331    * <p>
332    * Also record this fact so we can remove it when we exit the tool.
333    */
334   private void installNewProvider()
335   {
336     if (Configuration.DEBUG)
337       log.entering(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$
338     providerInstalled = ProviderUtil.addProvider(provider) != -1;
339     if (Configuration.DEBUG)
340       log.exiting(this.getClass().getName(), "installNewProvider"); //$NON-NLS-1$
341   }
342
343   /**
344    * After processing the command line arguments, this method is invoked to
345    * process the parameters which may have been encountered among the actual
346    * arguments, and which are specific to the signing action of the tool.
347    * 
348    * @throws KeyStoreException if no implementation of the designated (or
349    *           default type) of a key store is availabe.
350    * @throws IOException if an I/O related exception occurs during the process.
351    * @throws NoSuchAlgorithmException if an implementation of an algorithm used
352    *           by the key store is not available.
353    * @throws CertificateException if an exception occurs while reading a
354    *           certificate from the key store.
355    * @throws UnsupportedCallbackException if no implementation of a password
356    *           callback is available.
357    * @throws UnrecoverableKeyException if the wrong password was used to unlock
358    *           the key store.
359    * @throws SecurityException if the designated alias is not known to the key
360    *           store or is not an Alias of a Key Entry.
361    */
362   private void setupSigningParams() throws KeyStoreException, IOException,
363       NoSuchAlgorithmException, CertificateException,
364       UnsupportedCallbackException, UnrecoverableKeyException
365   {
366     if (Configuration.DEBUG)
367       log.entering(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$
368     if (ksURL == null || ksURL.trim().length() == 0)
369       {
370         String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$
371         if (userHome == null || userHome.trim().length() == 0)
372           throw new SecurityException(Messages.getString("Main.85")); //$NON-NLS-1$
373
374         ksURL = "file:" + userHome.trim() + "/.keystore"; //$NON-NLS-1$ //$NON-NLS-2$
375       }
376     else
377       {
378         ksURL = ksURL.trim();
379         if (ksURL.indexOf(":") == -1) //$NON-NLS-1$
380           ksURL = "file:" + ksURL; //$NON-NLS-1$
381       }
382
383     if (ksType == null || ksType.trim().length() == 0)
384       ksType = KeyStore.getDefaultType();
385     else
386       ksType = ksType.trim();
387
388     store = KeyStore.getInstance(ksType);
389
390     if (ksPassword == null)
391       {
392         // ask the user to provide one
393         PasswordCallback pcb = new PasswordCallback(Messages.getString("Main.92"), //$NON-NLS-1$
394                                                     false);
395         getCallbackHandler().handle(new Callback[] { pcb });
396         ksPasswordChars = pcb.getPassword();
397       }
398     else
399       ksPasswordChars = ksPassword.toCharArray();
400
401     URL url = new URL(ksURL);
402     InputStream stream = url.openStream();
403     store.load(stream, ksPasswordChars);
404
405     if (! store.containsAlias(alias))
406       throw new SecurityException(Messages.getFormattedString("Main.6", alias)); //$NON-NLS-1$
407
408     if (! store.isKeyEntry(alias))
409       throw new SecurityException(Messages.getFormattedString("Main.95", alias)); //$NON-NLS-1$
410
411     Key key;
412     if (password == null)
413       {
414         passwordChars = ksPasswordChars;
415         try
416           {
417             key = store.getKey(alias, passwordChars);
418           }
419         catch (UnrecoverableKeyException x)
420           {
421             // ask the user to provide one
422             String prompt = Messages.getFormattedString("Main.97", alias); //$NON-NLS-1$
423             PasswordCallback pcb = new PasswordCallback(prompt, false);
424             getCallbackHandler().handle(new Callback[] { pcb });
425             passwordChars = pcb.getPassword();
426             // take 2
427             key = store.getKey(alias, passwordChars);
428           }
429       }
430     else
431       {
432         passwordChars = password.toCharArray();
433         key = store.getKey(alias, passwordChars);
434       }
435
436     if (! (key instanceof PrivateKey))
437       throw new SecurityException(Messages.getFormattedString("Main.99", alias)); //$NON-NLS-1$
438
439     signerPrivateKey = (PrivateKey) key;
440     signerCertificateChain = store.getCertificateChain(alias);
441     if (Configuration.DEBUG)
442       log.fine(String.valueOf(signerCertificateChain));
443
444     if (sigFileName == null)
445       sigFileName = alias;
446
447     sigFileName = sigFileName.toUpperCase(EN_US_LOCALE);
448     if (sigFileName.length() > 8)
449       sigFileName = sigFileName.substring(0, 8);
450
451     char[] chars = sigFileName.toCharArray();
452     for (int i = 0; i < chars.length; i++)
453       {
454         char c = chars[i];
455         if (! (Character.isLetter(c)
456             || Character.isDigit(c)
457             || c == '_'
458             || c == '-'))
459           chars[i] = '_';
460       }
461
462     sigFileName = new String(chars);
463
464     if (signedJarFileName == null)
465       signedJarFileName = jarFileName;
466
467     if (Configuration.DEBUG)
468       log.exiting(this.getClass().getName(), "setupSigningParams"); //$NON-NLS-1$
469   }
470
471   boolean isVerbose()
472   {
473     return verbose;
474   }
475
476   boolean isCerts()
477   {
478     return certs;
479   }
480
481   String getSigFileName()
482   {
483     return this.sigFileName;
484   }
485
486   String getJarFileName()
487   {
488     return this.jarFileName;
489   }
490
491   boolean isSectionsOnly()
492   {
493     return this.sectionsOnly;
494   }
495
496   boolean isInternalSF()
497   {
498     return this.internalSF;
499   }
500
501   PrivateKey getSignerPrivateKey()
502   {
503     return this.signerPrivateKey;
504   }
505
506   Certificate[] getSignerCertificateChain()
507   {
508     return signerCertificateChain;
509   }
510
511   String getSignedJarFileName()
512   {
513     return this.signedJarFileName;
514   }
515
516   /**
517    * Return a CallbackHandler which uses the Console (System.in and System.out)
518    * for interacting with the user.
519    * <p>
520    * This method first finds all currently installed security providers capable
521    * of providing such service and then in turn attempts to instantiate the
522    * handler from those providers. As soon as one provider returns a non-null
523    * instance of the callback handler, the search stops and that instance is
524    * set to be used from now on.
525    * <p>
526    * If no installed providers were found, this method falls back on the GNU
527    * provider, by-passing the Security search mechanism. The default console
528    * callback handler implementation is {@link ConsoleCallbackHandler}.
529    * 
530    * @return a console-based {@link CallbackHandler}.
531    */
532   protected CallbackHandler getCallbackHandler()
533   {
534     if (handler == null)
535       handler = CallbackUtil.getConsoleHandler();
536
537     return handler;
538   }
539
540   private class ToolParserCallback
541       extends FileArgumentCallback
542   {
543     public void notifyFile(String fileArgument)
544     {
545       fileAndAlias.add(fileArgument);
546     }
547   }
548
549   private class ToolParser
550       extends ClasspathToolParser
551   {
552     public ToolParser()
553     {
554       super(KEYTOOL_TOOL, true);
555     }
556
557     protected void validate() throws OptionException
558     {
559       if (fileAndAlias.size() < 1)
560         throw new OptionException(Messages.getString("Main.133")); //$NON-NLS-1$
561
562       jarFileName = (String) fileAndAlias.get(0);
563       if (! verify) // must have an ALIAS. use "mykey" if undefined
564         if (fileAndAlias.size() < 2)
565           {
566             if (Configuration.DEBUG)
567               log.fine("Missing ALIAS argument. Will use [mykey] instead"); //$NON-NLS-1$
568             alias = "mykey"; //$NON-NLS-1$
569           }
570         else
571           alias = (String) fileAndAlias.get(1);
572     }
573
574     public void initializeParser()
575     {
576       setHeader(Messages.getString("Main.2")); //$NON-NLS-1$
577       setFooter(Messages.getString("Main.1")); //$NON-NLS-1$
578       OptionGroup signGroup = new OptionGroup(Messages.getString("Main.0")); //$NON-NLS-1$
579       signGroup.add(new Option("keystore", //$NON-NLS-1$
580                                Messages.getString("Main.101"), //$NON-NLS-1$
581                                Messages.getString("Main.102")) //$NON-NLS-1$
582       {
583         public void parsed(String argument) throws OptionException
584         {
585           ksURL = argument;
586         }
587       });
588       signGroup.add(new Option("storetype", //$NON-NLS-1$
589                                Messages.getString("Main.104"), //$NON-NLS-1$
590                                Messages.getString("Main.105")) //$NON-NLS-1$
591       {
592         public void parsed(String argument) throws OptionException
593         {
594           ksType = argument;
595         }
596       });
597       signGroup.add(new Option("storepass", //$NON-NLS-1$
598                                Messages.getString("Main.107"), //$NON-NLS-1$
599                                Messages.getString("Main.108")) //$NON-NLS-1$
600       {
601         public void parsed(String argument) throws OptionException
602         {
603           ksPassword = argument;
604         }
605       });
606       signGroup.add(new Option("keypass", //$NON-NLS-1$
607                                Messages.getString("Main.110"), //$NON-NLS-1$
608                                Messages.getString("Main.111")) //$NON-NLS-1$
609       {
610         public void parsed(String argument) throws OptionException
611         {
612           password = argument;
613         }
614       });
615       signGroup.add(new Option("sigfile", //$NON-NLS-1$
616                                Messages.getString("Main.113"), //$NON-NLS-1$
617                                Messages.getString("Main.114")) //$NON-NLS-1$
618       {
619         public void parsed(String argument) throws OptionException
620         {
621           sigFileName = argument;
622         }
623       });
624       signGroup.add(new Option("signedjar", //$NON-NLS-1$
625                                Messages.getString("Main.116"), //$NON-NLS-1$
626                                Messages.getString("Main.117")) //$NON-NLS-1$
627       {
628         public void parsed(String argument) throws OptionException
629         {
630           signedJarFileName = argument;
631         }
632       });
633       add(signGroup);
634
635       OptionGroup verifyGroup = new OptionGroup(Messages.getString("Main.118")); //$NON-NLS-1$
636       verifyGroup.add(new Option("verify", //$NON-NLS-1$
637                                  Messages.getString("Main.120")) //$NON-NLS-1$
638       {
639         public void parsed(String argument) throws OptionException
640         {
641           verify = true;
642         }
643       });
644       verifyGroup.add(new Option("certs", //$NON-NLS-1$
645                                  Messages.getString("Main.122")) //$NON-NLS-1$
646       {
647         public void parsed(String argument) throws OptionException
648         {
649           certs = true;
650         }
651       });
652       add(verifyGroup);
653
654       OptionGroup commonGroup = new OptionGroup(Messages.getString("Main.123")); //$NON-NLS-1$
655       commonGroup.add(new Option("verbose", //$NON-NLS-1$
656                                  Messages.getString("Main.125")) //$NON-NLS-1$
657       {
658         public void parsed(String argument) throws OptionException
659         {
660           verbose = true;
661         }
662       });
663       commonGroup.add(new Option("internalsf", //$NON-NLS-1$
664                                  Messages.getString("Main.127")) //$NON-NLS-1$
665       {
666         public void parsed(String argument) throws OptionException
667         {
668           internalSF = true;
669         }
670       });
671       commonGroup.add(new Option("sectionsonly", //$NON-NLS-1$
672                                  Messages.getString("Main.129")) //$NON-NLS-1$
673       {
674         public void parsed(String argument) throws OptionException
675         {
676           sectionsOnly = true;
677         }
678       });
679       commonGroup.add(new Option("provider", //$NON-NLS-1$
680                                  Messages.getString("Main.131"), //$NON-NLS-1$
681                                  Messages.getString("Main.132")) //$NON-NLS-1$
682       {
683         public void parsed(String argument) throws OptionException
684         {
685           providerClassName = argument;
686         }
687       });
688       add(commonGroup);
689     }
690   }
691 }