The attached file is a c program I have written, and am still working on, that first searches all filesystems on a windows host, then queries TSM for the filesets and then the files backed up for that host, then removes all files in the TSM list from the local list. Finally the program emails the list (really huge) to an admin.
I'm quite sure there are bugs and there are also enhancements I want to make. I'm putting this out now so people can start using it. Mike Eggleston
static char *rcsid = "$Id$"; /* * $Log$ */ /* generate a list of all files on the server * accept a list of all files in the TSM library * compare the two lists of files * output the differences... files on the server not in the library */ #include <stdio.h> #include <io.h> #include <string.h> #include <direct.h> #include <windows.h> /* global variables */ int smtp; /* send a message to a socket */ void msg(char *s) { (void) send(smtp, s, strlen(s), 0); (void) send(smtp, "\r\n", 2, 0); } /* simple error routing */ void err(char *msg) { (void) fprintf(stderr, "dsmcmp: %s\n", msg); (void) exit(1); } /* comparison function for qsort */ int linesCompare(const void *a, const void *b) { return strcmp(*((char **) a), *((char **) b)); } /* get a list of files from the library */ char **getTSMFiles(int *n) { char cmd[1024], fn[1024], path[1024], *p; int nlines, i; char **lines; char *host; FILE *fp; /* get a temporary filename */ (void) strcpy(fn, tmpnam((char *) NULL)); (void) unlink(fn); /* execute dsmc to get a list of filesets in TSM */ if(_chdrive(3)) { err("trying to find dsmc: unable to change to C: drive"); } if(chdir("/program files/tivoli/tsm/baclient")) { err("unable to cd to \\program files\\tivoli\\tsm\\baclient"); } if((host = getenv("COMPUTERNAME")) == (char *) NULL) { err("unable to read environment variable COMPUTERNAME"); } (void) sprintf(cmd, "dsmc.exe query files -virtualnodename=%s -password=%s", host, host); if((fp = _popen(cmd, "r")) == (FILE *) NULL) { (void) sprintf(path, "unable to execute '%s'", cmd); err(path); } while(fgets(path, sizeof(path) - 1, fp)) { if(strchr(path, '\n')) { *(strchr(path, '\n')) = '\0'; } msg(path); /* parse out the fileset name */ if(!strchr(path, '\\')) { continue; } (void) strcpy(path, strchr(path, '\\')); if(strchr(path, '\n')) { *(strchr(path, '\n')) = '\0'; } /* for each fileset, get a list of files in tsm */ (void) sprintf(cmd, "dsmc.exe query backup %s\\ -virtualnodename=%s -password=%s -su=yes -filesonly >> %s", path, host, host, fn); (void) system(cmd); } (void) fclose(fp); /* open the temporary file of TSM files */ if((fp = fopen(fn, "r")) == (FILE *) NULL) { err("unable to read temporary file of TSM files"); } /* how many files found? */ nlines = 0; while(fgets(path, sizeof(path) - 1, fp)) { if(strchr(path, '\\')) { nlines++; } } /* read the lines into memory */ (void) fseek(fp, 0, SEEK_SET); /* rewind to beginning of file */ if((lines = (char **) malloc(sizeof(char*) * nlines)) == (char **) NULL) { err("unable to allocate memory for local files"); } i = 0; while(fgets(path, sizeof(path) - 1, fp)) { if(!strchr(path, '\\')) { /* if the line does not have a '\', skip it */ continue; } if(!strstr(path, host)) { /* if the line does not have the hostname, skip it */ continue; } (void) strcpy(path, strchr(path, '\\')); /* remove all but the filepath */ if((p = strchr(path, '$')) != (char *) NULL) { *p = ':'; (void) strcpy(path, p - 1); } if(strchr(path, '\n')) { /* remove the newline */ *(strchr(path, '\n')) = '\0'; } lines[i++] = strdup(path); } (void) fclose(fp); nlines = i; /* sort the lines */ qsort(lines, nlines, sizeof(char *), linesCompare); /* remove the temporary file */ (void) unlink(fn); *n = nlines; return (char **) lines; } /* get a list of all local files */ void findFiles(FILE *fp, char drive, char *fn) { HANDLE h; WIN32_FIND_DATA finddata; char dir[1024]; (void) strcpy(dir, fn); (void) strcat(dir, "\\*.*"); h = FindFirstFile(dir, &finddata); if(h == INVALID_HANDLE_VALUE) { (void) printf("error %d\n", GetLastError()); } do { if(!strcmp(finddata.cFileName, ".") || !strcmp(finddata.cFileName, "..")) { continue; } if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { char path[1024]; (void) strcpy(path, dir); if(strchr(path, '*')) { *(strchr(path, '*')) = '\0'; } (void) strcat(path, finddata.cFileName); findFiles(fp, drive, path); } else { char path[1024]; (void) strcpy(path, dir); if(strchr(path, '*')) { *(strchr(path, '*')) = '\0'; } (void) strcat(path, finddata.cFileName); (void) fprintf(fp, "%c:%s\n", drive, path); } } while(FindNextFile(h, &finddata)); FindClose(h); } /* return a list of all local files */ char **getLocalFiles(int *n) { FILE *fp; int i, nlines; char path[1024], fn[1024]; char **lines; (void) strcpy(fn, tmpnam((char *) NULL)); if((fp = fopen(fn, "w+")) == (FILE *) NULL) { err("unable to create temporary file for local files"); } for(i = 3; i < 27; i++) { if(_chdrive(i)) { continue; } *path = '\0'; findFiles(fp, (char) ('a' + i - 1), path); } /* how many files found? */ (void) fseek(fp, 0, SEEK_SET); /* rewind to beginning of file */ nlines = 0; while(fgets(path, sizeof(path) - 1, fp)) { nlines++; } /* read the lines into memory */ (void) fseek(fp, 0, SEEK_SET); /* rewind to beginning of file */ if((lines = (char **) malloc(sizeof(char*) * nlines)) == (char **) NULL) { err("unable to allocate memory for local files"); } i = 0; while(fgets(path, sizeof(path) - 1, fp)) { if(strchr(path, '\n')) { *(strchr(path, '\n')) = '\0'; } lines[i++] = strdup(path); } (void) fclose(fp); /* sort the lines */ qsort(lines, nlines, sizeof(char *), linesCompare); /* remove the temporary file */ (void) unlink(fn); *n = nlines; return (char **) lines; } /* parse the dsm.opt file */ void parseDSMFile(char *fn) { } /* compare the TSM list and local list */ /* initially I'm using a brute force algorithm, this could be a *lot* nicer */ void compareLists(char **lfiles, int nlfiles, char **rfiles, int nrfiles) { int i, j, nfound; char buf[1024]; nfound = 0; for(i = 0; i < nlfiles; i++) { for(j = 0; j < nrfiles; j++) { if(lfiles[i] && !strcmp(lfiles[i], rfiles[j])) { (void) free(lfiles[i]); lfiles[i] = (char *) NULL; nfound++; break; } } } /* statistics */ msg(""); msg("File statistics:"); (void) sprintf(buf, "\t Found: %20d", nfound); msg(buf); (void) sprintf(buf, "\tNot Found: %20d", nlfiles - nfound); msg(buf); /* files */ msg("\nLocal files not existing in TSM library:"); for(i = 0; i < nlfiles; i++) { if(lfiles[i]) { msg(lfiles[i]); } } } int main(int argc, char **argv) { char **lfiles, **rfiles, buf[1024]; int nlfiles, nrfiles; WORD versionRequested; WSADATA wsadata; char *host = argv[1]; int port = 25; int s; SOCKADDR_IN sin; LPHOSTENT hp; /* connect to a smtp server, close stdout/stderr, reopen them to the smtp server */ versionRequested = MAKEWORD(2, 2); if(WSAStartup(versionRequested, &wsadata)) { err("error starting sockets"); } /* connect to the host */ if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR) { err("invalid socket"); } if((hp = gethostbyname(host)) == (LPHOSTENT) NULL) { err("could not get host entry"); } sin.sin_family = AF_INET; sin.sin_addr = *((LPIN_ADDR)*hp->h_addr_list); sin.sin_port = htons(port); if((connect(s, &sin, sizeof(sin))) == SOCKET_ERROR) { err("unable to connect to server"); } /* convert stdout/stderr to the socket */ smtp = s; /* tell the smtp server whom to send to */ (void) sprintf(buf, "HELO %s", getenv("COMPUTERNAME")); msg(buf); (void) _sleep(3000); (void) sprintf(buf, "mail from: [EMAIL PROTECTED]", getenv("COMPUTERNAME")); msg(buf); (void) _sleep(3000); msg("rcpt to: [EMAIL PROTECTED]"); (void) _sleep(3000); msg("data"); (void) _sleep(3000); (void) sprintf(buf, "Subject: Local files not in TSM on server %s\n\n", getenv("COMPUTERNAME")); msg(buf); if(_chdrive(3)) { err("trying to find dsmc: unable to change to C: drive\n"); } if(chdir("/")) { err("unable to cd to \\\n"); } lfiles = getLocalFiles(&nlfiles); rfiles = getTSMFiles(&nrfiles); compareLists(lfiles, nlfiles, rfiles, nrfiles); /* stop sending the email */ msg("."); (void) _sleep(3); msg("quit"); (void) _sleep(3); /* close sockets */ closesocket(s); (void) WSACleanup(); return 0; }