static int add_tty(int j, struct ipw_hardware *hardware, struct ipw_network *network, int channel_idx, int secondary_channel_idx, int tty_type) { ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); if (!ttys[j]) return -ENOMEM; ttys[j]->index = j; ttys[j]->hardware = hardware; ttys[j]->channel_idx = channel_idx; ttys[j]->secondary_channel_idx = secondary_channel_idx; ttys[j]->network = network; ttys[j]->tty_type = tty_type; mutex_init(&ttys[j]->ipw_tty_mutex); tty_port_init(&ttys[j]->port); tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); if (secondary_channel_idx != -1) ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); /* check if we provide raw device (if loopback is enabled) */ if (get_tty(j)) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": registering %s device ttyIPWp%d\n", tty_type_name(tty_type), j); return 0; }
uint32_t tty_read(int filehandle, void* buffer, int length) { /* Only support standard in for now. */ KERNEL_ASSERT(filehandle == FILEHANDLE_STDIN); gcd_t *gcd = get_tty(); return gcd->read(gcd, buffer, length); }
static int ipw_open(struct tty_struct *linux_tty, struct file *filp) { int minor = linux_tty->index; struct ipw_tty *tty = get_tty(minor); if (!tty) return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); if (tty->closing) { mutex_unlock(&tty->ipw_tty_mutex); return -ENODEV; } if (atomic_read(&tty->open_count) == 0) tty->tx_bytes_queued = 0; atomic_inc(&tty->open_count); tty->linux_tty = linux_tty; linux_tty->driver_data = tty; linux_tty->low_latency = 1; if (tty->tty_type == TTYTYPE_MODEM) ipwireless_ppp_open(tty->network); mutex_unlock(&tty->ipw_tty_mutex); return 0; }
static int add_tty(dev_node_t *nodesp, int j, struct ipw_hardware *hardware, struct ipw_network *network, int channel_idx, int secondary_channel_idx, int tty_type) { ttys[j] = kzalloc(sizeof(struct ipw_tty), GFP_KERNEL); if (!ttys[j]) return -ENOMEM; ttys[j]->index = j; ttys[j]->hardware = hardware; ttys[j]->channel_idx = channel_idx; ttys[j]->secondary_channel_idx = secondary_channel_idx; ttys[j]->network = network; ttys[j]->tty_type = tty_type; mutex_init(&ttys[j]->ipw_tty_mutex); tty_register_device(ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); if (secondary_channel_idx != -1) ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); if (nodesp != NULL) { sprintf(nodesp->dev_name, "ttyIPWp%d", j); nodesp->major = ipw_tty_driver->major; nodesp->minor = j + ipw_tty_driver->minor_start; } if (get_tty(j + ipw_tty_driver->minor_start) == ttys[j]) report_registering(ttys[j]); return 0; }
uint32_t tty_write(int filehandle, void* buffer, int length) { /* Only support standard out for now. */ KERNEL_ASSERT(filehandle == FILEHANDLE_STDOUT); gcd_t *gcd = get_tty(); return gcd->write(gcd, buffer, length); }
/* * Must be called before ipwireless_network_free(). */ void ipwireless_tty_free(struct ipw_tty *tty) { int j; struct ipw_network *network = ttys[tty->index]->network; for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; j += IPWIRELESS_PCMCIA_MINOR_RANGE) { struct ipw_tty *ttyj = ttys[j]; if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); if (get_tty(j + ipw_tty_driver->minor_start) == ttyj) report_deregistering(ttyj); ttyj->closing = 1; if (ttyj->linux_tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); tty_hangup(ttyj->linux_tty); /* Wait till the tty_hangup has completed */ flush_scheduled_work(); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ mutex_lock(&ttyj->ipw_tty_mutex); } while (atomic_read(&ttyj->open_count)) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); tty_unregister_device(ipw_tty_driver, j); ttys[j] = NULL; mutex_unlock(&ttyj->ipw_tty_mutex); kfree(ttyj); } } }
int fill_entry_struct(struct Entry *entry, const struct Rc *rc, const struct Options *opt) { unsigned int i; assert(entry); assert(rc); assert(opt); /* * Get information about the environment; hostname, current directory, * login name and tty. * * Fixme: Add check so this and the session info thing are run only * once. Only has some effect if creating many UUIDs. */ entry->host = get_hostname(rc); if (!entry->host) { myerror("fill_entry_struct(): Cannot get hostname"); return EXIT_FAILURE; } if (!valid_hostname(entry->host)) { myerror("fill_entry_struct(): Got invalid hostname: \"%s\"", entry->host); return EXIT_FAILURE; } entry->cwd = getpath(); entry->user = get_username(); entry->tty = get_tty(); /* * Store tags and comment in entry. */ for (i = 0; i < MAX_TAGS && opt->tag[i]; i++) if (store_tag(entry, opt->tag[i]) == EXIT_FAILURE) return EXIT_FAILURE; if (opt->comment) { entry->txt = process_comment_option(opt->comment); if (!entry->txt) return EXIT_FAILURE; } /* * Store session information from the environment variable. */ if (get_sess_info(entry) == EXIT_FAILURE) { free(entry->txt); return EXIT_FAILURE; } return EXIT_SUCCESS; }
int tty_read(void* buffer, int length) { gcd_t *gcd; gcd = get_tty(); if (gcd == NULL) { return VFS_ERROR; } return gcd->read(gcd, buffer, length); }
int tty_write_stdout(void* buffer, int length) { gcd_t *gcd; gcd = get_tty(); if (gcd == NULL) { return VFS_ERROR; } return gcd->write(gcd, buffer, length); }
void kernel_shell_start() { printk("Starting LevOS debug shell...\n"); shell_tty = get_tty(0); while (1) { show_prompt(); char *in = grab_input(); parse_input(in); } }
/* SMP racecondition */ void printk_switch_tty(int ctty) { struct tty *tty = get_tty(ctty); tty_set_output(tty, &console_dev); tty_set_input(tty, &keyboard_dev); //tty_set_input(tty, &serial_dev); tty_set_buffered(tty, 0); printk_tty = tty; __printk_emitter = __printk_emit_tty; }
static int check_out(select_table * wait, struct m_inode * inode) { struct tty_struct * tty; if (tty = get_tty(inode)) if (!FULL(tty->write_q)) return 1; else add_wait(&tty->write_q->proc_list, wait); else if (inode->i_pipe) if (!PIPE_FULL(*inode)) return 1; else add_wait(&inode->i_wait, wait); return 0; }
/* * The check_XX functions check out a file. We know it's either * a pipe, a character device or a fifo (fifo's not implemented) */ static int check_in(select_table * wait, struct m_inode * inode) { struct tty_struct * tty; if (tty = get_tty(inode)) if (!EMPTY(tty->secondary)) return 1; else add_wait(&tty->secondary->proc_list, wait); else if (inode->i_pipe) if (!PIPE_EMPTY(*inode)) return 1; else add_wait(&inode->i_wait, wait); return 0; }
static int check_ex(select_table * wait, struct m_inode * inode) { struct tty_struct * tty; if (tty = get_tty(inode)) if (!FULL(tty->write_q)) return 0; else return 0; else if (inode->i_pipe) if (inode->i_count < 2) return 1; else add_wait(&inode->i_wait,wait); return 0; }
PAM_EXTERN int pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, const char **argv) { const char *terminal_line; if (!(_pam_parse(pamh, flags, argc, argv) & LASTLOG_WTMP)) return PAM_SUCCESS; terminal_line = get_tty(pamh); /* Wipe out utmp logout entry */ logwtmp(terminal_line, "", ""); return PAM_SUCCESS; }
int execute_command(Term *term)//, int argc, const char **argv) { char **args; struct passwd *pw; pw = find_user(); if((term->cmd_fd.sys = get_pty(term)) < 0) return -1; if((pid = fork()) < 0) { fprintf(stderr, "Couldn't fork: %m\n"); return -1; } if(!pid) { /* child */ get_tty(term); putenv("TERM=xterm"); chdir(pw->pw_dir); args = calloc(3, sizeof(char*)); args[0] = malloc(strlen(pw->pw_shell) + 1); strcpy(args[0], pw->pw_shell); args[1] = "-i"; args[2] = NULL; execvp(pw->pw_shell, args); /* shouldn't be here */ fprintf(stderr, "Error executing %s: %m\n", pw->pw_shell); exit(1); } /* parent */ close(term->slave.sys); signal(SIGCHLD, sigchld_handler); return 0; }
int tty_write_stderr(void* buffer, int length) { gcd_t *gcd; int res; gcd = get_tty(); if (gcd == NULL) { return VFS_ERROR; } if (tty_set_red(gcd) != VFS_OK) { return VFS_ERROR; } res = gcd->write(gcd, buffer, length); if (tty_reset_red(gcd) != VFS_OK) { return VFS_ERROR; } return res; }
/* * Must be called before ipwireless_network_free(). */ void ipwireless_tty_free(struct ipw_tty *tty) { int j; struct ipw_network *network = ttys[tty->index]->network; for (j = tty->index; j < IPWIRELESS_PCMCIA_MINORS; j += IPWIRELESS_PCMCIA_MINOR_RANGE) { struct ipw_tty *ttyj = ttys[j]; if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); if (get_tty(j)) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": deregistering %s device ttyIPWp%d\n", tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); tty_vhangup(ttyj->port.tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ /* FIXME2: hangup does not mean all processes * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } while (ttyj->port.count) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); tty_unregister_device(ipw_tty_driver, j); tty_port_destroy(&ttyj->port); ttys[j] = NULL; mutex_unlock(&ttyj->ipw_tty_mutex); kfree(ttyj); } } }
static int ipw_open(struct tty_struct *linux_tty, struct file *filp) { struct ipw_tty *tty = get_tty(linux_tty->index); if (!tty) return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); if (tty->port.count == 0) tty->tx_bytes_queued = 0; tty->port.count++; tty->port.tty = linux_tty; linux_tty->driver_data = tty; tty->port.low_latency = 1; if (tty->tty_type == TTYTYPE_MODEM) ipwireless_ppp_open(tty->network); mutex_unlock(&tty->ipw_tty_mutex); return 0; }
/* init_console: * Initialises this subsystem. */ static int init_console(void) { char tmp[256]; /* Find our tty's VT number */ __al_linux_vt = get_tty(STDIN_FILENO); if (__al_linux_vt < 0) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Error finding our VT: %s"), ustrerror(errno)); return 1; } if (__al_linux_vt != 0) { /* Open our current console */ if ((__al_linux_console_fd = open("/dev/tty", O_RDWR)) < 0) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unable to open %s: %s"), uconvert_ascii("/dev/tty", tmp), ustrerror(errno)); return 1; } } else { int tty, console_fd, fd, child; unsigned short mask; char tty_name[16]; struct vt_stat vts; /* Now we need to find a VT we can use. It must be readable and * writable by us, if we're not setuid root. VT_OPENQRY itself * isn't too useful because it'll only ever come up with one * suggestion, with no guarrantee that we actually have access * to it. * * At some stage I think this is a candidate for config * file overriding, but for now we'll stat the first N consoles * to see which ones we can write to (hopefully at least one!), * so that we can use that one to do ioctls. We used to use * /dev/console for that purpose but it looks like it's not * always writable by enough people. * * Having found and opened a writable device, we query the state * of the first sixteen (fifteen really) consoles, and try * opening each unused one in turn. */ if ((console_fd = open ("/dev/console", O_WRONLY)) < 0) { int n; uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii("%s /dev/console: %s", tmp), get_config_text("Unable to open"), ustrerror (errno)); /* Try some ttys instead... */ for (n = 1; n <= 24; n++) { snprintf (tty_name, sizeof(tty_name), "/dev/tty%d", n); tty_name[sizeof(tty_name)-1] = 0; if ((console_fd = open (tty_name, O_WRONLY)) >= 0) break; } if (n > 24) return 1; /* leave the error message about /dev/console */ } /* Get the state of the console -- in particular, the free VT field */ if (ioctl (console_fd, VT_GETSTATE, &vts)) { uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii("VT_GETSTATE: %s", tmp), ustrerror (errno)); close (console_fd); return 1; } __al_linux_prev_vt = vts.v_active; /* We attempt to set our euid to 0; if we were run with euid 0 to * start with, we'll be able to do this now. Otherwise, we'll just * ignore the error returned since it might not be a problem if the * ttys we look at are owned by the user running the program. */ seteuid(0); /* tty0 is not really a console, so start counting at 2. */ fd = -1; for (tty = 1, mask = 2; mask; tty++, mask <<= 1) { if (!(vts.v_state & mask)) { snprintf (tty_name, sizeof(tty_name), "/dev/tty%d", tty); tty_name[sizeof(tty_name)-1] = 0; if ((fd = open (tty_name, O_RDWR)) != -1) { close (fd); break; } } } seteuid (getuid()); if (!mask) { ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("Unable to find a usable VT")); close (console_fd); return 1; } /* OK, now fork into the background, detach from the current console, * and attach to the new one. */ child = fork(); if (child < 0) { /* fork failed */ uszprintf (allegro_error, ALLEGRO_ERROR_SIZE, uconvert_ascii ("fork: %s", tmp), ustrerror (errno)); close (console_fd); return 1; } if (child) { /* We're the parent -- write a note to the user saying where the * app went, then quit */ fprintf (stderr, "Allegro application is running on VT %d\n", tty); exit (0); } /* We're the child. Detach from our controlling terminal, and start * a new session. */ close (console_fd); ioctl (0, TIOCNOTTY, 0); setsid(); /* Open the new one again. It becomes our ctty, because we started a * new session above. */ seteuid(0); fd = open (tty_name, O_RDWR); seteuid(getuid()); if (fd == -1) { ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("Unable to reopen new console")); return 1; } /* Try to switch to it -- should succeed, since it's our ctty */ ioctl (fd, VT_ACTIVATE, tty); __al_linux_vt = tty; __al_linux_console_fd = fd; /* Check we can reliably wait until we have the display */ if (__al_linux_wait_for_display()) { close (fd); ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE, get_config_text ("VT_WAITACTIVE failure")); return 1; } /* dup2 it to stdin, stdout and stderr if necessary */ if (isatty(0)) dup2 (fd, 0); if (isatty(1)) dup2 (fd, 1); if (isatty(2)) dup2 (fd, 2); } /* Get termio settings and make a working copy */ tcgetattr(__al_linux_console_fd, &__al_linux_startup_termio); __al_linux_work_termio = __al_linux_startup_termio; return 0; }
asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg) { struct tty_struct *tp, *rtp; mm_segment_t old_fs; int error = 0; #ifdef DEBUG_IOCTLS printk("[%s:%d] irix_ioctl(%d, ", current->comm, current->pid, fd); #endif switch(cmd) { case 0x00005401: #ifdef DEBUG_IOCTLS printk("TCGETA, %08lx) ", arg); #endif error = sys_ioctl(fd, TCGETA, arg); break; case 0x0000540d: { struct termios kt; struct irix_termios *it = (struct irix_termios *) arg; #ifdef DEBUG_IOCTLS printk("TCGETS, %08lx) ", arg); #endif if(!access_ok(VERIFY_WRITE, it, sizeof(*it))) { error = -EFAULT; break; } old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCGETS, (unsigned long) &kt); set_fs(old_fs); if (error) break; __put_user(kt.c_iflag, &it->c_iflag); __put_user(kt.c_oflag, &it->c_oflag); __put_user(kt.c_cflag, &it->c_cflag); __put_user(kt.c_lflag, &it->c_lflag); for(error = 0; error < NCCS; error++) __put_user(kt.c_cc[error], &it->c_cc[error]); error = 0; break; } case 0x0000540e: { struct termios kt; struct irix_termios *it = (struct irix_termios *) arg; #ifdef DEBUG_IOCTLS printk("TCSETS, %08lx) ", arg); #endif if (!access_ok(VERIFY_READ, it, sizeof(*it))) { error = -EFAULT; break; } old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCGETS, (unsigned long) &kt); set_fs(old_fs); if(error) break; __get_user(kt.c_iflag, &it->c_iflag); __get_user(kt.c_oflag, &it->c_oflag); __get_user(kt.c_cflag, &it->c_cflag); __get_user(kt.c_lflag, &it->c_lflag); for(error = 0; error < NCCS; error++) __get_user(kt.c_cc[error], &it->c_cc[error]); old_fs = get_fs(); set_fs(get_ds()); error = sys_ioctl(fd, TCSETS, (unsigned long) &kt); set_fs(old_fs); break; } case 0x0000540f: #ifdef DEBUG_IOCTLS printk("TCSETSW, %08lx) ", arg); #endif error = sys_ioctl(fd, TCSETSW, arg); break; case 0x00005471: #ifdef DEBUG_IOCTLS printk("TIOCNOTTY, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCNOTTY, arg); break; case 0x00007416: #ifdef DEBUG_IOCTLS printk("TIOCGSID, %08lx) ", arg); #endif tp = get_tty(fd); if(!tp) { error = -EINVAL; break; } rtp = get_real_tty(tp); #ifdef DEBUG_IOCTLS printk("rtp->session=%d ", rtp->session); #endif error = put_user(rtp->session, (unsigned long *) arg); break; case 0x746e: /* TIOCSTART, same effect as hitting ^Q */ #ifdef DEBUG_IOCTLS printk("TIOCSTART, %08lx) ", arg); #endif tp = get_tty(fd); if(!tp) { error = -EINVAL; break; } rtp = get_real_tty(tp); start_tty(rtp); break; case 0x20006968: #ifdef DEBUG_IOCTLS printk("SIOCGETLABEL, %08lx) ", arg); #endif error = -ENOPKG; break; case 0x40047477: #ifdef DEBUG_IOCTLS printk("TIOCGPGRP, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCGPGRP, arg); #ifdef DEBUG_IOCTLS printk("arg=%d ", *(int *)arg); #endif break; case 0x40087468: #ifdef DEBUG_IOCTLS printk("TIOCGWINSZ, %08lx) ", arg); #endif error = sys_ioctl(fd, TIOCGWINSZ, arg); break; case 0x8004667e: #ifdef DEBUG_IOCTLS printk("FIONBIO, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, FIONBIO, arg); break; case 0x80047476: #ifdef DEBUG_IOCTLS printk("TIOCSPGRP, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, TIOCSPGRP, arg); break; case 0x8020690c: #ifdef DEBUG_IOCTLS printk("SIOCSIFADDR, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, SIOCSIFADDR, arg); break; case 0x80206910: #ifdef DEBUG_IOCTLS printk("SIOCSIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, SIOCSIFFLAGS, arg); break; case 0xc0206911: #ifdef DEBUG_IOCTLS printk("SIOCGIFFLAGS, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, SIOCGIFFLAGS, arg); break; case 0xc020691b: #ifdef DEBUG_IOCTLS printk("SIOCGIFMETRIC, %08lx) arg=%d ", arg, *(int *)arg); #endif error = sys_ioctl(fd, SIOCGIFMETRIC, arg); break; default: { #ifdef DEBUG_MISSING_IOCTL char *msg = "Unimplemented IOCTL cmd tell [email protected]\n"; #ifdef DEBUG_IOCTLS printk("UNIMP_IOCTL, %08lx)\n", arg); #endif old_fs = get_fs(); set_fs(get_ds()); sys_write(2, msg, strlen(msg)); set_fs(old_fs); printk("[%s:%d] Does unimplemented IRIX ioctl cmd %08lx\n", current->comm, current->pid, cmd); do_exit(255); #else error = sys_ioctl (fd, cmd, arg); #endif } }; #ifdef DEBUG_IOCTLS printk("error=%d\n", error); #endif return error; }
static int last_login_write(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, const char *user) { struct flock last_lock; struct lastlog last_login; time_t ll_time; const void *void_remote_host = NULL; const char *remote_host; const char *terminal_line; int retval = PAM_SUCCESS; /* rewind */ if (lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET) < 0) { pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG); return PAM_SERVICE_ERR; } /* set this login date */ D(("set the most recent login time")); (void) time(&ll_time); /* set the time */ last_login.ll_time = ll_time; /* set the remote host */ if (pam_get_item(pamh, PAM_RHOST, &void_remote_host) != PAM_SUCCESS || void_remote_host == NULL) { remote_host = DEFAULT_HOST; } else { remote_host = void_remote_host; } /* copy to last_login */ last_login.ll_host[0] = '\0'; strncat(last_login.ll_host, remote_host, sizeof(last_login.ll_host)-1); /* set the terminal line */ terminal_line = get_tty(pamh); /* copy to last_login */ last_login.ll_line[0] = '\0'; strncat(last_login.ll_line, terminal_line, sizeof(last_login.ll_line)-1); terminal_line = NULL; D(("locking lastlog file")); /* now we try to lock this file-record exclusively; non-blocking */ memset(&last_lock, 0, sizeof(last_lock)); last_lock.l_type = F_WRLCK; last_lock.l_whence = SEEK_SET; last_lock.l_start = sizeof(last_login) * (off_t) uid; last_lock.l_len = sizeof(last_login); if (fcntl(last_fd, F_SETLK, &last_lock) < 0) { D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); pam_syslog(pamh, LOG_WARNING, "file %s is locked/write", _PATH_LASTLOG); sleep(LASTLOG_IGNORE_LOCK_TIME); } D(("writing to the lastlog file")); if (pam_modutil_write (last_fd, (char *) &last_login, sizeof (last_login)) != sizeof(last_login)) { pam_syslog(pamh, LOG_ERR, "failed to write %s: %m", _PATH_LASTLOG); retval = PAM_SERVICE_ERR; } last_lock.l_type = F_UNLCK; (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */ D(("unlocked")); if (announce & LASTLOG_WTMP) { /* write wtmp entry for user */ logwtmp(last_login.ll_line, user, remote_host); } /* cleanup */ memset(&last_login, 0, sizeof(last_login)); return retval; }