]> git.sur5r.net Git - bacula/bacula/commitdiff
Implement berrno for bpipes and run_program
authorKern Sibbald <kern@sibbald.com>
Wed, 28 Jul 2004 18:53:15 +0000 (18:53 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 28 Jul 2004 18:53:15 +0000 (18:53 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1496 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/kernstodo
bacula/src/dird/backup.c
bacula/src/dird/fd_cmds.c
bacula/src/dird/job.c
bacula/src/lib/berrno.c
bacula/src/lib/berrno.h
bacula/src/lib/bpipe.c
bacula/src/lib/message.c
bacula/src/lib/signal.c
bacula/src/stored/autochanger.c
bacula/src/stored/btape.c

index 377e7e83aca25e2f7afa9e719c069b583a045aa4..3f47599c7e4d75204d044f668c371ad24008b6b3 100644 (file)
@@ -4,10 +4,6 @@
 1.35 Items to do:
 - Add bscan to four-concurrent-jobs regression.
 - Do tape alerts -- see tapealert.txt
-- Fix errno handling in win32 compat routines.
-- Add better error codes to run_program (10000+)
-- Revisit and revise Disaster Recovery (fix SCSI and RAID 
-  disk detection)
 - Document a get out of jail procedure if everything breaks if 
   you lost/broke the Catalog -- do the same for "I know my
   file is there how do I get it back?".
@@ -27,6 +23,7 @@
 - Fix restore ++++ that get intermingled with "Building directory tree"
 - Solve the termcap.h problem on Solaris configure.
 - Fix ./configure to handle installed SQLite
+- Test Win32 errno handling.
 
 Documentation to do: (any release a little bit at a time)
 - Document query file format.
@@ -1115,3 +1112,8 @@ Block Position: 0
    Building directory tree for JobId 856 ...
    Building directory tree for JobId 797 ...3 
    Jobs inserted into the tree.
+- Fix errno handling in win32 compat routines.
+- Add better error codes to run_program (10000+)
+- Revisit and revise Disaster Recovery (fix SCSI and RAID 
+  disk detection)
+
index 9d0726f0dd593fcbde975125381b0958dbdff978..a10f73318059b429bd8954e61382ead615815098 100644 (file)
@@ -362,8 +362,9 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since, FILESET_DBR *fsr
            fclose(fd);
         }
       } else {
+        berrno be;
          Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n"
-              "%s: ERR=%s\n"), fname, strerror(errno));
+              "%s: ERR=%s\n"), fname, be.strerror());
         set_jcr_job_status(jcr, JS_ErrorTerminated);
       }
    }
index c37db4900a77753119902c1a786f06b81412b6d1..fdc8617cf49f14f345ba6b1c0ed8d45e326fae3b 100644 (file)
@@ -254,8 +254,9 @@ static int send_list(JCR *jcr, int list)
             fd->msg = edit_job_codes(jcr, fd->msg, p, "");
             bpipe = open_bpipe(fd->msg, 0, "r");
            if (!bpipe) {
+              berrno be;
                Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"),
-                 p, strerror(errno));
+                 p, be.strerror());
               goto bail_out;
            }
            /* Copy File options */
@@ -276,8 +277,10 @@ static int send_list(JCR *jcr, int list)
               }
            }
            if ((stat=close_bpipe(bpipe)) != 0) {
-               Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
-                 p, stat, strerror(errno));
+              berrno be;
+              be.set_errno(stat);
+               Jmsg(jcr, M_FATAL, 0, _("Error running program %p: ERR=%s\n"),
+                 p, be.strerror());
               goto bail_out;
            }
            break;
@@ -415,8 +418,10 @@ static int send_fileset(JCR *jcr)
                  }
               }
               if ((stat=close_bpipe(bpipe)) != 0) {
-                  Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. RtnStat=%d ERR=%s\n"),
-                    p, stat, strerror(errno));
+                 berrno be;
+                 be.set_errno(stat);
+                  Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. ERR=%s\n"),
+                    p, be.strerror());
                  goto bail_out;
               }
               break;
index bbbefa8997e049899c29c5d712e3060a4b362ae5..e387dd9255193a5622c35c6b9c1e1b9dae96508b 100644 (file)
@@ -57,7 +57,9 @@ void init_job_server(int max_workers)
    watchdog_t *wd;
    
    if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
-      Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), strerror(stat));
+      berrno be;
+      be.set_errno(stat);
+      Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.strerror());
    }
    if ((wd = new_watchdog()) == NULL) {
       Emsg0(M_ABORT, 0, _("Could not init job monitor watchdogs\n"));
@@ -89,7 +91,9 @@ JobId_t run_job(JCR *jcr)
 
    /* Initialize termination condition variable */
    if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
-      Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
+      berrno be;
+      be.set_errno(errstat);
+      Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.strerror());
       goto bail_out;
    }
    jcr->term_wait_inited = true;
@@ -129,7 +133,9 @@ JobId_t run_job(JCR *jcr)
 
    /* Queue the job to be run */
    if ((stat = jobq_add(&job_queue, jcr)) != 0) {
-      Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), strerror(stat));
+      berrno be;
+      be.set_errno(stat);
+      Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.strerror());
       JobId = 0;
       goto bail_out;
    }
@@ -189,8 +195,9 @@ static void *job_thread(void *arg)
            }
            status = close_bpipe(bpipe);
            if (status != 0) {
-               Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob returned non-zero status=%d\n"),
-                 status);
+              berrno be;
+              be.set_errno(status);
+               Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob error: ERR=%s\n"), be.strerror());
               set_jcr_job_status(jcr, JS_FatalError);
               update_job_end_record(jcr);
               goto bail_out;
@@ -248,12 +255,12 @@ static void *job_thread(void *arg)
             *  job in error, simply report the error condition.   
             */
            if (status != 0) {
+              berrno be;
+              be.set_errno(status);
               if (jcr->JobStatus == JS_Terminated) {
-                  Jmsg(jcr, M_WARNING, 0, _("RunAfterJob returned non-zero status=%d\n"),
-                      status);
+                  Jmsg(jcr, M_WARNING, 0, _("RunAfterJob error: ERR=%s\n"), be.strerror());
               } else {
-                  Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob returned non-zero status=%d\n"),
-                      status);
+                  Jmsg(jcr, M_FATAL, 0, _("RunAfterFailedJob error: ERR=%s\n"), be.strerror());
               }
            }
         }
index 9ec5fbd6bba196751d0806754380c87c3d694fe3..9354bb8ca93a8a65d824c56d12db11f02a17f241 100644 (file)
 
 #include "bacula.h"
 
+#ifndef HAVE_WIN32
+extern const char *get_signal_name(int sig);
+extern int num_execvp_errors;
+extern int execvp_errors[];
+#endif
+
 const char *berrno::strerror()
 {
+   int stat = 0; 
 #ifdef HAVE_WIN32
    LPVOID msg;
 
-   if (errnum && b_errno_win32) {
+   if (berrno_ && b_errno_win32) {
       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
          FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
          NULL,
          GetLastError(),
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-         (LPTSTR)&msg;
+         (LPTSTR)&msg,
          0,
          NULL);
 
-      pm_strcpy(&buf_, msg);
+      pm_strcpy(&buf_, (const char *)msg);
       LocalFree(msg);
       return (const char *)buf_;
    }
+#else
+   if (berrno_ & b_errno_exit) {
+      stat = (berrno_ & ~b_errno_exit);       /* remove bit */
+      if (stat == 0) {
+         return "Child exited normally.";    /* this really shouldn't happen */
+      } else {
+        /* Maybe an execvp failure */
+        if (stat >= 200) {
+           if (stat < 200 + num_execvp_errors) {
+              berrno_ = execvp_errors[stat - 200];
+           } else {
+               return "Unknown error during program execvp";
+           }
+        } else {
+            Mmsg(&buf_, "Child exited with code %d", stat);
+           return buf_;
+        }
+        /* If we drop out here, berrno_ is set to an execvp errno */
+      }
+   }
+   if (berrno_ & b_errno_signal) {
+      stat = (berrno_ & ~b_errno_signal);       /* remove bit */
+      Mmsg(&buf_, "Child died from signal %d: %s", stat, get_signal_name(stat));
+      return buf_;
+   }
 #endif
+   /* Normal errno */
    if (bstrerror(berrno_, buf_, 1024) < 0) {
       return "Invalid errno. No error message possible."; 
    }
-   return (const char *)buf_;
+   return buf_;
 }
 
 
 #ifdef TEST_PROGRAM
 
-
-struct FILESET {
-   alist mylist;
-};
-
 int main()
 {
-   FILESET *fileset;
-   char buf[30];
-   alist *mlist;
-
-   fileset = (FILESET *)malloc(sizeof(FILESET));
-   memset(fileset, 0, sizeof(FILESET));
-   fileset->mylist.init();
-
-   printf("Manual allocation/destruction of list:\n");
-   
-   for (int i=0; i<20; i++) {
-      sprintf(buf, "This is item %d", i);
-      fileset->mylist.append(bstrdup(buf));
-   } 
-   for (int i=0; i< fileset->mylist.size(); i++) {
-      printf("Item %d = %s\n", i, (char *)fileset->mylist[i]);  
-   }
-   fileset->mylist.destroy();
-   free(fileset);
-
-   printf("Allocation/destruction using new delete\n");
-   mlist = new alist(10);
-
-   for (int i=0; i<20; i++) {
-      sprintf(buf, "This is item %d", i);
-      mlist->append(bstrdup(buf));
-   } 
-   for (int i=0; i< mlist->size(); i++) {
-      printf("Item %d = %s\n", i, (char *)mlist->get(i));  
-   }
-
-   delete mlist;
-
-
-   sm_dump(false);
-
 }
 #endif
index 88492e1772e160e31ad83602c880bdc08d21bb0c..7efdeba61bede9cdc3d0aa34a2cadfadd2d6ba2d 100644 (file)
  */
 
 #ifdef HAVE_WIN32
-#define b_errno_win32 (1<<29)         /* user reserved bit */
+#define b_errno_win32  (1<<29)        /* user reserved bit */
 #endif
+#define b_errno_exit   (1<<28)        /* child exited, exit code returned */
+#define b_errno_signal (1<<27)        /* child died, signal code returned */
 
 /*
  * A more generalized way of handling errno that works with Unix, Windows,
index 6955aa650e0899838401f1d6b02be79fbec2687a..20cf5bee82f0572e83006b5e594bcee8b43622f7 100644 (file)
 #include "bacula.h"
 #include "jcr.h"
 
+int execvp_errors[] = {EACCES, ENOEXEC, EFAULT, EINTR, E2BIG, 
+                    ENAMETOOLONG, ENOMEM, ETXTBSY, ENOENT};
+int num_execvp_errors = (int)(sizeof(execvp_errors)/sizeof(int));
+
 
 #define MAX_ARGV 100
 static void build_argc_argv(char *cmd, int *bargc, char *bargv[], int max_arg);
 
-
-
 /*
  * Run an external program. Optionally wait a specified number
  *   of seconds. Program killed if wait exceeded. We open
@@ -49,6 +51,7 @@ BPIPE *open_bpipe(char *prog, int wait, const char *mode)
    POOLMEM *tprog;
    int mode_read, mode_write;
    BPIPE *bpipe;
+   int save_errno;
 
    bpipe = (BPIPE *)malloc(sizeof(BPIPE));
    memset(bpipe, 0, sizeof(BPIPE));
@@ -68,20 +71,25 @@ BPIPE *open_bpipe(char *prog, int wait, const char *mode)
 
    /* Each pipe is one way, write one end, read the other, so we need two */
    if (mode_write && pipe(writep) == -1) {
+      save_errno = errno;
       free(bpipe);
+      errno = save_errno;
       return NULL;
    }
    if (mode_read && pipe(readp) == -1) {
+      save_errno = errno;
       if (mode_write) {
         close(writep[0]);
         close(writep[1]);
       }
       free(bpipe);
+      errno = save_errno;
       return NULL;
    }
    /* Start worker process */
    switch (bpipe->worker_pid = fork()) {
    case -1:                          /* error */
+      save_errno = errno;
       if (mode_write) {
         close(writep[0]);
         close(writep[1]);
@@ -91,6 +99,7 @@ BPIPE *open_bpipe(char *prog, int wait, const char *mode)
         close(readp[1]);
       }
       free(bpipe);
+      errno = save_errno;
       return NULL;
 
    case 0:                           /* child */
@@ -108,7 +117,15 @@ BPIPE *open_bpipe(char *prog, int wait, const char *mode)
         close(i);
       }
       execvp(bargv[0], bargv);       /* call the program */
-      exit(errno);                    /* shouldn't get here */
+      /* Convert errno into an exit code for later analysis */
+      for (i=0; i< num_execvp_errors; i++) {
+        if (execvp_errors[i] == errno) {
+           exit(200 + i);            /* exit code => errno */
+        }
+      }
+      exit(255);                     /* unknown errno */
+
+
 
    default:                          /* parent */
       break;
@@ -148,7 +165,7 @@ int close_wpipe(BPIPE *bpipe)
  * Close both pipes and free resources  
  *
  *  Returns: 0 on success
- *          errno on failure
+ *          berrno on failure
  */
 int close_bpipe(BPIPE *bpipe) 
 {
@@ -183,6 +200,7 @@ int close_bpipe(BPIPE *bpipe)
         wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
       } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
       if (wpid == bpipe->worker_pid || wpid == -1) {
+        stat = errno;
          Dmsg3(200, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
             wpid==-1?strerror(errno):"none");
         break;
@@ -190,7 +208,7 @@ int close_bpipe(BPIPE *bpipe)
       Dmsg3(200, "Got wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
             wpid==-1?strerror(errno):"none");
       if (remaining_wait > 0) {
-        bmicrosleep(1, 0);            /* wait one second */
+        bmicrosleep(1, 0);           /* wait one second */
         remaining_wait--;
       } else {
         stat = ETIME;                /* set error status */
@@ -199,18 +217,19 @@ int close_bpipe(BPIPE *bpipe)
       }
    }
    if (wpid > 0) {
-      if (WIFEXITED(chldstatus)) {          /* process exit()ed */
+      if (WIFEXITED(chldstatus)) {    /* process exit()ed */
         stat = WEXITSTATUS(chldstatus);
         if (stat != 0) {
             Dmsg1(100, "Non-zero status %s returned from child.\n", stat);
-           stat = ECHILD;
+           stat |= b_errno_exit;        /* exit status returned */
         }
-         Dmsg1(200, "child status=%d\n", stat);
+         Dmsg1(200, "child status=%d\n", stat & ~b_errno_exit);
       } else if (WIFSIGNALED(chldstatus)) {  /* process died */
-        stat = ECHILD;
-         Dmsg0(200, "Signaled\n");
+        stat = WTERMSIG(chldstatus);
+         Dmsg1(200, "Child died from signale %d\n", stat);
+        stat |= b_errno_signal;      /* exit signal returned */
       }
-   }  
+   }      
    if (bpipe->timer_id) {
       stop_child_timer(bpipe->timer_id);
    }
@@ -228,7 +247,7 @@ int close_bpipe(BPIPE *bpipe)
  * Contrary to my normal calling conventions, this program 
  *
  *  Returns: 0 on success
- *          non-zero on error == errno
+ *          non-zero on error == berrno status
  */
 int run_program(char *prog, int wait, POOLMEM *results)
 {
index 93e82570a4c391ff3131e0b22205c2c3562af292..f33380aa678db9741e9b8699942302eea05a1cc1 100755 (executable)
@@ -473,10 +473,12 @@ void close_msg(JCR *jcr)
 
            stat = close_bpipe(bpipe);
            if (stat != 0 && msgs != daemon_msgs) {
+              berrno be;
+              be.set_errno(stat);
                Dmsg1(150, "Calling emsg. CMD=%s\n", cmd);
-               Jmsg3(jcr, M_ERROR, 0, _("Mail program terminated in error. stat=%d\n"
+               Jmsg2(jcr, M_ERROR, 0, _("Mail program terminated in error.\n"
                                         "CMD=%s\n"
-                                        "ERR=%s\n"), stat, cmd, strerror(stat));
+                                        "ERR=%s\n"), cmd, be.strerror());
            }
            free_memory(line);
 rem_temp_file:
@@ -645,9 +647,11 @@ void dispatch_message(JCR *jcr, int type, int level, char *msg)
                   /* Messages to the operator go one at a time */
                   stat = close_bpipe(bpipe);
                   if (stat != 0) {
+                     berrno be;
+                     be.set_errno(stat);
                       Jmsg2(jcr, M_ERROR, 0, _("Operator mail program terminated in error.\n"
                             "CMD=%s\n"
-                            "ERR=%s\n"), mcmd, strerror(stat));
+                            "ERR=%s\n"), mcmd, be.strerror());
                   }
                }
                free_pool_memory(mcmd);
index 74091e75c187087baab82a11ba3bde99c773769d..b6ae5eafa190c8a410ba68892f1a58e2080d9cb8 100644 (file)
@@ -55,6 +55,15 @@ static SIG_HANDLER *exit_handler;
 /* main process id */
 static pid_t main_pid = 0;
 
+const char *get_signal_name(int sig)
+{
+   if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
+      return "Invalid signal number";
+   } else {
+      return sig_names[sig];
+   }
+}
+
 /* 
  * Handle signals here
  */
index d73c564092c8c7cfa69da1e1f0cf824399207000..342619ad304eaa00b6c9e497f8172dc27c825109 100644 (file)
@@ -95,6 +95,13 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir)
            changer = edit_device_codes(jcr, changer, 
                         jcr->device->changer_command, "unload");
            status = run_program(changer, timeout, NULL);
+           if (status != 0) {
+              berrno be;
+              be.set_errno(status);
+               Jmsg(jcr, M_INFO, 0, _("3992 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"),
+                   slot, drive, be.strerror());
+           }
+
             Dmsg1(400, "unload status=%d\n", status);
         }
         /*
@@ -112,8 +119,10 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir)
             Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
                    slot, drive);
         } else {
-            Jmsg(jcr, M_INFO, 0, _("3992 Bad autochanger \"load slot %d, drive %d\", status=%d.\n"),
-                   slot, drive, status);
+          berrno be;
+          be.set_errno(status);
+            Jmsg(jcr, M_INFO, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"),
+                   slot, drive, be.strerror());
         }
          Dmsg2(400, "load slot %d status=%d\n", slot, status);
       } else { 
@@ -157,8 +166,10 @@ static int get_autochanger_loaded_slot(JCR *jcr)
              drive);
       }
    } else {
-      Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command, status=%d.\n"), 
-          drive, status);
+      berrno be;
+      be.set_errno(status);
+      Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"), 
+          drive, be.strerror());
       loaded = -1;             /* force unload */
    }
    free_pool_memory(changer);
@@ -216,7 +227,13 @@ bool autochanger_list(DCR *dcr, BSOCK *dir)
       slot = jcr->VolCatInfo.Slot; 
       jcr->VolCatInfo.Slot = loaded;
       changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "unload");
-      run_program(changer, timeout, NULL);
+      int stat = run_program(changer, timeout, NULL);
+      if (stat != 0) {
+        berrno be;
+        be.set_errno(stat);
+         Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d\" command: ERR=%s.\n"), 
+             loaded, be.strerror());
+      }
       jcr->VolCatInfo.Slot = slot;
    }
 
@@ -234,8 +251,13 @@ bool autochanger_list(DCR *dcr, BSOCK *dir)
       dir->msglen = strlen(dir->msg);
       bnet_send(dir);
    }
+   int stat = close_bpipe(bpipe);
+   if (stat != 0) {
+      berrno be;
+      be.set_errno(stat);
+      bnet_fsend(dir, "Autochanger error: ERR=%s\n", be.strerror());
+   }
    bnet_sig(dir, BNET_EOD);
-   close_bpipe(bpipe);
 
    free_pool_memory(changer);
    return true;
index 5ac4c6a46a2eddce8b501b540b2a5ddbf992d2f2..e9a1dc548b1d9aaa91042aef7040e399ad5e0cf3 100644 (file)
@@ -1102,12 +1102,14 @@ try_again:
    changer = edit_device_codes(jcr, changer, jcr->device->changer_command, 
                 "loaded");
    status = run_program(changer, timeout, results);
-   Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results);
+   Dmsg3(100, "run_prog: %s stat=%d result=\"%s\"\n", changer, status, results);
    if (status == 0) {
       loaded = atoi(results);
    } else {
+      berrno be;
+      be.set_errno(status);
       Pmsg1(-1, _("3991 Bad autochanger command: %s\n"), changer);
-      Pmsg2(-1, _("3991 status=%d result=%s\n"), status, results);
+      Pmsg2(-1, _("3991 result=\"%s\": ERR=%s\n"), results, be.strerror());
       goto bail_out;
    }
    if (loaded) {
@@ -1128,8 +1130,10 @@ try_again:
       status = run_program(changer, timeout, results);
       Pmsg2(-1, "unload status=%s %d\n", status==0?"OK":"Bad", status);
       if (status != 0) {
+        berrno be;
+        be.set_errno(status);
          Pmsg1(-1, _("3992 Bad autochanger command: %s\n"), changer);
-         Pmsg2(-1, _("3992 status=%d result=%s\n"), status, results);
+         Pmsg2(-1, _("3992 result=\"%s\": ERR=%s\n"), results, be.strerror());
       }
    }
 
@@ -1149,8 +1153,10 @@ try_again:
       Pmsg2(-1,  _("3303 Autochanger \"load slot %d %d\" status is OK.\n"),
         slot, dev->drive_index);
    } else {
+      berrno be;
+      be.set_errno(status);
       Pmsg1(-1, _("3993 Bad autochanger command: %s\n"), changer);
-      Pmsg2(-1, _("3993 status=%d result=%s\n"), status, results);
+      Pmsg2(-1, _("3993 result=\"%s\": ERR=%s\n"), results, be.strerror());
       goto bail_out;
    }