xcrl Technical Manual

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)