#include #include #include #include #include #include #include #include #include using namespace std; struct DATES{ string start,end; DATES(const char *_start, const char *_end){ start = _start; end = _end; } bool operator < (const DATES &d) const { return start < d.start; } }; /* Read a story file. When diskonly is used, it keeps only entries related to disk. It also trims the logical disk name (sda, sdb) and also the firmware revision to make sure it ends with unique keys. */ static int logstory_readstory (const char *fname, map > &items, bool diskonly) { glocal bool diskonly = diskonly; glocal map > *items = &items; (fname,true); // Log file for a server have 3 columns per line // type:id date-start date-end char tmp[strlen(line)+1]; strcpy (tmp,line); char *tb[10]; char *pt = tmp; int no = 0; while (no < 10 && *pt != '\0'){ if (*pt > ' '){ tb[no++] = pt; while (*pt > ' ') pt++; }else if (isspace(*pt)){ *pt++ = '\0'; }else{ break; } } if (no != 3){ tlmp_error ("Invalid line #%d in file %s: %s\n" ,noline,info.filename,line); }else{ const char *item = tb[0]; const char *start = tb[1]; const char *end = tb[2]; if (glocal.diskonly){ SSTRINGS parts; int n = str_splitline (item,'/',parts); const char *part0 = parts.getitem(0)->c_str(); if (strcmp(part0,"disk")==0){ SSTRING tmp(part0); for (int i=2; ic_str()); } debug_printf ("diskonly :%s: %s %s\n",tmp.c_str(),start,end); (*glocal.items)[tmp.c_str()].push_back(DATES(start,end)); } }else{ (*glocal.items)[item].push_back(DATES(start,end)); } } return 0; return 0; } /* Tell if an item is in used. It must have a end date == "-". */ static bool logstory_is_inuse(vector &v) { bool ret = false; for (vector::iterator p=v.begin(); p != v.end(); p++){ const char *end = p->end.c_str(); if (strcmp(end,"-")==0){ ret = true; break; } } return ret; } int main (int argc, char *argv[]) { glocal int ret = -1; glocal bool unused = false; glocal const char *deadstuff = "/var/log/logstory/deadstuff.file"; glocal.ret = (argc,argv); setproginfo ("logstory",VERSION ,"Manage server story files\n" "\n" "logstory file.story file.scan >file.story.out\n" "ssh server logstory-scan | logstory file.story - >file.story.out\n"); setarg (' ',"deadstuff","Story file for defective hardware",glocal.deadstuff,false); setarg (' ',"unused","Find stuff not used any more on any server",glocal.unused,false); int ret = -1; if (glocal.unused){ /* We read all the story files. We end up with a list of keys. Each key with an open period is still in use. The other are back in the inventory. */ map > items; for (int i=0; i >::iterator it = items.begin(); it != items.end(); it++){ if (!logstory_is_inuse(it->second)){ printf ("%s\n",it->first.c_str()); } } ret = 0; }else if (argc != 2){ usage(); }else{ glocal map > items; glocal set seen; // Which items were seen in the second file logstory_readstory (argv[0],glocal.items,false); (argv[1],true); if (strlen(line)>0){ glocal.seen.insert(line); } return 0; time_t now = time(NULL); struct tm *t = localtime(&now); char datenow[11]; snprintf (datenow,sizeof(datenow),"%04d/%02d/%02d",t->tm_year+1900,t->tm_mon+1,t->tm_mday); // We must add the new item found in the second file, but not in the first for (set::iterator it=glocal.seen.begin(); it != glocal.seen.end(); it++){ map >::iterator p = glocal.items.find(*it); if (p == glocal.items.end()){ // New item, we add it with a start date as today glocal.items[*it].push_back(DATES(datenow,"-")); }else{ // This item is known to this server. But maybe the item used to be there // then was removed and now is being re-injected. // We test this situation by making sure the item has an open end date if (!logstory_is_inuse(p->second)){ p->second.push_back(DATES(datenow,"-")); } } } // We print back the file, but with "end" the ownership of items that we not referenced in the second file // If they were not in the second file, they are not in the server anymore. for (map >::iterator it = glocal.items.begin(); it != glocal.items.end(); it++){ bool closeit = false; if (glocal.seen.count(it->first)==0){ // This item is not in the server anymore debug_printf ("We must end item %s\n",it->first.c_str()); closeit = true; } sort (it->second.begin(),it->second.end()); for (vector::iterator p=it->second.begin(); p != it->second.end(); p++){ const char *end = p->end.c_str(); if (strcmp(end,"-")==0 && closeit) end = datenow; printf ("%s %s %s\n",it->first.c_str(),p->start.c_str(),end); } } ret = 0; } return ret; return glocal.ret; }