5d06499f53b161995f025a64f5335f99a9d846fd
[openafs.git] / src / WINNT / afssvrcfg / partitions_page.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * INCLUDES _________________________________________________________________
12  *
13  */
14 #include <winsock2.h>
15 #include <ws2tcpip.h>
16
17 extern "C" {
18 #include <afs/param.h>
19 #include <afs/stds.h>
20 }
21
22 #include "afscfg.h"
23 #include "resource.h"
24 #include "create_partition_dlg.h"
25 #include "partition_utils.h"
26 #include "salvage_results_dlg.h"
27 extern "C" {
28 #include <afs\afs_vosAdmin.h>
29 #include <afs\afs_clientAdmin.h>
30 }
31
32
33 // TODO:  Add context menu to fastlist
34
35
36 /*
37  * DEFINITIONS _________________________________________________________________
38  *
39  */
40 #define MAX_PARTITIONS  26
41
42 static HWND hDlg = 0;
43 static HWND hPartitionList = 0;
44 static HLISTITEM hSelectedItem;
45
46 static TCHAR szYes[cchRESOURCE];
47 static TCHAR szNo[cchRESOURCE];
48
49 static const UINT DISK_DRIVE_IMAGE = 0;
50 //static const UINT DISABLED_DISK_DRIVE_IMAGE = 1;
51 //static const UINT DISK_DRIVE_WITH_WARNING_IMAGE = 2;
52
53 // Remember the config state of the FS so we can detect when it changes.
54 // When it changes we must redisplay the partition info.
55 static CONFIG_STATE configFS;
56
57
58
59 /*
60  * PROTOTYPES _________________________________________________________________
61  *
62  */
63 BOOL ShowSalvageDlg(HWND hParent, LPCTSTR pszPartitionName);
64
65 static void OnCreatePartitions();
66 static void OnInitDialog(HWND hwndDlg);
67 static void SetupListCols();
68 static void AddColumn(int nWidth, LPCTSTR pszTitle, DWORD dwFlags = FLCF_JUSTIFY_LEFT);
69 static void ShowPartitions();
70 cfg_partitionEntry_t *GetPartitionTableFromRegistry(int& cEntries);
71 static vos_partitionEntry_t *GetPartitionTableFromVos(int &nNumPartitions);
72 static void OnListSelection(LPFLN_ITEMSELECT_PARAMS pItemParms);
73 static void SetupImageLists();
74 static void OnRemove();
75 static BOOL CheckShowPartitions();
76 static void OnSalvage();
77 static void CheckEnableSalvage();
78
79
80 /*
81  * EXPORTED FUNCTIONS _________________________________________________________________
82  *
83  */
84 /*
85  * Dialog Proc _________________________________________________________________
86  *
87  */
88 BOOL CALLBACK PartitionsPageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
89 {
90     if (AfsAppLib_HandleHelp(IDD_PARTITIONS_PAGE, hwndDlg, uMsg, wParam, lParam))
91         return TRUE;
92
93     switch (uMsg) {
94     case WM_INITDIALOG: 
95         OnInitDialog(hwndDlg);
96         break;
97         
98     case WM_COMMAND:  
99         switch (LOWORD(wParam)) {
100         case IDINIT:
101             CheckShowPartitions();
102             break;
103
104         case IDC_CREATE_PARTITIONS:     
105             OnCreatePartitions();
106             break;
107
108         case IDC_REMOVE:  
109             OnRemove();
110             break;
111
112         case IDC_SALVAGE: 
113             OnSalvage();
114             break;
115         }
116         break;
117
118     case WM_NOTIFY:    
119         if ((((LPNMHDR)lParam)->code) == FLN_ITEMSELECT)
120             OnListSelection((LPFLN_ITEMSELECT_PARAMS)lParam);
121         break;
122     }
123
124     return FALSE;
125 }       
126
127 void UpdatePartitionList()
128 {
129     ShowPartitions();
130     CheckEnableSalvage();
131 }
132
133
134 /*
135  * STATIC FUNCTIONS _________________________________________________________________
136  *
137  */
138
139 /*
140  * Event Handler Functions _________________________________________________________________
141  *
142  */
143 static void OnInitDialog(HWND hwndDlg)
144 {
145     hDlg = hwndDlg;
146
147 //  PropSheet_CancelToClose(GetParent(hDlg));
148
149     hSelectedItem = 0;
150
151     hPartitionList = GetDlgItem(hDlg, IDC_PARTITION_LIST);
152     _ASSERTE(hPartitionList);
153
154     SetupImageLists();
155
156     GetString(szYes, IDS_YES);
157     GetString(szNo, IDS_NO);
158
159     SetupListCols();
160
161     configFS = g_CfgData.configFS;
162
163     ShowPartitions();
164
165     CheckEnableSalvage();
166 }       
167
168 static void OnCreatePartitions()
169 {
170     if (CreatePartition(hDlg))
171         ShowPartitions();
172 }
173
174 static void OnListSelection(LPFLN_ITEMSELECT_PARAMS pItemParms)
175 {
176     ASSERT(pItemParms);
177
178     hSelectedItem = pItemParms->hItem;
179
180     ENABLE_STATE es = pItemParms->hItem ? ES_ENABLE : ES_DISABLE;
181
182     SetEnable(hDlg, IDC_REMOVE, es);
183     SetEnable(hDlg, IDC_REMOVE_MSG, es);
184 }
185
186 static void OnRemove()
187 {
188     ASSERT(hSelectedItem);
189     ASSERT(g_hServer);
190         
191     afs_status_t nStatus;
192
193     BOOL bExported = (BOOL)FastList_GetItemParam(hPartitionList, hSelectedItem);
194     if (bExported) {
195         MsgBox(hDlg, IDS_CANT_DELETE_EXPORTED_PARTITION, GetAppTitleID(), MB_OK | MB_ICONSTOP);
196         return;
197     }
198
199     LPCTSTR pszPartitionName = FastList_GetItemText(hPartitionList, hSelectedItem, 0);
200     ASSERT(pszPartitionName);
201
202     int nResult = Message(MB_ICONQUESTION | MB_YESNO, GetAppTitleID(), IDS_DELETE_PARTITION_PROMPT, TEXT("%s"), pszPartitionName);
203     if (nResult == IDNO)
204         return;
205
206     g_LogFile.Write("Removing partition '%s'.\r\n", (char *)S2A(pszPartitionName));
207     nResult = cfg_HostPartitionTableRemoveEntry(g_hServer, S2A(pszPartitionName), &nStatus);
208     if (!nResult) {
209         ShowError(hDlg, nStatus, IDS_REMOVE_PARTITION_ERROR);
210         return;
211     }
212
213     FastList_RemoveItem(hPartitionList, hSelectedItem);
214
215     CheckEnableSalvage();
216 }       
217
218 static void OnSalvage()
219 {
220     // Can't salvage if the file server is not configured
221     if (!Configured(g_CfgData.configFS)) {
222         ShowError(hDlg, 0, IDS_CANT_SALVAGE_WHEN_FS_NOT_CONFIGURED);
223         return;
224     }
225
226     LPCTSTR pszPartitionName = TEXT("");
227
228     if (hSelectedItem) {
229         pszPartitionName = FastList_GetItemText(hPartitionList, hSelectedItem, 0);
230         ASSERT(pszPartitionName);
231     }   
232
233     if (!ShowSalvageDlg(hDlg, pszPartitionName))
234         return;
235
236     ShowSalvageResults(hDlg);
237
238     // Since a salvage was performed, there may be partitions exported that were
239     // not exported before the salvage.  Salvage may stop and restart the file
240     // server, which will pick up the previously unexported partitions.  We will
241     // update our partition list in case this has happened.
242     UpdatePartitionList();
243 }
244
245
246 /*
247  * Utility Functions _________________________________________________________________
248  *
249  */
250 static BOOL CheckShowPartitions()
251 {
252     if (configFS != g_CfgData.configFS) {
253         configFS = g_CfgData.configFS;
254         UpdatePartitionList();
255         return TRUE;
256     }
257
258     return FALSE;
259 }
260
261 static void SetupImageLists()
262 {
263     HIMAGELIST hiList = ImageList_Create(16, 16, TRUE, 1, 1);
264
265     AfsAppLib_AddToImageList(hiList, IDI_AGGREGATE, FALSE);
266     AfsAppLib_AddToImageList(hiList, IDI_DISABLED_DISK_DRIVE, FALSE);
267
268     FastList_SetImageLists(hPartitionList, hiList, 0);
269 }       
270
271 static void AddColumn(int nWidth, LPCTSTR pszTitle, DWORD dwFlags)
272 {
273     static int nCol = 1;
274     FASTLISTCOLUMN col;
275         
276     col.dwFlags = dwFlags;
277     col.cxWidth = nWidth;
278     lstrcpy(col.szText, pszTitle);
279
280     FastList_SetColumn(hPartitionList, nCol++, &col);
281 }
282
283 static void SetupListCols()
284 {
285     TCHAR szMsg[cchRESOURCE];
286
287     AddColumn(75, GetResString(IDS_NAME, szMsg));
288     AddColumn(55, GetResString(IDS_DRIVE, szMsg));
289     AddColumn(60, GetResString(IDS_EXPORTED, szMsg));
290     AddColumn(75, GetResString(IDS_TOTAL, szMsg), FLCF_JUSTIFY_RIGHT);
291     AddColumn(75, GetResString(IDS_FREE, szMsg), FLCF_JUSTIFY_RIGHT);
292 }
293
294 cfg_partitionEntry_t *GetPartitionTableFromRegistry(int& cEntries)
295 {
296     afs_status_t nStatus;
297  
298     // Read the parition table out of the registry
299     int nResult = ReadPartitionTable(&nStatus);
300     if (!nResult) {
301         ShowError(hDlg, nStatus, IDS_READ_PARTITIONS_ERROR);
302         return 0;
303     }
304
305     return GetPartitionTable(cEntries);
306 }
307
308 static vos_partitionEntry_t *GetPartitionTableFromVos(int &nNumPartitions)
309 {
310     ASSERT(g_hCell);
311     ASSERT(g_CfgData.szHostname[0]);
312
313     nNumPartitions = 0;
314
315     if (g_CfgData.configFS != CS_ALREADY_CONFIGURED)
316         return 0;
317
318     static vos_partitionEntry_t aPartitions[MAX_PARTITIONS];
319     afs_status_t nStatus, nIgnore;
320     void *hServer = 0;
321     int nNumParts = 0;
322
323     // Open this server
324     g_LogFile.Write("Opening server %s.\r\n", GetHostnameA());
325     int nResult = vos_ServerOpen(g_hCell, GetHostnameA(), &hServer, &nStatus);
326     if (nResult) {
327
328         // Read the partition info
329         g_LogFile.Write("Reading paritition information for this server.\r\n");
330         void *iterID;
331
332         nResult = vos_PartitionGetBegin(g_hCell, hServer, 0, &iterID, &nStatus);
333         if (nResult) {
334             while (nNumParts < MAX_PARTITIONS) {
335                 nResult = vos_PartitionGetNext(iterID, &aPartitions[nNumParts], &nStatus);
336                 if (!nResult) {
337                     if (nStatus == ADMITERATORDONE) {
338                         nResult = 1;
339                         nStatus = 0;
340                     }
341                     break;
342                 }
343
344                 nNumParts++;
345             }
346             vos_PartitionGetDone(iterID, &nIgnore);
347         }
348         vos_ServerClose(hServer, &nIgnore);
349     }
350
351     if (!nResult) {
352         ShowError(hDlg, nStatus, IDS_GET_PARTITION_LIST_ERROR);
353         return 0;
354     }
355
356     nNumPartitions = nNumParts;
357
358     return aPartitions;
359 }
360
361 // Convert a disk space value in Kbytes into a string
362 static LPTSTR DiskSpaceToString(int nSpace)
363 {
364     const float oneMB = 1024;   // in K bytes
365     const double oneGB = oneMB * 1024;
366     const double oneTB = oneGB * 1024;
367
368     static TCHAR szSpace[64];
369     double space;
370     LPTSTR pszUnits;
371
372     space = nSpace;     
373
374     if (space >= oneTB) {
375         space /= oneTB;
376         pszUnits = TEXT(" TB");
377     } else if (space >= oneGB) {
378         space /= oneGB;
379         pszUnits = TEXT(" GB");
380     } else if (space >= oneMB) {
381         space /= oneMB;
382         pszUnits = TEXT(" MB");
383     } else
384         pszUnits = TEXT(" KB");
385
386     int nNumDecimals = 0;
387     if (space - double(int(space)) > 0)
388         nNumDecimals = 2;
389
390     _stprintf(szSpace, TEXT("%3.*f%s"), nNumDecimals, space, pszUnits);
391
392     return szSpace;
393 }       
394
395 static void ShowPartitions()
396 {
397     FastList_RemoveAll(hPartitionList);
398
399     int cRegParts = 0, cVosParts = 0;
400
401     // If we got nothing from the registry, then leave the list empty
402     cfg_partitionEntry_t *pRegParts = GetPartitionTableFromRegistry(cRegParts);
403     if (!pRegParts)
404         return;
405
406     // If we failed to get vos info, then only show the registry info
407     vos_partitionEntry_t *pVosParts = GetPartitionTableFromVos(cVosParts);
408     if (!pVosParts)
409         cVosParts = 0;
410
411     // We have two partition tables, one from the registry and one from the vos
412     // library.  The one from the vos library tells us the partitions that are
413     // currently exported.  The one from the registry tells us the partitions
414     // that will be exported after the file server restarts.  The registry list
415     // should always be at least as big as the vos list.  The vos list can be
416     // smaller if one of the disks could not be exported.  To add a new partition,
417     // an entry must be added to the registry table and then the file server must
418     // be restarted.  To remove an entry, the partition must not be exported (due
419     // to an error) or the file server must not be running, in which case nothing
420     // will be exported.
421
422     // To display the partitions to the user, we use the list from the registry,
423     // looking up each of its entries in the vos list to see if it is exported,
424     // and if it is, to get its size info.
425
426
427     for (int nCurRegPart = 0; nCurRegPart < cRegParts; nCurRegPart++) {
428         LPTSTR pPartNameAsString = AnsiToString(pRegParts[nCurRegPart].partitionName);
429
430         // Show the partition in the list
431         FASTLISTADDITEM ai = { 0, DISK_DRIVE_IMAGE, IMAGE_NOIMAGE, pPartNameAsString, 0, 0 };
432         HLISTITEM hItem = FastList_AddItem(hPartitionList, &ai);
433
434         FreeString(pPartNameAsString);
435
436         FastList_SetItemText(hPartitionList, hItem, 1, pRegParts[nCurRegPart].deviceName);
437
438         // For the rest of the info we need to know if this guy is exported.
439         // Look him up in the vos table.
440         BOOL bExported = FALSE;
441         int nTotalSpace = 0;
442         int nFreeSpace = 0;
443
444         for (int nCurVosPart = 0; nCurVosPart < cVosParts; nCurVosPart++) {
445             if (stricmp(pVosParts[nCurVosPart].name, pRegParts[nCurRegPart].partitionName) == 0) {
446                 bExported = TRUE;
447                 nTotalSpace = pVosParts[nCurVosPart].totalSpace;
448                 nFreeSpace = pVosParts[nCurVosPart].totalFreeSpace;
449                 break;
450             }
451         }
452
453         FastList_SetItemText(hPartitionList, hItem, 2, bExported ? szYes : szNo);
454         FastList_SetItemText(hPartitionList, hItem, 3, bExported ? DiskSpaceToString(nTotalSpace) : TEXT(""));
455         FastList_SetItemText(hPartitionList, hItem, 4, bExported ? DiskSpaceToString(nFreeSpace) : TEXT(""));
456
457         // Set the item param to indicate that this partition is exported or not
458         FastList_SetItemParam(hPartitionList, hItem, bExported);
459     }
460 }
461
462 static void CheckEnableSalvage()
463 {
464     ENABLE_STATE es = (FastList_GetItemCount(hPartitionList) > 0) ? ES_ENABLE : ES_DISABLE;
465
466     SetEnable(hDlg, IDC_SALVAGE, es);
467     SetEnable(hDlg, IDC_SALVAGE_MSG, es);
468 }
469