VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/sysfs.cpp@ 15399

Last change on this file since 15399 was 15399, checked in by vboxsync, 16 years ago

iprt: new Linux sysfs APIs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.7 KB
Line 
1/* $Id: sysfs.cpp 15399 2008-12-12 22:02:14Z vboxsync $ */
2/** @file
3 * IPRT - Linux sysfs access.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_SYSTEM
36#include <unistd.h>
37#include <stdio.h>
38#include <sys/sysctl.h>
39#include <sys/stat.h>
40#include <sys/fcntl.h>
41#include <errno.h>
42
43#include <iprt/linux/sysfs.h>
44#include <iprt/assert.h>
45#include <iprt/param.h>
46#include <iprt/string.h>
47
48
49/**
50 * Constructs the path of a sysfs file from the format paramaters passed,
51 * prepending "/sys/" if the path is relative.
52 *
53 * @returns The number of characters written, or -1 and errno on failure.
54 * @param pszBuf Where to write the path. Must be at least
55 * sizeof("/sys/") characters long
56 * @param cchBuf The size of the buffer pointed to by @a pszBuf
57 * @param pszFormat The name format, either absolute or relative to "/sys/".
58 * @param va The format args.
59 */
60static ssize_t rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf,
61 const char *pszFormat, va_list va)
62{
63 char szFilename[RTPATH_MAX];
64 const char szPrefix[] = "/sys/";
65 if (cchBuf < sizeof(szPrefix))
66 AssertFailedReturnStmt(errno = EINVAL, -1);
67 size_t cch = RTStrPrintfV(szFilename, sizeof(szFilename), pszFormat, va);
68 if (szFilename[0] == '/')
69 *pszBuf = '\0';
70 else
71 strcpy(pszBuf, szPrefix);
72 strncat(pszBuf, szFilename, cchBuf);
73 return strlen(pszBuf);
74}
75
76/**
77 * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
78 *
79 * @returns true / false, errno is preserved.
80 * @param pszFormat The name format, either absolute or relative to "/sys/".
81 * @param va The format args.
82 */
83bool RTLinuxSysFsExistsV(const char *pszFormat, va_list va)
84{
85 int iSavedErrno = errno;
86
87 /*
88 * Construct the filename and call stat.
89 */
90 char szFilename[RTPATH_MAX];
91 bool fRet = false;
92 ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename),
93 pszFormat, va);
94 if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename))
95 {
96 struct stat st;
97 fRet = stat(szFilename, &st) == 0;
98 }
99
100 errno = iSavedErrno;
101 return fRet;
102}
103
104/**
105 * Checks if a sysfs file (or directory, device, symlink, whatever) exists.
106 *
107 * @returns true / false, errno is preserved.
108 * @param pszFormat The name format, either absolute or relative to "/sys/".
109 * @param ... The format args.
110 */
111bool RTLinuxSysFsExists(const char *pszFormat, ...)
112{
113 va_list va;
114 va_start(va, pszFormat);
115 bool fRet = RTLinuxSysFsExistsV(pszFormat, va);
116 va_end(va);
117 return fRet;
118}
119
120
121/**
122 * Opens a sysfs file.
123 *
124 * @returns The file descriptor. -1 and errno on failure.
125 * @param pszFormat The name format, either absolute or relative to "/sys/".
126 * @param va The format args.
127 */
128int RTLinuxSysFsOpenV(const char *pszFormat, va_list va)
129{
130 /*
131 * Construct the filename and call open.
132 */
133 char szFilename[RTPATH_MAX];
134 ssize_t rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename),
135 pszFormat, va);
136 if (rc > 0 && static_cast<size_t>(rc) < sizeof(szFilename))
137 rc = open(szFilename, O_RDONLY, 0);
138 return rc;
139}
140
141
142/**
143 * Opens a sysfs file.
144 *
145 * @returns The file descriptor. -1 and errno on failure.
146 * @param pszFormat The name format, either absolute or relative to "/sys/".
147 * @param ... The format args.
148 */
149int RTLinuxSysFsOpen(const char *pszFormat, ...)
150{
151 va_list va;
152 va_start(va, pszFormat);
153 int fd = RTLinuxSysFsOpenV(pszFormat, va);
154 va_end(va);
155 return fd;
156}
157
158
159/**
160 * Closes a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
161 *
162 * @param fd
163 */
164void RTLinuxSysFsClose(int fd)
165{
166 int iSavedErrno = errno;
167 close(fd);
168 errno = iSavedErrno;
169}
170
171
172/**
173 * Reads a string from a file opened with RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
174 *
175 * @returns The number of bytes read. -1 and errno on failure.
176 * @param fd The file descriptor returned by RTLinuxSysFsOpen or RTLinuxSysFsOpenV.
177 * @param pszBuf Where to store the string.
178 * @param cchBuf The size of the buffer. Must be at least 2 bytes.
179 */
180ssize_t RTLinuxSysFsReadStr(int fd, char *pszBuf, size_t cchBuf)
181{
182 Assert(cchBuf > 1);
183 ssize_t cchRead = read(fd, pszBuf, cchBuf - 1);
184 pszBuf[cchRead >= 0 ? cchRead : 0] = '\0';
185 return cchRead;
186}
187
188
189/**
190 * Reads a number from a sysfs file.
191 *
192 * @returns 64-bit signed value on success, -1 and errno on failure.
193 * @param uBase The number base, 0 for autodetect.
194 * @param pszFormat The filename format, either absolute or relative to "/sys/".
195 * @param va Format args.
196 */
197int64_t RTLinuxSysFsReadIntFileV(unsigned uBase, const char *pszFormat, va_list va)
198{
199 int fd = RTLinuxSysFsOpenV(pszFormat, va);
200 if (fd == -1)
201 return -1;
202
203 int64_t i64Ret = -1;
204 char szNum[128];
205 ssize_t cchNum = RTLinuxSysFsReadStr(fd, szNum, sizeof(szNum));
206 if (cchNum > 0)
207 {
208 int rc = RTStrToInt64Ex(szNum, NULL, uBase, &i64Ret);
209 if (RT_FAILURE(rc))
210 {
211 i64Ret = -1;
212 errno = -ETXTBSY; /* just something that won't happen at read / open. */
213 }
214 }
215 else if (cchNum == 0)
216 errno = -ETXTBSY; /* just something that won't happen at read / open. */
217
218 RTLinuxSysFsClose(fd);
219 return i64Ret;
220}
221
222
223/**
224 * Reads a number from a sysfs file.
225 *
226 * @returns 64-bit signed value on success, -1 and errno on failure.
227 * @param uBase The number base, 0 for autodetect.
228 * @param pszFormat The filename format, either absolute or relative to "/sys/".
229 * @param ... Format args.
230 */
231int64_t RTLinuxSysFsReadIntFile(unsigned uBase, const char *pszFormat, ...)
232{
233 va_list va;
234 va_start(va, pszFormat);
235 int64_t i64Ret = RTLinuxSysFsReadIntFileV(uBase, pszFormat, va);
236 va_end(va);
237 return i64Ret;
238}
239
240
241/**
242 * Reads a string from a sysfs file. If the file contains a newline, we only
243 * return the text up until there.
244 *
245 * @returns number of characters read on success, -1 and errno on failure.
246 * @param pszBuf Where to store the path element. Must be at least two
247 * characters, but a longer buffer would be advisable.
248 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
249 * @param pszFormat The filename format, either absolute or relative to "/sys/".
250 * @param va Format args.
251 */
252ssize_t RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
253{
254 int fd = RTLinuxSysFsOpenV(pszFormat, va);
255 if (fd == -1)
256 return -1;
257
258 ssize_t cchRet = RTLinuxSysFsReadStr(fd, pszBuf, cchBuf);
259 RTLinuxSysFsClose(fd);
260 char *pchNewLine = NULL;
261 if (cchRet > 0)
262 pchNewLine = reinterpret_cast<char *>(memchr(pszBuf, '\n', cchRet));
263 if (pchNewLine != NULL)
264 *pchNewLine = '\0';
265 return cchRet;
266}
267
268
269/**
270 * Reads a string from a sysfs file. If the file contains a newline, we only
271 * return the text up until there.
272 *
273 * @returns number of characters read on success, -1 and errno on failure.
274 * @param pszBuf Where to store the path element. Must be at least two
275 * characters, but a longer buffer would be advisable.
276 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
277 * @param pszFormat The filename format, either absolute or relative to "/sys/".
278 * @param ... Format args.
279 */
280ssize_t RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
281{
282 va_list va;
283 va_start(va, pszFormat);
284 ssize_t cchRet = RTLinuxSysFsReadStrFileV(pszBuf, cchBuf, pszFormat, va);
285 va_end(va);
286 return cchRet;
287}
288
289
290/**
291 * Reads the last element of the path of the file pointed to by the symbolic
292 * link specified. This is needed at least to get the name of the driver
293 * associated with a device, where pszFormat should be the "driver" link in the
294 * devices sysfs directory.
295 *
296 * @returns The number of characters written on success, -1 and errno on failure.
297 * @param pszBuf Where to store the path element. Must be at least two
298 * characters, but a longer buffer would be advisable.
299 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
300 * @param pszFormat The filename format, either absolute or relative to "/sys/".
301 * @param ... Format args.
302 */
303int RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, const char *pszFormat, ...)
304{
305 if (cchBuf < 2)
306 AssertFailedReturnStmt(errno = EINVAL, -1);
307 va_list va;
308 va_start(va, pszFormat);
309 char szFilename[RTPATH_MAX], szLink[RTPATH_MAX];
310 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
311 va_end(va);
312 if (rc == sizeof(szFilename))
313 {
314 rc = -1;
315 errno = EINVAL; /* Bad format arguements */
316 }
317 if (rc > 0)
318 rc = readlink(szFilename, szLink, sizeof(szLink));
319 if (rc > 0 && static_cast<size_t>(rc) > sizeof(szLink) - 1)
320 {
321 rc = -1;
322 errno = EIO; /* The path name can't be this big. */
323 }
324 if (rc >= 0)
325 {
326 szLink[rc] = '\0';
327 char *lastPart = strrchr(szLink, '/');
328 Assert(lastPart != NULL); /* rtLinuxSysFsConstructPath guarantees a path
329 * starting with '/'. */
330 *pszBuf = '\0';
331 strncat(pszBuf, lastPart + 1, cchBuf);
332 rc = strlen(pszBuf);
333 }
334 return rc;
335}
336
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette