sort out some prototypes, put them where they belong.
[apps/madmutt.git] / lib-sys / unix.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5  *
6  * This file is part of mutt-ng, see http://www.muttng.org/.
7  * It's licensed under the GNU General Public License,
8  * please see the file GPL in the top level source directory.
9  */
10
11 #include <errno.h>
12 #include <ctype.h>
13 #include <stdlib.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16
17 #include <lib-lib/lib-lib.h>
18
19 #include "unix.h"
20 #include "mutt_signal.h"
21
22 #include <imap/imap.h> /* for imap_wait_keepalive EEEEK */
23
24 /* Extract the real name from /etc/passwd's GECOS field.
25  * When set, honor the regular expression in rx,
26  * otherwise assume that the GECOS field is a comma-separated list.
27  * Replace "&" by a capitalized version of the user's login name.
28  */
29 ssize_t mutt_gecos_name(char *dst, ssize_t n, struct passwd *pw, regex_t *rx)
30 {
31     const char *p, *end;
32     ssize_t len;
33
34     *dst = '\0';
35     len  = 0;
36
37     if (!pw->pw_gecos)
38         return 0;
39
40     if (rx) {
41         regmatch_t pat_match[1];
42
43         if (regexec(rx, pw->pw_gecos, 1, pat_match, 0)) {
44             return 0;
45         }
46
47         p   = pw->pw_gecos + pat_match[0].rm_so;
48         end = pw->pw_gecos + pat_match[0].rm_so;
49     } else {
50         p   = pw->pw_gecos;
51         end = m_strchrnul(pw->pw_gecos, ',');
52     }
53
54     for (;;) {
55         const char *q = MIN(end, m_strchrnul(p, '&'));
56
57         len += m_strncpy(dst + len, n - len, p, q - p);
58         p = q + 1;
59
60         if (!p[-1] || p >= end)
61             break;
62
63         /* p[0] == '&' */
64         len += m_strcpy(dst + len, n - len, pw->pw_name);
65     }
66
67     return len;
68 }
69
70 int _mutt_system(const char *cmd, int flags)
71 {
72     int rc = -1;
73     struct sigaction act;
74     struct sigaction oldtstp;
75     struct sigaction oldcont;
76     sigset_t set;
77     pid_t pid;
78
79     if (m_strisempty(cmd))
80         return 0;
81
82     /* must ignore SIGINT and SIGQUIT */
83     mutt_block_signals_system();
84
85     /* also don't want to be stopped right now */
86     if (flags & M_DETACH_PROCESS) {
87         sigemptyset(&set);
88         sigaddset(&set, SIGTSTP);
89         sigprocmask(SIG_BLOCK, &set, NULL);
90     } else {
91         act.sa_handler = SIG_DFL;
92         /* we want to restart the waitpid() below */
93 #ifdef SA_RESTART
94         act.sa_flags = SA_RESTART;
95 #endif
96         sigemptyset(&act.sa_mask);
97         sigaction(SIGTSTP, &act, &oldtstp);
98         sigaction(SIGCONT, &act, &oldcont);
99     }
100
101     pid = fork ();
102     if (pid == 0) {
103         act.sa_flags = 0;
104
105         if (flags & M_DETACH_PROCESS) {
106             /* give up controlling terminal */
107             setsid();
108
109             switch (fork()) {
110                 int fd, nb_fds;
111
112               case 0:
113                 nb_fds = getdtablesize();
114                 for (fd = 0; fd < nb_fds; fd++) {
115                     close(fd);
116                 }
117                 chdir ("/");
118                 act.sa_handler = SIG_DFL;
119                 sigaction(SIGCHLD, &act, NULL);
120                 break;
121
122               case -1:
123                 _exit(127);
124
125               default:
126                 _exit(0);
127             }
128         }
129
130         /* reset signals for the child; not really needed, but... */
131         mutt_unblock_signals_system(0);
132         act.sa_handler = SIG_DFL;
133         act.sa_flags = 0;
134         sigemptyset(&act.sa_mask);
135         sigaction(SIGTERM, &act, NULL);
136         sigaction(SIGTSTP, &act, NULL);
137         sigaction(SIGCONT, &act, NULL);
138
139         execl("/bin/sh", "sh", "-c", cmd, NULL);
140         _exit(127);                /* execl error */
141     } else
142     if (pid != -1) {
143         rc = imap_wait_keepalive(pid);
144     }
145
146     sigaction(SIGCONT, &oldcont, NULL);
147     sigaction(SIGTSTP, &oldtstp, NULL);
148
149     /* reset SIGINT, SIGQUIT and SIGCHLD */
150     mutt_unblock_signals_system(1);
151     if (flags & M_DETACH_PROCESS) {
152         sigprocmask (SIG_UNBLOCK, &set, NULL);
153     }
154
155     return (pid > 0 && WIFEXITED(rc)) ? WEXITSTATUS(rc) : -1;
156 }
157
158 int getdnsdomainname(char *s, ssize_t n)
159 {
160     char tmp[1024];
161     FILE *f;
162
163     if ((f = fopen("/etc/resolv.conf", "r")) == NULL)
164         return -1;
165
166     while (fgets(tmp, sizeof(tmp), f)) {
167         const char *p = skipspaces(tmp);
168
169         if (m_strncmp("domain", p, 6) && m_strncmp("search", p, 6))
170             continue;
171
172         p += 6;
173
174         while (*p) {
175             int trailing_dot;
176             const char *q;
177
178             p = skipspaces(p);
179             q = m_strnextsp(p);
180
181             trailing_dot = q[-1] == '.';
182             if (!trailing_dot || q > p + 1) {
183                 m_strncpy(s, n, p, q - trailing_dot - p);
184                 safe_fclose(&f);
185                 return 0;
186             }
187
188             p = q;
189         }
190     }
191
192     safe_fclose (&f);
193     return -1;
194 }