fdiskGUI (Linux)

Share your advanced PureBasic knowledge/code with the community.
AZJIO
Addict
Addict
Posts: 2191
Joined: Sun May 14, 2017 1:48 am

fdiskGUI (Linux)

Post by AZJIO »

Download
I was told that graphical disk utilities use fdisk commands. That is, you can actually write a disk partition manager. I made a couple of commands for the partitions (Unmount and check the disk) and drew the partition squares.

Code: Select all

;-  ● TOP
EnableExplicit

;- # Constants
Enumeration Gadget
	#cnv
	#LV
	#cb
	#Editor
EndEnumeration

Enumeration Menu
	#fsck
	#umount
EndEnumeration


#Window = 0
#Win1 = 1
#Menu = 0

; 	https://www.purebasic.fr/english/viewtopic.php?f=12&t=71693
XIncludeFile "RunAsAdmin.pbi"
If Not RunAsAdmin::Login()
	End
EndIf

Structure Disk2
	name.s
	uuid.s
	mountpoint.s
	fstype.s
	label.s
	size.s
	rota.s
	tran.s
EndStructure

Define tmp$, item


;- ● Global
Global NewList Drive.Disk2()
Global Children

Procedure.s GetField(Value.s)
	Protected tmp, res$
	tmp  = GetJSONMember(Children, Value)
	If tmp
		Select JSONType(tmp)
			Case #PB_JSON_Boolean
				res$ = Str(GetJSONBoolean(tmp))
			Case #PB_JSON_Null
				res$ = "-"
			Case #PB_JSON_String
				res$ = GetJSONString(tmp)
		EndSelect
	EndIf
	ProcedureReturn res$
EndProcedure



Procedure GetDriveInfo()
	Protected res$, tmp
	Protected Blockdevices, ObjectBlockdevices, hJSON, i, j, ObjectChildren, BD1Children, oTran, Tran$
	
	; получить список дисков
	tmp = RunProgram("lsblk", "-J -n -o name,UUID,MOUNTPOINT,FSTYPE,LABEL,SIZE,ROTA,TRAN -I8", "", #PB_Program_Open | #PB_Program_Read)
	res$ = Chr(13)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				res$ + ReadProgramString(tmp) + Chr(13)
			EndIf
		Wend
		CloseProgram(tmp)
	EndIf
	; res$ = ReplaceString(res$, Chr(13) + "sd", Chr(13))
	res$ = Trim(res$, Chr(13))
	
	; 	Анализировать JSON и получить список дисков в Drive()
	hJSON = ParseJSON(#PB_Any, res$)
	If hJSON
		ObjectBlockdevices = GetJSONMember(JSONValue(hJSON), "blockdevices")
		If ObjectBlockdevices
			; Debug GetJSONString(ObjectBlockdevices)
			For j = 0 To JSONArraySize(ObjectBlockdevices) - 1
				Tran$ = ""
				BD1Children  = GetJSONElement(ObjectBlockdevices, j)
				ObjectChildren = GetJSONMember(BD1Children, "children")
				oTran = GetJSONMember(BD1Children, "tran")
				If oTran And JSONType(oTran) = #PB_JSON_String
					Tran$ = GetJSONString(oTran)
				EndIf
				; Debug GetJSONString(BD1Children)
				If ObjectChildren
					For i = 0 To JSONArraySize(ObjectChildren) - 1
						Children  = GetJSONElement(ObjectChildren, i)
						AddElement(Drive())
						Drive()\name = GetField("name")
						Drive()\uuid = GetField("uuid")
						Drive()\mountpoint = GetField("mountpoint")
						Drive()\fstype = GetField("fstype")
						Drive()\label = GetField("label")
						Drive()\size = GetField("size")
						Drive()\rota = GetField("rota")
						If Drive()\rota = "1"
							Drive()\rota = "hdd"
						ElseIf Drive()\rota = "0"
							Drive()\rota = "ssd"
						EndIf
						Drive()\tran = Tran$
						; Trim(Drive(), #LF$)
						; Drive() + #CR$
					Next i
				EndIf
			Next j
		EndIf
	EndIf
EndProcedure

Procedure fsch()
	Protected tmp
	tmp = RunProgram("e2fsck", "-f -y -v -C 0 /dev/" + Drive()\name, "", #PB_Program_Open | #PB_Program_Read)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				AddGadgetItem(#Editor, -1, ReadProgramString(tmp))
; 				WindowEvent()
			EndIf
		Wend
		CloseProgram(tmp)
	EndIf
EndProcedure


Procedure Report()
	Protected hWnd
	DisableWindow(#Window, 1)
	
	OpenWindow(#Win1, 0, 0, 900, 600, "Проверка диска", #PB_Window_SystemMenu | #PB_Window_ScreenCentered, WindowID(#Window))
	EditorGadget(#Editor, 0 , 0 , 900, 600)
	fsch()

	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_CloseWindow
				Break
		EndSelect
	ForEver

	DisableWindow(#Window, 0)
	CloseWindow(#Win1)
EndProcedure


Procedure ExeComStr(*Result.string, dev$)
	Protected NewList String$(), Len=0, tmp, *Point
	tmp = RunProgram("fdisk", "-l /dev/" + dev$, "", #PB_Program_Open | #PB_Program_Read)
	If tmp
		While ProgramRunning(tmp)
			If AvailableProgramOutput(tmp)
				; 				res$ + ReadProgramString(tmp) + Chr(10)
				; 				StrFastAdd(FS, ReadProgramString(tmp) + Chr(10))
				If AddElement(String$())
					String$() = ReadProgramString(tmp); + Chr(10)
				EndIf
			EndIf
		Wend
		
		; 		подсчитываем длину данных
		; 	   Count = ListSize(String$())
		ForEach String$()
			Len + Len(String$())
		Next
		Len+ListSize(String$()) ; добавляем число переносов строк #LF$ по количеству данных
		
		*Result\s = Space(Len)
		*Point = @*Result\s
		ForEach String$()
			CopyMemoryString(String$()+#LF$, @*Point)
		Next
		ClearList(String$())
		CloseProgram(tmp)
	EndIf
	
	; 	ProcedureReturn res$
EndProcedure

Global Text.String
GetDriveInfo()
ExeComStr(@Text, "sda")
; Debug Text\s
; MessageRequester("", Text\s)
; SetClipboardText(Text\s)

Structure Disk
	Name.s
	DiskSize.s
	DiskType.i
	DiskStart.q
	DiskEnd.q
	DiskSector.q
EndStructure

Global Size.q
Global WndW
Global SizePx.q
Global NewList Disks.Disk()



Procedure RegExp()
	Protected NbFound
	Protected Dim Result$(0)
	#RegExp = 0
	If CreateRegularExpression(#RegExp, "\A[^\r\n]+?\h\K(\d+)(?=\h[^\d]+\n)", #PB_RegularExpression_DotAll | #PB_RegularExpression_AnyNewLine)
		NbFound = ExtractRegularExpression(0, Text\s, Result$())
		If NbFound
			Size = Val(Result$(0))
		Else
			MessageRequester("", "The size could not be determined")
			ProcedureReturn 0
		EndIf
	EndIf
	FreeRegularExpression(#RegExp)
	
	ClearList(Disks())
	
	; If CreateRegularExpression(#RegExp, "/dev/sd\w(\d+)[\h*]+(\d+)\h+(\d+)\h+(\d+)")
	If CreateRegularExpression(#RegExp, "/dev/(sd\w\d+)[\h*]+(\d+)\h+(\d+)\h+(\d+)\h+([\d,]+[TGMKB])\h+([\da-f]+)")
		If ExamineRegularExpression(#RegExp, Text\s)
			While NextRegularExpressionMatch(#RegExp)
				If AddElement(Disks())
					Disks()\Name = RegularExpressionGroup(#RegExp, 1)
					Disks()\DiskStart = Val(RegularExpressionGroup(#RegExp, 2))
					Disks()\DiskEnd = Val(RegularExpressionGroup(#RegExp, 3))
					Disks()\DiskSector = Val(RegularExpressionGroup(#RegExp, 4))
					Disks()\DiskSize = RegularExpressionGroup(#RegExp, 5)
					Disks()\DiskType= Val(RegularExpressionGroup(#RegExp, 6))
				EndIf
			Wend
		EndIf
	EndIf
	FreeRegularExpression(#RegExp)
	ProcedureReturn 1
EndProcedure

Procedure Draw()
	Protected Found, bgcolor
	SizePx = Size/WndW
	ClearGadgetItems(#LV)
	If StartDrawing(CanvasOutput(#cnv))
		DrawingMode(#PB_2DDrawing_Transparent)
		Box(0, 0, WndW, 88, $3f3f3f)
		ForEach Disks()
			bgcolor = RGB(Random($FF, $99), Random($FF, $99), Random($FF, $99))
			Box(Disks()\DiskStart / SizePx, 0, Disks()\DiskSector / SizePx, 88, bgcolor)
			DrawText(Disks()\DiskStart / SizePx + 5, 30, Disks()\Name + #CRLF$ + Disks()\DiskSize, 0, #PB_2DDrawing_Transparent)
			Found = 0
			ForEach Drive()
				If Disks()\Name = Drive()\name
					Found = 1
					Break
				EndIf
			Next
			If Found
				AddGadgetItem(#LV, -1, Disks()\Name + Chr(10) + Disks()\DiskSize + Chr(10) + Disks()\DiskType +
				                       Chr(10) + Drive()\label + Chr(10) + Drive()\mountpoint + Chr(10) + Drive()\fstype + Chr(10) + Drive()\uuid)
			Else
				AddGadgetItem(#LV, -1, Disks()\Name + Chr(10) + Disks()\DiskSize + Chr(10) + Disks()\DiskType)
			EndIf
		Next
		StopDrawing()
	EndIf
EndProcedure

ExamineDesktops()
WndW = DesktopWidth(0) - 50


;-┌──GUI──┐
If OpenWindow(#Window, 0, 0, WndW + 10, 444, "HDD", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
	CanvasGadget(#cnv, 5, 0, WndW, 88, #PB_Canvas_Border)
	ComboBoxGadget(#cb, 5, 400 , 90 , 30)
	AddGadgetItem(#cb, -1, "sda")
	AddGadgetItem(#cb, -1, "sdb")
	AddGadgetItem(#cb, -1, "sdc")
	AddGadgetItem(#cb, -1, "sdd")
	AddGadgetItem(#cb, -1, "sde")
	AddGadgetItem(#cb, -1, "sdf")
	ListIconGadget(#LV, 5 , 93, WndW, 300, "Disks", 50)
	AddGadgetColumn(#LV, 1, "Size", 60)
	AddGadgetColumn(#LV, 2, "Type", 50)
	AddGadgetColumn(#LV, 3, "Label", 80)
	AddGadgetColumn(#LV, 4, "mount", 120)
	AddGadgetColumn(#LV, 5, "fs", 50)
	AddGadgetColumn(#LV, 6, "uuid", 150)
	
	If RegExp()
		Draw()
	EndIf
	If CreatePopupMenu(#Menu)
		MenuItem(#umount, "Unmount a disk")
		MenuItem(#fsck, "Checking the disk")
	EndIf
	

;-┌──Loop──┐
	Repeat
		Select WaitWindowEvent()
;- ├ Gadget
			Case #PB_Event_Gadget
				Select EventGadget()
					Case #LV
						If EventType() = #PB_EventType_RightClick
							item = GetGadgetState(#LV)
							If item <> -1
								DisplayPopupMenu(#Menu, WindowID(#Window))
							EndIf
						EndIf
					Case #cb
						If EventType() = #PB_EventType_Change
							tmp$ = GetGadgetText(#cb)
							ExeComStr(@Text, tmp$)
							If RegExp()
								Draw()
							EndIf
						EndIf
				EndSelect
				
;- ├ Menu
			Case #PB_Event_Menu
				Select EventMenu()
					Case #umount
						item = GetGadgetState(#LV)
						If item <> -1
							tmp$ = GetGadgetItemText(#LV, item, 0)
							ForEach Drive()
								If tmp$ = Drive()\name
									RunProgram("umount", "-l " + Drive()\mountpoint, "")
									Break
								EndIf
							Next
						EndIf
					Case #fsck
						item = GetGadgetState(#LV)
						If item <> -1
							tmp$ = GetGadgetItemText(#LV, item, 0)
							ForEach Drive()
								If tmp$ = Drive()\name
									Report()
; 									RunProgram("e2fsck", "-f -y -v -C 0 /dev/" + Drive()\name, "")
; 									RunProgram("bash", "e2fsck -f -y -v -C 0 /dev/" + Drive()\name, "")
; 									RunProgram("bash", "-c " + #DQUOTE$ + "e2fsck -f -y -v -C 0 /dev/" + Drive()\name + #DQUOTE$, "")
									Break
								EndIf
							Next
						EndIf
				EndSelect
				
			Case #PB_Event_CloseWindow
				CloseWindow(#Window)
				End
		EndSelect
	ForEver
;-└───Loop───┘
EndIf