master
c 983 lines 21.6 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 lxtmount.c
8
9 Abstract:
10
11 This file contains mount primitive support.
12
13 --*/
14
15 #include "lxtlog.h"
16 #include <sys/mman.h>
17 #include "lxtcommon.h"
18 #include <sys/mount.h>
19 #include <linux/capability.h>
20 #include <sys/sysmacros.h>
21 #include <libgen.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <libmount/libmount.h>
25 #include <sys/mman.h>
26 #include "lxtmount.h"
27
28 #define PATH_MAX (4096)
29
30 void MountEscapeString(const char* Source, char* Dest, size_t Length);
31 int MountCheckFsOptionsPattern(const char* Pattern, const char* Actual);
32
33 int MountCheckIsMount(
34 const char* Path,
35 int ExpectedParentId,
36 const char* ExpectedSource,
37 const char* ExpectedFsType,
38 const char* ExpectedRoot,
39 const char* ExpectedMountOptions,
40 const char* ExpectedFsOptions,
41 const char* ExpectedCombinedOptions,
42 int Flags)
43
44 /*++
45
46 Description:
47
48 This routine checks if a path is a mount point.
49
50 Arguments:
51
52 Args - Supplies the command line arguments.
53
54 Return Value:
55
56 Returns the mount ID on success, -1 on failure.
57
58 --*/
59
60 {
61
62 const char* ActualRoot;
63 int Direction;
64 const char* ExpectedSourceActual;
65 struct libmnt_fs* FileSystem;
66 char LocalPath[PATH_MAX];
67 int MountId;
68 int Result;
69 struct stat Stat;
70 const char* SubPath;
71 struct libmnt_table* Table;
72
73 Table = NULL;
74 if (strcmp(Path, "/") != 0)
75 {
76 LxtCheckResult(MountIsMount(AT_FDCWD, Path));
77 if (Result == 0)
78 {
79 LxtLogError("%s is not a mount point.", Path);
80 Result = LXT_RESULT_FAILURE;
81 goto ErrorExit;
82 }
83 }
84
85 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
86
87 //
88 // Verify the mount in the /proc/self/mountinfo file.
89 //
90
91 if ((Flags & MOUNT_FIRST_MOUNT) != 0)
92 {
93 Direction = MNT_ITER_FORWARD;
94 }
95 else
96 {
97 Direction = MNT_ITER_BACKWARD;
98 }
99
100 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, Direction));
101
102 LxtCheckNotEqual(FileSystem, NULL, "%p");
103 LxtLogInfo("%s on %s fstype %s (%s)", mnt_fs_get_source(FileSystem), mnt_fs_get_target(FileSystem), mnt_fs_get_fstype(FileSystem), mnt_fs_get_options(FileSystem));
104
105 ExpectedSourceActual = ExpectedSource;
106
107 #if LIBMOUNT_MAJOR_VERSION >= 2
108
109 if ((ExpectedSourceActual == NULL) && (strcmp(ExpectedFsType, "virtiofs") != 0))
110 {
111 ExpectedSourceActual = "none";
112 }
113
114 #endif
115
116 LxtCheckEqual(ExpectedParentId, mnt_fs_get_parent_id(FileSystem), "%d");
117 if (ExpectedSourceActual)
118 {
119 LxtCheckStringEqual(ExpectedSourceActual, mnt_fs_get_source(FileSystem));
120 }
121
122 LxtCheckStringEqual(ExpectedFsType, mnt_fs_get_fstype(FileSystem));
123 strcpy(LocalPath, ExpectedRoot);
124 if ((Flags & MOUNT_SOURCE_DELETED) != 0)
125 {
126 strcat(LocalPath, "//deleted");
127 }
128
129 //
130 // Aggregate virtio-fs exposes each Windows share as a named child of a
131 // single device, so a share mounted at <target> is a bind mount whose
132 // mountinfo root is "/<share-name>[<subpath>]" rather than the bare
133 // "<subpath>". The share name is a dynamically generated GUID, so strip the
134 // leading component before comparing against the expected root. Only strip
135 // when the root does not already match the expected value, so a virtio-fs
136 // mount whose root is already correct is left alone.
137 //
138
139 ActualRoot = mnt_fs_get_root(FileSystem);
140 if ((strcmp(ExpectedFsType, "virtiofs") == 0) && (strcmp(ActualRoot, LocalPath) != 0) && (ActualRoot[0] == '/'))
141 {
142 SubPath = strchr(ActualRoot + 1, '/');
143 ActualRoot = (SubPath != NULL) ? SubPath : "/";
144 }
145
146 LxtCheckStringEqual(LocalPath, ActualRoot);
147 LxtCheckStringEqual(ExpectedMountOptions, mnt_fs_get_vfs_options(FileSystem));
148 if (ExpectedFsOptions != NULL)
149 {
150 if (strchr(ExpectedFsOptions, '*') != NULL)
151 {
152 LxtCheckResult(MountCheckFsOptionsPattern(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem)));
153 }
154 else
155 {
156 LxtCheckStringEqual(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem));
157 }
158 }
159
160 LxtCheckEqual(Stat.st_dev, mnt_fs_get_devno(FileSystem), "%lu");
161 MountId = mnt_fs_get_id(FileSystem);
162 LxtCheckGreater(MountId, 0, "%d");
163 LxtCheckNotEqual(MountId, ExpectedParentId, "%d");
164 mnt_free_table(Table);
165 Table = NULL;
166
167 //
168 // Verify the mount in the /proc/mounts file.
169 //
170
171 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTS, Path, 0, &Table, &FileSystem, Direction));
172
173 LxtCheckNotEqual(FileSystem, NULL, "%p");
174 if (ExpectedSourceActual)
175 {
176 LxtCheckStringEqual(ExpectedSourceActual, mnt_fs_get_source(FileSystem));
177 }
178
179 LxtCheckStringEqual(ExpectedFsType, mnt_fs_get_fstype(FileSystem));
180 if (ExpectedCombinedOptions != NULL)
181 {
182 LxtCheckStringEqual(ExpectedCombinedOptions, mnt_fs_get_options(FileSystem));
183 }
184
185 //
186 // Verify the mount in the /proc/self/mountstats file.
187 //
188
189 if (ExpectedSourceActual)
190 {
191 LxtCheckResult(MountFindMountStats(ExpectedSource, Path, ExpectedFsType));
192 }
193
194 Result = MountId;
195
196 ErrorExit:
197 if (Table != NULL)
198 {
199 mnt_free_table(Table);
200 }
201
202 return Result;
203 }
204
205 int MountCheckIsNotMount(const char* Path)
206
207 /*++
208
209 Description:
210
211 This routine checks if a path is a mount point.
212
213 Arguments:
214
215 Args - Supplies the command line arguments.
216
217 Return Value:
218
219 Returns 0 on success, -1 on failure.
220
221 --*/
222
223 {
224
225 struct libmnt_fs* FileSystem;
226 int Result;
227 struct libmnt_table* Table;
228
229 Table = NULL;
230 LxtCheckResult(MountIsMount(AT_FDCWD, Path));
231 if (Result != 0)
232 {
233 LxtLogError("%s is a mount point.", Path);
234 Result = LXT_RESULT_FAILURE;
235 goto ErrorExit;
236 }
237
238 //
239 // Verify the mount is not in the /proc/self/mountinfo file.
240 //
241
242 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
243
244 LxtCheckEqual(FileSystem, NULL, "%p");
245 mnt_free_table(Table);
246 Table = NULL;
247
248 //
249 // Verify the mount in the /proc/mounts file.
250 //
251
252 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTS, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
253
254 LxtCheckEqual(FileSystem, NULL, "%p");
255
256 ErrorExit:
257 if (Table != NULL)
258 {
259 mnt_free_table(Table);
260 }
261
262 return Result;
263 }
264
265 int MountCheckFsOptionsPattern(const char* Pattern, const char* Actual)
266
267 /*++
268
269 Description:
270
271 This routine checks if mount options match a pattern with wildcards.
272 The '*' wildcard matches any sequence of characters.
273
274 Arguments:
275
276 Pattern - Supplies the expected pattern (e.g., "rfd=*,wfd=*").
277
278 Actual - Supplies the actual mount options string.
279
280 Return Value:
281
282 Returns 0 on success, -1 on failure.
283
284 --*/
285
286 {
287
288 const char* ActualPtr;
289 const char* MatchPosition;
290 const char* PatternPtr;
291 int Result;
292 const char* StarPosition;
293
294 PatternPtr = Pattern;
295 ActualPtr = Actual;
296 StarPosition = NULL;
297 MatchPosition = NULL;
298 Result = LXT_RESULT_FAILURE;
299
300 while (*ActualPtr != '\0')
301 {
302 if (*PatternPtr == '*')
303 {
304 //
305 // Remember position of * and where we are in actual string.
306 //
307
308 StarPosition = PatternPtr++;
309 MatchPosition = ActualPtr;
310 }
311 else if (*PatternPtr == *ActualPtr)
312 {
313 //
314 // Characters match, advance both.
315 //
316
317 PatternPtr++;
318 ActualPtr++;
319 }
320 else if (StarPosition != NULL)
321 {
322 //
323 // Mismatch but we have a *, backtrack and try matching one more character.
324 //
325
326 PatternPtr = StarPosition + 1;
327 ActualPtr = ++MatchPosition;
328 }
329 else
330 {
331 //
332 // Mismatch and no * to backtrack to.
333 //
334
335 goto ErrorExit;
336 }
337 }
338
339 //
340 // Consume any trailing *'s in pattern.
341 //
342
343 while (*PatternPtr == '*')
344 {
345 PatternPtr++;
346 }
347
348 //
349 // Both should be at end of string.
350 //
351
352 if (*PatternPtr != '\0')
353 {
354 goto ErrorExit;
355 }
356
357 Result = LXT_RESULT_SUCCESS;
358
359 ErrorExit:
360 if (!LXT_SUCCESS(Result))
361 {
362 LxtLogError("Mount options mismatch: expected '%s', got '%s'", Pattern, Actual);
363 }
364
365 return Result;
366 }
367
368 void MountEscapeString(const char* Source, char* Dest, size_t Length)
369
370 /*++
371
372 Description:
373
374 This routine escapes a string using procfs rules.
375
376 Arguments:
377
378 Source - Supplies the string to escape.
379
380 Dest - Supplies the buffer to write the escaped string to.
381
382 Length - Supplies the length of the destination buffer.
383
384 Return Value:
385
386 None.
387
388 --*/
389
390 {
391
392 size_t Index;
393
394 for (Index = 0; (Index < Length - 1) && (*Source != '\0'); Index += 1, Source += 1)
395 {
396 switch (*Source)
397 {
398 case ' ':
399 case '\n':
400 case '\t':
401 case '\\':
402 Index += snprintf(Dest + Index, Length - Index, "\\%03o", *Source) - 1;
403
404 break;
405
406 default:
407 Dest[Index] = *Source;
408 break;
409 }
410 }
411
412 Dest[Index] = '\0';
413 return;
414 }
415
416 int MountFindMount(const char* MountsFile, const char* MountPoint, dev_t Device, struct libmnt_table** Table, struct libmnt_fs** FileSystem, int Direction)
417
418 /*++
419
420 Description:
421
422 This routine finds a mount in the specified file by either mount point
423 or device.
424
425 Arguments:
426
427 MountsFile - Supplies the file to use (e.g. /proc/self/mountinfo).
428
429 MountPoint - Supplies the mount point to search for. If NULL, device is
430 used instead.
431
432 Device - Supplies the device to search for if mount point is NULL.
433
434 Table - Supplies a pointer that receives the parsed table. The caller
435 must use mnt_free_table to free the table.
436
437 FileSystem - Supplies a pointer that receives the file system, or NULL
438 if none was found.
439
440 Return Value:
441
442 Returns 0 on success, -1 on failure.
443
444 --*/
445
446 {
447
448 struct libmnt_iter* Iterator;
449 struct libmnt_fs* LocalFileSystem;
450 struct libmnt_table* LocalTable;
451 int Result;
452
453 LocalFileSystem = NULL;
454 Iterator = NULL;
455 LocalTable = mnt_new_table_from_file(MountsFile);
456 LxtCheckNotEqual(LocalTable, NULL, "%p");
457
458 //
459 // A backwards iterator is used to find the most recent mount.
460 //
461
462 if (MountPoint != NULL)
463 {
464 *FileSystem = mnt_table_find_target(LocalTable, MountPoint, Direction);
465 }
466 else
467 {
468 *FileSystem = NULL;
469 Iterator = mnt_new_iter(MNT_ITER_FORWARD);
470 LxtCheckNotEqual(Iterator, NULL, "%p");
471 while (mnt_table_next_fs(LocalTable, Iterator, &LocalFileSystem) == 0)
472 {
473 if (mnt_fs_get_devno(LocalFileSystem) == Device)
474 {
475 *FileSystem = LocalFileSystem;
476 break;
477 }
478 }
479 }
480
481 //
482 // Return the table so the memory for file system remains valid.
483 //
484
485 if (*FileSystem != NULL)
486 {
487 *Table = LocalTable;
488 LocalTable = NULL;
489 }
490
491 Result = 0;
492
493 ErrorExit:
494 if (Iterator != NULL)
495 {
496 mnt_free_iter(Iterator);
497 }
498
499 if (LocalTable != NULL)
500 {
501 mnt_free_table(LocalTable);
502 }
503
504 return Result;
505 }
506
507 int MountFindMountStats(const char* Device, const char* MountPoint, const char* FsType)
508
509 /*++
510
511 Description:
512
513 This routine finds a mount with the specified options in the
514 /proc/self/mountstats file.
515
516 N.B. libmount does not support parsing the mountstats file so this is done
517 manually.
518
519 Arguments:
520
521 Device - Supplies the mount source.
522
523 MountPoint - Supplies the mount point.
524
525 FsType - Supplies the file system type.
526
527 Return Value:
528
529 Returns 0 on success, -1 on failure.
530
531 --*/
532
533 {
534
535 char EscapedDevice[100];
536 char EscapedMountPoint[100];
537 char ExpectedLine[256];
538 int Result;
539
540 //
541 // Format the expected mountstats line.
542 //
543
544 MountEscapeString(MountPoint, EscapedMountPoint, LXT_COUNT_OF(EscapedMountPoint));
545 if (Device == NULL)
546 {
547 snprintf(ExpectedLine, sizeof(ExpectedLine), "no device mounted on %s with fstype %s", EscapedMountPoint, FsType);
548 }
549 else
550 {
551 MountEscapeString(Device, EscapedDevice, LXT_COUNT_OF(EscapedDevice));
552 snprintf(ExpectedLine, sizeof(ExpectedLine), "device %s mounted on %s with fstype %s", EscapedDevice, EscapedMountPoint, FsType);
553 }
554
555 LxtCheckResult(MountFindMountStatsLine(ExpectedLine));
556
557 ErrorExit:
558 return Result;
559 }
560
561 int MountFindMountStatsLine(char* ExpectedLine)
562
563 /*++
564
565 Description:
566
567 This routine checks if a specific line exists in the mountstats file.
568
569 Arguments:
570
571 ExpectedLine - Supplies the line to find.
572
573 Return Value:
574
575 Returns 0 on success, -1 on failure.
576
577 --*/
578
579 {
580
581 bool Found;
582 FILE* File;
583 char Line[256];
584 int Result;
585
586 File = fopen(MOUNT_PROC_MOUNTSTATS, "r");
587 LxtCheckNotEqual(File, NULL, "%p");
588 Found = FALSE;
589 while (feof(File) == 0)
590 {
591 if (fgets(Line, sizeof(Line), File) == NULL)
592 {
593 break;
594 }
595
596 //
597 // Strip the trailing \n and compare.
598 //
599
600 Line[strlen(Line) - 1] = '\0';
601 if (strncmp(ExpectedLine, Line, sizeof(Line)) == 0)
602 {
603 Found = TRUE;
604 break;
605 }
606 }
607
608 if (Found == false)
609 {
610 LxtLogError("'%s' not found in " MOUNT_PROC_MOUNTSTATS, ExpectedLine);
611 Result = LXT_RESULT_FAILURE;
612 goto ErrorExit;
613 }
614
615 Result = LXT_RESULT_SUCCESS;
616
617 ErrorExit:
618 if (File != NULL)
619 {
620 fclose(File);
621 }
622
623 return Result;
624 }
625
626 int MountGetMountId(const char* Path)
627
628 /*++
629
630 Description:
631
632 This routine gets the mount ID for the specified path.
633
634 Arguments:
635
636 Path - Supplies the path. Does not have to be a mount point.
637
638 Return Value:
639
640 Returns 0 on success, -1 on failure.
641
642 --*/
643
644 {
645
646 struct libmnt_fs* FileSystem;
647 int Result;
648 struct stat Stat;
649 struct libmnt_table* Table;
650
651 //
652 // Find the nearest mount containing the path without relying on the device
653 // number, which is shared by all aggregate virtio-fs shares.
654 //
655
656 FileSystem = NULL;
657 Table = NULL;
658 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
659 Table = mnt_new_table_from_file(MOUNT_PROC_MOUNTINFO);
660 LxtCheckNotEqual(Table, NULL, "%p");
661 FileSystem = mnt_table_find_mountpoint(Table, Path, MNT_ITER_BACKWARD);
662 LxtCheckNotEqual(FileSystem, NULL, "%p");
663 Result = mnt_fs_get_id(FileSystem);
664
665 ErrorExit:
666 if (Table != NULL)
667 {
668 mnt_free_table(Table);
669 }
670
671 return Result;
672 }
673
674 int MountGetFileSystem(const char* Path, char* FsType, int FsTypeLength, char* Options, int OptionsLength)
675
676 /*++
677
678 Description:
679
680 This routine gets the file system type of the mount containing the
681 specified path.
682
683 Arguments:
684
685 Path - Supplies the path.
686
687 FsType - Supplies a buffer that receives the name of the file system type.
688
689 Length - Supplies the size of the buffer.
690
691 Return Value:
692
693 Returns 0 on success, -1 on failure.
694
695 --*/
696
697 {
698
699 struct libmnt_fs* FileSystem;
700 const char* LocalFsType;
701 const char* LocalOptions;
702 int Result;
703 struct stat Stat;
704 struct libmnt_table* Table;
705
706 //
707 // Find the mount ID of the directory. This is done by device because
708 // it may not be a mount point.
709 //
710
711 FileSystem = NULL;
712 Table = NULL;
713 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
714 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, NULL, Stat.st_dev, &Table, &FileSystem, MNT_ITER_BACKWARD));
715
716 LxtCheckNotEqual(FileSystem, NULL, "%p");
717 LocalFsType = mnt_fs_get_fstype(FileSystem);
718 LocalOptions = mnt_fs_get_options(FileSystem);
719 LxtLogInfo("File system at %s uses fstype %s, options %s.", Path, LocalFsType, LocalOptions);
720
721 if (strlen(LocalFsType) >= FsTypeLength)
722 {
723 LxtLogError("Buffer too small for file system name");
724 Result = LXT_RESULT_FAILURE;
725 goto ErrorExit;
726 }
727
728 if (strlen(LocalOptions) >= OptionsLength)
729 {
730 LxtLogError("Buffer too small for options.");
731 Result = LXT_RESULT_FAILURE;
732 goto ErrorExit;
733 }
734
735 strcpy(FsType, LocalFsType);
736 strcpy(Options, LocalOptions);
737
738 ErrorExit:
739 if (Table != NULL)
740 {
741 mnt_free_table(Table);
742 }
743
744 return Result;
745 }
746
747 int MountGetMountOptions(const char* Path, char* Options)
748
749 /*++
750
751 Description:
752
753 This routine gets mount options, which generally describe the mount peer
754 group information for the specified path.
755
756 Arguments:
757
758 Path - Supplies the path. Does not have to be a mount point.
759
760 Options - Supplies a string buffer to receive the options
761
762 Return Value:
763
764 Returns 0 on success, -1 on failure.
765
766 --*/
767
768 {
769
770 struct libmnt_fs* FileSystem;
771 const char* LocalOptions;
772 int Result;
773 struct libmnt_table* Table;
774
775 //
776 // Find the mount ID of the directory.
777 //
778
779 FileSystem = NULL;
780 Table = NULL;
781 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
782
783 //
784 // shared:X, master:X, propagate_from:X, unbindable
785 //
786
787 LocalOptions = mnt_fs_get_optional_fields(FileSystem);
788 if (LocalOptions != NULL)
789 {
790 strcpy(Options, LocalOptions);
791 }
792 else
793 {
794 Options[0] = '\0';
795 }
796
797 ErrorExit:
798 if (Table != NULL)
799 {
800 mnt_free_table(Table);
801 }
802
803 return Result;
804 }
805
806 int MountIsFileSystem(const char* Path, const char* FsType)
807
808 /*++
809
810 Description:
811
812 This routine checks the file system type of the mount containing the
813 specified path.
814
815 Arguments:
816
817 Path - Supplies the path.
818
819 FsType - Supplies the name of the file system type.
820
821 Return Value:
822
823 Returns 1 if the path uses the specified file system, 0 if not, and -1 on
824 failure.
825
826 --*/
827
828 {
829
830 const char* ActualFsType;
831 struct libmnt_fs* FileSystem;
832 int Result;
833 struct stat Stat;
834 struct libmnt_table* Table;
835
836 //
837 // Find the mount ID of the directory. This is done by device because
838 // it may not be a mount point.
839 //
840
841 FileSystem = NULL;
842 Table = NULL;
843 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
844 LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, NULL, Stat.st_dev, &Table, &FileSystem, MNT_ITER_BACKWARD));
845
846 LxtCheckNotEqual(FileSystem, NULL, "%p");
847 ActualFsType = mnt_fs_get_fstype(FileSystem);
848 LxtLogInfo("File system at %s uses fstype %s.", Path, ActualFsType);
849 if (strcmp(ActualFsType, FsType) == 0)
850 {
851 Result = 1;
852 }
853 else
854 {
855 Result = 0;
856 }
857
858 ErrorExit:
859 if (Table != NULL)
860 {
861 mnt_free_table(Table);
862 }
863
864 return Result;
865 }
866
867 int MountIsMount(int DirFd, const char* Path)
868
869 /*++
870
871 Description:
872
873 This routine checks if a path is a mount point.
874
875 Arguments:
876
877 Fd - Supplies the file descriptor to start resolving the path.
878
879 Path - Supplies the path.
880
881 Return Value:
882
883 Returns 0 if the path is not a mount point, 1 if it is a mount point, or
884 -1 on failure.
885
886 --*/
887
888 {
889
890 char LocalPath[PATH_MAX];
891 char* ParentPath;
892 struct stat ParentStat;
893 int Result;
894 struct stat Stat;
895
896 LxtCheckErrnoZeroSuccess(fstatat(DirFd, Path, &Stat, AT_SYMLINK_NOFOLLOW));
897 strncpy(LocalPath, Path, sizeof(LocalPath) - 1);
898 ParentPath = dirname(LocalPath);
899 LxtCheckErrnoZeroSuccess(fstatat(DirFd, ParentPath, &ParentStat, AT_SYMLINK_NOFOLLOW));
900
901 LxtLogInfo(
902 "%s device: %u,%u; %s device: %u,%u", ParentPath, major(ParentStat.st_dev), minor(ParentStat.st_dev), Path, major(Stat.st_dev), minor(Stat.st_dev));
903
904 if (Stat.st_dev == ParentStat.st_dev)
905 {
906 Result = 0;
907 }
908 else
909 {
910 Result = 1;
911 }
912
913 ErrorExit:
914 return Result;
915 }
916
917 int MountPrepareTmpfs(char* Path, char* Device, int ExpectedParentId)
918
919 /*++
920
921 Description:
922
923 This routine creates a tmpfs mount for testing.
924
925 Arguments:
926
927 Path - Supplies the mount point path.
928
929 Device - Supplies the device name to use.
930
931 ExpectedParentId - Supplies the expected parent mount ID.
932
933 Return Value:
934
935 Returns the mount ID on success, -1 on failure.
936
937 --*/
938
939 {
940
941 return MountPrepareTmpfsEx(Path, Device, ExpectedParentId, 0, "rw,relatime");
942 }
943
944 int MountPrepareTmpfsEx(char* Path, char* Device, int ExpectedParentId, int Flags, const char* ExpectedOptions)
945
946 /*++
947
948 Description:
949
950 This routine creates a tmpfs mount for testing.
951
952 Arguments:
953
954 Path - Supplies the mount point path.
955
956 Device - Supplies the device name to use.
957
958 ExpectedParentId - Supplies the expected parent mount ID.
959
960 Flags - Supplies the mount flags.
961
962 ExpectedOptions - Supplies the expected mount option string.
963
964 Return Value:
965
966 Returns the mount ID on success, -1 on failure.
967
968 --*/
969
970 {
971
972 int MountId;
973 int Result;
974
975 LxtCheckErrnoZeroSuccess(mkdir(Path, 0700));
976 LxtCheckErrnoZeroSuccess(mount(Device, Path, "tmpfs", Flags, NULL));
977 LxtCheckResult(MountId = MountCheckIsMount(Path, ExpectedParentId, Device, "tmpfs", "/", ExpectedOptions, "rw", ExpectedOptions, 0));
978
979 Result = MountId;
980
981 ErrorExit:
982 return Result;
983 }