File indexing completed on 2024-04-14 05:43:23

0001 /*
0002 
0003     This file is part of the KFloppy program, part of the KDE project
0004 
0005     Copyright (C) 2002 Adriaan de Groot <groot@kde.org>
0006     Copyright (C) 2004, 2005 Nicolas GOUTTE <goutte@kde.org>
0007     Copyright (C) 2015, 2016 Wolfgang Bauer <wbauer@tmo.at>
0008 
0009     This program is free software; you can redistribute it and/or modify
0010     it under the terms of the GNU General Public License as published by
0011     the Free Software Foundation, version 2.
0012 
0013     This program is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016     GNU General Public License for more details.
0017 
0018     You should have received a copy of the GNU General Public License
0019     along with this program; if not, write to the Free Software
0020     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0021 
0022 */
0023 
0024 #include "format.h"
0025 
0026 #include <stdlib.h>
0027 #include <unistd.h>
0028 
0029 #include "qplatformdefs.h"
0030 #include <QRegExp>
0031 #include <QStandardPaths>
0032 #include <QTimer>
0033 
0034 #include <KLocalizedString>
0035 #include <KProcess>
0036 
0037 static QStringList extPath = QStringList();
0038 
0039 /* static */ QString findExecutable(const QString &e)
0040 {
0041     if (extPath.isEmpty()) {
0042         QStringList path = QString::fromLocal8Bit(qgetenv("PATH")).split(QStringLiteral(":"));
0043         path.append(QStringLiteral("/usr/sbin"));
0044         path.append(QStringLiteral("/sbin"));
0045         extPath = path;
0046     }
0047 
0048     return QStandardPaths::findExecutable(e, extPath);
0049 }
0050 
0051 KFAction::KFAction(QObject *parent)
0052     : QObject(parent)
0053 {
0054     DEBUGSETUP;
0055 }
0056 
0057 KFAction::~KFAction()
0058 {
0059     DEBUGSETUP;
0060     quit();
0061 }
0062 
0063 /* slot */ void KFAction::quit()
0064 {
0065     DEBUGSETUP;
0066 }
0067 
0068 /* slot */ void KFAction::exec()
0069 {
0070     DEBUGSETUP;
0071 }
0072 
0073 class KFActionQueue_p
0074 {
0075 public:
0076     QList<KFAction *> list;
0077 };
0078 
0079 KFActionQueue::KFActionQueue(QObject *parent)
0080     : KFAction(parent)
0081     , d(new KFActionQueue_p)
0082 {
0083     DEBUGSETUP;
0084 }
0085 
0086 KFActionQueue::~KFActionQueue()
0087 {
0088     DEBUGSETUP;
0089     qDeleteAll(d->list);
0090     d->list.clear();
0091     delete d;
0092 }
0093 
0094 void KFActionQueue::queue(KFAction *p)
0095 {
0096     DEBUGSETUP;
0097 
0098     d->list.append(p);
0099     DEBUGS(p->objectName());
0100 }
0101 
0102 /* virtual */ void KFActionQueue::exec()
0103 {
0104     DEBUGSETUP;
0105 
0106     actionDone(nullptr, true);
0107 }
0108 
0109 /* slot */ void KFActionQueue::actionDone(KFAction *p, bool success)
0110 {
0111     DEBUGSETUP;
0112 
0113     if (p) {
0114         if (!d->list.isEmpty() && d->list.first() == p) {
0115             d->list.removeFirst();
0116             delete p;
0117         } else {
0118             DEBUGS("Strange pointer received.");
0119             Q_EMIT done(this, false);
0120             return;
0121         }
0122     } else {
0123         DEBUGS("Starting action queue.");
0124     }
0125 
0126     if (!success) {
0127         DEBUGS("Action failed.");
0128         Q_EMIT done(this, false);
0129         return;
0130     }
0131 
0132     KFAction *next = d->list.isEmpty() ? nullptr : d->list.first();
0133     if (!next) {
0134         Q_EMIT done(this, true);
0135     } else {
0136         qCDebug(KFLOPPY_LOG) << "Running action " << next->objectName();
0137         QObject::connect(next, &KFAction::done, this, &KFActionQueue::actionDone);
0138         // Propagate signals
0139         QObject::connect(next, &KFAction::status, this, &KFAction::status);
0140         QTimer::singleShot(0, next, &KFAction::exec);
0141     }
0142 }
0143 
0144 // Here we have names of devices. The variable
0145 // names are basically the linux device names,
0146 // replace with whatever your OS needs instead.
0147 //
0148 //
0149 #ifdef ANY_LINUX
0150 
0151 const char *const fd0H1440[] = {"/dev/fd0u1440", "/dev/floppy/0u1440", "/dev/fd0h1440", "/dev/fd0H1440", "/dev/fd0", nullptr};
0152 const char *const fd0D720[] = {"/dev/fd0u720", "/dev/floppy/0u720", "/dev/fd0D720", "/dev/fd0h720", "/dev/fd0", nullptr};
0153 const char *const fd0h1200[] = {"/dev/fd0h1200", "/dev/floppy/0h1200", "/dev/fd0", nullptr};
0154 const char *const fd0h360[] = {"/dev/fd0u360", "/dev/floppy/0u360", "/dev/fd0h360", "/dev/fd0d360", "/dev/fd0", nullptr};
0155 
0156 const char *const fd1H1440[] = {"/dev/fd1u1440", "/dev/floppy/1u1440", "/dev/fd1h1440", "/dev/fd1H1440", "/dev/fd1", nullptr};
0157 const char *const fd1D720[] = {"/dev/fd1u720", "/dev/floppy/1u720", "/dev/fd1D720", "/dev/fd1h720", "/dev/fd1", nullptr};
0158 const char *const fd1h1200[] = {"/dev/fd1h1200", "/dev/floppy/1h1200", "/dev/fd1", nullptr};
0159 const char *const fd1h360[] = {"/dev/fd1u360", "/dev/floppy/1u360", "/dev/fd1h360", "/dev/fd1d360", "/dev/fd1", nullptr};
0160 
0161 const char *const fd0auto[] = {"/dev/fd0", nullptr};
0162 const char *const fd1auto[] = {"/dev/fd1", nullptr};
0163 
0164 #endif
0165 
0166 #ifdef ANY_BSD
0167 const char *const fd0[] = {"/dev/fd0", nullptr};
0168 const char *const fd1[] = {"/dev/fd1", nullptr};
0169 #endif
0170 
0171 // Next we have a table of device names and characteristics.
0172 // These are ordered according to 2*densityIndex+deviceIndex,
0173 // ie. primary (0) 1440K (0) is first, then secondary (1) 1440K is
0174 // second, down to secondary (1) 360k (4) in position 3*2+1=7.
0175 //
0176 //
0177 // Note that the data originally contained in KFloppy was
0178 // patently false, so most of this is fake. I guess no one ever
0179 // formatted a 5.25" floppy.
0180 //
0181 // The flags field is unused in this implementation.
0182 //
0183 //
0184 const fdinfo fdtable[] = {
0185 #ifdef ANY_LINUX
0186     // device  drv blks trk flg
0187     {fd0H1440, 0, 1440, 80, 0},
0188     {fd1H1440, 1, 1440, 80, 0},
0189     {fd0D720, 0, 720, 80, 0},
0190     {fd1D720, 1, 720, 80, 0},
0191     {fd0h1200, 0, 1200, 80, 0},
0192     {fd1h1200, 1, 1200, 80, 0},
0193     {fd0h360, 0, 360, 40, 0},
0194     {fd1h360, 1, 360, 40, 0},
0195     {fd0auto, 0, 0, 80, 0},
0196     {fd1auto, 1, 0, 80, 0},
0197 #endif
0198 
0199 #ifdef ANY_BSD
0200     // Instead of the number of tracks, which is
0201     // unneeded, we record the
0202     // number of F's printed during an fdformat
0203     {fd0, 0, 1440, 40, 0},
0204     {fd1, 1, 1440, 40, 0},
0205     {fd0, 0, 720, 40, 0},
0206     {fd1, 1, 720, 40, 0},
0207     {fd0, 0, 1200, 40, 0},
0208     {fd1, 1, 1200, 40, 0},
0209     {fd0, 0, 360, 40, 0},
0210     {fd1, 1, 360, 40, 0},
0211 #endif
0212     {nullptr, 0, 0, 0, 0}};
0213 
0214 FloppyAction::FloppyAction(QObject *p)
0215     : KFAction(p)
0216     , deviceInfo(nullptr)
0217     , theProcess(nullptr)
0218 {
0219     DEBUGSETUP;
0220 }
0221 
0222 void FloppyAction::quit()
0223 {
0224     DEBUGSETUP;
0225     delete theProcess;
0226     theProcess = nullptr;
0227 
0228     KFAction::quit();
0229 }
0230 
0231 bool FloppyAction::configureDevice(const QString &newDeviceName)
0232 {
0233     deviceInfo = nullptr; // We have not any idea what the device is
0234     deviceName = newDeviceName;
0235     return true; // No problem!
0236 }
0237 
0238 bool FloppyAction::configureDevice(int drive, int density)
0239 {
0240     DEBUGSETUP;
0241     const char *devicename = nullptr;
0242 
0243     deviceInfo = nullptr;
0244     deviceName.clear();
0245 
0246     if ((drive < 0) || (drive > 1)) {
0247         Q_EMIT status(i18n("Unexpected drive number %1.", drive), -1);
0248         return false;
0249     }
0250 
0251     const fdinfo *deviceinfo = fdtable;
0252     for (; deviceinfo && (deviceinfo->devices); deviceinfo++) {
0253         if (deviceinfo->blocks != density)
0254             continue;
0255     }
0256     if (!deviceinfo) {
0257         Q_EMIT status(i18n("Unexpected density number %1.", density), -1);
0258         return false;
0259     }
0260 
0261     deviceinfo = fdtable;
0262     for (; deviceinfo && (deviceinfo->devices); deviceinfo++) {
0263         if (deviceinfo->blocks != density)
0264             continue;
0265         if (deviceinfo->drive == drive)
0266             break;
0267     }
0268 
0269     if (!deviceinfo || !deviceinfo->devices) {
0270         Q_EMIT status(i18n("Cannot find a device for drive %1 and density %2.", drive, density), -1);
0271         return false;
0272     }
0273 
0274     for (const char *const *devices = deviceinfo->devices; *devices; devices++) {
0275         if (QT_ACCESS(*devices, W_OK) >= 0) {
0276             qCDebug(KFLOPPY_LOG) << "Found device " << *devices;
0277             devicename = *devices;
0278             break;
0279         }
0280     }
0281 
0282     if (!devicename) {
0283         const QString str = i18n(
0284             "Cannot access %1\nMake sure that the device exists and that "
0285             "you have write permission to it.",
0286             QLatin1String(deviceinfo->devices[0]));
0287         Q_EMIT status(str, -1);
0288         return false;
0289     }
0290 
0291     deviceName = QLatin1String(devicename);
0292     deviceInfo = deviceinfo;
0293 
0294     return true;
0295 }
0296 
0297 void FloppyAction::readStdOut()
0298 {
0299     processStdOut(QString::fromUtf8(theProcess->readAllStandardOutput()));
0300 }
0301 
0302 void FloppyAction::readStdErr()
0303 {
0304     processStdOut(QString::fromUtf8(theProcess->readAllStandardError()));
0305 }
0306 
0307 void FloppyAction::processDone(int exitCode, QProcess::ExitStatus exitStatus)
0308 {
0309     DEBUGSETUP;
0310 
0311     if (exitStatus == QProcess::NormalExit) {
0312         if (exitCode == 0) {
0313             Q_EMIT status(QString(), 100);
0314             Q_EMIT done(this, true);
0315         } else {
0316             Q_EMIT status(i18n("The program %1 terminated with an error.", theProcessName), 100);
0317             Q_EMIT done(this, false);
0318         }
0319     } else {
0320         Q_EMIT status(i18n("The program %1 terminated abnormally.", theProcessName), 100);
0321         Q_EMIT done(this, false);
0322     }
0323 }
0324 
0325 void FloppyAction::processStdOut(const QString &s)
0326 {
0327     qCDebug(KFLOPPY_LOG) << "stdout:" << s;
0328 }
0329 
0330 void FloppyAction::processStdErr(const QString &s)
0331 {
0332     processStdOut(s);
0333 }
0334 
0335 bool FloppyAction::startProcess()
0336 {
0337     DEBUGSETUP;
0338 
0339     connect(theProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processDone(int, QProcess::ExitStatus)));
0340     connect(theProcess, &QProcess::readyReadStandardOutput, this, &FloppyAction::readStdOut);
0341     connect(theProcess, &QProcess::readyReadStandardError, this, &FloppyAction::readStdErr);
0342 
0343     theProcess->setEnv(QStringLiteral("LC_ALL"), QStringLiteral("C")); // We need the untranslated output of the tool
0344     theProcess->setOutputChannelMode(KProcess::SeparateChannels);
0345     theProcess->start();
0346     return (theProcess->exitStatus() == QProcess::NormalExit);
0347 }
0348 
0349 /* static */ QString FDFormat::fdformatName = QString();
0350 
0351 FDFormat::FDFormat(QObject *p)
0352     : FloppyAction(p)
0353     , doVerify(true)
0354 {
0355     DEBUGSETUP;
0356     theProcessName = QStringLiteral("fdformat");
0357     setObjectName(QStringLiteral("FDFormat"));
0358 }
0359 
0360 /* static */ bool FDFormat::runtimeCheck()
0361 {
0362     fdformatName = findExecutable(QStringLiteral("fdformat"));
0363     return (!fdformatName.isEmpty());
0364 }
0365 
0366 bool FDFormat::configure(bool v)
0367 {
0368     doVerify = v;
0369     return true;
0370 }
0371 
0372 /* virtual */ void FDFormat::exec()
0373 {
0374     DEBUGSETUP;
0375 
0376     if (!deviceInfo || deviceName.isEmpty()) {
0377         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0378         Q_EMIT done(this, false);
0379         return;
0380     }
0381 
0382     if (fdformatName.isEmpty()) {
0383         Q_EMIT status(i18n("Cannot find fdformat."), -1);
0384         Q_EMIT done(this, false);
0385         return;
0386     }
0387 
0388     delete theProcess;
0389     theProcess = new KProcess;
0390 
0391     formatTrackCount = 0;
0392 
0393     *theProcess << fdformatName;
0394 
0395     // Common to Linux and BSD, others may differ
0396     if (!doVerify) {
0397         *theProcess << QStringLiteral("-n");
0398     }
0399 
0400 #ifdef ANY_BSD
0401     *theProcess << QStringLiteral("-y") << QStringLiteral("-f") << QString::number(deviceInfo->blocks);
0402 #elif defined(ANY_LINUX)
0403     // No Linux-specific flags
0404 #endif
0405 
0406     // Common to Linux and BSD, others may differ
0407     *theProcess << deviceName;
0408 
0409     if (!startProcess()) {
0410         Q_EMIT status(i18n("Could not start fdformat."), -1);
0411         Q_EMIT done(this, false);
0412     }
0413 
0414     // Now depend on fdformat running and producing output.
0415 }
0416 
0417 // Parse some output from the fdformat process. Lots of
0418 // #ifdefs here to account for variations in the basic
0419 // fdformat. Uses gotos to branch to whatever error message we
0420 // need, since the messages can be standardized across OSsen.
0421 //
0422 //
0423 void FDFormat::processStdOut(const QString &s)
0424 {
0425     DEBUGSETUP;
0426 
0427 #ifdef ANY_BSD
0428     if (s[0] == QLatin1Char('F')) {
0429         formatTrackCount++;
0430         Q_EMIT status(QString(), formatTrackCount * 100 / deviceInfo->tracks);
0431     } else if (s[0] == QLatin1Char('E')) {
0432         Q_EMIT status(i18n("Error formatting track %1.", formatTrackCount), -1);
0433     } else {
0434         if (s.contains(QLatin1String("ioctl(FD_FORM)"))) {
0435             Q_EMIT status(i18n("Cannot access floppy or floppy drive.\n"
0436                                "Please insert a floppy and make sure that you "
0437                                "have selected a valid floppy drive."),
0438                           -1);
0439             return;
0440         }
0441         if (s.indexOf(QLatin1String("/dev/")) >= 0) {
0442             Q_EMIT status(s, -1);
0443             return;
0444         }
0445         DEBUGS(s);
0446     }
0447 #elif defined(ANY_LINUX)
0448     DEBUGS(s);
0449     QRegExp regexp(QStringLiteral("([0-9]+)"));
0450     if (s.startsWith(QLatin1String("bad data at cyl")) || s.contains(QLatin1String("Problem reading cylinder"))) {
0451         if (regexp.indexIn(s) > -1) {
0452             const int track = regexp.cap(1).toInt();
0453             Q_EMIT status(i18n("Low-level formatting error at track %1.", track), -1);
0454         } else {
0455             // This error should not happen
0456             Q_EMIT status(i18n("Low-level formatting error: %1", s), -1);
0457         }
0458         return;
0459     } else if (s.contains(QLatin1String("ioctl(FDFMTBEG)"))) {
0460         Q_EMIT status(i18n("Cannot access floppy or floppy drive.\n"
0461                            "Please insert a floppy and make sure that you "
0462                            "have selected a valid floppy drive."),
0463                       -1);
0464         return;
0465     } else if (s.contains(QLatin1String("busy"))) // "Device or resource busy"
0466     {
0467         Q_EMIT status(i18n("Device busy.\nPerhaps you need to unmount the floppy first."), -1);
0468         return;
0469     }
0470     // Be careful to leave "iotcl" as last before checking numbers
0471     else if (s.contains(QLatin1String("ioctl"))) {
0472         Q_EMIT status(i18n("Low-level format error: %1", s), -1);
0473         return;
0474     }
0475     // Check for numbers at last (as /dev/fd0u1440 has numbers too)
0476     else if (regexp.indexIn(s) > -1) {
0477         // Normal track number (formatting or verifying)
0478         const int p = regexp.cap(1).toInt();
0479         if ((p >= 0) && (p < deviceInfo->tracks)) {
0480             Q_EMIT status(QString(), p * 100 / deviceInfo->tracks);
0481         }
0482     }
0483 #endif
0484     return;
0485 }
0486 
0487 /* static */ QString DDZeroOut::m_ddName = QString();
0488 
0489 DDZeroOut::DDZeroOut(QObject *p)
0490     : FloppyAction(p)
0491 {
0492     qCDebug(KFLOPPY_LOG) << k_funcinfo;
0493     theProcessName = QStringLiteral("dd");
0494     setObjectName(QStringLiteral("DD"));
0495 }
0496 
0497 /* static */ bool DDZeroOut::runtimeCheck()
0498 {
0499     m_ddName = findExecutable(QStringLiteral("dd"));
0500     return (!m_ddName.isEmpty());
0501 }
0502 
0503 /* virtual */ void DDZeroOut::exec()
0504 {
0505     qCDebug(KFLOPPY_LOG) << k_funcinfo;
0506 
0507     if (deviceName.isEmpty()) {
0508         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0509         Q_EMIT done(this, false);
0510         return;
0511     }
0512 
0513     if (m_ddName.isEmpty()) {
0514         Q_EMIT status(i18n("Cannot find dd."), -1);
0515         Q_EMIT done(this, false);
0516         return;
0517     }
0518 
0519     delete theProcess;
0520     theProcess = new KProcess;
0521 
0522     *theProcess << m_ddName;
0523 
0524     *theProcess << QStringLiteral("if=/dev/zero");
0525     *theProcess << QStringLiteral("of=") + deviceName;
0526 
0527     if (!startProcess()) {
0528         Q_EMIT status(i18n("Could not start dd."), -1);
0529         Q_EMIT done(this, false);
0530     }
0531 }
0532 
0533 void DDZeroOut::processDone(int exitCode, QProcess::ExitStatus exitStatus)
0534 {
0535     Q_UNUSED(exitCode);
0536     Q_UNUSED(exitStatus);
0537 
0538     qCDebug(KFLOPPY_LOG) << k_funcinfo;
0539 
0540     /**
0541      * As we do not give a number of blocks to dd(1), it will stop
0542      * with the error "No space left on device"
0543      *
0544      * ### TODO: really check if the exit is not on an other error and then abort the formatting
0545      */
0546     Q_EMIT status(QString(), 100);
0547     Q_EMIT done(this, true);
0548 }
0549 
0550 /* static */ QString FATFilesystem::newfs_fat = QString();
0551 
0552 FATFilesystem::FATFilesystem(QObject *parent)
0553     : FloppyAction(parent)
0554 {
0555     DEBUGSETUP;
0556     runtimeCheck();
0557     theProcessName = newfs_fat;
0558     setObjectName(QStringLiteral("FATFilesystem"));
0559 }
0560 
0561 /* static */ bool FATFilesystem::runtimeCheck()
0562 {
0563     DEBUGSETUP;
0564 
0565 #ifdef ANY_BSD
0566     newfs_fat = findExecutable(QStringLiteral("newfs_msdos"));
0567 #elif defined(ANY_LINUX)
0568     newfs_fat = findExecutable(QStringLiteral("mkdosfs"));
0569 #else
0570     return false;
0571 #endif
0572 
0573     return !newfs_fat.isEmpty();
0574 }
0575 
0576 bool FATFilesystem::configure(bool v, bool l, const QString &lbl)
0577 {
0578     doVerify = v;
0579     doLabel = l;
0580     if (l)
0581         label = lbl.simplified();
0582     else
0583         label.clear();
0584 
0585     return true;
0586 }
0587 
0588 void FATFilesystem::exec()
0589 {
0590     DEBUGSETUP;
0591 
0592     if (
0593 #ifdef ANY_BSD // BSD needs the deviceInfo for the block count
0594         !deviceInfo ||
0595 #endif
0596         deviceName.isEmpty()) {
0597         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0598         Q_EMIT done(this, false);
0599         return;
0600     }
0601 
0602     if (newfs_fat.isEmpty()) {
0603         Q_EMIT status(i18n("Cannot find a program to create FAT filesystems."), -1);
0604         Q_EMIT done(this, false);
0605         return;
0606     }
0607 
0608     delete theProcess;
0609     KProcess *p = theProcess = new KProcess;
0610 
0611     *p << newfs_fat;
0612 #ifdef ANY_BSD
0613     *p << QStringLiteral("-f") << QString::number(deviceInfo->blocks);
0614     if (doLabel) {
0615         *p << QStringLiteral("-L") << label;
0616     }
0617 #else
0618 #ifdef ANY_LINUX
0619     if (doLabel) {
0620         *p << QStringLiteral("-n") << label;
0621     }
0622     if (doVerify) {
0623         *p << QStringLiteral("-c");
0624     }
0625 #endif
0626 #endif
0627     *p << deviceName;
0628 
0629     if (!startProcess()) {
0630         Q_EMIT status(i18n("Cannot start FAT format program."), -1);
0631         Q_EMIT done(this, false);
0632     }
0633 }
0634 
0635 void FATFilesystem::processStdOut(const QString &s)
0636 {
0637 #ifdef ANY_BSD
0638     // ### TODO: do some checks
0639 #elif defined(ANY_LINUX)
0640     qCDebug(KFLOPPY_LOG) << s;
0641     if (s.contains(QLatin1String("mounted"))) // "/dev/fd0 contains a mounted filesystem"
0642     {
0643         Q_EMIT status(i18n("Floppy is mounted.\nYou need to unmount the floppy first."), -1);
0644         return;
0645     } else if (s.contains(QLatin1String("busy"))) // "Device or resource busy"
0646     {
0647         Q_EMIT status(i18n("Device busy.\nPerhaps you need to unmount the floppy first."), -1);
0648         return;
0649     } else if (s.contains(QLatin1String("denied"))) // "Permission denied"
0650     {
0651         Q_EMIT status(s, -1);
0652         return;
0653     }
0654 #if 0
0655     else if ( s.find( "mkdosfs" ) != -1 ) // DEBUG: get the program header and show it!
0656     {
0657         Q_EMIT status( s, -1 );
0658         return;
0659     }
0660 #endif
0661 #endif
0662 }
0663 
0664 #ifdef ANY_BSD
0665 
0666 /* static */ QString UFSFilesystem::newfs = QString();
0667 
0668 UFSFilesystem::UFSFilesystem(QObject *parent)
0669     : FloppyAction(parent)
0670 {
0671     DEBUGSETUP;
0672     runtimeCheck();
0673     theProcessName = newfs;
0674     setObjectName(QStringLiteral("UFSFilesystem"));
0675 }
0676 
0677 /* static */ bool UFSFilesystem::runtimeCheck()
0678 {
0679     DEBUGSETUP;
0680 
0681     newfs = findExecutable(QStringLiteral("newfs"));
0682 
0683     return !newfs.isEmpty();
0684 }
0685 
0686 void UFSFilesystem::exec()
0687 {
0688     DEBUGSETUP;
0689 
0690     if (deviceName.isEmpty()) {
0691         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0692         Q_EMIT done(this, false);
0693         return;
0694     }
0695 
0696     if (newfs.isEmpty()) {
0697         Q_EMIT status(i18nc("BSD", "Cannot find a program to create UFS filesystems."), -1);
0698         Q_EMIT done(this, false);
0699         return;
0700     }
0701 
0702     delete theProcess;
0703     KProcess *p = theProcess = new KProcess;
0704 
0705     *p << newfs;
0706 
0707     // ### TODO: is it still needed? (FreeBSD 5.3's man page says: "For backward compatibility.")
0708     if (deviceInfo)
0709         *p << QStringLiteral("-T") << QStringLiteral("fd%1").arg(deviceInfo->blocks);
0710 
0711     *p << deviceName;
0712 
0713     if (!startProcess()) {
0714         Q_EMIT status(i18nc("BSD", "Cannot start UFS format program."), -1);
0715         Q_EMIT done(this, false);
0716     }
0717 }
0718 #endif
0719 
0720 /* static */ QString Ext2Filesystem::newfs = QString();
0721 
0722 Ext2Filesystem::Ext2Filesystem(QObject *parent)
0723     : FloppyAction(parent)
0724 {
0725     DEBUGSETUP;
0726     runtimeCheck();
0727     theProcessName = QStringLiteral("mke2fs");
0728     setObjectName(QStringLiteral("Ext2Filesystem"));
0729 }
0730 
0731 /* static */ bool Ext2Filesystem::runtimeCheck()
0732 {
0733     DEBUGSETUP;
0734 
0735     newfs = findExecutable(QStringLiteral("mke2fs"));
0736 
0737     return !newfs.isEmpty();
0738 }
0739 
0740 bool Ext2Filesystem::configure(bool v, bool l, const QString &lbl)
0741 {
0742     doVerify = v;
0743     doLabel = l;
0744     if (l) {
0745         label = lbl.trimmed();
0746     } else {
0747         label.clear();
0748     }
0749 
0750     return true;
0751 }
0752 
0753 void Ext2Filesystem::exec()
0754 {
0755     DEBUGSETUP;
0756 
0757     if (
0758 #ifdef ANY_BSD // BSD needs the deviceInfo for the block count
0759         !deviceInfo ||
0760 #endif
0761         deviceName.isEmpty()) {
0762         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0763         Q_EMIT done(this, false);
0764         return;
0765     }
0766 
0767     if (newfs.isEmpty()) {
0768         Q_EMIT status(i18n("Cannot find a program to create ext2 filesystems."), -1);
0769         Q_EMIT done(this, false);
0770         return;
0771     }
0772 
0773     delete theProcess;
0774     KProcess *p = theProcess = new KProcess;
0775 
0776     *p << newfs;
0777     *p << QStringLiteral("-q");
0778     if (doVerify)
0779         *p << QStringLiteral("-c");
0780     if (doLabel)
0781         *p << QStringLiteral("-L") << label;
0782 
0783     *p << deviceName;
0784 
0785     if (!startProcess()) {
0786         Q_EMIT status(i18n("Cannot start ext2 format program."), -1);
0787         Q_EMIT done(this, false);
0788     }
0789 }
0790 
0791 void Ext2Filesystem::processStdOut(const QString &s)
0792 {
0793 #ifdef ANY_BSD
0794     // ### TODO: do some checks
0795 #elif defined(ANY_LINUX)
0796     qCDebug(KFLOPPY_LOG) << s;
0797     if (s.contains(QLatin1String("mounted"))) // "/dev/fd0 is mounted; will not make a filesystem here!"
0798     {
0799         Q_EMIT status(i18n("Floppy is mounted.\nYou need to unmount the floppy first."), -1);
0800         return;
0801     } else if (s.contains(QLatin1String("busy"))) // "Device or resource busy"
0802     {
0803         Q_EMIT status(i18n("Device busy.\nPerhaps you need to unmount the floppy first."), -1);
0804         return;
0805     } else if (s.contains(QLatin1String("denied"))) // "Permission denied"
0806     {
0807         Q_EMIT status(s, -1);
0808         return;
0809     }
0810 #endif
0811 }
0812 
0813 #ifdef ANY_LINUX
0814 /* static */ QString MinixFilesystem::newfs = QString();
0815 
0816 MinixFilesystem::MinixFilesystem(QObject *parent)
0817     : FloppyAction(parent)
0818 {
0819     DEBUGSETUP;
0820     runtimeCheck();
0821     theProcessName = QStringLiteral("mkfs.minix");
0822     setObjectName(QStringLiteral("Minix2Filesystem"));
0823 }
0824 
0825 /* static */ bool MinixFilesystem::runtimeCheck()
0826 {
0827     DEBUGSETUP;
0828 
0829     newfs = findExecutable(QStringLiteral("mkfs.minix"));
0830 
0831     return !newfs.isEmpty();
0832 }
0833 
0834 bool MinixFilesystem::configure(bool v, bool l, const QString &lbl)
0835 {
0836     doVerify = v;
0837     doLabel = l;
0838     if (l) {
0839         label = lbl.trimmed();
0840     } else {
0841         label.clear();
0842     }
0843 
0844     return true;
0845 }
0846 
0847 void MinixFilesystem::exec()
0848 {
0849     DEBUGSETUP;
0850 
0851     if (deviceName.isEmpty()) {
0852         Q_EMIT status(i18n("Internal error: device not correctly defined."), -1);
0853         Q_EMIT done(this, false);
0854         return;
0855     }
0856 
0857     if (newfs.isEmpty()) {
0858         Q_EMIT status(i18n("Cannot find a program to create Minix filesystems."), -1);
0859         Q_EMIT done(this, false);
0860         return;
0861     }
0862 
0863     delete theProcess;
0864     KProcess *p = theProcess = new KProcess;
0865 
0866     *p << newfs;
0867 
0868     // Labeling is not possible
0869     if (doVerify)
0870         *p << QStringLiteral("-c");
0871 
0872     *p << deviceName;
0873 
0874     if (!startProcess()) {
0875         Q_EMIT status(i18n("Cannot start Minix format program."), -1);
0876         Q_EMIT done(this, false);
0877     }
0878 }
0879 
0880 void MinixFilesystem::processStdOut(const QString &s)
0881 {
0882     qCDebug(KFLOPPY_LOG) << s;
0883     if (s.contains(QLatin1String("mounted"))) // "mkfs.minix: /dev/fd0 is mounted; will not make a filesystem here!"
0884     {
0885         Q_EMIT status(i18n("Floppy is mounted.\nYou need to unmount the floppy first."), -1);
0886         return;
0887     } else if (s.contains(QLatin1String("busy"))) // "Device or resource busy"
0888     {
0889         Q_EMIT status(i18n("Device busy.\nPerhaps you need to unmount the floppy first."), -1);
0890         return;
0891     } else if (s.contains(QLatin1String("denied"))) // "Permission denied"
0892     {
0893         Q_EMIT status(s, -1);
0894         return;
0895     }
0896 }
0897 
0898 #endif