Whamcloud - gitweb
LU-10444 utils: Don't remount debugfs every time
[fs/lustre-release.git] / libcfs / libcfs / util / param.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the GNU Lesser General Public License
8  * (LGPL) version 2.1 or (at your discretion) any later version.
9  * (LGPL) version 2.1 accompanies this distribution, and is available at
10  * http://www.gnu.org/licenses/lgpl-2.1.html
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * LGPL HEADER END
18  */
19 /*
20  * libcfs/libcfs/utils/param.c
21  *
22  * This code handles user interaction with the configuration interface
23  * to the Lustre file system to fine tune it.
24  */
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <glob.h>
28 #include <mntent.h>
29 #include <paths.h>
30 #include <stdarg.h>
31 #include <stdbool.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/mount.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <linux/limits.h>
40 #include <libcfs/util/string.h>
41 #include <sys/vfs.h>
42 #include <linux/magic.h>
43
44 /**
45  * Get parameter path matching the pattern
46  *
47  * \param[out] paths    glob_t structure used to hold the final result
48  * \param[in]  pattern  the pattern containing sprintf format specifiers
49  *                      which will be used to create the path to match
50  *
51  * The \param pattern is appended to the default path glob to complete the
52  * absolute path to the file the caller is requesting. If the results point
53  * to one or more files that exist those results are stored in the \param
54  * paths glob_t structure that is passed by the caller.
55  *
56  * Lustre tunables traditionally were in /proc/{sys,fs}/{lnet,lustre}
57  * but in upstream kernels starting with Linux 4.2 these parameters
58  * have been moved to /sys/fs/lustre and /sys/kernel/debug/{lnet,lustre}
59  * so the user tools need to check both locations.
60  *
61  * \retval       0 for success, with results stored in \param paths.
62  * \retval      -1 for failure with errno set to report the reason.
63  */
64 int
65 cfs_get_param_paths(glob_t *paths, const char *pattern, ...)
66 {
67         char path[PATH_MAX] = "{/sys/{fs,kernel/debug}/{lnet,lustre}/,"
68                                "/proc/{fs,sys}/{lnet,lustre}/}";
69         static bool test_mounted = false;
70         size_t len = strlen(path);
71         char buf[PATH_MAX];
72         struct statfs statfsbuf;
73         va_list args;
74         int rc;
75
76
77         if (test_mounted)
78                 goto skip_mounting;
79         test_mounted = true;
80
81         rc = statfs("/sys/kernel/debug/", &statfsbuf);
82         if (rc == 0 && statfsbuf.f_type == DEBUGFS_MAGIC)
83                 goto skip_mounting;
84
85         if (mount("none", "/sys/kernel/debug", "debugfs", 0, "") == -1) {
86                 /* Already mounted or don't have permission to mount is okay */
87                 if (errno != EPERM && errno != EBUSY)
88                         fprintf(stderr, "Warning: failed to mount debug: %s\n",
89                                 strerror(errno));
90         } else {
91                 struct stat mtab;
92
93                 /* This is all for RHEL6 which is old school. Can be removed
94                  * later when RHEL6 client support is dropped. */
95                 rc = lstat(_PATH_MOUNTED, &mtab);
96                 if (!rc && !S_ISLNK(mtab.st_mode)) {
97                         FILE *fp = setmntent(_PATH_MOUNTED, "r+");
98
99                         if (fp != NULL) {
100                                 const struct mntent fs = {
101                                         .mnt_fsname     = "debugfs",
102                                         .mnt_dir        = "/sys/kernel/debug",
103                                         .mnt_type       = "debugfs",
104                                         .mnt_opts       = "rw,relatime",
105                                 };
106
107                                 rc = addmntent(fp, &fs);
108                                 if (rc) {
109                                         fprintf(stderr,
110                                                 "failed to add debugfs to %s: %s\n",
111                                                 _PATH_MOUNTED, strerror(errno));
112                                 }
113                                 endmntent(fp);
114                         } else {
115                                 fprintf(stderr, "could not open %s: %s\n",
116                                         _PATH_MOUNTED, strerror(errno));
117                         }
118                 }
119         }
120 skip_mounting:
121         va_start(args, pattern);
122         rc = vsnprintf(buf, sizeof(buf), pattern, args);
123         va_end(args);
124         if (rc < 0) {
125                 return rc;
126         } else if (rc >= sizeof(buf)) {
127                 errno = EINVAL;
128                 return -1;
129         }
130         len += rc;
131
132         if (strlcat(path, buf, sizeof(path)) != len) {
133                 errno = E2BIG;
134                 return -1;
135         }
136
137         rc = glob(path, GLOB_BRACE, NULL, paths);
138         if (rc != 0) {
139                 switch (rc) {
140                 case GLOB_NOSPACE:
141                         errno = ENOMEM;
142                         break;
143                 case GLOB_ABORTED:
144                         errno = ENODEV;
145                         break;
146                 case GLOB_NOMATCH:
147                 default:
148                         errno = ENOENT;
149                         break;
150                 }
151                 rc = -1;
152         }
153
154         return rc;
155 }