/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/password-prompt.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-16 03:29:08 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080816032908-ihw7c05r2mnyk389
Add feature to specify custom environment variables for plugins.

* plugin-runner.c (plugin): New members "environ" and "envc" to
                            contain possible custom environment.
  (getplugin): Return NULL on failure instead of doing exit(); all
               callers changed.
  (add_to_char_array): New helper function for "add_argument" and
                       "add_environment".
  (addargument): Renamed to "add_argument".  Return bool.  Call
                 "add_to_char_array" to actually do things.
  (add_environment): New; analogous to "add_argument".
  (addcustomargument): Renamed to "add_to_argv" to avoid confusion
                       with "add_argument".
  (main): New options "--global-envs" and "--envs-for" to specify
          custom environment for plugins.  Print environment for
          plugins in debug mode.  Use asprintf instead of strcpy and
          strcat.  Use execve() for plugins with custom environments.
          Free environment for plugin when freeing plugin list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  -*- coding: utf-8; mode: c; mode: orgtbl -*- */
 
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Password-prompt - Read a password from the terminal and print it
4
 
 * 
5
 
 * Copyright © 2008-2010 Teddy Hogeborn
6
 
 * Copyright © 2008-2010 Björn Påhlsson
 
3
 * Passprompt - Read a password from the terminal and print it
 
4
 *
 
5
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
7
6
 * 
8
7
 * This program is free software: you can redistribute it and/or
9
8
 * modify it under the terms of the GNU General Public License as
19
18
 * along with this program.  If not, see
20
19
 * <http://www.gnu.org/licenses/>.
21
20
 * 
22
 
 * Contact the authors at <mandos@fukt.bsnet.se>.
 
21
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
 
22
 * <https://www.fukt.bsnet.se/~teddy/>.
23
23
 */
24
24
 
25
 
#define _GNU_SOURCE             /* getline(), asprintf() */
 
25
#define _GNU_SOURCE             /* getline() */
26
26
 
27
 
#include <termios.h>            /* struct termios, tcsetattr(),
 
27
#include <termios.h>            /* struct termios, tcsetattr(),
28
28
                                   TCSAFLUSH, tcgetattr(), ECHO */
29
29
#include <unistd.h>             /* struct termios, tcsetattr(),
30
30
                                   STDIN_FILENO, TCSAFLUSH,
31
 
                                   tcgetattr(), ECHO, readlink() */
 
31
                                   tcgetattr(), ECHO */
32
32
#include <signal.h>             /* sig_atomic_t, raise(), struct
33
33
                                   sigaction, sigemptyset(),
34
34
                                   sigaction(), sigaddset(), SIGINT,
35
 
                                   SIGQUIT, SIGHUP, SIGTERM,
36
 
                                   raise() */
 
35
                                   SIGQUIT, SIGHUP, SIGTERM */
37
36
#include <stddef.h>             /* NULL, size_t, ssize_t */
38
 
#include <sys/types.h>          /* ssize_t, struct dirent, pid_t,
39
 
                                   ssize_t, open() */
 
37
#include <sys/types.h>          /* ssize_t */
40
38
#include <stdlib.h>             /* EXIT_SUCCESS, EXIT_FAILURE,
41
 
                                   getenv(), free() */
42
 
#include <dirent.h>             /* scandir(), alphasort() */
 
39
                                   getopt_long */
43
40
#include <stdio.h>              /* fprintf(), stderr, getline(),
44
 
                                   stdin, feof(), fputc()
45
 
                                */
46
 
#include <errno.h>              /* errno, EBADF, ENOTTY, EINVAL,
47
 
                                   EFAULT, EFBIG, EIO, ENOSPC, EINTR
48
 
                                */
49
 
#include <error.h>              /* error() */
 
41
                                   stdin, feof(), perror(), fputc(),
 
42
                                   stdout, getopt_long */
 
43
#include <errno.h>              /* errno, EINVAL */
50
44
#include <iso646.h>             /* or, not */
51
45
#include <stdbool.h>            /* bool, false, true */
52
 
#include <inttypes.h>           /* strtoumax() */
53
 
#include <sys/stat.h>           /* struct stat, lstat(), open() */
54
 
#include <string.h>             /* strlen, rindex, memcmp */
 
46
#include <string.h>             /* strlen, rindex, strncmp, strcmp */
55
47
#include <argp.h>               /* struct argp_option, struct
56
48
                                   argp_state, struct argp,
57
49
                                   argp_parse(), error_t,
58
50
                                   ARGP_KEY_ARG, ARGP_KEY_END,
59
51
                                   ARGP_ERR_UNKNOWN */
60
 
#include <sysexits.h>           /* EX_SOFTWARE, EX_OSERR,
61
 
                                   EX_UNAVAILABLE, EX_IOERR, EX_OK */
62
 
#include <fcntl.h>              /* open() */
63
52
 
64
 
volatile sig_atomic_t quit_now = 0;
65
 
int signal_received;
 
53
volatile bool quit_now = false;
66
54
bool debug = false;
67
 
const char *argp_program_version = "password-prompt " VERSION;
 
55
const char *argp_program_version = "password-prompt 1.0";
68
56
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
69
57
 
70
 
/* Needed for conflict resolution */
71
 
const char plymouth_name[] = "plymouthd";
72
 
 
73
 
static void termination_handler(int signum){
74
 
  if(quit_now){
75
 
    return;
76
 
  }
77
 
  quit_now = 1;
78
 
  signal_received = signum;
79
 
}
80
 
 
81
 
bool conflict_detection(void){
82
 
 
83
 
  /* plymouth conflicts with password-prompt since both want to read
84
 
     from the terminal.  Password-prompt will exit if it detects
85
 
     plymouth since plymouth performs the same functionality.
86
 
   */
87
 
  int is_plymouth(const struct dirent *proc_entry){
88
 
    int ret;
89
 
    int cl_fd;
90
 
    {
91
 
      uintmax_t maxvalue;
92
 
      char *tmp;
93
 
      errno = 0;
94
 
      maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
95
 
      
96
 
      if(errno != 0 or *tmp != '\0'
97
 
         or maxvalue != (uintmax_t)((pid_t)maxvalue)){
98
 
        return 0;
99
 
      }
100
 
    }
101
 
    
102
 
    char *cmdline_filename;
103
 
    ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
104
 
                   proc_entry->d_name);
105
 
    if(ret == -1){
106
 
      error(0, errno, "asprintf");
107
 
      return 0;
108
 
    }
109
 
    
110
 
    /* Open /proc/<pid>/cmdline */
111
 
    cl_fd = open(cmdline_filename, O_RDONLY);
112
 
    free(cmdline_filename);
113
 
    if(cl_fd == -1){
114
 
      error(0, errno, "open");
115
 
      return 0;
116
 
    }
117
 
    
118
 
    char *cmdline = NULL;
119
 
    {
120
 
      size_t cmdline_len = 0;
121
 
      size_t cmdline_allocated = 0;
122
 
      char *tmp;
123
 
      const size_t blocksize = 1024;
124
 
      ssize_t sret;
125
 
      do {
126
 
        /* Allocate more space? */
127
 
        if(cmdline_len + blocksize + 1 > cmdline_allocated){
128
 
          tmp = realloc(cmdline, cmdline_allocated + blocksize + 1);
129
 
          if(tmp == NULL){
130
 
            error(0, errno, "realloc");
131
 
            free(cmdline);
132
 
            close(cl_fd);
133
 
            return 0;
134
 
          }
135
 
          cmdline = tmp;
136
 
          cmdline_allocated += blocksize;
137
 
        }
138
 
        
139
 
        /* Read data */
140
 
        sret = read(cl_fd, cmdline + cmdline_len,
141
 
                    cmdline_allocated - cmdline_len);
142
 
        if(sret == -1){
143
 
          error(0, errno, "read");
144
 
          free(cmdline);
145
 
          close(cl_fd);
146
 
          return 0;
147
 
        }
148
 
        cmdline_len += (size_t)sret;
149
 
      } while(sret != 0);
150
 
      ret = close(cl_fd);
151
 
      if(ret == -1){
152
 
        error(0, errno, "close");
153
 
        free(cmdline);
154
 
        return 0;
155
 
      }
156
 
      cmdline[cmdline_len] = '\0'; /* Make sure it is terminated */
157
 
    }
158
 
    /* we now have cmdline */
159
 
    
160
 
    /* get basename */
161
 
    char *cmdline_base = strrchr(cmdline, '/');
162
 
    if(cmdline_base != NULL){
163
 
      cmdline_base += 1;                /* skip the slash */
164
 
    } else {
165
 
      cmdline_base = cmdline;
166
 
    }
167
 
    
168
 
    if(strcmp(cmdline_base, plymouth_name) != 0){
169
 
      if(debug){
170
 
        fprintf(stderr, "\"%s\" is not \"%s\"\n", cmdline_base,
171
 
                plymouth_name);
172
 
      }
173
 
      free(cmdline);
174
 
      return 0;
175
 
    }
176
 
    if(debug){
177
 
      fprintf(stderr, "\"%s\" equals \"%s\"\n", cmdline_base,
178
 
              plymouth_name);
179
 
    }
180
 
    free(cmdline);
181
 
    return 1;
182
 
  }
183
 
  
184
 
  struct dirent **direntries;
185
 
  int ret;
186
 
  ret = scandir("/proc", &direntries, is_plymouth, alphasort);
187
 
  if (ret == -1){
188
 
    error(1, errno, "scandir");
189
 
  }
190
 
  return ret > 0;
191
 
}
192
 
 
 
58
static void termination_handler(__attribute__((unused))int signum){
 
59
  quit_now = true;
 
60
}
193
61
 
194
62
int main(int argc, char **argv){
195
 
  ssize_t sret;
196
 
  int ret;
 
63
  ssize_t ret;
197
64
  size_t n;
198
65
  struct termios t_new, t_old;
199
66
  char *buffer = NULL;
206
73
    struct argp_option options[] = {
207
74
      { .name = "prefix", .key = 'p',
208
75
        .arg = "PREFIX", .flags = 0,
209
 
        .doc = "Prefix shown before the prompt", .group = 2 },
 
76
        .doc = "Prefix used before the passprompt", .group = 2 },
210
77
      { .name = "debug", .key = 128,
211
78
        .doc = "Debug mode", .group = 3 },
212
 
      /*
213
 
       * These reproduce what we would get without ARGP_NO_HELP
214
 
       */
215
 
      { .name = "help", .key = '?',
216
 
        .doc = "Give this help list", .group = -1 },
217
 
      { .name = "usage", .key = -3,
218
 
        .doc = "Give a short usage message", .group = -1 },
219
 
      { .name = "version", .key = 'V',
220
 
        .doc = "Print program version", .group = -1 },
221
79
      { .name = NULL }
222
80
    };
223
 
    
224
 
    error_t parse_opt (int key, char *arg, struct argp_state *state){
225
 
      errno = 0;
226
 
      switch (key){
 
81
  
 
82
    error_t parse_opt (int key, char *arg, struct argp_state *state) {
 
83
      /* Get the INPUT argument from `argp_parse', which we know is a
 
84
         pointer to our plugin list pointer. */
 
85
      switch (key) {
227
86
      case 'p':
228
87
        prefix = arg;
229
88
        break;
230
89
      case 128:
231
90
        debug = true;
232
91
        break;
233
 
        /*
234
 
         * These reproduce what we would get without ARGP_NO_HELP
235
 
         */
236
 
      case '?':                 /* --help */
237
 
        argp_state_help(state, state->out_stream,
238
 
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
239
 
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
240
 
      case -3:                  /* --usage */
241
 
        argp_state_help(state, state->out_stream,
242
 
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
243
 
      case 'V':                 /* --version */
244
 
        fprintf(state->out_stream, "%s\n", argp_program_version);
245
 
        exit(argp_err_exit_status);
 
92
      case ARGP_KEY_ARG:
 
93
        argp_usage (state);
 
94
        break;
 
95
      case ARGP_KEY_END:
246
96
        break;
247
97
      default:
248
98
        return ARGP_ERR_UNKNOWN;
249
99
      }
250
 
      return errno;
 
100
      return 0;
251
101
    }
252
 
    
 
102
  
253
103
    struct argp argp = { .options = options, .parser = parse_opt,
254
104
                         .args_doc = "",
255
 
                         .doc = "Mandos password-prompt -- Read and"
256
 
                         " output a password" };
257
 
    ret = argp_parse(&argp, argc, argv,
258
 
                     ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL);
259
 
    switch(ret){
260
 
    case 0:
261
 
      break;
262
 
    case ENOMEM:
263
 
    default:
264
 
      errno = ret;
265
 
      error(0, errno, "argp_parse");
266
 
      return EX_OSERR;
267
 
    case EINVAL:
268
 
      return EX_USAGE;
 
105
                         .doc = "Mandos Passprompt -- Provides a passprompt" };
 
106
    ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
 
107
    if (ret == ARGP_ERR_UNKNOWN){
 
108
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
109
      return EXIT_FAILURE;
269
110
    }
270
111
  }
271
 
  
272
 
  if(debug){
 
112
    
 
113
  if (debug){
273
114
    fprintf(stderr, "Starting %s\n", argv[0]);
274
115
  }
275
 
 
276
 
  if (conflict_detection()){
277
 
    if(debug){
278
 
      fprintf(stderr, "Stopping %s because of conflict\n", argv[0]);
279
 
    }
280
 
    return EXIT_FAILURE;
281
 
  }
282
 
  
283
 
  if(debug){
 
116
  if (debug){
284
117
    fprintf(stderr, "Storing current terminal attributes\n");
285
118
  }
286
119
  
287
 
  if(tcgetattr(STDIN_FILENO, &t_old) != 0){
288
 
    int e = errno;
289
 
    error(0, errno, "tcgetattr");
290
 
    switch(e){
291
 
    case EBADF:
292
 
    case ENOTTY:
293
 
      return EX_UNAVAILABLE;
294
 
    default:
295
 
      return EX_OSERR;
296
 
    }
 
120
  if (tcgetattr(STDIN_FILENO, &t_old) != 0){
 
121
    return EXIT_FAILURE;
297
122
  }
298
123
  
299
124
  sigemptyset(&new_action.sa_mask);
300
 
  ret = sigaddset(&new_action.sa_mask, SIGINT);
301
 
  if(ret == -1){
302
 
    error(0, errno, "sigaddset");
303
 
    return EX_OSERR;
304
 
  }
305
 
  ret = sigaddset(&new_action.sa_mask, SIGHUP);
306
 
  if(ret == -1){
307
 
    error(0, errno, "sigaddset");
308
 
    return EX_OSERR;
309
 
  }
310
 
  ret = sigaddset(&new_action.sa_mask, SIGTERM);
311
 
  if(ret == -1){
312
 
    error(0, errno, "sigaddset");
313
 
    return EX_OSERR;
314
 
  }
315
 
  /* Need to check if the handler is SIG_IGN before handling:
316
 
     | [[info:libc:Initial Signal Actions]] |
317
 
     | [[info:libc:Basic Signal Handling]]  |
318
 
  */
 
125
  sigaddset(&new_action.sa_mask, SIGINT);
 
126
  sigaddset(&new_action.sa_mask, SIGHUP);
 
127
  sigaddset(&new_action.sa_mask, SIGTERM);
319
128
  ret = sigaction(SIGINT, NULL, &old_action);
320
129
  if(ret == -1){
321
 
    error(0, errno, "sigaction");
322
 
    return EX_OSERR;
 
130
    perror("sigaction");
 
131
    return EXIT_FAILURE;
323
132
  }
324
 
  if(old_action.sa_handler != SIG_IGN){
 
133
  if (old_action.sa_handler != SIG_IGN){
325
134
    ret = sigaction(SIGINT, &new_action, NULL);
326
135
    if(ret == -1){
327
 
      error(0, errno, "sigaction");
328
 
      return EX_OSERR;
 
136
      perror("sigaction");
 
137
      return EXIT_FAILURE;
329
138
    }
330
139
  }
331
140
  ret = sigaction(SIGHUP, NULL, &old_action);
332
141
  if(ret == -1){
333
 
    error(0, errno, "sigaction");
334
 
    return EX_OSERR;
 
142
    perror("sigaction");
 
143
    return EXIT_FAILURE;
335
144
  }
336
 
  if(old_action.sa_handler != SIG_IGN){
 
145
  if (old_action.sa_handler != SIG_IGN){
337
146
    ret = sigaction(SIGHUP, &new_action, NULL);
338
147
    if(ret == -1){
339
 
      error(0, errno, "sigaction");
340
 
      return EX_OSERR;
 
148
      perror("sigaction");
 
149
      return EXIT_FAILURE;
341
150
    }
342
151
  }
343
152
  ret = sigaction(SIGTERM, NULL, &old_action);
344
153
  if(ret == -1){
345
 
    error(0, errno, "sigaction");
346
 
    return EX_OSERR;
 
154
    perror("sigaction");
 
155
    return EXIT_FAILURE;
347
156
  }
348
 
  if(old_action.sa_handler != SIG_IGN){
 
157
  if (old_action.sa_handler != SIG_IGN){
349
158
    ret = sigaction(SIGTERM, &new_action, NULL);
350
159
    if(ret == -1){
351
 
      error(0, errno, "sigaction");
352
 
      return EX_OSERR;
 
160
      perror("sigaction");
 
161
      return EXIT_FAILURE;
353
162
    }
354
163
  }
355
164
  
356
165
  
357
 
  if(debug){
 
166
  if (debug){
358
167
    fprintf(stderr, "Removing echo flag from terminal attributes\n");
359
168
  }
360
169
  
361
170
  t_new = t_old;
362
 
  t_new.c_lflag &= ~(tcflag_t)ECHO;
363
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
364
 
    int e = errno;
365
 
    error(0, errno, "tcsetattr-echo");
366
 
    switch(e){
367
 
    case EBADF:
368
 
    case ENOTTY:
369
 
      return EX_UNAVAILABLE;
370
 
    case EINVAL:
371
 
    default:
372
 
      return EX_OSERR;
373
 
    }
 
171
  t_new.c_lflag &= ~ECHO;
 
172
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
 
173
    perror("tcsetattr-echo");
 
174
    return EXIT_FAILURE;
374
175
  }
375
 
  
376
 
  if(debug){
 
176
 
 
177
  if (debug){
377
178
    fprintf(stderr, "Waiting for input from stdin \n");
378
179
  }
379
180
  while(true){
380
 
    if(quit_now){
381
 
      if(debug){
382
 
        fprintf(stderr, "Interrupted by signal, exiting.\n");
383
 
      }
 
181
    if (quit_now){
384
182
      status = EXIT_FAILURE;
385
183
      break;
386
184
    }
387
185
 
388
186
    if(prefix){
389
 
      fprintf(stderr, "%s ", prefix);
390
 
    }
391
 
    {
392
 
      const char *cryptsource = getenv("CRYPTTAB_SOURCE");
393
 
      const char *crypttarget = getenv("CRYPTTAB_NAME");
394
 
      /* Before cryptsetup 1.1.0~rc2 */
395
 
      if(cryptsource == NULL){
396
 
        cryptsource = getenv("cryptsource");
397
 
      }
398
 
      if(crypttarget == NULL){
399
 
        crypttarget = getenv("crypttarget");
400
 
      }
401
 
      const char *const prompt1 = "Unlocking the disk";
402
 
      const char *const prompt2 = "Enter passphrase";
403
 
      if(cryptsource == NULL){
404
 
        if(crypttarget == NULL){
405
 
          fprintf(stderr, "%s to unlock the disk: ", prompt2);
406
 
        } else {
407
 
          fprintf(stderr, "%s (%s)\n%s: ", prompt1, crypttarget,
408
 
                  prompt2);
409
 
        }
410
 
      } else {
411
 
        if(crypttarget == NULL){
412
 
          fprintf(stderr, "%s %s\n%s: ", prompt1, cryptsource,
413
 
                  prompt2);
414
 
        } else {
415
 
          fprintf(stderr, "%s %s (%s)\n%s: ", prompt1, cryptsource,
416
 
                  crypttarget, prompt2);
417
 
        }
418
 
      }
419
 
    }
420
 
    sret = getline(&buffer, &n, stdin);
421
 
    if(sret > 0){
 
187
      fprintf(stderr, "%s Password: ", prefix);
 
188
    } else {
 
189
      fprintf(stderr, "Password: ");
 
190
    }      
 
191
    ret = getline(&buffer, &n, stdin);
 
192
    if (ret > 0){
 
193
      fprintf(stdout, "%s", buffer);
422
194
      status = EXIT_SUCCESS;
423
 
      /* Make n = data size instead of allocated buffer size */
424
 
      n = (size_t)sret;
425
 
      /* Strip final newline */
426
 
      if(n > 0 and buffer[n-1] == '\n'){
427
 
        buffer[n-1] = '\0';     /* not strictly necessary */
428
 
        n--;
429
 
      }
430
 
      size_t written = 0;
431
 
      while(written < n){
432
 
        sret = write(STDOUT_FILENO, buffer + written, n - written);
433
 
        if(sret < 0){
434
 
          int e = errno;
435
 
          error(0, errno, "write");
436
 
          switch(e){
437
 
          case EBADF:
438
 
          case EFAULT:
439
 
          case EINVAL:
440
 
          case EFBIG:
441
 
          case EIO:
442
 
          case ENOSPC:
443
 
          default:
444
 
            status = EX_IOERR;
445
 
            break;
446
 
          case EINTR:
447
 
            status = EXIT_FAILURE;
448
 
            break;
449
 
          }
450
 
          break;
451
 
        }
452
 
        written += (size_t)sret;
453
 
      }
454
 
      sret = close(STDOUT_FILENO);
455
 
      if(sret == -1){
456
 
        int e = errno;
457
 
        error(0, errno, "close");
458
 
        switch(e){
459
 
        case EBADF:
460
 
          status = EX_OSFILE;
461
 
          break;
462
 
        case EIO:
463
 
        default:
464
 
          status = EX_IOERR;
465
 
          break;
466
 
        }
467
 
      }
468
195
      break;
469
196
    }
470
 
    if(sret < 0){
471
 
      int e = errno;
472
 
      if(errno != EINTR and not feof(stdin)){
473
 
        error(0, errno, "getline");
474
 
        switch(e){
475
 
        case EBADF:
476
 
          status = EX_UNAVAILABLE;
477
 
        case EIO:
478
 
        case EINVAL:
479
 
        default:
480
 
          status = EX_IOERR;
481
 
          break;
482
 
        }
 
197
    if (ret < 0){
 
198
      if (errno != EINTR and not feof(stdin)){
 
199
        perror("getline");
 
200
        status = EXIT_FAILURE;
483
201
        break;
484
202
      }
485
203
    }
486
 
    /* if(sret == 0), then the only sensible thing to do is to retry
487
 
       to read from stdin */
 
204
    /* if(ret == 0), then the only sensible thing to do is to retry to
 
205
       read from stdin */
488
206
    fputc('\n', stderr);
489
 
    if(debug and not quit_now){
490
 
      /* If quit_now is nonzero, we were interrupted by a signal, and
491
 
         will print that later, so no need to show this too. */
492
 
      fprintf(stderr, "getline() returned 0, retrying.\n");
493
 
    }
494
207
  }
495
208
  
496
 
  free(buffer);
497
 
  
498
 
  if(debug){
 
209
  if (debug){
499
210
    fprintf(stderr, "Restoring terminal attributes\n");
500
211
  }
501
 
  if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
502
 
    error(0, errno, "tcsetattr+echo");
503
 
  }
504
 
  
505
 
  if(quit_now){
506
 
    sigemptyset(&old_action.sa_mask);
507
 
    old_action.sa_handler = SIG_DFL;
508
 
    ret = sigaction(signal_received, &old_action, NULL);
509
 
    if(ret == -1){
510
 
      error(0, errno, "sigaction");
511
 
    }
512
 
    raise(signal_received);
513
 
  }
514
 
  
515
 
  if(debug){
516
 
    fprintf(stderr, "%s is exiting with status %d\n", argv[0],
517
 
            status);
518
 
  }
519
 
  if(status == EXIT_SUCCESS or status == EX_OK){
520
 
    fputc('\n', stderr);
 
212
  if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
 
213
    perror("tcsetattr+echo");
 
214
  }
 
215
  
 
216
  if (debug){
 
217
    fprintf(stderr, "%s is exiting\n", argv[0]);
521
218
  }
522
219
  
523
220
  return status;