chiark / gitweb /
silent a few more gcc warnings
[elogind.git] / src / shared / time-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <time.h>
23 #include <string.h>
24 #include <sys/timex.h>
25
26 #include "util.h"
27 #include "time-util.h"
28
29 usec_t now(clockid_t clock_id) {
30         struct timespec ts;
31
32         assert_se(clock_gettime(clock_id, &ts) == 0);
33
34         return timespec_load(&ts);
35 }
36
37 dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
38         assert(ts);
39
40         ts->realtime = now(CLOCK_REALTIME);
41         ts->monotonic = now(CLOCK_MONOTONIC);
42
43         return ts;
44 }
45
46 dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
47         int64_t delta;
48         assert(ts);
49
50         if (u == (usec_t) -1) {
51                 ts->realtime = ts->monotonic = (usec_t) -1;
52                 return ts;
53         }
54
55         ts->realtime = u;
56
57         if (u == 0)
58                 ts->monotonic = 0;
59         else {
60                 delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
61
62                 ts->monotonic = now(CLOCK_MONOTONIC);
63
64                 if ((int64_t) ts->monotonic > delta)
65                         ts->monotonic -= delta;
66                 else
67                         ts->monotonic = 0;
68         }
69
70         return ts;
71 }
72
73 dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
74         int64_t delta;
75         assert(ts);
76
77         if (u == (usec_t) -1) {
78                 ts->realtime = ts->monotonic = (usec_t) -1;
79                 return ts;
80         }
81
82         ts->monotonic = u;
83         delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u;
84
85         ts->realtime = now(CLOCK_REALTIME);
86         if ((int64_t) ts->realtime > delta)
87                 ts->realtime -= delta;
88         else
89                 ts->realtime = 0;
90
91         return ts;
92 }
93
94 usec_t timespec_load(const struct timespec *ts) {
95         assert(ts);
96
97         if (ts->tv_sec == (time_t) -1 &&
98             ts->tv_nsec == (long) -1)
99                 return (usec_t) -1;
100
101         if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
102                 return (usec_t) -1;
103
104         return
105                 (usec_t) ts->tv_sec * USEC_PER_SEC +
106                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
107 }
108
109 struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
110         assert(ts);
111
112         if (u == (usec_t) -1) {
113                 ts->tv_sec = (time_t) -1;
114                 ts->tv_nsec = (long) -1;
115                 return ts;
116         }
117
118         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
119         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
120
121         return ts;
122 }
123
124 usec_t timeval_load(const struct timeval *tv) {
125         assert(tv);
126
127         if (tv->tv_sec == (time_t) -1 &&
128             tv->tv_usec == (suseconds_t) -1)
129                 return (usec_t) -1;
130
131         if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC)
132                 return (usec_t) -1;
133
134         return
135                 (usec_t) tv->tv_sec * USEC_PER_SEC +
136                 (usec_t) tv->tv_usec;
137 }
138
139 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
140         assert(tv);
141
142         if (u == (usec_t) -1) {
143                 tv->tv_sec = (time_t) -1;
144                 tv->tv_usec = (suseconds_t) -1;
145                 return tv;
146         }
147
148         tv->tv_sec = (time_t) (u / USEC_PER_SEC);
149         tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
150
151         return tv;
152 }
153
154 char *format_timestamp(char *buf, size_t l, usec_t t) {
155         struct tm tm;
156         time_t sec;
157
158         assert(buf);
159         assert(l > 0);
160
161         if (t <= 0)
162                 return NULL;
163
164         sec = (time_t) (t / USEC_PER_SEC);
165
166         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0)
167                 return NULL;
168
169         return buf;
170 }
171
172 char *format_timestamp_us(char *buf, size_t l, usec_t t) {
173         struct tm tm;
174         time_t sec;
175
176         assert(buf);
177         assert(l > 0);
178
179         if (t <= 0)
180                 return NULL;
181
182         sec = (time_t) (t / USEC_PER_SEC);
183         localtime_r(&sec, &tm);
184
185         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
186                 return NULL;
187         snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", t % USEC_PER_SEC);
188         if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0)
189                 return NULL;
190
191         return buf;
192 }
193
194 char *format_timestamp_relative(char *buf, size_t l, usec_t t) {
195         usec_t n, d;
196
197         n = now(CLOCK_REALTIME);
198
199         if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t)
200                 return NULL;
201
202         d = n - t;
203
204         if (d >= USEC_PER_YEAR)
205                 snprintf(buf, l, "%llu years %llu months ago",
206                          (unsigned long long) (d / USEC_PER_YEAR),
207                          (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH));
208         else if (d >= USEC_PER_MONTH)
209                 snprintf(buf, l, "%llu months %llu days ago",
210                          (unsigned long long) (d / USEC_PER_MONTH),
211                          (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY));
212         else if (d >= USEC_PER_WEEK)
213                 snprintf(buf, l, "%llu weeks %llu days ago",
214                          (unsigned long long) (d / USEC_PER_WEEK),
215                          (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY));
216         else if (d >= 2*USEC_PER_DAY)
217                 snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY));
218         else if (d >= 25*USEC_PER_HOUR)
219                 snprintf(buf, l, "1 day %lluh ago",
220                          (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR));
221         else if (d >= 6*USEC_PER_HOUR)
222                 snprintf(buf, l, "%lluh ago",
223                          (unsigned long long) (d / USEC_PER_HOUR));
224         else if (d >= USEC_PER_HOUR)
225                 snprintf(buf, l, "%lluh %llumin ago",
226                          (unsigned long long) (d / USEC_PER_HOUR),
227                          (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE));
228         else if (d >= 5*USEC_PER_MINUTE)
229                 snprintf(buf, l, "%llumin ago",
230                          (unsigned long long) (d / USEC_PER_MINUTE));
231         else if (d >= USEC_PER_MINUTE)
232                 snprintf(buf, l, "%llumin %llus ago",
233                          (unsigned long long) (d / USEC_PER_MINUTE),
234                          (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC));
235         else if (d >= USEC_PER_SEC)
236                 snprintf(buf, l, "%llus ago",
237                          (unsigned long long) (d / USEC_PER_SEC));
238         else if (d >= USEC_PER_MSEC)
239                 snprintf(buf, l, "%llums ago",
240                          (unsigned long long) (d / USEC_PER_MSEC));
241         else if (d > 0)
242                 snprintf(buf, l, "%lluus ago",
243                          (unsigned long long) d);
244         else
245                 snprintf(buf, l, "now");
246
247         buf[l-1] = 0;
248         return buf;
249 }
250
251 char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) {
252         static const struct {
253                 const char *suffix;
254                 usec_t usec;
255         } table[] = {
256                 { "y", USEC_PER_YEAR },
257                 { "month", USEC_PER_MONTH },
258                 { "w", USEC_PER_WEEK },
259                 { "d", USEC_PER_DAY },
260                 { "h", USEC_PER_HOUR },
261                 { "min", USEC_PER_MINUTE },
262                 { "s", USEC_PER_SEC },
263                 { "ms", USEC_PER_MSEC },
264                 { "us", 1 },
265         };
266
267         unsigned i;
268         char *p = buf;
269         bool something = false;
270
271         assert(buf);
272         assert(l > 0);
273
274         if (t == (usec_t) -1)
275                 return NULL;
276
277         if (t <= 0) {
278                 snprintf(p, l, "0");
279                 p[l-1] = 0;
280                 return p;
281         }
282
283         /* The result of this function can be parsed with parse_sec */
284
285         for (i = 0; i < ELEMENTSOF(table); i++) {
286                 int k = 0;
287                 size_t n;
288                 bool done = false;
289                 usec_t a, b;
290
291                 if (t <= 0)
292                         break;
293
294                 if (t < accuracy && something)
295                         break;
296
297                 if (t < table[i].usec)
298                         continue;
299
300                 if (l <= 1)
301                         break;
302
303                 a = t / table[i].usec;
304                 b = t % table[i].usec;
305
306                 /* Let's see if we should shows this in dot notation */
307                 if (t < USEC_PER_MINUTE && b > 0) {
308                         usec_t cc;
309                         int j;
310
311                         j = 0;
312                         for (cc = table[i].usec; cc > 1; cc /= 10)
313                                 j++;
314
315                         for (cc = accuracy; cc > 1; cc /= 10) {
316                                 b /= 10;
317                                 j--;
318                         }
319
320                         if (j > 0) {
321                                 k = snprintf(p, l,
322                                              "%s%llu.%0*llu%s",
323                                              p > buf ? " " : "",
324                                              (unsigned long long) a,
325                                              j,
326                                              (unsigned long long) b,
327                                              table[i].suffix);
328
329                                 t = 0;
330                                 done = true;
331                         }
332                 }
333
334                 /* No? Then let's show it normally */
335                 if (!done) {
336                         k = snprintf(p, l,
337                                      "%s%llu%s",
338                                      p > buf ? " " : "",
339                                      (unsigned long long) a,
340                                      table[i].suffix);
341
342                         t = b;
343                 }
344
345                 n = MIN((size_t) k, l);
346
347                 l -= n;
348                 p += n;
349
350                 something = true;
351         }
352
353         *p = 0;
354
355         return buf;
356 }
357
358 void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
359
360         assert(f);
361         assert(name);
362         assert(t);
363
364         if (!dual_timestamp_is_set(t))
365                 return;
366
367         fprintf(f, "%s=%llu %llu\n",
368                 name,
369                 (unsigned long long) t->realtime,
370                 (unsigned long long) t->monotonic);
371 }
372
373 void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
374         unsigned long long a, b;
375
376         assert(value);
377         assert(t);
378
379         if (sscanf(value, "%lli %llu", &a, &b) != 2)
380                 log_debug("Failed to parse finish timestamp value %s", value);
381         else {
382                 t->realtime = a;
383                 t->monotonic = b;
384         }
385 }
386
387 int parse_timestamp(const char *t, usec_t *usec) {
388         static const struct {
389                 const char *name;
390                 const int nr;
391         } day_nr[] = {
392                 { "Sunday",    0 },
393                 { "Sun",       0 },
394                 { "Monday",    1 },
395                 { "Mon",       1 },
396                 { "Tuesday",   2 },
397                 { "Tue",       2 },
398                 { "Wednesday", 3 },
399                 { "Wed",       3 },
400                 { "Thursday",  4 },
401                 { "Thu",       4 },
402                 { "Friday",    5 },
403                 { "Fri",       5 },
404                 { "Saturday",  6 },
405                 { "Sat",       6 },
406         };
407
408         const char *k;
409         struct tm tm, copy;
410         time_t x;
411         usec_t plus = 0, minus = 0, ret;
412         int r, weekday = -1;
413         unsigned i;
414
415         /*
416          * Allowed syntaxes:
417          *
418          *   2012-09-22 16:34:22
419          *   2012-09-22 16:34     (seconds will be set to 0)
420          *   2012-09-22           (time will be set to 00:00:00)
421          *   16:34:22             (date will be set to today)
422          *   16:34                (date will be set to today, seconds to 0)
423          *   now
424          *   yesterday            (time is set to 00:00:00)
425          *   today                (time is set to 00:00:00)
426          *   tomorrow             (time is set to 00:00:00)
427          *   +5min
428          *   -5days
429          *
430          */
431
432         assert(t);
433         assert(usec);
434
435         x = time(NULL);
436         assert_se(localtime_r(&x, &tm));
437         tm.tm_isdst = -1;
438
439         if (streq(t, "now"))
440                 goto finish;
441
442         else if (streq(t, "today")) {
443                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
444                 goto finish;
445
446         } else if (streq(t, "yesterday")) {
447                 tm.tm_mday --;
448                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
449                 goto finish;
450
451         } else if (streq(t, "tomorrow")) {
452                 tm.tm_mday ++;
453                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
454                 goto finish;
455
456         } else if (t[0] == '+') {
457
458                 r = parse_sec(t+1, &plus);
459                 if (r < 0)
460                         return r;
461
462                 goto finish;
463         } else if (t[0] == '-') {
464
465                 r = parse_sec(t+1, &minus);
466                 if (r < 0)
467                         return r;
468
469                 goto finish;
470
471         } else if (endswith(t, " ago")) {
472                 _cleanup_free_ char *z;
473
474                 z = strndup(t, strlen(t) - 4);
475                 if (!z)
476                         return -ENOMEM;
477
478                 r = parse_sec(z, &minus);
479                 if (r < 0)
480                         return r;
481
482                 goto finish;
483         }
484
485         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
486                 size_t skip;
487
488                 if (!startswith_no_case(t, day_nr[i].name))
489                         continue;
490
491                 skip = strlen(day_nr[i].name);
492                 if (t[skip] != ' ')
493                         continue;
494
495                 weekday = day_nr[i].nr;
496                 t += skip + 1;
497                 break;
498         }
499
500         copy = tm;
501         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
502         if (k && *k == 0)
503                 goto finish;
504
505         tm = copy;
506         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
507         if (k && *k == 0)
508                 goto finish;
509
510         tm = copy;
511         k = strptime(t, "%y-%m-%d %H:%M", &tm);
512         if (k && *k == 0) {
513                 tm.tm_sec = 0;
514                 goto finish;
515         }
516
517         tm = copy;
518         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
519         if (k && *k == 0) {
520                 tm.tm_sec = 0;
521                 goto finish;
522         }
523
524         tm = copy;
525         k = strptime(t, "%y-%m-%d", &tm);
526         if (k && *k == 0) {
527                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
528                 goto finish;
529         }
530
531         tm = copy;
532         k = strptime(t, "%Y-%m-%d", &tm);
533         if (k && *k == 0) {
534                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
535                 goto finish;
536         }
537
538         tm = copy;
539         k = strptime(t, "%H:%M:%S", &tm);
540         if (k && *k == 0)
541                 goto finish;
542
543         tm = copy;
544         k = strptime(t, "%H:%M", &tm);
545         if (k && *k == 0) {
546                 tm.tm_sec = 0;
547                 goto finish;
548         }
549
550         return -EINVAL;
551
552 finish:
553         x = mktime(&tm);
554         if (x == (time_t) -1)
555                 return -EINVAL;
556
557         if (weekday >= 0 && tm.tm_wday != weekday)
558                 return -EINVAL;
559
560         ret = (usec_t) x * USEC_PER_SEC;
561
562         ret += plus;
563         if (ret > minus)
564                 ret -= minus;
565         else
566                 ret = 0;
567
568         *usec = ret;
569
570         return 0;
571 }
572
573 int parse_sec(const char *t, usec_t *usec) {
574         static const struct {
575                 const char *suffix;
576                 usec_t usec;
577         } table[] = {
578                 { "seconds", USEC_PER_SEC },
579                 { "second", USEC_PER_SEC },
580                 { "sec", USEC_PER_SEC },
581                 { "s", USEC_PER_SEC },
582                 { "minutes", USEC_PER_MINUTE },
583                 { "minute", USEC_PER_MINUTE },
584                 { "min", USEC_PER_MINUTE },
585                 { "months", USEC_PER_MONTH },
586                 { "month", USEC_PER_MONTH },
587                 { "msec", USEC_PER_MSEC },
588                 { "ms", USEC_PER_MSEC },
589                 { "m", USEC_PER_MINUTE },
590                 { "hours", USEC_PER_HOUR },
591                 { "hour", USEC_PER_HOUR },
592                 { "hr", USEC_PER_HOUR },
593                 { "h", USEC_PER_HOUR },
594                 { "days", USEC_PER_DAY },
595                 { "day", USEC_PER_DAY },
596                 { "d", USEC_PER_DAY },
597                 { "weeks", USEC_PER_WEEK },
598                 { "week", USEC_PER_WEEK },
599                 { "w", USEC_PER_WEEK },
600                 { "years", USEC_PER_YEAR },
601                 { "year", USEC_PER_YEAR },
602                 { "y", USEC_PER_YEAR },
603                 { "usec", 1ULL },
604                 { "us", 1ULL },
605                 { "", USEC_PER_SEC }, /* default is sec */
606         };
607
608         const char *p;
609         usec_t r = 0;
610         bool something = false;
611
612         assert(t);
613         assert(usec);
614
615         p = t;
616         for (;;) {
617                 long long l, z = 0;
618                 char *e;
619                 unsigned i, n = 0;
620
621                 p += strspn(p, WHITESPACE);
622
623                 if (*p == 0) {
624                         if (!something)
625                                 return -EINVAL;
626
627                         break;
628                 }
629
630                 errno = 0;
631                 l = strtoll(p, &e, 10);
632
633                 if (errno > 0)
634                         return -errno;
635
636                 if (l < 0)
637                         return -ERANGE;
638
639                 if (*e == '.') {
640                         char *b = e + 1;
641
642                         errno = 0;
643                         z = strtoll(b, &e, 10);
644                         if (errno > 0)
645                                 return -errno;
646
647                         if (z < 0)
648                                 return -ERANGE;
649
650                         if (e == b)
651                                 return -EINVAL;
652
653                         n = e - b;
654
655                 } else if (e == p)
656                         return -EINVAL;
657
658                 e += strspn(e, WHITESPACE);
659
660                 for (i = 0; i < ELEMENTSOF(table); i++)
661                         if (startswith(e, table[i].suffix)) {
662                                 usec_t k = (usec_t) z * table[i].usec;
663
664                                 for (; n > 0; n--)
665                                         k /= 10;
666
667                                 r += (usec_t) l * table[i].usec + k;
668                                 p = e + strlen(table[i].suffix);
669
670                                 something = true;
671                                 break;
672                         }
673
674                 if (i >= ELEMENTSOF(table))
675                         return -EINVAL;
676
677         }
678
679         *usec = r;
680
681         return 0;
682 }
683
684 int parse_nsec(const char *t, nsec_t *nsec) {
685         static const struct {
686                 const char *suffix;
687                 nsec_t nsec;
688         } table[] = {
689                 { "seconds", NSEC_PER_SEC },
690                 { "second", NSEC_PER_SEC },
691                 { "sec", NSEC_PER_SEC },
692                 { "s", NSEC_PER_SEC },
693                 { "minutes", NSEC_PER_MINUTE },
694                 { "minute", NSEC_PER_MINUTE },
695                 { "min", NSEC_PER_MINUTE },
696                 { "months", NSEC_PER_MONTH },
697                 { "month", NSEC_PER_MONTH },
698                 { "msec", NSEC_PER_MSEC },
699                 { "ms", NSEC_PER_MSEC },
700                 { "m", NSEC_PER_MINUTE },
701                 { "hours", NSEC_PER_HOUR },
702                 { "hour", NSEC_PER_HOUR },
703                 { "hr", NSEC_PER_HOUR },
704                 { "h", NSEC_PER_HOUR },
705                 { "days", NSEC_PER_DAY },
706                 { "day", NSEC_PER_DAY },
707                 { "d", NSEC_PER_DAY },
708                 { "weeks", NSEC_PER_WEEK },
709                 { "week", NSEC_PER_WEEK },
710                 { "w", NSEC_PER_WEEK },
711                 { "years", NSEC_PER_YEAR },
712                 { "year", NSEC_PER_YEAR },
713                 { "y", NSEC_PER_YEAR },
714                 { "usec", NSEC_PER_USEC },
715                 { "us", NSEC_PER_USEC },
716                 { "nsec", 1ULL },
717                 { "ns", 1ULL },
718                 { "", 1ULL }, /* default is nsec */
719         };
720
721         const char *p;
722         nsec_t r = 0;
723         bool something = false;
724
725         assert(t);
726         assert(nsec);
727
728         p = t;
729         for (;;) {
730                 long long l, z = 0;
731                 char *e;
732                 unsigned i, n = 0;
733
734                 p += strspn(p, WHITESPACE);
735
736                 if (*p == 0) {
737                         if (!something)
738                                 return -EINVAL;
739
740                         break;
741                 }
742
743                 errno = 0;
744                 l = strtoll(p, &e, 10);
745
746                 if (errno > 0)
747                         return -errno;
748
749                 if (l < 0)
750                         return -ERANGE;
751
752                 if (*e == '.') {
753                         char *b = e + 1;
754
755                         errno = 0;
756                         z = strtoll(b, &e, 10);
757                         if (errno > 0)
758                                 return -errno;
759
760                         if (z < 0)
761                                 return -ERANGE;
762
763                         if (e == b)
764                                 return -EINVAL;
765
766                         n = e - b;
767
768                 } else if (e == p)
769                         return -EINVAL;
770
771                 e += strspn(e, WHITESPACE);
772
773                 for (i = 0; i < ELEMENTSOF(table); i++)
774                         if (startswith(e, table[i].suffix)) {
775                                 nsec_t k = (nsec_t) z * table[i].nsec;
776
777                                 for (; n > 0; n--)
778                                         k /= 10;
779
780                                 r += (nsec_t) l * table[i].nsec + k;
781                                 p = e + strlen(table[i].suffix);
782
783                                 something = true;
784                                 break;
785                         }
786
787                 if (i >= ELEMENTSOF(table))
788                         return -EINVAL;
789
790         }
791
792         *nsec = r;
793
794         return 0;
795 }
796
797 bool ntp_synced(void) {
798         struct timex txc = {};
799
800         if (adjtimex(&txc) < 0)
801                 return false;
802
803         if (txc.status & STA_UNSYNC)
804                 return false;
805
806         return true;
807 }