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