New bitmap method SetRGBConversionFunction which can be used to
[tangerine.git] / workbench / c / Info.c
blobfdc6877a66cc67eb1319e24dbb6204b34ef23d40
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: English
7 */
9 /******************************************************************************
12 NAME
14 Info
16 SYNOPSIS
18 DISKS/S, VOLS=VOLUMES/S, GOODONLY/S, BLOCKS/S, DEVICES/M
20 LOCATION
22 Workbench:C
24 FUNCTION
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.
31 INPUTS
33 DISKS -- show information on file system devices
34 VOLS -- show information on volumes
35 GOODONLY -- don't show any information on bad devices or volumes
36 BLOCKS -- show additional block size and usage information
37 DEVICES -- device names to show information about
39 RESULT
41 NOTES
43 EXAMPLE
45 Info
47 Unit Size Used Free Full Errs State Type Name
48 Foreign harddisk: 964.1M 776.7M 187.4M 81% 0 read/write OFS Workbench
49 RAM: 8.0M 7.1M 7.1M 12% 0 read/write OFS Ram Disk
51 BUGS
53 SEE ALSO
55 INTERNALS
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
60 NULL.
62 HISTORY
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
71 All rights resevered
74 #define DEBUG 0
75 #include <aros/debug.h>
77 #include <dos/dos.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>
89 #include <string.h>
92 #define ID_MAC_DISK2 (0x4d414300L) /* MAC\0 - xfs mac disk */
93 #define ID_MNX1_DISK (0x4d4e5801L) /* MNX\1 - xfs minix disk */
94 #define ID_MNX2_DISK (0x4d4e5802L) /* MNX\2 - xfs minix disk */
95 #define ID_QL5A_DISK (0x514c3541L) /* QL5A - xfs ql 720k / ed disk */
96 #define ID_QL5B_DISK (0x514c3542L) /* QL5B - xfs ql 1440k disk */
97 #define ID_ZXS0_DISK (0x5a585300L) /* Spectrum Disciple - xfs */
98 #define ID_ZXS1_DISK (0x5a585301L) /* Spectrum UniDos - xfs */
99 #define ID_ZXS2_DISK (0x5a585302L) /* Spectrum SamDos - xfs */
100 #define ID_ZXS4_DISK (0x5a585304L) /* Spectrum Opus 180k - xfs */
101 #define ID_ARME_DISK (0x41524d44L) /* Archimedes - xfs */
102 #define ID_ARMD_DISK (0x41524d43L) /* Archimedes - xfs */
103 #define ID_CPM_DISK (0x43505c4dL) /* CP/M - xfs */
104 #define ID_ZXS3_DISK (0x5a585303L) /* ZXS\3 - Plus3Dos xfs */
105 #define ID_1541_DISK (0x31353431L) /* 1541 - xfs */
106 #define ID_1581_DISK (0x31353831L) /* 1581 - xfs */
107 #define ID_MAC_DISK (0x4d534800L) /* MSH\0 - CrossDos MACDisk ?! */
108 #define ID_ACD0_DISK (0x41434400L) /* ACD\0 - AmiCDFS disk */
109 #define ID_CDFS_DISK (0x43444653L) /* CDFS - AmiCDFS disk */
110 #define ID_CACHECDFS_DISK (0x43443031L)
111 #define ID_ASIMCDFS_DISK (0x662dabacL)
112 #define ID_PFS2_DISK (0x50465302L)
113 #define ID_PFS2_SCSI_DISK (0x50445300L)
114 #define ID_PFS2_muFS_DISK (0x6d755046L)
115 #define ID_FLOPPY_PFS_DISK (0x50465300L)
116 #define ID_P2A0_DISK (0x50324130L)
117 #define ID_AFS0_DISK (0x41465300L) /* AFS\0 */
118 #define ID_muFS_DISK (0x6d754653L) /* muFS - Mulituserfsys */
121 /* Prototypes */
123 ULONG ComputeKBytes(ULONG a, ULONG b);
124 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale);
125 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod);
126 void doInfo();
129 STRPTR VersionStr = "$VER: Info 41.1 (16.11.2000)";
131 struct Catalog *cat;
132 struct Locale *loc = NULL;
133 ULONG MaxLen;
135 APTR Pool;
138 /* catalog string id:s */
139 enum
141 UNIT,
142 DEVTITLE,
143 DISKSTITLE,
144 DEVFMTSTR,
145 DATEFMTSTR,
146 READONLY,
147 READWRITE,
148 VALIDATING,
149 MOUNTEDSTR,
150 SMALLNUMFMT,
151 BIGNUMFMT,
152 VOLNAMEFMTSTR,
153 BLOCKSSTR
157 struct InfoDosNode
159 struct InfoDosNode *Next;
160 ULONG IsVolume;
161 ULONG DosType;
162 struct MsgPort *Task;
163 struct DateStamp VolumeDate;
164 TEXT Name[108];
167 struct InfoDosNode *head = NULL;
170 struct DiskTypeList
171 { ULONG id;
172 STRPTR str;
175 struct DiskTypeList dtl[] =
177 { ID_DOS_DISK, "OFS" },
178 { ID_FFS_DISK, "FFS" },
179 { ID_INTER_DOS_DISK, "OFS-INT" },
180 { ID_INTER_FFS_DISK, "FFS-INT" },
181 { ID_FASTDIR_DOS_DISK, "OFS-DC" },
182 { ID_FASTDIR_FFS_DISK, "FFS-DC" },
183 { ID_MSDOS_DISK, "MS-DOS" },
184 { ID_ACD0_DISK, "CDFS" },
185 { ID_CACHECDFS_DISK, "CDFS" },
186 { ID_ASIMCDFS_DISK, "CDFS" },
187 { ID_NOT_REALLY_DOS, "NO DOS" },
188 { ID_MAC_DISK2, "MAC" },
189 { ID_MNX1_DISK, "Minix" },
190 { ID_QL5A_DISK, "QL720k" },
191 { ID_QL5B_DISK, "QL1.4M" },
192 { ID_CPM_DISK, "CP/M" },
193 { ID_ZXS3_DISK, "+3Dos" },
194 { ID_ZXS0_DISK, "Disciple " },
195 { ID_ZXS1_DISK, "UniDos" },
196 { ID_ZXS2_DISK, "SamDos" },
197 { ID_ZXS4_DISK, "Opus" },
198 { ID_P2A0_DISK, "NETWORK" },
199 { 0L, 0L }
203 /****************************************************************************/
205 int UtilityBase_version = 0;
206 int LocaleBase_version = 0;
208 int __nocommandline;
210 int main(void)
212 static struct TagItem loctags[] = { { OC_Version, 1 },
213 { TAG_END , 0 } };
214 cat = OpenCatalogA(NULL, "info_com.catalog", loctags);
215 loc = OpenLocale(NULL);
217 D(bug("Calling doInfo()\n"));
219 doInfo();
221 CloseLocale(loc);
222 CloseCatalog(cat);
224 return RETURN_OK; /* TODO: Fix this */
228 CONST_STRPTR GetStrFromCat(ULONG id, CONST_STRPTR def)
230 if(cat != NULL)
232 def = GetCatalogStr(cat, id, def);
235 return def;
239 void LPrintf(ULONG id, CONST_STRPTR def, ...) __stackparm;
241 void LPrintf(ULONG id, CONST_STRPTR def, ...)
243 def = GetStrFromCat(id, def);
245 VPrintf(def, ((IPTR *)(&def))+1);
249 BOOL myMatchPatternNoCase(STRPTR *array, STRPTR str)
251 if(*array != NULL)
253 while(*array != NULL)
255 UBYTE matchstr[128];
256 UBYTE name[32];
257 UBYTE *p = *array++;
258 UBYTE len = strlen(p);
260 if(p[len - 1] != ':')
262 CopyMem(p, name, len);
263 name[len] = ':';
264 name[len + 1] = 0;
265 p = name;
268 if(ParsePatternNoCase(p, matchstr, sizeof(matchstr)) != -1)
270 if(MatchPatternNoCase(matchstr, str))
272 return TRUE;
277 return FALSE;
280 return TRUE;
284 BOOL ScanDosList(STRPTR *filter)
286 struct InfoDosNode *idn = 0L;
287 struct DosList *ndl, *dl;
288 STRPTR *strray = NULL, dummy = NULL;
289 BOOL err = FALSE;
291 D(bug("Entered ScanDosList()\n"));
293 if (filter == NULL) filter = &dummy;
295 if(*filter != NULL)
297 strray = AllocPooled(Pool, sizeof(STRPTR)*MAX_MULTIARGS);
299 if(strray != NULL)
301 STRPTR *p = filter;
302 LONG i = 0;
304 while(*p)
305 strray[i++] = *p++;
307 while(i < MAX_MULTIARGS)
308 strray[i++] = NULL;
310 else
311 return FALSE;
314 /* lock list of devices & vols */
315 dl = ndl = LockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
317 if(strray != NULL)
319 STRPTR *p = strray;
321 while(*p)
322 p++;
324 while((ndl = NextDosEntry(ndl, LDF_ASSIGNS | LDF_VOLUMES | LDF_READ)) != NULL)
326 TEXT name[108];
327 STRPTR taskName = NULL; /* Initialized to avoid a warning */
329 __sprintf(name, "%s:", ndl->dol_DevName);
331 if ((ndl->dol_Type > DLT_VOLUME) || !(myMatchPatternNoCase(strray, name)))
333 continue;
336 switch (ndl->dol_Type)
338 case DLT_VOLUME:
339 taskName = ndl->dol_DevName; // ((struct Task *)ndl->dol_Task->mp_SigTask)->tc_Node.ln_Name;
341 D(bug("Found volume %s\n", taskName));
342 break;
344 case DLT_DIRECTORY:
346 struct AssignList *al = ndl->dol_misc.dol_assign.dol_List;
349 taskName = ndl->dol_DevName; // ((struct Task *)((struct FileLock *)BADDR(ndl->dol_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
351 D(bug("Found directory %s\n", taskName));
353 while(al != NULL)
355 *p++ = ""; // TODO!!! ((struct Task *)((struct FileLock *)BADDR(al->al_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
356 al = al->al_Next;
359 break;
362 *p++ = taskName;
365 else
366 strray = filter;
368 ndl = dl;
370 while((ndl = NextDosEntry(ndl, LDF_VOLUMES | LDF_DEVICES | LDF_READ)) != NULL)
372 UBYTE len = 0;
373 UBYTE type = ndl->dol_Type;
374 UBYTE name[108];
376 // if(((type == DLT_DEVICE))) // && (!ndl->dol_Task) TODO Check this!
377 // continue;
379 __sprintf(name, "%s:", ndl->dol_DevName);
381 D(bug("Found name %s\n", ndl->dol_DevName));
383 if((type == DLT_DEVICE) && (myMatchPatternNoCase(strray, name) == FALSE))
385 int i;
387 D(bug("Failure! -- name = %s, strray = %p\n", name, (void *)strray));
389 for (i = 0; strray[i] != NULL; i++)
391 D(bug("Strray %i = %s\n", i, strray[i]));
394 continue;
397 idn = (struct InfoDosNode *)AllocPooled(Pool, sizeof(struct InfoDosNode));
399 if(idn == NULL)
401 err = TRUE;
402 break;
405 // idn->Task = (struct MsgPort *)ndl->dol_Task;
406 idn->IsVolume = type == DLT_VOLUME;
408 while((idn->Name[len] = name[len]))
409 len++;
411 if(type == DLT_VOLUME)
413 idn->VolumeDate = ((struct DeviceList *)ndl)->dl_VolumeDate;
414 idn->Name[len - 1] = '\0'; /* remove ':' */
416 else
418 // struct FileSysStartupMsg *fssm = (struct FileSysStartupMsg *)BADDR(ndl->dol_misc.dol_handler.dol_Startup);
420 idn->DosType = ID_DOS_DISK;
422 // DLT_DEVICE
423 if(len > MaxLen)
424 MaxLen = len;
426 #if 0
427 if(TypeOfMem(fssm))
429 if(*(UBYTE *)fssm == 0 || *(UBYTE *)BADDR(fssm->fssm_Device) != 0)
431 struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
433 if(de != NULL && (de->de_TableSize & 0xffffff00) == 0L)
435 if(de->de_DosType)
436 idn->DosType = de->de_DosType;
440 #endif
444 /* kinda insert sort */
446 struct InfoDosNode *work = head;
447 struct InfoDosNode *prev = NULL;
449 while((work != NULL) && (Stricmp(idn->Name, work->Name) > 0))
451 prev = work;
452 work = work->Next;
455 if(prev != NULL)
456 prev->Next = idn;
457 else
458 head = idn;
460 idn->Next = work;
464 /* unlock list of devices and volumes */
465 UnLockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
467 // strray freed at DeletePool
469 return !err;
473 void PrintNum(ULONG num)
475 /* MBytes ? */
476 if(num > 1023)
478 ULONG x, xx;
479 char fmt = 'M';
481 /* GBytes ? */
482 if(num > 0xfffff)
484 num >>= 10;
485 fmt = 'G';
488 num = ExtUDivMod32(UMult32(num, 100) >> 10, 100, &x);
490 /* round */
491 x = ExtUDivMod32(x, 10, &xx);
493 if(xx > 4)
495 if(++x > 9)
497 x = 0;
498 num++;
502 LPrintf(BIGNUMFMT, "%5ld.%ld%lc", num, x, fmt);
504 else
506 LPrintf(SMALLNUMFMT, "%7ldK", num);
511 STRPTR GetFSysStr(ULONG DiskType)
513 struct DiskTypeList *dtlptr = dtl;
515 STRPTR ptr = NULL;
517 do {
518 if(dtlptr->id == DiskType)
520 ptr = dtlptr->str;
521 break;
523 } while(*((ULONG *)dtlptr++));
525 if(ptr == NULL)
527 static TEXT buffer[5];
529 ptr = (STRPTR)buffer;
530 *((ULONG *)ptr) = DiskType;
532 if(ptr[3] < ' ')
533 ptr[3] += '0';
535 ptr[4] = '\0';
538 return ptr;
542 enum
544 ARG_DISKS,
545 ARG_VOLS,
546 ARG_GOODONLY,
547 ARG_BLOCKS,
548 ARG_DEVS,
549 NOOFARGS
553 void doInfo()
555 struct RDArgs *rdargs;
556 struct Process *proc;
557 struct Window *win;
558 struct InfoDosNode *idn;
560 static struct InfoData id;
562 IPTR args[] = { (IPTR)FALSE,
563 (IPTR)FALSE,
564 (IPTR)FALSE,
565 (IPTR)FALSE,
566 (IPTR)NULL };
568 CONST_STRPTR unit = GetStrFromCat(UNIT, "Unit");
570 Pool = CreatePool(MEMF_ANY, 1024, 1024);
572 if(Pool == NULL)
574 PrintFault(ERROR_NO_FREE_STORE, NULL);
575 return; /* ??? */
578 D(bug("Calling ReadArgs()\n"));
580 /* read arguments */
581 rdargs = ReadArgs("DISKS/S,VOLS=VOLUMES/S,GOODONLY/S,BLOCKS/S,DEVICES/M",
582 args, NULL);
584 if(rdargs != NULL)
586 BOOL disks = (BOOL)args[ARG_DISKS];
587 BOOL vols = (BOOL)args[ARG_VOLS];
588 BOOL goodOnly = (BOOL)args[ARG_GOODONLY];
589 BOOL blocks = (BOOL)args[ARG_BLOCKS];
590 STRPTR *devs = (STRPTR *)args[ARG_DEVS];
592 if (devs && (*devs == NULL)) devs = NULL;
594 /* If nothing is specified, show everything we got */
595 if(devs == NULL && !disks && !vols)
597 vols = TRUE;
598 disks = TRUE;
601 /* check pattern strings */
603 if(devs != NULL)
605 STRPTR *p = devs;
607 while(*p != NULL)
609 TEXT matchstr[128];
611 if(ParsePatternNoCase(*p, matchstr, sizeof(matchstr)) == -1)
613 PrintFault(IoErr(), *p);
614 goto end;
617 p++;
621 /* avoid requesters */
622 proc = (struct Process *)FindTask(NULL);
623 win = (struct Window *)proc->pr_WindowPtr;
624 proc->pr_WindowPtr = (struct Window *)~0;
626 MaxLen = strlen(unit);
628 D(bug("Calling ScanDosList()\n"));
630 /* scan doslist */
631 if(ScanDosList(devs))
633 CONST_STRPTR dstate[3] = { GetStrFromCat(READONLY, "read only"),
634 GetStrFromCat(VALIDATING, "validating"),
635 GetStrFromCat(READWRITE, "read/write") };
636 STRPTR datetimeFmt = NULL;
637 BOOL first = TRUE;
638 TEXT nfmtstr[16];
639 TEXT buf[64];
641 D(bug("Printing stuff\n"));
643 /* get datetimefmt string */
644 if(loc && (GetVar("info_datetime", buf, sizeof(buf), 0L) > 0L))
646 datetimeFmt = buf;
649 /* calc format string for 'Unit' */
650 __sprintf(nfmtstr, "%%-%lds", MaxLen);
652 /* show device infomation */
653 if(devs != NULL || disks || !vols)
655 for(idn = head; idn; idn = idn->Next)
657 BPTR lock;
658 STRPTR name = idn->Name;
660 D(bug("Got name = %s\n", name));
662 if(!idn->IsVolume && IsFileSystem(name))
664 /* if first device to print, print title */
665 if(first || blocks)
667 if(!first)
668 Printf("\n");
670 D(bug("Printing device\n"));
672 LPrintf(~0, nfmtstr, unit);
673 LPrintf(DEVTITLE, " Size Used Free Full Errs State Type Name\n");
675 first = FALSE;
678 D(bug("Locking \"%s\"\n", name));
679 lock = Lock(name, SHARED_LOCK);
681 D(bug("Lock = %p\n", lock));
683 if(lock != NULL)
685 D(bug("Got lock on %s\n", name));
687 if(Info(lock, &id) == DOSTRUE)
689 ULONG x, y;
691 D(bug("Got info on %s\n", name));
693 LPrintf(~0, nfmtstr, name);
695 x = ComputeKBytes(id.id_NumBlocks, id.id_BytesPerBlock);
696 y = ComputeKBytes(id.id_NumBlocksUsed, id.id_BytesPerBlock);
698 PrintNum(x);
699 PrintNum(y);
700 PrintNum(x - y);
702 D(bug("Calling NameFromLock()\n"));
704 if(NameFromLock(lock, name, 108L))
706 LONG len = strlen(name) - 1;
708 if(name[len] == ':')
710 name[len] = '\0';
714 if(x > 0xfffff)
716 x >>= 10;
717 y >>= 10;
720 if(x)
722 x = ExtUDivMod32(UDivMod32(UMult32(y, 1000), x), 10, &y);
724 if(y > 4)
725 x++;
727 else
728 x = 0;
730 // y = ((struct DeviceList *)BADDR(id.id_VolumeNode))->dl_DiskType;
732 // if(!y)
733 y = id.id_DiskType;
735 if((idn->DosType & ID_DOS_DISK) != ID_DOS_DISK)
736 y = idn->DosType;
738 LPrintf(DEVFMTSTR, "%4ld%% %4ld %-11s%-8s%s\n",
739 x, id.id_NumSoftErrors,
740 ((id.id_DiskState >= ID_WRITE_PROTECTED) && (id.id_DiskState <= ID_VALIDATED)) ?
741 dstate[id.id_DiskState - ID_WRITE_PROTECTED] : (STRPTR)"", GetFSysStr(y), name);
743 if(blocks)
745 LPrintf(BLOCKSSTR,
746 "\nTotal blocks: %-10ld Blocks used: %ld\n"
747 " Blocks free: %-10ld Blocksize: %ld\n",
748 id.id_NumBlocks, id.id_NumBlocksUsed,
749 id.id_NumBlocks-id.id_NumBlocksUsed, id.id_BytesPerBlock );
752 else
753 D(bug("Info failure\n"));
755 UnLock(lock);
759 LONG err = IoErr();
761 if((err != 0) && !goodOnly)
763 LPrintf(~0, nfmtstr, name);
764 PrintFault(err, NULL);
771 /* show volumes */
772 if(vols || (!devs && !disks))
774 if(!first)
775 PutStr("\n");
777 LPrintf(DISKSTITLE, "Volumes\n");
779 for(MaxLen = 15, idn = head; idn; idn = idn->Next)
781 if(idn->IsVolume)
783 LONG len = strlen(idn->Name);
785 if(len > MaxLen)
786 MaxLen = len;
790 __sprintf(nfmtstr, "%%-%lds%%-10s", MaxLen+1);
792 for(idn = head; idn; idn = idn->Next)
794 if(idn->IsVolume)
796 LPrintf(VOLNAMEFMTSTR, nfmtstr, idn->Name,
797 GetStrFromCat(MOUNTEDSTR, "[Mounted]"));
798 // idn->Task ? GetStrFromCat(MOUNTEDSTR, "[Mounted]") : ""); TODO
800 if(datetimeFmt)
802 UBYTE datestr[128];
803 static struct Hook hook;
805 memset(&hook, 0, sizeof(struct Hook));
807 hook.h_SubEntry = (HOOKFUNC)FmtProcedure;
808 hook.h_Data = datestr;
810 FormatDate(loc, datetimeFmt, &idn->VolumeDate, &hook);
812 PutStr(datestr);
814 else
816 TEXT StrDay[LEN_DATSTRING];
817 TEXT StrDate[LEN_DATSTRING];
818 TEXT StrTime[LEN_DATSTRING];
820 struct DateTime dt;
822 dt.dat_Flags = DTF_SUBST;
823 dt.dat_Format = FORMAT_DOS;
824 dt.dat_StrDay = StrDay;
825 dt.dat_StrDate = StrDate;
826 dt.dat_StrTime = StrTime;
827 dt.dat_Stamp = idn->VolumeDate;
829 if(DateToStr(&dt))
831 if(Strnicmp(StrDate, StrDay, strlen(StrDay)) == 0)
833 dt.dat_Flags = 0L;
834 DateToStr(&dt);
837 LPrintf(DATEFMTSTR, "created %.3s, %-10s %s",
838 StrDay, StrDate, StrTime);
842 PutStr("\n");
847 else
849 PrintFault( ERROR_NO_FREE_STORE, NULL);
852 /* reset window pointer of our process */
853 proc->pr_WindowPtr = win;
855 /* free args */
856 FreeArgs(rdargs);
860 end: /* free allocated memory */
862 DeletePool(Pool);
866 ULONG ComputeKBytes(ULONG a, ULONG b)
868 // UQUAD result = UMult64(a, b);
870 UQUAD result = (UQUAD)a * b;
872 return (ULONG)(result >> 10);
876 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale)
878 *((STRPTR)hook->h_Data) = a;
879 hook->h_Data = (STRPTR) hook->h_Data + 1;
883 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod)
885 *mod = a % b;
887 return a/b;