/* * @(#)Cdrecord.cpp * * This file is part of webCDwriter - Network CD/DVD Writing. * * Copyright (C) 2000-2005 Jörg P. M. Haeger * * webCDwriter is free software. See CDWserver.cpp for details. * * Jörg Haeger, 13.03.2000 */ #include "Config.h" #include "Cdrecord.h" #include "CDstate.h" #include "String.h" Cdrecord::Cdrecord(int writerNo, struct CDstate *CDstate): CDstate(CDstate), Process(config.getCdrecordPath()) { for (int i = 0; i < 256; i++) { results[i].key = -1; results[i].code = 0; results[i].qual = 0; results[i].str = NULL; results[i].successCounter = 0; } firstError = lastCommand = lastError = -1; cannotReadTOC = cannotReadSessionOffset = 0; fixating = 0; mayNotFit = 0; mediumNotPresent = 0; trayOpen = -1; fifoPercent = MBwritten = MBofTrackWritten = MBtotal = 0; time(&t0); t1 = t2 = t0; overburn = 0; fixationSeconds = (4500 + 2250 + 4500) / 75 / 1; noSuchDevice = 0; // add dev-argument of cdrecord char str[4*1024]; sprintf(str, "dev=%s", config.getWriter(writerNo)); addArg(str); } Cdrecord::~Cdrecord() { for (int i = 0; i < 256; i++) if (results[i].str != NULL) delete results[i].str; } const char *Cdrecord::getFirstError() { if (firstError >= 0 && firstError < 256) { if (results[firstError].str == NULL) results[firstError].str = new String(); return results[firstError].str->getBytes(); } else if (mayNotFit) return "may not fit"; else return NULL; } const char *Cdrecord::getLastError() { if (lastError >= 0 && lastError < 256) { if (results[lastError].str == NULL) results[lastError].str = new String(); return results[lastError].str->getBytes(); } else return NULL; } void Cdrecord::getProgress(int ¤t, int &total) { /* time(&t1); current = t1 - t0; total = t2 - t0; */ current = MBwritten + MBofTrackWritten; total = MBtotal; } int Cdrecord::isBlankDisk() { // a blank disk is detected by read toc return results[0x43].code == 0x8F && results[0x43].qual == 0x00; } int Cdrecord::isDriveReady() { return results[0x00].successCounter > 0; // results[0x00].key == 0x00 // && results[0x00].code == 0x00 // && results[0x00].qual == 0x00; } int Cdrecord::isInProcessOfBecomingReady() { // logical unit is in process of becoming ready return results[0x00].code == 0x04 && results[0x00].qual == 0x01; } int Cdrecord::isMediumNotPresent() { // return mediumNotPresent; return results[0x00].code == 0x3A; } int Cdrecord::isNoSuchDevicePresent() { return noSuchDevice; } int Cdrecord::isTrayClosed() { return trayOpen == 0; } bool Cdrecord::isTrayOpen() { return mediumNotPresent && trayOpen == 1; } const char *Cdrecord::readLine(int timeout) { const char *lineStr = Process::readLine(timeout); if (lineStr == NULL) return NULL; lineType = none; int a, b, c, d = 100; /* if (sscanf(lineStr, " ATIP start of lead out: %d", &a) == 1) { if (CDstate != NULL) CDstate->ATIPLeadOut = a; } else */ if (sscanf(lineStr, "Blocks total: %d " "Blocks current: %d " "Blocks remaining: %d", &a, &b, &c) == 3) { if (CDstate != NULL) { CDstate->blocks0 = a; CDstate->blocks1 = b; CDstate->blocks2 = c; } lineType = capacity; } else if (strstr(lineStr, "Cannot read first writable address") != NULL) throw new Exception("can't read first writable address"); else if (strstr(lineStr, "Cannot read session offset") != NULL) cannotReadSessionOffset = 1; else if (strstr(lineStr, "Cannot read TOC header") != NULL || strstr(lineStr, "Cannot read TOC/PMA") != NULL) cannotReadTOC = 1; else if (sscanf(lineStr, "CDB: %x", &lastCommand) == 1) { // see cdrecord-1.8/libscg/scsierrs.c if (0 <= lastCommand && lastCommand < 256) { // start of the next command results[lastCommand].key = 0; results[lastCommand].code = 0; results[lastCommand].qual = 0; if (results[lastCommand].str == NULL) results[lastCommand].str = new String(); *results[lastCommand].str = ""; } else lastCommand = -1; } else if (strstr(lineStr, "cmd finished") == lineStr) { if (results[lastCommand].key == 0 && results[lastCommand].code == 0 && results[lastCommand].qual == 0) results[lastCommand].successCounter++; } else if (sscanf(lineStr, "Current Secsize: %d", &a) == 1) { if (CDstate != NULL) CDstate->blockSize = a; } else /* if (strstr(lineStr, "Drive needs to reload") != NULL) { // the media to return to proper status. terminate(); throw new Exception("reload media"); } else */ if (strstr(lineStr, "Fixating...") == lineStr) fixating = 1; else if (strstr(lineStr, "Is erasable") != NULL) { if (CDstate != NULL) CDstate->isRW = 1; } else if (strstr(lineStr, "Is not erasable") != NULL) { if (CDstate != NULL) CDstate->isRW = 0; } else if (strstr(lineStr, "Last chance to quit") != NULL) { if (mayNotFit) { terminate(); throw new Exception("may not fit"); } else if (CDstate != NULL && !CDstate->isClosed && CDstate->blocks2 < 4500 + 6750) { terminate(); throw new Exception("restartWithoutMulti"); } } else if (sscanf(lineStr, "Manuf. index: %d", &a) == 1) { if (CDstate != NULL) CDstate->manufacturerIndex = a; } else if (strstr(lineStr, "may not fit on current disk") != NULL) mayNotFit = !overburn; else if (sscanf(lineStr, "Mode Sense Data %x %x %x", &a, &b, &c) == 3) { if (trayOpen < 0 && c > 0) trayOpen = c & 0x01; } else if (strstr(lineStr, "No such device") != NULL) // No such device or address. Cannot open '/dev/pg0'. Cannot open SCSI driver. // No such device. noSuchDevice = 1; else if (strstr(lineStr, "Re-load disk and hit ") != NULL) throw new Exception("Hardware error. Try again!"); else if (sscanf(lineStr, "Sense Code: %x Qual %x", &code, &qual) == 2) { if (0 <= lastCommand && lastCommand < 256) { // printf("cmd = %02x, key = %02x, " // "code = %02x, qual = %02x\n", // lastCommand, key, code, qual); if (firstError == -1) firstError = lastCommand; lastError = lastCommand; results[lastCommand].key = key; results[lastCommand].code = code; results[lastCommand].qual = qual; String line = lineStr; int p0 = line.indexOf("("); if (p0 >= 0) { int p = line.indexOf(")"); if (p > p0) { if (p - p0 > 45) p = p0 + 45; String str = line.substring(p0 + 1, p); if (results[lastCommand].str == NULL) results[lastCommand].str = new String(); *results[lastCommand].str = str; } } } // if (strstr(lineStr, "medium not present") != NULL) { if (lastCommand == 0x00 && code == 0x3A) { mediumNotPresent = 1; // if (strstr(lineStr, "- tray closed") != NULL) if (qual == 0x01) trayOpen = 0; else // if (strstr(lineStr, "- tray open") != NULL) if (qual == 0x02) trayOpen = 1; } } else if (sscanf(lineStr, "Sense Key: %x", &key) == 1) ; else if (sscanf(lineStr, "Starting to write CD/DVD at speed %d", &a) == 1) { if (CDstate != NULL) { CDstate->speed = a; if (CDstate->speed == 0) CDstate->speed = 1; if (strstr(lineStr, "multi session") != NULL) CDstate->isClosed = 0; else if (strstr(lineStr, "single session") != NULL) CDstate->isClosed = 1; time(&t0); t1 = t0; int numOfSectors = 4500 + (CDstate->blocks1 - CDstate->blocks2) + 2250; if (CDstate->blocks1 == CDstate->blocks0) numOfSectors += 4500; t2 = t0 + 9 + numOfSectors / 75 / CDstate->speed; numOfSectors = 4500 + 2250; if (CDstate->blocks1 == CDstate->blocks0) numOfSectors += 4500; fixationSeconds = numOfSectors / 75 / CDstate->speed; if (CDstate->isRW) fixationSeconds = 220 * fixationSeconds / 100; else fixationSeconds = 140 * fixationSeconds / 100; } } else if (sscanf(lineStr, "Track %d: audio %d", &a, &b) == 2) // numOfSectors += (1024 * 1024 * b) / 2352; MBtotal += b; else if (sscanf(lineStr, "Track %d: data %d", &a, &b) == 2) // numOfSectors += (1024 * 1024 * b) / 2048; MBtotal += b; else if (sscanf(lineStr, "Track %d: %d of %d MB written (fifo %d", &a, &b, &c, &d) >= 3) { lineType = progress; if (b == c) { MBwritten += c; MBofTrackWritten = 0; } else MBofTrackWritten = b; fifoPercent = d; } else if (strstr(lineStr, "Trying to use high speed medium on low speed writer.") != NULL) throw new Exception( "Trying to use high speed medium on low speed writer."); return lineStr; }