Benjamin Chamberlain
May 9, 1996
Contents
1. Technical Overview
1.1 Design Overview
1.2 Source Code Overview
1.3 Compiling Notes
2. The Forms Libary
2.1 Xforms Information/Documentation
2.2 Xforms Programming Interface
2.3 Form Designer
2.4 Xforms and C++
3. Commands Reference
3.1 UNICOS Commands
3.2 Site-Specific Commands
3.3 Notes
4. Source Code Review (not complete)
4.1 Global variables
4.2 main()
4.3 Classes and Methods
4.3.1 main_window
4.3.2 files_window
4.3.3 volumes_window
4.3.4 volsetcat_window
4.3.5 filecat_window
4.3.6 volcat_window
4.3.7 tapestat_window
4.3.8 movevol_window
4.3.9 movemessage_window
4.3.10 newtar_window
4.3.11 opentar_window
4.3.12 tapeio
4.4 Other Routines
4.4.1 File and Directory Routines
4.4.2 CRL Listings Routines
4.4.3 CRL Catalog Entry Report Routines
4.4.4 CRL Catalog Entry Edition Routines
4.4.5 Miscellaneous CRL Routines
5. Known Bugs
6. Useful Future Additions
1 Technical Overview
1.1 Design Overview
An object oriented approach was used when designing xcrl. All windows in xcrl are objects, and an object is used to handle all tape IO operations.
In addition to these objects, all CRL functions are implemented with stand-alone routines.
The following diagram illustrates the interfaces between the various window objects of xcrl:
An arrow pointing from on window to another indicates that the first window calls a public method of the second.
This next diagram illustrates the interdependencies between the windows and the stand-alone routines that handle the retrieval of CRL volume set, file and volume listings:
This next diagram illustrates the interdependencies between the windows and the stand-alone routines that handle the retrieval of CRL catalog entries:
This next diagram illustrates the interdependencies between the windows and the stand-alone routines that handle the edition of CRL catalog entries:
This next diagram illustrates the interdependencies between the windows and the stand-alone routines that handle the movement of volumes to and from the silo:
This next diagram illustrates the interdependencies between the windows and the stand-alone routines that handle the creation, deletion, and checking of volume sets:
1.2 Source Code Overview
The source code of xcrl consists of the following files:
CRLCatEntries.c routines to obtain catalog entries
CRLCatEntries.h header file for CRLCatEntries.c
CRLEdit.c routines to edit catalog entries
CRLEdit.h header file for CRLEdit.c
CRLInOut.c routines to move volumes
CRLInOut.h header file for CRLInOut.c
CRLLists.c routines to list volsets, files & vols
CRLLists.h header file for CRLLists.c
CRLMisc.c miscellaneous CRL routines
CRLMisc.h header file for CRLMisc.c
FileCatWinC.c method definitions for the class filecat_window
FileCatWinC.h class definition for the class filecat_window
FileDir.c routines to check files and directories
FileDir.h header file for FileDir.c
FilesWinC.c method definitions for class files_window
FilesWinC.h class definition for class files_window
HelpWinC.c method definitions for class help_window
HelpWinC.h class definition for class help_window
ListC.c method definitions for class list
ListC.h class definition for class list
MainWinC.c method definitions for class main_window
MainWinC.h class definition for class main_window
Makefile the makefile
NewTarWinC.c method definitions for class newtar_window
NewTarWinC.h class definition for class newtar_window
OpenTarWinC.c method definitions for class opentar_window
OpenTarWinC.h class definition for class opentar_window
StringC.c method definitions for class string
StringC.h class definition for class string
TapeIOC.c method definitions for class tapeio
TapeIOC.h class definition for class tapeio
TapeStatWinC.c method definitions for class tapestat_window
TapeStatWinC.h class definition for class tapestat_window
VSCatWinC.c method definitions for class volsetcat_window
VSCatWinC.h class definition for class volsetcat_window
main.c the main routine
xforms.xcrl.c form structures and construction routines -
saved by Form Designer
xforms.xcrl.compiled.c compiled file corresponding to xforms.xcrl.c
xforms.xcrl.fd Form Designer file - read and saved by Form Designer
xforms.xcrl.h form structures definitions and construction
routine declarations - saved for Form
Designer
1.3 Compiling Notes
To compile xcrl, simply type make in the source directory.
The directory ptrrepository in the source directory is created by the C++ compiler when instantiating the list template class.
When compiling xforms.xcrl.compiled.o, you will receive warning messages about a variable fdui being used before set. Ignore these messages. For one, it the variable is a pointer being passed to a routine that uses the space it points to, so it is not a problem. Secondly, the compiler is complaining about xforms.xcrl.c, which the programmer shouldn't touch anyway (see the Form Designer section below).
2 The Forms Library
The Forms Library, or Xforms, is a graphical user interface toolkit based on Xlib (i.e. it doesn't use Xt). Xforms version .80 was used to develop the UI for xcrl.
This version of xforms was downloaded from the following location:
ftp://laue.phys.uwm.edu/pub/xforms/test/
and the file downloaded was:
bxform-crayYMP.tgz
2.1 Xforms Information
The Xforms Home Page is located at
http://bragg.phys.uwm.edu/xforms
An on-line manual for Xforms is located at:
http://www.westworld.com/~dau/xforms/forms.html
The mailing list for Xforms can be subscribed to by sending e-mail to
listserv@ra.york.cuny.edu
2.2 Xforms Programming Interface
The home page and on-line manual for Xforms contain plenty of information so little will be repeated here except for the most essential and xcrl-specific.
Xforms was used in two ways to develop xforms. First, the interactive GUI builder Form Designer was used to construct the "Forms", or windows, of the application. The Form Designer will be discussed further in the next section. Second, several Forms Library routines were used in the xcrl code to perform such actions as creating windows, popping up dialog boxes, getting information from input fields, etc. All Forms Library routine names begin with "fl_" so they are easy to spot.
The basic notion of Xforms is a "form," which to the programmer and user equates to a window. Forms are of the type FL_FORM in the Xforms library. Each form contains any number of objects, which are buttons, input fields, browsers, etc. Objects are of the type FL_OBJECT in the Xforms library. From within a program, forms are created, displayed and hidden, among other things. When a form is displayed, a window corresponding to that form appears on the screen, and takes user input. Each object has associated with it a callback routine, which is called whenever the object is activated in some way.
2.3 The Form Designer
The Form Designer, an interfactive GUI builder, was used to construct the windows of xcrl. The Form Designer executable, called fdesign, is located in the Xforms distribution in the DESIGN directory.
Fdesign uses three files: a .fd, a .c and a .h file. Each file has the same name besides the extension. In the case of xcrl, these files are called
xforms.xcrl.fd
xforms.xcrl.c
xforms.xcrl.h
The .fd file is the file which is read in by fdesign when opening a "User Interface" to code, and is the file which is saved by fdesign. When fdesign saves the .fd file, it also creates the .c and .h files.
The .c and .h files each contain the definitions and declarations of two items associated with each from created with the Form Designer - a unique structure corresponding to the form, and a routine with creates the forms and returns a pointer to the form's structure.
For example, a form may have the following structure and construction routine:
typedef struct {
FL_FORM *movemessage;
FL_OBJECT *close_button;
FL_OBJECT *title;
FL_OBJECT *message;
void *vdata;
long ldata;
} FD_movemessage;
FD_movemessage *create_form_movemessage(void)
{
FL_OBJECT *obj;
FD_movemessage *fdui = (FD_movemessage *) fl_calloc(1, sizeof(*fdui));
fdui->movemessage = fl_bgn_form(FL_NO_BOX, 360, 260);
obj = fl_add_box(FL_UP_BOX,0,0,360,260,"");
fl_set_object_color(obj,FL_WHITE,FL_COL1);
fdui->close_button = obj = fl_add_button(FL_NORMAL_BUTTON,130,220,110,30,"OK")
;
fl_set_object_color(obj,FL_LEFT_BCOL,FL_COL1);
fl_set_object_lstyle(obj,FL_BOLD_STYLE);
fl_set_object_callback(obj,movemessage_window::close_cb,0);
fdui->title = obj = fl_add_text(FL_NORMAL_TEXT,30,10,300,30,"");
fl_set_object_color(obj,FL_WHITE,FL_MCOL);
fl_set_object_lsize(obj,FL_MEDIUM_SIZE);
fl_set_object_lalign(obj,FL_ALIGN_CENTER);
fl_set_object_lstyle(obj,FL_BOLD_STYLE);
fdui->message = obj = fl_add_browser(FL_NORMAL_BROWSER,20,50,320,160,"");
fl_set_object_color(obj,FL_WHITE,FL_YELLOW);
fl_end_form();
return fdui;
}
The .h file contains the definition of the structure and a declartion of the construction routine and the .c file contains the definition of the construction routine for each form in the .fd file.
Since the .c and .h files are written by Form Designer, it is important that these file not be manually modified it the Form Designer it to be used again and the changes will be overwritten when the From Designer saves the source code.
2.4 Xforms and C++
A problem arises when using the files created by the Form Designer in a C++ program. The problem is that the Form Designer files register the callback routines for each object when that object is created in the construction routine. When a callback routine is a method of a class, it must be referenced in the following kind of way by the construction routine:
fl_set_object_callback(obj,movemessage_window::close_cb,0);
Note that the class (movemessage_window) must be used when referencing the callback routine. However, the class is undeclared when compiling the .c file. The #include could be added to the .c file to include the header file defining the class, but that would require modifying the .c file which is written by the Form Designer.
The following solution was used to alleviate this problem. Another files is used to hold the source code from the .c file and this file is the one that is compiled and linked together with the rest of the application. This file is called xforms.xcrl.compiled.c and looks like this:
#include "MainWinC.h"
#include "FilesWinC.h"
#include "VolsWinC.h"
#include "NewTarWinC.h"
#include "OpenTarWinC.h"
#include "VSCatWinC.h"
#include "FileCatWinC.h"
#include "VolCatWinC.h"
#include "HelpWinC.h"
#include "TapeStatWinC.h"
#include "MoveVolWinC.h"
#include "MoveMessageWinC.h"
#include "xforms.xcrl.c"
It consists of include statements for the header files of each of the classes which contain callback routines, followed by a #include of xforms.xcrl.c. This file is compiled and linked with the other object files.
Note: a problem similar to this existed in version .75 of the Forms Library in the .h file when the callback routines belonging to classes would be declared. However, starting with version .80, any method callback routines are not declared in the .h file.
3 Commands Reference
xcrl does its work by issueing commands to the host UNICOS computer. This section describes exactly which commands xcrl uses.
3.1 UNICOS Commands
The following listing describes each UNICOS command that is executed, and the routine and file it is used in:
UNICOS Command Routine File
/bin/rlr get_cat_entry CRLCatEntries.c
get_list CRLLists.c
check_volset CRLMisc.c
/bin/rlvedit edit_volset CRLEdit.c
/bin/rlfedit edit_file CRLEdit.c
/bin/rlvcreate create_new_volset CRLMisc.c
/bin/rlvscratch delete_vs CRLMisc.c
/bin/rsv rsv_cart TapeIOC.c
/bin/tpmnt mount_tape TapeIOC.c
/bin/cp copy TapeIOC.c
/bin/tar tar TapeIOC.c
/bin/rls rls_all TapeIOC.c
exec copy TapeIOC.c
tar TapeIOC.c
mount_tape TapeIOC.c
/bin/echo copy TapeIOC.c
tar TapeIOC.c
mount_tape TapeIOC.c
/bin/tail get_tape_msg_error TapeIOC.c
cd tar TapeIOC.c
3.2 Site-specific commands:
These two locally developed scripts are used by xcrl:
Scripts Routine File
/usr/local/bin/crlin crlin CRLInOut.c
/usr/local/bin/crlout crlout CRLInOut.c
3.3 Notes:
Note: all commands are opened issued either with popen() or system(). Also, all commands are echoed in the main window in their entriety with the exception of the cp, tar, and tpmnt commands. These commands are actually issued as something like:
echo $$; exec [command]
The echo command returns the process id of the shell executing the command. The exec commans executes the command with the processes id of its parent shell. Thus, the process id echo eventaully becomes the process id of the command.
This is done to obtain the process id of the command being executed. When either of these three commands are executed, they could take several minutes to complete. Therefore, the commands are issued to the host machine and left to run while xcrl continues on. The process id's of these commands must be known so that when the user cancels the operation, xcrl knows which process to kill.
These entire commands are not shown in the main window to hide what could be confusing complexity from the user, considering that users may see these commands and try to execute them exactly from the command line (it probably wouldn't be good to have the user do a command like the on above when all they really need to do is a copy).
4. Source Code Review (not complete)
4.1 Global variables
The main global variables in xcrl are pointers to each window object.
4.2 main()
4.3 Classes and methods
4.3.1 main_window
Class: main_window
Description: The main_window class defines the main_window object. It contains the user interface elements as well as the callback routines associated with those elements.
Note: all callback routines have to check the values of the username and volset fields before anything else as the values may have changed without the field callbacks being called. Thus, every callback (besideds the username and volset field callbacks) do this at the beginning of the routine.
Private data members:
FD_main *fp pointer to the Xforms structure for the main window form. Used to handle all user interface functions
int no_vs_flag true is a volset is in the volset field and valid, false otherwise
int un_state current state of username in username field,
can be OWNER, OTHER, or NONE
string cur_volset the current volset name - used to compare with a value entered the volset field and do nothing if they are identical
string cur_username the current username - used to compare with a value entered the username field and do nothing if they are identical
Public data members:
none.
Private methods:
void enable_volset_buttons();
void enable_object(FL_OBJECT *);
void disable_volset_buttons();
void disable_object(FL_OBJECT *);
void set_volset_true();
void set_volset_false();
string get_selected();
int set_browser();
int username_field_cb_function();
void add_browser_entries(list<string>);
void set_volset_field(string);
static int system_close(FL_FORM*, void*);
Public methods:
main_window();
void initialize();
void show();
void update_status (string);
static void help_cb(FL_OBJECT *, long);
static void browser_cb(FL_OBJECT *, long);
static void username_field_cb(FL_OBJECT *, long);
static void volset_field_cb(FL_OBJECT *, long);
static void app_file_cb(FL_OBJECT *, long);
static void app_tar_cb(FL_OBJECT *, long);
static void dis_cat_cb(FL_OBJECT *, long);
static void list_files_cb(FL_OBJECT *, long);
static void list_volumes_cb(FL_OBJECT *, long);
static void delete_volset_cb(FL_OBJECT *, long);
static void new_volset_cb(FL_OBJECT *, long);
static void quit_cb(FL_OBJECT *, long);
Method: main_window::main_window()
Description: calls xforms construction routine, sets fonts and initializes variables.
Method: void main_window::initialize()
Description: set the username input and set the list of volume sets. Note: this routine is needed separate from the constructor because get_volset_list() (called by set_browser()) sends an update to the main window and the global variable isn't yet initialized while in the constructor.
Method: void main_window::show()
Description: call the xforms routine to display the window
Method: void update_status(string)
Description: add the argument to the browser listing the commands executed on the host machine.
Method: void main_window::enable_volset_buttons()
Description: enable all of the selected volume set - specific buttons except for the delete volume set button
Method: void main_window::enable_object(FL_OBJECT *)
Description: calls the xforms routine to enable an object
Method: void main_window::disable_object(FL_OBJECT *)
Description: calls the xforms routine to disable an object
Method: void main_window::set_volset_true()
Description: set the no_vs_flag and enable the volset buttons
Method: void main_window::set_volset_false()
Description: set the no_vs_flag and disable the volset buttons
Method: string main_window::get_selected()
Description: get the currently selected volume set name. This routine works by grabbing the entire selected line, taking the first 26 characters, and trimming off any trailing whitespace.
Method: int main_window::set_browser()
Description: calls get_volset_list with the current username and checks the return value. The return value explains whether the username exists, and if it does, whether the user can list the volume sets. Depending on the return value, the appropriate changes are made. (Enabling/Disabling buttons etc..)
Method: int main_window::username_field_cb_function();
Description: grab the value in the username field and call set_browser()
Note: this routine is separate from the username_field_cb because other parts of the code need to know if the set_browser call was successful, so a function is needed that can return a value, which callback function can't do.
Method: int main_window::volset_field_cb_function();
Description: grab the value in the volset_field and call check_volset. Takes the appropriate action depending on the value returned.
Note: this routine is separate from the username_field_cb because other parts of the code need to know if the set_browser call was successful, so a function is needed that can return a value, which callback function can't do.
Method: void main_window::add_browser_entries(list<string>)
Description: add the strings in the list argument to the browser
Method: void set_volset_field(string)
Description: sets the volset_field with its argument, but first checks to see if the current user's username is prepended to the volume set name in the listing. If it is, it removes that part of the string and puts the rest into the volset_field.
Method: static int system_close(FL_FORM *, void *)
Description: called whenever close from the system menu is selected. Calls the quit callback.
Method: static void main_window::help_cb
Description: opens the help window if it isn't already
Method: static void main_window::browser_cb
Description: sets the volset_field with the selected volume set and calls set_volset_true()
Method: static void main_window::username_field_cb
Description: calls username_field_cb_function()
Method: static void main_window::volset_field_cb
Description: calls volset_field_cb_function()
Method: static void main_window::app_file_cb
Description: appends a file to the currently selected volume set. If not tape operation is in progress, prompts for a file to append and a filename for the file on the volume set. Then it creates a tapeio object to handle the tape operation.
Method: static void main_window::app_tar_cb
Description: creates a newtar_window and displays it.
Method: static void main_window::dis_cat_cb
Description: creates a vscat_window and displays it.
Method: static void main_window::list_files_cb
Description: creates a files_window and displays it
Method: static void main_window::list_volumes_cb
Description: creates a volumes_window and displays it
Method: static void main_window::delete_volset_cb
Description: displays a confirmation dialog for the deletion. If the user selects "Yes", calls delete_vs()
Method: static void main_window::new_volset_cb
Description: prompts for the name of the volume set and if a name is given, calls create_new_volset and then calls set_browser to update.
Method: static void main_window::quit_cb
Description: if a tape operation is in progress (tapeio != NULL) prompts for confirmation), if confirmed, cancels the tape operation and calls exit. If no tape operation, just calls exit.
4.3.12 tapeio
Class: tapeio
Description: this class defines a tapeio object, which is used to handle interaction with the tape IO subsystem. Whenever a tape operation is needed to be done, a tapeio object is created and one of its operation routines is called. This begins the process of mounting the tape and reading or writing the tape. The tapeio object uses asynchronous io when issueing the tpmnt and cp or tar commands, as these commands could take several minutes to complete. In other words, when these commands are issued, an io_callback is assigned to a pipe to the process. Whenever the process has output available, the io_callback is called just like any other callback. This allows the user to take other actions while these processes are executing.
Unfortunately, a bug in Xforms doesn't allow an io_callback to be removed from within an io_callback. This means that each io_callback has to be removed by some other means. To solve this problem, an idle callback is used. The idle callback is called whenever there aren't any other events for xcrl to handle. The idle callback checks the io_cb_state variable and if it indicates that the io_callback is done, it calls next_op, which removes the io_callback and moves on to the next step.
Each operation works in the same way. The tapio object is instantiated, then one of its public operation methods is called with several arguments. The appropriate members of the tapeio object are set with these arguments, including the io_type variable, which all of the other methods in the object use to determine exactly what to do. To start the operation, the state variable is set to START_STATE and next_op is called. For each step in the operation, the state variable is set to the next state and next_op is called again, until state is set to DONE_STATE and the tapeio object deletes itself.
Private data members:
FILE *procp pointer to current process opened with popen()
string username
string tape_path the path of the mounted tape
string volset
string rel_dir the directory from which to archive or extract tar files
string filename the file on the file system being read or written
string crl_filename the name of the file on the volume set
string error_msg the error message printed out from a command
string file_passwd the password for the CRL file
string vol_passwd the password for the volume
list<string> file_list the list of files to extract or put into a tar file
int state the current state of the tape operation
int io_cb_state the current state of the io_cb
int pid the process id of the currently running process
int file_desc the file descriptor of the currently running process
int io_type the type of io being done in this particular operation
int vol_pass_flag flag indicating if a volume password has been entered yet
int file_pass_flag flag indicating if a file password has been entered yet
int file_perms_flag flag indicating if the file permissions 777 have been tried yet when attempting to write to another user's volume set.
Private methods:
static void io_cb(int, void *)
void rls_all()
int rsv_cart()
void error()
void mount_tape()
void copy()
void tar()
string get_pid()
string get_tape_msg_error()
Public data members:
None.
Public methods:
tapeio()
static int check_io_cb(XEvent *, void *)
void next_op()
void retrieve_file(string, string, string, string)
void retrieve_tar(string, string, string, string, string)
void append_file(string, string, string, string)
void append_tar(string, string, string, string, string)
void tar_file_list(string, string, string)
void cancel()
void kill_tapeio()
Method: tapeio::tapeio()
Description: the constructor for tapeio, initializes some of the variables
Method: static int tapeio::check_io_cb(XEvent *, void *)
Description: the idle callback (which is registered in main() ) which checks the io_cb_state variable to see if the io_callback is ready to be removed. If it is, this routine calls next_op
Method: void tapeio::next_op()
Description: this routine does all of the work. It checks to see what the current state of the operation is and executes the next operation in the process. The routine consists of a large case statement. Of interest is that the step for the tape mount is listed first in the case for good reason. If the tape mount command fails due to a password error or file permissions error, we would like to start the operation over again immediately after prompting the user for a password or trying different permissions. When this occurs, the flow of execution just falls through to the first step in the operation, which is listed second in the case statement.
Method: void tapeio::retrieve_file(string, string, string, string)
Description: routine that begins the operation to retrieve a file. This routine sets the appropriate data members and calls next_op()
Method: void tapeio::retrieve_tar(string, string, string, string, string)
Description: routine that begins the operation to retrieve files from a tar file. This routine sets the appropriate data members and calls next_op()
Method: void tapeio::append_file(string, string, string, string)
Description: routine that begins the operation to archive a file. This routine sets the appropriate data members and calls next_op()
Method: void tapeio::append_tar(string, string, string, string, string)
Description: routine that begins the operation to append a tar file. This routine sets the appropriate data members and calls next_op()
Method: void tapeio::tar_file_list(string, string, string, string)
Description: routine that begins the operation to build a list of files in a tar file. This routine sets the appropriate data members and calls next_op()
Method: void tapeio::cancel()
Descripton: routine to cancel the tape operation. If a process is currently executing, it is killed, and a dialog is popped up stating that the operation is complete.
Method: void tapeio::kill_tapeio()
Description: this routine cancels the operation with extreme prejudice. No messages are displayed. This routine is used when the program is killed with a interrupt or kill signal.
5. Known Bugs
1. Keystrokes don't replace selected text in input fields, and sometimes, a delete won't even delete the selected text in an input field. This is a bug in Xforms and will probably be fixed eventually. A message was posted to the Xforms mailing list on May 9, 1996 regarding this bug, so the developer is aware of it and may issue a fix for it soon.
2. Information entered in some input fields, like those on the catalog entry windows, is not checked for content before putting it into a command that is issued to the host machine. In all cases, quotation marks are wrapped around the information before it is used on the command line, but the user can put a quotation mark in the input field, thus closing the quotation marks, and enter a command that would be executed on the host machine. For example, if the user typed the following into the comment field on one of the catalog entry windows,
this is a comment"; ls;
xcrl would end up executing an ls. This doesn't cause any security problems, because xcrl doesn't allow the user to do anything they couldn't do on the command line, but it might be considered an unwanted feature.
6. Useful Future Additions
1. Notification given to user when trying to access migrated files
2. Support of archiving and retrieving cpio files
3. More fields to edit in the catalog entry windows (as long as they are safe)