drm/radeon: Use atomic_cmpxchg()
[dragonfly.git] / contrib / amd / libamu / xutil.c
blob0208045f98e0686385666b9a13735fd431d962b5
1 /*
2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 * %W% (Berkeley) %G%
41 * $Id: xutil.c,v 1.8 1999/09/30 21:01:42 ezk Exp $
45 #ifdef HAVE_CONFIG_H
46 # include <config.h>
47 #endif /* HAVE_CONFIG_H */
48 #include <am_defs.h>
49 #include <amu.h>
52 * Logfp is the default logging device, and is initialized to stderr by
53 * default in dplog/plog below, and in
54 * amd/amfs_program.c:amfs_program_exec().
56 FILE *logfp = NULL;
58 static char *am_progname = "unknown"; /* "amd" */
59 static char am_hostname[MAXHOSTNAMELEN + 1] = "unknown"; /* Hostname */
60 pid_t am_mypid = -1; /* process ID */
61 serv_state amd_state; /* amd's state */
62 int foreground = 1; /* 1 == this is the top-level server */
63 #ifdef DEBUG
64 int debug_flags = 0;
65 #endif /* DEBUG */
67 #ifdef HAVE_SYSLOG
68 int syslogging;
69 #endif /* HAVE_SYSLOG */
70 int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS;
71 int xlog_level_init = ~0;
72 static int amd_program_number = AMQ_PROGRAM;
74 time_t clock_valid = 0;
75 time_t xclock_valid = 0;
77 #ifdef DEBUG_MEM
78 static int mem_bytes;
79 static int orig_mem_bytes;
80 #endif /* DEBUG_MEM */
82 /* forward definitions */
83 static void real_plog(int lvl, char *fmt, va_list vargs);
85 #ifdef DEBUG
87 * List of debug options.
89 struct opt_tab dbg_opt[] =
91 {"all", D_ALL}, /* All */
92 {"amq", D_AMQ}, /* Register for AMQ program */
93 {"daemon", D_DAEMON}, /* Enter daemon mode */
94 {"fork", D_FORK}, /* Fork server (nofork = don't fork) */
95 {"full", D_FULL}, /* Program trace */
96 /* info service specific debugging (hesiod, nis, etc) */
97 {"info", D_INFO},
98 # ifdef DEBUG_MEM
99 {"mem", D_MEM}, /* Trace memory allocations */
100 # endif /* DEBUG_MEM */
101 {"mtab", D_MTAB}, /* Use local mtab file */
102 {"str", D_STR}, /* Debug string munging */
103 {"test", D_TEST}, /* Full debug - but no daemon */
104 {"trace", D_TRACE}, /* Protocol trace */
105 {0, 0}
107 #endif /* DEBUG */
110 * List of log options
112 struct opt_tab xlog_opt[] =
114 {"all", XLOG_ALL}, /* All messages */
115 #ifdef DEBUG
116 {"debug", XLOG_DEBUG}, /* Debug messages */
117 #endif /* DEBUG */ /* DEBUG */
118 {"error", XLOG_ERROR}, /* Non-fatal system errors */
119 {"fatal", XLOG_FATAL}, /* Fatal errors */
120 {"info", XLOG_INFO}, /* Information */
121 {"map", XLOG_MAP}, /* Map errors */
122 {"stats", XLOG_STATS}, /* Additional statistical information */
123 {"user", XLOG_USER}, /* Non-fatal user errors */
124 {"warn", XLOG_WARNING}, /* Warnings */
125 {"warning", XLOG_WARNING}, /* Warnings */
126 {0, 0}
130 void
131 am_set_progname(char *pn)
133 am_progname = pn;
137 const char *
138 am_get_progname(void)
140 return am_progname;
144 void
145 am_set_hostname(char *hn)
147 strncpy(am_hostname, hn, MAXHOSTNAMELEN);
148 am_hostname[MAXHOSTNAMELEN] = '\0';
152 const char *
153 am_get_hostname(void)
155 return am_hostname;
159 pid_t
160 am_set_mypid(void)
162 am_mypid = getpid();
163 return am_mypid;
167 voidp
168 xmalloc(int len)
170 voidp p;
171 int retries = 600;
174 * Avoid malloc's which return NULL for malloc(0)
176 if (len == 0)
177 len = 1;
179 do {
180 p = (voidp) malloc((unsigned) len);
181 if (p) {
182 #if defined(DEBUG) && defined(DEBUG_MEM)
183 amuDebug(D_MEM)
184 plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p);
185 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
186 return p;
188 if (retries > 0) {
189 plog(XLOG_ERROR, "Retrying memory allocation");
190 sleep(1);
192 } while (--retries);
194 plog(XLOG_FATAL, "Out of memory");
195 going_down(1);
197 abort();
199 return 0;
203 /* like xmalloc, but zeros out the bytes */
204 voidp
205 xzalloc(int len)
207 voidp p = xmalloc(len);
209 if (p)
210 memset(p, 0, len);
211 return p;
215 voidp
216 xrealloc(voidp ptr, int len)
218 #if defined(DEBUG) && defined(DEBUG_MEM)
219 amuDebug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr);
220 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
222 if (len == 0)
223 len = 1;
225 if (ptr)
226 ptr = (voidp) realloc(ptr, (unsigned) len);
227 else
228 ptr = (voidp) xmalloc((unsigned) len);
230 if (!ptr) {
231 plog(XLOG_FATAL, "Out of memory in realloc");
232 going_down(1);
233 abort();
235 return ptr;
239 #if defined(DEBUG) && defined(DEBUG_MEM)
240 void
241 dxfree(char *file, int line, voidp ptr)
243 amuDebug(D_MEM)
244 plog(XLOG_DEBUG, "Free in %s:%d: block %#x", file, line, ptr);
245 /* this is the only place that must NOT use XFREE()!!! */
246 free(ptr);
247 ptr = NULL; /* paranoid */
249 #endif /* defined(DEBUG) && defined(DEBUG_MEM) */
252 #ifdef DEBUG_MEM
253 static void
254 checkup_mem(void)
256 struct mallinfo mi = mallinfo();
257 u_long uordbytes = mi.uordblks * 4096;
259 if (mem_bytes != uordbytes) {
260 if (orig_mem_bytes == 0)
261 mem_bytes = orig_mem_bytes = uordbytes;
262 else {
263 fprintf(logfp, "%s[%ld]: ", am_get_progname(), (long) am_mypid);
264 if (mem_bytes < uordbytes) {
265 fprintf(logfp, "ALLOC: %ld bytes", uordbytes - mem_bytes);
266 } else {
267 fprintf(logfp, "FREE: %ld bytes", mem_bytes - uordbytes);
269 mem_bytes = uordbytes;
270 fprintf(logfp, ", making %d missing\n", mem_bytes - orig_mem_bytes);
273 malloc_verify();
275 #endif /* DEBUG_MEM */
279 * Take a log format string and expand occurrences of %m
280 * with the current error code taken from errno. Make sure
281 * 'e' never gets longer than maxlen characters.
283 static void
284 expand_error(char *f, char *e, int maxlen)
286 char *p, *q;
287 int error = errno;
288 int len = 0;
290 for (p = f, q = e; (*q = *p) && len < maxlen; len++, q++, p++) {
291 if (p[0] == '%' && p[1] == 'm') {
292 const char *errstr;
293 if (error < 0 || error >= sys_nerr)
294 errstr = NULL;
295 else
296 #ifdef HAVE_STRERROR
297 errstr = strerror(error);
298 #else /* not HAVE_STRERROR */
299 errstr = sys_errlist[error];
300 #endif /* not HAVE_STRERROR */
301 if (errstr)
302 strcpy(q, errstr);
303 else
304 sprintf(q, "Error %d", error);
305 len += strlen(q) - 1;
306 q += strlen(q) - 1;
307 p++;
310 e[maxlen-1] = '\0'; /* null terminate, to be sure */
315 * Output the time of day and hostname to the logfile
317 static void
318 show_time_host_and_name(int lvl)
320 static time_t last_t = 0;
321 static char *last_ctime = 0;
322 time_t t = clocktime();
323 char *sev;
325 if (t != last_t) {
326 last_ctime = ctime(&t);
327 last_t = t;
329 switch (lvl) {
330 case XLOG_FATAL:
331 sev = "fatal:";
332 break;
333 case XLOG_ERROR:
334 sev = "error:";
335 break;
336 case XLOG_USER:
337 sev = "user: ";
338 break;
339 case XLOG_WARNING:
340 sev = "warn: ";
341 break;
342 case XLOG_INFO:
343 sev = "info: ";
344 break;
345 case XLOG_DEBUG:
346 sev = "debug:";
347 break;
348 case XLOG_MAP:
349 sev = "map: ";
350 break;
351 case XLOG_STATS:
352 sev = "stats:";
353 break;
354 default:
355 sev = "hmm: ";
356 break;
358 fprintf(logfp, "%15.15s %s %s[%ld]/%s ",
359 last_ctime + 4, am_get_hostname(),
360 am_get_progname(),
361 (long) am_mypid,
362 sev);
366 #ifdef DEBUG
368 * Switch on/off debug options
371 debug_option(char *opt)
373 return cmdoption(opt, dbg_opt, &debug_flags);
377 void
378 dplog(char *fmt, ...)
380 va_list ap;
382 if (!logfp)
383 logfp = stderr; /* initialize before possible first use */
385 va_start(ap, fmt);
386 real_plog(XLOG_DEBUG, fmt, ap);
387 va_end(ap);
389 #endif /* DEBUG */
392 void
393 plog(int lvl, char *fmt, ...)
395 va_list ap;
397 if (!logfp)
398 logfp = stderr; /* initialize before possible first use */
400 va_start(ap, fmt);
401 real_plog(lvl, fmt, ap);
402 va_end(ap);
406 static void
407 real_plog(int lvl, char *fmt, va_list vargs)
409 char msg[1024];
410 char efmt[1024];
411 char *ptr = msg;
412 static char last_msg[1024];
413 static int last_count = 0, last_lvl = 0;
415 if (!(xlog_level & lvl))
416 return;
418 #ifdef DEBUG_MEM
419 checkup_mem();
420 #endif /* DEBUG_MEM */
422 expand_error(fmt, efmt, 1024);
424 #ifdef HAVE_VSNPRINTF
425 vsnprintf(ptr, 1024, efmt, vargs);
426 #else /* not HAVE_VSNPRINTF */
428 * XXX: ptr is 1024 bytes long. It is possible to write into it
429 * more than 1024 bytes, if efmt is already large, and vargs expand
430 * as well. This is not as safe as using vsnprintf().
432 vsprintf(ptr, efmt, vargs);
433 msg[1023] = '\0'; /* null terminate, to be sure */
434 #endif /* not HAVE_VSNPRINTF */
436 ptr += strlen(ptr);
437 if (ptr[-1] == '\n')
438 *--ptr = '\0';
440 #ifdef HAVE_SYSLOG
441 if (syslogging) {
442 switch (lvl) { /* from mike <mcooper@usc.edu> */
443 case XLOG_FATAL:
444 lvl = LOG_CRIT;
445 break;
446 case XLOG_ERROR:
447 lvl = LOG_ERR;
448 break;
449 case XLOG_USER:
450 lvl = LOG_WARNING;
451 break;
452 case XLOG_WARNING:
453 lvl = LOG_WARNING;
454 break;
455 case XLOG_INFO:
456 lvl = LOG_INFO;
457 break;
458 case XLOG_DEBUG:
459 lvl = LOG_DEBUG;
460 break;
461 case XLOG_MAP:
462 lvl = LOG_DEBUG;
463 break;
464 case XLOG_STATS:
465 lvl = LOG_INFO;
466 break;
467 default:
468 lvl = LOG_ERR;
469 break;
471 syslog(lvl, "%s", msg);
472 return;
474 #endif /* HAVE_SYSLOG */
476 *ptr++ = '\n';
477 *ptr = '\0';
480 * mimic syslog behavior: only write repeated strings if they differ
482 switch (last_count) {
483 case 0: /* never printed at all */
484 last_count = 1;
485 strncpy(last_msg, msg, 1024);
486 last_lvl = lvl;
487 show_time_host_and_name(lvl); /* mimic syslog header */
488 fwrite(msg, ptr - msg, 1, logfp);
489 fflush(logfp);
490 break;
492 case 1: /* item printed once, if same, don't repeat */
493 if (STREQ(last_msg, msg)) {
494 last_count++;
495 } else { /* last msg printed once, new one differs */
496 /* last_count remains at 1 */
497 strncpy(last_msg, msg, 1024);
498 last_lvl = lvl;
499 show_time_host_and_name(lvl); /* mimic syslog header */
500 fwrite(msg, ptr - msg, 1, logfp);
501 fflush(logfp);
503 break;
505 case 100:
507 * Don't allow repetitions longer than 100, so you can see when something
508 * cycles like crazy.
510 show_time_host_and_name(last_lvl);
511 sprintf(last_msg, "last message repeated %d times\n", last_count);
512 fwrite(last_msg, strlen(last_msg), 1, logfp);
513 fflush(logfp);
514 last_count = 0; /* start from scratch */
515 break;
517 default: /* item repeated multiple times */
518 if (STREQ(last_msg, msg)) {
519 last_count++;
520 } else { /* last msg repeated+skipped, new one differs */
521 show_time_host_and_name(last_lvl);
522 sprintf(last_msg, "last message repeated %d times\n", last_count);
523 fwrite(last_msg, strlen(last_msg), 1, logfp);
524 strncpy(last_msg, msg, 1024);
525 last_count = 1;
526 last_lvl = lvl;
527 show_time_host_and_name(lvl); /* mimic syslog header */
528 fwrite(msg, ptr - msg, 1, logfp);
529 fflush(logfp);
531 break;
538 * Display current debug options
540 void
541 show_opts(int ch, struct opt_tab *opts)
543 int i;
544 int s = '{';
546 fprintf(stderr, "\t[-%c {no}", ch);
547 for (i = 0; opts[i].opt; i++) {
548 fprintf(stderr, "%c%s", s, opts[i].opt);
549 s = ',';
551 fputs("}]\n", stderr);
556 cmdoption(char *s, struct opt_tab *optb, int *flags)
558 char *p = s;
559 int errs = 0;
561 while (p && *p) {
562 int neg;
563 char *opt;
564 struct opt_tab *dp, *dpn = 0;
566 s = p;
567 p = strchr(p, ',');
568 if (p)
569 *p = '\0';
571 /* check for "no" prefix to options */
572 if (s[0] == 'n' && s[1] == 'o') {
573 opt = s + 2;
574 neg = 1;
575 } else {
576 opt = s;
577 neg = 0;
581 * Scan the array of debug options to find the
582 * corresponding flag value. If it is found
583 * then set (or clear) the flag (depending on
584 * whether the option was prefixed with "no").
586 for (dp = optb; dp->opt; dp++) {
587 if (STREQ(opt, dp->opt))
588 break;
589 if (opt != s && !dpn && STREQ(s, dp->opt))
590 dpn = dp;
593 if (dp->opt || dpn) {
594 if (!dp->opt) {
595 dp = dpn;
596 neg = !neg;
598 if (neg)
599 *flags &= ~dp->flag;
600 else
601 *flags |= dp->flag;
602 } else {
604 * This will log to stderr when parsing the command line
605 * since any -l option will not yet have taken effect.
607 plog(XLOG_USER, "option \"%s\" not recognized", s);
608 errs++;
612 * Put the comma back
614 if (p)
615 *p++ = ',';
618 return errs;
623 * Switch on/off logging options
626 switch_option(char *opt)
628 int xl = xlog_level;
629 int rc = cmdoption(opt, xlog_opt, &xl);
631 if (rc) {
632 rc = EINVAL;
633 } else {
635 * Keep track of initial log level, and
636 * don't allow options to be turned off.
638 if (xlog_level_init == ~0)
639 xlog_level_init = xl;
640 else
641 xl |= xlog_level_init;
642 xlog_level = xl;
644 return rc;
647 #ifdef LOG_DAEMON
649 * get syslog facility to use.
650 * logfile can be "syslog", "syslog:daemon", "syslog:local7", etc.
652 static int
653 get_syslog_facility(const char *logfile)
655 char *facstr;
657 /* parse facility string */
658 facstr = strchr(logfile, ':');
659 if (!facstr) /* log file was "syslog" */
660 return LOG_DAEMON;
661 facstr++;
662 if (!facstr || facstr[0] == '\0') { /* log file was "syslog:" */
663 plog(XLOG_WARNING, "null syslog facility, using LOG_DAEMON");
664 return LOG_DAEMON;
667 #ifdef LOG_KERN
668 if (STREQ(facstr, "kern"))
669 return LOG_KERN;
670 #endif /* not LOG_KERN */
671 #ifdef LOG_USER
672 if (STREQ(facstr, "user"))
673 return LOG_USER;
674 #endif /* not LOG_USER */
675 #ifdef LOG_MAIL
676 if (STREQ(facstr, "mail"))
677 return LOG_MAIL;
678 #endif /* not LOG_MAIL */
680 if (STREQ(facstr, "daemon"))
681 return LOG_DAEMON;
683 #ifdef LOG_AUTH
684 if (STREQ(facstr, "auth"))
685 return LOG_AUTH;
686 #endif /* not LOG_AUTH */
687 #ifdef LOG_SYSLOG
688 if (STREQ(facstr, "syslog"))
689 return LOG_SYSLOG;
690 #endif /* not LOG_SYSLOG */
691 #ifdef LOG_LPR
692 if (STREQ(facstr, "lpr"))
693 return LOG_LPR;
694 #endif /* not LOG_LPR */
695 #ifdef LOG_NEWS
696 if (STREQ(facstr, "news"))
697 return LOG_NEWS;
698 #endif /* not LOG_NEWS */
699 #ifdef LOG_UUCP
700 if (STREQ(facstr, "uucp"))
701 return LOG_UUCP;
702 #endif /* not LOG_UUCP */
703 #ifdef LOG_CRON
704 if (STREQ(facstr, "cron"))
705 return LOG_CRON;
706 #endif /* not LOG_CRON */
707 #ifdef LOG_LOCAL0
708 if (STREQ(facstr, "local0"))
709 return LOG_LOCAL0;
710 #endif /* not LOG_LOCAL0 */
711 #ifdef LOG_LOCAL1
712 if (STREQ(facstr, "local1"))
713 return LOG_LOCAL1;
714 #endif /* not LOG_LOCAL1 */
715 #ifdef LOG_LOCAL2
716 if (STREQ(facstr, "local2"))
717 return LOG_LOCAL2;
718 #endif /* not LOG_LOCAL2 */
719 #ifdef LOG_LOCAL3
720 if (STREQ(facstr, "local3"))
721 return LOG_LOCAL3;
722 #endif /* not LOG_LOCAL3 */
723 #ifdef LOG_LOCAL4
724 if (STREQ(facstr, "local4"))
725 return LOG_LOCAL4;
726 #endif /* not LOG_LOCAL4 */
727 #ifdef LOG_LOCAL5
728 if (STREQ(facstr, "local5"))
729 return LOG_LOCAL5;
730 #endif /* not LOG_LOCAL5 */
731 #ifdef LOG_LOCAL6
732 if (STREQ(facstr, "local6"))
733 return LOG_LOCAL6;
734 #endif /* not LOG_LOCAL6 */
735 #ifdef LOG_LOCAL7
736 if (STREQ(facstr, "local7"))
737 return LOG_LOCAL7;
738 #endif /* not LOG_LOCAL7 */
740 /* didn't match anything else */
741 plog(XLOG_WARNING, "unknown syslog facility \"%s\", using LOG_DAEMON", facstr);
742 return LOG_DAEMON;
744 #endif /* not LOG_DAEMON */
748 * Change current logfile
751 switch_to_logfile(char *logfile, int old_umask)
753 FILE *new_logfp = stderr;
755 if (logfile) {
756 #ifdef HAVE_SYSLOG
757 syslogging = 0;
758 #endif /* HAVE_SYSLOG */
760 if (STREQ(logfile, "/dev/stderr"))
761 new_logfp = stderr;
762 else if (NSTREQ(logfile, "syslog", strlen("syslog"))) {
764 #ifdef HAVE_SYSLOG
765 syslogging = 1;
766 new_logfp = stderr;
767 openlog(am_get_progname(),
768 LOG_PID
769 # ifdef LOG_CONS
770 | LOG_CONS
771 # endif /* LOG_CONS */
772 # ifdef LOG_NOWAIT
773 | LOG_NOWAIT
774 # endif /* LOG_NOWAIT */
775 # ifdef LOG_DAEMON
776 , get_syslog_facility(logfile)
777 # endif /* LOG_DAEMON */
779 #else /* not HAVE_SYSLOG */
780 plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
781 #endif /* not HAVE_SYSLOG */
783 } else {
784 (void) umask(old_umask);
785 new_logfp = fopen(logfile, "a");
786 umask(0);
791 * If we couldn't open a new file, then continue using the old.
793 if (!new_logfp && logfile) {
794 plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
795 return 1;
799 * Close the previous file
801 if (logfp && logfp != stderr)
802 (void) fclose(logfp);
803 logfp = new_logfp;
805 plog(XLOG_INFO, "switched to logfile \"%s\"", logfile);
806 return 0;
810 void
811 unregister_amq(void)
813 #ifdef DEBUG
814 amuDebug(D_AMQ)
815 #endif /* DEBUG */
816 /* find which instance of amd to unregister */
817 pmap_unset(get_amd_program_number(), AMQ_VERSION);
821 void
822 going_down(int rc)
824 if (foreground) {
825 if (amd_state != Start) {
826 if (amd_state != Done)
827 return;
828 unregister_amq();
831 if (foreground) {
832 plog(XLOG_INFO, "Finishing with status %d", rc);
833 } else {
834 #ifdef DEBUG
835 dlog("background process exiting with status %d", rc);
836 #endif /* DEBUG */
839 exit(rc);
843 /* return the rpc program number under which amd was used */
845 get_amd_program_number(void)
847 return amd_program_number;
851 /* set the rpc program number used for amd */
852 void
853 set_amd_program_number(int program)
855 amd_program_number = program;
860 * Release the controlling tty of the process pid.
862 * Algorithm: try these in order, if available, until one of them
863 * succeeds: setsid(), ioctl(fd, TIOCNOTTY, 0).
864 * Do not use setpgid(): on some OSs it may release the controlling tty,
865 * even if the man page does not mention it, but on other OSs it does not.
866 * Also avoid setpgrp(): it works on some systems, and on others it is
867 * identical to setpgid().
869 void
870 amu_release_controlling_tty(void)
872 #ifdef TIOCNOTTY
873 int fd;
874 #endif /* TIOCNOTTY */
876 #ifdef HAVE_SETSID
877 /* XXX: one day maybe use vhangup(2) */
878 if (setsid() < 0) {
879 plog(XLOG_WARNING, "Could not release controlling tty using setsid(): %m");
880 } else {
881 plog(XLOG_INFO, "released controlling tty using setsid()");
882 return;
884 #endif /* HAVE_SETSID */
886 #ifdef TIOCNOTTY
887 fd = open("/dev/tty", O_RDWR);
888 if (fd < 0) {
889 /* not an error if already no controlling tty */
890 if (errno != ENXIO)
891 plog(XLOG_WARNING, "Could not open controlling tty: %m");
892 } else {
893 if (ioctl(fd, TIOCNOTTY, 0) < 0 && errno != ENOTTY)
894 plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
895 else
896 plog(XLOG_INFO, "released controlling tty using ioctl(TIOCNOTTY)");
897 close(fd);
899 return;
900 #endif /* not TIOCNOTTY */
902 plog(XLOG_ERROR, "unable to release controlling tty");