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