utmp.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * utmp/wtmp support routines.
  4. *
  5. * Copyright (C) 2010 Denys Vlasenko
  6. *
  7. * Licensed under GPLv2, see file LICENSE in this source tree.
  8. */
  9. #include "libbb.h"
  10. static void touch(const char *filename)
  11. {
  12. if (access(filename, R_OK | W_OK) == -1)
  13. close(open(filename, O_WRONLY | O_CREAT, 0664));
  14. }
  15. void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
  16. {
  17. struct utmpx utent;
  18. char *id;
  19. unsigned width;
  20. memset(&utent, 0, sizeof(utent));
  21. utent.ut_pid = pid;
  22. utent.ut_type = new_type;
  23. tty_name = skip_dev_pfx(tty_name);
  24. safe_strncpy(utent.ut_line, tty_name, sizeof(utent.ut_line));
  25. if (username)
  26. safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
  27. if (hostname)
  28. safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
  29. utent.ut_tv.tv_sec = time(NULL);
  30. /* Invent our own ut_id. ut_id is only 4 chars wide.
  31. * Try to fit something remotely meaningful... */
  32. id = utent.ut_id;
  33. width = sizeof(utent.ut_id);
  34. if (tty_name[0] == 'p') {
  35. /* if "ptyXXX", map to "pXXX" */
  36. /* if "pts/XX", map to "p/XX" */
  37. *id++ = 'p';
  38. width--;
  39. } /* else: usually it's "ttyXXXX", map to "XXXX" */
  40. if (strlen(tty_name) > 3)
  41. tty_name += 3;
  42. strncpy(id, tty_name, width);
  43. touch(_PATH_UTMPX);
  44. //utmpxname(_PATH_UTMPX);
  45. setutxent();
  46. /* Append new one (hopefully, unless we collide on ut_id) */
  47. pututxline(&utent);
  48. endutxent();
  49. #if ENABLE_FEATURE_WTMP
  50. /* "man utmp" says wtmp file should *not* be created automagically */
  51. /*touch(bb_path_wtmp_file);*/
  52. updwtmpx(bb_path_wtmp_file, &utent);
  53. #endif
  54. }
  55. /*
  56. * Read "man utmp" to make sense out of it.
  57. */
  58. void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname)
  59. {
  60. struct utmpx utent;
  61. struct utmpx *utp;
  62. touch(_PATH_UTMPX);
  63. //utmpxname(_PATH_UTMPX);
  64. setutxent();
  65. /* Did init/getty/telnetd/sshd/... create an entry for us?
  66. * It should be (new_type-1), but we'd also reuse
  67. * any other potentially stale xxx_PROCESS entry */
  68. while ((utp = getutxent()) != NULL) {
  69. if (utp->ut_pid == pid
  70. // && ut->ut_line[0]
  71. && utp->ut_id[0] /* must have nonzero id */
  72. && ( utp->ut_type == INIT_PROCESS
  73. || utp->ut_type == LOGIN_PROCESS
  74. || utp->ut_type == USER_PROCESS
  75. || utp->ut_type == DEAD_PROCESS
  76. )
  77. ) {
  78. if (utp->ut_type >= new_type) {
  79. /* Stale record. Nuke hostname */
  80. memset(utp->ut_host, 0, sizeof(utp->ut_host));
  81. }
  82. /* NB: pututxline (see later) searches for matching utxent
  83. * using getutxid(utent) - we must not change ut_id
  84. * if we want *exactly this* record to be overwritten!
  85. */
  86. break;
  87. }
  88. }
  89. //endutxent(); - no need, pututxline can deal with (and actually likes)
  90. //the situation when utmp file is positioned on found record
  91. if (!utp) {
  92. if (new_type != DEAD_PROCESS)
  93. write_new_utmp(pid, new_type, tty_name, username, hostname);
  94. else
  95. endutxent();
  96. return;
  97. }
  98. /* Make a copy. We can't use *utp, pututxline's internal getutxid
  99. * will overwrite it before it is used! */
  100. utent = *utp;
  101. utent.ut_type = new_type;
  102. if (tty_name)
  103. safe_strncpy(utent.ut_line, skip_dev_pfx(tty_name), sizeof(utent.ut_line));
  104. if (username)
  105. safe_strncpy(utent.ut_user, username, sizeof(utent.ut_user));
  106. if (hostname)
  107. safe_strncpy(utent.ut_host, hostname, sizeof(utent.ut_host));
  108. utent.ut_tv.tv_sec = time(NULL);
  109. /* Update, or append new one */
  110. //setutxent();
  111. pututxline(&utent);
  112. endutxent();
  113. #if ENABLE_FEATURE_WTMP
  114. /* "man utmp" says wtmp file should *not* be created automagically */
  115. /*touch(bb_path_wtmp_file);*/
  116. updwtmpx(bb_path_wtmp_file, &utent);
  117. #endif
  118. }
  119. /* man utmp:
  120. * When init(8) finds that a process has exited, it locates its utmp entry
  121. * by ut_pid, sets ut_type to DEAD_PROCESS, and clears ut_user, ut_host
  122. * and ut_time with null bytes.
  123. * [same applies to other processes which maintain utmp entries, like telnetd]
  124. *
  125. * We do not bother actually clearing fields:
  126. * it might be interesting to know who was logged in and from where
  127. */
  128. void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid)
  129. {
  130. update_utmp(pid, DEAD_PROCESS, NULL, NULL, NULL);
  131. }