Home | History | Annotate | Line # | Download | only in import
      1      1.1  christos /* Create /proc/self/fd-related names for subfiles of open directories.
      2      1.1  christos 
      3  1.1.1.2  christos    Copyright (C) 2006, 2009-2022 Free Software Foundation, Inc.
      4      1.1  christos 
      5      1.1  christos    This program is free software: you can redistribute it and/or modify
      6      1.1  christos    it under the terms of the GNU General Public License as published by
      7  1.1.1.2  christos    the Free Software Foundation, either version 3 of the License, or
      8      1.1  christos    (at your option) any later version.
      9      1.1  christos 
     10      1.1  christos    This program is distributed in the hope that it will be useful,
     11      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13      1.1  christos    GNU General Public License for more details.
     14      1.1  christos 
     15      1.1  christos    You should have received a copy of the GNU General Public License
     16      1.1  christos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18      1.1  christos /* Written by Paul Eggert.  */
     19      1.1  christos 
     20      1.1  christos #include <config.h>
     21      1.1  christos 
     22      1.1  christos #include "openat-priv.h"
     23      1.1  christos 
     24      1.1  christos #include <sys/types.h>
     25      1.1  christos #include <sys/stat.h>
     26      1.1  christos #include <fcntl.h>
     27      1.1  christos 
     28      1.1  christos #include <stdio.h>
     29      1.1  christos #include <stdlib.h>
     30      1.1  christos #include <string.h>
     31      1.1  christos #include <unistd.h>
     32      1.1  christos 
     33      1.1  christos #ifdef __KLIBC__
     34      1.1  christos # include <InnoTekLIBC/backend.h>
     35      1.1  christos #endif
     36      1.1  christos 
     37      1.1  christos #include "intprops.h"
     38      1.1  christos 
     39      1.1  christos /* Set BUF to the name of the subfile of the directory identified by
     40      1.1  christos    FD, where the subfile is named FILE.  If successful, return BUF if
     41      1.1  christos    the result fits in BUF, dynamically allocated memory otherwise.
     42      1.1  christos    Return NULL (setting errno) on error.  */
     43      1.1  christos char *
     44      1.1  christos openat_proc_name (char buf[OPENAT_BUFFER_SIZE], int fd, char const *file)
     45      1.1  christos {
     46      1.1  christos   char *result = buf;
     47      1.1  christos   int dirlen;
     48      1.1  christos 
     49      1.1  christos   /* Make sure the caller gets ENOENT when appropriate.  */
     50      1.1  christos   if (!*file)
     51      1.1  christos     {
     52      1.1  christos       buf[0] = '\0';
     53      1.1  christos       return buf;
     54      1.1  christos     }
     55      1.1  christos 
     56      1.1  christos #ifndef __KLIBC__
     57      1.1  christos # define PROC_SELF_FD_FORMAT "/proc/self/fd/%d/"
     58      1.1  christos   {
     59      1.1  christos     enum {
     60      1.1  christos       PROC_SELF_FD_DIR_SIZE_BOUND
     61      1.1  christos         = (sizeof PROC_SELF_FD_FORMAT - (sizeof "%d" - 1)
     62      1.1  christos            + INT_STRLEN_BOUND (int))
     63      1.1  christos     };
     64      1.1  christos 
     65      1.1  christos     static int proc_status = 0;
     66      1.1  christos     if (! proc_status)
     67      1.1  christos       {
     68      1.1  christos         /* Set PROC_STATUS to a positive value if /proc/self/fd is
     69      1.1  christos            reliable, and a negative value otherwise.  Solaris 10
     70      1.1  christos            /proc/self/fd mishandles "..", and any file name might expand
     71      1.1  christos            to ".." after symbolic link expansion, so avoid /proc/self/fd
     72      1.1  christos            if it mishandles "..".  Solaris 10 has openat, but this
     73      1.1  christos            problem is exhibited on code that built on Solaris 8 and
     74      1.1  christos            running on Solaris 10.  */
     75      1.1  christos 
     76      1.1  christos         int proc_self_fd =
     77      1.1  christos           open ("/proc/self/fd",
     78      1.1  christos                 O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK | O_CLOEXEC);
     79      1.1  christos         if (proc_self_fd < 0)
     80      1.1  christos           proc_status = -1;
     81      1.1  christos         else
     82      1.1  christos           {
     83      1.1  christos             /* Detect whether /proc/self/fd/%i/../fd exists, where %i is the
     84      1.1  christos                number of a file descriptor open on /proc/self/fd.  On Linux,
     85      1.1  christos                that name resolves to /proc/self/fd, which was opened above.
     86      1.1  christos                However, on Solaris, it may resolve to /proc/self/fd/fd, which
     87      1.1  christos                cannot exist, since all names in /proc/self/fd are numeric.  */
     88      1.1  christos             char dotdot_buf[PROC_SELF_FD_DIR_SIZE_BOUND + sizeof "../fd" - 1];
     89      1.1  christos             sprintf (dotdot_buf, PROC_SELF_FD_FORMAT "../fd", proc_self_fd);
     90      1.1  christos             proc_status = access (dotdot_buf, F_OK) ? -1 : 1;
     91      1.1  christos             close (proc_self_fd);
     92      1.1  christos           }
     93      1.1  christos       }
     94      1.1  christos 
     95      1.1  christos     if (proc_status < 0)
     96      1.1  christos       return NULL;
     97      1.1  christos     else
     98      1.1  christos       {
     99      1.1  christos         size_t bufsize = PROC_SELF_FD_DIR_SIZE_BOUND + strlen (file);
    100      1.1  christos         if (OPENAT_BUFFER_SIZE < bufsize)
    101      1.1  christos           {
    102      1.1  christos             result = malloc (bufsize);
    103      1.1  christos             if (! result)
    104      1.1  christos               return NULL;
    105      1.1  christos           }
    106      1.1  christos 
    107      1.1  christos         dirlen = sprintf (result, PROC_SELF_FD_FORMAT, fd);
    108      1.1  christos       }
    109      1.1  christos   }
    110      1.1  christos #else
    111      1.1  christos   /* OS/2 kLIBC provides a function to retrieve a path from a fd.  */
    112      1.1  christos   {
    113      1.1  christos     char dir[_MAX_PATH];
    114      1.1  christos     size_t bufsize;
    115      1.1  christos 
    116      1.1  christos     if (__libc_Back_ioFHToPath (fd, dir, sizeof dir))
    117      1.1  christos       return NULL;
    118      1.1  christos 
    119      1.1  christos     dirlen = strlen (dir);
    120      1.1  christos     bufsize = dirlen + 1 + strlen (file) + 1; /* 1 for '/', 1 for null */
    121      1.1  christos     if (OPENAT_BUFFER_SIZE < bufsize)
    122      1.1  christos       {
    123      1.1  christos         result = malloc (bufsize);
    124      1.1  christos         if (! result)
    125      1.1  christos           return NULL;
    126      1.1  christos       }
    127      1.1  christos 
    128      1.1  christos     strcpy (result, dir);
    129      1.1  christos     result[dirlen++] = '/';
    130      1.1  christos   }
    131      1.1  christos #endif
    132      1.1  christos 
    133      1.1  christos   strcpy (result + dirlen, file);
    134      1.1  christos   return result;
    135      1.1  christos }
    136