/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/usplash.c

  • Committer: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support:
Pluginbased client handler
rewritten Mandos client
       Avahi instead of udp server discovery
       openpgp encrypted key support
Passprompt stand alone application for direct console input
Added logging for Mandos server

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8 -*- */
2
 
/*
3
 
 * Usplash - Read a password from usplash and output it
4
 
 * 
5
 
 * Copyright © 2008,2009 Teddy Hogeborn
6
 
 * Copyright © 2008,2009 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
14
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 
 * General Public License for more details.
17
 
 * 
18
 
 * 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
 
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
23
 
 */
24
 
 
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
 
                                   SIG_IGN, kill(), SIGKILL */
30
 
#include <stdbool.h>            /* bool, false, true */
31
 
#include <fcntl.h>              /* open(), O_WRONLY, O_RDONLY */
32
 
#include <iso646.h>             /* and, or, not*/
33
 
#include <errno.h>              /* errno, EINTR */
34
 
#include <error.h>
35
 
#include <sys/types.h>          /* size_t, ssize_t, pid_t, DIR, struct
36
 
                                   dirent */
37
 
#include <stddef.h>             /* NULL */
38
 
#include <string.h>             /* strlen(), memcmp() */
39
 
#include <stdio.h>              /* asprintf()*/
40
 
#include <unistd.h>             /* close(), write(), readlink(),
41
 
                                   read(), STDOUT_FILENO, sleep(),
42
 
                                   fork(), setuid(), geteuid(),
43
 
                                   setsid(), chdir(), dup2(),
44
 
                                   STDERR_FILENO, execv() */
45
 
#include <stdlib.h>             /* free(), EXIT_FAILURE, realloc(),
46
 
                                   EXIT_SUCCESS, malloc(), _exit(),
47
 
                                   getenv() */
48
 
#include <dirent.h>             /* opendir(), readdir(), closedir() */
49
 
#include <inttypes.h>           /* intmax_t, strtoimax() */
50
 
#include <sys/stat.h>           /* struct stat, lstat(), S_ISLNK */
51
 
#include <sysexits.h>           /* EX_OSERR, EX_UNAVAILABLE */
52
 
 
53
 
sig_atomic_t interrupted_by_signal = 0;
54
 
int signal_received;
55
 
const char usplash_name[] = "/sbin/usplash";
56
 
 
57
 
static void termination_handler(int signum){
58
 
  if(interrupted_by_signal){
59
 
    return;
60
 
  }
61
 
  interrupted_by_signal = 1;
62
 
  signal_received = signum;
63
 
}
64
 
 
65
 
static bool usplash_write(int *fifo_fd_r,
66
 
                          const char *cmd, const char *arg){
67
 
  /* 
68
 
   * usplash_write(&fd, "TIMEOUT", "15") will write "TIMEOUT 15\0"
69
 
   * usplash_write(&fd, "PULSATE", NULL) will write "PULSATE\0"
70
 
   * SEE ALSO
71
 
   *         usplash_write(8)
72
 
   */
73
 
  int ret;
74
 
  if(*fifo_fd_r == -1){
75
 
    ret = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
76
 
    if(ret == -1){
77
 
      return false;
78
 
    }
79
 
    *fifo_fd_r = ret;
80
 
  }
81
 
  
82
 
  const char *cmd_line;
83
 
  size_t cmd_line_len;
84
 
  char *cmd_line_alloc = NULL;
85
 
  if(arg == NULL){
86
 
    cmd_line = cmd;
87
 
    cmd_line_len = strlen(cmd) + 1;
88
 
  } else {
89
 
    do {
90
 
      ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
91
 
      if(ret == -1){
92
 
        int e = errno;
93
 
        TEMP_FAILURE_RETRY(close(*fifo_fd_r));
94
 
        errno = e;
95
 
        return false;
96
 
      }
97
 
    } while(ret == -1);
98
 
    cmd_line = cmd_line_alloc;
99
 
    cmd_line_len = (size_t)ret + 1;
100
 
  }
101
 
  
102
 
  size_t written = 0;
103
 
  ssize_t sret = 0;
104
 
  while(written < cmd_line_len){
105
 
    sret = write(*fifo_fd_r, cmd_line + written,
106
 
                 cmd_line_len - written);
107
 
    if(sret == -1){
108
 
      int e = errno;
109
 
      TEMP_FAILURE_RETRY(close(*fifo_fd_r));
110
 
      free(cmd_line_alloc);
111
 
      errno = e;
112
 
      return false;
113
 
    }
114
 
    written += (size_t)sret;
115
 
  }
116
 
  free(cmd_line_alloc);
117
 
  
118
 
  return true;
119
 
}
120
 
 
121
 
/* Create prompt string */
122
 
char *makeprompt(void){
123
 
  int ret = 0;
124
 
  char *prompt;
125
 
  const char *const cryptsource = getenv("cryptsource");
126
 
  const char *const crypttarget = getenv("crypttarget");
127
 
  const char prompt_start[] = "Enter passphrase to unlock the disk";
128
 
  
129
 
  if(cryptsource == NULL){
130
 
    if(crypttarget == NULL){
131
 
      ret = asprintf(&prompt, "%s: ", prompt_start);
132
 
    } else {
133
 
      ret = asprintf(&prompt, "%s (%s): ", prompt_start,
134
 
                     crypttarget);
135
 
    }
136
 
  } else {
137
 
    if(crypttarget == NULL){
138
 
      ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
139
 
    } else {
140
 
      ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
141
 
                     cryptsource, crypttarget);
142
 
    }
143
 
  }
144
 
  if(ret == -1){
145
 
    return NULL;
146
 
  }
147
 
  return prompt;
148
 
}
149
 
 
150
 
pid_t find_usplash(char **cmdline_r, size_t *cmdline_len_r){
151
 
  int ret = 0;
152
 
  ssize_t sret = 0;
153
 
  char *cmdline = NULL;
154
 
  size_t cmdline_len = 0;
155
 
  DIR *proc_dir = opendir("/proc");
156
 
  if(proc_dir == NULL){
157
 
    error(0, errno, "opendir");
158
 
    return -1;
159
 
  }
160
 
  errno = 0;
161
 
  for(struct dirent *proc_ent = readdir(proc_dir);
162
 
      proc_ent != NULL;
163
 
      proc_ent = readdir(proc_dir)){
164
 
    pid_t pid;
165
 
    {
166
 
      intmax_t tmpmax;
167
 
      char *tmp;
168
 
      tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
169
 
      if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
170
 
         or tmpmax != (pid_t)tmpmax){
171
 
        /* Not a process */
172
 
        errno = 0;
173
 
        continue;
174
 
      }
175
 
      pid = (pid_t)tmpmax;
176
 
    }
177
 
    /* Find the executable name by doing readlink() on the
178
 
       /proc/<pid>/exe link */
179
 
    char exe_target[sizeof(usplash_name)];
180
 
    {
181
 
      /* create file name string */
182
 
      char *exe_link;
183
 
      ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
184
 
      if(ret == -1){
185
 
        error(0, errno, "asprintf");
186
 
        goto fail_find_usplash;
187
 
      }
188
 
      
189
 
      /* Check that it refers to a symlink owned by root:root */
190
 
      struct stat exe_stat;
191
 
      ret = lstat(exe_link, &exe_stat);
192
 
      if(ret == -1){
193
 
        if(errno == ENOENT){
194
 
          free(exe_link);
195
 
          continue;
196
 
        }
197
 
        error(0, errno, "lstat");
198
 
        free(exe_link);
199
 
        goto fail_find_usplash;
200
 
      }
201
 
      if(not S_ISLNK(exe_stat.st_mode)
202
 
         or exe_stat.st_uid != 0
203
 
         or exe_stat.st_gid != 0){
204
 
        free(exe_link);
205
 
        continue;
206
 
      }
207
 
        
208
 
      sret = readlink(exe_link, exe_target, sizeof(exe_target));
209
 
      free(exe_link);
210
 
    }
211
 
    /* Compare executable name */
212
 
    if((sret != ((ssize_t)sizeof(exe_target)-1))
213
 
       or (memcmp(usplash_name, exe_target,
214
 
                  sizeof(exe_target)-1) != 0)){
215
 
      /* Not it */
216
 
      continue;
217
 
    }
218
 
    /* Found usplash */
219
 
    /* Read and save the command line of usplash in "cmdline" */
220
 
    {
221
 
      /* Open /proc/<pid>/cmdline  */
222
 
      int cl_fd;
223
 
      {
224
 
        char *cmdline_filename;
225
 
        ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
226
 
                       proc_ent->d_name);
227
 
        if(ret == -1){
228
 
          error(0, errno, "asprintf");
229
 
          goto fail_find_usplash;
230
 
        }
231
 
        cl_fd = open(cmdline_filename, O_RDONLY);
232
 
        free(cmdline_filename);
233
 
        if(cl_fd == -1){
234
 
          error(0, errno, "open");
235
 
          goto fail_find_usplash;
236
 
        }
237
 
      }
238
 
      size_t cmdline_allocated = 0;
239
 
      char *tmp;
240
 
      const size_t blocksize = 1024;
241
 
      do {
242
 
        /* Allocate more space? */
243
 
        if(cmdline_len + blocksize > cmdline_allocated){
244
 
          tmp = realloc(cmdline, cmdline_allocated + blocksize);
245
 
          if(tmp == NULL){
246
 
            error(0, errno, "realloc");
247
 
            close(cl_fd);
248
 
            goto fail_find_usplash;
249
 
          }
250
 
          cmdline = tmp;
251
 
          cmdline_allocated += blocksize;
252
 
        }
253
 
        /* Read data */
254
 
        sret = read(cl_fd, cmdline + cmdline_len,
255
 
                    cmdline_allocated - cmdline_len);
256
 
        if(sret == -1){
257
 
          error(0, errno, "read");
258
 
          close(cl_fd);
259
 
          goto fail_find_usplash;
260
 
        }
261
 
        cmdline_len += (size_t)sret;
262
 
      } while(sret != 0);
263
 
      ret = close(cl_fd);
264
 
      if(ret == -1){
265
 
        error(0, errno, "close");
266
 
        goto fail_find_usplash;
267
 
      }
268
 
    }
269
 
    /* Close directory */
270
 
    ret = closedir(proc_dir);
271
 
    if(ret == -1){
272
 
      error(0, errno, "closedir");
273
 
      goto fail_find_usplash;
274
 
    }
275
 
    /* Success */
276
 
    *cmdline_r = cmdline;
277
 
    *cmdline_len_r = cmdline_len;
278
 
    return pid;
279
 
  }
280
 
  
281
 
 fail_find_usplash:
282
 
  
283
 
  free(cmdline);
284
 
  if(proc_dir != NULL){
285
 
    int e = errno;
286
 
    closedir(proc_dir);
287
 
    errno = e;
288
 
  }
289
 
  return 0;
290
 
}
291
 
 
292
 
int main(__attribute__((unused))int argc,
293
 
         __attribute__((unused))char **argv){
294
 
  int ret = 0;
295
 
  ssize_t sret;
296
 
  int fifo_fd = -1;
297
 
  int outfifo_fd = -1;
298
 
  char *buf = NULL;
299
 
  size_t buf_len = 0;
300
 
  pid_t usplash_pid = -1;
301
 
  bool usplash_accessed = false;
302
 
  int status = EXIT_FAILURE;    /* Default failure exit status */
303
 
  
304
 
  char *prompt = makeprompt();
305
 
  if(prompt == NULL){
306
 
    status = EX_OSERR;
307
 
    goto failure;
308
 
  }
309
 
  
310
 
  /* Find usplash process */
311
 
  char *cmdline = NULL;
312
 
  size_t cmdline_len = 0;
313
 
  usplash_pid = find_usplash(&cmdline, &cmdline_len);
314
 
  if(usplash_pid == 0){
315
 
    status = EX_UNAVAILABLE;
316
 
    goto failure;
317
 
  }
318
 
  
319
 
  /* Set up the signal handler */
320
 
  {
321
 
    struct sigaction old_action,
322
 
      new_action = { .sa_handler = termination_handler,
323
 
                     .sa_flags = 0 };
324
 
    sigemptyset(&new_action.sa_mask);
325
 
    ret = sigaddset(&new_action.sa_mask, SIGINT);
326
 
    if(ret == -1){
327
 
      error(0, errno, "sigaddset");
328
 
      status = EX_OSERR;
329
 
      goto failure;
330
 
    }
331
 
    ret = sigaddset(&new_action.sa_mask, SIGHUP);
332
 
    if(ret == -1){
333
 
      error(0, errno, "sigaddset");
334
 
      status = EX_OSERR;
335
 
      goto failure;
336
 
    }
337
 
    ret = sigaddset(&new_action.sa_mask, SIGTERM);
338
 
    if(ret == -1){
339
 
      error(0, errno, "sigaddset");
340
 
      status = EX_OSERR;
341
 
      goto failure;
342
 
    }
343
 
    ret = sigaction(SIGINT, NULL, &old_action);
344
 
    if(ret == -1){
345
 
      if(errno != EINTR){
346
 
        error(0, errno, "sigaction");
347
 
        status = EX_OSERR;
348
 
      }
349
 
      goto failure;
350
 
    }
351
 
    if(old_action.sa_handler != SIG_IGN){
352
 
      ret = sigaction(SIGINT, &new_action, NULL);
353
 
      if(ret == -1){
354
 
        if(errno != EINTR){
355
 
          error(0, errno, "sigaction");
356
 
          status = EX_OSERR;
357
 
        }
358
 
        goto failure;
359
 
      }
360
 
    }
361
 
    ret = sigaction(SIGHUP, NULL, &old_action);
362
 
    if(ret == -1){
363
 
      if(errno != EINTR){
364
 
        error(0, errno, "sigaction");
365
 
        status = EX_OSERR;
366
 
      }
367
 
      goto failure;
368
 
    }
369
 
    if(old_action.sa_handler != SIG_IGN){
370
 
      ret = sigaction(SIGHUP, &new_action, NULL);
371
 
      if(ret == -1){
372
 
        if(errno != EINTR){
373
 
          error(0, errno, "sigaction");
374
 
          status = EX_OSERR;
375
 
        }
376
 
        goto failure;
377
 
      }
378
 
    }
379
 
    ret = sigaction(SIGTERM, NULL, &old_action);
380
 
    if(ret == -1){
381
 
      if(errno != EINTR){
382
 
        error(0, errno, "sigaction");
383
 
        status = EX_OSERR;
384
 
      }
385
 
      goto failure;
386
 
    }
387
 
    if(old_action.sa_handler != SIG_IGN){
388
 
      ret = sigaction(SIGTERM, &new_action, NULL);
389
 
      if(ret == -1){
390
 
        if(errno != EINTR){
391
 
          error(0, errno, "sigaction");
392
 
          status = EX_OSERR;
393
 
        }
394
 
        goto failure;
395
 
      }
396
 
    }
397
 
  }
398
 
  
399
 
  usplash_accessed = true;
400
 
  /* Write command to FIFO */
401
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
402
 
    if(errno != EINTR){
403
 
      error(0, errno, "usplash_write");
404
 
      status = EX_OSERR;
405
 
    }
406
 
    goto failure;
407
 
  }
408
 
  
409
 
  if(interrupted_by_signal){
410
 
    goto failure;
411
 
  }
412
 
  
413
 
  if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
414
 
    if(errno != EINTR){
415
 
      error(0, errno, "usplash_write");
416
 
      status = EX_OSERR;
417
 
    }
418
 
    goto failure;
419
 
  }
420
 
  
421
 
  if(interrupted_by_signal){
422
 
    goto failure;
423
 
  }
424
 
  
425
 
  free(prompt);
426
 
  prompt = NULL;
427
 
  
428
 
  /* Read reply from usplash */
429
 
  /* Open FIFO */
430
 
  outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
431
 
  if(outfifo_fd == -1){
432
 
    if(errno != EINTR){
433
 
      error(0, errno, "open");
434
 
      status = EX_OSERR;
435
 
    }
436
 
    goto failure;
437
 
  }
438
 
  
439
 
  if(interrupted_by_signal){
440
 
    goto failure;
441
 
  }
442
 
  
443
 
  /* Read from FIFO */
444
 
  size_t buf_allocated = 0;
445
 
  const size_t blocksize = 1024;
446
 
  do {
447
 
    /* Allocate more space */
448
 
    if(buf_len + blocksize > buf_allocated){
449
 
      char *tmp = realloc(buf, buf_allocated + blocksize);
450
 
      if(tmp == NULL){
451
 
        if(errno != EINTR){
452
 
          error(0, errno, "realloc");
453
 
          status = EX_OSERR;
454
 
        }
455
 
        goto failure;
456
 
      }
457
 
      buf = tmp;
458
 
      buf_allocated += blocksize;
459
 
    }
460
 
    sret = read(outfifo_fd, buf + buf_len,
461
 
                buf_allocated - buf_len);
462
 
    if(sret == -1){
463
 
      if(errno != EINTR){
464
 
        error(0, errno, "read");
465
 
        status = EX_OSERR;
466
 
      }
467
 
      TEMP_FAILURE_RETRY(close(outfifo_fd));
468
 
      goto failure;
469
 
    }
470
 
    if(interrupted_by_signal){
471
 
      break;
472
 
    }
473
 
    
474
 
    buf_len += (size_t)sret;
475
 
  } while(sret != 0);
476
 
  ret = close(outfifo_fd);
477
 
  if(ret == -1){
478
 
    if(errno != EINTR){
479
 
      error(0, errno, "close");
480
 
      status = EX_OSERR;
481
 
    }
482
 
    goto failure;
483
 
  }
484
 
  outfifo_fd = -1;
485
 
  
486
 
  if(interrupted_by_signal){
487
 
    goto failure;
488
 
  }
489
 
  
490
 
  if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
491
 
    if(errno != EINTR){
492
 
      error(0, errno, "usplash_write");
493
 
      status = EX_OSERR;
494
 
    }
495
 
    goto failure;
496
 
  }
497
 
  
498
 
  if(interrupted_by_signal){
499
 
    goto failure;
500
 
  }
501
 
  
502
 
  ret = close(fifo_fd);
503
 
  if(ret == -1){
504
 
    if(errno != EINTR){
505
 
      error(0, errno, "close");
506
 
      status = EX_OSERR;
507
 
    }
508
 
    goto failure;
509
 
  }
510
 
  fifo_fd = -1;
511
 
  
512
 
  /* Print password to stdout */
513
 
  size_t written = 0;
514
 
  while(written < buf_len){
515
 
    do {
516
 
      sret = write(STDOUT_FILENO, buf + written, buf_len - written);
517
 
      if(sret == -1){
518
 
        if(errno != EINTR){
519
 
          error(0, errno, "write");
520
 
          status = EX_OSERR;
521
 
        }
522
 
        goto failure;
523
 
      }
524
 
    } while(sret == -1);
525
 
    
526
 
    if(interrupted_by_signal){
527
 
      goto failure;
528
 
    }
529
 
    written += (size_t)sret;
530
 
  }
531
 
  free(buf);
532
 
  buf = NULL;
533
 
  
534
 
  if(interrupted_by_signal){
535
 
    goto failure;
536
 
  }
537
 
  
538
 
  free(cmdline);
539
 
  return EXIT_SUCCESS;
540
 
  
541
 
 failure:
542
 
  
543
 
  free(buf);
544
 
  
545
 
  free(prompt);
546
 
  
547
 
  /* If usplash was never accessed, we can stop now */
548
 
  if(not usplash_accessed){
549
 
    return status;
550
 
  }
551
 
  
552
 
  /* Close FIFO */
553
 
  if(fifo_fd != -1){
554
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
555
 
    if(ret == -1 and errno != EINTR){
556
 
      error(0, errno, "close");
557
 
    }
558
 
    fifo_fd = -1;
559
 
  }
560
 
  
561
 
  /* Close output FIFO */
562
 
  if(outfifo_fd != -1){
563
 
    ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
564
 
    if(ret == -1){
565
 
      error(0, errno, "close");
566
 
    }
567
 
  }
568
 
  
569
 
  /* Create argc and argv for new usplash*/
570
 
  int cmdline_argc = 0;
571
 
  char **cmdline_argv = malloc(sizeof(char *));
572
 
  {
573
 
    size_t position = 0;
574
 
    while(position < cmdline_len){
575
 
      char **tmp = realloc(cmdline_argv,
576
 
                           (sizeof(char *)
577
 
                            * (size_t)(cmdline_argc + 2)));
578
 
      if(tmp == NULL){
579
 
        error(0, errno, "realloc");
580
 
        free(cmdline_argv);
581
 
        return status;
582
 
      }
583
 
      cmdline_argv = tmp;
584
 
      cmdline_argv[cmdline_argc] = cmdline + position;
585
 
      cmdline_argc++;
586
 
      position += strlen(cmdline + position) + 1;
587
 
    }
588
 
    cmdline_argv[cmdline_argc] = NULL;
589
 
  }
590
 
  /* Kill old usplash */
591
 
  kill(usplash_pid, SIGTERM);
592
 
  sleep(2);
593
 
  while(kill(usplash_pid, 0) == 0){
594
 
    kill(usplash_pid, SIGKILL);
595
 
    sleep(1);
596
 
  }
597
 
  
598
 
  pid_t new_usplash_pid = fork();
599
 
  if(new_usplash_pid == 0){
600
 
    /* Child; will become new usplash process */
601
 
    
602
 
    /* Make the effective user ID (root) the only user ID instead of
603
 
       the real user ID (_mandos) */
604
 
    ret = setuid(geteuid());
605
 
    if(ret == -1){
606
 
      error(0, errno, "setuid");
607
 
    }
608
 
    
609
 
    setsid();
610
 
    ret = chdir("/");
611
 
    if(ret == -1){
612
 
      error(0, errno, "chdir");
613
 
      _exit(EX_OSERR);
614
 
    }
615
 
/*     if(fork() != 0){ */
616
 
/*       _exit(EXIT_SUCCESS); */
617
 
/*     } */
618
 
    ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
619
 
    if(ret == -1){
620
 
      error(0, errno, "dup2");
621
 
      _exit(EX_OSERR);
622
 
    }
623
 
    
624
 
    execv(usplash_name, cmdline_argv);
625
 
    if(not interrupted_by_signal){
626
 
      error(0, errno, "execv");
627
 
    }
628
 
    free(cmdline);
629
 
    free(cmdline_argv);
630
 
    _exit(EX_OSERR);
631
 
  }
632
 
  free(cmdline);
633
 
  free(cmdline_argv);
634
 
  sleep(2);
635
 
  if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
636
 
    if(errno != EINTR){
637
 
      error(0, errno, "usplash_write");
638
 
    }
639
 
  }
640
 
  
641
 
  /* Close FIFO (again) */
642
 
  if(fifo_fd != -1){
643
 
    ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
644
 
    if(ret == -1 and errno != EINTR){
645
 
      error(0, errno, "close");
646
 
    }
647
 
    fifo_fd = -1;
648
 
  }
649
 
  
650
 
  if(interrupted_by_signal){
651
 
    struct sigaction signal_action = { .sa_handler = SIG_DFL };
652
 
    sigemptyset(&signal_action.sa_mask);
653
 
    ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
654
 
                                            &signal_action, NULL));
655
 
    if(ret == -1){
656
 
      error(0, errno, "sigaction");
657
 
    }
658
 
    do {
659
 
      ret = raise(signal_received);
660
 
    } while(ret != 0 and errno == EINTR);
661
 
    if(ret != 0){
662
 
      error(0, errno, "raise");
663
 
      abort();
664
 
    }
665
 
    TEMP_FAILURE_RETRY(pause());
666
 
  }
667
 
  
668
 
  return status;
669
 
}