Partitions.Mod 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. MODULE Partitions; (** AUTHOR "staubesv"; PURPOSE "Commandline front-end for PartitionsLib"; *)
  2. (**
  3. * This is the commandline front-end for PartitionsLib.
  4. *
  5. * Command overview:
  6. *
  7. * Uncritical operations:
  8. *
  9. * Partitions.Show ~ Show all disk devices and their partition layout
  10. * Partitions.Show detail ~ Show detailed information about all disk devices and their partition layout
  11. * Partitions.ShowAosFSLimits ~ Show limitations of the Aos File System
  12. *
  13. * Partitions.ShowOps~ Show all pending disk operations
  14. * Partitions.ShowOps detail ~ Show detailed information about all pending disk operations
  15. *
  16. * Partitions.ShowOp uid ~ Show detailed status of the specified operation
  17. * Partitions.Abort <opID> ~ Abort the disk operation with the specified operation ID
  18. * Partitions.Remove <opID> ~ Abort the disk operation with the specified operation ID and remove it from the operation manager
  19. *
  20. * Partitions.Check dev#part ~ Perform a read test on the specified partition
  21. * Partitions.Eject dev ~ Eject medium of the specified device
  22. * Partitions.Sync dev ~ Synchronize device caches to medium
  23. *
  24. * Partitions.Safe~ Disallow extremely critical operations
  25. * Partitions.Unsafe~ Allow extermely critical operations
  26. *
  27. * Partitions.ShowBlocks dev#part first nbr Show <nbr> blocks starting at block <first> of the specified partition
  28. *
  29. * Critical operations:
  30. *
  31. * Partitions.Create dev#part type sizeMB ~ Create a partition
  32. * Partitions.Delete dev#part type ~ Delete the specified partition
  33. * Partitions.Activate dev#part ~ Set the active bit (boot) of the specified partition
  34. * Partitions.Deactivate dev#part ~ Clear the active bit (boot) of the specified partition
  35. * Partitions.ChangeType dev#part from to ~ Change the type of the specified partition from <from> to <to>
  36. * Partitions.Format dev#part fs ~ Format the specified partition with the specified file system (AosFS, FatFS)
  37. * Partitions.WriteMBR dev#part ~ Write MBR boot code to specified partition (partition table will be untouched)
  38. *
  39. * Partitions.InstallBootManager dev#0 ~ Install boot manager
  40. * Partitions.PartitionToFile dev#part file f nbr~ Write <nbr> blocks starting at block <f> to the specified file.
  41. * Partitions.FileToPartition dev#part file f nbr~ Write the content of <file> to the specified partition starting at block <f>, <nbr> blocks
  42. *
  43. * Bluebottle-specific opertaions
  44. *
  45. * Partitions.UpdateBootFile dev#part bootfile Update the boot file (e.g. IDE.Bin) for the specified partition
  46. * Partitions.UpdateBootLoader dev#part bl Update the boot loader (e.g. OBL.Bin) for the specified partition
  47. *
  48. * Partitions.GetConfig dev#part ~ Get the config string of the specified partition
  49. * Partitions.SetConfig dev#part config Set the config string for the specified partition
  50. *
  51. *
  52. * History:
  53. *
  54. * 05.08.2005 Cleanup (staubesv)
  55. * 25.11.2005 Added ShowOp procedure (staubesv)
  56. * 06.01.2006 Small cleanup (staubesv)
  57. * 17.01.2006 WriteMBR: Caller can specify "DESTROY" parameter, fixed SetConfig (staubesv)
  58. *)
  59. IMPORT KernelLog, Texts, TextUtilities, Disks, Files, Lib := PartitionsLib, Plugins, Commands, Streams, Strings, FATScavenger;
  60. CONST
  61. Trace = FALSE;
  62. Invalid = MIN(LONGINT);
  63. (* InstallBootManager default arguments *)
  64. BootManagerMBRFile = "BootManagerMBR.Bin";
  65. BootManagerTailFile = "BootManagerTail.Bin";
  66. (** Show all currently pending disk operations *)
  67. PROCEDURE ShowOps*(context : Commands.Context); (** [detail] ~ *)
  68. VAR par : ARRAY 10 OF CHAR; details : BOOLEAN;
  69. BEGIN
  70. par := ""; context.arg.SkipWhitespace; context.arg.String(par);
  71. details := (par = "detail");
  72. Lib.operations.Show(context.out, details);
  73. END ShowOps;
  74. (** Show the detailed state of the specified operation *)
  75. PROCEDURE ShowOp*(context : Commands.Context); (** uid ~ *)
  76. VAR operation : Lib.Operation; uid : LONGINT;
  77. BEGIN
  78. IF context.arg.GetInteger(uid, FALSE) THEN
  79. operation := Lib.operations.GetByUid(uid);
  80. IF operation # NIL THEN
  81. operation.Show(context.out, TRUE);
  82. ELSE
  83. context.error.String("Error: Operation UID "); context.error.Int(uid, 0); context.error.String(" not found"); context.error.Ln;
  84. context.result := Commands.CommandError;
  85. END;
  86. ELSE
  87. context.error.String("Exspected parameters: uid"); context.error.Ln;
  88. context.result := Commands.CommandParseError;
  89. END;
  90. END ShowOp;
  91. (** Abort a running operation *)
  92. PROCEDURE Abort*(context : Commands.Context); (** uid ~ *)
  93. VAR operation : Lib.Operation; uid : LONGINT;
  94. BEGIN
  95. IF context.arg.GetInteger(uid, FALSE) THEN
  96. operation := Lib.operations.GetByUid(uid);
  97. IF operation # NIL THEN
  98. operation.Abort;
  99. context.out.String("Operation UID "); context.out.Int(uid, 0); context.out.String(" aborted"); context.out.Ln;
  100. ELSE
  101. context.error.String("Error: Operation UID "); context.error.Int(uid, 0); context.error.String(" not found"); context.error.Ln;
  102. context.result := Commands.CommandParseError;
  103. END;
  104. ELSE
  105. context.error.String("Exspected parameters: uid"); context.error.Ln;
  106. context.result := Commands.CommandError;
  107. END;
  108. END Abort;
  109. (** Remove (and if necessary abort) operations from the operations registry *)
  110. PROCEDURE Remove*(context : Commands.Context); (** uid | "all" | "finished" ~*)
  111. VAR par : ARRAY 128 OF CHAR; uid, num : LONGINT;
  112. BEGIN
  113. IF context.arg.GetInteger(uid, FALSE) THEN
  114. IF Lib.operations.RemoveByUid(uid) THEN
  115. context.out.String("Operation UID "); context.out.Int(uid, 0); context.out.String(" has been removed"); context.out.Ln;
  116. ELSE
  117. context.error.String("Error: Could not remove operation UID "); context.error.Int(uid, 0); context.error.Ln;
  118. context.result := Commands.CommandError;
  119. END;
  120. ELSIF context.arg.res = Streams.FormatError THEN
  121. par := "";
  122. context.arg.SetPos(0);
  123. IF context.arg.GetString(par) THEN
  124. Strings.UpperCase(par);
  125. IF par = "ALL" THEN
  126. num := Lib.operations.RemoveAll(TRUE);
  127. context.out.Int(num, 0); context.out.String(" operations have been removed"); context.out.Ln;
  128. ELSIF par = "FINISHED" THEN
  129. context.out.String("All finished operation have been removed"); context.out.Ln;
  130. ELSE
  131. context.error.String("Expected parameters: uid | all | finished"); context.error.Ln;
  132. context.result := Commands.CommandParseError;
  133. END;
  134. ELSE
  135. context.error.String("Expected parameters: uid | all | finished"); context.error.Ln;
  136. context.result := Commands.CommandParseError;
  137. END;
  138. ELSE
  139. context.error.String("Expected parameters: uid | all | finished"); context.error.Ln;
  140. context.result := Commands.CommandParseError;
  141. END;
  142. END Remove;
  143. PROCEDURE Mount*(context : Commands.Context);
  144. VAR
  145. mount :Lib.Mount;
  146. prefix, alias, volumePars, fsPars : ARRAY 64 OF CHAR;
  147. selection : Lib.Selection;
  148. BEGIN
  149. IF GetSelection(context, TRUE, selection) THEN
  150. volumePars := ""; fsPars := "";
  151. IF context.arg.GetString(alias) & context.arg.GetString(prefix) THEN
  152. NEW(mount, selection.disk, selection.partition, context.out);
  153. mount.SetParameters(prefix, alias, volumePars, fsPars);
  154. mount.SetBlockingStart;
  155. IF Lib.StatusError IN mount.state.status THEN context.result := Commands.CommandError END;
  156. ELSE
  157. context.error.String("Expected parameters: dev#part alias prefix"); context.error.Ln;
  158. context.result := Commands.CommandError;
  159. END;
  160. END;
  161. END Mount;
  162. (* Format a partition with an N2KFS, AosFS or FatFS. *)
  163. PROCEDURE Format*(context : Commands.Context); (** dev#part [ "AosFS" | "NatFS" | "NatFS2" [ FSRes [ BootFile [ Flag ] ] ] ] | ["FatFS" ["Quick"]] ~ *)
  164. VAR
  165. formatAos : Lib.FormatPartition; formatFat : FATScavenger.FormatPartition;
  166. fsname, bootfile, quick : ARRAY 128 OF CHAR;
  167. fsRes, flags : LONGINT;
  168. quickFormat : BOOLEAN;
  169. selection : Lib.Selection;
  170. BEGIN
  171. IF GetSelection(context, TRUE, selection) THEN
  172. IF context.arg.GetString(fsname) THEN
  173. IF fsname = "FatFS" THEN
  174. quickFormat := context.arg.GetString(quick) & (quick = "Quick");
  175. NEW(formatFat, selection.disk, selection.partition, context.out);
  176. formatFat.SetParameters(Strings.NewString("no name"), quickFormat);
  177. formatFat.SetBlockingStart;
  178. IF Lib.StatusError IN formatFat.state.status THEN context.result := Commands.CommandError END;
  179. context.out.String("Partitions UID "); context.out.Int(formatFat.uid, 0);
  180. context.out.String(": Started FAT format on "); context.out.String(formatFat.diskpartString); context.out.Ln;
  181. ELSIF (fsname = "AosFS") OR (fsname = "NatFS") OR (fsname = "NatFS1") OR (fsname = "NatFS2") THEN
  182. bootfile := ""; fsRes := -2; flags := 0;
  183. IF context.arg.GetInteger(fsRes, FALSE) THEN
  184. IF context.arg.GetString(bootfile) THEN
  185. context.arg.SkipWhitespace; context.arg.Int(flags, FALSE);
  186. END;
  187. END;
  188. NEW(formatAos, selection.disk, selection.partition, context.out);
  189. formatAos.SetParameters(fsname, bootfile, fsRes, flags);
  190. formatAos.SetBlockingStart;
  191. IF Lib.StatusError IN formatAos.state.status THEN context.result := Commands.CommandError END;
  192. ELSE
  193. context.error.String("File system "); context.error.String(fsname); context.error.String(" is not supported"); context.error.Ln;
  194. context.result := Commands.CommandError;
  195. END;
  196. ELSE (* optional parameters not specified *)
  197. NEW(formatAos, selection.disk, selection.partition, context.out);
  198. formatAos.SetParameters("AosFS", "", -2, 0);
  199. formatAos.SetBlockingStart;
  200. IF Lib.StatusError IN formatAos.state.status THEN context.result := Commands.CommandError END;
  201. context.out.String("Partitions UID "); context.out.Int(formatAos.uid, 0);
  202. context.out.String(": Started format on "); context.out.String(formatAos.diskpartString); context.out.Ln;
  203. END;
  204. END;
  205. END Format;
  206. (* Update the boot file in an existing Oberon partition. *)
  207. PROCEDURE UpdateBootFile*(context : Commands.Context); (** dev#part BootFile ~ *)
  208. VAR
  209. updateBootFile : Lib.UpdateBootFile;
  210. selection : Lib.Selection;
  211. filename : Files.FileName;
  212. BEGIN
  213. IF GetSelection(context, FALSE, selection) THEN
  214. IF context.arg.GetString(filename) THEN
  215. NEW(updateBootFile, selection.disk, selection.partition, context.out);
  216. updateBootFile.SetParameters(filename);
  217. updateBootFile.SetBlockingStart;
  218. IF Lib.StatusError IN updateBootFile.state.status THEN context.result := Commands.CommandError END;
  219. ELSE
  220. context.error.String("Expected parameters: dev#part bootfilename"); context.error.Ln;
  221. context.result := Commands.CommandParseError;
  222. END;
  223. END;
  224. END UpdateBootFile;
  225. PROCEDURE GetConfig*(context : Commands.Context); (** dev#part *)
  226. CONST MaxSize = 2048;
  227. VAR
  228. getConfig : Lib.GetConfig;
  229. selection : Lib.Selection;
  230. configuration : Lib.Configuration;
  231. table : Streams.StringWriter;
  232. string : ARRAY MaxSize OF CHAR;
  233. i : LONGINT;
  234. BEGIN
  235. IF GetSelection(context, TRUE, selection) THEN
  236. NEW(getConfig, selection.disk, selection.partition, context.out);
  237. getConfig.SetBlockingStart;
  238. IF Lib.StatusError IN getConfig.state.status THEN
  239. context.result := Commands.CommandError;
  240. ELSE
  241. NEW(configuration);
  242. configuration.table := getConfig.GetTable();
  243. table := configuration.GetTableAsString();
  244. table.Get(string);
  245. (* Commands uses the quote character to separate commands *)
  246. FOR i := 0 TO LEN(string)-1 DO IF string[i] = ";" THEN string[i] := ","; END; END;
  247. context.out.String("Partitions.SetConfig "); context.out.String(getConfig.diskpartString); context.out.Ln;
  248. context.out.String(string); context.out.Ln;
  249. END;
  250. END;
  251. END GetConfig;
  252. (* Write the specified configuration string to the specified partition. *)
  253. (* Notes: *)
  254. (* - Use the "," character to separate commands *)
  255. (* - After an "#" character, the rest of the line is skipped/ignored *)
  256. PROCEDURE SetConfig*(context : Commands.Context); (** dev#part { str = "val" } ~ *)
  257. VAR
  258. setConfig : Lib.SetConfig;
  259. selection : Lib.Selection;
  260. configString : Strings.String;
  261. ch : CHAR;
  262. i : LONGINT;
  263. BEGIN
  264. IF GetSelection(context, TRUE, selection) THEN
  265. IF context.arg.CanSetPos() THEN
  266. (* append character "~" to config string *)
  267. NEW(configString, context.arg.Available() + 1);
  268. i := 0;
  269. WHILE (context.arg.Available() > 0) DO
  270. context.arg.Char(ch);
  271. IF (ch = ",") THEN
  272. configString[i] := ";"; (* Commands uses comma character to separate commands *)
  273. ELSE
  274. configString[i] := ch;
  275. END;
  276. INC(i);
  277. END;
  278. configString[i-1] := "~";
  279. configString[i] := 0X;
  280. NEW(setConfig, selection.disk, selection.partition, context.out);
  281. setConfig.SetParameters(configString, 0);
  282. setConfig.SetBlockingStart;
  283. IF Lib.StatusError IN setConfig.state.status THEN context.result := Commands.CommandError END;
  284. ELSE
  285. context.error.String("Expected argument stream that supports SetPos"); context.error.Ln;
  286. context.result := Commands.CommandError;
  287. END;
  288. END;
  289. END SetConfig;
  290. (** Perform a read check on partition *)
  291. PROCEDURE Check*(context : Commands.Context); (** dev#part *)
  292. VAR
  293. selection : Lib.Selection;
  294. checkPartition : Lib.CheckPartition;
  295. BEGIN
  296. IF GetSelection(context, FALSE, selection) THEN
  297. NEW(checkPartition, selection.disk, selection.partition, context.out);
  298. checkPartition.SetBlockingStart;
  299. IF Lib.StatusError IN checkPartition.state.status THEN context.result := Commands.CommandError END;
  300. ELSE (* skip; error written to <w> by ScanOpenPart *)
  301. END;
  302. END Check;
  303. (** Change the type of dev#part from oldtype to newtype *)
  304. PROCEDURE ChangeType*(context : Commands.Context); (** dev#part oldtype newtype ~ *)
  305. VAR
  306. change : Lib.ChangePartType;
  307. oldtype, newtype : LONGINT;
  308. selection : Lib.Selection;
  309. BEGIN
  310. IF GetSelection(context, TRUE, selection) THEN
  311. IF ~selection.disk.isDiskette THEN
  312. IF context.arg.GetInteger(oldtype, FALSE) & (oldtype > 0) & (oldtype < 256) THEN
  313. IF context.arg.GetInteger(newtype, FALSE) & (newtype > 0) & (newtype < 256) THEN
  314. NEW(change, selection.disk, selection.partition, context.out);
  315. change.SetParameters(oldtype, newtype);
  316. change.SetBlockingStart;
  317. IF Lib.StatusError IN change.state.status THEN context.result := Commands.CommandError END;
  318. ELSE
  319. context.error.String("Expected parameters: dev#part oldtype newtype, failed to parse newtype"); context.error.Ln;
  320. context.result := Commands.CommandParseError;
  321. END;
  322. ELSE
  323. context.error.String("Expected parameters: dev#part oldtype newtype, failed to parse oldtype"); context.error.Ln;
  324. context.result := Commands.CommandParseError;
  325. END;
  326. ELSE
  327. context.error.String("Operation not support for floppy disk drives."); context.error.Ln;
  328. context.result := Commands.CommandError;
  329. END;
  330. END;
  331. END ChangeType;
  332. (** Delete a partition *)
  333. PROCEDURE Delete*(context : Commands.Context); (** dev#part type ~ *)
  334. VAR
  335. delete : Lib.DeletePartition;
  336. selection : Lib.Selection;
  337. type : LONGINT;
  338. BEGIN
  339. IF GetSelection(context, FALSE, selection) THEN
  340. IF ~selection.disk.isDiskette THEN
  341. IF context.arg.GetInteger(type, FALSE) & (type > 0) & (type < 256) THEN
  342. NEW(delete, selection.disk, selection.partition, context.out);
  343. delete.SetParameters(type);
  344. delete.SetBlockingStart;
  345. IF Lib.StatusError IN delete.state.status THEN context.result := Commands.CommandError END;
  346. ELSE
  347. context.error.String("Expected parameters: dev#part type sizeMB, error while parsing type"); context.error.Ln;
  348. context.result := Commands.CommandParseError;
  349. END;
  350. ELSE
  351. context.error.String("Operation not supported for floppy disks"); context.error.Ln;
  352. context.result := Commands.CommandError;
  353. END;
  354. END;
  355. END Delete;
  356. PROCEDURE Create*(context : Commands.Context); (** dev#part type sizeMB ~ *)
  357. VAR
  358. create : Lib.CreatePartition;
  359. selection : Lib.Selection;
  360. type, size : LONGINT;
  361. BEGIN
  362. IF GetSelection(context, FALSE, selection) THEN
  363. IF ~selection.disk.isDiskette THEN
  364. IF context.arg.GetInteger(type, FALSE) & (type > 0) & (type < 256) THEN
  365. IF context.arg.GetInteger(size, FALSE) & (size > 0) THEN
  366. NEW(create, selection.disk, selection.partition, context.out);
  367. create.SetParameters(size, type, FALSE);
  368. create.SetBlockingStart;
  369. IF Lib.StatusError IN create.state.status THEN context.result := Commands.CommandError END;
  370. ELSE
  371. context.error.String("Expected parameters: dev#part type sizeMB, error while parsing size"); context.error.Ln;
  372. context.result := Commands.CommandParseError;
  373. END;
  374. ELSE
  375. context.error.String("Expected parameters: dev#part type sizeMB, error while parsing type"); context.error.Ln;
  376. context.result := Commands.CommandParseError;
  377. END;
  378. ELSE
  379. context.error.String("Operation not supported on floppy disks"); context.error.Ln;
  380. context.result := Commands.CommandError;
  381. END;
  382. END;
  383. END Create;
  384. (** Mark partition as active *)
  385. PROCEDURE Activate*(context : Commands.Context); (** dev#part ~ *)
  386. BEGIN
  387. ChangeActiveBit(TRUE, context);
  388. END Activate;
  389. (** Mark partition as inactive *)
  390. PROCEDURE Deactivate*(context : Commands.Context); (** dev#part ~ *)
  391. BEGIN
  392. ChangeActiveBit(FALSE, context);
  393. END Deactivate;
  394. PROCEDURE ChangeActiveBit(active : BOOLEAN; context : Commands.Context);
  395. VAR
  396. setFlags : Lib.SetFlags;
  397. selection : Lib.Selection;
  398. BEGIN
  399. IF GetSelection(context, TRUE, selection) THEN
  400. IF ~selection.disk.isDiskette THEN
  401. NEW(setFlags, selection.disk, selection.partition, context.out);
  402. setFlags.SetParameters(active);
  403. setFlags.SetBlockingStart;
  404. IF Lib.StatusError IN setFlags.state.status THEN context.result := Commands.CommandError END;
  405. ELSE
  406. context.error.String("Operation not supported for floppy disks"); context.error.Ln;
  407. context.result := Commands.CommandError;
  408. END;
  409. END;
  410. END ChangeActiveBit;
  411. (** Write <numblock> sectors from a file to a partition, starting at block <block> *)
  412. PROCEDURE FileToPartition*(context : Commands.Context); (** dev#part filename [block numblocks] ~ *)
  413. VAR
  414. fileToPartition : Lib.FileToPartition;
  415. filename : ARRAY 128 OF CHAR;
  416. block, numblocks : LONGINT;
  417. selection : Lib.Selection;
  418. BEGIN
  419. IF GetSelection(context, TRUE, selection) THEN
  420. IF context.arg.GetString(filename) THEN
  421. IF context.arg.GetInteger(block, FALSE) THEN
  422. IF ~context.arg.GetInteger(numblocks, FALSE) THEN
  423. context.error.String("Exspected parameters: dev#part filename [block numblocks], failed to parse numblocks"); context.error.Ln;
  424. context.result := Commands.CommandParseError;
  425. RETURN;
  426. END;
  427. ELSE (* optional parameters not specified *)
  428. block := -1; numblocks := -1;
  429. END;
  430. NEW(fileToPartition, selection.disk, selection.partition, context.out);
  431. fileToPartition.SetParameters(filename, block, numblocks);
  432. fileToPartition.SetBlockingStart;
  433. IF Lib.StatusError IN fileToPartition.state.status THEN context.result := Commands.CommandError END;
  434. ELSE
  435. context.error.String("Exspected parameters: dev#part name [block numblocks], failed to parse filename"); context.error.Ln;
  436. context.result := Commands.CommandParseError;
  437. END;
  438. END;
  439. END FileToPartition;
  440. (** Write <numblock> sectors from a partition to a file, starting at block <block>.
  441. If the optional parameters are not specified, store whole partition into file *)
  442. PROCEDURE PartitionToFile*(context : Commands.Context); (** dev#part filename [block numblocks] ~ *)
  443. VAR
  444. partitionToFile : Lib.PartitionToFile;
  445. filename : ARRAY 128 OF CHAR;
  446. block, numblocks : LONGINT;
  447. selection : Lib.Selection;
  448. BEGIN
  449. IF GetSelection(context, TRUE, selection) THEN
  450. IF context.arg.GetString(filename) THEN
  451. IF context.arg.GetInteger(block, FALSE) THEN
  452. IF ~context.arg.GetInteger(numblocks, FALSE) THEN
  453. context.error.String("Exspected parameters: dev#part filename [block numblocks], failed to parse numblocks"); context.error.Ln;
  454. context.result := Commands.CommandParseError;
  455. RETURN;
  456. END;
  457. ELSE (* optional parameters not specified *)
  458. block := -1; numblocks := -1;
  459. END;
  460. NEW(partitionToFile, selection.disk, selection.partition, context.out);
  461. partitionToFile.SetParameters(filename, block, numblocks);
  462. partitionToFile.SetBlockingStart;
  463. IF Lib.StatusError IN partitionToFile.state.status THEN context.result := Commands.CommandError END;
  464. context.out.String("Partitions UID "); context.out.Int(partitionToFile.uid, 0); context.out.String(": Started PartitionToFile on ");
  465. context.out.String(partitionToFile.diskpartString); context.out.Ln;
  466. ELSE
  467. context.error.String("Exspected parameters: dev#part name [block numblocks], failed to parse filename"); context.error.Ln;
  468. context.result := Commands.CommandParseError;
  469. END;
  470. END;
  471. END PartitionToFile;
  472. (** Write the specified Master Boot Record (MBR) to the specified partition. The partition table will be preserved *)
  473. (* unless the optional parameter "DESTROY" is specified. *)
  474. (* WARNING: Using the DESTROY parameter will render any disk content unusable. *)
  475. PROCEDURE WriteMBR*(context : Commands.Context); (** dev#0 filename ["DESTROY"] ~ *)
  476. VAR
  477. writeMBR : Lib.WriteMBR;
  478. filename, destroy : ARRAY 128 OF CHAR;
  479. selection : Lib.Selection;
  480. BEGIN
  481. IF GetSelection(context, FALSE, selection) THEN
  482. IF ~selection.disk.isDiskette THEN
  483. IF selection.partition = 0 THEN
  484. IF context.arg.GetString(filename) THEN
  485. NEW(writeMBR, selection.disk, selection.partition, context.out);
  486. IF context.arg.GetString(destroy) & (destroy = "DESTROY") THEN
  487. writeMBR.SetParameters(filename, FALSE, FALSE);
  488. ELSE
  489. writeMBR.SetParameters(filename, TRUE, FALSE);
  490. END;
  491. writeMBR.SetBlockingStart;
  492. IF Lib.StatusError IN writeMBR.state.status THEN context.result := Commands.CommandError END;
  493. ELSE
  494. context.error.String("Expected parameters: dev#0 filename, failed to parse filename"); context.error.Ln;
  495. context.result := Commands.CommandParseError;
  496. END;
  497. ELSE
  498. context.error.String("Expected parameters: dev#0 filename, partition is not 0"); context.error.Ln;
  499. context.result := Commands.CommandParseError;
  500. END;
  501. ELSE
  502. context.error.String("Operation not supported for floppy disks"); context.error.Ln;
  503. context.result := Commands.CommandError;
  504. END;
  505. END;
  506. END WriteMBR;
  507. (** Update the boot loader OBL in an existing AosFS partition, replacing it by the new BBL handling the Init string differently.
  508. The BBL must imperatively have the same size, 4 blocks, as the OBL. The same BBL is applicable to all AosFS partitions. *)
  509. PROCEDURE UpdateBootLoader*(context : Commands.Context); (** dev#part BootLoader ~ *)
  510. VAR
  511. updateLoader : Lib.UpdateBootLoader;
  512. selection : Lib.Selection;
  513. filename : Files.FileName;
  514. BEGIN
  515. IF GetSelection(context, FALSE, selection) THEN
  516. IF context.arg.GetString(filename) THEN
  517. NEW(updateLoader, selection.disk, selection.partition, context.out);
  518. updateLoader.SetParameters(filename);
  519. updateLoader.SetBlockingStart;
  520. IF Lib.StatusError IN updateLoader.state.status THEN context.result := Commands.CommandError END;
  521. ELSE
  522. context.error.String("Expected parameters: dev#part bootloader"); context.error.Ln;
  523. context.result := Commands.CommandError;
  524. END;
  525. END;
  526. END UpdateBootLoader;
  527. (** Install boot manager on the specified device *)
  528. PROCEDURE InstallBootManager*(context : Commands.Context); (** dev#0 [BootManagerMBR [BootManagerTail]] ~ *)
  529. VAR installBootManager : Lib.InstallBootManager; selection : Lib.Selection; mbrFile, tailFile : Files.FileName;
  530. BEGIN
  531. IF GetSelection(context, FALSE, selection) THEN
  532. IF ~context.arg.GetString(mbrFile) THEN mbrFile := BootManagerMBRFile; END;
  533. IF ~context.arg.GetString(tailFile) THEN tailFile := BootManagerTailFile; END;
  534. NEW(installBootManager, selection.disk, selection.partition, context.out);
  535. installBootManager.SetParameters(mbrFile, tailFile);
  536. installBootManager.SetBlockingStart;
  537. IF Lib.StatusError IN installBootManager.state.status THEN context.result := Commands.CommandError END;
  538. END;
  539. END InstallBootManager;
  540. PROCEDURE ShowBlockCallback(text : Texts.Text);
  541. VAR string : Strings.String;
  542. BEGIN
  543. text.AcquireRead;
  544. NEW(string, text.GetLength()); TextUtilities.TextToStr(text, string^);
  545. text.ReleaseRead;
  546. KernelLog.String(string^); KernelLog.Ln;
  547. END ShowBlockCallback;
  548. PROCEDURE ShowBlocks*(context : Commands.Context); (** dev#part block [numblocks] ~ *)
  549. VAR
  550. showBlocks : Lib.ShowBlocks;
  551. block, numblocks : LONGINT;
  552. selection : Lib.Selection;
  553. BEGIN
  554. IF GetSelection(context, FALSE, selection) THEN
  555. IF context.arg.GetInteger(block, FALSE) THEN
  556. IF ~context.arg.GetInteger(numblocks, FALSE) THEN
  557. (* optional parameter not specified *) numblocks := -1;
  558. END;
  559. NEW(showBlocks, selection.disk, selection.partition, context.out);
  560. showBlocks.SetParameters(block, numblocks);
  561. showBlocks.SetCallback(ShowBlockCallback);
  562. showBlocks.SetBlockingStart;
  563. IF Lib.StatusError IN showBlocks.state.status THEN context.result := Commands.CommandError END;
  564. ELSE
  565. context.error.String("Exspected parameters: dev#part block [numblocks], failed to parse block"); context.error.Ln;
  566. context.result := Commands.CommandParseError;
  567. END;
  568. END;
  569. END ShowBlocks;
  570. (** Eject medium of device dev *)
  571. PROCEDURE Eject*(context : Commands.Context); (** dev ~ *)
  572. VAR
  573. plugin : Plugins.Plugin;
  574. dev : Disks.Device;
  575. name : ARRAY 32 OF CHAR;
  576. temp: ARRAY 256 OF CHAR;
  577. BEGIN
  578. IF context.arg.GetString(name) THEN
  579. plugin := Disks.registry.Get(name);
  580. IF plugin # NIL THEN
  581. dev := plugin (Disks.Device);
  582. Lib.Eject(dev, temp); context.out.String(temp); context.out.Ln;
  583. ELSE
  584. context.error.String("Device "); context.error.String(name); context.error.String(" not found"); context.error.Ln;
  585. context.result := Commands.CommandError;
  586. END;
  587. ELSE
  588. context.error.String("Expected parameters: dev"); context.error.Ln;
  589. context.result := Commands.CommandParseError;
  590. END;
  591. END Eject;
  592. (** Sync device to medium *)
  593. PROCEDURE Sync*(context: Commands.Context); (** dev ~ *)
  594. VAR
  595. plugin: Plugins.Plugin;
  596. dev: Disks.Device;
  597. name: ARRAY 32 OF CHAR;
  598. temp: ARRAY 256 OF CHAR;
  599. BEGIN
  600. IF context.arg.GetString(name) THEN
  601. plugin := Disks.registry.Get(name);
  602. IF plugin # NIL THEN
  603. dev := plugin (Disks.Device);
  604. Lib.Sync(dev, temp); context.out.String(temp); context.out.Ln;
  605. ELSE
  606. context.error.String("Device "); context.error.String(name); context.error.String(" not found"); context.error.Ln;
  607. context.result := Commands.CommandError;
  608. END;
  609. ELSE
  610. context.error.String("Expected parameters: dev"); context.error.Ln;
  611. context.result := Commands.CommandParseError;
  612. END;
  613. END Sync;
  614. PROCEDURE Unsafe*(context : Commands.Context); (** ~ *)
  615. BEGIN
  616. Lib.safe := FALSE;
  617. context.out.String("NOW in UNSAFE mode!"); context.out.Ln;
  618. END Unsafe;
  619. PROCEDURE Safe*(context : Commands.Context); (** ~ *)
  620. BEGIN
  621. Lib.safe := TRUE;
  622. context.out.String("Now in safe mode"); context.out.Ln;
  623. END Safe;
  624. (** Show all disk devices and their partition layout. *)
  625. PROCEDURE Show*(context : Commands.Context); (** ["detail"] ~ *)
  626. VAR
  627. diskTable : Lib.Disks; disk : Lib.Disk;
  628. par : ARRAY 10 OF CHAR;
  629. verbose : BOOLEAN;
  630. i : LONGINT;
  631. temp : ARRAY 256 OF CHAR;
  632. BEGIN
  633. par := ""; context.arg.SkipWhitespace; context.arg.String(par);
  634. verbose := (par = "detail");
  635. Lib.diskModel.Update;
  636. Lib.diskModel.Acquire;
  637. diskTable := Lib.diskModel.disks;
  638. IF diskTable # NIL THEN
  639. FOR i := 0 TO LEN(diskTable)-1 DO
  640. disk := diskTable[i];
  641. ShowDevice(context, disk, verbose);
  642. IF disk.res # Disks.MediaMissing THEN
  643. IF (disk.table # NIL) THEN
  644. ShowTable(context, disk, disk.table, verbose)
  645. ELSE
  646. Lib.GetErrorMsg("Error", disk.res, temp); context.error.String(temp); context.error.Ln;
  647. END
  648. END;
  649. context.error.Ln;
  650. END;
  651. ELSE
  652. context.error.String("No Devices found"); context.error.Ln;
  653. context.result := Commands.CommandError;
  654. END;
  655. Lib.diskModel.Release;
  656. END Show;
  657. PROCEDURE ShowDevice(context : Commands.Context; disk: Lib.Disk; verbose: BOOLEAN);
  658. VAR temp: ARRAY 256 OF CHAR;
  659. BEGIN
  660. context.out.String("Disk: "); context.out.String(disk.device.name); context.out.String(", ");
  661. IF disk.res = Disks.Ok THEN
  662. Lib.WriteK(context.out, ENTIER(disk.size * 1.0 * disk.device.blockSize / 1024));
  663. IF verbose THEN
  664. context.out.String(" = "); context.out.Int(disk.size, 1);
  665. context.out.String(" * "); context.out.Int(disk.device.blockSize,1);
  666. END
  667. ELSE
  668. Lib.GetErrorMsg("GetSize failed", disk.res, temp); context.error.String(temp);
  669. END;
  670. IF Disks.Removable IN disk.device.flags THEN context.out.String(", removable") END;
  671. IF Disks.ReadOnly IN disk.device.flags THEN context.out.String(", read-only") END;
  672. IF verbose THEN
  673. IF disk.res # Disks.MediaMissing THEN
  674. context.out.String(", ");
  675. IF disk.gres = Disks.Ok THEN
  676. context.out.String("CHS: "); context.out.Int(disk.geo.cyls, 1); context.out.String("*");
  677. context.out.Int(disk.geo.hds, 1); context.out. String("*"); context.out.Int(disk.geo.spt, 1);
  678. ELSE
  679. Lib.GetErrorMsg("GetCHS: ", disk.gres, temp); context.error.String(temp);
  680. END
  681. END
  682. END;
  683. IF disk.device.desc # "" THEN context.out.String(", "); context.out.String(disk.device.desc) END;
  684. IF verbose THEN context.out.String(", mntcnt="); context.out.Int(disk.device.openCount, 1) END;
  685. context.out.Ln;
  686. END ShowDevice;
  687. PROCEDURE ShowTable( context : Commands.Context; disk: Lib.Disk; table: Disks.PartitionTable; verbose: BOOLEAN);
  688. VAR j: LONGINT; r: LONGREAL; ugly : ARRAY 10 OF CHAR; temp : ARRAY 128 OF CHAR; ignore : LONGINT;
  689. BEGIN
  690. FOR j := 0 TO LEN(table)-1 DO
  691. r := (table[j].size * 1.0D0 * disk.device.blockSize) / (1024*1024); (* M *)
  692. Lib.WritePart(context.out, disk.device, j);
  693. IF verbose THEN
  694. context.out.Int(table[j].start, 12);
  695. context.out.Int(table[j].size, 12)
  696. END;
  697. Strings.FloatToStr(r, 6, 1, 0, ugly);
  698. IF r < 10 THEN context.out.String(ugly);
  699. ELSE context.out.Int(ENTIER(r), 6)
  700. END;
  701. context.out.String(" MB ");
  702. IF (table[j].type >= 1) & (table[j].type <= 255) THEN
  703. context.out.Int(table[j].type, 3)
  704. ELSE
  705. context.out.String("---")
  706. END;
  707. context.out.Char(" ");
  708. IF (j # 0) & ~(Disks.Primary IN table[j].flags) THEN context.out.String( " | ") END; (* logical drive *)
  709. IF Disks.Boot IN table[j].flags THEN context.out.String(" * ") END; (* bootable *)
  710. Lib.WriteType(table[j].type, temp, ignore); context.out.String(temp);
  711. IF verbose THEN
  712. IF Disks.Mounted IN table[j].flags THEN context.out.String(" [mounted]") END
  713. END;
  714. context.out.Ln;
  715. END
  716. END ShowTable;
  717. (** Display limitations of AosFS *)
  718. PROCEDURE ShowAosFSLimits*(context : Commands.Context); (** ~ *)
  719. BEGIN
  720. Lib.ShowAosFSLimits;
  721. END ShowAosFSLimits;
  722. PROCEDURE UpdateDiskModel*(context : Commands.Context);(** ~ *)
  723. BEGIN
  724. Lib.diskModel.Update;
  725. context.out.String("Disk model updated."); context.out.Ln;
  726. END UpdateDiskModel;
  727. (* Scan the command line parameters for a device#partition specification. *)
  728. (* The Writer <w> is used to return error messages, <r> contains p.str (dev#part skipped) *)
  729. (* check : IF TRUE, only Disks.Valid partitions are returns *)
  730. PROCEDURE GetSelection*(context : Commands.Context; check : BOOLEAN; VAR selection : Lib.Selection) : BOOLEAN;
  731. VAR devpart : ARRAY 32 OF CHAR;
  732. BEGIN
  733. selection.disk.device := NIL; selection.partition := -1; (* invalid *)
  734. IF ~context.arg.GetString(devpart) THEN
  735. context.error.String("Expected parameters: dev#part"); context.error.Ln; context.error.Update;
  736. context.result := Commands.CommandParseError;
  737. RETURN FALSE;
  738. END;
  739. context.arg.SkipWhitespace;
  740. (* special case: diskette *)
  741. IF Strings.Match("Diskette*", devpart) THEN
  742. check := FALSE;
  743. END;
  744. Lib.diskModel.Update;
  745. IF Lib.diskModel.GetDisk(devpart, selection, check) THEN
  746. IF Trace THEN
  747. KernelLog.String("Partitions: Command line selection: "); KernelLog.String(selection.disk.device.name);
  748. KernelLog.Char("#"); KernelLog.Int(selection.partition, 0); KernelLog.Ln;
  749. END;
  750. RETURN TRUE;
  751. ELSE
  752. context.error.String("Partition "); context.error.String(devpart); context.out.String(" not found."); context.error.Ln;
  753. context.error.Update; context.result := Commands.CommandError;
  754. END;
  755. RETURN FALSE;
  756. END GetSelection;
  757. END Partitions.
  758. System.Free DiskBenchmark Partitions ~