Skip to content

gh-99987: fcntl add the F_KINFO constant for FreeBSD 13.1 and onwards. #99988

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Doc/library/fcntl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ descriptor.
``FICLONERANGE`` constants, which allow to share some data of one file with
another file by reflinking on some filesystems (e.g., btrfs, OCFS2, and
XFS). This behavior is commonly referred to as "copy-on-write".
On FreeBSD >= 13.1, the :mod:`fcntl` module exposes the ``F_KINFO``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be versionchanged:: 3.13 now.

constant which allow to get the path of the file descriptor.

The module defines the following functions:

Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_fcntl.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ def test_fcntl_f_getpath(self):
res = fcntl.fcntl(self.f.fileno(), fcntl.F_GETPATH, bytes(len(expected)))
self.assertEqual(expected, res)

@unittest.skipUnless(sys.platform.startswith("freebsd") and hasattr(fcntl, "F_KINFO"), "F_KINFO is only available on freebsd")
def test_fcntl_f_kinfo(self):
self.f = open(TESTFN, 'wb')
buffer = fcntl.kinfoalloc()
expected = os.path.abspath(TESTFN).encode('utf-8')
res = fcntl.fcntl(self.f.fileno(), fcntl.F_KINFO, buffer)
path = fcntl.kinfodict(res)["path"]
self.assertEqual(expected, path)

@unittest.skipUnless(
hasattr(fcntl, "F_SETPIPE_SZ") and hasattr(fcntl, "F_GETPIPE_SZ"),
"F_SETPIPE_SZ and F_GETPIPE_SZ are not available on all platforms.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Expose ``F_KINFO`` constant in :mod:`fcntl`. Patch by David Carlier.
68 changes: 67 additions & 1 deletion Modules/clinic/fcntlmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 65 additions & 1 deletion Modules/fcntlmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include <stropts.h>
#endif

#ifdef HAVE_SYS_USER_H
#include <sys/user.h>
#endif

/*[clinic input]
module fcntl
[clinic start generated code]*/
Expand Down Expand Up @@ -55,7 +59,6 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
int ret;
char *str;
Py_ssize_t len;
char buf[1024];
int async_err = 0;

if (PySys_Audit("fcntl.fcntl", "iiO", fd, code, arg ? arg : Py_None) < 0) {
Expand All @@ -66,6 +69,7 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
int parse_result;

if (PyArg_Parse(arg, "s#", &str, &len)) {
char buf[4096];
if ((size_t)len > sizeof buf) {
PyErr_SetString(PyExc_ValueError,
"fcntl string arg too long");
Expand Down Expand Up @@ -438,13 +442,70 @@ fcntl_lockf_impl(PyObject *module, int fd, int code, PyObject *lenobj,
Py_RETURN_NONE;
}

#ifdef F_KINFO
/*[clinic input]
fcntl.kinfoalloc

Return a FreeBSD's kinfo_file buffer with the `kf_structsize` field pre-initialised.

[clinic start generated code]*/

static PyObject *
fcntl_kinfoalloc_impl(PyObject *module)
/*[clinic end generated code: output=c61603aeb3d91a0e input=28e2e82cc296f82c]*/
{
char buf[KINFO_FILE_SIZE+1];
((struct kinfo_file *)buf)->kf_structsize = KINFO_FILE_SIZE;
return PyBytes_FromStringAndSize(buf, KINFO_FILE_SIZE);
}

/*[clinic input]
fcntl.kinfodict

arg: object(c_default='NULL') = 0
/

Return a FreeBSD's kinfo_file as dictionary.

[clinic start generated code]*/

static PyObject *
fcntl_kinfodict_impl(PyObject *module, PyObject *arg)
/*[clinic end generated code: output=3873ae40aeac8e7f input=faba1f2ce099752f]*/
{
PyObject *dict;

if (PySys_Audit("fcntl.kinfodict", "O", arg) < 0 || arg == NULL) {
return NULL;
}

dict = PyDict_New();
if (dict) {
struct kinfo_file *kf;
kf = (struct kinfo_file *)PyBytes_AsString(arg);

PyDict_SetItemString(dict, "status", PyLong_FromLong(kf->kf_status));
PyDict_SetItemString(dict, "type", PyLong_FromLong(kf->kf_type));
PyDict_SetItemString(dict, "offset", PyLong_FromLongLong(kf->kf_offset));
PyDict_SetItemString(dict, "path", PyBytes_FromString(kf->kf_path));
return dict;
}

PyErr_SetString(PyExc_ValueError, "fcntl.kinfodict could not create its dictionary");
return NULL;
}

#endif

/* List of functions */

static PyMethodDef fcntl_methods[] = {
FCNTL_FCNTL_METHODDEF
FCNTL_IOCTL_METHODDEF
FCNTL_FLOCK_METHODDEF
FCNTL_LOCKF_METHODDEF
FCNTL_KINFOALLOC_METHODDEF
FCNTL_KINFODICT_METHODDEF
{NULL, NULL} /* sentinel */
};

Expand Down Expand Up @@ -485,6 +546,9 @@ all_ins(PyObject* m)
#ifdef F_DUPFD_CLOEXEC
if (PyModule_AddIntMacro(m, F_DUPFD_CLOEXEC)) return -1;
#endif
#ifdef F_KINFO
if (PyModule_AddIntMacro(m, F_KINFO)) return -1;
#endif
#ifdef F_GETFD
if (PyModule_AddIntMacro(m, F_GETFD)) return -1;
#endif
Expand Down
6 changes: 6 additions & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2702,7 +2702,7 @@ AC_CHECK_HEADERS([ \
sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h sys/param.h sys/poll.h \
sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \
sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.h sys/termio.h sys/time.h sys/times.h sys/timerfd.h \
sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \
sys/types.h sys/uio.h sys/un.h sys/user.h sys/utsname.h sys/wait.h sys/xattr.h sysexits.h syslog.h \
termios.h util.h utime.h utmp.h \
])
AC_HEADER_DIRENT
Expand Down
3 changes: 3 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,9 @@
/* Define to 1 if you have the <sys/un.h> header file. */
#undef HAVE_SYS_UN_H

/* Define to 1 if you have the <sys/user.h> header file. */
#undef HAVE_SYS_USER_H

/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H

Expand Down