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