• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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