/*
 * 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);
}
Exemple #2
0
/*
 * ndmpd_config_update
 *
 * Updates the specified config param with the given value.
 * This function is called both on (re)load and set.
 */
static int
ndmpd_config_update(ndmpd_cfg_param_t *cfg, char *value)
{
	char *curval;
	int rc = 0;
	int len;

	if (value) {
		len = strlen(value);
		if (cfg->sc_value) {
			curval = realloc(cfg->sc_value, (len + 1));
		} else {
			curval = ndmp_malloc(len + 1);
		}

		if (curval) {
			cfg->sc_value = curval;
			(void) strcpy(cfg->sc_value, value);
			cfg->sc_flags |= NDMP_CF_DEFINED;
		} else {
			syslog(LOG_ERR, "Out of memory.");
			rc = -1;
		}
	} else if (cfg->sc_value) {
		free(cfg->sc_value);
		cfg->sc_value = 0;
		cfg->sc_flags &= ~NDMP_CF_DEFINED;
	}

	return (rc);
}
Exemple #3
0
/*
 * malloc_paths
 *
 * Allocate the path names (direct and checkpointed paths)
 */
static boolean_t
malloc_paths(ndmp_run_args_t *np)
{
	boolean_t rv;

	rv = TRUE;
	np->nr_chkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
	np->nr_unchkp_nm = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (!np->nr_chkp_nm || !np->nr_unchkp_nm) {
		free_paths(np);
		rv = FALSE;
	} else if ((np->nr_excls = ndmpd_make_exc_list()) == NULL) {
		free_paths(np);
		rv = FALSE;
	}
	return (rv);
}
Exemple #4
0
/*
 * cstack_new
 *
 * Allocate and initialize a new stack, which is just an empty cstack_t.
 * A pointer to the new stack is returned. This should be treated as an
 * opaque handle by the caller.
 */
cstack_t *
cstack_new(void)
{
	cstack_t *stk;

	if ((stk = ndmp_malloc(sizeof (cstack_t))) == NULL)
		return (NULL);

	return (stk);
}
Exemple #5
0
/*
 * dup_dir_info
 *
 * Make and return a copy of the directory info.
 */
struct full_dir_info *
dup_dir_info(struct full_dir_info *old_dir_info)
{
	struct	full_dir_info *new_dir_info;
	new_dir_info = ndmp_malloc(sizeof (struct full_dir_info));

	if (new_dir_info) {
		bcopy(old_dir_info, new_dir_info,
		    sizeof (struct full_dir_info));
	}
	return (new_dir_info);
}
/*
 * 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);
		}
	}
}
Exemple #7
0
/*
 * 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);
}
Exemple #8
0
/*
 * 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);
}
Exemple #9
0
/*
 * Initialize the file history callback functions
 */
lbr_fhlog_call_backs_t *
lbrlog_callbacks_init(void *cookie, path_hist_func_t log_pname_func,
                      dir_hist_func_t log_dir_func, node_hist_func_t log_node_func)
{
    lbr_fhlog_call_backs_t *p;

    p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
    if (p == NULL)
        return (NULL);

    p->fh_cookie = cookie;
    p->fh_logpname = (func_t)log_pname_func;
    p->fh_log_dir = (func_t)log_dir_func;
    p->fh_log_node = (func_t)log_node_func;
    return (p);
}
Exemple #10
0
/*
 * Creates a new traversing state based on the path passed to it.
 */
static traverse_state_t *
new_tsp(char *path)
{
	traverse_state_t *tsp;
	tsp = ndmp_malloc(sizeof (traverse_state_t));
	if (!tsp)
		return (NULL);

	tsp->ts_end = strchr(path, '\0');
	if (*(tsp->ts_end-1) == '/')
		*--tsp->ts_end = '\0';
	tsp->ts_ent = NULL;
	tsp->ts_dpos = 0;

	return (tsp);
}
Exemple #11
0
/*
 * tlm_new_dir_info
 *
 * Create a new structure, set fh field to what is specified and the path
 * to the concatenation of directory and the component
 */
struct full_dir_info *
tlm_new_dir_info(struct  fs_fhandle *fhp, char *dir, char *nm)
{
	struct full_dir_info *fdip;

	if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info))))
		return (NULL);

	(void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t));
	if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) {
		free(fdip);
		NDMP_LOG(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]",
		    dir, nm);
		return (NULL);
	}
	return (fdip);
}
Exemple #12
0
/*
 * cstack_push
 *
 * Push an element onto the stack. Allocate a new node and assign the
 * data and len values. We don't care what about the real values of
 * data or len and we never try to access them. The stack head will
 * point to the new node.
 *
 * Returns 0 on success. Otherwise returns -1 to indicate overflow.
 */
int
cstack_push(cstack_t *stk, void *data, int len)
{
	cstack_t *stk_node;

	if (stk == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_push: invalid stack");
		return (-1);
	}

	if ((stk_node = ndmp_malloc(sizeof (cstack_t))) == NULL)
		return (-1);

	stk_node->data = data;
	stk_node->len = len;
	stk_node->next = stk->next;
	stk->next = stk_node;

	NDMP_LOG(LOG_DEBUG, "cstack_push(0x%p): 0x%p", stk, stk_node);
	return (0);
}
Exemple #13
0
/*
 * output_humongus_header
 *
 * output a special header record for HUGE files
 * output is:	1) a TAR "HUGE" header redord
 * 		2) a "file" of size, name
 */
static int
output_humongus_header(char *fullname, longlong_t file_size,
    tlm_cmd_t *local_commands)
{
	char	*buf;
	int	len;
	long	actual_size;
	tlm_tar_hdr_t *tar_hdr;

	/*
	 * buf will contain: "%llu %s":
	 * - 20 is the maximum length of 'ulong_tlong' decimal notation.
	 * - The first '1' is for the ' ' between the "%llu" and the fullname.
	 * - The last '1' is for the null-terminator of fullname.
	 */
	len = 20 + 1 + strlen(fullname) + 1;

	if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
		return (-1);

	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
	    &actual_size, TRUE, local_commands);
	if (!tar_hdr) {
		free(buf);
		return (0);
	}

	tar_hdr->th_linkflag = LF_HUMONGUS;
	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
	    len);
	tlm_build_header_checksum(tar_hdr);
	(void) snprintf(buf, len, "%lld %s", file_size, fullname);
	(void) output_mem(local_commands, buf, len);

	free(buf);
	return (0);
}
Exemple #14
0
/*
 * Attach the SCSI device by updating the structures
 */
void
scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name,
                 int type)
{
    scsi_link_t *sl, *next;
    scsi_sasd_drive_t *ssd;

    ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t));
    if (ssd == NULL)
        return;

    scsi_sasd_drives[sasd_drive_count++] = ssd;

    switch (type) {
    case DTYPE_CHANGER:
        (void) snprintf(ssd->ss_sd.sd_name,
                        sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_CHANGER_DIR,
                        name);
        break;
    case DTYPE_SEQUENTIAL:
        (void) snprintf(ssd->ss_sd.sd_name,
                        sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_TAPE_DIR, name);
        break;
    }

    sl = &ssd->ss_slink;
    sl->sl_type = type;
    sl->sl_sa = sa;
    sl->sl_lun = lun;
    sl->sl_sid = sid;
    sl->sl_requested_max_active = 1;

    /* Insert slink */
    next = sa->sa_link_head.sl_next;
    sa->sa_link_head.sl_next = sl;
    sl->sl_next = next;
}
Exemple #15
0
/*
 * create the IPC area between the reader and writer
 */
tlm_cmd_t *
tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size)
{
    tlm_cmd_t *cmd;

    cmd = ndmp_malloc(sizeof (tlm_cmd_t));
    if (cmd == NULL)
        return (NULL);

    cmd->tc_reader = TLM_BACKUP_RUN;
    cmd->tc_writer = TLM_BACKUP_RUN;
    cmd->tc_ref = 1;

    cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size);
    if (cmd->tc_buffers == NULL) {
        free(cmd);
        return (NULL);
    }

    (void) mutex_init(&cmd->tc_mtx, 0, NULL);
    (void) cond_init(&cmd->tc_cv, 0, NULL);

    return (cmd);
}
Exemple #16
0
/*
 * ndmpd_api_file_history_file_v3
 *
 * Add a file history file entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie   (input) - session pointer.
 *   name     (input) - file name.
 *		      NULL forces buffered data to be sent.
 *   file_stat (input) - file status pointer.
 *   fh_info  (input) - data stream position of file data used during
 *		      fast restore.
 *
 * Returns:
 *   0 - success
 *  -1 - error
 */
int
ndmpd_api_file_history_file_v3(void *cookie, char *name,
    struct stat64 *file_stat, u_longlong_t fh_info)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_file_v3 *file_entry;
	ndmp_file_name_v3 *file_name_entry;
	ndmp_file_stat_v3 *file_stat_entry;
	ndmp_fh_add_file_request_v3 request;

	if (name == NULL && session->ns_fh_v3.fh_file_index == 0)
		return (0);

	/*
	 * If the buffer does not have space
	 * for the current entry, send the buffered data to the client.
	 * A NULL name indicates that any buffered data should be sent.
	 */
	if (name == NULL ||
	    session->ns_fh_v3.fh_file_index == N_FILE_ENTRIES ||
	    session->ns_fh_v3.fh_file_name_buf_index + strlen(name) + 1 >
	    PATH_NAMEBUF_SIZE) {

		syslog(LOG_DEBUG, "sending %ld entries",
		    session->ns_fh_v3.fh_file_index);

		request.files.files_len = session->ns_fh_v3.fh_file_index;
		request.files.files_val = session->ns_fh_v3.fh_files;

		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_FILE, NDMP_NO_ERR, (void *) &request, 0) < 0) {
			syslog(LOG_ERR,
			    "Sending ndmp_fh_add_file request failed");
			return (-1);
		}

		session->ns_fh_v3.fh_file_index = 0;
		session->ns_fh_v3.fh_file_name_buf_index = 0;
	}

	if (name == NULL)
		return (0);

	if (session->ns_fh_v3.fh_files == 0) {
		session->ns_fh_v3.fh_files = ndmp_malloc(sizeof (ndmp_file_v3) *
		    N_FILE_ENTRIES);
		if (session->ns_fh_v3.fh_files == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_file_names == 0) {
		session->ns_fh_v3.fh_file_names =
		    ndmp_malloc(sizeof (ndmp_file_name_v3) * N_FILE_ENTRIES);
		if (session->ns_fh_v3.fh_file_names == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_file_name_buf == 0) {
		session->ns_fh_v3.fh_file_name_buf =
		    ndmp_malloc(sizeof (char) * PATH_NAMEBUF_SIZE);
		if (session->ns_fh_v3.fh_file_name_buf == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_file_stats == 0) {
		session->ns_fh_v3.fh_file_stats =
		    ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_FILE_ENTRIES);
		if (session->ns_fh_v3.fh_file_stats == 0)
			return (-1);
	}

	file_entry =
	    &session->ns_fh_v3.fh_files[session->ns_fh_v3.fh_file_index];
	file_name_entry =
	    &session->ns_fh_v3.fh_file_names[session->ns_fh_v3.fh_file_index];
	file_stat_entry =
	    &session->ns_fh_v3.fh_file_stats[session->ns_fh_v3.fh_file_index];
	file_entry->names.names_len = 1;
	file_entry->names.names_val = file_name_entry;
	file_entry->stats.stats_len = 1;
	file_entry->stats.stats_val = file_stat_entry;
	file_entry->node = long_long_to_quad(file_stat->st_ino);
	file_entry->fh_info = long_long_to_quad(fh_info);

	file_name_entry->fs_type = NDMP_FS_UNIX;
	file_name_entry->ndmp_file_name_v3_u.unix_name =
	    &session->ns_fh_v3.fh_file_name_buf[session->
	    ns_fh_v3.fh_file_name_buf_index];
	(void) strlcpy(&session->ns_fh_v3.fh_file_name_buf[session->
	    ns_fh_v3.fh_file_name_buf_index], name, PATH_NAMEBUF_SIZE);
	session->ns_fh_v3.fh_file_name_buf_index += strlen(name) + 1;
	ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);

	file_stat_entry->invalid = 0;
	file_stat_entry->fs_type = NDMP_FS_UNIX;
	file_stat_entry->mtime = file_stat->st_mtime;
	file_stat_entry->atime = file_stat->st_atime;
	file_stat_entry->ctime = file_stat->st_ctime;
	file_stat_entry->owner = file_stat->st_uid;
	file_stat_entry->group = file_stat->st_gid;
	file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
	file_stat_entry->size =
	    long_long_to_quad((u_longlong_t)file_stat->st_size);
	file_stat_entry->links = file_stat->st_nlink;

	session->ns_fh_v3.fh_file_index++;

	return (0);
}
Exemple #17
0
/*
 * ndmpd_api_file_history_node_v2
 *
 * Add a file history node entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie   (input) - session pointer.
 *   node     (input) - file inode.
 *	      must match a node from a prior ndmpd_api_file_history_dir()
 *		      call.
 *   file_stat (input) - file status pointer.
 *		      0 forces buffered data to be sent.
 *   fh_info  (input) - data stream position of file data used during
 *		      fast restore.
 *
 * Returns:
 *   0 - success
 *  -1 - error.
 */
int
ndmpd_api_file_history_node_v2(void *cookie, ulong_t node,
    struct stat64 *file_stat, u_longlong_t fh_info)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_fh_unix_node *entry;

	if (file_stat == NULL && session->ns_fh.fh_node_index == 0)
		return (-1);

	/*
	 * If the buffer does not have space
	 * for the current entry, send the buffered data to the client.
	 * A 0 file_stat pointer indicates that any buffered data should
	 * be sent.
	 */
	if (file_stat == NULL ||
	    (ndmp_syncfh && session->ns_fh.fh_node_index != 0) ||
	    session->ns_fh.fh_node_index == N_NODE_ENTRIES) {
		ndmp_fh_add_unix_node_request request;

		syslog(LOG_DEBUG,
		    "sending %ld entries", session->ns_fh.fh_node_index);

		request.nodes.nodes_val = session->ns_fh.fh_node_entries;
		request.nodes.nodes_len = session->ns_fh.fh_node_index;
		/*
		 * Need to send Dir entry as well. Since Dir entry is more than
		 * Node entry, we may send a Node entry that hasn't have
		 * its dir entry sent. Therefore, we need to flush Dir entry
		 * as well everytime the Dir entry is send.
		 */
		(void) ndmpd_api_file_history_dir_v2(session, 0, 0, 0);

		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_UNIX_NODE, NDMP_NO_ERR, (void *) &request,
		    0) < 0) {
			syslog(LOG_ERR, "Sending file history data failed");
			return (-1);
		}
		session->ns_fh.fh_node_index = 0;
	}
	if (file_stat == NULL)
		return (0);

	if (session->ns_fh.fh_node_entries == 0) {
		session->ns_fh.fh_node_entries = ndmp_malloc(N_NODE_ENTRIES
		    * sizeof (ndmp_fh_unix_node));
		if (session->ns_fh.fh_node_entries == 0)
			return (-1);
	}
	entry = &session->ns_fh.fh_node_entries[session->ns_fh.fh_node_index];
	ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);

	entry->node = node;
	entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
	entry->fstat.atime = (ulong_t)file_stat->st_atime;
	entry->fstat.ctime = (ulong_t)file_stat->st_ctime;
	entry->fstat.uid = file_stat->st_uid;
	entry->fstat.gid = file_stat->st_gid;
	entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
	entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
	entry->fstat.fh_info = long_long_to_quad(fh_info);

	session->ns_fh.fh_node_index++;
	return (0);
}
Exemple #18
0
/*
 * ndmpd_api_file_history_dir_v2
 *
 * Add a file history dir entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie (input) - session pointer.
 *   name   (input) - file name.
 *		    NULL forces buffered data to be sent.
 *   node   (input) - file inode.
 *   parent (input) - file parent inode.
 *		    Should equal node if the file is the root of
 *		    the filesystem and has no parent.
 *
 * Returns:
 *   0 - success
 *  -1 - error
 */
int
ndmpd_api_file_history_dir_v2(void *cookie, char *name, ulong_t node,
    ulong_t parent)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_fh_unix_dir *entry;

	if (name == NULL && session->ns_fh.fh_dir_index == 0)
		return (0);

	/*
	 * If the buffer does not have space for the current entry,
	 * send the buffered data to the client. A NULL name indicates
	 * that any buffered data should be sent.
	 */
	if (name == NULL ||
	    (ndmp_syncfh && session->ns_fh.fh_dir_index != 0) ||
	    session->ns_fh.fh_dir_index == N_DIR_ENTRIES ||
	    session->ns_fh.fh_dir_name_buf_index + strlen(name) + 1 >
	    DIR_NAMEBUF_SIZE) {
		ndmp_fh_add_unix_dir_request request;

		syslog(LOG_DEBUG,
		    "sending %ld entries", session->ns_fh.fh_dir_index);

		request.dirs.dirs_val = session->ns_fh.fh_dir_entries;
		request.dirs.dirs_len = session->ns_fh.fh_dir_index;
		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_UNIX_DIR, NDMP_NO_ERR, (void *) &request,
		    0) < 0) {
			syslog(LOG_DEBUG, "Sending file history data");
			return (-1);
		}
		session->ns_fh.fh_dir_index = 0;
		session->ns_fh.fh_dir_name_buf_index = 0;
	}
	if (name == NULL)
		return (0);

	if (session->ns_fh.fh_dir_entries == 0) {
		session->ns_fh.fh_dir_entries = ndmp_malloc(N_DIR_ENTRIES
		    * sizeof (ndmp_fh_unix_dir));
		if (session->ns_fh.fh_dir_entries == 0)
			return (-1);
	}
	if (session->ns_fh.fh_dir_name_buf == 0) {
		session->ns_fh.fh_dir_name_buf = ndmp_malloc(DIR_NAMEBUF_SIZE);
		if (session->ns_fh.fh_dir_name_buf == 0)
			return (-1);
	}
	entry = &session->ns_fh.fh_dir_entries[session->ns_fh.fh_dir_index];

	entry->name = &session->
	    ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index];
	(void) strlcpy(&session->
	    ns_fh.fh_dir_name_buf[session->ns_fh.fh_dir_name_buf_index],
	    name, PATH_NAMEBUF_SIZE);
	session->ns_fh.fh_dir_name_buf_index += strlen(name) + 1;

	entry->node = node;
	entry->parent = parent;

	session->ns_fh.fh_dir_index++;
	return (0);
}
Exemple #19
0
/*
 * ndmpd_api_file_history_path_v2
 *
 * Add a file history path entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie   (input) - session pointer.
 *   name     (input) - file name.
 *		      NULL forces buffered data to be sent.
 *   file_stat (input) - file status pointer.
 *   fh_info  (input) - data stream position of file data used during
 *		      fast restore.
 *
 * Returns:
 *   0 - success
 *  -1 - error
 */
int
ndmpd_api_file_history_path_v2(void *cookie, char *name,
    struct stat64 *file_stat, u_longlong_t fh_info)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_fh_unix_path *entry;

	if (name == NULL && session->ns_fh.fh_path_index == 0)
		return (0);

	/*
	 * If the buffer does not have space
	 * for the current entry, send the buffered data to the client.
	 * A NULL name indicates that any buffered data should be sent.
	 */
	if (name == NULL ||
	    (ndmp_syncfh && session->ns_fh.fh_path_index != 0) ||
	    session->ns_fh.fh_path_index == N_PATH_ENTRIES ||
	    session->ns_fh.fh_path_name_buf_index + strlen(name) + 1 >
	    PATH_NAMEBUF_SIZE) {
		ndmp_fh_add_unix_path_request request;

		syslog(LOG_DEBUG,
		    "sending %ld entries", session->ns_fh.fh_path_index);

		request.paths.paths_val = session->ns_fh.fh_path_entries;
		request.paths.paths_len = session->ns_fh.fh_path_index;

		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_UNIX_PATH, NDMP_NO_ERR, (void *) &request,
		    0) < 0) {
			syslog(LOG_ERR, "Sending file history data failed");
			return (-1);
		}
		session->ns_fh.fh_path_index = 0;
		session->ns_fh.fh_path_name_buf_index = 0;
	}
	if (name == NULL)
		return (0);

	if (session->ns_fh.fh_path_entries == 0) {
		session->ns_fh.fh_path_entries = ndmp_malloc(N_PATH_ENTRIES *
		    sizeof (ndmp_fh_unix_path));
		if (session->ns_fh.fh_path_entries == 0)
			return (-1);
	}
	if (session->ns_fh.fh_path_name_buf == 0) {
		session->ns_fh.fh_path_name_buf =
		    ndmp_malloc(PATH_NAMEBUF_SIZE);
		if (session->ns_fh.fh_path_name_buf == 0)
			return (-1);
	}
	entry = &session->ns_fh.fh_path_entries[session->ns_fh.fh_path_index];
	ndmpd_get_file_entry_type(file_stat->st_mode, &entry->fstat.ftype);

	entry->name = &session->
	    ns_fh.fh_path_name_buf[session->ns_fh.fh_path_name_buf_index];
	(void) strlcpy(entry->name, name, PATH_NAMEBUF_SIZE);
	session->ns_fh.fh_path_name_buf_index += strlen(name) + 1;
	entry->fstat.mtime = (ulong_t)file_stat->st_mtime;
	entry->fstat.atime = (ulong_t)file_stat->st_atime;
	entry->fstat.ctime = (ulong_t)file_stat->st_ctime;
	entry->fstat.uid = file_stat->st_uid;
	entry->fstat.gid = file_stat->st_gid;
	entry->fstat.mode = (file_stat->st_mode) & 0x0fff;
	entry->fstat.size = long_long_to_quad((u_longlong_t)file_stat->st_size);
	entry->fstat.fh_info = long_long_to_quad((u_longlong_t)fh_info);
	session->ns_fh.fh_path_index++;
	return (0);
}
Exemple #20
0
/*
 * backup_work
 *
 * Start the NDMP backup (V2 only).
 */
int
backup_work(char *bk_path, tlm_job_stats_t *job_stats,
    ndmp_run_args_t *np, tlm_commands_t *commands,
    ndmp_lbr_params_t *nlp)
{
	struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
	struct full_dir_info *t_dir_info, *p_dir_info;
	struct stat64 ret_attr; /* attributes of current file name */
	fs_fhandle_t ret_fh;
	char *first_name; /* where the first name is located */
	char *dname;
	int erc;
	int retval;
	cstack_t *stk;
	unsigned long fileid;
	tlm_acls_t tlm_acls;
	int dname_size;
	longlong_t fsize;
	bk_selector_t bks;
	tlm_cmd_t *local_commands;
	long 	dpos;

	NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
	    NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);

	/* Get every name in this directory */
	dname = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (dname == NULL)
		return (-ENOMEM);

	local_commands = commands->tcs_command;
	retval = 0;
	(void) memset(&bks, 0, sizeof (bks));
	bks.bs_cookie = (void *)nlp;
	bks.bs_level = nlp->nlp_clevel;
	bks.bs_ldate = nlp->nlp_ldate;
	bks.bs_fn = timecmp;

	/*
	 * should we skip the whole thing?
	 */
	if (tlm_is_excluded("", bk_path, np->nr_excls)) {
		NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path);
		free(dname);
		return (0);
	}

	/*
	 * Search for the top-level file-directory
	 */
	if (NLP_ISCHKPNTED(nlp)) {
		first_name = np->nr_chkp_nm;
		(void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
	} else {
		first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
		    nlp->nlp_jstat->js_job_name);
	}

	(void) memset(&ret_fh, 0, sizeof (ret_fh));
	erc = fs_getstat(first_name, &ret_fh, &ret_attr);
	if (erc != 0) {
		NDMP_LOG(LOG_ERR, "Path %s not found.", first_name);
		free(dname);
		return (-EINVAL);
	}

	if ((stk = cstack_new()) == NULL) {
		free(dname);
		NDMP_LOG(LOG_DEBUG, "cstack_new failed");
		return (-ENOMEM);
	}
	(void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
	(void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
	p_dir_info = dup_dir_info(&dir_info);

	/*
	 * Push the first name onto the stack so that we can pop it back
	 * off as part of the normal cycle
	 */
	if (cstack_push(stk, p_dir_info, 0)) {
		free(dname);
		free(p_dir_info);
		cstack_delete(stk);
		NDMP_LOG(LOG_DEBUG, "cstack_push failed");
		return (-ENOMEM);
	}

	(void) memset(&tlm_acls, 0, sizeof (tlm_acls));
	/*
	 * Did NDMP create a checkpoint?
	 */
	if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
		tlm_acls.acl_checkpointed = FALSE;
	} else {
		/* Use the checkpoint created by NDMP */
		tlm_acls.acl_checkpointed = TRUE;
	}

	/*
	 * This is level-backup.  It never resets the archive bit.
	 */
	tlm_acls.acl_clear_archive = FALSE;

	NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
	    NDMP_YORN(tlm_acls.acl_checkpointed),
	    NDMP_YORN(tlm_acls.acl_clear_archive));

	while (commands->tcs_reader == TLM_BACKUP_RUN &&
	    local_commands->tc_reader == TLM_BACKUP_RUN &&
	    cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {

		if (NLP_ISCHKPNTED(nlp))
			(void) strlcpy(np->nr_unchkp_nm,
			    p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
		else
			(void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
			    np->nr_unchkp_nm);

		(void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
		    job_stats, &bks);


		while (commands->tcs_reader == TLM_BACKUP_RUN &&
		    local_commands->tc_reader == TLM_BACKUP_RUN) {

			dname_size = TLM_MAX_PATH_NAME - 1;

			NDMP_LOG(LOG_DEBUG,
			    "dir_name: %s", p_dir_info->fd_dir_name);

			(void) memset(&ret_fh, 0, sizeof (ret_fh));
			erc = fs_readdir(&p_dir_info->fd_dir_fh,
			    p_dir_info->fd_dir_name, &dpos,
			    dname, &dname_size, &ret_fh, &ret_attr);
			if (erc == 0) {
				fileid = ret_fh.fh_fid;
			} else {
				NDMP_LOG(LOG_DEBUG,
				    "Filesystem readdir in [%s]",
				    p_dir_info->fd_dir_name);
				retval = -ENOENT;
				break;
			}

			/* an empty name size marks the end of the list */
			if (dname_size == 0)
				break;
			dname[dname_size] = '\0';

			NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname);

			/*
			 * If name refers to a directory, push its file
			 *   handle onto the stack  (skip "." and "..").
			 */
			if (rootfs_dot_or_dotdot(dname)) {
				fileid = 0;
				continue;
			}

			/*
			 * Skip the:
			 * non-dir entries which should not be backed up
			 * Or
			 * dir-type entries which have have nothing under
			 * their hierarchy to be backed up.
			 */
			if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
				NDMP_LOG(LOG_DEBUG, "Skipping %s/%s",
				    p_dir_info->fd_dir_name, dname);
				fileid = 0;
				continue;
			}

			if (tlm_is_excluded(np->nr_unchkp_nm, dname,
			    np->nr_excls)) {
				fileid = 0;
				continue;
			}
			if (S_ISDIR(ret_attr.st_mode)) {
				/*
				 * only directories get pushed onto this stack,
				 * so we do not have to test for regular files.
				 */
				t_dir_info = tlm_new_dir_info(&ret_fh,
				    p_dir_info->fd_dir_name, dname);
				if (t_dir_info == NULL) {
					NDMP_LOG(LOG_DEBUG,
					    "While backing up [%s][%s]",
					    p_dir_info->fd_dir_name, dname);
				} else if (cstack_push(stk, t_dir_info,
				    0) != 0) {
					NDMP_LOG(LOG_DEBUG,
					    "No enough memory stack_push");
					retval = -ENOMEM;
					break;
				}
			} else if (S_ISREG(ret_attr.st_mode) ||
			    S_ISLNK(ret_attr.st_mode)) {

				fsize = backup_file(np->nr_unchkp_nm, dname,
				    &tlm_acls, commands, local_commands,
				    job_stats, &bks);

				if (fsize >= 0) {
					job_stats->js_files_so_far++;
					job_stats->js_bytes_total += fsize;
				} else
					job_stats->js_errors++;
				fileid = 0;
			}
		}
		fileid = 0;
		free(p_dir_info);
		if (retval != 0)
			break;
	}

	free(dname);

	while (cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
		free(p_dir_info);
	}

	cstack_delete(stk);
	return (retval);
}
Exemple #21
0
/*
 * get_dir_acl_info
 *
 * load up all ACL and attr info about a directory
 */
static int
get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
{
	int	erc;
	char	*checkpointed_dir;
	char	root_dir[TLM_VOLNAME_MAX_LENGTH];
	char	*spot;
	char	*fil;
	acl_t	*aclp = NULL;
	char 	*acltp;

	checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (checkpointed_dir == NULL)
		return (-1);

	if (tlm_acls->acl_checkpointed)
		fil = tlm_build_snapshot_name(dir, checkpointed_dir,
		    js->js_job_name);
	else
		fil = dir;
	erc = lstat64(fil, &tlm_acls->acl_attr);
	if (erc != 0) {
		NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir);
		free(checkpointed_dir);
		return (-1);
	}

	spot = strchr(&fil[1], '/');
	if (spot == NULL) {
		(void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
	} else {
		*spot = 0;
		(void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
		*spot = '/';
	}
	if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
		struct stat64 attr;

		erc = lstat64(root_dir, &attr);
		if (erc != 0) {
			NDMP_LOG(LOG_ERR, "Cannot find root directory %s.",
			    root_dir);
			free(checkpointed_dir);
			return (-1);
		}
		(void) strlcpy(tlm_acls->acl_root_dir, root_dir,
		    TLM_VOLNAME_MAX_LENGTH);
	}
	erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
	if (erc != 0) {
		NDMP_LOG(LOG_DEBUG,
		    "Could not read metadata for directory [%s]", dir);
		free(checkpointed_dir);
		return (-1);
	}
	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);
	}

	free(checkpointed_dir);
	return (0);
}
Exemple #22
0
/*
 * output_file_header
 *
 * output the TAR header record
 */
static int
output_file_header(char *name, char *link,
    tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
{
	static	longlong_t file_count = 0;
	struct stat64 *attr = &tlm_acls->acl_attr;
	tlm_tar_hdr_t *tar_hdr;
	long	actual_size;
	boolean_t long_name = FALSE;
	boolean_t long_link = FALSE;
	char	*section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
	int	nmlen, lnklen;
	uid_t uid;
	gid_t gid;
	char *uname = "";
	char *gname = "";
	struct passwd *pwd;
	struct group *grp;

	if (section_name == NULL)
		return (-TLM_NO_SCRATCH_SPACE);

	/*
	 * if the file has to go out in sections,
	 * we must mung the name.
	 */
	if (section == 0) {
		(void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
	} else {
		(void) snprintf(section_name,
		    TLM_MAX_PATH_NAME, "%s.%03d", name, section);
	}

	if ((pwd = getpwuid(attr->st_uid)) != NULL)
		uname = pwd->pw_name;
	if ((grp = getgrgid(attr->st_gid)) != NULL)
		gname = grp->gr_name;

	if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
		uid = UID_NOBODY;
	if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
		gid = GID_NOBODY;

	nmlen = strlen(section_name);
	if (nmlen >= NAMSIZ) {
		/*
		 * file name is too big, it must go out
		 * in its own data file
		 */
		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
		    &actual_size, TRUE, local_commands);
		if (!tar_hdr) {
			free(section_name);
			return (0);
		}
		(void) snprintf(tar_hdr->th_name,
		    sizeof (tar_hdr->th_name),
		    "%s%08qd.fil",
		    LONGNAME_PREFIX,
		    file_count++);

		tar_hdr->th_linkflag = LF_LONGNAME;
		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
		    "%011o ", nmlen);
		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
		    "%06o ", attr->st_mode & 07777);
		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
		    "%06o ", uid);
		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
		    "%06o ", gid);
		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
		    "%.31s", uname);
		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
		    "%.31s", gname);
		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
		    "%011o ", attr->st_mtime);
		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
		    sizeof (tar_hdr->th_magic));

		tlm_build_header_checksum(tar_hdr);

		(void) output_mem(local_commands,
		    (void *)section_name, nmlen);
		long_name = TRUE;
	}

	lnklen = strlen(link);
	if (lnklen >= NAMSIZ) {
		/*
		 * link name is too big, it must go out
		 * in its own data file
		 */
		tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
		    &actual_size, TRUE, local_commands);
		if (!tar_hdr) {
			free(section_name);
			return (0);
		}
		(void) snprintf(tar_hdr->th_linkname,
		    sizeof (tar_hdr->th_name),
		    "%s%08qd.slk",
		    LONGNAME_PREFIX,
		    file_count++);

		tar_hdr->th_linkflag = LF_LONGLINK;
		(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
		    "%011o ", lnklen);
		(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
		    "%06o ", attr->st_mode & 07777);
		(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
		    "%06o ", uid);
		(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
		    "%06o ", gid);
		(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
		    "%.31s", uname);
		(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
		    "%.31s", gname);
		(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
		    "%011o ", attr->st_mtime);
		(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
		    sizeof (tar_hdr->th_magic));

		tlm_build_header_checksum(tar_hdr);

		(void) output_mem(local_commands, (void *)link,
		    lnklen);
		long_link = TRUE;
	}
	tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
	    &actual_size, TRUE, local_commands);
	if (!tar_hdr) {
		free(section_name);
		return (0);
	}
	if (long_name) {
		(void) snprintf(tar_hdr->th_name,
		    sizeof (tar_hdr->th_name),
		    "%s%08qd.fil",
		    LONGNAME_PREFIX,
		    file_count++);
	} else {
		(void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
	}

	if (long_link) {
		(void) snprintf(tar_hdr->th_linkname,
		    sizeof (tar_hdr->th_name),
		    "%s%08qd.slk",
		    LONGNAME_PREFIX,
		    file_count++);
	} else {
		(void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
	}
	switch (attr->st_mode & S_IFMT) {
	case S_IFDIR:
		tar_hdr->th_linkflag = LF_DIR;
		break;
	case S_IFIFO:
		tar_hdr->th_linkflag = LF_FIFO;
		break;
	case S_IFBLK:
	case S_IFCHR:
		if (S_ISBLK(attr->st_mode))
			tar_hdr->th_linkflag = LF_BLK;
		else
			tar_hdr->th_linkflag = LF_CHR;
		(void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
		    sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
		    major(attr->st_rdev));
		(void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
		    sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
		    minor(attr->st_rdev));
		break;
	default:
		if (attr->st_nlink > 1) {
			/* mark file with hardlink LF_LINK */
			tar_hdr->th_linkflag = LF_LINK;
			(void) snprintf(tar_hdr->th_shared.th_hlink_ino,
			    sizeof (tar_hdr->th_shared.th_hlink_ino),
			    "%011llo ", attr->st_ino);
		} else {
			tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
			    LF_SYMLINK;
		}
	}
	(void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
	    (long)attr->st_size);
	(void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
	    attr->st_mode & 07777);
	(void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
	    uid);
	(void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
	    gid);
	(void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
	    uname);
	(void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
	    gname);
	(void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
	    attr->st_mtime);
	(void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
	    sizeof (tar_hdr->th_magic));

	tlm_build_header_checksum(tar_hdr);
	if (long_name || long_link) {
		if (file_count > 99999990) {
			file_count = 0;
		}
	}
	free(section_name);
	return (0);
}
Exemple #23
0
/*ARGSUSED*/
longlong_t
tlm_output_xattr(char  *dir, char *name, char *chkdir,
    tlm_acls_t *tlm_acls, tlm_commands_t *commands,
    tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
{
	char	*fullname;		/* directory + name */
	char	*snapname;		/* snapshot name */
	int	section;		/* section of a huge file */
	int	fd;
	int	afd = 0;
	longlong_t seek_spot = 0;	/* location in the file */
					/* for Multi Volume record */
	DIR *dp;
	struct dirent *dtp;
	char *attrname;
	char *fnamep;
	int rv = 0;

	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
		return (TLM_NO_SOURCE_FILE);
	}

	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (fullname == NULL) {
		free(fullname);
		return (-TLM_NO_SCRATCH_SPACE);
	}

	if (!tlm_cat_path(fullname, dir, name)) {
		syslog(LOG_ERR, "Path too long.");
		free(fullname);
		return (-TLM_NO_SCRATCH_SPACE);
	}

	if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
	    sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
		free(fullname);
		return (0);
	}

	attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (attrname == NULL || snapname == NULL) {
		rv = -TLM_NO_SCRATCH_SPACE;
		goto err_out;
	}

	if (!tlm_cat_path(snapname, chkdir, name)) {
		syslog(LOG_ERR, "Path too long.");
		rv = -TLM_NO_SCRATCH_SPACE;
		goto err_out;
	}

	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;

	/*
	 * Open the file for reading.
	 */
	fd = attropen(fnamep, ".", O_RDONLY);
	if (fd == -1) {
		syslog(LOG_ERR, "BACKUP> Can't open file [%s][%s]",
		    fullname, fnamep);
		rv = TLM_NO_SOURCE_FILE;
		goto err_out;
	}

	section = 0;

	dp = (DIR *)fdopendir(fd);
	if (dp == NULL) {
		syslog(LOG_ERR, "BACKUP> Can't open file [%s]", fullname);
		(void) close(fd);
		rv = TLM_NO_SOURCE_FILE;
		goto err_out;
	}

	while ((dtp = readdir(dp)) != NULL) {
		int section_size;

		if (*dtp->d_name == '.')
			continue;

		if (sysattr_rdonly(dtp->d_name))
			continue;

		afd = attropen(fnamep, dtp->d_name, O_RDONLY);
		if (afd == -1) {
			syslog(LOG_ERR,
			    "problem(%d) opening xattr file [%s][%s]", errno,
			    fullname, fnamep);
			goto tear_down;
		}

		(void) output_xattr_header(fullname, dtp->d_name, afd,
		    tlm_acls, section, local_commands);
		(void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
		    dtp->d_name);
		(void) output_file_header(attrname, "", tlm_acls, 0,
		    local_commands);

		section_size = (long)llmin(tlm_acls->acl_attr.st_size,
		    (longlong_t)TLM_MAX_TAR_IMAGE);

		/* We only can read upto one section extended attribute */
		while (section_size > 0) {
			char	*buf;
			long	actual_size;
			int	read_size;
			int sysattr_read = 0;
			char *rec;
			int size;

			/*
			 * check for Abort commands
			 */
			if (commands->tcs_reader != TLM_BACKUP_RUN) {
				local_commands->tc_writer = TLM_ABORT;
				goto tear_down;
			}

			local_commands->tc_buffers->tbs_buffer[
			    local_commands->tc_buffers->tbs_buffer_in].
			    tb_file_size = section_size;
			local_commands->tc_buffers->tbs_buffer[
			    local_commands->tc_buffers->tbs_buffer_in].
			    tb_seek_spot = seek_spot;

			buf = get_write_buffer(section_size,
			    &actual_size, FALSE, local_commands);
			if (!buf)
				goto tear_down;

			if ((actual_size < section_size) &&
			    sysattr_rw(dtp->d_name)) {
				rec = buf;
				buf = ndmp_malloc(section_size);
				if (!buf)
					goto tear_down;
				size = actual_size;
				actual_size = section_size;
				sysattr_read = 1;
			}

			/*
			 * check for Abort commands
			 */
			if (commands->tcs_reader != TLM_BACKUP_RUN) {
				local_commands->tc_writer = TLM_ABORT;
				goto tear_down;
			}

			read_size = min(section_size, actual_size);
			if ((actual_size = read(afd, buf, read_size)) < 0)
				break;

			if (sysattr_read) {
				if (get_write_one_buf(buf, rec, read_size,
				    size, local_commands) == 0) {
					free(buf);
					goto tear_down;
				}
				free(buf);
			}


			NS_ADD(rdisk, actual_size);
			NS_INC(rfile);

			if (actual_size == -1) {
				syslog(LOG_ERR,
				    "problem(%d) reading file [%s][%s]",
				    errno, fullname, snapname);
				goto tear_down;
			}
			seek_spot += actual_size;
			section_size -= actual_size;
		}
		(void) close(afd);
		afd = -1;
	}

tear_down:
	local_commands->tc_buffers->tbs_buffer[
	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;

	if (afd > 0)
		(void) close(afd);

	/* closedir closes fd too */
	(void) closedir(dp);

err_out:
	free(fullname);
	free(attrname);
	free(snapname);
	return (rv);
}
Exemple #24
0
/*
 * Traverse the file system in the level-order way.  The description
 * and example is in the header file.
 */
int
traverse_level(struct fs_traverse *ftp)
{
	char path[PATH_MAX + 1];	/* full path name of the current dir */
	char nm[NAME_MAX + 1];	/* directory entry name */
	char *lp;		/* last position on the path */
	int next_dir, rv;
	int pl, el;		/* path and directory entry length */

	cstack_t *sp;
	fs_fhandle_t pfh, efh;
	struct stat64 pst, est;
	traverse_state_t *tsp;
	struct fst_node pn, en;  /* parent and entry nodes */
	dent_arg_t darg;

	if (!ftp || !ftp->ft_path || !*ftp->ft_path || !ftp->ft_callbk) {
		NDMP_LOG(LOG_DEBUG, "Invalid argument");
		errno = EINVAL;
		return (-1);
	}
	/* set the default log function if it's not already set */
	if (!ftp->ft_logfp) {
		ftp->ft_logfp = (ft_log_t)syslog;
		NDMP_LOG(LOG_DEBUG, "Log to system log \"%s\"", ftp->ft_path);
	}
	if (!ftp->ft_lpath) {
		NDMP_LOG(LOG_DEBUG,
		    "report the same paths \"%s\"", ftp->ft_path);
		ftp->ft_lpath = ftp->ft_path;
	}

	pl = strlen(ftp->ft_lpath);
	if (pl + 1 > PATH_MAX) { /* +1 for the '/' */
		NDMP_LOG(LOG_DEBUG, "lpath too long \"%s\"", ftp->ft_path);
		errno = ENAMETOOLONG;
		return (-1);
	}
	(void) strcpy(path, ftp->ft_lpath);
	(void) memset(&pfh, 0, sizeof (pfh));
	rv = fs_getstat(ftp->ft_lpath, &pfh, &pst);
	if (rv != 0) {
		NDMP_LOG(LOG_DEBUG,
		    "Error %d on fs_getstat(%s)", rv, ftp->ft_path);
		return (-1);
	}

	en.tn_path = NULL;
	en.tn_fh = NULL;
	en.tn_st = NULL;
	if (!S_ISDIR(pst.st_mode)) {
		pn.tn_path = ftp->ft_lpath;
		pn.tn_fh = &pfh;
		pn.tn_st = &pst;
		rv = CALLBACK(&pn, &en);
		if (VERBOSE(ftp))
			NDMP_LOG(LOG_DEBUG, "CALLBACK(%s): %d", pn.tn_path, rv);

		free(pfh.fh_fpath);
		return (rv);
	}

	sp = cstack_new();
	if (!sp) {
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}
	tsp = new_tsp(path);
	if (!tsp) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		errno = ENOMEM;
		return (-1);
	}

	darg.da_buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (!darg.da_buf) {
		cstack_delete(sp);
		free(pfh.fh_fpath);
		free(tsp);
		errno = ENOMEM;
		return (-1);
	}
	darg.da_size = MAX_DENT_BUF_SIZE;

	tsp->ts_ent = tsp->ts_end;
	tsp->ts_fh = pfh;
	tsp->ts_st = pst;
	pn.tn_path = path;
	pn.tn_fh = &tsp->ts_fh;
	pn.tn_st = &tsp->ts_st;

	/* call the callback function on the path itself */
	traverse_stats.fss_dir_calls++;
	rv = CALLBACK(&pn, &en);
	if (rv < 0) {
		free(tsp);
		goto end;
	}
	if (rv == FST_SKIP) {
		traverse_stats.fss_dir_skipped++;
		free(tsp);
		rv = 0;
		goto end;
	}

	rv = 0;
	next_dir = 1;
	do {
		if (next_dir) {
			traverse_stats.fss_newdirs++;

			*tsp->ts_end = '\0';
			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "pl %d \"%s\"", pl, path);

			rv = traverse_level_nondir(ftp, tsp, &pn, &darg);
			if (rv < 0) {
				NEGATE(rv);
				free(tsp->ts_fh.fh_fpath);
				free(tsp);
				break;
			}
			/*
			 * If skipped by the callback function or
			 * error happened reading the information
			 */
			if (rv == FST_SKIP || rv == SKIP_ENTRY) {
				/*
				 * N.B. next_dir should be set to 0 as
				 * well. This prevents the infinite loop.
				 * If it's not set the same directory will
				 * be poped from the stack and will be
				 * scanned again.
				 */
				next_dir = 0;
				rv = 0;
				goto skip_dir;
			}

			/* re-start reading entries of the directory */
			tsp->ts_dpos = 0;
		}

		next_dir = 0;
		do {
			el = NAME_MAX;
			rv = fs_readdir(&tsp->ts_fh, pn.tn_path,
			    &tsp->ts_dpos, nm, &el, &efh,
			    &est);
			if (rv != 0) {
				traverse_stats.fss_readdir_err++;

				NDMP_LOG(LOG_DEBUG,
				    "Error %d on readdir(%s) pos %d",
				    rv, path, tsp->ts_dpos);
				if (STOP_ONERR(ftp))
					break;
				rv = SKIP_ENTRY;
				continue;
			}

			/* done with this directory */
			if (el == 0)
				break;

			nm[el] = '\0';

			if (rootfs_dot_or_dotdot(nm)) {
				free(efh.fh_fpath);
				continue;
			}

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "%u dname: \"%s\"",
				    tsp->ts_dpos, nm);

			if (pl + 1 + el > PATH_MAX) {
				/*
				 * The long paths were already encountered
				 * when processing non-dir entries in.
				 * traverse_level_nondir.
				 * We don't increase fss_longpath_err
				 * counter for them again here.
				 */
				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    path, nm);
				if (STOP_ONLONG(ftp))
					rv = ENAMETOOLONG;
				free(efh.fh_fpath);
				continue;
			}

			if (!S_ISDIR(est.st_mode))
				continue;

			/*
			 * Call the callback function for the new
			 * directory found, then push the current
			 * directory on to the stack.  Then dive
			 * into the entry found.
			 */
			traverse_stats.fss_dir_calls++;
			en.tn_path = nm;
			en.tn_fh = &efh;
			en.tn_st = &est;
			rv = CALLBACK(&pn, &en);

			if (rv < 0) {
				NEGATE(rv);
				free(efh.fh_fpath);
				break;
			}
			if (rv == FST_SKIP) {
				traverse_stats.fss_dir_skipped++;
				free(efh.fh_fpath);
				rv = 0;
				continue;
			}

			/*
			 * Push the current directory on to the stack and
			 * dive into the entry found.
			 */
			if (cstack_push(sp, tsp, 0)) {
				rv = ENOMEM;
			} else {
				traverse_stats.fss_pushes++;

				lp = tsp->ts_end;
				*tsp->ts_end = '/';
				(void) strcpy(tsp->ts_end + 1, nm);

				tsp = new_tsp(path);
				if (!tsp)
					rv = ENOMEM;
				else {
					next_dir = 1;
					pl += el + 1;
					tsp->ts_fh = efh;
					tsp->ts_st = est;
					tsp->ts_ent = lp;
					pn.tn_fh = &tsp->ts_fh;
					pn.tn_st = &tsp->ts_st;
				}
			}
			break;

		} while (rv == 0);

		/*
		 * A new directory must be processed, go to the start of
		 * the loop, open it and process it.
		 */
		if (next_dir)
			continue;
skip_dir:
		if (tsp) {
			free(tsp->ts_fh.fh_fpath);
			free(tsp);
		}

		if (rv == SKIP_ENTRY)
			rv = 0;

		if (rv == 0) {
			if (cstack_pop(sp, (void **)&tsp, (int *)NULL))
				break;

			traverse_stats.fss_pops++;

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG,
				    "Poped pl %d \"%s\"", pl, path);

			*tsp->ts_end = '\0';
			pl = tsp->ts_end - path;
			pn.tn_fh = &tsp->ts_fh;
			pn.tn_st = &tsp->ts_st;
		}
	} while (rv == 0);

	/*
	 * Pop and free all the remaining entries on the stack.
	 */
	while (!cstack_pop(sp, (void **)&tsp, (int *)NULL)) {
		traverse_stats.fss_stack_residue++;

		free(tsp->ts_fh.fh_fpath);
		free(tsp);
	}
end:
	free(darg.da_buf);
	cstack_delete(sp);
	return (rv);
}
Exemple #25
0
/*
 * In one pass, read all the directory entries of the specified
 * directory and call the callback function for non-directory
 * entries.
 *
 * On return:
 *    0: Lets the directory to be scanned for directory entries.
 *    < 0: Completely stops traversing.
 *    FST_SKIP: stops further scanning of the directory.  Traversing
 *        will continue with the next directory in the hierarchy.
 *    SKIP_ENTRY: Failed to get the directory entries, so the caller
 *	  should skip this entry.
 */
static int
traverse_level_nondir(struct fs_traverse *ftp,
    traverse_state_t *tsp, struct fst_node *pnp, dent_arg_t *darg)
{
	int pl; /* path length */
	int rv;
	struct fst_node en; /* entry node */
	longlong_t cookie_verf;
	fs_dent_info_t *dent;
	struct dirent *buf;
	size_t len = 0;
	int fd;

	rv = 0;
	pl = strlen(pnp->tn_path);

	buf = ndmp_malloc(MAX_DENT_BUF_SIZE);
	if (buf == NULL)
		return (errno);

	fd = open(tsp->ts_fh.fh_fpath, O_RDONLY);
	if (fd == -1) {
		free(buf);
		return (errno);
	}

	while (rv == 0) {
		long i, n_entries;

		darg->da_end = 0;
		n_entries = 0;
		rv = fs_getdents(fd, buf, &len, pnp->tn_path, &tsp->ts_dpos,
		    &cookie_verf, &n_entries, darg);
		if (rv < 0) {
			traverse_stats.fss_readdir_err++;

			NDMP_LOG(LOG_DEBUG, "Error %d on readdir(%s) pos %d",
			    rv, pnp->tn_path, tsp->ts_dpos);
			if (STOP_ONERR(ftp))
				break;
			/*
			 * We cannot read the directory entry, we should
			 * skip to the next directory.
			 */
			rv = SKIP_ENTRY;
			continue;
		} else {
			/* Break at the end of directory */
			if (rv > 0)
				rv = 0;
			else
				break;
		}

		/* LINTED imporper alignment */
		dent = (fs_dent_info_t *)darg->da_buf;
		/* LINTED imporper alignment */
		for (i = 0; i < n_entries; i++, dent = (fs_dent_info_t *)
		    ((char *)dent + dent->fd_len)) {

			if (VERBOSE(ftp))
				NDMP_LOG(LOG_DEBUG, "i %u dname: \"%s\"",
				    dent->fd_fh.fh_fid, dent->fd_name);

			if ((pl + strlen(dent->fd_name)) > PATH_MAX) {
				traverse_stats.fss_longpath_err++;

				NDMP_LOG(LOG_ERR, "Path %s/%s is too long.",
				    pnp->tn_path, dent->fd_name);
				if (STOP_ONLONG(ftp))
					rv = -ENAMETOOLONG;
				free(dent->fd_fh.fh_fpath);
				continue;
			}

			/*
			 * The entry is not a directory so the callback
			 * function must be called.
			 */
			if (!S_ISDIR(dent->fd_attr.st_mode)) {
				traverse_stats.fss_nondir_calls++;

				en.tn_path = dent->fd_name;
				en.tn_fh = &dent->fd_fh;
				en.tn_st = &dent->fd_attr;
				rv = CALLBACK(pnp, &en);
				dent->fd_fh.fh_fpath = NULL;
				if (rv < 0)
					break;
				if (rv == FST_SKIP) {
					traverse_stats.fss_nondir_skipped++;
					break;
				}
			}
		}
	}

	free(buf);
	(void) close(fd);
	return (rv);
}
Exemple #26
0
/*
 * tlm_output_file
 *
 * Put this file into the output buffers.
 */
longlong_t
tlm_output_file(char *dir, char *name, char *chkdir,
    tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
    tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
{
	char	*fullname;		/* directory + name */
	char	*snapname;		/* snapshot name */
	char	*linkname;		/* where this file points */
	int	section = 0;		/* section of a huge file */
	int	fd;
	longlong_t real_size;		/* the origional file size */
	longlong_t file_size;		/* real size of this file */
	longlong_t seek_spot = 0;	/* location in the file */
					/* for Multi Volume record */
	u_longlong_t pos;
	char *fnamep;

	/* Indicate whether a file with the same inode has been backed up. */
	int hardlink_done = 0;

	/*
	 * If a file with the same inode has been backed up, hardlink_pos holds
	 * the tape offset of the data record.
	 */
	u_longlong_t hardlink_pos = 0;

	if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
		syslog(LOG_ERR, "Path too long [%s][%s]", dir, name);
		return (-TLM_NO_SCRATCH_SPACE);
	}

	fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
	linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
	snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
	if (fullname == NULL || linkname == NULL || snapname == NULL) {
		real_size = -TLM_NO_SCRATCH_SPACE;
		goto err_out;
	}
	if (!tlm_cat_path(fullname, dir, name) ||
	    !tlm_cat_path(snapname, chkdir, name)) {
		syslog(LOG_ERR, "Path too long.");
		real_size = -TLM_NO_SCRATCH_SPACE;
		goto err_out;
	}

	pos = tlm_get_data_offset(local_commands);

	if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
		if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
			file_size = tlm_readlink(fullname, snapname, linkname,
			    TLM_MAX_PATH_NAME-1);
			if (file_size < 0) {
				real_size = -ENOENT;
				goto err_out;
			}
		}

		/*
		 * Since soft links can not be read(2), we should only
		 * backup the file header.
		 */
		(void) output_file_header(fullname,
		    linkname,
		    tlm_acls,
		    section,
		    local_commands);

		(void) tlm_log_fhnode(job_stats, dir, name,
		    &tlm_acls->acl_attr, pos);
		(void) tlm_log_fhpath_name(job_stats, fullname,
		    &tlm_acls->acl_attr, pos);

		free(fullname);
		free(linkname);
		free(snapname);
		return (0);
	}

	fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;

	/*
	 * For hardlink, only read the data if no other link
	 * belonging to the same inode has been backed up.
	 */
	if (tlm_acls->acl_attr.st_nlink > 1) {
		hardlink_done = !hardlink_q_get(hardlink_q,
		    tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
	}

	if (!hardlink_done) {
		/*
		 * Open the file for reading.
		 */
		fd = open(fnamep, O_RDONLY);
		if (fd == -1) {
			syslog(LOG_ERR,
			    "BACKUP> Can't open file [%s][%s] err(%d)",
			    fullname, fnamep, errno);
			real_size = -TLM_NO_SOURCE_FILE;
			goto err_out;
		}
	} else {
		syslog(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
		    tlm_acls->acl_attr.st_ino, hardlink_pos);

		fd = -1;
	}

	linkname[0] = 0;

	real_size = tlm_acls->acl_attr.st_size;
	(void) output_acl_header(&tlm_acls->acl_info,
	    local_commands);

	/*
	 * section = 0: file is small enough for TAR
	 * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
	 * 		and the file name gets munged
	 */
	file_size = real_size;
	if (file_size > TLM_MAX_TAR_IMAGE) {
		if (output_humongus_header(fullname, file_size,
		    local_commands) < 0) {
			(void) close(fd);
			real_size = -TLM_NO_SCRATCH_SPACE;
			goto err_out;
		}
		section = 1;
	} else {
		section = 0;
	}

	/*
	 * For hardlink, if other link belonging to the same inode
	 * has been backed up, only backup an empty record.
	 */
	if (hardlink_done)
		file_size = 0;

	/*
	 * work
	 */
	if (file_size == 0) {
		(void) output_file_header(fullname,
		    linkname,
		    tlm_acls,
		    section,
		    local_commands);
		/*
		 * this can fall right through since zero size files
		 * will be skipped by the WHILE loop anyway
		 */
	}

	while (file_size > 0) {
		int section_size = llmin(file_size,
		    (longlong_t)TLM_MAX_TAR_IMAGE);

		tlm_acls->acl_attr.st_size = (longlong_t)section_size;
		(void) output_file_header(fullname,
		    linkname,
		    tlm_acls,
		    section,
		    local_commands);
		while (section_size > 0) {
			char	*buf;
			long	actual_size;
			int	read_size;

			/*
			 * check for Abort commands
			 */
			if (commands->tcs_reader != TLM_BACKUP_RUN) {
				local_commands->tc_writer = TLM_ABORT;
				goto tear_down;
			}

			local_commands->tc_buffers->tbs_buffer[
			    local_commands->tc_buffers->tbs_buffer_in].
			    tb_file_size = section_size;
			local_commands->tc_buffers->tbs_buffer[
			    local_commands->tc_buffers->tbs_buffer_in].
			    tb_seek_spot = seek_spot;

			buf = get_write_buffer(section_size,
			    &actual_size, FALSE, local_commands);
			if (!buf)
				goto tear_down;

			/*
			 * check for Abort commands
			 */
			if (commands->tcs_reader != TLM_BACKUP_RUN) {
				local_commands->tc_writer = TLM_ABORT;
				goto tear_down;
			}

			read_size = min(section_size, actual_size);
			actual_size = read(fd, buf, read_size);
			NS_ADD(rdisk, actual_size);
			NS_INC(rfile);

			if (actual_size == 0)
				break;

			if (actual_size == -1) {
				syslog(LOG_ERR,
				    "problem(%d) reading file [%s][%s]",
				    errno, fullname, snapname);
				goto tear_down;
			}
			seek_spot += actual_size;
			file_size -= actual_size;
			section_size -= actual_size;
		}
		section++;
	}

	/*
	 * If data belonging to this hardlink has been backed up, add the link
	 * to hardlink queue.
	 */
	if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
		(void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
		    pos, NULL, 0);
		syslog(LOG_DEBUG,
		    "backed up hardlink file %s, inode = %llu, pos = %llu ",
		    fullname, tlm_acls->acl_attr.st_ino, pos);
	}

	/*
	 * For hardlink, if other link belonging to the same inode has been
	 * backed up, no add_node entry should be sent for this link.
	 */
	if (hardlink_done) {
		syslog(LOG_DEBUG,
		    "backed up hardlink link %s, inode = %llu, pos = %llu ",
		    fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
	} else {
		(void) tlm_log_fhnode(job_stats, dir, name,
		    &tlm_acls->acl_attr, pos);
	}

	(void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
	    pos);

tear_down:
	local_commands->tc_buffers->tbs_buffer[
	    local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;

	(void) close(fd);

err_out:
	free(fullname);
	free(linkname);
	free(snapname);
	return (real_size);
}
Exemple #27
0
/*
 * ndmpd_api_file_history_dir_v3
 *
 * Add a file history dir entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie (input) - session pointer.
 *   name   (input) - file name.
 *		    NULL forces buffered data to be sent.
 *   node   (input) - file inode.
 *   parent (input) - file parent inode.
 *		    Should equal node if the file is the root of
 *		    the filesystem and has no parent.
 *
 * Returns:
 *   0 - success
 *  -1 - error
 */
int
ndmpd_api_file_history_dir_v3(void *cookie, char *name, ulong_t node,
    ulong_t parent)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_dir_v3 *dir_entry;
	ndmp_file_name_v3 *dir_name_entry;
	ndmp_fh_add_dir_request_v3 request;

	if (name == NULL && session->ns_fh_v3.fh_dir_index == 0)
		return (0);

	/*
	 * If the buffer does not have space
	 * for the current entry, send the buffered data to the client.
	 * A NULL name indicates that any buffered data should be sent.
	 */
	if (name == NULL ||
	    session->ns_fh_v3.fh_dir_index == N_DIR_ENTRIES ||
	    session->ns_fh_v3.fh_dir_name_buf_index + strlen(name) + 1 >
	    DIR_NAMEBUF_SIZE) {

		syslog(LOG_DEBUG, "sending %ld entries",
		    session->ns_fh_v3.fh_dir_index);

		request.dirs.dirs_val = session->ns_fh_v3.fh_dirs;
		request.dirs.dirs_len = session->ns_fh_v3.fh_dir_index;

		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_DIR, NDMP_NO_ERR, (void *) &request, 0) < 0) {
			syslog(LOG_ERR,
			    "Sending ndmp_fh_add_dir request failed");
			return (-1);
		}

		session->ns_fh_v3.fh_dir_index = 0;
		session->ns_fh_v3.fh_dir_name_buf_index = 0;
	}

	if (name == NULL)
		return (0);

	if (session->ns_fh_v3.fh_dirs == 0) {
		session->ns_fh_v3.fh_dirs =
		    ndmp_malloc(sizeof (ndmp_dir_v3) * N_DIR_ENTRIES);
		if (session->ns_fh_v3.fh_dirs == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_dir_names == 0) {
		session->ns_fh_v3.fh_dir_names =
		    ndmp_malloc(sizeof (ndmp_file_name_v3) * N_DIR_ENTRIES);
		if (session->ns_fh_v3.fh_dir_names == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_dir_name_buf == 0) {
		session->ns_fh_v3.fh_dir_name_buf =
		    ndmp_malloc(sizeof (char) * DIR_NAMEBUF_SIZE);
		if (session->ns_fh_v3.fh_dir_name_buf == 0)
			return (-1);
	}

	dir_entry = &session->ns_fh_v3.fh_dirs[session->ns_fh_v3.fh_dir_index];
	dir_name_entry =
	    &session->ns_fh_v3.fh_dir_names[session->ns_fh_v3.fh_dir_index];

	dir_name_entry->fs_type = NDMP_FS_UNIX;
	dir_name_entry->ndmp_file_name_v3_u.unix_name =
	    &session->ns_fh_v3.fh_dir_name_buf[session->
	    ns_fh_v3.fh_dir_name_buf_index];

	(void) strlcpy(&session->ns_fh_v3.fh_dir_name_buf[session->
	    ns_fh_v3.fh_dir_name_buf_index], name, PATH_NAMEBUF_SIZE);
	session->ns_fh_v3.fh_dir_name_buf_index += strlen(name) + 1;

	dir_entry->names.names_len = 1;
	dir_entry->names.names_val = dir_name_entry;
	dir_entry->node = long_long_to_quad(node);
	dir_entry->parent = long_long_to_quad(parent);

	session->ns_fh_v3.fh_dir_index++;

	return (0);
}
/*
 * ndmp_recv_msg
 *
 * Read the next message.
 *
 * Parameters:
 *   connection (input)  - connection pointer.
 *   msg	(output) - received message.
 *
 * Returns:
 *   0 - Message successfully received.
 *   error number - Message related error.
 *  -1 - Error decoding the message header.
 */
static int
ndmp_recv_msg(ndmp_connection_t *connection)
{
	bool_t(*xdr_func) (XDR *, ...) = NULL;

	/* Decode the header. */
	connection->conn_xdrs.x_op = XDR_DECODE;
	(void) xdrrec_skiprecord(&connection->conn_xdrs);
	if (!xdr_ndmp_header(&connection->conn_xdrs,
	    &connection->conn_msginfo.mi_hdr))
		return (-1);

	/* Lookup info necessary for processing this message. */
	if ((connection->conn_msginfo.mi_handler = ndmp_get_handler(connection,
	    connection->conn_msginfo.mi_hdr.message)) == 0) {
		NDMP_LOG(LOG_DEBUG, "Message 0x%x not supported",
		    connection->conn_msginfo.mi_hdr.message);
		return (NDMP_NOT_SUPPORTED_ERR);
	}
	connection->conn_msginfo.mi_body = 0;

	if (connection->conn_msginfo.mi_hdr.error != NDMP_NO_ERR)
		return (0);

	/* Determine body type */
	if (connection->conn_msginfo.mi_hdr.message_type ==
	    NDMP_MESSAGE_REQUEST) {
		if (ndmp_check_auth_required(
		    connection->conn_msginfo.mi_hdr.message) &&
		    !connection->conn_authorized) {
			NDMP_LOG(LOG_DEBUG,
			    "Processing request 0x%x:connection not authorized",
			    connection->conn_msginfo.mi_hdr.message);
			return (NDMP_NOT_AUTHORIZED_ERR);
		}
		if (connection->conn_msginfo.mi_handler->mh_sizeof_request >
		    0) {
			xdr_func =
			    connection->conn_msginfo.mi_handler->mh_xdr_request;
			if (xdr_func == NULL) {
				NDMP_LOG(LOG_DEBUG,
				    "Processing request 0x%x: no xdr function "
				    "in handler table",
				    connection->conn_msginfo.mi_hdr.message);
				return (NDMP_NOT_SUPPORTED_ERR);
			}
			connection->conn_msginfo.mi_body = ndmp_malloc(
			    connection->conn_msginfo.mi_handler->
			    mh_sizeof_request);
			if (connection->conn_msginfo.mi_body == NULL)
				return (NDMP_NO_MEM_ERR);

			(void) memset(connection->conn_msginfo.mi_body, 0,
			    connection->conn_msginfo.mi_handler->
			    mh_sizeof_request);
		}
	} else {
		if (connection->conn_msginfo.mi_handler->mh_sizeof_reply > 0) {
			xdr_func =
			    connection->conn_msginfo.mi_handler->mh_xdr_reply;
			if (xdr_func == NULL) {
				NDMP_LOG(LOG_DEBUG,
				    "Processing reply 0x%x: no xdr function "
				    "in handler table",
				    connection->conn_msginfo.mi_hdr.message);
				return (NDMP_NOT_SUPPORTED_ERR);
			}
			connection->conn_msginfo.mi_body = ndmp_malloc(
			    connection->conn_msginfo.mi_handler->
			    mh_sizeof_reply);
			if (connection->conn_msginfo.mi_body == NULL)
				return (NDMP_NO_MEM_ERR);

			(void) memset(connection->conn_msginfo.mi_body, 0,
			    connection->conn_msginfo.mi_handler->
			    mh_sizeof_reply);
		}
	}

	/* Decode message arguments if needed */
	if (xdr_func) {
		if (!(*xdr_func)(&connection->conn_xdrs,
		    connection->conn_msginfo.mi_body)) {
			NDMP_LOG(LOG_DEBUG,
			    "Processing message 0x%x: error decoding arguments",
			    connection->conn_msginfo.mi_hdr.message);
			free(connection->conn_msginfo.mi_body);
			connection->conn_msginfo.mi_body = 0;
			return (NDMP_XDR_DECODE_ERR);
		}
	}
	return (0);
}
Exemple #29
0
/*
 * ndmpd_api_file_history_node_v3
 *
 * Add a file history node entry to the buffer.
 * History data is buffered until the buffer is filled.
 * Full buffers are then sent to the client.
 *
 * Parameters:
 *   cookie   (input) - session pointer.
 *   node     (input) - file inode.
 *		must match a node from a prior ndmpd_api_file_history_dir()
 *		      call.
 *   file_stat (input) - file status pointer.
 *		      0 forces buffered data to be sent.
 *   fh_info  (input) - data stream position of file data used during
 *		      fast restore.
 *
 * Returns:
 *   0 - success
 *  -1 - error.
 */
int
ndmpd_api_file_history_node_v3(void *cookie, ulong_t node,
    struct stat64 *file_stat, u_longlong_t fh_info)
{
	ndmpd_session_t *session = (ndmpd_session_t *)cookie;
	ndmp_node_v3 *node_entry;
	ndmp_file_stat_v3 *file_stat_entry;
	ndmp_fh_add_node_request_v3 request;

	if (file_stat == NULL && session->ns_fh_v3.fh_node_index == 0)
		return (0);

	/*
	 * If the buffer does not have space
	 * for the current entry, send the buffered data to the client.
	 * A 0 file_stat pointer indicates that any buffered data should
	 * be sent.
	 */
	if (file_stat == NULL ||
	    session->ns_fh_v3.fh_node_index == N_NODE_ENTRIES) {
		syslog(LOG_DEBUG, "sending %ld entries",
		    session->ns_fh_v3.fh_node_index);

		/*
		 * Need to send Dir entry as well. Since Dir entry is more
		 * than a Node entry, we may send a Node entry that hasn't
		 * had its Dir entry sent. Therefore, we need to flush Dir
		 * entry as well every time the Dir entry is sent.
		 */
		(void) ndmpd_api_file_history_dir_v3(session, 0, 0, 0);

		request.nodes.nodes_len = session->ns_fh_v3.fh_node_index;
		request.nodes.nodes_val = session->ns_fh_v3.fh_nodes;

		if (ndmp_send_request_lock(session->ns_connection,
		    NDMP_FH_ADD_NODE,
		    NDMP_NO_ERR, (void *) &request, 0) < 0) {
			syslog(LOG_ERR,
			    "Sending ndmp_fh_add_node request failed");
			return (-1);
		}

		session->ns_fh_v3.fh_node_index = 0;
	}

	if (file_stat == NULL)
		return (0);

	if (session->ns_fh_v3.fh_nodes == 0) {
		session->ns_fh_v3.fh_nodes =
		    ndmp_malloc(sizeof (ndmp_node_v3) * N_NODE_ENTRIES);
		if (session->ns_fh_v3.fh_nodes == 0)
			return (-1);
	}

	if (session->ns_fh_v3.fh_node_stats == 0) {
		session->ns_fh_v3.fh_node_stats =
		    ndmp_malloc(sizeof (ndmp_file_stat_v3) * N_NODE_ENTRIES);
		if (session->ns_fh_v3.fh_node_stats == 0)
			return (-1);
	}

	node_entry =
	    &session->ns_fh_v3.fh_nodes[session->ns_fh_v3.fh_node_index];

	file_stat_entry =
	    &session->ns_fh_v3.fh_node_stats[session->ns_fh_v3.fh_node_index];
	ndmpd_get_file_entry_type(file_stat->st_mode, &file_stat_entry->ftype);

	file_stat_entry->invalid = 0;
	file_stat_entry->fs_type = NDMP_FS_UNIX;
	file_stat_entry->mtime = file_stat->st_mtime;
	file_stat_entry->atime = file_stat->st_atime;
	file_stat_entry->ctime = file_stat->st_ctime;
	file_stat_entry->owner = file_stat->st_uid;
	file_stat_entry->group = file_stat->st_gid;
	file_stat_entry->fattr = file_stat->st_mode & 0x0fff;
	file_stat_entry->size =
	    long_long_to_quad((u_longlong_t)file_stat->st_size);
	file_stat_entry->links = file_stat->st_nlink;

	node_entry->stats.stats_len = 1;
	node_entry->stats.stats_val = file_stat_entry;
	node_entry->node = long_long_to_quad((u_longlong_t)node);
	node_entry->fh_info = long_long_to_quad(fh_info);

	session->ns_fh_v3.fh_node_index++;

	return (0);
}
Exemple #30
0
int
filecopy(char *dest, char *src)
{
	FILE *src_fh = 0;
	FILE *dst_fh = 0;
	struct stat64 src_attr;
	struct stat64 dst_attr;
	char *buf = 0;
	u_longlong_t bytes_to_copy;
	size_t nbytes;
	int file_copied = 0;

	buf = ndmp_malloc(BUFSIZE);
	if (!buf)
		return (-1);

	src_fh = fopen(src, "r");
	if (src_fh == 0) {
		free(buf);
		return (-2);
	}

	dst_fh = fopen(dest, "w");
	if (dst_fh == NULL) {
		free(buf);
		(void) fclose(src_fh);
		return (-3);
	}

	if (stat64(src, &src_attr) < 0) {
		free(buf);
		(void) fclose(src_fh);
		(void) fclose(dst_fh);
		return (-2);
	}

	bytes_to_copy = src_attr.st_size;
	while (bytes_to_copy) {
		if (bytes_to_copy > BUFSIZE)
			nbytes = BUFSIZE;
		else
			nbytes = bytes_to_copy;

		if ((fread(buf, nbytes, 1, src_fh) != 1) ||
		    (fwrite(buf, nbytes, 1, dst_fh) != 1))
			break;
		bytes_to_copy -= nbytes;
	}

	(void) fclose(src_fh);
	(void) fclose(dst_fh);

	if (bytes_to_copy > 0) {
		free(buf);
		/* short read/write, remove the partial file */
		return (-4);
	}

	if (stat64(src, &dst_attr) < 0) {
		free(buf);
		return (-2);
	}

	free(buf);

	if (!file_copied)
		return (-5);	/* source modified during copy */
	else
		return (0);
}