6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libc / port / gen / getut.c
bloba622293d736499c033e7ce9471fabbd53fe9e824
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
31 * Compatibility routines to read and write alternate
32 * utmp-like files. These routines are only used in
33 * the case where utmpname() is used to change to a file
34 * other than /var/adm/utmp or /var/adm/wtmp. In this case,
35 * we assume that someone really wants to read old utmp-format
36 * files. Otherwise, the getutent, setutent, getutid, setutline,
37 * and pututline functions are actually wrappers around the
38 * equivalent function operating on utmpx-like files.
41 #include "lint.h"
42 #include <stdio.h>
43 #include <sys/param.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <utmpx.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <string.h>
50 #include <strings.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <ctype.h>
54 #include <utime.h>
55 #include <sys/wait.h>
57 #define IDLEN 4 /* length of id field in utmp */
58 #define SC_WILDC 0xff /* wild char for utmp ids */
59 #define MAXVAL 255 /* max value for an id 'character' */
61 #ifdef ut_time
62 #undef ut_time
63 #endif
65 static void utmp_frec2api(const struct futmp *, struct utmp *);
66 static void utmp_api2frec(const struct utmp *, struct futmp *);
67 struct utmp *_compat_getutent(void);
68 struct utmp *_compat_getutid(const struct utmp *);
69 struct utmp *_compat_getutline(const struct utmp *);
70 struct utmp *_compat_pututline(const struct utmp *);
71 void _compat_setutent(void);
72 void _compat_endutent(void);
73 void _compat_updwtmp(const char *, struct utmp *);
74 struct utmp *_compat_makeut(struct utmp *);
75 struct utmp *_compat_modut(struct utmp *);
77 static void unlockut(void);
78 static int idcmp(const char *, const char *);
79 static int allocid(char *, unsigned char *);
80 static int lockut(void);
83 static int fd = -1; /* File descriptor for the utmp file. */
85 * name of the current utmp-like file - set by utmpname (getutx.c)
86 * only if running in backward compatibility mode
87 * We don't modify this, but we can't declare it const or lint will freak.
89 extern char _compat_utmpfile[];
91 #ifdef ERRDEBUG
92 static long loc_utmp; /* Where in "utmp" the current "ubuf" was found. */
93 #endif
95 static struct futmp fubuf; /* Copy of last entry read in. */
96 static struct utmp ubuf; /* Last entry returned to client */
99 * In the 64-bit world, the utmp data structure grows because of
100 * the ut_time field (a time_t) at the end of it.
102 static void
103 utmp_frec2api(const struct futmp *src, struct utmp *dst)
105 if (src == NULL)
106 return;
108 (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
109 (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
110 (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
111 dst->ut_pid = src->ut_pid;
112 dst->ut_type = src->ut_type;
113 dst->ut_exit.e_termination = src->ut_exit.e_termination;
114 dst->ut_exit.e_exit = src->ut_exit.e_exit;
115 dst->ut_time = (time_t)src->ut_time;
118 static void
119 utmp_api2frec(const struct utmp *src, struct futmp *dst)
121 if (src == NULL)
122 return;
124 (void) strncpy(dst->ut_user, src->ut_user, sizeof (dst->ut_user));
125 (void) strncpy(dst->ut_line, src->ut_line, sizeof (dst->ut_line));
126 (void) memcpy(dst->ut_id, src->ut_id, sizeof (dst->ut_id));
127 dst->ut_pid = src->ut_pid;
128 dst->ut_type = src->ut_type;
129 dst->ut_exit.e_termination = src->ut_exit.e_termination;
130 dst->ut_exit.e_exit = src->ut_exit.e_exit;
131 dst->ut_time = (time32_t)src->ut_time;
135 * "getutent_frec" gets the raw version of the next entry in the utmp file.
137 static struct futmp *
138 getutent_frec(void)
141 * If the "utmp" file is not open, attempt to open it for
142 * reading. If there is no file, attempt to create one. If
143 * both attempts fail, return NULL. If the file exists, but
144 * isn't readable and writeable, do not attempt to create.
146 if (fd < 0) {
147 if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0) {
150 * If the open failed for permissions, try opening
151 * it only for reading. All "pututline()" later
152 * will fail the writes.
154 if ((fd = open(_compat_utmpfile, O_RDONLY)) < 0)
155 return (NULL);
159 /* Try to read in the next entry from the utmp file. */
161 if (read(fd, &fubuf, sizeof (fubuf)) != sizeof (fubuf)) {
162 bzero(&fubuf, sizeof (fubuf));
163 return (NULL);
166 /* Save the location in the file where this entry was found. */
168 (void) lseek(fd, 0L, 1);
169 return (&fubuf);
173 * "_compat_getutent" gets the next entry in the utmp file.
175 struct utmp *
176 _compat_getutent(void)
178 struct futmp *futp;
180 futp = getutent_frec();
181 utmp_frec2api(&fubuf, &ubuf);
182 if (futp == NULL)
183 return (NULL);
184 return (&ubuf);
188 * "_compat_getutid" finds the specified entry in the utmp file. If
189 * it can't find it, it returns NULL.
191 struct utmp *
192 _compat_getutid(const struct utmp *entry)
194 short type;
196 utmp_api2frec(&ubuf, &fubuf);
199 * Start looking for entry. Look in our current buffer before
200 * reading in new entries.
202 do {
204 * If there is no entry in "ubuf", skip to the read.
206 if (fubuf.ut_type != EMPTY) {
207 switch (entry->ut_type) {
210 * Do not look for an entry if the user sent
211 * us an EMPTY entry.
213 case EMPTY:
214 return (NULL);
217 * For RUN_LVL, BOOT_TIME, DOWN_TIME,
218 * OLD_TIME, and NEW_TIME entries, only the
219 * types have to match. If they do, return
220 * the address of internal buffer.
222 case RUN_LVL:
223 case BOOT_TIME:
224 case DOWN_TIME:
225 case OLD_TIME:
226 case NEW_TIME:
227 if (entry->ut_type == fubuf.ut_type) {
228 utmp_frec2api(&fubuf, &ubuf);
229 return (&ubuf);
231 break;
234 * For INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
235 * and DEAD_PROCESS the type of the entry in "fubuf",
236 * must be one of the above and id's must match.
238 case INIT_PROCESS:
239 case LOGIN_PROCESS:
240 case USER_PROCESS:
241 case DEAD_PROCESS:
242 if (((type = fubuf.ut_type) == INIT_PROCESS ||
243 type == LOGIN_PROCESS ||
244 type == USER_PROCESS ||
245 type == DEAD_PROCESS) &&
246 fubuf.ut_id[0] == entry->ut_id[0] &&
247 fubuf.ut_id[1] == entry->ut_id[1] &&
248 fubuf.ut_id[2] == entry->ut_id[2] &&
249 fubuf.ut_id[3] == entry->ut_id[3]) {
250 utmp_frec2api(&fubuf, &ubuf);
251 return (&ubuf);
253 break;
255 /* Do not search for illegal types of entry. */
256 default:
257 return (NULL);
260 } while (getutent_frec() != NULL);
262 /* the proper entry wasn't found. */
264 utmp_frec2api(&fubuf, &ubuf);
265 return (NULL);
269 * "_compat_getutline" searches the "utmp" file for a LOGIN_PROCESS or
270 * USER_PROCESS with the same "line" as the specified "entry".
272 struct utmp *
273 _compat_getutline(const struct utmp *entry)
275 utmp_api2frec(&ubuf, &fubuf);
277 do {
279 * If the current entry is the one we are interested in,
280 * return a pointer to it.
282 if (fubuf.ut_type != EMPTY &&
283 (fubuf.ut_type == LOGIN_PROCESS ||
284 fubuf.ut_type == USER_PROCESS) &&
285 strncmp(&entry->ut_line[0], &fubuf.ut_line[0],
286 sizeof (fubuf.ut_line)) == 0) {
287 utmp_frec2api(&fubuf, &ubuf);
288 return (&ubuf);
290 } while (getutent_frec() != NULL);
292 utmp_frec2api(&fubuf, &ubuf);
293 return (NULL);
297 * "_compat_pututline" writes the structure sent into the utmp file
298 * If there is already an entry with the same id, then it is
299 * overwritten, otherwise a new entry is made at the end of the
300 * utmp file.
302 struct utmp *
303 _compat_pututline(const struct utmp *entry)
305 int fc;
306 struct utmp *answer;
307 struct utmp tmpbuf;
308 struct futmp ftmpbuf;
311 * Copy the user supplied entry into our temporary buffer to
312 * avoid the possibility that the user is actually passing us
313 * the address of "ubuf".
315 tmpbuf = *entry;
316 utmp_api2frec(entry, &ftmpbuf);
318 (void) getutent_frec();
319 if (fd < 0) {
320 #ifdef ERRDEBUG
321 gdebug("pututline: Unable to create utmp file.\n");
322 #endif
323 return (NULL);
326 /* Make sure file is writable */
328 if ((fc = fcntl(fd, F_GETFL, NULL)) == -1 || (fc & O_RDWR) != O_RDWR)
329 return (NULL);
332 * Find the proper entry in the utmp file. Start at the current
333 * location. If it isn't found from here to the end of the
334 * file, then reset to the beginning of the file and try again.
335 * If it still isn't found, then write a new entry at the end of
336 * the file. (Making sure the location is an integral number of
337 * utmp structures into the file incase the file is scribbled.)
340 if (_compat_getutid(&tmpbuf) == NULL) {
341 #ifdef ERRDEBUG
342 gdebug("1st getutid() failed. fd: %d", fd);
343 #endif
344 _compat_setutent();
345 if (_compat_getutid(&tmpbuf) == NULL) {
346 #ifdef ERRDEBUG
347 loc_utmp = lseek(fd, 0L, 1);
348 gdebug("2nd getutid() failed. fd: %d loc_utmp: %ld\n",
349 fd, loc_utmp);
350 #endif
351 (void) fcntl(fd, F_SETFL, fc | O_APPEND);
352 } else
353 (void) lseek(fd, -(long)sizeof (struct futmp), 1);
354 } else
355 (void) lseek(fd, -(long)sizeof (struct futmp), 1);
358 * Write out the user supplied structure. If the write fails,
359 * then the user probably doesn't have permission to write the
360 * utmp file.
362 if (write(fd, &ftmpbuf, sizeof (ftmpbuf)) != sizeof (ftmpbuf)) {
363 #ifdef ERRDEBUG
364 gdebug("pututline failed: write-%d\n", errno);
365 #endif
366 answer = NULL;
367 } else {
369 * Copy the new user structure into ubuf so that it will
370 * be up to date in the future.
372 fubuf = ftmpbuf;
373 utmp_frec2api(&fubuf, &ubuf);
374 answer = &ubuf;
376 #ifdef ERRDEBUG
377 gdebug("id: %c%c loc: %ld\n", fubuf.ut_id[0],
378 fubuf.ut_id[1], fubuf.ut_id[2], fubuf.ut_id[3],
379 loc_utmp);
380 #endif
383 (void) fcntl(fd, F_SETFL, fc);
385 return (answer);
389 * "_compat_setutent" just resets the utmp file back to the beginning.
391 void
392 _compat_setutent(void)
394 if (fd != -1)
395 (void) lseek(fd, 0L, 0);
398 * Zero the stored copy of the last entry read, since we are
399 * resetting to the beginning of the file.
401 bzero(&ubuf, sizeof (ubuf));
402 bzero(&fubuf, sizeof (fubuf));
406 * "_compat_endutent" closes the utmp file.
408 void
409 _compat_endutent(void)
411 if (fd != -1)
412 (void) close(fd);
413 fd = -1;
414 bzero(&ubuf, sizeof (ubuf));
415 bzero(&fubuf, sizeof (fubuf));
420 * If one of wtmp and wtmpx files exist, create the other, and the record.
421 * If they both exist add the record.
423 void
424 _compat_updwtmp(const char *file, struct utmp *ut)
426 struct futmp fut;
427 int fd;
430 fd = open(file, O_WRONLY | O_APPEND);
432 if (fd < 0) {
433 if ((fd = open(file, O_WRONLY|O_CREAT, 0644)) < 0)
434 return;
437 (void) lseek(fd, 0, 2);
439 utmp_api2frec(ut, &fut);
440 (void) write(fd, &fut, sizeof (fut));
442 (void) close(fd);
448 * makeut - create a utmp entry, recycling an id if a wild card is
449 * specified.
451 * args: utmp - point to utmp structure to be created
453 struct utmp *
454 _compat_makeut(struct utmp *utmp)
456 int i;
457 struct utmp *utp; /* "current" utmp entry being examined */
458 int wild; /* flag, true iff wild card char seen */
460 /* the last id we matched that was NOT a dead proc */
461 unsigned char saveid[IDLEN];
463 wild = 0;
464 for (i = 0; i < IDLEN; i++)
465 if ((unsigned char)utmp->ut_id[i] == SC_WILDC) {
466 wild = 1;
467 break;
470 if (wild) {
473 * try to lock the utmp file, only needed if we're
474 * doing wildcard matching
477 if (lockut())
478 return (0);
479 _compat_setutent();
481 /* find the first alphanumeric character */
482 for (i = 0; i < MAXVAL; ++i)
483 if (isalnum(i))
484 break;
486 (void) memset(saveid, i, IDLEN);
488 while ((utp = _compat_getutent()) != 0) {
489 if (idcmp(utmp->ut_id, utp->ut_id))
490 continue;
491 if (utp->ut_type == DEAD_PROCESS)
492 break;
493 (void) memcpy(saveid, utp->ut_id, IDLEN);
496 if (utp) {
498 * found an unused entry, reuse it
500 (void) memcpy(utmp->ut_id, utp->ut_id, IDLEN);
501 utp = _compat_pututline(utmp);
502 if (utp)
503 _compat_updwtmp(WTMP_FILE, utp);
504 _compat_endutent();
505 unlockut();
506 return (utp);
508 } else {
510 * nothing available, try to allocate an id
512 if (allocid(utmp->ut_id, saveid)) {
513 _compat_endutent();
514 unlockut();
515 return (NULL);
516 } else {
517 utp = _compat_pututline(utmp);
518 if (utp)
519 _compat_updwtmp(WTMP_FILE, utp);
520 _compat_endutent();
521 unlockut();
522 return (utp);
525 } else {
526 utp = _compat_pututline(utmp);
527 if (utp)
528 _compat_updwtmp(WTMP_FILE, utp);
529 _compat_endutent();
530 return (utp);
536 * _compat_modut - modify a utmp entry.
538 * args: utmp - point to utmp structure to be created
540 struct utmp *
541 _compat_modut(struct utmp *utp)
543 int i; /* scratch variable */
544 struct utmp utmp; /* holding area */
545 struct utmp *ucp = &utmp; /* and a pointer to it */
546 struct utmp *up; /* "current" utmp entry being examined */
547 struct futmp *fup;
549 for (i = 0; i < IDLEN; ++i)
550 if ((unsigned char)utp->ut_id[i] == SC_WILDC)
551 return (0);
553 /* copy the supplied utmp structure someplace safe */
554 utmp = *utp;
555 _compat_setutent();
556 while (fup = getutent_frec()) {
557 if (idcmp(ucp->ut_id, fup->ut_id))
558 continue;
559 break;
561 up = _compat_pututline(ucp);
562 if (up)
563 _compat_updwtmp(WTMP_FILE, up);
564 _compat_endutent();
565 return (up);
571 * idcmp - compare two id strings, return 0 if same, non-zero if not *
572 * args: s1 - first id string
573 * s2 - second id string
575 static int
576 idcmp(const char *s1, const char *s2)
578 int i;
580 for (i = 0; i < IDLEN; ++i)
581 if ((unsigned char)*s1 != SC_WILDC && (*s1++ != *s2++))
582 return (-1);
583 return (0);
588 * allocid - allocate an unused id for utmp, either by recycling a
589 * DEAD_PROCESS entry or creating a new one. This routine only
590 * gets called if a wild card character was specified.
592 * args: srcid - pattern for new id
593 * saveid - last id matching pattern for a non-dead process
595 static int
596 allocid(char *srcid, unsigned char *saveid)
598 int i; /* scratch variable */
599 int changed; /* flag to indicate that a new id has been generated */
600 char copyid[IDLEN]; /* work area */
602 (void) memcpy(copyid, srcid, IDLEN);
603 changed = 0;
604 for (i = 0; i < IDLEN; ++i) {
606 * if this character isn't wild, it'll
607 * be part of the generated id
609 if ((unsigned char) copyid[i] != SC_WILDC)
610 continue;
612 * it's a wild character, retrieve the
613 * character from the saved id
615 copyid[i] = saveid[i];
617 * if we haven't changed anything yet,
618 * try to find a new char to use
620 if (!changed && (saveid[i] < MAXVAL)) {
623 * Note: this algorithm is taking the "last matched" id and trying to make
624 * a 1 character change to it to create a new one. Rather than special-case
625 * the first time (when no perturbation is really necessary), just don't
626 * allocate the first valid id.
629 while (++saveid[i] < MAXVAL) {
630 /* make sure new char is alphanumeric */
631 if (isalnum(saveid[i])) {
632 copyid[i] = saveid[i];
633 changed = 1;
634 break;
638 if (!changed) {
640 * Then 'reset' the current count at
641 * this position to it's lowest valid
642 * value, and propagate the carry to
643 * the next wild-card slot
645 * See 1113208.
647 saveid[i] = 0;
648 while (!isalnum(saveid[i]))
649 saveid[i]++;
650 copyid[i] = ++saveid[i];
654 /* changed is true if we were successful in allocating an id */
655 if (changed) {
656 (void) memcpy(srcid, copyid, IDLEN);
657 return (0);
658 } else
659 return (-1);
664 * lockut - lock utmp file
666 static int
667 lockut(void)
669 if ((fd = open(_compat_utmpfile, O_RDWR|O_CREAT, 0644)) < 0)
670 return (-1);
672 if (lockf(fd, F_LOCK, 0) < 0) {
673 (void) close(fd);
674 fd = -1;
675 return (-1);
677 return (0);
682 * unlockut - unlock utmp file
684 static void
685 unlockut(void)
687 (void) lockf(fd, F_ULOCK, 0);
688 (void) close(fd);
689 fd = -1;
694 #ifdef ERRDEBUG
696 #include <stdarg.h>
697 #include <stdio.h>
699 static void
700 gdebug(const char *fmt, ...)
702 FILE *fp;
703 int errnum;
704 va_list ap;
706 if ((fp = fopen("/etc/dbg.getut", "a+F")) == NULL)
707 return;
708 va_start(ap, fmt);
709 (void) vfprintf(fp, fmt, ap);
710 va_end(ap);
711 (void) fclose(fp);
713 #endif