int main(int argc, char **argv) { int i; dm_attrlist_t bufp[1024]; void *dmhandle=NULL; size_t dmhandle_len=0; int ret; dm_sessid_t sid = DM_NO_SESSION; dm_attrname_t attrname; size_t rlen; if(argc<3) { fprintf(stderr,"Usage: %s <file name> <attribute name>\n", argv[0]); return 1; } if(strlen(argv[2])>DM_ATTR_NAME_SIZE-1) { fprintf(stderr,"Usage: %s <file name> <attribute name>\n", argv[0]); fprintf(stderr,"<attribute name> must be %d characters long at maximum\n", DM_ATTR_NAME_SIZE-1); return 1; } if (dm_create_session(DM_NO_SESSION, "dmattr", &sid)!=0) { fprintf(stderr,"dm_create_session: failed, %s\n", strerror(errno)); return 1; } if (dm_path_to_handle(argv[1], &dmhandle, &dmhandle_len) != 0) { fprintf(stderr,"dm_path_to_handle: failed, %s\n", strerror(errno)); dm_destroy_session(sid); return 1; } memset((void *)&attrname.an_chars[0], 0, DM_ATTR_NAME_SIZE); memcpy((void *)&attrname.an_chars[0], argv[2], strlen(argv[2])); ret = dm_get_dmattr(sid, dmhandle, dmhandle_len, DM_NO_TOKEN, &attrname, sizeof(bufp), bufp, &rlen); if(ret==-1) { fprintf(stderr,"dm_get_dmattr: failed, %s\n", strerror(errno)); dm_handle_free(dmhandle, dmhandle_len); dm_destroy_session(sid); return 1; } for(i=0;i<rlen;i++) { unsigned char c=((unsigned char*)bufp)[i]; printf("%02x",c); } printf("\n"); dm_handle_free(dmhandle, dmhandle_len); dm_destroy_session(sid); return 0; }
/* see if a file is offline return -1 on failure. Set *offline to true/false according to offline status */ static int is_offline(char *fname, time_t now, bool *offline) { struct stat st; void *handle=NULL; size_t handle_len=0; size_t rlen; int ret; dm_attrname_t dmAttrName; /* keep some state between calls, to save on session creation calls */ static struct dmapi_state { dm_sessid_t sid; void *handle; size_t handle_len; } state; if (state.sid == 0) { /* create a new session if needed */ if (dm_create_session(DM_NO_SESSION, "samba", &state.sid) != 0) { return -1; } } /* try shortcut methods first */ if (stat(fname, &st) != 0) { return -1; } /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available, then assume its not offline (it may not be 100%, as it could be sparse) */ if (512 * (off_t)st.st_blocks > st.st_size * FILE_IS_ONLINE_RATIO) { *offline = false; return 0; } /* go the slow DMAPI route */ if (dm_path_to_handle(fname, &handle, &handle_len) != 0) { return -1; } memset(&dmAttrName, 0, sizeof(dmAttrName)); strcpy((char *)&dmAttrName.an_chars[0], "IBMObj"); ret = dm_get_dmattr(state.sid, handle, handle_len, DM_NO_TOKEN, &dmAttrName, 0, NULL, &rlen); /* its offline if the IBMObj attribute exists */ *offline = (ret == 0 || (ret == -1 && errno == E2BIG)); dm_handle_free(handle, handle_len); return 0; }
void my_print_victim( dm_sessid_t sid, void *hanp, size_t hlen, dm_attrname_t *dm_attrp, int verbose) { size_t rlen; size_t buflen = 10000; char buf[buflen]; if (hlen > HANDLE_LEN) { if (verbose & V_PRINT) printf("-- invalid length --\n"); } else { char handle_str[HANDLE_STR]; if (verbose & V_PRINT) { printf("%zd\t", hlen); hantoa(hanp, hlen, handle_str); printf("%s ", handle_str); } if (dm_get_dmattr(sid, hanp, hlen, DM_NO_TOKEN, dm_attrp, buflen, (char*)buf, &rlen)) { if (verbose & V_PRINT) { if( errno == E2BIG ){ printf("E2BIG\n"); } else if (errno == ENOMEM){ printf("ENOMEM\n"); } else { printf("<none>\n"); } } } else if (verbose & V_PRINT) { if( isalpha(buf[0]) ) printf("(%s)\n", buf); else printf("<len=%zd>\n",rlen); } } }
static int dmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { sys_dmapi_args_t kargs; sys_dmapi_args_t *uap = &kargs; int error = 0; int rvp = -ENOSYS; int use_rvp = 0; if (!capable(CAP_MKNOD)) return(-EPERM); if( copy_from_user( &kargs, (sys_dmapi_args_t*)arg, sizeof(sys_dmapi_args_t) ) ) return -EFAULT; switch (cmd) { case DM_CLEAR_INHERIT: error = dm_clear_inherit( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrname_t *) uap->arg5); /* attrnamep */ break; case DM_CREATE_BY_HANDLE: error = dm_create_by_handle( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* dirhanp */ (size_t) uap->arg3, /* dirhlen */ (dm_token_t) uap->arg4, /* token */ (void *) uap->arg5, /* hanp */ (size_t) uap->arg6, /* hlen */ (char *) uap->arg7); /* cname */ break; case DM_CREATE_SESSION: error = dm_create_session( (dm_sessid_t) uap->arg1, /* oldsid */ (char *) uap->arg2, /* sessinfop */ (dm_sessid_t *) uap->arg3); /* newsidp */ break; case DM_CREATE_USEREVENT: error = dm_create_userevent( (dm_sessid_t) uap->arg1, /* sid */ (size_t) uap->arg2, /* msglen */ (void *) uap->arg3, /* msgdatap */ (dm_token_t *) uap->arg4); /* tokenp */ break; case DM_DESTROY_SESSION: error = dm_destroy_session( (dm_sessid_t) uap->arg1); /* sid */ break; case DM_DOWNGRADE_RIGHT: error = dm_downgrade_right( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4); /* token */ break; case DM_FD_TO_HANDLE: error = dm_fd_to_hdl( (int) uap->arg1, /* fd */ (void *) uap->arg2, /* hanp */ (size_t *) uap->arg3); /* hlenp */ break; case DM_FIND_EVENTMSG: error = dm_find_eventmsg( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (size_t) uap->arg3, /* buflen */ (void *) uap->arg4, /* bufp */ (size_t *) uap->arg5); /* rlenp */ break; case DM_GET_ALLOCINFO: use_rvp = 1; error = dm_get_allocinfo_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_off_t *) uap->arg5, /* offp */ (u_int) uap->arg6, /* nelem */ (dm_extent_t *) uap->arg7, /* extentp */ (u_int *) uap->arg8, /* nelemp */ &rvp); break; case DM_GET_BULKALL: use_rvp = 1; error = dm_get_bulkall_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* mask */ (dm_attrname_t *) uap->arg6, /* attrnamep */ (dm_attrloc_t *) uap->arg7, /* locp */ (size_t) uap->arg8, /* buflen */ (void *) uap->arg9, /* bufp */ (size_t *) uap->arg10, /* rlenp */ &rvp); break; case DM_GET_BULKATTR: use_rvp = 1; error = dm_get_bulkattr_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* mask */ (dm_attrloc_t *)uap->arg6, /* locp */ (size_t) uap->arg7, /* buflen */ (void *) uap->arg8, /* bufp */ (size_t *) uap->arg9, /* rlenp */ &rvp); break; case DM_GET_CONFIG: error = dm_get_config( (void *) uap->arg1, /* hanp */ (size_t) uap->arg2, /* hlen */ (dm_config_t) uap->arg3, /* flagname */ (dm_size_t *) uap->arg4); /* retvalp */ break; case DM_GET_CONFIG_EVENTS: error = dm_get_config_events( (void *) uap->arg1, /* hanp */ (size_t) uap->arg2, /* hlen */ (u_int) uap->arg3, /* nelem */ (dm_eventset_t *) uap->arg4, /* eventsetp */ (u_int *) uap->arg5); /* nelemp */ break; case DM_GET_DIOINFO: error = dm_get_dioinfo( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_dioinfo_t *)uap->arg5); /* diop */ break; case DM_GET_DIRATTRS: use_rvp = 1; error = dm_get_dirattrs_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* mask */ (dm_attrloc_t *)uap->arg6, /* locp */ (size_t) uap->arg7, /* buflen */ (void *) uap->arg8, /* bufp */ (size_t *) uap->arg9, /* rlenp */ &rvp); break; case DM_GET_DMATTR: error = dm_get_dmattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrname_t *) uap->arg5, /* attrnamep */ (size_t) uap->arg6, /* buflen */ (void *) uap->arg7, /* bufp */ (size_t *) uap->arg8); /* rlenp */ break; case DM_GET_EVENTLIST: error = dm_get_eventlist( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* nelem */ (dm_eventset_t *) uap->arg6, /* eventsetp */ (u_int *) uap->arg7); /* nelemp */ break; case DM_GET_EVENTS: error = dm_get_events( (dm_sessid_t) uap->arg1, /* sid */ (u_int) uap->arg2, /* maxmsgs */ (u_int) uap->arg3, /* flags */ (size_t) uap->arg4, /* buflen */ (void *) uap->arg5, /* bufp */ (size_t *) uap->arg6); /* rlenp */ break; case DM_GET_FILEATTR: error = dm_get_fileattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* mask */ (dm_stat_t *) uap->arg6); /* statp */ break; case DM_GET_MOUNTINFO: error = dm_get_mountinfo( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (size_t) uap->arg5, /* buflen */ (void *) uap->arg6, /* bufp */ (size_t *) uap->arg7); /* rlenp */ break; case DM_GET_REGION: error = dm_get_region( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* nelem */ (dm_region_t *) uap->arg6, /* regbufp */ (u_int *) uap->arg7); /* nelemp */ break; case DM_GETALL_DISP: error = dm_getall_disp( (dm_sessid_t) uap->arg1, /* sid */ (size_t) uap->arg2, /* buflen */ (void *) uap->arg3, /* bufp */ (size_t *) uap->arg4); /* rlenp */ break; case DM_GETALL_DMATTR: error = dm_getall_dmattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (size_t) uap->arg5, /* buflen */ (void *) uap->arg6, /* bufp */ (size_t *) uap->arg7); /* rlenp */ break; case DM_GETALL_INHERIT: error = dm_getall_inherit( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* nelem */ (dm_inherit_t *)uap->arg6, /* inheritbufp*/ (u_int *) uap->arg7); /* nelemp */ break; case DM_GETALL_SESSIONS: error = dm_getall_sessions( (u_int) uap->arg1, /* nelem */ (dm_sessid_t *) uap->arg2, /* sidbufp */ (u_int *) uap->arg3); /* nelemp */ break; case DM_GETALL_TOKENS: error = dm_getall_tokens( (dm_sessid_t) uap->arg1, /* sid */ (u_int) uap->arg2, /* nelem */ (dm_token_t *) uap->arg3, /* tokenbufp */ (u_int *) uap->arg4); /* nelemp */ break; case DM_INIT_ATTRLOC: error = dm_init_attrloc( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrloc_t *) uap->arg5); /* locp */ break; case DM_MKDIR_BY_HANDLE: error = dm_mkdir_by_handle( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* dirhanp */ (size_t) uap->arg3, /* dirhlen */ (dm_token_t) uap->arg4, /* token */ (void *) uap->arg5, /* hanp */ (size_t) uap->arg6, /* hlen */ (char *) uap->arg7); /* cname */ break; case DM_MOVE_EVENT: error = dm_move_event( (dm_sessid_t) uap->arg1, /* srcsid */ (dm_token_t) uap->arg2, /* token */ (dm_sessid_t) uap->arg3, /* targetsid */ (dm_token_t *) uap->arg4); /* rtokenp */ break; case DM_OBJ_REF_HOLD: error = dm_obj_ref_hold( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (void *) uap->arg3, /* hanp */ (size_t) uap->arg4); /* hlen */ break; case DM_OBJ_REF_QUERY: use_rvp = 1; error = dm_obj_ref_query_rvp( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (void *) uap->arg3, /* hanp */ (size_t) uap->arg4, /* hlen */ &rvp); break; case DM_OBJ_REF_RELE: error = dm_obj_ref_rele( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (void *) uap->arg3, /* hanp */ (size_t) uap->arg4); /* hlen */ break; case DM_PATH_TO_FSHANDLE: error = dm_path_to_fshdl( (char *) uap->arg1, /* path */ (void *) uap->arg2, /* hanp */ (size_t *) uap->arg3); /* hlenp */ break; case DM_PATH_TO_HANDLE: error = dm_path_to_hdl( (char *) uap->arg1, /* path */ (void *) uap->arg2, /* hanp */ (size_t *) uap->arg3); /* hlenp */ break; case DM_PENDING: error = dm_pending( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (dm_timestruct_t *) uap->arg3); /* delay */ break; case DM_PROBE_HOLE: error = dm_probe_hole( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_off_t) uap->arg5, /* off */ (dm_size_t) uap->arg6, /* len */ (dm_off_t *) uap->arg7, /* roffp */ (dm_size_t *) uap->arg8); /* rlenp */ break; case DM_PUNCH_HOLE: error = dm_punch_hole( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_off_t) uap->arg5, /* off */ (dm_size_t) uap->arg6); /* len */ break; case DM_QUERY_RIGHT: error = dm_query_right( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_right_t *) uap->arg5); /* rightp */ break; case DM_QUERY_SESSION: error = dm_query_session( (dm_sessid_t) uap->arg1, /* sid */ (size_t) uap->arg2, /* buflen */ (void *) uap->arg3, /* bufp */ (size_t *) uap->arg4); /* rlenp */ break; case DM_READ_INVIS: use_rvp = 1; error = dm_read_invis_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_off_t) uap->arg5, /* off */ (dm_size_t) uap->arg6, /* len */ (void *) uap->arg7, /* bufp */ &rvp); break; case DM_RELEASE_RIGHT: error = dm_release_right( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4); /* token */ break; case DM_REMOVE_DMATTR: error = dm_remove_dmattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (int) uap->arg5, /* setdtime */ (dm_attrname_t *) uap->arg6); /* attrnamep */ break; case DM_REQUEST_RIGHT: error = dm_request_right( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* flags */ (dm_right_t) uap->arg6); /* right */ break; case DM_RESPOND_EVENT: error = dm_respond_event( (dm_sessid_t) uap->arg1, /* sid */ (dm_token_t) uap->arg2, /* token */ (dm_response_t) uap->arg3, /* response */ (int) uap->arg4, /* reterror */ (size_t) uap->arg5, /* buflen */ (void *) uap->arg6); /* respbufp */ break; case DM_SEND_MSG: error = dm_send_msg( (dm_sessid_t) uap->arg1, /* targetsid */ (dm_msgtype_t) uap->arg2, /* msgtype */ (size_t) uap->arg3, /* buflen */ (void *) uap->arg4); /* bufp */ break; case DM_SET_DISP: error = dm_set_disp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_eventset_t *) uap->arg5, /* eventsetp */ (u_int) uap->arg6); /* maxevent */ break; case DM_SET_DMATTR: error = dm_set_dmattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrname_t *) uap->arg5, /* attrnamep */ (int) uap->arg6, /* setdtime */ (size_t) uap->arg7, /* buflen */ (void *) uap->arg8); /* bufp */ break; case DM_SET_EVENTLIST: error = dm_set_eventlist( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_eventset_t *) uap->arg5, /* eventsetp */ (u_int) uap->arg6); /* maxevent */ break; case DM_SET_FILEATTR: error = dm_set_fileattr( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* mask */ (dm_fileattr_t *)uap->arg6); /* attrp */ break; case DM_SET_INHERIT: error = dm_set_inherit( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrname_t *)uap->arg5, /* attrnamep */ (mode_t) uap->arg6); /* mode */ break; case DM_SET_REGION: error = dm_set_region( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (u_int) uap->arg5, /* nelem */ (dm_region_t *) uap->arg6, /* regbufp */ (dm_boolean_t *) uap->arg7); /* exactflagp */ break; case DM_SET_RETURN_ON_DESTROY: error = dm_set_return_on_destroy( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (dm_attrname_t *) uap->arg5, /* attrnamep */ (dm_boolean_t) uap->arg6); /* enable */ break; case DM_SYMLINK_BY_HANDLE: error = dm_symlink_by_handle( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* dirhanp */ (size_t) uap->arg3, /* dirhlen */ (dm_token_t) uap->arg4, /* token */ (void *) uap->arg5, /* hanp */ (size_t) uap->arg6, /* hlen */ (char *) uap->arg7, /* cname */ (char *) uap->arg8); /* path */ break; case DM_SYNC_BY_HANDLE: error = dm_sync_by_handle( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4); /* token */ break; case DM_UPGRADE_RIGHT: error = dm_upgrade_right( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4); /* token */ break; case DM_WRITE_INVIS: use_rvp = 1; error = dm_write_invis_rvp( (dm_sessid_t) uap->arg1, /* sid */ (void *) uap->arg2, /* hanp */ (size_t) uap->arg3, /* hlen */ (dm_token_t) uap->arg4, /* token */ (int) uap->arg5, /* flags */ (dm_off_t) uap->arg6, /* off */ (dm_size_t) uap->arg7, /* len */ (void *) uap->arg8, /* bufp */ &rvp); break; default: error = ENOSYS; break; } /* If it was an *_rvp() function, then if error==0, return |rvp| */ if( use_rvp && (error == 0) ) return rvp; else return -error; }
static bool tsmsm_is_offline(struct vfs_handle_struct *handle, const struct smb_filename *fname, SMB_STRUCT_STAT *stbuf) { struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data; const dm_sessid_t *dmsession_id; void *dmhandle = NULL; size_t dmhandle_len = 0; size_t rlen; dm_attrname_t dmname; int ret, lerrno; bool offline; char *buf = NULL; size_t buflen; NTSTATUS status; char *path; status = get_full_smb_filename(talloc_tos(), fname, &path); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); return false; } /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available, then assume it is not offline (it may not be 100%, as it could be sparse) */ if (512 * stbuf->st_ex_blocks >= stbuf->st_ex_size * tsmd->online_ratio) { DEBUG(10,("%s not offline: st_blocks=%llu st_size=%llu " "online_ratio=%.2f\n", path, (unsigned long long)stbuf->st_ex_blocks, (unsigned long long)stbuf->st_ex_size, tsmd->online_ratio)); return false; } dmsession_id = dmapi_get_current_session(); if (dmsession_id == NULL) { DEBUG(2, ("tsmsm_is_offline: no DMAPI session available? " "Assume file is online.\n")); return false; } /* using POSIX capabilities does not work here. It's a slow path, so * become_root() is just as good anyway (tridge) */ /* Also, AIX has DMAPI but no POSIX capablities support. In this case, * we need to be root to do DMAPI manipulations. */ become_root(); /* go the slow DMAPI route */ if (dm_path_to_handle((char*)path, &dmhandle, &dmhandle_len) != 0) { DEBUG(2,("dm_path_to_handle failed - assuming offline (%s) - %s\n", path, strerror(errno))); offline = true; goto done; } memset(&dmname, 0, sizeof(dmname)); strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars)); if (tsmd->attrib_value != NULL) { buflen = strlen(tsmd->attrib_value); } else { buflen = 1; } buf = talloc_zero_size(tsmd, buflen); if (buf == NULL) { DEBUG(0,("out of memory in tsmsm_is_offline -- assuming online (%s)\n", path)); errno = ENOMEM; offline = false; goto done; } do { lerrno = 0; ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len, DM_NO_TOKEN, &dmname, buflen, buf, &rlen); if (ret == -1 && errno == EINVAL) { DEBUG(0, ("Stale DMAPI session, re-creating it.\n")); lerrno = EINVAL; if (dmapi_new_session()) { dmsession_id = dmapi_get_current_session(); } else { DEBUG(0, ("Unable to re-create DMAPI session, assuming offline (%s) - %s\n", path, strerror(errno))); offline = true; dm_handle_free(dmhandle, dmhandle_len); goto done; } } } while (ret == -1 && lerrno == EINVAL); /* check if we need a specific attribute value */ if (tsmd->attrib_value != NULL) { offline = (ret == 0 && rlen == buflen && memcmp(buf, tsmd->attrib_value, buflen) == 0); } else { /* its offline if the specified DMAPI attribute exists */ offline = (ret == 0 || (ret == -1 && errno == E2BIG)); } DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno))); ret = 0; dm_handle_free(dmhandle, dmhandle_len); done: talloc_free(buf); unbecome_root(); return offline; }
int main( int argc, char **argv) { dm_sessid_t sid, oldsid, targetsid, *newsidp, *sidbufp; dm_token_t token, *tokenp, *rtokenp, *tokenbufp; dm_attrname_t *attrnamep; dm_off_t off, *offp, *roffp; dm_extent_t *extentp; dm_inherit_t *inheritbufp; dm_stat_t *statp; dm_size_t len, *dmrlenp, *retvalp; dm_attrloc_t *locp; dm_eventset_t *eventsetp; dm_config_t flagname; dm_region_t *regbufp; dm_response_t response; dm_right_t right, *rightp; dm_igen_t igen, *igenp; dm_msgtype_t msgtype; dm_fileattr_t *attrp; dm_boolean_t enable, *exactflagp; dm_timestruct_t *delay; mode_t mode; size_t hlen, dirhlen, hlen1, hlen2, targhlen, *fshlenp, *hlenp; size_t msglen, buflen, *rlenp; u_int nelem, mask, maxmsgs, uflags, *nelemp, maxevent; void *hanp, *dirhanp, *hanp1, *hanp2, *targhanp; void *msgdatap, *bufp, **hanpp, *respbufp, **fshanpp; dm_fsid_t fsid, *fsidp; dm_ino_t ino, *inop; char *cname, *sessinfop, *path, *pathbufp, **versionstrpp; int flags, fd, setdtime, reterror; u_int urc; int rc; dm_ssize_t ssrc; /* Definitions per the prototypes in dmport.h, in the same order. */ rc = dm_clear_inherit(sid, hanp, hlen, token, attrnamep); rc = dm_create_by_handle(sid, dirhanp, dirhlen, token, hanp, hlen, cname); rc = dm_create_session(oldsid, sessinfop, newsidp); rc = dm_create_userevent(sid, msglen, msgdatap, tokenp); rc = dm_destroy_session(sid); rc = dm_downgrade_right(sid, hanp, hlen, token); rc = dm_fd_to_handle(fd, hanpp, hlenp); rc = dm_find_eventmsg(sid, token, buflen, bufp, rlenp); rc = dm_get_allocinfo(sid, hanp, hlen, token, offp, nelem, extentp, nelemp); rc = dm_get_bulkall(sid, hanp, hlen, token, mask, attrnamep, locp, buflen, bufp, rlenp); rc = dm_get_bulkattr(sid, hanp, hlen, token, mask, locp, buflen, bufp, rlenp); rc = dm_get_config(hanp, hlen, flagname, retvalp); rc = dm_get_config_events(hanp, hlen, nelem, eventsetp, nelemp); rc = dm_get_dirattrs(sid, hanp, hlen, token, mask, locp, buflen, bufp, rlenp); rc = dm_get_dmattr(sid, hanp, hlen, token, attrnamep, buflen, bufp, rlenp); rc = dm_get_eventlist(sid, hanp, hlen, token, nelem, eventsetp, nelemp); rc = dm_get_events(sid, maxmsgs, flags, buflen, bufp, rlenp); rc = dm_get_fileattr(sid, hanp, hlen, token, mask, statp); rc = dm_get_mountinfo(sid, hanp, hlen, token, buflen, bufp, rlenp); rc = dm_get_region(sid, hanp, hlen, token, nelem, regbufp, nelemp); rc = dm_getall_disp(sid, buflen, bufp, rlenp); rc = dm_getall_dmattr(sid, hanp, hlen, token, buflen, bufp, rlenp); rc = dm_getall_inherit(sid, hanp, hlen, token, nelem, inheritbufp, nelemp); rc = dm_getall_sessions(nelem, sidbufp, nelemp); rc = dm_getall_tokens(sid, nelem, tokenbufp, nelemp); rc = dm_handle_cmp(hanp1, hlen1, hanp2, hlen2); dm_handle_free(hanp, hlen); urc = dm_handle_hash(hanp, hlen); rc = dm_handle_is_valid(hanp, hlen); rc = dm_handle_to_fshandle(hanp, hlen, fshanpp, fshlenp); rc = dm_handle_to_fsid(hanp, hlen, fsidp); rc = dm_handle_to_igen(hanp, hlen, igenp); rc = dm_handle_to_ino(hanp, hlen, inop); rc = dm_handle_to_path(dirhanp, dirhlen, targhanp, targhlen, buflen, pathbufp, rlenp); rc = dm_init_attrloc(sid, hanp, hlen, token, locp); rc = dm_init_service(versionstrpp); rc = dm_make_handle(&fsid, &ino, &igen, hanpp, hlenp); rc = dm_make_fshandle(&fsid, hanpp, hlenp); rc = dm_mkdir_by_handle(sid, dirhanp, dirhlen, token, hanp, hlen, cname); rc = dm_move_event(sid, token, targetsid, rtokenp); rc = dm_obj_ref_hold(sid, token, hanp, hlen); rc = dm_obj_ref_query(sid, token, hanp, hlen); rc = dm_obj_ref_rele(sid, token, hanp, hlen); rc = dm_path_to_fshandle(path, hanpp, hlenp); rc = dm_path_to_handle(path, hanpp, hlenp); rc = dm_pending(sid, token, delay); rc = dm_probe_hole(sid, hanp, hlen, token, off, len, roffp, dmrlenp); rc = dm_punch_hole(sid, hanp, hlen, token, off, len); rc = dm_query_right(sid, hanp, hlen, token, rightp); rc = dm_query_session(sid, buflen, bufp, rlenp); ssrc = dm_read_invis(sid, hanp, hlen, token, off, len, bufp); rc = dm_release_right(sid, hanp, hlen, token); rc = dm_remove_dmattr(sid, hanp, hlen, token, setdtime, attrnamep); rc = dm_request_right(sid, hanp, hlen, token, uflags, right); rc = dm_respond_event(sid, token, response, reterror, buflen, respbufp); rc = dm_send_msg(sid, msgtype, buflen, bufp); rc = dm_set_disp(sid, hanp, hlen, token, eventsetp, maxevent); rc = dm_set_dmattr(sid, hanp, hlen, token, attrnamep, setdtime, buflen, bufp); rc = dm_set_eventlist(sid, hanp, hlen, token, eventsetp, maxevent); rc = dm_set_fileattr(sid, hanp, hlen, token, mask, attrp); rc = dm_set_inherit(sid, hanp, hlen, token, attrnamep, mode); rc = dm_set_region(sid, hanp, hlen, token, nelem, regbufp, exactflagp); rc = dm_set_return_on_destroy(sid, hanp, hlen, token, attrnamep, enable); rc = dm_symlink_by_handle(sid, dirhanp, dirhlen, token, hanp, hlen, cname, path); rc = dm_sync_by_handle(sid, hanp, hlen, token); rc = dm_upgrade_right(sid, hanp, hlen, token); ssrc = dm_write_invis(sid, hanp, hlen, flags, token, off, len, bufp); exit(0); }
/* migrate one file */ static int hsm_migrate(const char *path) { int ret; void *hanp = NULL; size_t hlen = 0; dm_attrname_t attrname; uint8_t buf[0x1000]; size_t rlen; struct stat st; struct hsm_attr h; dm_region_t region; dm_boolean_t exactFlag; off_t ofs; int retval = 1; struct hsm_store_handle *handle; dmapi.token = DM_NO_TOKEN; ret = dm_path_to_handle(discard_const(path), &hanp, &hlen); if (ret != 0) { printf("dm_path_to_handle failed for %s - %s\n", path, strerror(errno)); exit(1); } /* we create a user event which we use to gain exclusive rights on the file */ ret = dm_create_userevent(dmapi.sid, 0, NULL, &dmapi.token); if (ret != 0) { printf("dm_create_userevent failed for %s - %s\n", path, strerror(errno)); exit(1); } /* getting an exclusive right first guarantees that two migrate commands don't happen at the same time on the same file, and also guarantees that a recall isn't happening at the same time. We then downgrade to a shared right immediately, which still gives the same guarantee, but means that any reads on the file can proceeed while we are saving away the data during the migrate */ ret = dm_request_right(dmapi.sid, hanp, hlen, dmapi.token, DM_RR_WAIT, DM_RIGHT_EXCL); if (ret != 0) { printf("dm_request_right failed for %s - %s\n", path, strerror(errno)); goto respond; } /* now downgrade the right - reads on the file can then proceed during the expensive migration step */ ret = dm_downgrade_right(dmapi.sid, hanp, hlen, dmapi.token); if (ret != 0) { printf("dm_downgrade_right failed for %s - %s\n", path, strerror(errno)); goto respond; } memset(attrname.an_chars, 0, DM_ATTR_NAME_SIZE); strncpy((char*)attrname.an_chars, HSM_ATTRNAME, DM_ATTR_NAME_SIZE); /* get any existing attribute on the file */ ret = dm_get_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname, sizeof(h), &h, &rlen); if (ret != 0 && errno != ENOENT) { printf("dm_get_dmattr failed for %s - %s\n", path, strerror(errno)); goto respond; } /* check it is valid */ if (ret == 0) { if (strncmp(h.magic, HSM_MAGIC, sizeof(h.magic)) != 0) { printf("Bad magic '%*.*s'\n", (int)sizeof(h.magic), (int)sizeof(h.magic), h.magic); exit(1); } if (h.state == HSM_STATE_START) { /* a migration has died on this file */ printf("Continuing migration of partly migrated file\n"); hsm_store_remove(store_ctx, h.device, h.inode); } else { /* it is either fully migrated, or waiting recall */ printf("Not migrating already migrated file %s\n", path); goto respond; } } if (lstat(path, &st) != 0) { printf("failed to stat %s - %s\n", path, strerror(errno)); goto respond; } if (!S_ISREG(st.st_mode)) { printf("Not migrating non-regular file %s\n", path); goto respond; } if (st.st_size == 0) { printf("Not migrating file '%s' of size 0\n", path); goto respond; } /* open up the store file */ handle = hsm_store_open(store_ctx, st.st_dev, st.st_ino, false); if (handle == NULL) { printf("Failed to open store file for %s - %s\n", path, strerror(errno)); goto respond; } /* read the file data and store it away */ ofs = 0; while ((ret = dm_read_invis(dmapi.sid, hanp, hlen, dmapi.token, ofs, sizeof(buf), buf)) > 0) { if (hsm_store_write(handle, buf, ret) != 0) { printf("Failed to write to store for %s - %s\n", path, strerror(errno)); hsm_store_close(handle); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } ofs += ret; } if (ret == -1) { printf("failed dm_read_invis on %s - %s\n", path, strerror(errno)); hsm_store_close(handle); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } hsm_store_close(handle); /* now upgrade to a exclusive right on the file before we change the dmattr and punch holes in the file. */ ret = dm_upgrade_right(dmapi.sid, hanp, hlen, dmapi.token); if (ret != 0) { printf("dm_upgrade_right failed for %s - %s\n", path, strerror(errno)); goto respond; } strncpy(h.magic, HSM_MAGIC, sizeof(h.magic)); h.size = st.st_size; h.migrate_time = time(NULL); h.device = st.st_dev; h.inode = st.st_ino; h.state = HSM_STATE_START; /* mark the file as starting to migrate */ ret = dm_set_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname, 0, sizeof(h), (void*)&h); if (ret == -1) { printf("failed dm_set_dmattr on %s - %s\n", path, strerror(errno)); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } /* mark the whole file as offline, including parts beyond EOF */ region.rg_offset = 0; region.rg_size = 0; /* zero means the whole file */ region.rg_flags = DM_REGION_WRITE | DM_REGION_READ; ret = dm_set_region(dmapi.sid, hanp, hlen, dmapi.token, 1, ®ion, &exactFlag); if (ret == -1) { printf("failed dm_set_region on %s - %s\n", path, strerror(errno)); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } /* this dm_get_dmattr() is not strictly necessary - it is just paranoia */ ret = dm_get_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname, sizeof(h), &h, &rlen); if (ret != 0) { printf("ERROR: Abandoning partial migrate - attribute gone!?\n"); goto respond; } if (h.state != HSM_STATE_START) { printf("ERROR: Abandoning partial migrate - state=%d\n", h.state); goto respond; } ret = dm_punch_hole(dmapi.sid, hanp, hlen, dmapi.token, 0, st.st_size); if (ret == -1) { printf("failed dm_punch_hole on %s - %s\n", path, strerror(errno)); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } h.state = HSM_STATE_MIGRATED; /* mark the file as fully migrated */ ret = dm_set_dmattr(dmapi.sid, hanp, hlen, dmapi.token, &attrname, 0, sizeof(h), (void*)&h); if (ret == -1) { printf("failed dm_set_dmattr on %s - %s\n", path, strerror(errno)); hsm_store_remove(store_ctx, st.st_dev, st.st_ino); goto respond; } printf("Migrated file '%s' of size %d\n", path, (int)st.st_size); retval = 0; respond: /* destroy our userevent */ ret = dm_respond_event(dmapi.sid, dmapi.token, DM_RESP_CONTINUE, 0, 0, NULL); if (ret == -1) { printf("failed dm_respond_event on %s - %s\n", path, strerror(errno)); exit(1); } dmapi.token = DM_NO_TOKEN; dm_handle_free(hanp, hlen); return retval; }
// for a child and manage the supplied event void spawn_child(dm_token_t token, void *hanp, size_t hlen, char *action) { pid_t mypid; pid_t pid; char sidbuf[32]; char tokenbufh[32]; char tokenbufl[32]; dm_attrname_t attrname; dm_attrlist_t bufp[1024]; size_t rlenp; dm_stat_t statp; FILE* mnttab; struct mntent *ent; struct statfs sbuf; dm_ino_t inop; char s[512]; char hname[512]; char *yamssRecallPath="/system/YAMSS_DMRECALL"; char *yamssDMAPIPath="/system/YAMSS_DMERROR"; int fd; int i; int ret; unsigned char c; char extobj[1024]; char inode[32]; time_t rectime, now; struct stat filebuf; // fork a new child pid = fork(); if (pid == 0) { // fork succeeded, we are in the child now mypid=getpid(); // block signals block_signals(mypid); sprintf(sidbuf, "%llx", sid); sprintf(tokenbufh, "%llx", token.high); sprintf(tokenbufl, "%llx", token.low); if (Verbose) { fprintf(stderr, "%d: New child spawn with action=%s, sidbuf=%s, tokenbufh=%s, tokenbufl=%s\n", mypid, action, sidbuf, tokenbufh, tokenbufl); } // green light to mount requests if(!strcmp(action,"MOUNT")) { if (dm_respond_event(sid, token, DM_RESP_CONTINUE, 0, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); exit(1); } if(Verbose) fprintf(stderr,"%d: MOUNT request served\n", mypid); exit(0); } // give error message to write and truncate events // i.e. we don't allow modifications of files on tape if(strcmp(action,"READ")) { // tell client that writing is not permitted if (dm_respond_event(sid, token, DM_RESP_ABORT, EPERM, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); exit(1); } if(Verbose) fprintf(stderr,"%d: %s event rejected with EPERM\n", mypid, action); exit(0); } // get file inode number ret = dm_handle_to_ino(hanp, hlen, &inop); if(ret==-1) { fprintf(stderr,"%d: dm_handle_to_ino: failed, %s\n", mypid, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } // get dmapi extended attribute with tsm external object id memset((void *)&attrname.an_chars[0], 0, DM_ATTR_NAME_SIZE); memcpy((void *)&attrname.an_chars[0], "IBMObj", 6); ret = dm_get_dmattr(sid, hanp, hlen, DM_NO_TOKEN, &attrname, sizeof(bufp), bufp, &rlenp); if(ret==-1&&errno!=ENOENT) { fprintf(stderr,"%d: dm_get_dmattr: failed, %s\n", mypid, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } else if(ret==-1) { // get file attributes structure ret=dm_get_fileattr(sid,hanp,hlen,DM_NO_TOKEN,DM_AT_STAT,&statp); if(ret==-1) { fprintf(stderr,"%d: dm_get_fileattr: failed, %s\n", mypid, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } // IBMObj is not there, double-check if number of blocks on disk is OK if(statp.dt_blocks>=(statp.dt_size/statp.dt_blksize)) { // File has been recalled if (dm_respond_event(sid, token, DM_RESP_CONTINUE, 0, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } printf("%d: %s event for inode %llu on mount point %s served correctly (file was found to be already on disk)\n", mypid, action, inop, fsname); exit(0); } } // get file attributes structure ret=dm_get_fileattr(sid,hanp,hlen,DM_NO_TOKEN,DM_AT_STAT,&statp); if(ret==-1) { fprintf(stderr,"%d: dm_get_fileattr: failed, %s\n", mypid, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } // determine mount point for the requested file mnttab = fopen("/etc/mtab", "r"); ent=getmntent(mnttab); while(ent) { if(!statfs(ent->mnt_dir, &sbuf)) { if(statp.dt_dev==*(int*)&sbuf.f_fsid) { break; } } ent = getmntent(mnttab); } fclose(mnttab); if(!ent) { fprintf(stderr,"%d: cannot determine mountpoint\n", mypid); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } printf("%d: serving %s event for file on mount point %s with inode number %llu and external object id ", mypid, action, ent->mnt_dir, inop); for(i=0;i<EXTOBJID_LEN;i++) { c=((unsigned char*)bufp)[i]; sprintf(extobj+i*2,"%02X",c); } *(extobj+i*2)=0; printf("%s\n",extobj); // get host name if(gethostname(hname,512)) { // this should never happen... but don't need to fail fprintf(stderr,"%d: cannot get hostname. Setting to dummy\n", mypid); sprintf(hname,"dummy"); } // generate temporary file with unique name containing the external object id of the file to be recalled sprintf(s,"%s%s/%s.%d.XXXXXXXX",ent->mnt_dir,yamssRecallPath,hname,mypid); if((fd=mkstemp(s))<0) { fprintf(stderr,"%d: cannot generate temporary file %s\n",mypid, s); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } // write external object id, mount point and inode number into temporary file sprintf(inode,"%llu",inop); if(write(fd,extobj,strlen(extobj))<0 || write(fd," ",1)<0 || write(fd,ent->mnt_dir,strlen(ent->mnt_dir))<0 || write(fd," ",1)<0 || write(fd,inode,strlen(inode))<0 || write(fd,"\n",1)<0) { fprintf(stderr,"%d: cannot write into temporary file %s, %d/%s\n",mypid, s,errno,strerror(errno)); close(fd); if(unlink(s)<0) { fprintf(stderr,"%d: cannot unlink temporary file %s, %d/%s\n",mypid, s, errno,strerror(errno)); } // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } close(fd); // save start time rectime=time(NULL); // Poll until file is on disk while(1) { // get file attributes structure ret=dm_get_fileattr(sid,hanp,hlen,DM_NO_TOKEN,DM_AT_STAT,&statp); if(ret==-1) { fprintf(stderr,"%d: dm_get_fileattr: failed, %s\n", mypid, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } if(Verbose&&statp.dt_blocks!=0) { fprintf(stderr,"%d: recalling inode %s dt_blocks %llu dt_size %lld dt_blksize %u\n", mypid, inode, statp.dt_blocks, statp.dt_size, statp.dt_blksize); } // check if IBMObj is there memset((void *)&attrname.an_chars[0], 0, DM_ATTR_NAME_SIZE); memcpy((void *)&attrname.an_chars[0], "IBMObj", 6); ret = dm_get_dmattr(sid, hanp, hlen, DM_NO_TOKEN, &attrname, sizeof(bufp), bufp, &rlenp); if(ret==-1&&errno!=ENOENT) { // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); fprintf(stderr,"%d: dm_get_dmattr: failed, %s\n", mypid, strerror(errno)); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } else if(ret==-1) { if(Verbose) { fprintf(stderr,"%d: IBMObj has been removed for inode %s\n", mypid, inode); } } // check if number of blocks on disk is OK and if IBMObj has been removed if(statp.dt_blocks>=(statp.dt_size/statp.dt_blksize)&&ret==-1&&errno==ENOENT) { // File has been recalled if (dm_respond_event(sid, token, DM_RESP_CONTINUE, 0, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); // if filesystem is not mounted don't reply with error // it might be a normal mmshutdown and event will be taken over if(!filesystem_is_mounted()) exit(1); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } printf("%d: %s event for inode %llu on mount point %s served correctly\n", mypid, action, inop, ent->mnt_dir); exit(0); } sleep(RECALL_CHECK_SLEEP_TIME); // check if an error flag file has been raised sprintf(s,"%s%s/%s",ent->mnt_dir,yamssDMAPIPath,inode); if(!stat(s, &filebuf) && filebuf.st_ctime>rectime) { fprintf(stderr,"%d: error flag found - cannot recall inode %s on disk\n", mypid, inode); // respond EIO in this case to differentiate with EBUSY generic errors if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } // check if recall timeout expired now=time(NULL); if((now-rectime)>RECALL_TIMEOUT) { fprintf(stderr,"%d: timed out - cannot recall inode %s on disk after %d seconds\n", mypid, inode, RECALL_TIMEOUT); if (dm_respond_event(sid, token, DM_RESP_ABORT, ETIMEDOUT, 0, NULL)) { fprintf(stderr, "%d: dm_respond_event failed, %d/%s\n", mypid, errno, strerror(errno)); } exit(1); } } } // fork failed if (pid < 0) { fprintf(stderr,"Can't fork child\n"); if (dm_respond_event(sid, token, DM_RESP_ABORT, EBUSY, 0, NULL)) { fprintf(stderr, "dm_respond_event failed, %d/%s\n", errno, strerror(errno)); } return; } // only the father can reach here, increase child counter child_proc_count++; return; }