VirtualBox

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

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

Runtime/linux/sysfs: RTLinuxSysFsReadStr() has to be return VERR_BUFFER_OVERFLOW like RTLinuxSysFsReadFile()

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 18.8 KB
Line 
1/* $Id: sysfs.cpp 60424 2016-04-11 12:55:57Z 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.215389.xyz. 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) RTLinuxSysFsOpenExV(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, va_list va)
195{
196 /*
197 * Construct the filename and call open.
198 */
199 char szFilename[RTPATH_MAX];
200 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
201 if (RT_SUCCESS(rc))
202 rc = RTFileOpen(phFile, szFilename, fOpen);
203 return rc;
204}
205
206
207RTDECL(int) RTLinuxSysFsOpen(PRTFILE phFile, const char *pszFormat, ...)
208{
209 va_list va;
210 va_start(va, pszFormat);
211 int rc = RTLinuxSysFsOpenV(phFile, pszFormat, va);
212 va_end(va);
213 return rc;
214}
215
216
217RTDECL(int) RTLinuxSysFsOpenEx(PRTFILE phFile, uint64_t fOpen, const char *pszFormat, ...)
218{
219 va_list va;
220 va_start(va, pszFormat);
221 int rc = RTLinuxSysFsOpenExV(phFile, fOpen, pszFormat, va);
222 va_end(va);
223 return rc;
224}
225
226
227RTDECL(int) RTLinuxSysFsReadStr(RTFILE hFile, char *pszBuf, size_t cchBuf, size_t *pcchRead)
228{
229 Assert(cchBuf > 1);
230 size_t cchRead = 0;
231 int rc = RTFileRead(hFile, pszBuf, cchBuf - 1, &cchRead);
232 pszBuf[RT_SUCCESS(rc) ? cchRead : 0] = '\0';
233 if ( RT_SUCCESS(rc)
234 && pcchRead)
235 *pcchRead = cchRead;
236 if (RT_SUCCESS(rc))
237 {
238 /* Check for EOF */
239 uint64_t offCur = 0;
240 uint64_t offEnd = 0;
241 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_CURRENT, &offCur);
242 if (RT_SUCCESS(rc))
243 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, &offEnd);
244 if ( RT_SUCCESS(rc)
245 && offEnd > offCur)
246 rc = VERR_BUFFER_OVERFLOW;
247 }
248 return rc;
249}
250
251
252RTDECL(int) RTLinuxSysFsWriteStr(RTFILE hFile, const char *pszBuf, size_t cchBuf, size_t *pcchWritten)
253{
254 if (!cchBuf)
255 cchBuf = strlen(pszBuf);
256 return RTFileWrite(hFile, pszBuf, cchBuf, pcchWritten);
257}
258
259
260RTDECL(int) RTLinuxSysFsReadFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbRead)
261{
262 int rc;
263 size_t cbRead = 0;
264
265 rc = RTFileRead(hFile, pvBuf, cbBuf, &cbRead);
266 if (RT_SUCCESS(rc))
267 {
268 if (pcbRead)
269 *pcbRead = cbRead;
270 if (cbRead < cbBuf)
271 rc = VINF_SUCCESS;
272 else
273 {
274 /* Check for EOF */
275 uint64_t offCur = 0;
276 uint64_t offEnd = 0;
277 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_CURRENT, &offCur);
278 if (RT_SUCCESS(rc))
279 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, &offEnd);
280 if ( RT_SUCCESS(rc)
281 && offEnd > offCur)
282 rc = VERR_BUFFER_OVERFLOW;
283 }
284 }
285
286 return rc;
287}
288
289
290RTDECL(int) RTLinuxSysFsWriteFile(RTFILE hFile, void *pvBuf, size_t cbBuf, size_t *pcbWritten)
291{
292 return RTFileWrite(hFile, pvBuf, cbBuf, pcbWritten);
293}
294
295
296RTDECL(int) RTLinuxSysFsReadIntFileV(unsigned uBase, int64_t *pi64, const char *pszFormat, va_list va)
297{
298 RTFILE hFile;
299
300 AssertPtrReturn(pi64, VERR_INVALID_POINTER);
301
302 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
303 if (RT_SUCCESS(rc))
304 {
305 char szNum[128];
306 size_t cchNum;
307 rc = RTLinuxSysFsReadStr(hFile, szNum, sizeof(szNum), &cchNum);
308 if (RT_SUCCESS(rc))
309 {
310 if (cchNum > 0)
311 {
312 int64_t i64Ret = -1;
313 rc = RTStrToInt64Ex(szNum, NULL, uBase, &i64Ret);
314 if (RT_SUCCESS(rc))
315 *pi64 = i64Ret;
316 }
317 else
318 rc = VERR_INVALID_PARAMETER;
319 }
320
321 RTFileClose(hFile);
322 }
323
324 return rc;
325}
326
327
328RTDECL(int) RTLinuxSysFsReadIntFile(unsigned uBase, int64_t *pi64, const char *pszFormat, ...)
329{
330 va_list va;
331 va_start(va, pszFormat);
332 int rc = RTLinuxSysFsReadIntFileV(uBase, pi64, pszFormat, va);
333 va_end(va);
334 return rc;
335}
336
337
338RTDECL(int) RTLinuxSysFsWriteU8FileV(unsigned uBase, uint8_t u8, const char *pszFormat, va_list va)
339{
340 return RTLinuxSysFsWriteU64FileV(uBase, u8, pszFormat, va);
341}
342
343
344RTDECL(int) RTLinuxSysFsWriteU8File(unsigned uBase, uint8_t u8, const char *pszFormat, ...)
345{
346 va_list va;
347 va_start(va, pszFormat);
348 int rc = RTLinuxSysFsWriteU64FileV(uBase, u8, pszFormat, va);
349 va_end(va);
350 return rc;
351}
352
353
354RTDECL(int) RTLinuxSysFsWriteU16FileV(unsigned uBase, uint16_t u16, const char *pszFormat, va_list va)
355{
356 return RTLinuxSysFsWriteU64FileV(uBase, u16, pszFormat, va);
357}
358
359
360RTDECL(int) RTLinuxSysFsWriteU16File(unsigned uBase, uint16_t u16, const char *pszFormat, ...)
361{
362 va_list va;
363 va_start(va, pszFormat);
364 int rc = RTLinuxSysFsWriteU64FileV(uBase, u16, pszFormat, va);
365 va_end(va);
366 return rc;
367}
368
369
370RTDECL(int) RTLinuxSysFsWriteU32FileV(unsigned uBase, uint32_t u32, const char *pszFormat, va_list va)
371{
372 return RTLinuxSysFsWriteU64FileV(uBase, u32, pszFormat, va);
373}
374
375
376RTDECL(int) RTLinuxSysFsWriteU32File(unsigned uBase, uint32_t u32, const char *pszFormat, ...)
377{
378 va_list va;
379 va_start(va, pszFormat);
380 int rc = RTLinuxSysFsWriteU64FileV(uBase, u32, pszFormat, va);
381 va_end(va);
382 return rc;
383}
384
385
386RTDECL(int) RTLinuxSysFsWriteU64FileV(unsigned uBase, uint64_t u64, const char *pszFormat, va_list va)
387{
388 RTFILE hFile;
389
390 const char *pszFmt = NULL;
391 switch (uBase)
392 {
393 case 8:
394 pszFmt = "%#llo";
395 break;
396 case 10:
397 pszFmt = "%llu";
398 break;
399 case 16:
400 pszFmt = "%#llx";
401 break;
402 default:
403 return VERR_INVALID_PARAMETER;
404 }
405
406 int rc = RTLinuxSysFsOpenExV(&hFile, RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_DENY_NONE, pszFormat, va);
407 if (RT_SUCCESS(rc))
408 {
409 char szNum[128];
410 size_t cchNum = RTStrPrintf(szNum, sizeof(szNum), pszFmt, u64);
411 if (cchNum > 0)
412 {
413 size_t cbWritten = 0;
414 rc = RTLinuxSysFsWriteStr(hFile, &szNum[0], cchNum, &cbWritten);
415 if ( RT_SUCCESS(rc)
416 && cbWritten != cchNum)
417 rc = VERR_BUFFER_OVERFLOW;
418 }
419 else
420 rc = VERR_INVALID_PARAMETER;
421
422 RTFileClose(hFile);
423 }
424
425 return rc;
426}
427
428
429RTDECL(int) RTLinuxSysFsWriteU64File(unsigned uBase, uint32_t u64, const char *pszFormat, ...)
430{
431 va_list va;
432 va_start(va, pszFormat);
433 int rc = RTLinuxSysFsWriteU64FileV(uBase, u64, pszFormat, va);
434 va_end(va);
435 return rc;
436}
437
438
439RTDECL(int) RTLinuxSysFsReadDevNumFileV(dev_t *pDevNum, const char *pszFormat, va_list va)
440{
441 RTFILE hFile;
442
443 AssertPtrReturn(pDevNum, VERR_INVALID_POINTER);
444
445 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
446 if (RT_SUCCESS(rc))
447 {
448 size_t cchNum = 0;
449 char szNum[128];
450 rc = RTLinuxSysFsReadStr(hFile, szNum, sizeof(szNum), &cchNum);
451 if (RT_SUCCESS(rc))
452 {
453 if (cchNum > 0)
454 {
455 uint32_t u32Maj = 0;
456 uint32_t u32Min = 0;
457 char *pszNext = NULL;
458 rc = RTStrToUInt32Ex(szNum, &pszNext, 10, &u32Maj);
459 if (RT_FAILURE(rc) || (rc != VWRN_TRAILING_CHARS) || (*pszNext != ':'))
460 rc = VERR_INVALID_PARAMETER;
461 else
462 {
463 rc = RTStrToUInt32Ex(pszNext + 1, NULL, 10, &u32Min);
464 if ( rc != VINF_SUCCESS
465 && rc != VWRN_TRAILING_CHARS
466 && rc != VWRN_TRAILING_SPACES)
467 rc = VERR_INVALID_PARAMETER;
468 else
469 *pDevNum = makedev(u32Maj, u32Min);
470 }
471 }
472 else
473 rc = VERR_INVALID_PARAMETER;
474 }
475
476 RTFileClose(hFile);
477 }
478
479 return rc;
480}
481
482
483RTDECL(int) RTLinuxSysFsReadDevNumFile(dev_t *pDevNum, const char *pszFormat, ...)
484{
485 va_list va;
486 va_start(va, pszFormat);
487 int rc = RTLinuxSysFsReadDevNumFileV(pDevNum, pszFormat, va);
488 va_end(va);
489 return rc;
490}
491
492
493RTDECL(int) RTLinuxSysFsReadStrFileV(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, va_list va)
494{
495 RTFILE hFile;
496
497 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
498
499 int rc = RTLinuxSysFsOpenV(&hFile, pszFormat, va);
500 if (RT_SUCCESS(rc))
501 {
502 size_t cchRead = 0;
503 rc = RTLinuxSysFsReadStr(hFile, pszBuf, cchBuf, &cchRead);
504 RTFileClose(hFile);
505 if ( RT_SUCCESS(rc)
506 && cchRead > 0)
507 {
508 char *pchNewLine = (char *)memchr(pszBuf, '\n', cchRead);
509 if (pchNewLine)
510 *pchNewLine = '\0';
511 }
512
513 if (pcchRead)
514 *pcchRead = cchRead;
515 }
516 return rc;
517}
518
519
520RTDECL(int) RTLinuxSysFsReadStrFile(char *pszBuf, size_t cchBuf, size_t *pcchRead, const char *pszFormat, ...)
521{
522 va_list va;
523 va_start(va, pszFormat);
524 int rc = RTLinuxSysFsReadStrFileV(pszBuf, cchBuf, pcchRead, pszFormat, va);
525 va_end(va);
526 return rc;
527}
528
529
530RTDECL(int) RTLinuxSysFsWriteStrFileV(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, va_list va)
531{
532 RTFILE hFile;
533
534 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
535
536 int rc = RTLinuxSysFsOpenExV(&hFile, RTFILE_O_OPEN | RTFILE_O_WRITE | RTFILE_O_DENY_NONE, pszFormat, va);
537 if (RT_SUCCESS(rc))
538 {
539 rc = RTLinuxSysFsWriteStr(hFile, pszBuf, cchBuf, pcchWritten);
540 RTFileClose(hFile);
541 }
542 return rc;
543}
544
545
546RTDECL(int) RTLinuxSysFsWriteStrFile(const char *pszBuf, size_t cchBuf, size_t *pcchWritten, const char *pszFormat, ...)
547{
548 va_list va;
549 va_start(va, pszFormat);
550 int rc = RTLinuxSysFsWriteStrFileV(pszBuf, cchBuf, pcchWritten, pszFormat, va);
551 va_end(va);
552 return rc;
553}
554
555RTDECL(int) RTLinuxSysFsGetLinkDestV(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, va_list va)
556{
557 AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
558
559 /*
560 * Construct the filename and read the link.
561 */
562 char szFilename[RTPATH_MAX];
563 int rc = rtLinuxSysFsConstructPath(szFilename, sizeof(szFilename), pszFormat, va);
564 if (RT_SUCCESS(rc))
565 {
566 char szLink[RTPATH_MAX];
567 rc = RTSymlinkRead(szFilename, szLink, sizeof(szLink), 0);
568 if (RT_SUCCESS(rc))
569 {
570 /*
571 * Extract the file name component and copy it into the return buffer.
572 */
573 size_t cchName;
574 const char *pszName = RTPathFilename(szLink);
575 if (pszName)
576 {
577 cchName = strlen(pszName);
578 if (cchName < cchBuf)
579 memcpy(pszBuf, pszName, cchName + 1);
580 else
581 rc = VERR_BUFFER_OVERFLOW;
582 }
583 else
584 {
585 *pszBuf = '\0';
586 cchName = 0;
587 }
588
589 if (pchBuf)
590 *pchBuf = cchName;
591 }
592 }
593
594 return rc;
595}
596
597
598RTDECL(int) RTLinuxSysFsGetLinkDest(char *pszBuf, size_t cchBuf, size_t *pchBuf, const char *pszFormat, ...)
599{
600 va_list va;
601 va_start(va, pszFormat);
602 int rc = RTLinuxSysFsGetLinkDestV(pszBuf, cchBuf, pchBuf, pszFormat, va);
603 va_end(va);
604 return rc;
605}
606
607
608RTDECL(int) RTLinuxCheckDevicePathV(dev_t DevNum, RTFMODE fMode, char *pszBuf,
609 size_t cchBuf, const char *pszPattern,
610 va_list va)
611{
612 AssertReturn(cchBuf >= 2, VERR_INVALID_PARAMETER);
613 AssertReturn( fMode == RTFS_TYPE_DEV_CHAR
614 || fMode == RTFS_TYPE_DEV_BLOCK,
615 VERR_INVALID_PARAMETER);
616 AssertPtrReturn(pszPattern, VERR_INVALID_PARAMETER);
617
618 /*
619 * Construct the filename and read the link.
620 */
621 char szFilename[RTPATH_MAX];
622 int rc = rtLinuxConstructPathV(szFilename, sizeof(szFilename), "/dev/",
623 pszPattern, va);
624 if (RT_SUCCESS(rc))
625 {
626 RTFSOBJINFO Info;
627 rc = RTPathQueryInfo(szFilename, &Info, RTFSOBJATTRADD_UNIX);
628 if ( rc == VERR_PATH_NOT_FOUND
629 || ( RT_SUCCESS(rc)
630 && ( Info.Attr.u.Unix.Device != DevNum
631 || (Info.Attr.fMode & RTFS_TYPE_MASK) != fMode)))
632 rc = VERR_FILE_NOT_FOUND;
633
634 if (RT_SUCCESS(rc))
635 {
636 size_t cchPath = strlen(szFilename);
637 if (cchPath < cchBuf)
638 memcpy(pszBuf, szFilename, cchPath + 1);
639 else
640 rc = VERR_BUFFER_OVERFLOW;
641 }
642 }
643
644 return rc;
645}
646
647
648RTDECL(int) RTLinuxCheckDevicePath(dev_t DevNum, RTFMODE fMode, char *pszBuf,
649 size_t cchBuf, const char *pszPattern,
650 ...)
651{
652 va_list va;
653 va_start(va, pszPattern);
654 int rc = RTLinuxCheckDevicePathV(DevNum, fMode, pszBuf, cchBuf,
655 pszPattern, va);
656 va_end(va);
657 return rc;
658}
659
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