~droetker/ubuntu/saucy/bumblebee/fix-for-1250745

« back to all changes in this revision

Viewing changes to src/bumblebeed.c

  • Committer: Package Import Robot
  • Author(s): Vincent Cheng
  • Date: 2013-05-03 03:04:38 UTC
  • Revision ID: package-import@ubuntu.com-20130503030438-uvmvja55iicztpxf
Tags: upstream-3.2.1
Import upstream version 3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011-2013, The Bumblebee Project
 
3
 * Author: Joaquín Ignacio Aramendía <samsagax@gmail.com>
 
4
 * Author: Jaron Viëtor AKA "Thulinma" <jaron@vietors.com>
 
5
 *
 
6
 * This file is part of Bumblebee.
 
7
 *
 
8
 * Bumblebee is free software: you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation, either version 3 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * Bumblebee is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
16
 * GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with Bumblebee. If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
/*
 
23
 * C-coded version of the Bumblebee daemon and optirun.
 
24
 */
 
25
 
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#include <fcntl.h>
 
29
#include <stdlib.h>
 
30
#include <stdbool.h>
 
31
#include <grp.h>
 
32
#include <signal.h>
 
33
#include <stdio.h>
 
34
#include <string.h>
 
35
#include <errno.h>
 
36
#include <getopt.h>
 
37
#ifdef WITH_PIDFILE
 
38
#ifdef HAVE_LIBBSD_020
 
39
#include <libutil.h>
 
40
#else
 
41
#include <bsd/libutil.h>
 
42
#endif
 
43
#endif
 
44
#include "bbconfig.h"
 
45
#include "bbsocket.h"
 
46
#include "bblogger.h"
 
47
#include "bbsecondary.h"
 
48
#include "bbrun.h"
 
49
#include "pci.h"
 
50
#include "driver.h"
 
51
#include "switch/switching.h"
 
52
 
 
53
/**
 
54
 * Change GID and umask of the daemon
 
55
 * @return EXIT_SUCCESS if the gid could be changed, EXIT_FAILURE otherwise
 
56
 */
 
57
static int bb_chgid(void) {
 
58
  /* Change the Group ID of bumblebee */
 
59
  struct group *gp;
 
60
  errno = 0;
 
61
  gp = getgrnam(bb_config.gid_name);
 
62
  if (gp == NULL) {
 
63
    int error_num = errno;
 
64
    bb_log(LOG_ERR, "%s\n", strerror(error_num));
 
65
    bb_log(LOG_ERR, "There is no \"%s\" group\n", bb_config.gid_name);
 
66
    return EXIT_FAILURE;
 
67
  }
 
68
  if (setgid(gp->gr_gid) != 0) {
 
69
    bb_log(LOG_ERR, "Could not set the GID of bumblebee: %s\n", strerror(errno));
 
70
    return EXIT_FAILURE;
 
71
  }
 
72
  /* Change the file mode mask */
 
73
  umask(027);
 
74
  return EXIT_SUCCESS;
 
75
}
 
76
 
 
77
/**
 
78
 * Fork to the background, and exit parent.
 
79
 * @return EXIT_SUCCESS if the daemon could fork, EXIT_FAILURE otherwise. Note
 
80
 * that the parent exits and the child continues to run
 
81
 */
 
82
static int daemonize(void) {
 
83
  /* Fork off the parent process */
 
84
  pid_t bb_pid = fork();
 
85
  if (bb_pid < 0) {
 
86
    bb_log(LOG_ERR, "Could not fork to background\n");
 
87
    return EXIT_FAILURE;
 
88
  }
 
89
 
 
90
  /* If we got a good PID, then we can exit the parent process. */
 
91
  if (bb_pid > 0) {
 
92
    exit(EXIT_SUCCESS);
 
93
  }
 
94
 
 
95
  /* Create a new SID for the child process */
 
96
  pid_t bb_sid = setsid();
 
97
  if (bb_sid < 0) {
 
98
    bb_log(LOG_ERR, "Could not set SID: %s\n", strerror(errno));
 
99
    return EXIT_FAILURE;
 
100
  }
 
101
 
 
102
  /* Change the current working directory */
 
103
  if ((chdir("/")) < 0) {
 
104
    bb_log(LOG_ERR, "Could not change to root directory: %s\n", strerror(errno));
 
105
    return EXIT_FAILURE;
 
106
  }
 
107
 
 
108
  /* Reroute standard file descriptors to /dev/null */
 
109
  int devnull = open("/dev/null", O_RDWR);
 
110
  if (devnull < 0){
 
111
    bb_log(LOG_ERR, "Could not open /dev/null: %s\n", strerror(errno));
 
112
    return EXIT_FAILURE;
 
113
  }
 
114
  dup2(devnull, STDIN_FILENO);
 
115
  dup2(devnull, STDOUT_FILENO);
 
116
  dup2(devnull, STDERR_FILENO);
 
117
  close(devnull);
 
118
  return EXIT_SUCCESS;
 
119
}
 
120
 
 
121
/**
 
122
 *  Handle recieved signals - except SIGCHLD, which is handled in bbrun.c
 
123
 */
 
124
static void handle_signal(int sig) {
 
125
  static int sigpipes = 0;
 
126
 
 
127
  switch (sig) {
 
128
    case SIGHUP:
 
129
      bb_log(LOG_WARNING, "Received %s signal (ignoring...)\n", strsignal(sig));
 
130
      break;
 
131
    case SIGPIPE:
 
132
      /* if bb_log generates a SIGPIPE, i.e. when bumblebeed runs like
 
133
       * bumblebeed 2>&1 | cat and the pipe is killed, don't die infinitely */
 
134
      if (sigpipes <= 10) {
 
135
        bb_log(LOG_WARNING, "Received %s signal %i (signals 10> are ignored)\n",
 
136
                strsignal(sig), ++sigpipes);
 
137
      }
 
138
      break;
 
139
    case SIGINT:
 
140
    case SIGQUIT:
 
141
      bb_log(LOG_WARNING, "Received %s signal.\n", strsignal(sig));
 
142
      socketClose(&bb_status.bb_socket); //closing the socket terminates the server
 
143
      break;
 
144
    case SIGTERM:
 
145
      bb_log(LOG_WARNING, "Received %s signal.\n", strsignal(sig));
 
146
      socketClose(&bb_status.bb_socket); //closing the socket terminates the server
 
147
      bb_run_stopwaiting(); //speed up shutdown by not waiting for processes anymore
 
148
      break;
 
149
    default:
 
150
      bb_log(LOG_WARNING, "Unhandled signal %s\n", strsignal(sig));
 
151
      break;
 
152
  }
 
153
}
 
154
 
 
155
/// Socket list structure for use in main_loop.
 
156
 
 
157
struct clientsocket {
 
158
  int sock;
 
159
  int inuse;
 
160
  struct clientsocket * prev;
 
161
  struct clientsocket * next;
 
162
};
 
163
 
 
164
/// Receive and/or sent data to/from this socket.
 
165
/// \param sock Pointer to socket. Assumed to be valid.
 
166
 
 
167
static void handle_socket(struct clientsocket * C) {
 
168
  static char buffer[BUFFER_SIZE], *conf_key;
 
169
  bool need_secondary;
 
170
  //since these are local sockets, we can safely assume we get whole messages at a time
 
171
  int r = socketRead(&C->sock, buffer, BUFFER_SIZE);
 
172
  if (r > 0) {
 
173
    ensureZeroTerminated(buffer, r, BUFFER_SIZE);
 
174
    conf_key = strchr(buffer, ' ');
 
175
    switch (buffer[0]) {
 
176
      case 'S'://status
 
177
        if (bb_status.errors[0] != 0) {
 
178
          r = snprintf(buffer, BUFFER_SIZE, "Error (%s): %s\n", GITVERSION, bb_status.errors);
 
179
        } else {
 
180
          if (bb_is_running(bb_status.x_pid)) {
 
181
            r = snprintf(buffer, BUFFER_SIZE, "Ready (%s). X is PID %i, %i applications using bumblebeed.\n", GITVERSION, bb_status.x_pid, bb_status.appcount);
 
182
          } else {
 
183
            char *card_status;
 
184
            switch (switch_status()) {
 
185
              case SWITCH_OFF:
 
186
                card_status = "off";
 
187
                break;
 
188
              case SWITCH_ON:
 
189
                card_status = "on";
 
190
                break;
 
191
              default:
 
192
                /* no PM available, assume it's on */
 
193
                card_status = "likely on";
 
194
                break;
 
195
            }
 
196
            r = snprintf(buffer, BUFFER_SIZE, "Ready (%s). X inactive. Discrete"
 
197
                    " video card is %s.\n", GITVERSION, card_status);
 
198
          }
 
199
        }
 
200
        /* don't rely on result of snprintf, instead calculate length including
 
201
         * null byte. We assume a succesful write */
 
202
        socketWrite(&C->sock, buffer, strlen(buffer) + 1);
 
203
        break;
 
204
      case 'F'://force VirtualGL if possible
 
205
      case 'C'://check if VirtualGL is allowed
 
206
        need_secondary = conf_key ? strcmp(conf_key + 1, "NoX") : true;
 
207
        if (start_secondary(need_secondary)) {
 
208
          r = snprintf(buffer, BUFFER_SIZE, "Yes. X is active.\n");
 
209
          if (C->inuse == 0) {
 
210
            C->inuse = 1;
 
211
            bb_status.appcount++;
 
212
          }
 
213
        } else {
 
214
          if (bb_status.errors[0] != 0) {
 
215
            r = snprintf(buffer, BUFFER_SIZE, "No - error: %s\n", bb_status.errors);
 
216
          } else {
 
217
            r = snprintf(buffer, BUFFER_SIZE, "No, secondary X is not active.\n");
 
218
          }
 
219
        }
 
220
        /* don't rely on result of snprintf, instead calculate length including
 
221
         * null byte. We assume a succesful write */
 
222
        socketWrite(&C->sock, buffer, strlen(buffer) + 1);
 
223
        break;
 
224
      case 'D'://done, close the socket.
 
225
        socketClose(&C->sock);
 
226
        break;
 
227
      case 'Q': /* query for configuration details */
 
228
        /* required since labels can only be attached on statements */;
 
229
        if (conf_key) {
 
230
          conf_key++;
 
231
          if (strcmp(conf_key, "VirtualDisplay") == 0) {
 
232
            snprintf(buffer, BUFFER_SIZE, "Value: %s\n", bb_config.x_display);
 
233
          } else if (strcmp(conf_key, "LibraryPath") == 0) {
 
234
            snprintf(buffer, BUFFER_SIZE, "Value: %s\n", bb_config.ld_path);
 
235
          } else if (strcmp(conf_key, "Driver") == 0) {
 
236
            /* note: this is not the auto-detected value, but the actual one */
 
237
            snprintf(buffer, BUFFER_SIZE, "Value: %s\n", bb_config.driver);
 
238
          } else {
 
239
            snprintf(buffer, BUFFER_SIZE, "Unknown key requested.\n");
 
240
          }
 
241
        } else {
 
242
          snprintf(buffer, BUFFER_SIZE, "Error: invalid protocol message.\n");
 
243
        }
 
244
        socketWrite(&C->sock, buffer, strlen(buffer) + 1);
 
245
        break;
 
246
      default:
 
247
        bb_log(LOG_WARNING, "Unhandled message received: %s\n", buffer);
 
248
        break;
 
249
    }
 
250
  }
 
251
}
 
252
 
 
253
/* The main loop handles all connections and cleanup.
 
254
 * It returns if there are any problems with the listening socket.
 
255
 */
 
256
static void main_loop(void) {
 
257
  int optirun_socket_fd;
 
258
  struct clientsocket *client;
 
259
  struct clientsocket *last = 0; // the last client
 
260
 
 
261
  bb_log(LOG_INFO, "Initialization completed - now handling client requests\n");
 
262
  /* Listen for Optirun conections and act accordingly */
 
263
  while (bb_status.bb_socket != -1) {
 
264
    fd_set readfds;
 
265
    int max_fd = 0;
 
266
 
 
267
    FD_ZERO(&readfds);
 
268
#define FD_SET_AND_MAX(fd)                   \
 
269
    do if ((fd) >= 0 && (fd) < FD_SETSIZE) { \
 
270
      FD_SET((fd), &readfds);                \
 
271
      if (max_fd < (fd))                     \
 
272
        max_fd = (fd);                       \
 
273
    } while (0)
 
274
    FD_SET_AND_MAX(bb_status.bb_socket);
 
275
    FD_SET_AND_MAX(bb_status.x_pipe[0]);
 
276
    for (client = last; client; client = client->prev)
 
277
      FD_SET_AND_MAX(client->sock);
 
278
#undef FD_SET_AND_MAX
 
279
 
 
280
    if (select(max_fd + 1, &readfds, NULL, NULL, NULL) < 0) {
 
281
      if (errno == EINTR)
 
282
        continue;
 
283
      bb_log(LOG_ERR, "select() failed: %s\n", strerror(errno));
 
284
      break;
 
285
    }
 
286
 
 
287
#define FD_EVENT(fd) ((fd) >= 0 && FD_ISSET((fd), &readfds))
 
288
    if (FD_EVENT(bb_status.bb_socket)) {
 
289
      /* Accept a connection. */
 
290
      optirun_socket_fd = socketAccept(&bb_status.bb_socket, SOCK_NOBLOCK);
 
291
      if (optirun_socket_fd >= 0) {
 
292
        bb_log(LOG_DEBUG, "Accepted new connection\n", optirun_socket_fd, bb_status.appcount);
 
293
 
 
294
        /* add to list of sockets */
 
295
        client = malloc(sizeof (struct clientsocket));
 
296
        client->sock = optirun_socket_fd;
 
297
        client->inuse = 0;
 
298
        client->prev = last;
 
299
        client->next = 0;
 
300
        if (last) {
 
301
          last->next = client;
 
302
        }
 
303
        last = client;
 
304
      }
 
305
    }
 
306
 
 
307
    //check the X output pipe, if open
 
308
    if (FD_EVENT(bb_status.x_pipe[0]))
 
309
      check_xorg_pipe();
 
310
 
 
311
    /* loop through all connections, removing dead ones, receiving/sending data to the rest */
 
312
    struct clientsocket *next_iter;
 
313
    for (client = last; client; client = next_iter) {
 
314
      /* set the next client here because client may be free()'d */
 
315
      next_iter = client->prev;
 
316
      if (FD_EVENT(client->sock))
 
317
        handle_socket(client);
 
318
      if (client->sock < 0) {
 
319
        //remove from list
 
320
        if (client->inuse > 0) {
 
321
          bb_status.appcount--;
 
322
          //stop X / card if there is no need to keep it running
 
323
          if ((bb_status.appcount == 0) && (bb_config.stop_on_exit)) {
 
324
            stop_secondary();
 
325
          }
 
326
        }
 
327
        if (client->next) {
 
328
          client->next->prev = client->prev;
 
329
        } else {
 
330
          last = client->prev;
 
331
        }
 
332
        if (client->prev) {
 
333
          client->prev->next = client->next;
 
334
        }
 
335
        free(client);
 
336
      }
 
337
    }
 
338
#undef FD_EVENT
 
339
  }//socket server loop
 
340
 
 
341
  /* loop through all connections, closing all of them */
 
342
  client = last;
 
343
  while (client) {
 
344
    //close socket if not already closed
 
345
    if (client->sock >= 0) {
 
346
      socketClose(&client->sock);
 
347
    }
 
348
    //remove from list
 
349
    if (client->inuse > 0) {
 
350
      bb_status.appcount--;
 
351
    }
 
352
    // change the client here because after free() there is no way to know prev
 
353
    last = client;
 
354
    client = client->prev;
 
355
    free(last);
 
356
  }
 
357
  if (bb_status.appcount != 0) {
 
358
    bb_log(LOG_WARNING, "appcount = %i (should be 0)\n", bb_status.appcount);
 
359
  }
 
360
}
 
361
 
 
362
/**
 
363
 * Returns the option string for this program
 
364
 * @return An option string which can be used for getopt
 
365
 */
 
366
const char *bbconfig_get_optstr(void) {
 
367
  return BBCONFIG_COMMON_OPTSTR "Dx:g:m:k:";
 
368
}
 
369
 
 
370
/**
 
371
 * Returns the long options for this program
 
372
 * @return A option struct which can be used for getopt_long
 
373
 */
 
374
const struct option *bbconfig_get_lopts(void) {
 
375
  static struct option longOpts[] = {
 
376
    {"daemon", 0, 0, 'D'},
 
377
    {"xconf", 1, 0, 'x'},
 
378
    {"xconfdir", 1, 0, OPT_X_CONF_DIR_PATH},
 
379
    {"group", 1, 0, 'g'},
 
380
    {"module-path", 1, 0, 'm'},
 
381
    {"driver-module", 1, 0, 'k'},
 
382
    {"driver", 1, 0, OPT_DRIVER},
 
383
#ifdef WITH_PIDFILE
 
384
    {"pidfile", 1, 0, OPT_PIDFILE},
 
385
#endif
 
386
    {"use-syslog", 0, 0, OPT_USE_SYSLOG},
 
387
    {"pm-method", 1, 0, OPT_PM_METHOD},
 
388
    BBCONFIG_COMMON_LOPTS
 
389
  };
 
390
  return longOpts;
 
391
}
 
392
 
 
393
/**
 
394
 * Parses local command line options
 
395
 * @param opt The short option
 
396
 * @param value Value for the option if any
 
397
 * @return 1 if the option has been processed, 0 otherwise
 
398
 */
 
399
int bbconfig_parse_options(int opt, char *value) {
 
400
  switch (opt) {
 
401
    case OPT_USE_SYSLOG:
 
402
      /* already processed in bbconfig.c */
 
403
      break;
 
404
    case 'D'://daemonize
 
405
      bb_status.runmode = BB_RUN_DAEMON;
 
406
      break;
 
407
    case 'x'://xorg.conf path
 
408
      set_string_value(&bb_config.x_conf_file, value);
 
409
      break;
 
410
    case OPT_X_CONF_DIR_PATH://xorg.conf.d path
 
411
      set_string_value(&bb_config.x_conf_dir, value);
 
412
      break;
 
413
    case 'g'://group name to use
 
414
      set_string_value(&bb_config.gid_name, value);
 
415
      break;
 
416
    case 'm'://modulepath
 
417
      set_string_value(&bb_config.mod_path, value);
 
418
      break;
 
419
    case OPT_DRIVER://driver
 
420
      set_string_value(&bb_config.driver, value);
 
421
      break;
 
422
    case 'k'://kernel module
 
423
      set_string_value(&bb_config.module_name, value);
 
424
      break;
 
425
    case OPT_PM_METHOD:
 
426
      bb_config.pm_method = bb_pm_method_from_string(value);
 
427
      break;
 
428
#ifdef WITH_PIDFILE
 
429
    case OPT_PIDFILE:
 
430
      set_string_value(&bb_config.pid_file, value);
 
431
      break;
 
432
#endif
 
433
    default:
 
434
      /* no options parsed */
 
435
      return 0;
 
436
  }
 
437
  return 1;
 
438
}
 
439
 
 
440
int main(int argc, char* argv[]) {
 
441
#ifdef WITH_PIDFILE
 
442
  struct pidfh *pfh = NULL;
 
443
  pid_t otherpid;
 
444
#endif
 
445
 
 
446
  /* the logs needs to be ready before the signal handlers */
 
447
  init_early_config(argv, BB_RUN_SERVER);
 
448
  bbconfig_parse_opts(argc, argv, PARSE_STAGE_LOG);
 
449
  bb_init_log();
 
450
 
 
451
  /* Setup signal handling before anything else. Note that messages are not
 
452
   * shown until init_config has set bb_status.verbosity
 
453
   */
 
454
  signal(SIGHUP, handle_signal);
 
455
  signal(SIGTERM, handle_signal);
 
456
  signal(SIGINT, handle_signal);
 
457
  signal(SIGQUIT, handle_signal);
 
458
  signal(SIGPIPE, handle_signal);
 
459
 
 
460
  /* first load the config to make the logging verbosity level available */
 
461
  init_config();
 
462
  bbconfig_parse_opts(argc, argv, PARSE_STAGE_PRECONF);
 
463
 
 
464
  /* First look for an intel card */
 
465
  struct pci_bus_id *pci_id_igd = pci_find_gfx_by_vendor(PCI_VENDOR_ID_INTEL, 0);
 
466
  if (!pci_id_igd) {
 
467
    /* This is no Optimus configuration. But maybe it's a
 
468
       dual-nvidia configuration. Let us test that.
 
469
    */
 
470
    pci_id_igd = pci_find_gfx_by_vendor(PCI_VENDOR_ID_NVIDIA, 1);
 
471
    bb_log(LOG_INFO, "No Intel video card found, testing for dual-nvidia system.\n");
 
472
 
 
473
    if (!pci_id_igd) {
 
474
      /* Ok, this is not a double gpu setup supported (there is at most
 
475
         one nvidia and no intel cards */
 
476
      bb_log(LOG_ERR, "No integrated video card found, quitting.\n");
 
477
      return (EXIT_FAILURE);
 
478
    }
 
479
  }
 
480
  pci_bus_id_discrete = pci_find_gfx_by_vendor(PCI_VENDOR_ID_NVIDIA, 0);
 
481
  if (!pci_bus_id_discrete) {
 
482
    bb_log(LOG_ERR, "No discrete video card found, quitting\n");
 
483
    return (EXIT_FAILURE);
 
484
  }
 
485
 
 
486
  bb_log(LOG_DEBUG, "Found card: %02x:%02x.%x (discrete)\n", pci_bus_id_discrete->bus, pci_bus_id_discrete->slot, pci_bus_id_discrete->func);
 
487
  bb_log(LOG_DEBUG, "Found card: %02x:%02x.%x (integrated)\n", pci_id_igd->bus, pci_id_igd->slot, pci_id_igd->func);
 
488
 
 
489
  free(pci_id_igd);
 
490
 
 
491
  GKeyFile *bbcfg = bbconfig_parse_conf();
 
492
  bbconfig_parse_opts(argc, argv, PARSE_STAGE_DRIVER);
 
493
  driver_detect();
 
494
  if (bbcfg) {
 
495
    bbconfig_parse_conf_driver(bbcfg, bb_config.driver);
 
496
    g_key_file_free(bbcfg);
 
497
  }
 
498
  bbconfig_parse_opts(argc, argv, PARSE_STAGE_OTHER);
 
499
  check_pm_method();
 
500
 
 
501
  /* dump the config after detecting the driver */
 
502
  config_dump();
 
503
  if (config_validate() != 0) {
 
504
    return (EXIT_FAILURE);
 
505
  }
 
506
 
 
507
#ifdef WITH_PIDFILE
 
508
  /* only write PID if a pid file has been set */
 
509
  if (bb_config.pid_file[0]) {
 
510
    pfh = pidfile_open(bb_config.pid_file, 0644, &otherpid);
 
511
    if (pfh == NULL) {
 
512
      if (errno == EEXIST) {
 
513
        bb_log(LOG_ERR, "Daemon already running, pid %d\n", otherpid);
 
514
      } else {
 
515
        bb_log(LOG_ERR, "Cannot open or write pidfile %s.\n", bb_config.pid_file);
 
516
      }
 
517
      bb_closelog();
 
518
      exit(EXIT_FAILURE);
 
519
    }
 
520
  }
 
521
#endif
 
522
 
 
523
  /* Change GID and mask according to configuration */
 
524
  if ((bb_config.gid_name != 0) && (bb_config.gid_name[0] != 0)) {
 
525
    int retval = bb_chgid();
 
526
    if (retval != EXIT_SUCCESS) {
 
527
      bb_closelog();
 
528
#ifdef WITH_PIDFILE
 
529
      pidfile_remove(pfh);
 
530
#endif
 
531
      exit(retval);
 
532
    }
 
533
  }
 
534
 
 
535
  bb_log(LOG_NOTICE, "%s %s started\n", bb_status.program_name, GITVERSION);
 
536
 
 
537
  /* Daemonized if daemon flag is activated */
 
538
  if (bb_status.runmode == BB_RUN_DAEMON) {
 
539
    int retval = daemonize();
 
540
    if (retval != EXIT_SUCCESS) {
 
541
      bb_closelog();
 
542
#ifdef WITH_PIDFILE
 
543
      pidfile_remove(pfh);
 
544
#endif
 
545
      exit(retval);
 
546
    }
 
547
  }
 
548
 
 
549
#ifdef WITH_PIDFILE
 
550
  /* write PID after daemonizing */
 
551
  pidfile_write(pfh);
 
552
#endif
 
553
 
 
554
  /* Initialize communication socket, enter main loop */
 
555
  bb_status.bb_socket = socketServer(bb_config.socket_path, SOCK_NOBLOCK);
 
556
  stop_secondary(); //turn off card, nobody is connected right now.
 
557
  main_loop();
 
558
  unlink(bb_config.socket_path);
 
559
  bb_status.runmode = BB_RUN_EXIT; //make sure all methods understand we are shutting down
 
560
  if (bb_config.card_shutdown_state) {
 
561
    //if shutdown state = 1, turn on card
 
562
    start_secondary(false);
 
563
  } else {
 
564
    //if shutdown state = 0, turn off card
 
565
    stop_secondary();
 
566
  }
 
567
  bb_closelog();
 
568
#ifdef WITH_PIDFILE
 
569
  pidfile_remove(pfh);
 
570
#endif
 
571
  bb_stop_all(); //stop any started processes that are left
 
572
  //close X pipe, if any parts of it are open still
 
573
  if (bb_status.x_pipe[0] != -1){close(bb_status.x_pipe[0]); bb_status.x_pipe[0] = -1;}
 
574
  if (bb_status.x_pipe[1] != -1){close(bb_status.x_pipe[1]); bb_status.x_pipe[1] = -1;}
 
575
  return (EXIT_SUCCESS);
 
576
}