/* * backup_dir * * Create a TAR entry record for a directory */ static int backup_dir(char *dir, tlm_acls_t *tlm_acls, tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats, bk_selector_t *bksp) { int erc; NDMP_LOG(LOG_DEBUG, "\"%s\"", dir); erc = get_dir_acl_info(dir, tlm_acls, job_stats); if (erc != 0) { NDMP_LOG(LOG_DEBUG, "Could not read directory info for %s", dir); job_stats->js_errors++; } else { /* * See if the directory must be backed up. */ if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) { NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir); return (erc); } if (tm_tar_ops.tm_putdir != NULL) (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls, local_commands, job_stats); } return (erc); }
/* * check_restore_paths * * Go through the restore list and check the validity of the * restore path. */ static int check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath) { int i, rv; ndmp_name *ent; rv = 0; if (rspath != NULL && *rspath != '\0') { NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath); if (!fs_volexist(rspath)) { MOD_LOG(params, "Error: Invalid volume name for restore."); rv = -1; } } else { for (i = 0; i < n; i++) { ent = (ndmp_name *)MOD_GETNAME(params, i); NDMP_LOG(LOG_DEBUG, "ent[%d].name: \"%s\"", i, ent->name); if (!fs_volexist(ent->name)) { MOD_LOG(params, "Error: Invalid volume name for restore.", ent->name); rv = -1; break; } } } return (rv); }
int snapshot_release(char *volname, char *snapname, char *jname, boolean_t recursive) { zfs_handle_t *zhp; char *p; int rv = 0; if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { NDMP_LOG(LOG_ERR, "Cannot open volume %s", volname); return (-1); } p = strchr(snapname, '@') + 1; if (zfs_release(zhp, p, jname, recursive) != 0) { NDMP_LOG(LOG_DEBUG, "Cannot release snapshot %s", p); rv = -1; } if (cleanup_fd != -1) { (void) close(cleanup_fd); cleanup_fd = -1; } zfs_close(zhp); return (rv); }
/* * Get the checkpoint (snapshot) creation time. * This is necessary to check for checkpoints not being stale. */ int tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname) { char volname[TLM_VOLNAME_MAX_LENGTH]; char chk_name[PATH_MAX]; char *cp_nm; NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d", path, auto_checkpoint); if (path == NULL || *path == '\0' || tp == NULL) return (-1); if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH, path) == -1) return (-1); if (auto_checkpoint) { NDMP_LOG(LOG_DEBUG, "volname [%s]", volname); (void) snprintf(chk_name, PATH_MAX, "%s", jname); return (chkpnt_creationtime_bypattern(volname, chk_name, tp)); } cp_nm = strchr(volname, '@'); NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm); return (chkpnt_creationtime_bypattern(volname, cp_nm, tp)); }
/*ARGSUSED*/ void ndmpd_scsi_reset_device_v2(ndmp_connection_t *connection, void *body) { ndmp_scsi_reset_device_reply reply; ndmpd_session_t *session = ndmp_get_client_data(connection); struct uscsi_cmd cmd; if (session->ns_scsi.sd_devid == -1) { NDMP_LOG(LOG_ERR, "SCSI device is not open."); reply.error = NDMP_DEV_NOT_OPEN_ERR; } else { reply.error = NDMP_NO_ERR; (void) memset((void*)&cmd, 0, sizeof (cmd)); cmd.uscsi_flags |= USCSI_RESET; if (ioctl(session->ns_scsi.sd_devid, USCSICMD, &cmd) < 0) { NDMP_LOG(LOG_ERR, "USCSI reset failed: %m."); NDMP_LOG(LOG_DEBUG, "ioctl(USCSICMD) USCSI_RESET failed: %m."); reply.error = NDMP_IO_ERR; } } ndmp_send_reply(connection, (void *) &reply, "sending scsi_reset_device reply"); }
/* * Put a hold on snapshot */ int snapshot_hold(char *volname, char *snapname, char *jname, boolean_t recursive) { zfs_handle_t *zhp; char *p; if ((zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == 0) { NDMP_LOG(LOG_ERR, "Cannot open volume %s.", volname); return (-1); } if (cleanup_fd == -1 && (cleanup_fd = open(ZFS_DEV, O_RDWR|O_EXCL)) < 0) { NDMP_LOG(LOG_ERR, "Cannot open dev %d", errno); zfs_close(zhp); return (-1); } p = strchr(snapname, '@') + 1; if (zfs_hold(zhp, p, jname, recursive, cleanup_fd) != 0) { NDMP_LOG(LOG_ERR, "Cannot hold snapshot %s", p); zfs_close(zhp); return (-1); } zfs_close(zhp); return (0); }
/* * get_acl_info * * load up all the access and attribute info */ static int get_acl_info(char *name, tlm_acls_t *tlm_acls) { int erc; acl_t *aclp = NULL; char *acltp; erc = lstat64(name, &tlm_acls->acl_attr); if (erc != 0) { NDMP_LOG(LOG_ERR, "Could not find file %s.", name); erc = TLM_NO_SOURCE_FILE; return (erc); } erc = acl_get(name, ACL_NO_TRIVIAL, &aclp); if (erc != 0) { NDMP_LOG(LOG_DEBUG, "Could not read ACL for file [%s]", name); erc = TLM_NO_SOURCE_FILE; return (erc); } if (aclp && (acltp = acl_totext(aclp, ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { (void) strlcpy(tlm_acls->acl_info.attr_info, acltp, TLM_MAX_ACL_TXT); acl_free(aclp); free(acltp); } return (erc); }
/* * cstack_pop * * Pop an element off the stack. Set up the data and len references for * the caller, advance the stack head and free the popped stack node. * * Returns 0 on success. Otherwise returns -1 to indicate underflow. */ int cstack_pop(cstack_t *stk, void **data, int *len) { cstack_t *stk_node; if (stk == NULL) { NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack"); return (-1); } if ((stk_node = stk->next) == NULL) { NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow"); return (-1); } if (data) *data = stk_node->data; if (len) *len = stk_node->len; stk->next = stk_node->next; NDMP_LOG(LOG_DEBUG, "cstack_pop(0x%p): 0x%p", stk, stk_node); free(stk_node); return (0); }
/* * backup_create_structs * * Allocate the structures before performing backup * * Parameters: * sesison (input) - session handle * jname (input) - backup job name * * Returns: * 0: on success * -1: otherwise */ static int backup_create_structs(ndmpd_session_t *session, char *jname) { int n; long xfer_size; ndmp_lbr_params_t *nlp; tlm_commands_t *cmds; if ((nlp = ndmp_get_nlp(session)) == NULL) { NDMP_LOG(LOG_DEBUG, "nlp == NULL"); return (-1); } if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) { NDMP_LOG(LOG_DEBUG, "Creating job stats"); return (-1); } cmds = &nlp->nlp_cmds; (void) memset(cmds, 0, sizeof (*cmds)); xfer_size = ndmp_buffer_get_size(session); if (xfer_size < 512*KILOBYTE) { /* * Read multiple of mover_record_size near to 512K. This * will prevent the data being copied in the mover buffer * when we write the data. */ if ((n = (512 * KILOBYTE/xfer_size)) <= 0) n = 1; xfer_size *= n; NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", xfer_size); } cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size); if (cmds->tcs_command == NULL) { NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers"); tlm_un_ref_job_stats(jname); return (-1); } nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, ndmpd_file_history_path, ndmpd_file_history_dir, ndmpd_file_history_node); if (nlp->nlp_logcallbacks == NULL) { tlm_release_reader_writer_ipc(cmds->tcs_command); tlm_un_ref_job_stats(jname); return (-1); } nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); return (0); }
/* * backup_file * * Create a TAR record entry for a file */ static longlong_t backup_file(char *dir, char *name, tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats, bk_selector_t *bksp) { int erc; char buf[TLM_MAX_PATH_NAME]; longlong_t rv; NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name); (void) strlcpy(buf, dir, sizeof (buf)); (void) strlcat(buf, "/", sizeof (buf)); (void) strlcat(buf, name, sizeof (buf)); /* * get_acl_info extracts file handle, attributes and ACLs of the file. * This is not efficient when the attributes and file handle of * the file is already known. */ erc = get_acl_info(buf, tlm_acls); if (erc != TLM_NO_ERRORS) { NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name); return (-ENOENT); } /* Should the file be backed up? */ if (!bksp) { NDMP_LOG(LOG_DEBUG, "[%s/%s] has no selection criteria", dir, name); } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) { NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name); return (0); } /* Only the regular files and symbolic links can be backed up. */ if (!S_ISLNK(tlm_acls->acl_attr.st_mode) && !S_ISREG(tlm_acls->acl_attr.st_mode)) { NDMP_LOG(LOG_DEBUG, "Warning: skip backing up [%s][%s]", dir, name); return (-EINVAL); } if (tm_tar_ops.tm_putfile != NULL) rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands, local_commands, job_stats); return (rv); }
/* * Print the list of array of strings in the backup log */ void tlm_log_list(char *title, char **lpp) { int i; if (!lpp) return; NDMP_LOG(LOG_DEBUG, "%s:", title); for (i = 0; *lpp; lpp++, i++) NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp); }
/* * ndmp_run * * Creates a socket for listening and accepting connections * from NDMP clients. * Accepts connections and passes each connection to the connection * handler. * * Parameters: * port (input) - NDMP server port. * If 0, the port number will be retrieved from * the network service database. If not found there, * the default NDMP port number (from ndmp.x) * will be used. * handler (input) - connection handler function. * * Returns: * This function normally never returns unless there's error. * -1 : error * * Notes: * This function does not return unless encountering an error * related to the listen socket. */ int ndmp_run(ulong_t port, ndmp_con_handler_func_t con_handler_func) { int ns; int on; int server_socket; unsigned int ipaddr; struct sockaddr_in sin; ndmpd_worker_arg_t *argp; sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { NDMP_LOG(LOG_DEBUG, "Socket error: %m"); return (-1); } on = 1; (void) setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)); if (bind(server_socket, (struct sockaddr *)&sin, sizeof (sin)) < 0) { NDMP_LOG(LOG_DEBUG, "bind error: %m"); (void) close(server_socket); return (-1); } if (listen(server_socket, 5) < 0) { NDMP_LOG(LOG_DEBUG, "listen error: %m"); (void) close(server_socket); return (-1); } for (; ; ) { if ((ns = tcp_accept(server_socket, &ipaddr)) < 0) { NDMP_LOG(LOG_DEBUG, "tcp_accept error: %m"); continue; } NDMP_LOG(LOG_DEBUG, "connection fd: %d", ns); set_socket_options(ns); if ((argp = ndmp_malloc(sizeof (ndmpd_worker_arg_t))) != NULL) { argp->nw_sock = ns; argp->nw_ipaddr = ipaddr; argp->nw_con_handler_func = con_handler_func; (void) ndmp_start_worker(argp); } } }
/* * correct_ents * * Correct the entries in the restore list by appending the appropriate * path to them */ static int correct_ents(ndmpd_module_params_t *params, int n, char *bkpath) { char *cp, *pathname; int i, len, rv; ndmp_name *ent; if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) { MOD_LOG(params, "Error: insufficient memory.\n"); return (-1); } rv = 0; /* Append the backup path to all the "ent[].name"s. */ for (i = 0; i < n; i++) { ent = (ndmp_name *)MOD_GETNAME(params, i); NDMP_LOG(LOG_DEBUG, "Old: ent[%d].name: \"%s\"", i, ent->name); NDMP_LOG(LOG_DEBUG, "Old: ent[%d].dest: \"%s\"", i, ent->dest); /* remove trailing slash */ len = strlen(ent->name); if (ent->name[len - 1] == '/') ent->name[len - 1] = '\0'; if (!tlm_cat_path(pathname, bkpath, ent->name)) { MOD_LOG(params, "Error: path too long.\n"); rv = -1; break; } /* Make a copy of the new string and save it in ent->name. */ cp = strdup(pathname); if (cp == NULL) { MOD_LOG(params, "Error: insufficient memory.\n"); rv = -1; break; } free(ent->name); ent->name = cp; NDMP_LOG(LOG_DEBUG, "New: ent[%d].name: \"%s\"", i, ent->name); } free(pathname); return (rv); }
/* * restore_create_structs * * Allocate structures for performing a restore * * Parameters: * sesison (input) - session handle * jname (input) - backup job name * * Returns: * 0: on success * -1: otherwise */ static int restore_create_structs(ndmpd_session_t *session, char *jname) { int i; long xfer_size; ndmp_lbr_params_t *nlp; tlm_commands_t *cmds; if ((nlp = ndmp_get_nlp(session)) == NULL) { NDMP_LOG(LOG_DEBUG, "nlp == NULL"); return (-1); } if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) { NDMP_LOG(LOG_DEBUG, "Creating job stats"); return (-1); } cmds = &nlp->nlp_cmds; (void) memset(cmds, 0, sizeof (*cmds)); xfer_size = ndmp_buffer_get_size(session); cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); if (cmds->tcs_command == NULL) { NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers"); tlm_un_ref_job_stats(jname); return (-1); } nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, ndmpd_path_restored, NULL, NULL); if (nlp->nlp_logcallbacks == NULL) { tlm_release_reader_writer_ipc(cmds->tcs_command); tlm_un_ref_job_stats(jname); return (-1); } nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles); if (nlp->nlp_restored == NULL) { lbrlog_callbacks_done(nlp->nlp_logcallbacks); tlm_release_reader_writer_ipc(cmds->tcs_command); tlm_un_ref_job_stats(jname); return (-1); } for (i = 0; i < (int)nlp->nlp_nfiles; i++) nlp->nlp_restored[i] = FALSE; return (0); }
/* * ndmpd_api_file_recovered_v3 * * Notify the NDMP client that the specified file was recovered. * * Parameters: * cookie (input) - session pointer. * name (input) - name of recovered file. * ssid (input) - selection set id. * error (input) - 0 if file successfully recovered. * otherwise, error code indicating why recovery failed. * * Returns: * 0 - success. * -1 - error. */ int ndmpd_api_file_recovered_v3(void *cookie, char *name, int error) { ndmpd_session_t *session = (ndmpd_session_t *)cookie; ndmp_log_file_request_v3 request; if (session == NULL) return (-1); request.name = name; switch (error) { case 0: request.error = NDMP_NO_ERR; break; case ENOENT: request.error = NDMP_FILE_NOT_FOUND_ERR; break; default: request.error = NDMP_PERMISSION_ERR; } if (ndmp_send_request_lock(session->ns_connection, NDMP_LOG_FILE, NDMP_NO_ERR, (void *)&request, 0) < 0) { NDMP_LOG(LOG_DEBUG, "Error sending log file request"); return (-1); } return (0); }
/* * ndmp_create_connection * * Allocate and initialize a connection structure. * * Parameters: * handler_tbl (input) - message handlers. * * Returns: * NULL - error * connection pointer * * Notes: * The returned connection should be destroyed using * ndmp_destroy_connection(). */ ndmp_connection_t * ndmp_create_connection(void) { ndmp_connection_t *connection; connection = ndmp_malloc(sizeof (ndmp_connection_t)); if (connection == NULL) return (NULL); connection->conn_sock = -1; connection->conn_my_sequence = 0; connection->conn_authorized = FALSE; connection->conn_eof = FALSE; connection->conn_msginfo.mi_body = 0; connection->conn_version = ndmp_ver; connection->conn_client_data = 0; (void) mutex_init(&connection->conn_lock, 0, NULL); connection->conn_xdrs.x_ops = 0; xdrrec_create(&connection->conn_xdrs, 0, 0, (caddr_t)connection, ndmp_readit, ndmp_writeit); if (connection->conn_xdrs.x_ops == 0) { NDMP_LOG(LOG_DEBUG, "xdrrec_create failed"); (void) mutex_destroy(&connection->conn_lock); (void) close(connection->conn_sock); free(connection); return (0); } return ((ndmp_connection_t *)connection); }
/*ARGSUSED*/ void ndmpd_scsi_close_v2(ndmp_connection_t *connection, void *body) { ndmp_scsi_close_reply reply; ndmpd_session_t *session = ndmp_get_client_data(connection); if (session->ns_scsi.sd_is_open == -1) { NDMP_LOG(LOG_ERR, "SCSI device is not open."); reply.error = NDMP_DEV_NOT_OPEN_ERR; ndmp_send_reply(connection, (void *) &reply, "sending scsi_close reply"); return; } (void) ndmp_open_list_del(session->ns_scsi.sd_adapter_name, session->ns_scsi.sd_sid, session->ns_scsi.sd_lun); (void) close(session->ns_scsi.sd_devid); session->ns_scsi.sd_is_open = -1; session->ns_scsi.sd_devid = -1; session->ns_scsi.sd_sid = 0; session->ns_scsi.sd_lun = 0; session->ns_scsi.sd_valid_target_set = FALSE; (void) memset(session->ns_scsi.sd_adapter_name, 0, sizeof (session->ns_scsi.sd_adapter_name)); reply.error = NDMP_NO_ERR; ndmp_send_reply(connection, (void *) &reply, "sending scsi_close reply"); }
/*ARGSUSED*/ int ndmpd_api_log_v2(void *cookie, char *format, ...) { ndmpd_session_t *session = (ndmpd_session_t *)cookie; ndmp_log_log_request request; static char buf[1024]; va_list ap; if (session == NULL) return (-1); va_start(ap, format); /*LINTED variable format specifier */ (void) vsnprintf(buf, sizeof (buf), format, ap); va_end(ap); request.entry = buf; if (ndmp_send_request(session->ns_connection, _NDMP_LOG_LOG, NDMP_NO_ERR, (void *)&request, 0) < 0) { NDMP_LOG(LOG_DEBUG, "Sending log request"); return (-1); } return (0); }
/*ARGSUSED*/ int ndmpd_api_log_v4(void *cookie, ndmp_log_type type, ulong_t msg_id, char *format, ...) { ndmpd_session_t *session = (ndmpd_session_t *)cookie; ndmp_log_message_request_v4 request; static char buf[1024]; va_list ap; if (session == NULL) return (-1); va_start(ap, format); /*LINTED variable format specifier */ (void) vsnprintf(buf, sizeof (buf), format, ap); va_end(ap); request.entry = buf; request.log_type = type; request.message_id = msg_id; request.associated_message_valid = NDMP_NO_ASSOCIATED_MESSAGE; request.associated_message_sequence = 0; if (ndmp_send_request(session->ns_connection, NDMP_LOG_MESSAGE, NDMP_NO_ERR, (void *)&request, 0) < 0) { NDMP_LOG(LOG_DEBUG, "Error sending log message request."); return (-1); } return (0); }
/* * Get the snapshot creation time */ int chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp) { char chk_name[PATH_MAX]; zfs_handle_t *zhp; char *p; if (!volname || !*volname) return (-1); /* Should also return -1 if checkpoint not enabled */ /* Remove the leading slash */ p = volname; while (*p == '/') p++; (void) strlcpy(chk_name, p, PATH_MAX); (void) strlcat(chk_name, "@", PATH_MAX); (void) strlcat(chk_name, pattern, PATH_MAX); (void) mutex_lock(&zlib_mtx); if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) { NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed", chk_name); (void) mutex_unlock(&zlib_mtx); return (-1); } *tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION); zfs_close(zhp); (void) mutex_unlock(&zlib_mtx); return (0); }
/* * ndmpd_api_add_env * * Adds an environment variable name/value pair to the environment * variable list. * * Parameters: * session (input) - session pointer. * name (input) - variable name. * val (input) - value. * * Returns: * 0 - success. * -1 - error. */ int ndmpd_api_add_env(void *cookie, char *name, char *value) { ndmpd_session_t *session = (ndmpd_session_t *)cookie; char *namebuf; char *valbuf; if (session == NULL) return (-1); session->ns_data.dd_env = realloc((void *)session->ns_data.dd_env, sizeof (ndmp_pval) * (session->ns_data.dd_env_len + 1)); if (session->ns_data.dd_env == NULL) { NDMP_LOG(LOG_ERR, "Out of memory."); return (-1); } namebuf = strdup(name); if (namebuf == NULL) return (-1); valbuf = strdup(value); if (valbuf == NULL) { free(namebuf); return (-1); } (void) mutex_lock(&session->ns_lock); session->ns_data.dd_env[session->ns_data.dd_env_len].name = namebuf; session->ns_data.dd_env[session->ns_data.dd_env_len].value = valbuf; session->ns_data.dd_env_len++; (void) mutex_unlock(&session->ns_lock); return (0); }
/* * ndmp_backup_reader * * Backup reader thread which uses backup_work to read and TAR * the files/dirs to be backed up (V2 only) */ static int ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp, char *job_name) { int retval; ndmp_run_args_t np; tlm_job_stats_t *job_stats; tlm_cmd_t *local_commands; NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path); local_commands = commands->tcs_command; (void) memset(&np, 0, sizeof (np)); if (!malloc_paths(&np)) return (-1); local_commands->tc_ref++; commands->tcs_reader_count++; job_stats = tlm_ref_job_stats(job_name); retval = backup_work(nlp->nlp_backup_path, job_stats, &np, commands, nlp); write_tar_eof(local_commands); commands->tcs_reader_count--; local_commands->tc_writer = TLM_STOP; tlm_release_reader_writer_ipc(local_commands); tlm_un_ref_job_stats(job_name); free_paths(&np); return (retval); }
/* * Log call back to report the entry recovery */ int tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos) { lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */ NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos); if (job_stats == NULL) { NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL"); return (0); } cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks; if (cbp == NULL) { NDMP_LOG(LOG_DEBUG, "entry_restored is NULL"); return (0); } return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos); }
/* * cstack_delete * * Deallocate the stack. This goes through the list freeing all of the * cstack nodes but not the data because we don't know how the data was * allocated. A stack really should be empty before it is deleted. */ void cstack_delete(cstack_t *stk) { cstack_t *tmp; if (stk == NULL) { NDMP_LOG(LOG_DEBUG, "cstack_delete: invalid stack"); return; } while ((tmp = stk->next) != NULL) { stk->next = tmp->next; NDMP_LOG(LOG_DEBUG, "cstack_delete(element): 0x%p", tmp); free(tmp); } NDMP_LOG(LOG_DEBUG, "cstack_delete: 0x%p", stk); free(stk); }
/* * verify the tar header checksum */ int tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr) { int chksum = oct_atoi(tar_hdr->th_chksum); uchar_t *p = (uchar_t *)tar_hdr; int sum = 0; /* initial value of checksum */ int i; /* loop counter */ /* * compute the checksum */ for (i = 0; i < RECORDSIZE; i++) { sum += p[i] & 0xFF; } if (sum == 0) { NDMP_LOG(LOG_DEBUG, "should be %d, is 0", chksum); /* a zero record ==> end of tar file */ return (0); } /* * subtract out the label's checksum values * this lets us undo the old checksum "in- * place", no need to swap blanks in and out */ for (i = 0; i < 8; i++) { sum -= 0xFF & tar_hdr->th_chksum[i]; } /* * replace the old checksum field with blanks */ sum += ' ' * 8; if (sum != chksum) NDMP_LOG(LOG_DEBUG, "should be %d, is %d", chksum, sum); return ((sum == chksum) ? 1 : -1); }
/*ARGSUSED*/ void ndmpd_scsi_reset_bus_v2(ndmp_connection_t *connection, void *body) { ndmp_scsi_reset_bus_reply reply; NDMP_LOG(LOG_DEBUG, "request not supported"); reply.error = NDMP_NOT_SUPPORTED_ERR; ndmp_send_reply(connection, (void *) &reply, "sending scsi_reset_bus reply"); }
/* * Enable the barcode capability on the library */ void tlm_enable_barcode(int l) { tlm_library_t *lp; if ((lp = tlm_library(l))) { lp->tl_capability_barcodes = TRUE; NDMP_LOG(LOG_DEBUG, "Barcode capability on library %d enabled.", l); } }
/* * ndmpd_api_seek_v2 * * Seek to the specified position in the data stream and start a * read for the specified amount of data. * * Parameters: * cookie (input) - session pointer. * offset (input) - stream position to seek to. * length (input) - amount of data that will be read using ndmpd_api_read * * Returns: * 0 - seek successful. * -1 - error. */ int ndmpd_api_seek_v2(void *cookie, u_longlong_t offset, u_longlong_t length) { ndmpd_session_t *session = (ndmpd_session_t *)cookie; int err; if (session == NULL) return (-1); session->ns_data.dd_read_offset = offset; session->ns_data.dd_read_length = length; /* * Send a notify_data_read request if the mover is remote. */ if (session->ns_data.dd_mover.addr_type == NDMP_ADDR_TCP) { ndmp_notify_data_read_request request; session->ns_mover.md_discard_length = session->ns_mover.md_bytes_left_to_read; session->ns_mover.md_bytes_left_to_read = length; session->ns_mover.md_position = offset; request.offset = long_long_to_quad(offset); request.length = long_long_to_quad(length); if (ndmp_send_request_lock(session->ns_connection, NDMP_NOTIFY_DATA_READ, NDMP_NO_ERR, (void *)&request, 0) < 0) { NDMP_LOG(LOG_DEBUG, "Sending notify_data_read request"); return (-1); } return (0); } /* Mover is local. */ err = ndmpd_mover_seek(session, offset, length); if (err < 0) { ndmpd_mover_error(session, NDMP_MOVER_HALT_INTERNAL_ERROR); return (-1); } if (err == 0) return (0); /* * NDMP client intervention is required to perform the seek. * Wait for the client to either do the seek and send a continue * request or send an abort request. */ return (ndmp_wait_for_mover(session)); }
/* * ndmp_write_utf8magic * * Write a magic pattern to the tar header. This is used * as a crest to indicate that tape belongs to us. */ int ndmp_write_utf8magic(tlm_cmd_t *cmd) { char *cp; long actual_size; if (cmd->tc_buffers == NULL) { NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL"); return (-1); } cp = tlm_get_write_buffer(RECORDSIZE, &actual_size, cmd->tc_buffers, TRUE); if (actual_size < RECORDSIZE) { NDMP_LOG(LOG_DEBUG, "Couldn't get enough buffer"); return (-1); } (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE); return (0); }
/* * cstack_top * * Returns the top data element on the stack without removing it. * * Returns 0 on success. Otherwise returns -1 to indicate underflow. */ int cstack_top(cstack_t *stk, void **data, int *len) { if (stk == NULL) { NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack"); return (-1); } if (stk->next == NULL) { NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow"); return (-1); } if (data) *data = stk->next->data; if (len) *len = stk->next->len; return (0); }