File indexing completed on 2024-04-28 04:49:43
0001 /* 0002 SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "k3bgrowisofshandler.h" 0007 #include "k3bjob.h" 0008 #include "k3bcore.h" 0009 #include "k3bglobalsettings.h" 0010 #include "k3bdevicehandler.h" 0011 #include "k3b_i18n.h" 0012 0013 #include <QDebug> 0014 #include <QLocale> 0015 #include <QTimer> 0016 0017 #include <errno.h> 0018 #include <string.h> 0019 0020 0021 class K3b::GrowisofsHandler::Private 0022 { 0023 public: 0024 int lastBuffer; 0025 int lastDeviceBuffer; 0026 }; 0027 0028 0029 K3b::GrowisofsHandler::GrowisofsHandler( QObject* parent ) 0030 : QObject( parent ), 0031 m_mediaType(Device::MEDIA_DVD_ALL) 0032 { 0033 d = new Private; 0034 reset(); 0035 } 0036 0037 0038 K3b::GrowisofsHandler::~GrowisofsHandler() 0039 { 0040 delete d; 0041 } 0042 0043 0044 void K3b::GrowisofsHandler::reset( K3b::Device::Device* dev, bool dao ) 0045 { 0046 m_device = dev; 0047 m_error = ERROR_UNKNOWN; 0048 m_dao = dao; 0049 d->lastBuffer = 0; 0050 d->lastDeviceBuffer = 0; 0051 } 0052 0053 0054 void K3b::GrowisofsHandler::handleStart() 0055 { 0056 // QTimer::singleShot( 2000, this, SLOT(slotCheckBufferStatus()) ); 0057 } 0058 0059 0060 void K3b::GrowisofsHandler::handleLine( const QString& line ) 0061 { 0062 int pos = 0; 0063 0064 if( line.startsWith( ":-[" ) ) { 0065 // Error 0066 0067 if( line.contains( "ASC=30h" ) ) 0068 m_error = ERROR_MEDIA; 0069 0070 // :-[ PERFORM OPC failed with SK=3h/ASC=73h/ASCQ=03h 0071 else if( line.startsWith( ":-[ PERFORM OPC failed" ) ) 0072 emit infoMessage( i18n("OPC failed. Please try writing speed 1x."), K3b::Job::MessageError ); 0073 0074 else if( line.startsWith( ":-[ Failed to change write speed" ) ) { 0075 m_error = ERROR_SPEED_SET_FAILED; 0076 } 0077 } 0078 else if( line.startsWith( ":-(" ) ) { 0079 if( line.contains( "No space left on device" ) ) 0080 m_error = ERROR_OVERSIZE; 0081 0082 else if( line.contains( "blocks are free" ) && line.contains( "to be written" ) ) { 0083 m_error = ERROR_OVERSIZE; 0084 if( k3bcore->globalSettings()->overburn() ) 0085 emit infoMessage( i18n("Trying to write more than the official disk capacity"), K3b::Job::MessageWarning ); 0086 } 0087 0088 else if( line.startsWith( ":-( unable to anonymously mmap" ) ) { 0089 m_error = ERROR_MEMLOCK; 0090 } 0091 0092 else if( line.startsWith( ":-( write failed" ) ) { 0093 m_error = ERROR_WRITE_FAILED; 0094 } 0095 0096 // :-( attempt to re-run with -dvd-compat -dvd-compat to engage DAO or apply full blanking procedure 0097 else if( !m_dao && 0098 ( line.contains( "engage DAO" ) || line.contains( "media is not formatted or unsupported" ) ) ) 0099 emit infoMessage( i18n("Please try again with writing mode DAO."), K3b::Job::MessageError ); 0100 0101 else 0102 emit infoMessage( line, K3b::Job::MessageError ); 0103 } 0104 else if( line.startsWith( "PERFORM OPC" ) ) { 0105 m_error = ERROR_OPC; 0106 } 0107 else if( line.contains( "flushing cache" ) ) { 0108 // here is where we already should stop querying the buffer fill 0109 // since the device is only used there so far... 0110 m_device = 0; 0111 0112 emit flushingCache(); 0113 emit newSubTask( i18n("Flushing Cache") ); 0114 emit infoMessage( i18n("Flushing the cache may take some time."), K3b::Job::MessageInfo ); 0115 } 0116 0117 // FIXME: I think this starts with dev->blockDeviceName() so we could improve parsing with: 0118 // if( line.startsWith( dev->blockDeviceName() ) ) { 0119 // line = line.mid( dev->blockDeviceName().length() ); 0120 // if( line.startsWith( "closing..... 0121 0122 else if( line.contains( "closing track" ) ) { 0123 emit newSubTask( i18n("Closing Track") ); 0124 } 0125 else if( line.contains( "closing disc" ) ) { 0126 emit newSubTask( i18n("Closing Disk") ); 0127 } 0128 else if( line.contains( "updating RMA" ) ) { 0129 emit newSubTask( i18n("Updating RMA") ); 0130 emit infoMessage( i18n("Updating RMA..."), K3b::Job::MessageInfo ); 0131 } 0132 else if (line.contains("closing session")) { 0133 emit newSubTask(i18n("Closing Session")); 0134 emit infoMessage(i18n("Closing Session..."), K3b::Job::MessageInfo); 0135 } 0136 else if( line.contains( "writing lead-out" ) ) { 0137 emit newSubTask( i18n("Writing Lead-out") ); 0138 emit infoMessage( i18n("Writing the lead-out may take some time."), K3b::Job::MessageInfo ); 0139 } 0140 else if( line.contains( "Quick Grow" ) ) { 0141 emit infoMessage( i18n("Removing reference to lead-out."), K3b::Job::MessageInfo ); 0142 } 0143 else if( line.contains( "copying volume descriptor" ) ) { 0144 emit infoMessage( i18n("Modifying ISO 9660 volume descriptor"), K3b::Job::MessageInfo ); 0145 } 0146 else if( line.contains( "FEATURE 21h is not on" ) ) { 0147 if( !m_dao ) { 0148 // FIXME: it's not only the writer. It may be the media: something like does not support it with this media 0149 // da war was mit: wenn einmal formattiert, dann geht nur noch dao oder wenn einmal als overwrite 0150 // formattiert, dann nur noch dao oder sowas 0151 emit infoMessage( i18n("Writing mode Incremental Streaming not available"), K3b::Job::MessageWarning ); 0152 emit infoMessage( i18n("Engaging DAO"), K3b::Job::MessageWarning ); 0153 } 0154 } 0155 else if( ( pos = line.indexOf( "Current Write Speed" ) ) > 0 ) { 0156 // parse write speed 0157 // /dev/sr0: "Current Write Speed" is 2.4x1385KBps for DVD or 4.1x4496KBps for BD 0158 0159 pos += 24; 0160 int endPos = line.indexOf( 'x', pos+1 ); 0161 bool ok = true; 0162 double speed = line.mid( pos, endPos-pos ).toDouble(&ok); 0163 if (ok) { 0164 emit infoMessage(i18n("Writing speed: %1 KB/s (%2x)", 0165 int(speed * double(m_mediaType == Device::MEDIA_DVD_ALL ? Device::SPEED_FACTOR_DVD : Device::SPEED_FACTOR_BD)), 0166 QLocale::system().toString(speed)), K3b::Job::MessageInfo); 0167 } else 0168 qDebug() << "(K3b::GrowisofsHandler) parsing error: '" << line.mid( pos, endPos-pos ) << "'"; 0169 } 0170 else if( (pos = line.indexOf( "RBU" )) > 0 ) { 0171 0172 // FIXME: use QRegExp 0173 0174 // parse ring buffer fill for growisofs >= 6.0 0175 pos += 4; 0176 int endPos = line.indexOf( '%', pos+1 ); 0177 bool ok = true; 0178 double val = line.mid( pos, endPos-pos ).toDouble( &ok ); 0179 if( ok ) { 0180 int newBuffer = (int)(val+0.5); 0181 if( newBuffer != d->lastBuffer ) { 0182 d->lastBuffer = newBuffer; 0183 emit buffer( newBuffer ); 0184 } 0185 0186 // device buffer for growisofs >= 7.0 0187 pos = line.indexOf( "UBU", pos ); 0188 endPos = line.indexOf( '%', pos+5 ); 0189 if( pos > 0 ) { 0190 pos += 4; 0191 val = line.mid( pos, endPos-pos ).toDouble( &ok ); 0192 if( ok ) { 0193 int newBuffer = (int)(val+0.5); 0194 if( newBuffer != d->lastDeviceBuffer ) { 0195 d->lastDeviceBuffer = newBuffer; 0196 emit deviceBuffer( newBuffer ); 0197 } 0198 } 0199 } 0200 } 0201 else 0202 qDebug() << "(K3b::GrowisofsHandler) failed to parse ring buffer fill from '" << line.mid( pos, endPos-pos ) << "'"; 0203 } 0204 0205 else { 0206 qDebug() << "(growisofs) " << line; 0207 } 0208 } 0209 0210 0211 void K3b::GrowisofsHandler::handleExit( int exitCode ) 0212 { 0213 switch( m_error ) { 0214 case ERROR_MEDIA: 0215 emit infoMessage( i18n("K3b detected a problem with the medium."), K3b::Job::MessageError ); 0216 emit infoMessage( i18n("Please try another brand of media, preferably one explicitly recommended by your writer's vendor."), K3b::Job::MessageError ); 0217 emit infoMessage( i18n("Report the problem if it persists anyway."), K3b::Job::MessageError ); 0218 break; 0219 0220 case ERROR_OVERSIZE: 0221 if( k3bcore->globalSettings()->overburn() ) 0222 emit infoMessage( i18n("Data did not fit on disk."), K3b::Job::MessageError ); 0223 else 0224 emit infoMessage( i18n("Data does not fit on disk."), K3b::Job::MessageError ); 0225 break; 0226 0227 case ERROR_SPEED_SET_FAILED: 0228 emit infoMessage( i18n("Unable to set writing speed."), K3b::Job::MessageError ); 0229 emit infoMessage( i18n("Please try again with the 'ignore speed' setting."), K3b::Job::MessageError ); 0230 break; 0231 0232 case ERROR_OPC: 0233 emit infoMessage( i18n("Optimum Power Calibration failed."), K3b::Job::MessageError ); 0234 emit infoMessage( i18n("Try adding '-use-the-force-luke=noopc' to the " 0235 "growisofs user parameters in the K3b settings."), K3b::Job::MessageError ); 0236 break; 0237 0238 case ERROR_MEMLOCK: 0239 emit infoMessage( i18n("Unable to allocate software buffer."), K3b::Job::MessageError ); 0240 emit infoMessage( i18n("This error is caused by the low memorylocked resource limit."), K3b::Job::MessageError ); 0241 emit infoMessage( i18n("It can be solved by issuing the command 'ulimit -l unlimited'..."), K3b::Job::MessageError ); 0242 emit infoMessage( i18n("...or by lowering the used software buffer size in the advanced K3b settings."), K3b::Job::MessageError ); 0243 break; 0244 0245 case ERROR_WRITE_FAILED: 0246 emit infoMessage( i18n("Write error"), K3b::Job::MessageError ); 0247 break; 0248 0249 default: 0250 0251 // 0252 // The growisofs error codes: 0253 // 0254 // 128 + errno: fatal error upon program startup 0255 // errno : fatal error during recording 0256 // 0257 0258 if( exitCode > 128 ) { 0259 // for now we just emit a message with the error 0260 // in the future when I know more about what kinds of errors may occur 0261 // we will enhance this 0262 emit infoMessage( i18n( "Fatal error at startup: %1", QString::fromLocal8Bit( ::strerror( exitCode-128 ) ) ), 0263 K3b::Job::MessageError ); 0264 } 0265 else if( exitCode == 1 ) { 0266 // Doku says: warning at exit 0267 // Example: mkisofs error 0268 // unable to reload 0269 // So basically this is just for mkisofs failure since we do not let growisofs reload the media 0270 emit infoMessage( i18n("Warning at exit: (1)"), K3b::Job::MessageError ); 0271 emit infoMessage( i18n("Most likely mkisofs failed in some way."), K3b::Job::MessageError ); 0272 } 0273 else { 0274 emit infoMessage( i18n( "Fatal error during recording: %1", QString::fromLocal8Bit( ::strerror(exitCode) ) ), 0275 K3b::Job::MessageError ); 0276 } 0277 } 0278 0279 reset(); 0280 } 0281 0282 0283 void K3b::GrowisofsHandler::slotCheckBufferStatus() 0284 { 0285 connect( K3b::Device::sendCommand( K3b::Device::DeviceHandler::CommandBufferCapacity, m_device ), 0286 SIGNAL(finished(K3b::Device::DeviceHandler*)), 0287 this, 0288 SLOT(slotCheckBufferStatusDone(K3b::Device::DeviceHandler*)) ); 0289 } 0290 0291 0292 void K3b::GrowisofsHandler::slotCheckBufferStatusDone( K3b::Device::DeviceHandler* dh ) 0293 { 0294 if( dh->success() && dh->bufferCapacity() > 0 ) { 0295 emit deviceBuffer( 100 * (dh->bufferCapacity() - dh->availableBufferCapacity() ) / dh->bufferCapacity() ); 0296 QTimer::singleShot( 500, this, SLOT(slotCheckBufferStatus()) ); 0297 } 0298 else { 0299 qDebug() << "(K3b::GrowisofsHandler) stopping buffer check."; 0300 } 0301 } 0302 0303 void K3b::GrowisofsHandler::setMediaType(Device::MediaType mediaType) 0304 { 0305 m_mediaType = mediaType; 0306 } 0307 0308 #include "moc_k3bgrowisofshandler.cpp"