#include #include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "hd.h" #include "intl.h" #include "install.h" #include "log.h" #include "scsi.h" static int scsiChoicePanel(int * addSCSI); static int scsiChoicePanel(int * addSCSI) { int rc; DIR * dir; struct dirent * ent; char buffer[4000]; int foundSome; dir = opendir("/proc/scsi"), foundSome = 0; if (dir) { strcpy(buffer, _("I have found the following types of SCSI " "adapters on your system:\n\n")); errno = 0; while ((ent = readdir(dir))) { if (*ent->d_name == '.') continue; if (!strcmp("scsi", ent->d_name)) continue; strcat(buffer, "\t"); strcat(buffer, getModuleDescription(ent->d_name)); strcat(buffer, "\n"); foundSome = 1; } closedir(dir); strcat(buffer, _("\nDo you have any more SCSI adapters on your system?")); } if (!foundSome) { strcpy(buffer, _("Do you have any SCSI adapters?")); } rc = newtWinTernary(_("SCSI Configuration"), _("No"), _("Yes"), _("Back"), buffer); if (rc == 3) return INST_CANCEL; else if (rc == 2) *addSCSI = 1; else *addSCSI = 0; return 0; } int setupSCSIInterfaces(int forceConfig, struct driversLoaded ** dl, int automatic, int dir) { int rc; int hasscsi = 1; /* First of all, autodetect all the SCSI devices we can. */ rc = loadDeviceDriver(DRIVER_SCSI, dl, DEVICE_JUSTPROBE | DEVICE_NOPAUSE); if (automatic) return dir < 0 ? INST_CANCEL : INST_OKAY; if (rc == INST_CANCEL) return INST_CANCEL; #if defined(__sparc__) || defined(__alpha__) rc = dir < 0 ? INST_CANCEL : INST_OKAY; #else /* There could be undetected (ISA) SCSI adapters sitting around still (or we could be in expert mode where we don't autodetect these things. So, give the user a chance for manual configuration now. */ while (hasscsi) { if (forceConfig) { forceConfig = 0; hasscsi = 1; } else { if (scsiChoicePanel(&hasscsi) == INST_CANCEL) return INST_CANCEL; } if (hasscsi) { rc = loadDeviceDriver(DRIVER_SCSI, dl, DEVICE_NOPROBE); if (rc == INST_ERROR) hasscsi = 0; /* break out */ } else { rc = 0; } } #endif return rc; } int scsiDeviceAvailable(void) { int fd; char buf[80]; int i; fd = open("/proc/scsi/scsi", O_RDONLY); if (fd < 0) { logMessage("failed to open /proc/scsi/scsi: %s", strerror(errno)); return 0; } i = read(fd, buf, sizeof(buf) - 1); if (i < 1) { logMessage("failed to read /proc/scsi/scsi: %s", strerror(errno)); return 0; } close(fd); buf[i] = '\0'; logMessage("/proc/scsi/scsi: %s", buf); if (strstr(buf, "devices: none")) { logMessage("no scsi devices are available"); return 0; } logMessage("scsi devices are available"); return 1; } #define SCSISCSI_TOP 0 #define SCSISCSI_HOST 1 #define SCSISCSI_VENDOR 2 #define SCSISCSI_TYPE 3 int scsiGetDevices(struct deviceInfo ** sdiPtr) { int fd; char buf[16384]; char linebuf[80]; char typebuf[10]; int i, state = SCSISCSI_TOP; char * start, * chptr, * next, *end; char driveName = 'a'; char cdromNum = '0'; char tapeNum = '0'; int numMatches = 0; struct deviceInfo * sdi; int id = 0; /* FIXME: this should be big enough */ sdi = malloc(sizeof(*sdi) * 65); fd = open("/proc/scsi/scsi", O_RDONLY); if (fd < 0) { logMessage("failed to open /proc/scsi/scsi: %s", strerror(errno)); return 1; } i = read(fd, buf, sizeof(buf) - 1); if (i < 1) { logMessage("failed to read /proc/scsi/scsi: %s", strerror(errno)); return 1; } close(fd); buf[i] = '\0'; start = buf; while (*start) { chptr = start; while (*chptr != '\n') chptr++; *chptr = '\0'; next = chptr + 1; switch (state) { case SCSISCSI_TOP: if (strcmp("Attached devices: ", start)) { logMessage("unexpected line in /proc/scsi/scsi: %s", start); free(sdi); return INST_ERROR; } state = SCSISCSI_HOST; break; case SCSISCSI_HOST: if (strncmp("Host: ", start, 6)) { logMessage("unexpected line in /proc/scsi/scsi: %s", start); free(sdi); return INST_ERROR; } start = strstr(start, "Id: "); if (!start) { logMessage("Id: missing in /proc/scsi/scsi"); return INST_ERROR; } start += 4; id = strtol(start, NULL, 10); state = SCSISCSI_VENDOR; break; case SCSISCSI_VENDOR: if (strncmp(" Vendor: ", start, 10)) { logMessage("unexpected line in /proc/scsi/scsi: %s", start); free(sdi); return INST_ERROR; } start += 10; end = chptr = strstr(start, "Model:"); if (!chptr) { logMessage("Model missing in /proc/scsi/scsi"); free(sdi); return INST_ERROR; } chptr--; while (*chptr == ' ') chptr--; *(chptr + 1) = '\0'; strcpy(linebuf, start); *linebuf = toupper(*linebuf); chptr = linebuf + 1; while (*chptr) { *chptr = tolower(*chptr); chptr++; } start = end; /* beginning of "Model:" */ start += 7; chptr = strstr(start, "Rev:"); if (!chptr) { logMessage("Rev missing in /proc/scsi/scsi"); free(sdi); return INST_ERROR; } chptr--; while (*chptr == ' ') chptr--; *(chptr + 1) = '\0'; strcat(linebuf, " "); strcat(linebuf, start); state = SCSISCSI_TYPE; break; case SCSISCSI_TYPE: if (strncmp(" Type:", start, 7)) { logMessage("unexpected line in /proc/scsi/scsi: %s", start); free(sdi); return INST_ERROR; } *typebuf = '\0'; if (strstr(start, "Direct-Access")) { sprintf(typebuf, "sd%c", driveName++); sdi[numMatches].type = DEVICE_HD; } else if (strstr(start, "Sequential-Access")) { sprintf(typebuf, "st%c", tapeNum++); sdi[numMatches].type = DEVICE_TAPE; } else if (strstr(start, "CD-ROM")) { sprintf(typebuf, "scd%c", cdromNum++); sdi[numMatches].type = DEVICE_CDROM; } if (*typebuf) { /*sdi = realloc(sdi, sizeof(*sdi) * (numMatches + 2));*/ sdi[numMatches].deviceName = strdup(typebuf); sdi[numMatches].info = strdup(linebuf); sdi[numMatches].bus = 0; sdi[numMatches++].id = id; } state = SCSISCSI_HOST; } start = next; } sdi[numMatches].deviceName = NULL; sdi[numMatches].info = NULL; sdi = realloc(sdi, sizeof(*sdi) * (numMatches + 1)); *sdiPtr = sdi; return 0; } int ideGetDevices(struct deviceInfo ** idiPtr) { struct deviceInfo * idi; struct stat sb; char * filename; char * buf, * end; char * absend; int numMatches = 0; int fd; int base = testing ? 0 : 3; idi = malloc(sizeof(*idi) * 9); if (!access("/proc/ide", R_OK)) { /* Great. 2.2 kernel, things are much easier and less error prone. */ char b[20]; FILE *f; strcpy(b, "/proc/ide/hda"); buf = alloca (256); /* Maybe we should use readdir here instead... */ for (; b[12] <= 'm'; b[12]++) { b[13] = '\0'; if (access(b, R_OK)) continue; strcpy(b + 13, "/media"); f = fopen(b, "r"); if (!f) { newtWinMessage("Error", "Ok", "Failed to open %s: %s\n", b, strerror(errno)); return INST_ERROR; } fgets(buf, 256, f); fclose(f); if (!strcmp(buf, "disk\n")) idi[numMatches].type = DEVICE_HD; else if (!strcmp(buf, "cdrom\n")) idi[numMatches].type = DEVICE_CDROM; else if (!strcmp(buf, "tape\n")) idi[numMatches].type = DEVICE_TAPE; else if (!strcmp(buf, "floppy\n")) idi[numMatches].type = DEVICE_FD; else continue; idi[numMatches].deviceName = malloc(4); strcpy(idi[numMatches].deviceName, "hda"); idi[numMatches].deviceName[2] = b[12]; strcpy(b + 13, "/model"); f = fopen(b, "r"); if (!f) idi[numMatches].info = strdup("(none)"); else { fgets(buf, 256, f); fclose(f); end = strchr (buf, '\n'); if (end) *end = '\0'; idi[numMatches].info = strdup(buf); } idi[numMatches].bus = (b[12] - 'a') / 2; idi[numMatches].id = (b[12] - 'a') % 2; numMatches++; } } else { /* normal string handling doesn't work here as the syslog can contain binary 0's! */ if (!access("/var/log/dmesg", R_OK)) filename = "/var/log/dmesg"; else filename = "/tmp/syslog"; if (stat(filename, &sb)) { newtWinMessage("Error", "Ok", "Failed to stat %s: %s\n", filename, strerror(errno)); return 0; } if ((fd = open(filename, O_RDONLY)) < 0) { newtWinMessage("Error", "Ok", "Failed to open %s: %s\n", filename, strerror(errno)); return INST_ERROR; } buf = alloca(sb.st_size); read(fd, buf, sb.st_size); close(fd); absend = buf + sb.st_size; while (buf && buf < absend) { if (buf[0 + base] == 'h' && buf[1 + base] == 'd' && buf[3 + base] == ':') { idi[numMatches].deviceName = malloc(4); strcpy(idi[numMatches].deviceName, "hda"); idi[numMatches].deviceName[2] = buf[2 + base]; buf += 5 + base; end = buf; while (*end != '\n' && *end != ',') end++; if (*end == ',') { idi[numMatches].info = malloc(end - buf + 1); strncpy(idi[numMatches].info, buf, end - buf); idi[numMatches].info[end - buf] = '\0'; /* see if this is a cdrom or not */ while (*end != '\n' && strncmp(end, "CDROM", 5) && strncmp(end, "TAPE", 4) && strncmp(end, "FLOPPY", 6) && strncmp(end, "CHS", 3)) end++; if (!strncmp(end, "CDROM", 5)) idi[numMatches].type = DEVICE_CDROM; else if (!strncmp(end, "TAPE", 4)) idi[numMatches].type = DEVICE_TAPE; else if (!strncmp(end, "FLOPPY", 6)) idi[numMatches].type = DEVICE_FD; else if (!strncmp(end, "CHS", 3)) idi[numMatches].type = DEVICE_HD; else idi[numMatches].type = DEVICE_NONE; /* we could do better here */ idi[numMatches].bus = idi[numMatches].id = 0; if (idi[numMatches].type != DEVICE_NONE) numMatches++; } } end = memchr(buf, '\n', absend - buf); if (!end) buf = NULL; else buf = end + 1; } } idi[numMatches].deviceName = NULL; idi[numMatches].info = NULL; idi = realloc(idi, sizeof(*idi) * (numMatches + 1)); *idiPtr = idi; return 0; } int CompaqSmartArrayDeviceAvailable(void) { int fd; fd = open("/proc/array/ida0", O_RDONLY); if (fd < 0) { return 0; } close (fd); logMessage("Compaq Smart Array controllers available"); return 1; } int CompaqSmartArrayGetDevices(struct deviceInfo ** idiPtr) { struct deviceInfo * idi; FILE *f; char buf[256]; char *ptr; int numMatches = 0, ctlNum = 0; char ctl[20]; idi = malloc(sizeof(*idi) * 30); sprintf(ctl, "/proc/array/ida%d", ctlNum++); while ((f = fopen(ctl, "r"))){ while (fgets(buf, sizeof(buf) - 1, f)) { if (!strncmp(buf, "ida/", 4)) { ptr = strchr(buf, ':'); *ptr = '\0'; idi[numMatches].deviceName = strdup(buf); idi[numMatches].info = strdup("Compaq RAID logical disk"); idi[numMatches++].type = DEVICE_HD; } } sprintf(ctl, "/proc/array/ida%d", ctlNum++); } idi[numMatches].deviceName = NULL; idi[numMatches].info = NULL; idi = realloc(idi, sizeof(*idi) * (numMatches + 1)); *idiPtr = idi; return 0; } int dac960GetDevices(struct deviceInfo ** idiPtr) { struct deviceInfo * idi = NULL; const char *filename; char buf[256]; char *ptr, *iptr; int numMatches = 0; int numIDIs = 0; FILE* f; if (!access("/var/log/dmesg", R_OK)) filename = "/var/log/dmesg"; else filename = "/tmp/syslog"; if (!(f = fopen(filename, "r"))) { newtWinMessage("Error", "Ok", "Failed to open %s: %s\n", filename, strerror(errno)); return INST_ERROR; } /* We are looking for lines of this format: DAC960#0: /dev/rd/c0d0: RAID-7, Online, 17928192 blocks, Write Thru 0123456790123456789012 */ buf [sizeof(buf) - 1] = '\0'; while (fgets(buf, sizeof(buf) - 1, f)) { ptr = strstr (buf, "/dev/rd/"); if (ptr) { iptr = strchr (ptr, ':'); if (iptr) { if (idi == NULL) { numIDIs = 16; idi = malloc(sizeof(*idi) * numIDIs); } else if (numMatches >= numIDIs) { numIDIs += 16; idi = realloc (idi, sizeof(*idi) * numIDIs); } memset (&idi [numMatches], 0, sizeof (*idi)); /* put a NULL at the ':' */ *iptr = '\0'; idi[numMatches].deviceName = strdup(ptr + 5); ptr = iptr; while (*ptr != ',') ptr++; *ptr = '\0'; idi[numMatches].info = strdup(iptr + 2); idi[numMatches].type = DEVICE_HD; logMessage("DAC960: %s: %s", idi[numMatches].deviceName, idi[numMatches].info); numMatches++; } } } if (numMatches > 0) { idi[numMatches].deviceName = NULL; idi[numMatches].info = NULL; idi = realloc(idi, sizeof(*idi) * (numMatches + 1)); } *idiPtr = idi; return 0; }