Everhart, Glenn From: wayne@tachyon.xxx044179killspam-3944 Sent: Sunday, April 04, 1999 3:12 PM To: Info-VAX@Mvb.Saic.Com Subject: version incompatibility in callable backup (1100 lines) I have discovered a major flaw in callable backup for 7.1-2 and 7.2, one which makes it extremely difficult to use for its intended purpose: user-written or third-party backup programs. If the error was inadvertent, digital quality assurance needs to be tightened up. People who are more familiar with vms concepts need to review changes. The person(s) who made the changes (on two separate occasions) apparently is/are not. If the change was deliberate, it represents a philosophy not in keeping with vms. I want everyone to know about it, so that pressure can be placed on digipaq to avoid spreading this concept to other parts of vms. All software developers should be interested in this, because if this spreads to other interfaces, your job will become much harder. Toward that end, I am sending this to digital via regular support channels. In addition, I am mailing directly to Hoff and am posting in comp.os.vms. Changes were made to the backup shareable for 7.1 and 7.1-2 that are not backwardly compatible with the 7.1 backupshr. In other words, an image compiled and linked under 7.1 will not run properly under 7.1-2 or 7.2, nor will one built under 7.1-2 work right on 7.2. You have to recompile and relink specifically for 7.1-2, and then again for 7.2. It is not possible for the same image, or even the same object if using the bapidefs.h C header file, to run on all three. Well, it is possible, but it is a pain in the ass, because you have to build a different parameter list for each version of backupshr, using the C header files specifically for that version, and select at link time or at run time the proper one to use. This is a major departure for vms, where images, especially user-mode images, from older versions of vms normally work on all subsequent versions of vms without modification. The way callable backup works is that you build a binary parameter list which is then passed to backup$start. This list is a series of data structures, each of which corresponds roughly to one of the dcl parameters or qualifiers for vms backup. When backup$start returns, the backup is finished. In the parameter list, each parameter or qualifier is represented by a binary code, such as BCK_OPT_K_VERIFY for /verify. These are simple sequentially- assigned numeric values. In the header file sys$examples:bapidef.h, we find the following: /* */ /* arg buffer items/options */ /* */ #define BCK_OPT_K_BCK_K_OPT_MIN 0 #define BCK_OPT_K_END_OPT 0 #define BCK_OPT_K_ALIAS 1 #define BCK_OPT_K_ASSIST 2 [lines deleted] #define BCK_OPT_K_VERIFY 81 #define BCK_OPT_K_UNSHELVE 82 #define BCK_OPT_K_VOLUME 83 #define BCK_K_OPT_MAX 83 This is unfortunately a common way to define numeric constants in C programs. Essentially a hard-coded number is used in the object module. The only way for that number to change is for the program to be recompiled with a new header file. Simply relinking the program has no effect, because the symbols are resolved to numeric values at compile time, not at link time. The way these codes are generated is with a simple list in bapidef.sdl: CONSTANT ( END_OPT, ALIAS, ASSIST, BACKUP, [lines deleted] VERIFY, UNSHELVE, VOLUME ) EQUALS #opt_counter INCREMENT 1 COUNTER #opt_counter PREFIX BCK_OPT_ TAG K; As you can see, the value of the constant is determined by it's position in the list. The first item in the list is zero, and the remaining items are assigned sequentially. There is nothing wrong with this in principle. However, the backup developers *changed the numbers of existing option codes* for versions 7.1-2 and 7.2. This is against the philosophy of vms. One of the fundamental principles of vms is that images linked under an older version continue to run unchanged on later versions. This is why there are still images running today that were originally linked under 1.x or 2.x. You never change an existing interface, you merely add new functionality to it using new codes and entry points. New programs can use the new functionality, yet programs using the old interface continue to run. There are many obsolete system services and RTL routines that are still present in vms so that the old programs using them will still run. Whenever one has a sequential list like this, it is necessary to add any new codes to the end of the list. When you mark codes as obsolete, you leave a placeholder, but you still handle the old code, probably by ignoring it or outputting a warning message, if an old program uses it. This way the existing codes retain the same values, i.e. BCK_OPT_K_VERIFY will be 81 forever, and programs compiled and linked under 7.1 will continue running on later versions. Remember, the object module contains a hard-coded 81, since BCK_OPT_K_VERIFY is resolved at compile time. Instead, the backup developers inserted entries in the middle of the list, changing the values of all following entries. They wanted the list to be pretty by remaining alphabetical and didn't think about the ramifications. At least I *hope* it was a mistake and not a deliberate act. This was especially bad for 7.2, because the new option CONVERT is pretty high in the list. Nearly all the codes were skewed for 7.2. Under 7.1-2, BCK_OPT_K_VERIFY changed from 81 to 82 (and 84 on 7.2). However, a program compiled under 7.1 does not know this and still uses the old value of 81, which is misinterpreted as BCK_OPT_K_VALIDATE_PARAMETERS (whatever the hell that does). According to the documentation, this code is reserved to digital, which means it should not be used by customers. This is probably what is causing the access violation I get when I run my program under 7.1-2 with /verify. The validate-parameters code is not expecting to be called by a third-party or user_written backup program and probably expects some special condition to be set up. Or maybe it is expecting a virtual address, whereas verify is a boolean parameter. Even if the program did not get an access violation, /verify would not actually be performed. This problem is even worse than it sounds, because there is no obvious cause for the failure. It took me weeks, off and on, to figure out the actual cause. When I put my backup program into diag mode, it dumps out the binary parameter list that it is passing to backup$start. I could never see anything wrong with the parameter list. The values matched perfectly what was in the 7.1 header file. It never crossed my mind that digital might have changed the meaning of those codes between versions, and that those codes meant something completely different under 7.1-2. 7.2 is much worse than 7.1-2, as far as renumbered option codes is concerned. The SNAPSHOT code added to 7.1-2 is later in the alphabet, so comparatively few codes were corrupted. VERIFY is probably the only one heavily used. Unfortunately, it is used *very* heavily. If you don't use /verify, your 7.1 backup image may work. However, I can't imagine anyone *not* using /verify, if they care about their backup. In 7.2, CONVERT was added, which means nearly all of the codes were renumbered. Therefore, it is almost impossible to get a 7.1 image to run on 7.2, since almost everything is reinterpreted. I have included a log illustrating this behavior after the text of this message. I basically compiled and ran a dummy backup program, using fairly simple qualifiers, under 7.1, then ran the same image on a 7.2 system, without recompiling or relinking. As you can see, the image did not work under 7.2. Normally when the vms developers make changes that cause incompatibilities with older versions of the os, they do it in such a way that programs written to the old specification die with some type of version mismatch error, or the compile or link fails. However, in this case, the program runs, but runs incorrectly. What happens depends entirely on what qualifiers are used, and what they get reinterpreted as. You do not necessarily see "invalid op type", because nearly everything gets reinterpreted as something else. For instance, if you use BCK_OPT_K_VERIFY under 7.1-2, you get the access violation mentioned above. BCK_OPT_K_TRUNCATE is seen as BCK_OPT_K_TAPE_EXPIRATION, BCK_OPT_K_TAPE_EXPIRATION as BCK_OPT_K_STORAGE_MANAGEMENT, etc. You can imagine what sort of chaos this causes. In some cases, an error occurs, such as when a string parameter is reinterpreted as a boolean parameter and vice versa. In other case, the backup just does the wrong thing. In 7.2, BCK_OPT_K_DENSITY (value 20) becomes BCK_OPT_K_DELETE. Doesn't that sound like fun? You have now specified /delete in your backup. It would be a good way to lose some files, though the mismatch of parameter types would probably cause an error instead. I wouldn't want to count on it, though. Even more confusing is that only some of the codes have changed. For 7.1-2, those alphabetically following SNAPSHOT have changed. Those which precede SNAPSHOT alphabetically retain the original values. Digipaq's response to this will probably be: "So? Recompile and relink. What's the problem?" That is semi-feasible if you are using a backup program you wrote yourself, in use only at your own site. What if you are a software developer for a commercial package which includes a backup program utilizing the api? Since callable backup is a supported interface, documented in the utilities manual, there is no reason not to use it in a commercial product (or at least there wasn't until this fiasco). It is a common practice to link images to the current version of the operating system during a product installation, but *this* incompatibility requires that the module be *compiled* as well. What if the customer doesn't have a DEC C compiler? How can the installation do the required recompile? Also, this is a commercial product, not shareware. We don't really want to put sources in the kit, which would be necessary to recompile. We have a product currently in the field that uses callable backup. As sites upgrade to either 7.1-2 or 7.2, the product suddenly starts failing. Simply relinking the product has no effect, because the old codes are locked into the object. There is no easy way to resolve this problem as it stands now. Possibly the least painful is to provide three different objects in your kit, built for each of the three versions of bapidef. Then link whichever one matches the target version of the os. Unfortunately, unless we speak up, the practice of completely redefining the option codes for every version will continue, which means we will have to supply a new object for each release of the os. I would advise everyone, especially software developers, to complain long and bitterly to digital about this. This foolishness defeats the whole purpose of the backup api concept. Admittedly, there are probably few people using the backup api. However, this philosophy on the part of digital should be curtailed lest it spread to other interfaces in vms. The correct response from digital would be to issue backupshr patches for 7.1-2 and 7.2, making the option codes for these versions match the original 7.1 list. That would resolve the problem, assuming 7.3 and later versions of backupshr do not make the same mistake. This could be an extremely low priority patch. Sites performing all backups with the regular backup command would not need it, because backup.exe does not have this problem. Any time the interface to backupshr.exe changes, backup.exe changes with it, so the two always agree on the option codes. Only sites with user-written backup programs using backupshr, or sites using third-party backups such as ours would need the patch. We could simply tell our customers to get the patch rather than try to handle the different versions of the parameter list (currently three, put possibly more if the practice continues). The modification itself would be trivially easy and would take less than a minute to make, not including build time and patch packaging. In 7.1-2 backupshr, the SNAPSHOT option was added to the list. In 7.2, CONVERT and MT3_DENSITY were added. In each BAPIDEF.SDL module, move these new codes to the end of the list, after VOLUME, the last code of 7.1. Then rebuild and issue a patch that includes the resulting backup.exe, backupshr.exe and header files. That's it. All of the option codes would return to their original 7.1 values and programs built under 7.1 would start working again. Note: there may be other new codes added to other lists in the SDL files. I did not do an exhaustive comparison, because the change to the option list was so catastrophic that I was in a state of shock. Digital should verify that *all* codes previously defined in 7.1 retain their original values. For 7.2, the end of the list would now look like this (I don't show the entire list, but assume the new codes have been removed from their alphabetical positions, so that everything before VOLUME is the same as 7.1): VERIFY, UNSHELVE, VOLUME, /* /* new code for 7.1-2 /* SNAPSHOT, /* /* new codes for 7.2 /* CONVERT, MT3_DENSITY /* ) EQUALS #opt_counter INCREMENT 1 COUNTER #opt_counter PREFIX BCK_OPT_ TAG K; See, you can still make it alphabetical, you just have multiple alphabetical lists, one for each version. :-) I would also add comments to the beginning of the list: "DO NOT INSERT NEW CODES TO THE MIDDLE OF THIS LIST. ADD NEW CODES AT THE END". If digital won't patch backupshr, maybe we can get them to at least correct this situation for later versions. In other words, *don't* insert any more codes in the middle of the list. Unless the patches are performed, we will always have three different parameter lists, but don't force us to use a different list for 7.3 and 7.4 as well. Add all new codes to the end of the list from now on. It should go without saying that the 7.1-2 and 7.2 backupshr should be able to handle a 7.1 parameter list. Such backward compatability has always been a fundamental concept of vms, as in system services and the various run time libraries. The developers of backupshr appear to be new to vms and not be aware of this concept. I assume they came from the wintel/gates world, where interfaces change daily and compatibility across versions is an unknown concept. For future versions of vms, I have a couple of proposals that would make the backup api a lot easier to work with and would solve many of these problems in a cleaner way. Since this message is so long-winded already, I might as well continue. Much of the problem is that the option code definitions are contained within a c header file and are therefore static as far as the object module is concerned. You can't pick up new values unless you recompile. It would be better if these were defined within backupshr itself as universal symbols. Then the module would not need to be recompiled to pick up the codes. They would be resolved at link time. Image version control would be required to force a relink if the codes changed between versions. (It is still better not to change the values for backward compatibility, but at least it would be detected this way.) The header file used by the caller could still do the symbol definitions, but without hard-coded values: #pragma extern_model save #pragma extern_model globalvalue extern int BCK_OPT_K_xxx; /* and so on */ #pragma extern_model restore The actual values would be picked up from backupshr at link time. This would be easy to do, by making the values global and making them universal symbols in the link of backupshr. Better yet, the api should provide a means for actually building the parameter list itself from the dcl qualifiers. While there may be programs using the api which build the parameter list from scratch according to internally generated criteria, many of us are essentially writing jackets around regular vms backup. In other words, we have a substitute backup that does preprocessing, performs a vms backup, possibly with callbacks, then does postprocessing. Therefore, we have a dcl command definition with *exactly* the same qualifiers as the backup command itself and we build the parameter list from those parameters *exactly* as backup.exe does. backup.exe already contains a parsing routine that builds a binary parameter list from the dcl parameters and qualifiers. We essentially have to duplicate that code now. It would be nice if we could simply call that routine. The change would almost be as simple as moving the routine from backup.exe to backupshr and providing a transfer vector to it. The only gotcha is that we would need some way of specifying callbacks, since these are also part of the parameter list, and we must supply those. The parsing routine could be modified to accept a list of callbacks as an input parameter, and it could merge those into the main list along with the stuff from dcl. Or maybe there could be a separate add_callback_to_parameter_list routine. The main advantage of using a parse routine built into backupshr is that as new qualifiers are added to vms backup, they would automatically get picked up. As it stands now, we have to add new qualifiers to our own parsing routines. Those building their own parameter lists from scratch, i.e. not using dcl or using dcl different from vms backup, would simply not call the parse routine. =========================================================================== =========================================================================== =========================================================================== =========================================================================== =========================================================================== This log shows building and successfully running a program that uses callable backup. This log is from a 7.1 system, so the program is built with the original option codes. ============================================================================ $! $! create the backup source file $! $ create dummy_backup.c #include #include #include #include #include #include "sys$examples:bapidef.h" #include "sys$examples:backdef.h" #include "sys$examples:backstruc.h" int backup$start(); static char param_list[50000]; unsigned int saveset_close_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering saveset_close_callback\n"); printf("exiting saveset_close_callback\n"); return (1); } unsigned int saveset_read_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering saveset_read_callback\n"); printf("exiting saveset_read_callback\n"); return (1); } unsigned int saveset_write_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering saveset_write_callback\n"); printf("exiting saveset_write_callback\n"); return (1); } unsigned int saveset_open_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering saveset_open_callback\n"); printf("exiting saveset_open_callback\n"); return (1); } unsigned int log_callback(bckEvent *param) { int len, ret_code; printf("entering log_callback\n"); ret_code = param->bckevt_l_event_subtype; lib$signal(ret_code,1,param); printf("exiting log_callback\n"); return (1); } unsigned int op_phase_callback(bckEvent *param) { int ret_code; printf("entering op_phase_callback\n"); ret_code = param->bckevt_l_event_subtype; lib$signal(ret_code); printf("exiting op_phase_callback\n"); return (1); } unsigned int user_msg_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering user_msg_callback\n"); sys$putmsg(param->bckevt_r_event_buffer.dsc$a_pointer,0,0,0); printf("exiting user_msg_callback\n"); return (1); } unsigned int error_msg_callback(bckEvent *param) { lib$establish(lib$sig_to_ret); printf("entering error_msg_callback\n"); sys$putmsg(param->bckevt_r_event_buffer.dsc$a_pointer,0,0,0); printf("exiting error_msg_callback\n"); return (1); } #define init_opt_string(str) if (str <= BCK_K_OPT_MAX) opt_strings[str] = #str #define init_callback_string(str) if (str <= BCK_K_EVENT_MAX) callback_strings[str] = #str void dump_param_list(void) { unsigned int bck_arg_count,arg_size; bck_opt_struct_flag *local_buff; char *opt_strings[BCK_K_OPT_MAX + 1]; char *callback_strings[BCK_K_EVENT_MAX + 1]; char *str, *strptr; char work_string[500]; int len; lib$establish(lib$sig_to_ret); init_opt_string(BCK_OPT_K_ALIAS); init_opt_string(BCK_OPT_K_ASSIST); init_opt_string(BCK_OPT_K_BACKUP); init_opt_string(BCK_OPT_K_BEFORE_TYPE); init_opt_string(BCK_OPT_K_BLOCK); init_opt_string(BCK_OPT_K_CREATED); init_opt_string(BCK_OPT_K_CARTRIDGE_SIDE_IN); init_opt_string(BCK_OPT_K_CARTRIDGE_SIDE_OUT); init_opt_string(BCK_OPT_K_COMPARE); init_opt_string(BCK_OPT_K_CONFIRM); init_opt_string(BCK_OPT_K_CRC); init_opt_string(BCK_OPT_K_DELETE); init_opt_string(BCK_OPT_K_DENSITY); init_opt_string(BCK_OPT_K_DISMOUNT); init_opt_string(BCK_OPT_K_DISPOSITION); init_opt_string(BCK_OPT_K_EXACT_ORDER); init_opt_string(BCK_OPT_K_FAST); init_opt_string(BCK_OPT_K_FILEMERGE); init_opt_string(BCK_OPT_K_FULL); init_opt_string(BCK_OPT_K_GROUP); init_opt_string(BCK_OPT_K_IGNORE_TYPES); init_opt_string(BCK_OPT_K_IMAGE); init_opt_string(BCK_OPT_K_INCREMENTAL); init_opt_string(BCK_OPT_K_INITIALIZE); init_opt_string(BCK_OPT_K_INTERCHANGE); init_opt_string(BCK_OPT_K_JOURNAL); init_opt_string(BCK_OPT_K_LIST); init_opt_string(BCK_OPT_K_LOG); init_opt_string(BCK_OPT_K_MEDIA_FORMAT); init_opt_string(BCK_OPT_K_MODIFIED); init_opt_string(BCK_OPT_K_NEW_VERSION); init_opt_string(BCK_OPT_K_OPERATION_TYPE); init_opt_string(BCK_OPT_K_OVERLAY); init_opt_string(BCK_OPT_K_OWNER_IN_VALUE); init_opt_string(BCK_OPT_K_OWNER_OUT_TYPE); init_opt_string(BCK_OPT_K_OWNER_OUT_VALUE); init_opt_string(BCK_OPT_K_PROTECTION); init_opt_string(BCK_OPT_K_PHYSICAL); init_opt_string(BCK_OPT_K_RECORD); init_opt_string(BCK_OPT_K_RELEASE_TAPE); init_opt_string(BCK_OPT_K_REPLACE); init_opt_string(BCK_OPT_K_REWIND); init_opt_string(BCK_OPT_K_REWIND_IN); init_opt_string(BCK_OPT_K_REWIND_OUT); init_opt_string(BCK_OPT_K_SAVE_SET_IN); init_opt_string(BCK_OPT_K_SAVE_SET_OUT); init_opt_string(BCK_OPT_K_SCRATCH_ASGN_TYPE); init_opt_string(BCK_OPT_K_SINCE_TYPE); init_opt_string(BCK_OPT_K_TRUNCATE); init_opt_string(BCK_OPT_K_VALIDATE_PARAMETERS); init_opt_string(BCK_OPT_K_VERIFY); init_opt_string(BCK_OPT_K_UNSHELVE); init_opt_string(BCK_OPT_K_VOLUME); init_opt_string(BCK_OPT_K_EVENT_CALLBACK); init_opt_string(BCK_OPT_K_FILE_CALLBACK); init_opt_string(BCK_OPT_K_HANDLE); init_opt_string(BCK_OPT_K_BEFORE_VALUE); init_opt_string(BCK_OPT_K_EXPIRED); init_opt_string(BCK_OPT_K_SINCE_VALUE); init_opt_string(BCK_OPT_K_TAPE_EXPIRATION); init_opt_string(BCK_OPT_K_CARTRIDGE_MEDIA_IN); init_opt_string(BCK_OPT_K_CARTRIDGE_NAME_IN); init_opt_string(BCK_OPT_K_CARTRIDGE_MEDIA_OUT); init_opt_string(BCK_OPT_K_CARTRIDGE_NAME_OUT); init_opt_string(BCK_OPT_K_COMMAND); init_opt_string(BCK_OPT_K_COMMENT); init_opt_string(BCK_OPT_K_DRIVE_CLASS_IN); init_opt_string(BCK_OPT_K_DRIVE_CLASS_OUT); init_opt_string(BCK_OPT_K_ENCRYPT_USERALG); init_opt_string(BCK_OPT_K_ENCRYPT_USERKEY); init_opt_string(BCK_OPT_K_ENCRYPT_KEY_VALUE); init_opt_string(BCK_OPT_K_EXCLUDE); init_opt_string(BCK_OPT_K_INPUT); init_opt_string(BCK_OPT_K_JOURNAL_FILE); init_opt_string(BCK_OPT_K_LABEL); init_opt_string(BCK_OPT_K_LIST_FILE); init_opt_string(BCK_OPT_K_OUTPUT); init_opt_string(BCK_OPT_K_SCRATCH_COLLECTION); init_opt_string(BCK_OPT_K_SCRATCH_LOCATION); init_opt_string(BCK_OPT_K_SCRATCH_MEDIA_NAME); init_opt_string(BCK_OPT_K_SELECT); init_opt_string(BCK_OPT_K_STORAGE_MANAGEMENT); init_callback_string(BCK_EVENT_K_CONTROL); init_callback_string(BCK_EVENT_K_ERROR_MSG); init_callback_string(BCK_EVENT_K_FILE_OPEN); init_callback_string(BCK_EVENT_K_FILE_READ); init_callback_string(BCK_EVENT_K_FILE_WRITE); init_callback_string(BCK_EVENT_K_FILE_CLOSE); init_callback_string(BCK_EVENT_K_JOURNAL_OPEN); init_callback_string(BCK_EVENT_K_JOURNAL_WRITE); init_callback_string(BCK_EVENT_K_JOURNAL_CLOSE); init_callback_string(BCK_EVENT_K_LIST_OPEN); init_callback_string(BCK_EVENT_K_LIST_WRITE); init_callback_string(BCK_EVENT_K_LISTJOUR_WRITE); init_callback_string(BCK_EVENT_K_LIST_CLOSE); init_callback_string(BCK_EVENT_K_LOG); init_callback_string(BCK_EVENT_K_OP_PHASE); init_callback_string(BCK_EVENT_K_SAVESET_OPEN); init_callback_string(BCK_EVENT_K_SAVESET_READ); init_callback_string(BCK_EVENT_K_SAVESET_WRITE); init_callback_string(BCK_EVENT_K_SAVESET_CLOSE); init_callback_string(BCK_EVENT_K_STATISTICS); init_callback_string(BCK_EVENT_K_USER_MSG); /* Initialize the count of options specified in the API arg. buffer */ bck_arg_count = 0; local_buff = (bck_opt_struct_flag *) param_list; printf("this is the parameter list being passed to backup$start\n"); while ((*local_buff).option_type != BCK_OPT_K_END_OPT) { if ((*local_buff).option_type <= BCK_K_OPT_MAX) str = opt_strings[(*local_buff).option_type] ; else str = "?"; printf("BCKAPI OPTYPE: %d (%s)\n", (*local_buff).option_type, str); switch( (*local_buff).option_type ) { case BCK_OPT_K_ALIAS : case BCK_OPT_K_ASSIST : case BCK_OPT_K_BACKUP : case BCK_OPT_K_BEFORE_TYPE : case BCK_OPT_K_CREATED : case BCK_OPT_K_COMPARE : case BCK_OPT_K_CONFIRM : case BCK_OPT_K_CRC : case BCK_OPT_K_DELETE : case BCK_OPT_K_DISMOUNT : case BCK_OPT_K_DISPOSITION : case BCK_OPT_K_EXACT_ORDER : case BCK_OPT_K_FAST : case BCK_OPT_K_FILEMERGE: case BCK_OPT_K_FULL : case BCK_OPT_K_IGNORE_TYPES : case BCK_OPT_K_IMAGE : case BCK_OPT_K_INCREMENTAL : case BCK_OPT_K_INITIALIZE : case BCK_OPT_K_INTERCHANGE : case BCK_OPT_K_JOURNAL : case BCK_OPT_K_LIST : case BCK_OPT_K_LOG : case BCK_OPT_K_MEDIA_FORMAT : case BCK_OPT_K_MODIFIED : case BCK_OPT_K_NEW_VERSION : case BCK_OPT_K_OPERATION_TYPE : case BCK_OPT_K_OVERLAY : case BCK_OPT_K_OWNER_OUT_TYPE : case BCK_OPT_K_PHYSICAL : case BCK_OPT_K_RECORD : case BCK_OPT_K_RELEASE_TAPE : case BCK_OPT_K_REPLACE : case BCK_OPT_K_REWIND : case BCK_OPT_K_REWIND_IN : case BCK_OPT_K_REWIND_OUT : case BCK_OPT_K_SAVE_SET_IN : case BCK_OPT_K_SAVE_SET_OUT : case BCK_OPT_K_SCRATCH_ASGN_TYPE : case BCK_OPT_K_SINCE_TYPE : case BCK_OPT_K_TRUNCATE : case BCK_OPT_K_VALIDATE_PARAMETERS: case BCK_OPT_K_VERIFY : case BCK_OPT_K_UNSHELVE : printf("OPTION FLAG VALUE: %d\n", (*local_buff).opt_flag_value); arg_size = bck_opt_struct_flag_k_len; break; case BCK_OPT_K_BLOCK : case BCK_OPT_K_CARTRIDGE_SIDE_IN : case BCK_OPT_K_CARTRIDGE_SIDE_OUT : case BCK_OPT_K_DENSITY : case BCK_OPT_K_GROUP : case BCK_OPT_K_OWNER_IN_VALUE : case BCK_OPT_K_OWNER_OUT_VALUE : case BCK_OPT_K_PROTECTION : case BCK_OPT_K_VOLUME : printf("OPTION NUM VALUE: %x %x\n", (*(bck_opt_struct_int *) local_buff).opt_int_value[1], (*(bck_opt_struct_int *) local_buff).opt_int_value[0]); arg_size = bck_opt_struct_int_k_len; break; case BCK_OPT_K_EVENT_CALLBACK : str = callback_strings[((bck_opt_struct_adr *) local_buff)->opt_adr_attributes] ; printf("event callback: %s\n", str); case BCK_OPT_K_FILE_CALLBACK : printf("OPTION ADDRESS ATTRIBUTE VALUE: %d\n", ((bck_opt_struct_adr *) local_buff)->opt_adr_attributes); case BCK_OPT_K_HANDLE : printf("OPTION ADDRESS VALUE: %x %x\n", ((bck_opt_struct_adr *) local_buff)->opt_adr_value[0], ((bck_opt_struct_adr *) local_buff)->opt_adr_value[1]); arg_size = bck_opt_struct_adr_k_len; break; case BCK_OPT_K_BEFORE_VALUE : case BCK_OPT_K_EXPIRED : case BCK_OPT_K_SINCE_VALUE : case BCK_OPT_K_TAPE_EXPIRATION : printf("DATE VALUE\n"); arg_size = bck_opt_struct_dt_k_len; break; case BCK_OPT_K_CARTRIDGE_MEDIA_IN : case BCK_OPT_K_CARTRIDGE_NAME_IN : case BCK_OPT_K_CARTRIDGE_MEDIA_OUT : case BCK_OPT_K_CARTRIDGE_NAME_OUT : case BCK_OPT_K_COMMAND : case BCK_OPT_K_COMMENT : case BCK_OPT_K_DRIVE_CLASS_IN : case BCK_OPT_K_DRIVE_CLASS_OUT : case BCK_OPT_K_ENCRYPT_USERALG : case BCK_OPT_K_ENCRYPT_USERKEY : case BCK_OPT_K_ENCRYPT_KEY_VALUE : case BCK_OPT_K_EXCLUDE : case BCK_OPT_K_INPUT : case BCK_OPT_K_JOURNAL_FILE : case BCK_OPT_K_LABEL : case BCK_OPT_K_LIST_FILE : case BCK_OPT_K_OUTPUT : case BCK_OPT_K_SCRATCH_COLLECTION : case BCK_OPT_K_SCRATCH_LOCATION : case BCK_OPT_K_SCRATCH_MEDIA_NAME : case BCK_OPT_K_SELECT : case BCK_OPT_K_STORAGE_MANAGEMENT : /* ** Convert the Option-type Value from a text descriptor to ** text string. (No conversion is really necessary.) */ strptr = (char *) ((bck_opt_struct_dsc *) local_buff)->opt_dsc.dsc$a_pointer; len = ((bck_opt_struct_dsc *) local_buff)->opt_dsc.dsc$w_length; strncpy(work_string,strptr,len); work_string[len] = 0; printf("OPT VALUE: %s\n", work_string); arg_size = bck_opt_struct_dsc_k_len; break; default : printf(" BAD ARGUMENT TYPE - ARG# %d !!!\n", bck_arg_count); arg_size = bck_opt_struct_flag_k_len; /* Assume a flag [type] option */ break; } /* end switch - ( option_type ) */ local_buff = (void *) ((unsigned int) local_buff + arg_size); bck_arg_count++; } /* end while - ( processing arg buffer ) */ if ((*local_buff).option_type == BCK_OPT_K_END_OPT) { printf("BCKAPI OPTYPE: 0 = BCK_OPT_K_END_OPT\n"); printf("OPTION FLAG VALUE: %d\n", (*local_buff).opt_flag_value); } else printf("warning --- no BCK_OPT_K_END_OPT\n"); printf("BACKUP API Argument Count = %d\n", bck_arg_count); } #define flag_param(which,val) \ (*local_buff).option_type = BCK_OPT_K_ ## which ; \ (*local_buff).opt_flag_value = val; \ arg_size = bck_opt_struct_flag_k_len; \ local_buff = (void *) ((unsigned int) local_buff + arg_size); #define string_param(which,val) \ (*local_buff).option_type = BCK_OPT_K_ ## which ; \ ((bck_opt_struct_dsc *) local_buff)->opt_dsc.dsc$w_length = \ strlen(val); \ ((bck_opt_struct_dsc *) local_buff)->opt_dsc.dsc$a_pointer = val; \ arg_size = bck_opt_struct_dsc_k_len; \ local_buff = (void *) ((unsigned int) local_buff + arg_size); #define callback_param(which,routine) \ (*local_buff).option_type = BCK_OPT_K_EVENT_CALLBACK; \ ((bck_opt_struct_adr *) local_buff)->opt_adr_attributes = \ BCK_EVENT_K_ ## which; \ ((bck_opt_struct_adr *) local_buff)->opt_adr_value[0] = \ (int *) routine; \ ((bck_opt_struct_adr *) local_buff)->opt_adr_value[1] = 0;\ arg_size = bck_opt_struct_adr_k_len; \ local_buff = (void *) ((unsigned int) local_buff + arg_size); void get_parameters(void) { unsigned int bck_arg_count,arg_size; bck_opt_struct_flag *local_buff; bck_arg_count = 0; local_buff = (bck_opt_struct_flag *) param_list; string_param(COMMAND,"BACK/LIST=sys$scratch:/FULL " "sys$sysdevice:[sys0.sysexe]params.dat/LOG " "_NLA0:$40$DKA100.BAK/REWI/SAVE/IGNO=LABE/NOASSI"); flag_param(ASSIST,0); flag_param(FULL,1); flag_param(IGNORE_TYPES,4); callback_param(SAVESET_CLOSE,saveset_close_callback); callback_param(SAVESET_READ,saveset_read_callback); callback_param(SAVESET_OPEN,saveset_open_callback); callback_param(SAVESET_WRITE,saveset_write_callback); callback_param(LOG,log_callback); callback_param(OP_PHASE,op_phase_callback); callback_param(USER_MSG,user_msg_callback); callback_param(ERROR_MSG,error_msg_callback); string_param(LIST_FILE,"sys$scratch:"); flag_param(LOG,1); flag_param(REWIND_OUT,1); string_param(INPUT,"sys$sysdevice:[sys0.sysexe]params.dat"); string_param(OUTPUT,"_NLA0:$40$DKA100.BAK"); flag_param(SAVE_SET_OUT,1); flag_param(OPERATION_TYPE,1); flag_param(END_OPT,0); } /************************************************************************/ /* */ /* This routine calls the backup shareable image */ /* */ /* Input: */ /* */ /* none */ /* */ /* Output: */ /* */ /* run_backup_shareable = status from backup */ /* */ /************************************************************************/ int run_backup_shareable (void) { unsigned long int sts, sts2; printf("calling get_parameters \n"); get_parameters (); printf("after call to get_parameters\n"); dump_param_list(); printf("calling backup_start\n"); sts = backup$start (param_list); printf("after call to backup_start, sts = %d\n",sts); return (sts); } int main(void) { int sts; sts = run_backup_shareable(); return (sts); } $ cc/decc/stand=relax dummy_backup $ link dummy_backup+sys$input:/opt sys$library:backupshr/share $ run dummy_backup calling get_parameters after call to get_parameters this is the parameter list being passed to backup$start BCKAPI OPTYPE: 14 (BCK_OPT_K_COMMAND) OPT VALUE: BACK/LIST=sys$scratch:/FULL sys$sysdevice:[sys0.sysexe]params.dat/LOG _NLA0:$40$DKA100.BAK/REWI/SAVE/IGNO=LABE/NOASSI BCKAPI OPTYPE: 2 (BCK_OPT_K_ASSIST) OPTION FLAG VALUE: 0 BCKAPI OPTYPE: 36 (BCK_OPT_K_FULL) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 39 (BCK_OPT_K_IGNORE_TYPES) OPTION FLAG VALUE: 4 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_CLOSE OPTION ADDRESS ATTRIBUTE VALUE: 19 OPTION ADDRESS VALUE: 10400 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_READ OPTION ADDRESS ATTRIBUTE VALUE: 17 OPTION ADDRESS VALUE: 103d0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_OPEN OPTION ADDRESS ATTRIBUTE VALUE: 16 OPTION ADDRESS VALUE: 103a0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_WRITE OPTION ADDRESS ATTRIBUTE VALUE: 18 OPTION ADDRESS VALUE: 10370 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_LOG OPTION ADDRESS ATTRIBUTE VALUE: 14 OPTION ADDRESS VALUE: 10350 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_OP_PHASE OPTION ADDRESS ATTRIBUTE VALUE: 15 OPTION ADDRESS VALUE: 10320 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_USER_MSG OPTION ADDRESS ATTRIBUTE VALUE: 21 OPTION ADDRESS VALUE: 102f0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_ERROR_MSG OPTION ADDRESS ATTRIBUTE VALUE: 2 OPTION ADDRESS VALUE: 102b0 0 BCKAPI OPTYPE: 49 (BCK_OPT_K_LIST_FILE) OPT VALUE: sys$scratch: BCKAPI OPTYPE: 50 (BCK_OPT_K_LOG) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 67 (BCK_OPT_K_REWIND_OUT) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 43 (BCK_OPT_K_INPUT) OPT VALUE: sys$sysdevice:[sys0.sysexe]params.dat BCKAPI OPTYPE: 55 (BCK_OPT_K_OUTPUT) OPT VALUE: _NLA0:$40$DKA100.BAK BCKAPI OPTYPE: 69 (BCK_OPT_K_SAVE_SET_OUT) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 54 (BCK_OPT_K_OPERATION_TYPE) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 0 = BCK_OPT_K_END_OPT OPTION FLAG VALUE: 0 BACKUP API Argument Count = 19 calling backup_start entering saveset_open_callback exiting saveset_open_callback entering log_callback entering user_msg_callback %BACKUP-S-COPIED, copied SYS$SYSDEVICE:[SYS0.SYSEXE]PARAMS.DAT;16 exiting user_msg_callback exiting log_callback entering log_callback entering user_msg_callback %BACKUP-S-COPIED, copied SYS$SYSDEVICE:[SYS0.SYSEXE]PARAMS.DAT;15 exiting user_msg_callback exiting log_callback entering log_callback entering user_msg_callback %BACKUP-S-COPIED, copied SYS$SYSDEVICE:[SYS0.SYSEXE]PARAMS.DAT;14 exiting user_msg_callback exiting log_callback entering saveset_read_callback exiting saveset_read_callback entering saveset_write_callback exiting saveset_write_callback entering saveset_write_callback exiting saveset_write_callback entering saveset_close_callback exiting saveset_close_callback after call to backup_start, sts = 1 =========================================================================== Okay, so it did the backup. As you can see from the log, all the callbacks were executed properly. Now we will log onto 7.2 and try to run the image we created under 7.1. =========================================================================== %PHOTO-I-INIT, recording initiated at 3-APR-1999 10:56:42.97 %PHOTO-I-FILE, log file is MOE_DISK2:[WAYNE]PHOTO.LOG;85 CURLY> set host chico OpenVMS Alpha V7.2 (private system, unauthorized use prohibited/illegal) Username: wayne Password: Access to and use of this computer system is restricted to authorized personnel of Tachyon Software Consulting. Any unauthorized access and/or use is strictly prohibited. Violators will be prosecuted to the fullest extent of the law. Last interactive login on Sunday, 21-MAR-1999 07:32:50.57 Last non-interactive login on Saturday, 3-APR-1999 10:41:55.71 CHICO> run MOE_DISK:[SCRATCH_AREA]DUMMY_BACKUP calling get_parameters after call to get_parameters this is the parameter list being passed to backup$start BCKAPI OPTYPE: 14 (BCK_OPT_K_COMMAND) OPT VALUE: BACK/LIST=sys$scratch:/FULL sys$sysdevice:[sys0.sysexe]params.dat/LO G _NLA0:$40$DKA100.BAK/REWI/SAVE/IGNO=LABE/NOASSI BCKAPI OPTYPE: 2 (BCK_OPT_K_ASSIST) OPTION FLAG VALUE: 0 BCKAPI OPTYPE: 36 (BCK_OPT_K_FULL) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 39 (BCK_OPT_K_IGNORE_TYPES) OPTION FLAG VALUE: 4 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_CLOSE OPTION ADDRESS ATTRIBUTE VALUE: 19 OPTION ADDRESS VALUE: 10400 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_READ OPTION ADDRESS ATTRIBUTE VALUE: 17 OPTION ADDRESS VALUE: 103d0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_OPEN OPTION ADDRESS ATTRIBUTE VALUE: 16 OPTION ADDRESS VALUE: 103a0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_SAVESET_WRITE OPTION ADDRESS ATTRIBUTE VALUE: 18 OPTION ADDRESS VALUE: 10370 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_LOG OPTION ADDRESS ATTRIBUTE VALUE: 14 OPTION ADDRESS VALUE: 10350 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_OP_PHASE OPTION ADDRESS ATTRIBUTE VALUE: 15 OPTION ADDRESS VALUE: 10320 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_USER_MSG OPTION ADDRESS ATTRIBUTE VALUE: 21 OPTION ADDRESS VALUE: 102f0 0 BCKAPI OPTYPE: 29 (BCK_OPT_K_EVENT_CALLBACK) event callback: BCK_EVENT_K_ERROR_MSG OPTION ADDRESS ATTRIBUTE VALUE: 2 OPTION ADDRESS VALUE: 102b0 0 BCKAPI OPTYPE: 49 (BCK_OPT_K_LIST_FILE) OPT VALUE: sys$scratch: BCKAPI OPTYPE: 50 (BCK_OPT_K_LOG) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 67 (BCK_OPT_K_REWIND_OUT) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 43 (BCK_OPT_K_INPUT) OPT VALUE: sys$sysdevice:[sys0.sysexe]params.dat BCKAPI OPTYPE: 55 (BCK_OPT_K_OUTPUT) OPT VALUE: _NLA0:$40$DKA100.BAK BCKAPI OPTYPE: 69 (BCK_OPT_K_SAVE_SET_OUT) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 54 (BCK_OPT_K_OPERATION_TYPE) OPTION FLAG VALUE: 1 BCKAPI OPTYPE: 0 = BCK_OPT_K_END_OPT OPTION FLAG VALUE: 0 BACKUP API Argument Count = 19 calling backup_start %BACKUP-F-BADOPTTYP, invalid callable interface option type, argument position 3, option type = 36 after call to backup_start, sts = 10717164 %BACKUP-F-BADOPTTYP, invalid callable interface option type, argument position 0, option type = 65531 CHICO> log WAYNE logged out at 3-APR-1999 10:58:05.73 %REM-S-END, control returned to node LOCAL:.CURLY:: CURLY> photo/off %PHOTO-I-FINI, recording finished at 3-APR-1999 10:58:09.61 =================================================================== As you can see, the same image fails on 7.2. Nothing about version mismatches. It just doesn't like the 7.1 option list. It is complaining about the BCK_OPT_K_FULL (/full on the command line, i.e. a full listing), which has a value of 36 on 7.1. However, for 7.2, a value of 36 is interpreted as BCK_OPT_K_FILEMERGE, which the documentation says is reserved for use by digital. Who knows what type of value it wants? My guess is that it is not a boolean parameter (0 or 1) like BCK_OPT_K_FULL is. Even if the parameter was not rejected, it would have done the wrong thing. We didn't ask for filemerge, we asked for a full listing. Note that if the full command procedure is run, i.e. the program is recompiled and relinked, that it works okay. However, as a software developer, I do not consider this a solution. See the discussion of product installation above. -- =============================================================================== Wayne Sewell, Tachyon Software Consulting (281)812-0738 wayne@tachyon.xxx http://www.tachyon.xxx/www/tachyon.html and wayne.html change .xxx to .com in addresses above, assuming you are not a spambot :-) =============================================================================== Flounder: "I can't believe I threw up in front of Dean Wormer." Otter: "Face it, Flounder. You threw up *on* Dean Wormer."