diff --git a/include/stdio.h b/include/stdio.h index eaebff85e473..5a5b82bc665e 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -396,6 +396,7 @@ int (dprintf)(int, const char * __restrict, ...); int asprintf(char **, const char *, ...) __printflike(2, 3); char *ctermid_r(char *); void fcloseall(void); +int fdclose(FILE *, int *); char *fgetln(FILE *, size_t *); const char *fmtcheck(const char *, const char *) __format_arg(2); int fpurge(FILE *); diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map index d2a8c92b2411..a332ab26d3c0 100644 --- a/lib/libc/stdio/Symbol.map +++ b/lib/libc/stdio/Symbol.map @@ -162,6 +162,10 @@ FBSD_1.3 { mkostemps; }; +FBSD_1.4 { + fdclose; +}; + FBSDprivate_1.0 { _flockfile; _flockfile_debug_stub; diff --git a/lib/libc/stdio/fclose.3 b/lib/libc/stdio/fclose.3 index 883aa108e7db..596ee3db0e6b 100644 --- a/lib/libc/stdio/fclose.3 +++ b/lib/libc/stdio/fclose.3 @@ -1,5 +1,6 @@ -.\" Copyright (c) 1990, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 1990, 1991, 1993 The Regents of the University of California. +.\" Copyright (c) 2015 Mariusz Zaborski +.\" All rights reserved. .\" .\" This code is derived from software contributed to Berkeley by .\" Chris Torek and the American National Standards Committee X3, @@ -32,11 +33,12 @@ .\" @(#)fclose.3 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd April 22, 2006 +.Dd July 4, 2015 .Dt FCLOSE 3 .Os .Sh NAME .Nm fclose , +.Nm fdclose , .Nm fcloseall .Nd close a stream .Sh LIBRARY @@ -45,6 +47,8 @@ .In stdio.h .Ft int .Fn fclose "FILE *stream" +.Ft int +.Fn fdclose "FILE *stream" "int *fdp" .Ft void .Fn fcloseall void .Sh DESCRIPTION @@ -59,36 +63,77 @@ first, using .Xr fflush 3 . .Pp The +.Fn fdclose +function is equivalent to +.Fn fclose +except that it does not close the underlying file descriptor. +If +.Fa fdp +is not +.Dv NULL , +the file descriptor will be written to it. +If the +.Fa fdp +argument will be different then NULL the file descriptor will be returned in it, +If the stream does not have an associated file descriptor, +.Fa fdp +will be set to -1. +This type of stream is created with functions such as +.Xr fmemopen 3 , +.Xr funopen 3 , +or +.Xr open_memstream 3 . +.Pp +The .Fn fcloseall function calls .Fn fclose on all open streams. .Sh RETURN VALUES -Upon successful completion 0 is returned. +.Fn fcloseall +does not return a value. +.Pp +Upon successful completion the +.Fn fclose +and +.Fn fdclose +functions return 0. Otherwise, .Dv EOF is returned and the global variable .Va errno is set to indicate the error. -In either case no further access to the stream is possible. .Sh ERRORS +.Fn fdclose +fails if: +.Bl -tag -width Er +.It Bq Er EOPNOTSUPP +The stream does not have an associated file descriptor. +.El +.Pp The .Fn fclose -function -may also fail and set +and +.Fn fdclose +functions may also fail and set .Va errno -for any of the errors specified for the routines -.Xr close 2 -or +for any of the errors specified for .Xr fflush 3 . +.Pp +The +.Fn fclose +function may also fail and set errno for any of the errors specified for +.Xr close 2 . .Sh NOTES The .Fn fclose -function -does not handle NULL arguments; they will result in a segmentation -violation. -This is intentional - it makes it easier to make sure programs written -under +and +.Fn fdclose +functions do not handle NULL arguments in the +.Fa stream +variable; this will result in a segmentation violation. +This is intentional. +It makes it easier to make sure programs written under .Fx are bug free. This behaviour is an implementation detail, and programs should not @@ -104,8 +149,13 @@ The function conforms to .St -isoC . -.Pp +.Sh HISTORY The .Fn fcloseall function first appeared in .Fx 7.0 . +.Pp +The +.Fn fdclose +function first appeared in +.Fx 11.0 . diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 5ed8b2c548f6..24b9b90af985 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -1,6 +1,7 @@ /*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. + * Copyright (c) 1990, 1993 The Regents of the University of California. + * Copyright (c) 2013 Mariusz Zaborski + * All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. @@ -38,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include +#include #include #include #include "un-namespace.h" @@ -45,19 +47,17 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" -int -fclose(FILE *fp) +static int +cleanfile(FILE *fp, bool c) { int r; - if (fp->_flags == 0) { /* not open! */ - errno = EBADF; - return (EOF); - } - FLOCKFILE(fp); r = fp->_flags & __SWR ? __sflush(fp) : 0; - if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) - r = EOF; + if (c) { + if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) + r = EOF; + } + if (fp->_flags & __SMBF) free((char *)fp->_bf._base); if (HASUB(fp)) @@ -80,6 +80,59 @@ fclose(FILE *fp) STDIO_THREAD_LOCK(); fp->_flags = 0; /* Release this FILE for reuse. */ STDIO_THREAD_UNLOCK(); - FUNLOCKFILE(fp); + + return (r); +} + +int +fdclose(FILE *fp, int *fdp) +{ + int r, err; + + if (fdp != NULL) + *fdp = -1; + + if (fp->_flags == 0) { /* not open! */ + errno = EBADF; + return (EOF); + } + + FLOCKFILE(fp); + r = 0; + if (fp->_close != __sclose) { + r = EOF; + errno = EOPNOTSUPP; + } else if (fp->_file < 0) { + r = EOF; + errno = EBADF; + } + if (r == EOF) { + err = errno; + (void)cleanfile(fp, true); + errno = err; + } else { + if (fdp != NULL) + *fdp = fp->_file; + r = cleanfile(fp, false); + } + FUNLOCKFILE(fp); + + return (r); +} + +int +fclose(FILE *fp) +{ + int r; + + if (fp->_flags == 0) { /* not open! */ + errno = EBADF; + return (EOF); + } + + FLOCKFILE(fp); + r = cleanfile(fp, true); + FUNLOCKFILE(fp); + return (r); }