| /* |
| * Copyright (c) 2002 Silicon Graphics, Inc. |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include <xfs/xfs.h> |
| #include <xfs/jdm.h> |
| #include <ncurses.h> |
| #include <sys/mman.h> |
| #include <sys/stat.h> |
| |
| #include "types.h" |
| #include "mlog.h" |
| #include "inv_priv.h" |
| #include "getopt.h" |
| |
| #include "invutil.h" |
| #include "timeutil.h" |
| #include "cmenu.h" |
| #include "list.h" |
| #include "stobj.h" |
| |
| stobj_fileinfo_t *stobj_file; |
| int stobj_numfiles; |
| |
| menu_ops_t stobjsess_ops = { |
| NULL, |
| stobj_undelete, |
| NULL, |
| stobj_select, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| stobjsess_highlight, |
| menu_unhighlight, |
| stobjsess_commit, |
| stobj_prune, |
| }; |
| |
| menu_ops_t stobjstrm_ops = { |
| stobjstrm_delete, |
| stobj_undelete, |
| NULL, |
| stobj_select, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| stobjstrm_highlight, |
| menu_unhighlight, |
| stobjstrm_commit, |
| NULL, |
| }; |
| |
| menu_ops_t stobjmed_ops = { |
| stobjmed_delete, |
| NULL, |
| NULL, |
| stobj_select, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| stobjmed_highlight, |
| menu_unhighlight, |
| stobjmed_commit, |
| NULL, |
| }; |
| |
| /*ARGSUSED*/ |
| int |
| stobjmed_commit(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| return stobjstrm_commit(win, d->parent, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjstrm_commit(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| return stobjsess_commit(win, d->parent, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjmed_delete(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| return stobjstrm_delete(win, d->parent, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjstrm_delete(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| return menu_delete(win, d->parent, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjsess_commit(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| invt_seshdr_t *stobjhdr; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| stobjhdr = ((stobjsess_t *)(stobj_file[d->file_idx].data[d->data_idx]))->header; |
| |
| mark_all_children_commited(current); |
| |
| if(d->deleted == BOOL_TRUE) { |
| stobjhdr->sh_pruned = 1; |
| } |
| else { |
| stobjhdr->sh_pruned = 0; |
| } |
| |
| return 0; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjsess_highlight(WINDOW *win, node_t *current, node_t *list) |
| { |
| static char txt[256]; |
| char uuidstr[UUID_STR_LEN + 1]; |
| data_t *d; |
| invt_seshdr_t *stobjhdr; |
| invt_session_t *stobjses; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| stobjhdr = ((stobjsess_t *)(stobj_file[d->file_idx].data[d->data_idx]))->header; |
| stobjses = ((stobjsess_t *)(stobj_file[d->file_idx].data[d->data_idx]))->session; |
| |
| wclear(infowin); |
| |
| put_info_header("session entry"); |
| |
| snprintf(txt, sizeof(txt), "pruned: %s, flags: %#x, time: %s", |
| (stobjhdr->sh_pruned == BOOL_TRUE) ? "yes" : "no", |
| stobjhdr->sh_flag, |
| ctime32(&(stobjhdr->sh_time))); |
| txt[strlen(txt)-1] = '\0'; |
| put_info_line(1, txt); |
| |
| uuid_unparse(stobjses->s_fsid, uuidstr); |
| snprintf(txt, sizeof(txt), "mountpt: %s, fsid: %s", stobjses->s_mountpt, uuidstr); |
| put_info_line(2, txt); |
| |
| uuid_unparse(stobjses->s_sesid, uuidstr); |
| snprintf(txt, sizeof(txt), "device: %s, sesid: %s", stobjses->s_devpath, uuidstr); |
| put_info_line(3, txt); |
| |
| return FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjstrm_highlight(WINDOW *win, node_t *current, node_t *list) |
| { |
| static char txt[256]; |
| data_t *d; |
| invt_stream_t *stobjstrm; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| stobjstrm = (invt_stream_t *)(stobj_file[d->file_idx].data[d->data_idx]); |
| |
| wclear(infowin); |
| |
| put_info_header("session stream"); |
| |
| snprintf(txt, sizeof(txt), "interrupted: %s, cmdarg: %s", |
| (stobjstrm->st_interrupted == BOOL_TRUE) ? "yes" : "no", |
| stobjstrm->st_cmdarg); |
| put_info_line(1, txt); |
| |
| snprintf(txt, sizeof(txt), "start ino: %llu, offset %lld", |
| (unsigned long long) stobjstrm->st_startino.ino, |
| (long long) stobjstrm->st_startino.offset); |
| put_info_line(2, txt); |
| |
| snprintf(txt, sizeof(txt), " end ino: %llu, offset %lld", |
| (unsigned long long) stobjstrm->st_endino.ino, |
| (long long) stobjstrm->st_endino.offset); |
| put_info_line(3, txt); |
| |
| return FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobjmed_highlight(WINDOW *win, node_t *current, node_t *list) |
| { |
| static char txt[256]; |
| char uuidstr[UUID_STR_LEN + 1]; |
| data_t *d; |
| invt_mediafile_t *stobjmed; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| stobjmed = (invt_mediafile_t *)(stobj_file[d->file_idx].data[d->data_idx]); |
| |
| wclear(infowin); |
| |
| put_info_header("session media file"); |
| |
| uuid_unparse(stobjmed->mf_moid, uuidstr); |
| snprintf(txt, sizeof(txt), "flags: %#x, id: %s", stobjmed->mf_flag, uuidstr); |
| put_info_line(1, txt); |
| |
| snprintf(txt, sizeof(txt), "start ino: %llu, offset %lld", |
| (unsigned long long) stobjmed->mf_startino.ino, |
| (long long) stobjmed->mf_startino.offset); |
| put_info_line(2, txt); |
| |
| snprintf(txt, sizeof(txt), " end ino: %llu, offset %lld", |
| (unsigned long long) stobjmed->mf_endino.ino, |
| (long long) stobjmed->mf_endino.offset); |
| put_info_line(3, txt); |
| |
| return FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobj_select(WINDOW *win, node_t *current, node_t *list) |
| { |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return 0; |
| } |
| d = (data_t *)(current->data); |
| |
| if(d->expanded == TRUE) { |
| return menu_collapse(win, current, list); |
| } |
| |
| return menu_expand(win, current, list); |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobj_prune(char *mountpt, uuid_t *uuidp, time32_t prunetime, node_t *node, node_t *list) |
| { |
| data_t *d; |
| stobjsess_t *stobj; |
| invt_seshdr_t *stobj_header; |
| invt_session_t *stobj_session; |
| |
| if(node == NULL || node->data == NULL) { |
| return BOOL_FALSE; |
| } |
| d = (data_t *)(node->data); |
| stobj = stobj_file[d->file_idx].data[d->data_idx]; |
| stobj_header = stobj->header; |
| stobj_session = stobj->session; |
| |
| if(stobj_header == NULL || stobj_session == NULL) { |
| return BOOL_FALSE; |
| } |
| if(stobj_header->sh_pruned) { |
| return BOOL_TRUE; |
| } |
| if(stobj_header->sh_time < prunetime) { |
| if(mountpt != NULL && mntpnt_equal(mountpt, stobj_session->s_mountpt)) { |
| return BOOL_TRUE; |
| } |
| if((!uuid_is_null(*uuidp)) |
| && (uuid_compare(*uuidp, stobj_session->s_fsid) == 0)) { |
| return BOOL_TRUE; |
| } |
| } |
| |
| return BOOL_FALSE; |
| } |
| |
| /*ARGSUSED*/ |
| int |
| stobj_undelete(WINDOW *win, node_t *current, node_t *list) |
| { |
| node_t *n; |
| data_t *d; |
| |
| if(current == NULL || current->data == NULL) { |
| return BOOL_FALSE; |
| } |
| |
| list_undelete(current, list); |
| |
| d = ((data_t *)(current->data)); |
| n = current->next; |
| while(n != NULL && n->data != NULL && ((data_t *)(n->data))->level > d->level) { |
| ((data_t *)(n->data))->deleted = BOOL_FALSE; |
| ((data_t *)(n->data))->text[0] = ' '; |
| n = n->next; |
| } |
| |
| redraw_screen = BOOL_TRUE; |
| |
| return BOOL_FALSE; |
| } |
| |
| int |
| add_stobj_data(int fidx, void *data) |
| { |
| if(stobj_file[fidx].numrecords == 0) { |
| stobj_file[fidx].data = malloc(sizeof(*stobj_file[fidx].data)); |
| if(stobj_file[fidx].data == NULL) { |
| fprintf(stderr, "%s: internal memory error: stobj data allocation\n", |
| g_programName); |
| exit(1); |
| } |
| } |
| else { |
| stobj_file[fidx].data = realloc(stobj_file[fidx].data, |
| sizeof(*stobj_file[fidx].data) |
| * (stobj_file[fidx].numrecords + 1)); |
| if(stobj_file[fidx].data == NULL) { |
| fprintf(stderr, "%s: internal memory error: stobj data reallocation\n", |
| g_programName); |
| exit(1); |
| } |
| } |
| stobj_file[fidx].data[stobj_file[fidx].numrecords] = data; |
| stobj_file[fidx].numrecords++; |
| |
| return 0; |
| } |
| |
| node_t * |
| generate_stobj_menu(node_t *startnode, int level, char *StObjFileName) |
| { |
| int i; |
| int j; |
| int k; |
| int idx; |
| int data_idx; |
| int len; |
| char *txt; |
| node_t *n; |
| node_t *parent_stream; |
| node_t *parent_session; |
| |
| stobjsess_t *session; |
| invt_seshdr_t *StObjhdr; |
| invt_session_t *StObjses; |
| invt_stream_t *StObjstrm; |
| invt_mediafile_t *StObjmed; |
| |
| if((idx = open_stobj(StObjFileName)) < 0) { |
| return startnode; |
| } |
| |
| StObjhdr = (invt_seshdr_t *)( stobj_file[idx].mapaddr + sizeof(invt_sescounter_t)); |
| StObjses = (invt_session_t *)(stobj_file[idx].mapaddr + StObjhdr->sh_sess_off); |
| |
| data_idx = 0; |
| n = startnode; |
| for (i=0; i < stobj_file[idx].counter->ic_curnum; ) { |
| session = malloc(sizeof(*session)); |
| if(session == NULL) { |
| fprintf(stderr, "%s: internal memory error: session malloc\n", g_programName); |
| exit(1); |
| } |
| session->header = StObjhdr; |
| session->session = StObjses; |
| |
| len = 60+strlen(session->session->s_label); |
| txt = malloc(len); |
| if(txt == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx_text\n", g_programName); |
| exit(1); |
| } |
| snprintf(txt, len, " session level: %d label: %s", |
| session->header->sh_level, |
| session->session->s_label); |
| |
| n = list_add(n, node_create(BOOL_TRUE, /* hidden */ |
| BOOL_FALSE, /* expanded */ |
| level, /* level */ |
| session->header->sh_pruned, /* deleted */ |
| idx, /* file_idx */ |
| txt, /* text */ |
| &(stobjsess_ops), /* menu ops */ |
| startnode, /* parent */ |
| NULL, /* children */ |
| 0, /* nbr_children */ |
| data_idx)); |
| if(n == NULL) { |
| fprintf(stderr, "%s: internal memory error: list_add: node_create: session\n", g_programName); |
| exit(1); |
| } |
| |
| data_idx++; |
| add_stobj_data(idx, session); |
| |
| parent_session = n; |
| for ( j = 0; j < (int) StObjses->s_cur_nstreams; j++ ) { |
| StObjstrm = (invt_stream_t *)(stobj_file[idx].mapaddr + |
| StObjhdr->sh_streams_off + |
| (j * sizeof(invt_stream_t))); |
| |
| len = strlen(StObjstrm->st_cmdarg) + 33; |
| txt = malloc(len); |
| if(txt == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx_text\n", g_programName); |
| exit(1); |
| } |
| snprintf(txt, len, " stream: drive path: %s", StObjstrm->st_cmdarg); |
| |
| n = list_add(n, node_create(BOOL_TRUE, /* hidden */ |
| BOOL_FALSE, /* expanded */ |
| level + 1, /* level */ |
| session->header->sh_pruned, /* deleted */ |
| idx, /* file_idx */ |
| txt, /* text */ |
| &(stobjstrm_ops), /* menu ops */ |
| parent_session, /* parent */ |
| NULL, /* children */ |
| 0, /* nbr_children */ |
| data_idx)); |
| if(n == NULL) { |
| fprintf(stderr, "%s: internal memory error: list_add: node_create: StObjstrm\n", g_programName); |
| exit(1); |
| } |
| |
| data_idx++; |
| add_stobj_data(idx, StObjstrm); |
| |
| parent_stream = n; |
| for ( k = 0; k < StObjstrm->st_nmediafiles; k++) { |
| StObjmed = (invt_mediafile_t *)(stobj_file[idx].mapaddr + |
| StObjstrm->st_firstmfile + |
| (k * sizeof(invt_mediafile_t))); |
| |
| len = strlen(StObjmed->mf_label) + 26; |
| txt = malloc(len); |
| if(txt == NULL) { |
| fprintf(stderr, "%s: internal memory error: invidx_text\n", g_programName); |
| exit(1); |
| } |
| snprintf(txt, len, " media file: %s", StObjmed->mf_label); |
| |
| n = list_add(n, node_create(BOOL_TRUE, /* hidden */ |
| BOOL_FALSE, /* expanded */ |
| level + 2, /* level */ |
| session->header->sh_pruned, /* deleted */ |
| idx, /* file_idx */ |
| txt, /* text */ |
| &(stobjmed_ops), /* menu ops */ |
| parent_stream, /* parent */ |
| NULL, /* children */ |
| 0, /* nbr_children */ |
| data_idx)); |
| if(n == NULL) { |
| fprintf(stderr, "%s: internal memory error: list_add: node_create: StObjmed\n", g_programName); |
| exit(1); |
| } |
| |
| data_idx++; |
| add_stobj_data(idx, StObjmed); |
| } |
| } |
| |
| i++; |
| |
| StObjhdr = (invt_seshdr_t *)( stobj_file[idx].mapaddr + sizeof(invt_sescounter_t) + |
| (i * sizeof(invt_seshdr_t)) ); |
| StObjses = (invt_session_t *)(stobj_file[idx].mapaddr + StObjhdr->sh_sess_off); |
| } |
| |
| return n; |
| } |
| |
| int |
| add_stobj(char *name, int fd, off_t size, char *mapaddr, invt_sescounter_t *counter) |
| { |
| static int highwatermark = 20; |
| |
| if(stobj_numfiles == 0) { |
| stobj_file = malloc(sizeof(*stobj_file) * highwatermark); |
| if(stobj_file == NULL) { |
| fprintf(stderr, "%s: internal memory error: malloc stobj_file\n", g_programName); |
| exit(1); |
| } |
| } |
| else { |
| if(stobj_numfiles >= highwatermark - 1) { |
| highwatermark += highwatermark; |
| |
| stobj_file = realloc(stobj_file, sizeof(*stobj_file) * highwatermark); |
| if(stobj_file == NULL) { |
| fprintf(stderr, "%s: internal memory error: realloc stobj_file\n", g_programName); |
| exit(1); |
| } |
| } |
| } |
| |
| stobj_file[stobj_numfiles].size = size; |
| stobj_file[stobj_numfiles].mapaddr = mapaddr; |
| stobj_file[stobj_numfiles].fd = fd; |
| stobj_file[stobj_numfiles].counter = counter; |
| stobj_file[stobj_numfiles].name = name; |
| stobj_file[stobj_numfiles].data = NULL; |
| stobj_file[stobj_numfiles].numrecords = 0; |
| |
| stobj_numfiles++; |
| |
| return stobj_numfiles - 1; |
| } |
| |
| int |
| open_stobj(char *StObjFileName) |
| { |
| int fd; |
| struct stat sb; |
| off_t size; |
| char *mapaddr; |
| invt_sescounter_t cnt; |
| char *name; |
| |
| errno=0; |
| fd = open_and_lock( StObjFileName, FILE_WRITE, wait_for_locks ); |
| if (fd < 0) { |
| return fd; |
| } |
| |
| name = strdup(StObjFileName); |
| if(name == NULL) { |
| fprintf(stderr, "%s: internal memory error: strdup stobj_name\n", g_programName); |
| exit(1); |
| } |
| |
| read_n_bytes(fd, &cnt, sizeof(invt_sescounter_t), StObjFileName); |
| lseek( fd, 0, SEEK_SET ); |
| errno = 0; |
| if (fstat(fd, &sb) < 0) { |
| fprintf(stderr, "Could not get stat info on %s\n", StObjFileName); |
| perror("fstat"); |
| return -1; |
| } |
| size = sb.st_size; |
| mapaddr = mmap_n_bytes(fd, size, BOOL_FALSE, StObjFileName); |
| |
| return add_stobj(name, fd, size, mapaddr, (invt_sescounter_t *)mapaddr); |
| } |
| |
| int |
| close_stobj_file(int fidx, int unlink_ok) |
| { |
| if(fidx >= stobj_numfiles || stobj_file[fidx].fd < 0) |
| return 0; |
| |
| munmap( stobj_file[fidx].mapaddr, stobj_file[fidx].size); |
| close( stobj_file[fidx].fd ); |
| stobj_file[fidx].fd = -1; |
| |
| if(unlink_ok == BOOL_TRUE) { |
| unlink(stobj_file[fidx].name); |
| } |
| |
| free( stobj_file[fidx].name ); |
| free( stobj_file[fidx].data ); |
| |
| stobj_file[fidx].name = NULL; |
| stobj_file[fidx].data = NULL; |
| |
| return 0; |
| } |
| |
| int |
| close_all_stobj() |
| { |
| int i; |
| int j; |
| invt_seshdr_t *StObjhdr; |
| int unlink_ok; |
| |
| for(i = 0; i < stobj_numfiles; i++) { |
| |
| if(stobj_file[i].fd < 0) |
| continue; |
| |
| unlink_ok = BOOL_TRUE; |
| StObjhdr = (invt_seshdr_t *)( stobj_file[i].mapaddr + sizeof(invt_sescounter_t)); |
| for(j = 0; j < stobj_file[i].counter->ic_curnum; ) { |
| if(StObjhdr->sh_pruned != 1) { |
| unlink_ok = BOOL_FALSE; |
| break; |
| } |
| j++; |
| StObjhdr = (invt_seshdr_t *)( stobj_file[i].mapaddr + sizeof(invt_sescounter_t) + |
| (j * sizeof(invt_seshdr_t)) ); |
| } |
| |
| close_stobj_file(i, unlink_ok); |
| } |
| |
| free(stobj_file); |
| stobj_file = NULL; |
| return 0; |
| } |