2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
9 /******************************************************************************
18 DISKS/S, VOLS=VOLUMES/S, ALL/S, BLOCKS/S, DEVICES/M
26 Show information on file system devices and volumes. When given no
27 arguments, information on all devices and volumes found in the system
28 is displayed. If information is wanted only for some specific devices,
29 these names may be given as arguments.
33 DISKS -- show information on file system devices
34 VOLS -- show information on volumes
35 ALL -- show information on bad devices or volumes
36 BLOCKS -- show additional block size and usage information
37 DEVICES -- device names to show information about
47 Unit Size Used Free Full Errs State Type Name
48 Harddisk: 964.1M 776.7M 187.4M 81% 0 read/write OFS AROS
49 RAM: 8.0M 7.1M 7.1M 12% 0 read/write OFS Ram Disk
57 The original source showed that AROS version of ReadArgs() handles
58 the /M switch with zero arguments differently from AmigaOS. While AROS
59 returns an array where the first pointer is NULL, AmigaOS just returns
64 16.11.2000 SDuvan -- converted to AROS
65 23.12.2000 SDuvan -- changed semantics and updated
66 (now fully functional)
67 17.02.2005 Joe Fenton -- fixed 64bit calculation
69 Based on the original by:
70 © 1997-1998 by Stephan Rupprecht
72 ******************************************************************************/
75 #include <aros/debug.h>
78 #include <dos/dosextens.h>
79 #include <dos/filehandler.h>
80 #include <exec/memory.h>
81 #include <libraries/locale.h>
83 #include <proto/dos.h>
84 #include <proto/exec.h>
85 #include <proto/utility.h>
86 #include <proto/locale.h>
87 #include <proto/alib.h>
93 ULONG
ComputeKBytes(ULONG a
, ULONG b
);
94 void FmtProcedure(struct Hook
*hook
, char a
, struct Locale
*locale
);
95 ULONG
ExtUDivMod32(ULONG a
, ULONG b
, ULONG
*mod
);
99 const TEXT VersionStr
[] = "$VER: Info 41.2 (26.05.2012)";
102 struct Locale
*loc
= NULL
;
108 /* catalog string id:s */
129 struct InfoDosNode
*Next
;
132 struct MsgPort
*Task
;
133 struct DateStamp VolumeDate
;
137 struct InfoDosNode
*head
= NULL
;
145 struct DiskTypeList dtl
[] =
147 { ID_DOS_DISK
, "OFS" },
148 { ID_FFS_DISK
, "FFS" },
149 { ID_INTER_DOS_DISK
, "OFS-INT" },
150 { ID_INTER_FFS_DISK
, "FFS-INT" },
151 { ID_FASTDIR_DOS_DISK
, "OFS-DC" },
152 { ID_FASTDIR_FFS_DISK
, "FFS-DC" },
154 { ID_DOS_muFS_DISK
, "muFS OFS" },
155 { ID_FFS_muFS_DISK
, "muFS FFS" },
156 { ID_INTER_DOS_muFS_DISK
, "muFS OFS-INT" },
157 { ID_INTER_FFS_muFS_DISK
, "muFS FFS-INT" },
158 { ID_FASTDIR_DOS_muFS_DISK
, "muFS OFS-DC" },
159 { ID_FASTDIR_FFS_muFS_DISK
, "muFS FFS-DC" },
161 { ID_MSDOS_DISK
, "MS-DOS" },
162 { ID_ACD0_DISK
, "CDFS" },
163 { ID_CACHECDFS_DISK
, "CDFS" },
164 { ID_ASIMCDFS_DISK
, "CDFS" },
165 { ID_NOT_REALLY_DOS
, "NO DOS" },
166 { ID_MAC_DISK2
, "MAC" },
167 { ID_MNX1_DISK
, "Minix" },
168 { ID_QL5A_DISK
, "QL720k" },
169 { ID_QL5B_DISK
, "QL1.4M" },
170 { ID_CPM_DISK
, "CP/M" },
171 { ID_ZXS3_DISK
, "+3Dos" },
172 { ID_ZXS0_DISK
, "Disciple" },
173 { ID_ZXS1_DISK
, "UniDos" },
174 { ID_ZXS2_DISK
, "SamDos" },
175 { ID_ZXS4_DISK
, "Opus" },
176 { ID_P2A0_DISK
, "NETWORK" },
178 { ID_FAT12_DISK
, "FAT12" },
179 { ID_FAT16_DISK
, "FAT16" },
180 { ID_FAT32_DISK
, "FAT32" },
182 { ID_SFS_BE_DISK
, "SFS-BE" },
183 { ID_SFS_LE_DISK
, "SFS-LE" },
185 { ID_PFS_DISK
, "PFS" },
187 { ID_EXT2_DISK
, "EXT2" },
192 /****************************************************************************/
194 int UtilityBase_version
= 0;
195 int LocaleBase_version
= 0;
201 static struct TagItem loctags
[] = { { OC_Version
, 1 },
203 cat
= OpenCatalogA(NULL
, "info_com.catalog", loctags
);
204 loc
= OpenLocale(NULL
);
206 D(bug("Calling doInfo()\n"));
213 return RETURN_OK
; /* TODO: Fix this */
217 CONST_STRPTR
GetStrFromCat(ULONG id
, CONST_STRPTR def
)
221 def
= GetCatalogStr(cat
, id
, def
);
228 void VLPrintf(ULONG id
, CONST_STRPTR def
, ...)
230 CONST_STRPTR format
= GetStrFromCat(id
, def
);
231 AROS_SLOWSTACKFORMAT_PRE_USING(def
, format
);
232 VPrintf(format
, AROS_SLOWSTACKFORMAT_ARG(def
));
233 AROS_SLOWSTACKFORMAT_POST(def
);
237 BOOL
myMatchPatternNoCase(STRPTR
*array
, STRPTR str
)
241 while(*array
!= NULL
)
246 UBYTE len
= strlen(p
);
248 if(p
[len
- 1] != ':')
250 CopyMem(p
, name
, len
);
256 if(ParsePatternNoCase(p
, matchstr
, sizeof(matchstr
)) != -1)
258 if(MatchPatternNoCase(matchstr
, str
))
272 BOOL
ScanDosList(STRPTR
*filter
)
274 struct InfoDosNode
*idn
= 0L;
275 struct DosList
*ndl
, *dl
;
276 STRPTR
*strray
= NULL
, dummy
= NULL
;
279 D(bug("Entered ScanDosList()\n"));
281 if (filter
== NULL
) filter
= &dummy
;
285 strray
= AllocPooled(Pool
, sizeof(STRPTR
)*MAX_MULTIARGS
);
295 while(i
< MAX_MULTIARGS
)
302 /* lock list of devices & vols */
303 dl
= ndl
= LockDosList(LDF_ASSIGNS
| LDF_VOLUMES
| LDF_DEVICES
| LDF_READ
);
312 while((ndl
= NextDosEntry(ndl
, LDF_ASSIGNS
| LDF_VOLUMES
| LDF_READ
)) != NULL
)
315 STRPTR taskName
= NULL
; /* Initialized to avoid a warning */
317 __sprintf(name
, "%b:", ndl
->dol_Name
);
319 if ((ndl
->dol_Type
> DLT_VOLUME
) || !(myMatchPatternNoCase(strray
, name
)))
324 switch (ndl
->dol_Type
)
327 taskName
= ((struct Task
*)ndl
->dol_Task
->mp_SigTask
)->tc_Node
.ln_Name
;
329 D(bug("Found volume %s\n", taskName
));
334 struct AssignList
*al
= ndl
->dol_misc
.dol_assign
.dol_List
;
336 taskName
= ((struct Task
*)((struct FileLock
*)BADDR(ndl
->dol_Lock
))->fl_Task
->mp_SigTask
)->tc_Node
.ln_Name
;
338 D(bug("Found directory %s\n", taskName
));
342 *p
++ = ""; // TODO!!! ((struct Task *)((struct FileLock *)BADDR(al->al_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
357 while((ndl
= NextDosEntry(ndl
, LDF_VOLUMES
| LDF_DEVICES
| LDF_READ
)) != NULL
)
360 UBYTE type
= ndl
->dol_Type
;
363 /* do not start non-started handlers or open CON: or RAW: windows */
364 if(type
== DLT_DEVICE
&& !ndl
->dol_Task
)
367 __sprintf(name
, "%b:", ndl
->dol_Name
);
368 D(bug("Found name %s\n", name
));
370 if((type
== DLT_DEVICE
) && (myMatchPatternNoCase(strray
, name
) == FALSE
))
374 D(bug("Failure! -- name = %s, strray = %p\n", name
, (void *)strray
));
376 D(for (i
= 0; strray
[i
] != NULL
; i
++)
378 bug("Strray %i = %s\n", i
, strray
[i
]);
384 idn
= (struct InfoDosNode
*)AllocPooled(Pool
, sizeof(struct InfoDosNode
));
392 idn
->Task
= ndl
->dol_Task
;
393 idn
->IsVolume
= type
== DLT_VOLUME
;
395 while((idn
->Name
[len
] = name
[len
]))
398 if(type
== DLT_VOLUME
)
400 idn
->VolumeDate
= ((struct DeviceList
*)ndl
)->dl_VolumeDate
;
401 idn
->Name
[len
- 1] = '\0'; /* remove ':' */
405 BPTR ptr
= ndl
->dol_misc
.dol_handler
.dol_Startup
;
406 struct FileSysStartupMsg
*fssm
= NULL
;
408 if (IsFileSystem(idn
->Name
))
410 // Only filesystems have a valid FileSysStartupMsg
411 fssm
= (struct FileSysStartupMsg
*)BADDR(ptr
);
414 idn
->DosType
= ID_DOS_DISK
;
423 de
= (struct DosEnvec
*)BADDR(fssm
->fssm_Environ
);
425 if (de
&& (de
->de_TableSize
& 0xffffff00) == 0)
427 idn
->DosType
= de
->de_DosType
;
431 /* kinda insert sort */
433 struct InfoDosNode
*work
= head
;
434 struct InfoDosNode
*prev
= NULL
;
436 while((work
!= NULL
) && (Stricmp(idn
->Name
, work
->Name
) > 0))
451 /* unlock list of devices and volumes */
452 UnLockDosList(LDF_ASSIGNS
| LDF_VOLUMES
| LDF_DEVICES
| LDF_READ
);
454 // strray freed at DeletePool
460 void PrintNum(ULONG num
)
475 num
= ExtUDivMod32(UMult32(num
, 100) >> 10, 100, &x
);
478 x
= ExtUDivMod32(x
, 10, &xx
);
489 VLPrintf(BIGNUMFMT
, "%5ld.%ld%lc", num
, x
, fmt
);
493 VLPrintf(SMALLNUMFMT
, "%7ldK", num
);
498 STRPTR
GetFSysStr(ULONG DiskType
)
500 struct DiskTypeList
*dtlptr
= dtl
;
505 if(dtlptr
->id
== DiskType
)
510 } while(*((ULONG
*)dtlptr
++));
514 static TEXT buffer
[5];
516 ptr
= (STRPTR
)buffer
;
517 *((ULONG
*)ptr
) = AROS_LONG2BE(DiskType
);
542 struct RDArgs
*rdargs
;
543 struct Process
*proc
;
545 struct InfoDosNode
*idn
;
547 struct InfoData
*id
= AllocVec(sizeof(struct InfoData
), MEMF_ANY
);
549 IPTR args
[] = { (IPTR
)FALSE
,
555 CONST_STRPTR unit
= GetStrFromCat(UNIT
, "Unit");
559 PrintFault(ERROR_NO_FREE_STORE
, NULL
);
563 Pool
= CreatePool(MEMF_ANY
, 1024, 1024);
567 PrintFault(ERROR_NO_FREE_STORE
, NULL
);
571 D(bug("Calling ReadArgs()\n"));
574 rdargs
= ReadArgs("DISKS/S,VOLS=VOLUMES/S,ALL/S,BLOCKS/S,DEVICES/M",
579 BOOL disks
= (BOOL
)args
[ARG_DISKS
];
580 BOOL vols
= (BOOL
)args
[ARG_VOLS
];
581 BOOL showall
= (BOOL
)args
[ARG_ALL
];
582 BOOL blocks
= (BOOL
)args
[ARG_BLOCKS
];
583 STRPTR
*devs
= (STRPTR
*)args
[ARG_DEVS
];
585 if (devs
&& (*devs
== NULL
)) devs
= NULL
;
587 /* If nothing is specified, show everything we got */
588 if(devs
== NULL
&& !disks
&& !vols
)
594 /* check pattern strings */
603 if(ParsePatternNoCase(*p
, matchstr
, sizeof(matchstr
)) == -1)
605 PrintFault(IoErr(), *p
);
613 /* avoid requesters */
614 proc
= (struct Process
*)FindTask(NULL
);
615 win
= (struct Window
*)proc
->pr_WindowPtr
;
616 proc
->pr_WindowPtr
= (struct Window
*)~0;
618 MaxLen
= strlen(unit
);
620 D(bug("Calling ScanDosList()\n"));
623 if(ScanDosList(devs
))
625 CONST_STRPTR dstate
[3] = { GetStrFromCat(READONLY
, "read only"),
626 GetStrFromCat(VALIDATING
, "validating"),
627 GetStrFromCat(READWRITE
, "read/write") };
628 STRPTR datetimeFmt
= NULL
;
633 D(bug("Printing stuff\n"));
635 /* get datetimefmt string */
636 if(loc
&& (GetVar("info_datetime", buf
, sizeof(buf
), 0L) > 0L))
641 /* calc format string for 'Unit' */
642 __sprintf(nfmtstr
, "%%-%lds", MaxLen
);
644 /* show device infomation */
645 if(devs
!= NULL
|| disks
|| !vols
)
647 for(idn
= head
; idn
; idn
= idn
->Next
)
650 STRPTR name
= idn
->Name
;
652 D(bug("Got name = %s\n", name
));
654 if(!idn
->IsVolume
&& IsFileSystem(name
))
656 BOOL gotinfo
= FALSE
;
657 /* if first device to print, print title */
663 D(bug("Printing device\n"));
665 VLPrintf(~0, nfmtstr
, unit
);
666 VLPrintf(DEVTITLE
, " Size Used Free Full Errs State Type Name\n");
671 VLPrintf(~0, nfmtstr
, name
);
673 D(bug("Locking \"%s\"\n", name
));
674 lock
= Lock(name
, SHARED_LOCK
);
676 D(bug("Lock = %p\n", (APTR
)lock
));
680 D(bug("Got lock on %s\n", name
));
682 if(Info(lock
, id
) == DOSTRUE
)
684 D(bug("Calling NameFromLock()\n"));
686 if(NameFromLock(lock
, name
, 108L))
688 LONG len
= strlen(name
) - 1;
700 } else if (idn
->Task
) {
702 D(bug("Calling ACTION_DISK_INFO\n"));
703 if (DoPkt(idn
->Task
, ACTION_DISK_INFO
, (SIPTR
)MKBADDR(id
), (SIPTR
)BNULL
, (SIPTR
)BNULL
, (SIPTR
)BNULL
, (SIPTR
)BNULL
)) {
711 D(bug("Got info on %s\n", name
));
713 if (id
->id_DiskType
== ID_NO_DISK_PRESENT
) {
714 VLPrintf(~0, " No disk present\n");
715 } else if (id
->id_DiskType
== ID_NOT_REALLY_DOS
) {
716 VLPrintf(~0, " Not a DOS disk\n");
717 } else if (id
->id_DiskType
== ID_UNREADABLE_DISK
) {
718 VLPrintf(~0, " Unreadable disk\n");
720 x
= ComputeKBytes(id
->id_NumBlocks
, id
->id_BytesPerBlock
);
721 y
= ComputeKBytes(id
->id_NumBlocksUsed
, id
->id_BytesPerBlock
);
735 x
= ExtUDivMod32(UDivMod32(UMult32(y
, 1000), x
), 10, &y
);
743 // y = ((struct DeviceList *)BADDR(id->id_VolumeNode))->dl_DiskType;
748 if((idn
->DosType
& ID_DOS_DISK
) != ID_DOS_DISK
)
752 VLPrintf(DEVFMTSTR
, "%4ld%% %4ld %-11s%-8s%s\n",
753 x
, id
->id_NumSoftErrors
,
754 ((id
->id_DiskState
>= ID_WRITE_PROTECTED
) && (id
->id_DiskState
<= ID_VALIDATED
)) ? (const char *)dstate
[id
->id_DiskState
- ID_WRITE_PROTECTED
] : (const char *)"",
762 "\nTotal blocks: %-10ld Blocks used: %ld\n"
763 " Blocks free: %-10ld Blocksize: %ld\n",
765 id
->id_NumBlocksUsed
,
766 id
->id_NumBlocks
-id
->id_NumBlocksUsed
,
767 id
->id_BytesPerBlock
);
773 D(bug("Info failure\n"));
780 /* just ignore PIPEFS */
781 if (err
== ERROR_ACTION_NOT_KNOWN
)
782 if (strcmp(name
, "PIPEFS:") == 0)
787 VLPrintf(~0, nfmtstr
, name
);
788 PrintFault(err
, NULL
);
796 if(vols
|| (!devs
&& !disks
))
801 VLPrintf(DISKSTITLE
, "Volumes\n");
803 /* find the longest volume name */
804 for(MaxLen
= 15, idn
= head
; idn
; idn
= idn
->Next
)
808 LONG len
= strlen(idn
->Name
);
815 __sprintf(nfmtstr
, "%%-%lds%%-10s", MaxLen
+1);
817 for(idn
= head
; idn
; idn
= idn
->Next
)
821 VLPrintf(VOLNAMEFMTSTR
, nfmtstr
, idn
->Name
,
822 idn
->Task
? (const char *)GetStrFromCat(MOUNTEDSTR
, "[Mounted]") : (const char *)"");
824 if(idn
->VolumeDate
.ds_Days
!= 0)
829 static struct Hook hook
;
831 memset(&hook
, 0, sizeof(struct Hook
));
833 hook
.h_SubEntry
= (HOOKFUNC
)FmtProcedure
;
834 hook
.h_Data
= datestr
;
836 FormatDate(loc
, datetimeFmt
, &idn
->VolumeDate
, &hook
);
842 TEXT StrDay
[LEN_DATSTRING
];
843 TEXT StrDate
[LEN_DATSTRING
];
844 TEXT StrTime
[LEN_DATSTRING
];
848 dt
.dat_Flags
= DTF_SUBST
;
849 dt
.dat_Format
= FORMAT_DOS
;
850 dt
.dat_StrDay
= StrDay
;
851 dt
.dat_StrDate
= StrDate
;
852 dt
.dat_StrTime
= StrTime
;
853 dt
.dat_Stamp
= idn
->VolumeDate
;
857 if(Strnicmp(StrDate
, StrDay
, strlen(StrDay
)) == 0)
863 VLPrintf(DATEFMTSTR
, "created %.3s, %-10s %s", StrDay
, StrDate
, StrTime
);
875 PrintFault( ERROR_NO_FREE_STORE
, NULL
);
878 /* reset window pointer of our process */
879 proc
->pr_WindowPtr
= win
;
886 end
: /* free allocated memory */
892 ULONG
ComputeKBytes(ULONG a
, ULONG b
)
894 // UQUAD result = UMult64(a, b);
896 UQUAD result
= (UQUAD
)a
* b
;
898 return (ULONG
)(result
>> 10);
902 void FmtProcedure(struct Hook
*hook
, char a
, struct Locale
*locale
)
904 *((STRPTR
)hook
->h_Data
) = a
;
905 hook
->h_Data
= (STRPTR
) hook
->h_Data
+ 1;
909 ULONG
ExtUDivMod32(ULONG a
, ULONG b
, ULONG
*mod
)