/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to plugins.d/plymouth.c

  • Committer: Teddy Hogeborn
  • Date: 2019-08-02 22:16:53 UTC
  • mto: This revision was merged to the branch mainline in revision 386.
  • Revision ID: teddy@recompile.se-20190802221653-ic1iko9hbefzwsk7
Fix bug in server Debian package: Fails to start on first install

There has been a very long-standing bug where installation of the
server (the "mandos" Debian package) would fail to start the server
properly right after installation.  It would work on manual (re)start
after installation, or after reboot, and even after package purge and
reinstall, it would then work the first time.  The problem, it turns
out, is when the new "_mandos" user (and corresponding group) is
created, the D-Bus server is not reloaded, and is therefore not aware
of that user, and does not recognize the user and group name in the
/etc/dbus-1/system.d/mandos.conf file.  The Mandos server, when it
tries to start and access the D-Bus, is then not permitted to connect
to its D-Bus bus name, and disables D-Bus use as a fallback measure;
i.e. the server works, but it is not controllable via D-Bus commands
(via mandos-ctl or mandos-monitor).  The next time the D-Bus daemon is
reloaded for any reason, the new user & group would become visible to
the D-Bus daemon and after that, any restart of the Mandos server
would succeed and it would bind to its D-Bus name properly, and
thereby be visible and controllable by mandos-ctl & mandos-monitor.
This was mostly invisible when using sysvinit, but systemd makes the
problem visible since the systemd service file for the Mandos server
is configured to not consider the Mandos server "started" until the
D-Bus name has been bound; this makes the starting of the service wait
for 90 seconds and then fail with a timeout error.

Fixing this should also make the Debian CI autopkgtest tests work.

* debian/mandos.postinst (configure): After creating (or renaming)
                                      user & group, reload D-Bus
                                      daemon (if present).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*  -*- coding: utf-8 -*- */
 
2
/*
 
3
 * Plymouth - Read a password from Plymouth and output it
 
4
 * 
 
5
 * Copyright © 2010-2019 Teddy Hogeborn
 
6
 * Copyright © 2010-2019 Björn Påhlsson
 
7
 * 
 
8
 * This file is part of Mandos.
 
9
 * 
 
10
 * Mandos is free software: you can redistribute it and/or modify it
 
11
 * under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 * 
 
15
 * Mandos is distributed in the hope that it will be useful, but
 
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * General Public License for more details.
 
19
 * 
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
22
 * 
 
23
 * Contact the authors at <mandos@recompile.se>.
 
24
 */
 
25
 
1
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
2
27
#include <signal.h>             /* sig_atomic_t, struct sigaction,
3
28
                                   sigemptyset(), sigaddset(), SIGINT,
6
31
#include <stdbool.h>            /* bool, false, true */
7
32
#include <fcntl.h>              /* open(), O_RDONLY */
8
33
#include <iso646.h>             /* and, or, not*/
9
 
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct dirent,
10
 
                                   waitpid() */
 
34
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct
 
35
                                   dirent, waitpid() */
11
36
#include <sys/wait.h>           /* waitpid() */
12
37
#include <stddef.h>             /* NULL */
13
38
#include <string.h>             /* strchr(), memcmp() */
14
 
#include <stdio.h>              /* asprintf(), perror(), fopen(), fscanf() */
15
 
#include <unistd.h>             /* close(), readlink(), read(), fork()
16
 
                                   setsid(), chdir(), dup2()
 
39
#include <stdio.h>              /* asprintf(), perror(), fopen(),
 
40
                                   fscanf(), vasprintf(), fprintf(),
 
41
                                   vfprintf() */
 
42
#include <unistd.h>             /* close(), readlink(), read(),
 
43
                                   fork(), setsid(), chdir(), dup2(),
17
44
                                   STDERR_FILENO, execv(), access() */
18
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
19
46
                                   EXIT_SUCCESS, malloc(), _exit(),
21
48
#include <dirent.h>             /* scandir(), alphasort() */
22
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
23
50
#include <sys/stat.h>           /* struct stat, lstat() */
24
 
#include <sysexits.h>           /* EX_OSERR */
 
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
25
52
#include <error.h>              /* error() */
26
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
27
 
#include <stdarg.h>
 
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
 
56
#include <argp.h>
28
57
 
29
58
sig_atomic_t interrupted_by_signal = 0;
30
 
const char plymouth_pid[] = "/dev/.initramfs/plymouth.pid";
 
59
const char *argp_program_version = "plymouth " VERSION;
 
60
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
61
 
 
62
/* Used by Ubuntu 11.04 (Natty Narwahl) */
 
63
const char plymouth_old_old_pid[] = "/dev/.initramfs/plymouth.pid";
 
64
/* Used by Ubuntu 11.10 (Oneiric Ocelot) */
 
65
const char plymouth_old_pid[] = "/run/initramfs/plymouth.pid";
 
66
/* Used by Debian 9 (stretch) */
 
67
const char plymouth_pid[] = "/run/plymouth/pid";
 
68
 
31
69
const char plymouth_path[] = "/bin/plymouth";
32
70
const char plymouthd_path[] = "/sbin/plymouthd";
33
 
const char *plymouthd_default_argv[] = {"/sbin/plymouthd", "--mode=boot",
 
71
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
 
72
                                        "--mode=boot",
34
73
                                        "--attach-to-session",
35
 
                                        "--pid-file=/dev/.initramfs/plymouth.pid",
36
74
                                        NULL };
 
75
bool debug = false;
37
76
 
38
77
static void termination_handler(__attribute__((unused))int signum){
39
78
  if(interrupted_by_signal){
42
81
  interrupted_by_signal = 1;
43
82
}
44
83
 
 
84
__attribute__((format (gnu_printf, 2, 3), nonnull))
 
85
int fprintf_plus(FILE *stream, const char *format, ...){
 
86
  va_list ap;
 
87
  va_start (ap, format);
 
88
  fprintf(stream, "Mandos plugin %s: ", program_invocation_short_name);
 
89
  return vfprintf(stream, format, ap);
 
90
}
 
91
 
 
92
/* Function to use when printing errors */
 
93
__attribute__((format (gnu_printf, 3, 4)))
 
94
void error_plus(int status, int errnum, const char *formatstring,
 
95
                ...){
 
96
  va_list ap;
 
97
  char *text;
 
98
  int ret;
 
99
  
 
100
  va_start(ap, formatstring);
 
101
  ret = vasprintf(&text, formatstring, ap);
 
102
  if(ret == -1){
 
103
    fprintf(stderr, "Mandos plugin %s: ",
 
104
            program_invocation_short_name);
 
105
    vfprintf(stderr, formatstring, ap);
 
106
    fprintf(stderr, ": ");
 
107
    fprintf(stderr, "%s\n", strerror(errnum));
 
108
    error(status, errno, "vasprintf while printing error");
 
109
    return;
 
110
  }
 
111
  fprintf(stderr, "Mandos plugin ");
 
112
  error(status, errnum, "%s", text);
 
113
  free(text);
 
114
}
 
115
 
45
116
/* Create prompt string */
46
117
char *makeprompt(void){
47
118
  int ret = 0;
48
119
  char *prompt;
49
120
  const char *const cryptsource = getenv("cryptsource");
50
121
  const char *const crypttarget = getenv("crypttarget");
51
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
 
122
  const char prompt_start[] = "Unlocking the disk";
 
123
  const char prompt_end[] = "Enter passphrase";
52
124
  
53
125
  if(cryptsource == NULL){
54
126
    if(crypttarget == NULL){
55
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
 
127
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
56
128
    } else {
57
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
58
 
                     crypttarget);
 
129
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
 
130
                     crypttarget, prompt_end);
59
131
    }
60
132
  } else {
61
133
    if(crypttarget == NULL){
62
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
 
134
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
 
135
                     prompt_end);
63
136
    } else {
64
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
65
 
                     cryptsource, crypttarget);
 
137
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
 
138
                     cryptsource, crypttarget, prompt_end);
66
139
    }
67
140
  }
68
141
  if(ret == -1){
79
152
bool become_a_daemon(void){
80
153
  int ret = setuid(geteuid());
81
154
  if(ret == -1){
82
 
    error(0, errno, "setuid");
 
155
    error_plus(0, errno, "setuid");
83
156
  }
84
157
    
85
158
  setsid();
86
159
  ret = chdir("/");
87
160
  if(ret == -1){
88
 
    error(0, errno, "chdir");
 
161
    error_plus(0, errno, "chdir");
89
162
    return false;
90
163
  }
91
164
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
92
165
  if(ret == -1){
93
 
    error(0, errno, "dup2");
 
166
    error_plus(0, errno, "dup2");
94
167
    return false;
95
168
  }
96
169
  return true;
97
170
}
98
171
 
 
172
__attribute__((nonnull (2, 3)))
99
173
bool exec_and_wait(pid_t *pid_return, const char *path,
100
 
                   const char **argv, bool interruptable,
 
174
                   const char * const * const argv, bool interruptable,
101
175
                   bool daemonize){
102
176
  int status;
103
177
  int ret;
104
178
  pid_t pid;
 
179
  if(debug){
 
180
    for(const char * const *arg = argv; *arg != NULL; arg++){
 
181
      fprintf_plus(stderr, "exec_and_wait arg: %s\n", *arg);
 
182
    }
 
183
    fprintf_plus(stderr, "exec_and_wait end of args\n");
 
184
  }
 
185
 
105
186
  pid = fork();
106
187
  if(pid == -1){
107
 
    error(0, errno, "fork");
 
188
    error_plus(0, errno, "fork");
108
189
    return false;
109
190
  }
110
191
  if(pid == 0){
114
195
        _exit(EX_OSERR);
115
196
      }
116
197
    }
117
 
 
118
 
    char **new_argv = NULL;
119
 
    char *tmp;
 
198
    
 
199
    char **new_argv = malloc(sizeof(const char *));
 
200
    if(new_argv == NULL){
 
201
      error_plus(0, errno, "malloc");
 
202
      _exit(EX_OSERR);
 
203
    }
 
204
    char **tmp;
120
205
    int i = 0;
121
 
    for (; argv[i]!=(char *)NULL; i++){
122
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
123
 
      if (tmp == NULL){
124
 
        error(0, errno, "realloc");
 
206
    for (; argv[i] != NULL; i++){
 
207
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 2));
 
208
      if(tmp == NULL){
 
209
        error_plus(0, errno, "realloc");
125
210
        free(new_argv);
126
 
        _exit(EXIT_FAILURE);
 
211
        _exit(EX_OSERR);
127
212
      }
128
 
      new_argv = (char **)tmp;
 
213
      new_argv = tmp;
129
214
      new_argv[i] = strdup(argv[i]);
130
215
    }
131
 
    new_argv[i] = (char *) NULL;
 
216
    new_argv[i] = NULL;
132
217
    
133
218
    execv(path, (char *const *)new_argv);
134
 
    error(0, errno, "execv");
 
219
    error_plus(0, errno, "execv");
135
220
    _exit(EXIT_FAILURE);
136
221
  }
137
222
  if(pid_return != NULL){
143
228
          and ((not interrupted_by_signal)
144
229
               or (not interruptable)));
145
230
  if(interrupted_by_signal and interruptable){
 
231
    if(debug){
 
232
      fprintf_plus(stderr, "Interrupted by signal\n");
 
233
    }
146
234
    return false;
147
235
  }
148
236
  if(ret == -1){
149
 
    error(0, errno, "waitpid");
 
237
    error_plus(0, errno, "waitpid");
150
238
    return false;
151
239
  }
152
 
  if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
 
240
  if(debug){
 
241
    if(WIFEXITED(status)){
 
242
      fprintf_plus(stderr, "exec_and_wait exited: %d\n",
 
243
                   WEXITSTATUS(status));
 
244
    } else if(WIFSIGNALED(status)) {
 
245
      fprintf_plus(stderr, "exec_and_wait signaled: %d\n",
 
246
                   WTERMSIG(status));
 
247
    }
 
248
  }
 
249
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
153
250
    return true;
154
251
  }
155
252
  return false;
156
253
}
157
254
 
 
255
__attribute__((nonnull))
158
256
int is_plymouth(const struct dirent *proc_entry){
159
257
  int ret;
160
258
  {
161
 
    uintmax_t maxvalue;
 
259
    uintmax_t proc_id;
162
260
    char *tmp;
163
261
    errno = 0;
164
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
262
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
165
263
 
166
 
    if(errno != 0 or *tmp != '\0' or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
264
    if(errno != 0 or *tmp != '\0'
 
265
       or proc_id != (uintmax_t)((pid_t)proc_id)){
167
266
      return 0;
168
267
    }
169
268
  }
170
 
  char exe_target[sizeof(plymouth_path)];
 
269
  char exe_target[sizeof(plymouthd_path)];
171
270
  char *exe_link;
172
271
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
173
272
  if(ret == -1){
174
 
    error(0, errno, "asprintf");
 
273
    error_plus(0, errno, "asprintf");
175
274
    return 0;
176
275
  }
177
 
 
 
276
  
178
277
  struct stat exe_stat;
179
278
  ret = lstat(exe_link, &exe_stat);
180
279
  if(ret == -1){
181
280
    free(exe_link);
182
281
    if(errno != ENOENT){
183
 
      error(0, errno, "lstat");
 
282
      error_plus(0, errno, "lstat");
184
283
    }
185
284
    return 0;
186
285
  }
191
290
    free(exe_link);
192
291
    return 0;
193
292
  }
194
 
 
 
293
  
195
294
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
196
295
  free(exe_link);
197
 
  if((sret != (ssize_t)sizeof(plymouth_path)-1) or
198
 
      (memcmp(plymouth_path, exe_target,
199
 
              sizeof(plymouth_path)-1) != 0)){
 
296
  if((sret != (ssize_t)sizeof(plymouthd_path)-1) or
 
297
      (memcmp(plymouthd_path, exe_target,
 
298
              sizeof(plymouthd_path)-1) != 0)){
200
299
    return 0;
201
300
  }
202
301
  return 1;
204
303
 
205
304
pid_t get_pid(void){
206
305
  int ret;
 
306
  uintmax_t proc_id = 0;
207
307
  FILE *pidfile = fopen(plymouth_pid, "r");
208
 
  uintmax_t maxvalue = 0;
 
308
  /* Try the new pid file location */
209
309
  if(pidfile != NULL){
210
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
310
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
211
311
    if(ret != 1){
212
 
      maxvalue = 0;
 
312
      proc_id = 0;
213
313
    }
214
314
    fclose(pidfile);
215
315
  }
216
 
  if(maxvalue == 0){
217
 
    struct dirent **direntries;
 
316
  /* Try the old pid file location */
 
317
  if(proc_id == 0){
 
318
    pidfile = fopen(plymouth_old_pid, "r");
 
319
    if(pidfile != NULL){
 
320
      ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
 
321
      if(ret != 1){
 
322
        proc_id = 0;
 
323
      }
 
324
      fclose(pidfile);
 
325
    }
 
326
  }
 
327
  /* Try the old old pid file location */
 
328
  if(proc_id == 0){
 
329
    pidfile = fopen(plymouth_old_old_pid, "r");
 
330
    if(pidfile != NULL){
 
331
      ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
 
332
      if(ret != 1){
 
333
        proc_id = 0;
 
334
      }
 
335
      fclose(pidfile);
 
336
    }
 
337
  }
 
338
  /* Look for a plymouth process */
 
339
  if(proc_id == 0){
 
340
    struct dirent **direntries = NULL;
218
341
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
219
 
    sscanf(direntries[0]->d_name, "%" SCNuMAX, &maxvalue);
 
342
    if(ret == -1){
 
343
      error_plus(0, errno, "scandir");
 
344
    }
 
345
    if(ret > 0){
 
346
      for(int i = ret-1; i >= 0; i--){
 
347
        if(proc_id == 0){
 
348
          ret = sscanf(direntries[i]->d_name, "%" SCNuMAX, &proc_id);
 
349
          if(ret < 0){
 
350
            error_plus(0, errno, "sscanf");
 
351
          }
 
352
        }
 
353
        free(direntries[i]);
 
354
      }
 
355
    }
 
356
    /* scandir might preallocate for this variable (man page unclear).
 
357
       even if ret == 0, therefore we need to free it. */
 
358
    free(direntries);
220
359
  }
221
360
  pid_t pid;
222
 
  pid = (pid_t)maxvalue;
223
 
  if((uintmax_t)pid == maxvalue){
 
361
  pid = (pid_t)proc_id;
 
362
  if((uintmax_t)pid == proc_id){
224
363
    return pid;
225
364
  }
226
365
  
227
366
  return 0;
228
367
}
229
368
 
230
 
const char **getargv(pid_t pid){
 
369
char **getargv(pid_t pid){
231
370
  int cl_fd;
232
371
  char *cmdline_filename;
233
372
  ssize_t sret;
236
375
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
237
376
                 (uintmax_t)pid);
238
377
  if(ret == -1){
239
 
    error(0, errno, "asprintf");
 
378
    error_plus(0, errno, "asprintf");
240
379
    return NULL;
241
380
  }
242
381
  
244
383
  cl_fd = open(cmdline_filename, O_RDONLY);
245
384
  free(cmdline_filename);
246
385
  if(cl_fd == -1){
247
 
    error(0, errno, "open");
 
386
    error_plus(0, errno, "open");
248
387
    return NULL;
249
388
  }
250
389
  
258
397
    if(cmdline_len + blocksize > cmdline_allocated){
259
398
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
260
399
      if(tmp == NULL){
261
 
        error(0, errno, "realloc");
 
400
        error_plus(0, errno, "realloc");
262
401
        free(cmdline);
263
402
        close(cl_fd);
264
403
        return NULL;
271
410
    sret = read(cl_fd, cmdline + cmdline_len,
272
411
                cmdline_allocated - cmdline_len);
273
412
    if(sret == -1){
274
 
      error(0, errno, "read");
 
413
      error_plus(0, errno, "read");
275
414
      free(cmdline);
276
415
      close(cl_fd);
277
416
      return NULL;
280
419
  } while(sret != 0);
281
420
  ret = close(cl_fd);
282
421
  if(ret == -1){
283
 
    error(0, errno, "close");
 
422
    error_plus(0, errno, "close");
284
423
    free(cmdline);
285
424
    return NULL;
286
425
  }
287
426
  
288
427
  /* we got cmdline and cmdline_len, ignore rest... */
289
 
  const char **argv = NULL;
290
 
  size_t argv_size = 0;
291
 
  for(char *arg = cmdline; arg-cmdline < (ssize_t)cmdline_len;
292
 
      arg = strchr(arg, '\0')+1){
293
 
    tmp = realloc(argv, ((++argv_size)+1)*sizeof(char *));
294
 
    if(tmp == NULL){
295
 
      error(0, errno, "realloc");
296
 
      free(argv);
297
 
      return NULL;
298
 
    }
299
 
    argv = (const char **)tmp;
300
 
    argv[argv_size-1] = arg;
 
428
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
 
429
                       * sizeof(char *)); /* Get number of args */
 
430
  if(argv == NULL){
 
431
    error_plus(0, errno, "argv = malloc()");
 
432
    free(cmdline);
 
433
    return NULL;
301
434
  }
302
 
  argv[argv_size] = NULL;
 
435
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
303
436
  return argv;
304
437
}
305
438
 
306
439
int main(__attribute__((unused))int argc,
307
440
         __attribute__((unused))char **argv){
308
 
  char *prompt;
 
441
  char *prompt = NULL;
309
442
  char *prompt_arg;
310
443
  pid_t plymouth_command_pid;
311
444
  int ret;
312
445
  bool bret;
313
446
 
 
447
  {
 
448
    struct argp_option options[] = {
 
449
      { .name = "prompt", .key = 128, .arg = "PROMPT",
 
450
        .doc = "The prompt to show" },
 
451
      { .name = "debug", .key = 129,
 
452
        .doc = "Debug mode" },
 
453
      { .name = NULL }
 
454
    };
 
455
    
 
456
    __attribute__((nonnull(3)))
 
457
    error_t parse_opt (int key, char *arg, __attribute__((unused))
 
458
                       struct argp_state *state){
 
459
      errno = 0;
 
460
      switch (key){
 
461
      case 128:                 /* --prompt */
 
462
        prompt = arg;
 
463
        if(debug){
 
464
          fprintf_plus(stderr, "Custom prompt \"%s\"\n", prompt);
 
465
        }
 
466
        break;
 
467
      case 129:                 /* --debug */
 
468
        debug = true;
 
469
        break;
 
470
      default:
 
471
        return ARGP_ERR_UNKNOWN;
 
472
      }
 
473
      return errno;
 
474
    }
 
475
    
 
476
    struct argp argp = { .options = options, .parser = parse_opt,
 
477
                         .args_doc = "",
 
478
                         .doc = "Mandos plymouth -- Read and"
 
479
                         " output a password" };
 
480
    ret = argp_parse(&argp, argc, argv, ARGP_IN_ORDER, NULL, NULL);
 
481
    switch(ret){
 
482
    case 0:
 
483
      break;
 
484
    case ENOMEM:
 
485
    default:
 
486
      errno = ret;
 
487
      error_plus(0, errno, "argp_parse");
 
488
      return EX_OSERR;
 
489
    case EINVAL:
 
490
      error_plus(0, errno, "argp_parse");
 
491
      return EX_USAGE;
 
492
    }
 
493
  }
 
494
  
314
495
  /* test -x /bin/plymouth */
315
496
  ret = access(plymouth_path, X_OK);
316
497
  if(ret == -1){
317
 
    exit(EXIT_FAILURE);
 
498
    /* Plymouth is probably not installed.  Don't print an error
 
499
       message, just exit. */
 
500
    if(debug){
 
501
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
 
502
                   plymouth_path);
 
503
    }
 
504
    exit(EX_UNAVAILABLE);
318
505
  }
319
 
 
 
506
  
320
507
  { /* Add signal handlers */
321
508
    struct sigaction old_action,
322
509
      new_action = { .sa_handler = termination_handler,
323
510
                     .sa_flags = 0 };
324
511
    sigemptyset(&new_action.sa_mask);
325
 
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 }; *sig != 0; sig++){
 
512
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 };
 
513
        *sig != 0; sig++){
326
514
      ret = sigaddset(&new_action.sa_mask, *sig);
327
515
      if(ret == -1){
328
 
        error(0, errno, "sigaddset");
329
 
        exit(EX_OSERR);
 
516
        error_plus(EX_OSERR, errno, "sigaddset");
330
517
      }
331
518
      ret = sigaction(*sig, NULL, &old_action);
332
519
      if(ret == -1){
333
 
        error(0, errno, "sigaction");
334
 
        exit(EX_OSERR);
 
520
        error_plus(EX_OSERR, errno, "sigaction");
335
521
      }
336
522
      if(old_action.sa_handler != SIG_IGN){
337
523
        ret = sigaction(*sig, &new_action, NULL);
338
524
        if(ret == -1){
339
 
          error(0, errno, "sigaction");
340
 
          exit(EX_OSERR);
 
525
          error_plus(EX_OSERR, errno, "sigaction");
341
526
        }
342
527
      }
343
528
    }
344
529
  }
345
 
    
 
530
  
346
531
  /* plymouth --ping */
347
532
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
348
 
                       (const char *[]){ (const char *)plymouth_path, (const char *)"--ping", (const char *)NULL},
 
533
                       (const char *[])
 
534
                       { plymouth_path, "--ping", NULL },
349
535
                       true, false);
350
536
  if(not bret){
351
537
    if(interrupted_by_signal){
352
538
      kill_and_wait(plymouth_command_pid);
353
 
    }
354
 
    exit(EXIT_FAILURE);
 
539
      exit(EXIT_FAILURE);
 
540
    }
 
541
    /* Plymouth is probably not running.  Don't print an error
 
542
       message, just exit. */
 
543
    if(debug){
 
544
      fprintf_plus(stderr, "Plymouth not running\n");
 
545
    }
 
546
    exit(EX_UNAVAILABLE);
355
547
  }
356
548
  
357
 
  prompt = makeprompt();
358
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
359
 
  free(prompt);
 
549
  if(prompt != NULL){
 
550
    ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
 
551
  } else {
 
552
    char *made_prompt = makeprompt();
 
553
    ret = asprintf(&prompt_arg, "--prompt=%s", made_prompt);
 
554
    free(made_prompt);
 
555
  }
360
556
  if(ret == -1){
361
 
    error(0, errno, "asprintf");
362
 
    exit(EXIT_FAILURE);
 
557
    error_plus(EX_OSERR, errno, "asprintf");
363
558
  }
364
559
  
365
560
  /* plymouth ask-for-password --prompt="$prompt" */
366
 
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
367
 
                       (const char *[]){plymouth_path, "ask-for-password", prompt_arg, NULL},
 
561
  if(debug){
 
562
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
 
563
  }
 
564
  bret = exec_and_wait(&plymouth_command_pid,
 
565
                       plymouth_path, (const char *[])
 
566
                       { plymouth_path, "ask-for-password",
 
567
                           prompt_arg, NULL },
368
568
                       true, false);
369
569
  free(prompt_arg);
370
 
  if(not bret){
371
 
    if(interrupted_by_signal){
372
 
      kill_and_wait(plymouth_command_pid);
373
 
    } else {
374
 
      exit(EXIT_FAILURE);
375
 
    }
376
 
  }
377
 
  
378
570
  if(bret){
379
571
    exit(EXIT_SUCCESS);
380
572
  }
 
573
  if(not interrupted_by_signal){
 
574
    /* exec_and_wait failed for some other reason */
 
575
    exit(EXIT_FAILURE);
 
576
  }
 
577
  kill_and_wait(plymouth_command_pid);
381
578
  
382
 
  const char **plymouthd_argv = NULL;
 
579
  char **plymouthd_argv = NULL;
383
580
  pid_t pid = get_pid();
384
581
  if(pid == 0){
385
 
    error(0, 0, "plymouthd pid not found");
 
582
    error_plus(0, 0, "plymouthd pid not found");
386
583
  } else {
387
584
    plymouthd_argv = getargv(pid);
388
585
  }
389
 
  if(plymouthd_argv == NULL){
390
 
    plymouthd_argv = plymouthd_default_argv;
391
 
  }
392
586
  
393
 
  bret = exec_and_wait(NULL, plymouth_path,
394
 
                       (const char *[]){plymouth_path, "quit", NULL}, false, false);
395
 
  if(not bret){
396
 
    exit(EXIT_FAILURE);
397
 
  }
398
 
  bret = exec_and_wait(NULL, plymouthd_path, plymouthd_argv, false, true);
399
 
  if(not bret){
400
 
    exit(EXIT_FAILURE);
401
 
  }
402
 
  exec_and_wait(NULL, plymouth_path,
403
 
                (const char *[]){ plymouth_path, "show-splash", NULL }, false, false);
 
587
  bret = exec_and_wait(NULL, plymouth_path, (const char *[])
 
588
                       { plymouth_path, "quit", NULL },
 
589
                       false, false);
 
590
  if(not bret){
 
591
    if(plymouthd_argv != NULL){
 
592
      free(*plymouthd_argv);
 
593
      free(plymouthd_argv);
 
594
    }
 
595
    exit(EXIT_FAILURE);
 
596
  }
 
597
  bret = exec_and_wait(NULL, plymouthd_path,
 
598
                       (plymouthd_argv != NULL)
 
599
                       ? (const char * const *)plymouthd_argv
 
600
                       : plymouthd_default_argv,
 
601
                       false, true);
 
602
  if(plymouthd_argv != NULL){
 
603
    free(*plymouthd_argv);
 
604
    free(plymouthd_argv);
 
605
  }
 
606
  if(not bret){
 
607
    exit(EXIT_FAILURE);
 
608
  }
 
609
  exec_and_wait(NULL, plymouth_path, (const char *[])
 
610
                { plymouth_path, "show-splash", NULL },
 
611
                false, false);
404
612
  exit(EXIT_FAILURE);
405
613
}