/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: 2024-09-09 04:24:39 UTC
  • Revision ID: teddy@recompile.se-20240909042439-j85mr20uli2hnyis
Eliminate compiler warnings

Many programs use nested functions, which now result in a linker
warning about executable stack.  Hide this warning.  Also, rewrite a
loop in the plymouth plugin to avoid warning about signed overflow.
This change also makes the plugin pick the alphabetically first
process entry instead of the last, in case many plymouth processes are
found (which should be unlikely).

* Makefile (plugin-runner, dracut-module/password-agent,
  plugins.d/password-prompt, plugins.d/mandos-client,
  plugins.d/plymouth): New target; set LDFLAGS to add "-Xlinker
  --no-warn-execstack".
* plugins.d/plymouth.c (get_pid): When no pid files are found, and we
  are looking through the process list, go though it from the start
  instead of from the end, i.e. in normal alphabetical order and not
  in reverse order.

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