static void makeutmp(int runlevel) { D_("Making utmp file for runlevel %d\n", runlevel); struct utmp utmp; time_t t; /* * this is created by bootmisc, if this isn't there we can't set * runlevel. */ if (access(UTMP_FILE, F_OK) < 0) { F_("/var/run/utmp does not exist, this should be created by " "bootmisc.i\n"); return; } /* TODO, is this a good idea or a bad idea? utmpname("/var/run/utmp"); */ setutent(); memset(&utmp, 0, sizeof(utmp)); utmp.ut_type = RUN_LVL; utmp.ut_pid = ('#' << 8) + runlevel + '0'; time(&t); utmp.ut_time = (int)t; if (!pututline(&utmp)) { F_("pututline failed\n"); endutent(); return; } endutent(); return; }
int runlevel_main(int argc UNUSED_PARAM, char **argv) { struct utmp *ut; char prev; if (argv[1]) utmpname(argv[1]); setutent(); while ((ut = getutent()) != NULL) { if (ut->ut_type == RUN_LVL) { prev = ut->ut_pid / 256; if (prev == 0) prev = 'N'; printf("%c %c\n", prev, ut->ut_pid % 256); if (ENABLE_FEATURE_CLEAN_UP) endutent(); return 0; } } puts("unknown"); if (ENABLE_FEATURE_CLEAN_UP) endutent(); return 1; }
static pid_t spawn_process(uint8_t * p, uint8_t wait) { static const char *args[MAX_ARGS + 3]; uint8_t *dp = p + 5; uint8_t *ep = p + *p - 1; /* -1 as there is a final \0 */ pid_t pid; int an = 3; args[0] = "/bin/sh"; args[1] = "-c"; args[2] = dp; /* Set pointers to each string */ while (dp < ep) { if (*dp++ == 0 && an < MAX_ARGS) args[an++] = dp; } args[an] = NULL; /* Check for internal processes */ if (strcmp(args[2], "getty") == 0) pid = getty(args[3], p + 1); else { /* External */ pid = fork(); if (pid == -1) { perror("fork"); return 0; } if (pid == 0) { /* Child */ ut.ut_type = INIT_PROCESS; ut.ut_pid = getpid(); ut.ut_id[0] = p[1]; ut.ut_id[1] = p[2]; pututline(&ut); /* Don't leak utmp into the child */ endutent(); /* Run the child */ execv(args[2], (char**) (args + 2)); /* If it didn't look binary run it via the shell */ if (errno == ENOEXEC) execv("/bin/sh", (char**) args); /* Oh bugger */ perror(args[2]); exit(1); } } /* We need to force utmp closed otherwise we may end up fd sharing with our child and having our lseek() calls messed up. Or maybe it's time to support pread/pwrite ? */ endutent(); /* Let it complete if that is the instruction */ if (wait) { while (waitpid(pid, NULL, 0) != pid); return 0; } else return pid; }
/* * Return currently connected users as a list of tuples. */ static PyObject* get_system_users(PyObject* self, PyObject* args) { PyObject *ret_list = PyList_New(0); PyObject *tuple = NULL; PyObject *user_proc = NULL; struct utmp *ut; setutent(); while (NULL != (ut = getutent())) { if (ut->ut_type == USER_PROCESS) user_proc = Py_True; else user_proc = Py_False; tuple = Py_BuildValue("(sssfO)", ut->ut_user, // username ut->ut_line, // tty ut->ut_host, // hostname (float)ut->ut_tv.tv_sec, // tstamp user_proc // (bool) user process ); PyList_Append(ret_list, tuple); Py_DECREF(tuple); } endutent(); return ret_list; }
static int getUptime(void) { struct sysinfo s_info; error = sysinfo(&s_info); int days, hours, minutes; long int upmind, upminh, uptimes; uptimes = s_info.uptime; /* returned in seconds */ days = uptimes / ONEDAY; upmind = uptimes - (days * ONEDAY); hours = upmind / ONEHOUR; upminh = upmind - hours * ONEHOUR; minutes = upminh / ONEMINUTE; float av1, av2, av3; av1 = s_info.loads[0] / LOADS_SCALE; av2 = s_info.loads[1] / LOADS_SCALE; av3 = s_info.loads[2] / LOADS_SCALE; /* This next block is stolen fron GNU uptime */ struct utmp *utmpstruct; int numuser = 0; setutent(); while ((utmpstruct = getutent())) { if ((utmpstruct->ut_type == USER_PROCESS) && (utmpstruct->ut_name[0] != '\0')) numuser++; } endutent(); printf(" up %i day%s, %02i:%02i, %i user%s, load average: %2.2f, %2.2f, %2.2f\n", days, (days != 1) ? "s" : "", hours, minutes, numuser, (numuser != 1) ? "s" : "", av1, av2, av3); return error; }
/* count the number of users */ static int get_unique ( void ) { apr_pool_t *subpool; apr_hash_t *hashuser; char *name; void *user; unsigned int numunique = 0; struct utmp *utmpstruct; apr_pool_create(&subpool, pool); hashuser = apr_hash_make(subpool); apr_thread_mutex_lock(mutex); setutent(); while ((utmpstruct = getutent())) { if ((utmpstruct->ut_type == USER_PROCESS) && (utmpstruct->ut_name[0] != '\0')) { name = apr_pstrndup(subpool, utmpstruct->ut_name, UT_NAMESIZE); user = name; /* use key for value, not interested in it anyway */ apr_hash_set(hashuser, name, APR_HASH_KEY_STRING, user); } } endutent(); apr_thread_mutex_unlock(mutex); numunique = apr_hash_count(hashuser); apr_pool_destroy(subpool); return numunique; }
static int count_users(void) { int total = 0; #if HAVE_UTMPX_H #define setutent setutxent #define pututline pututxline #define getutent getutxent #define endutent endutxent struct utmpx *utmp_p; #else struct utmp *utmp_p; #endif setutent(); while ((utmp_p = getutent()) != NULL) { #ifndef UTMP_HAS_NO_TYPE if (utmp_p->ut_type != USER_PROCESS) continue; #endif #ifndef UTMP_HAS_NO_PID /* This block of code fixes zombie user PIDs in the utmp/utmpx file that would otherwise be counted as a current user */ if (kill(utmp_p->ut_pid, 0) == -1 && errno == ESRCH) { utmp_p->ut_type = DEAD_PROCESS; pututline(utmp_p); continue; } #endif ++total; } endutent(); return total; }
static int simulate_logout (const char *line) { int n; for (n = 0; n < num_entries; n++) { if (strcmp (line, entry[n].ut_line) == 0) { entry[n].ut_type = DEAD_PROCESS; strncpy (entry[n].ut_user, "", sizeof (entry[n].ut_user)); #if _HAVE_UT_TV - 0 || defined UTMPX entry[n].ut_tv.tv_sec = (entry_time += 1000); #else entry[n].ut_time = (entry_time += 1000); #endif setutent (); if (pututline (&entry[n]) == NULL) { perror("cannot write UTMP entry"); ++errors; return 1; } endutent (); return 0; } } printf ("no entry found for `%s'", line); ++errors; return 1; }
/* * Notify all available ttys about device insertion. * * Return the number of ttys notified. */ static int notify_all_ttys(const char *manufacturer, const char *product, const char *devnode) { struct utmp *ut = NULL; int ttys_notified = 0; setutent(); /* Don't free ut, it is statically allocated. */ while ((ut = getutent()) != NULL) { /* Skip invalid entries. */ if (ut->ut_type != USER_PROCESS) continue; if (notify_tty(ut->ut_line, manufacturer, product, devnode) == -1) { log_fn("Could not notify %s (@%s) about device %s (%s %s).", ut->ut_user, ut->ut_line, devnode, manufacturer, product); } else { log_fn("Notified %s (@%s) about device %s (%s %s).", ut->ut_user, ut->ut_line, devnode, manufacturer, product); ttys_notified++; } } endutent(); return ttys_notified; }
static int check_login_time(const char *ruser, time_t timestamp) { struct utmp utbuf, *ut; time_t oldest_login = 0; setutent(); while( #ifdef HAVE_GETUTENT_R !getutent_r(&utbuf, &ut) #else (ut = getutent()) != NULL #endif ) { if (ut->ut_type != USER_PROCESS) { continue; } if (strncmp(ruser, ut->ut_user, sizeof(ut->ut_user) != 0)) { continue; } if (oldest_login == 0 || oldest_login > ut->ut_tv.tv_sec) { oldest_login = ut->ut_tv.tv_sec; } } endutent(); if(oldest_login == 0 || timestamp < oldest_login) { return PAM_AUTH_ERR; } return PAM_SUCCESS; }
static void cleanup_utmp(void) { #ifndef OMIT_UTMP FILE *wtmp; time_t uttime; if (!pty_stamped_utmp) return; utmp_entry.ut_type = DEAD_PROCESS; memset(utmp_entry.ut_user, 0, lenof(utmp_entry.ut_user)); time(&uttime); utmp_entry.ut_time = uttime; if ((wtmp = fopen(WTMP_FILE, "a")) != NULL) { fwrite(&utmp_entry, 1, sizeof(utmp_entry), wtmp); fclose(wtmp); } memset(utmp_entry.ut_line, 0, lenof(utmp_entry.ut_line)); utmp_entry.ut_time = 0; #if defined HAVE_PUTUTLINE utmpname(UTMP_FILE); setutent(); pututline(&utmp_entry); endutent(); #endif pty_stamped_utmp = 0; /* ensure we never double-cleanup */ #endif }
int who_main(int argc, char **argv) { char str6[6]; struct utmp *ut; struct stat st; char *name; if (argc > 1) { bb_show_usage(); } setutent(); printf("USER TTY IDLE TIME HOST\n"); while ((ut = getutent()) != NULL) { if (ut->ut_user[0] && ut->ut_type == USER_PROCESS) { time_t thyme = ut->ut_tv.tv_sec; /* ut->ut_line is device name of tty - "/dev/" */ name = concat_path_file("/dev", ut->ut_line); str6[0] = '?'; str6[1] = '\0'; if (stat(name, &st) == 0) idle_string(str6, st.st_atime); printf("%-10s %-8s %-9s %-14.14s %s\n", ut->ut_user, ut->ut_line, str6, ctime(&thyme) + 4, ut->ut_host); if (ENABLE_FEATURE_CLEAN_UP) free(name); } } if (ENABLE_FEATURE_CLEAN_UP) endutent(); return 0; }
static int do_check (void) { struct utmp *ut; int n; setutent (); n = 0; while ((ut = getutent ())) { if (n < num_entries && memcmp (ut, &entry[n], sizeof (struct utmp))) { printf ("UTMP entry does not match"); ++errors; return 1; } n++; } if (n != num_entries) { printf ("number of UTMP entries is incorrect"); ++errors; return 1; } endutent (); return 0; }
int uv_uptime(double* uptime) { struct utmp *utmp_buf; size_t entries = 0; time_t boot_time; boot_time = 0; utmpname(UTMP_FILE); setutent(); while ((utmp_buf = getutent()) != NULL) { if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS) ++entries; if (utmp_buf->ut_type == BOOT_TIME) boot_time = utmp_buf->ut_time; } endutent(); if (boot_time == 0) return UV_ENOSYS; *uptime = time(NULL) - boot_time; return 0; }
/* * get_current_utmp - return the most probable utmp entry for the current * session * * The utmp file is scanned for an entry with the same process ID. * The line enterred by the *getty / telnetd, etc. should also match * the current terminal. * * When an entry is returned by get_current_utmp, and if the utmp * structure has a ut_id field, this field should be used to update * the entry information. * * Return NULL if no entries exist in utmp for the current process. */ /*@null@*/ /*@only@*/struct utmp *get_current_utmp (void) { struct utmp *ut; struct utmp *ret = NULL; setutent (); /* First, try to find a valid utmp entry for this process. */ while ((ut = getutent ()) != NULL) { if ( (ut->ut_pid == getpid ()) #ifdef HAVE_STRUCT_UTMP_UT_ID && ('\0' != ut->ut_id[0]) #endif #ifdef HAVE_STRUCT_UTMP_UT_TYPE && ( (LOGIN_PROCESS == ut->ut_type) || (USER_PROCESS == ut->ut_type)) #endif /* A process may have failed to close an entry * Check if this entry refers to the current tty */ && is_my_tty (ut->ut_line)) { break; } } if (NULL != ut) { ret = (struct utmp *) xmalloc (sizeof (*ret)); memcpy (ret, ut, sizeof (*ret)); } endutent (); return ret; }
/* * See if we were started directly from init. * Get the runlevel from /var/run/utmp or the environment. */ int get_runlevel(void) { struct utmp *ut; char *r; /* * First see if we were started directly from init. */ if (getenv("INIT_VERSION") && (r = getenv("RUNLEVEL")) != NULL) return *r; /* * Find runlevel in utmp. */ setutent(); while ((ut = getutent()) != NULL) { if (ut->ut_type == RUN_LVL) return (ut->ut_pid & 255); } endutent(); /* This should not happen but warn the user! */ fprintf(stderr, "WARNING: could not determine runlevel" " - doing soft %s\n", progname); fprintf(stderr, " (it's better to use shutdown instead of %s" " from the command line)\n", progname); return -1; }
static void _add_utmp(TE_Pty* pty, int spid) { memset(&pty->ut_entry, 0, sizeof(pty->ut_entry) ); #if 0 pty->ut_entry.ut_type = USER_PROCESS; pty->ut_entry.ut_pid = spid; // strcpy(pty->ut_entry.ut_line, pty->ptyname+5); // printf("ut name \"%s\" (%d)\n", pty->ut_entry.ut_user, getuid()); #ifdef __APPLE__ // strcpy(pty->ut_entry.ut_id, pty->ptyname+8); strcpy(pty->ut_entry.ut_user, getpwuid(getuid())->pw_name); gettimeofday(&pty->ut_entry.ut_tv, NULL); setutxent(); pututxline(&pty->ut_entry); endutxent(); #else strcpy(pty->ut_entry.ut_host, getenv("DISPLAY")); time_t tt; time(&tt); pty->ut_entry.ut_time = tt; pty->ut_entry.ut_addr = 0; setutent(); pututline(&pty->ut_entry); endutent(); #endif #endif }
void utmp_login(char *tty, const char *username, const char *hostname) { struct utmp utmp; int fd; prepare_utmp (&utmp, tty, username, hostname); #ifdef HAVE_SETUTENT utmpname(_PATH_UTMP); setutent(); pututline(&utmp); endutent(); #else #ifdef HAVE_TTYSLOT { int ttyno; ttyno = ttyslot(); if (ttyno > 0 && (fd = open(_PATH_UTMP, O_WRONLY, 0)) >= 0) { lseek(fd, (long)(ttyno * sizeof(struct utmp)), SEEK_SET); write(fd, &utmp, sizeof(struct utmp)); close(fd); } } #endif /* HAVE_TTYSLOT */ #endif /* HAVE_SETUTENT */ if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) { write(fd, &utmp, sizeof(struct utmp)); close(fd); } }
void utmpname(const char * new_ut_name) { endutent(); if (new_ut_name!=NULL) ut_name=new_ut_name; }
static void endutxent (void) { #ifdef IS_BIONIC /* bionic isn't exporting endutend */ return; #else return endutent(); #endif }
int who_main(int argc UNUSED_PARAM, char **argv) { struct utmp *ut; unsigned opt; int do_users = (ENABLE_USERS && (!ENABLE_WHO || applet_name[0] == 'u')); const char *fmt = "%s"; opt_complementary = "=0"; opt = getopt32(argv, do_users ? "" : "aH"); if (opt & 2) // -H printf("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST\n"); setutent(); while ((ut = getutent()) != NULL) { if (ut->ut_user[0] && ((opt & 1) || ut->ut_type == USER_PROCESS) ) { if (!do_users) { char str6[6]; char name[sizeof("/dev/") + sizeof(ut->ut_line) + 1]; struct stat st; time_t seconds; str6[0] = '?'; str6[1] = '\0'; strcpy(name, "/dev/"); safe_strncpy(ut->ut_line[0] == '/' ? name : name + sizeof("/dev/")-1, ut->ut_line, sizeof(ut->ut_line)+1 ); if (stat(name, &st) == 0) idle_string(str6, st.st_atime); /* manpages say ut_tv.tv_sec *is* time_t, * but some systems have it wrong */ seconds = ut->ut_tv.tv_sec; /* How wide time field can be? * "Nov 10 19:33:20": 15 chars * "2010-11-10 19:33": 16 chars */ printf("%-15.*s %-15.*s %-7s %-16.16s %.*s\n", (int)sizeof(ut->ut_user), ut->ut_user, (int)sizeof(ut->ut_line), ut->ut_line, str6, ctime(&seconds) + 4, (int)sizeof(ut->ut_host), ut->ut_host ); } else { printf(fmt, ut->ut_user); fmt = " %s"; } } } if (do_users) bb_putchar('\n'); if (ENABLE_FEATURE_CLEAN_UP) endutent(); return EXIT_SUCCESS; }
int main(int argc, char **argv) { extern int optind; int ch; struct iovec iov; struct utmp *utmpptr; char *p; char line[sizeof(utmpptr->ut_line) + 1]; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); while ((ch = getopt(argc, argv, "n")) != -1) { switch (ch) { case 'n': if (geteuid() == 0) nobanner = 1; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc > 1) usage(); makemsg(*argv); setutent(); iov.iov_base = mbuf; iov.iov_len = mbufsize; while((utmpptr = getutent())) { if (!utmpptr->ut_name[0] || !strncmp(utmpptr->ut_name, IGNOREUSER, sizeof(utmpptr->ut_name))) continue; #ifdef USER_PROCESS if (utmpptr->ut_type != USER_PROCESS) continue; #endif /* Joey Hess reports that use-sessreg in /etc/X11/wdm/ produces ut_line entries like :0, and a write to /dev/:0 fails. */ if (utmpptr->ut_line[0] == ':') continue; xstrncpy(line, utmpptr->ut_line, sizeof(utmpptr->ut_line)); if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL) warnx("%s", p); } endutent(); exit(EXIT_SUCCESS); }
static int utmp_write_library(struct logininfo *li, struct utmp *ut) { setutent(); pututline(ut); # ifdef HAVE_ENDUTENT endutent(); # endif return (1); }
static void spawn_login(struct passwd *pwd, const char *tty, const char *id) { char *p, buf[50]; /* utmp */ ut.ut_type = USER_PROCESS; ut.ut_pid = getpid(); strncpy(ut.ut_line, tty, UT_LINESIZE); strncpy(ut.ut_id, id, 2); time(&ut.ut_time); strncpy(ut.ut_user, pwd->pw_name, UT_NAMESIZE); pututline(&ut); /* Don't leak utmp into the child */ endutent(); /* We don't care if initgroups fails - it only grants extra rights */ //initgroups(pwd->pw_name, pwd->pw_gid); /* But we do care if these fail! */ if (setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) _exit(255); signal(SIGINT, SIG_DFL); /* setup user environment variables */ envset("LOGNAME", pwd->pw_name); envset("HOME", pwd->pw_dir); envset("SHELL", pwd->pw_shell); /* home directory */ if (chdir(pwd->pw_dir)) putstr("login: unable to change to home directory, using /\n"); /* show the motd file */ if (!showfile("/etc/motd")) crlf(); /* and spawn the shell */ strcpy(buf, "-"); if ((p = strrchr(pwd->pw_shell, '/')) != NULL) strcat(buf, ++p); else strcat(buf, pwd->pw_shell); argp[0] = buf; argp[1] = NULL; execve(pwd->pw_shell, (void *) argp, (void *) env); putstr("login: can't execute shell\n"); exit(1); }
int logout (const char *line) { struct UT tmp; struct UT *ut; int result = 0; /* if (utmpname (_PATH_UTMP) == -1) return 0; - why? * this makes it impossible for caller to use other file! * Does any standard or historical precedent says this must be done? */ /* Open UTMP file. */ setutent (); /* Fill in search information. */ #if _HAVE_UT_TYPE - 0 tmp.ut_type = USER_PROCESS; #endif strncpy (tmp.ut_line, line, sizeof tmp.ut_line); /* Read the record. */ if ((ut = getutline(&tmp)) != NULL) { /* Clear information about who & from where. */ memset (ut->ut_name, 0, sizeof ut->ut_name); #if _HAVE_UT_HOST - 0 memset (ut->ut_host, 0, sizeof ut->ut_host); #endif #if _HAVE_UT_TV - 0 # if !defined __WORDSIZE_TIME64_COMPAT32 gettimeofday (&ut->ut_tv, NULL); # else { struct timeval tv; gettimeofday (&tv, NULL); ut->ut_tv.tv_sec = tv.tv_sec; ut->ut_tv.tv_usec = tv.tv_usec; } # endif #else time (&ut->ut_time); #endif #if _HAVE_UT_TYPE - 0 ut->ut_type = DEAD_PROCESS; #endif if (pututline (ut) != NULL) result = 1; } /* Close UTMP file. */ endutent (); return result; }
void deallocpty(void) { #ifndef NO_ROOT setutent(); myu.ut_type = DEAD_PROCESS; getutid(&myu); pututline(&myu); endutent(); #endif /*NO_ROOT*/ }
char *sprint_uptime(void) { struct utmp *utmpstruct; int upminutes, uphours, updays; int pos; struct tm *realtime; time_t realseconds; int numuser; double uptime_secs, idle_secs; /* first get the current time */ time(&realseconds); realtime = localtime(&realseconds); pos = sprintf(buf, " %02d:%02d:%02d ", realtime->tm_hour, realtime->tm_min, realtime->tm_sec); /* read and calculate the amount of uptime */ uptime(&uptime_secs, &idle_secs); updays = (int) uptime_secs / (60*60*24); strcat (buf, "up "); pos += 3; if (updays) pos += sprintf(buf + pos, "%d day%s, ", updays, (updays != 1) ? "s" : ""); upminutes = (int) uptime_secs / 60; uphours = upminutes / 60; uphours = uphours % 24; upminutes = upminutes % 60; if (uphours) pos += sprintf(buf + pos, "%2d:%02d, ", uphours, upminutes); else pos += sprintf(buf + pos, "%d min, ", upminutes); /* count the number of users */ numuser = 0; setutent(); while ((utmpstruct = getutent())) { if ((utmpstruct->ut_type == USER_PROCESS) && (utmpstruct->ut_name[0] != '\0')) numuser++; } endutent(); pos += sprintf(buf + pos, "%2d user%s, ", numuser, numuser == 1 ? "" : "s"); loadavg(&av[0], &av[1], &av[2]); pos += sprintf(buf + pos, " load average: %.2f, %.2f, %.2f", av[0], av[1], av[2]); return buf; }
static int users_read (void) { #if HAVE_GETUTXENT unsigned int users = 0; struct utmpx *entry = NULL; /* according to the *utent(3) man page none of the functions sets errno in case of an error, so we cannot do any error-checking here */ setutxent(); while (NULL != (entry = getutxent())) { if (USER_PROCESS == entry->ut_type) { ++users; } } endutxent(); users_submit (users); /* #endif HAVE_GETUTXENT */ #elif HAVE_GETUTENT unsigned int users = 0; struct utmp *entry = NULL; /* according to the *utent(3) man page none of the functions sets errno in case of an error, so we cannot do any error-checking here */ setutent(); while (NULL != (entry = getutent())) { if (USER_PROCESS == entry->ut_type) { ++users; } } endutent(); users_submit (users); /* #endif HAVE_GETUTENT */ #elif HAVE_LIBSTATGRAB sg_user_stats *us; us = sg_get_user_stats (); if (us == NULL) return (-1); users_submit ((gauge_t) us->num_entries); /* #endif HAVE_LIBSTATGRAB */ #else # error "No applicable input method." #endif return (0); } /* int users_read */
static int count_users(void) { int ct = 0; struct utmp *entry; setutent(); while(entry = getutent()) if (entry->ut_type == USER_PROCESS) ct++; endutent(); return ct; }
void setutmp (const char *name, const char *line, const char *host) { utent.ut_type = USER_PROCESS; strncpy (utent.ut_user, name, sizeof utent.ut_user); utent.ut_time = time (NULL); /* other fields already filled in by checkutmp above */ setutent (); pututline (&utent); endutent (); updwtmp (_WTMP_FILE, &utent); }