1 /* 2 Test porting lib (common/system_*.c) 3 4 Copyright (C) Mathieu Parent 2013 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "replace.h" 21 #include "system/filesys.h" 22 #include "system/network.h" 23 24 #include <popt.h> 25 #include <talloc.h> 26 #include <tevent.h> 27 #include <tdb.h> 28 #include <assert.h> 29 30 #include "lib/util/debug.h" 31 #include "lib/util/blocking.h" 32 33 #include "protocol/protocol.h" 34 #include "common/system.h" 35 #include "common/logging.h" 36 37 38 static struct { 39 const char *socketname; 40 const char *debuglevel; writer_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd,uint8_t * buf,size_t buflen)41 pid_t helper_pid; 42 int socket; 43 } globals = { 44 .socketname = "/tmp/test.sock" 45 }; 46 47 48 49 /* 50 Socket functions 51 */ 52 /* 53 create a unix domain socket and bind it 54 return a file descriptor open on the socket 55 */ 56 static int socket_server_create(void) 57 { 58 struct sockaddr_un addr; 59 int ret; 60 61 globals.socket = socket(AF_UNIX, SOCK_STREAM, 0); 62 assert(globals.socket != -1); 63 64 set_close_on_exec(globals.socket); 65 //set_blocking(globals.socket, false); 66 67 memset(&addr, 0, sizeof(addr)); 68 addr.sun_family = AF_UNIX; 69 strncpy(addr.sun_path, globals.socketname, sizeof(addr.sun_path)-1); writer_next(struct tevent_req * subreq)70 71 ret = bind(globals.socket, (struct sockaddr *)&addr, sizeof(addr)); 72 assert(ret == 0); 73 74 ret = chown(globals.socketname, geteuid(), getegid()); 75 assert(ret == 0); 76 77 ret = chmod(globals.socketname, 0700); 78 assert(ret == 0); 79 80 ret = listen(globals.socket, 100); 81 assert(ret == 0); 82 83 return 0; 84 } 85 86 static int socket_server_wait_peer(void) 87 { 88 struct sockaddr_un addr; 89 socklen_t len; 90 int fd; 91 92 memset(&addr, 0, sizeof(addr)); 93 len = sizeof(addr); 94 fd = accept(globals.socket, (struct sockaddr *)&addr, &len); 95 assert(fd != -1); 96 97 //set_blocking(fd, false); 98 set_close_on_exec(fd); 99 return fd; 100 } 101 102 static int socket_server_close(void) 103 { 104 int ret; 105 106 ret = close(globals.socket); 107 assert(ret == 0); writer_recv(struct tevent_req * req,int * perr)108 109 ret = unlink(globals.socketname); 110 assert(ret == 0); 111 112 return 0; 113 } 114 115 static int socket_client_connect(void) 116 { 117 struct sockaddr_un addr; 118 int client = 0; 119 int ret; 120 121 client = socket(AF_UNIX, SOCK_STREAM, 0); 122 assert(client != -1); 123 124 memset(&addr, 0, sizeof(addr)); 125 addr.sun_family = AF_UNIX; 126 strncpy(addr.sun_path, globals.socketname, sizeof(addr.sun_path)-1); writer_handler(struct tevent_context * ev,struct tevent_fd * fde,uint16_t flags,void * private_data)127 128 ret = connect(client, (struct sockaddr *)&addr, sizeof(addr)); 129 assert(ret == 0); 130 131 return client; 132 } 133 134 static int socket_client_close(int client) 135 { 136 int ret; 137 138 ret = close(client); writer(int fd)139 assert(ret == 0); 140 141 return 0; 142 } 143 144 /* 145 forked program 146 */ 147 static int fork_helper(void) 148 { 149 pid_t pid; 150 int client; 151 152 pid = fork(); 153 assert(pid != -1); 154 155 if (pid == 0) { // Child 156 pid = getppid(); 157 client = socket_client_connect(); 158 while (kill(pid, 0) == 0) { 159 sleep(1); 160 } 161 socket_client_close(client); 162 exit(0); 163 } else { 164 globals.helper_pid = pid; 165 } 166 return 0; 167 } 168 169 /* 170 tests 171 */ 172 static int test_ctdb_sys_check_iface_exists(void) 173 { 174 const char *fakename = "fake"; 175 bool test; 176 177 test = ctdb_sys_check_iface_exists(fakename); 178 if (geteuid() == 0) { 179 assert(test == false); 180 } else { 181 assert(test == true); 182 } 183 return 0; 184 } 185 186 static int test_ctdb_get_peer_pid(void) 187 { 188 int ret; 189 int fd; 190 pid_t peer_pid = 0; 191 192 fd = socket_server_wait_peer(); 193 194 ret = ctdb_get_peer_pid(fd, &peer_pid); reader_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd)195 assert(ret == 0 || ret == ENOSYS); 196 197 if (ret == 0) { 198 assert(peer_pid == globals.helper_pid); 199 200 kill(peer_pid, SIGTERM); 201 } else { 202 kill(globals.helper_pid, SIGTERM); 203 } 204 205 close(fd); 206 return 0; 207 } 208 209 /* 210 main program 211 */ 212 int main(int argc, const char *argv[]) 213 { 214 struct poptOption popt_options[] = { 215 POPT_AUTOHELP 216 { "socket", 0, POPT_ARG_STRING, &globals.socketname, 0, "local socket name", "filename" }, 217 POPT_TABLEEND 218 }; 219 int opt, ret; 220 const char **extra_argv; reader_more(uint8_t * buf,size_t buflen,void * private_data)221 int extra_argc = 0; 222 poptContext pc; 223 224 pc = poptGetContext(argv[0], argc, argv, popt_options, POPT_CONTEXT_KEEP_FIRST); 225 226 while ((opt = poptGetNextOpt(pc)) != -1) { 227 switch (opt) { 228 default: 229 fprintf(stderr, "Invalid option %s: %s\n", 230 poptBadOption(pc, 0), poptStrerror(opt)); 231 exit(1); 232 } reader_done(struct tevent_req * subreq)233 } 234 235 /* setup the remaining options for the main program to use */ 236 extra_argv = poptGetArgs(pc); 237 if (extra_argv) { 238 extra_argv++; 239 while (extra_argv[extra_argc]) extra_argc++; 240 } 241 242 assert(globals.socketname != NULL); 243 244 ret = socket_server_create(); 245 assert(ret == 0); 246 247 /* FIXME: Test tcp_checksum6, tcp_checksum */ 248 /* FIXME: Test ctdb_sys_send_arp, ctdb_sys_send_tcp */ 249 /* FIXME: Test ctdb_sys_{open,close}_capture_socket, ctdb_sys_read_tcp_packet */ 250 test_ctdb_sys_check_iface_exists(); 251 252 ret = fork_helper(); 253 assert(ret == 0); 254 test_ctdb_get_peer_pid(); 255 256 ret = socket_server_close(); 257 assert(ret == 0); 258 259 return 0; 260 } 261