LCOV - code coverage report
Current view: top level - app/platform - fd_sys_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 123 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_sys_util.h"
       3             : 
       4             : #include <pwd.h>
       5             : #include <errno.h>
       6             : #include <fcntl.h>
       7             : #include <stdlib.h> /* getenv */
       8             : #include <time.h>
       9             : #include <unistd.h>
      10             : #include <sys/syscall.h>
      11             : #include <sys/mman.h>
      12             : #include <sys/wait.h>
      13             : 
      14             : void __attribute__((noreturn))
      15           0 : fd_sys_util_exit_group( int code ) {
      16           0 :   syscall( SYS_exit_group, code );
      17           0 :   for(;;);
      18           0 : }
      19             : 
      20             : int
      21             : fd_sys_util_nanosleep( uint secs,
      22           0 :                        uint nanos ) {
      23           0 :   struct timespec ts = { .tv_sec = secs, .tv_nsec = nanos };
      24           0 :   struct timespec rem;
      25           0 :   while( FD_UNLIKELY( -1==nanosleep( &ts, &rem ) ) ) {
      26           0 :     if( FD_LIKELY( errno==EINTR ) ) ts = rem;
      27           0 :     else return -1;
      28           0 :   }
      29           0 :   return 0;
      30           0 : }
      31             : 
      32             : int
      33             : fd_sys_util_modprobe( char const * module,
      34           0 :                       int          is_dry_run ) {
      35           0 :   pid_t pid = fork();
      36           0 :   if( FD_UNLIKELY( -1==pid ) ) {
      37           0 :     FD_LOG_WARNING(( "fork() for modprobe failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      38           0 :     return -1;
      39           0 :   }
      40           0 :   if( 0==pid ) {
      41           0 :     int null_fd = open( "/dev/null", O_RDWR );
      42           0 :     if( FD_UNLIKELY( -1==null_fd ) ) {
      43           0 :       FD_LOG_WARNING(( "open(/dev/null) for modprobe failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      44           0 :       _exit( 1 );
      45           0 :     }
      46           0 :     if( FD_UNLIKELY( -1==dup2( null_fd, STDIN_FILENO ) ||
      47           0 :                      ( is_dry_run && -1==dup2( null_fd, STDOUT_FILENO ) ) ) ) {
      48           0 :       FD_LOG_WARNING(( "dup2() for modprobe failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      49           0 :       _exit( 1 );
      50           0 :     }
      51           0 :     if( null_fd!=STDIN_FILENO &&
      52           0 :         !( is_dry_run && null_fd==STDOUT_FILENO ) ) close( null_fd );
      53             : 
      54           0 :     char * argv[] = { "modprobe", "--quiet", (char *)module, NULL, NULL };
      55           0 :     if( is_dry_run ) {
      56           0 :       argv[2] = "--dry-run";
      57           0 :       argv[3] = (char *)module;
      58           0 :     }
      59           0 :     char * const envp[] = { NULL };
      60           0 :     execve( "/sbin/modprobe", argv, envp );
      61           0 :     FD_LOG_WARNING(( "execve(/sbin/modprobe) failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      62           0 :     _exit( 1 );
      63           0 :   }
      64             : 
      65           0 :   int status;
      66           0 :   while( FD_UNLIKELY( -1==waitpid( pid, &status, 0 ) ) ) {
      67           0 :     if( errno==EINTR ) continue;
      68           0 :     FD_LOG_WARNING(( "waitpid() for modprobe failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      69           0 :     return -1;
      70           0 :   }
      71           0 :   return WIFEXITED( status ) && 0==WEXITSTATUS( status ) ? 0 : -1;
      72           0 : }
      73             : 
      74             : char const *
      75           0 : fd_sys_util_login_user( void ) {
      76           0 :   char * name = getenv( "SUDO_USER" );
      77           0 :   if( FD_UNLIKELY( name ) ) return name;
      78             : 
      79           0 :   name = getenv( "LOGNAME" );
      80           0 :   if( FD_LIKELY( name ) ) return name;
      81             : 
      82           0 :   name = getenv( "USER" );
      83           0 :   if( FD_LIKELY( name ) ) return name;
      84             : 
      85           0 :   name = getenv( "LNAME" );
      86           0 :   if( FD_LIKELY( name ) ) return name;
      87             : 
      88           0 :   name = getenv( "USERNAME" );
      89           0 :   if( FD_LIKELY( name ) ) return name;
      90             : 
      91           0 :   name = getlogin();
      92           0 :   if( FD_UNLIKELY( !name && (errno==ENXIO || errno==ENOTTY) ) ) return NULL;
      93           0 :   else if( FD_UNLIKELY( !name ) ) FD_LOG_ERR(( "getlogin failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      94           0 :   return name;
      95           0 : }
      96             : 
      97             : int
      98             : fd_sys_util_user_to_uid( char const * user,
      99             :                          uint *       uid,
     100           0 :                          uint *       gid ) {
     101           0 :   uint * results = mmap( NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0 );
     102           0 :   if( FD_UNLIKELY( results==MAP_FAILED ) ) return -1;
     103             : 
     104           0 :   results[ 0 ] = UINT_MAX;
     105           0 :   results[ 1 ] = UINT_MAX;
     106             : 
     107             :   /* This is extremely unfortunate.  We just want to call getpwnam but
     108             :      on various glibc it can open `/var/lib/sss/mc/passwd` and then not
     109             :      close it.  We could go and find this file descriptor and close it
     110             :      for the library, but that is a bit of a hack.  Instead we fork a
     111             :      new process to call getpwnam and then exit.
     112             : 
     113             :      We could try just reading /etc/passwd here instead, but the glibc
     114             :      getpwnam implementation does a lot of things we need, including
     115             :      potentially reading from NCSD or SSSD. */
     116             : 
     117           0 :   pid_t pid = fork();
     118           0 :   if( FD_UNLIKELY( -1==pid ) ) {
     119           0 :     munmap( results, 4096 );
     120           0 :     return -1;
     121           0 :   }
     122             : 
     123           0 :   if( FD_LIKELY( !pid ) ) {
     124           0 :     char buf[ 16384 ];
     125           0 :     struct passwd pwd;
     126           0 :     struct passwd * result;
     127           0 :     int error = getpwnam_r( user, &pwd, buf, sizeof(buf), &result );
     128           0 :     if( FD_UNLIKELY( error ) ) {
     129           0 :       if( FD_LIKELY( error==ENOENT || error==ESRCH ) ) {
     130           0 :         FD_LOG_WARNING(( "configuration file wants firedancer to run as user `%s` but it does not exist", user ));
     131           0 :         fd_sys_util_exit_group( 1 );
     132           0 :       } else {
     133           0 :         FD_LOG_WARNING(( "could not get user id for `%s` (%i-%s)", user, errno, fd_io_strerror( errno ) ));
     134           0 :         fd_sys_util_exit_group( 1 );
     135           0 :       }
     136           0 :     }
     137           0 :     if( FD_UNLIKELY( !result ) ) {
     138           0 :       FD_LOG_WARNING(( "configuration file wants firedancer to run as user `%s` but it does not exist", user ));
     139           0 :       fd_sys_util_exit_group( 1 );
     140           0 :     }
     141             : 
     142           0 :     results[ 0 ] = pwd.pw_uid;
     143           0 :     results[ 1 ] = pwd.pw_gid;
     144           0 :     fd_sys_util_exit_group( 0 );
     145           0 :   } else {
     146           0 :     int wstatus;
     147           0 :     if( FD_UNLIKELY( -1==waitpid( pid, &wstatus, 0 ) ) ) return -1;
     148           0 :     if( FD_UNLIKELY( WIFSIGNALED( wstatus ) ) ) {
     149           0 :       FD_LOG_WARNING(( "uid fetch process terminated by signal %i-%s", WTERMSIG( wstatus ), fd_io_strsignal( WTERMSIG( wstatus ) ) ));
     150           0 :       munmap( results, 4096 );
     151           0 :       errno = EINTR;
     152           0 :       return -1;
     153           0 :     }
     154           0 :     if( FD_UNLIKELY( WEXITSTATUS( wstatus ) ) ) {
     155           0 :       FD_LOG_WARNING(( "uid fetch process exited with status %i", WEXITSTATUS( wstatus ) ));
     156           0 :       munmap( results, 4096 );
     157           0 :       errno = EINTR;
     158           0 :       return -1;
     159           0 :     }
     160           0 :   }
     161             : 
     162           0 :   if( FD_UNLIKELY( results[ 0 ]==UINT_MAX || results[ 1 ]==UINT_MAX ) ) {
     163           0 :     munmap( results, 4096 );
     164           0 :     errno = ENOENT;
     165           0 :     return -1;
     166           0 :   }
     167             : 
     168           0 :   *uid = results[ 0 ];
     169           0 :   *gid = results[ 1 ];
     170             : 
     171           0 :   if( FD_UNLIKELY( -1==munmap( results, 4096 ) ) ) return -1;
     172             : 
     173           0 :   return 0;
     174           0 : }

Generated by: LCOV version 1.14