VirtualBox

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

Last change on this file since 60373 was 60373, checked in by vboxsync, 9 years ago

Runtime/linux/sysfs.cpp: Convert RTLinuxSysFs* API to always use IPRT status codes instead of using errno and adapt all of its users

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.2 KB
Line 
1/* $Id: sysfs.cpp 60373 2016-04-07 14:21:30Z vboxsync $ */
2/** @file
3 * IPRT - Linux sysfs access.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_SYSTEM
32#include <iprt/assert.h>
33#include <iprt/dir.h>
34#include <iprt/err.h>
35#include <iprt/file.h>
36#include <iprt/fs.h>
37#include <iprt/param.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40#include <iprt/symlink.h>
41
42#include <iprt/linux/sysfs.h>
43
44#include <unistd.h>
45#include <stdio.h>
46#include <sys/sysctl.h>
47#include <sys/stat.h>
48#include <sys/fcntl.h>
49#include <errno.h>
50
51
52
53/**
54 * Constructs the path of a sysfs file from the format parameters passed,
55 * prepending a prefix if the path is relative.
56 *
57 * @returns IPRT status code.
58 * @param pszPrefix The prefix to prepend if the path is relative. Must end
59 * in '/'.
60 * @param pszBuf Where to write the path. Must be at least
61 * sizeof(@a pszPrefix) characters long
62 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
63 * @param pszFormat The name format, either absolute or relative to the
64 * prefix specified by @a pszPrefix.
65 * @param va The format args.
66 */
67static int rtLinuxConstructPathV(char *pszBuf, size_t cchBuf,
68 const char *pszPrefix,
69 const char *pszFormat, va_list va)
70{
71 size_t cchPrefix = strlen(pszPrefix);
72 AssertReturn(pszPrefix[cchPrefix - 1] == '/', VERR_INVALID_PARAMETER);
73 AssertReturn(cchBuf > cchPrefix + 1, VERR_INVALID_PARAMETER);
74
75 /** @todo While RTStrPrintfV prevents overflows, it doesn't make it easy to
76 * check for truncations. RTPath should provide some formatters and
77 * joiners which can take over this rather common task that is
78 * performed here. */
79 size_t cch = RTStrPrintfV(pszBuf, cchBuf, pszFormat, va);
80 if (*pszBuf != '/')
81 {
82 AssertReturn(cchBuf >= cch + cchPrefix + 1, VERR_BUFFER_OVERFLOW);
83 memmove(pszBuf + cchPrefix, pszBuf, cch + 1);
84 memcpy(pszBuf, pszPrefix, cchPrefix);
85 cch += cchPrefix;
86 }
87 return VINF_SUCCESS;
88}
89
90
91/**
92 * Constructs the path of a sysfs file from the format parameters passed,
93 * prepending a prefix if the path is relative.
94 *
95 * @returns IPRT status code.
96 * @param pszPrefix The prefix to prepend if the path is relative. Must end
97 * in '/'.
98 * @param pszBuf Where to write the path. Must be at least
99 * sizeof(@a pszPrefix) characters long
100 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
101 * @param pszFormat The name format, either absolute or relative to "/sys/".
102 * @param ... The format args.
103 */
104DECLINLINE(int) rtLinuxConstructPath(char *pszBuf, size_t cchBuf,
105 const char *pszPrefix,
106 const char *pszFormat, ...)
107{
108 va_list va;
109 va_start(va, pszFormat);
110 int rc = rtLinuxConstructPathV(pszBuf, cchBuf, pszPrefix, pszFormat, va);
111 va_end(va);
112 return rc;
113}
114
115
116/**
117 * Constructs the path of a sysfs file from the format parameters passed,
118 * prepending "/sys/" if the path is relative.
119 *
120 * @returns IPRT status code.
121 * @param pszBuf Where to write the path. Must be at least
122 * sizeof("/sys/") characters long
123 * @param cchBuf The size of the buffer pointed to by @a pszBuf.
124 * @param pszFormat The name format, either absolute or relative to "/sys/".
125 * @param va The format args.
126 */
127DECLINLINE(int) rtLinuxSysFsConstructPath(char *pszBuf, size_t cchBuf, const char *pszFormat, va_list va)
128{
129 return rtLinuxConstructPathV(pszBuf, cchBuf, "/sys/", pszFormat, va);
130}
131
132
133RTDECL(int) RTLinuxSysFsExistsExV(const char *pszFormat, va_list va)
134{
135 int iSavedErrno = errno;
136
137 /*
138 * Construct the filename and call stat.
139 */
140 char szFilename[RTPATH_MAX];
141 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
142 if (RT_SUCCESS(rc))
143 {
144 struct stat st;
145 int rcStat = stat(szFilename, &st);
146 if (rcStat != 0)
147 rc = RTErrConvertFromErrno(errno);
148 }
149
150 errno = iSavedErrno;
151 return rc;
152}
153
154
155RTDECL(bool) RTLinuxSysFsExistsV(const char *pszFormat, va_list va)
156{
157 return RT_SUCCESS(RTLinuxSysFsExistsExV(pszFormat, va));
158}
159
160
161RTDECL(int) RTLinuxSysFsExistsEx(const char *pszFormat, ...)
162{
163 va_list va;
164 va_start(va, pszFormat);
165 int rc = RTLinuxSysFsExistsExV(pszFormat, va);
166 va_end(va);
167 return rc;
168}
169
170
171RTDECL(bool) RTLinuxSysFsExists(const char *pszFormat, ...)
172{
173 va_list va;
174 va_start(va, pszFormat);
175 bool fRet = RTLinuxSysFsExistsV(pszFormat, va);
176 va_end(va);
177 return fRet;
178}
179
180
181RTDECL(int) RTLinuxSysFsOpenV(PRTFILE phFile, const char *pszFormat, va_list va)
182{
183 /*
184 * Construct the filename and call open.
185 */
186 char szFilename[RTPATH_MAX];
187 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
188 if (RT_SUCCESS(rc))
189 rc = RTFileOpen(phFile, szFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
190 return rc;
191}
192
193
194RTDECL(int) RTLinuxSysFsOpen(PRTFILE phFile, const char *pszFormat, ...)
195{
196 va_list va;
197 va_start(va, pszFormat);
198 int rc = RTLinuxSysFsOpenV(phFile, pszFormat, va);
199 va_end(va);
200 return rc;
201}
202
203
204RTDECL(int) RTLinuxSysFsReadStr(RTFILE hFile, char *pszBuf, size_t cchBuf, size_t *pcchRead)
205{
206 Assert(cchBuf > 1);
207 size_t cchRead = 0;
208 int rc = RTFileRead(hFile, pszBuf, cchBuf - 1, &cchRead);
209 pszBuf[RT_SUCCESS(rc) ? cchRead : 0] = '\0';
210 if ( RT_SUCCESS(rc)
211 && pcchRead)
212 *pcchRead = cchRead;
213
214 return rc;
215}
216
217
218RTDECL(int) RTLinuxSysFsReadFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbRead)
219{
220 int rc;
221 size_t cbRead = 0;
222
223 rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead);
224 if (RT_SUCCESS(rc))
225 {
226 if (pcbRead)
227 *pcbRead = cbRead;
228 if (cbRead < cbBuf)
229 rc = VINF_SUCCESS;
230 else
231 {
232 /* Check for EOF */
233 char ch;
234 uint64_t offCur = 0;
235 uint64_t offEnd = 0;
236 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_CURRENT, &offCur);
237 if (RT_SUCCESS(rc))
238 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, &offEnd);
239 if ( RT_SUCCESS(rc)
240 && offEnd > offCur)
241 rc = VERR_BUFFER_OVERFLOW;
242 }
243 }
244
245 return rc;
246}
247
248
249RTDECL(int) RTLinuxSysFsReadIntFileV(unsigned uBase, int64_t *pi64, const char *pszFormat, va_list va)
250{
251 RTFILE hFile;
252
253 AssertPtrReturn(pi64, VERR_INVALID_POINTER);
254
255 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
256 if (RT_SUCCESS(rc))
257 {
258 char szNum[128];
259 size_t cchNum;
260 rc = RTLinuxSysFsReadStr(hFile, szNum, sizeof(szNum), &cchNum);
261 if (RT_SUCCESS(rc))
262 {
263 if (cchNum > 0)
264 {
265 int64_t i64Ret = -1;
266 rc = RTStrToInt64Ex(szNum, NULL, uBase, &i64Ret);
267 if (RT_SUCCESS(rc))
268 *pi64 = i64Ret;
269 }
270 else
271 rc = VERR_INVALID_PARAMETER;
272 }
273
274 RTFileClose(hFile);
275 }
276
277 return rc;
278}
279
280
281RTDECL(int) RTLinuxSysFsReadIntFile(unsigned uBase, int64_t *pi64, const char *pszFormat, ...)
282{
283 va_list va;
284 va_start(va, pszFormat);
285 int rc = RTLinuxSysFsReadIntFileV(uBase, pi64, pszFormat, va);
286 va_end(va);
287 return rc;
288}
289
290
291RTDECL(int) RTLinuxSysFsReadDevNumFileV(dev_t *pDevNum, const char *pszFormat, va_list va)
292{
293 RTFILE hFile;
294
295 AssertPtrReturn(pDevNum, VERR_INVALID_POINTER);
296
297 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
298 if (RT_SUCCESS(rc))
299 {
300 size_t cchNum = 0;
301 char szNum[128];
302 rc = RTLinuxSysFsReadStr(hFile, szNum, sizeof(szNum), &cchNum);
303 if (RT_SUCCESS(rc))
304 {
305 if (cchNum > 0)
306 {
307 uint32_t u32Maj = 0;
308 uint32_t u32Min = 0;
309 char *pszNext = NULL;
310 rc = RTStrToUInt32Ex(szNum, &pszNext, 10, &u32Maj);
311 if (RT_FAILURE(rc) || (rc != VWRN_TRAILING_CHARS) || (*pszNext != ':'))
312 rc = VERR_INVALID_PARAMETER;
313 else
314 {
315 rc = RTStrToUInt32Ex(pszNext + 1, NULL, 10, &u32Min);
316 if ( rc != VINF_SUCCESS
317 && rc != VWRN_TRAILING_CHARS
318 && rc != VWRN_TRAILING_SPACES)
319 rc = VERR_INVALID_PARAMETER;
320 else
321 *pDevNum = makedev(u32Maj, u32Min);
322 }
323 }
324 else
325 rc = VERR_INVALID_PARAMETER;
326 }
327
328 RTFileClose(hFile);
329 }
330
331 return rc;
332}
333
334
335RTDECL(int) RTLinuxSysFsReadDevNumFile(dev_t *pDevNum, const char *pszFormat, ...)
336{
337 va_list va;
338 va_start(va, pszFormat);
339 int rc = RTLinuxSysFsReadDevNumFileV(pDevNum, pszFormat, va);
340 va_end(va);
341 return rc;
342}
343
344
345RTDECL(int) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, va_list va)
346{
347 RTFILE hFile;
348
349 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
350
351 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
352 if (RT_SUCCESS(rc))
353 {
354 size_t cchRead = 0;
355 rc = RTLinuxSysFsReadStr(hFile, pszBuf, cchBuf, &cchRead);
356 RTFileClose(hFile);
357 if ( RT_SUCCESS(rc)
358 && cchRead > 0)
359 {
360 char *pchNewLine = (char *)memchr(pszBuf, '\n', cchRead);
361 if (pchNewLine)
362 *pchNewLine = '\0';
363 }
364
365 if (pcchRead)
366 *pcchRead = cchRead;
367 }
368 return rc;
369}
370
371
372RTDECL(int) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, ...)
373{
374 va_list va;
375 va_start(va, pszFormat);
376 int rc = RTLinuxSysFsReadStrFileV(pszBuf, cchBuf, pcchRead, pszFormat, va);
377 va_end(va);
378 return rc;
379}
380
381
382RTDECL(int) RTLinuxSysFsGetLinkDestV(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, va_list va)
383{
384 AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
385
386 /*
387 * Construct the filename and read the link.
388 */
389 char szFilename[RTPATH_MAX];
390 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
391 if (RT_SUCCESS(rc))
392 {
393 char szLink[RTPATH_MAX];
394 rc = RTSymlinkRead(szFilename, szLink, sizeof(szLink), 0);
395 if (RT_SUCCESS(rc))
396 {
397 /*
398 * Extract the file name component and copy it into the return buffer.
399 */
400 size_t cchName;
401 const char *pszName = RTPathFilename(szLink);
402 if (pszName)
403 {
404 cchName = strlen(pszName);
405 if (cchName < cchBuf)
406 memcpy(pszBuf, pszName, cchName + 1);
407 else
408 rc = VERR_BUFFER_OVERFLOW;
409 }
410 else
411 {
412 *pszBuf = '\0';
413 cchName = 0;
414 }
415
416 if (pchBuf)
417 *pchBuf = cchName;
418 }
419 }
420
421 return rc;
422}
423
424
425RTDECL(int) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, ...)
426{
427 va_list va;
428 va_start(va, pszFormat);
429 int rc = RTLinuxSysFsGetLinkDestV(pszBuf, cchBuf, pchBuf, pszFormat, va);
430 va_end(va);
431 return rc;
432}
433
434
435RTDECL(int) RTLinuxCheckDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf,
436 size_t cchBuf, const char *pszPattern,
437 va_list va)
438{
439 AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
440 AssertReturn( fMode == RTFS_TYPE_DEV_CHAR
441 || fMode == RTFS_TYPE_DEV_BLOCK,
442 VERR_INVALID_PARAMETER);
443 AssertPtrReturn(pszPattern, VERR_INVALID_PARAMETER);
444
445 /*
446 * Construct the filename and read the link.
447 */
448 char szFilename[RTPATH_MAX];
449 int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/",
450 pszPattern, va);
451 if (RT_SUCCESS(rc))
452 {
453 RTFSOBJINFO Info;
454 rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
455 if ( rc == VERR_PATH_NOT_FOUND
456 || ( RT_SUCCESS(rc)
457 && ( Info.Attr.u.Unix.Device != DevNum
458 || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode)))
459 rc = VERR_FILE_NOT_FOUND;
460
461 if (RT_SUCCESS(rc))
462 {
463 size_t cchPath = strlen(szFilename);
464 if (cchPath < cchBuf)
465 memcpy(pszBuf, szFilename, cchPath + 1);
466 else
467 rc = VERR_BUFFER_OVERFLOW;
468 }
469 }
470
471 return rc;
472}
473
474
475RTDECL(int) RTLinuxCheckDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf,
476 size_t cchBuf, const char *pszPattern,
477 ...)
478{
479 va_list va;
480 va_start(va, pszPattern);
481 int rc = RTLinuxCheckDevicePathV(DevNum, fMode, pszBuf, cchBuf,
482 pszPattern, va);
483 va_end(va);
484 return rc;
485}
486
Note: See TracBrowser for help on using the repository browser.

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