File indexing completed on 2024-04-21 05:50:36

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 
0010     This program is free software; you can redistribute it and/or modify
0011     it under the terms of the GNU General Public License as published by
0012     the Free Software Foundation, version 2.
0013 
0014     This program is distributed in the hope that it will be useful,
0015     but WITHOUT ANY WARRANTY; without even the implied warranty of
0016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017     GNU General Public License for more details.
0018 
0019     You should have received a copy of the GNU General Public License
0020     along with this program; if not, write to the Free Software
0021     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0022 
0023 */
0024 
0025 #ifndef FORMAT_H
0026 #define FORMAT_H
0027 
0028 /** \file format.h
0029  * This file defines a hierarchy of classes that
0030  * can run a sequence of external programs (like
0031  * fdformat, mkisofs, etc.) in sequence. Stdout
0032  * and stderr of those programs can be captured
0033  * and analyzed in order to provide feedback to
0034  * the user.
0035  *
0036  * <ul>
0037  * <li>KFAction:           Base class, just for performing some action.
0038  * <li>KFActionQueue:     Provides sequencing of KFActions
0039  * <li>FloppyAction:      Weird name; handles running a program,
0040  *                     understands FD device names. This can be
0041  *                     considered the "useful" base class of
0042  *                     programming actions.
0043  * <li>FDFormat:        Runs fdformat(1) under BSD or Linux.
0044  * <li>FATFilesystem:   Creates an msdos (FAT) filesystem.
0045  * <li>Ext2Filesystem:  Creates ext2 filesystems.
0046  * <li>MinixFilesystem: Creates Minix filesystems, under Linux.
0047  * <li>UFSFilesystem:   Creates UFS filesystem, under BSD.
0048  * </ul>
0049  *
0050  * \note Maybe this is overkill, since for floppies all you need is
0051  * fdformat(1) and some create-filesystem program like newfs(1)
0052  * or mke2fs(1). However, for Zip disks, should they ever be supported,
0053  * this is quite useful since you need to dd, fdisk, disklabel, and
0054  * newfs them.
0055  */
0056 
0057 #include "debug.h"
0058 #include <QObject>
0059 #include <QProcess>
0060 
0061 /**
0062  * \brief Abstract base class of actions to be undertaken.
0063  *
0064  * Basically you can create a KFActionStack (See below)
0065  * and push a bunch of actions on it, then run exec()
0066  * on the stack and wait for the done() signal.
0067  */
0068 class KFAction : public QObject
0069 {
0070     Q_OBJECT
0071 
0072 public:
0073     explicit KFAction(QObject *parent = nullptr);
0074     ~KFAction() override;
0075 
0076 public Q_SLOTS:
0077     /**
0078      * Exec() should return quickly to ensure that the GUI
0079      * thread stays alive. quit() should abort the action.
0080      */
0081     virtual void exec();
0082     /**
0083      * Quit aborts the action. No done() signal should
0084      * be emitted.
0085      */
0086     virtual void quit();
0087 
0088 Q_SIGNALS:
0089     /**
0090      * done() should always be emitted with this as first
0091      * parameter, to avoid sender() magic and the like.
0092      * @p success indicates whether the action was
0093      * successful.
0094      */
0095     void done(KFAction *me, bool success);
0096 
0097     /**
0098      * Emit this signal to inform the user of interesting
0099      * changes; setting msg to an empty string doesn't
0100      * change any visible user message. @p progress
0101      * indicates the action's progress (if that can be determined)
0102      * and sending -1 leaves the visible indicator unchanged.
0103      */
0104     void status(const QString &msg, int progress);
0105 
0106     /** error() displays a box. It interrupts
0107      * the user's work and should be used with care.
0108      */
0109     void error(const QString &msg, const QString &details);
0110 };
0111 
0112 /**
0113  * Acts as a queue and executes the actions in the
0114  * queue in FIFO order.
0115  */
0116 class KFActionQueue : public KFAction
0117 {
0118     Q_OBJECT
0119 
0120 public:
0121     explicit KFActionQueue(QObject *parent = nullptr);
0122     ~KFActionQueue() override;
0123 
0124     /**
0125      * Add a KFAction to the queue. When exec() is called,
0126      * the actions are called one after the other (if each
0127      * action is successful; if any action fails, the whole
0128      * queue fails and the unsuccessful action is the last
0129      * one run.) Actions become the property of the queue
0130      * action. Note that queues can be nested.
0131      */
0132     void queue(KFAction *);
0133 
0134     void exec() override;
0135 
0136 protected Q_SLOTS:
0137     void actionDone(KFAction *, bool);
0138 
0139 private:
0140     class KFActionQueue_p *d;
0141 };
0142 
0143 /*
0144 ** The remainder of the Actions are concrete ones and
0145 ** might better go off to live in another header file,
0146 ** but this is only needed if the number of supported
0147 ** formats grows enormously.
0148 */
0149 
0150 /**
0151  * Description structure for floppy devices.
0152  * devices is a list of possible device names (yay
0153  * /dev/ consistency) while drive,blocks denotes
0154  * fd0 or fd1, and the size of the disk (ought to
0155  * be 1440, 1200, 720 or 360. I've never seen a 2880
0156  * floppy drive).
0157  *
0158  * Tracks is pretty bogus; see the internal code for its use.
0159  * Similarly, flags are internal too.
0160  */
0161 
0162 using fdinfo = struct {
0163     const char *const *devices;
0164     int drive;
0165     int blocks;
0166     int tracks;
0167     int flags;
0168 };
0169 
0170 class KProcess;
0171 
0172 /**
0173  * Concrete action for running a single external program.
0174  */
0175 
0176 class FloppyAction : public KFAction
0177 {
0178     Q_OBJECT
0179 
0180 public:
0181     explicit FloppyAction(QObject *parent = nullptr);
0182 
0183     /**
0184      * Kills the running process, if one exists.
0185      */
0186     void quit() override;
0187 
0188     /**
0189      * ConfigureDevice() needs to be called prior to exec()
0190      * or exec() will fail; this indicates which drive and
0191      * density to use.
0192      *
0193      * \param driveno Number of drive (0 or 1)
0194      * \param density Floppy density (in Kilobytes)
0195      * \note This same function needs to be
0196      * called on all subclasses in order to configure them
0197      * for which drive to use, _along_ with their local
0198      * configuration functions.
0199      */
0200 
0201     bool configureDevice(int driveno, int density);
0202 
0203     /**
0204      * \brief Configure the device with a device name
0205      *
0206      * This is an alternate to FloppyAction::configureDevice
0207      * for user-given devices.
0208      *
0209      * \note It does not work for each type of FloppyAction yet
0210      */
0211     bool configureDevice(const QString &newDeviceName);
0212 
0213 protected:
0214     const fdinfo *deviceInfo; ///< Configuration info (Pointer into list of "/dev/..." entries)
0215     QString deviceName; ///< Name of the device
0216 
0217 protected Q_SLOTS:
0218     /**
0219      * \brief Provide handling of the exit of the external program
0220      */
0221     virtual void processDone(int, QProcess::ExitStatus);
0222     /**
0223      * \brief Provide handling of stdout
0224      */
0225     virtual void processStdOut(const QString &s);
0226     /**
0227      * \brief Provide handling stderr.
0228      *
0229      * The default implementation just sends stderr on
0230      * to processStdOut(), so you need reimplement only
0231      * FloppyAction::processStdOut if you choose.
0232      */
0233     virtual void processStdErr(const QString &s);
0234 
0235 protected:
0236     KProcess *theProcess;
0237     QString theProcessName; ///< human-readable
0238 
0239     /**
0240      * Sets up connections, calls KProcess::start().
0241      * You need to *theProcess << program << args ; first.
0242      */
0243 
0244     bool startProcess();
0245 private Q_SLOTS:
0246     /**
0247      * These functions read stdout/stderr and call
0248      * processStdOut()/processStdErr() accordingly
0249      */
0250     void readStdOut();
0251     void readStdErr();
0252 };
0253 
0254 /**
0255  * Concrete class that runs fdformat(1)
0256  */
0257 
0258 class FDFormat : public FloppyAction
0259 {
0260 public:
0261     explicit FDFormat(QObject *parent = nullptr);
0262 
0263     void exec() override;
0264 
0265     /**
0266      * Concrete classes can provide a runtimeCheck
0267      * function (heck, this is static, so the name
0268      * is up to you) that checks if the required
0269      * applications are available. This way, the
0270      * calling application can decide not to use
0271      * actions whose prerequisites are absent anyway.
0272      */
0273     static bool runtimeCheck();
0274 
0275     /** @p verify instructs fdformat(1) to verify the
0276      * medium as well.
0277      */
0278 
0279     bool configure(bool verify);
0280 
0281     void processStdOut(const QString &s) override;
0282 
0283 protected:
0284     static QString fdformatName; ///< path to executable.
0285     int formatTrackCount; ///< How many tracks formatted.
0286     bool doVerify;
0287 };
0288 
0289 /**
0290  * Zero out disk by running dd(1)
0291  * \bug As dd terminates with the error "No space left on device", KFloppy aborts
0292  */
0293 class DDZeroOut : public FloppyAction
0294 {
0295 public:
0296     explicit DDZeroOut(QObject *parent = nullptr);
0297 
0298     void exec() override;
0299 
0300     /**
0301      * Concrete classes can provide a runtimeCheck
0302      * function (heck, this is static, so the name
0303      * is up to you) that checks if the required
0304      * applications are available. This way, the
0305      * calling application can decide not to use
0306      * actions whose prerequisites are absent anyway.
0307      */
0308     static bool runtimeCheck();
0309 
0310 protected:
0311     /**
0312      * \brief Provide handling of the exit of the external program
0313      */
0314     void processDone(int exitCode, QProcess::ExitStatus exitStatus) override;
0315 
0316 protected:
0317     static QString m_ddName; ///< path to executable.
0318 };
0319 
0320 /**
0321  * Create an msdos (FAT) filesystem on the floppy.
0322  */
0323 class FATFilesystem : public FloppyAction
0324 {
0325 public:
0326     explicit FATFilesystem(QObject *parent = nullptr);
0327 
0328     void exec() override;
0329 
0330     static bool runtimeCheck();
0331 
0332     /**
0333      * newfs_msdos(1) doesn't support an additional verify,
0334      * but Linux mkdosfs(1) does. Enable additional medium
0335      * verify with @p verify. Disks can be labeled (@p label) with the
0336      * remaining parameters (@p l).
0337      */
0338     bool configure(bool verify, bool label, const QString &l);
0339 
0340     /// Parse output
0341     void processStdOut(const QString &s) override;
0342 
0343 protected:
0344     static QString newfs_fat;
0345 
0346     bool doVerify, doLabel;
0347     QString label;
0348 };
0349 
0350 /**
0351  * Format with Ext2
0352  */
0353 class Ext2Filesystem : public FloppyAction
0354 {
0355 public:
0356     explicit Ext2Filesystem(QObject *parent = nullptr);
0357 
0358     void exec() override;
0359 
0360     static bool runtimeCheck();
0361 
0362     /// Same args as FATFilesystem::configure
0363     bool configure(bool verify, bool label, const QString &l);
0364 
0365     /// Parse output
0366     void processStdOut(const QString &s) override;
0367 
0368 protected:
0369     static QString newfs;
0370 
0371     bool doVerify, doLabel;
0372     QString label;
0373 };
0374 
0375 #ifdef ANY_BSD
0376 
0377 /**
0378  * \brief Format with UFS
0379  * \note BSD only
0380  */
0381 class UFSFilesystem : public FloppyAction
0382 {
0383 public:
0384     explicit UFSFilesystem(QObject *parent = nullptr);
0385 
0386     void exec() override;
0387 
0388     static bool runtimeCheck();
0389 
0390 protected:
0391     static QString newfs;
0392 
0393     bool doVerify, doLabel;
0394     QString label;
0395 };
0396 #endif
0397 
0398 #ifdef ANY_LINUX
0399 /**
0400  * \brief Format with Minix
0401  * \note Linux only
0402  */
0403 class MinixFilesystem : public FloppyAction
0404 {
0405 public:
0406     explicit MinixFilesystem(QObject *parent = nullptr);
0407 
0408     void exec() override;
0409 
0410     static bool runtimeCheck();
0411 
0412     /// Same args as FATFilesystem::configure
0413     bool configure(bool verify, bool label, const QString &l);
0414 
0415     /// Parse output
0416     void processStdOut(const QString &s) override;
0417 
0418 protected:
0419     static QString newfs;
0420 
0421     bool doVerify, doLabel;
0422     QString label;
0423 };
0424 #endif
0425 
0426 /**
0427  * Utility function that looks for executables in $PATH
0428  * and in /sbin and /usr/sbin.
0429  */
0430 
0431 QString findExecutable(const QString &);
0432 
0433 #endif