/* * Burn.java * * Copyright (c) 2007 Vreixo Formoso * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * See COPYING file for details. */ package org.pykix.libburnia.libburn; /** * Library initialization/shutdown and miscellaneous functions. * * * @author Vreixo Formoso * @since 0.1 */ public class Burn { static final String JNI_LIBRARY_NAME = "java-libburn-0.1"; /** Maximum number of particularly permissible drive addresses. */ public static final int WHITELIST_LEN = 255; /** * Initialize the library. * *
* This must be called before using any other functions in the library. It * may be called more than once with no effect. * *
* It is possible to 'restart' the library by shutting it down and * re-initializing it. This is necessary if you follow the older and * more general way of accessing a drive via burn_drive_scan() and * burn_drive_grab(). See burn_drive_scan_and_grab() with its strong * urges and its explanations. TODO fix this comment * * @throws BurnException * If library initialization fails. */ public static void initialize() throws BurnException { if ( burn_initialize() == 0 ) { throw new BurnException("Can't initialize libburnia library"); } } /** * Shutdown the library. * *
* This should be called before exiting your application. Make sure that all * drives you have grabbed are released before calling this. */ public static void finish() { burn_finish(); } /** * Set parameters for behavior on opening device files. To be called early * after {@link #initialize()} and before any bus scan. But not mandatory at * all. * *
* Parameter value 1 enables a feature, 0 disables. Default is (1,0,0). * Have a good reason before you change it. * * @param exclusive *
true
to allow all implemented profiles,
* false
only tested media (default)
*/
public static void allowUntestedProfiles(boolean yes) {
burn_allow_untested_profiles(yes);
}
/**
* Scan for drives.
*
* * No drives may be in use when this is called. All drive objects are * invalidated by using this function. Do NOT store drive * objects across calls to this function or death AND pain will ensue. * *
* After this call all drives depicted by the returned array are subject * to eventual (O_EXCL) locking. See burn_preset_device_open(). This state * ends either with burn_drive_info_forget() or with burn_drive_release(). * *
* It is unfriendly to other processes on the system to hold drives locked * which one does not definitely plan to use soon. * * @return * an array of drive info items (cdroms/burners). * The returned array must be freed by burn_drive_info_free() * before burn_finish(), and also before calling this function * burn_drive_scan() again. * @throws BurnException * If scan fails * * TODO correct above comment */ public static DriveInfo[] scan() throws BurnException { DriveInfo[] infos = burn_drive_scan(); if ( infos == null ) { throw new BurnException("No drives found"); } return infos; } /** * Aquire a drive with known persistent address. * *
* This is the sysadmin friendly way to open one drive and to leave all * others untouched. It bundles the following API calls to form a * non-obtrusive way to use libburn: * burn_drive_add_whitelist() , {@link #scan()}, {@link Drive#grab(boolean)} * *
* You are strongly urged to use this call whenever you know the * drive address in advance. * *
* If not, then you have to use directly above calls. In that case, you are * strongly urged to drop any unintended drive which will be * exclusively occupied and not closed by {@link #scan()}. * This can be done by shutting down the library including a call to * {@link #finish()}. You may later start a new libburn session and should * then use the function described here with an address obtained after * {@link #scan()} via {@link DriveInfo#getAdr()}. * *
* Another way is to drop the unwanted drives by {@link DriveInfo#forget(int)}.
*
* @param adr
* The persistent address of the desired drive. Either obtained
* by {@link DriveInfo#getAdr()} or guessed skillfully by application
* resp. its user.
* @param load
* true
to make the drive attempt to load a disc (close
* its tray door, etc).
* @return
* A DriveInfo object with the requested cdrom/burner.
* @throws BurnException
* If drive not found.
*/
public static DriveInfo scanAndGrab(String adr, boolean load)
throws BurnException {
DriveInfo info = burn_drive_scan_and_grab(adr, load);
if ( info == null ) {
throw new BurnException("Drive not found");
}
return info;
}
/**
* Add a device to the list of permissible drives. As soon as some entry
* is in the whitelist all non-listed drives are banned from scanning.
*
*
* The number of devices that can be added to the whitelist is limited
* to {@link #WHITELIST_LEN}.
*
* @param adr
* The persistent address of the drive.
* @return
* true
on success, false
otherwise.
*/
public static boolean addWhiteList(String adr) {
return (burn_drive_add_whitelist(adr) == 1);
}
/**
* Remove all drives from whitelist. This enables all possible drives.
*/
public static void clearWhiteList() {
burn_drive_clear_whitelist();
}
/**
* Set the verbosity level of the library.
*
*
* The default value is 0, which means that nothing is output on stderr. * The more you increase this, the more debug output should be displayed * on stderr for you. * *
* This is for development only. Not suitable for applications.
*
* @param level
* The verbosity level desired. 0 for nothing, higher positive
* values for more information output.
*/
public static void setVerbosity(int level) {
burn_set_verbosity(level);
}
/**
* Evaluate wether the given address would be a possible persistent
* drive address of libburn.
*/
public static boolean isEnumerableAdr(String adr) {
return burn_drive_is_enumerable_adr(adr);
}
/**
* Try to convert a given existing filesystem address into a persistent
* drive address. This succeeds with symbolic links or if a hint about
* the drive's system address can be read from the filesystem object and
* a matching drive is found.
*
* @param path
* The address of an existing file system object
* @return
* The persistent address or null
on failure
*/
public static String convertFsAdr(String path) {
return burn_drive_convert_fs_adr(path);
}
/**
*
*/
public interface AbortHandler {
/**
* Function suitable to produce appeasing messages while
* burn is been canceled.
*
* @param patience
* Maximum number of seconds to wait.
* @param elapsed
* Elapsed number of seconds.
* @return
*/
public int abortPacifier(int patience, int elapsed);
}
/**
* Abort any running drive operation and finally call {@link #finish()}.
*
*
* You MUST calm down the busy drive if an aborting event occurs during a * burn run. For that you may call this function either from your own signal * handling code or indirectly by activating the builtin signal handling: * burn_set_signal_handling("my_app_name : ", NULL, 0); * *
* Else you may eventually call {@link Drive#cancel()} on the active drive
* and wait for it to assume state {@link DriveStatus#IDLE}.
*
* @param patience
* Maximum number of seconds to wait for drives to finish
* @param pacifier
* A function to produce appeasing messages. You can pass
* null
to not produce those messages.
* @return
* true
if all went well, false
if had
* to leave a drive in unclean state
* @throws BurnException
* On severe error, do no use libburn again
* @see #abort(int, String)
*/
public static boolean abort(int patience, AbortHandler pacifier)
throws BurnException {
return burn_abort_java(patience, pacifier);
}
/**
* Abort any running drive operation and finally call {@link #finish()}.
*
*
* You MUST calm down the busy drive if an aborting event occurs during a * burn run. For that you may call this function either from your own signal * handling code or indirectly by activating the builtin signal handling: * burn_set_signal_handling("my_app_name : ", NULL, 0); * *
* Else you may eventually call {@link Drive#cancel()} on the active drive * and wait for it to assume state {@link DriveStatus#IDLE}. * *
* This version of abort uses the default pacifier function that print
* messages to stdout.
*
* @param patience
* Maximum number of seconds to wait for drives to finish
* @param msg
* The message to be printed.
* @return
* true
if all went well, false
if had
* to leave a drive in unclean state
* @throws BurnException
* On severe error, do no use libburn again
* @see #abort(int, org.pykix.libburnia.libburn.Burn.AbortHandler)
*/
public static boolean abort(int patience, String msg) throws BurnException {
return burn_abort_def(patience, msg);
}
/**
* Interface suitable for {@link Burn#setSignalHandler(org.pykix.libburnia.libburn.Burn.SignalHandler, int)}
*/
public interface SignalHandler {
/**
* Function to be called when a signal is received.
*
* @param signum
* @param flag
* @return
* has to return -2 if it does not want the process to
* exit with value 1.
*/
public int handleSignal(int signum, int flag);
}
/**
* Control builtin signal handling. See also
* {@link #abort(int, org.pykix.libburnia.libburn.Burn.AbortHandler)}.
*
* @param handler
* A handler to be called on signals. It's
* {@link SignalHandler#handleSignal(int, int) handleSignal} method
* will be called when a signal is received. It should finally call
* {@link #abort(int, org.pykix.libburnia.libburn.Burn.AbortHandler)}.
* @param mode
* 0 call handler(signum, 0) on nearly all signals
* 1 enable system default reaction on all signals
* 2 try to ignore nearly all signals
* 10 like mode 2 but handle SIGABRT like with mode 0
*/
public static void setSignalHandler(SignalHandler handler, int mode) {
if ( handler == null ) {
throw new NullPointerException("Handler cannot be null");
}
burn_set_signal_handling(handler, mode);
}
/**
* Control builtin signal handling.
*
*
* This forces the usage of the default signal handler, that will * eventually call {@link #abort(int, String) abort} and then perform * exit(1). * *
* If you want to provide a custom signal handler you can use
* {@link #setSignalHandler(org.pykix.libburnia.libburn.Burn.SignalHandler, int)}
*
* @param msg
* If not null
then it is used as prefix for pacifier
* messages.
* @param mode
* 0 call handler(signum, 0) on nearly all signals
* 1 enable system default reaction on all signals
* 2 try to ignore nearly all signals
* 10 like mode 2 but handle SIGABRT like with mode 0
*/
public static void setDefaultSignalHandler(String msg, int mode) {
burn_set_default_signal_handling(msg, mode);
}
public static class Version {
public int major;
public int minor;
public int micro;
public Version(int major, int minor, int micro) {
super();
this.major = major;
this.minor = minor;
this.micro = micro;
}
@Override
public String toString() {
return major + "." + minor + "." + micro;
}
}
/**
* Returns the library's version.
*/
public static Version getVersion() {
return burn_version();
}
private static native int burn_initialize();
private static native void burn_finish();
private static native void burn_preset_device_open(int exclusive,
int blocking, int abort_on_busy);
private static native void burn_allow_untested_profiles(boolean yes);
private static native DriveInfo[] burn_drive_scan();
private static native DriveInfo burn_drive_scan_and_grab(String adr,
boolean load);
private static native int burn_drive_add_whitelist(String adr);
private static native void burn_drive_clear_whitelist();
private static native void burn_set_verbosity(int level);
private static native boolean burn_drive_is_enumerable_adr(String adr);
private static native String burn_drive_convert_fs_adr(String path);
private static native boolean burn_abort_def(int patience, String msg)
throws BurnException;
//TODO not tested at all!!
private static native boolean burn_abort_java(int patience, AbortHandler h)
throws BurnException;
private static native void burn_set_signal_handling(SignalHandler handler,
int mode);
private static native void burn_set_default_signal_handling(String msg,
int mode);
private static native Version burn_version();
static {
System.loadLibrary(JNI_LIBRARY_NAME);
}
}