| File: | src/usr.sbin/iscsid/iscsid.c |
| Warning: | line 100, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: iscsid.c,v 1.22 2021/04/16 14:37:06 claudio Exp $ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 2009 Claudio Jeker <claudio@openbsd.org> |
| 5 | * |
| 6 | * Permission to use, copy, modify, and distribute this software for any |
| 7 | * purpose with or without fee is hereby granted, provided that the above |
| 8 | * copyright notice and this permission notice appear in all copies. |
| 9 | * |
| 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 17 | */ |
| 18 | |
| 19 | #include <sys/queue.h> |
| 20 | #include <sys/socket.h> |
| 21 | #include <sys/sysctl.h> |
| 22 | #include <sys/time.h> |
| 23 | #include <sys/uio.h> |
| 24 | |
| 25 | #include <err.h> |
| 26 | #include <event.h> |
| 27 | #include <pwd.h> |
| 28 | #include <signal.h> |
| 29 | #include <stdio.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <string.h> |
| 32 | #include <unistd.h> |
| 33 | |
| 34 | #include "iscsid.h" |
| 35 | #include "log.h" |
| 36 | |
| 37 | void main_sig_handler(int, short, void *); |
| 38 | __dead__attribute__((__noreturn__)) void usage(void); |
| 39 | void shutdown_cb(int, short, void *); |
| 40 | |
| 41 | extern struct initiator *initiator; |
| 42 | struct event exit_ev; |
| 43 | int exit_rounds; |
| 44 | #define ISCSI_EXIT_WAIT5 5 |
| 45 | |
| 46 | const struct session_params iscsi_sess_defaults = { |
| 47 | .MaxBurstLength = 262144, |
| 48 | .FirstBurstLength = 65536, |
| 49 | .DefaultTime2Wait = 2, |
| 50 | .DefaultTime2Retain = 20, |
| 51 | .MaxOutstandingR2T = 1, |
| 52 | .MaxConnections = 1, |
| 53 | .InitialR2T = 1, |
| 54 | .ImmediateData = 1, |
| 55 | .DataPDUInOrder = 1, |
| 56 | .DataSequenceInOrder = 1, |
| 57 | .ErrorRecoveryLevel = 0 |
| 58 | }; |
| 59 | |
| 60 | const struct connection_params iscsi_conn_defaults = { |
| 61 | .MaxRecvDataSegmentLength = 8192 |
| 62 | }; |
| 63 | |
| 64 | int |
| 65 | main(int argc, char *argv[]) |
| 66 | { |
| 67 | struct event ev_sigint, ev_sigterm, ev_sighup; |
| 68 | struct passwd *pw; |
| 69 | char *ctrlsock = ISCSID_CONTROL"/var/run/iscsid.sock"; |
| 70 | char *vscsidev = ISCSID_DEVICE"/dev/vscsi0"; |
| 71 | int name[] = { CTL_KERN1, KERN_PROC_NOBROADCASTKILL79, 0 }; |
| 72 | int ch, debug = 0, verbose = 0, nobkill = 1; |
| 73 | |
| 74 | log_procname = getprogname(); |
| 75 | |
| 76 | log_init(1); /* log to stderr until daemonized */ |
| 77 | log_verbose(1); |
| 78 | |
| 79 | while ((ch = getopt(argc, argv, "dn:s:v")) != -1) { |
| 80 | switch (ch) { |
| 81 | case 'd': |
| 82 | debug = 1; |
| 83 | break; |
| 84 | case 'n': |
| 85 | vscsidev = optarg; |
| 86 | break; |
| 87 | case 's': |
| 88 | ctrlsock = optarg; |
| 89 | break; |
| 90 | case 'v': |
| 91 | verbose = 1; |
| 92 | break; |
| 93 | default: |
| 94 | usage(); |
| 95 | /* NOTREACHED */ |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | argc -= optind; |
| 100 | argv += optind; |
Value stored to 'argv' is never read | |
| 101 | |
| 102 | if (argc > 0) |
| 103 | usage(); |
| 104 | |
| 105 | /* check for root privileges */ |
| 106 | if (geteuid()) |
| 107 | errx(1, "need root privileges"); |
| 108 | |
| 109 | log_init(debug); |
| 110 | log_verbose(verbose); |
| 111 | |
| 112 | if (control_init(ctrlsock) == -1) |
| 113 | fatalx("control socket setup failed"); |
| 114 | |
| 115 | if (!debug) |
| 116 | daemon(1, 0); |
| 117 | log_info("startup"); |
| 118 | |
| 119 | name[2] = getpid(); |
| 120 | if (sysctl(name, 3, NULL((void *)0), 0, &nobkill, sizeof(nobkill)) != 0) |
| 121 | fatal("sysctl"); |
| 122 | |
| 123 | event_init(); |
| 124 | vscsi_open(vscsidev); |
| 125 | |
| 126 | /* chroot and drop to iscsid user */ |
| 127 | if ((pw = getpwnam(ISCSID_USER"_iscsid")) == NULL((void *)0)) |
| 128 | errx(1, "unknown user %s", ISCSID_USER"_iscsid"); |
| 129 | |
| 130 | if (chroot(pw->pw_dir) == -1) |
| 131 | fatal("chroot"); |
| 132 | if (chdir("/") == -1) |
| 133 | fatal("chdir(\"/\")"); |
| 134 | if (setgroups(1, &pw->pw_gid) || |
| 135 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
| 136 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
| 137 | fatal("can't drop privileges"); |
| 138 | |
| 139 | /* setup signal handler */ |
| 140 | signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL)event_set(&ev_sigint, 2, 0x08|0x10, main_sig_handler, ((void *)0)); |
| 141 | signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL)event_set(&ev_sigterm, 15, 0x08|0x10, main_sig_handler, ( (void *)0)); |
| 142 | signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL)event_set(&ev_sighup, 1, 0x08|0x10, main_sig_handler, ((void *)0)); |
| 143 | signal_add(&ev_sigint, NULL)event_add(&ev_sigint, ((void *)0)); |
| 144 | signal_add(&ev_sigterm, NULL)event_add(&ev_sigterm, ((void *)0)); |
| 145 | signal_add(&ev_sighup, NULL)event_add(&ev_sighup, ((void *)0)); |
| 146 | signal(SIGPIPE13, SIG_IGN(void (*)(int))1); |
| 147 | |
| 148 | control_event_init(); |
| 149 | initiator = initiator_init(); |
| 150 | |
| 151 | event_dispatch(); |
| 152 | |
| 153 | /* do some cleanup on the way out */ |
| 154 | control_cleanup(ctrlsock); |
| 155 | initiator_cleanup(initiator); |
| 156 | log_info("exiting."); |
| 157 | return 0; |
| 158 | } |
| 159 | |
| 160 | void |
| 161 | shutdown_cb(int fd, short event, void *arg) |
| 162 | { |
| 163 | struct timeval tv; |
| 164 | |
| 165 | if (exit_rounds++ >= ISCSI_EXIT_WAIT5 || initiator_isdown(initiator)) |
| 166 | event_loopexit(NULL((void *)0)); |
| 167 | |
| 168 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
| 169 | tv.tv_sec = 1; |
| 170 | |
| 171 | if (evtimer_add(&exit_ev, &tv)event_add(&exit_ev, &tv) == -1) |
| 172 | fatal("shutdown_cb"); |
| 173 | } |
| 174 | |
| 175 | void |
| 176 | main_sig_handler(int sig, short event, void *arg) |
| 177 | { |
| 178 | struct timeval tv; |
| 179 | |
| 180 | /* signal handler rules don't apply, libevent decouples for us */ |
| 181 | switch (sig) { |
| 182 | case SIGTERM15: |
| 183 | case SIGINT2: |
| 184 | case SIGHUP1: |
| 185 | initiator_shutdown(initiator); |
| 186 | evtimer_set(&exit_ev, shutdown_cb, NULL)event_set(&exit_ev, -1, 0, shutdown_cb, ((void *)0)); |
| 187 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; |
| 188 | if (evtimer_add(&exit_ev, &tv)event_add(&exit_ev, &tv) == -1) |
| 189 | fatal("main_sig_handler"); |
| 190 | break; |
| 191 | default: |
| 192 | fatalx("unexpected signal"); |
| 193 | /* NOTREACHED */ |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | __dead__attribute__((__noreturn__)) void |
| 198 | usage(void) |
| 199 | { |
| 200 | extern char *__progname; |
| 201 | |
| 202 | fprintf(stderr(&__sF[2]), "usage: %s [-dv] [-n device] [-s socket]\n", |
| 203 | __progname); |
| 204 | exit(1); |
| 205 | } |
| 206 | |
| 207 | void |
| 208 | iscsid_ctrl_dispatch(void *ch, struct pdu *pdu) |
| 209 | { |
| 210 | struct ctrlmsghdr *cmh; |
| 211 | struct initiator_config *ic; |
| 212 | struct session_config *sc; |
| 213 | struct session *s; |
| 214 | struct session_poll p = { 0 }; |
| 215 | int *valp; |
| 216 | |
| 217 | cmh = pdu_getbuf(pdu, NULL((void *)0), 0); |
| 218 | if (cmh == NULL((void *)0)) |
| 219 | goto done; |
| 220 | |
| 221 | switch (cmh->type) { |
| 222 | case CTRL_INITIATOR_CONFIG4: |
| 223 | if (cmh->len[0] != sizeof(*ic)) { |
| 224 | log_warnx("CTRL_INITIATOR_CONFIG bad size"); |
| 225 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 226 | break; |
| 227 | } |
| 228 | ic = pdu_getbuf(pdu, NULL((void *)0), 1); |
| 229 | memcpy(&initiator->config, ic, sizeof(initiator->config)); |
| 230 | control_compose(ch, CTRL_SUCCESS1, NULL((void *)0), 0); |
| 231 | break; |
| 232 | case CTRL_SESSION_CONFIG5: |
| 233 | if (cmh->len[0] != sizeof(*sc)) { |
| 234 | log_warnx("CTRL_SESSION_CONFIG bad size"); |
| 235 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 236 | break; |
| 237 | } |
| 238 | sc = pdu_getbuf(pdu, NULL((void *)0), 1); |
| 239 | if (cmh->len[1]) |
| 240 | sc->TargetName = pdu_getbuf(pdu, NULL((void *)0), 2); |
| 241 | else if (sc->SessionType != SESSION_TYPE_DISCOVERY1) { |
| 242 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 243 | goto done; |
| 244 | } else |
| 245 | sc->TargetName = NULL((void *)0); |
| 246 | if (cmh->len[2]) |
| 247 | sc->InitiatorName = pdu_getbuf(pdu, NULL((void *)0), 3); |
| 248 | else |
| 249 | sc->InitiatorName = NULL((void *)0); |
| 250 | |
| 251 | s = session_find(initiator, sc->SessionName); |
| 252 | if (s == NULL((void *)0)) { |
| 253 | s = session_new(initiator, sc->SessionType); |
| 254 | if (s == NULL((void *)0)) { |
| 255 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 256 | goto done; |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | session_config(s, sc); |
| 261 | if (s->state == SESS_INIT0x0001) |
| 262 | session_fsm(s, SESS_EV_START, NULL((void *)0), 0); |
| 263 | |
| 264 | control_compose(ch, CTRL_SUCCESS1, NULL((void *)0), 0); |
| 265 | break; |
| 266 | case CTRL_LOG_VERBOSE6: |
| 267 | if (cmh->len[0] != sizeof(int)) { |
| 268 | log_warnx("CTRL_LOG_VERBOSE bad size"); |
| 269 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 270 | break; |
| 271 | } |
| 272 | valp = pdu_getbuf(pdu, NULL((void *)0), 1); |
| 273 | log_verbose(*valp); |
| 274 | control_compose(ch, CTRL_SUCCESS1, NULL((void *)0), 0); |
| 275 | break; |
| 276 | case CTRL_VSCSI_STATS7: |
| 277 | control_compose(ch, CTRL_VSCSI_STATS7, vscsi_stats(), |
| 278 | sizeof(struct vscsi_stats)); |
| 279 | break; |
| 280 | case CTRL_SHOW_SUM8: |
| 281 | control_compose(ch, CTRL_INITIATOR_CONFIG4, &initiator->config, |
| 282 | sizeof(initiator->config)); |
| 283 | |
| 284 | TAILQ_FOREACH(s, &initiator->sessions, entry)for((s) = ((&initiator->sessions)->tqh_first); (s) != ((void *)0); (s) = ((s)->entry.tqe_next)) { |
| 285 | struct ctrldata cdv[3]; |
| 286 | bzero(cdv, sizeof(cdv)); |
| 287 | |
| 288 | cdv[0].buf = &s->config; |
| 289 | cdv[0].len = sizeof(s->config); |
| 290 | |
| 291 | if (s->config.TargetName) { |
| 292 | cdv[1].buf = s->config.TargetName; |
| 293 | cdv[1].len = |
| 294 | strlen(s->config.TargetName) + 1; |
| 295 | } |
| 296 | if (s->config.InitiatorName) { |
| 297 | cdv[2].buf = s->config.InitiatorName; |
| 298 | cdv[2].len = |
| 299 | strlen(s->config.InitiatorName) + 1; |
| 300 | } |
| 301 | |
| 302 | control_build(ch, CTRL_SESSION_CONFIG5, |
| 303 | nitems(cdv)(sizeof((cdv)) / sizeof((cdv)[0])), cdv); |
| 304 | } |
| 305 | |
| 306 | control_compose(ch, CTRL_SUCCESS1, NULL((void *)0), 0); |
| 307 | break; |
| 308 | case CTRL_SESS_POLL9: |
| 309 | TAILQ_FOREACH(s, &initiator->sessions, entry)for((s) = ((&initiator->sessions)->tqh_first); (s) != ((void *)0); (s) = ((s)->entry.tqe_next)) |
| 310 | poll_session(&p, s); |
| 311 | poll_finalize(&p); |
| 312 | control_compose(ch, CTRL_SESS_POLL9, &p, sizeof(p)); |
| 313 | break; |
| 314 | default: |
| 315 | log_warnx("unknown control message type %d", cmh->type); |
| 316 | control_compose(ch, CTRL_FAILURE2, NULL((void *)0), 0); |
| 317 | break; |
| 318 | } |
| 319 | |
| 320 | done: |
| 321 | pdu_free(pdu); |
| 322 | } |
| 323 | |
| 324 | #define MERGE_MIN(r, a, b, v) \ |
| 325 | r->v = (a->v < b->v ? a->v : b->v) |
| 326 | #define MERGE_MAX(r, a, b, v) \ |
| 327 | r->v = (a->v > b->v ? a->v : b->v) |
| 328 | #define MERGE_OR(r, a, b, v) \ |
| 329 | r->v = (a->v || b->v) |
| 330 | #define MERGE_AND(r, a, b, v) \ |
| 331 | r->v = (a->v && b->v) |
| 332 | |
| 333 | void |
| 334 | iscsi_merge_sess_params(struct session_params *res, |
| 335 | struct session_params *mine, struct session_params *his) |
| 336 | { |
| 337 | MERGE_MIN(res, mine, his, MaxBurstLength); |
| 338 | MERGE_MIN(res, mine, his, FirstBurstLength); |
| 339 | MERGE_MAX(res, mine, his, DefaultTime2Wait); |
| 340 | MERGE_MIN(res, mine, his, DefaultTime2Retain); |
| 341 | MERGE_MIN(res, mine, his, MaxOutstandingR2T); |
| 342 | res->TargetPortalGroupTag = his->TargetPortalGroupTag; |
| 343 | MERGE_MIN(res, mine, his, MaxConnections); |
| 344 | MERGE_OR(res, mine, his, InitialR2T); |
| 345 | MERGE_AND(res, mine, his, ImmediateData); |
| 346 | MERGE_OR(res, mine, his, DataPDUInOrder); |
| 347 | MERGE_OR(res, mine, his, DataSequenceInOrder); |
| 348 | MERGE_MIN(res, mine, his, ErrorRecoveryLevel); |
| 349 | |
| 350 | } |
| 351 | |
| 352 | void |
| 353 | iscsi_merge_conn_params(struct connection_params *res, |
| 354 | struct connection_params *mine, struct connection_params *his) |
| 355 | { |
| 356 | res->MaxRecvDataSegmentLength = his->MaxRecvDataSegmentLength; |
| 357 | /* XXX HeaderDigest and DataDigest */ |
| 358 | } |
| 359 | |
| 360 | #undef MERGE_MIN |
| 361 | #undef MERGE_MAX |
| 362 | #undef MERGE_OR |
| 363 | #undef MERGE_AND |