Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Server-side request handling |
| 3 | * |
| 4 | * Copyright (C) 1998 Alexandre Julliard |
| 5 | */ |
| 6 | |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 7 | #include "config.h" |
| 8 | |
Alexandre Julliard | aa0ebd0 | 1998-12-30 12:06:45 +0000 | [diff] [blame] | 9 | #include <assert.h> |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 10 | #include <errno.h> |
| 11 | #include <fcntl.h> |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 12 | #include <pwd.h> |
| 13 | #include <signal.h> |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 14 | #include <stdio.h> |
| 15 | #include <stdlib.h> |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 16 | #include <stdarg.h> |
| 17 | #include <string.h> |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 18 | #include <sys/stat.h> |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 19 | #include <sys/time.h> |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 20 | #include <sys/types.h> |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 21 | #ifdef HAVE_SYS_SOCKET_H |
| 22 | # include <sys/socket.h> |
| 23 | #endif |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 24 | #include <sys/uio.h> |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 25 | #include <sys/un.h> |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 26 | #include <unistd.h> |
| 27 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 28 | #include "winnt.h" |
| 29 | #include "winbase.h" |
Alexandre Julliard | 4b46112 | 1999-01-31 19:04:30 +0000 | [diff] [blame] | 30 | #include "wincon.h" |
Alexandre Julliard | 43c190e | 1999-05-15 10:48:19 +0000 | [diff] [blame] | 31 | #include "thread.h" |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 32 | #include "process.h" |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 33 | #include "server.h" |
| 34 | #define WANT_REQUEST_HANDLERS |
| 35 | #include "request.h" |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 36 | |
| 37 | /* Some versions of glibc don't define this */ |
| 38 | #ifndef SCM_RIGHTS |
| 39 | #define SCM_RIGHTS 1 |
| 40 | #endif |
| 41 | |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 42 | /* path names for server master Unix socket */ |
| 43 | #define CONFDIR "/.wine" /* directory for Wine config relative to $HOME */ |
| 44 | #define SERVERDIR "/wineserver-" /* server socket directory (hostname appended) */ |
| 45 | #define SOCKETNAME "socket" /* name of the socket file */ |
| 46 | |
| 47 | struct master_socket |
| 48 | { |
| 49 | struct object obj; /* object header */ |
| 50 | }; |
| 51 | |
| 52 | static void master_socket_dump( struct object *obj, int verbose ); |
| 53 | static void master_socket_poll_event( struct object *obj, int event ); |
| 54 | static void master_socket_destroy( struct object *obj ); |
| 55 | |
| 56 | static const struct object_ops master_socket_ops = |
| 57 | { |
| 58 | sizeof(struct master_socket), /* size */ |
| 59 | master_socket_dump, /* dump */ |
| 60 | no_add_queue, /* add_queue */ |
| 61 | NULL, /* remove_queue */ |
| 62 | NULL, /* signaled */ |
| 63 | NULL, /* satisfied */ |
| 64 | NULL, /* get_poll_events */ |
| 65 | master_socket_poll_event, /* poll_event */ |
| 66 | no_read_fd, /* get_read_fd */ |
| 67 | no_write_fd, /* get_write_fd */ |
| 68 | no_flush, /* flush */ |
| 69 | no_get_file_info, /* get_file_info */ |
| 70 | master_socket_destroy /* destroy */ |
| 71 | }; |
| 72 | |
| 73 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 74 | struct thread *current = NULL; /* thread handling the current request */ |
Alexandre Julliard | 6c8d917 | 2000-08-26 04:40:07 +0000 | [diff] [blame] | 75 | int global_error = 0; /* global error code for when no thread is current */ |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 76 | |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 77 | static struct master_socket *master_socket; /* the master socket object */ |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 78 | |
| 79 | /* socket communication static structures */ |
| 80 | static struct iovec myiovec; |
Patrik Stridvall | a9f6a9d | 2000-10-24 02:22:16 +0000 | [diff] [blame] | 81 | static struct msghdr msghdr = { NULL, 0, &myiovec, 1, /* remaining fields depend on system */ }; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 82 | #ifndef HAVE_MSGHDR_ACCRIGHTS |
| 83 | struct cmsg_fd |
| 84 | { |
| 85 | int len; /* sizeof structure */ |
| 86 | int level; /* SOL_SOCKET */ |
| 87 | int type; /* SCM_RIGHTS */ |
| 88 | int fd; /* fd to pass */ |
| 89 | }; |
| 90 | static struct cmsg_fd cmsg = { sizeof(cmsg), SOL_SOCKET, SCM_RIGHTS, -1 }; |
| 91 | #endif /* HAVE_MSGHDR_ACCRIGHTS */ |
| 92 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 93 | /* complain about a protocol error and terminate the client connection */ |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 94 | void fatal_protocol_error( struct thread *thread, const char *err, ... ) |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 95 | { |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 96 | va_list args; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 97 | |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 98 | va_start( args, err ); |
| 99 | fprintf( stderr, "Protocol error:%p: ", thread ); |
| 100 | vfprintf( stderr, err, args ); |
| 101 | va_end( args ); |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 102 | thread->exit_code = 1; |
| 103 | kill_thread( thread, 1 ); |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 104 | } |
| 105 | |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 106 | /* die on a fatal error */ |
Alexandre Julliard | 6c8d917 | 2000-08-26 04:40:07 +0000 | [diff] [blame] | 107 | void fatal_error( const char *err, ... ) |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 108 | { |
| 109 | va_list args; |
| 110 | |
| 111 | va_start( args, err ); |
| 112 | fprintf( stderr, "wineserver: " ); |
| 113 | vfprintf( stderr, err, args ); |
| 114 | va_end( args ); |
| 115 | exit(1); |
| 116 | } |
| 117 | |
| 118 | /* die on a fatal error */ |
Alexandre Julliard | 6c8d917 | 2000-08-26 04:40:07 +0000 | [diff] [blame] | 119 | void fatal_perror( const char *err, ... ) |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 120 | { |
| 121 | va_list args; |
| 122 | |
| 123 | va_start( args, err ); |
| 124 | fprintf( stderr, "wineserver: " ); |
| 125 | vfprintf( stderr, err, args ); |
| 126 | perror( " " ); |
| 127 | va_end( args ); |
| 128 | exit(1); |
| 129 | } |
| 130 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 131 | /* call a request handler */ |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 132 | static inline void call_req_handler( struct thread *thread ) |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 133 | { |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 134 | enum request req; |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 135 | current = thread; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 136 | clear_error(); |
| 137 | |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 138 | req = ((struct request_header *)current->buffer)->req; |
| 139 | |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 140 | if (debug_level) trace_request( req ); |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 141 | |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 142 | if (req < REQ_NB_REQUESTS) |
| 143 | { |
Alexandre Julliard | ea0d028 | 2000-03-10 22:16:10 +0000 | [diff] [blame] | 144 | req_handlers[req]( current->buffer ); |
Alexandre Julliard | 9de03f4 | 2000-01-04 02:23:38 +0000 | [diff] [blame] | 145 | if (current && !current->wait) send_reply( current ); |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 146 | current = NULL; |
| 147 | return; |
| 148 | } |
| 149 | fatal_protocol_error( current, "bad request %d\n", req ); |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 152 | /* set the fd to pass to the thread */ |
| 153 | void set_reply_fd( struct thread *thread, int pass_fd ) |
| 154 | { |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 155 | assert( thread->pass_fd == -1 ); |
| 156 | thread->pass_fd = pass_fd; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | /* send a reply to a thread */ |
| 160 | void send_reply( struct thread *thread ) |
| 161 | { |
Alexandre Julliard | 9de03f4 | 2000-01-04 02:23:38 +0000 | [diff] [blame] | 162 | assert( !thread->wait ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 163 | if (debug_level) trace_reply( thread ); |
| 164 | if (!write_request( thread )) set_select_events( &thread->obj, POLLOUT ); |
| 165 | } |
| 166 | |
| 167 | /* read a message from a client that has something to say */ |
| 168 | void read_request( struct thread *thread ) |
| 169 | { |
| 170 | int ret; |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 171 | char dummy[1]; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 172 | |
| 173 | #ifdef HAVE_MSGHDR_ACCRIGHTS |
| 174 | msghdr.msg_accrightslen = sizeof(int); |
| 175 | msghdr.msg_accrights = (void *)&thread->pass_fd; |
| 176 | #else /* HAVE_MSGHDR_ACCRIGHTS */ |
| 177 | msghdr.msg_control = &cmsg; |
| 178 | msghdr.msg_controllen = sizeof(cmsg); |
| 179 | cmsg.fd = -1; |
| 180 | #endif /* HAVE_MSGHDR_ACCRIGHTS */ |
| 181 | |
| 182 | assert( thread->pass_fd == -1 ); |
| 183 | |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 184 | myiovec.iov_base = dummy; |
| 185 | myiovec.iov_len = 1; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 186 | |
| 187 | ret = recvmsg( thread->obj.fd, &msghdr, 0 ); |
| 188 | #ifndef HAVE_MSGHDR_ACCRIGHTS |
| 189 | thread->pass_fd = cmsg.fd; |
| 190 | #endif |
| 191 | |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 192 | if (ret > 0) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 193 | { |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 194 | call_req_handler( thread ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 195 | thread->pass_fd = -1; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 196 | return; |
| 197 | } |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 198 | if (!ret) /* closed pipe */ |
| 199 | { |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 200 | kill_thread( thread, 0 ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 201 | return; |
| 202 | } |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 203 | perror("recvmsg"); |
| 204 | thread->exit_code = 1; |
| 205 | kill_thread( thread, 1 ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 206 | } |
| 207 | |
| 208 | /* send a message to a client that is ready to receive something */ |
| 209 | int write_request( struct thread *thread ) |
| 210 | { |
| 211 | int ret; |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 212 | struct request_header *header = thread->buffer; |
| 213 | |
| 214 | header->error = thread->error; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 215 | |
| 216 | if (thread->pass_fd == -1) |
| 217 | { |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 218 | /* write a single byte; the value is ignored anyway */ |
| 219 | ret = write( thread->obj.fd, header, 1 ); |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 220 | } |
| 221 | else /* we have an fd to send */ |
| 222 | { |
| 223 | #ifdef HAVE_MSGHDR_ACCRIGHTS |
| 224 | msghdr.msg_accrightslen = sizeof(int); |
| 225 | msghdr.msg_accrights = (void *)&thread->pass_fd; |
| 226 | #else /* HAVE_MSGHDR_ACCRIGHTS */ |
| 227 | msghdr.msg_control = &cmsg; |
| 228 | msghdr.msg_controllen = sizeof(cmsg); |
| 229 | cmsg.fd = thread->pass_fd; |
| 230 | #endif /* HAVE_MSGHDR_ACCRIGHTS */ |
| 231 | |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 232 | myiovec.iov_base = (void *)header; |
| 233 | myiovec.iov_len = 1; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 234 | |
| 235 | ret = sendmsg( thread->obj.fd, &msghdr, 0 ); |
| 236 | close( thread->pass_fd ); |
| 237 | thread->pass_fd = -1; |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 238 | } |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 239 | if (ret > 0) |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 240 | { |
| 241 | set_select_events( &thread->obj, POLLIN ); |
| 242 | return 1; |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 243 | } |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 244 | if (errno == EWOULDBLOCK) return 0; /* not a fatal error */ |
| 245 | if (errno == EPIPE) |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 246 | { |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 247 | kill_thread( thread, 0 ); /* normal death */ |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 248 | } |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 249 | else |
| 250 | { |
Alexandre Julliard | 8611353 | 2000-08-29 03:54:30 +0000 | [diff] [blame] | 251 | perror("sendmsg"); |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 252 | thread->exit_code = 1; |
| 253 | kill_thread( thread, 1 ); |
Alexandre Julliard | 12f29b5 | 2000-03-17 15:16:57 +0000 | [diff] [blame] | 254 | } |
Alexandre Julliard | 1dca5e2 | 2000-01-01 00:56:27 +0000 | [diff] [blame] | 255 | return -1; |
Alexandre Julliard | 5bc7808 | 1999-06-22 17:26:53 +0000 | [diff] [blame] | 256 | } |
| 257 | |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 258 | static void master_socket_dump( struct object *obj, int verbose ) |
Alexandre Julliard | 338e757 | 1998-12-27 15:28:54 +0000 | [diff] [blame] | 259 | { |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 260 | struct master_socket *sock = (struct master_socket *)obj; |
| 261 | assert( obj->ops == &master_socket_ops ); |
| 262 | fprintf( stderr, "Master socket fd=%d\n", sock->obj.fd ); |
| 263 | } |
| 264 | |
| 265 | /* handle a socket event */ |
| 266 | static void master_socket_poll_event( struct object *obj, int event ) |
| 267 | { |
| 268 | struct master_socket *sock = (struct master_socket *)obj; |
| 269 | assert( obj->ops == &master_socket_ops ); |
| 270 | |
| 271 | assert( sock == master_socket ); /* there is only one master socket */ |
| 272 | |
| 273 | if (event & (POLLERR | POLLHUP)) |
| 274 | { |
| 275 | /* this is not supposed to happen */ |
| 276 | fprintf( stderr, "wineserver: Error on master socket\n" ); |
| 277 | release_object( obj ); |
| 278 | } |
| 279 | else if (event & POLLIN) |
| 280 | { |
| 281 | struct sockaddr_un dummy; |
| 282 | int len = sizeof(dummy); |
Patrik Stridvall | 7e9913f | 2000-03-08 18:25:22 +0000 | [diff] [blame] | 283 | int client = accept( master_socket->obj.fd, (struct sockaddr *) &dummy, &len ); |
Alexandre Julliard | 5b4f3e8 | 2000-05-01 16:24:22 +0000 | [diff] [blame] | 284 | if (client != -1) create_process( client ); |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 285 | } |
| 286 | } |
| 287 | |
| 288 | /* remove the socket upon exit */ |
| 289 | static void socket_cleanup(void) |
| 290 | { |
Alexandre Julliard | c10c9ef | 2000-08-11 21:16:53 +0000 | [diff] [blame] | 291 | static int do_it_once; |
| 292 | if (!do_it_once++) unlink( SOCKETNAME ); |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 293 | } |
| 294 | |
| 295 | static void master_socket_destroy( struct object *obj ) |
| 296 | { |
| 297 | socket_cleanup(); |
| 298 | } |
| 299 | |
Alexandre Julliard | de1d5ad | 2000-04-06 20:36:17 +0000 | [diff] [blame] | 300 | /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */ |
Alexandre Julliard | 6c8d917 | 2000-08-26 04:40:07 +0000 | [diff] [blame] | 301 | const char *get_config_dir(void) |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 302 | { |
| 303 | static char *confdir; |
| 304 | if (!confdir) |
| 305 | { |
Alexandre Julliard | de1d5ad | 2000-04-06 20:36:17 +0000 | [diff] [blame] | 306 | const char *prefix = getenv( "WINEPREFIX" ); |
| 307 | if (prefix) |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 308 | { |
Alexandre Julliard | de1d5ad | 2000-04-06 20:36:17 +0000 | [diff] [blame] | 309 | int len = strlen(prefix); |
| 310 | if (!(confdir = strdup( prefix ))) fatal_error( "out of memory\n" ); |
| 311 | if (len > 1 && confdir[len-1] == '/') confdir[len-1] = 0; |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 312 | } |
Alexandre Julliard | de1d5ad | 2000-04-06 20:36:17 +0000 | [diff] [blame] | 313 | else |
| 314 | { |
| 315 | const char *home = getenv( "HOME" ); |
| 316 | if (!home) |
| 317 | { |
| 318 | struct passwd *pwd = getpwuid( getuid() ); |
| 319 | if (!pwd) fatal_error( "could not find your home directory\n" ); |
| 320 | home = pwd->pw_dir; |
| 321 | } |
| 322 | if (!(confdir = malloc( strlen(home) + strlen(CONFDIR) + 1 ))) |
| 323 | fatal_error( "out of memory\n" ); |
| 324 | strcpy( confdir, home ); |
| 325 | strcat( confdir, CONFDIR ); |
| 326 | } |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 327 | mkdir( confdir, 0755 ); /* just in case */ |
| 328 | } |
| 329 | return confdir; |
| 330 | } |
| 331 | |
| 332 | /* create the server directory and chdir to it */ |
| 333 | static void create_server_dir(void) |
| 334 | { |
| 335 | char hostname[64]; |
| 336 | char *serverdir; |
| 337 | const char *confdir = get_config_dir(); |
| 338 | struct stat st; |
| 339 | |
| 340 | if (gethostname( hostname, sizeof(hostname) ) == -1) fatal_perror( "gethostname" ); |
| 341 | |
| 342 | if (!(serverdir = malloc( strlen(confdir) + strlen(SERVERDIR) + strlen(hostname) + 1 ))) |
| 343 | fatal_error( "out of memory\n" ); |
| 344 | |
| 345 | strcpy( serverdir, confdir ); |
| 346 | strcat( serverdir, SERVERDIR ); |
| 347 | strcat( serverdir, hostname ); |
| 348 | |
| 349 | if (chdir( serverdir ) == -1) |
| 350 | { |
| 351 | if (errno != ENOENT) fatal_perror( "chdir %s", serverdir ); |
| 352 | if (mkdir( serverdir, 0700 ) == -1) fatal_perror( "mkdir %s", serverdir ); |
| 353 | if (chdir( serverdir ) == -1) fatal_perror( "chdir %s", serverdir ); |
| 354 | } |
| 355 | if (stat( ".", &st ) == -1) fatal_perror( "stat %s", serverdir ); |
| 356 | if (!S_ISDIR(st.st_mode)) fatal_error( "%s is not a directory\n", serverdir ); |
| 357 | if (st.st_uid != getuid()) fatal_error( "%s is not owned by you\n", serverdir ); |
| 358 | if (st.st_mode & 077) fatal_error( "%s must not be accessible by other users\n", serverdir ); |
| 359 | } |
| 360 | |
| 361 | /* open the master server socket and start waiting for new clients */ |
| 362 | void open_master_socket(void) |
| 363 | { |
| 364 | struct sockaddr_un addr; |
Juergen Lock | 2d33ab9 | 2000-02-13 16:03:29 +0000 | [diff] [blame] | 365 | int fd, slen; |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 366 | |
| 367 | create_server_dir(); |
| 368 | if ((fd = socket( AF_UNIX, SOCK_STREAM, 0 )) == -1) fatal_perror( "socket" ); |
| 369 | addr.sun_family = AF_UNIX; |
Juergen Lock | 2d33ab9 | 2000-02-13 16:03:29 +0000 | [diff] [blame] | 370 | strcpy( addr.sun_path, SOCKETNAME ); |
| 371 | slen = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path) + 1; |
| 372 | #ifdef HAVE_SOCKADDR_SUN_LEN |
| 373 | addr.sun_len = slen; |
| 374 | #endif |
| 375 | if (bind( fd, (struct sockaddr *)&addr, slen ) == -1) |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 376 | { |
| 377 | if ((errno == EEXIST) || (errno == EADDRINUSE)) |
Alexandre Julliard | c10c9ef | 2000-08-11 21:16:53 +0000 | [diff] [blame] | 378 | exit(0); /* pretend we succeeded to start */ |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 379 | else |
| 380 | fatal_perror( "bind" ); |
| 381 | } |
| 382 | atexit( socket_cleanup ); |
| 383 | |
Juergen Lock | 2d33ab9 | 2000-02-13 16:03:29 +0000 | [diff] [blame] | 384 | chmod( SOCKETNAME, 0600 ); /* make sure no other user can connect */ |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 385 | if (listen( fd, 5 ) == -1) fatal_perror( "listen" ); |
| 386 | |
| 387 | if (!(master_socket = alloc_object( &master_socket_ops, fd ))) |
| 388 | fatal_error( "out of memory\n" ); |
| 389 | set_select_events( &master_socket->obj, POLLIN ); |
Alexandre Julliard | d804111 | 2000-04-14 14:42:41 +0000 | [diff] [blame] | 390 | |
| 391 | /* go in the background */ |
| 392 | switch(fork()) |
| 393 | { |
| 394 | case -1: |
| 395 | fatal_perror( "fork" ); |
| 396 | case 0: |
| 397 | setsid(); |
| 398 | break; |
| 399 | default: |
| 400 | _exit(0); /* do not call atexit functions */ |
| 401 | } |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | /* close the master socket and stop waiting for new clients */ |
| 405 | void close_master_socket(void) |
| 406 | { |
Alexandre Julliard | c10c9ef | 2000-08-11 21:16:53 +0000 | [diff] [blame] | 407 | /* if a new client is waiting, we keep on running */ |
| 408 | if (!check_select_events( master_socket->obj.fd, POLLIN )) |
| 409 | release_object( master_socket ); |
Alexandre Julliard | 2fe5777 | 2000-01-25 01:40:27 +0000 | [diff] [blame] | 410 | } |
| 411 | |
| 412 | /* lock/unlock the master socket to stop accepting new clients */ |
| 413 | void lock_master_socket( int locked ) |
| 414 | { |
| 415 | set_select_events( &master_socket->obj, locked ? 0 : POLLIN ); |
Alexandre Julliard | 338e757 | 1998-12-27 15:28:54 +0000 | [diff] [blame] | 416 | } |