吃饱饭继续浏览Manager.c的scanmanager函数,这个函数的功能吧,暂时理解如下。
接收一个命令行参数(经过处理的optstruct结构指针)。
然后根据选项判断文件类型种类,还有一些扫描选项。看到了AC-Only选项,可是没有BM-Only选项,不解。然后就进行了病毒库的加载和引擎的初始化,接着进行了一些扫描限制(扫描文件大小、数量、递归深度等)设定,还有扫描的文件类型(貌似上面的是用来构建引擎,现在的是用来设置扫描)。然后就是重点,针对文件名进行处理,判断是否是目录还是单个文件,调用不同的扫描函数。
代码注释如下:(应该不是完全正确的)
int scanmanager(const struct optstruct *opt) { mode_t fmode; int ret = 0, extunpacker = 0, fmodeint, i, x; unsigned int options = 0, dboptions = 0; struct cl_engine *engine = NULL; struct cl_limits limits; struct passwd *user = NULL; struct stat sb; char *fullpath = NULL, cwd[1024]; //扫描文件类型判断 if(opt_check(opt, "unzip") || opt_check(opt, "unrar") || opt_check(opt, "arj") || opt_check(opt, "unzoo") || opt_check(opt, "jar") || opt_check(opt, "lha") || opt_check(opt, "tar") || opt_check(opt, "tgz") || opt_check(opt, "deb")) extunpacker = 1; //获取CLAMAVUSER的用户信息,识别码和根目录 //参考passwd结构 /* njh@bandsman.co.uk: BeOS */ #if !defined(C_CYGWIN) && !defined(C_OS2) && !defined(C_BEOS) && !defined(C_WINDOWS) if(extunpacker && !geteuid()) { if((user = getpwnam(CLAMAVUSER)) == NULL) { logg("!Can't get information about user "CLAMAVUSER" (required to run external unpackers) "); exit(60); /* this is critical problem, so we just exit here */ } } #endif //添加扫描选项 if(!opt_check(opt, "no-phishing-sigs")) dboptions |= CL_DB_PHISHING; if(!opt_check(opt,"no-phishing-scan-urls")) dboptions |= CL_DB_PHISHING_URLS; if(opt_check(opt,"phishing-ssl")) { options |= CL_SCAN_PHISHING_BLOCKSSL; } if(opt_check(opt,"phishing-cloak")) { options |= CL_SCAN_PHISHING_BLOCKCLOAK; } if(opt_check(opt, "dev-ac-only")) dboptions |= CL_DB_ACONLY; //这个选项需要学习下,深度搜查用AC? if(opt_check(opt, "dev-ac-depth")) cli_ac_setdepth(AC_DEFAULT_MIN_DEPTH, atoi(opt_arg(opt, "dev-ac-depth"))); if(opt_check(opt, "detect-pua")) dboptions |= CL_DB_PUA; //传说中的病毒库加载 if(opt_check(opt, "database")) { if((ret = cl_load(opt_arg(opt, "database"), &engine, &info.sigs, dboptions))) { logg("!%s ", cl_strerror(ret)); return 50; } } else { char *dbdir = freshdbdir(); //病毒库更新后重新加载 if((ret = cl_load(dbdir, &engine, &info.sigs, dboptions))) { logg("!%s ", cl_strerror(ret)); free(dbdir); return 50; } free(dbdir); } if(!engine) { logg("!Can't initialize the virus database "); return 50; } //引擎构建 if((ret = cl_build(engine)) != 0) { logg("!Database initialization error: %s ", cl_strerror(ret));; return 50; } /* set limits */ //开始设置限制,应该是扫描大小等 memset(&limits, 0, sizeof(struct cl_limits)); //最大的扫描大小 if(opt_check(opt, "max-scansize")) { char *cpy, *ptr; ptr = opt_arg(opt, "max-scansize"); if(tolower(ptr[strlen(ptr) - 1]) == 'm') { cpy = calloc(strlen(ptr), 1); strncpy(cpy, ptr, strlen(ptr) - 1); cpy[strlen(ptr)-1]=''; limits.maxscansize = atoi(cpy) * 1024 * 1024; free(cpy); } else limits.maxscansize = atoi(ptr) * 1024; } else limits.maxscansize = 104857600; //最大文件大小 if(opt_check(opt, "max-filesize")) { char *cpy, *ptr; ptr = opt_arg(opt, "max-filesize"); if(tolower(ptr[strlen(ptr) - 1]) == 'm') { cpy = calloc(strlen(ptr), 1); strncpy(cpy, ptr, strlen(ptr) - 1); cpy[strlen(ptr)-1]=''; limits.maxfilesize = atoi(cpy) * 1024 * 1024; free(cpy); } else limits.maxfilesize = atoi(ptr) * 1024; } else limits.maxfilesize = 26214400; //最大文件数 if(opt_check(opt, "max-files")) limits.maxfiles = atoi(opt_arg(opt, "max-files")); else limits.maxfiles = 10000; //最大递归深度 if(opt_check(opt, "max-recursion")) limits.maxreclevel = atoi(opt_arg(opt, "max-recursion")); else limits.maxreclevel = 16; /* set options */ //设置选项,扫描文件类型相关 if(opt_check(opt, "disable-archive") || opt_check(opt, "no-archive")) options &= ~CL_SCAN_ARCHIVE; else options |= CL_SCAN_ARCHIVE; if(opt_check(opt, "detect-broken")) options |= CL_SCAN_BLOCKBROKEN; if(opt_check(opt, "block-encrypted")) options |= CL_SCAN_BLOCKENCRYPTED; if(opt_check(opt, "no-pe")) options &= ~CL_SCAN_PE; else options |= CL_SCAN_PE; if(opt_check(opt, "no-elf")) options &= ~CL_SCAN_ELF; else options |= CL_SCAN_ELF; if(opt_check(opt, "no-ole2")) options &= ~CL_SCAN_OLE2; else options |= CL_SCAN_OLE2; if(opt_check(opt, "no-pdf")) options &= ~CL_SCAN_PDF; else options |= CL_SCAN_PDF; if(opt_check(opt, "no-html")) options &= ~CL_SCAN_HTML; else options |= CL_SCAN_HTML; if(opt_check(opt, "no-mail")) { options &= ~CL_SCAN_MAIL; } else { options |= CL_SCAN_MAIL; if(opt_check(opt, "mail-follow-urls")) options |= CL_SCAN_MAILURL; } if(opt_check(opt, "no-algorithmic")) options &= ~CL_SCAN_ALGORITHMIC; else options |= CL_SCAN_ALGORITHMIC; //Linux下,需要获取设备号 //具体参见文件属性stat结构 #ifdef C_LINUX procdev = (dev_t) 0; if(stat("/proc", &sb) != -1 && !sb.st_size) procdev = sb.st_dev; #endif /* check filetype */ //遇到扫描目录的情况 if(opt->filename == NULL || strlen(opt->filename) == 0) { /* we need full path for some reasons (eg. archive handling) */ //获取当前工作目录 //获取到后调用目录扫描函数scandirs if(!getcwd(cwd, sizeof(cwd))) { logg("!Can't get absolute pathname of current working directory "); ret = 57; } else ret = scandirs(cwd, engine, user, opt, &limits, options); } else if(!strcmp(opt->filename, "-")) { /* read data from stdin */ ret = scanstdin(engine, &limits, options); } else { //扫描文件的情况 char *thefilename; for (x = 0; (thefilename = cli_strtok(opt->filename, x, " ")) != NULL; x++) { //fileinfo函数在clamscan的others.c里定义 //2代表获取文件权限 //有访问权限后找出最右边/的个数 if((fmodeint = fileinfo(thefilename, 2)) == -1) { logg("^Can't access file %s ", thefilename); perror(thefilename); ret = 56; } else { int slash = 1; for(i = strlen(thefilename) - 1; i > 0 && slash; i--) { if(thefilename[i] == '/') thefilename[i] = 0; else slash = 0; } fmode = (mode_t) fmodeint; //下面依旧是处理文件名的 if(extunpacker && (thefilename[0] != '/' && thefilename[0] != '\' && thefilename[1] != ':')) { /* we need to complete the path */ if(!getcwd(cwd, sizeof(cwd))) { logg("!Can't get absolute pathname of current working directory "); return 57; } else { fullpath = malloc(512); #ifdef NO_SNPRINTF sprintf(fullpath, "%s/%s", cwd, thefilename); #else snprintf(fullpath, 512, "%s/%s", cwd, thefilename); #endif logg("*Full path: %s ", fullpath); } } else fullpath = thefilename; //开始区别扫描文件和文件夹 switch(fmode & S_IFMT) { case S_IFREG: ret = scanfile(fullpath, engine, user, opt, &limits, options); break; case S_IFDIR: ret = scandirs(fullpath, engine, user, opt, &limits, options); break; default: logg("!Not supported file type (%s) ", thefilename); ret = 52; } if(extunpacker && (thefilename[0] != '/' && thefilename[0] != '\' && thefilename[1] != ':')) { free(fullpath); fullpath = NULL; } } free(thefilename); } } /* free the engine */ cl_free(engine); /* overwrite return code */ if(info.ifiles) ret = 1; else if(ret < 50) /* hopefully no error detected */ ret = 0; /* just make sure it's 0 */ return ret; }