1 /** @file
2   Main file for time, timezone, and date shell level 2 and shell level 3 functions.
3 
4   (C) Copyright 2012-2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "UefiShellLevel2CommandsLib.h"
17 
18 /**
19   Determine if String is a valid representation for a time or date.
20 
21   @param[in] String     The pointer to the string to test.
22   @param[in] Char       The delimeter character.
23   @param[in] Min        The minimum value allowed.
24   @param[in] Max        The maximum value allowed.
25   @param[in] MinusOk    Whether negative numbers are permitted.
26 
27   @retval TRUE    String is a valid representation.
28   @retval FALSE   String is invalid.
29 **/
30 BOOLEAN
InternalIsTimeLikeString(IN CONST CHAR16 * String,IN CONST CHAR16 Char,IN CONST UINTN Min,IN CONST UINTN Max,IN CONST BOOLEAN MinusOk)31 InternalIsTimeLikeString (
32   IN CONST CHAR16   *String,
33   IN CONST CHAR16   Char,
34   IN CONST UINTN    Min,
35   IN CONST UINTN    Max,
36   IN CONST BOOLEAN  MinusOk
37   )
38 {
39   UINTN Count;
40   Count = 0;
41 
42   if (MinusOk) {
43     //
44     // A single minus is ok.
45     //
46     if (*String == L'-') {
47       String++;
48     }
49   }
50 
51   //
52   // the first char must be numeric.
53   //
54   if (!ShellIsDecimalDigitCharacter(*String)) {
55     return (FALSE);
56   }
57   //
58   // loop through the characters and use the lib function
59   //
60   for ( ; String != NULL && *String != CHAR_NULL ; String++){
61     if (*String == Char) {
62       Count++;
63       if (Count > Max) {
64         return (FALSE);
65       }
66       continue;
67     }
68     if (!ShellIsDecimalDigitCharacter(*String)) {
69       return (FALSE);
70     }
71   }
72   if (Count < Min) {
73     return (FALSE);
74   }
75   return (TRUE);
76 }
77 
78 /**
79   Verify that the DateString is valid and if so set that as the current
80   date.
81 
82   @param[in] DateString     The pointer to a string representation of the date.
83 
84   @retval SHELL_INVALID_PARAMETER   DateString was NULL.
85   @retval SHELL_INVALID_PARAMETER   DateString was mis-formatted.
86   @retval SHELL_SUCCESS             The operation was successful.
87 **/
88 SHELL_STATUS
CheckAndSetDate(IN CONST CHAR16 * DateString)89 CheckAndSetDate (
90   IN CONST CHAR16 *DateString
91   )
92 {
93   EFI_TIME      TheTime;
94   EFI_STATUS    Status;
95   CHAR16        *DateStringCopy;
96   CHAR16        *Walker;
97   CHAR16        *Walker1;
98 
99   if (!InternalIsTimeLikeString(DateString, L'/', 2, 2, FALSE)) {
100     return (SHELL_INVALID_PARAMETER);
101   }
102 
103   Status = gRT->GetTime(&TheTime, NULL);
104   if (EFI_ERROR(Status)) {
105     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status);
106     return (SHELL_DEVICE_ERROR);
107   }
108 
109   DateStringCopy = NULL;
110   DateStringCopy = StrnCatGrow(&DateStringCopy, NULL, DateString, 0);
111   if (DateStringCopy == NULL) {
112     return (SHELL_OUT_OF_RESOURCES);
113   }
114   Walker = DateStringCopy;
115 
116   TheTime.Month = 0xFF;
117   TheTime.Day   = 0xFF;
118   TheTime.Year  = 0xFFFF;
119 
120   Walker1 = StrStr(Walker, L"/");
121   if (Walker1 != NULL && *Walker1 == L'/') {
122     *Walker1 = CHAR_NULL;
123   }
124 
125   TheTime.Month = (UINT8)ShellStrToUintn (Walker);
126   if (Walker1 != NULL) {
127     Walker = Walker1 + 1;
128   }
129   Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL;
130   if (Walker1 != NULL && *Walker1 == L'/') {
131     *Walker1 = CHAR_NULL;
132   }
133   if (Walker != NULL && Walker[0] != CHAR_NULL) {
134     TheTime.Day = (UINT8)ShellStrToUintn (Walker);
135     if (Walker1 != NULL) {
136       Walker = Walker1 + 1;
137     }
138     Walker1 = Walker!=NULL?StrStr(Walker, L"/"):NULL;
139     if (Walker1 != NULL && *Walker1 == L'/') {
140       *Walker1 = CHAR_NULL;
141     }
142     if (Walker != NULL && Walker[0] != CHAR_NULL) {
143       TheTime.Year = (UINT16)ShellStrToUintn (Walker);
144     }
145   }
146 
147   if (TheTime.Year < 100) {
148     if (TheTime.Year >= 98) {
149       TheTime.Year = (UINT16)(1900 + TheTime.Year);
150     } else {
151       TheTime.Year = (UINT16)(2000 + TheTime.Year);
152     }
153   }
154 
155   Status = gRT->SetTime(&TheTime);
156 
157   if (!EFI_ERROR(Status)){
158     return (SHELL_SUCCESS);
159   }
160   return (SHELL_INVALID_PARAMETER);
161 }
162 
163 /**
164   Function for 'date' command.
165 
166   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
167   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
168 **/
169 SHELL_STATUS
170 EFIAPI
ShellCommandRunDate(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)171 ShellCommandRunDate (
172   IN EFI_HANDLE        ImageHandle,
173   IN EFI_SYSTEM_TABLE  *SystemTable
174   )
175 {
176   EFI_STATUS    Status;
177   LIST_ENTRY    *Package;
178   EFI_TIME      TheTime;
179   CHAR16        *ProblemParam;
180   SHELL_STATUS  ShellStatus;
181   CONST CHAR16  *Param1;
182 
183   ShellStatus  = SHELL_SUCCESS;
184   ProblemParam = NULL;
185 
186   //
187   // initialize the shell lib (we must be in non-auto-init...)
188   //
189   Status = ShellInitialize();
190   ASSERT_EFI_ERROR(Status);
191 
192   //
193   // parse the command line
194   //
195   Status = ShellCommandLineParse (SfoParamList, &Package, &ProblemParam, TRUE);
196   if (EFI_ERROR(Status)) {
197     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
198       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"date", ProblemParam);
199       FreePool(ProblemParam);
200       ShellStatus = SHELL_INVALID_PARAMETER;
201     } else {
202       ASSERT(FALSE);
203     }
204   } else {
205     //
206     // check for "-?"
207     //
208     if (ShellCommandLineGetFlag(Package, L"-?")) {
209       ASSERT(FALSE);
210     } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
211       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date");
212       ShellStatus = SHELL_INVALID_PARAMETER;
213     } else {
214       //
215       // If there are 0 value parameters, then print the current date
216       // else If there are any value paramerers, then print error
217       //
218       if (ShellCommandLineGetRawValue(Package, 1) == NULL) {
219         //
220         // get the current date
221         //
222         Status = gRT->GetTime(&TheTime, NULL);
223         if (EFI_ERROR(Status)) {
224           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"date", L"gRT->GetTime", Status);
225           return (SHELL_DEVICE_ERROR);
226         }
227 
228         //
229         // ShellPrintEx the date in SFO or regular format
230         //
231         if (ShellCommandLineGetFlag(Package, L"-sfo")) {
232           //
233           // Match UEFI Shell spec:
234           // ShellCommand,"date"
235           // Date,"DD","MM","YYYY"
236           //
237           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"date");
238           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DATE_SFO_FORMAT), gShellLevel2HiiHandle, TheTime.Day, TheTime.Month, TheTime.Year);
239         } else {
240           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DATE_FORMAT), gShellLevel2HiiHandle, TheTime.Month, TheTime.Day, TheTime.Year);
241         }
242       } else {
243         if (PcdGet8(PcdShellSupportLevel) == 2) {
244           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"date");
245           ShellStatus = SHELL_INVALID_PARAMETER;
246         } else {
247           //
248           // perform level 3 operation here.
249           //
250           Param1 = ShellCommandLineGetRawValue(Package, 1);
251           if (Param1 == NULL) {
252             ShellStatus = SHELL_INVALID_PARAMETER;
253           } else {
254             ShellStatus = CheckAndSetDate(Param1);
255           }
256           if (ShellStatus != SHELL_SUCCESS) {
257             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"date", Param1);
258             ShellStatus = SHELL_INVALID_PARAMETER;
259           }
260         }
261       }
262     }
263   }
264   //
265   // free the command line package
266   //
267   ShellCommandLineFreeVarList (Package);
268 
269   //
270   // return the status
271   //
272   return (ShellStatus);
273 }
274 
275 //
276 // Note "-tz" is invalid for this (non-interactive) version of 'time'.
277 //
278 STATIC CONST SHELL_PARAM_ITEM TimeParamList2[] = {
279   {L"-d", TypeValue},
280   {NULL, TypeMax}
281   };
282 
283 STATIC CONST SHELL_PARAM_ITEM TimeParamList3[] = {
284   {L"-d", TypeValue},
285   {L"-tz", TypeValue},
286   {NULL, TypeMax}
287   };
288 
289 /**
290   Verify that the TimeString is valid and if so set that as the current
291   time.
292 
293   @param[in] TimeString     The pointer to a string representation of the time.
294   @param[in] Tz             The value to set for TimeZone.
295   @param[in] Daylight       The value to set for Daylight.
296 
297   @retval SHELL_INVALID_PARAMETER   TimeString was NULL.
298   @retval SHELL_INVALID_PARAMETER   TimeString was mis-formatted.
299   @retval SHELL_SUCCESS             The operation was successful.
300 **/
301 SHELL_STATUS
CheckAndSetTime(IN CONST CHAR16 * TimeString,IN CONST INT16 Tz,IN CONST UINT8 Daylight)302 CheckAndSetTime (
303   IN CONST CHAR16 *TimeString,
304   IN CONST INT16  Tz,
305   IN CONST UINT8  Daylight
306   )
307 {
308   EFI_TIME      TheTime;
309   EFI_STATUS    Status;
310   CHAR16        *TimeStringCopy;
311   CHAR16        *Walker1;
312   CHAR16        *Walker2;
313 
314   if (TimeString != NULL && !InternalIsTimeLikeString(TimeString, L':', 1, 2, FALSE)) {
315     return (SHELL_INVALID_PARAMETER);
316   }
317   if (Daylight != 0xFF &&((Daylight & (EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT)) != Daylight)) {
318     return (SHELL_INVALID_PARAMETER);
319   }
320 
321   Status = gRT->GetTime(&TheTime, NULL);
322   if (EFI_ERROR(Status)) {
323     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status);
324     return (SHELL_DEVICE_ERROR);
325   }
326 
327   if (TimeString != NULL) {
328     TimeStringCopy = NULL;
329     TimeStringCopy = StrnCatGrow(&TimeStringCopy, NULL, TimeString, 0);
330     Walker1          = TimeStringCopy;
331     TheTime.Hour    = 0xFF;
332     TheTime.Minute  = 0xFF;
333 
334     Walker2          = Walker1!=NULL?StrStr(Walker1, L":"):NULL;
335     if (Walker2 != NULL && *Walker2 == L':') {
336       *Walker2 = CHAR_NULL;
337     }
338     TheTime.Hour    = (UINT8)ShellStrToUintn (Walker1);
339     if (Walker2 != NULL) {
340       Walker1 = Walker2 + 1;
341     }
342     Walker2          = Walker1!=NULL?StrStr(Walker1, L":"):NULL;
343     if (Walker2 != NULL && *Walker2 == L':') {
344       *Walker2 = CHAR_NULL;
345       TheTime.Second = (UINT8)0;
346     }
347     else if (Walker2 == NULL) {
348       TheTime.Second = (UINT8)0;
349     }
350     if (Walker1 != NULL && Walker1[0] != CHAR_NULL) {
351       TheTime.Minute = (UINT8)ShellStrToUintn (Walker1);
352       if (Walker2 != NULL) {
353         Walker1 = Walker2 + 1;
354         if (Walker1 != NULL && Walker1[0] != CHAR_NULL) {
355           TheTime.Second = (UINT8)ShellStrToUintn (Walker1);
356         }
357       }
358     }
359     SHELL_FREE_NON_NULL(TimeStringCopy);
360   }
361 
362 
363   if (Tz >= -1440 && Tz <= 1440) {
364     //
365     // EFI_TIME TimeZone is stored to meet the following calculation (see UEFI Spec):
366     // Localtime = UTC - TimeZone
367     // This means the sign must be changed for the user provided Tz.
368     // EX: User wants to set TimeZone to Pacific Standard Time, so runs
369     // time -tz -480 # set to UTC-08:00
370     // To meet the calculation, the sign must be changed.
371     //
372     TheTime.TimeZone = -Tz;
373   } else if (Tz == EFI_UNSPECIFIED_TIMEZONE) {
374     TheTime.TimeZone = Tz;
375   }
376 
377   if (Daylight != 0xFF) {
378     TheTime.Daylight = Daylight;
379   }
380 
381   Status = gRT->SetTime(&TheTime);
382 
383   if (!EFI_ERROR(Status)){
384     return (SHELL_SUCCESS);
385   }
386 
387   return (SHELL_INVALID_PARAMETER);
388 }
389 
390 /**
391   Function for 'time' command.
392 
393   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
394   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
395 **/
396 SHELL_STATUS
397 EFIAPI
ShellCommandRunTime(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)398 ShellCommandRunTime (
399   IN EFI_HANDLE        ImageHandle,
400   IN EFI_SYSTEM_TABLE  *SystemTable
401   )
402 {
403   EFI_STATUS    Status;
404   LIST_ENTRY    *Package;
405   EFI_TIME      TheTime;
406   CHAR16        *ProblemParam;
407   SHELL_STATUS  ShellStatus;
408   INT16         Tz;
409   UINT8         Daylight;
410   CONST CHAR16  *TempLocation;
411   UINTN         TzMinutes;
412 
413   //
414   // Initialize variables
415   //
416   ShellStatus  = SHELL_SUCCESS;
417   ProblemParam = NULL;
418 
419   //
420   // initialize the shell lib (we must be in non-auto-init...)
421   //
422   Status = ShellInitialize();
423   ASSERT_EFI_ERROR(Status);
424 
425   //
426   // parse the command line
427   //
428   if (PcdGet8(PcdShellSupportLevel) == 2) {
429     Status = ShellCommandLineParseEx (TimeParamList2, &Package, &ProblemParam, TRUE, TRUE);
430   } else {
431     ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
432     Status = ShellCommandLineParseEx (TimeParamList3, &Package, &ProblemParam, TRUE, TRUE);
433   }
434   if (EFI_ERROR(Status)) {
435     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
436       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"time", ProblemParam);
437       FreePool(ProblemParam);
438       ShellStatus = SHELL_INVALID_PARAMETER;
439     } else {
440       ASSERT(FALSE);
441     }
442   } else {
443     //
444     // check for "-?"
445     //
446     Status = gRT->GetTime(&TheTime, NULL);
447     if (EFI_ERROR(Status)) {
448       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", Status);
449       return (SHELL_DEVICE_ERROR);
450     }
451 
452     if (ShellCommandLineGetFlag(Package, L"-?")) {
453       ASSERT(FALSE);
454     } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
455       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time");
456       ShellStatus = SHELL_INVALID_PARAMETER;
457     } else {
458       //
459       // If there are no parameters, then print the current time
460       //
461       if (ShellCommandLineGetRawValue(Package, 1) == NULL
462         && !ShellCommandLineGetFlag(Package, L"-d")
463         && !ShellCommandLineGetFlag(Package, L"-tz")) {
464         //
465         // ShellPrintEx the current time
466         //
467         if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) {
468           TzMinutes = 0;
469         } else {
470           TzMinutes = (ABS(TheTime.TimeZone)) % 60;
471         }
472 
473         if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
474           ShellPrintHiiEx (
475             -1,
476             -1,
477             NULL,
478             STRING_TOKEN (STR_TIME_FORMAT),
479             gShellLevel2HiiHandle,
480             TheTime.Hour,
481             TheTime.Minute,
482             TheTime.Second,
483             (TheTime.TimeZone > 0?L"-":L"+"),
484             ((ABS(TheTime.TimeZone)) / 60),
485             TzMinutes
486             );
487         } else {
488           ShellPrintHiiEx (
489             -1,
490             -1,
491             NULL,
492             STRING_TOKEN (STR_TIME_FORMAT_LOCAL),
493             gShellLevel2HiiHandle,
494             TheTime.Hour,
495             TheTime.Minute,
496             TheTime.Second
497             );
498         }
499         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF), gShellLevel2HiiHandle);
500       } else if (ShellCommandLineGetFlag(Package, L"-d") && ShellCommandLineGetValue(Package, L"-d") == NULL) {
501         if (TheTime.TimeZone == EFI_UNSPECIFIED_TIMEZONE) {
502           ShellPrintHiiEx (
503             -1,
504             -1,
505             NULL,
506             STRING_TOKEN (STR_TIME_FORMAT_LOCAL),
507             gShellLevel2HiiHandle,
508             TheTime.Hour,
509             TheTime.Minute,
510             TheTime.Second
511             );
512         } else {
513           TzMinutes = (ABS(TheTime.TimeZone)) % 60;
514           ShellPrintHiiEx (
515             -1,
516             -1,
517             NULL,
518             STRING_TOKEN (STR_TIME_FORMAT),
519             gShellLevel2HiiHandle,
520             TheTime.Hour,
521             TheTime.Minute,
522             TheTime.Second,
523             (TheTime.TimeZone > 0?L"-":L"+"),
524             ((ABS(TheTime.TimeZone)) / 60),
525             TzMinutes
526            );
527         }
528           switch (TheTime.Daylight) {
529             case 0:
530               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST0), gShellLevel2HiiHandle);
531               break;
532             case EFI_TIME_ADJUST_DAYLIGHT:
533               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST1), gShellLevel2HiiHandle);
534               break;
535             case EFI_TIME_IN_DAYLIGHT:
536               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST2), gShellLevel2HiiHandle);
537               break;
538             case EFI_TIME_IN_DAYLIGHT|EFI_TIME_ADJUST_DAYLIGHT:
539               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TIME_DST3), gShellLevel2HiiHandle);
540               break;
541             default:
542               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_ERROR), gShellLevel2HiiHandle, L"time", L"gRT->GetTime", L"TheTime.Daylight", TheTime.Daylight);
543           }
544       } else {
545         if (PcdGet8(PcdShellSupportLevel) == 2) {
546           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"time");
547           ShellStatus = SHELL_INVALID_PARAMETER;
548         } else {
549           //
550           // perform level 3 operation here.
551           //
552           if ((TempLocation = ShellCommandLineGetValue(Package, L"-tz")) != NULL) {
553             if (StrniCmp (TempLocation, L"_local", StrLen (TempLocation)) == NULL) {
554               Tz = EFI_UNSPECIFIED_TIMEZONE;
555             } else if (TempLocation[0] == L'-') {
556 
557               Tz = (INT16) ShellStrToUintn (++TempLocation);
558               //
559               // When the argument of "time [-tz tz]" is not numeric, ShellStrToUintn() returns "-1".
560               // Here we can detect the argument error by checking the return of ShellStrToUintn().
561               //
562               if (Tz == -1) {
563                 Tz = 1441; //make it to be out of bounds value
564               } else {
565                 Tz *= (-1); //sign convert
566               }
567             } else {
568               if (TempLocation[0] == L'+') {
569                 Tz = (INT16)ShellStrToUintn (++TempLocation);
570               } else {
571                 Tz = (INT16)ShellStrToUintn (TempLocation);
572               }
573               //
574               // Detect the return of ShellStrToUintn() to make sure the argument is valid.
575               //
576               if (Tz == -1) {
577                 Tz = 1441; //make it to be out of bounds value
578               }
579             }
580             if (!(Tz >= -1440 && Tz <= 1440) && Tz != EFI_UNSPECIFIED_TIMEZONE) {
581               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-tz");
582               ShellStatus = SHELL_INVALID_PARAMETER;
583             }
584           } else {
585             //
586             // intentionally out of bounds value will prevent changing it...
587             //
588             Tz = 1441;
589           }
590           TempLocation = ShellCommandLineGetValue(Package, L"-d");
591           if (TempLocation != NULL) {
592             Daylight = (UINT8)ShellStrToUintn(TempLocation);
593             //
594             // The argument of "time [-d dl]" is unsigned, if the first character is '-',
595             // the argument is incorrect.  That's because ShellStrToUintn() will skip past
596             // any '-' sign and convert what's next, forgetting the sign is here.
597             //
598             if (TempLocation[0] == '-') {
599               Daylight = 0xff; //make it invalid = will not use
600             }
601             if (Daylight != 0 && Daylight != 1 && Daylight != 3) {
602               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"time", TempLocation, L"-d");
603               ShellStatus = SHELL_INVALID_PARAMETER;
604             }
605           } else {
606             //
607             // invalid = will not use
608             //
609             Daylight = 0xFF;
610           }
611           if (ShellStatus == SHELL_SUCCESS) {
612             ShellStatus = CheckAndSetTime(ShellCommandLineGetRawValue(Package, 1), Tz, Daylight);
613             if (ShellStatus != SHELL_SUCCESS) {
614               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"time", ShellCommandLineGetRawValue(Package, 1));
615               ShellStatus = SHELL_INVALID_PARAMETER;
616             }
617           }
618         }
619       }
620     }
621   }
622 
623   //
624   // free the command line package
625   //
626   ShellCommandLineFreeVarList (Package);
627 
628   //
629   // return the status
630   //
631   return (ShellStatus);
632 }
633 
634 typedef struct {
635   INT16         TimeZone;
636   EFI_STRING_ID StringId;
637 } TIME_ZONE_ITEM;
638 
639 STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList2[] = {
640   {L"-l", TypeFlag},
641   {L"-f", TypeFlag},
642   {NULL, TypeMax}
643   };
644 STATIC CONST SHELL_PARAM_ITEM TimeZoneParamList3[] = {
645   {L"-l", TypeFlag},
646   {L"-f", TypeFlag},
647   {L"-s", TypeTimeValue},
648   {NULL, TypeMax}
649   };
650 
651   STATIC CONST TIME_ZONE_ITEM TimeZoneList[] = {
652     {720, STRING_TOKEN (STR_TIMEZONE_M12)},
653     {660, STRING_TOKEN (STR_TIMEZONE_M11)},
654     {600, STRING_TOKEN (STR_TIMEZONE_M10)},
655     {540, STRING_TOKEN (STR_TIMEZONE_M9)},
656     {480, STRING_TOKEN (STR_TIMEZONE_M8)},
657     {420, STRING_TOKEN (STR_TIMEZONE_M7)},
658     {360, STRING_TOKEN (STR_TIMEZONE_M6)},
659     {300, STRING_TOKEN (STR_TIMEZONE_M5)},
660     {270, STRING_TOKEN (STR_TIMEZONE_M430)},
661     {240, STRING_TOKEN (STR_TIMEZONE_M4)},
662     {210, STRING_TOKEN (STR_TIMEZONE_M330)},
663     {180, STRING_TOKEN (STR_TIMEZONE_M3)},
664     {120, STRING_TOKEN (STR_TIMEZONE_M2)},
665     {60 , STRING_TOKEN (STR_TIMEZONE_M1)},
666     {0   , STRING_TOKEN (STR_TIMEZONE_0)},
667     {-60  , STRING_TOKEN (STR_TIMEZONE_P1)},
668     {-120 , STRING_TOKEN (STR_TIMEZONE_P2)},
669     {-180 , STRING_TOKEN (STR_TIMEZONE_P3)},
670     {-210 , STRING_TOKEN (STR_TIMEZONE_P330)},
671     {-240 , STRING_TOKEN (STR_TIMEZONE_P4)},
672     {-270 , STRING_TOKEN (STR_TIMEZONE_P430)},
673     {-300 , STRING_TOKEN (STR_TIMEZONE_P5)},
674     {-330 , STRING_TOKEN (STR_TIMEZONE_P530)},
675     {-345 , STRING_TOKEN (STR_TIMEZONE_P545)},
676     {-360 , STRING_TOKEN (STR_TIMEZONE_P6)},
677     {-390 , STRING_TOKEN (STR_TIMEZONE_P630)},
678     {-420 , STRING_TOKEN (STR_TIMEZONE_P7)},
679     {-480 , STRING_TOKEN (STR_TIMEZONE_P8)},
680     {-540 , STRING_TOKEN (STR_TIMEZONE_P9)},
681     {-570 , STRING_TOKEN (STR_TIMEZONE_P930)},
682     {-600 , STRING_TOKEN (STR_TIMEZONE_P10)},
683     {-660 , STRING_TOKEN (STR_TIMEZONE_P11)},
684     {-720 , STRING_TOKEN (STR_TIMEZONE_P12)},
685     {-780 , STRING_TOKEN (STR_TIMEZONE_P13)},
686     {-840 , STRING_TOKEN (STR_TIMEZONE_P14)},
687     {EFI_UNSPECIFIED_TIMEZONE, STRING_TOKEN (STR_TIMEZONE_LOCAL)}
688 };
689 
690 /**
691   Verify that the TimeZoneString is valid and if so set that as the current
692   timezone.
693 
694   @param[in] TimeZoneString     The pointer to a string representation of the timezone.
695 
696   @retval SHELL_INVALID_PARAMETER   TimeZoneString was NULL.
697   @retval SHELL_INVALID_PARAMETER   TimeZoneString was mis-formatted.
698   @retval SHELL_SUCCESS             The operation was successful.
699 **/
700 SHELL_STATUS
CheckAndSetTimeZone(IN CONST CHAR16 * TimeZoneString)701 CheckAndSetTimeZone (
702   IN CONST CHAR16 *TimeZoneString
703   )
704 {
705   EFI_TIME      TheTime;
706   EFI_STATUS    Status;
707   CHAR16        *TimeZoneCopy;
708   CHAR16        *Walker;
709   CHAR16        *Walker2;
710   UINTN         LoopVar;
711 
712   if (TimeZoneString == NULL) {
713     return (SHELL_INVALID_PARAMETER);
714   }
715 
716   if (StrniCmp (TimeZoneString, L"_local", StrLen (TimeZoneString)) == NULL) {
717     Status = gRT->GetTime (&TheTime, NULL);
718     if (EFI_ERROR (Status)) {
719       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"gRT->GetTime", Status);
720       return (SHELL_DEVICE_ERROR);
721     }
722 
723     TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
724     Status = gRT->SetTime (&TheTime);
725     if (!EFI_ERROR(Status)){
726       return (SHELL_SUCCESS);
727     }
728     return (SHELL_INVALID_PARAMETER);
729   }
730   if (TimeZoneString != NULL && !InternalIsTimeLikeString(TimeZoneString, L':', 1, 1, TRUE)) {
731     return (SHELL_INVALID_PARAMETER);
732   }
733 
734   Status = gRT->GetTime(&TheTime, NULL);
735   if (EFI_ERROR(Status)) {
736     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status);
737     return (SHELL_DEVICE_ERROR);
738   }
739 
740   TimeZoneCopy = NULL;
741   TimeZoneCopy = StrnCatGrow(&TimeZoneCopy, NULL, TimeZoneString, 0);
742   if (TimeZoneCopy == NULL) {
743     return (SHELL_OUT_OF_RESOURCES);
744   }
745   Walker = TimeZoneCopy;
746   Walker2 = StrStr(Walker, L":");
747   if (Walker2 != NULL && *Walker2 == L':') {
748     *Walker2 = CHAR_NULL;
749   }
750   if (*Walker == L'-') {
751     TheTime.TimeZone = (INT16)((ShellStrToUintn (++Walker)) * 60);
752   } else {
753     TheTime.TimeZone = (INT16)((INT16)(ShellStrToUintn (Walker)) * -60);
754   }
755   if (Walker2 != NULL) {
756     Walker = Walker2 + 1;
757   }
758   if (Walker != NULL && Walker[0] != CHAR_NULL) {
759     if (TheTime.TimeZone < 0) {
760       TheTime.TimeZone = (INT16)(TheTime.TimeZone - (UINT8)ShellStrToUintn (Walker));
761     } else {
762       TheTime.TimeZone = (INT16)(TheTime.TimeZone + (UINT8)ShellStrToUintn (Walker));
763     }
764   }
765 
766   Status = EFI_INVALID_PARAMETER;
767 
768   for ( LoopVar = 0
769       ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
770       ; LoopVar++
771      ){
772     if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
773         Status = gRT->SetTime(&TheTime);
774         break;
775     }
776   }
777 
778   FreePool(TimeZoneCopy);
779 
780   if (!EFI_ERROR(Status)){
781     return (SHELL_SUCCESS);
782   }
783   return (SHELL_INVALID_PARAMETER);
784 }
785 
786 
787 /**
788   Function for 'timezone' command.
789 
790   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
791   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
792 **/
793 SHELL_STATUS
794 EFIAPI
ShellCommandRunTimeZone(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)795 ShellCommandRunTimeZone (
796   IN EFI_HANDLE        ImageHandle,
797   IN EFI_SYSTEM_TABLE  *SystemTable
798   )
799 {
800   //
801   // non interactive
802   //
803   EFI_STATUS    Status;
804   LIST_ENTRY    *Package;
805   CHAR16        *ProblemParam;
806   SHELL_STATUS  ShellStatus;
807   UINT8         LoopVar;
808   EFI_TIME      TheTime;
809   BOOLEAN       Found;
810   UINTN         TzMinutes;
811 
812   ShellStatus  = SHELL_SUCCESS;
813   ProblemParam = NULL;
814 
815   //
816   // initialize the shell lib (we must be in non-auto-init...)
817   //
818   Status = ShellInitialize();
819   ASSERT_EFI_ERROR(Status);
820 
821   //
822   // parse the command line
823   //
824   if (PcdGet8(PcdShellSupportLevel) == 2) {
825     Status = ShellCommandLineParse (TimeZoneParamList2, &Package, &ProblemParam, TRUE);
826   } else {
827     ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
828     Status = ShellCommandLineParseEx (TimeZoneParamList3, &Package, &ProblemParam, TRUE, TRUE);
829   }
830   if (EFI_ERROR(Status)) {
831     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
832       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"timezone", ProblemParam);
833       FreePool(ProblemParam);
834       ShellStatus = SHELL_INVALID_PARAMETER;
835     } else {
836       ASSERT(FALSE);
837     }
838   } else {
839     //
840     // check for "-?"
841     //
842     if (ShellCommandLineGetCount(Package) > 1) {
843       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"timezone");
844       ShellStatus = SHELL_INVALID_PARAMETER;
845     } else if (ShellCommandLineGetFlag(Package, L"-?")) {
846       ASSERT(FALSE);
847     } else if (ShellCommandLineGetFlag(Package, L"-s")) {
848       if ((ShellCommandLineGetFlag(Package, L"-l")) || (ShellCommandLineGetFlag(Package, L"-f"))) {
849         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", L"-l or -f");
850         ShellStatus = SHELL_INVALID_PARAMETER;
851       } else {
852         ASSERT(PcdGet8(PcdShellSupportLevel) == 3);
853         if (ShellCommandLineGetValue(Package, L"-s") == NULL) {
854           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"timezone", L"-s");
855           ShellStatus = SHELL_INVALID_PARAMETER;
856         } else {
857           //
858           // Set the time zone
859           //
860           ShellStatus = CheckAndSetTimeZone(ShellCommandLineGetValue(Package, L"-s"));
861           if (ShellStatus != SHELL_SUCCESS) {
862             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"timezone", ShellCommandLineGetValue(Package, L"-s"));
863             ShellStatus = SHELL_INVALID_PARAMETER;
864           }
865         }
866       }
867     } else if (ShellCommandLineGetFlag(Package, L"-l")) {
868       //
869       // Print a list of all time zones
870       //
871       for ( LoopVar = 0
872           ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
873           ; LoopVar++
874          ){
875         ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
876       }
877     } else {
878       //
879       // Get Current Time Zone Info
880       //
881       Status = gRT->GetTime(&TheTime, NULL);
882       if (EFI_ERROR(Status)) {
883         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"timezone", L"gRT->GetTime", Status);
884         return (SHELL_DEVICE_ERROR);
885       }
886 
887       if (TheTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) {
888         Found = FALSE;
889         for ( LoopVar = 0
890             ; LoopVar < sizeof(TimeZoneList) / sizeof(TimeZoneList[0])
891             ; LoopVar++
892            ){
893           if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
894             if (ShellCommandLineGetFlag(Package, L"-f")) {
895               //
896               //  Print all info about current time zone
897               //
898               ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
899             } else {
900               //
901               // Print basic info only
902               //
903               TzMinutes = (ABS(TheTime.TimeZone)) % 60;
904 
905               ShellPrintHiiEx (
906                 -1,
907                 -1,
908                 NULL,
909                 STRING_TOKEN(STR_TIMEZONE_SIMPLE),
910                 gShellLevel2HiiHandle,
911                 (TheTime.TimeZone > 0?L"-":L"+"),
912                 (ABS(TheTime.TimeZone)) / 60,
913                 TzMinutes);
914             }
915             Found = TRUE;
916             break;
917           }
918         }
919         if (!Found) {
920           //
921           // Print basic info only
922           //
923           TzMinutes = (ABS(TheTime.TimeZone)) % 60;
924 
925           ShellPrintHiiEx (
926             -1,
927             -1,
928             NULL,
929             STRING_TOKEN(STR_TIMEZONE_SIMPLE),
930             gShellLevel2HiiHandle,
931             (TheTime.TimeZone > 0?L"-":L"+"),
932             (ABS(TheTime.TimeZone)) / 60,
933             TzMinutes);
934 
935           if (ShellCommandLineGetFlag(Package, L"-f")) {
936             ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_TIMEZONE_NI), gShellLevel2HiiHandle);
937           }
938         }
939       } else {
940         //
941         // TimeZone was EFI_UNSPECIFIED_TIMEZONE (local) from GetTime()
942         //
943         if (ShellCommandLineGetFlag (Package, L"-f")) {
944           for ( LoopVar = 0
945               ; LoopVar < ARRAY_SIZE (TimeZoneList)
946               ; LoopVar++
947              ){
948             if (TheTime.TimeZone == TimeZoneList[LoopVar].TimeZone) {
949               //
950               //  Print all info about current time zone
951               //
952               ShellPrintHiiEx (-1, -1, NULL, TimeZoneList[LoopVar].StringId, gShellLevel2HiiHandle);
953               break;
954             }
955           }
956         } else {
957           //
958           // Print basic info only
959           //
960           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_TIMEZONE_SIMPLE_LOCAL), gShellLevel2HiiHandle);
961         }
962       }
963     }
964   }
965 
966   //
967   // free the command line package
968   //
969   ShellCommandLineFreeVarList (Package);
970 
971   return (ShellStatus);
972 }
973