multipath tests: alias: add tests for allocate_binding()
[multipath-tools/.git] / tests / alias.c
1 #include <stdint.h>
2 #include <setjmp.h>
3 #include <stdio.h>
4 #include <cmocka.h>
5 #include "util.h"
6 #include "alias.h"
7 #include "test-log.h"
8 #include <errno.h>
9
10 #include "globals.c"
11 #include "../libmultipath/alias.c"
12
13 #if INT_MAX == 0x7fffffff
14 /* user_friendly_name for map #INT_MAX */
15 #define MPATH_ID_INT_MAX "fxshrxw"
16 /* ... and one less */
17 #define MPATH_ID_INT_MAX_m1 "fxshrxv"
18 /* ... and one more */
19 #define MPATH_ID_INT_MAX_p1 "fxshrxx"
20 #endif
21
22 void __wrap_rewind(FILE *stream)
23 {}
24
25 char *__wrap_fgets(char *buf, int n, FILE *stream)
26 {
27         char *val = mock_ptr_type(char *);
28         if (!val)
29                 return NULL;
30         strlcpy(buf, val, n);
31         return buf;
32 }
33
34 static int __set_errno(int err)
35 {
36         if (err >= 0) {
37                 errno = 0;
38                 return err;
39         } else {
40                 errno = -err;
41                 return -1;
42         }
43 }
44
45 off_t __wrap_lseek(int fd, off_t offset, int whence)
46 {
47         return __set_errno(mock_type(int));
48
49 }
50
51 ssize_t __wrap_write(int fd, const void *buf, size_t count)
52 {
53         check_expected(count);
54         check_expected(buf);
55         return __set_errno(mock_type(int));
56 }
57
58 int __wrap_ftruncate(int fd, off_t length)
59 {
60         check_expected(length);
61         return __set_errno(mock_type(int));
62 }
63
64 static void fd_mpatha(void **state)
65 {
66         char buf[32];
67         int rc;
68
69         rc = format_devname(buf, 1, sizeof(buf), "FOO");
70         assert_int_equal(rc, 4);
71         assert_string_equal(buf, "FOOa");
72 }
73
74 static void fd_mpathz(void **state)
75 {
76         /* This also tests a "short" buffer, see fd_mpath_short1 */
77         char buf[5];
78         int rc;
79
80         rc = format_devname(buf, 26, sizeof(buf), "FOO");
81         assert_int_equal(rc, 4);
82         assert_string_equal(buf, "FOOz");
83 }
84
85 static void fd_mpathaa(void **state)
86 {
87         char buf[32];
88         int rc;
89
90         rc = format_devname(buf, 26 + 1, sizeof(buf), "FOO");
91         assert_int_equal(rc, 5);
92         assert_string_equal(buf, "FOOaa");
93 }
94
95 static void fd_mpathzz(void **state)
96 {
97         char buf[32];
98         int rc;
99
100         rc = format_devname(buf, 26*26 + 26, sizeof(buf), "FOO");
101         assert_int_equal(rc, 5);
102         assert_string_equal(buf, "FOOzz");
103 }
104
105 static void fd_mpathaaa(void **state)
106 {
107         char buf[32];
108         int rc;
109
110         rc = format_devname(buf, 26*26 + 27, sizeof(buf), "FOO");
111         assert_int_equal(rc, 6);
112         assert_string_equal(buf, "FOOaaa");
113 }
114
115 static void fd_mpathzzz(void **state)
116 {
117         char buf[32];
118         int rc;
119
120         rc = format_devname(buf, 26*26*26 + 26*26 + 26, sizeof(buf), "FOO");
121         assert_int_equal(rc, 6);
122         assert_string_equal(buf, "FOOzzz");
123 }
124
125 static void fd_mpathaaaa(void **state)
126 {
127         char buf[32];
128         int rc;
129
130         rc = format_devname(buf, 26*26*26 + 26*26 + 27, sizeof(buf), "FOO");
131         assert_int_equal(rc, 7);
132         assert_string_equal(buf, "FOOaaaa");
133 }
134
135 static void fd_mpathzzzz(void **state)
136 {
137         char buf[32];
138         int rc;
139
140         rc = format_devname(buf, 26*26*26*26 + 26*26*26 + 26*26 + 26,
141                             sizeof(buf), "FOO");
142         assert_int_equal(rc, 7);
143         assert_string_equal(buf, "FOOzzzz");
144 }
145
146 #ifdef MPATH_ID_INT_MAX
147 static void fd_mpath_max(void **state)
148 {
149         char buf[32];
150         int rc;
151
152         rc  = format_devname(buf, INT_MAX, sizeof(buf), "");
153         assert_int_equal(rc, strlen(MPATH_ID_INT_MAX));
154         assert_string_equal(buf, MPATH_ID_INT_MAX);
155 }
156 #endif
157
158 static void fd_mpath_max1(void **state)
159 {
160         char buf[32];
161         int rc;
162
163         rc  = format_devname(buf, INT_MIN, sizeof(buf), "");
164         assert_int_equal(rc, -1);
165 }
166
167 static void fd_mpath_short(void **state)
168 {
169         char buf[4];
170         int rc;
171
172         rc = format_devname(buf, 1, sizeof(buf), "FOO");
173         assert_int_equal(rc, -1);
174 }
175
176 static void fd_mpath_short1(void **state)
177 {
178         char buf[5];
179         int rc;
180
181         rc = format_devname(buf, 27, sizeof(buf), "FOO");
182         assert_int_equal(rc, -1);
183 }
184
185 static int test_format_devname(void)
186 {
187         const struct CMUnitTest tests[] = {
188                 cmocka_unit_test(fd_mpatha),
189                 cmocka_unit_test(fd_mpathz),
190                 cmocka_unit_test(fd_mpathaa),
191                 cmocka_unit_test(fd_mpathzz),
192                 cmocka_unit_test(fd_mpathaaa),
193                 cmocka_unit_test(fd_mpathzzz),
194                 cmocka_unit_test(fd_mpathaaaa),
195                 cmocka_unit_test(fd_mpathzzzz),
196 #ifdef MPATH_ID_INT_MAX
197                 cmocka_unit_test(fd_mpath_max),
198 #endif
199                 cmocka_unit_test(fd_mpath_max1),
200                 cmocka_unit_test(fd_mpath_short),
201                 cmocka_unit_test(fd_mpath_short1),
202         };
203
204         return cmocka_run_group_tests(tests, NULL, NULL);
205 }
206
207 static void sd_mpatha(void **state)
208 {
209         int rc = scan_devname("MPATHa", "MPATH");
210
211         assert_int_equal(rc, 1);
212 }
213
214 /*
215  * Text after whitespace is ignored. But an overlong input
216  * errors out, even if it's just whitespace.
217  * It's kind of strange that scan_devname() treats whitespace
218  * like this. But I'm not sure if some corner case depends
219  * on this behavior.
220  */
221 static void sd_mpatha_spc(void **state)
222 {
223         int rc = scan_devname("MPATHa  00", "MPATH");
224
225         assert_int_equal(rc, 1);
226 }
227
228 static void sd_mpatha_tab(void **state)
229 {
230         int rc = scan_devname("MPATHa\t00", "MPATH");
231
232         assert_int_equal(rc, 1);
233 }
234
235 static void sd_overlong(void **state)
236 {
237         int rc = scan_devname("MPATHa       ", "MPATH");
238
239         assert_int_equal(rc, -1);
240 }
241
242 static void sd_overlong1(void **state)
243 {
244         int rc = scan_devname("MPATHabcdefgh", "MPATH");
245
246         assert_int_equal(rc, -1);
247 }
248
249 static void sd_noprefix(void **state)
250 {
251         int rc = scan_devname("MPATHa", NULL);
252
253         assert_int_equal(rc, -1);
254 }
255
256 static void sd_nomatchprefix(void **state)
257 {
258         int rc = scan_devname("MPATHa", "mpath");
259
260         assert_int_equal(rc, -1);
261 }
262
263 static void sd_eq_prefix(void **state)
264 {
265         int rc = scan_devname("MPATH", "MPATH");
266
267         assert_int_equal(rc, -1);
268 }
269
270 static void sd_bad_1(void **state)
271 {
272         int rc = scan_devname("MPATH0", "MPATH");
273
274         assert_int_equal(rc, -1);
275 }
276
277 static void sd_bad_2(void **state)
278 {
279         int rc = scan_devname("MPATHa0c", "MPATH");
280
281         assert_int_equal(rc, -1);
282 }
283
284 #ifdef MPATH_ID_INT_MAX
285 static void sd_max(void **state)
286 {
287         int rc = scan_devname("MPATH" MPATH_ID_INT_MAX, "MPATH");
288
289         assert_int_equal(rc, INT_MAX);
290 }
291
292 static void sd_max_p1(void **state)
293 {
294         int rc = scan_devname("MPATH" MPATH_ID_INT_MAX_p1, "MPATH");
295
296         assert_int_equal(rc, -1);
297 }
298 #endif
299
300 static int test_scan_devname(void)
301 {
302         const struct CMUnitTest tests[] = {
303                 cmocka_unit_test(sd_mpatha),
304                 cmocka_unit_test(sd_mpatha_spc),
305                 cmocka_unit_test(sd_mpatha_tab),
306                 cmocka_unit_test(sd_overlong),
307                 cmocka_unit_test(sd_overlong1),
308                 cmocka_unit_test(sd_noprefix),
309                 cmocka_unit_test(sd_nomatchprefix),
310                 cmocka_unit_test(sd_eq_prefix),
311                 cmocka_unit_test(sd_bad_1),
312                 cmocka_unit_test(sd_bad_2),
313 #ifdef MPATH_ID_INT_MAX
314                 cmocka_unit_test(sd_max),
315                 cmocka_unit_test(sd_max_p1),
316 #endif
317         };
318
319         return cmocka_run_group_tests(tests, NULL, NULL);
320 }
321
322 static void lb_empty(void **state)
323 {
324         int rc;
325         char *alias;
326
327         will_return(__wrap_fgets, NULL);
328         expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n");
329         rc = lookup_binding(NULL, "WWID0", &alias, NULL);
330         assert_int_equal(rc, 1);
331         assert_ptr_equal(alias, NULL);
332 }
333
334 static void lb_match_a(void **state)
335 {
336         int rc;
337         char *alias;
338
339         will_return(__wrap_fgets, "MPATHa WWID0\n");
340         expect_condlog(3, "Found matching wwid [WWID0] in bindings file."
341                        " Setting alias to MPATHa\n");
342         rc = lookup_binding(NULL, "WWID0", &alias, "MPATH");
343         assert_int_equal(rc, 0);
344         assert_ptr_not_equal(alias, NULL);
345         assert_string_equal(alias, "MPATHa");
346         free(alias);
347 }
348
349 static void lb_nomatch_a(void **state)
350 {
351         int rc;
352         char *alias;
353
354         will_return(__wrap_fgets, "MPATHa WWID0\n");
355         will_return(__wrap_fgets, NULL);
356         expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n");
357         rc = lookup_binding(NULL, "WWID1", &alias, "MPATH");
358         assert_int_equal(rc, 2);
359         assert_ptr_equal(alias, NULL);
360 }
361
362 static void lb_match_c(void **state)
363 {
364         int rc;
365         char *alias;
366
367         will_return(__wrap_fgets, "MPATHa WWID0\n");
368         will_return(__wrap_fgets, "MPATHc WWID1\n");
369         expect_condlog(3, "Found matching wwid [WWID1] in bindings file."
370                        " Setting alias to MPATHc\n");
371         rc = lookup_binding(NULL, "WWID1", &alias, "MPATH");
372         assert_int_equal(rc, 0);
373         assert_ptr_not_equal(alias, NULL);
374         assert_string_equal(alias, "MPATHc");
375         free(alias);
376 }
377
378 static void lb_nomatch_a_c(void **state)
379 {
380         int rc;
381         char *alias;
382
383         will_return(__wrap_fgets, "MPATHa WWID0\n");
384         will_return(__wrap_fgets, "MPATHc WWID1\n");
385         will_return(__wrap_fgets, NULL);
386         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
387         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
388         assert_int_equal(rc, 2);
389         assert_ptr_equal(alias, NULL);
390 }
391
392 static void lb_nomatch_c_a(void **state)
393 {
394         int rc;
395         char *alias;
396
397         will_return(__wrap_fgets, "MPATHc WWID1\n");
398         will_return(__wrap_fgets, "MPATHa WWID0\n");
399         will_return(__wrap_fgets, NULL);
400         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
401         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
402         assert_int_equal(rc, 2);
403         assert_ptr_equal(alias, NULL);
404 }
405
406 static void lb_nomatch_a_b(void **state)
407 {
408         int rc;
409         char *alias;
410
411         will_return(__wrap_fgets, "MPATHa WWID0\n");
412         will_return(__wrap_fgets, "MPATHz WWID26\n");
413         will_return(__wrap_fgets, "MPATHb WWID1\n");
414         will_return(__wrap_fgets, NULL);
415         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
416         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
417         assert_int_equal(rc, 3);
418         assert_ptr_equal(alias, NULL);
419 }
420
421 static void lb_nomatch_a_b_bad(void **state)
422 {
423         int rc;
424         char *alias;
425
426         will_return(__wrap_fgets, "MPATHa WWID0\n");
427         will_return(__wrap_fgets, "MPATHz WWID26\n");
428         will_return(__wrap_fgets, "MPATHb\n");
429         will_return(__wrap_fgets, NULL);
430         expect_condlog(3, "Ignoring malformed line 3 in bindings file\n");
431         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
432         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
433         assert_int_equal(rc, 3);
434         assert_ptr_equal(alias, NULL);
435 }
436
437 static void lb_nomatch_b_a(void **state)
438 {
439         int rc;
440         char *alias;
441
442         will_return(__wrap_fgets, "MPATHb WWID1\n");
443         will_return(__wrap_fgets, "MPATHz WWID26\n");
444         will_return(__wrap_fgets, "MPATHa WWID0\n");
445         will_return(__wrap_fgets, NULL);
446         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
447         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
448         assert_int_equal(rc, 27);
449         assert_ptr_equal(alias, NULL);
450 }
451
452 #ifdef MPATH_ID_INT_MAX
453 static void lb_nomatch_int_max(void **state)
454 {
455         int rc;
456         char *alias;
457
458         will_return(__wrap_fgets, "MPATHb WWID1\n");
459         will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n");
460         will_return(__wrap_fgets, "MPATHa WWID0\n");
461         will_return(__wrap_fgets, NULL);
462         expect_condlog(0, "no more available user_friendly_names\n");
463         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
464         assert_int_equal(rc, -1);
465         assert_ptr_equal(alias, NULL);
466 }
467
468 static void lb_nomatch_int_max_m1(void **state)
469 {
470         int rc;
471         char *alias;
472
473         will_return(__wrap_fgets, "MPATHb WWID1\n");
474         will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n");
475         will_return(__wrap_fgets, "MPATHa WWID0\n");
476         will_return(__wrap_fgets, NULL);
477         expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n");
478         rc = lookup_binding(NULL, "WWID2", &alias, "MPATH");
479         assert_int_equal(rc, INT_MAX);
480         assert_ptr_equal(alias, NULL);
481 }
482 #endif
483
484 static int test_lookup_binding(void)
485 {
486         const struct CMUnitTest tests[] = {
487                 cmocka_unit_test(lb_empty),
488                 cmocka_unit_test(lb_match_a),
489                 cmocka_unit_test(lb_nomatch_a),
490                 cmocka_unit_test(lb_match_c),
491                 cmocka_unit_test(lb_nomatch_a_c),
492                 cmocka_unit_test(lb_nomatch_c_a),
493                 cmocka_unit_test(lb_nomatch_a_b),
494                 cmocka_unit_test(lb_nomatch_a_b_bad),
495                 cmocka_unit_test(lb_nomatch_b_a),
496 #ifdef MPATH_ID_INT_MAX
497                 cmocka_unit_test(lb_nomatch_int_max),
498                 cmocka_unit_test(lb_nomatch_int_max_m1),
499 #endif
500         };
501
502         return cmocka_run_group_tests(tests, NULL, NULL);
503 }
504
505 static void rl_empty(void **state)
506 {
507         int rc;
508         char buf[WWID_SIZE];
509
510         buf[0] = '\0';
511         will_return(__wrap_fgets, NULL);
512         expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n");
513         rc = rlookup_binding(NULL, buf, "MPATHa");
514         assert_int_equal(rc, -1);
515         assert_string_equal(buf, "");
516 }
517
518 static void rl_match_a(void **state)
519 {
520         int rc;
521         char buf[WWID_SIZE];
522
523         buf[0] = '\0';
524         will_return(__wrap_fgets, "MPATHa WWID0\n");
525         expect_condlog(3, "Found matching alias [MPATHa] in bindings file.\n"
526                        "Setting wwid to WWID0\n");
527         rc = rlookup_binding(NULL, buf, "MPATHa");
528         assert_int_equal(rc, 0);
529         assert_string_equal(buf, "WWID0");
530 }
531
532 static void rl_nomatch_a(void **state)
533 {
534         int rc;
535         char buf[WWID_SIZE];
536
537         buf[0] = '\0';
538         will_return(__wrap_fgets, "MPATHa WWID0\n");
539         will_return(__wrap_fgets, NULL);
540         expect_condlog(3, "No matching alias [MPATHb] in bindings file.\n");
541         rc = rlookup_binding(NULL, buf, "MPATHb");
542         assert_int_equal(rc, -1);
543         assert_string_equal(buf, "");
544 }
545
546 static void rl_malformed_a(void **state)
547 {
548         int rc;
549         char buf[WWID_SIZE];
550
551         buf[0] = '\0';
552         will_return(__wrap_fgets, "MPATHa     \n");
553         will_return(__wrap_fgets, NULL);
554         expect_condlog(3, "Ignoring malformed line 1 in bindings file\n");
555         expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n");
556         rc = rlookup_binding(NULL, buf, "MPATHa");
557         assert_int_equal(rc, -1);
558         assert_string_equal(buf, "");
559 }
560
561 static void rl_overlong_a(void **state)
562 {
563         int rc;
564         char buf[WWID_SIZE];
565         char line[WWID_SIZE + 10];
566
567         snprintf(line, sizeof(line), "MPATHa ");
568         memset(line + strlen(line), 'W', sizeof(line) - 2 - strlen(line));
569         snprintf(line + sizeof(line) - 2, 2, "\n");
570
571         buf[0] = '\0';
572         will_return(__wrap_fgets, line);
573         will_return(__wrap_fgets, NULL);
574         expect_condlog(3, "Ignoring too large wwid at 1 in bindings file\n");
575         expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n");
576         rc = rlookup_binding(NULL, buf, "MPATHa");
577         assert_int_equal(rc, -1);
578         assert_string_equal(buf, "");
579 }
580
581 static void rl_match_b(void **state)
582 {
583         int rc;
584         char buf[WWID_SIZE];
585
586         buf[0] = '\0';
587         will_return(__wrap_fgets, "MPATHa WWID0\n");
588         will_return(__wrap_fgets, "MPATHz WWID26\n");
589         will_return(__wrap_fgets, "MPATHb WWID2\n");
590         expect_condlog(3, "Found matching alias [MPATHb] in bindings file.\n"
591                        "Setting wwid to WWID2\n");
592         rc = rlookup_binding(NULL, buf, "MPATHb");
593         assert_int_equal(rc, 0);
594         assert_string_equal(buf, "WWID2");
595 }
596
597 static int test_rlookup_binding(void)
598 {
599         const struct CMUnitTest tests[] = {
600                 cmocka_unit_test(rl_empty),
601                 cmocka_unit_test(rl_match_a),
602                 cmocka_unit_test(rl_nomatch_a),
603                 cmocka_unit_test(rl_malformed_a),
604                 cmocka_unit_test(rl_overlong_a),
605                 cmocka_unit_test(rl_match_b),
606         };
607
608         return cmocka_run_group_tests(tests, NULL, NULL);
609 }
610
611 static void al_a(void **state)
612 {
613         static const char ln[] = "MPATHa WWIDa\n";
614         char *alias;
615
616         will_return(__wrap_lseek, 0);
617         expect_value(__wrap_write, count, strlen(ln));
618         expect_string(__wrap_write, buf, ln);
619         will_return(__wrap_write, strlen(ln));
620         expect_condlog(3, "Created new binding [MPATHa] for WWID [WWIDa]\n");
621
622         alias = allocate_binding(0, "WWIDa", 1, "MPATH");
623         assert_ptr_not_equal(alias, NULL);
624         assert_string_equal(alias, "MPATHa");
625 }
626
627 static void al_zz(void **state)
628 {
629         static const char ln[] = "MPATHzz WWIDzz\n";
630         char *alias;
631
632         will_return(__wrap_lseek, 0);
633         expect_value(__wrap_write, count, strlen(ln));
634         expect_string(__wrap_write, buf, ln);
635         will_return(__wrap_write, strlen(ln));
636         expect_condlog(3, "Created new binding [MPATHzz] for WWID [WWIDzz]\n");
637
638         alias = allocate_binding(0, "WWIDzz", 26*26 + 26, "MPATH");
639         assert_ptr_not_equal(alias, NULL);
640         assert_string_equal(alias, "MPATHzz");
641 }
642
643 static void al_0(void **state)
644 {
645         char *alias;
646
647         expect_condlog(0, "allocate_binding: cannot allocate new binding for id 0\n");
648         alias = allocate_binding(0, "WWIDa", 0, "MPATH");
649         assert_ptr_equal(alias, NULL);
650 }
651
652 static void al_m2(void **state)
653 {
654         char *alias;
655
656         expect_condlog(0, "allocate_binding: cannot allocate new binding for id -2\n");
657         alias = allocate_binding(0, "WWIDa", -2, "MPATH");
658         assert_ptr_equal(alias, NULL);
659 }
660
661 static void al_lseek_err(void **state)
662 {
663         char *alias;
664
665         will_return(__wrap_lseek, -ENODEV);
666         expect_condlog(0, "Cannot seek to end of bindings file : No such device\n");
667         alias = allocate_binding(0, "WWIDa", 1, "MPATH");
668         assert_ptr_equal(alias, NULL);
669 }
670
671 static void al_write_err(void **state)
672 {
673         static const char ln[] = "MPATHa WWIDa\n";
674         const int offset = 20;
675         char *alias;
676
677         will_return(__wrap_lseek, offset);
678         expect_value(__wrap_write, count, strlen(ln));
679         expect_string(__wrap_write, buf, ln);
680         will_return(__wrap_write, strlen(ln) - 1);
681         expect_value(__wrap_ftruncate, length, offset);
682         will_return(__wrap_ftruncate, 0);
683         expect_condlog(0, "Cannot write binding to bindings file : Success\n");
684
685         alias = allocate_binding(0, "WWIDa", 1, "MPATH");
686         assert_ptr_equal(alias, NULL);
687 }
688
689 static int test_allocate_binding(void)
690 {
691         const struct CMUnitTest tests[] = {
692                 cmocka_unit_test(al_a),
693                 cmocka_unit_test(al_zz),
694                 cmocka_unit_test(al_0),
695                 cmocka_unit_test(al_m2),
696                 cmocka_unit_test(al_lseek_err),
697                 cmocka_unit_test(al_write_err),
698         };
699
700         return cmocka_run_group_tests(tests, NULL, NULL);
701 }
702
703 int main(void)
704 {
705         int ret = 0;
706
707         ret += test_format_devname();
708         ret += test_scan_devname();
709         ret += test_lookup_binding();
710         ret += test_rlookup_binding();
711         ret += test_allocate_binding();
712
713         return ret;
714 }