/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/plymouth.c

  • Committer: Teddy Hogeborn
  • Date: 2019-07-29 16:35:53 UTC
  • Revision ID: teddy@recompile.se-20190729163553-1i442i2cbx64c537
Make tests and man page examples match

Make the tests test_manual_page_example[1-5] match exactly what is
written in the manual page, and add comments to manual page as
reminders to keep tests and manual page examples in sync.

* mandos-ctl (Test_commands_from_options.test_manual_page_example_1):
  Remove "--verbose" option, since the manual does not have it as the
  first example, and change assertion to match.
* mandos-ctl.xml (EXAMPLE): Add comments to all examples documenting
  which test function they correspond to.  Also remove unnecessary
  quotes from option arguments in fourth example, and clarify language
  slightly in fifth example.

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
 
 
26
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
 
27
#include <signal.h>             /* sig_atomic_t, struct sigaction,
 
28
                                   sigemptyset(), sigaddset(), SIGINT,
 
29
                                   SIGHUP, SIGTERM, sigaction(),
 
30
                                   kill(), SIG_IGN */
 
31
#include <stdbool.h>            /* bool, false, true */
 
32
#include <fcntl.h>              /* open(), O_RDONLY */
 
33
#include <iso646.h>             /* and, or, not*/
 
34
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct
 
35
                                   dirent, waitpid() */
 
36
#include <sys/wait.h>           /* waitpid() */
 
37
#include <stddef.h>             /* NULL */
 
38
#include <string.h>             /* strchr(), memcmp() */
 
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(),
 
44
                                   STDERR_FILENO, execv(), access() */
 
45
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
 
46
                                   EXIT_SUCCESS, malloc(), _exit(),
 
47
                                   getenv() */
 
48
#include <dirent.h>             /* scandir(), alphasort() */
 
49
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
 
50
#include <sys/stat.h>           /* struct stat, lstat() */
 
51
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
 
52
#include <error.h>              /* error() */
 
53
#include <errno.h>              /* TEMP_FAILURE_RETRY */
 
54
#include <argz.h>               /* argz_count(), argz_extract() */
 
55
#include <stdarg.h>             /* va_list, va_start(), ... */
 
56
#include <argp.h>
 
57
 
 
58
sig_atomic_t interrupted_by_signal = 0;
 
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
 
 
69
const char plymouth_path[] = "/bin/plymouth";
 
70
const char plymouthd_path[] = "/sbin/plymouthd";
 
71
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
 
72
                                        "--mode=boot",
 
73
                                        "--attach-to-session",
 
74
                                        NULL };
 
75
bool debug = false;
 
76
 
 
77
static void termination_handler(__attribute__((unused))int signum){
 
78
  if(interrupted_by_signal){
 
79
    return;
 
80
  }
 
81
  interrupted_by_signal = 1;
 
82
}
 
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
 
 
116
/* Create prompt string */
 
117
char *makeprompt(void){
 
118
  int ret = 0;
 
119
  char *prompt;
 
120
  const char *const cryptsource = getenv("cryptsource");
 
121
  const char *const crypttarget = getenv("crypttarget");
 
122
  const char prompt_start[] = "Unlocking the disk";
 
123
  const char prompt_end[] = "Enter passphrase";
 
124
  
 
125
  if(cryptsource == NULL){
 
126
    if(crypttarget == NULL){
 
127
      ret = asprintf(&prompt, "%s\n%s", prompt_start, prompt_end);
 
128
    } else {
 
129
      ret = asprintf(&prompt, "%s (%s)\n%s", prompt_start,
 
130
                     crypttarget, prompt_end);
 
131
    }
 
132
  } else {
 
133
    if(crypttarget == NULL){
 
134
      ret = asprintf(&prompt, "%s %s\n%s", prompt_start, cryptsource,
 
135
                     prompt_end);
 
136
    } else {
 
137
      ret = asprintf(&prompt, "%s %s (%s)\n%s", prompt_start,
 
138
                     cryptsource, crypttarget, prompt_end);
 
139
    }
 
140
  }
 
141
  if(ret == -1){
 
142
    return NULL;
 
143
  }
 
144
  return prompt;
 
145
}
 
146
 
 
147
void kill_and_wait(pid_t pid){
 
148
  TEMP_FAILURE_RETRY(kill(pid, SIGTERM));
 
149
  TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
 
150
}
 
151
 
 
152
bool become_a_daemon(void){
 
153
  int ret = setuid(geteuid());
 
154
  if(ret == -1){
 
155
    error_plus(0, errno, "setuid");
 
156
  }
 
157
    
 
158
  setsid();
 
159
  ret = chdir("/");
 
160
  if(ret == -1){
 
161
    error_plus(0, errno, "chdir");
 
162
    return false;
 
163
  }
 
164
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
 
165
  if(ret == -1){
 
166
    error_plus(0, errno, "dup2");
 
167
    return false;
 
168
  }
 
169
  return true;
 
170
}
 
171
 
 
172
__attribute__((nonnull (2, 3)))
 
173
bool exec_and_wait(pid_t *pid_return, const char *path,
 
174
                   const char * const * const argv, bool interruptable,
 
175
                   bool daemonize){
 
176
  int status;
 
177
  int ret;
 
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
 
 
186
  pid = fork();
 
187
  if(pid == -1){
 
188
    error_plus(0, errno, "fork");
 
189
    return false;
 
190
  }
 
191
  if(pid == 0){
 
192
    /* Child */
 
193
    if(daemonize){
 
194
      if(not become_a_daemon()){
 
195
        _exit(EX_OSERR);
 
196
      }
 
197
    }
 
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;
 
205
    int i = 0;
 
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");
 
210
        free(new_argv);
 
211
        _exit(EX_OSERR);
 
212
      }
 
213
      new_argv = tmp;
 
214
      new_argv[i] = strdup(argv[i]);
 
215
    }
 
216
    new_argv[i] = NULL;
 
217
    
 
218
    execv(path, (char *const *)new_argv);
 
219
    error_plus(0, errno, "execv");
 
220
    _exit(EXIT_FAILURE);
 
221
  }
 
222
  if(pid_return != NULL){
 
223
    *pid_return = pid;
 
224
  }
 
225
  do {
 
226
    ret = waitpid(pid, &status, 0);
 
227
  } while(ret == -1 and errno == EINTR
 
228
          and ((not interrupted_by_signal)
 
229
               or (not interruptable)));
 
230
  if(interrupted_by_signal and interruptable){
 
231
    if(debug){
 
232
      fprintf_plus(stderr, "Interrupted by signal\n");
 
233
    }
 
234
    return false;
 
235
  }
 
236
  if(ret == -1){
 
237
    error_plus(0, errno, "waitpid");
 
238
    return false;
 
239
  }
 
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)){
 
250
    return true;
 
251
  }
 
252
  return false;
 
253
}
 
254
 
 
255
__attribute__((nonnull))
 
256
int is_plymouth(const struct dirent *proc_entry){
 
257
  int ret;
 
258
  {
 
259
    uintmax_t proc_id;
 
260
    char *tmp;
 
261
    errno = 0;
 
262
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
 
263
 
 
264
    if(errno != 0 or *tmp != '\0'
 
265
       or proc_id != (uintmax_t)((pid_t)proc_id)){
 
266
      return 0;
 
267
    }
 
268
  }
 
269
  char exe_target[sizeof(plymouthd_path)];
 
270
  char *exe_link;
 
271
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
 
272
  if(ret == -1){
 
273
    error_plus(0, errno, "asprintf");
 
274
    return 0;
 
275
  }
 
276
  
 
277
  struct stat exe_stat;
 
278
  ret = lstat(exe_link, &exe_stat);
 
279
  if(ret == -1){
 
280
    free(exe_link);
 
281
    if(errno != ENOENT){
 
282
      error_plus(0, errno, "lstat");
 
283
    }
 
284
    return 0;
 
285
  }
 
286
  
 
287
  if(not S_ISLNK(exe_stat.st_mode)
 
288
     or exe_stat.st_uid != 0
 
289
     or exe_stat.st_gid != 0){
 
290
    free(exe_link);
 
291
    return 0;
 
292
  }
 
293
  
 
294
  ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
 
295
  free(exe_link);
 
296
  if((sret != (ssize_t)sizeof(plymouthd_path)-1) or
 
297
      (memcmp(plymouthd_path, exe_target,
 
298
              sizeof(plymouthd_path)-1) != 0)){
 
299
    return 0;
 
300
  }
 
301
  return 1;
 
302
}
 
303
 
 
304
pid_t get_pid(void){
 
305
  int ret;
 
306
  uintmax_t proc_id = 0;
 
307
  FILE *pidfile = fopen(plymouth_pid, "r");
 
308
  /* Try the new pid file location */
 
309
  if(pidfile != NULL){
 
310
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
 
311
    if(ret != 1){
 
312
      proc_id = 0;
 
313
    }
 
314
    fclose(pidfile);
 
315
  }
 
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;
 
341
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
 
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);
 
359
  }
 
360
  pid_t pid;
 
361
  pid = (pid_t)proc_id;
 
362
  if((uintmax_t)pid == proc_id){
 
363
    return pid;
 
364
  }
 
365
  
 
366
  return 0;
 
367
}
 
368
 
 
369
char **getargv(pid_t pid){
 
370
  int cl_fd;
 
371
  char *cmdline_filename;
 
372
  ssize_t sret;
 
373
  int ret;
 
374
  
 
375
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
 
376
                 (uintmax_t)pid);
 
377
  if(ret == -1){
 
378
    error_plus(0, errno, "asprintf");
 
379
    return NULL;
 
380
  }
 
381
  
 
382
  /* Open /proc/<pid>/cmdline  */
 
383
  cl_fd = open(cmdline_filename, O_RDONLY);
 
384
  free(cmdline_filename);
 
385
  if(cl_fd == -1){
 
386
    error_plus(0, errno, "open");
 
387
    return NULL;
 
388
  }
 
389
  
 
390
  size_t cmdline_allocated = 0;
 
391
  size_t cmdline_len = 0;
 
392
  char *cmdline = NULL;
 
393
  char *tmp;
 
394
  const size_t blocksize = 1024;
 
395
  do {
 
396
    /* Allocate more space? */
 
397
    if(cmdline_len + blocksize > cmdline_allocated){
 
398
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
 
399
      if(tmp == NULL){
 
400
        error_plus(0, errno, "realloc");
 
401
        free(cmdline);
 
402
        close(cl_fd);
 
403
        return NULL;
 
404
      }
 
405
      cmdline = tmp;
 
406
      cmdline_allocated += blocksize;
 
407
    }
 
408
    
 
409
    /* Read data */
 
410
    sret = read(cl_fd, cmdline + cmdline_len,
 
411
                cmdline_allocated - cmdline_len);
 
412
    if(sret == -1){
 
413
      error_plus(0, errno, "read");
 
414
      free(cmdline);
 
415
      close(cl_fd);
 
416
      return NULL;
 
417
    }
 
418
    cmdline_len += (size_t)sret;
 
419
  } while(sret != 0);
 
420
  ret = close(cl_fd);
 
421
  if(ret == -1){
 
422
    error_plus(0, errno, "close");
 
423
    free(cmdline);
 
424
    return NULL;
 
425
  }
 
426
  
 
427
  /* we got cmdline and cmdline_len, ignore rest... */
 
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;
 
434
  }
 
435
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
 
436
  return argv;
 
437
}
 
438
 
 
439
int main(__attribute__((unused))int argc,
 
440
         __attribute__((unused))char **argv){
 
441
  char *prompt = NULL;
 
442
  char *prompt_arg;
 
443
  pid_t plymouth_command_pid;
 
444
  int ret;
 
445
  bool bret;
 
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
  
 
495
  /* test -x /bin/plymouth */
 
496
  ret = access(plymouth_path, X_OK);
 
497
  if(ret == -1){
 
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);
 
505
  }
 
506
  
 
507
  { /* Add signal handlers */
 
508
    struct sigaction old_action,
 
509
      new_action = { .sa_handler = termination_handler,
 
510
                     .sa_flags = 0 };
 
511
    sigemptyset(&new_action.sa_mask);
 
512
    for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 };
 
513
        *sig != 0; sig++){
 
514
      ret = sigaddset(&new_action.sa_mask, *sig);
 
515
      if(ret == -1){
 
516
        error_plus(EX_OSERR, errno, "sigaddset");
 
517
      }
 
518
      ret = sigaction(*sig, NULL, &old_action);
 
519
      if(ret == -1){
 
520
        error_plus(EX_OSERR, errno, "sigaction");
 
521
      }
 
522
      if(old_action.sa_handler != SIG_IGN){
 
523
        ret = sigaction(*sig, &new_action, NULL);
 
524
        if(ret == -1){
 
525
          error_plus(EX_OSERR, errno, "sigaction");
 
526
        }
 
527
      }
 
528
    }
 
529
  }
 
530
  
 
531
  /* plymouth --ping */
 
532
  bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
 
533
                       (const char *[])
 
534
                       { plymouth_path, "--ping", NULL },
 
535
                       true, false);
 
536
  if(not bret){
 
537
    if(interrupted_by_signal){
 
538
      kill_and_wait(plymouth_command_pid);
 
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);
 
547
  }
 
548
  
 
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
  }
 
556
  if(ret == -1){
 
557
    error_plus(EX_OSERR, errno, "asprintf");
 
558
  }
 
559
  
 
560
  /* plymouth ask-for-password --prompt="$prompt" */
 
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 },
 
568
                       true, false);
 
569
  free(prompt_arg);
 
570
  if(bret){
 
571
    exit(EXIT_SUCCESS);
 
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);
 
578
  
 
579
  char **plymouthd_argv = NULL;
 
580
  pid_t pid = get_pid();
 
581
  if(pid == 0){
 
582
    error_plus(0, 0, "plymouthd pid not found");
 
583
  } else {
 
584
    plymouthd_argv = getargv(pid);
 
585
  }
 
586
  
 
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);
 
612
  exit(EXIT_FAILURE);
 
613
}