📄 aimage_os.cpp
字号:
#include "config.h"#include "afflib.h"#include "afflib_i.h"#include "aimage.h"#include "imager.h"/* ident_update_seg: * If af!=NULL, then update segname to contain the string str. * Otherwise just print it (for debugging) */void ident_update_seg(AFFILE *af,char *segname,char *str,int is_number){ if(af){ if(is_number){ af_update_seg(af,segname,atoi(str),0,0); } else{ af_update_seg(af,segname,0,str,strlen(str)); } } else{ printf("%s: %s\n",segname,str); }}/* checkline: * Looks for a name in a line in a buf and, if found, * make a copy of the text, put a copy of the next into the * AFFILE... */void checkline(char *name,char *segname, char *buf,char *copy,AFFILE *af,int is_number){ while(buf[0] && isspace(buf[0])) buf++; // advance buf to end of spaces char *pos = strstr(buf,name); if(pos==0) return; /* The string was found */ char *cc = pos + strlen(name); // skip past to the end of the string while(*cc && isspace(*cc)) cc++; // scan to end of spaces char *dd = index(cc,'\n'); // can we find a \n? if(dd) *dd = '\000'; // yes; clear it ident_update_seg(af,segname,cc,is_number); if(copy) strcpy(copy,cc); // make a copy}/* FreeBSD-specific ident routines */#ifdef __FreeBSD__#include <sys/param.h>#include <sys/mount.h>int freebsd_get_ata_params(const char *infile,int *controller,int *channel){ int adnum; if(sscanf(infile,"/dev/ad%d",&adnum)==1){ if(controller) *controller = adnum / 2; if(channel) *channel = adnum % 2; return 0; } return(-1);}/* fix_freebsd_sn: * FreeBSD 6.0 release returns ^_ as the serial number of some USB devices. * If that is the case here, scan the output of sysctl -a to find the * device and put in the S/N. This can fail if there is more than * one USB device with the same S/N. */#include <regex.h>static void fix_freebsd_sn(AFFILE *af,char *serial_number,int sn_len,char *device_model){ char word1[1024]; char buf[1024]; /* Get the first word of the model number */ strlcpy(word1,device_model,sizeof(word1)); char *cc = index(word1,' ' ); if(cc) *cc = '\000'; sprintf(buf,"sysctl -a dev.umass"); FILE *f = popen(buf,"r"); int in_section = 0; while(!feof(f)){ if(fgets(buf,sizeof(buf),f)){ /* See if this is the new section */ if(strstr(buf,"dev.umass.") && strstr(buf,"desc:")){ if(strstr(buf,word1)){ in_section = 1; } else { in_section = 0; } } if(in_section){ regex_t r_sn; if(regcomp(&r_sn,"sernum=\"([^\"]*)\"",REG_EXTENDED|REG_ICASE)) err(1,"regcomp"); regmatch_t pm[2]; memset(pm,0,sizeof(pm)); if(regexec(&r_sn,buf,2,pm,REG_NOTBOL)==0){ char b2[1024]; memset(b2,0,sizeof(b2)); strncpy(b2,buf+pm[1].rm_so,pm[1].rm_eo-pm[1].rm_so); strlcpy(serial_number,b2,sn_len); ident_update_seg(af,AF_DEVICE_SN,serial_number,0); } regfree(&r_sn); } } } pclose(f);}#define IDENT_DEFINED/* ident for freebsd */void imager::ident(){ int controller = 0; int channel = 0; /* Check for a SCSI drive. * This needs to be cleaned up; right now it assumes SCSI bus 2. */ int da_dev = -1; if(sscanf(infile,"/dev/da%d",&da_dev)==1){ char checkbuf[64]; char want[64]; char buf[256]; /* Now do the devlist to figure out which device this is... */ scsi_bus = -1; // for now snprintf(want,sizeof(want),"da%d",da_dev); sprintf(checkbuf,"camcontrol devlist"); FILE *f = popen(checkbuf,"r"); while(!feof(f)){ if(fgets(buf,sizeof(buf),f)){ if(strstr(buf,want)){ // this is the correct line char *cc = strstr(buf,"at scbus"); if(cc){ if(sscanf(cc, "at scbus%d target %d lun %d (pass%d,da%d)", &scsi_bus,&scsi_tid,&scsi_lun, &scsi_pass,&da_dev)==5){ break; // found it! } if(sscanf(cc, "at scbus%d target %d lun %d (da%d,pass%d)", &scsi_bus,&scsi_tid,&scsi_lun, &da_dev,&scsi_pass)==5){ break; // found it! } } } } } pclose(f); if(scsi_bus==-1) err(1,"can't find SCSI device for %s",infile); /* Now we need to inquiry */ sprintf(checkbuf,"camcontrol inquiry %d:%d",scsi_bus,scsi_tid); f = popen(checkbuf,"r"); char capbuf[65536]; capbuf[0] = 0; while(!feof(f)){ if(fgets(buf,sizeof(buf),f)){ strlcat(capbuf,buf,sizeof(capbuf)); char *cc = index(buf,'>'); // see if it should be terminated if(cc) *cc = 0; sprintf(checkbuf,"pass%d: <",scsi_pass); checkline(checkbuf,AF_DEVICE_MODEL,buf,device_model,af,0); sprintf(checkbuf,"pass%d: Serial Number ",scsi_pass); checkline(checkbuf,AF_DEVICE_SN,buf,serial_number,af,0); } } pclose(f); if(serial_number[0]=='\037' && serial_number[1]=='\000'){ fix_freebsd_sn(af,serial_number,sizeof(serial_number),device_model); } ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0); return; } /* Check for an IDE drive */ if(strncmp(infile,"/dev/ad",7)==0 && freebsd_get_ata_params(infile,&controller,&channel)==0){ char capbuf[65536]; char buf[256];#if __FreeBSD_version > 600000 /* Syntax of command was changed in FreeBSD 6.0 */ sprintf(buf,"atacontrol cap ad%d",controller*2+channel);#else sprintf(buf,"atacontrol cap ata%d %d",controller,channel);#endif capbuf[0] = 0; FILE *f = popen(buf,"r"); while(!feof(f)){ if(fgets(buf,sizeof(buf),f)){ buf[sizeof(buf)-1] = 0; // make sure it is null-terminated strlcat(capbuf,buf,sizeof(capbuf)); checkline("device model",AF_DEVICE_MODEL,buf,device_model,af,0); checkline("serial number",AF_DEVICE_SN,buf,serial_number,af,0); checkline("firmware revision",AF_DEVICE_FIRMWARE,buf,firmware_revision,af,0); checkline("cylinders",AF_CYLINDERS,buf,0,af,1); checkline("heads",AF_HEADS,buf,0,af,1); checkline("sectors/track",AF_SECTORS_PER_TRACK,buf,0,af,1); } } pclose(f); ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0); return; }}/* FreeBSD ata attach commands */#define MAKE_ATA_ATTACH_COMMANDS_DEFINEDvoid make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev){ sprintf(attach,"atacontrol attach ata%d",dev); sprintf(detach,"atacontrol detach ata%d",dev); sprintf(master,"/dev/ad%d",dev*2); sprintf(slave,"/dev/ad%d",dev*2+1);}/* FreeBSD scsi attach commands. Actually does it and returns 0 if successful, * as well as the device. */#define SCSI_ATTACH_DEFINEDint scsi_attach(char *fname,int fname_len, class imager *im) // returns 0 if successful & sets fname{ char buf[256]; char looking[64]; sprintf(buf,"camcontrol rescan %d",im->scsi_bus); system(buf); sprintf(looking,"scbus%d",im->scsi_bus); // what I'm looking for /* Now, see if there is a device on this scsi bus */ FILE *f = popen("camcontrol devlist","r"); if(!f) err(1,"camcontrol devlist"); while(!feof(f)){ memset(buf,0,sizeof(buf)); if(fgets(buf,sizeof(buf),f)){ char *cc = strstr(buf,looking); if(cc){ int da_num; /* Get the target and lun. * Notice that FreeBSD is inconsistent in the way that this * is reported. */ if(sscanf(cc+strlen(looking)+1, "target %d lun %d (pass%d,da%d)", &im->scsi_tid,&im->scsi_lun,&im->scsi_pass,&da_num)==4){ snprintf(fname,fname_len,"/dev/da%d",da_num); return 0; } if(sscanf(cc+strlen(looking)+1, "target %d lun %d (da%d,pass%d)", &im->scsi_tid,&im->scsi_lun,&da_num,&im->scsi_pass)==4){ snprintf(fname,fname_len,"/dev/da%d",da_num); return 0; } err(1,"could not parse: '%s'",buf); } } } pclose(f); fprintf(stderr,"No SCSI device found:\n"); fprintf(stderr,"# camcontrol rescan all\n"); system("camcontrol rescan all"); return -1; // failure }#endif#ifdef linux#include <dirent.h>static void getfile(const char *dirname,const char *filename,char *copy, int copysize, AFFILE *af,char *segname){ char path[MAXPATHLEN]; char buf[1024]; /* Build the pathname we are supposed to get */ memset(buf,0,sizeof(buf)); strlcpy(path,dirname,sizeof(path)); strlcat(path,filename,sizeof(path)); FILE *f = fopen(path,"r"); if(f){ if(fgets(buf,sizeof(buf),f)){ char *cc = rindex(buf,'\n'); if(cc) *cc = '\000'; // remove trailing \n ident_update_seg(af,segname,buf,0); if(copy) strlcat(copy,buf,copysize); } fclose(f); }}#define IDENT_DEFINEDvoid imager::ident(){ /* Is this a regular file? If so, just return */ struct stat so; if(stat(infile,&so)==0){ if(so.st_mode & S_IFMT) return; } /* Check to see if infile is a USB device. If so, print things about it. * If the Linux /sys file system is installed, then /sys/bus/scsi/devices/.../block * are symlinks to the actual devices. * These have the same name as the /dev/<name>, minus the partition. */ if(strncmp(infile,"/dev/",5)==0){ char *cc; char sdname[MAXPATHLEN]; memset(sdname,0,sizeof(sdname)); strcpy(sdname,infile+5); /* If a partition name was provided, eliminate it */ for(cc=sdname;*cc;cc++){ if(isdigit(*cc)){ *cc = '\000'; break; } } /* Look to see if this is a USB device*/ DIR *dir = opendir("/sys/bus/scsi/devices/"); struct dirent *dp; while((dp = readdir(dir))!=0){ if(dp->d_name[0]=='.') continue; // skip the dot names char dirname[MAXPATHLEN]; strlcpy(dirname,"/sys/bus/scsi/devices/",sizeof(dirname)); strlcat(dirname,dp->d_name,sizeof(dirname)); char devname[MAXPATHLEN]; strlcpy(devname,dirname,sizeof(devname)); strlcat(devname,"/",sizeof(devname)); strlcat(devname,"/block",sizeof(devname)); /* If this is a link, then stat it */ char path[MAXPATHLEN]; memset(path,0,sizeof(path)); if(readlink(devname,path,sizeof(path))>0){ cc = rindex(path,'/'); // find the end of the link if(cc && strcmp(cc+1,sdname)==0){ /* Found it! * Now, it turns out that dirname is also a symbolic link. * Use it to find the directory where the USB information is stored. */ char usbdir[MAXPATHLEN]; strlcpy(usbdir,dirname,sizeof(usbdir)); strlcat(usbdir,"/../../../../",sizeof(usbdir)); device_model[0] = 0; serial_number[0] = 0; getfile(usbdir,"manufacturer",device_model,sizeof(device_model), af,AF_DEVICE_MANUFACTURER); strlcat(device_model," ",sizeof(device_model)); getfile(usbdir,"product",device_model,sizeof(device_model), af,AF_DEVICE_MODEL); getfile(usbdir,"serial",serial_number,sizeof(serial_number), af,AF_DEVICE_SN); //getfile(usbdir,"version",0,0,af,AF_DEVICE_FIRMWARE); return; // we have successfully identified the device } } } /* Fall back to a regular hard drive */ if(access(infile,R_OK)==0){ char capbuf[65536]; char buf[256]; if(af_hasmeta(infile)) return; // something is wrong here snprintf(buf,sizeof(buf),"hdparm -I %s",infile); capbuf[0] = 0; FILE *f = popen(buf,"r"); while(!feof(f)){ if(fgets(buf,sizeof(buf),f)){ buf[sizeof(buf)-1] = 0; // make sure it is null-terminated strlcat(capbuf,buf,sizeof(capbuf)); // append to the buffer /* Now check for each of the lines */ checkline("Model Number:",AF_DEVICE_MODEL,buf,device_model,af,0); checkline("Serial Number:",AF_DEVICE_SN,buf,serial_number,af,0); checkline("Firmware Revision:",AF_DEVICE_FIRMWARE, buf,firmware_revision,af,0); checkline("cylinders",AF_CYLINDERS,buf,0,af,1); checkline("heads",AF_HEADS,buf,0,af,1); checkline("sectors/track",AF_SECTORS_PER_TRACK,buf,0,af,1); } } pclose(f); ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0); } } return; // can't figure it out}/* * Here are some parameters you may find interesting: * hdparm -R 0x1700 0 0 /dev/hda (to remove /dev/hda) * ide2: BM-DMA at 0xb800-0xb807, BIOS settings: hde:DMA, hdf:pio * Unfortunately, I can't get Linux ATA attach to work. Can you? * Note: "These mknod calls should be eliminated. If this is not possible, * a secure sub-directory should be created to hold them, and * umask() should be called to control access." --- VSecurity */#define MAKE_ATA_ATTACH_COMMANDS_DEFINEDvoid make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev){#if 0 system("/sbin/mknod /tmp/hda c 3 0"); system("/sbin/mknod /tmp/hdb c 3 64"); system("/sbin/mknod /tmp/hdc c 22 0"); system("/sbin/mknod /tmp/hdd c 22 64"); sprintf(attach,"hdparm -R %d",dev); sprintf(detach,"hdparm -U %d",dev); sprintf(master,"/dev/ad%d",dev*2); sprintf(slave,"/dev/ad%d",dev*2+1);#endif}/* Linux scsi attach commands *//* I can't figure out how to do this. */void make_scsi_attach_commands(char *cmd_attach,char *cmd_detach, int scsi_bus){ cmd_attach[0] = 0; cmd_detach[0] = 0;}#define SCSI_ATTACH_DEFINEDint scsi_attach(char *fname,int fname_len,class imager *) // returns 0 if successful & sets fname{ return -1; // can't do it}#endif/**************************************************************** *** MacOS ****************************************************************/#ifdef __APPLE__int get_block(FILE *f,char *buf,int buflen){ /* Get a block from FILE f, where a block is defined as lines until a \n\n */ memset(buf,0,buflen); buflen--; // so we won't lose the last \n int consecutive_newlines = 0; int lns = 0; while(!feof(f)){ if(!fgets(buf,buflen,f)) break; if(buf[0]=='\n'){ return 1; // blank line } consecutive_newlines = 0; int bytes = strlen(buf); // number of bytes that was read buf += bytes; buflen -= bytes; lns++; } return lns>0;}#define IDENT_DEFINEDvoid imager::ident(){ if(strncmp(infile,"/dev/",5)==0){ char *name = infile+5; char buf[65536]; char looking[65536]; snprintf(looking,sizeof(looking),"BSD Name: %s",name); FILE *f = popen("system_profiler SPUSBDataType","r"); while(get_block(f,buf,sizeof(buf))){ if(strstr(buf,looking)){ // did I find the block I'm looking for? checkline("Serial Number:",AF_DEVICE_SN,buf,serial_number,af,0); checkline("Manufacturer:",AF_DEVICE_MANUFACTURER,buf,device_model,af,0); } } pclose(f); } }#endif/* If we do not have an ident, make it a stub... */#ifndef IDENT_DEFINEDvoid imager::ident(){ return;}#endif#ifndef MAKE_ATA_ATTACH_COMMANDS_DEFINED/* We do not have these defined either... */void make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev){ attach[0] = 0; detach[0] = 0; master[0] = 0; slave[0] = 0;}#endif#ifndef SCSI_ATTACH_DEFINEDint scsi_attach(char *fname,int fname_len,class imager *) // returns 0 if successful & sets fname{ return -1; // can't do it}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -