Rearrange the python scripting support a bit.
[screen-lua.git] / src / utmp.c
blob20f3c3c5d899ebdac66ab47a97cb6e86531f8fc2
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
33 #include "config.h"
34 #include "screen.h"
35 #include "extern.h"
37 #ifdef HAVE_UTEMPTER
38 #include <utempter.h>
39 #endif
42 extern struct display *display;
43 #ifdef CAREFULUTMP
44 extern struct win *windows;
45 #endif
46 extern struct win *fore;
47 extern char *LoginName;
48 extern int real_uid, eff_uid;
52 * UTNOKEEP: A (ugly) hack for apollo that does two things:
53 * 1) Always close and reopen the utmp file descriptor. (I don't know
54 * for what reason this is done...)
55 * 2) Implement an unsorted utmp file much like GETUTENT.
56 * (split into UT_CLOSE and UT_UNSORTED)
60 #ifdef UTNOKEEP
61 # define UT_CLOSE
62 # define UT_UNSORTED
63 #endif
65 #ifdef UT_CLOSE
66 # undef UT_CLOSE
67 # define UT_CLOSE endutent()
68 #else
69 # define UT_CLOSE
70 #endif
74 * we have a suid-root helper app that changes the utmp for us
75 * (won't work for login-slots)
77 #if (defined(sun) && defined(SVR4) && defined(GETUTENT)) || defined(HAVE_UTEMPTER)
78 # define UTMP_HELPER
79 #endif
83 #ifdef UTMPOK
86 static slot_t TtyNameSlot __P((char *));
87 static void makeuser __P((struct utmp *, char *, char *, int));
88 static void makedead __P((struct utmp *));
89 static int pututslot __P((slot_t, struct utmp *, char *, struct win *));
90 static struct utmp *getutslot __P((slot_t));
91 #ifndef GETUTENT
92 static struct utmp *getutent __P((void));
93 static void endutent __P((void));
94 static int initutmp __P((void));
95 static void setutent __P((void));
96 #endif
97 #if defined(linux) && defined(GETUTENT)
98 static struct utmp *xpututline __P((struct utmp *utmp));
99 # define pututline xpututline
100 #endif
103 static int utmpok;
104 static char UtmpName[] = UTMPFILE;
105 #ifndef UTMP_HELPER
106 static int utmpfd = -1;
107 #endif
110 # if defined(GETUTENT) && (!defined(SVR4) || defined(__hpux)) && ! defined(__CYGWIN__)
111 # if defined(hpux) /* cruel hpux release 8.0 */
112 # define pututline _pututline
113 # endif /* hpux */
114 extern struct utmp *getutline(), *pututline();
115 # if defined(_SEQUENT_)
116 extern struct utmp *ut_add_user(), *ut_delete_user();
117 extern char *ut_find_host();
118 # ifndef UTHOST
119 # define UTHOST /* _SEQUENT_ has ut_find_host() */
120 # endif
121 # endif /* _SEQUENT_ */
122 # endif /* GETUTENT && !SVR4 */
124 # if !defined(GETUTENT) && !defined(UT_UNSORTED)
125 # ifdef GETTTYENT
126 # include <ttyent.h>
127 # else
128 struct ttyent { char *ty_name; };
129 static void setttyent __P((void));
130 static struct ttyent *getttyent __P((void));
131 # endif
132 # endif /* !GETUTENT && !UT_UNSORTED */
134 #ifndef _SEQUENT_
135 # undef D_loginhost
136 # define D_loginhost D_utmp_logintty.ut_host
137 #endif
138 #ifndef UTHOST
139 # undef D_loginhost
140 # define D_loginhost ((char *)0)
141 #endif
144 #endif /* UTMPOK */
148 * SlotToggle - modify the utmp slot of the fore window.
150 * how > 0 do try to set a utmp slot.
151 * how = 0 try to withdraw a utmp slot.
153 * w_slot = -1 window not logged in.
154 * w_slot = 0 window not logged in, but should be logged in.
155 * (unable to write utmp, or detached).
158 #ifndef UTMPOK
159 void
160 SlotToggle(how)
161 int how;
163 debug1("SlotToggle (!UTMPOK) %d\n", how);
164 # ifdef UTMPFILE
165 Msg(0, "Unable to modify %s.\n", UTMPFILE);
166 # else
167 Msg(0, "Unable to modify utmp-database.\n");
168 # endif
170 #endif
174 #ifdef UTMPOK
176 void
177 SlotToggle(how)
178 int how;
180 debug1("SlotToggle %d\n", how);
181 if (fore->w_type != W_TYPE_PTY)
183 Msg(0, "Can only work with normal windows.\n");
184 return;
186 if (how)
188 debug(" try to log in\n");
189 if ((fore->w_slot == (slot_t) -1) || (fore->w_slot == (slot_t) 0))
191 #ifdef USRLIMIT
192 if (CountUsers() >= USRLIMIT)
194 Msg(0, "User limit reached.");
195 return;
197 #endif
198 if (SetUtmp(fore) == 0)
199 Msg(0, "This window is now logged in.");
200 else
201 Msg(0, "This window should now be logged in.");
202 WindowChanged(fore, 'f');
204 else
205 Msg(0, "This window is already logged in.");
207 else
209 debug(" try to log out\n");
210 if (fore->w_slot == (slot_t) -1)
211 Msg(0, "This window is already logged out\n");
212 else if (fore->w_slot == (slot_t) 0)
214 debug("What a relief! In fact, it was not logged in\n");
215 Msg(0, "This window is not logged in.");
216 fore->w_slot = (slot_t) -1;
218 else
220 RemoveUtmp(fore);
221 if (fore->w_slot != (slot_t) -1)
222 Msg(0, "What? Cannot remove Utmp slot?");
223 else
224 Msg(0, "This window is no longer logged in.");
225 #ifdef CAREFULUTMP
226 CarefulUtmp();
227 #endif
228 WindowChanged(fore, 'f');
234 #ifdef CAREFULUTMP
236 /* CAREFULUTMP: goodie for paranoid sysadmins: always leave one
237 * window logged in
239 void
240 CarefulUtmp()
242 struct win *p;
244 if (!windows) /* hopeless */
245 return;
246 debug("CarefulUtmp counting slots\n");
247 for (p = windows; p; p = p->w_next)
248 if (p->w_ptyfd >= 0 && p->w_slot != (slot_t)-1)
249 return; /* found one, nothing to do */
251 debug("CarefulUtmp: no slots, log one in again.\n");
252 for (p = windows; p; p = p->w_next)
253 if (p->w_ptyfd >= 0) /* no zombies please */
254 break;
255 if (!p)
256 return; /* really hopeless */
257 SetUtmp(p);
258 Msg(0, "Window %d is now logged in.\n", p->w_number);
260 #endif /* CAREFULUTMP */
263 void
264 InitUtmp()
266 debug1("InitUtmp testing '%s'...\n", UtmpName);
267 #ifndef UTMP_HELPER
268 if ((utmpfd = open(UtmpName, O_RDWR)) == -1)
270 if (errno != EACCES)
271 Msg(errno, UtmpName);
272 debug("InitUtmp failed.\n");
273 utmpok = 0;
274 return;
276 # ifdef GETUTENT
277 close(utmpfd); /* it was just a test */
278 utmpfd = -1;
279 # endif /* GETUTENT */
280 #endif /* UTMP_HELPER */
281 utmpok = 1;
285 #ifdef USRLIMIT
287 CountUsers()
289 struct utmp *ut;
290 int UserCount;
292 debug1("CountUsers() - utmpok=%d\n", utmpok);
293 if (!utmpok)
294 return 0;
295 UserCount = 0;
296 setutent();
297 while (ut = getutent())
298 if (SLOT_USED(ut))
299 UserCount++;
300 UT_CLOSE;
301 return UserCount;
303 #endif /* USRLIMIT */
308 * the utmp entry for tty is located and removed.
309 * it is stored in D_utmp_logintty.
311 void
312 RemoveLoginSlot()
314 struct utmp u, *uu;
316 ASSERT(display);
317 debug("RemoveLoginSlot: removing your logintty\n");
318 D_loginslot = TtyNameSlot(D_usertty);
319 if (D_loginslot == (slot_t)0 || D_loginslot == (slot_t)-1)
320 return;
321 #ifdef UTMP_HELPER
322 if (eff_uid) /* helpers can't do login slots. sigh. */
323 #else
324 if (!utmpok)
325 #endif
327 D_loginslot = 0;
328 debug("RemoveLoginSlot: utmpok == 0\n");
330 else
332 #ifdef _SEQUENT_
334 char *p;
335 if ((p = ut_find_host(D_loginslot)) != 0)
336 strncpy(D_loginhost, p, sizeof(D_loginhost) - 1);
337 D_loginhost[sizeof(D_loginhost) - 1] = 0;
339 #endif /* _SEQUENT_ */
341 if ((uu = getutslot(D_loginslot)) == 0)
343 debug("Utmp slot not found -> not removed");
344 D_loginslot = 0;
346 else
348 D_utmp_logintty = *uu;
349 u = *uu;
350 makedead(&u);
351 if (pututslot(D_loginslot, &u, (char *)0, (struct win *)0) == 0)
352 D_loginslot = 0;
354 UT_CLOSE;
356 debug1(" slot %d zapped\n", (int)D_loginslot);
357 if (D_loginslot == (slot_t)0)
359 /* couldn't remove slot, do a 'mesg n' at least. */
360 struct stat stb;
361 char *tty;
362 debug("couln't zap slot -> do mesg n\n");
363 D_loginttymode = 0;
364 if ((tty = ttyname(D_userfd)) && stat(tty, &stb) == 0 && (int)stb.st_uid == real_uid && ((int)stb.st_mode & 0777) != 0666)
366 D_loginttymode = (int)stb.st_mode & 0777;
367 chmod(D_usertty, stb.st_mode & 0600);
373 * D_utmp_logintty is reinserted into utmp
375 void
376 RestoreLoginSlot()
378 char *tty;
380 debug("RestoreLoginSlot()\n");
381 ASSERT(display);
382 if (utmpok && D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1)
384 debug1(" logging you in again (slot %#x)\n", (int)D_loginslot);
385 if (pututslot(D_loginslot, &D_utmp_logintty, D_loginhost, (struct win *)0) == 0)
386 Msg(errno,"Could not write %s", UtmpName);
388 UT_CLOSE;
389 D_loginslot = (slot_t)0;
390 if (D_loginttymode && (tty = ttyname(D_userfd)))
391 chmod(tty, D_loginttymode);
397 * Construct a utmp entry for window wi.
398 * the hostname field reflects what we know about the user (display)
399 * location. If d_loginhost is not set, then he is local and we write
400 * down the name of his terminal line; else he is remote and we keep
401 * the hostname here. The letter S and the window id will be appended.
402 * A saved utmp entry in wi->w_savut serves as a template, usually.
406 SetUtmp(wi)
407 struct win *wi;
409 register slot_t slot;
410 struct utmp u;
411 int saved_ut;
412 #ifdef UTHOST
413 char *p;
414 char host[sizeof(D_loginhost) + 15];
415 #else
416 char *host = 0;
417 #endif /* UTHOST */
419 wi->w_slot = (slot_t)0;
420 if (!utmpok || wi->w_type != W_TYPE_PTY)
421 return -1;
422 if ((slot = TtyNameSlot(wi->w_tty)) == (slot_t)0)
424 debug1("SetUtmp failed (tty %s).\n",wi->w_tty);
425 return -1;
427 debug2("SetUtmp %d will get slot %d...\n", wi->w_number, (int)slot);
429 bzero((char *)&u, sizeof(u));
430 if ((saved_ut = bcmp((char *) &wi->w_savut, (char *)&u, sizeof(u))))
431 /* restore original, of which we will adopt all fields but ut_host */
432 bcopy((char *)&wi->w_savut, (char *) &u, sizeof(u));
434 if (!saved_ut)
435 makeuser(&u, stripdev(wi->w_tty), LoginName, wi->w_pid);
437 #ifdef UTHOST
438 host[sizeof(host) - 15] = '\0';
439 if (display)
441 strncpy(host, D_loginhost, sizeof(host) - 15);
442 if (D_loginslot != (slot_t)0 && D_loginslot != (slot_t)-1 && host[0] != '\0')
445 * we want to set our ut_host field to something like
446 * ":ttyhf:s.0" or
447 * "faui45:s.0" or
448 * "132.199.81.4:s.0" (even this may hurt..), but not
449 * "faui45.informati"......:s.0
450 * HPUX uses host:0.0, so chop at "." and ":" (Eric Backus)
452 for (p = host; *p; p++)
453 if ((*p < '0' || *p > '9') && (*p != '.'))
454 break;
455 if (*p)
457 for (p = host; *p; p++)
458 if (*p == '.' || (*p == ':' && p != host))
460 *p = '\0';
461 break;
465 else
467 strncpy(host + 1, stripdev(D_usertty), sizeof(host) - 15 - 1);
468 host[0] = ':';
471 else
472 strncpy(host, "local", sizeof(host) - 15);
474 sprintf(host + strlen(host), ":S.%d", wi->w_number);
475 debug1("rlogin hostname: '%s'\n", host);
477 # if !defined(_SEQUENT_) && !defined(sequent)
478 strncpy(u.ut_host, host, sizeof(u.ut_host));
479 # endif
480 #endif /* UTHOST */
482 if (pututslot(slot, &u, host, wi) == 0)
484 Msg(errno,"Could not write %s", UtmpName);
485 UT_CLOSE;
486 return -1;
488 debug("SetUtmp successful\n");
489 wi->w_slot = slot;
490 bcopy((char *)&u, (char *)&wi->w_savut, sizeof(u));
491 UT_CLOSE;
492 return 0;
496 * if slot could be removed or was 0, wi->w_slot = -1;
497 * else not changed.
501 RemoveUtmp(wi)
502 struct win *wi;
504 struct utmp u, *uu;
505 slot_t slot;
507 slot = wi->w_slot;
508 debug1("RemoveUtmp slot=%#x\n", slot);
509 if (!utmpok)
510 return -1;
511 if (slot == (slot_t)0 || slot == (slot_t)-1)
513 wi->w_slot = (slot_t)-1;
514 return 0;
516 bzero((char *) &u, sizeof(u));
517 #ifdef sgi
518 bcopy((char *)&wi->w_savut, (char *)&u, sizeof(u));
519 uu = &u;
520 #else
521 if ((uu = getutslot(slot)) == 0)
523 Msg(0, "Utmp slot not found -> not removed");
524 return -1;
526 bcopy((char *)uu, (char *)&wi->w_savut, sizeof(wi->w_savut));
527 #endif
528 u = *uu;
529 makedead(&u);
530 if (pututslot(slot, &u, (char *)0, wi) == 0)
532 Msg(errno,"Could not write %s", UtmpName);
533 UT_CLOSE;
534 return -1;
536 debug("RemoveUtmp successfull\n");
537 wi->w_slot = (slot_t)-1;
538 UT_CLOSE;
539 return 0;
544 /*********************************************************************
546 * routines using the getut* api
549 #ifdef GETUTENT
551 #define SLOT_USED(u) (u->ut_type == USER_PROCESS)
553 static struct utmp *
554 getutslot(slot)
555 slot_t slot;
557 struct utmp u;
558 bzero((char *)&u, sizeof(u));
559 strncpy(u.ut_line, slot, sizeof(u.ut_line));
560 setutent();
561 return getutline(&u);
564 static int
565 pututslot(slot, u, host, wi)
566 slot_t slot;
567 struct utmp *u;
568 char *host;
569 struct win *wi;
571 #ifdef _SEQUENT_
572 if (SLOT_USED(u) && host && *host)
573 return ut_add_user(u.ut_name, slot, u.ut_pid, host) != 0;
574 if (!SLOT_USED(u))
575 return ut_delete_user(slot, u.ut_pid, 0, 0) != 0;
576 #endif
577 #ifdef HAVE_UTEMPTER
578 if (eff_uid && wi->w_ptyfd != -1)
580 /* sigh, linux hackers made the helper functions void */
581 if (SLOT_USED(u))
582 addToUtmp(wi->w_tty, host, wi->w_ptyfd);
583 else
584 removeLineFromUtmp(wi->w_tty, wi->w_ptyfd);
585 return 1; /* pray for success */
587 #endif
588 setutent();
589 #ifndef __CYGWIN__
590 return pututline(u) != 0;
591 #else
592 return 1;
593 #endif
596 static void
597 makedead(u)
598 struct utmp *u;
600 u->ut_type = DEAD_PROCESS;
601 #if (!defined(linux) || defined(EMPTY)) && !defined(__CYGWIN__)
602 u->ut_exit.e_termination = 0;
603 u->ut_exit.e_exit = 0;
604 #endif
605 #if !defined(sun) || !defined(SVR4)
606 u->ut_user[0] = 0; /* for Digital UNIX, kilbi@rad.rwth-aachen.de */
607 #endif
610 static void
611 makeuser(u, line, user, pid)
612 struct utmp *u;
613 char *line, *user;
614 int pid;
616 time_t now;
617 u->ut_type = USER_PROCESS;
618 strncpy(u->ut_user, user, sizeof(u->ut_user));
619 /* Now the tricky part... guess ut_id */
620 #if defined(sgi) || defined(linux)
621 strncpy(u->ut_id, line + 3, sizeof(u->ut_id));
622 #else /* sgi */
623 # ifdef _IBMR2
624 strncpy(u->ut_id, line, sizeof(u->ut_id));
625 # else
626 strncpy(u->ut_id, line + strlen(line) - 2, sizeof(u->ut_id));
627 # endif
628 #endif /* sgi */
629 strncpy(u->ut_line, line, sizeof(u->ut_line));
630 u->ut_pid = pid;
631 /* must use temp variable because of NetBSD/sparc64, where
632 * ut_xtime is long(64) but time_t is int(32) */
633 (void)time(&now);
634 u->ut_time = now;
637 static slot_t
638 TtyNameSlot(nam)
639 char *nam;
641 return stripdev(nam);
645 #else /* GETUTENT */
647 /*********************************************************************
649 * getut emulation for systems lacking the api
652 static struct utmp uent;
654 #define SLOT_USED(u) (u.ut_name[0] != 0)
656 static int
657 initutmp()
659 if (utmpfd >= 0)
660 return 1;
661 return (utmpfd = open(UtmpName, O_RDWR)) >= 0;
664 static void
665 setutent()
667 if (utmpfd >= 0)
668 (void)lseek(utmpfd, (off_t)0, 0);
671 static void
672 endutent()
674 if (utmpfd >= 0)
675 close(utmpfd);
676 utmpfd = -1;
679 static struct utmp *
680 getutent()
682 if (utmpfd < 0 && !initutmp())
683 return 0;
684 if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent))
685 return 0;
686 return &uent;
689 static struct utmp *
690 getutslot(slot)
691 slot_t slot;
693 if (utmpfd < 0 && !initutmp())
694 return 0;
695 lseek(utmpfd, (off_t)(slot * sizeof(struct utmp)), 0);
696 if (read(utmpfd, &uent, sizeof(uent)) != sizeof(uent))
697 return 0;
698 return &uent;
701 static int
702 pututslot(slot, u, host, wi)
703 slot_t slot;
704 struct utmp *u;
705 char *host;
706 struct win *wi;
708 #ifdef sequent
709 if (SLOT_USED(u))
710 return add_utmp(slot, u) != -1;
711 #endif
712 if (utmpfd < 0 && !initutmp())
713 return 0;
714 lseek(utmpfd, (off_t)(slot * sizeof(*u)), 0);
715 if (write(utmpfd, u, sizeof(*u)) != sizeof(*u))
716 return 0;
717 return 1;
721 static void
722 makedead(u)
723 struct utmp *u;
725 #ifdef UT_UNSORTED
726 bzero(u->ut_name, sizeof(u->ut_name));
727 # ifdef UTHOST
728 bzero(u->ut_host, sizeof(u->ut_host));
729 # endif
730 #else
731 bzero((char *)u, sizeof(*u));
732 #endif
736 static void
737 makeuser(u, line, user, pid)
738 struct utmp *u;
739 char *line, *user;
740 int pid;
742 time_t now;
743 strncpy(u->ut_line, line, sizeof(u->ut_line));
744 strncpy(u->ut_name, user, sizeof(u->ut_name));
745 (void)time(&now);
746 u->ut_time = now;
749 static slot_t
750 TtyNameSlot(nam)
751 char *nam;
753 slot_t slot;
754 char *line;
755 #ifndef UT_UNSORTED
756 struct ttyent *tp;
757 #endif
759 line = stripdev(nam);
760 #ifdef UT_UNSORTED
761 setutent();
762 if (utmpfd < 0)
763 return -1;
764 for (slot = 0; getutent(); slot++)
765 if (strcmp(uent.ut_line, line) == 0)
766 break;
767 UT_CLOSE;
768 #else
769 slot = 1;
770 setttyent();
771 while ((tp = getttyent()) != 0 && strcmp(line, tp->ty_name) != 0)
772 slot++;
773 #endif
774 return slot;
777 #endif /* GETUTENT */
781 /*********************************************************************
783 * Cheap plastic imitation of ttyent routines.
786 #if !defined(GETTTYENT) && !defined(GETUTENT) && !defined(UT_UNSORTED)
789 static char *tt, *ttnext;
790 static char ttys[] = "/etc/ttys";
792 static void
793 setttyent()
795 if (ttnext == 0)
797 struct stat s;
798 register int f;
799 register char *p, *ep;
801 if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
802 Panic(errno, ttys);
803 if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
804 Panic(0, strnomem);
805 if (read(f, tt, s.st_size) != s.st_size)
806 Panic(errno, ttys);
807 close(f);
808 for (p = tt, ep = p + s.st_size; p < ep; p++)
809 if (*p == '\n')
810 *p = '\0';
811 *p = '\0';
813 ttnext = tt;
816 static struct ttyent *
817 getttyent()
819 static struct ttyent t;
821 if (*ttnext == '\0')
822 return NULL;
823 t.ty_name = ttnext + 2;
824 ttnext += strlen(ttnext) + 1;
825 return &t;
828 #endif /* !GETTTYENT && !GETUTENT && !UT_UNSORTED*/
832 #endif /* UTMPOK */
837 /*********************************************************************
839 * getlogin() replacement (for SVR4 machines)
842 # if defined(BUGGYGETLOGIN) && defined(UTMP_FILE)
843 char *
844 getlogin()
846 char *tty = NULL;
847 #ifdef utmp
848 # undef utmp
849 #endif
850 struct utmp u;
851 static char retbuf[sizeof(u.ut_user)+1];
852 int fd;
854 for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++)
856 if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0))
857 return NULL;
858 tty = stripdev(tty);
859 retbuf[0] = '\0';
860 while (read(fd, (char *)&u, sizeof(struct utmp)) == sizeof(struct utmp))
862 if (!strncmp(tty, u.ut_line, sizeof(u.ut_line)))
864 strncpy(retbuf, u.ut_user, sizeof(u.ut_user));
865 retbuf[sizeof(u.ut_user)] = '\0';
866 if (u.ut_type == USER_PROCESS)
867 break;
870 close(fd);
872 return *retbuf ? retbuf : NULL;
874 # endif /* BUGGYGETLOGIN */
876 #if defined(linux) && defined(GETUTENT)
877 # undef pututline
879 /* aargh, linux' pututline returns void! */
880 struct utmp *
881 xpututline(u)
882 struct utmp *u;
884 struct utmp *u2;
885 pututline(u);
886 setutent();
887 u2 = getutline(u);
888 if (u2 == 0)
889 return u->ut_type == DEAD_PROCESS ? u : 0;
890 return u->ut_type == u2->ut_type ? u : 0;
892 #endif