All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aoindustries.aoserv.client.aosh.AOSH Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ Platform.
 * Copyright (C) 2001-2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client.aosh;

import com.aoindustries.aoserv.client.AOServClientConfiguration;
import com.aoindustries.aoserv.client.AOServConnector;
import com.aoindustries.aoserv.client.AOServTable;
import com.aoindustries.aoserv.client.account.Account;
import com.aoindustries.aoserv.client.account.User;
import com.aoindustries.aoserv.client.linux.Group;
import com.aoindustries.aoserv.client.linux.PosixPath;
import com.aoindustries.aoserv.client.linux.User.Gecos;
import com.aoindustries.aoserv.client.net.FirewallZone;
import com.aoindustries.aoserv.client.schema.Table;
import com.aoindustries.aoserv.client.schema.TableTable;
import com.aoindustries.aoserv.client.schema.Type;
import com.aoindustries.exception.ConfigurationException;
import com.aoindustries.io.TerminalWriter;
import com.aoindustries.net.DomainName;
import com.aoindustries.net.Email;
import com.aoindustries.net.HostAddress;
import com.aoindustries.net.InetAddress;
import com.aoindustries.net.Port;
import com.aoindustries.sql.SQLUtility;
import com.aoindustries.util.ShellInterpreter;
import com.aoindustries.validation.ValidationException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.CharArrayReader;
import java.io.Console;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.SQLException;
import java.util.Locale;

/**
 * AOSH is a command interpreter and scripting language
 * based on the Bourne shell.  It may be used to control the
 * AOServ Client utilities.
 *
 * @author  AO Industries, Inc.
 */
final public class AOSH extends ShellInterpreter {

	private static final Reader nullInput=new CharArrayReader(new char[0]);

	final private AOServConnector connector;

	public AOSH(AOServConnector connector, Reader in, TerminalWriter out, TerminalWriter err) {
		super(in, out, err);
		this.connector=connector;
	}

	public AOSH(AOServConnector connector, Reader in, TerminalWriter out, TerminalWriter err, String ... args) {
		super(in, out, err, args);
		this.connector=connector;
	}

	public static boolean checkMinParamCount(String function, String[] args, int minCount, PrintWriter err) {
		int paramCount=args.length-1;
		if(paramCountmaxCount) {
			err.print("aosh: ");
			err.print(function);
			err.println(": too many parameters");
			err.flush();
			return false;
		}
		return true;
	}

	private void echo(String[] args) {
		for(int c=1;c1) out.print(' ');
			out.print(args[c]);
		}
		out.println();
		out.flush();
	}

	public static String executeCommand(AOServConnector connector, String[] args) throws IOException, SQLException {
		StringWriter buff = new StringWriter();
		TerminalWriter out=new TerminalWriter(buff);
		out.setEnabled(false);
		AOSH sh=new AOSH(connector, nullInput, out, out);
		sh.handleCommand(args);
		out.flush();
		return buff.toString();
	}

	@Override
	protected String getName() {
		return "aosh";
	}

	@Override
	protected String getPrompt() throws SQLException, IOException {
		return '['+connector.getCurrentAdministrator().toString()+'@'+connector.getHostname()+"]$ ";
	}

	/** Avoid repeated array copies. */
	private static final int numTables = Table.TableID.values().length;

	/**
	 * Processes one command and returns.
	 *
	 * @param  args  the command and argments to process
	 *
	 * @return  true if more commands should be processed
	 */
	@Override
	public boolean handleCommand(String[] args) throws IOException, SQLException {
		int argCount=args.length;
		if(argCount>0) {
			String command=args[0];
			if(Command.EXIT.equalsIgnoreCase(command)) {
				if(argCount!=1) {
					err.println("aosh: "+Command.EXIT+": too many parameters");
					err.flush();
				} else return false;
			} else {
				if(Command.CLEAR.equalsIgnoreCase(command)) clear(args);
				else if(Command.ECHO.equalsIgnoreCase(command)) echo(args);
				else if(Command.INVALIDATE.equalsIgnoreCase(command)) invalidate(args);
				else if(Command.JOBS.equalsIgnoreCase(command)) jobs(args);
				else if(Command.PING.equalsIgnoreCase(command)) ping(args);
				else if(Command.REPEAT.equalsIgnoreCase(command)) repeat(args);
				else if(Command.SLEEP.equalsIgnoreCase(command)) sleep(args);
				else if(Command.SU.equalsIgnoreCase(command)) su(args);
				else if(Command.TIME.equalsIgnoreCase(command)) time(args);
				else if(Command.WHOAMI.equalsIgnoreCase(command)) whoami(args);
				else {
					boolean done=false;
					CommandTable commandTable = connector.getAosh().getCommand();
					Command aoshCommand = commandTable.get(command);
					if(aoshCommand == null) {
						// Case-insensitive search
						for(Command com : commandTable.getRows()) {
							if(com.getCommand().equalsIgnoreCase(command)) {
								aoshCommand = com;
								break;
							}
						}
					}
					if(aoshCommand!=null) {
						AOServTable table = aoshCommand.getTable(connector).getAOServTable(connector);
						done=table.handleCommand(args, in, out, err, isInteractive());
						if(!done) throw new RuntimeException("AOSHCommand found, but command not processed.  command='"+command+"', table='"+table.getTableName()+'\'');
					}
					/*
					for(int c=0;c=0) {
				connector.getSimpleAOClient().invalidate(tableID, args.length>2?args[2]:null);
			} else {
				err.print("aosh: "+Command.INVALIDATE+": unable to find table: ");
				err.println(tableName);
				err.flush();
			}
		}
	}

	public static void main(String[] args) {
		TerminalWriter out=new TerminalWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
		TerminalWriter err=System.out==System.err ? out : new TerminalWriter(new BufferedWriter(new OutputStreamWriter(System.err)));
		try {
			User.Name username = getConfigUsername(System.in, err);
			String password = getConfigPassword(System.in, err);
			AOServConnector connector = AOServConnector.getConnector(username, password);
			AOSH aosh=new AOSH(connector, new BufferedReader(new InputStreamReader(System.in)), out, err, args);
			aosh.run();
			if(aosh.isInteractive()) {
				out.println();
				out.flush();
			}
		} catch(RuntimeException | IOException exc) {
			err.println("aosh: unable to connect: "+exc.getMessage());
			err.flush();
		}
	}

	public static User.Name getConfigUsername(InputStream in, TerminalWriter err) throws ConfigurationException, IOException {
		User.Name username = AOServClientConfiguration.getUsername();
		if(username == null) {
			try {
				// Prompt for the username
				String prompt = "Username: ";
				Console console = System.console();
				if(console == null) {
					err.print(prompt);
					err.flush();
					username = User.Name.valueOf(readLine(in));
					err.flush();
				} else {
					username = User.Name.valueOf(console.readLine(prompt));
					if(username == null) throw new EOFException("End-of-file reading username");
				}
			} catch(ValidationException e) {
				throw new IOException(e);
			}
		}
		return username;
	}

	public static String getConfigPassword(InputStream in, TerminalWriter err) throws ConfigurationException, IOException {
		String password = AOServClientConfiguration.getPassword();
		if(password == null || password.isEmpty()) {
			// Prompt for the password
			String prompt = "Password: ";
			Console console = System.console();
			if(console == null) {
				err.print(prompt);
				err.flush();
				password = readLine(in);
				err.flush();
			} else {
				char[] pwchars = console.readPassword(prompt);
				if(pwchars == null) throw new EOFException("End-of-file reading password");
				password = new String(pwchars);
			}
		}
		return password;
	}

	@Override
	protected AOSH newShellInterpreter(Reader in, TerminalWriter out, TerminalWriter err, String[] args) {
		return new AOSH(connector, in, out, err, args);
	}

	public static Account.Name parseAccountingCode(String S, String field) {
		try {
			return Account.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for accounting (" + field + "): " + S, err);
		}
	}

	public static BigDecimal parseBigDecimal(String S, String field) {
		try {
			return new BigDecimal(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for big_decimal (" + field + "): " + S, err);
		}
	}

	public static boolean parseBoolean(String S, String field) {
		if(
			S.equalsIgnoreCase("true")
			|| S.equalsIgnoreCase("t")
			|| S.equalsIgnoreCase("yes")
			|| S.equalsIgnoreCase("y")
			|| S.equalsIgnoreCase("vang")
			|| S.equalsIgnoreCase("da")
			|| S.equalsIgnoreCase("si")
			|| S.equalsIgnoreCase("oui")
			|| S.equalsIgnoreCase("ja")
			|| S.equalsIgnoreCase("nam")
		) return true;
		else if(
			S.equalsIgnoreCase("false")
			|| S.equalsIgnoreCase("f")
			|| S.equalsIgnoreCase("no")
			|| S.equalsIgnoreCase("n")
			|| S.equalsIgnoreCase("khong")
			|| S.equalsIgnoreCase("nyet")
			|| S.equalsIgnoreCase("non")
			|| S.equalsIgnoreCase("nien")
			|| S.equalsIgnoreCase("la")
		) return false;
		else throw new IllegalArgumentException("Invalid argument for boolean (" + field + "): " + S);
	}

	/**
	 * @see  SQLUtility#parseDate(java.lang.String, java.util.TimeZone)
	 * @see  Type#DATE_TIME_ZONE
	 */
	public static Date parseDate(String S, String field) {
		try {
			return SQLUtility.parseDate(S, Type.DATE_TIME_ZONE);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for date (" + field + "): " + S, err);
		}
	}

	public static FirewallZone.Name parseFirewalldZoneName(String S, String field) {
		try {
			return FirewallZone.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for firewalld zone (" + field + "): " + S, err);
		}
	}

	public static HostAddress parseHostAddress(String S, String field) {
		try {
			return HostAddress.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for host address (" + field + "): " + S, err);
		}
	}

	public static int parseInt(String S, String field) {
		try {
			return Integer.parseInt(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for int (" + field + "): " + S, err);
		}
	}

	public static float parseFloat(String S, String field) {
		try {
			return Float.parseFloat(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for float (" + field + "): " + S, err);
		}
	}

	public static long parseLong(String S, String field) {
		try {
			return Long.parseLong(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for long (" + field + "): " + S, err);
		}
	}

	/**
	 * @see  SQLUtility#parseDecimal3(java.lang.String)
	 */
	public static int parseDecimal3(String S, String field) {
		try {
			return SQLUtility.parseDecimal3(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for decimal (" + field + "): " + S, err);
		}
	}

	public static int parseOctalInt(String S, String field) {
		try {
			return Integer.parseInt(S, 8);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for octal int (" + field + "): " + S, err);
		}
	}

	public static long parseOctalLong(String S, String field) {
		try {
			return Long.parseLong(S, 8);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for octal long (" + field + "): " + S, err);
		}
	}

	/**
	 * @see  SQLUtility#parseDecimal2(java.lang.String)
	 */
	public static int parseDecimal2(String S, String field) {
		try {
			return SQLUtility.parseDecimal2(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for decimal (" + field + "): " + S, err);
		}
	}

	public static short parseShort(String S, String field) {
		try {
			return Short.parseShort(S);
		} catch(NumberFormatException err) {
			throw new IllegalArgumentException("Invalid argument for short (" + field + "): " + S, err);
		}
	}

	public static DomainName parseDomainName(String S, String field) {
		try {
			return DomainName.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for domain_name (" + field + "): " + S, err);
		}
	}

	public static Email parseEmail(String S, String field) {
		try {
			return Email.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for email address (" + field + "): " + S, err);
		}
	}

	public static Gecos parseGecos(String S, String field) {
		try {
			return Gecos.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for gecos (" + field + "): " + S, err);
		}
	}

	public static Group.Name parseGroupName(String S, String field) {
		try {
			return Group.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for group (" + field + "): " + S, err);
		}
	}

	public static InetAddress parseInetAddress(String S, String field) {
		try {
			return InetAddress.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for ip_address (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.linux.User.Name parseLinuxUserName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.linux.User.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for Linux username (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.mysql.Database.Name parseMySQLDatabaseName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.mysql.Database.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for MySQL database name (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.mysql.Server.Name parseMySQLServerName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.mysql.Server.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for MySQL server name (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.mysql.User.Name parseMySQLUserName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.mysql.User.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for MySQL username (" + field + "): " + S, err);
		}
	}

	public static Port parsePort(
		String port,
		String portField,
		String protocol,
		String protocolField
	) {
		int portInt = parseInt(port, portField);
		com.aoindustries.net.Protocol protocolObj;
		try {
			protocolObj = com.aoindustries.net.Protocol.valueOf(protocol.toUpperCase(Locale.ROOT));
		} catch(IllegalArgumentException e) {
			throw new IllegalArgumentException("Invalid argument for protocol ("+protocolField+"): "+protocol, e);
		}
		try {
			return Port.valueOf(
				portInt,
				protocolObj
			);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for port ("+portField+"): "+port, err);
		}
	}

	public static com.aoindustries.aoserv.client.postgresql.Database.Name parsePostgresDatabaseName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.postgresql.Database.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for PostgreSQL database name (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.postgresql.Server.Name parsePostgresServerName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.postgresql.Server.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for PostgreSQL server name (" + field + "): " + S, err);
		}
	}

	public static com.aoindustries.aoserv.client.postgresql.User.Name parsePostgresUserName(String S, String field) {
		try {
			return com.aoindustries.aoserv.client.postgresql.User.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for PostgreSQL username (" + field + "): " + S, err);
		}
	}

	public static PosixPath parseUnixPath(String S, String field) {
		try {
			return PosixPath.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for POSIX path (" + field + "): " + S, err);
		}
	}

	public static User.Name parseUserName(String S, String field) {
		try {
			return User.Name.valueOf(S);
		} catch(ValidationException err) {
			throw new IllegalArgumentException("Invalid argument for username (" + field + "): " + S, err);
		}
	}

	private void ping(String[] args) throws IOException, SQLException {
		if(checkParamCount(Command.PING, args, 0, err)) {
			out.print(connector.getSimpleAOClient().ping());
			out.println(" ms");
			out.flush();
		}
	}

	public static String readLine(InputStream in) throws IOException {
		StringBuilder SB=new StringBuilder();
		readLine(in, SB);
		return SB.toString();
	}

	public static void readLine(InputStream in, StringBuilder SB) throws IOException {
		SB.setLength(0);
		int ch;
		while((ch=in.read())!=-1 && ch!='\n') if(ch!='\r') SB.append((char)ch);
	}

	private void repeat(String[] args) throws IOException, SQLException {
		int argCount=args.length;
		if(argCount>2) {
			try {
				int count=Integer.parseInt(args[1]);
				if(count>=0) {
					String[] newArgs=new String[argCount-2];
					System.arraycopy(args, 2, newArgs, 0, argCount-2);

					for(int c=0;c1) {
			try {
				for(int c=1;c=2) {
			try {
				String[] newArgs=new String[argCount+(isInteractive()?0:-1)];
				int pos=0;
				if(isInteractive()) newArgs[pos++]="-i";
				newArgs[pos++]="--";
				System.arraycopy(args, 2, newArgs, pos, argCount-2);
				new AOSH(
					connector.switchUsers(User.Name.valueOf(args[1])
					),
					in,
					out,
					err,
					newArgs
				).run();
			} catch(ValidationException e) {
				err.println("aosh: "+Command.SU+": " + e.getResult().toString());
				err.flush();
			}
		} else {
			err.println("aosh: "+Command.SU+": not enough parameters");
			err.flush();
		}
	}

	private void time(String[] args) throws IOException, SQLException {
		int argCount=args.length;
		if(argCount>1) {
			String[] newArgs=new String[argCount-1];
			System.arraycopy(args, 1, newArgs, 0, argCount-1);
			long startTime=System.currentTimeMillis();
			try {
				handleCommand(newArgs);
			} finally {
				long timeSpan=System.currentTimeMillis()-startTime;
				int mins=(int)(timeSpan/60000);
				int secs=(int)(timeSpan%60000);
				out.println();
				out.print("real    ");
				out.print(mins);
				out.print('m');
				out.print(SQLUtility.formatDecimal3(secs));
				out.println('s');
				out.flush();
			}
		} else {
			err.println("aosh: "+Command.TIME+": not enough parameters");
			err.flush();
		}
	}

	private void whoami(String[] args) throws SQLException, IOException {
		if(args.length==1) {
			out.println(connector.getCurrentAdministrator().getUsername().getUsername());
			out.flush();
		} else {
			err.println("aosh: "+Command.WHOAMI+": too many parameters");
			err.flush();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy