1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3 * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG
4 * All rights reserved.
5 *******************************************************************************/
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <poll.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 /* Need for some libc-versions */
21 #ifndef __FreeBSD__
22 #include <malloc.h>
23 #endif
24
25 #include "tss2_common.h"
26 #include "ifapi_io.h"
27 #include "ifapi_helpers.h"
28 #include "ifapi_macros.h"
29 #define LOGMODULE fapi
30 #include "util/log.h"
31 #include "util/aux_util.h"
32
33 /** Start reading a file's complete content into memory in an asynchronous way.
34 *
35 * @param[in,out] io The input/output context being used for file I/O.
36 * @param[in] filename The name of the file to be read into memory.
37 * @retval TSS2_RC_SUCCESS: if the function call was a success.
38 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
39 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
40 */
41 TSS2_RC
ifapi_io_read_async(struct IFAPI_IO * io,const char * filename)42 ifapi_io_read_async(
43 struct IFAPI_IO *io,
44 const char *filename)
45 {
46 if (io->char_rbuffer) {
47 LOG_ERROR("rbuffer still in use; maybe use of old API.");
48 return TSS2_FAPI_RC_IO_ERROR;
49 }
50
51 io->stream = fopen(filename, "rt");
52 if (io->stream == NULL) {
53 LOG_ERROR("File \"%s\" not found.", filename);
54 return TSS2_FAPI_RC_IO_ERROR;
55 }
56 /* Locking the file. Lock will be release upon close */
57 if (lockf(fileno(io->stream), F_TLOCK, 0) == -1 && errno == EAGAIN) {
58 LOG_ERROR("File %s currently locked.", filename);
59 fclose(io->stream);
60 return TSS2_FAPI_RC_IO_ERROR;
61 }
62
63 fseek(io->stream, 0L, SEEK_END);
64 long length = ftell(io->stream);
65 fclose(io->stream);
66
67 io->stream = fopen(filename, "rt");
68 io->char_rbuffer = malloc (length + 1);
69 if (io->char_rbuffer == NULL) {
70 fclose(io->stream);
71 io->stream = NULL;
72 LOG_ERROR("Memory could not be allocated. %li bytes requested", length + 1);
73 return TSS2_FAPI_RC_MEMORY;
74 }
75
76 int rc, flags = fcntl(fileno(io->stream), F_GETFL, 0);
77 rc = fcntl(fileno(io->stream), F_SETFL, flags | O_NONBLOCK);
78 if (rc < 0) {
79 LOG_ERROR("fcntl failed with %d", errno);
80 return TSS2_FAPI_RC_IO_ERROR;
81 }
82
83 io->buffer_length = length;
84 io->buffer_idx = 0;
85 io->char_rbuffer[length] = '\0';
86
87 return TSS2_RC_SUCCESS;
88 }
89
90 /** Finish reading a file's complete content into memory in an asynchronous way.
91 *
92 * This function needs to be called repeatedly until it does not return TSS2_FAPI_RC_TRY_AGAIN.
93 *
94 * @param[in,out] io The input/output context being used for file I/O.
95 * @param[out] buffer The data that was read from file. (callee-allocated; use free())
96 * @param[out] length The length of the data that was read from file.
97 * @retval TSS2_RC_SUCCESS: if the function call was a success.
98 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
99 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet complete.
100 * Call this function again later.
101 */
102 TSS2_RC
ifapi_io_read_finish(struct IFAPI_IO * io,uint8_t ** buffer,size_t * length)103 ifapi_io_read_finish(
104 struct IFAPI_IO *io,
105 uint8_t **buffer,
106 size_t *length)
107 {
108 io->pollevents = POLLIN;
109 if (_ifapi_io_retry-- > 0)
110 return TSS2_FAPI_RC_TRY_AGAIN;
111 else
112 _ifapi_io_retry = _IFAPI_IO_RETRIES;
113
114 ssize_t ret = read(fileno(io->stream),
115 &io->char_rbuffer[io->buffer_idx],
116 io->buffer_length - io->buffer_idx);
117 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
118 return TSS2_FAPI_RC_TRY_AGAIN;
119
120 if (ret < 0) {
121 LOG_ERROR("Error reading from file: %i.", errno);
122 fclose(io->stream);
123 io->pollevents = 0;
124 SAFE_FREE(io->char_rbuffer);
125 return TSS2_FAPI_RC_IO_ERROR;
126 }
127
128 io->pollevents = 0;
129 io->buffer_idx += ret;
130 if (io->buffer_idx < io->buffer_length)
131 return TSS2_FAPI_RC_TRY_AGAIN;
132
133 fclose(io->stream);
134
135 if (!buffer) {
136 LOG_WARNING("The old file read API is still being used");
137 return TSS2_RC_SUCCESS;
138 }
139 *buffer = (uint8_t *)io->char_rbuffer;
140 io->char_rbuffer = NULL;
141
142 if (length)
143 *length = io->buffer_length;
144
145 return TSS2_RC_SUCCESS;
146 }
147
148 /** Start writing a buffer into a file in an asynchronous way.
149 *
150 * @param[in,out] io The input/output context being used for file I/O.
151 * @param[in] filename The name of the file to be read into memory.
152 * @param[in] buffer The buffer to be written.
153 * @param[in] length The number of bytes to be written.
154 * @retval TSS2_RC_SUCCESS: if the function call was a success.
155 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
156 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
157 */
158 TSS2_RC
ifapi_io_write_async(struct IFAPI_IO * io,const char * filename,const uint8_t * buffer,size_t length)159 ifapi_io_write_async(
160 struct IFAPI_IO *io,
161 const char *filename,
162 const uint8_t *buffer,
163 size_t length)
164 {
165 if (io->char_rbuffer) {
166 LOG_ERROR("rbuffer still in use; maybe use of old API.");
167 return TSS2_FAPI_RC_IO_ERROR;
168 }
169
170 io->buffer_length = length;
171 io->buffer_idx = 0;
172 io->char_rbuffer = malloc(length);
173 if (io->char_rbuffer == NULL) {
174 LOG_ERROR("Memory could not be allocated. %zi bytes requested", length);
175 return TSS2_FAPI_RC_MEMORY;
176 }
177 memcpy(io->char_rbuffer, buffer, length);
178
179 io->stream = fopen(filename, "wt");
180 if (io->stream == NULL) {
181 SAFE_FREE(io->char_rbuffer);
182 LOG_ERROR("Could not open file \"%s\" for writing.", filename);
183 return TSS2_FAPI_RC_IO_ERROR;
184 }
185 /* Locking the file. Lock will be release upon close */
186 if (lockf(fileno(io->stream), F_TLOCK, 0) == -1 && errno == EAGAIN) {
187 LOG_ERROR("File %s currently locked.", filename);
188 fclose(io->stream);
189 return TSS2_FAPI_RC_IO_ERROR;
190 }
191
192 /* Use non blocking IO, so asynchronous write will be needed */
193 int rc, flags = fcntl(fileno(io->stream), F_GETFL, 0);
194 rc = fcntl(fileno(io->stream), F_SETFL, flags | O_NONBLOCK);
195 if (rc < 0) {
196 LOG_ERROR("fcntl failed with %d", errno);
197 return TSS2_FAPI_RC_IO_ERROR;
198 }
199 return TSS2_RC_SUCCESS;
200 }
201
202 /** Finish writing a buffer into a file in an asynchronous way.
203 *
204 * This function needs to be called repeatedly until it does not return TSS2_FAPI_RC_TRY_AGAIN.
205 *
206 * @param[in,out] io The input/output context being used for file I/O.
207 * @retval TSS2_RC_SUCCESS: if the function call was a success.
208 * @retval TSS2_FAPI_RC_IO_ERROR: if an I/O error was encountered; such as the file was not found.
209 * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet complete.
210 * Call this function again later.
211 */
212 TSS2_RC
ifapi_io_write_finish(struct IFAPI_IO * io)213 ifapi_io_write_finish(
214 struct IFAPI_IO *io)
215 {
216 io->pollevents = POLLOUT;
217 if (_ifapi_io_retry-- > 0)
218 return TSS2_FAPI_RC_TRY_AGAIN;
219 else
220 _ifapi_io_retry = _IFAPI_IO_RETRIES;
221
222 ssize_t ret = write(fileno(io->stream),
223 &io->char_rbuffer[io->buffer_idx],
224 io->buffer_length - io->buffer_idx);
225 if (ret < 0 && (errno == EINTR || errno == EAGAIN))
226 return TSS2_FAPI_RC_TRY_AGAIN;
227
228 if (ret < 0) {
229 LOG_ERROR("Error writing to file: %i.", errno);
230 fclose(io->stream);
231 io->pollevents = 0;
232 SAFE_FREE(io->char_rbuffer);
233 return TSS2_FAPI_RC_IO_ERROR;
234 }
235
236 io->pollevents = 0;
237 io->buffer_idx += ret;
238 if (io->buffer_idx < io->buffer_length)
239 return TSS2_FAPI_RC_TRY_AGAIN;
240
241 SAFE_FREE(io->char_rbuffer);
242 fclose(io->stream);
243
244 return TSS2_RC_SUCCESS;
245 }
246
247 /** Check whether a file is writeable.
248 *
249 * @param[in] file The name of the fileto be checked.
250 * @retval TSS2_RC_SUCCESS if the directories existed or were successfully created
251 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
252 */
253 TSS2_RC
ifapi_io_check_file_writeable(const char * file)254 ifapi_io_check_file_writeable(
255 const char *file)
256 {
257 /* Check access rights to file */
258 if (access(file, W_OK)) {
259 return_error2(TSS2_FAPI_RC_IO_ERROR, "File %s is not writeable.", file);
260 }
261 return TSS2_RC_SUCCESS;
262 }
263
264 /** Check for the existence of a directory and create it if it does not yet exist.
265 *
266 * @param[in] dirname The name of the directory to be checked / created
267 * @retval TSS2_RC_SUCCESS if the directories existed or were successfully created
268 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
269 * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated.
270 * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
271 * the function.
272 */
273 TSS2_RC
ifapi_io_check_create_dir(const char * dirname)274 ifapi_io_check_create_dir(
275 const char *dirname)
276 {
277 TSS2_RC r;
278 struct stat fbuffer;
279
280 /* Check existence of dirname and try to create it otherwise */
281 if (stat(dirname, &fbuffer)) {
282 LOG_WARNING("Directory %s does not exist, creating", dirname);
283
284 r = ifapi_create_dirs("", dirname);
285 return_if_error2(r, "Directory %s can't be created.", dirname);
286
287 LOG_DEBUG("Created directory: %s", dirname);
288 }
289
290 /* Check access rights to dirname */
291 if (access(dirname, W_OK)) {
292 return_error2(TSS2_FAPI_RC_IO_ERROR, "Directory %s is not writeable.", dirname);
293 }
294
295 return TSS2_RC_SUCCESS;
296 }
297
298 /** Remove a file.
299 *
300 * @param[in] file The absolute path of the file to be removed.
301 * @retval TSS2_RC_SUCCESS If the file was successfully removed
302 * @retval TSS2_FAPI_RC_IO_ERROR If the file could not be removed.
303 */
304 TSS2_RC
ifapi_io_remove_file(const char * file)305 ifapi_io_remove_file(const char *file)
306 {
307 if (remove(file) != 0) {
308 LOG_ERROR("File: %s can't be deleted.", file);
309 return TSS2_FAPI_RC_IO_ERROR;
310 }
311 return TSS2_RC_SUCCESS;
312 }
313
314 /** Remove a directory recursively; i.e. including its subdirectories.
315 *
316 * @param[in] dirname The directory to be removed
317 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
318 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
319 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
320 */
321 TSS2_RC
ifapi_io_remove_directories(const char * dirname)322 ifapi_io_remove_directories(
323 const char *dirname)
324 {
325 DIR *dir;
326 struct dirent *entry;
327 TSS2_RC r;
328 char *path;
329
330 LOG_TRACE("Removing directory: %s", dirname);
331
332 if (!(dir = opendir(dirname))) {
333 return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not open directory: %s",
334 dirname);
335 }
336
337 /* Iterating through the list of entries inside the directory. */
338 while ((entry = readdir(dir)) != NULL) {
339 LOG_TRACE("Deleting directory entry %s", entry->d_name);
340
341 /* Entries . and .. are obviously ignored */
342 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
343 continue;
344
345 /* If an entry is a directory then we call ourself recursively to remove those */
346 if (entry->d_type == DT_DIR) {
347 r = ifapi_asprintf(&path, "%s/%s", dirname, entry->d_name);
348 goto_if_error(r, "Out of memory", error_cleanup);
349
350 r = ifapi_io_remove_directories(path);
351 free(path);
352 goto_if_error(r, "remove directories.", error_cleanup);
353
354 continue;
355 }
356
357 /* If an entry is a file or symlink or anything else, we remove it */
358 r = ifapi_asprintf(&path, "%s/%s", dirname, entry->d_name);
359 goto_if_error(r, "Out of memory", error_cleanup);
360
361 LOG_WARNING("Found a file in directory; removing: %s", path);
362
363 if (remove(path) != 0) {
364 free(path);
365 closedir(dir);
366 return_error2(TSS2_FAPI_RC_IO_ERROR, "Removing file");
367 }
368
369 free(path);
370 }
371 closedir(dir);
372 LOG_TRACE("Removing target directory %s", dirname);
373
374 if (rmdir(dirname) != 0)
375 return_error2(TSS2_FAPI_RC_IO_ERROR, "Removing directory: %s", dirname);
376
377 LOG_TRACE("SUCCESS");
378 return TSS2_RC_SUCCESS;
379
380 error_cleanup:
381 closedir(dir);
382 return r;
383 }
384
385 /** Enumerate the list of files in a directory.
386 *
387 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
388 *
389 * @param[in] dirname The directory to list files from.
390 * @param[out] files The list of file names.
391 * @param[out] numfiles The size of files.
392 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
393 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
394 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
395 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
396 */
397 TSS2_RC
ifapi_io_dirfiles(const char * dirname,char *** files,size_t * numfiles)398 ifapi_io_dirfiles(
399 const char *dirname,
400 char ***files,
401 size_t *numfiles)
402 {
403 DIR *dir;
404 struct dirent *entry;
405 char **paths;
406 size_t numpaths = 0;
407 check_not_null(dirname);
408 check_not_null(files);
409 check_not_null(numfiles);
410
411 LOG_TRACE("Removing directory: %s", dirname);
412
413 paths = calloc(10, sizeof(*paths));
414 check_oom(paths);
415
416 if (!(dir = opendir(dirname))) {
417 free(paths);
418 return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not open directory: %s",
419 dirname);
420 }
421
422 /* Iterating through the list of entries inside the directory. */
423 while ((entry = readdir(dir)) != NULL) {
424 LOG_TRACE("Looking at %s", entry->d_name);
425 if (entry->d_type != DT_REG)
426 continue;
427
428 if (numpaths % 10 == 9) {
429 #ifdef HAVE_REALLOCARRAY
430 paths = reallocarray(paths, numpaths + 10, sizeof(*paths));
431 #else /* HAVE_REALLOCARRAY */
432 paths = realloc(paths, (numpaths + 10) * sizeof(*paths));
433 #endif /* HAVE_REALLOCARRAY */
434 if (!paths)
435 closedir(dir);
436 check_oom(paths);
437 }
438
439 paths[numpaths] = strdup(entry->d_name);
440 if (!paths[numpaths])
441 goto error_oom;
442
443 LOG_TRACE("Added %s to the list at index %zi", paths[numpaths], numpaths);
444 numpaths += 1;
445 }
446 closedir(dir);
447
448 *files = paths;
449 *numfiles = numpaths;
450
451 return TSS2_RC_SUCCESS;
452
453 error_oom:
454 closedir(dir);
455 LOG_ERROR("Out of memory");
456 for (size_t i = 0; i < numpaths; i++)
457 free(paths[i]);
458 free(paths);
459 return TSS2_FAPI_RC_MEMORY;
460 }
461
462 /** Get a linked list of files in a directory and all sub directories.
463 *
464 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
465 *
466 * @param[in] dir_name The directory to list files from.
467 * @param[out] list The linked list with the file names.
468 * @param[out] n The number of filesl
469 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
470 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
471 */
472 static TSS2_RC
dirfiles_all(const char * dir_name,NODE_OBJECT_T ** list,size_t * n)473 dirfiles_all(const char *dir_name, NODE_OBJECT_T **list, size_t *n)
474 {
475 DIR *dir;
476 struct dirent *entry;
477 TSS2_RC r;
478 char *path;
479 NODE_OBJECT_T *second;
480
481 if (!(dir = opendir(dir_name))) {
482 return TSS2_RC_SUCCESS;
483 }
484
485 /* Iterating through the list of entries inside the directory. */
486 while ((entry = readdir(dir)) != NULL) {
487 path = NULL;
488 if (entry->d_type == DT_DIR) {
489 /* Recursive call for sub directories */
490 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
491 continue;
492 r = ifapi_asprintf(&path, "%s/%s", dir_name, entry->d_name);
493 if (r)
494 closedir(dir);
495 return_if_error(r, "Out of memory");
496
497 LOG_TRACE("Directory: %s", path);
498 r = dirfiles_all(path, list, n);
499 SAFE_FREE(path);
500 if (r)
501 closedir(dir);
502 return_if_error(r, "get_entities");
503
504 } else {
505 r = ifapi_asprintf(&path, "%s/%s", dir_name, entry->d_name);
506 if (r)
507 closedir(dir);
508 return_if_error(r, "Out of memory");
509
510 NODE_OBJECT_T *file_obj = calloc(sizeof(NODE_OBJECT_T), 1);
511 if (!file_obj) {
512 LOG_ERROR("Out of memory.");
513 SAFE_FREE(path);
514 closedir(dir);
515 return TSS2_FAPI_RC_MEMORY;
516 }
517
518 *n += 1;
519 /* Add file name to linked list */
520 file_obj->object = strdup(path);
521 if (file_obj->object == NULL) {
522 LOG_ERROR("Out of memory.");
523 SAFE_FREE(file_obj);
524 SAFE_FREE(path);
525 closedir(dir);
526 return TSS2_FAPI_RC_MEMORY;
527 }
528 if (*list != NULL) {
529 second = *list;
530 file_obj->next = second;
531 }
532 *list = file_obj;
533 LOG_TRACE("File: %s", path);
534 SAFE_FREE(path);
535 }
536 }
537 closedir(dir);
538 return TSS2_RC_SUCCESS;
539 }
540
541
542 /** Recursive enumerate the list of files in a directory.
543 *
544 * Enumerage the regular files (no directories, symlinks etc) from a given directory.
545 *
546 * @param[in] searchPath The directory to list files from.
547 * @param[out] pathlist The list of file names.
548 * @param[out] numPaths The size of files.
549 * @retval TSS2_RC_SUCCESS if the directories were successfully removed
550 * @retval TSS2_FAPI_RC_IO_ERROR if an I/O error occurred
551 * @retval TSS2_FAPI_RC_MEMORY: if memory could not be allocated to hold the read data.
552 */
553 TSS2_RC
ifapi_io_dirfiles_all(const char * searchPath,char *** pathlist,size_t * numPaths)554 ifapi_io_dirfiles_all(
555 const char *searchPath,
556 char ***pathlist,
557 size_t *numPaths)
558 {
559 TSS2_RC r;
560 size_t n;
561 NODE_OBJECT_T *head;
562
563 *numPaths = 0;
564 char **pathlist2;
565
566 NODE_OBJECT_T *file_list = NULL;
567 r = dirfiles_all(searchPath, &file_list, numPaths);
568 goto_if_error(r, "get all sub files of directory", cleanup);
569
570 if (*numPaths > 0) {
571 size_t size_path_list = *numPaths * sizeof(char *);
572 pathlist2 = calloc(1, size_path_list);
573 goto_if_null2(pathlist2, "Out of memory.", r, TSS2_FAPI_RC_MEMORY,
574 cleanup);
575 n = *numPaths;
576
577 /* Move file names from list to array */
578 while (n > 0 && file_list) {
579 n -= 1;
580 pathlist2[n] = file_list->object;
581 head = file_list;
582 file_list = file_list->next;
583 SAFE_FREE(head);
584 }
585 *pathlist = pathlist2;
586 }
587 cleanup:
588 /* Free linked list with file names */
589 while (file_list) {
590 head = file_list;
591 file_list = file_list->next;
592 SAFE_FREE(head);
593 }
594 return r;
595 }
596
597 /** Determine whether a path exists.
598 *
599 * @param[in] path The absolute path of the file.
600 * @retval true The file exists.
601 * @retval false The file does not exist.
602 */
603 bool
ifapi_io_path_exists(const char * path)604 ifapi_io_path_exists(const char *path)
605 {
606 struct stat fbuffer;
607
608 if (stat(path, &fbuffer) == 0)
609 return true;
610 else
611 return false;
612 }
613
614
615 /** Wait for file I/O to be ready.
616 *
617 * If FAPI state automata are in a file I/O state it will be waited for an
618 * event on a file descriptor.
619 *
620 * @param[in] io The input/output context being used for file I/O.
621 * @retval TSS2_RC_SUCCESS After the end of the wait.
622 * @retval TSS2_FAPI_RC_IO_ERROR if the poll function returns an error.
623 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
624 */
625 TSS2_RC
ifapi_io_poll(IFAPI_IO * io)626 ifapi_io_poll(IFAPI_IO * io) {
627 int rc;
628 /* Check for NULL parameters */
629 check_not_null(io);
630
631 if (io->pollevents) {
632 struct pollfd fds;
633 fds.events = io->pollevents;
634 fds.fd = fileno(io->stream);
635 LOG_TRACE("Waiting for fd %i with event %i", fds.fd, fds.events);
636 rc = poll(&fds, 1, -1);
637 if (rc < 0) {
638 LOG_ERROR("Poll failed with %d", errno);
639 return TSS2_FAPI_RC_IO_ERROR;
640 }
641 }
642 return TSS2_RC_SUCCESS;
643 }
644
645 /** Get a list of poll handles.
646 *
647 * @param[in] io The input/output context being used for file I/O.
648 * @param[out] handles The array with the poll handles.
649 * @param[out] num_handles The number of poll handles.
650 * @retval TSS2_RC_SUCCESS on success.
651 * @retval TSS2_FAPI_RC_NO_HANDLE In no poll events are stored in IO context.
652 * @retval TSS2_FAPI_RC_MEMORY If the output data cannot be allocated.
653 * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed.
654 */
655 TSS2_RC
ifapi_io_poll_handles(IFAPI_IO * io,FAPI_POLL_HANDLE ** handles,size_t * num_handles)656 ifapi_io_poll_handles(IFAPI_IO *io, FAPI_POLL_HANDLE **handles, size_t *num_handles) {
657 /* Check for NULL parameters */
658 check_not_null(io);
659 check_not_null(handles);
660 check_not_null(num_handles);
661
662 if (!io->pollevents) {
663 /* We're not spilling out error here, because this is called in the
664 functional path of Fapi_GetPollHandles(). */
665 LOG_DEBUG("No pollable operation in progress.");
666 return TSS2_FAPI_RC_NO_HANDLE;
667 }
668
669 *handles = calloc(1, sizeof(**handles));
670 check_oom(*handles);
671 (*handles)->events = io->pollevents;
672 (*handles)->fd = fileno(io->stream);
673 *num_handles = 1;
674
675 LOG_TRACE("Returning %zi poll handles for fd %i with event %i",
676 *num_handles, (*handles)->fd, (*handles)->events);
677
678 return TSS2_RC_SUCCESS;
679 }
680