File indexing completed on 2024-04-21 04:50:15

0001 /*
0002     SPDX-FileCopyrightText: 2003-2008 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 
0009 #include <config-k3b.h>
0010 
0011 
0012 #include "k3bsystemproblemdialog.h"
0013 #include "k3b.h"
0014 #include "k3bapplication.h"
0015 #include "k3bthemedheader.h"
0016 #include "k3btitlelabel.h"
0017 #include "k3bexternalbinmanager.h"
0018 #include "k3bstdguiitems.h"
0019 #include "k3bdevicemanager.h"
0020 #include "k3bdevice.h"
0021 #include "k3bversion.h"
0022 #include "k3bglobals.h"
0023 #include "k3bpluginmanager.h"
0024 #include "k3bplugin.h"
0025 #include "k3bthememanager.h"
0026 #include "k3bcore.h"
0027 
0028 #include <KColorScheme>
0029 #include <KConfigGroup>
0030 #include <KSharedConfig>
0031 #include <KProcess>
0032 #include <KNotification>
0033 #include <KLocalizedString>
0034 #include <KMessageBox>
0035 #include <KStandardGuiItem>
0036 
0037 #include <QFileInfo>
0038 #include <QList>
0039 #include <QCloseEvent>
0040 #include <QIcon>
0041 #include <QCheckBox>
0042 #include <QDialogButtonBox>
0043 #include <QGridLayout>
0044 #include <QHBoxLayout>
0045 #include <QPushButton>
0046 #include <QTextEdit>
0047 
0048 #ifdef HAVE_ICONV
0049 #include <langinfo.h>
0050 #endif
0051 
0052 #ifdef HAVE_FSTAB_H
0053 #include <fstab.h>
0054 #endif
0055 #include <unistd.h>
0056 
0057 
0058 static QString markupString( const QString& s_ )
0059 {
0060     QString s(s_);
0061     s.replace( '<', "&lt;" );
0062     s.replace( '>', "&gt;" );
0063     return s;
0064 }
0065 
0066 
0067 K3b::SystemProblem::SystemProblem( Type t,
0068                                    const QString& p,
0069                                    const QString& d,
0070                                    const QString& s )
0071     : type(t),
0072       problem(p),
0073       details(d),
0074       solution(s)
0075 {
0076 }
0077 
0078 
0079 K3b::SystemProblemDialog::SystemProblemDialog( const QList<K3b::SystemProblem>& problems,
0080                                                bool showDeviceSettingsButton,
0081                                                bool showBinSettingsButton,
0082                                                bool forceCheck,
0083                                                QWidget* parent)
0084     : QDialog( parent )
0085 {
0086     setWindowTitle( i18n("System Configuration Problems") );
0087     // setup the title
0088     // ---------------------------------------------------------------------------------------------------
0089     K3b::ThemedHeader* titleFrame = new K3b::ThemedHeader( this );
0090     titleFrame->setTitle( i18n("System Configuration Problems"),
0091                           i18np("1 problem", "%1 problems", problems.count() ) );
0092 
0093     QDialogButtonBox* buttonBox = new QDialogButtonBox( this );
0094     connect( buttonBox, SIGNAL(accepted()), SLOT(accept()) );
0095     connect( buttonBox, SIGNAL(rejected()), SLOT(reject()) );
0096 
0097     if( showDeviceSettingsButton || showBinSettingsButton ) {
0098         QPushButton* configureButton = buttonBox->addButton( i18n("Configure K3b..."), QDialogButtonBox::NoRole );
0099         if( showDeviceSettingsButton ) {
0100             connect( configureButton, SIGNAL(clicked()), SLOT(slotShowDeviceSettings()) );
0101         } else if( showBinSettingsButton ) {
0102             connect( configureButton, SIGNAL(clicked()), SLOT(slotShowBinSettings()) );
0103        }
0104     }
0105 
0106     buttonBox->addButton( QDialogButtonBox::Close );
0107 
0108     m_checkDontShowAgain = new QCheckBox( i18n("Do not show again"), this );
0109     m_checkDontShowAgain->setVisible(!forceCheck);
0110 
0111     // setup the problem view
0112     // ---------------------------------------------------------------------------------------------------
0113     QTextEdit* view = new QTextEdit( this );
0114     view->setReadOnly(true);
0115 
0116     // layout everything
0117     QGridLayout* grid = new QGridLayout( this );
0118     grid->addWidget( titleFrame, 0, 0, 1, 2 );
0119     grid->addWidget( view, 1, 0, 1, 2 );
0120     grid->addWidget( m_checkDontShowAgain, 2, 0 );
0121     grid->addWidget( buttonBox, 2, 1 );
0122     grid->setColumnStretch( 0, 1 );
0123     grid->setRowStretch( 1, 1 );
0124 
0125     const KColorScheme colorScheme( QPalette::Normal, KColorScheme::Button );
0126     const QColor negativeTextColor = colorScheme.foreground( KColorScheme::NegativeText ).color();
0127 
0128     QString text = "<html>";
0129 
0130     for( QList<K3b::SystemProblem>::const_iterator it = problems.constBegin();
0131          it != problems.constEnd(); ++it ) {
0132         const K3b::SystemProblem& p = *it;
0133 
0134         text.append( "<p><b>" );
0135         if( p.type == K3b::SystemProblem::CRITICAL ) {
0136             text.append( QString("<span style=\"color:%1\">").arg( negativeTextColor.name() ) );
0137         }
0138         text.append( markupString( p.problem ) );
0139         if( p.type == K3b::SystemProblem::CRITICAL )
0140             text.append( "</span>" );
0141         text.append( "</b><br>" );
0142         text.append( markupString( p.details ) + "<br>" );
0143         if( !p.solution.isEmpty() )
0144             text.append( "<i>" + i18n("Solution") + "</i>: " + p.solution );
0145         text.append( "</p>" );
0146     }
0147 
0148     text.append( "</html>" );
0149 
0150     view->setText(text);
0151     view->moveCursor( QTextCursor::Start );
0152     view->ensureCursorVisible();
0153 }
0154 
0155 
0156 void K3b::SystemProblemDialog::done(int r)
0157 {
0158     if (m_checkDontShowAgain->isChecked()) {
0159         KConfigGroup grp(KSharedConfig::openConfig(), QStringLiteral("General Options"));
0160         grp.writeEntry("check system config", false);
0161     }
0162     QDialog::done(r);
0163 }
0164 
0165 
0166 void K3b::SystemProblemDialog::checkSystem(QWidget* parent, NotificationLevel level, bool forceCheck)
0167 {
0168     QList<K3b::SystemProblem> problems;
0169     bool showDeviceSettingsButton = false;
0170     bool showBinSettingsButton = false;
0171 
0172     if (!forceCheck && !readCheckSystemConfig())
0173         return;
0174 
0175     const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord");
0176 
0177     if( k3bcore->deviceManager()->allDevices().isEmpty() ) {
0178         problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0179                                            i18n("No optical drive found."),
0180                                            i18n("K3b did not find any optical device in your system."),
0181 #ifdef ENABLE_HAL_SUPPORT
0182                                            i18n("Make sure HAL daemon is running, it is used by K3b for finding devices.")
0183 #else
0184                                            QString()
0185 #endif
0186                                            ) );
0187     }
0188     else if( k3bcore->deviceManager()->cdWriter().isEmpty() ) {
0189         problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0190                                            i18n("No CD/DVD/BD writer found."),
0191                                            i18n("K3b did not find an optical writing device in your system. Thus, "
0192                                                 "you will not be able to burn CDs or DVDs. However, you can still "
0193                                                 "use other K3b features such as audio track extraction, audio "
0194                                                 "transcoding or ISO 9660 image creation."),
0195                                            QString() ) );
0196     }
0197     else {
0198         // 1. cdrecord, cdrdao
0199         if( !k3bcore->externalBinManager()->binNeedGroup( "cdrecord" ).isEmpty() ) {
0200             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0201                                                i18n("Insufficient permissions for %1 executable: %2",QString("cdrecord"),k3bcore->externalBinManager()->binPath("cdrecord")),
0202                                                i18n("K3b uses cdrecord to actually write CDs."),
0203                                                i18n("Check permissions via Settings -> Configure K3b... -> Programs -> Permissions. "
0204                                                     "If K3b's default value is set make sure you are member of \"%1\" group.", k3bcore->externalBinManager()->binNeedGroup( "cdrecord" )) ) );
0205         }
0206         else if( !k3bcore->externalBinManager()->foundBin( "cdrecord" ) ) {
0207             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0208                                                i18n("Unable to find %1 executable",QString("cdrecord")),
0209                                                i18n("K3b uses cdrecord to actually write CDs."),
0210                                                i18n("Install the cdrtools package which contains "
0211                                                     "cdrecord.") ) );
0212         }
0213         else {
0214             if( cdrecordBin && cdrecordBin->hasFeature( "outdated" ) ) {
0215                 problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0216                                                    i18n("Used %1 version %2 is outdated",QString("cdrecord"),QString(cdrecordBin->version())),
0217                                                    i18n("Although K3b supports all cdrtools versions since "
0218                                                         "1.10 it is highly recommended to at least use "
0219                                                         "version 2.0."),
0220                                                    i18n("Install a more recent version of the cdrtools.") ) );
0221             }
0222 
0223 #ifdef Q_OS_LINUX
0224 
0225             //
0226             // Since kernel 2.6.8 older cdrecord versions are not able to use the SCSI subsystem when running suid root anymore
0227             // So far we ignore the suid root issue with kernel >= 2.6.8 and cdrecord < 2.01.01a02
0228             //
0229             // Kernel 2.6.16.something seems to introduce another problem which was apparently worked around in cdrecord 2.01.01a05
0230             //
0231             if( K3b::simpleKernelVersion() >= K3b::Version( 2, 6, 8 ) && cdrecordBin &&
0232                 cdrecordBin->version() < K3b::Version( 2, 1, 1, "a05" ) && !cdrecordBin->hasFeature( "wodim" ) ) {
0233                 if( cdrecordBin->hasFeature( "suidroot" ) ) {
0234                     showBinSettingsButton = true;
0235                     problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0236                                                          i18n("%1 will be run with root privileges on kernel >= 2.6.8",QString("cdrecord <= 2.01.01a05")),
0237                                                          i18n("Since Linux kernel 2.6.8 %1 will not work when run suid "
0238                                                               "root for security reasons anymore.",
0239                                                          QLatin1String( "cdrecord <= 2.01.01a05") ),
0240                                                          i18n("Click \"Configure K3b...\" to solve this problem.") ) );
0241                 }
0242             }
0243 #ifdef CDRECORD_SUID_ROOT_CHECK
0244             else if( !k3bcore->externalBinManager()->binObject( "cdrecord" )->hasFeature( "suidroot" ) && getuid() != 0 ) { // not root
0245                 showBinSettingsButton = true;
0246                 problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0247                                                      i18n("%1 will be run without root privileges",QString("cdrecord")),
0248                                                      i18n("It is highly recommended to configure cdrecord "
0249                                                           "to run with root privileges, as then cdrecord "
0250                                                           "runs with high priority that increases the overall "
0251                                                           "stability of the burning process. As well as this, "
0252                                                           "it allows the size of the burning buffer to be changed, "
0253                                                           "and a lot of user problems can be solved this way."),
0254                                                      i18n("Click \"Configure K3b...\" to solve this problem.") ) );
0255             }
0256 #endif // CDRECORD_SUID_ROOT_CHECK
0257 #endif
0258         }
0259 
0260         if( !k3bcore->externalBinManager()->binNeedGroup( "cdrdao" ).isEmpty() ) {
0261             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0262                                                i18n("Insufficient permissions for %1 executable: %2",QString("cdrdao"),k3bcore->externalBinManager()->binPath("cdrdao")),
0263                                                i18n("K3b uses cdrdao to actually write CDs."),
0264                                                i18n("Check permissions via Settings -> Configure K3b... -> Programs -> Permissions. "
0265                                                     "If K3b's default value is set make sure you are member of \"%1\" group.", k3bcore->externalBinManager()->binNeedGroup( "cdrdao" )) ) ) ;
0266         }
0267 
0268         else if( !k3bcore->externalBinManager()->foundBin( "cdrdao" ) ) {
0269             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0270                                                i18n("Unable to find %1 executable",QString("cdrdao")),
0271                                                i18n("K3b uses cdrdao to actually write CDs."),
0272                                                i18n("Install the cdrdao package.") ) );
0273         }
0274         else {
0275 #ifdef Q_OS_LINUX
0276 #ifdef CDRECORD_SUID_ROOT_CHECK
0277             if( !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "suidroot" ) && getuid() != 0 ) {
0278                 showBinSettingsButton = true;
0279                 problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0280                                                      i18n("%1 will be run without root privileges",QString("cdrdao")),
0281                                                      i18n("It is highly recommended to configure cdrdao "
0282                                                           "to run with root privileges to increase the "
0283                                                           "overall stability of the burning process."),
0284                                                      i18n("Click \"Configure K3b...\" to solve this problem.") ) );
0285             }
0286 #endif // CDRECORD_SUID_ROOT_CHECK
0287 #endif
0288         }
0289 
0290         if (!k3bcore->externalBinManager()->foundBin("cdrskin")) {
0291             problems.append(K3b::SystemProblem(K3b::SystemProblem::NON_CRITICAL,
0292                 i18n("Unable to find %1 executable", QString("cdrskin")),
0293                 i18n("Cdrskin can substitute for cdrecord with data and audio"
0294                      " CD, and for growisofs with DVD and BD."),
0295                 i18n("Consider to install the libburn and cdrskin packages.")));
0296         }
0297     }
0298 
0299 
0300     if( !k3bcore->deviceManager()->dvdWriter().isEmpty() ) {
0301 
0302         if( !k3bcore->externalBinManager()->binNeedGroup( "growisofs" ).isEmpty() ) {
0303             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0304                                                i18n("Insufficient permissions for %1 executable: %2",QString("growisofs"),k3bcore->externalBinManager()->binPath("growisofs")),
0305                                                i18n("K3b uses growisofs to actually write DVDs. "
0306                                                     "Without growisofs you will not be able to write DVDs. "
0307                                                     "Make sure to install at least version 5.10."),
0308                                                i18n("Check permissions via Settings -> Configure K3b... -> Programs -> Permissions. "
0309                                                     "If K3b's default value is set make sure you are member of \"%1\" group.", k3bcore->externalBinManager()->binNeedGroup( "growisofs" )) ) );
0310         }
0311 
0312         else if( !k3bcore->externalBinManager()->foundBin( "growisofs" ) ) {
0313             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0314                                                i18n("Unable to find %1 executable",QString("growisofs")),
0315                                                i18n("K3b uses growisofs to actually write DVDs. "
0316                                                     "Without growisofs you will not be able to write DVDs. "
0317                                                     "Make sure to install at least version 5.10."),
0318                                                i18n("Install the dvd+rw-tools package.") ) );
0319         }
0320         else {
0321             if( k3bcore->externalBinManager()->binObject( "growisofs" )->version() < K3b::Version( 5, 10 ) ) {
0322                 problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0323                                                    i18n("Used %1 version %2 is outdated",QString("growisofs"),k3bcore->externalBinManager()->binObject( "growisofs" )->version()),
0324                                                    i18n("K3b needs at least growisofs version 5.10 to write DVDs. "
0325                                                         "All older versions will not work and K3b will refuse to use them."),
0326                                                    i18n("Install a more recent version of %1.",QString("growisofs")) ) );
0327             }
0328             else if( k3bcore->externalBinManager()->binObject( "growisofs" )->version() < K3b::Version( 5, 12 ) ) {
0329                 problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0330                                                    i18n("Used %1 version %2 is outdated",QString("growisofs"),k3bcore->externalBinManager()->binObject( "growisofs" )->version()),
0331                                                    i18n("K3b will not be able to copy DVDs on-the-fly or write a DVD+RW in multiple "
0332                                                         "sessions using a growisofs "
0333                                                         "version older than 5.12."),
0334                                                    i18n("Install a more recent version of %1.",QString("growisofs")) ) );
0335             }
0336             else if( k3bcore->externalBinManager()->binObject( "growisofs" )->version() < K3b::Version( 7, 0 ) ) {
0337                 problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0338                                                    i18n("Used %1 version %2 is outdated",QString("growisofs"),k3bcore->externalBinManager()->binObject( "growisofs" )->version()),
0339                                                    i18n("It is highly recommended to use growisofs 7.0 or higher. "
0340                                                         "K3b will not be able to write a DVD+RW in multiple "
0341                                                         "sessions using a growisofs version older than 7.0." ),
0342                                                    i18n("Install a more recent version of %1.",QString("growisofs")) ) );
0343             }
0344 //            // for now we ignore the suid root bit because of the memorylocked issue
0345 //            else if( !k3bcore->externalBinManager()->binObject( "growisofs" )->hasFeature( "suidroot" ) ) {
0346 //                showBinSettingsButton = true;
0347 //                problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0348 //                                                     i18n("%1 will be run without root privileges","growisofs"),
0349 //                                                     i18n("It is highly recommended to configure growisofs "
0350 //                                                          "to run with root privileges. Only then growisofs "
0351 //                                                          "runs with high priority which increases the overall "
0352 //                                                          "stability of the burning process."),
0353 //                                                     i18n("Click \"Configure K3b...\" to solve this problem.") ) );
0354 //            }
0355         }
0356 
0357         if( !k3bcore->externalBinManager()->foundBin( "dvd+rw-format" ) ) {
0358             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0359                                                i18n("Unable to find %1 executable",QString("dvd+rw-format")),
0360                                                i18n("K3b uses dvd+rw-format to format DVD-RWs and DVD+RWs."),
0361                                                i18n("Install the dvd+rw-tools package.") ) );
0362         }
0363     }
0364 
0365     if( !k3bcore->externalBinManager()->foundBin( "mkisofs" ) ) {
0366 
0367     }
0368     else if( k3bcore->externalBinManager()->binObject( "mkisofs" )->hasFeature( "outdated" ) ) {
0369         problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0370                                            i18n("Used %1 version %2 is outdated",
0371                                                 QString("mkisofs"),
0372                                                 k3bcore->externalBinManager()->binObject( "mkisofs" )->version()),
0373                                            i18n("K3b needs at least mkisofs version 1.14. Older versions may introduce problems "
0374                                                 "when creating data projects."),
0375                                            i18n("Install a more recent version of %1.",QString("mkisofs")) ) );
0376     }
0377 
0378     // 2. device check
0379 #ifdef __GNUC__
0380 #warning Make sure we have a proper new kernel and cdrecord for simple dev= stuff
0381 #endif
0382     bool atapiWriter = false;
0383     bool dvd_r_dl = false;
0384     QList<K3b::Device::Device *> items(k3bcore->deviceManager()->readingDevices());
0385     for( QList<K3b::Device::Device *>::const_iterator it = items.constBegin();
0386          it != items.constEnd(); ++it ) {
0387         if( (*it)->type() & K3b::Device::DEVICE_DVD_R_DL )
0388             dvd_r_dl = true;
0389     }
0390 
0391 #ifdef HAVE_FSTAB_H
0392     // check automounted devices
0393     QList<K3b::Device::Device*> automountedDevices = checkForAutomounting();
0394     for( QList<K3b::Device::Device *>::const_iterator it = automountedDevices.constBegin();
0395          it != automountedDevices.constEnd(); ++it ) {
0396         problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0397                                            i18n("Device %1 - %2 is automounted.",
0398                                                 (*it)->vendor(),(*it)->description()),
0399                                            i18n("K3b is not able to unmount automounted devices. Thus, especially "
0400                                                 "DVD+RW rewriting might fail. There is no need to report this as "
0401                                                 "a bug or feature wish; it is not possible to solve this problem "
0402                                                 "from within K3b."),
0403                                            i18n("Replace the automounting entries in /etc/fstab with old-fashioned "
0404                                                 "ones or use a user-space mounting solution like pmount or ivman.") ) );
0405     }
0406 
0407 #endif
0408     if( atapiWriter ) {
0409         if( !K3b::plainAtapiSupport() &&
0410             !K3b::hackedAtapiSupport() ) {
0411             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0412                                                i18n("No ATAPI writing support in kernel"),
0413                                                i18n("Your kernel does not support writing without "
0414                                                     "SCSI emulation but there is at least one "
0415                                                     "writer in your system not configured to use "
0416                                                     "SCSI emulation."),
0417                                                i18n("The best and recommended solution is to enable "
0418                                                     "ide-scsi (SCSI emulation) for all devices. "
0419                                                     "This way you will not have any problems. "
0420                                                     "Be aware that you may still enable DMA on ide-scsi "
0421                                                     "emulated drives.") ) );
0422         }
0423         else {
0424             // we have atapi support in some way in the kernel
0425 
0426             if( k3bcore->externalBinManager()->foundBin( "cdrecord" ) ) {
0427 
0428                 if( !( cdrecordBin->hasFeature( "hacked-atapi" ) &&
0429                        K3b::hackedAtapiSupport() ) &&
0430                     !( cdrecordBin->hasFeature( "plain-atapi" ) &&
0431                        K3b::plainAtapiSupport() ) ) {
0432                     problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0433                                                        i18n("%1 %2 does not support ATAPI",QString("cdrecord"),cdrecordBin->version()),
0434                                                        i18n("The configured version of %1 does not "
0435                                                             "support writing to ATAPI devices without "
0436                                                             "SCSI emulation and there is at least one writer "
0437                                                             "in your system not configured to use "
0438                                                             "SCSI emulation.",QString("cdrecord")),
0439                                                        i18n("The best, and recommended, solution is to use "
0440                                                             "ide-scsi (SCSI emulation) for all writer devices: "
0441                                                             "this way you will not have any problems; or, you can install "
0442                                                             "(or select as the default) a more recent version of %1.",QString("cdrtools")) ) );
0443                 }
0444             }
0445 
0446             if( k3bcore->externalBinManager()->foundBin( "cdrdao" ) ) {
0447 
0448                 if( !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "hacked-atapi" ) &&
0449                     !k3bcore->externalBinManager()->binObject( "cdrdao" )->hasFeature( "plain-atapi") ) {
0450                     // FIXME: replace ">" with "&gt;"
0451                     problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0452                                                        i18n("%1 %2 does not support ATAPI",
0453                                                             QLatin1String( "cdrdao"),
0454                                                             k3bcore->externalBinManager()->binObject("cdrdao")->version().toString() ),
0455                                                        i18n("The configured version of %1 does not "
0456                                                             "support writing to ATAPI devices without "
0457                                                             "SCSI emulation and there is at least one writer "
0458                                                             "in your system not configured to use "
0459                                                             "SCSI emulation.", QLatin1String( "cdrdao" ) ),
0460                                                        K3b::simpleKernelVersion() > K3b::Version( 2, 5, 0 )
0461                                                        ? i18n("Install cdrdao >= 1.1.8 which supports writing to "
0462                                                               "ATAPI devices directly.")
0463                                                        : i18n("The best, and recommended, solution is to use "
0464                                                               "ide-scsi (SCSI emulation) for all writer devices: "
0465                                                               "this way you will not have any problems; or, you can install "
0466                                                               "(or select as the default) a more recent version of %1.",
0467                                                               QString("cdrdao")) ) );
0468                 }
0469             }
0470         }
0471     }
0472 
0473     if( dvd_r_dl && k3bcore->externalBinManager()->foundBin( "growisofs" ) && k3bcore->externalBinManager()->binNeedGroup( "growisofs" ).isEmpty() ) {
0474         if( k3bcore->externalBinManager()->binObject( "growisofs" )->version() < K3b::Version( 6, 0 ) ) {
0475             problems.append( K3b::SystemProblem( K3b::SystemProblem::NON_CRITICAL,
0476                                                i18n("Used %1 version %2 is outdated",QString("growisofs"),k3bcore->externalBinManager()->binObject( "growisofs" )->version()),
0477                                                i18n("K3b will not be able to write DVD-R Dual Layer media using a growisofs "
0478                                                     "version older than 6.0."),
0479                                                i18n("Install a more recent version of growisofs.") ) );
0480         }
0481     }
0482 
0483     QList<K3b::Device::Device *> items2(k3bcore->deviceManager()->allDevices());
0484     for( QList<K3b::Device::Device *>::const_iterator it = items2.constBegin();
0485          it != items2.constEnd(); ++it ) {
0486         K3b::Device::Device* dev = (*it);
0487 #ifndef Q_OS_WIN32
0488         if( !QFileInfo( dev->blockDeviceName() ).isWritable() ) {
0489             showDeviceSettingsButton = true;
0490             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0491                                                i18n("No write access to device %1",dev->blockDeviceName()),
0492                                                i18n("K3b needs write access to all the devices to perform certain tasks. "
0493                                                     "Without it you might encounter problems with %1 - %2",dev->vendor(),dev->description()),
0494                                                i18n("Make sure you have write access to %1. In case you are not using "
0495                                                     "devfs or udev click \"Modify Permissions...\" and setup permissions by hand.",dev->blockDeviceName()) ) );
0496         }
0497 
0498         if( !dmaActivated( dev ) ) {
0499             problems.append( K3b::SystemProblem( K3b::SystemProblem::CRITICAL,
0500                                                i18n("DMA disabled on device %1 - %2",dev->vendor(),dev->description()),
0501                                                i18n("With most modern CD/DVD/BD devices enabling DMA highly increases "
0502                                                     "read/write performance. If you experience very low writing speeds "
0503                                                     "this is probably the cause."),
0504                                                i18n("Enable DMA temporarily as root with 'hdparm -d 1 %1'.",dev->blockDeviceName()) ) );
0505         }
0506 #endif
0507     }
0508 
0509 
0510     //
0511     // Check if the user specified some user parameters and warn about it
0512     //
0513     const QMap<QString, K3b::ExternalProgram*>& programMap = k3bcore->externalBinManager()->programs();
0514     for( QMap<QString, K3b::ExternalProgram*>::const_iterator it = programMap.constBegin();
0515          it != programMap.constEnd(); ++it ) {
0516         const K3b::ExternalProgram* p = *it;
0517         if( !p->userParameters().isEmpty() ) {
0518             problems.append( K3b::SystemProblem( K3b::SystemProblem::WARNING,
0519                                                i18n("User parameters specified for external program %1",p->name()),
0520                                                i18n("Sometimes it may be necessary to specify user parameters in addition to "
0521                                                     "the parameters generated by K3b. This is simply a warning to make sure that "
0522                                                     "these parameters are really wanted and will not be part of some bug report."),
0523                                                i18n("To remove the user parameters for the external program %1 open the "
0524                                                     "K3b settings page 'Programs' and choose the tab 'User Parameters'."
0525                                                     ,p->name()) ) );
0526         }
0527     }
0528 
0529     //
0530     // Way too many users are complaining about K3b not being able to decode mp3 files. So just warn them about
0531     // the legal restrictions with many distros
0532     //
0533     QList<K3b::Plugin*> plugins = k3bcore->pluginManager()->plugins( "AudioDecoder" );
0534     bool haveMp3Decoder = false;
0535     for( QList<K3b::Plugin*>::const_iterator it = plugins.constBegin();
0536          it != plugins.constEnd(); ++it ) {
0537         const KPluginMetaData &metaData = (*it)->pluginMetaData();
0538         if (metaData.isValid() && metaData.pluginId() == "k3bmaddecoder" ) {
0539             haveMp3Decoder = true;
0540             break;
0541         }
0542     }
0543     if( !haveMp3Decoder ) {
0544         problems.append( K3b::SystemProblem( K3b::SystemProblem::WARNING,
0545                                            i18n("MP3 Audio Decoder plugin not found."),
0546                                            i18n("K3b could not load or find the MP3 decoder plugin. This means that you will not "
0547                                                 "be able to create Audio CDs from MP3 files. Many Linux distributions do not "
0548                                                 "include MP3 support for legal reasons."),
0549                                            i18n("To enable MP3 support, please install the MAD MP3 decoding library as well as the "
0550                                                 "K3b MAD MP3 decoder plugin (the latter may already be installed but not functional "
0551                                                 "due to the missing libmad). Some distributions allow installation of MP3 support "
0552                                                 "via an online update tool.") ) );
0553     }
0554 
0555 #ifdef HAVE_ICONV
0556     char* codec = nl_langinfo( CODESET );
0557     if( strcmp( codec, "ANSI_X3.4-1968" ) == 0 ) {
0558         //
0559         // On a glibc system the system locale defaults to ANSI_X3.4-1968
0560         // It is very unlikely that one would set the locale to ANSI_X3.4-1968
0561         // intentionally
0562         //
0563         problems.append( K3b::SystemProblem( K3b::SystemProblem::WARNING,
0564                                            i18n("System locale charset is ANSI_X3.4-1968"),
0565                                            i18n("Your system's locale charset (i.e. the charset used to encode filenames) "
0566                                                 "is set to ANSI_X3.4-1968. It is highly unlikely that this has been done "
0567                                                 "intentionally. Most likely the locale is not set at all. An invalid setting "
0568                                                 "will result in problems when creating data projects."),
0569                                            i18n("To properly set the locale charset make sure the LC_* environment variables "
0570                                                 "are set. Normally the distribution setup tools take care of this.") ) );
0571     }
0572 #endif
0573 
0574 
0575     //
0576     // Never run K3b as root and especially not suid root! The latter is not possible anyway since
0577     // the kdelibs refuse it.
0578     //
0579     if( ::getuid() == 0 ) {
0580         showDeviceSettingsButton = true;
0581         problems.append( K3b::SystemProblem( K3b::SystemProblem::WARNING,
0582                                            i18n("Running K3b as root user"),
0583                                            i18n("It is not recommended to run K3b under the root user account. "
0584                                                 "This introduces unnecessary security risks."),
0585                                            i18n("Run K3b from a proper user account and setup the device and "
0586                                                 "external tool permissions appropriately.")
0587                                            + ' ' + i18n("The latter can be done via \"Configure K3b...\".")
0588                                            ) );
0589     }
0590 
0591 
0592     qDebug() << "(K3b::Core) System problems:";
0593     for( QList<K3b::SystemProblem>::const_iterator it = problems.constBegin();
0594          it != problems.constEnd(); ++it ) {
0595         const K3b::SystemProblem& p = *it;
0596 
0597         switch( p.type ) {
0598         case K3b::SystemProblem::CRITICAL:
0599             qDebug() << " CRITICAL";
0600             break;
0601         case K3b::SystemProblem::NON_CRITICAL:
0602             qDebug() << " NON_CRITICAL";
0603             break;
0604         case K3b::SystemProblem::WARNING:
0605             qDebug() << " WARNING";
0606             break;
0607         }
0608         qDebug() << " PROBLEM:  " << p.problem << Qt::endl
0609                  << " DETAILS:  " << p.details << Qt::endl
0610                  << " SOLUTION: " << p.solution << Qt::endl << Qt::endl;
0611 
0612     }
0613     if( problems.isEmpty() ) {
0614         qDebug() << "          - none - ";
0615         if( level == AlwaysNotify ) {
0616             KNotification::event( "NoProblemsFound",
0617                                   i18n("System configured properly"),
0618                                   i18n("No problems found in system configuration.") );
0619         }
0620     }
0621     else {
0622         static K3b::SystemProblemDialog* s_openDlg = 0;
0623         if( s_openDlg )
0624             s_openDlg->close();
0625         K3b::SystemProblemDialog dlg( problems, showDeviceSettingsButton, showBinSettingsButton, forceCheck, parent );
0626         s_openDlg = &dlg;
0627         dlg.exec();
0628         s_openDlg = 0;
0629     }
0630 
0631     // remember which version of K3b checked the system the last time
0632     KConfigGroup cfg( KSharedConfig::openConfig(), QStringLiteral("General Options") );
0633     cfg.writeEntry( "Last system check version", QString(k3bcore->version()) );
0634 }
0635 
0636 void K3b::SystemProblemDialog::slotShowDeviceSettings()
0637 {
0638     k3bappcore->k3bMainWindow()->showOptionDialog( OptionDialog::Devices );
0639 }
0640 
0641 
0642 void K3b::SystemProblemDialog::slotShowBinSettings()
0643 {
0644     k3bappcore->k3bMainWindow()->showOptionDialog( OptionDialog::Programs );
0645 }
0646 
0647 
0648 int K3b::SystemProblemDialog::dmaActivated( K3b::Device::Device* dev )
0649 {
0650     QString hdparm = K3b::findExe( "hdparm" );
0651     if( hdparm.isEmpty() )
0652         return -1;
0653 
0654     KProcess p;
0655     p.setOutputChannelMode( KProcess::MergedChannels );
0656 
0657     p << hdparm << "-d" << dev->blockDeviceName();
0658     p.start();
0659     if( !p.waitForFinished( -1 ) )
0660         return -1;
0661 
0662     // output is something like:
0663     //
0664     // /dev/hda:
0665     //  using_dma    =  1 (on)
0666     //
0667     // But we ignore the on/off since it might be translated
0668     //
0669     QByteArray out = p.readAll();
0670     if( out.contains( "1 (" ) )
0671         return 1;
0672     else if( out.contains( "0 (" ) )
0673         return 0;
0674     else
0675         return -1;
0676 }
0677 
0678 
0679 #ifdef HAVE_FSTAB_H
0680 QList<K3b::Device::Device*> K3b::SystemProblemDialog::checkForAutomounting()
0681 {
0682     QList<K3b::Device::Device *> l;
0683     ::setfsent();
0684 
0685     struct fstab * mountInfo = 0;
0686     while( (mountInfo = ::getfsent()) )
0687     {
0688         // check if the entry corresponds to a device
0689         QString md = K3b::resolveLink( QFile::decodeName( mountInfo->fs_spec ) );
0690         QString type = QFile::decodeName( mountInfo->fs_vfstype );
0691 
0692         if( type == "supermount" || type == "subfs" ) {
0693             // parse the device
0694             QStringList opts = QString::fromLocal8Bit(mountInfo->fs_mntops).split( ',' );
0695             for( QStringList::const_iterator it = opts.constBegin(); it != opts.constEnd(); ++it ) {
0696                 if( (*it).startsWith("dev=") ) {
0697                     md = (*it).mid( 4 );
0698                     break;
0699                 }
0700             }
0701 
0702             if( K3b::Device::Device* dev = k3bcore->deviceManager()->findDevice( md ) )
0703                 l.append( dev );
0704         }
0705     } // while mountInfo
0706 
0707     ::endfsent();
0708     return l;
0709 }
0710 #endif
0711 
0712 
0713 bool K3b::SystemProblemDialog::readCheckSystemConfig()
0714 {
0715     KConfigGroup cfgGrp(KSharedConfig::openConfig(), QStringLiteral("General Options"));
0716 
0717     K3b::Version configVersion(cfgGrp.readEntry( "Last system check version", "0.1" ));
0718     if (configVersion < k3bcore->version())
0719         cfgGrp.writeEntry("check system config", true);
0720 
0721     return cfgGrp.readEntry("check system config", false);
0722 }
0723 
0724 #include "moc_k3bsystemproblemdialog.cpp"