1 /* 2 3 This file is part of the KFloppy program, part of the KDE project 4 5 Copyright (C) 2002 Adriaan de Groot <groot@kde.org> 6 Copyright (C) 2004, 2005 Nicolas GOUTTE <goutte@kde.org> 7 Copyright (C) 2015, 2016 Wolfgang Bauer <wbauer@tmo.at> 8 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation, version 2. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 23 */ 24 25 #ifndef FORMAT_H 26 #define FORMAT_H 27 28 /** \file format.h 29 * This file defines a hierarchy of classes that 30 * can run a sequence of external programs (like 31 * fdformat, mkisofs, etc.) in sequence. Stdout 32 * and stderr of those programs can be captured 33 * and analyzed in order to provide feedback to 34 * the user. 35 * 36 * <ul> 37 * <li>KFAction: Base class, just for performing some action. 38 * <li>KFActionQueue: Provides sequencing of KFActions 39 * <li>FloppyAction: Weird name; handles running a program, 40 * understands FD device names. This can be 41 * considered the "useful" base class of 42 * programming actions. 43 * <li>FDFormat: Runs fdformat(1) under BSD or Linux. 44 * <li>FATFilesystem: Creates an msdos (FAT) filesystem. 45 * <li>Ext2Filesystem: Creates ext2 filesystems. 46 * <li>MinixFilesystem: Creates Minix filesystems, under Linux. 47 * <li>UFSFilesystem: Creates UFS filesystem, under BSD. 48 * </ul> 49 * 50 * \note Maybe this is overkill, since for floppies all you need is 51 * fdformat(1) and some create-filesystem program like newfs(1) 52 * or mke2fs(1). However, for Zip disks, should they ever be supported, 53 * this is quite useful since you need to dd, fdisk, disklabel, and 54 * newfs them. 55 */ 56 57 #include "debug.h" 58 #include <QObject> 59 #include <QProcess> 60 61 /** 62 * \brief Abstract base class of actions to be undertaken. 63 * 64 * Basically you can create a KFActionStack (See below) 65 * and push a bunch of actions on it, then run exec() 66 * on the stack and wait for the done() signal. 67 */ 68 class KFAction : public QObject 69 { 70 Q_OBJECT 71 72 public: 73 explicit KFAction(QObject *parent = nullptr); 74 ~KFAction() override; 75 76 public Q_SLOTS: 77 /** 78 * Exec() should return quickly to ensure that the GUI 79 * thread stays alive. quit() should abort the action. 80 */ 81 virtual void exec(); 82 /** 83 * Quit aborts the action. No done() signal should 84 * be emitted. 85 */ 86 virtual void quit(); 87 88 Q_SIGNALS: 89 /** 90 * done() should always be emitted with this as first 91 * parameter, to avoid sender() magic and the like. 92 * @p success indicates whether the action was 93 * successful. 94 */ 95 void done(KFAction *me, bool success); 96 97 /** 98 * Emit this signal to inform the user of interesting 99 * changes; setting msg to an empty string doesn't 100 * change any visible user message. @p progress 101 * indicates the action's progress (if that can be determined) 102 * and sending -1 leaves the visible indicator unchanged. 103 */ 104 void status(const QString &msg, int progress); 105 106 /** error() displays a box. It interrupts 107 * the user's work and should be used with care. 108 */ 109 void error(const QString &msg, const QString &details); 110 }; 111 112 /** 113 * Acts as a queue and executes the actions in the 114 * queue in FIFO order. 115 */ 116 class KFActionQueue : public KFAction 117 { 118 Q_OBJECT 119 120 public: 121 explicit KFActionQueue(QObject *parent = nullptr); 122 ~KFActionQueue() override; 123 124 /** 125 * Add a KFAction to the queue. When exec() is called, 126 * the actions are called one after the other (if each 127 * action is successful; if any action fails, the whole 128 * queue fails and the unsuccessful action is the last 129 * one run.) Actions become the property of the queue 130 * action. Note that queues can be nested. 131 */ 132 void queue(KFAction *); 133 134 void exec() override; 135 136 protected Q_SLOTS: 137 void actionDone(KFAction *, bool); 138 139 private: 140 class KFActionQueue_p *d; 141 }; 142 143 /* 144 ** The remainder of the Actions are concrete ones and 145 ** might better go off to live in another header file, 146 ** but this is only needed if the number of supported 147 ** formats grows enormously. 148 */ 149 150 /** 151 * Description structure for floppy devices. 152 * devices is a list of possible device names (yay 153 * /dev/ consistency) while drive,blocks denotes 154 * fd0 or fd1, and the size of the disk (ought to 155 * be 1440, 1200, 720 or 360. I've never seen a 2880 156 * floppy drive). 157 * 158 * Tracks is pretty bogus; see the internal code for its use. 159 * Similarly, flags are internal too. 160 */ 161 162 using fdinfo = struct { 163 const char *const *devices; 164 int drive; 165 int blocks; 166 int tracks; 167 int flags; 168 }; 169 170 class KProcess; 171 172 /** 173 * Concrete action for running a single external program. 174 */ 175 176 class FloppyAction : public KFAction 177 { 178 Q_OBJECT 179 180 public: 181 explicit FloppyAction(QObject *parent = nullptr); 182 183 /** 184 * Kills the running process, if one exists. 185 */ 186 void quit() override; 187 188 /** 189 * ConfigureDevice() needs to be called prior to exec() 190 * or exec() will fail; this indicates which drive and 191 * density to use. 192 * 193 * \param driveno Number of drive (0 or 1) 194 * \param density Floppy density (in Kilobytes) 195 * \note This same function needs to be 196 * called on all subclasses in order to configure them 197 * for which drive to use, _along_ with their local 198 * configuration functions. 199 */ 200 201 bool configureDevice(int driveno, int density); 202 203 /** 204 * \brief Configure the device with a device name 205 * 206 * This is an alternate to FloppyAction::configureDevice 207 * for user-given devices. 208 * 209 * \note It does not work for each type of FloppyAction yet 210 */ 211 bool configureDevice(const QString &newDeviceName); 212 213 protected: 214 const fdinfo *deviceInfo; ///< Configuration info (Pointer into list of "/dev/..." entries) 215 QString deviceName; ///< Name of the device 216 217 protected Q_SLOTS: 218 /** 219 * \brief Provide handling of the exit of the external program 220 */ 221 virtual void processDone(int, QProcess::ExitStatus); 222 /** 223 * \brief Provide handling of stdout 224 */ 225 virtual void processStdOut(const QString &s); 226 /** 227 * \brief Provide handling stderr. 228 * 229 * The default implementation just sends stderr on 230 * to processStdOut(), so you need reimplement only 231 * FloppyAction::processStdOut if you choose. 232 */ 233 virtual void processStdErr(const QString &s); 234 235 protected: 236 KProcess *theProcess; 237 QString theProcessName; ///< human-readable 238 239 /** 240 * Sets up connections, calls KProcess::start(). 241 * You need to *theProcess << program << args ; first. 242 */ 243 244 bool startProcess(); 245 private Q_SLOTS: 246 /** 247 * These functions read stdout/stderr and call 248 * processStdOut()/processStdErr() accordingly 249 */ 250 void readStdOut(); 251 void readStdErr(); 252 }; 253 254 /** 255 * Concrete class that runs fdformat(1) 256 */ 257 258 class FDFormat : public FloppyAction 259 { 260 public: 261 explicit FDFormat(QObject *parent = nullptr); 262 263 void exec() override; 264 265 /** 266 * Concrete classes can provide a runtimeCheck 267 * function (heck, this is static, so the name 268 * is up to you) that checks if the required 269 * applications are available. This way, the 270 * calling application can decide not to use 271 * actions whose prerequisites are absent anyway. 272 */ 273 static bool runtimeCheck(); 274 275 /** @p verify instructs fdformat(1) to verify the 276 * medium as well. 277 */ 278 279 bool configure(bool verify); 280 281 void processStdOut(const QString &s) override; 282 283 protected: 284 static QString fdformatName; ///< path to executable. 285 int formatTrackCount; ///< How many tracks formatted. 286 bool doVerify; 287 }; 288 289 /** 290 * Zero out disk by running dd(1) 291 * \bug As dd terminates with the error "No space left on device", KFloppy aborts 292 */ 293 class DDZeroOut : public FloppyAction 294 { 295 public: 296 explicit DDZeroOut(QObject *parent = nullptr); 297 298 void exec() override; 299 300 /** 301 * Concrete classes can provide a runtimeCheck 302 * function (heck, this is static, so the name 303 * is up to you) that checks if the required 304 * applications are available. This way, the 305 * calling application can decide not to use 306 * actions whose prerequisites are absent anyway. 307 */ 308 static bool runtimeCheck(); 309 310 protected: 311 /** 312 * \brief Provide handling of the exit of the external program 313 */ 314 void processDone(int exitCode, QProcess::ExitStatus exitStatus) override; 315 316 protected: 317 static QString m_ddName; ///< path to executable. 318 }; 319 320 /** 321 * Create an msdos (FAT) filesystem on the floppy. 322 */ 323 class FATFilesystem : public FloppyAction 324 { 325 public: 326 explicit FATFilesystem(QObject *parent = nullptr); 327 328 void exec() override; 329 330 static bool runtimeCheck(); 331 332 /** 333 * newfs_msdos(1) doesn't support an additional verify, 334 * but Linux mkdosfs(1) does. Enable additional medium 335 * verify with @p verify. Disks can be labeled (@p label) with the 336 * remaining parameters (@p l). 337 */ 338 bool configure(bool verify, bool label, const QString &l); 339 340 /// Parse output 341 void processStdOut(const QString &s) override; 342 343 protected: 344 static QString newfs_fat; 345 346 bool doVerify, doLabel; 347 QString label; 348 }; 349 350 /** 351 * Format with Ext2 352 */ 353 class Ext2Filesystem : public FloppyAction 354 { 355 public: 356 explicit Ext2Filesystem(QObject *parent = nullptr); 357 358 void exec() override; 359 360 static bool runtimeCheck(); 361 362 /// Same args as FATFilesystem::configure 363 bool configure(bool verify, bool label, const QString &l); 364 365 /// Parse output 366 void processStdOut(const QString &s) override; 367 368 protected: 369 static QString newfs; 370 371 bool doVerify, doLabel; 372 QString label; 373 }; 374 375 #ifdef ANY_BSD 376 377 /** 378 * \brief Format with UFS 379 * \note BSD only 380 */ 381 class UFSFilesystem : public FloppyAction 382 { 383 public: 384 explicit UFSFilesystem(QObject *parent = nullptr); 385 386 void exec() override; 387 388 static bool runtimeCheck(); 389 390 protected: 391 static QString newfs; 392 393 bool doVerify, doLabel; 394 QString label; 395 }; 396 #endif 397 398 #ifdef ANY_LINUX 399 /** 400 * \brief Format with Minix 401 * \note Linux only 402 */ 403 class MinixFilesystem : public FloppyAction 404 { 405 public: 406 explicit MinixFilesystem(QObject *parent = nullptr); 407 408 void exec() override; 409 410 static bool runtimeCheck(); 411 412 /// Same args as FATFilesystem::configure 413 bool configure(bool verify, bool label, const QString &l); 414 415 /// Parse output 416 void processStdOut(const QString &s) override; 417 418 protected: 419 static QString newfs; 420 421 bool doVerify, doLabel; 422 QString label; 423 }; 424 #endif 425 426 /** 427 * Utility function that looks for executables in $PATH 428 * and in /sbin and /usr/sbin. 429 */ 430 431 QString findExecutable(const QString &); 432 433 #endif 434