New module 'grantpt'.
[gnulib.git] / lib / grantpt.c
1 /* Acquire ownership of the slave side of a pseudo-terminal.
2    Copyright (C) 1998-2002, 2009-2010 Free Software Foundation, Inc.
3    Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 #include <stdlib.h>
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27
28 #if HAVE_SETRLIMIT
29 # include <sys/types.h>
30 # include <sys/time.h>
31 # include <sys/resource.h>
32 #endif
33
34 #include "configmake.h"
35 #include "pty-private.h"
36
37 #ifndef _LIBC
38 # define __builtin_expect(expr,val) (expr)
39 # define __set_errno(e) errno = (e)
40 # define __dup2 dup2
41 # define __fork fork
42 # define __setrlimit setrlimit
43 # define __waitpid waitpid
44 #endif
45
46 int
47 grantpt (int fd)
48 {
49   /* This function is most often called from a process without 'root'
50      credentials.  Use the helper program.  */
51   int retval = -1;
52   pid_t pid = __fork ();
53   if (pid == -1)
54     goto cleanup;
55   else if (pid == 0)
56     {
57       /* This is executed in the child process.  */
58
59 #if HAVE_SETRLIMIT && defined RLIMIT_CORE
60       /* Disable core dumps.  */
61       struct rlimit rl = { 0, 0 };
62       __setrlimit (RLIMIT_CORE, &rl);
63 #endif
64
65       /* We pass the master pseudo terminal as file descriptor PTY_FILENO.  */
66       if (fd != PTY_FILENO)
67         if (__dup2 (fd, PTY_FILENO) < 0)
68           _exit (FAIL_EBADF);
69
70 #ifdef CLOSE_ALL_FDS
71       CLOSE_ALL_FDS ();
72 #endif
73
74       execle (_PATH_PT_CHOWN, strrchr (_PATH_PT_CHOWN, '/') + 1, NULL, NULL);
75       _exit (FAIL_EXEC);
76     }
77   else
78     {
79       int w;
80
81       if (__waitpid (pid, &w, 0) == -1)
82         goto cleanup;
83       if (!WIFEXITED (w))
84         __set_errno (ENOEXEC);
85       else
86         switch (WEXITSTATUS (w))
87           {
88           case 0:
89             retval = 0;
90             break;
91           case FAIL_EBADF:
92             __set_errno (EBADF);
93             break;
94           case FAIL_EINVAL:
95             __set_errno (EINVAL);
96             break;
97           case FAIL_EACCES:
98             __set_errno (EACCES);
99             break;
100           case FAIL_EXEC:
101             __set_errno (ENOEXEC);
102             break;
103           case FAIL_ENOMEM:
104             __set_errno (ENOMEM);
105             break;
106
107           default:
108             assert(! "getpt: internal error: invalid exit code from pt_chown");
109           }
110     }
111
112  cleanup:
113   return retval;
114 }