static int on_runlevel(Context *c) { int r = 0, q, previous, runlevel; assert(c); /* We finished changing runlevel, so let's write the * utmp record and send the audit msg */ /* First, get last runlevel */ q = utmp_get_runlevel(&previous, NULL); if (q < 0) { if (q != -ESRCH && q != -ENOENT) { log_error("Failed to get current runlevel: %s", strerror(-q)); return q; } previous = 0; } /* Secondly, get new runlevel */ runlevel = get_current_runlevel(c); if (runlevel < 0) return runlevel; if (previous == runlevel) return 0; #ifdef HAVE_AUDIT if (c->audit_fd >= 0) { _cleanup_free_ char *s = NULL; if (asprintf(&s, "old-level=%c new-level=%c", previous > 0 ? previous : 'N', runlevel > 0 ? runlevel : 'N') < 0) return log_oom(); if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0 && errno != EPERM) { log_error("Failed to send audit message: %m"); r = -errno; } } #endif q = utmp_put_runlevel(runlevel, previous); if (q < 0 && q != -ESRCH && q != -ENOENT) { log_error("Failed to write utmp record: %s", strerror(-q)); r = q; } return r; }
static int on_runlevel(Context *c) { int r = 0, q, previous, runlevel; assert(c); /* We finished changing runlevel, so let's write the * utmp record and send the audit msg */ /* First, get last runlevel */ if ((q = utmp_get_runlevel(&previous, NULL)) < 0) { if (q != -ESRCH && q != -ENOENT) { log_error("Failed to get current runlevel: %s", strerror(-q)); return q; } /* Hmm, we didn't find any runlevel, that means we * have been rebooted */ r = on_reboot(c); previous = 0; } /* Secondly, get new runlevel */ if ((runlevel = get_current_runlevel(c)) < 0) return runlevel; if (previous == runlevel) return 0; #ifdef HAVE_AUDIT if (c->audit_fd >= 0) { char *s = NULL; if (asprintf(&s, "old-level=%c new-level=%c", previous > 0 ? previous : 'N', runlevel > 0 ? runlevel : 'N') < 0) return -ENOMEM; if (audit_log_user_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, NULL, NULL, NULL, 1) < 0) { log_error("Failed to send audit message: %m"); r = -errno; } free(s); } #endif if ((q = utmp_put_runlevel(0, runlevel, previous)) < 0) { log_error("Failed to write utmp record: %s", strerror(-q)); r = q; } return r; }
static int utmp_handler(int fd, void *data, struct lxc_epoll_descr *descr) { struct inotify_event *ie; int size, ret, length; struct lxc_utmp *utmp_data = (struct lxc_utmp *)data; /* * we're monitoring a directory. ie->name is not included in * sizeof(struct inotify_event) if we don't read it all at once, * read gives us EINVAL, so we read and cast to struct ie */ char buffer[MAXPATHLEN]; if (ioctl(fd, FIONREAD, &size) < 0) { SYSERROR("cannot determine the size of this notification"); return -1; } if (read(fd, buffer, size) < 0) { SYSERROR("failed to read notification"); return -1; } ie = (struct inotify_event *)buffer; if (ie->len <= 0) { if (ie->mask & IN_UNMOUNT) { DEBUG("watched directory removed"); goto out; } SYSERROR("inotify event with no name (mask %d)", ie->mask); return -1; } ret = 0; DEBUG("got inotify event %d for %s", ie->mask, ie->name); length = (4 < ie->len) ? 4 : ie->len; /* only care about utmp */ if (strncmp(ie->name, "utmp", length)) return 0; if (ie->mask & (IN_MODIFY | IN_CREATE)) ret = utmp_get_runlevel(utmp_data); if (ret < 0) goto out; /* container halting, from running or starting state */ if (utmp_data->curr_runlevel == '0' && ((utmp_data->container_state == CONTAINER_RUNNING) || (utmp_data->container_state == CONTAINER_STARTING))) { utmp_data->container_state = CONTAINER_HALTING; if (utmp_data->timer_fd == -1) lxc_utmp_add_timer(descr, utmp_shutdown_handler, data); DEBUG("Container halting"); goto out; } /* container rebooting, from running or starting state */ if (utmp_data->curr_runlevel == '6' && ((utmp_data->container_state == CONTAINER_RUNNING) || (utmp_data->container_state == CONTAINER_STARTING))) { utmp_data->container_state = CONTAINER_REBOOTING; if (utmp_data->timer_fd == -1) lxc_utmp_add_timer(descr, utmp_shutdown_handler, data); DEBUG("Container rebooting"); goto out; } /* normal operation, running, from starting state. */ if (utmp_data->curr_runlevel > '0' && utmp_data->curr_runlevel < '6') { utmp_data->container_state = CONTAINER_RUNNING; if (utmp_data->timer_fd > 0) lxc_utmp_del_timer(descr, utmp_data); DEBUG("Container running"); goto out; } out: return 0; }