blob: d844d4fd17140a5ebb427f7f073fd9dfff2fab2b [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Implementation of the POSIX pclose function for Linux.
///
//===----------------------------------------------------------------------===//
#include "src/stdio/pclose.h"
#include "hdr/types/FILE.h"
#include "hdr/types/pid_t.h"
#include "src/__support/File/linux/popen_file.h"
#include "src/__support/OSUtil/linux/shell_fork.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/null_check.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, pclose, (::FILE * stream)) {
LIBC_CRASH_ON_NULLPTR(stream);
// Passing a stream that was not created by popen is undefined behavior.
auto *file = reinterpret_cast<PopenFile *>(stream);
const pid_t pid = file->get_pid();
// Closing the stream flushes it and closes the parent's end of the pipe, so
// a child reading from it sees EOF. It also frees the stream.
// TODO: File::close returns early without closing the fd if flushing fails,
// which could leave a child reading from the pipe waiting forever. Fix
// File::close to always release the fd in a followup.
int close_result = file->close();
// POSIX requires that pclose not return before the child has terminated, so
// wait even if closing failed.
ErrorOr<int> wait_result = shell_wait(pid);
if (!wait_result) {
libc_errno = wait_result.error();
return -1;
}
if (close_result != 0) {
libc_errno = close_result;
return -1;
}
return wait_result.value();
}
} // namespace LIBC_NAMESPACE_DECL