maint: update copyright
[gnulib.git] / lib / grantpt.c
1 /* Acquire ownership of the slave side of a pseudo-terminal.
2    Copyright (C) 1998-2002, 2009-2014 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 #if defined __OpenBSD__
50   /* On OpenBSD, master and slave of a pseudo-terminal are allocated together,
51      through an ioctl on /dev/ptm.  There is no need for grantpt().  */
52   return 0;
53 #else
54   /* This function is most often called from a process without 'root'
55      credentials.  Use the helper program.  */
56   int retval = -1;
57   pid_t pid = __fork ();
58   if (pid == -1)
59     goto cleanup;
60   else if (pid == 0)
61     {
62       /* This is executed in the child process.  */
63
64 # if HAVE_SETRLIMIT && defined RLIMIT_CORE
65       /* Disable core dumps.  */
66       struct rlimit rl = { 0, 0 };
67       __setrlimit (RLIMIT_CORE, &rl);
68 # endif
69
70       /* We pass the master pseudo terminal as file descriptor PTY_FILENO.  */
71       if (fd != PTY_FILENO)
72         if (__dup2 (fd, PTY_FILENO) < 0)
73           _exit (FAIL_EBADF);
74
75 # ifdef CLOSE_ALL_FDS
76       CLOSE_ALL_FDS ();
77 # endif
78
79       execle (_PATH_PT_CHOWN, strrchr (_PATH_PT_CHOWN, '/') + 1, NULL, NULL);
80       _exit (FAIL_EXEC);
81     }
82   else
83     {
84       int w;
85
86       if (__waitpid (pid, &w, 0) == -1)
87         goto cleanup;
88       if (!WIFEXITED (w))
89         __set_errno (ENOEXEC);
90       else
91         switch (WEXITSTATUS (w))
92           {
93           case 0:
94             retval = 0;
95             break;
96           case FAIL_EBADF:
97             __set_errno (EBADF);
98             break;
99           case FAIL_EINVAL:
100             __set_errno (EINVAL);
101             break;
102           case FAIL_EACCES:
103             __set_errno (EACCES);
104             break;
105           case FAIL_EXEC:
106             __set_errno (ENOEXEC);
107             break;
108           case FAIL_ENOMEM:
109             __set_errno (ENOMEM);
110             break;
111
112           default:
113             assert(! "getpt: internal error: invalid exit code from pt_chown");
114           }
115     }
116
117  cleanup:
118   return retval;
119 #endif
120 }