The API package that you receive includes a sample application. This chapter uses examples that are taken from that sample application to demonstrate how to use the API. You should be familiar with this chapter before you design or write an application that uses the API.
Note: | The examples in this chapter are program fragments that demonstrate how you use the API functions in context. Many of the examples in this chapter are taken from the UNIX sample application. The program fragments on other platforms might look somewhat different; some of these examples are shown. |
When you design your application, carefully consider session control, object naming, management class, and object size. The following paragraphs describe each item.
Ensure that you understand and follow these conditions of session control:
Carefully think through the object naming convention. Consider the following:
Do not store objectID values to use for future restores. They are not guaranteed to be persistent during the life of the object.
Think through how much control the application wants over the management class associated with its objects. The end user can define Include statements, or the application can specify a name on the dsmSendObj function call.
Tivoli Storage Manager needs to know a size estimate for each object. Consider how your application will do this.
Certain data structures or fields in the API have size limits. These structures are often names or other text fields that cannot exceed a predetermined length. Examples of fields with such limits include:
These limits are defined as constants within the header file, dsmapitd.h. Any storage allocation should be based on these constants rather than numbers you enter. Refer to Appendix A, API Type Definitions Source File for further information and a list of the current constants.
All APIs have some form of version control, and Tivoli Storage Manager is no exception. The API version that you use in your application must be compatible with the version of the API library that is installed on the end user workstation.
The dsmQueryApiVersionEx should be the first API call that you enter when you use the API. This call:
The API is designed to be upwardly compatible. Applications written to older versions or releases of the API library will operate correctly if the end user is running a newer version. An exception to this is an OS/2 application that is compiled with the Version 2 DLL. This will not run with the adsmv3.dll because of memory model incompatibility. See "Summary of Code Changes" for differences between levels.
Determining the release of the API library is very important because some
releases might have different memory requirements and data structure
definitions. Downward compatibility is unlikely. See Table 8 for information about your platform.
Platform | Description |
---|---|
Intel | The message files must be at the same level as the library (DLL). The dsmtca is not used. |
UNIX | The API library, the Trusted Communication Agent module (dsmtca), and the message files must be at the same level. |
The dsmQueryApiVersionEx call returns the version of the API library that is installed on the end user workstation. You can then compare the returned value with the version of the API that the application client is using.
The API version number of the application client is entered in the compiled object code as a set of four constants defined in dsmapitd.h:
DSM_API_VERSION DSM_API_RELEASE DSM_API_LEVEL DSM_API_SUB_LEVEL
See Appendix A, API Type Definitions Source File.
The API version of the application client should be less than, or equal to, the API library that is installed on the user's system. Be careful about any other condition. You can enter the dsmQueryApiVersionEx call at any time, whether the API session has been started or not.
Data structures that the API uses also have version control information in them. Structures have version information as the first field. As enhancements are made to structures, the version number is increased. When initializing the version field, use the defined structure Version value in dsmapitd.h.
Figure 1 demonstrates the type definition of the structure, dsmApiVersionEx from the header file, dsmapitd.h. The example then defines a global variable that is named apiLibVer. It also demonstrates how you can use it in a call to dsmQueryApiVersionEx to return the version of the end user's API library. Finally, the returned value is compared to the API version number of the application client.
Figure 1. An Example of Obtaining the Version Level of the API
typedef struct
{
dsUint16_t stVersion; /* Structure version */
dsUint16_t version; /* API version */
dsUint16_t release; /* API release */
dsUint16_t level; /* API level */
dsUint16_t subLevel; /* API sub level */
} dsmApiVersionEx;
dsmApiVersionEx apiLibVer;
memset(&apiLibVer,0x00,sizeof(dsmApiVersionEx));
dsmQueryApiVersionEx(&apiLibVer);
/* check for compatibility problems */
dsInt16_t appVersion= 0, libVersion = 0;
appVersion = (DSM_API_VERSION * 1000) + (DSM_API_RELEASE * 100) +
(DSM_API_LEVEL * 10) + (DSM_API_SUBLEVEL)
libVersion = (apiLibVer.version * 1000) + (apiLibVer.release * 100) +
(apiLibVer.level * 10) + (apiLibVer.subLevel);
if (libVersion < appVersion)
{
printf("\n***********************************************************\n");
printf("The TSM API library is lower than the application version\n");
printf("Install the current library version.\n");
printf("*************************************************************\n");
return 0;
}
printf("* API Library Version = %d.%d.%d.%d *\n",
apiLibVer.version,
apiLibVer.release,
apiLibVer.level,
apiLibVer.subLevel);
Note: | When you run applications that assume a multi-threaded API, use the dsmQueryAPIVersionEx call. This verifies that the level of the API is 3.1.6 or a higher level. |
The multi-threaded API permits applications to create multiple sessions with the TSM server within the same process. The API can be entered again. Any calls can run in parallel from within different threads. To run the API in multi-threaded mode, set the mtflag value to DSM_MULTITHREAD on the dsmSetUp call. The dsmSetUp call must be the first call after the dsmQueryAPIVersionEx call. This call must return before any thread calls the dsmInitEx call. When all threads complete processing, enter a call to dsmCleanUp. The primary process should not end before all the threads complete processing. See callmt1.c in the sample.
Note: | The default for the API is single-thread mode. If an application does not call dsmSetUp with the mtflag value set to DSM_MULTITHREAD, the API permits only one session for each process. |
For UNIX Only: You cannot use the Trusted Communication Agent in multi-thread mode. If you want to use passwordaccess generate, you must be a TSM-Authorized user.
Once dsmSetUp successfully completes, the application can begin multiple threads and enter multiple dsmInitEx calls. Each dsmInitEx call returns a handle for that session. Any subsequent calls on that thread for that session must use that handle value. Certain values are process-wide, environmental variables (values that are set on dsmSetUp). Each dsmInitEx call will parse options again. Each thread can run with different options by specifying an overwrite file or an options string on the dsmInitEx call. This enables different threads to go to different servers, or use different node names.
Note: | On Netware, we recommend setting the thread stack to 32K or greater. The dynamic reallocation of thread stack is not reliable. The Netware server stops a program because of errors. |
It is the responsibility of the application to handle signals from the user or the operating system. If the user enters a ctrl-c, the application should catch the signal and send dsmTerminate calls for each of the active threads. Then, call dsmCleanUp to exit. Failure to do this might result in unexpected results on the server if sessions are not closed properly.
Note: | We recommend that the application install signal handlers such as, SIGPIPE and SIGUSR1, for signals that cause the application to end. The application then receives the return code from the API. |
You can use the the child process, Trusted Communication Agent (TCA) if passwordaccess is set to generate. When the TCA is used, TSM uses the SIGCLD signal. If you want your application to use the SIGCLD signal, be aware of potential interference from the TSM program and how it uses SIGCLD. See "Session Security" for more information about using the TCA.
The TSM program is a session-based program, and all activities must be performed within a TSM session. To start a session, the application starts the dsmInitEx call. This call must be performed before any other API call other than dsmQueryApiVersionEx, dsmQueryCliOptions, or dsmSetUp.
The dsmQueryCliOptions function can only be called before the dsmInitEx call. It returns the values of important options, such as option files, compression settings, and communication parameters. The dsmInitEx call sets up a session with the server as indicated in the parameters that are passed in the call or defined in the options files.
The client node name, the owner name, and the password parameters are passed to the dsmInitEx call. The owner name is case-sensitive, but the node name and password are not. The application client nodes must be registered with the server before starting a session.
Each time an API application client starts a session with the server, the client application type is registered with the server. We recommend that the application type value contain an operating system abbreviation because this value is entered in the "platform" field on the server. The maximum string length is DSM_MAX_PLATFORM_LENGTH.
The dsmInitEx function call establishes the TSM session with the API configuration file and option list of the application client. The application client can use the API configuration file and option list to set a number of TSM options. These values override the values that are set in the user's configuration files at installation time. They can not change the options that the TSM administrator defines. If the application client does not have its own configuration file and option list, you can set both of these parameters to NULL. For more information about configuration files, see Understanding Configuration Files and Options Files.
The dsmInitEx function call establishes the TSM session, using additional parameters that permit extended verification.
The dsmQuerySessOptions call returns the same fields as the dsmQueryCliOptions call. It can be sent only within a session. The values reflect the client options that are valid during that session, from option files, and from any overrides from the dsmInitEx call.
Once a session starts, the application can send a call to dsmQuerySessInfo to determine the server parameters that are set for this session. Items such as the policy domain and transaction limits are returned to the application with this call.
End sessions with a dsmTerminate call. This closes any connection with the server and frees all resources that are associated with this session.
Tivoli Storage Manager, a session-based system, has security components that permit applications to start sessions in a secure manner. These security measures prohibit unauthorized access to the server and help to insure system integrity.
Every session that is started with the server must complete a sign-on process. This sign-on process requires the use of a password. When the password is coupled with the node name of the client, it insures proper authorization when it connects to the server. The application client provides this password to the API to start the session.
Two methods of password processing are available: passwordaccess prompt, or passwordaccess =generate. If you use the passwordaccess prompt option, you must include the password value on each dsmInitEx call. Or, you can supply the node name and owner name on the dsmInitEx call.
Passwords have expiration times associated with them. If a dsmInitEx call fails with a password-expired return code (DSM_RC_REJECT_VERIFIER_EXPIRED), the application client must enter the dsmChangePW call. This will update the password before the session can be established successfully. The example in Figure 4 demonstrates the procedure to change a password by using dsmChangePW. The login owner must be root or TSM-Authorized to change the password.
The second method, passwordaccess generate, encrypts and stores the password value in a file. The node name and owner name cannot be supplied on the dsmInitEx call, and the system default values will be used. This protects the security of the password file. When the password expires, the generate parameter creates a new one and updates the password file automatically.
For UNIX: Only the root user or the TSM-Authorized user can change the password when using passwordaccess prompt. Only the root user or the TSM-Authorized user can start the password file when using passwordaccess= generate. You can use the Trusted Communication Agent (TCA) child process for password processing. The application should be aware of this because a child process and the SIGCLD signal are used. The TCA is not used in these situations:
The example in Figure 2 defines a number of global and local variables and then uses them in calls to dsmInitEx and dsmTerminate. The dsmInitEx call takes a pointer to dsmHandle for one of its parameters, while the dsmTerminate call takes the dsmHandle itself. The example in Figure 3 displays the details of rcApiOut. The function, rcApiOut, calls the API function dsmRCMsg, that translates a return code into a message. The rcApiOut call then prints the message for the user. A version of rcApiOut is included in the API sample application. The dsmApiVersion function is a type definition that is found in the header file, dsmapitd.h.
Figure 2. An Example of Starting and Ending A Session
dsmApiVersionEx * apiApplVer;
char *node;
char *owner;
char *pw;
char *confFile = NULL;
char *options = NULL;
dsInt16_t rc = 0;
dsUint32_t dsmHandle;
dsmInitExIn_t initIn;
dsmInitExOut_t initOut;
char *userName;
char *userNamePswd;
memset(&initIn, 0x00, sizeof(dsmInitExIn_t));
memset(&initOut, 0x00, sizeof(dsmInitExOut_t));
memset(&apiApplVer,0x00,sizeof(dsmapiVersionEx));
apiApplVer.version = DSM_API_VERSION; /* Set the applications compile */
apiApplVer.release = DSM_API_RELEASE; /* time version. */
apiApplVer.level = DSM_API_LEVEL;
apiApplVer.subLevel= DSM_API_SUBLEVEL;
printf("Doing signon for node %s, owner %s, with password %s\n", node,owner,pw);
initIn.stVersion = dsmInitExInVersion;
initIn.dsmApiVersionP = &apiApplVer
initIn.clientNodeNameP = node;
initIn.clientOwnerNameP = owner ;
initIn.clientPasswordP = pw;
initIn.applicationTypeP = "Sample-API AIX";
initIn.configfile = confFile;
initIn.options = options;
initIn.userNameP = userName;
initIn.userPasswordP = userNamePswd;
rc = dsmInitEx(&dsmHandle, &initIn, &initOut);
if (rc == DSM_RC_REJECT_VERIFIER_EXPIRED)
{
printf("*** Password expired. Select Change Password.\n");
return(rc);
}
else if (rc)
{
printf("*** Init failed: ");
rcApiOut(dsmHandle, rc); /* Call function to print error message */
dsmTerminate(dsmHandle); /* clean up memory blocks */
return(rc);
}
Figure 3. Details of rcApiOut
void rcApiOut (dsUint32_t handle, dsInt16_t rc)
{
char *msgBuf ;
if ((msgBuf = (char *)malloc(DSM_MAX_RC_MSG_LENGTH+1)) == NULL)
{
printf("Abort: Not enough memory.\n") ;
exit(1) ;
}
dsmRCMsg(handle, rc, msgBuf);
printf("%s\n",msgBuf);
free(msgBuf) ;
return;
}
Figure 4. An Example of Changing A Password
printf("Enter your current password:");
gets(current_pw);
printf("Enter your new password:");
gets(new_pw1);
printf("Enter your new password again:");
gets(new_pw2);
/* If new password entries don't match, try again or exit. */
/* If they do match, call dsmChangePW. */
rc = dsmChangePW(dsmHandle,current_pw,new_pw1);
if (rc)
{
printf("*** Password change failed. Rc = %i\n",rc);
}
else
{
printf("*** Your new password has been accepted and updated.\n");
}
return 0;
The TSM server, an object storage server whose primary function is to efficiently store and retrieve named objects, has two main storage areas, database and data storage, to meet this requirement:
Each object that is stored on the server has a name associated with it. The client controls the following key components of that name:
When making decisions about naming objects for an application, you might need to use an external name for the full object names to the end user. Specifically, the end user might need to specify the object in an Include or Exclude statement when the application is run. The exact syntax of the object name in these statements is platform-dependent. On the OS/2 and Windows platforms, the drive letter associated with the file space rather than the filespace name itself is used in the Include or Exclude statement. On the Novell and AS/400 platforms, the first character of the low-level name must be a forward slash (/).
The filespace name is one of the most important components. It can be the name of a file system or disk drive, or any other high-level qualifier that groups related data together. Tivoli Storage Manager uses the file space to identify the file system or disk drive on which the data is located. In this way, actions can be performed on all entities within a file space, such as querying all objects within a specified file space. Because the file space is such an important component of the TSM naming convention, TSM has special calls to register, update, query, and delete file spaces.
The server also has administrative commands to query the file spaces on any node in TSM storage, and delete them if necessary. All data stored by the application client must have a filespace name associated with it. Select the name carefully to group similar data together in the system.
To avoid possible interference, an application client should select different filespace names from those that a backup-archive client would use. The application client should publish its filespace names so that end users can identify the objects for Include and Exclude statements, if necessary.
Note: | On Intel platforms, a drive letter is associated with a file space. When you register or update a file space, you must supply the drive letter. Because the Include-Exclude list refers to the drive letter, you must keep track of each letter and its associated file space. In the sample program dapismp, the drive letter is set to 'G' by default. |
For more information, see the sample program installed on your system.
Two other components of the object name are the high-level name qualifier and the low-level name qualifier. The high-level name qualifier is the directory path in which the object belongs, and the low-level name qualifier is the actual name of the object in that directory path. When the filespace name, high-level name, and low-level name are concatenated, they must form a syntactically correct name on the operating system on which the client runs. It is not necessary for the name to exist as an object on the system or resemble the actual data on the local file system. However, the name must meet the standard naming rules to be properly processed by the dsmBindMC calls. See "Understand Backup And Archive Objects" for naming considerations.
The object type identifies the object as either a file or a directory. A file is an object that contains both attributes and binary data, and a directory is an object that contains only attributes.
Following are four examples of object names. The first example displays what the application client would code on a UNIX platform:
/myfs/highlev/lowlev
The second example displays what the application client would code on a Windows or OS/2 platform:
"myvol\\highlev\\lowlev"
Note: | On Windows and OS/2, you must use a double backslash because a backslash is the escape character. The double backslashes are translated to single backslashes. Filespace names start with a slash on the UNIX platform, but do not start with a slash on the Windows platform. |
The third example displays what the application client would code on a Novell NetWare platform:
myvol:/highlev/lowlev
The fourth example displays what the application client would code on the AS/400 platform:
myfs/highlev/lowlev
Each object has an owner name associated with it. The rules determining what objects are accessed depend on what owner name is used when a session is started. Use this session owner value to control access to the object.
The session owner is set during the call to dsmInitEx in the clientOwnerNameP parameter. If you start a session with dsmInitEx owner name of NULL and you use passwordaccess prompt, that session owner is handled with session (root or TSM-Authorized) authority. This is also true if you log in with a root ID or TSM-authorized ID and you use passwordaccess generate. This session can perform any action on any object that is owned by this node regardless of the actual owner of that object.
If a session is started with a specific owner name, the session can only perform actions on objects that have that object owner name associated with them. Backups or archives into the system all must have this owner name associated with them. Any queries performed return only the values that have this owner name associated with them. The object owner value is set during the dsmSendObj call in the Owner field of the ObjAttr structure. An owner name is case-sensitive. Table 9 summarizes the conditions under which a user has access to an object.
Table 9. Summary of User Access to Objects
Session Owner | Object Owner | User Access |
---|---|---|
NULL (Root, system owner) | " " (Empty string) | Yes |
NULL | Specific name | Yes |
Specific name | " " (Empty string) | No |
Specific name | Same name | Yes |
Specific name | Different name | No |
Three function calls, dsmSetAccess, dsmDeleteAccess,
and dsmQueryAccess support cross-node, cross-owner access on the
same platform. These functions, along with the -fromnode and
-fromowner string options that are passed on dsmInitEx,
permit a complete cross-node query, restore and retrieve process through the
API. For example, User A on node A uses the dsmSetAccess
function call to give access to its backups under the /db filespace
to User B from Node B. The access rule is displayed as:
ID | Type | Node | User | Path |
---|---|---|---|---|
1 | Backup | Node B | User B | /db/*/* |
When User B logs on at Node B, the option string to dsmInitEx is:
-fromnode=nodeA -fromowner=userA
These options are set for this session. Any queries will access the filespaces, and files of Node A. Backups and archives are not permitted. Only query, restore, and retrieve processes are permitted from the filespaces for which User B has access. See the individual function calls and dsmInitEx for more information.
Because the filespace is so important to the operation of the system, a separate set of calls is used to register, update, and delete filespace identifiers. Before you can store any objects that are associated with a filespace on the system, you must first register the filespace with TSM. Use the dsmRegisterFS call to accomplish this task. See Identifying the Object for more information.
The filespace identifier is the top-level qualifier in a three-part name hierarchy. Grouping related data together within a filespace makes management of that data much easier. For example, either the application client or the TSM server administrator can delete a filespace and all the objects within that filespace.
Filespaces also permit the application client to provide information about
the filespace to the server that the TSM administrator can then query.
This information is returned on the query in the qryRespFSData
structure and includes:
Type | Definition |
---|---|
fstype | The filespace type. This field is a character string that the application client sets. |
fsAttr[platform].fsInfo | A client information field used for client-specific data. |
capacity | The total amount of space in the file space. |
occupancy | The amount of space currently occupied in the file space. |
backStartDate | The time stamp when the latest backup started (set by sending a dsmUpdateFS call). |
backCompleteDate | The time stamp when the latest backup completed (set by sending a dsmUpdateFS call). |
Using capacity and occupancy depends on the application client. Some applications might not need information about the size of the file space, in which case these fields can default to zero. See Querying the TSM System for more information about querying file spaces.
After a file space is registered with the system, you can back up or archive objects at any time. We recommend that you call dsmUpdateFS to update the occupancy and the capacity fields of the file space after a backup or archive operation. This ensures that the values for the occupancy and capacity of the file system are current. You can also update the fsinfo, backupstart, and backupcomplete fields.
If you want to monitor your last backup dates, enter a dsmUpdateFS call before starting your backup. Set the update action to DSM_FSUPD_BACKSTARTDATE. This will force the server to set the backStartDate field of the file space to the current time. After the backup is complete for that file space, enter a dsmUpdateFS call with the update action that is set to DSM_FSUPD_BACKCOMPLETEDATE. This will time stamp the end of the backup.
If a file space is no longer needed, you can delete it with the dsmDeleteFS command. On the UNIX platform, only the root user or TSM-Authorized user can delete file spaces.
The examples in Figure 5 demonstrate how to use the three filespace calls for UNIX. For an example of how to use the three filespace calls for Intel, see the sample program code installed on your system.
Figure 5. An Example of Working With File Spaces
/* Register the file space if it has not already been done. */
dsInt16 rc;
regFSData fsData;
char fsName[DSM_MAX_FSNAME_LENGTH];
char smpAPI[] = "Sample-API";
strcpy(fsName,"/home/tallan/text");
memset(&fsData,0x00,sizeof(fsData));
fsData.stVersion = regFSDataVersion;
fsData.fsName = fsName;
fsData.fsType = smpAPI;
strcpy(fsData.fsAttr.unixFSAttr.fsInfo,"Sample API FS Info");
fsData.fsAttr.unixFSAttr.fsInfoLength =
strlen(fsData.fsAttr.unixFSAttr.fsInfo) + 1;
fsData.occupancy.hi=0;
fsData.occupancy.lo=100;
fsData.capacity.hi=0;
fsData.capacity.lo=300;
rc = dsmRegisterFS(dsmHandle,fsData);
if (rc == DSM_RC_FS_ALREADY_REGED) rc = DSM_RC_OK; /* already done */
if (rc)
{
printf("Filespace registration failed: ");
rcApiOut(dsmHandle, rc);
free(bkup_buff);
return (RC_SESSION_FAILED);
}
/* Update the file space. */
dsmFSUpd updFilespace; /* for update FS */
updFilespace.stVersion = dsmFSUpdVersion;
updFilespace.fsType = 0; /* no change */
updFilespace.occupancy.hi = 0;
updFilespace.occupancy.lo = 50;
updFilespace.capacity.hi = 0;
updFilespace.capacity.lo = 200;
strcpy(updFilespace.fsAttr.unixFSAttr.fsInfo,
"My update for filespace") ;
updFilespace.fsAttr.unixFSAttr.fsInfoLength =
strlen(updFilespace.fsAttr.unixFSAttr.fsInfo);
updAction = DSM_FSUPD_FSINFO |
DSM_FSUPD_OCCUPANCY |
DSM_FSUPD_CAPACITY;
rc = dsmUpdateFS(handle,fsName,&updFilespace,updAction);
printf("dsmUpdateFS rc=%d\n", rc);
/* Delete the file space. */
printf("\nDeleting file space %s",fsName);
rc = dsmDeleteFS(dsmHandle,fsName,DSM_REPOS_ALL);
if (rc)
{
printf(" FAILED!!! ");
rcApiOut(dsmHandle, rc);
}
else printf(" OK!\n");
A primary feature of TSM is the use of policy (management classes) to define how objects are stored and managed in TSM storage. A management class is associated with an object when the object is backed up or archived. This management class determines:
Management classes consist of both backup copy groups and archive copy groups. A copy group is a set of attributes that define the management policies for an object that is being backed up or archived. If a backup operation is being performed, the attributes in the backup copy group apply. If an archive operation is being performed, the attributes in the archive copy group apply.
The backup or archive copy group in a particular management class can be empty or NULL. If an object is bound to the NULL backup copy group, that object cannot be backed up. If an object is bound to the NULL archive copy group, the object cannot be archived.
Because the use of policy is a very important component of TSM, the API requires that all objects sent to the server are first assigned a management class by using the dsmBindMC call. The TSM product supports using an Include-Exclude list to affect management class binding. The dsmBindMC call uses the current Include-Exclude list to perform management class binding.
Include statements can associate a specific management class with a backup or archive object. Exclude statements can prevent objects from being backed up but not from being archived. For more information, see Tivoli Storage Manager Installing the Clients.
The API requires that dsmBindMC is called before you back up or
archive an object. The dsmBindMC call returns a
mcBindKey structure that contains information on management class
and copy groups that are associated with the object. Check the copy
group destination before proceeding with a send. When you send multiple
objects in a single transaction, they must have the same copy group
destination. The dsmBindMC function call returns the
following information:
Table 10. Information Returned on the dsmBindMC Call
Information | Description |
---|---|
Management Class | The name of the management class that was bound to the object. The application client can send the dsmBeginQuery call to determine all attributes of this management class. |
Backup Copy Group | Informs you if a backup copy group exists for this management class. If a backup operation is being performed and a backup copy group does not exist, this object cannot be sent to TSM storage. You will receive an error code if you attempted to send it using the dsmSendObj call. |
Backup Copy Destination | This field identifies the TSM storage pool to which the data is sent. If you are performing a multiple object backup transaction, all copy destinations within that transaction must be the same. If an object has a different copy destination than previous objects in the transaction, end the current transaction and begin a new transaction before you can send the object. You will receive an error code if you attempt to send objects to different copy destinations within the same transaction. |
Archive Copy Group | Informs you if an archive copy group exists for this management class. If an archive operation is being performed and an archive copy group does not exist, this object cannot be sent to TSM storage. You will receive an error code if you attempted to send it using the dsmSendObj call. |
Archive Copy Destination | This field identifies the TSM storage pool to which the data is sent. If you are performing a multiple object archive transaction, all copy destinations within that transaction must be the same. If an object has a different copy destination than previous objects in the transaction, end the current transaction and begin a new transaction before you send the object. You will receive an error code if you attempt to send objects to different copy destinations within the same transaction. |
Applications can query management classes to determine what management classes are possible for a given node, and to determine what the attributes are within the management class. You can only bind objects to management classes by using the dsmBindMC call. You might want your applications to query the management class attributes and display them to end users. See Querying the TSM System for more information.
In the example in Figure 6, a switch statement is used to distinguish between backup and archive operations when calling dsmBindMC. The information returned from this call is stored in the MCBindKey structure.
Figure 6. An Example of Associating A Management Class With An Object
dsUint16_t send_type;
dsUint32_t dsmHandle;
dsmObjName objName; /* structure containing the object name */
mcBindKey MCBindKey; /* management class information */
char *dest; /* save destination value */
switch (send_type)
{
case (Backup_Send) :
rc = dsmBindMC(dsmHandle,&objName,stBackup,&MCBindKey);
dest = MCBindKey.backup_copy_dest;
break;
case (Archive_Send) :
rc = dsmBindMC(dsmHandle,&objName,stArchive,&MCBindKey);
dest = MCBindKey.archive_copy_dest;
break;
default : ;
}
if (rc)
{
printf("*** dsmBindMC failed: ");
rcApiOut(dsmHandle, rc);
rc = (RC_SESSION_FAILED);
return;
}
The API has several queries, such as management class query, that applications can use. All queries that use dsmBeginQuery follow the same steps that are described below:
The dsmBeginQuery call informs the API in what format the data is returning from the server. The appropriate fields can be placed in the data structures that are passed by the dsmGetNextQObj calls. The begin query call also permits the application client to set the scope of the query by properly specifying the parameters on the begin query call.
Note: | On the UNIX platform, only the root user can query active backed-up objects (also known as fast path). |
Figure 7 displays the state diagram for performing query operations.
Figure 7. State Diagram for General Queries
![]() |
Figure 8 displays the flowchart for performing query operations.
Figure 8. Flowchart for General Queries
![]() |
In the example in Figure 9, a management class query prints out the values of all the fields in the backup and archive copy groups for a particular management class.
Figure 9. An Example of Performing a System Query
dsInt16 rc;
qryMCData qMCData;
DataBlk qData;
qryRespMCDetailData qRespMCData, *mcResp;
char *mc, *s;
dsBool_t done = bFalse;
dsUint32_t qry_item;
/* Fill in the qMCData structure with the query criteria we want */
qMCData.stVersion = qryMCDataVersion; /* structure version */
qMCData.mcName = mc; /* management class name */
qMCData.mcDetail = bTrue; /* want full details? */
/* Set parameters of the data block used to get or send data */
qData.stVersion = DataBlkVersion;
qData.bufferLen = sizeof(qryRespMCDetailData);
qData.bufferPtr = (char *)&qRespMCData;
qRespMCData.stVersion = qryRespMCDetailDataVersion;
if ((rc = dsmBeginQuery(dsmHandle,qtMC,(dsmQueryBuff *)&qMCData)))
{
printf("*** dsmBeginQuery failed: ");
rcApiOut(dsmHandle, rc);
rc = (RC_SESSION_FAILED);
}
else
{
done = bFalse;
qry_item = 0;
while (!done)
{
rc = dsmGetNextQObj(dsmHandle,&qData);
if (( (rc == DSM_RC_MORE_DATA)
|| (rc == DSM_RC_FINISHED))
&& qData.numBytes)
{
qry_item++;
mcResp = (qryRespMCDetailData *)qData.bufferPtr;
printf("Mgmt. Class %lu:\n",qry_item);
printf(" Name: %s\n",mcResp->mcName);
printf(" Backup CG Name: %s\n",mcResp->backupDet.cgName);
.
. /* other fields of backup and archive copy groups */
.
printf(" Copy Destination: %s\n",mcResp->archDet.destName);
}
else
{
done = bTrue;
if (rc != DSM_RC_FINISHED)
{
printf("*** dsmGetNextQObj failed: ");
rcApiOut(dsmHandle, rc);
}
}
if (rc == DSM_RC_FINISHED) done = bTrue;
}
rc = dsmEndQuery(dsmHandle);
}
The API permits application clients to send data, or named objects and their associated data, to TSM server storage.
Note: | You can either back up or archive data. Perform all send operations within a transaction. |
All data sent to TSM storage during a backup or archive operation is done within a transaction. This provides a high level of data integrity for the TSM product, but it does impose some restrictions that an application client must take into consideration.
Start a transaction by a call to dsmBeginTxn or end a transaction by a call to dsmEndTxn. A single transaction is an atomic action. Data sent within the boundaries of a transaction is either committed to the system at the end of the transaction, or rolled back if the transaction ends prematurely.
Transactions can consist of either single object sends or multiple object sends. Send smaller objects in a multiple object transaction. This greatly improves total system performance, because transaction overhead is decreased. The application client determines whether single or multiple transactions are appropriate.
Send all objects within a multiple object transaction to the same copy destination. If you need to send an object to a different destination than the previous object, end the current transaction and start a new one. Within the new transaction, you can send the object to the new copy destination.
Tivoli Storage Manager limits the number of objects that can be sent in a multiple object transaction. To find this limit, call dsmQuerySessInfo and examine the maxObjPerTxn field. This field displays the value of the TXNGroupmax option that is set on your server.
The application client must keep track of the objects sent within a transaction to perform retry processing or error processing if the transaction ends prematurely. Either the server or the client can stop a transaction at any time. The application client must be prepared to handle sudden transaction ends that it did not start.
Tivoli Storage Manager servers use a function that is called file aggregation. With file aggregation, all objects sent in a single transaction are stored together, which saves space and improves performance. You can still query and restore the objects separately.
To use this new function, all of the objects in a transaction should have the same filespace name. If the filespace name changes within a transaction, the server closes the existing aggregated object and begins a new one.
Attention: It is important that you try to be as accurate as possible on this size, because the TSM server uses this attribute for efficient space allocation and object placement within its storage resources.
Application clients can send data, or named objects and their associated data, to TSM storage by using the API backup and archive functions. The backup and archive components of the system permit use of different management procedures for data that is sent to TSM storage.
The size estimate attribute is an estimate of the total size of the data object to send to the server. If the application does not know the exact object size, set the sizeEstimate to a higher estimate. If the estimate is smaller than the actual size, the TSM server would use extra resources to manage extra space allocations.
You might encounter problems if the sizeEstimate is much too large. The TSM server might not have enough space for the estimated size, but it does have space for the actual size. Or, the server might use slower devices.
You can back up or archive objects that are larger than two gigabytes in size. The objects can be either compressed or uncompressed.
To start a send operation, call dsmSendObj. If you have more data than you can send at one time, you can make repeated calls to dsmSendData to transfer the remainder of the information. Call dsmEndSendObj to complete the send operation.
The backup component of the TSM system supports several versions of named objects that are stored on the server. Any object backed up to the server that has the same name as an object that is already stored on the server from that client is subject to version control. Objects are considered to be in active or inactive states on the server. The latest copy of an object on the server that has not been deactivated is in the active state. Any other object, whether it is an older version or a deactivated copy, is considered inactive. Management class constructs define different management criteria. They are assigned to active and inactive objects on the server. Backup copy group fields that apply include:
If backup versions each have a unique name, such as using a time stamp in the name, then versioning will not happen automatically; every object will be active. Active objects never expire, so an application would be responsible for deactivating these with the dsmDeleteObj call. In this situation, the application would need the deactivated objects to expire as soon as possible. The user would define a backup copy group with VERDELETED=0 and RETONLY=0.
The archive component of the TSM system permits objects to be stored on the server with retention or expiration period controls instead of version control. Each object stored is unique, even though its name might be the same as an object already archived. Archive objects have a description field associated with the meta data that can be used during query to identify a specific object.
Every object on a TSM server is assigned a unique object ID. The persistence of the original value is not guaranteed during the life of an object (specifically, after an export or import). Therefore, an application should not query and save the original object ID for use on later restores. Rather, an application should save the object name and insert date. You can use this information during a restore to query objects and verify the insert date. Then, the current object ID can be used to restore the object.
The end user's configuration, along with the dsmSendObj objCompressed flag, determines whether TSM will compress the object during a send. Also, objects with a sizeEstimate less than DSM_MIN_COMPRESS_SIZE will never be compressed.
If the object is compressed already (objCompressed=bTrue), TSM does not try to compress it again. If it is not compressed, TSM decides whether to compress the object, based on the values of the compression option that is set by the TSM administrator and is set in the API configuration sources.
The TSM server administrator can affect compression behavior with the register node command (compression=yes, compression=no, or client-determined). If this is client-determined, then the compression behavior is determined by the option value in the configuration sources.
Some types of data, such as data that is already compressed, might actually get bigger when processed with the compression algorithm. When this happens, the return code DSM_RC_COMPRESS_GREW is generated. If you recognize that this may happen, but want the send operation to continue anyway, tell the end users to specify the following option in their options file:
COMPRESSAlways Yes
Note: | If your application plans to use partial object restore or retrieve, you cannot compress the data while sending it. To enforce this, set ObjAttr.objCompressed to bTrue. |
The API is designed for straightforward logic flows and clear transitions between the various states of the application client. This clean state transition catches logic flaws and program errors early in the development cycle, greatly enhancing the quality and reliability of the system. For example, you cannot make a dsmSendObj call unless a transaction was started and a dsmBindMC call was previously made for the object that you are backing up.
Figure 10 displays the state diagram for performing backup or archive operations within a transaction. The arrow pointing from "In Send Object" to dsmEndTxn indicates that a dsmEndTxn call can be started after a call to dsmSendObj or dsmSendData. You might want to do do this if an error condition occurred during the send of an object and you want to stop the entire operation. In this case, you must use a vote of DSM_VOTE_ABORT. In normal circumstances, however, call dsmEndSendObj before you end the transaction.
Figure 10. State Diagram for Backup and Archive Operations
![]() |
Figure 11 displays the flowchart for performing backup or archive operations within a transaction.
Figure 11. Flowchart for Backup and Archive Operations
![]() |
The primary feature in these two diagrams is the loop between the following API calls from within a transaction:
The dsmBindMC call is unique in that you can start it from inside or outside of a transaction boundary. You can also start it from a different transaction, if required. The only requirement for the dsmBindMC call is that it is made prior to backing up or archiving an object. If the object that you are backing up or archiving is not associated with a management class, an error code is returned from dsmSendObj. In this situation, the transaction is ended by calling dsmEndTxn (this error condition is not shown in the flowchart).
The flowchart illustrates how an application would use multiple object transactions. It shows where decision points can be placed to determine if the object that is sent fits within the transaction or whether to start a new transaction.
Figure 12 demonstrates the use of the API functions that send data to TSM storage. The dsmSendObj call appears inside a switch statement, so that different parameters can be called depending on whether a backup or archive operation is being performed. The dsmSendData call is called from inside a loop that repeatedly sends data until a flag is set that permits the program execution to exit the loop. The entire send operation is performed from within the transaction.
The third parameter on the dsmSendObj call is a buffer that contains the archive description. Because backup objects do not have a description, this parameter is NULL when backing up an object.
Figure 6 displays an example that shows the use of the dsmBindMC function call.
Figure 12. An Example of Sending Data to a Server
if ((rc = dsmBeginTxn(dsmHandle)) ) /* API session handle */
{
printf("*** dsmBeginTxn failed: ");
rcApiOut(dsmHandle, rc);
return;
}
/* Call dsmBindMC if not done previously */
objAttr.sizeEstimate.hi = 0; /* estimate of */
objAttr.sizeEstimate.lo = 32000; /* object size */
switch (send_type)
{
case (Backup_Send) :
rc = dsmSendObj(dsmHandle,stBackup,
NULL,&objName,&objAttr,NULL);
break;
case (Archive_Send) :
archData.stVersion = sndArchiveDataVersion;
archData.descr = desc;
rc = dsmSendObj(dsmHandle,stArchive,
&archData,&objName,&objAttr,NULL);
break;
default : ;
}
if (rc)
{
printf("*** dsmSendObj failed: ");
rcApiOut(dsmHandle, rc);
return;
}
done = bFalse;
while (!done)
{
dataBlk.stVersion = DataBlkVersion;
dataBlk.bufferLen = send_amt;
dataBlk.numBytes = 0;
dataBlk.bufferPtr = bkup_buff;
rc = dsmSendData(dsmHandle,&dataBlk);
if (rc)
{
printf("*** dsmSendData failed: ");
rcApiOut(dsmHandle, rc);
done = bTrue;
}
/* Adjust the dataBlk buffer for the next piece to send */
}
rc = dsmEndSendObj(dsmHandle);
if (rc)
{
printf("*** dsmEndSendObj failed: ");
rcApiOut(dsmHandle, rc);
}
txn_reason = 0;
rc = dsmEndTxn(dsmHandle, /* API session handle */
DSM_VOTE_COMMIT, /* Commit transaction */
&txn_reason); /* Reason if txn aborted */
if (rc || txn_reason)
{
printf("*** dsmEndTxn failed: rc = ");
rcApiOut(dsmHandle, rc);
printf(" reason = %u\n",txn_reason);
}
Application clients can receive data, or named objects and their associated data, from TSM storage by using the restore and retrieve functions of the product. The restore function accesses objects that previously were backed up, and the retrieve function accesses objects that previously were archived.
Note: | The API can only restore or retrieve objects that were backed up or archived using API calls. |
Both restore and retrieve functions start with a query operation. The query returns different information depending on whether the data was originally backed up or archived. For instance, a query on backup objects returns information on whether an object is active or inactive, while a query on archive objects returns information such as object descriptions. Both queries return object IDs that TSM uses to uniquely identify the object on the server.
The application client can receive only a portion of the object. This is called a partial object restore or a partial object retrieve.
Note: | A partial object restore or retrieve works only with TSM Version 2 or 3 servers. If your application plans to use a partial object restore or retrieve, you cannot compress the data while sending it. To enforce this, set ObjAttr.objCompressed to bTrue. |
To perform a partial object restore or retrieve, associate the following two data fields with each object GetList entry:
Use DSM_MAX_PARTIAL_GET_OBJ to determine the maximum number of objects that can perform a partial object restore or retrieve.
The following data fields, used on the dsmBeginGetData call, determine what portion of the object is restored or retrieved:
After a query is made and a session is established with the TSM server, the procedure to restore or retrieve data is to:
Before you can begin any restore or retrieve operation, first query the TSM server to determine what objects you can receive from storage. To send the query, the application must enter the proper parameter lists and structures for the dsmBeginQuery call. This includes the file space that the query will examine and pattern-match entries for the high-level and low-level name fields. If the session was initialized with a NULL owner name, it is not necessary to specify the owner field. However, if the session was initialized with an explicit owner name, only objects that explicitly have that owner name associated with them are returned.
The Point-in-time BackupQuery supplies a snapshot of the system at a given time. By specifying a valid date, you can query all files that were backed up to that time. Point-in-time overrides an object state so that, even if an object has an active backup from a later date, the previous inactive copy is returned. An example of this is in pitDate. You must be connected to a Version 3 server to use point-in-time BackupQuery.
A query returns all information that was originally stored with the object, in addition to the following:
You must keep some or all of the query information for later processing. Keep the copyId and restoreOrderExt fields because they are needed for the actual restore operation. You must also keep any other information needed to properly open a data file or identify a destination.
Call dsmEndQuery to finish the query operation.
Once the backup or archive query is performed, the application client must determine which objects, if any, are to be restored or retrieved.
Once the objects to restore or retrieve are selected, sort them in ascending order (low to high). This sorting is very important to the performance of the restore operation. Sorting the objects on the restoreOrderExt fields ensures that the data is read from the server in the most efficient order. All data on disk is restored first, followed by data on media classes that require volume mounts (such as tape). The restoreOrderExt field also ensures that data on tape is read in order with processing starting at the front of a tape and progressing towards the end.
Properly sorting on the restoreOrderExt field means that duplicate tape mounts and unnecessary tape rewinds do not occur.
Following is an example of sorting objects by using Restore Order fields.
Figure 13. An Example of Sorting Objects With the Restore Order Fields
typedef struct {
dsStruct64_t objId;
dsUint160_t restoreOrderExt;
} SortOrder; /* struct used for sorting */
===================================================================
/* the code for sorting starts from here */
dsmQueryType queryType;
qryBackupData queryBuffer;
DataBlk qDataBlkArea;
qryRespBackupData qbDataArea;
dsInt16_t rc;
dsBool_t done = bTrue;
int i = 0;
int qry_item;
SortOrder sortorder[100]; /* sorting can be done up to 100 items
only right now. Set appropriate
array size to fit your needs */
/*-----------------------------------------------------------------+
| NOTE: Make sure that proper initializations have been done to
| queryType,
| queryBuffer, qDataBlkAre, and qbDataArea.
|
------------------------------------------------------------------*/
qDataBlkArea.bufferPtf = (char*) &qbDataArea;
rc = dsmBeginQuery(dsmHandle, queryType, (void *) &queryBuffer);
/*----------------------------------------+
| Make sure to check rc from dsmBeginQuery
+-----------------------------------------*/
while (!done)
{
rc = dsmGetNextQObj(dsmHandle, &qDataBlkArea);
if ((rc == DSM_RC_MORE_DATA) ||
(rc == DSM_RC_FINISHED))
&&( qDataBlkArea.numBytes))
{
/******************************************/
/* transferring restoreOrderExt and objId */
/******************************************/
sortorder[i].restoreOrderExt = qbDataArea.restoreOrderExt;
sortorder[i].objId = qbDataArea.objId;
} /* if ((rc == DSM_RC_MORE_DATA) || (rc == DSM_RC_FINISHED)) */
else
{
done = bFalse;
/****************************/
/* take appropriate action. */
/****************************/
}
i++;
qry_item++;
} /* while (!done) */
/*****************************************************/
/* sorting the array using qsort. After the call, */
/* sortorder will be sorted by restoreOrderExt field */
/*****************************************************/
qsort(sortorder, qry_item, sizeof(SortOrder), SortRestoreOrder);
/*-----------------------------------------------------------------+
| NOTE: Make sure to extract sorted object ids and store them in
| any data structure you want.
------------------------------------------------------------------*/
/*----------------------------------------------------------------+
| int SortRestoreOrder(SortOrder *a, SortOrder *b)
|
| This function compares restoreOrder fields from two structures.
| if (a > b)
| return(GREATERTHAN);
|| if (a < b)
| return(LESSTHAN);
|| if (a == b)
| return(EQUAL);
|+----------------------------------------------------------------*/
int SortRestoreOrder(SortOrder *a, SortOrder *b)
{
if (a->restoreOrderExt.top > b->restoreOrderExt.top)
return(GREATERTHAN);
else if (a->restoreOrderExt.top < b->restoreOrderExt.top)
return(LESSTHAN);
else if (a->restoreOrderExt.hi_hi > b->restoreOrderExt.hi_hi)
return(GREATERTHAN);
else if (a->restoreOrderExt.hi_hi < b->restoreOrderExt.hi_hi)
return(LESSTHAN);
else if (a->restoreOrderExt.hi_lo > b->restoreOrderExt.hi_lo)
return(GREATERTHAN);
else if (a->restoreOrderExt.hi_lo < b->restoreOrderExt.hi_lo)
return(LESSTHAN);
else if (a->restoreOrderExt.lo_hi > b->restoreOrderExt.lo_hi)
return(GREATERTHAN);
else if (a->restoreOrderExt.lo_hi < b->restoreOrderExt.lo_hi)
return(LESSTHAN);
else if (a->restoreOrderExt.lo_lo > b->restoreOrderExt.lo_lo)
return(GREATERTHAN);
else if (a->restoreOrderExt.lo_lo < b->restoreOrderExt.lo_lo)
return(LESSTHAN);
else
return(EQUAL);
}
Once you select and sort the objects to receive, submit them to TSM for either a restore or retrieve. The dsmBeginGetData call begins a restore or retrieve operation. Complete the information for these two parameters in these calls:
Each objId is eight bytes in length, so a single restore or retrieve request can contain thousands of objects. The number of objects to request in a single call is limited to DSM_MAX_GET_OBJ or DSM_MAX_PARTIAL_GET_OBJ.
The objects are returned to the application client in the order you requested.
Once the dsmBeginGetData call is sent, perform the following procedure to receive each object that is sent from the server:
The DSM_RC_MORE_DATA return code means that a buffer was returned and you should call dsmGetData again. The DSM_RC_FINISHED return code means that the last buffer was returned and you should call dsmEndGetObj again. Check the DataBlk.num Bytes for the actual number of returned bytes.
When you obtain all data for an object, you must send a dsmEndGetObj call. If more objects will be received, send the dsmGetObj call again. If you need to stop the process (normally or abnormally), send the dsmEndGetData call.
After all data for all requested objects is received, send the dsmEndGetData call. You can also use this call to discard any remaining data in the restore stream for all objects not yet received. This will flush the data from the server to the client. However, using this method might take time to complete. If you need to end a restore, use dsmTerminate to close the session.
Figure 14 displays the state diagram for performing restore or retrieve operations. The arrow pointing from "In Get Object" to dsmEndGetData indicates that you can send a dsmEndGetData call after a call to dsmGetObj or dsmGetData. You might need to do this if an error condition occurred while getting an object from TSM storage and you want to stop the operation. In normal circumstances, however, call dsmEndGetObj first.
Figure 14. State Diagram for Restore and Retrieve Operations
![]() |
Figure 15 displays the flowchart for performing restore or retrieve operations.
Figure 15. Flowchart for Restore and Retrieve Operations
![]() |
The example in Figure 16 demonstrates using the API functions to retrieve data from TSM storage. The dsmBeginGetData function call appears inside a switch statement, so that different parameters can be called depending on whether a restore or retrieve operation is being performed. The dsmGetData function call is called from inside a loop that repeatedly gets data from the server until a flag is set that permits the program execution to exit the loop.
Figure 16. An Example of Receiving Data from a Server
/* Call dsmBeginQuery and create a linked list of objects to restore. */
/* Process this list to create the proper list for the GetData calls. */
/* Set up the getList structure to point to this list. */
/* This example is set up to perform a partial object retrieve. To */
/* retrieve only complete objects, set up: */
/* getList.stVersion = dsmGetListVersion; */
/* getList.partialObjData = NULL; */
dsmGetList getList;
getList.stVersion = dsmGetListPORVersion; /* structure version */
getList.numObjId = items; /* number of items in list */
getList.objId = (ObjID *)rest_ibuff;
/* list of object IDs to restore */
getList.partialObjData = (PartialObjData *) part_ibuff;
/* list of partial object data */
switch(get_type)
{
case (Restore_Get) :
rc = dsmBeginGetData(dsmHandle,bFalse,gtBackup,&getList);
break;
case (Retrieve_Get) :
rc = dsmBeginGetData(dsmHandle,bFalse,gtArchive,&getList);
break;
default : ;
}
if (rc)
{
printf("*** dsmBeginGetData failed: ");
rcApiOut(dsmHandle, rc);
return rc;
}
/* Get each object from the list and verify whether it is on the */
/* server. If so, initialize structures with object attributes for */
/* data validation checks. When done, call dsmGetObj. */
rc = dsmGetObj(dsmHandle,objId,&dataBlk);
done = bFalse;
while(!done)
{
if ( (rc == DSM_RC_MORE_DATA)
|| (rc == DSM_RC_FINISHED))
{
if (rc == DSM_RC_MORE_DATA)
{
dataBlk.numBytes = 0;
rc = dsmGetData(dsmHandle,&dataBlk);
}
else
done = bTrue;
}
else
{
printf("*** dsmGetObj or dsmGetData failed: ");
rcApiOut(dsmHandle, rc);
done = bTrue;
}
} /* while */
rc = dsmEndGetObj(dsmHandle);
rc = dsmEndGetData(dsmHandle);
return 0;
The API applications can use dsmUpdateObject to update objects that were archived or backed up. Use this call in the session state only, updating one object at a time.
To select an archive object, set the dsmSendType function call to stArchive. Only the latest archive object with this assigned name is updated. For an archived object, the application can update the following fields:
To select a backup object, set dsmSendType to stBack. For backed-up objects, only the active copy is updated. For a backed-up object, the application can update the following fields:
API applications can make calls to either delete objects that were archived or turn off objects that were backed up. Deleting archived objects is dependent on the node authorization that was given when the TSM administrator registered the node. Administrators can specify that nodes can delete archived objects. Use the dsmDeleteObj function call to delete archived objects and turn off backup objects.
An archived object is marked for deletion in TSM storage when the system performs its next object expiration cycle. Once you delete an archived object from the server, you cannot retrieve it.
When you turn off a backup object at the server, the object moves from an active state to an inactive state. These states have different retention policies associated with them that are based on the management class that is assigned.
Similar to the dsmSendObj call, a call to dsmDeleteObj is sent within the boundary of a transaction. The state diagram in Figure 10 displays how a call to dsmDeleteObj is preceded by a call to dsmBeginTxn and followed by a call to dsmEndTxn.
An API application can log event messages to central locations. It can direct logging to the TSM server, the local machine, or both. The dsmLogEventEx function call is performed inside a session. To view messages logged on the server, use the query actlog command through the Administrative Client. See the TSM Administrator's Reference for more information.
We recommend that you use the TSM client option, errorlogretention, to prune the client error log file if the application generates numerous client messages that are written to the client log (dsmLogType either logLocal or logBoth).
Figure 17 contains the state diagram for the API. It contains all previously displayed state diagrams in addition to several other calls previously not displayed. The points in this diagram include:
Note: | If the dsmInitEx call returns with a password-expired return code, the dsmChangePW call must be made before you start a valid session. See Figure 4 for an example that uses dsmChangePW. |
Figure 17. Summary State Diagram for the API
![]() |