• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "shcmd.h"
33 #include "shell.h"
34 #include "stdlib.h"
35 #include "time.h"
36 #include "los_typedef.h"
37 #include "sys/stat.h"
38 #include "securec.h"
39 
40 #if defined(__LP64__)
41 #define  timeval64      timeval
42 #define  settimeofday64 settimeofday
43 #define  gettimeofday64 gettimeofday
44 #endif
45 
46 #define  localtime64    localtime
47 #define  ctime64        ctime
48 #define  mktime64       mktime
49 
50 #define  DATE_ERR_INFO      1
51 #define  DATE_HELP_INFO     0
52 #define  DATE_ERR           (-1)
53 #define  DATE_OK            0
54 #define  DATE_BASE_YEAR     1900
55 #define  LEAPYEAR(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
56 
57 STATIC const INT32 g_monLengths[2][12] = { /* 2: 2 Column,Contains leap year; 12: 12 months */
58     {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
59     {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
60 };
61 
OsCopyTm(struct tm * destTm,const struct tm * srcTm)62 STATIC VOID OsCopyTm(struct tm *destTm, const struct tm *srcTm)
63 {
64     if (srcTm == NULL) {
65         (VOID)memset_s(destTm, sizeof(struct tm), 0, sizeof(struct tm));
66     } else {
67         destTm->tm_sec = srcTm->tm_sec;
68         destTm->tm_min = srcTm->tm_min;
69         destTm->tm_hour = srcTm->tm_hour;
70         destTm->tm_mday = srcTm->tm_mday;
71         destTm->tm_mon = srcTm->tm_mon;
72         destTm->tm_year = srcTm->tm_year;
73         destTm->tm_wday = srcTm->tm_wday;
74         destTm->tm_yday = srcTm->tm_yday;
75         destTm->tm_isdst = srcTm->tm_isdst;
76         destTm->tm_gmtoff = srcTm->tm_gmtoff;
77         destTm->tm_zone = srcTm->tm_zone;
78     }
79 }
80 
OsCmdUsageDate(INT32 order)81 STATIC VOID OsCmdUsageDate(INT32 order)
82 {
83     if (order) {
84         PRINTK("date: invalid option or parameter.\n");
85         PRINTK("Try 'date --help' for more information.\n");
86         return;
87     }
88     PRINTK("\nUsage: date [+FORMAT]\n");
89     PRINTK("   or: date [-s] [YY/MM/DD] [hh:mm:ss]\n");
90     PRINTK("Display the current time in the given FORMAT, or set the system date.\n");
91     PRINTK("FORMAT controls the output.  Interpreted sequences are:\n");
92     PRINTK("  %%b     The abbreviated month name according to the current locale.\n");
93     PRINTK("  %%B     The full month name according to the current locale.\n");
94     PRINTK("  %%C     The century number (year/100) as a 2-digit integer. (SU)\n");
95     PRINTK("  %%d     The day of the month as a decimal number (range 01 to 31).\n");
96     PRINTK("  %%e     Like %%d, the day of the month as a decimal number, \n");
97     PRINTK("         but a leading zero is replaced by a space.\n");
98     PRINTK("  %%h     Equivalent to %%b.  (SU)\n");
99     PRINTK("  %%H     The hour as a decimal number using a 24-hour clock (range 00 to 23).\n");
100     PRINTK("  %%I     The  hour as a decimal number using a 12-hour clock (range 01 to 12).\n");
101     PRINTK("  %%j     The day of the year as a decimal number (range 001 to 366).\n");
102     PRINTK("  %%k     The hour (24-hour clock) as a decimal number (range  0  to  23); \n");
103     PRINTK("         single digits are preceded by a blank.  (See also %H.)  (TZ)\n");
104     PRINTK("  %%l     The  hour  (12-hour  clock) as a decimal number (range 1 to 12); \n");
105     PRINTK("         single digits are preceded by a blank.  (See also %I.)  (TZ)\n");
106     PRINTK("  %%m     The month as a decimal number (range 01 to 12).\n");
107     PRINTK("  %%M     The minute as a decimal number (range 00 to 59).\n");
108     PRINTK("  %%n     A newline character. (SU)\n");
109     PRINTK("  %%p     Either \"AM\" or \"PM\" according to the given time  value, \n");
110     PRINTK("         or the corresponding  strings  for the current locale.\n");
111     PRINTK("         Noon is treated as \"PM\" and midnight as \"AM\".\n");
112     PRINTK("  %%P     Like %%p but in lowercase: \"am\" or \"pm\" \n");
113     PRINTK("         or a corresponding string for the current locale. (GNU)\n");
114     PRINTK("  %%s     The number of seconds since the Epoch, that is,\n");
115     PRINTK("         since 1970-01-01 00:00:00 UTC. (TZ)\n");
116     PRINTK("  %%S     The second as a decimal number (range 00 to 60).\n");
117     PRINTK("         (The range is up to 60 to allow for occasional leap seconds.)\n");
118     PRINTK("  %%t     A tab character. (SU)\n");
119     PRINTK("  %%y     The year as a decimal number without a century (range 00 to 99).\n");
120     PRINTK("  %%Y     The year as a decimal number including the century.\n");
121     PRINTK("  %%%%     A literal '%%' character.\n");
122     PRINTK("\nExamples:\n");
123     PRINTK("Set system date (2017-01-01)\n");
124     PRINTK("$ date -s 20170101\n");
125     PRINTK("Set system time (12:00:00)\n");
126     PRINTK("$ date -s 12:00:00\n");
127     PRINTK("Show the time with format Year-Month-Day\n");
128     PRINTK("$ date +%%Y-%%m-%%d\n");
129 }
130 
OsStrToTm(const CHAR * str,struct tm * tm)131 STATIC INT32 OsStrToTm(const CHAR *str, struct tm *tm)
132 {
133     CHAR *ret = NULL;
134     UINT32 strLen = strlen(str);
135     if (strLen == 8) { /* 8:Time format string length, such as hh:mm:ss or yyyymmdd */
136         if (str[2] == ':') { /* 2:Index of Eigenvalues */
137             ret = strptime(str, "%H:%M:%S", tm);
138         } else {
139             ret = strptime(str, "%Y%m%d", tm);
140         }
141     } else if (strLen == 10) { /* 10:Time format string length,such as yyyy/mm/dd  */
142         ret = strptime(str, "%Y/%m/%d", tm);
143     } else if (strLen == 5) { /* 5:Time format string length,such as hh:mm or mm/dd */
144         if (str[2] == ':') { /* 2:Index of Eigenvalues */
145             ret = strptime(str, "%H:%M", tm);
146         } else if (str[2] == '/') { /* 2:Index of Eigenvalues */
147             ret = strptime(str, "%m/%d", tm);
148         }
149     } else if (strLen == 7) { /* 7:Time format string length,such as yyyy/mm */
150         if (str[4] == '/') { /* 4:Index of Eigenvalues */
151             ret = strptime(str, "%Y/%m", tm);
152         }
153     }
154 
155     if (tm->tm_year < 70) { /* 70:the year is starting in 1970,tm_year must be greater than 70 */
156         PRINTK("\nUsage: date -s set system time starting from 1970.\n");
157         return DATE_ERR;
158     }
159 
160     if (tm->tm_mday > g_monLengths[(INT32)LEAPYEAR(tm->tm_year + DATE_BASE_YEAR)][tm->tm_mon]) {
161         return DATE_ERR;
162     }
163 
164     if ((tm->tm_sec < 0) || (tm->tm_sec > 59)) { /* Seconds (0-59), leap seconds shall not be used when set time. */
165         return DATE_ERR;
166     }
167     return (ret == NULL) ? DATE_ERR : DATE_OK;
168 }
169 
OsFormatPrintTime(const CHAR * formatStr)170 STATIC INT32 OsFormatPrintTime(const CHAR *formatStr)
171 {
172     CHAR timebuf[SHOW_MAX_LEN] = {0};
173     struct tm *tm = NULL;
174     struct timeval64 nowTime = {0};
175 
176     if (strlen(formatStr) < 2) { /* 2:check format string length */
177         OsCmdUsageDate(DATE_ERR_INFO);
178         return DATE_ERR;
179     }
180 
181     if (gettimeofday64(&nowTime, NULL)) {
182         return DATE_ERR;
183     }
184     tm = localtime64(&nowTime.tv_sec);
185     if (tm == NULL) {
186         return DATE_ERR;
187     }
188 
189     if (strftime(timebuf, SHOW_MAX_LEN - 1, formatStr + 1, tm)) {
190         PRINTK("%s\n", timebuf);
191     } else {
192         OsCmdUsageDate(DATE_ERR_INFO);
193         return DATE_ERR;
194     }
195     return DATE_OK;
196 }
197 
OsDateSetTime(const CHAR * timeStr)198 STATIC INT32 OsDateSetTime(const CHAR *timeStr)
199 {
200     struct tm tm = {0};
201     struct timeval64 nowTime = {0};
202     struct timeval64 setTime = {0};
203 
204     if (gettimeofday64(&nowTime, NULL)) {
205         PRINTK("Setting time failed...\n");
206         return DATE_ERR;
207     }
208 
209     setTime.tv_usec = nowTime.tv_usec;
210     OsCopyTm(&tm, localtime64(&nowTime.tv_sec));
211 
212     if (OsStrToTm(timeStr, &tm)) {
213         OsCmdUsageDate(DATE_ERR_INFO);
214         return DATE_ERR;
215     }
216 
217     setTime.tv_sec = mktime64(&tm);
218 
219     if (settimeofday64(&setTime, NULL)) {
220         PRINTK("setting time failed...\n");
221         return DATE_ERR;
222     }
223 
224     return DATE_OK;
225 }
226 
227 #ifdef  LOSCFG_FS_VFS
OsViewFileTime(const CHAR * filename)228 STATIC INT32 OsViewFileTime(const CHAR *filename)
229 {
230 #define BUFFER_SIZE 26 /* The buffer size is equal to the size used by the asctime_r interface */
231     struct stat statBuf = {0};
232     CHAR *fullpath = NULL;
233     INT32 ret;
234     CHAR buf[BUFFER_SIZE];
235     CHAR *shellWorkingDirectory = OsShellGetWorkingDirectory();
236 
237     ret = vfs_normalize_path(shellWorkingDirectory, filename, &fullpath);
238     if (ret < 0) {
239         set_errno(-ret);
240         perror("date error");
241         return DATE_ERR;
242     }
243 
244     if (stat(fullpath, &statBuf) != 0) {
245         OsCmdUsageDate(DATE_ERR_INFO);
246         free(fullpath);
247         return DATE_ERR;
248     }
249     PRINTK("%s\n", ctime_r(&(statBuf.st_mtim.tv_sec), buf));
250     free(fullpath);
251     return DATE_OK;
252 }
253 #endif
254 
OsShellCmdDate(INT32 argc,const CHAR ** argv)255 INT32 OsShellCmdDate(INT32 argc, const CHAR **argv)
256 {
257     struct timeval64 nowTime = {0};
258 
259     if (argc == 1) { /* 1:count of parameters */
260         if (gettimeofday64(&nowTime, NULL)) {
261             return DATE_ERR;
262         }
263         PRINTK("%s\n", ctime64(&nowTime.tv_sec));
264         return DATE_OK;
265     }
266 
267     if (argc == 2) { /* 2:count of parameters */
268         if (argv == NULL) {
269             OsCmdUsageDate(DATE_HELP_INFO);
270             return DATE_ERR;
271         }
272 
273         if (!(strcmp(argv[1], "--help"))) {
274             OsCmdUsageDate(DATE_HELP_INFO);
275             return DATE_OK;
276         }
277         if (!(strncmp(argv[1], "+", 1))) {
278             return OsFormatPrintTime(argv[1]);
279         }
280     }
281 
282     if (argc > 2) { /* 2:count of parameters */
283         if (argv == NULL) {
284             OsCmdUsageDate(DATE_HELP_INFO);
285             return DATE_ERR;
286         }
287 
288         if (!(strcmp(argv[1], "-s"))) {
289             return OsDateSetTime(argv[2]); /* 2:index of parameters */
290         } else if (!(strcmp(argv[1], "-r"))) {
291 #ifdef  LOSCFG_FS_VFS
292             return OsViewFileTime(argv[2]); /* 2:index of parameters */
293 #endif
294         }
295     }
296 
297     OsCmdUsageDate(DATE_ERR_INFO);
298     return DATE_OK;
299 }
300 
301 SHELLCMD_ENTRY(date_shellcmd, CMD_TYPE_STD, "date", XARGS, (CmdCallBackFunc)OsShellCmdDate);
302