1 1.1 christos /* $NetBSD: irp.c,v 1.1.1.2 2012/09/09 16:07:50 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * Copyright (C) 1996, 1998-2001, 2003 Internet Software Consortium. 6 1.1 christos * 7 1.1 christos * Permission to use, copy, modify, and/or distribute this software for any 8 1.1 christos * purpose with or without fee is hereby granted, provided that the above 9 1.1 christos * copyright notice and this permission notice appear in all copies. 10 1.1 christos * 11 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 1.1 christos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 1.1 christos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 1.1 christos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 1.1 christos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 1.1 christos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 1.1 christos * PERFORMANCE OF THIS SOFTWARE. 18 1.1 christos */ 19 1.1 christos 20 1.1 christos #if !defined(LINT) && !defined(CODECENTER) 21 1.1.1.2 christos static const char rcsid[] = "Id: irp.c,v 1.12 2008/11/14 02:36:51 marka Exp "; 22 1.1 christos #endif 23 1.1 christos 24 1.1 christos /* Imports */ 25 1.1 christos 26 1.1 christos #include "port_before.h" 27 1.1 christos 28 1.1 christos #include <syslog.h> 29 1.1 christos #include <sys/types.h> 30 1.1 christos #include <sys/socket.h> 31 1.1 christos #include <sys/un.h> 32 1.1 christos #include <netinet/in.h> 33 1.1 christos #include <arpa/inet.h> 34 1.1 christos #include <stdlib.h> 35 1.1 christos #include <errno.h> 36 1.1 christos #include <string.h> 37 1.1 christos #include <stdarg.h> 38 1.1 christos #include <fcntl.h> 39 1.1 christos #include <syslog.h> 40 1.1 christos #include <ctype.h> 41 1.1 christos #include <unistd.h> 42 1.1 christos 43 1.1 christos #include <isc/memcluster.h> 44 1.1 christos 45 1.1 christos #include <irs.h> 46 1.1 christos #include <irp.h> 47 1.1 christos 48 1.1 christos #include "irs_p.h" 49 1.1 christos #include "irp_p.h" 50 1.1 christos 51 1.1 christos #include "port_after.h" 52 1.1 christos 53 1.1 christos /* Forward. */ 54 1.1 christos 55 1.1 christos static void irp_close(struct irs_acc *); 56 1.1 christos 57 1.1 christos #define LINEINCR 128 58 1.1 christos 59 1.1 christos #if !defined(SUN_LEN) 60 1.1 christos #define SUN_LEN(su) \ 61 1.1 christos (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path)) 62 1.1 christos #endif 63 1.1 christos 64 1.1 christos 65 1.1 christos /* Public */ 66 1.1 christos 67 1.1 christos 68 1.1 christos /* send errors to syslog if true. */ 69 1.1 christos int irp_log_errors = 1; 70 1.1 christos 71 1.1 christos /*% 72 1.1 christos * This module handles the irp module connection to irpd. 73 1.1 christos * 74 1.1 christos * The client expects a synchronous interface to functions like 75 1.1 christos * getpwnam(3), so we can't use the ctl_* i/o library on this end of 76 1.1 christos * the wire (it's used in the server). 77 1.1 christos */ 78 1.1 christos 79 1.1 christos /*% 80 1.1 christos * irs_acc *irs_irp_acc(const char *options); 81 1.1 christos * 82 1.1 christos * Initialize the irp module. 83 1.1 christos */ 84 1.1 christos struct irs_acc * 85 1.1 christos irs_irp_acc(const char *options) { 86 1.1 christos struct irs_acc *acc; 87 1.1 christos struct irp_p *irp; 88 1.1 christos 89 1.1 christos UNUSED(options); 90 1.1 christos 91 1.1 christos if (!(acc = memget(sizeof *acc))) { 92 1.1 christos errno = ENOMEM; 93 1.1 christos return (NULL); 94 1.1 christos } 95 1.1 christos memset(acc, 0x5e, sizeof *acc); 96 1.1 christos if (!(irp = memget(sizeof *irp))) { 97 1.1 christos errno = ENOMEM; 98 1.1 christos free(acc); 99 1.1 christos return (NULL); 100 1.1 christos } 101 1.1 christos irp->inlast = 0; 102 1.1 christos irp->incurr = 0; 103 1.1 christos irp->fdCxn = -1; 104 1.1 christos acc->private = irp; 105 1.1 christos 106 1.1 christos #ifdef WANT_IRS_GR 107 1.1 christos acc->gr_map = irs_irp_gr; 108 1.1 christos #else 109 1.1 christos acc->gr_map = NULL; 110 1.1 christos #endif 111 1.1 christos #ifdef WANT_IRS_PW 112 1.1 christos acc->pw_map = irs_irp_pw; 113 1.1 christos #else 114 1.1 christos acc->pw_map = NULL; 115 1.1 christos #endif 116 1.1 christos acc->sv_map = irs_irp_sv; 117 1.1 christos acc->pr_map = irs_irp_pr; 118 1.1 christos acc->ho_map = irs_irp_ho; 119 1.1 christos acc->nw_map = irs_irp_nw; 120 1.1 christos acc->ng_map = irs_irp_ng; 121 1.1 christos acc->close = irp_close; 122 1.1 christos return (acc); 123 1.1 christos } 124 1.1 christos 125 1.1 christos 126 1.1 christos int 127 1.1 christos irs_irp_connection_setup(struct irp_p *cxndata, int *warned) { 128 1.1 christos if (irs_irp_is_connected(cxndata)) { 129 1.1 christos return (0); 130 1.1 christos } else if (irs_irp_connect(cxndata) != 0) { 131 1.1 christos if (warned != NULL && !*warned) { 132 1.1 christos syslog(LOG_ERR, "irpd connection failed: %m\n"); 133 1.1 christos (*warned)++; 134 1.1 christos } 135 1.1 christos 136 1.1 christos return (-1); 137 1.1 christos } 138 1.1 christos 139 1.1 christos return (0); 140 1.1 christos } 141 1.1 christos 142 1.1 christos /*% 143 1.1 christos * int irs_irp_connect(void); 144 1.1 christos * 145 1.1 christos * Sets up the connection to the remote irpd server. 146 1.1 christos * 147 1.1 christos * Returns: 148 1.1 christos * 149 1.1 christos * 0 on success, -1 on failure. 150 1.1 christos * 151 1.1 christos */ 152 1.1 christos int 153 1.1 christos irs_irp_connect(struct irp_p *pvt) { 154 1.1 christos int flags; 155 1.1 christos struct sockaddr *addr; 156 1.1 christos struct sockaddr_in iaddr; 157 1.1 christos #ifndef NO_SOCKADDR_UN 158 1.1 christos struct sockaddr_un uaddr; 159 1.1 christos #endif 160 1.1 christos long ipaddr; 161 1.1 christos const char *irphost; 162 1.1 christos int code; 163 1.1 christos char text[256]; 164 1.1 christos int socklen = 0; 165 1.1 christos 166 1.1 christos if (pvt->fdCxn != -1) { 167 1.1 christos perror("fd != 1"); 168 1.1 christos return (-1); 169 1.1 christos } 170 1.1 christos 171 1.1 christos #ifndef NO_SOCKADDR_UN 172 1.1 christos memset(&uaddr, 0, sizeof uaddr); 173 1.1 christos #endif 174 1.1 christos memset(&iaddr, 0, sizeof iaddr); 175 1.1 christos 176 1.1 christos irphost = getenv(IRPD_HOST_ENV); 177 1.1 christos if (irphost == NULL) { 178 1.1 christos irphost = "127.0.0.1"; 179 1.1 christos } 180 1.1 christos 181 1.1 christos #ifndef NO_SOCKADDR_UN 182 1.1 christos if (irphost[0] == '/') { 183 1.1 christos addr = (struct sockaddr *)&uaddr; 184 1.1 christos strncpy(uaddr.sun_path, irphost, sizeof uaddr.sun_path); 185 1.1 christos uaddr.sun_family = AF_UNIX; 186 1.1 christos socklen = SUN_LEN(&uaddr); 187 1.1 christos #ifdef HAVE_SA_LEN 188 1.1 christos uaddr.sun_len = socklen; 189 1.1 christos #endif 190 1.1 christos } else 191 1.1 christos #endif 192 1.1 christos { 193 1.1 christos if (inet_pton(AF_INET, irphost, &ipaddr) != 1) { 194 1.1 christos errno = EADDRNOTAVAIL; 195 1.1 christos perror("inet_pton"); 196 1.1 christos return (-1); 197 1.1 christos } 198 1.1 christos 199 1.1 christos addr = (struct sockaddr *)&iaddr; 200 1.1 christos socklen = sizeof iaddr; 201 1.1 christos #ifdef HAVE_SA_LEN 202 1.1 christos iaddr.sin_len = socklen; 203 1.1 christos #endif 204 1.1 christos iaddr.sin_family = AF_INET; 205 1.1 christos iaddr.sin_port = htons(IRPD_PORT); 206 1.1 christos iaddr.sin_addr.s_addr = ipaddr; 207 1.1 christos } 208 1.1 christos 209 1.1 christos 210 1.1 christos pvt->fdCxn = socket(addr->sa_family, SOCK_STREAM, PF_UNSPEC); 211 1.1 christos if (pvt->fdCxn < 0) { 212 1.1 christos perror("socket"); 213 1.1 christos return (-1); 214 1.1 christos } 215 1.1 christos 216 1.1 christos if (connect(pvt->fdCxn, addr, socklen) != 0) { 217 1.1 christos perror("connect"); 218 1.1 christos return (-1); 219 1.1 christos } 220 1.1 christos 221 1.1 christos flags = fcntl(pvt->fdCxn, F_GETFL, 0); 222 1.1 christos if (flags < 0) { 223 1.1 christos close(pvt->fdCxn); 224 1.1 christos perror("close"); 225 1.1 christos return (-1); 226 1.1 christos } 227 1.1 christos 228 1.1 christos #if 0 229 1.1 christos flags |= O_NONBLOCK; 230 1.1 christos if (fcntl(pvt->fdCxn, F_SETFL, flags) < 0) { 231 1.1 christos close(pvt->fdCxn); 232 1.1 christos perror("fcntl"); 233 1.1 christos return (-1); 234 1.1 christos } 235 1.1 christos #endif 236 1.1 christos 237 1.1 christos code = irs_irp_read_response(pvt, text, sizeof text); 238 1.1 christos if (code != IRPD_WELCOME_CODE) { 239 1.1 christos if (irp_log_errors) { 240 1.1 christos syslog(LOG_WARNING, "Connection failed: %s", text); 241 1.1 christos } 242 1.1 christos irs_irp_disconnect(pvt); 243 1.1 christos return (-1); 244 1.1 christos } 245 1.1 christos 246 1.1 christos return (0); 247 1.1 christos } 248 1.1 christos 249 1.1 christos /*% 250 1.1 christos * int irs_irp_is_connected(struct irp_p *pvt); 251 1.1 christos * 252 1.1 christos * Returns: 253 1.1 christos * 254 1.1 christos * Non-zero if streams are setup to remote. 255 1.1 christos * 256 1.1 christos */ 257 1.1 christos 258 1.1 christos int 259 1.1 christos irs_irp_is_connected(struct irp_p *pvt) { 260 1.1 christos return (pvt->fdCxn >= 0); 261 1.1 christos } 262 1.1 christos 263 1.1 christos /*% 264 1.1 christos * void 265 1.1 christos * irs_irp_disconnect(struct irp_p *pvt); 266 1.1 christos * 267 1.1 christos * Closes streams to remote. 268 1.1 christos */ 269 1.1 christos 270 1.1 christos void 271 1.1 christos irs_irp_disconnect(struct irp_p *pvt) { 272 1.1 christos if (pvt->fdCxn != -1) { 273 1.1 christos close(pvt->fdCxn); 274 1.1 christos pvt->fdCxn = -1; 275 1.1 christos } 276 1.1 christos } 277 1.1 christos 278 1.1 christos 279 1.1 christos 280 1.1 christos int 281 1.1 christos irs_irp_read_line(struct irp_p *pvt, char *buffer, int len) { 282 1.1 christos char *realstart = &pvt->inbuffer[0]; 283 1.1 christos char *p, *start, *end; 284 1.1 christos int spare; 285 1.1 christos int i; 286 1.1 christos int buffpos = 0; 287 1.1 christos int left = len - 1; 288 1.1 christos 289 1.1 christos while (left > 0) { 290 1.1 christos start = p = &pvt->inbuffer[pvt->incurr]; 291 1.1 christos end = &pvt->inbuffer[pvt->inlast]; 292 1.1 christos 293 1.1 christos while (p != end && *p != '\n') 294 1.1 christos p++; 295 1.1 christos 296 1.1 christos if (p == end) { 297 1.1 christos /* Found no newline so shift data down if necessary 298 1.1 christos * and append new data to buffer 299 1.1 christos */ 300 1.1 christos if (start > realstart) { 301 1.1 christos memmove(realstart, start, end - start); 302 1.1 christos pvt->inlast = end - start; 303 1.1 christos start = realstart; 304 1.1 christos pvt->incurr = 0; 305 1.1 christos end = &pvt->inbuffer[pvt->inlast]; 306 1.1 christos } 307 1.1 christos 308 1.1 christos spare = sizeof (pvt->inbuffer) - pvt->inlast; 309 1.1 christos 310 1.1 christos p = end; 311 1.1 christos i = read(pvt->fdCxn, end, spare); 312 1.1 christos if (i < 0) { 313 1.1 christos close(pvt->fdCxn); 314 1.1 christos pvt->fdCxn = -1; 315 1.1 christos return (buffpos > 0 ? buffpos : -1); 316 1.1 christos } else if (i == 0) { 317 1.1 christos return (buffpos); 318 1.1 christos } 319 1.1 christos 320 1.1 christos end += i; 321 1.1 christos pvt->inlast += i; 322 1.1 christos 323 1.1 christos while (p != end && *p != '\n') 324 1.1 christos p++; 325 1.1 christos } 326 1.1 christos 327 1.1 christos if (p == end) { 328 1.1 christos /* full buffer and still no newline */ 329 1.1 christos i = sizeof pvt->inbuffer; 330 1.1 christos } else { 331 1.1 christos /* include newline */ 332 1.1 christos i = p - start + 1; 333 1.1 christos } 334 1.1 christos 335 1.1 christos if (i > left) 336 1.1 christos i = left; 337 1.1 christos memcpy(buffer + buffpos, start, i); 338 1.1 christos pvt->incurr += i; 339 1.1 christos buffpos += i; 340 1.1 christos buffer[buffpos] = '\0'; 341 1.1 christos 342 1.1 christos if (p != end) { 343 1.1 christos left = 0; 344 1.1 christos } else { 345 1.1 christos left -= i; 346 1.1 christos } 347 1.1 christos } 348 1.1 christos 349 1.1 christos #if 0 350 1.1 christos fprintf(stderr, "read line: %s\n", buffer); 351 1.1 christos #endif 352 1.1 christos return (buffpos); 353 1.1 christos } 354 1.1 christos 355 1.1 christos /*% 356 1.1 christos * int irp_read_response(struct irp_p *pvt); 357 1.1 christos * 358 1.1 christos * Returns: 359 1.1 christos * 360 1.1 christos * The number found at the beginning of the line read from 361 1.1 christos * FP. 0 on failure(0 is not a legal response code). The 362 1.1 christos * rest of the line is discarded. 363 1.1 christos * 364 1.1 christos */ 365 1.1 christos 366 1.1 christos int 367 1.1 christos irs_irp_read_response(struct irp_p *pvt, char *text, size_t textlen) { 368 1.1 christos char line[1024]; 369 1.1 christos int code; 370 1.1 christos char *p; 371 1.1 christos 372 1.1 christos if (irs_irp_read_line(pvt, line, sizeof line) <= 0) { 373 1.1 christos return (0); 374 1.1 christos } 375 1.1 christos 376 1.1 christos p = strchr(line, '\n'); 377 1.1 christos if (p == NULL) { 378 1.1 christos return (0); 379 1.1 christos } 380 1.1 christos 381 1.1 christos if (sscanf(line, "%d", &code) != 1) { 382 1.1 christos code = 0; 383 1.1 christos } else if (text != NULL && textlen > 0U) { 384 1.1 christos p = line; 385 1.1 christos while (isspace((unsigned char)*p)) p++; 386 1.1 christos while (isdigit((unsigned char)*p)) p++; 387 1.1 christos while (isspace((unsigned char)*p)) p++; 388 1.1 christos strncpy(text, p, textlen - 1); 389 1.1 christos p[textlen - 1] = '\0'; 390 1.1 christos } 391 1.1 christos 392 1.1 christos return (code); 393 1.1 christos } 394 1.1 christos 395 1.1 christos /*% 396 1.1 christos * char *irp_read_body(struct irp_p *pvt, size_t *size); 397 1.1 christos * 398 1.1 christos * Read in the body of a response. Terminated by a line with 399 1.1 christos * just a dot on it. Lines should be terminated with a CR-LF 400 1.1 christos * sequence, but we're nt piccky if the CR is missing. 401 1.1 christos * No leading dot escaping is done as the protcol doesn't 402 1.1 christos * use leading dots anywhere. 403 1.1 christos * 404 1.1 christos * Returns: 405 1.1 christos * 406 1.1 christos * Pointer to null-terminated buffer allocated by memget. 407 1.1 christos * *SIZE is set to the length of the buffer. 408 1.1 christos * 409 1.1 christos */ 410 1.1 christos 411 1.1 christos char * 412 1.1 christos irs_irp_read_body(struct irp_p *pvt, size_t *size) { 413 1.1 christos char line[1024]; 414 1.1 christos u_int linelen; 415 1.1 christos size_t len = LINEINCR; 416 1.1 christos char *buffer = memget(len); 417 1.1 christos int idx = 0; 418 1.1 christos 419 1.1 christos if (buffer == NULL) 420 1.1 christos return (NULL); 421 1.1 christos 422 1.1 christos for (;;) { 423 1.1 christos if (irs_irp_read_line(pvt, line, sizeof line) <= 0 || 424 1.1 christos strchr(line, '\n') == NULL) 425 1.1 christos goto death; 426 1.1 christos 427 1.1 christos linelen = strlen(line); 428 1.1 christos 429 1.1 christos if (line[linelen - 1] != '\n') 430 1.1 christos goto death; 431 1.1 christos 432 1.1 christos /* We're not strict about missing \r. Should we be?? */ 433 1.1 christos if (linelen > 2 && line[linelen - 2] == '\r') { 434 1.1 christos line[linelen - 2] = '\n'; 435 1.1 christos line[linelen - 1] = '\0'; 436 1.1 christos linelen--; 437 1.1 christos } 438 1.1 christos 439 1.1 christos if (linelen == 2 && line[0] == '.') { 440 1.1 christos *size = len; 441 1.1 christos buffer[idx] = '\0'; 442 1.1 christos 443 1.1 christos return (buffer); 444 1.1 christos } 445 1.1 christos 446 1.1 christos if (linelen > (len - (idx + 1))) { 447 1.1 christos char *p = memget(len + LINEINCR); 448 1.1 christos 449 1.1 christos if (p == NULL) 450 1.1 christos goto death; 451 1.1 christos memcpy(p, buffer, len); 452 1.1 christos memput(buffer, len); 453 1.1 christos buffer = p; 454 1.1 christos len += LINEINCR; 455 1.1 christos } 456 1.1 christos 457 1.1 christos memcpy(buffer + idx, line, linelen); 458 1.1 christos idx += linelen; 459 1.1 christos } 460 1.1 christos death: 461 1.1 christos memput(buffer, len); 462 1.1 christos return (NULL); 463 1.1 christos } 464 1.1 christos 465 1.1 christos /*% 466 1.1 christos * int irs_irp_get_full_response(struct irp_p *pvt, int *code, 467 1.1 christos * char **body, size_t *bodylen); 468 1.1 christos * 469 1.1 christos * Gets the response to a command. If the response indicates 470 1.1 christos * there's a body to follow(code % 10 == 1), then the 471 1.1 christos * body buffer is allcoated with memget and stored in 472 1.1 christos * *BODY. The length of the allocated body buffer is stored 473 1.1 christos * in *BODY. The caller must give the body buffer back to 474 1.1 christos * memput when done. The results code is stored in *CODE. 475 1.1 christos * 476 1.1 christos * Returns: 477 1.1 christos * 478 1.1 christos * 0 if a result was read. -1 on some sort of failure. 479 1.1 christos * 480 1.1 christos */ 481 1.1 christos 482 1.1 christos int 483 1.1 christos irs_irp_get_full_response(struct irp_p *pvt, int *code, char *text, 484 1.1 christos size_t textlen, char **body, size_t *bodylen) { 485 1.1 christos int result = irs_irp_read_response(pvt, text, textlen); 486 1.1 christos 487 1.1 christos *body = NULL; 488 1.1 christos 489 1.1 christos if (result == 0) { 490 1.1 christos return (-1); 491 1.1 christos } 492 1.1 christos 493 1.1 christos *code = result; 494 1.1 christos 495 1.1 christos /* Code that matches 2xx is a good result code. 496 1.1 christos * Code that matches xx1 means there's a response body coming. 497 1.1 christos */ 498 1.1 christos if ((result / 100) == 2 && (result % 10) == 1) { 499 1.1 christos *body = irs_irp_read_body(pvt, bodylen); 500 1.1 christos if (*body == NULL) { 501 1.1 christos return (-1); 502 1.1 christos } 503 1.1 christos } 504 1.1 christos 505 1.1 christos return (0); 506 1.1 christos } 507 1.1 christos 508 1.1 christos /*% 509 1.1 christos * int irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...); 510 1.1 christos * 511 1.1 christos * Sends command to remote connected via the PVT 512 1.1 christos * structure. FMT and args after it are fprintf-like 513 1.1 christos * arguments for formatting. 514 1.1 christos * 515 1.1 christos * Returns: 516 1.1 christos * 517 1.1 christos * 0 on success, -1 on failure. 518 1.1 christos */ 519 1.1 christos 520 1.1 christos int 521 1.1 christos irs_irp_send_command(struct irp_p *pvt, const char *fmt, ...) { 522 1.1 christos va_list ap; 523 1.1 christos char buffer[1024]; 524 1.1 christos int pos = 0; 525 1.1 christos int i, todo; 526 1.1 christos 527 1.1 christos 528 1.1 christos if (pvt->fdCxn < 0) { 529 1.1 christos return (-1); 530 1.1 christos } 531 1.1 christos 532 1.1 christos va_start(ap, fmt); 533 1.1 christos (void) vsprintf(buffer, fmt, ap); 534 1.1 christos todo = strlen(buffer); 535 1.1 christos va_end(ap); 536 1.1 christos if (todo > (int)sizeof(buffer) - 3) { 537 1.1 christos syslog(LOG_CRIT, "memory overrun in irs_irp_send_command()"); 538 1.1 christos exit(1); 539 1.1 christos } 540 1.1 christos strcat(buffer, "\r\n"); 541 1.1 christos todo = strlen(buffer); 542 1.1 christos 543 1.1 christos while (todo > 0) { 544 1.1 christos i = write(pvt->fdCxn, buffer + pos, todo); 545 1.1 christos #if 0 546 1.1 christos /* XXX brister */ 547 1.1 christos fprintf(stderr, "Wrote: \""); 548 1.1 christos fwrite(buffer + pos, sizeof (char), todo, stderr); 549 1.1 christos fprintf(stderr, "\"\n"); 550 1.1 christos #endif 551 1.1 christos if (i < 0) { 552 1.1 christos close(pvt->fdCxn); 553 1.1 christos pvt->fdCxn = -1; 554 1.1 christos return (-1); 555 1.1 christos } 556 1.1 christos todo -= i; 557 1.1 christos } 558 1.1 christos 559 1.1 christos return (0); 560 1.1 christos } 561 1.1 christos 562 1.1 christos 563 1.1 christos /* Methods */ 564 1.1 christos 565 1.1 christos /*% 566 1.1 christos * void irp_close(struct irs_acc *this) 567 1.1 christos * 568 1.1 christos */ 569 1.1 christos 570 1.1 christos static void 571 1.1 christos irp_close(struct irs_acc *this) { 572 1.1 christos struct irp_p *irp = (struct irp_p *)this->private; 573 1.1 christos 574 1.1 christos if (irp != NULL) { 575 1.1 christos irs_irp_disconnect(irp); 576 1.1 christos memput(irp, sizeof *irp); 577 1.1 christos } 578 1.1 christos 579 1.1 christos memput(this, sizeof *this); 580 1.1 christos } 581 1.1 christos 582 1.1 christos 583 1.1 christos 584 1.1 christos 585 1.1 christos /*! \file */ 586