1 /* 2 * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 #include "precompiled.hpp" 25 #include "gc/z/zArray.inline.hpp" 26 #include "gc/z/zErrno.hpp" 27 #include "gc/z/zMountPoint_linux.hpp" 28 #include "runtime/globals.hpp" 29 #include "logging/log.hpp" 30 31 #include <stdio.h> 32 #include <unistd.h> 33 34 // Mount information, see proc(5) for more details. 35 #define PROC_SELF_MOUNTINFO "/proc/self/mountinfo" 36 37 ZMountPoint::ZMountPoint(const char* filesystem, const char** preferred_mountpoints) { 38 if (AllocateHeapAt != NULL) { 39 // Use specified path 40 _path = strdup(AllocateHeapAt); 41 } else { 42 // Find suitable path 43 _path = find_mountpoint(filesystem, preferred_mountpoints); 44 } 45 } 46 47 ZMountPoint::~ZMountPoint() { 48 free(_path); 49 _path = NULL; 50 } 51 52 char* ZMountPoint::get_mountpoint(const char* line, const char* filesystem) const { 53 char* line_mountpoint = NULL; 54 char* line_filesystem = NULL; 55 56 // Parse line and return a newly allocated string containing the mount point if 57 // the line contains a matching filesystem and the mount point is accessible by 58 // the current user. 59 if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-]- %ms", &line_mountpoint, &line_filesystem) != 2 || 60 strcmp(line_filesystem, filesystem) != 0 || 61 access(line_mountpoint, R_OK|W_OK|X_OK) != 0) { 62 // Not a matching or accessible filesystem 63 free(line_mountpoint); 64 line_mountpoint = NULL; 65 } 66 67 free(line_filesystem); 68 69 return line_mountpoint; 70 } 71 72 void ZMountPoint::get_mountpoints(const char* filesystem, ZArray<char*>* mountpoints) const { 73 FILE* fd = fopen(PROC_SELF_MOUNTINFO, "r"); 74 if (fd == NULL) { 75 ZErrno err; 76 log_error(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string()); 77 return; 78 } 79 80 char* line = NULL; 81 size_t length = 0; 82 83 while (getline(&line, &length, fd) != -1) { 84 char* const mountpoint = get_mountpoint(line, filesystem); 85 if (mountpoint != NULL) { 86 mountpoints->add(mountpoint); 87 } 88 } 89 90 free(line); 91 fclose(fd); 92 } 93 94 void ZMountPoint::free_mountpoints(ZArray<char*>* mountpoints) const { 95 ZArrayIterator<char*> iter(mountpoints); 96 for (char* mountpoint; iter.next(&mountpoint);) { 97 free(mountpoint); 98 } 99 mountpoints->clear(); 100 } 101 102 char* ZMountPoint::find_preferred_mountpoint(const char* filesystem, 103 ZArray<char*>* mountpoints, 104 const char** preferred_mountpoints) const { 105 // Find preferred mount point 106 ZArrayIterator<char*> iter1(mountpoints); 107 for (char* mountpoint; iter1.next(&mountpoint);) { 108 for (const char** preferred = preferred_mountpoints; *preferred != NULL; preferred++) { 109 if (!strcmp(mountpoint, *preferred)) { 110 // Preferred mount point found 111 return strdup(mountpoint); 112 } 113 } 114 } 115 116 // Preferred mount point not found 117 log_error(gc)("More than one %s filesystem found:", filesystem); 118 ZArrayIterator<char*> iter2(mountpoints); 119 for (char* mountpoint; iter2.next(&mountpoint);) { 120 log_error(gc)(" %s", mountpoint); 121 } 122 123 return NULL; 124 } 125 126 char* ZMountPoint::find_mountpoint(const char* filesystem, const char** preferred_mountpoints) const { 127 char* path = NULL; 128 ZArray<char*> mountpoints; 129 130 get_mountpoints(filesystem, &mountpoints); 131 132 if (mountpoints.size() == 0) { 133 // No mount point found 134 log_error(gc)("Failed to find an accessible %s filesystem", filesystem); 135 } else if (mountpoints.size() == 1) { 136 // One mount point found 137 path = strdup(mountpoints.at(0)); 138 } else { 139 // More than one mount point found 140 path = find_preferred_mountpoint(filesystem, &mountpoints, preferred_mountpoints); 141 } 142 143 free_mountpoints(&mountpoints); 144 145 return path; 146 } 147 148 const char* ZMountPoint::get() const { 149 return _path; 150 }