/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:
2
2
/*
3
3
 * Plymouth - Read a password from Plymouth and output it
4
4
 * 
5
 
 * Copyright © 2010 Teddy Hogeborn
6
 
 * Copyright © 2010 Björn Påhlsson
7
 
 * 
8
 
 * This program is free software: you can redistribute it and/or
9
 
 * modify it under the terms of the GNU General Public License as
10
 
 * published by the Free Software Foundation, either version 3 of the
11
 
 * License, or (at your option) any later version.
12
 
 * 
13
 
 * This program is distributed in the hope that it will be useful, but
 
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
14
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
18
 * General Public License for more details.
17
19
 * 
18
20
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program.  If not, see
20
 
 * <http://www.gnu.org/licenses/>.
 
21
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
21
22
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
23
 * Contact the authors at <mandos@recompile.se>.
23
24
 */
24
25
 
25
 
#define _GNU_SOURCE             /* asprintf(), TEMP_FAILURE_RETRY() */
26
 
#include <signal.h>             /* sig_atomic_t, struct sigaction,
27
 
                                   sigemptyset(), sigaddset(), SIGINT,
28
 
                                   SIGHUP, SIGTERM, sigaction(),
29
 
                                   kill(), SIG_IGN */
 
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 */
30
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() */
31
73
#include <fcntl.h>              /* open(), O_RDONLY */
32
 
#include <iso646.h>             /* and, or, not*/
33
 
#include <sys/types.h>          /* size_t, ssize_t, pid_t, struct
34
 
                                   dirent, waitpid() */
35
 
#include <sys/wait.h>           /* waitpid() */
36
 
#include <stddef.h>             /* NULL */
37
 
#include <string.h>             /* strchr(), memcmp() */
38
 
#include <stdio.h>              /* asprintf(), perror(), fopen(),
39
 
                                   fscanf() */
40
 
#include <unistd.h>             /* close(), readlink(), read(),
41
 
                                   fork(), setsid(), chdir(), dup2(),
42
 
                                   STDERR_FILENO, execv(), access() */
43
 
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
44
 
                                   EXIT_SUCCESS, malloc(), _exit(),
45
 
                                   getenv() */
46
 
#include <dirent.h>             /* scandir(), alphasort() */
47
 
#include <inttypes.h>           /* intmax_t, strtoumax(), SCNuMAX */
48
 
#include <sys/stat.h>           /* struct stat, lstat() */
49
 
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
50
 
#include <error.h>              /* error() */
51
 
#include <errno.h>              /* TEMP_FAILURE_RETRY */
52
74
#include <argz.h>               /* argz_count(), argz_extract() */
53
75
 
54
76
sig_atomic_t interrupted_by_signal = 0;
55
 
const char plymouth_pid[] = "/dev/.initramfs/plymouth.pid";
 
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
 
56
87
const char plymouth_path[] = "/bin/plymouth";
57
88
const char plymouthd_path[] = "/sbin/plymouthd";
58
89
const char *plymouthd_default_argv[] = {"/sbin/plymouthd",
59
90
                                        "--mode=boot",
60
91
                                        "--attach-to-session",
61
 
                                        "--pid-file="
62
 
                                        "/dev/.initramfs/"
63
 
                                        "plymouth.pid",
64
92
                                        NULL };
 
93
bool debug = false;
65
94
 
66
95
static void termination_handler(__attribute__((unused))int signum){
67
96
  if(interrupted_by_signal){
70
99
  interrupted_by_signal = 1;
71
100
}
72
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
 
73
134
/* Create prompt string */
74
135
char *makeprompt(void){
75
136
  int ret = 0;
109
170
bool become_a_daemon(void){
110
171
  int ret = setuid(geteuid());
111
172
  if(ret == -1){
112
 
    error(0, errno, "setuid");
 
173
    error_plus(0, errno, "setuid");
113
174
  }
114
175
    
115
176
  setsid();
116
177
  ret = chdir("/");
117
178
  if(ret == -1){
118
 
    error(0, errno, "chdir");
 
179
    error_plus(0, errno, "chdir");
119
180
    return false;
120
181
  }
121
182
  ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
122
183
  if(ret == -1){
123
 
    error(0, errno, "dup2");
 
184
    error_plus(0, errno, "dup2");
124
185
    return false;
125
186
  }
126
187
  return true;
127
188
}
128
189
 
 
190
__attribute__((nonnull (2, 3)))
129
191
bool exec_and_wait(pid_t *pid_return, const char *path,
130
 
                   const char **argv, bool interruptable,
 
192
                   const char * const * const argv, bool interruptable,
131
193
                   bool daemonize){
132
194
  int status;
133
195
  int ret;
134
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
 
135
204
  pid = fork();
136
205
  if(pid == -1){
137
 
    error(0, errno, "fork");
 
206
    error_plus(0, errno, "fork");
138
207
    return false;
139
208
  }
140
209
  if(pid == 0){
145
214
      }
146
215
    }
147
216
    
148
 
    char **new_argv = NULL;
 
217
    char **new_argv = malloc(sizeof(const char *));
 
218
    if(new_argv == NULL){
 
219
      error_plus(0, errno, "malloc");
 
220
      _exit(EX_OSERR);
 
221
    }
149
222
    char **tmp;
150
223
    int i = 0;
151
 
    for (; argv[i]!=NULL; i++){
152
 
      tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
153
 
      if (tmp == NULL){
154
 
        error(0, errno, "realloc");
 
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");
155
239
        free(new_argv);
156
240
        _exit(EX_OSERR);
157
241
      }
161
245
    new_argv[i] = NULL;
162
246
    
163
247
    execv(path, (char *const *)new_argv);
164
 
    error(0, errno, "execv");
 
248
    error_plus(0, errno, "execv");
165
249
    _exit(EXIT_FAILURE);
166
250
  }
167
251
  if(pid_return != NULL){
173
257
          and ((not interrupted_by_signal)
174
258
               or (not interruptable)));
175
259
  if(interrupted_by_signal and interruptable){
 
260
    if(debug){
 
261
      fprintf_plus(stderr, "Interrupted by signal\n");
 
262
    }
176
263
    return false;
177
264
  }
178
265
  if(ret == -1){
179
 
    error(0, errno, "waitpid");
 
266
    error_plus(0, errno, "waitpid");
180
267
    return false;
181
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
  }
182
278
  if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
183
279
    return true;
184
280
  }
185
281
  return false;
186
282
}
187
283
 
 
284
__attribute__((nonnull))
188
285
int is_plymouth(const struct dirent *proc_entry){
189
286
  int ret;
190
287
  {
191
 
    uintmax_t maxvalue;
 
288
    uintmax_t proc_id;
192
289
    char *tmp;
193
290
    errno = 0;
194
 
    maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
 
291
    proc_id = strtoumax(proc_entry->d_name, &tmp, 10);
195
292
 
196
293
    if(errno != 0 or *tmp != '\0'
197
 
       or maxvalue != (uintmax_t)((pid_t)maxvalue)){
 
294
       or proc_id != (uintmax_t)((pid_t)proc_id)){
198
295
      return 0;
199
296
    }
200
297
  }
202
299
  char *exe_link;
203
300
  ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
204
301
  if(ret == -1){
205
 
    error(0, errno, "asprintf");
 
302
    error_plus(0, errno, "asprintf");
206
303
    return 0;
207
304
  }
208
305
  
211
308
  if(ret == -1){
212
309
    free(exe_link);
213
310
    if(errno != ENOENT){
214
 
      error(0, errno, "lstat");
 
311
      error_plus(0, errno, "lstat");
215
312
    }
216
313
    return 0;
217
314
  }
235
332
 
236
333
pid_t get_pid(void){
237
334
  int ret;
 
335
  uintmax_t proc_id = 0;
238
336
  FILE *pidfile = fopen(plymouth_pid, "r");
239
 
  uintmax_t maxvalue = 0;
 
337
  /* Try the new pid file location */
240
338
  if(pidfile != NULL){
241
 
    ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
 
339
    ret = fscanf(pidfile, "%" SCNuMAX, &proc_id);
242
340
    if(ret != 1){
243
 
      maxvalue = 0;
 
341
      proc_id = 0;
244
342
    }
245
343
    fclose(pidfile);
246
344
  }
247
 
  if(maxvalue == 0){
248
 
    struct dirent **direntries;
 
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;
249
370
    ret = scandir("/proc", &direntries, is_plymouth, alphasort);
250
 
    if (ret == -1){
251
 
      error(0, errno, "scandir");
 
371
    if(ret == -1){
 
372
      error_plus(0, errno, "scandir");
252
373
    }
253
 
    if (ret > 0){
254
 
      ret = sscanf(direntries[0]->d_name, "%" SCNuMAX, &maxvalue);
255
 
      if (ret < 0){
256
 
        error(0, errno, "sscanf");
 
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]);
257
384
      }
258
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);
259
389
  }
260
390
  pid_t pid;
261
 
  pid = (pid_t)maxvalue;
262
 
  if((uintmax_t)pid == maxvalue){
 
391
  pid = (pid_t)proc_id;
 
392
  if((uintmax_t)pid == proc_id){
263
393
    return pid;
264
394
  }
265
395
  
266
396
  return 0;
267
397
}
268
398
 
269
 
const char **getargv(pid_t pid){
 
399
char **getargv(pid_t pid){
270
400
  int cl_fd;
271
401
  char *cmdline_filename;
272
402
  ssize_t sret;
275
405
  ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
276
406
                 (uintmax_t)pid);
277
407
  if(ret == -1){
278
 
    error(0, errno, "asprintf");
 
408
    error_plus(0, errno, "asprintf");
279
409
    return NULL;
280
410
  }
281
411
  
283
413
  cl_fd = open(cmdline_filename, O_RDONLY);
284
414
  free(cmdline_filename);
285
415
  if(cl_fd == -1){
286
 
    error(0, errno, "open");
 
416
    error_plus(0, errno, "open");
287
417
    return NULL;
288
418
  }
289
419
  
297
427
    if(cmdline_len + blocksize > cmdline_allocated){
298
428
      tmp = realloc(cmdline, cmdline_allocated + blocksize);
299
429
      if(tmp == NULL){
300
 
        error(0, errno, "realloc");
 
430
        error_plus(0, errno, "realloc");
301
431
        free(cmdline);
302
432
        close(cl_fd);
303
433
        return NULL;
310
440
    sret = read(cl_fd, cmdline + cmdline_len,
311
441
                cmdline_allocated - cmdline_len);
312
442
    if(sret == -1){
313
 
      error(0, errno, "read");
 
443
      error_plus(0, errno, "read");
314
444
      free(cmdline);
315
445
      close(cl_fd);
316
446
      return NULL;
319
449
  } while(sret != 0);
320
450
  ret = close(cl_fd);
321
451
  if(ret == -1){
322
 
    error(0, errno, "close");
 
452
    error_plus(0, errno, "close");
323
453
    free(cmdline);
324
454
    return NULL;
325
455
  }
328
458
  char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
329
459
                       * sizeof(char *)); /* Get number of args */
330
460
  if(argv == NULL){
331
 
    error(0, errno, "argv = malloc()");
 
461
    error_plus(0, errno, "argv = malloc()");
332
462
    free(cmdline);
333
463
    return NULL;
334
464
  }
335
465
  argz_extract(cmdline, cmdline_len, argv); /* Create argv */
336
 
  return (const char **)argv;
 
466
  return argv;
337
467
}
338
468
 
339
469
int main(__attribute__((unused))int argc,
340
470
         __attribute__((unused))char **argv){
341
 
  char *prompt;
 
471
  char *prompt = NULL;
342
472
  char *prompt_arg;
343
473
  pid_t plymouth_command_pid;
344
474
  int ret;
345
475
  bool bret;
346
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
  
347
525
  /* test -x /bin/plymouth */
348
526
  ret = access(plymouth_path, X_OK);
349
527
  if(ret == -1){
350
528
    /* Plymouth is probably not installed.  Don't print an error
351
529
       message, just exit. */
 
530
    if(debug){
 
531
      fprintf_plus(stderr, "Plymouth (%s) not found\n",
 
532
                   plymouth_path);
 
533
    }
352
534
    exit(EX_UNAVAILABLE);
353
535
  }
354
536
  
361
543
        *sig != 0; sig++){
362
544
      ret = sigaddset(&new_action.sa_mask, *sig);
363
545
      if(ret == -1){
364
 
        error(EX_OSERR, errno, "sigaddset");
 
546
        error_plus(EX_OSERR, errno, "sigaddset");
365
547
      }
366
548
      ret = sigaction(*sig, NULL, &old_action);
367
549
      if(ret == -1){
368
 
        error(EX_OSERR, errno, "sigaction");
 
550
        error_plus(EX_OSERR, errno, "sigaction");
369
551
      }
370
552
      if(old_action.sa_handler != SIG_IGN){
371
553
        ret = sigaction(*sig, &new_action, NULL);
372
554
        if(ret == -1){
373
 
          error(EX_OSERR, errno, "sigaction");
 
555
          error_plus(EX_OSERR, errno, "sigaction");
374
556
        }
375
557
      }
376
558
    }
388
570
    }
389
571
    /* Plymouth is probably not running.  Don't print an error
390
572
       message, just exit. */
 
573
    if(debug){
 
574
      fprintf_plus(stderr, "Plymouth not running\n");
 
575
    }
391
576
    exit(EX_UNAVAILABLE);
392
577
  }
393
578
  
394
 
  prompt = makeprompt();
395
 
  ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
396
 
  free(prompt);
 
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
  }
397
586
  if(ret == -1){
398
 
    error(EX_OSERR, errno, "asprintf");
 
587
    error_plus(EX_OSERR, errno, "asprintf");
399
588
  }
400
589
  
401
590
  /* plymouth ask-for-password --prompt="$prompt" */
 
591
  if(debug){
 
592
    fprintf_plus(stderr, "Prompting for password via Plymouth\n");
 
593
  }
402
594
  bret = exec_and_wait(&plymouth_command_pid,
403
595
                       plymouth_path, (const char *[])
404
596
                       { plymouth_path, "ask-for-password",
414
606
  }
415
607
  kill_and_wait(plymouth_command_pid);
416
608
  
417
 
  const char **plymouthd_argv;
 
609
  char **plymouthd_argv = NULL;
418
610
  pid_t pid = get_pid();
419
611
  if(pid == 0){
420
 
    error(0, 0, "plymouthd pid not found");
421
 
    plymouthd_argv = plymouthd_default_argv;
 
612
    error_plus(0, 0, "plymouthd pid not found");
422
613
  } else {
423
614
    plymouthd_argv = getargv(pid);
424
615
  }
427
618
                       { plymouth_path, "quit", NULL },
428
619
                       false, false);
429
620
  if(not bret){
 
621
    if(plymouthd_argv != NULL){
 
622
      free(*plymouthd_argv);
 
623
      free(plymouthd_argv);
 
624
    }
430
625
    exit(EXIT_FAILURE);
431
626
  }
432
 
  bret = exec_and_wait(NULL, plymouthd_path, plymouthd_argv,
 
627
  bret = exec_and_wait(NULL, plymouthd_path,
 
628
                       (plymouthd_argv != NULL)
 
629
                       ? (const char * const *)plymouthd_argv
 
630
                       : plymouthd_default_argv,
433
631
                       false, true);
 
632
  if(plymouthd_argv != NULL){
 
633
    free(*plymouthd_argv);
 
634
    free(plymouthd_argv);
 
635
  }
434
636
  if(not bret){
435
637
    exit(EXIT_FAILURE);
436
638
  }