/*
* Mibble MIB Parser (www.mibble.org)
*
* See LICENSE.txt for licensing information.
*
* Copyright (c) 2004-2017 Per Cederberg. All rights reserved.
*/
package net.percederberg.mibble;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.ArrayList;
/**
* A program that parses and validates a MIB file. If the MIB file(s)
* specified on the command-line uses constructs or syntax that are
* not supported, an error message will be printed to the standard
* output. The program will also return the number of validation
* failures as its exit code.
*
* @author Per Cederberg
* @version 2.10
* @since 2.0
*/
public class MibbleValidator {
/**
* The command-line help output.
*/
private static final String COMMAND_HELP =
"Validates a set of SNMP MIB files. This program comes with\n" +
"ABSOLUTELY NO WARRANTY; for details see the LICENSE.txt file.\n" +
"\n" +
"Syntax: MibbleValidator <file(s) or URL(s)>";
/**
* The internal error message.
*/
private static final String INTERNAL_ERROR =
"INTERNAL ERROR: An internal error has been found. Please report\n" +
" this error to the maintainers (see the web site for\n" +
" instructions). Be sure to include the version number, as\n" +
" well as the text below:\n";
/**
* The application main entry point.
*
* @param args the command-line parameters
*/
public static void main(String[] args) {
// Check command-line arguments
if (args.length < 1) {
printHelp("No file(s) specified");
System.exit(1);
}
ArrayList<Object> queue = new ArrayList<>();
for (String arg : args) {
try {
if (arg.contains(":")) {
queue.add(new URL(arg));
} else {
File file = new File(arg);
if (!file.exists()) {
System.out.println("Warning: Skipping " + arg +
": file not found");
} else if (file.isDirectory()) {
addMibs(file, queue);
} else {
queue.add(file);
}
}
} catch (MalformedURLException e) {
System.out.println("Warning: Skipping " + arg +
": " + e.getMessage());
}
}
// Parse MIB files
MibLoader loader = new MibLoader();
int errors = 0;
int warnings = 0;
for (int i = 0; i < queue.size(); i++) {
Object src = queue.get(i);
System.out.print(i + 1);
System.out.print("/");
System.out.print(queue.size());
System.out.print(": Reading " + src + "... ");
System.out.flush();
try {
loader.unloadAll();
Mib mib = null;
if (src instanceof URL) {
loader.removeAllDirs();
mib = loader.load((URL) src);
} else {
File file = (File) src;
if (!loader.hasDir(file.getParentFile())) {
loader.removeAllDirs();
loader.addDir(file.getParentFile());
}
mib = loader.load(file);
}
System.out.println("[OK]");
if (mib.getLog().warningCount() > 0) {
mib.getLog().printTo(System.out);
warnings++;
}
} catch (FileNotFoundException e) {
System.out.println("[FAILED]");
printError(src.toString(), e);
errors++;
} catch (IOException e) {
System.out.println("[FAILED]");
printError(src.toString(), e);
errors++;
} catch (MibLoaderException e) {
System.out.println("[FAILED]");
e.getLog().printTo(System.out);
errors++;
} catch (RuntimeException e) {
System.out.println();
printInternalError(e);
System.exit(1);
}
}
// Print error count
System.out.println();
System.out.println("Files processed: " + queue.size());
System.out.println(" with errors: " + errors);
System.out.println(" with warnings: " + warnings);
if (errors > 0) {
System.err.println("Error: validation errors were encountered");
}
// Return error count
System.exit(errors);
}
/**
* Prints command-line help information.
*
* @param error an optional error message, or null
*/
private static void printHelp(String error) {
System.err.println(COMMAND_HELP);
System.err.println();
if (error != null) {
System.err.print("Error: ");
System.err.println(error);
System.err.println();
}
}
/**
* Prints an internal error message. This type of error should
* only be reported when run-time exceptions occur, such as null
* pointer and the likes. All these error should be reported as
* bugs to the program maintainers.
*
* @param e the exception to be reported
*/
private static void printInternalError(Exception e) {
System.err.println(INTERNAL_ERROR);
e.printStackTrace();
}
/**
* Prints a file not found error message.
*
* @param file the file name not found
* @param e the detailed exception
*/
private static void printError(String file, FileNotFoundException e) {
StringBuilder buffer = new StringBuilder();
buffer.append("Error: couldn't open file:");
buffer.append("\n ");
buffer.append(file);
System.out.println(buffer.toString());
}
/**
* Prints a URL not found error message.
*
* @param url the URL not found
* @param e the detailed exception
*/
private static void printError(String url, IOException e) {
StringBuilder buffer = new StringBuilder();
buffer.append("Error: couldn't open URL:");
buffer.append("\n ");
buffer.append(url);
System.out.println(buffer.toString());
}
/**
* Adds all MIB files from a directory to the specified queue.
*
* @param dir the directory to check
* @param queue the queue to add files to
*
* @since 2.9
*/
private static void addMibs(File dir, ArrayList<Object> queue) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isHidden()) {
// Hidden file or directories are ignored
} else if (file.isDirectory()) {
addMibs(file, queue);
} else if (isMib(file)) {
queue.add(file);
}
}
}
}
/**
* Checks if the first lines of a text files looks like a MIB.
*
* @param file the file to check
*
* @return true if the file is probably a MIB file, or
* false otherwise
*
* @since 2.9
*/
private static boolean isMib(File file) {
if (!file.canRead() || !file.isFile()) {
return false;
}
try (
BufferedReader in = new BufferedReader(new FileReader(file));
) {
while (true) {
String str = in.readLine();
if (str == null) {
break;
}
str = str.trim();
if (!str.equals("") && !str.startsWith("--")) {
return str.contains("DEFINITIONS");
}
}
} catch (Exception ignore) {
// Do nothing
}
return false;
}
}