From 2fa1e55628bdb8042e5b2a00a8b2b3e21bf3a347 Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 8 Jul 2021 11:11:28 +0800 Subject: [PATCH] libc: Implement ttyname and ttyname_r Note: this patch can get file path from root pseudo file handle, but a general infrastructure is setup for other file system too. Signed-off-by: Xiang Xiao Change-Id: I86cd79ebb741f2f43fdd398bb7498c40687d949b --- fs/inode/Make.defs | 4 +- fs/inode/fs_inodegetpath.c | 72 +++++++++++++++++++++++++++ fs/inode/inode.h | 10 ++++ fs/vfs/fs_fcntl.c | 10 ++++ fs/vfs/fs_ioctl.c | 7 +++ include/fcntl.h | 1 + include/limits.h | 1 + include/nuttx/fs/ioctl.h | 3 ++ include/unistd.h | 3 ++ libs/libc/termios/Make.defs | 1 + libs/libc/termios/lib_ttyname.c | 69 ++++++++++++++++++++++++++ libs/libc/termios/lib_ttynamer.c | 85 ++++++++++++++++++++++++++++++++ 12 files changed, 264 insertions(+), 2 deletions(-) create mode 100644 fs/inode/fs_inodegetpath.c create mode 100644 libs/libc/termios/lib_ttyname.c create mode 100644 libs/libc/termios/lib_ttynamer.c diff --git a/fs/inode/Make.defs b/fs/inode/Make.defs index 2926963746f..503cfdcc342 100644 --- a/fs/inode/Make.defs +++ b/fs/inode/Make.defs @@ -19,8 +19,8 @@ ############################################################################ CSRCS += fs_files.c fs_foreachinode.c fs_inode.c fs_inodeaddref.c -CSRCS += fs_inodebasename.c fs_inodefind.c fs_inodefree.c fs_inoderelease.c -CSRCS += fs_inoderemove.c fs_inodereserve.c fs_inodesearch.c +CSRCS += fs_inodebasename.c fs_inodefind.c fs_inodefree.c fs_inodegetpath.c +CSRCS += fs_inoderelease.c fs_inoderemove.c fs_inodereserve.c fs_inodesearch.c # Include inode/utils build support diff --git a/fs/inode/fs_inodegetpath.c b/fs/inode/fs_inodegetpath.c new file mode 100644 index 00000000000..4c4a163d668 --- /dev/null +++ b/fs/inode/fs_inodegetpath.c @@ -0,0 +1,72 @@ +/**************************************************************************** + * fs/inode/fs_inodegetpath.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "inode/inode.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inode_getpath + * + * Description: + * Given the full path from inode. + * + ****************************************************************************/ + +int inode_getpath(FAR struct inode *node, FAR char *path) +{ + if (path == NULL) + { + return -EINVAL; + } + else if (node == NULL) + { + path[0] = '\0'; + return OK; + } + else if (node->i_parent != NULL) + { + int ret = inode_getpath(node->i_parent, path); + if (ret < 0) + { + return ret; + } + } + + strcat(path, node->i_name); + if (node->i_child) + { + strcat(path, "/"); + } + + return OK; +} diff --git a/fs/inode/inode.h b/fs/inode/inode.h index ddd7f450b3c..a43993096b7 100644 --- a/fs/inode/inode.h +++ b/fs/inode/inode.h @@ -245,6 +245,16 @@ int inode_find(FAR struct inode_search_s *desc); struct stat; /* Forward reference */ int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve); +/**************************************************************************** + * Name: inode_getpath + * + * Description: + * Given the full path from inode. + * + ****************************************************************************/ + +int inode_getpath(FAR struct inode *node, FAR char *path); + /**************************************************************************** * Name: inode_free * diff --git a/fs/vfs/fs_fcntl.c b/fs/vfs/fs_fcntl.c index 83b746f4031..657742286f0 100644 --- a/fs/vfs/fs_fcntl.c +++ b/fs/vfs/fs_fcntl.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -206,6 +207,15 @@ static int file_vfcntl(FAR struct file *filep, int cmd, va_list ap) ret = -ENOSYS; /* Not implemented */ break; + case F_GETPATH: + /* Get the path of the file descriptor. The argument must be a buffer + * of size PATH_MAX or greater. + */ + + { + ret = file_ioctl(filep, FIOC_FILEPATH, va_arg(ap, FAR char *)); + } + default: break; } diff --git a/fs/vfs/fs_ioctl.c b/fs/vfs/fs_ioctl.c index 4849418064c..689a69cd4c6 100644 --- a/fs/vfs/fs_ioctl.c +++ b/fs/vfs/fs_ioctl.c @@ -103,6 +103,13 @@ int file_vioctl(FAR struct file *filep, int req, va_list ap) ret = file_fcntl(filep, F_SETFD, file_fcntl(filep, F_GETFD) & ~FD_CLOEXEC); break; + + case FIOC_FILEPATH: + if (!INODE_IS_MOUNTPT(inode)) + { + ret = inode_getpath(inode, (FAR char *)(uintptr_t)arg); + } + break; } return ret; diff --git a/include/fcntl.h b/include/fcntl.h index a96a58caf4c..e17f69ffb36 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -95,6 +95,7 @@ #define F_SETLKW 12 /* Like F_SETLK, but wait for lock to become available */ #define F_SETOWN 13 /* Set pid that will receive SIGIO and SIGURG signals for fd */ #define F_SETSIG 14 /* Set the signal to be sent */ +#define F_GETPATH 15 /* Get the path of the file descriptor(BSD/macOS) */ /* For posix fcntl() and lockf() */ diff --git a/include/limits.h b/include/limits.h index 28f02c42549..9836f159c29 100644 --- a/include/limits.h +++ b/include/limits.h @@ -201,6 +201,7 @@ #define MAX_CANON _POSIX_MAX_CANON #define MAX_INPUT _POSIX_MAX_INPUT #define NAME_MAX _POSIX_NAME_MAX +#define TTY_NAME_MAX _POSIX_NAME_MAX #define NGROUPS_MAX _POSIX_NGROUPS_MAX #define OPEN_MAX _POSIX_OPEN_MAX #define PATH_MAX _POSIX_PATH_MAX diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h index bceba81d1a5..d93390f2484 100644 --- a/include/nuttx/fs/ioctl.h +++ b/include/nuttx/fs/ioctl.h @@ -180,6 +180,9 @@ #define FIONCLEX _FIOC(0x000e) /* IN: None * OUT: None */ +#define FIOC_FILEPATH _FIOC(0x000f) /* IN: FAR char *(length >= PATH_MAX) + * OUT: The full file path + */ /* NuttX file system ioctl definitions **************************************/ diff --git a/include/unistd.h b/include/unistd.h index 0f86f822749..9095453da0f 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -322,6 +322,9 @@ int ftruncate(int fd, off_t length); /* Check if a file descriptor corresponds to a terminal I/O file */ int isatty(int fd); + +FAR char *ttyname(int fd); +int ttyname_r(int fd, FAR char *buf, size_t buflen); #endif /* Memory management */ diff --git a/libs/libc/termios/Make.defs b/libs/libc/termios/Make.defs index 6d9bb6acf61..28467581fcb 100644 --- a/libs/libc/termios/Make.defs +++ b/libs/libc/termios/Make.defs @@ -27,6 +27,7 @@ ifeq ($(CONFIG_SERIAL_TERMIOS),y) CSRCS += lib_cfspeed.c lib_cfmakeraw.c lib_isatty.c lib_tcflush.c CSRCS += lib_tcflow.c lib_tcgetattr.c lib_tcsetattr.c +CSRCS += lib_ttyname.c lib_ttynamer.c # Add the termios directory to the build diff --git a/libs/libc/termios/lib_ttyname.c b/libs/libc/termios/lib_ttyname.c new file mode 100644 index 00000000000..f94a7ca3447 --- /dev/null +++ b/libs/libc/termios/lib_ttyname.c @@ -0,0 +1,69 @@ +/**************************************************************************** + * libs/libc/termios/lib_ttyname.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ttyname + * + * Description: + * The ttyname() function shall return a pointer to a string containing + * a null-terminated pathname of the terminal associated with file + * descriptor fildes. The application shall not modify the string returned. + * The returned pointer might be invalidated or the string content might + * be overwritten by a subsequent call to ttyname(). The returned pointer + * and the string content might also be invalidated if the calling thread + * is terminated. + * + * Input Parameters: + * fd - The 'fd' argument is an open file descriptor associated with + * a terminal. + * + * Returned Value: + * Upon successful completion, ttyname() shall return a pointer to + * a string. Otherwise, a null pointer shall be returned and errno + * set to indicate the error. + * + ****************************************************************************/ + +FAR char *ttyname(int fd) +{ + static char name[TTY_NAME_MAX]; + int ret; + + ret = ttyname_r(fd, name, TTY_NAME_MAX); + if (ret != 0) + { + set_errno(ret); + return NULL; + } + + return name; +} diff --git a/libs/libc/termios/lib_ttynamer.c b/libs/libc/termios/lib_ttynamer.c new file mode 100644 index 00000000000..97dd6d11284 --- /dev/null +++ b/libs/libc/termios/lib_ttynamer.c @@ -0,0 +1,85 @@ +/**************************************************************************** + * libs/libc/termios/lib_ttynamer.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ttyname_r + * + * Description: + * The ttyname_r() function shall store the null-terminated pathname of + * the terminal associated with the file descriptor fildes in the + * character array referenced by name. The array is namesize characters + * long and should have space for the name and the terminating null + * character. The maximum length of the terminal name shall be + * {TTY_NAME_MAX}. + * + * Input Parameters: + * fd - The 'fd' argument is an open file descriptor associated with + * a terminal. + * buf - Caller provided buffer to hold tty name. + * buflen - The size of the caller-provided buffer. + * + * Returned Value: + * If successful, the ttyname_r() function shall return zero. + * Otherwise, an error number shall be returned to indicate the error. + * + ****************************************************************************/ + +int ttyname_r(int fd, FAR char *buf, size_t buflen) +{ + if (!isatty(fd)) + { + return ENOTTY; + } + + if (buflen >= TTY_NAME_MAX) + { + return fcntl(fd, F_GETPATH, buf) < 0 ? get_errno() : 0; + } + else + { + char name[TTY_NAME_MAX]; + + if (fcntl(fd, F_GETPATH, name) < 0) + { + return get_errno(); + } + + if (strlen(name) >= buflen) + { + return ERANGE; + } + + strcpy(buf, name); + return OK; + } +}