PageRenderTime 30ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/aimage-3.2.5/src/aimage_os.cpp

#
C++ | 562 lines | 427 code | 60 blank | 75 comment | 60 complexity | 86d1680e8543b463a9aaf8230e7b2565 MD5 | raw file
  1. #include "config.h"
  2. #include "aimage.h"
  3. #include "imager.h"
  4. /* ident_update_seg:
  5. * If af!=NULL, then update segname to contain the string str.
  6. * Otherwise just print it (for debugging)
  7. */
  8. void ident_update_seg(AFFILE *af,const char *segname,const char *str,int is_number)
  9. {
  10. if(af){
  11. if(is_number){
  12. af_update_seg(af,segname,atoi(str),0,0);
  13. }
  14. else{
  15. int len = strlen(str);
  16. af_update_seg(af,segname,0,(const u_char *)str,len);
  17. }
  18. }
  19. else{
  20. printf("%s: %s\n",segname,str);
  21. }
  22. }
  23. /* checkline:
  24. * Looks for a name in a line in a buf and, if found,
  25. * put a copy of the next into the
  26. * AFFILE and optionally make a copy of the text..
  27. */
  28. void checkline(const char *name,const char *segname, const char *buf,char *copy,AFFILE *af,int is_number)
  29. {
  30. while(buf[0] && isspace(buf[0])) buf++; // advance buf to end of spaces
  31. const char *pos = strstr(buf,name);
  32. if(pos==0) return;
  33. /* The string was found */
  34. const char *cc = pos + strlen(name); // skip past to the end of the string
  35. while(*cc && isspace(*cc)) cc++; // scan to end of spaces
  36. char *tmp = strdup(cc);
  37. /* Terminate tmp at EOL if there is one first */
  38. char *dd = index(tmp,'\n'); // can we find a \n?
  39. if(dd) *dd = '\000'; // yes; clear it
  40. ident_update_seg(af,segname,tmp,is_number);
  41. if(copy) strcpy(copy,tmp); // make a copy
  42. free(tmp);
  43. }
  44. /* FreeBSD-specific ident routines */
  45. #ifdef __FreeBSD__
  46. #include <sys/param.h>
  47. #include <sys/mount.h>
  48. int freebsd_get_ata_params(const char *infile,int *controller,int *channel)
  49. {
  50. int adnum;
  51. if(sscanf(infile,"/dev/ad%d",&adnum)==1){
  52. if(controller) *controller = adnum / 2;
  53. if(channel) *channel = adnum % 2;
  54. return 0;
  55. }
  56. return(-1);
  57. }
  58. /* fix_freebsd_sn:
  59. * FreeBSD 6.0 release returns ^_ as the serial number of some USB devices.
  60. * If that is the case here, scan the output of sysctl -a to find the
  61. * device and put in the S/N. This can fail if there is more than
  62. * one USB device with the same S/N.
  63. */
  64. #include <regex.h>
  65. static void fix_freebsd_sn(AFFILE *af,char *serial_number,int sn_len,char *device_model)
  66. {
  67. char word1[1024];
  68. /* Get the first word of the model number */
  69. strlcpy(word1,device_model,sizeof(word1));
  70. char *cc = index(word1,' ' );
  71. if(cc) *cc = '\000';
  72. FILE *f = popen("sysctl -a dev.umass","r");
  73. int in_section = 0;
  74. while(!feof(f)){
  75. char buf[1024];
  76. memset(buf,0,sizeof(buf));
  77. if(fgets(buf,sizeof(buf),f)){
  78. /* See if this is the new section */
  79. if(strstr(buf,"dev.umass.") && strstr(buf,"desc:")){
  80. if(strstr(buf,word1)){
  81. in_section = 1;
  82. }
  83. else {
  84. in_section = 0;
  85. }
  86. }
  87. if(in_section){
  88. regex_t r_sn;
  89. if(regcomp(&r_sn,"sernum=\"([^\"]*)\"",REG_EXTENDED|REG_ICASE)) err(1,"regcomp");
  90. regmatch_t pm[3];
  91. memset(pm,0,sizeof(pm));
  92. if(regexec(&r_sn,buf,2,pm,REG_NOTBOL)==0){
  93. char b2[1024];
  94. memset(b2,0,sizeof(b2));
  95. strncpy(b2,buf+pm[1].rm_so,pm[1].rm_eo-pm[1].rm_so);
  96. strlcpy(serial_number,b2,sn_len);
  97. ident_update_seg(af,AF_DEVICE_SN,serial_number,0);
  98. }
  99. regfree(&r_sn);
  100. }
  101. }
  102. }
  103. pclose(f);
  104. }
  105. #define IDENT_DEFINED
  106. /* ident for freebsd */
  107. void imager::ident()
  108. {
  109. int controller = 0;
  110. int channel = 0;
  111. /* Check for a SCSI drive.
  112. * This needs to be cleaned up; right now it assumes SCSI bus 2.
  113. */
  114. int da_dev = -1;
  115. if(sscanf(infile,"/dev/da%d",&da_dev)==1){
  116. char checkbuf[64];
  117. char want[64];
  118. char buf[65536];
  119. /* Now do the devlist to figure out which device this is... */
  120. scsi_bus = -1; // for now
  121. snprintf(want,sizeof(want),"da%d",da_dev);
  122. sprintf(checkbuf,"camcontrol devlist");
  123. FILE *f = popen(checkbuf,"r");
  124. while(!feof(f)){
  125. if(fgets(buf,sizeof(buf),f)){
  126. if(strstr(buf,want)){ // this is the correct line
  127. char *cc = strstr(buf,"at scbus");
  128. if(cc){
  129. if(sscanf(cc,
  130. "at scbus%d target %d lun %d (pass%d,da%d)",
  131. &scsi_bus,&scsi_tid,&scsi_lun,
  132. &scsi_pass,&da_dev)==5){
  133. break; // found it!
  134. }
  135. if(sscanf(cc,
  136. "at scbus%d target %d lun %d (da%d,pass%d)",
  137. &scsi_bus,&scsi_tid,&scsi_lun,
  138. &da_dev,&scsi_pass)==5){
  139. break; // found it!
  140. }
  141. }
  142. }
  143. }
  144. }
  145. pclose(f);
  146. if(scsi_bus==-1) err(1,"can't find SCSI device for %s",infile);
  147. /* Now we need to inquiry */
  148. sprintf(checkbuf,"camcontrol inquiry %d:%d",scsi_bus,scsi_tid);
  149. f = popen(checkbuf,"r");
  150. char capbuf[65536];
  151. capbuf[0] = 0;
  152. while(!feof(f)){
  153. if(fgets(buf,sizeof(buf),f)){
  154. strlcat(capbuf,buf,sizeof(capbuf));
  155. char *cc = index(buf,'>'); // see if it should be terminated
  156. if(cc) *cc = 0;
  157. sprintf(checkbuf,"pass%d: <",scsi_pass);
  158. checkline(checkbuf,AF_DEVICE_MODEL,buf,device_model,af,0);
  159. sprintf(checkbuf,"pass%d: Serial Number ",scsi_pass);
  160. checkline(checkbuf,AF_DEVICE_SN,buf,serial_number,af,0);
  161. }
  162. }
  163. pclose(f);
  164. if(serial_number[0]=='\037' && serial_number[1]=='\000'){
  165. fix_freebsd_sn(af,serial_number,sizeof(serial_number),device_model);
  166. }
  167. ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0);
  168. return;
  169. }
  170. /* Check for an IDE drive */
  171. if(strncmp(infile,"/dev/ad",7)==0 &&
  172. freebsd_get_ata_params(infile,&controller,&channel)==0){
  173. char capbuf[65536];
  174. char buf[256];
  175. #if __FreeBSD_version > 600000
  176. /* Syntax of command was changed in FreeBSD 6.0 */
  177. sprintf(buf,"atacontrol cap ad%d",controller*2+channel);
  178. #else
  179. sprintf(buf,"atacontrol cap ata%d %d",controller,channel);
  180. #endif
  181. capbuf[0] = 0;
  182. FILE *f = popen(buf,"r");
  183. while(!feof(f)){
  184. if(fgets(buf,sizeof(buf),f)){
  185. buf[sizeof(buf)-1] = 0; // make sure it is null-terminated
  186. strlcat(capbuf,buf,sizeof(capbuf));
  187. checkline("device model",AF_DEVICE_MODEL,buf,device_model,af,0);
  188. checkline("serial number",AF_DEVICE_SN,buf,serial_number,af,0);
  189. checkline("firmware revision",AF_DEVICE_FIRMWARE,buf,firmware_revision,af,0);
  190. checkline("cylinders",AF_CYLINDERS,buf,0,af,1);
  191. checkline("heads",AF_HEADS,buf,0,af,1);
  192. checkline("sectors/track",AF_SECTORS_PER_TRACK,buf,0,af,1);
  193. }
  194. }
  195. pclose(f);
  196. ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0);
  197. return;
  198. }
  199. }
  200. /* FreeBSD ata attach commands */
  201. #define MAKE_ATA_ATTACH_COMMANDS_DEFINED
  202. void make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev)
  203. {
  204. sprintf(attach,"atacontrol attach ata%d",dev);
  205. sprintf(detach,"atacontrol detach ata%d",dev);
  206. sprintf(master,"/dev/ad%d",dev*2);
  207. sprintf(slave,"/dev/ad%d",dev*2+1);
  208. }
  209. /* FreeBSD scsi attach commands. Actually does it and returns 0 if successful,
  210. * as well as the device.
  211. */
  212. #define SCSI_ATTACH_DEFINED
  213. int scsi_attach(char *fname,int fname_len,
  214. class imager *im) // returns 0 if successful & sets fname
  215. {
  216. char buf[256];
  217. char looking[64];
  218. sprintf(buf,"camcontrol rescan %d",im->scsi_bus);
  219. system(buf);
  220. sprintf(looking,"scbus%d",im->scsi_bus); // what I'm looking for
  221. /* Now, see if there is a device on this scsi bus */
  222. FILE *f = popen("camcontrol devlist","r");
  223. if(!f) err(1,"camcontrol devlist");
  224. while(!feof(f)){
  225. memset(buf,0,sizeof(buf));
  226. if(fgets(buf,sizeof(buf),f)){
  227. char *cc = strstr(buf,looking);
  228. if(cc){
  229. int da_num;
  230. /* Get the target and lun.
  231. * Notice that FreeBSD is inconsistent in the way that this
  232. * is reported.
  233. */
  234. if(sscanf(cc+strlen(looking)+1,
  235. "target %d lun %d (pass%d,da%d)",
  236. &im->scsi_tid,&im->scsi_lun,&im->scsi_pass,&da_num)==4){
  237. snprintf(fname,fname_len,"/dev/da%d",da_num);
  238. return 0;
  239. }
  240. if(sscanf(cc+strlen(looking)+1,
  241. "target %d lun %d (da%d,pass%d)",
  242. &im->scsi_tid,&im->scsi_lun,&da_num,&im->scsi_pass)==4){
  243. snprintf(fname,fname_len,"/dev/da%d",da_num);
  244. return 0;
  245. }
  246. err(1,"could not parse: '%s'",buf);
  247. }
  248. }
  249. }
  250. pclose(f);
  251. fprintf(stderr,"No SCSI device found:\n");
  252. fprintf(stderr,"# camcontrol rescan all\n");
  253. system("camcontrol rescan all");
  254. return -1; // failure
  255. }
  256. #endif
  257. #ifdef linux
  258. #include <dirent.h>
  259. static void getfile(const char *dirname,const char *filename,char *copy,
  260. int copysize,
  261. AFFILE *af,const char *segname)
  262. {
  263. char path[MAXPATHLEN];
  264. char buf[1024];
  265. /* Build the pathname we are supposed to get */
  266. memset(buf,0,sizeof(buf));
  267. strlcpy(path,dirname,sizeof(path));
  268. strlcat(path,filename,sizeof(path));
  269. FILE *f = fopen(path,"r");
  270. if(f){
  271. if(fgets(buf,sizeof(buf),f)){
  272. char *cc = rindex(buf,'\n');
  273. if(cc) *cc = '\000'; // remove trailing \n
  274. ident_update_seg(af,segname,buf,0);
  275. if(copy) strlcat(copy,buf,copysize);
  276. }
  277. fclose(f);
  278. }
  279. }
  280. #define IDENT_DEFINED
  281. void imager::ident()
  282. {
  283. /* Is this a regular file? If so, just return */
  284. struct stat so;
  285. if(stat(infile,&so)==0){
  286. if(S_ISREG(so.st_mode)) return;
  287. }
  288. /* If udev is installed, just use that */
  289. if(stat("/sbin/udevadm",&so)==0){
  290. char capbuf[65536];
  291. char buf[1024];
  292. memset(capbuf,0,sizeof(capbuf));
  293. snprintf(buf,sizeof(buf),"/sbin/udevadm info --query=all --name=%s",infile);
  294. FILE *f=popen(buf,"r");
  295. while(!feof(f)){
  296. memset(buf,0,sizeof(buf));
  297. if(fgets(buf,sizeof(buf),f)){
  298. strlcat(capbuf,buf,sizeof(capbuf)); // make local copy
  299. checkline("E: ID_MODEL=",AF_DEVICE_MODEL,buf,this->device_model,af,0);
  300. checkline("E: ID_SERIAL_SHORT=",AF_DEVICE_SN,buf,this->serial_number,af,0);
  301. checkline("E: ID_VENDOR=",AF_DEVICE_MANUFACTURER,buf,0,af,0);
  302. }
  303. }
  304. pclose(f);
  305. ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0);
  306. return;
  307. }
  308. /* Check to see if infile is a USB device. If so, print things about it.
  309. * If the Linux /sys file system is installed, then /sys/bus/scsi/devices/.../block
  310. * are symlinks to the actual devices.
  311. * These have the same name as the /dev/<name>, minus the partition.
  312. */
  313. if(strncmp(infile,"/dev/",5)==0){
  314. char *cc;
  315. char sdname[MAXPATHLEN];
  316. memset(sdname,0,sizeof(sdname));
  317. strcpy(sdname,infile+5);
  318. /* If a partition name was provided, eliminate it */
  319. for(cc=sdname;*cc;cc++){
  320. if(isdigit(*cc)){
  321. *cc = '\000';
  322. break;
  323. }
  324. }
  325. /* Look to see if this is a USB device*/
  326. DIR *dir = opendir("/sys/bus/scsi/devices/");
  327. if(dir){
  328. struct dirent *dp;
  329. while((dp = readdir(dir))!=0){
  330. if(dp->d_name[0]=='.') continue; // skip the dot names
  331. char dirname[MAXPATHLEN];
  332. strlcpy(dirname,"/sys/bus/scsi/devices/",sizeof(dirname));
  333. strlcat(dirname,dp->d_name,sizeof(dirname));
  334. char devname[MAXPATHLEN];
  335. strlcpy(devname,dirname,sizeof(devname));
  336. strlcat(devname,"/",sizeof(devname));
  337. strlcat(devname,"/block",sizeof(devname));
  338. /* If this is a link, then stat it */
  339. char path[MAXPATHLEN];
  340. memset(path,0,sizeof(path));
  341. if(readlink(devname,path,sizeof(path))>0){
  342. cc = rindex(path,'/'); // find the end of the link
  343. if(cc && strcmp(cc+1,sdname)==0){
  344. /* Found it!
  345. * Now, it turns out that dirname is also a symbolic link.
  346. * Use it to find the directory where the USB information is stored.
  347. */
  348. char usbdir[MAXPATHLEN];
  349. strlcpy(usbdir,dirname,sizeof(usbdir));
  350. strlcat(usbdir,"/../../../../",sizeof(usbdir));
  351. device_model[0] = 0;
  352. serial_number[0] = 0;
  353. getfile(usbdir,"manufacturer",device_model,sizeof(device_model),
  354. af,AF_DEVICE_MANUFACTURER);
  355. strlcat(device_model," ",sizeof(device_model));
  356. getfile(usbdir,"product",device_model,sizeof(device_model),
  357. af,AF_DEVICE_MODEL);
  358. getfile(usbdir,"serial",serial_number,sizeof(serial_number),
  359. af,AF_DEVICE_SN);
  360. //getfile(usbdir,"version",0,0,af,AF_DEVICE_FIRMWARE);
  361. closedir(dir);
  362. return; // we have successfully identified the device
  363. }
  364. }
  365. }
  366. closedir(dir); // never found it
  367. }
  368. /* Fall back to a regular hard drive */
  369. if(access(infile,R_OK)==0){
  370. char capbuf[65536];
  371. char buf[256];
  372. if(af_hasmeta(infile)) return; // something is wrong here
  373. snprintf(buf,sizeof(buf),"hdparm -I %s",infile);
  374. capbuf[0] = 0;
  375. FILE *f = popen(buf,"r");
  376. while(!feof(f)){
  377. if(fgets(buf,sizeof(buf),f)){
  378. buf[sizeof(buf)-1] = 0; // make sure it is null-terminated
  379. strlcat(capbuf,buf,sizeof(capbuf)); // append to the buffer
  380. /* Now check for each of the lines */
  381. checkline("Model Number:",AF_DEVICE_MODEL,buf,device_model,af,0);
  382. checkline("Serial Number:",AF_DEVICE_SN,buf,serial_number,af,0);
  383. checkline("Firmware Revision:",AF_DEVICE_FIRMWARE,
  384. buf,firmware_revision,af,0);
  385. checkline("cylinders",AF_CYLINDERS,buf,0,af,1);
  386. checkline("heads",AF_HEADS,buf,0,af,1);
  387. checkline("sectors/track",AF_SECTORS_PER_TRACK,buf,0,af,1);
  388. }
  389. }
  390. pclose(f);
  391. ident_update_seg(af,AF_DEVICE_CAPABILITIES,capbuf,0);
  392. }
  393. }
  394. return; // can't figure it out
  395. }
  396. /*
  397. * Here are some parameters you may find interesting:
  398. * hdparm -R 0x1700 0 0 /dev/hda (to remove /dev/hda)
  399. * ide2: BM-DMA at 0xb800-0xb807, BIOS settings: hde:DMA, hdf:pio
  400. * Unfortunately, I can't get Linux ATA attach to work. Can you?
  401. * Note: "These mknod calls should be eliminated. If this is not possible,
  402. * a secure sub-directory should be created to hold them, and
  403. * umask() should be called to control access." --- VSecurity
  404. */
  405. #define MAKE_ATA_ATTACH_COMMANDS_DEFINED
  406. void make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev)
  407. {
  408. #if 0
  409. system("/sbin/mknod /tmp/hda c 3 0");
  410. system("/sbin/mknod /tmp/hdb c 3 64");
  411. system("/sbin/mknod /tmp/hdc c 22 0");
  412. system("/sbin/mknod /tmp/hdd c 22 64");
  413. sprintf(attach,"hdparm -R %d",dev);
  414. sprintf(detach,"hdparm -U %d",dev);
  415. sprintf(master,"/dev/ad%d",dev*2);
  416. sprintf(slave,"/dev/ad%d",dev*2+1);
  417. #endif
  418. }
  419. /* Linux scsi attach commands */
  420. /* I can't figure out how to do this. */
  421. void make_scsi_attach_commands(char *cmd_attach,char *cmd_detach, int scsi_bus)
  422. {
  423. cmd_attach[0] = 0;
  424. cmd_detach[0] = 0;
  425. }
  426. #define SCSI_ATTACH_DEFINED
  427. int scsi_attach(char *fname,int fname_len,class imager *) // returns 0 if successful & sets fname
  428. {
  429. return -1; // can't do it
  430. }
  431. #endif
  432. /****************************************************************
  433. *** MacOS
  434. ****************************************************************/
  435. #ifdef __APPLE__
  436. int get_block(FILE *f,char *buf,int buflen)
  437. {
  438. /* Get a block from FILE f, where a block is defined as lines until a \n\n */
  439. memset(buf,0,buflen);
  440. buflen--; // so we won't lose the last \n
  441. int consecutive_newlines = 0;
  442. int lns = 0;
  443. while(!feof(f)){
  444. if(!fgets(buf,buflen,f)) break;
  445. if(buf[0]=='\n'){
  446. return 1; // blank line
  447. }
  448. consecutive_newlines = 0;
  449. int bytes = strlen(buf); // number of bytes that was read
  450. buf += bytes;
  451. buflen -= bytes;
  452. lns++;
  453. }
  454. return lns>0;
  455. }
  456. #define IDENT_DEFINED
  457. void imager::ident()
  458. {
  459. /* Removed because system profiler causes problems with MacOS 10.5
  460. * when diskarbitrationdaemon is disabled.
  461. */
  462. #if 0
  463. if(strncmp(infile,"/dev/",5)==0){
  464. char *name = infile+5;
  465. char buf[65536];
  466. char looking[65536];
  467. snprintf(looking,sizeof(looking),"BSD Name: %s",name);
  468. FILE *f = popen("system_profiler SPUSBDataType","r");
  469. while(get_block(f,buf,sizeof(buf))){
  470. if(strstr(buf,looking)){ // did I find the block I'm looking for?
  471. checkline("Serial Number:",AF_DEVICE_SN,buf,this->serial_number,af,0);
  472. checkline("Manufacturer:",AF_DEVICE_MANUFACTURER,buf,this->device_model,af,0);
  473. }
  474. }
  475. pclose(f);
  476. }
  477. #endif
  478. }
  479. #endif
  480. /* If we do not have an ident, make it a stub... */
  481. #ifndef IDENT_DEFINED
  482. void imager::ident()
  483. {
  484. return;
  485. }
  486. #endif
  487. #ifndef MAKE_ATA_ATTACH_COMMANDS_DEFINED
  488. /* We do not have these defined either... */
  489. void make_ata_attach_commands(char *attach,char *detach,char *master,char *slave,int dev)
  490. {
  491. attach[0] = 0;
  492. detach[0] = 0;
  493. master[0] = 0;
  494. slave[0] = 0;
  495. }
  496. #endif
  497. #ifndef SCSI_ATTACH_DEFINED
  498. int scsi_attach(char *fname,int fname_len,class imager *) // returns 0 if successful & sets fname
  499. {
  500. return -1; // can't do it
  501. }
  502. #endif