source: rxlvm/trunk/rxlvm.c@ 35

Last change on this file since 35 was 35, checked in by Alex Taylor, 9 years ago

Import of RXLVM sources

File size: 42.3 KB
Line 
1#ifndef OS2_INCLUDED
2 #include <os2.h>
3#endif
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <ctype.h>
8#include <lvm_intr.h>
9
10#define INCL_RXSHV
11#define INCL_RXFUNC
12#include <rexxsaa.h>
13
14
15// CONSTANTS
16
17#define US_VERSION_MAJOR 0 // Major version number of this library
18#define US_VERSION_MINOR 5 // Minor version number of this library
19#define US_VERSION_REFRESH 1 // Refresh level of this library
20
21// (string length constants ending in 'Z' include space for the null terminator)
22#define US_INTEGER_MAXZ 12 // Maximum length of an integer string
23#define US_ERRSTR_MAXZ ( 10 + US_INTEGER_MAXZ ) // Maximum length of a SZ_ENGINE_ERROR string
24#define US_DEVTYPE_MAXZ 4 // Maximum length of a device-type string
25#define US_BMINFO_MAXZ 32 // Maximum length of a Boot Manager information string
26#define US_SZINFO_MAXZ 255 // Maximum length of an information string (used for stem values)
27#define US_STEM_MAXZ 238 // Maximum length of a stem variable (no extension)
28#define US_COMPOUND_MAXZ ( US_STEM_MAXZ + US_INTEGER_MAXZ ) // Maximum length of a compound variable (stem+extension)
29
30#define UL_SECTORS_PER_MB ( 1048576 / BYTES_PER_SECTOR ) // Used to convert sector sizes to MB
31
32#define SZ_ENGINE_ERROR "ERROR: %d" // Template for LVM error string
33#define SZ_LIBRARY_NAME "RXLVM" // Name of this library
34
35// Device type constants
36#define SZ_DEVICE_HDD "HDD" // Hard disk drive
37#define SZ_DEVICE_PRM "PRM" // Partitioned removeable media
38#define SZ_DEVICE_CDROM "CD" // CD/DVD drive
39#define SZ_DEVICE_NETWORK "LAN" // Network drive
40#define SZ_DEVICE_OTHER "?" // Unrecognized non-LVM device (e.g. RAM disk)
41
42// Partition status constants
43#define CH_PTYPE_FREESPACE 'F' // Free space
44#define CH_PTYPE_AVAILABLE 'A' // Available (not part of a volume)
45#define CH_PTYPE_CVOLUME 'C' // Belongs to a compatibility volume
46#define CH_PTYPE_LVOLUME 'L' // Belongs to an LVM-type (advanced) volume
47#define CH_PTYPE_INUSE 'U' // Marked 'in use' but not part of a volume
48#define CH_PTYPE_UNKNOWN '?' // Unknown/error condition (should be impossible)
49
50// Boot flag constants
51#define CH_FBOOT_BOOTABLE 'B' // Bootable (on Boot Manager menu)
52#define CH_FBOOT_STARTABLE 'S' // Startable (directly bootable)
53#define CH_FBOOT_INSTABLE 'I' // Installable (specific to IBM installer)
54#define CH_FBOOT_NONE 'N' // None (not bootable)
55
56// Removeable media type flags
57#define US_RMEDIA_PRM 1 // Partitionable removeable media
58#define US_RMEDIA_BIGFLOPPY 2 // "Big floppy" style removeable media
59
60// List of functions to be registered by RxLvmAddFuncs
61static PSZ RxLvmFunctionTbl[] = {
62 "RxLvmDropFuncs",
63 "RxLvmVersion",
64 "RxLvmBootMgrInfo",
65 "RxLvmBootMgrMenu",
66 "RxLvmEngineClose",
67 "RxLvmEngineOpen",
68 "RxLvmGetDisks",
69 "RxLvmGetPartitions",
70 "RxLvmGetVolumes",
71 "RxLvmRediscoverPRM"
72};
73
74
75// FUNCTION DECLARATIONS
76
77// Exported REXX functions
78RexxFunctionHandler RxLvmLoadFuncs;
79RexxFunctionHandler RxLvmDropFuncs;
80RexxFunctionHandler RxLvmVersion;
81RexxFunctionHandler RxLvmBootMgrInfo;
82RexxFunctionHandler RxLvmEngineClose;
83RexxFunctionHandler RxLvmEngineOpen;
84RexxFunctionHandler RxLvmGetDisks;
85RexxFunctionHandler RxLvmGetPartitions;
86RexxFunctionHandler RxLvmGetVolumes;
87RexxFunctionHandler RxLvmRediscoverPRM;
88
89// Private internal functions
90PSZ FixedVolumeFileSystem( ADDRESS volume, PSZ pszReportedFS );
91PSZ FixedPartitionFileSystem( BYTE fOS, PSZ pszReportedFS );
92void EngineError( PRXSTRING prsResult, ULONG ulErrorCode );
93void WriteStemElement( PSZ pszStem, ULONG ulIndex, PSZ pszValue );
94
95
96/* ------------------------------------------------------------------------- *
97 * RxLvmLoadFuncs *
98 * *
99 * Should be self-explanatory... *
100 * *
101 * REXX ARGUMENTS: none *
102 * REXX RETURN VALUE: "" *
103 * ------------------------------------------------------------------------- */
104ULONG APIENTRY RxLvmLoadFuncs( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
105{
106 int entries,
107 i;
108
109 if ( argc > 0 ) return ( 40 );
110 entries = sizeof(RxLvmFunctionTbl) / sizeof(PSZ);
111 for ( i = 0; i < entries; i++ )
112 RexxRegisterFunctionDll( RxLvmFunctionTbl[i], SZ_LIBRARY_NAME, RxLvmFunctionTbl[i] );
113
114 MAKERXSTRING( *prsResult, "", 0 );
115 return ( 0 );
116}
117
118
119/* ------------------------------------------------------------------------- *
120 * RxLvmDropFuncs *
121 * *
122 * Ditto. *
123 * *
124 * REXX ARGUMENTS: none *
125 * REXX RETURN VALUE: "" *
126 * ------------------------------------------------------------------------- */
127ULONG APIENTRY RxLvmDropFuncs( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
128{
129 int entries,
130 i;
131
132 if ( argc > 0 ) return ( 40 );
133 entries = sizeof(RxLvmFunctionTbl) / sizeof(PSZ);
134 for ( i = 0; i < entries; i++ )
135 RexxDeregisterFunction( RxLvmFunctionTbl[i] );
136
137 MAKERXSTRING( *prsResult, "", 0 );
138 return ( 0 );
139}
140
141
142/* ------------------------------------------------------------------------- *
143 * RxLvmVersion *
144 * *
145 * Returns the current version string. *
146 * *
147 * REXX ARGUMENTS: none *
148 * REXX RETURN VALUE: current version in the form "major.minor.refresh" *
149 * ------------------------------------------------------------------------- */
150ULONG APIENTRY RxLvmVersion( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
151{
152 CHAR szVersion[ 12 ];
153
154 if ( argc > 0 ) return ( 40 );
155 sprintf( szVersion, "%d.%d.%d", US_VERSION_MAJOR, US_VERSION_MINOR, US_VERSION_REFRESH );
156 MAKERXSTRING( *prsResult, szVersion, strlen(szVersion) );
157 return ( 0 );
158}
159
160
161/* ------------------------------------------------------------------------- *
162 * RxLvmRediscoverPRM() *
163 * *
164 * Checks to see if any Partitionable Removeable Media (e.g. Zip disks) have *
165 * been inserted since the last check. IMPORTANT: the LVM Engine must be *
166 * CLOSED before this function may be called. This function will fail if *
167 * the LVM Engine is open. *
168 * *
169 * REXX ARGUMENTS: none *
170 * REXX RETURN VALUE: "" or error string *
171 * ------------------------------------------------------------------------- */
172ULONG APIENTRY RxLvmRediscoverPRM( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
173{
174 ULONG ulError; // LVM.DLL error indicator
175
176 if ( argc > 0 ) return ( 40 );
177 Rediscover_PRMs( &ulError );
178 if ( ulError != LVM_ENGINE_NO_ERROR ) EngineError( prsResult, ulError );
179 else MAKERXSTRING( *prsResult, "", 0 );
180 return ( 0 );
181}
182
183
184/* ------------------------------------------------------------------------- *
185 * RxLvmEngineOpen *
186 * *
187 * Opens the LVM engine (LVM.DLL), which is required for all LVM operations *
188 * (except, for some reason, the Rediscover_PRMs operation). *
189 * *
190 * REXX ARGUMENTS: none *
191 * REXX RETURN VALUE: "" or error string *
192 * ------------------------------------------------------------------------- */
193ULONG APIENTRY RxLvmEngineOpen( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
194{
195 ULONG ulError;
196
197 if ( argc > 0 ) return ( 40 );
198 Open_LVM_Engine( TRUE, &ulError );
199 if ( ulError != LVM_ENGINE_NO_ERROR ) {
200 EngineError( prsResult, ulError );
201 return ( 0 );
202 }
203 MAKERXSTRING( *prsResult, "", 0 );
204 return ( 0 );
205}
206
207
208/* ------------------------------------------------------------------------- *
209 * RxLvmEngineClose *
210 * *
211 * Closes the LVM engine. *
212 * *
213 * REXX ARGUMENTS: none *
214 * REXX RETURN VALUE: "" or error string *
215 * ------------------------------------------------------------------------- */
216ULONG APIENTRY RxLvmEngineClose( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
217{
218 if ( argc > 0 ) return ( 40 );
219 Close_LVM_Engine();
220 MAKERXSTRING( *prsResult, "", 0 );
221 return ( 0 );
222}
223
224
225/* ------------------------------------------------------------------------- *
226 * RxLvmBootMgrInfo *
227 * *
228 * REXX ARGUMENTS: none *
229 * *
230 * REXX RETURN VALUE: *
231 * "" if Boot Manager is not installed. If an LVM error occurs, an error *
232 * string is returned. Otherwise, the returned string is in the format: *
233 * "<disk> <active> <timeout> <default-type> <default-handle>". As usual, *
234 * can also return an error string if an LVM error occurs. *
235 * ------------------------------------------------------------------------- */
236ULONG APIENTRY RxLvmBootMgrInfo( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
237{
238 // Data structures defined by LVM.DLL that we use for our queries
239 Partition_Information_Record enginePartitionInfo;
240 Drive_Control_Array engineDisks;
241 Drive_Control_Record engineCurrentDisk;
242
243 ULONG ulDisk = 0, // Number of the physical disk Boot Manager is on
244 i, // Guess :)
245 ulTimeout, // Indicates the timeout value for a timeout boot
246 ulError; // LVM.DLL error indicator
247 ADDRESS partition, // LVM handle of physical Boot Manager partition
248 drive, // LVM handle of the disk drive Boot Manager is on
249 defaultEntry; // LVM handle of the default boot menu entry
250 BOOLEAN fVolume, // Indicates whether said entry is a volume rather just than a partition
251 fAdvanced, // Indicates whether Advanced (verbose) view mode is used
252 fTimeout, // Indicates whether a timeout boot will occur
253 fActive; // Indicates whether the Boot Manager partition is 'active'
254 CHAR szInfo[ US_BMINFO_MAXZ ]; // Buffer used to build the final return string
255
256
257 if ( argc > 0 ) return ( 40 );
258
259 // Query the Boot Manager partition handle
260 partition = Get_Boot_Manager_Handle( &ulError );
261 if ( ulError != LVM_ENGINE_NO_ERROR ) {
262 EngineError( prsResult, ulError );
263 return ( 0 );
264 }
265
266 // Return '' if Boot Manager is not installed
267 if ( partition == NULL ) {
268 MAKERXSTRING( *prsResult, "", 0 );
269 return ( 0 );
270 }
271
272 // Find out what disk drive the Boot Manager partition resides on
273 enginePartitionInfo = Get_Partition_Information( partition, &ulError );
274 if ( ulError != LVM_ENGINE_NO_ERROR ) {
275 EngineError( prsResult, ulError );
276 return ( 0 );
277 }
278 drive = enginePartitionInfo.Drive_Handle;
279 engineDisks = Get_Drive_Control_Data( &ulError );
280 if ( ulError != LVM_ENGINE_NO_ERROR ) {
281 EngineError( prsResult, ulError );
282 return ( 0 );
283 }
284 for ( i = 0; i < engineDisks.Count; i++ ) {
285 engineCurrentDisk = engineDisks.Drive_Control_Data[ i ];
286 if ( engineCurrentDisk.Drive_Handle == drive )
287 ulDisk = engineCurrentDisk.Drive_Number;
288 }
289
290 // Get the current Boot Manager configuration
291 Get_Boot_Manager_Options( &defaultEntry, &fVolume,
292 &fTimeout, &ulTimeout,
293 &fAdvanced, &ulError );
294 if ( ulError != LVM_ENGINE_NO_ERROR ) {
295 EngineError( prsResult, ulError );
296 return ( 0 );
297 }
298
299 // Figure out if Boot Manager is 'active'
300 if ( enginePartitionInfo.Active_Flag == ACTIVE_PARTITION )
301 fActive = TRUE;
302 else
303 fActive = FALSE;
304
305 // Now return all the nice data
306 sprintf( szInfo, "%d %d %d %d %X", ulDisk, fActive, ulTimeout, fVolume, defaultEntry );
307 MAKERXSTRING( *prsResult, szInfo, strlen(szInfo) );
308 return ( 0 );
309}
310
311
312
313/* ------------------------------------------------------------------------- *
314 * RxLvmBootMgrMenu() *
315 * *
316 * Returns the list of volumes and/or partitions on the Boot Manager menu *
317 * (i.e. have the 'bootable' flag set). *
318 * *
319 * Data representing the menu entries is written to the specified REXX *
320 * variable. stem.0 contains the number of entries, and each other item is: *
321 * "<handle> <type> <name>" *
322 * e.g. menu.1 == "0C0FB884 V OS/2 System" *
323 * *
324 * REXX ARGUMENTS: name of the REXX stem variable to populate *
325 * *
326 * REXX RETURN VALUE: "1" or error string *
327 * ------------------------------------------------------------------------- */
328ULONG APIENTRY RxLvmBootMgrMenu( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
329{
330 // Data structures defined by LVM.DLL that we use for our queries
331 Boot_Manager_Menu engineBootMenu;
332 Boot_Manager_Menu_Item engineBootMenuEntry;
333 Volume_Information_Record engineVolumeInfo;
334 Partition_Information_Record enginePartitionInfo;
335
336 ULONG ulError, // LVM Engine error code
337 i;
338 CHAR szStem[ US_STEM_MAXZ ], // Buffers used for building strings ...
339 szNumber[ US_INTEGER_MAXZ ],
340 szMenuItem[ US_SZINFO_MAXZ ];
341 USHORT usRemoveable = 0;
342
343
344 // Do some validity checking on the arguments
345 if (( argc != 1 ) || // Make sure we have exactly one argument...
346 ( ! RXVALIDSTRING(argv[0]) ) || // ...which is a valid REXX string...
347 ( RXSTRLEN(argv[0]) > US_STEM_MAXZ )) // ...and isn't too long.
348 return ( 40 );
349
350 engineBootMenu = Get_Boot_Manager_Menu( &ulError );
351 if ( ulError != LVM_ENGINE_NO_ERROR ) {
352 EngineError( prsResult, ulError );
353 return ( 0 );
354 }
355
356 // Generate the stem variable name from the argument (stripping any final dot)
357 if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--;
358 strncpy( szStem, argv[0].strptr, RXSTRLEN(argv[0]) );
359 szStem[ RXSTRLEN(argv[0]) ] = '\0';
360
361 // Create a stem.0 element containing the number of disks
362 sprintf( szNumber, "%d", engineBootMenu.Count );
363 WriteStemElement( szStem, 0, szNumber );
364
365 for ( i = 0; i < engineBootMenu.Count; i++ ) {
366 engineBootMenuEntry = engineBootMenu.Menu_Items[ i ];
367 if ( engineBootMenuEntry.Volume ) {
368 engineVolumeInfo = Get_Volume_Information( engineBootMenuEntry.Handle, &ulError );
369 if ( ulError != LVM_ENGINE_NO_ERROR ) {
370 EngineError( prsResult, ulError );
371 return ( 0 );
372 }
373 sprintf( szMenuItem, "%08X 1 %s", engineBootMenuEntry.Handle, engineVolumeInfo.Volume_Name );
374 } else {
375 enginePartitionInfo = Get_Partition_Information( engineBootMenuEntry.Handle, &ulError );
376 if ( ulError != LVM_ENGINE_NO_ERROR ) {
377 EngineError( prsResult, ulError );
378 return ( 0 );
379 }
380 sprintf( szMenuItem, "%08X 0 %s", engineBootMenuEntry.Handle, enginePartitionInfo.Partition_Name );
381 }
382 // Create a stem variable item for the current disk
383 WriteStemElement( szStem, i+1, szMenuItem );
384 }
385
386 // Always return a standard value (1) on success
387 MAKERXSTRING( *prsResult, "1", 1 );
388 return ( 0 );
389}
390
391
392/* ------------------------------------------------------------------------- *
393 * RxLvmGetDisks *
394 * *
395 * Data representing all disk drives is written to the specified REXX *
396 * variable. stem.0 contains the number of disks, and each other item is: *
397 * "<handle> <num> <size> <unusable> <corrupt> <removable> <serial> <name>" *
398 * e.g. disks.1 == "0C0FB884 1 156327 0 0 0 485209174 [ D1 ]" *
399 * *
400 * REXX ARGUMENTS: name of the REXX stem variable to populate *
401 * *
402 * REXX RETURN VALUE: "1" or error string *
403 * ------------------------------------------------------------------------- */
404ULONG APIENTRY RxLvmGetDisks( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
405{
406 // Data structures defined by LVM.DLL that we use for our queries
407 Drive_Control_Array engineDrives;
408 Drive_Control_Record engineDriveRecord;
409 Drive_Information_Record engineDriveInfo;
410
411 ULONG ulError,
412 i,
413 ulSize,
414 ulSerial;
415 CHAR szStem[ US_STEM_MAXZ ], // Buffers used for building strings ...
416 szNumber[ US_INTEGER_MAXZ ],
417 szDiskInfo[ US_STEM_MAXZ ];
418 USHORT usRemoveable = 0;
419 BOOL fUnuseable = FALSE,
420 fCorrupt = FALSE;
421
422
423 // Do some validity checking on the arguments
424 if (( argc != 1 ) || // Make sure we have exactly one argument...
425 ( ! RXVALIDSTRING(argv[0]) ) || // ...which is a valid REXX string...
426 ( RXSTRLEN(argv[0]) > US_STEM_MAXZ )) // ...and isn't too long.
427 return ( 40 );
428
429 // Get the list of disks from LVM.DLL
430 engineDrives = Get_Drive_Control_Data( &ulError );
431 if ( ulError != LVM_ENGINE_NO_ERROR ) {
432 EngineError( prsResult, ulError );
433 return ( 0 );
434 }
435
436 // Generate the stem variable name from the argument (stripping any final dot)
437 if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--;
438 strncpy( szStem, argv[0].strptr, RXSTRLEN(argv[0]) );
439 szStem[ RXSTRLEN(argv[0]) ] = '\0';
440
441 // Create a stem.0 element containing the number of disks
442 sprintf( szNumber, "%d", engineDrives.Count );
443 WriteStemElement( szStem, 0, szNumber );
444
445 // Now generate the information for each disk
446 for ( i = 0; i < engineDrives.Count; i++ ) {
447
448 // Get the current drive information
449 engineDriveRecord = engineDrives.Drive_Control_Data[ i ];
450 engineDriveInfo = Get_Drive_Status( engineDriveRecord.Drive_Handle, &ulError );
451 if ( ulError != LVM_ENGINE_NO_ERROR ) {
452 EngineError( prsResult, ulError );
453 return ( 0 );
454 }
455
456 if ( engineDriveRecord.Drive_Is_PRM ) usRemoveable = US_RMEDIA_PRM;
457 if ( engineDriveInfo.Is_Big_Floppy ) usRemoveable = US_RMEDIA_BIGFLOPPY;
458
459 if (( engineDriveInfo.Is_Big_Floppy ) || ( engineDriveInfo.Unusable )) {
460 fUnuseable = TRUE;
461 ulSize = 0;
462 ulSerial = 0;
463 } else {
464 if ( engineDriveInfo.Corrupt_Partition_Table ) fCorrupt = TRUE;
465 ulSize = ( engineDriveRecord.Drive_Size ) / UL_SECTORS_PER_MB;
466 ulSerial = engineDriveRecord.Drive_Serial_Number;
467 }
468
469 sprintf( szDiskInfo, "%08X %d %d %d %d %d %d %s",
470 engineDriveRecord.Drive_Handle,
471 engineDriveRecord.Drive_Number,
472 ulSize,
473 fUnuseable,
474 fCorrupt,
475 usRemoveable,
476 ulSerial,
477 engineDriveInfo.Drive_Name );
478
479 // Create a stem variable item for the current disk
480 WriteStemElement( szStem, i+1, szDiskInfo );
481
482 }
483 // Free the LVM data structures
484 Free_Engine_Memory( engineDrives.Drive_Control_Data );
485
486 // Always return a standard value (1) on success
487 MAKERXSTRING( *prsResult, "1", 1 );
488 return ( 0 );
489}
490
491
492/* ------------------------------------------------------------------------- *
493 * RxLvmGetPartitions *
494 * *
495 * Data representing all partitions belonging to the specified object is *
496 * written to the specified REXX variable. stem.0 contains the number of *
497 * disks, and each other item is: *
498 * "<phandle> <dhandle> <vhandle> <status> <fs> <size> <os> <boot> <name>" *
499 * e.g. parts.1 == "FC177C67 FC177717 FC179B17 C HPFS 2047 07 N OS/2" *
500 * *
501 * REXX ARGUMENTS: 1 - handle of the object to query *
502 * 2 - name of the REXX stem variable to populate *
503 * *
504 * REXX RETURN VALUE: "1" or error string *
505 * ------------------------------------------------------------------------- */
506ULONG APIENTRY RxLvmGetPartitions( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
507{
508 // Data structures defined by LVM.DLL that we use for our queries
509 Partition_Information_Array enginePartitions;
510 Partition_Information_Record enginePartInfo;
511 Volume_Information_Record engineVolumeInfo;
512
513 ADDRESS ulHandle; // requested handle
514 ULONG ulError, // LVM.DLL error indicator
515 i, // Duh
516 ulRc; // Used for return code
517 PSZ pszCompound, // The current compound variable name
518 pszPartInfo; // The current partition info string
519 CHAR szStem[ US_STEM_MAXZ ], // Buffers used for building strings ...
520 szNumber[ US_INTEGER_MAXZ ],
521 szDevice[ US_DEVTYPE_MAXZ ],
522 szPartInfo[ US_STEM_MAXZ ],
523 cStatus, // adjusted partition status flag
524 cBootable; // Partition bootable flag (N/B/S/I)
525
526
527 // Do some validity checking on the arguments
528 if (( argc != 2 ) || // Make sure we have exactly two arguments...
529 ( ! RXVALIDSTRING(argv[0]) ) || // ...which are valid REXX strings...
530 ( ! RXVALIDSTRING(argv[1]) ) ||
531 ( RXSTRLEN(argv[1]) > US_STEM_MAXZ ) // ...and the stem name isn't too long.
532 )
533 return ( 40 );
534
535 // Parse the handle argument
536 if ( sscanf( argv[0].strptr, "%X", &ulHandle ) < 1 )
537 return ( 40 );
538
539 // Get the list of partitions from LVM.DLL
540 enginePartitions = Get_Partitions( ulHandle, &ulError );
541 if ( ulError != LVM_ENGINE_NO_ERROR ) {
542 EngineError( prsResult, ulError );
543 return ( 0 );
544 }
545
546 // Generate the stem variable name from the argument
547 // (and strip any terminating dot while we're at it)
548 if ( argv[1].strptr[ argv[1].strlength-1 ] == '.') argv[1].strlength--;
549 strncpy( szStem, argv[1].strptr, RXSTRLEN(argv[1]) );
550 szStem[ RXSTRLEN(argv[1]) ] = '\0';
551
552 // Create a stem.0 element containing the number of volumes
553 sprintf( szNumber, "%d", enginePartitions.Count );
554 WriteStemElement( szStem, 0, szNumber );
555
556 // Now generate the information for each partition
557 for ( i = 0; i < enginePartitions.Count; i++ ) {
558 enginePartInfo = enginePartitions.Partition_Array[ i ];
559
560 switch ( enginePartInfo.Partition_Status ) {
561 case PARTITION_IS_FREE_SPACE:
562 cStatus = CH_PTYPE_FREESPACE;
563 cBootable = CH_FBOOT_NONE;
564 break;
565
566 case PARTITION_IS_IN_USE:
567 if ( enginePartInfo.Volume_Handle == NULL ) {
568 // Marked "in use", but not part of a volume - probably Boot Manager
569 cStatus = CH_PTYPE_INUSE;
570 if ( enginePartInfo.Active_Flag == ACTIVE_PARTITION )
571 cBootable = CH_FBOOT_STARTABLE;
572 else if ( enginePartInfo.On_Boot_Manager_Menu )
573 cBootable = CH_FBOOT_BOOTABLE;
574 else
575 cBootable = CH_FBOOT_NONE;
576 } else {
577 // Partition belongs to a volume
578 switch ( enginePartInfo.Partition_Type ) {
579 case 0 : cStatus = CH_PTYPE_FREESPACE; break; // Free space
580 case 1 : cStatus = CH_PTYPE_LVOLUME; break; // (Part of) LVM volume
581 case 2 : cStatus = CH_PTYPE_CVOLUME; break; // Compatibility volume
582 default: cStatus = CH_PTYPE_UNKNOWN; break; // Unknown/error
583 }
584 engineVolumeInfo = Get_Volume_Information( enginePartInfo.Volume_Handle, &ulError );
585 if ( ulError != LVM_ENGINE_NO_ERROR ) {
586 EngineError( prsResult, ulError );
587 return ( 0 );
588 }
589 switch ( engineVolumeInfo.Status ) {
590 case 1 : cBootable = CH_FBOOT_BOOTABLE; break;
591 case 2 : cBootable = CH_FBOOT_STARTABLE; break;
592 case 3 : cBootable = CH_FBOOT_INSTABLE; break;
593 default: cBootable = CH_FBOOT_NONE; break;
594 }
595 }
596 break;
597
598 case PARTITION_IS_AVAILABLE:
599 cStatus = CH_PTYPE_AVAILABLE;
600 if ( enginePartInfo.Active_Flag == ACTIVE_PARTITION ) cBootable = CH_FBOOT_STARTABLE;
601 else if ( enginePartInfo.On_Boot_Manager_Menu ) cBootable = CH_FBOOT_BOOTABLE;
602 else cBootable = CH_FBOOT_NONE;
603 break;
604
605 default:
606 // Fall-through; should be unreachable
607 cStatus = CH_PTYPE_UNKNOWN;
608 cBootable = CH_FBOOT_NONE;
609 break;
610 }
611
612 sprintf( szPartInfo, "%08X %08X %08X %c %s %d %02X %c %s",
613 enginePartInfo.Partition_Handle,
614 enginePartInfo.Drive_Handle,
615 enginePartInfo.Volume_Handle,
616 cStatus,
617 FixedPartitionFileSystem( enginePartInfo.OS_Flag, enginePartInfo.File_System_Name ),
618 enginePartInfo.Usable_Partition_Size / UL_SECTORS_PER_MB,
619 enginePartInfo.OS_Flag,
620 cBootable,
621 enginePartInfo.Partition_Name );
622
623 // Create a stem variable item for the current partition
624 WriteStemElement( szStem, i+1, szPartInfo );
625
626 }
627
628 // Free the LVM data structures
629 Free_Engine_Memory( enginePartitions.Partition_Array );
630
631 // Always return a standard value (1) on success
632 MAKERXSTRING( *prsResult, "1", 1 );
633 return ( 0 );
634}
635
636
637/* ------------------------------------------------------------------------- *
638 * RxLvmGetVolumes *
639 * *
640 * Data representing all logical volumes is written to the specified REXX *
641 * variable. stem.0 contains the number of volumes, and each other item is: *
642 * "<handle> <letter> <pref> <fs> <size> <dev> <type> <bootable> <name>" *
643 * e.g. volumes.1 == "0A00CDB1 C C HPFS 2047 HDD 0 B eComStation" *
644 * *
645 * REXX ARGUMENTS: name of the REXX stem variable to populate *
646 * *
647 * REXX RETURN VALUE: "1" or error string *
648 * ------------------------------------------------------------------------- */
649ULONG APIENTRY RxLvmGetVolumes( PSZ pszName, ULONG argc, RXSTRING argv[], PSZ pszQueue, PRXSTRING prsResult )
650{
651 // Data structures defined by LVM.DLL that we use for our queries
652 Volume_Control_Array engineVolumes;
653 Volume_Information_Record engineVolumeInfo;
654 Partition_Information_Array enginePartitions;
655 Partition_Information_Record enginePartInfo;
656
657 ULONG ulError, // LVM.DLL error indicator
658 i, // Duh
659 ulRc; // Used for return code
660 USHORT usVolType; // Volume type flag (0 or 1)
661 PSZ pszCompound, // The current compound variable name
662 pszVolInfo; // The current volume info string
663 CHAR szStem[ US_STEM_MAXZ ], // Buffers used for building strings ...
664 szNumber[ US_INTEGER_MAXZ ],
665 szDevice[ US_DEVTYPE_MAXZ ],
666 szVolInfo[ US_STEM_MAXZ ],
667 cCurrent, // A volume's current drive letter
668 cPreference, // A volume's preferred drive letter
669 cBootable; // Volume bootable flag (N/B/S/I)
670 BOOLEAN fCompatible; // Use to query volume type from LVM.DLL
671
672
673 // Do some validity checking on the arguments
674 if (( argc != 1 ) || // Make sure we have exactly one argument...
675 ( ! RXVALIDSTRING(argv[0]) ) || // ...which is a valid REXX string...
676 ( RXSTRLEN(argv[0]) > US_STEM_MAXZ ) // ...and isn't too long.
677 )
678 return ( 40 );
679
680 // Get the list of volumes from LVM.DLL
681 engineVolumes = Get_Volume_Control_Data( &ulError );
682 if ( ulError != LVM_ENGINE_NO_ERROR ) {
683 EngineError( prsResult, ulError );
684 return ( 0 );
685 }
686
687 // Generate the stem variable name from the argument
688 // (and strip any terminating dot while we're at it)
689 // if ( argv[0].strlength > US_STEM_MAXZ - 5 ) argv[0].strlength = US_STEM_MAXZ - 5;
690 if ( argv[0].strptr[ argv[0].strlength-1 ] == '.') argv[0].strlength--;
691 strncpy( szStem, argv[0].strptr, RXSTRLEN(argv[0]) );
692 szStem[ RXSTRLEN(argv[0]) ] = '\0';
693
694 // Create a stem.0 element containing the number of volumes
695 sprintf( szNumber, "%d", engineVolumes.Count );
696 WriteStemElement( szStem, 0, szNumber );
697
698 // Now generate the information for each volume
699 for ( i = 0; i < engineVolumes.Count; i++ ) {
700
701 // Get the current volume information record
702 engineVolumeInfo = Get_Volume_Information( engineVolumes.Volume_Control_Data[ i ].Volume_Handle, &ulError );
703 if ( ulError != LVM_ENGINE_NO_ERROR ) {
704 EngineError( prsResult, ulError );
705 return ( 0 );
706 }
707
708 // Now build our info-string that will be returned to the REXX program
709 switch ( engineVolumes.Volume_Control_Data[ i ].Device_Type ) {
710 case LVM_HARD_DRIVE : strcpy( szDevice, SZ_DEVICE_HDD ); break;
711 case LVM_PRM : strcpy( szDevice, SZ_DEVICE_PRM ); break;
712 case NON_LVM_CDROM : strcpy( szDevice, SZ_DEVICE_CDROM ); break;
713 case NETWORK_DRIVE : strcpy( szDevice, SZ_DEVICE_NETWORK ); break;
714 default : strcpy( szDevice, SZ_DEVICE_OTHER ); break;
715 }
716 usVolType = ! engineVolumeInfo.Compatibility_Volume;
717 if ( engineVolumes.Volume_Control_Data[ i ].Device_Type >= NON_LVM_CDROM ) cBootable = CH_FBOOT_NONE;
718 else switch ( engineVolumeInfo.Status ) {
719 case 1 : cBootable = CH_FBOOT_BOOTABLE; break;
720 case 2 : cBootable = CH_FBOOT_STARTABLE; break;
721 case 3 : cBootable = CH_FBOOT_INSTABLE; break;
722 default: cBootable = CH_FBOOT_NONE; break;
723 }
724 if ( isalpha(engineVolumeInfo.Current_Drive_Letter) | engineVolumeInfo.Current_Drive_Letter == '*')
725 cCurrent = engineVolumeInfo.Current_Drive_Letter;
726 else cCurrent = '?';
727 if ( isalpha(engineVolumeInfo.Drive_Letter_Preference) | engineVolumeInfo.Drive_Letter_Preference == '*')
728 cPreference = engineVolumeInfo.Drive_Letter_Preference;
729 else cPreference = '?';
730
731 sprintf( szVolInfo, "%08X %c %c %s %d %s %d %c %s",
732 engineVolumes.Volume_Control_Data[ i ].Volume_Handle,
733 cCurrent,
734 cPreference,
735 FixedVolumeFileSystem( engineVolumes.Volume_Control_Data[ i ].Volume_Handle, engineVolumeInfo.File_System_Name ),
736 engineVolumeInfo.Volume_Size / UL_SECTORS_PER_MB,
737 szDevice,
738 usVolType,
739 cBootable,
740 engineVolumeInfo.Volume_Name );
741
742 // Create a stem variable item for the current volume
743 WriteStemElement( szStem, i+1, szVolInfo );
744
745 }
746
747 // Free the LVM data structures
748 Free_Engine_Memory( engineVolumes.Volume_Control_Data );
749
750 // Always return a standard value (1) on success
751 MAKERXSTRING( *prsResult, "1", 1 );
752 return ( 0 );
753}
754
755
756/* ------------------------------------------------------------------------- *
757 * FixedVolumeFileSystem *
758 * *
759 * Double-checks the given volume's filesystem-type string in order to work *
760 * around a bug in the LVM.DLL's reporting of Linux partition types. *
761 * OS Flag 0x82 is Linux Swap, but LVM.DLL reports it as 'Linux'; 0x83 is *
762 * Linux Native, but LVM.DLL reports it as '????'. *
763 * *
764 * ARGUMENTS: *
765 * ADDRESS volume : Handle to the volume being queried *
766 * PSZ pszReportedFS : FS name as reported by LVM.DLL *
767 * *
768 * RETURNS: PSZ *
769 * The "fixed" filesystem string. *
770 * ------------------------------------------------------------------------- */
771PSZ FixedVolumeFileSystem( ADDRESS volume, PSZ pszReportedFS )
772{
773 Partition_Information_Array enginePartitions;
774
775 ULONG ulError;
776 BYTE fOS;
777 PSZ s,
778 pszFixed;
779
780 // Get the OS flag reported by the (first) underlying partition
781 enginePartitions = Get_Partitions( volume, &ulError );
782 if (( ulError != LVM_ENGINE_NO_ERROR ) || ( enginePartitions.Count == 0 )) {
783 if ( strlen(pszReportedFS) == 0 ) return "?";
784 while (( s = strchr( pszReportedFS, ' ')) != NULL ) *s = 0xFF;
785 return pszReportedFS;
786 }
787
788 // Now fix the reported file system based on the OS flag
789 pszFixed = FixedPartitionFileSystem( enginePartitions.Partition_Array[ 0 ].OS_Flag,
790 pszReportedFS );
791
792 // Free the LVM data structure
793 Free_Engine_Memory( enginePartitions.Partition_Array );
794
795 return ( pszFixed );
796}
797
798
799/* ------------------------------------------------------------------------- *
800 * FixedPartitionFileSystem *
801 * *
802 * Double-checks the given partition's filesystem-type string in order to *
803 * work around a bug in the LVM.DLL's reporting of Linux partition types; *
804 * see FixedVolumeFileSystem() description. *
805 * *
806 * ARGUMENTS: *
807 * BYTE fOS : OS flag reported by the partition *
808 * PSZ pszReportedFS : FS name as reported by LVM.DLL *
809 * *
810 * RETURNS: PSZ *
811 * The "fixed" filesystem string. *
812 * ------------------------------------------------------------------------- */
813PSZ FixedPartitionFileSystem( BYTE fOS, PSZ pszReportedFS )
814{
815 PSZ s;
816
817 if ( strlen(pszReportedFS) == 0 ) return "?";
818 while (( s = strchr( pszReportedFS, ' ')) != NULL ) *s = 0xFF;
819 switch ( fOS ) {
820 case 0x82 : return ("Linux_Swap");
821 case 0x83 : return ("Linux");
822 default : return ( pszReportedFS );
823 }
824}
825
826
827/* ------------------------------------------------------------------------- *
828 * EngineError *
829 * *
830 * Writes a standardized error message to an RXSTRING, in the event that an *
831 * error code is returned by LVM.DLL during an operation. *
832 * *
833 * ARGUMENTS: *
834 * PRXSTRING prsResult : Pointer to the RXSTRING in which the message *
835 * will be written. Must be allocated already. *
836 * ULONG ulErrorCode : The error code returned by LVM.DLL. *
837 * *
838 * RETURNS: N/A *
839 * ------------------------------------------------------------------------- */
840void EngineError( PRXSTRING prsResult, ULONG ulErrorCode )
841{
842 CHAR szError[ US_ERRSTR_MAXZ ];
843
844 sprintf( szError, SZ_ENGINE_ERROR, ulErrorCode );
845 if ( prsResult->strptr == NULL )
846 DosAllocMem( (PPVOID) &(prsResult->strptr), strlen(szError), PAG_COMMIT | PAG_WRITE );
847 MAKERXSTRING( *prsResult, szError, strlen(szError) );
848}
849
850
851/* ------------------------------------------------------------------------- *
852 * WriteStemElement *
853 * *
854 * Creates a stem element (compound variable) in the calling REXX program *
855 * using the REXX shared variable pool interface. *
856 * *
857 * ARGUMENTS: *
858 * PSZ pszStem : The name of the stem (before the '.') *
859 * ULONG ulIndex : The number of the stem element (after the '.') *
860 * PSZ pszValue : The value to write to the compound variable. *
861 * *
862 * RETURNS: N/A *
863 * ------------------------------------------------------------------------- */
864void WriteStemElement( PSZ pszStem, ULONG ulIndex, PSZ pszValue )
865{
866 SHVBLOCK shvVar; // REXX shared variable pool block
867 ULONG ulRc;
868 CHAR szCompoundName[ US_COMPOUND_MAXZ ],
869 szValue[ US_SZINFO_MAXZ ];
870
871 sprintf( szCompoundName, "%s.%d", pszStem, ulIndex );
872 strncpy( szValue, pszValue, US_SZINFO_MAXZ );
873 MAKERXSTRING( shvVar.shvname, szCompoundName, strlen(szCompoundName) );
874 MAKERXSTRING( shvVar.shvvalue, szValue, strlen(szValue) );
875 shvVar.shvnamelen = RXSTRLEN( shvVar.shvname );
876 shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
877 shvVar.shvcode = RXSHV_SYSET;
878 shvVar.shvnext = NULL;
879 ulRc = RexxVariablePool( &shvVar );
880 if ( ulRc > 1 )
881 printf("Unable to set %s: rc = %d\n", shvVar.shvname.strptr, shvVar.shvret );
882
883}
884
885
886
Note: See TracBrowser for help on using the repository browser.