Don't call InvertPixelArray with negative width and/or height.
[tangerine.git] / workbench / c / Info.c
blob9e39680d9dc8e176238377fffc06ac25677d1d0f
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 */
119 #define ID_FAT_DISK (0x46415400L) /* FAT12/16/32 */
122 /* Prototypes */
124 ULONG ComputeKBytes(ULONG a, ULONG b);
125 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale);
126 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod);
127 void doInfo();
130 STRPTR VersionStr = "$VER: Info 41.1 (16.11.2000)";
132 struct Catalog *cat;
133 struct Locale *loc = NULL;
134 ULONG MaxLen;
136 APTR Pool;
139 /* catalog string id:s */
140 enum
142 UNIT,
143 DEVTITLE,
144 DISKSTITLE,
145 DEVFMTSTR,
146 DATEFMTSTR,
147 READONLY,
148 READWRITE,
149 VALIDATING,
150 MOUNTEDSTR,
151 SMALLNUMFMT,
152 BIGNUMFMT,
153 VOLNAMEFMTSTR,
154 BLOCKSSTR
158 struct InfoDosNode
160 struct InfoDosNode *Next;
161 ULONG IsVolume;
162 ULONG DosType;
163 struct MsgPort *Task;
164 struct DateStamp VolumeDate;
165 TEXT Name[108];
168 struct InfoDosNode *head = NULL;
171 struct DiskTypeList
172 { ULONG id;
173 STRPTR str;
176 struct DiskTypeList dtl[] =
178 { ID_DOS_DISK, "OFS" },
179 { ID_FFS_DISK, "FFS" },
180 { ID_INTER_DOS_DISK, "OFS-INT" },
181 { ID_INTER_FFS_DISK, "FFS-INT" },
182 { ID_FASTDIR_DOS_DISK, "OFS-DC" },
183 { ID_FASTDIR_FFS_DISK, "FFS-DC" },
184 { ID_MSDOS_DISK, "MS-DOS" },
185 { ID_ACD0_DISK, "CDFS" },
186 { ID_CACHECDFS_DISK, "CDFS" },
187 { ID_ASIMCDFS_DISK, "CDFS" },
188 { ID_NOT_REALLY_DOS, "NO DOS" },
189 { ID_MAC_DISK2, "MAC" },
190 { ID_MNX1_DISK, "Minix" },
191 { ID_QL5A_DISK, "QL720k" },
192 { ID_QL5B_DISK, "QL1.4M" },
193 { ID_CPM_DISK, "CP/M" },
194 { ID_ZXS3_DISK, "+3Dos" },
195 { ID_ZXS0_DISK, "Disciple " },
196 { ID_ZXS1_DISK, "UniDos" },
197 { ID_ZXS2_DISK, "SamDos" },
198 { ID_ZXS4_DISK, "Opus" },
199 { ID_P2A0_DISK, "NETWORK" },
200 { ID_FAT_DISK, "FAT" },
201 { 0L, 0L }
205 /****************************************************************************/
207 int UtilityBase_version = 0;
208 int LocaleBase_version = 0;
210 int __nocommandline;
212 int main(void)
214 static struct TagItem loctags[] = { { OC_Version, 1 },
215 { TAG_END , 0 } };
216 cat = OpenCatalogA(NULL, "info_com.catalog", loctags);
217 loc = OpenLocale(NULL);
219 D(bug("Calling doInfo()\n"));
221 doInfo();
223 CloseLocale(loc);
224 CloseCatalog(cat);
226 return RETURN_OK; /* TODO: Fix this */
230 CONST_STRPTR GetStrFromCat(ULONG id, CONST_STRPTR def)
232 if(cat != NULL)
234 def = GetCatalogStr(cat, id, def);
237 return def;
241 void LPrintf(ULONG id, CONST_STRPTR def, ...) __stackparm;
243 void LPrintf(ULONG id, CONST_STRPTR def, ...)
245 def = GetStrFromCat(id, def);
247 VPrintf(def, ((IPTR *)(&def))+1);
251 BOOL myMatchPatternNoCase(STRPTR *array, STRPTR str)
253 if(*array != NULL)
255 while(*array != NULL)
257 UBYTE matchstr[128];
258 UBYTE name[32];
259 UBYTE *p = *array++;
260 UBYTE len = strlen(p);
262 if(p[len - 1] != ':')
264 CopyMem(p, name, len);
265 name[len] = ':';
266 name[len + 1] = 0;
267 p = name;
270 if(ParsePatternNoCase(p, matchstr, sizeof(matchstr)) != -1)
272 if(MatchPatternNoCase(matchstr, str))
274 return TRUE;
279 return FALSE;
282 return TRUE;
286 BOOL ScanDosList(STRPTR *filter)
288 struct InfoDosNode *idn = 0L;
289 struct DosList *ndl, *dl;
290 STRPTR *strray = NULL, dummy = NULL;
291 BOOL err = FALSE;
293 D(bug("Entered ScanDosList()\n"));
295 if (filter == NULL) filter = &dummy;
297 if(*filter != NULL)
299 strray = AllocPooled(Pool, sizeof(STRPTR)*MAX_MULTIARGS);
301 if(strray != NULL)
303 STRPTR *p = filter;
304 LONG i = 0;
306 while(*p)
307 strray[i++] = *p++;
309 while(i < MAX_MULTIARGS)
310 strray[i++] = NULL;
312 else
313 return FALSE;
316 /* lock list of devices & vols */
317 dl = ndl = LockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
319 if(strray != NULL)
321 STRPTR *p = strray;
323 while(*p)
324 p++;
326 while((ndl = NextDosEntry(ndl, LDF_ASSIGNS | LDF_VOLUMES | LDF_READ)) != NULL)
328 TEXT name[108];
329 STRPTR taskName = NULL; /* Initialized to avoid a warning */
331 __sprintf(name, "%s:", ndl->dol_DevName);
333 if ((ndl->dol_Type > DLT_VOLUME) || !(myMatchPatternNoCase(strray, name)))
335 continue;
338 switch (ndl->dol_Type)
340 case DLT_VOLUME:
341 taskName = ndl->dol_DevName; // ((struct Task *)ndl->dol_Task->mp_SigTask)->tc_Node.ln_Name;
343 D(bug("Found volume %s\n", taskName));
344 break;
346 case DLT_DIRECTORY:
348 struct AssignList *al = ndl->dol_misc.dol_assign.dol_List;
351 taskName = ndl->dol_DevName; // ((struct Task *)((struct FileLock *)BADDR(ndl->dol_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
353 D(bug("Found directory %s\n", taskName));
355 while(al != NULL)
357 *p++ = ""; // TODO!!! ((struct Task *)((struct FileLock *)BADDR(al->al_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
358 al = al->al_Next;
361 break;
364 *p++ = taskName;
367 else
368 strray = filter;
370 ndl = dl;
372 while((ndl = NextDosEntry(ndl, LDF_VOLUMES | LDF_DEVICES | LDF_READ)) != NULL)
374 UBYTE len = 0;
375 UBYTE type = ndl->dol_Type;
376 UBYTE name[108];
378 // if(((type == DLT_DEVICE))) // && (!ndl->dol_Task) TODO Check this!
379 // continue;
381 __sprintf(name, "%s:", ndl->dol_DevName);
383 D(bug("Found name %s\n", ndl->dol_DevName));
385 if((type == DLT_DEVICE) && (myMatchPatternNoCase(strray, name) == FALSE))
387 int i;
389 D(bug("Failure! -- name = %s, strray = %p\n", name, (void *)strray));
391 for (i = 0; strray[i] != NULL; i++)
393 D(bug("Strray %i = %s\n", i, strray[i]));
396 continue;
399 idn = (struct InfoDosNode *)AllocPooled(Pool, sizeof(struct InfoDosNode));
401 if(idn == NULL)
403 err = TRUE;
404 break;
407 // idn->Task = (struct MsgPort *)ndl->dol_Task;
408 idn->IsVolume = type == DLT_VOLUME;
410 while((idn->Name[len] = name[len]))
411 len++;
413 if(type == DLT_VOLUME)
415 idn->VolumeDate = ((struct DeviceList *)ndl)->dl_VolumeDate;
416 idn->Name[len - 1] = '\0'; /* remove ':' */
418 else
420 // struct FileSysStartupMsg *fssm = (struct FileSysStartupMsg *)BADDR(ndl->dol_misc.dol_handler.dol_Startup);
422 idn->DosType = ID_DOS_DISK;
424 // DLT_DEVICE
425 if(len > MaxLen)
426 MaxLen = len;
428 #if 0
429 if(TypeOfMem(fssm))
431 if(*(UBYTE *)fssm == 0 || *(UBYTE *)BADDR(fssm->fssm_Device) != 0)
433 struct DosEnvec *de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
435 if(de != NULL && (de->de_TableSize & 0xffffff00) == 0L)
437 if(de->de_DosType)
438 idn->DosType = de->de_DosType;
442 #endif
446 /* kinda insert sort */
448 struct InfoDosNode *work = head;
449 struct InfoDosNode *prev = NULL;
451 while((work != NULL) && (Stricmp(idn->Name, work->Name) > 0))
453 prev = work;
454 work = work->Next;
457 if(prev != NULL)
458 prev->Next = idn;
459 else
460 head = idn;
462 idn->Next = work;
466 /* unlock list of devices and volumes */
467 UnLockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
469 // strray freed at DeletePool
471 return !err;
475 void PrintNum(ULONG num)
477 /* MBytes ? */
478 if(num > 1023)
480 ULONG x, xx;
481 char fmt = 'M';
483 /* GBytes ? */
484 if(num > 0xfffff)
486 num >>= 10;
487 fmt = 'G';
490 num = ExtUDivMod32(UMult32(num, 100) >> 10, 100, &x);
492 /* round */
493 x = ExtUDivMod32(x, 10, &xx);
495 if(xx > 4)
497 if(++x > 9)
499 x = 0;
500 num++;
504 LPrintf(BIGNUMFMT, "%5ld.%ld%lc", num, x, fmt);
506 else
508 LPrintf(SMALLNUMFMT, "%7ldK", num);
513 STRPTR GetFSysStr(ULONG DiskType)
515 struct DiskTypeList *dtlptr = dtl;
517 STRPTR ptr = NULL;
519 do {
520 if(dtlptr->id == DiskType)
522 ptr = dtlptr->str;
523 break;
525 } while(*((ULONG *)dtlptr++));
527 if(ptr == NULL)
529 static TEXT buffer[5];
531 ptr = (STRPTR)buffer;
532 *((ULONG *)ptr) = DiskType;
534 if(ptr[3] < ' ')
535 ptr[3] += '0';
537 ptr[4] = '\0';
540 return ptr;
544 enum
546 ARG_DISKS,
547 ARG_VOLS,
548 ARG_GOODONLY,
549 ARG_BLOCKS,
550 ARG_DEVS,
551 NOOFARGS
555 void doInfo()
557 struct RDArgs *rdargs;
558 struct Process *proc;
559 struct Window *win;
560 struct InfoDosNode *idn;
562 static struct InfoData id;
564 IPTR args[] = { (IPTR)FALSE,
565 (IPTR)FALSE,
566 (IPTR)FALSE,
567 (IPTR)FALSE,
568 (IPTR)NULL };
570 CONST_STRPTR unit = GetStrFromCat(UNIT, "Unit");
572 Pool = CreatePool(MEMF_ANY, 1024, 1024);
574 if(Pool == NULL)
576 PrintFault(ERROR_NO_FREE_STORE, NULL);
577 return; /* ??? */
580 D(bug("Calling ReadArgs()\n"));
582 /* read arguments */
583 rdargs = ReadArgs("DISKS/S,VOLS=VOLUMES/S,GOODONLY/S,BLOCKS/S,DEVICES/M",
584 args, NULL);
586 if(rdargs != NULL)
588 BOOL disks = (BOOL)args[ARG_DISKS];
589 BOOL vols = (BOOL)args[ARG_VOLS];
590 BOOL goodOnly = (BOOL)args[ARG_GOODONLY];
591 BOOL blocks = (BOOL)args[ARG_BLOCKS];
592 STRPTR *devs = (STRPTR *)args[ARG_DEVS];
594 if (devs && (*devs == NULL)) devs = NULL;
596 /* If nothing is specified, show everything we got */
597 if(devs == NULL && !disks && !vols)
599 vols = TRUE;
600 disks = TRUE;
603 /* check pattern strings */
605 if(devs != NULL)
607 STRPTR *p = devs;
609 while(*p != NULL)
611 TEXT matchstr[128];
613 if(ParsePatternNoCase(*p, matchstr, sizeof(matchstr)) == -1)
615 PrintFault(IoErr(), *p);
616 goto end;
619 p++;
623 /* avoid requesters */
624 proc = (struct Process *)FindTask(NULL);
625 win = (struct Window *)proc->pr_WindowPtr;
626 proc->pr_WindowPtr = (struct Window *)~0;
628 MaxLen = strlen(unit);
630 D(bug("Calling ScanDosList()\n"));
632 /* scan doslist */
633 if(ScanDosList(devs))
635 CONST_STRPTR dstate[3] = { GetStrFromCat(READONLY, "read only"),
636 GetStrFromCat(VALIDATING, "validating"),
637 GetStrFromCat(READWRITE, "read/write") };
638 STRPTR datetimeFmt = NULL;
639 BOOL first = TRUE;
640 TEXT nfmtstr[16];
641 TEXT buf[64];
643 D(bug("Printing stuff\n"));
645 /* get datetimefmt string */
646 if(loc && (GetVar("info_datetime", buf, sizeof(buf), 0L) > 0L))
648 datetimeFmt = buf;
651 /* calc format string for 'Unit' */
652 __sprintf(nfmtstr, "%%-%lds", MaxLen);
654 /* show device infomation */
655 if(devs != NULL || disks || !vols)
657 for(idn = head; idn; idn = idn->Next)
659 BPTR lock;
660 STRPTR name = idn->Name;
662 D(bug("Got name = %s\n", name));
664 if(!idn->IsVolume && IsFileSystem(name))
666 /* if first device to print, print title */
667 if(first || blocks)
669 if(!first)
670 Printf("\n");
672 D(bug("Printing device\n"));
674 LPrintf(~0, nfmtstr, unit);
675 LPrintf(DEVTITLE, " Size Used Free Full Errs State Type Name\n");
677 first = FALSE;
680 D(bug("Locking \"%s\"\n", name));
681 lock = Lock(name, SHARED_LOCK);
683 D(bug("Lock = %p\n", lock));
685 if(lock != NULL)
687 D(bug("Got lock on %s\n", name));
689 if(Info(lock, &id) == DOSTRUE)
691 ULONG x, y;
693 D(bug("Got info on %s\n", name));
695 LPrintf(~0, nfmtstr, name);
697 x = ComputeKBytes(id.id_NumBlocks, id.id_BytesPerBlock);
698 y = ComputeKBytes(id.id_NumBlocksUsed, id.id_BytesPerBlock);
700 PrintNum(x);
701 PrintNum(y);
702 PrintNum(x - y);
704 D(bug("Calling NameFromLock()\n"));
706 if(NameFromLock(lock, name, 108L))
708 LONG len = strlen(name) - 1;
710 if(name[len] == ':')
712 name[len] = '\0';
716 if(x > 0xfffff)
718 x >>= 10;
719 y >>= 10;
722 if(x)
724 x = ExtUDivMod32(UDivMod32(UMult32(y, 1000), x), 10, &y);
726 if(y > 4)
727 x++;
729 else
730 x = 0;
732 // y = ((struct DeviceList *)BADDR(id.id_VolumeNode))->dl_DiskType;
734 // if(!y)
735 y = id.id_DiskType;
737 if((idn->DosType & ID_DOS_DISK) != ID_DOS_DISK)
738 y = idn->DosType;
740 LPrintf(DEVFMTSTR, "%4ld%% %4ld %-11s%-8s%s\n",
741 x, id.id_NumSoftErrors,
742 ((id.id_DiskState >= ID_WRITE_PROTECTED) && (id.id_DiskState <= ID_VALIDATED)) ?
743 dstate[id.id_DiskState - ID_WRITE_PROTECTED] : (STRPTR)"", GetFSysStr(y), name);
745 if(blocks)
747 LPrintf(BLOCKSSTR,
748 "\nTotal blocks: %-10ld Blocks used: %ld\n"
749 " Blocks free: %-10ld Blocksize: %ld\n",
750 id.id_NumBlocks, id.id_NumBlocksUsed,
751 id.id_NumBlocks-id.id_NumBlocksUsed, id.id_BytesPerBlock );
754 else
755 D(bug("Info failure\n"));
757 UnLock(lock);
761 LONG err = IoErr();
763 if((err != 0) && !goodOnly)
765 LPrintf(~0, nfmtstr, name);
766 PrintFault(err, NULL);
773 /* show volumes */
774 if(vols || (!devs && !disks))
776 if(!first)
777 PutStr("\n");
779 LPrintf(DISKSTITLE, "Volumes\n");
781 for(MaxLen = 15, idn = head; idn; idn = idn->Next)
783 if(idn->IsVolume)
785 LONG len = strlen(idn->Name);
787 if(len > MaxLen)
788 MaxLen = len;
792 __sprintf(nfmtstr, "%%-%lds%%-10s", MaxLen+1);
794 for(idn = head; idn; idn = idn->Next)
796 if(idn->IsVolume)
798 LPrintf(VOLNAMEFMTSTR, nfmtstr, idn->Name,
799 GetStrFromCat(MOUNTEDSTR, "[Mounted]"));
800 // idn->Task ? GetStrFromCat(MOUNTEDSTR, "[Mounted]") : ""); TODO
802 if(datetimeFmt)
804 UBYTE datestr[128];
805 static struct Hook hook;
807 memset(&hook, 0, sizeof(struct Hook));
809 hook.h_SubEntry = (HOOKFUNC)FmtProcedure;
810 hook.h_Data = datestr;
812 FormatDate(loc, datetimeFmt, &idn->VolumeDate, &hook);
814 PutStr(datestr);
816 else
818 TEXT StrDay[LEN_DATSTRING];
819 TEXT StrDate[LEN_DATSTRING];
820 TEXT StrTime[LEN_DATSTRING];
822 struct DateTime dt;
824 dt.dat_Flags = DTF_SUBST;
825 dt.dat_Format = FORMAT_DOS;
826 dt.dat_StrDay = StrDay;
827 dt.dat_StrDate = StrDate;
828 dt.dat_StrTime = StrTime;
829 dt.dat_Stamp = idn->VolumeDate;
831 if(DateToStr(&dt))
833 if(Strnicmp(StrDate, StrDay, strlen(StrDay)) == 0)
835 dt.dat_Flags = 0L;
836 DateToStr(&dt);
839 LPrintf(DATEFMTSTR, "created %.3s, %-10s %s",
840 StrDay, StrDate, StrTime);
844 PutStr("\n");
849 else
851 PrintFault( ERROR_NO_FREE_STORE, NULL);
854 /* reset window pointer of our process */
855 proc->pr_WindowPtr = win;
857 /* free args */
858 FreeArgs(rdargs);
862 end: /* free allocated memory */
864 DeletePool(Pool);
868 ULONG ComputeKBytes(ULONG a, ULONG b)
870 // UQUAD result = UMult64(a, b);
872 UQUAD result = (UQUAD)a * b;
874 return (ULONG)(result >> 10);
878 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale)
880 *((STRPTR)hook->h_Data) = a;
881 hook->h_Data = (STRPTR) hook->h_Data + 1;
885 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod)
887 *mod = a % b;
889 return a/b;