fix some flag usage in mmakefiles. provide suitable names for amiga hardware devices...
[AROS.git] / workbench / c / Info.c
blob3cc6b1344baa814798d418f751432d59d5392396
1 /*
2 Copyright © 1995-2019, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Info Cli Command
6 Lang: English
7 */
9 /******************************************************************************
12 NAME
14 Info
16 SYNOPSIS
18 DISKS/S, VOLS=VOLUMES/S, ALL/S, BLOCKS/S, DEVICES/M
20 LOCATION
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 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
39 RESULT
41 NOTES
43 EXAMPLE
45 Info
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
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
72 ******************************************************************************/
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>
91 /* Prototypes */
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);
96 void doInfo();
99 const TEXT VersionStr[] = "$VER: Info 41.2 (26.05.2012)";
101 struct Catalog *cat;
102 struct Locale *loc = NULL;
103 ULONG MaxLen;
105 APTR Pool;
108 /* catalog string id:s */
109 enum
111 UNIT,
112 DEVTITLE,
113 DISKSTITLE,
114 DEVFMTSTR,
115 DATEFMTSTR,
116 READONLY,
117 READWRITE,
118 VALIDATING,
119 MOUNTEDSTR,
120 SMALLNUMFMT,
121 BIGNUMFMT,
122 VOLNAMEFMTSTR,
123 BLOCKSSTR
127 struct InfoDosNode
129 struct InfoDosNode *Next;
130 ULONG IsVolume;
131 ULONG DosType;
132 struct MsgPort *Task;
133 struct DateStamp VolumeDate;
134 TEXT Name[108];
137 struct InfoDosNode *head = NULL;
140 struct DiskTypeList
141 { ULONG id;
142 STRPTR str;
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" },
153 { ID_MSDOS_DISK, "MS-DOS" },
154 { ID_ACD0_DISK, "CDFS" },
155 { ID_CACHECDFS_DISK, "CDFS" },
156 { ID_ASIMCDFS_DISK, "CDFS" },
157 { ID_NOT_REALLY_DOS, "NO DOS" },
158 { ID_MAC_DISK2, "MAC" },
159 { ID_MNX1_DISK, "Minix" },
160 { ID_QL5A_DISK, "QL720k" },
161 { ID_QL5B_DISK, "QL1.4M" },
162 { ID_CPM_DISK, "CP/M" },
163 { ID_ZXS3_DISK, "+3Dos" },
164 { ID_ZXS0_DISK, "Disciple " },
165 { ID_ZXS1_DISK, "UniDos" },
166 { ID_ZXS2_DISK, "SamDos" },
167 { ID_ZXS4_DISK, "Opus" },
168 { ID_P2A0_DISK, "NETWORK" },
169 { ID_FAT12_DISK, "FAT12" },
170 { ID_FAT16_DISK, "FAT16" },
171 { ID_FAT32_DISK, "FAT32" },
172 { ID_SFS_BE_DISK, "SFS" },
173 { ID_SFS_LE_DISK, "sfs" },
174 { ID_PFS_DISK, "PFS" },
175 { ID_EXT2_DISK, "EXT2" },
176 { 0L, 0L }
180 /****************************************************************************/
182 int UtilityBase_version = 0;
183 int LocaleBase_version = 0;
185 int __nocommandline;
187 int main(void)
189 static struct TagItem loctags[] = { { OC_Version, 1 },
190 { TAG_END , 0 } };
191 cat = OpenCatalogA(NULL, "info_com.catalog", loctags);
192 loc = OpenLocale(NULL);
194 D(bug("Calling doInfo()\n"));
196 doInfo();
198 CloseLocale(loc);
199 CloseCatalog(cat);
201 return RETURN_OK; /* TODO: Fix this */
205 CONST_STRPTR GetStrFromCat(ULONG id, CONST_STRPTR def)
207 if(cat != NULL)
209 def = GetCatalogStr(cat, id, def);
212 return def;
216 void VLPrintf(ULONG id, CONST_STRPTR def, ...)
218 CONST_STRPTR format = GetStrFromCat(id, def);
219 AROS_SLOWSTACKFORMAT_PRE_USING(def, format);
220 VPrintf(format, AROS_SLOWSTACKFORMAT_ARG(def));
221 AROS_SLOWSTACKFORMAT_POST(def);
225 BOOL myMatchPatternNoCase(STRPTR *array, STRPTR str)
227 if(*array != NULL)
229 while(*array != NULL)
231 UBYTE matchstr[128];
232 UBYTE name[32];
233 UBYTE *p = *array++;
234 UBYTE len = strlen(p);
236 if(p[len - 1] != ':')
238 CopyMem(p, name, len);
239 name[len] = ':';
240 name[len + 1] = 0;
241 p = name;
244 if(ParsePatternNoCase(p, matchstr, sizeof(matchstr)) != -1)
246 if(MatchPatternNoCase(matchstr, str))
248 return TRUE;
253 return FALSE;
256 return TRUE;
260 BOOL ScanDosList(STRPTR *filter)
262 struct InfoDosNode *idn = 0L;
263 struct DosList *ndl, *dl;
264 STRPTR *strray = NULL, dummy = NULL;
265 BOOL err = FALSE;
267 D(bug("Entered ScanDosList()\n"));
269 if (filter == NULL) filter = &dummy;
271 if(*filter != NULL)
273 strray = AllocPooled(Pool, sizeof(STRPTR)*MAX_MULTIARGS);
275 if(strray != NULL)
277 STRPTR *p = filter;
278 LONG i = 0;
280 while(*p)
281 strray[i++] = *p++;
283 while(i < MAX_MULTIARGS)
284 strray[i++] = NULL;
286 else
287 return FALSE;
290 /* lock list of devices & vols */
291 dl = ndl = LockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
293 if(strray != NULL)
295 STRPTR *p = strray;
297 while(*p)
298 p++;
300 while((ndl = NextDosEntry(ndl, LDF_ASSIGNS | LDF_VOLUMES | LDF_READ)) != NULL)
302 TEXT name[108];
303 STRPTR taskName = NULL; /* Initialized to avoid a warning */
305 __sprintf(name, "%b:", ndl->dol_Name);
307 if ((ndl->dol_Type > DLT_VOLUME) || !(myMatchPatternNoCase(strray, name)))
309 continue;
312 switch (ndl->dol_Type)
314 case DLT_VOLUME:
315 taskName = ((struct Task *)ndl->dol_Task->mp_SigTask)->tc_Node.ln_Name;
317 D(bug("Found volume %s\n", taskName));
318 break;
320 case DLT_DIRECTORY:
322 struct AssignList *al = ndl->dol_misc.dol_assign.dol_List;
324 taskName = ((struct Task *)((struct FileLock *)BADDR(ndl->dol_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
326 D(bug("Found directory %s\n", taskName));
328 while(al != NULL)
330 *p++ = ""; // TODO!!! ((struct Task *)((struct FileLock *)BADDR(al->al_Lock))->fl_Task->mp_SigTask)->tc_Node.ln_Name;
331 al = al->al_Next;
334 break;
337 *p++ = taskName;
340 else
341 strray = filter;
343 ndl = dl;
345 while((ndl = NextDosEntry(ndl, LDF_VOLUMES | LDF_DEVICES | LDF_READ)) != NULL)
347 UBYTE len = 0;
348 UBYTE type = ndl->dol_Type;
349 UBYTE name[108];
351 /* do not start non-started handlers or open CON: or RAW: windows */
352 if(type == DLT_DEVICE && !ndl->dol_Task)
353 continue;
355 __sprintf(name, "%b:", ndl->dol_Name);
356 D(bug("Found name %s\n", name));
358 if((type == DLT_DEVICE) && (myMatchPatternNoCase(strray, name) == FALSE))
360 D(int i);
362 D(bug("Failure! -- name = %s, strray = %p\n", name, (void *)strray));
364 D(for (i = 0; strray[i] != NULL; i++)
366 bug("Strray %i = %s\n", i, strray[i]);
369 continue;
372 idn = (struct InfoDosNode *)AllocPooled(Pool, sizeof(struct InfoDosNode));
374 if(idn == NULL)
376 err = TRUE;
377 break;
380 idn->Task = ndl->dol_Task;
381 idn->IsVolume = type == DLT_VOLUME;
383 while((idn->Name[len] = name[len]))
384 len++;
386 if(type == DLT_VOLUME)
388 idn->VolumeDate = ((struct DeviceList *)ndl)->dl_VolumeDate;
389 idn->Name[len - 1] = '\0'; /* remove ':' */
391 else
393 BPTR ptr = ndl->dol_misc.dol_handler.dol_Startup;
394 struct FileSysStartupMsg *fssm = NULL;
396 if (IsFileSystem(idn->Name))
398 // Only filesystems have a valid FileSysStartupMsg
399 fssm = (struct FileSysStartupMsg *)BADDR(ptr);
402 idn->DosType = ID_DOS_DISK;
404 // DLT_DEVICE
405 if (len > MaxLen)
406 MaxLen = len;
408 if (fssm)
410 struct DosEnvec *de;
411 de = (struct DosEnvec *)BADDR(fssm->fssm_Environ);
413 if (de && (de->de_TableSize & 0xffffff00) == 0)
414 if (de->de_DosType)
415 idn->DosType = de->de_DosType;
419 /* kinda insert sort */
421 struct InfoDosNode *work = head;
422 struct InfoDosNode *prev = NULL;
424 while((work != NULL) && (Stricmp(idn->Name, work->Name) > 0))
426 prev = work;
427 work = work->Next;
430 if(prev != NULL)
431 prev->Next = idn;
432 else
433 head = idn;
435 idn->Next = work;
439 /* unlock list of devices and volumes */
440 UnLockDosList(LDF_ASSIGNS | LDF_VOLUMES | LDF_DEVICES | LDF_READ);
442 // strray freed at DeletePool
444 return !err;
448 void PrintNum(ULONG num)
450 /* MBytes ? */
451 if(num > 1023)
453 ULONG x, xx;
454 char fmt = 'M';
456 /* GBytes ? */
457 if(num > 0xfffff)
459 num >>= 10;
460 fmt = 'G';
463 num = ExtUDivMod32(UMult32(num, 100) >> 10, 100, &x);
465 /* round */
466 x = ExtUDivMod32(x, 10, &xx);
468 if(xx > 4)
470 if(++x > 9)
472 x = 0;
473 num++;
477 VLPrintf(BIGNUMFMT, "%5ld.%ld%lc", num, x, fmt);
479 else
481 VLPrintf(SMALLNUMFMT, "%7ldK", num);
486 STRPTR GetFSysStr(ULONG DiskType)
488 struct DiskTypeList *dtlptr = dtl;
490 STRPTR ptr = NULL;
492 do {
493 if(dtlptr->id == DiskType)
495 ptr = dtlptr->str;
496 break;
498 } while(*((ULONG *)dtlptr++));
500 if(ptr == NULL)
502 static TEXT buffer[5];
504 ptr = (STRPTR)buffer;
505 *((ULONG *)ptr) = AROS_LONG2BE(DiskType);
507 if(ptr[3] < ' ')
508 ptr[3] += '0';
510 ptr[4] = '\0';
513 return ptr;
517 enum
519 ARG_DISKS,
520 ARG_VOLS,
521 ARG_ALL,
522 ARG_BLOCKS,
523 ARG_DEVS,
524 NOOFARGS
528 void doInfo()
530 struct RDArgs *rdargs;
531 struct Process *proc;
532 struct Window *win;
533 struct InfoDosNode *idn;
535 struct InfoData *id = AllocVec(sizeof(struct InfoData), MEMF_ANY);
537 IPTR args[] = { (IPTR)FALSE,
538 (IPTR)FALSE,
539 (IPTR)FALSE,
540 (IPTR)FALSE,
541 (IPTR)NULL };
543 CONST_STRPTR unit = GetStrFromCat(UNIT, "Unit");
545 if(id == NULL)
547 PrintFault(ERROR_NO_FREE_STORE, NULL);
548 return;
551 Pool = CreatePool(MEMF_ANY, 1024, 1024);
553 if(Pool == NULL)
555 PrintFault(ERROR_NO_FREE_STORE, NULL);
556 return; /* ??? */
559 D(bug("Calling ReadArgs()\n"));
561 /* read arguments */
562 rdargs = ReadArgs("DISKS/S,VOLS=VOLUMES/S,ALL/S,BLOCKS/S,DEVICES/M",
563 args, NULL);
565 if(rdargs != NULL)
567 BOOL disks = (BOOL)args[ARG_DISKS];
568 BOOL vols = (BOOL)args[ARG_VOLS];
569 BOOL showall = (BOOL)args[ARG_ALL];
570 BOOL blocks = (BOOL)args[ARG_BLOCKS];
571 STRPTR *devs = (STRPTR *)args[ARG_DEVS];
573 if (devs && (*devs == NULL)) devs = NULL;
575 /* If nothing is specified, show everything we got */
576 if(devs == NULL && !disks && !vols)
578 vols = TRUE;
579 disks = TRUE;
582 /* check pattern strings */
583 if(devs != NULL)
585 STRPTR *p = devs;
587 while(*p != NULL)
589 TEXT matchstr[128];
591 if(ParsePatternNoCase(*p, matchstr, sizeof(matchstr)) == -1)
593 PrintFault(IoErr(), *p);
594 goto end;
597 p++;
601 /* avoid requesters */
602 proc = (struct Process *)FindTask(NULL);
603 win = (struct Window *)proc->pr_WindowPtr;
604 proc->pr_WindowPtr = (struct Window *)~0;
606 MaxLen = strlen(unit);
608 D(bug("Calling ScanDosList()\n"));
610 /* scan doslist */
611 if(ScanDosList(devs))
613 CONST_STRPTR dstate[3] = { GetStrFromCat(READONLY, "read only"),
614 GetStrFromCat(VALIDATING, "validating"),
615 GetStrFromCat(READWRITE, "read/write") };
616 STRPTR datetimeFmt = NULL;
617 BOOL first = TRUE;
618 TEXT nfmtstr[16];
619 TEXT buf[64];
621 D(bug("Printing stuff\n"));
623 /* get datetimefmt string */
624 if(loc && (GetVar("info_datetime", buf, sizeof(buf), 0L) > 0L))
626 datetimeFmt = buf;
629 /* calc format string for 'Unit' */
630 __sprintf(nfmtstr, "%%-%lds", MaxLen);
632 /* show device infomation */
633 if(devs != NULL || disks || !vols)
635 for(idn = head; idn; idn = idn->Next)
637 BPTR lock;
638 STRPTR name = idn->Name;
640 D(bug("Got name = %s\n", name));
642 if(!idn->IsVolume && IsFileSystem(name))
644 BOOL gotinfo = FALSE;
645 /* if first device to print, print title */
646 if(first || blocks)
648 if(!first)
649 Printf("\n");
651 D(bug("Printing device\n"));
653 VLPrintf(~0, nfmtstr, unit);
654 VLPrintf(DEVTITLE, " Size Used Free Full Errs State Type Name\n");
656 first = FALSE;
659 VLPrintf(~0, nfmtstr, name);
661 D(bug("Locking \"%s\"\n", name));
662 lock = Lock(name, SHARED_LOCK);
664 D(bug("Lock = %p\n", (APTR)lock));
666 if(lock != BNULL)
668 D(bug("Got lock on %s\n", name));
670 if(Info(lock, id) == DOSTRUE)
672 D(bug("Calling NameFromLock()\n"));
674 if(NameFromLock(lock, name, 108L))
676 LONG len = strlen(name) - 1;
678 if(name[len] == ':')
680 name[len] = '\0';
684 gotinfo = TRUE;
686 UnLock(lock);
688 } else if (idn->Task) {
689 name = NULL;
690 D(bug("Calling ACTION_DISK_INFO\n"));
691 if (DoPkt(idn->Task, ACTION_DISK_INFO, (SIPTR)MKBADDR(id), (SIPTR)BNULL, (SIPTR)BNULL, (SIPTR)BNULL, (SIPTR)BNULL)) {
692 gotinfo = TRUE;
696 if (gotinfo) {
697 ULONG x, y;
699 D(bug("Got info on %s\n", name));
701 if (id->id_DiskType == ID_NO_DISK_PRESENT) {
702 VLPrintf(~0, " No disk present\n");
703 } else if (id->id_DiskType == ID_NOT_REALLY_DOS) {
704 VLPrintf(~0, " Not a DOS disk\n");
705 } else if (id->id_DiskType == ID_UNREADABLE_DISK) {
706 VLPrintf(~0, " Unreadable disk\n");
707 } else {
708 x = ComputeKBytes(id->id_NumBlocks, id->id_BytesPerBlock);
709 y = ComputeKBytes(id->id_NumBlocksUsed, id->id_BytesPerBlock);
711 PrintNum(x);
712 PrintNum(y);
713 PrintNum(x - y);
715 if(x > 0xfffff)
717 x >>= 10;
718 y >>= 10;
721 if(x)
723 x = ExtUDivMod32(UDivMod32(UMult32(y, 1000), x), 10, &y);
725 if(y > 4)
726 x++;
728 else
729 x = 0;
731 // y = ((struct DeviceList *)BADDR(id->id_VolumeNode))->dl_DiskType;
733 // if(!y)
734 y = id->id_DiskType;
736 if((idn->DosType & ID_DOS_DISK) != ID_DOS_DISK)
737 y = idn->DosType;
740 VLPrintf(DEVFMTSTR, "%4ld%% %4ld %-11s%-8s%s\n",
741 x, id->id_NumSoftErrors,
742 ((id->id_DiskState >= ID_WRITE_PROTECTED) && (id->id_DiskState <= ID_VALIDATED)) ? (const char *)dstate[id->id_DiskState - ID_WRITE_PROTECTED] : (const char *)"",
743 GetFSysStr(y),
744 name);
747 if(blocks)
749 VLPrintf(BLOCKSSTR,
750 "\nTotal blocks: %-10ld Blocks used: %ld\n"
751 " Blocks free: %-10ld Blocksize: %ld\n",
752 id->id_NumBlocks,
753 id->id_NumBlocksUsed,
754 id->id_NumBlocks-id->id_NumBlocksUsed,
755 id->id_BytesPerBlock);
759 else
761 D(bug("Info failure\n"));
762 VLPrintf(~0, "\n");
766 LONG err = IoErr();
768 /* just ignore PIPEFS */
769 if (err == ERROR_ACTION_NOT_KNOWN)
770 if (strcmp(name, "PIPEFS:") == 0)
771 err = 0;
773 if (err && showall)
775 VLPrintf(~0, nfmtstr, name);
776 PrintFault(err, NULL);
783 /* show volumes */
784 if(vols || (!devs && !disks))
786 if(!first)
787 PutStr("\n");
789 VLPrintf(DISKSTITLE, "Volumes\n");
791 /* find the longest volume name */
792 for(MaxLen = 15, idn = head; idn; idn = idn->Next)
794 if(idn->IsVolume)
796 LONG len = strlen(idn->Name);
798 if(len > MaxLen)
799 MaxLen = len;
803 __sprintf(nfmtstr, "%%-%lds%%-10s", MaxLen+1);
805 for(idn = head; idn; idn = idn->Next)
807 if(idn->IsVolume)
809 VLPrintf(VOLNAMEFMTSTR, nfmtstr, idn->Name,
810 idn->Task ? (const char *)GetStrFromCat(MOUNTEDSTR, "[Mounted]") : (const char *)"");
812 if(idn->VolumeDate.ds_Days != 0)
814 if(datetimeFmt)
816 UBYTE datestr[128];
817 static struct Hook hook;
819 memset(&hook, 0, sizeof(struct Hook));
821 hook.h_SubEntry = (HOOKFUNC)FmtProcedure;
822 hook.h_Data = datestr;
824 FormatDate(loc, datetimeFmt, &idn->VolumeDate, &hook);
826 PutStr(datestr);
828 else
830 TEXT StrDay[LEN_DATSTRING];
831 TEXT StrDate[LEN_DATSTRING];
832 TEXT StrTime[LEN_DATSTRING];
834 struct DateTime dt;
836 dt.dat_Flags = DTF_SUBST;
837 dt.dat_Format = FORMAT_DOS;
838 dt.dat_StrDay = StrDay;
839 dt.dat_StrDate = StrDate;
840 dt.dat_StrTime = StrTime;
841 dt.dat_Stamp = idn->VolumeDate;
843 if(DateToStr(&dt))
845 if(Strnicmp(StrDate, StrDay, strlen(StrDay)) == 0)
847 dt.dat_Flags = 0L;
848 DateToStr(&dt);
851 VLPrintf(DATEFMTSTR, "created %.3s, %-10s %s", StrDay, StrDate, StrTime);
856 PutStr("\n");
861 else
863 PrintFault( ERROR_NO_FREE_STORE, NULL);
866 /* reset window pointer of our process */
867 proc->pr_WindowPtr = win;
869 /* free args */
870 FreeArgs(rdargs);
874 end: /* free allocated memory */
875 FreeVec(id);
876 DeletePool(Pool);
880 ULONG ComputeKBytes(ULONG a, ULONG b)
882 // UQUAD result = UMult64(a, b);
884 UQUAD result = (UQUAD)a * b;
886 return (ULONG)(result >> 10);
890 void FmtProcedure(struct Hook *hook, char a, struct Locale *locale)
892 *((STRPTR)hook->h_Data) = a;
893 hook->h_Data = (STRPTR) hook->h_Data + 1;
897 ULONG ExtUDivMod32(ULONG a, ULONG b, ULONG *mod)
899 *mod = a % b;
901 return a/b;